Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
processing_switch_crossfade.hpp File Reference

A gap-free, click-free switch between two realisations of the same effect whose LATENCIES differ — a linear-phase and a minimum-phase filter, a high-quality and a low-latency mode, a CPU and a GPU path. More...

#include "transition_mixer.hpp"
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstdint>

Go to the source code of this file.

Classes

struct  pulp::signal::ProcessingSwitchPlan
 How long each phase of a switch lasts, in samples. More...
class  pulp::signal::ProcessingSwitchCrossfadeT< SampleType >
 The audio-thread state of one switch. More...

Namespaces

namespace  pulp
namespace  pulp::signal

Typedefs

using pulp::signal::ProcessingSwitchCrossfade = ProcessingSwitchCrossfadeT<float>
using pulp::signal::ProcessingSwitchCrossfade64 = ProcessingSwitchCrossfadeT<double>

Functions

ProcessingSwitchPlan pulp::signal::plan_processing_switch (std::int64_t incoming_latency, std::int64_t incoming_history, double sample_rate, double fade_seconds) noexcept
 The plan for switching INTO a realisation with incoming_latency samples of delay that needs incoming_history samples of input before its output is steady (an FIR's length; zero for a realisation that primes its own stream start).
template<typename SampleType = float>
void pulp::signal::processing_switch_gains_at (const ProcessingSwitchPlan &plan, std::int64_t position, SampleType &outgoing, SampleType &incoming) noexcept
 Gains for the outgoing and incoming outputs at absolute position samples into a switch following plan.

Detailed Description

A gap-free, click-free switch between two realisations of the same effect whose LATENCIES differ — a linear-phase and a minimum-phase filter, a high-quality and a low-latency mode, a CPU and a GPU path.

Swapping such realisations at a block boundary is audible twice over:

  • the incoming realisation starts with no history, so for its own latency it emits silence (a dropout — 213 ms for an 8192/2048 WOLA engine at 48 kHz) and for the length of its impulse a partial response;
  • the outgoing realisation stops mid-waveform, leaving a step.

The switch therefore runs in two phases, counted in samples on the audio thread:

  1. WARM — both realisations process the same input; only the outgoing one is heard. The incoming one fills its delay line and its impulse history, so when it is first heard its output is already steady.
  2. FADE — a TransitionMixer EqualPower fade (smoothstep-shaped, so both ends are corner-free) from the outgoing output to the incoming one. The two carry the same material at different delays, which is uncorrelated over a fade, so equal POWER keeps the level constant.

What no fade can remove: the content moves in time by the difference of the two latencies, because that is what changing the latency means. The host's delay compensation re-aligns it; the fade makes the move smooth.

The caller owns both realisations and runs them; this type owns only the sample schedule and the blend. plan_processing_switch() and processing_switch_gains_at() are pure, so a test or a UI can state what a switch will do without running audio through it.