209template <
typename SampleType =
double>
225 0.4021921162426, 0.8561710882420, 0.9722909545651, 0.9952884791278};
230 0.6923878, 0.9360654322959, 0.9882295226860, 0.9987488452737};
256 in_phase_state_ = {};
257 quadrature_state_ = {};
262 const SampleType in_phase = cascade(x,
kInPhasePoles, in_phase_state_);
263 const SampleType quadrature = cascade(x,
kQuadraturePoles, quadrature_state_);
264 const Outputs out{in_phase, delayed_};
265 delayed_ = quadrature;
285 struct SectionState {
290 using BranchState = std::array<SectionState, kSections>;
292 static SampleType cascade(SampleType x,
const std::array<double, kSections>& poles,
293 BranchState&
state) {
295 for (std::size_t k = 0; k <
kSections; ++k) {
296 const auto c =
static_cast<SampleType
>(poles[k] * poles[k]);
297 const SampleType y =
c * v +
state[k].s1;
308 BranchState in_phase_state_{};
309 BranchState quadrature_state_{};
310 SampleType delayed_ = 0;
331template <
typename SampleType =
float>
404 sample_rate_ = sample_rate > 0.0 ? sample_rate : sample_rate_;
406 const int max_delay = std::max(
408 for (
auto& line : delay_) line.prepare(max_delay);
409 max_delay_samples_ =
static_cast<double>(max_delay);
414 const auto pole =
static_cast<double>(std::exp(-2.0 * kPi *
kDcCornerHz / sample_rate_));
415 for (
auto& dc : dc_blocker_) dc.set_pole(pole);
417 const auto sr =
static_cast<double>(sample_rate_);
424 update_delay_target();
432 for (
auto& n : network_) n.reset();
433 for (
auto& dc : dc_blocker_) dc.reset();
434 for (
auto& line : delay_) line.reset();
436 shift_smoother_.set_immediate(shift_hz_);
437 feedback_smoother_.set_immediate(feedback_);
438 mix_smoother_.set_immediate(mix_);
439 spread_smoother_.set_immediate(spread_);
440 delay_smoother_.set_immediate(delay_target_samples_);
446 for (
auto& n : network_) n.reset();
447 for (
auto& dc : dc_blocker_) dc.reset();
448 for (
auto& line : delay_) line.discard_history();
450 shift_smoother_.set_immediate(shift_hz_);
451 feedback_smoother_.set_immediate(feedback_);
452 mix_smoother_.set_immediate(mix_);
453 spread_smoother_.set_immediate(spread_);
454 delay_smoother_.set_immediate(delay_target_samples_);
470 if (!std::isfinite(hz))
return;
472 shift_smoother_.set_target(shift_hz_);
479 if (!std::isfinite(g))
return;
481 feedback_smoother_.set_target(feedback_);
490 if (!std::isfinite(ms))
return;
492 update_delay_target();
493 delay_smoother_.set_target(delay_target_samples_);
503 if (!std::isfinite(wet01))
return;
504 mix_ = std::clamp(wet01, 0.0, 1.0);
505 mix_smoother_.set_target(mix_);
523 if (!std::isfinite(spread01))
return;
524 spread_ = std::clamp(spread01, 0.0, 1.0);
525 spread_smoother_.set_target(spread_);
534 if (!std::isfinite(
static_cast<double>(x))) {
536 return SampleType{0};
538 const Controls
c = advance_controls();
539 const double dry =
static_cast<double>(x);
540 const double wet = shift_channel(0, dry,
c,
true);
541 return static_cast<SampleType
>(
snap_to_zero(dry +
c.mix * (wet - dry)));
548 if (!std::isfinite(
static_cast<double>(
left)) ||
549 !std::isfinite(
static_cast<double>(
right))) {
554 const Controls
c = advance_controls();
555 const double dry_l =
static_cast<double>(
left);
556 const double dry_r =
static_cast<double>(
right);
557 const double wet_l = shift_channel(0, dry_l,
c,
true);
558 const double wet_r = shift_channel(1, dry_r,
c,
false);
595 const double clamped = std::clamp(knob, -1.0, 1.0);
596 const double m = std::abs(clamped);
597 const double magnitude =
600 return clamped < 0.0 ? -magnitude : magnitude;
606 const double m = std::abs(clamped);
607 const double position =
611 return clamped < 0.0 ? -position : position;
622 static constexpr double kPi = 3.14159265358979323846;
623 static constexpr double kTwoPi = 6.283185307179586476925286766559;
631 double delay_samples = 0.0;
636 Controls advance_controls() {
638 c.feedback = feedback_smoother_.
next();
639 c.delay_samples = delay_smoother_.
next();
640 c.mix = mix_smoother_.
next();
641 c.spread = spread_smoother_.
next();
647 const double shift = shift_smoother_.
next() *
648 (mode_ == Mode::stereo_split ?
c.spread : 1.0);
654 carrier_.
advance(shift / sample_rate_);
655 const double radians = kTwoPi * carrier_.
phase();
656 c.cosine = std::cos(radians);
657 c.sine = std::sin(radians);
663 double shift_channel(std::size_t channel,
double input,
const Controls&
c,
bool left) {
669 const double read_position = std::clamp(
c.delay_samples - 1.0, 0.0, max_delay_samples_);
670 const double recirculated = delay_[channel].read(read_position);
672 const double driven = dc_blocker_[channel].process(input +
c.feedback * recirculated);
673 const auto pair = network_[channel].process(driven);
679 double quadrature_gain = 0.0;
682 case Mode::dual_mono:
683 quadrature_gain = -1.0;
686 quadrature_gain = 1.0;
688 case Mode::stereo_split:
689 quadrature_gain =
left ? -1.0 : 1.0;
694 quadrature_gain * pair.quadrature *
c.sine);
695 delay_[channel].push(wet);
699 void update_delay_target() {
701 delay_target_samples_ = std::clamp(samples, 1.0, max_delay_samples_);
704 double sample_rate_ = 44100.0;
705 double max_delay_samples_ = 1.0;
707 double shift_hz_ = 0.0;
708 double feedback_ = 0.0;
709 double feedback_delay_ms_ = 8.0;
711 double spread_ = 1.0;
712 double delay_target_samples_ = 1.0;
713 Mode mode_ = Mode::up;
715 std::array<Network, 2> network_{};
716 std::array<DcBlocker<double>, 2> dc_blocker_{};
717 std::array<DelayLineT<double>, 2> delay_{};
719 osc::PhaseAccumulator carrier_{};
721 SmoothedValue<double> shift_smoother_{};
722 SmoothedValue<double> feedback_smoother_{};
723 SmoothedValue<double> mix_smoother_{1.0};
724 SmoothedValue<double> spread_smoother_{1.0};
725 SmoothedValue<double> delay_smoother_{1.0};
A pair of allpass cascades whose outputs stand a quarter cycle apart across nearly the whole band — t...
Definition frequency_shifter_ssb.hpp:210
static constexpr std::size_t kSections
Definition frequency_shifter_ssb.hpp:217
static constexpr std::array< double, kSections > kQuadraturePoles
Definition frequency_shifter_ssb.hpp:229
static constexpr double band_low_hz(double sample_rate)
Definition frequency_shifter_ssb.hpp:271
void reset()
Definition frequency_shifter_ssb.hpp:255
static constexpr double kImageRejectDb
Definition frequency_shifter_ssb.hpp:246
static constexpr double kBandEdgeNormalized
Definition frequency_shifter_ssb.hpp:240
static constexpr std::array< double, kSections > kInPhasePoles
Definition frequency_shifter_ssb.hpp:224
Outputs process(SampleType x)
Definition frequency_shifter_ssb.hpp:261
static constexpr double band_high_hz(double sample_rate)
Definition frequency_shifter_ssb.hpp:276
T next()
Definition smoothed_value.hpp:79
The single-sideband frequency shifter.
Definition frequency_shifter_ssb.hpp:332
void set_mix(double wet01)
Dry/wet, 0 .. 1.
Definition frequency_shifter_ssb.hpp:502
double feedback_delay_ms() const
Definition frequency_shifter_ssb.hpp:496
static constexpr double kLinZoneHz
Definition frequency_shifter_ssb.hpp:347
double feedback() const
Definition frequency_shifter_ssb.hpp:484
static double shift_hz_from_knob(double knob)
The signed piecewise taper: a linear fine zone out to kLinZoneHz, geometric beyond it to kMaxShiftHz,...
Definition frequency_shifter_ssb.hpp:594
static constexpr double kShiftSmoothingMs
Definition frequency_shifter_ssb.hpp:384
int latency_samples() const noexcept
Zero, and reported exactly rather than estimated (series law 5).
Definition frequency_shifter_ssb.hpp:571
static constexpr double kMaxFeedback
Definition frequency_shifter_ssb.hpp:355
static constexpr double kMaxShiftHz
Definition frequency_shifter_ssb.hpp:342
static constexpr double kMinDelayMs
Definition frequency_shifter_ssb.hpp:362
double shift_hz() const
Definition frequency_shifter_ssb.hpp:475
void set_feedback(double g)
Barberpole feedback depth, in the range [0, kMaxFeedback].
Definition frequency_shifter_ssb.hpp:478
static double knob_from_shift_hz(double hz)
Inverse of shift_hz_from_knob.
Definition frequency_shifter_ssb.hpp:604
SampleType process(SampleType x)
One mono sample.
Definition frequency_shifter_ssb.hpp:533
void prepare(double sample_rate)
Sizes the two feedback delay lines for kMaxLoopMs at this rate and recomputes the DC-blocker pole and...
Definition frequency_shifter_ssb.hpp:403
static double feedback_delay_ms_from_knob(double u)
The loop-delay taper.
Definition frequency_shifter_ssb.hpp:617
void process_stereo(SampleType &left, SampleType &right)
One stereo frame.
Definition frequency_shifter_ssb.hpp:547
static constexpr double kDcCornerHz
Definition frequency_shifter_ssb.hpp:379
void set_mode(Mode mode)
Definition frequency_shifter_ssb.hpp:498
static constexpr double kGshiftBudget
Definition frequency_shifter_ssb.hpp:374
static constexpr double kMaxLoopMs
Definition frequency_shifter_ssb.hpp:367
static constexpr double kSplit
Definition frequency_shifter_ssb.hpp:351
void set_stereo_spread(double spread01)
stereo_split only: scales how far apart the two channels are driven.
Definition frequency_shifter_ssb.hpp:522
static constexpr double kDelaySmoothingMs
Definition frequency_shifter_ssb.hpp:396
static constexpr double worst_case_gain()
The bound Forge's registry cites (series law 8): the steady-state envelope of a comb-like loop at the...
Definition frequency_shifter_ssb.hpp:585
void set_feedback_delay_ms(double ms)
Feedback-loop delay in ms, in the range [kMinDelayMs, kMaxLoopMs].
Definition frequency_shifter_ssb.hpp:489
void set_shift_hz(double hz)
Signed shift in Hz: positive shifts the retained sideband up, negative down.
Definition frequency_shifter_ssb.hpp:469
void discard_history() noexcept
Audio-thread fault recovery: identical running state to reset() but logically invalidates the delay h...
Definition frequency_shifter_ssb.hpp:445
void reset()
Clears every filter, line, accumulator and smoother, and snaps each smoother onto its target so a ren...
Definition frequency_shifter_ssb.hpp:431
static constexpr double kGainSmoothingMs
Definition frequency_shifter_ssb.hpp:390
HilbertQuadratureNetworkT< double > Network
Definition frequency_shifter_ssb.hpp:335
FrequencyShiftMode Mode
Definition frequency_shifter_ssb.hpp:334
Mode mode() const
Definition frequency_shifter_ssb.hpp:499
double phase() const
Current phase, always in [0, 1).
Definition phase.hpp:176
int advance(double increment)
Advance one sample by increment cycles. Returns the number of events.
Definition phase.hpp:142
T taper_log(T u, T lo, T hi)
Geometric ("log") taper: maps a normalised knob position u ∈ [0, 1] onto [lo, hi] so equal knob trave...
Definition units.hpp:233
T untaper_log(T value, T lo, T hi)
Inverse of taper_log: a value in [lo, hi] → its knob position in [0, 1].
Definition units.hpp:241
T ms_to_samples(T ms, T sample_rate)
Milliseconds → samples at sample_rate Hz.
Definition units.hpp:147
Definition additive_bank.hpp:218
@ right
Definition multi_channel_meter.hpp:67
@ left
Definition multi_channel_meter.hpp:66
@ c
Definition spectrum_trace.hpp:35
FrequencyShiftMode
Which sideband a SsbFrequencyShifterT keeps, and how it spreads it.
Definition frequency_shifter_ssb.hpp:314
@ stereo_split
Up on the left, down on the right, scaled by the spread.
Definition frequency_shifter_ssb.hpp:318
@ dual_mono
Two independent identical mono shifters. See the note below.
Definition frequency_shifter_ssb.hpp:317
@ up
Upper sideband on both channels: f → f + Δf.
Definition frequency_shifter_ssb.hpp:315
@ down
Lower sideband on both channels: f → f − Δf.
Definition frequency_shifter_ssb.hpp:316
T snap_to_zero(T x)
Returns 0 if |x| < snap_threshold, else x.
Definition denormal.hpp:45
@ u
Definition formant_filter_bank.hpp:20
HilbertQuadratureNetworkT< double > HilbertQuadratureNetwork
Definition frequency_shifter_ssb.hpp:728
SsbFrequencyShifterT< double > SsbFrequencyShifter64
Definition frequency_shifter_ssb.hpp:730
SsbFrequencyShifterT< float > SsbFrequencyShifter
Definition frequency_shifter_ssb.hpp:729
SequencerStateChannel is the audio-safe transport for a plugin's structured NON-parameter state: the ...
Definition audio_device_manager.hpp:48
Definition frequency_shifter_ssb.hpp:248
SampleType in_phase
the reference branch, no bulk delay
Definition frequency_shifter_ssb.hpp:249
SampleType quadrature
a quarter cycle behind it
Definition frequency_shifter_ssb.hpp:250
The real-unit vocabulary shared by every DSP block in the catalog.