Delay with an optional latency-bearing processor inside the feedback loop (pitch/formant shifters and similar), tempo sync, bounded feedback, and a freeze-aware feedback gate. More...
#include <algorithm>#include <cassert>#include <cmath>#include <cstdint>#include <vector>Go to the source code of this file.
Classes | |
| class | pulp::signal::FeedbackLoopProcessorT< SampleType > |
| Interface for a processor placed inside the feedback loop. More... | |
| class | pulp::signal::PitchedFeedbackDelayT< SampleType > |
| struct | pulp::signal::PitchedFeedbackDelayT< SampleType >::Config |
Namespaces | |
| namespace | pulp |
| namespace | pulp::signal |
Typedefs | |
| using | pulp::signal::FeedbackLoopProcessor = FeedbackLoopProcessorT<float> |
| using | pulp::signal::FeedbackLoopProcessor64 = FeedbackLoopProcessorT<double> |
| using | pulp::signal::PitchedFeedbackDelay = PitchedFeedbackDelayT<float> |
| using | pulp::signal::PitchedFeedbackDelay64 = PitchedFeedbackDelayT<double> |
Delay with an optional latency-bearing processor inside the feedback loop (pitch/formant shifters and similar), tempo sync, bounded feedback, and a freeze-aware feedback gate.
Topology (per channel):
loop_in[n] = in[n] + feedback * gate * wet[n] wet[n] = P(ring[n - (D - L_P)]) // P = loop processor out[n] = wet[n]
where D is the requested delay and L_P the loop processor's reported latency, so the effective echo spacing is exactly D and the minimum legal delay is min_delay_samples() = L_P + 1 — computed from the inserted processor at runtime, never hardcoded from any reference product. Stability comes from clamping |feedback| < 1 (standard feedback-comb bound: J. O. Smith III, Physical Audio Signal Processing, W3K; Zölzer (ed.), DAFX, delay-effects chapter).
When the loop processor reports frozen, the feedback injection gate ramps to zero (equal-power, ~50 ms) so frozen sustain does not recirculate, and ramps back on release.
Delay changes are smoothed (one-pole on the read offset) to avoid clicks. Feedback recursion shorter than a host block is handled by internal sub-chunking down to single samples, so any D >= L_P + 1 is honored exactly. No allocation or locks after prepare().