4:1 ratio, hard knee, threshold -20. Drive at -10 dBFS peak. Expected output peak: -20 + (10/4) = -17.5 dBFS steady-state. Uses long attack/release so the log-domain envelope settles to the peak instead of riding the 1kHz sine waveform.
| 148 | // Uses long attack/release so the log-domain envelope settles to the |
| 149 | // peak instead of riding the 1kHz sine waveform. |
| 150 | void testStaticRatio() |
| 151 | { |
| 152 | ClientComp comp; |
| 153 | comp.prepare(kSampleRate); |
| 154 | comp.setEnabled(true); |
| 155 | comp.setThresholdDb(-20.0f); |
| 156 | comp.setRatio(4.0f); |
| 157 | comp.setKneeDb(0.0f); |
| 158 | comp.setMakeupDb(0.0f); |
| 159 | comp.setAttackMs(50.0f); |
| 160 | comp.setReleaseMs(500.0f); |
| 161 | comp.setLimiterEnabled(false); |
| 162 | |
| 163 | const float amp = std::pow(10.0f, -10.0f / 20.0f); // -10 dBFS peak |
| 164 | |
| 165 | // Warmup: envelope τ = 500ms, settle over 3s. |
| 166 | const int warm = static_cast<int>(kSampleRate) * 3; |
| 167 | auto warmBuf = makeTone(1000.0, warm, amp); |
| 168 | processBlocks(comp, warmBuf.data(), warm); |
| 169 | |
| 170 | const int frames = static_cast<int>(kSampleRate); |
| 171 | auto buf = makeTone(1000.0, frames, amp); |
| 172 | processBlocks(comp, buf.data(), frames); |
| 173 | |
| 174 | const float measPeak = peakAbsStereo(buf.data(), frames); |
| 175 | const float measDbfs = linToDb(measPeak); |
| 176 | const float errDb = measDbfs - (-17.5f); |
| 177 | report("4:1 ratio above threshold: -10 dBFS in -> -17.5 dBFS out", |
| 178 | std::fabs(errDb) < 1.0f, |
| 179 | "measured=" + std::to_string(measDbfs) + " dBFS, err=" |
| 180 | + std::to_string(errDb) + " dB"); |
| 181 | } |
| 182 | |
| 183 | // High ratio (20:1) clamps near threshold. |
| 184 | void testLimitRatio() |
no test coverage detected