Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::signal::PitchShifterT< SampleType > Class Template Reference

Time-domain ratio pitch shifter: dual-tap crossfaded modulated delay. More...

#include <pitch_shifter.hpp>

Public Member Functions

double dc_blocker_magnitude_peak () const
 The DC blocker's MAGNITUDE-response peak, 2/(1+p) at Nyquist.
 PitchShifterT ()
void prepare (double sample_rate)
 Sizes the delay line for kWindowMsMax plus the stencil guard and prepares the composed primitives.
void reset ()
 Zeroes the line, the phase, and the filter state, and rewinds the drift stream (series law 2).
void discard_history () noexcept
 Constant-time counterpart to reset() for hostile audio input.
void set_shift_source (ShiftSource source)
 Selects the pedal law or the direct semitone target. Default pedal.
ShiftSource shift_source () const
void set_shift_semitones (double semitones)
 Direct shift target, used when shift_source() == ShiftSource::direct.
double shift_semitones () const
void set_pedal (double e01)
 Expression position, heel = 0 to toe = 1.
double pedal () const
void set_pedal_mode (PedalMode mode)
 Picks the pedal LAW only.
PedalMode pedal_mode () const
void set_targets (double heel, double toe)
 Whammy/dive endpoints in semitones.
void set_harmony (double a, double b)
 Harmony A (heel) and B (toe) intervals in semitones.
void set_detune_cents (double cents)
void set_dive_floor_semis (double semitones)
void set_window_ms (double ms)
 Crossfade window in ms.
double window_ms () const
void set_glide_ms (double up_ms, double down_ms)
 Independent rise/fall portamento on the SEMITONE signal, so a glide is perceptually even.
double glide_up_ms () const
double glide_down_ms () const
void set_mix (double wet01)
 Equal-power dry↔wet. 0 is the untouched input; 1 is wet only.
double mix () const
void set_detents (bool on)
 Snap the pedal-law target table to musical intervals.
bool detents () const
void set_interp (PitchInterp interp)
PitchInterp interp () const
void set_drift_depth (double d01)
 Optional seeded pitch drift, 0 (default) .
double drift_depth () const
void snap_to_target ()
 Jumps the glide to its current target with no portamento — what a harmony voice wants on a note-on, so it starts ON its interval instead of sliding up from the previous note's.
double target_semitones () const
 The pre-slew target in semitones: the pedal law plus detents, or the direct value.
double pedal_law (double e01) const
 The §5 pedal law alone, before detents and before the glide.
double current_semitones () const
 The post-slew shift the block is applying right now, before drift.
double current_ratio () const
 The ratio the taps ACTUALLY ramped at on the last processed sample, drift included.
