Attack timing: envelope should reach ~63 % of step in τ ms. Drive silence → 0.5 amp step, sample GR shortly after the step.
| 328 | // Attack timing: envelope should reach ~63 % of step in τ ms. |
| 329 | // Drive silence → 0.5 amp step, sample GR shortly after the step. |
| 330 | void testAttackTiming() |
| 331 | { |
| 332 | ClientComp comp; |
| 333 | comp.prepare(kSampleRate); |
| 334 | comp.setEnabled(true); |
| 335 | comp.setThresholdDb(-20.0f); |
| 336 | comp.setRatio(10.0f); |
| 337 | comp.setKneeDb(0.0f); |
| 338 | comp.setMakeupDb(0.0f); |
| 339 | comp.setAttackMs(20.0f); |
| 340 | comp.setReleaseMs(500.0f); |
| 341 | comp.setLimiterEnabled(false); |
| 342 | comp.reset(); |
| 343 | |
| 344 | // 20ms of silence, then loud tone burst. |
| 345 | const int preFrames = static_cast<int>(kSampleRate * 0.020); |
| 346 | const int burstFrames = static_cast<int>(kSampleRate * 0.200); |
| 347 | |
| 348 | std::vector<float> pre(preFrames * 2, 0.0f); |
| 349 | processBlocks(comp, pre.data(), preFrames); |
| 350 | |
| 351 | auto burst = makeTone(1000.0, burstFrames, 0.5f); |
| 352 | processBlocks(comp, burst.data(), burstFrames); |
| 353 | |
| 354 | // After 200ms (10× attack time constant) gain reduction should be |
| 355 | // close to the steady-state value. For 0.5 amp = -6 dBFS with |
| 356 | // threshold -20, ratio 10: overshoot 14 dB / ratio 10 = 1.4 dB |
| 357 | // above threshold, so GR = 14 - 1.4 = 12.6 dB. |
| 358 | const float gr = comp.gainReductionDb(); |
| 359 | report("attack reaches steady-state after 10τ", |
| 360 | gr < -10.0f && gr > -14.0f, |
| 361 | "GR=" + std::to_string(gr) + " dB"); |
| 362 | } |
| 363 | |
| 364 | // Soft-knee continuity: sweep the static curve and verify no discontinuity. |
| 365 | void testSoftKneeMonotonic() |
no test coverage detected