Round-2 effect-wave vocabulary. More...
Classes | |
| class | StreamingAnalysisWindowT |
| struct | EnvelopeStageClock |
| Sample counter for one envelope stage. More... | |
| class | EnvelopeEngine |
| The DAHDSR superset state machine. More... | |
| struct | FftRealSplit |
| The packed split-complex form of a real transform, for Pulp's own frequency-domain stages (the overlap-add ConvolverT). More... | |
| struct | FractionalDelaySplit |
| class | BasicLfoT |
| Shared implementation selected by the two explicit public LFO types below. More... | |
| class | NonlinearOversamplingT |
| class | FixedHalfBandFir65 |
| class | LinearPhaseOversamplingStage2x |
| class | FixedOrderFirBranch |
| One polyphase branch of a block 2x stage: a direct-form FIR whose every output is the taps summed oldest-first, one multiply-add each (fused where the hardware has it; see fir_multiply_add()). More... | |
| class | LinearPhaseOversamplingBlockStage2x |
| The block form of LinearPhaseOversamplingStage2x, for OversamplerT: the same prototype and the same polyphase split, run a block at a time. More... | |
| struct | SaturatorShapeMath |
| The waveshaper family's three closed forms per member: the curve f, its derivative f' (needed for the bias normaliser), and its antiderivative F1 (needed for ADAA). More... | |
| class | DualTapResonatorT |
| Dual-tap TPT state-variable resonator (Zavalishin topology, identical to SvfT) returning the highpass and lowpass outputs from ONE tick. More... | |
| struct | CapacityLayout |
| struct | ReservationToken |
| class | ProgramBank |
| class | Segmenter |
| class | ReservationLedger |
| class | OutputSplicer |
| class | SlicedFftPlanT |
| Resumable in-place radix-2 complex FFT (Cooley & Tukey 1965). More... | |
| struct | ZeroLatencyConvolverGroup |
| struct | ZeroLatencyConvolverCell |
| struct | ZeroLatencyConvolverOnePole |
Concepts | |
| concept | MirroredHistorySample |
Enumerations | |
| enum class | AnalysisWindow : std::uint8_t { rectangular , symmetric_hann } |
| enum class | LfoConvention : std::uint8_t { toolkit , effect } |
| Selects the waveform/rate convention at the type boundary. More... | |
Functions | |
| template<typename SampleType, std::size_t MaxChannels> | |
| bool | mix_planar_frame (const SampleType *const *channels, std::size_t channel_count, std::size_t frame, bool compute_power, double &mono, double &channel_power) noexcept |
| int | pitch_class_for_frequency (double frequency_hz) noexcept |
| bool | beat_repeat_checked_add (std::int64_t lhs, std::int64_t rhs, std::int64_t &result) noexcept |
| bool | beat_repeat_checked_subtract (std::int64_t lhs, std::int64_t rhs, std::int64_t &result) noexcept |
| bool | beat_repeat_ceil_tick (std::int64_t value, std::int64_t quantum, std::int64_t &result) noexcept |
| constexpr std::size_t | convolver_block_size (std::size_t block_size) noexcept |
| The block size a convolver prepared for block_size accepts: the request rounded up to the next power of two (the radix-2 FFT needs it), with 0 treated as 1. | |
| template<typename SampleType = float> | |
| std::unique_ptr< ConvolverIrStateT< SampleType > > | build_convolver_ir_state (const SampleType *ir, std::size_t ir_length, std::size_t block_size) |
| Build a ConvolverIrState from a raw IR. | |
| template<typename SampleType = float> | |
| void | migrate_input_history (ConvolverInputHistoryT< SampleType > &from, ConvolverInputHistoryT< SampleType > &to) |
| Migrate the recorded input history from from into to, age-aligned. | |
| void | apply_diode_model (junction::JunctionPair &network, DiodeModel model) |
| The (Is, n) pair for a device family. | |
| void | apply_symmetry (junction::JunctionPair &network, double symmetry) |
| symmetry ∈ [−1, +1] → the two legs' reciprocal series counts. | |
| template<typename Residual, typename Derivative> | |
| double | solve_safeguarded_newton (Residual &&f, Derivative &&df, double lo, double hi, double initial, double alternate, double tolerance, int max_iterations, int &iterations_out) |
| One monotone implicit stage, solved by a SAFEGUARDED Newton iteration. | |
| double | solve_implicit_flow_stage (const junction::JunctionPair &network, double history_voltage, double history_flow, double source_current, double flow_weight, double c_over_step, double resistance, double initial, int &iterations_out) |
| Solves one implicit stage of C·dv/dt = source_current − v/R − i_D(v). | |
| double | solve_tr_bdf2 (const junction::JunctionPair &network, double previous_voltage, double previous_source_current, double source_current, double capacitance, double timestep, double resistance, int &iterations_out) |
| One L-stable TR-BDF2 step of C·dv/dt = source_current(t) − v/R − i_D(v). | |
| long long | envelope_ms_to_samples (double ms, double sample_rate) |
| template<typename T> | |
| T | select_bits (bool condition, T if_true, T if_false) noexcept |
| condition ?
| |
| template<typename T> | |
| T | snap_to_zero_bits (T x) noexcept |
| snap_to_zero() as bit operations (see select_bits()). | |
| float | tanh_accurate_bits (float x) noexcept |
| FastMath::tanh_accurate() with its clamps as bit operations; the same value for every input. | |
| constexpr bool | is_power_of_two (int value) noexcept |
| constexpr std::size_t | fft_twiddle_index (int phase_index, int stride) noexcept |
| template<typename SampleType> | |
| constexpr bool | fft_real_split_needs_scratch (std::uint64_t fft_size) noexcept |
| Whether a FftT of fft_size points keeps a real_bins()-long complex scratch for the split-spectrum path (FftRealSplit): every size the portable real transform serves, which is all of them except vDSP's float sizes. | |
| template<typename SampleType> | |
| void | multiply_packed_split (const SampleType *a_re, const SampleType *a_im, const SampleType *b_re, const SampleType *b_im, SampleType *out_re, SampleType *out_im, int half) noexcept |
| Product of two packed split spectra of half = size() / 2 slots each (see FftRealSplit): bin k of out is bin k of a times bin k of b for k = 1..half-1, and slot 0's DC and Nyquist reals multiply separately. | |
| template<typename SampleType> | |
| void | multiply_accumulate_packed_split (const SampleType *a_re, const SampleType *a_im, const SampleType *b_re, const SampleType *b_im, SampleType *acc_re, SampleType *acc_im, int half) noexcept |
| acc += a * b over packed split spectra, with the product as in multiply_packed_split(). | |
| template<typename SampleType> | |
| SampleType | fm_bright_band_gain (SampleType base_hz, SampleType sample_rate, FmOperatorAliasPolicy policy) noexcept |
| template<typename SampleType, std::size_t MaxOperators, typename FrequencyFn, typename PhaseRouteFn, typename FrequencyRouteFn, typename CarrierGainFn, typename OscillatorFn> | |
| SampleType | render_fm_operator_sample (std::size_t operator_count, SampleType sample_rate, FmOperatorAliasPolicy alias_policy, std::array< SampleType, MaxOperators > &phases, std::array< SampleType, MaxOperators > &previous, const std::array< SampleType, MaxOperators > &litudes, const std::array< SampleType, MaxOperators > &feedback_radians, FrequencyFn &&base_frequency, PhaseRouteFn &&phase_route, FrequencyRouteFn &&frequency_route, CarrierGainFn &&carrier_gain, OscillatorFn &&oscillator) noexcept |
| Canonical one-sample-delayed operator evaluator shared by melodic and drum engines. | |
| FractionalDelaySplit | split_fractional_delay (double delay_samples) noexcept |
| template<typename Coefficient> | |
| void | halfband_path_response (const HalfBandIirDesign &design, bool path_a, double frequency, std::complex< double > &response, double &group_delay) noexcept |
| template<typename Coefficient> | |
| HalfBandIirDesign | halfband_design_from_paths (std::span< const Coefficient > a, std::span< const Coefficient > b) noexcept |
| HalfBandIirDesign | default_halfband_design () noexcept |
| double | wrap01 (double x) noexcept |
| double | clamp_open (double x) noexcept |
| double | wave_integral_in_cycle (LfoWave wave, double x, const LfoShapeParams ¶ms) noexcept |
| The integral of one wave over [0, x] for x in [0, 1]. | |
| double | wave_integral_per_cycle (LfoWave wave, const LfoShapeParams ¶ms) noexcept |
| The integral over one whole cycle: zero for every wave but the square. | |
| template<typename SampleType> | |
| SampleType | precise_stage_curve (SampleType progress, SampleType curve) noexcept |
| bool | valid_alias_policy (NonlinearAliasPolicy policy) noexcept |
| double | triangle_fold (double input) noexcept |
| double | triangle_fold_slope (double input) noexcept |
| std::vector< double > | linear_phase_oversampling_prototype (double passband_edge_fraction, double stopband_db, std::size_t taps) |
| The Kaiser-windowed lowpass prototype both linear-phase 2x stage forms split into polyphase branches. | |
| template<typename SampleType> | |
| SampleType | fir_multiply_add (SampleType a, SampleType b, SampleType acc) noexcept |
| acc + a * b for the block FIR: one fused multiply-add where the hardware has it, a separate multiply and add otherwise. | |
| template<typename Transitioning, typename Sample, typename Block> | |
| void | transition_then_block (std::size_t frames, Transitioning &&transitioning, Sample &&sample, Block &&block) |
| The block path the cascade EQs share: a design transition (crossfade or coefficient ramp) runs sample by sample through sample(i) while transitioning() holds; once it has finished, the rest of the block goes to block(first, count) in one call. | |
| template<typename SampleType> | |
| bool | valid_spectral_band_layout (const SpectralBandLayoutT< SampleType > &layout, SampleType nyquist, SampleType &effective_min, SampleType &effective_max) noexcept |
| template<typename SampleType> | |
| SampleType | band_coordinate (SampleType hz, SampleType min_hz, SampleType max_hz, SpectralBandSpacing spacing) noexcept |
| template<typename SampleType> | |
| SampleType | frequency_at_coordinate (SampleType coordinate, SampleType min_hz, SampleType max_hz, SpectralBandSpacing spacing) noexcept |
| template<typename SampleType> | |
| SampleType | raised_cosine (SampleType position) noexcept |
| template<typename SampleType> | |
| SampleType | band_gain (const SpectralBandLayoutT< SampleType > &layout, std::uint32_t index) noexcept |
| template<typename SampleType> | |
| std::uint32_t | band_index_at_frequency (SampleType hz, SampleType min_hz, SampleType max_hz, SpectralBandSpacing spacing, std::uint32_t band_count) noexcept |
| template<typename SampleType> | |
| std::vector< SampleType > | build_wavetable_band_ceilings (std::size_t num_bands, SampleType reference_sample_rate) |
| Shared ceiling plan for synthesized and authored wavetable stacks. | |
| template<typename SampleType, typename HarmonicAmp> | |
| std::vector< SampleType > | generate_wavetable (std::size_t length, std::size_t max_harmonic, HarmonicAmp &&harmonic_amp) |
| template<typename SampleType, typename HarmonicAmp> | |
| std::vector< WavetableEntryT< SampleType > > | build_wavetable_band_stack (std::size_t num_bands, std::size_t table_length, SampleType reference_sample_rate, HarmonicAmp &&harmonic_amp) |
| template<typename SampleType> | |
| SampleType | four_term_cosine_window (SampleType phase, SampleType a0, SampleType a1, SampleType a2, SampleType a3) |
| template<typename SampleType> | |
| SampleType | blackman_harris_window (SampleType phase) |
| template<typename SampleType> | |
| SampleType | blackman_nuttall_window (SampleType phase) |
Variables | |
| template<std::size_t Inputs, std::size_t Outputs> | |
| constexpr bool | valid_audio_matrix_capacity |
| constexpr double | kTwoPi = 6.283185307179586477 |
| constexpr double | kNonlinearMinimumSampleRate = 1000.0 |
| constexpr double | kNonlinearMaximumSampleRate = 768000.0 |
| template<typename SampleType> | |
| constexpr SampleType | kWavetableTwoPi |
Round-2 effect-wave vocabulary.
Returns normalized travel from the start of a segment to its end.
It is intentionally distinct from the modulation toolkit's nested LfoT::Wave: selecting this overload also selects the effect convention whose triangle is sine-aligned (zero at phase 0, positive peak at 0.25) instead of the toolkit convention (-1 at phase 0).
rising selects the musical direction used by exponential/logarithmic labels; it does not constrain the caller's endpoint values.
|
strong |
|
strong |
Selects the waveform/rate convention at the type boundary.
The default is the shipped modulation-toolkit contract; Round-2 effects opt into their distinct phase and waveform laws through EffectLfoT below.
| Enumerator | |
|---|---|
| toolkit | |
| effect | |
|
inline |
The (Is, n) pair for a device family.
Honest [design parameter] rows representing a class's published order of magnitude, never a measured part.
[design parameter] silicon Is 1e-14 (range 1e-15 .. 1e-12), n 1.0 (1.0 .. 1.05) [design parameter] germanium Is 1e-6 (range 1e-7 .. 1e-5), n 1.1 (1.0 .. 1.3) [design parameter] led Is 1e-18 (range 1e-19 .. 1e-17), n 2.0 (1.5 .. 2.5)
|
inline |
symmetry ∈ [−1, +1] → the two legs' reciprocal series counts.
Positive symmetry lengthens the positive leg (turns on later); negative symmetry fades the negative leg out entirely. Both are continuous and both reduce to the matched pair at 0.
|
inlinenoexcept |
|
inlinenoexcept |
|
inlinenoexcept |
|
inlinenoexcept |
|
inlinenoexcept |
|
inlinenoexcept |
|
inline |
|
inline |
|
inline |
Build a ConvolverIrState from a raw IR.
This is the expensive path (allocations + N forward FFTs) and must run off the audio thread.
|
inline |
Shared ceiling plan for synthesized and authored wavetable stacks.
Keeping the geometric ladder in one helper prevents offline-authored tables from drifting away from WavetableT's band-selection contract.
|
inline |
|
inlinenodiscardnoexcept |
|
constexprnoexcept |
The block size a convolver prepared for block_size accepts: the request rounded up to the next power of two (the radix-2 FFT needs it), with 0 treated as 1.
Every fixed-block convolver uses this one rule so their accepted block sizes cannot drift apart.
|
inlinenoexcept |
|
inline |
|
inlineconstexprnoexcept |
Whether a FftT of fft_size points keeps a real_bins()-long complex scratch for the split-spectrum path (FftRealSplit): every size the portable real transform serves, which is all of them except vDSP's float sizes.
|
inlineconstexprnoexcept |
|
inlinenoexcept |
acc + a * b for the block FIR: one fused multiply-add where the hardware has it, a separate multiply and add otherwise.
Either way the same expression runs for every output, so partition exactness holds; the two forms differ only by rounding, and only between targets.
|
inlinenoexcept |
|
inline |
|
inlinenoexcept |
|
inline |
|
inlinenoexcept |
|
inlinenoexcept |
|
inlineconstexprnoexcept |
|
inline |
The Kaiser-windowed lowpass prototype both linear-phase 2x stage forms split into polyphase branches.
Fractions are expressed against the input rate; the filter runs at twice that rate, so base Nyquist is 0.25 cycles/output-sample and the transition ends there.
|
inline |
Migrate the recorded input history from from into to, age-aligned.
Used when the convolver must move to a longer (or differently-shaped) ring than the one it is holding: the incoming ring is a freshly-built spare, so everything the old ring recorded has to be carried across or the input stream restarts from silence.
The carried spectra are copied from one arena into the other: no allocation, and work bounded by the carried ring length times fft_size / 2 + 1 bins (about 0.8 MB for a 96000-tap IR at 64-sample blocks), so this is safe on the audio thread. from keeps its own copy, which is harmless: the caller hands from off to be freed off the audio thread.
from.write_pos is the slot the next block would be written to, so the most-recent (age 0) block is at from.write_pos - 1. History is laid out in to so that the next write lands at slot 0, and to.write_pos is set to 0 accordingly. Ages older than the shorter of the two rings can hold are dropped; they are beyond the reach of any IR that ring can serve.
A geometry mismatch (different block or FFT size) leaves to cold, which is the only correct answer: spectra taken at one FFT size cannot be reinterpreted at another.
|
noexcept |
|
inlinenoexcept |
acc += a * b over packed split spectra, with the product as in multiply_packed_split().
acc must not overlap a or b. Allocation-free.
|
inlinenoexcept |
Product of two packed split spectra of half = size() / 2 slots each (see FftRealSplit): bin k of out is bin k of a times bin k of b for k = 1..half-1, and slot 0's DC and Nyquist reals multiply separately.
The result is the packed spectrum of the circular convolution. out may be a or b; partial overlap is not allowed. Allocation-free.
|
inlinenoexcept |
|
inlinenoexcept |
|
inlinenoexcept |
|
noexcept |
Canonical one-sample-delayed operator evaluator shared by melodic and drum engines.
Delaying every edge uniformly permits cycles and makes evaluation order irrelevant; it is the routing law already used by the 6/8-op drums.
|
inlinenoexcept |
condition ?
if_true : if_false as bit operations. Same value as the conditional for every input, including NaN payloads and signed zeros, but with no control flow: GCC with its default -ftrapping-math will not if-convert a float conditional whose arms it may sink, which leaves loops over per-voice state unvectorized; this form vectorizes under GCC and Clang alike.
|
inlinenoexcept |
snap_to_zero() as bit operations (see select_bits()).
|
inline |
Solves one implicit stage of C·dv/dt = source_current − v/R − i_D(v).
Both halves of TR-BDF2 have this exact shape. They differ only in the history voltage, the already-known flow carried by that history, the weight of the new flow, and the effective C/dt coefficient. Keeping the nonlinear solve here gives the two stages one bracket, warm-start, tolerance, and iteration policy.
|
inline |
One monotone implicit stage, solved by a SAFEGUARDED Newton iteration.
Plain Newton from the previous sample — what the specification calls for — diverges here, and it is worth being precise about why rather than just damping it. The residual's curvature is set by exp(v/θ) with θ ≈ 26 mV, so a single unguarded step taken from outside the conducting region overshoots by orders of magnitude and lands where the exponential is astronomically large; the next step is worse. In practice the iterate escapes to ±10¹⁶ within a few samples of a cold start and never returns.
The fix is the standard one for monotone root finds: keep a bracket and fall back to bisection whenever a Newton step would leave it. This is globally convergent — F is strictly increasing in v, since every term of F' is positive — while still getting Newton's quadratic convergence once the iterate is close, which is the common case at audio rates where consecutive samples differ little.
The bracket is physical rather than arbitrary: the diode network can only sink current toward ground, so the node voltage always lies between where it was and where the linear network alone would drive it.
Returns the solved voltage and writes the iteration count taken, so the RT-safety cap can be asserted rather than assumed.
|
inline |
One L-stable TR-BDF2 step of C·dv/dt = source_current(t) − v/R − i_D(v).
gamma = 2 − sqrt(2) is the standard TR-BDF2 choice that makes the method second-order and L-stable. The first implicit trapezoid stage advances to t + gamma·T; the variable-step BDF2 stage completes the sample. Unlike a full trapezoidal step, the composite method drives infinitely stiff modes to zero instead of preserving them as an alternating sample-to-sample mode.
|
inlinenodiscardnoexcept |
|
inlinenoexcept |
FastMath::tanh_accurate() with its clamps as bit operations; the same value for every input.
|
inline |
The block path the cascade EQs share: a design transition (crossfade or coefficient ramp) runs sample by sample through sample(i) while transitioning() holds; once it has finished, the rest of the block goes to block(first, count) in one call.
A transition never starts inside a block, so the split happens at most once.
|
inlinenoexcept |
|
inlinenoexcept |
|
inlinenoexcept |
|
inlinenoexcept |
|
inlinenodiscardnoexcept |
The integral of one wave over [0, x] for x in [0, 1].
|
inlinenodiscardnoexcept |
The integral over one whole cycle: zero for every wave but the square.
|
inlinenodiscardnoexcept |
|
inlineconstexpr |
|
inlineconstexpr |
|
constexpr |
|
constexpr |
|
inlineconstexpr |