double warble_hz () const
 f_warble for the current ratio and window (Eq.
double tap_phase_pi (double hz) const
 q = ψ/π for an input partial at hz: the half-window separation of the two taps in half-cycles of that partial.
double window_samples () const
 Window length in samples at the prepared rate.
int latency_samples () const
 Honest processing throughput, not phase-aligned PDC: the delay sweeps [0, L], so the crossfaded output's effective delay hovers at the window centre (Eq.
SampleType process (SampleType x)
 One sample through the dry/wet mix.
SampleType process_wet (SampleType x)
 The shifted leg alone, with no dry mixed in — for callers summing several shifted voices themselves and applying their own balance.

Static Public Member Functions

static constexpr double default_mix_for (PedalMode mode)
 Per-mode conventional dry/wet default (§6).
static constexpr bool mode_uses_detents (PedalMode mode)
 Whether a mode's targets are intervals the detent table can express.

Static Public Attributes

static constexpr double kWindowMsDefault = 40.0
 Crossfade window in ms — sets the warble rate (Eq.
static constexpr double kWindowMsMin = 10.0
static constexpr double kWindowMsMax = 100.0
static constexpr double kGlideMsDefault = 60.0
 Pedal portamento, rise and fall.
static constexpr double kGlideMsMin = 0.0
static constexpr double kGlideMsMax = 2000.0
static constexpr double kDetuneCentsDefault = 12.0
 PedalMode::detune offset at the toe, in cents.
static constexpr double kDetuneCentsMax = 50.0
static constexpr double kDiveFloorSemisDefault = -48.0
 PedalMode::dive floor.
static constexpr double kDiveFloorSemisMin = -72.0
static constexpr double kDiveFloorSemisMax = -24.0
static constexpr double kHeelSemisDefault = 0.0
 Whammy endpoints and harmony intervals.
static constexpr double kToeSemisDefault = 12.0
static constexpr double kIntervalASemisDefault = 7.0
static constexpr double kIntervalBSemisDefault = 12.0
static constexpr double kShiftSemisMin = -48.0
 The node's shift_semitones range.
static constexpr double kShiftSemisMax = 24.0
static constexpr double kSemitonesFloor = kDiveFloorSemisMin
 Hard clamp on the slewed semitone signal, and therefore on r.
static constexpr double kSemitonesCeil = kShiftSemisMax
static constexpr double kDetentTable []
 Detent table, in semitones: unison, 4ths, 5ths, octaves, double octaves.
static constexpr int kDetentCount = 9
static constexpr double kDetentSnapSemis = 0.35
 Detent capture half-width.
static constexpr double kDetentReleaseRatio = 1.5
 A Schmitt trigger needs TWO thresholds; the spec names the band but gives only one, which is not hysteresis — a target sitting exactly at the capture edge would still chatter across it.
static constexpr double kDetentReleaseLimitSemis = 1.0
 The release band is additionally clamped here, so no reachable (kDetentSnapSemis, kDetentReleaseRatio) pair can make two detents capture the same target.
static constexpr int kInterpMargin = 4
 Guard samples reserved for the read stencil.
static constexpr double kDriftMaxDepthPercent = 0.5
 Maximum 1σ pitch drift, as a percent of r, at drift_depth = 100 %.
static constexpr std::uint32_t kDriftSeed = 0x57484D59u
 Fixed drift seed (series law 2: seeded, never automated, never exposed as a parameter).
static constexpr double kDcBlockerCornerHz = 5.0
 Corner of the wet leg's DC blocker, in Hz, converted to a pole at prepare as p = 1 − 2π·f_c/fs.
static constexpr double kClickBound = 0.25
 Sample-to-sample step ceiling the raised-cosine window must hold the wet output under.
static constexpr double kWorstCaseGain = 2.23606797749979
 Analytic peak-gain bound with an equal-power dry/wet mix and no feedback.
static constexpr double kDcBlockerPeakGain = 2.0
 The DC blocker's TIME-DOMAIN peak gain: the L1 norm of its impulse response, which is exactly 2 for every pole position.
static constexpr double kDefaultSampleRate = 48000.0
 Fallback sample rate for a block that is queried before prepare.

Detailed Description

template<typename SampleType = float>
class pulp::signal::PitchShifterT< SampleType >

Time-domain ratio pitch shifter: dual-tap crossfaded modulated delay.

See the file doc block for the topology, the warble law, and the aliasing policy. The short version of the public surface:

  • set_shift_source picks between the pedal law and a direct semitone target. A pitch-tracked harmonizer drives direct; a pedal drives pedal.
  • process returns the dry/wet mix; process_wet returns the shifted leg alone, for callers doing their own summing across several voices. Call exactly ONE of them per sample — both advance the line and the phase.
  • current_semitones / current_ratio / warble_hz / latency_samples report what the block is actually doing right now.

Constructor & Destructor Documentation

◆ PitchShifterT()

template<typename SampleType = float>
pulp::signal::PitchShifterT< SampleType >::PitchShifterT ( )
inline

Member Function Documentation

◆ current_ratio()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::current_ratio ( ) const
inline

The ratio the taps ACTUALLY ramped at on the last processed sample, drift included.

Identical to 2^(current_semitones/12) while drift_depth() == 0, which is the default — reporting the undrifted value would make the one control that is allowed to move the pitch invisible to every caller and every test.

◆ current_semitones()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::current_semitones ( ) const
inline

The post-slew shift the block is applying right now, before drift.

◆ dc_blocker_magnitude_peak()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::dc_blocker_magnitude_peak ( ) const
inline

The DC blocker's MAGNITUDE-response peak, 2/(1+p) at Nyquist.

Deliberately a separate accessor from kDcBlockerPeakGain above, and deliberately renamed: the two differ by a factor of ~2 and confusing them is exactly the defect this pair now documents. Use THIS one for steady-state questions — sideband amplitudes, frequency response — and the L1 constant for anything about a worst single sample.

◆ default_mix_for()

template<typename SampleType = float>
constexpr double pulp::signal::PitchShifterT< SampleType >::default_mix_for ( PedalMode mode)
inlinestaticconstexpr

Per-mode conventional dry/wet default (§6).

Applied by the node or the preset layer, NOT by set_pedal_mode: a mode change mid-performance must not jump the level under the player's foot.

◆ detents()

template<typename SampleType = float>
bool pulp::signal::PitchShifterT< SampleType >::detents ( ) const
inline

◆ discard_history()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::discard_history ( )
inlinenoexcept

Constant-time counterpart to reset() for hostile audio input.

◆ drift_depth()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::drift_depth ( ) const
inline

◆ glide_down_ms()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::glide_down_ms ( ) const
inline

◆ glide_up_ms()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::glide_up_ms ( ) const
inline

◆ interp()

template<typename SampleType = float>
PitchInterp pulp::signal::PitchShifterT< SampleType >::interp ( ) const
inline

◆ latency_samples()

template<typename SampleType = float>
int pulp::signal::PitchShifterT< SampleType >::latency_samples ( ) const
inline

Honest processing throughput, not phase-aligned PDC: the delay sweeps [0, L], so the crossfaded output's effective delay hovers at the window centre (Eq.

3.6). Series law 5 — report the centre, never claim zero. Sample-rate invariant in wall-clock terms.

◆ mix()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::mix ( ) const
inline

◆ mode_uses_detents()

template<typename SampleType = float>
constexpr bool pulp::signal::PitchShifterT< SampleType >::mode_uses_detents ( PedalMode mode)
inlinestaticconstexpr

Whether a mode's targets are intervals the detent table can express.

The spec states detents generally, which read literally makes two modes inert: detune's default target is 0.12 semitone, three times INSIDE the 0.35 capture band, so every detune setting would snap to unison and the mode would do nothing; and dive is a continuous collapse whose whole character is the un-stepped fall (its −48 floor is not even in the table). Detents quantise interval targets, so they apply where the targets are intervals.

◆ pedal()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::pedal ( ) const
inline

◆ pedal_law()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::pedal_law ( double e01) const
inline

The §5 pedal law alone, before detents and before the glide.

Exposed so the law can be asserted without rendering audio.

◆ pedal_mode()

template<typename SampleType = float>
PedalMode pulp::signal::PitchShifterT< SampleType >::pedal_mode ( ) const
inline

◆ prepare()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::prepare ( double sample_rate)
inline

Sizes the delay line for kWindowMsMax plus the stencil guard and prepares the composed primitives.

The only allocating call (§3.6): N = ceil(window_max_ms · fs / 1000) + 2·kInterpMargin, which is the spec's + kInterpMargin plus a second margin so the low-end clamp and the i+2 stencil node both stay inside the buffer.

◆ process()

template<typename SampleType = float>
SampleType pulp::signal::PitchShifterT< SampleType >::process ( SampleType x)
inline

One sample through the dry/wet mix.

Call exactly one of process / process_wet per sample — both write the line and advance the phase.

◆ process_wet()

template<typename SampleType = float>
SampleType pulp::signal::PitchShifterT< SampleType >::process_wet ( SampleType x)
inline

The shifted leg alone, with no dry mixed in — for callers summing several shifted voices themselves and applying their own balance.

◆ reset()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::reset ( )
inline

Zeroes the line, the phase, and the filter state, and rewinds the drift stream (series law 2).

The glide is snapped to the CURRENT target rather than to zero: a reset at +12 must not glide up from unison.

◆ set_detents()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_detents ( bool on)
inline

Snap the pedal-law target table to musical intervals.

Applies in whammy and harmony only (see mode_uses_detents) and never in ShiftSource::direct, where the caller's semitone value is the point.

◆ set_detune_cents()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_detune_cents ( double cents)
inline

◆ set_dive_floor_semis()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_dive_floor_semis ( double semitones)
inline

◆ set_drift_depth()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_drift_depth ( double d01)
inline

Optional seeded pitch drift, 0 (default) .

. 1. At 0 the drift generator is not advanced at all, so the deterministic path is bypassed rather than merely zero-amplitude.

◆ set_glide_ms()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_glide_ms ( double up_ms,
double down_ms )
inline

Independent rise/fall portamento on the SEMITONE signal, so a glide is perceptually even.

SlewMode::linear: a move takes this long whether it is one semitone or two octaves, and it arrives exactly.

◆ set_harmony()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_harmony ( double a,
double b )
inline

Harmony A (heel) and B (toe) intervals in semitones.

◆ set_interp()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_interp ( PitchInterp interp)
inline

◆ set_mix()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_mix ( double wet01)
inline

Equal-power dry↔wet. 0 is the untouched input; 1 is wet only.

◆ set_pedal()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_pedal ( double e01)
inline

Expression position, heel = 0 to toe = 1.

◆ set_pedal_mode()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_pedal_mode ( PedalMode mode)
inline

Picks the pedal LAW only.

Deliberately does not touch the mix — see default_mix_for.

◆ set_shift_semitones()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_shift_semitones ( double semitones)
inline

Direct shift target, used when shift_source() == ShiftSource::direct.

Clamped to the node's shift_semitones range.

◆ set_shift_source()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_shift_source ( ShiftSource source)
inline

Selects the pedal law or the direct semitone target. Default pedal.

◆ set_targets()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_targets ( double heel,
double toe )
inline

Whammy/dive endpoints in semitones.

◆ set_window_ms()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::set_window_ms ( double ms)
inline

Crossfade window in ms.

This is a VOICING control, not a performance one: it sets the warble rate and the latency. The change is deferred — each tap latches the new length at the instant its own phase passes zero, where its delay AND its crossfade weight are both zero, so neither tap steps. The cost is that for at most half a warble cycle the two taps run different window lengths, during which the fading tap's ratio is 1 − (1−r)·L_b/L_a rather than r — a brief detune on a tap that is on its way out, in exchange for no click at all. latency_samples() reports the requested window immediately.

◆ shift_semitones()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::shift_semitones ( ) const
inline

◆ shift_source()

template<typename SampleType = float>
ShiftSource pulp::signal::PitchShifterT< SampleType >::shift_source ( ) const
inline

◆ snap_to_target()

template<typename SampleType = float>
void pulp::signal::PitchShifterT< SampleType >::snap_to_target ( )
inline

Jumps the glide to its current target with no portamento — what a harmony voice wants on a note-on, so it starts ON its interval instead of sliding up from the previous note's.

◆ tap_phase_pi()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::tap_phase_pi ( double hz) const
inline

q = ψ/π for an input partial at hz: the half-window separation of the two taps in half-cycles of that partial.

Even → that partial shifts with no warble; odd → its carrier is suppressed and it splits into two lines at ±f_warble. See the file doc block.

◆ target_semitones()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::target_semitones ( ) const
inline

The pre-slew target in semitones: the pedal law plus detents, or the direct value.

Pure — safe to call from a test or a UI thread.

◆ warble_hz()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::warble_hz ( ) const
inline

f_warble for the current ratio and window (Eq.

3.5). Zero at unison, where the taps freeze into a static two-tap comb.

◆ window_ms()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::window_ms ( ) const
inline

◆ window_samples()

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::window_samples ( ) const
inline

Window length in samples at the prepared rate.

Member Data Documentation

◆ kClickBound

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kClickBound = 0.25
staticconstexpr

Sample-to-sample step ceiling the raised-cosine window must hold the wet output under.

Lives here rather than in the test so the acceptance criterion is computed from a shipped constant. A naive single-tap sawtooth spikes near 2.0 at a reset. [design parameter] default 0.25, range 0.15 .. 0.40 (with a 1.0-peak input; the floor allows legitimate fast-transient content, the ceiling still rejects an unsuppressed reset click).

◆ kDcBlockerCornerHz

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDcBlockerCornerHz = 5.0
staticconstexpr

Corner of the wet leg's DC blocker, in Hz, converted to a pole at prepare as p = 1 − 2π·f_c/fs.

Specified as a FREQUENCY rather than as DcBlocker's pole because the pole is not sample-rate invariant and the default one is not as gentle as it looks: a first-order blocker's corner is (1−p)·fs/(2π), so the primitive's 0.995 sits at 38 Hz at 48 kHz — −2.0 dB at 50 Hz and −0.57 dB at 100 Hz. That lands squarely on the oct-down "bass drop" this module exists to do (a guitar low E shifted down an octave is 41 Hz), so the blocker would be eating the effect it is insuring. At 5 Hz the same 41 Hz partial loses 0.065 dB. Series law 7: the corner is in Hz so the behaviour is identical at every sample rate. [design parameter] default 5 Hz, range 1 .. 20 Hz.

◆ kDcBlockerPeakGain

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDcBlockerPeakGain = 2.0
staticconstexpr

The DC blocker's TIME-DOMAIN peak gain: the L1 norm of its impulse response, which is exactly 2 for every pole position.

This used to return 2/(1+p) — the peak of the MAGNITUDE response at Nyquist, 1.000327 at the default corner — and call it "the exact bound". A magnitude-response peak bounds the response to a STEADY SINUSOID; it says nothing about the largest single sample. For y[n] = x[n] − x[n−1] + p·y[n−1] the impulse response is h[0] = 1, h[n] = p^(n−1)(p−1), so the worst-case sample gain is 1 + (1−p)/(1−p) = 2 — 5.9 dB above what was claimed, reachable on sustained near-DC content (bass, organ pedal).

The suite certified the old bound with a single 997 Hz sine, which is precisely the signal for which a magnitude-response bound IS valid. That is why it shipped.

◆ kDefaultSampleRate

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDefaultSampleRate = 48000.0
staticconstexpr

Fallback sample rate for a block that is queried before prepare.

◆ kDetentCount

template<typename SampleType = float>
int pulp::signal::PitchShifterT< SampleType >::kDetentCount = 9
staticconstexpr

◆ kDetentReleaseLimitSemis

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDetentReleaseLimitSemis = 1.0
staticconstexpr

The release band is additionally clamped here, so no reachable (kDetentSnapSemis, kDetentReleaseRatio) pair can make two detents capture the same target.

Half the closest detent spacing (−7/−5 and +5/+7, 2 semitones apart), so it is a property of the table.

◆ kDetentReleaseRatio

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDetentReleaseRatio = 1.5
staticconstexpr

A Schmitt trigger needs TWO thresholds; the spec names the band but gives only one, which is not hysteresis — a target sitting exactly at the capture edge would still chatter across it.

The release half-width is this ratio times the capture half-width. [design parameter] default 1.5, range 1.05 .. 2.0.

◆ kDetentSnapSemis

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDetentSnapSemis = 0.35
staticconstexpr

Detent capture half-width.

A Schmitt band so a resting pedal does not chatter between neighbours: below this the target snaps to the detent. [design parameter] default 0.35 semitone, range 0.1 .. 1.0 (the floor keeps the band audible above pedal-CV jitter, the ceiling keeps neighbouring detents — closest spacing 2 semitones — from overlapping).

◆ kDetentTable

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDetentTable[]
staticconstexpr
Initial value:
= {-24.0, -12.0, -7.0, -5.0, 0.0,
5.0, 7.0, 12.0, 24.0}

Detent table, in semitones: unison, 4ths, 5ths, octaves, double octaves.

12-TET, definitional — +5 → 1.334840, +7 → 1.498307.

◆ kDetuneCentsDefault

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDetuneCentsDefault = 12.0
staticconstexpr

PedalMode::detune offset at the toe, in cents.

[design parameter] default +12, range ±50 (the mode is meaningless below about ±1).

◆ kDetuneCentsMax

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDetuneCentsMax = 50.0
staticconstexpr

◆ kDiveFloorSemisDefault

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDiveFloorSemisDefault = -48.0
staticconstexpr

PedalMode::dive floor.

Sets r_min = 2^(floor/12); r never reaches zero, which would be DC. [design parameter] default −48, range −72 .. −24.

◆ kDiveFloorSemisMax

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDiveFloorSemisMax = -24.0
staticconstexpr

◆ kDiveFloorSemisMin

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDiveFloorSemisMin = -72.0
staticconstexpr

◆ kDriftMaxDepthPercent

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kDriftMaxDepthPercent = 0.5
staticconstexpr

Maximum 1σ pitch drift, as a percent of r, at drift_depth = 100 %.

0.5 % is about 8.6 cents — an analog wobble, not a vibrato. [design parameter] default 0.5, range 0.05 .. 5.

◆ kDriftSeed

template<typename SampleType = float>
std::uint32_t pulp::signal::PitchShifterT< SampleType >::kDriftSeed = 0x57484D59u
staticconstexpr

Fixed drift seed (series law 2: seeded, never automated, never exposed as a parameter).

Any non-zero constant works.

◆ kGlideMsDefault

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kGlideMsDefault = 60.0
staticconstexpr

Pedal portamento, rise and fall.

[design parameter] default 60, range 0 .. 2000.

◆ kGlideMsMax

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kGlideMsMax = 2000.0
staticconstexpr

◆ kGlideMsMin

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kGlideMsMin = 0.0
staticconstexpr

◆ kHeelSemisDefault

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kHeelSemisDefault = 0.0
staticconstexpr

Whammy endpoints and harmony intervals.

[design parameter] defaults 0 / +12 and +7 / +12, ranges as the node's heel_semis / toe_semis (−48 .. +24) and interval_*_semis (±24).

◆ kInterpMargin

template<typename SampleType = float>
int pulp::signal::PitchShifterT< SampleType >::kInterpMargin = 4
staticconstexpr

Guard samples reserved for the read stencil.

The floor of 4 is a hard requirement of the 4-point stencil, not tunable headroom; values above 4 only pad against future higher-order interpolants. [design parameter] default 4, range 4 .. 8.

◆ kIntervalASemisDefault

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kIntervalASemisDefault = 7.0
staticconstexpr

◆ kIntervalBSemisDefault

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kIntervalBSemisDefault = 12.0
staticconstexpr

◆ kSemitonesCeil

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kSemitonesCeil = kShiftSemisMax
staticconstexpr

◆ kSemitonesFloor

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kSemitonesFloor = kDiveFloorSemisMin
staticconstexpr

Hard clamp on the slewed semitone signal, and therefore on r.

[kSemitonesFloor, kSemitonesCeil] = [2^-6, 2^2] = [0.015625, 4].

◆ kShiftSemisMax

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kShiftSemisMax = 24.0
staticconstexpr

◆ kShiftSemisMin

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kShiftSemisMin = -48.0
staticconstexpr

The node's shift_semitones range.

Note it does NOT reach the dive floor's −72: the internal clamp below is the union of the two, because a dive to −72 has to be expressible even though the direct-shift knob stops at −48.

◆ kToeSemisDefault

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kToeSemisDefault = 12.0
staticconstexpr

◆ kWindowMsDefault

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kWindowMsDefault = 40.0
staticconstexpr

Crossfade window in ms — sets the warble rate (Eq.

3.5) and the latency (Eq. 3.6). [design parameter] default 40, range 10 .. 100.

◆ kWindowMsMax

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kWindowMsMax = 100.0
staticconstexpr

◆ kWindowMsMin

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kWindowMsMin = 10.0
staticconstexpr

◆ kWorstCaseGain

template<typename SampleType = float>
double pulp::signal::PitchShifterT< SampleType >::kWorstCaseGain = 2.23606797749979
staticconstexpr

Analytic peak-gain bound with an equal-power dry/wet mix and no feedback.

This is Forge's worst_case_gain, so it is a headroom figure downstream plans against and understating it is the expensive direction.

√5, not √2. The dry leg is bounded by the input peak and the wet leg by kDcBlockerPeakGain = 2, and an equal-power mix maximises cos θ · 1 + sin θ · 2 at √(1² + 2²). It was √2 — derived from both legs being bounded by 1 — which understated the real peak by 3.9 dB.


The documentation for this class was generated from the following file: