RT-safe hot-swap slot for a Processor. More...
#include <pulp/audio/buffer.hpp>#include <pulp/format/processor.hpp>#include <pulp/format/state_restore_gate.hpp>#include <pulp/midi/buffer.hpp>#include <algorithm>#include <pulp/signal/transition_mixer.hpp>#include <atomic>#include <cstddef>#include <cstdint>#include <memory>#include <mutex>#include <shared_mutex>#include <vector>Go to the source code of this file.
Classes | |
| class | pulp::format::reload::ProcessorHotSwapSlot |
Namespaces | |
| namespace | pulp |
| namespace | pulp::format |
| What the product grants a device: the quota table indexed by capability tier and live thermal state. | |
| namespace | pulp::format::reload |
Typedefs | |
| using | pulp::format::reload::CrossfadeCurve = signal::TransitionCurve |
| The crossfade amplitude law is the shared signal::TransitionMixer primitive — extracted so the hot-swap slot, the convolver IR swapper, and the Phase-2 SwapUnit transitions all fade identically and are covered by one click-free fixture. | |
RT-safe hot-swap slot for a Processor.
The lifetime invariant: a Processor instance is destroyed only on the control thread, and only after that thread has proven no audio callback is inside the old instance's process() body. A try_lock around entry is not enough — a reader already inside process() is invisible to the swapper.
Mechanism (the simplest correct one; RCU/epoch is a later optimization):
A naive atomic<shared_ptr<Processor>> is intentionally NOT used: the last reference can drop on the audio thread, running ~Processor() in the callback (an RT violation).
── Click-free crossfade (opt-in) ─────────────────────────────────────────── An instantaneous swap cuts from the old DSP's output to the new one's at a block boundary — if they disagree there (different gain, phase, waveform) the discontinuity clicks. With a crossfade configured (set_crossfade_samples() + prepare_crossfade() to allocate the parallel-render scratch off the audio thread), a swap instead keeps the OLD processor and runs it in parallel with the new for a short window, mixing old→new along a smoothstep ramp (zero slope at both ends, so neither the swap instant nor the fade end clicks). The faded-out processor is then retired the RT-safe way: the audio thread only marks the fade done; the control thread frees it in reclaim() (or the next swap()/the destructor), never on the audio thread. With no crossfade configured the swap is instantaneous and returns the displaced instance, as before.