Brickwall limiter must clamp peaks to ceiling even with comp off.
| 244 | |
| 245 | // Brickwall limiter must clamp peaks to ceiling even with comp off. |
| 246 | void testLimiterCeiling() |
| 247 | { |
| 248 | ClientComp comp; |
| 249 | comp.prepare(kSampleRate); |
| 250 | comp.setEnabled(false); // comp off, only limiter active |
| 251 | comp.setLimiterEnabled(true); |
| 252 | comp.setLimiterCeilingDb(-6.0f); // ceiling at 0.5012 linear |
| 253 | |
| 254 | const float ceilingLin = std::pow(10.0f, -6.0f / 20.0f); |
| 255 | const int frames = static_cast<int>(kSampleRate); |
| 256 | auto buf = makeTone(1000.0, frames, 0.9f); // well above ceiling |
| 257 | |
| 258 | // Warmup pass so limiter envelope is primed |
| 259 | auto warm = makeTone(1000.0, frames, 0.9f); |
| 260 | processBlocks(comp, warm.data(), frames); |
| 261 | |
| 262 | processBlocks(comp, buf.data(), frames); |
| 263 | const float peak = peakAbsStereo(buf.data(), frames); |
| 264 | |
| 265 | // Allow a tiny overshoot (≤ +0.5 dB) for limiter settling between sine peaks. |
| 266 | const float peakDb = 20.0f * std::log10(peak); |
| 267 | const float ceilingDb = 20.0f * std::log10(ceilingLin); |
| 268 | report("limiter clamps 0.9 peak to -6 dBFS ceiling", |
| 269 | peakDb - ceilingDb < 0.5f, |
| 270 | "peak=" + std::to_string(peakDb) + " dBFS (ceiling=" |
| 271 | + std::to_string(ceilingDb) + ")"); |
| 272 | } |
| 273 | |
| 274 | // Stereo linking: max(|L|,|R|) drives envelope, and the same gain is |
| 275 | // applied to both. Feed L-only signal and check R remains silent (no |
no test coverage detected