210template <
typename SampleType =
float>
265 static constexpr double kDetentTable[] = {-24.0, -12.0, -7.0, -5.0, 0.0,
266 5.0, 7.0, 12.0, 24.0};
337 static_assert(
kWorstCaseGain > 2.0,
"the wet leg alone can reach 2x");
396 dc_.set_pole(
static_cast<SampleType
>(dc_pole()));
398 drift_.set_depth_percent(0.0);
414 sample_rate_ = (std::isfinite(sample_rate) && sample_rate > 0.0)
422 line_.prepare(capacity);
426 glide_.prepare(sample_rate_);
427 drift_.prepare(sample_rate_);
428 dc_.set_pole(
static_cast<SampleType
>(dc_pole()));
441 window_a_ = window_b_ = window_samples_;
449 line_.discard_history();
453 window_a_ = window_b_ = window_samples_;
468 if (!std::isfinite(semitones))
return;
475 if (!std::isfinite(e01))
return;
476 pedal_ = clamp_finite(e01, 0.0, 1.0);
478 double pedal()
const {
return pedal_; }
487 if (!std::isfinite(heel) || !std::isfinite(toe))
return;
494 if (!std::isfinite(
a) || !std::isfinite(b))
return;
495 interval_a_semis_ = clamp_finite(
a, -24.0, 24.0);
496 interval_b_semis_ = clamp_finite(b, -24.0, 24.0);
500 if (!std::isfinite(cents))
return;
505 if (!std::isfinite(semitones))
return;
520 if (!std::isfinite(ms))
return;
530 if (!std::isfinite(up_ms) || !std::isfinite(down_ms))
return;
539 if (!std::isfinite(wet01))
return;
540 mix_ = clamp_finite(wet01, 0.0, 1.0);
542 double mix()
const {
return mix_; }
549 if (!on) detent_held_ =
false;
560 if (!std::isfinite(d01))
return;
561 drift_depth_ = clamp_finite(d01, 0.0, 1.0);
589 const double e = std::clamp(e01, 0.0, 1.0);
592 return lerp(interval_a_semis_, interval_b_semis_,
e);
596 return lerp(0.0, dive_floor_semis_,
e);
599 return lerp(heel_semis_, toe_semis_,
e);
616 return window_ms_ > 0.0
617 ? std::abs(1.0 - effective_ratio_) * 1000.0 / window_ms_
626 return hz * window_ms_ / 1000.0;
637 return static_cast<int>(
638 std::lround(window_ms_ * sample_rate_ / 2000.0));
646 if (!std::isfinite(
static_cast<double>(x))) {
648 return SampleType{0};
650 const double dry =
static_cast<double>(x);
651 const double wet = advance(dry);
652 double dry_gain = 0.0;
653 double wet_gain = 0.0;
655 return static_cast<SampleType
>(dry_gain * dry + wet_gain * wet);
661 if (!std::isfinite(
static_cast<double>(x))) {
663 return SampleType{0};
665 return static_cast<SampleType
>(advance(
static_cast<double>(x)));
669 static constexpr double kPi = 3.14159265358979323846;
671 static double lerp(
double a,
double b,
double t) {
return a + (b -
a) * t; }
673 static double clamp_finite(
double v,
double lo,
double hi) {
674 if (!std::isfinite(v))
return lo;
675 return std::clamp(v, lo, hi);
681 double detented(
double raw)
const {
683 detent_held_ =
false;
693 if (std::abs(raw - held) <=
release)
return held;
694 detent_held_ =
false;
714 void update_window() {
716 if (window_a_ <= 0.0) window_a_ = window_samples_;
717 if (window_b_ <= 0.0) window_b_ = window_samples_;
720 void update_ratio() {
722 effective_ratio_ = ratio_;
727 double dc_pole()
const {
728 constexpr double kTwoPi = 2.0 * kPi;
730 return std::clamp(p, 0.0, 0.9999);
737 double read_tap(
double delay_samples)
const {
746 if (max_read_samples_ <=
static_cast<double>(
kInterpMargin))
return 0.0;
748 std::min(delay_samples, max_read_samples_));
749 const int i =
static_cast<int>(std::floor(d));
750 const double frac =
d -
static_cast<double>(
i);
751 const double y0 =
static_cast<double>(line_.read(
i));
752 const double y1 =
static_cast<double>(line_.read(
i + 1));
755 const double ym1 =
static_cast<double>(line_.read(
i - 1));
756 const double y2 =
static_cast<double>(line_.read(
i + 2));
760 static double frac1(
double v) {
return v - std::floor(v); }
763 double advance(
double x) {
770 if (max_read_samples_ <=
static_cast<double>(
kInterpMargin))
return 0.0;
772 line_.push(
static_cast<SampleType
>(x));
776 const double slewed = glide_.process(
778 if (slewed != semitones_) {
782 effective_ratio_ = ratio_;
783 if (drift_depth_ > 0.0)
784 effective_ratio_ *=
static_cast<double>(drift_.next());
785 const double r = effective_ratio_;
788 const double pa = phase_;
789 const double pb = frac1(phase_ + 0.5);
790 const double tap_a = read_tap(pa * window_a_);
791 const double tap_b = read_tap(pb * window_b_);
796 const double s = std::sin(kPi * pa);
800 const double wet =
static_cast<double>(
801 dc_.process(
static_cast<SampleType
>(w_a * tap_a + w_b * tap_b)));
807 const double dphi = window_a_ > 0.0 ? (1.0 -
r) / window_a_ : 0.0;
808 const double pa_next = frac1(phase_ + dphi);
809 const double pb_next = frac1(pa_next + 0.5);
810 const bool rising = dphi > 0.0;
811 const bool wrapped_a =
rising ? (pa_next < pa) : (pa_next > pa);
812 const bool wrapped_b =
rising ? (pb_next < pb) : (pb_next > pb);
813 if (wrapped_a) window_a_ = window_samples_;
814 if (wrapped_b) window_b_ = window_samples_;
821 DelayLineT<SampleType> line_{};
822 DcBlocker<SampleType> dc_{};
823 ConstantTimeSlewLimiterT<double> glide_{};
824 DriftT<double> drift_{};
833 double shift_semitones_ = 0.0;
842 double drift_depth_ = 0.0;
843 bool detents_ =
false;
846 double window_samples_ = 0.0;
847 double window_a_ = 0.0;
848 double window_b_ = 0.0;
849 double max_read_samples_ =
static_cast<double>(
kInterpMargin);
851 double semitones_ = 0.0;
853 double effective_ratio_ = 1.0;
858 mutable bool detent_held_ =
false;
859 mutable int detent_index_ = 0;
Time-domain ratio pitch shifter: dual-tap crossfaded modulated delay.
Definition pitch_shifter.hpp:211
double window_samples() const
Window length in samples at the prepared rate.
Definition pitch_shifter.hpp:630
void set_shift_semitones(double semitones)
Direct shift target, used when shift_source() == ShiftSource::direct.
Definition pitch_shifter.hpp:467
static constexpr double kWindowMsMin
Definition pitch_shifter.hpp:223
static constexpr int kDetentCount
Definition pitch_shifter.hpp:267
double pedal() const
Definition pitch_shifter.hpp:478
void set_interp(PitchInterp interp)
Definition pitch_shifter.hpp:553
static constexpr bool mode_uses_detents(PedalMode mode)
Whether a mode's targets are intervals the detent table can express.
Definition pitch_shifter.hpp:389
double mix() const
Definition pitch_shifter.hpp:542
void set_shift_source(ShiftSource source)
Selects the pedal law or the direct semitone target. Default pedal.
Definition pitch_shifter.hpp:462
double glide_up_ms() const
Definition pitch_shifter.hpp:534
static constexpr double kDcBlockerCornerHz
Definition pitch_shifter.hpp:317
void set_detents(bool on)
Snap the pedal-law target table to musical intervals.
Definition pitch_shifter.hpp:547
static constexpr double kShiftSemisMax
Definition pitch_shifter.hpp:256
double window_ms() const
Definition pitch_shifter.hpp:524
static constexpr double kWindowMsDefault
Definition pitch_shifter.hpp:222
static constexpr double kDriftMaxDepthPercent
Definition pitch_shifter.hpp:298
static constexpr std::uint32_t kDriftSeed
Definition pitch_shifter.hpp:302
PitchInterp interp() const
Definition pitch_shifter.hpp:554
static constexpr double kDiveFloorSemisMin
Definition pitch_shifter.hpp:240
static constexpr double kDetentReleaseRatio
Definition pitch_shifter.hpp:281
double pedal_law(double e01) const
The §5 pedal law alone, before detents and before the glide.
Definition pitch_shifter.hpp:588
static constexpr double kGlideMsMax
Definition pitch_shifter.hpp:230
double current_semitones() const
The post-slew shift the block is applying right now, before drift.
Definition pitch_shifter.hpp:604
static constexpr double kGlideMsMin
Definition pitch_shifter.hpp:229
static constexpr double default_mix_for(PedalMode mode)
Per-mode conventional dry/wet default (§6).
Definition pitch_shifter.hpp:370
static constexpr double kDetuneCentsMax
Definition pitch_shifter.hpp:235
double target_semitones() const
The pre-slew target in semitones: the pedal law plus detents, or the direct value.
Definition pitch_shifter.hpp:579
double drift_depth() const
Definition pitch_shifter.hpp:564
bool detents() const
Definition pitch_shifter.hpp:551
static constexpr double kDiveFloorSemisDefault
Definition pitch_shifter.hpp:239
double glide_down_ms() const
Definition pitch_shifter.hpp:535
static constexpr double kDetentReleaseLimitSemis
Definition pitch_shifter.hpp:287
static constexpr double kIntervalASemisDefault
Definition pitch_shifter.hpp:248
SampleType process_wet(SampleType x)
The shifted leg alone, with no dry mixed in — for callers summing several shifted voices themselves a...
Definition pitch_shifter.hpp:660
static constexpr double kWindowMsMax
Definition pitch_shifter.hpp:224
ShiftSource shift_source() const
Definition pitch_shifter.hpp:463
SampleType process(SampleType x)
One sample through the dry/wet mix.
Definition pitch_shifter.hpp:645
double dc_blocker_magnitude_peak() const
The DC blocker's MAGNITUDE-response peak, 2/(1+p) at Nyquist.
Definition pitch_shifter.hpp:362
void set_dive_floor_semis(double semitones)
Definition pitch_shifter.hpp:504
void set_drift_depth(double d01)
Optional seeded pitch drift, 0 (default) .
Definition pitch_shifter.hpp:559
PitchShifterT()
Definition pitch_shifter.hpp:395
static constexpr double kDcBlockerPeakGain
Definition pitch_shifter.hpp:353
void prepare(double sample_rate)
Sizes the delay line for kWindowMsMax plus the stencil guard and prepares the composed primitives.
Definition pitch_shifter.hpp:413
static constexpr double kClickBound
Definition pitch_shifter.hpp:326
static constexpr double kShiftSemisMin
Definition pitch_shifter.hpp:255
static constexpr double kDiveFloorSemisMax
Definition pitch_shifter.hpp:241
void set_targets(double heel, double toe)
Whammy/dive endpoints in semitones.
Definition pitch_shifter.hpp:486
void set_pedal_mode(PedalMode mode)
Picks the pedal LAW only.
Definition pitch_shifter.hpp:482
void discard_history() noexcept
Constant-time counterpart to reset() for hostile audio input.
Definition pitch_shifter.hpp:448
static constexpr double kDetentTable[]
Definition pitch_shifter.hpp:265
static constexpr int kInterpMargin
Definition pitch_shifter.hpp:293
static constexpr double kDetentSnapSemis
Definition pitch_shifter.hpp:274
static constexpr double kWorstCaseGain
Definition pitch_shifter.hpp:336
static constexpr double kSemitonesCeil
Definition pitch_shifter.hpp:261
void set_glide_ms(double up_ms, double down_ms)
Independent rise/fall portamento on the SEMITONE signal, so a glide is perceptually even.
Definition pitch_shifter.hpp:529
void snap_to_target()
Jumps the glide to its current target with no portamento — what a harmony voice wants on a note-on,...
Definition pitch_shifter.hpp:569
void set_window_ms(double ms)
Crossfade window in ms.
Definition pitch_shifter.hpp:519
static constexpr double kIntervalBSemisDefault
Definition pitch_shifter.hpp:249
PedalMode pedal_mode() const
Definition pitch_shifter.hpp:483
int latency_samples() const
Honest processing throughput, not phase-aligned PDC: the delay sweeps [0, L], so the crossfaded outpu...
Definition pitch_shifter.hpp:636
void set_detune_cents(double cents)
Definition pitch_shifter.hpp:499
static constexpr double kDetuneCentsDefault
Definition pitch_shifter.hpp:234
double shift_semitones() const
Definition pitch_shifter.hpp:471
double current_ratio() const
The ratio the taps ACTUALLY ramped at on the last processed sample, drift included.
Definition pitch_shifter.hpp:611
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...
Definition pitch_shifter.hpp:625
static constexpr double kHeelSemisDefault
Definition pitch_shifter.hpp:246
static constexpr double kDefaultSampleRate
Definition pitch_shifter.hpp:365
void set_mix(double wet01)
Equal-power dry↔wet. 0 is the untouched input; 1 is wet only.
Definition pitch_shifter.hpp:538
void set_pedal(double e01)
Expression position, heel = 0 to toe = 1.
Definition pitch_shifter.hpp:474
static constexpr double kToeSemisDefault
Definition pitch_shifter.hpp:247
double warble_hz() const
f_warble for the current ratio and window (Eq.
Definition pitch_shifter.hpp:615
static constexpr double kGlideMsDefault
Definition pitch_shifter.hpp:228
void reset()
Zeroes the line, the phase, and the filter state, and rewinds the drift stream (series law 2).
Definition pitch_shifter.hpp:436
void set_harmony(double a, double b)
Harmony A (heel) and B (toe) intervals in semitones.
Definition pitch_shifter.hpp:493
static constexpr double kSemitonesFloor
Definition pitch_shifter.hpp:260
The one shared old→new crossfade gain law for the SIGNAL side.
High-quality sample interpolation for delay lines and resampling.
@ d
Definition pitch.hpp:22
constexpr double kTwoPi
Definition lfo_sampling.hpp:77
T semitones_to_ratio(T semitones)
Semitones → frequency ratio. +12 → 2, −12 → 0.5.
Definition units.hpp:105
constexpr double kCentsPerSemitone
Definition units.hpp:62
T ms_to_samples(T ms, T sample_rate)
Milliseconds → samples at sample_rate Hz.
Definition units.hpp:147
Definition additive_bank.hpp:218
PitchShifterT< float > PitchShifter
Definition pitch_shifter.hpp:862
@ linear
Definition mod_tools.hpp:106
@ rising
Definition rise_fall_generator.hpp:19
@ release
Definition envelope.hpp:62
PitchShifterT< double > PitchShifter64
Definition pitch_shifter.hpp:863
PitchInterp
Fractional-delay read quality for the two taps.
Definition pitch_shifter.hpp:180
@ cubic
4-point Lagrange. Brighter tap, ~4× the read cost.
Definition pitch_shifter.hpp:182
@ linear
2-point. Dattorro's recommendation for modulated delays.
Definition pitch_shifter.hpp:181
@ EqualPower
(cos(u·π/2), sin(u·π/2)) — power sum == 1.
Definition crossfade.hpp:43
@ EqualGain
(1−u, u) — amplitude sum == 1.
Definition crossfade.hpp:42
@ a
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
@ e
Definition formant_filter_bank.hpp:20
@ nearest
Snap to the nearest in-scale degree in either direction.
Definition harmony_engine.hpp:175
@ linear
2-point. Cheapest; audible imaging when pitching up.
Definition granular.hpp:133
ShiftSource
Which control feeds the shift target.
Definition pitch_shifter.hpp:192
@ pedal
set_pedal through the §5 law. The default.
Definition pitch_shifter.hpp:193
@ direct
set_shift_semitones. Detents and the pedal law are bypassed.
Definition pitch_shifter.hpp:194
void crossfade_gains(T u, CrossfadeGainLaw law, T &old_gain, T &new_gain) noexcept
Old/new blend gains for an ALREADY-SHAPED progress u (the caller applies any smoothstep/clamp first).
Definition crossfade.hpp:61
PedalMode
How the expression pedal maps to a shift target.
Definition pitch_shifter.hpp:168
@ detune
Sub-semitone offset scaled by the pedal. Dry on.
Definition pitch_shifter.hpp:171
@ whammy
Continuous heel→toe bend. Dry conventionally muted.
Definition pitch_shifter.hpp:169
@ dive
Dive-bomb toward a floor near (but never at) r = 0.
Definition pitch_shifter.hpp:172
@ harmony
Morph between two fixed intervals. Dry conventionally on.
Definition pitch_shifter.hpp:170
@ s
Definition input_events.hpp:41
@ r
Definition input_events.hpp:41
@ p
Definition input_events.hpp:40
@ v
Definition input_events.hpp:41
Deterministic randomness for modulation: a counter-free PRNG, a Gaussian draw, a stateless purpose-ke...
Compatibility include for the canonical modulation-toolkit slew limiter and sample-and-hold implement...
static SampleType linear(SampleType frac, SampleType y0, SampleType y1)
Linear interpolation between two samples.
Definition interpolator.hpp:33
static SampleType lagrange(SampleType frac, SampleType ym1, SampleType y0, SampleType y1, SampleType y2)
4-point Lagrange interpolation.
Definition interpolator.hpp:60
The real-unit vocabulary shared by every DSP block in the catalog.