Loudness make-up for a static (or slowly edited) spectral shape, weighted by the long-term spectrum of the material going through it. More...
#include <pulp/signal/biquad.hpp>#include <pulp/signal/fft.hpp>#include <pulp/signal/frequency_response.hpp>#include <pulp/signal/multi_channel_meter.hpp>#include <pulp/signal/windowing.hpp>#include <algorithm>#include <array>#include <cmath>#include <complex>#include <cstddef>#include <cstdint>#include <memory>#include <span>#include <vector>Go to the source code of this file.
Classes | |
| struct | pulp::signal::LoudnessCompensationConfig |
| Every tunable of the stateful stages. More... | |
| struct | pulp::signal::MakeupLimits |
| struct | pulp::signal::LegSpectra |
| The long-term spectra of the two legs on one bin grid, K-weighted, on a common scale. More... | |
| struct | pulp::signal::BandPowerGain |
| One band of a band-wise response: its frequency span and power gain. More... | |
| class | pulp::signal::SpectrumCdf |
| The normalised cumulative of a power spectrum on a uniform bin grid. More... | |
| class | pulp::signal::MinimumPhaseResponse |
| The minimum-phase response with a given magnitude on an FFT grid, by the folded real cepstrum: ln|H| -> cepstrum -> fold onto positive quefrency -> exp(FFT). More... | |
| struct | pulp::signal::SpectrumBands |
| A band-compressed, rate-independent copy of a LongTermSpectrum's estimate, for saving with a session and restoring warm. More... | |
| class | pulp::signal::MaterialChangeDetector |
| Detects a genuine change of material from the gap between the make-up the fast and the slow estimates give the current shape. More... | |
| class | pulp::signal::LongTermSpectrum |
| class | pulp::signal::MakeupTarget |
| What the make-up gain is heading for. More... | |
Namespaces | |
| namespace | pulp |
| namespace | pulp::signal |
Functions | |
| double | pulp::signal::k_weighting_power (double hz, const pulp::signal::KWeightingCoefficients &k, double sample_rate) noexcept |
|K(f)|^2 for BS.1770 K-weighting at sample_rate, through Pulp's own K-weighting design and biquad response evaluator. | |
| float | pulp::signal::clamp_makeup_db_ (double ratio, MakeupLimits limits) noexcept |
| float | pulp::signal::blend_makeup_gain_db (std::span< const std::complex< double > > response, const LegSpectra &s, double mix, MakeupLimits limits) noexcept |
Make-up, dB, for the two-leg model in the file comment: response is the wet leg's complex response per bin, s the legs' spectra on the same grid, mix the wet share. | |
| float | pulp::signal::makeup_gain_db (std::span< const double > response_power, std::span< const double > spectrum_power, MakeupLimits limits) noexcept |
| The single-leg, real-response form: per-bin power response |H|^2 against a per-bin power spectrum on the same grid. | |
| template<typename WeightFn> | |
| float | pulp::signal::band_makeup_gain_db (std::span< const BandPowerGain > bands, WeightFn &&weight, MakeupLimits limits) noexcept |
| The single-leg form over bands, each weighted by weight(lo_hz, hi_hz) – the material's energy between two frequencies (SpectrumCdf::weight, or any reference weighting). | |
Loudness make-up for a static (or slowly edited) spectral shape, weighted by the long-term spectrum of the material going through it.
This header depends on Pulp and the standard library only; it has no product-specific types in its public interface. Its focused tests link Pulp::signal and Catch2 only.
THE MODEL. A shaping effect's output is a blend of a WET leg (the shaped signal, w, through the response H) and a DRY leg (d) at a mix m:
y = m H w + (1 - m) d
With long-term, K-weighted per-bin spectra Pww = <|W|^2>, Pdd = <|D|^2> and the cross-spectrum Pwd = <W conj(D)>, the output power per bin is
m^2 |H|^2 Pww + (1-m)^2 Pdd + 2 m (1-m) Re(H Pwd)
and the make-up is the ratio of the flat (H = 1) output to this, summed over bins: -10 log10(sum out / sum flat), clamped. When the wet leg IS the dry leg (an ordinary effect) all three spectra are one P and this is sum P |m H + 1 - m|^2 / sum P; when the wet leg is unrelated to the dry one (a freeze or a hold playing while the input moves on) the cross term vanishes and the two legs add as powers. Nothing has to be told which case it is in: the cross-spectrum measures it. The phase of H matters only through the cross term, i.e. only below 100 % mix.
THE PIPELINE, exposed stage by stage:
RT CONTRACT. prepare() allocates (control thread). Everything else – reset(), push(), MinimumPhaseResponse::compute(), the pure functions, SpectrumCdf::assign() into a prepared size, MakeupTarget – is allocation-free, lock-free and reads no clock. LongTermSpectrum advances on a frame grid counted in samples from prepare()/reset(), so its state after N samples does not depend on how the N samples were chunked.