Classes | |
| struct | Instance |
Typedefs | |
| using | Voc = signal::Vocoder |
Functions | |
| float | vocoder_worst_case_gain (double sample_rate=48000.0) |
| Worst-case linear gain for the Forge registry (series law 8). | |
| float | vocoder_all_sample_rates_worst_case_gain () |
| Sample-rate-independent ceiling for registries whose metadata cannot vary with the host rate. | |
| CustomNodeType | make_vocoder_node () |
| Two inputs, one output. | |
| ForgeNodeDescriptor | descriptor () |
Variables | |
| constexpr const char * | kTypeId = "synthesis.vocoder" |
| constexpr PortIndex | kModulatorPort = 0 |
| Input port roles. | |
| constexpr PortIndex | kCarrierPort = 1 |
| constexpr state::ParamID | kBandCount = 1 |
| constexpr state::ParamID | kFreqLoHz = 2 |
| constexpr state::ParamID | kFreqHiHz = 3 |
| constexpr state::ParamID | kCarrierSource = 4 |
| constexpr state::ParamID | kInternalWave = 5 |
| constexpr state::ParamID | kInternalPw = 6 |
| constexpr state::ParamID | kCarrierPitchHz = 7 |
| constexpr state::ParamID | kNoiseMix = 8 |
| constexpr state::ParamID | kAttackMs = 9 |
| constexpr state::ParamID | kReleaseMs = 10 |
| constexpr state::ParamID | kUnvoicedSens = 11 |
| constexpr state::ParamID | kSibilanceMix = 12 |
| constexpr state::ParamID | kFormantShiftSt = 13 |
| constexpr state::ParamID | kFormantFreeze = 14 |
| constexpr state::ParamID | kOutputTrimDb = 15 |
| constexpr state::ParamID | kDryWet = 16 |
| ForgeNodeDescriptor pulp::host::synthesis::vocoder::descriptor | ( | ) |
| CustomNodeType pulp::host::synthesis::vocoder::make_vocoder_node | ( | ) |
Two inputs, one output.
See this file's header for why the ports are plain audio ports rather than a sidechain, and why the modulator is port 0.
| float pulp::host::synthesis::vocoder::vocoder_all_sample_rates_worst_case_gain | ( | ) |
Sample-rate-independent ceiling for registries whose metadata cannot vary with the host rate.
The high-pass L1 term approaches (but never exceeds) 2 as the sample rate rises, so this is the supremum of vocoder_worst_case_gain(sample_rate) over every positive sample rate.
| float pulp::host::synthesis::vocoder::vocoder_worst_case_gain | ( | double | sample_rate = 48000.0 | ) |
Worst-case linear gain for the Forge registry (series law 8).
The DSP's own asserted invariant is the RECONSTRUCTION bound: its suite measures the summed synthesis bank against kWorstCaseGain at every band count from 10 to 20, with the per-band VcaT clamp making that a bound rather than an estimate. But the node exposes two things the DSP's own T-GAIN case deliberately parks: the sibilance path (which that test sets to zero so the bank's bound is measured alone) and the output trim. A baked param can be automated anywhere in its declared range, so the node's number has to include both — the FET compressor reports at its parameter ceilings for the same reason.
Assembled from shipped constants:
The dry/wet blend cannot raise it: it is a convex combination of that wet sum and a dry signal bounded by 1.
This is a GAIN, i.e. a bound for |input| ≤ 1, and the premise matters more here than it does for most nodes. The two paths respond to input level completely differently: the bank's is amplitude-INSENSITIVE, because the per-band VcaT clamps its control and a louder modulator only saturates it sooner — while the sibilance path is amplitude-PROPORTIONAL, passing the modulator's own high end straight to the output. A modulator driven 20 dB hot therefore does not make the vocoding 20 dB louder; it makes the SIBILANCE 20 dB louder, and the balance the sibilance_mix control sets moves under the level. Worth knowing at the mixer as well as at the bound.
Sample-rate dependent through the high-pass term, which is why this takes a rate rather than pretending to be a constant.
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
Input port roles.
Named constants rather than bare 0 and 1, because the one mistake this node cannot survive is a transposition and a named port is harder to swap by accident than an integer literal.
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |