Initial release — InstaShadow mastering compressor v1.0

Dual-stage compressor (optical + VCA) with output transformer saturation.
- Port-Hamiltonian T4B opto-cell model with implicit trapezoidal integration
- Feed-forward VCA with 7 ratios, 6 attack/release presets, Dual release mode
- 3 transformer types (Nickel/Iron/Steel) with 4x oversampled waveshaping
- Analog-style needle VU meters, horizontal GR meters
- Sidechain HPF, stereo link, independent section bypass
- Full state save/restore, CI/CD for Windows/macOS/Linux
This commit is contained in:
hariel1985
2026-03-27 16:03:24 +01:00
commit a587a43ff9
33 fájl változott, egészen pontosan 2417 új sor hozzáadva és 0 régi sor törölve

96
Source/OpticalCell.cpp Normal file
Fájl megtekintése

@@ -0,0 +1,96 @@
#include "OpticalCell.h"
OpticalCell::OpticalCell() {}
void OpticalCell::prepare (double sampleRate)
{
sr = sampleRate;
dt = 1.0 / (2.0 * sampleRate); // 2x oversampled
reset();
}
void OpticalCell::reset()
{
q_el = 0.0;
R_cds = R_cds_dark;
lightOutput = 0.0;
lightHistory = 0.0;
currentGain = 1.0;
prevInput = 0.0f;
}
void OpticalCell::solveImplicitStep (double inputLevel)
{
// Drive from sidechain level (rectified, normalized 0..1+)
double i_drive = std::max (0.0, inputLevel);
// Store old state for trapezoidal rule
double q_old = q_el;
double f_old = (i_drive - q_old / C_el) / R_el;
// Initial guess (forward Euler)
double q_new = q_old + dt * f_old;
// Newton-Raphson iteration (implicit trapezoidal)
for (int iter = 0; iter < maxNewtonIter; ++iter)
{
double f_new = (i_drive - q_new / C_el) / R_el;
double residual = q_new - q_old - (dt / 2.0) * (f_old + f_new);
double jacobian = 1.0 + dt / (2.0 * R_el * C_el);
double delta = residual / jacobian;
q_new -= delta;
if (std::abs (delta) < newtonTol)
break;
}
q_el = q_new;
// Light output proportional to STORED ENERGY (voltage^2)
// This ensures continuous light output at steady state
double voltage = q_el / C_el;
lightOutput = eta_el * voltage * voltage;
// Update memory (illumination history) — explicit Euler
lightHistory += dt * (lightOutput - lightHistory) / memoryTau;
lightHistory = std::max (0.0, lightHistory);
// CdS resistance: R = k * (L_eff)^(-gamma)
// Memory effect: effective light includes accumulated history
double L_eff = lightOutput + memoryAlpha * lightHistory;
double epsilon = 1.0e-10;
R_cds = k_cds * std::pow (L_eff + epsilon, -gamma);
R_cds = std::clamp (R_cds, R_cds_min, R_cds_dark);
}
void OpticalCell::updateGain()
{
// Shunt attenuator: high R_cds = pass, low R_cds = attenuate
currentGain = R_cds / (R_fixed + R_cds);
}
float OpticalCell::processSample (float sidechainLevel, float thresholdLinear)
{
// Envelope above threshold
float envelope = std::max (0.0f, sidechainLevel - thresholdLinear);
// 2x oversampling: interpolate and process two sub-samples
float mid = (prevInput + envelope) * 0.5f;
prevInput = envelope;
solveImplicitStep ((double) mid);
solveImplicitStep ((double) envelope);
updateGain();
return (float) currentGain;
}
float OpticalCell::getGainReductionDb() const
{
if (currentGain <= 0.0)
return -60.0f;
return (float) (20.0 * std::log10 (currentGain));
}