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

A rotary speaker cabinet: two rotors, a crossover, a stereo mic pair and a reflective box. More...

#include <leslie_rotary.hpp>

Public Types

using Speed = LeslieSpeed

Public Member Functions

 LeslieRotaryT ()
void prepare (double sample_rate)
 Sizes the delay lines and filter state. May allocate.
void reset ()
 Returns to a fresh, silent cabinet already turning at the selected speed.
void discard_history () noexcept
 Constant-time audio fault recovery; retains controls and makes all old delay samples unreachable without walking the prepared allocations.
void set_speed (Speed speed)
 The switch, and the most important control on the cabinet.
Speed speed () const
void set_horn_fast_hz (double hz)
void set_horn_slow_hz (double hz)
void set_drum_fast_hz (double hz)
void set_drum_slow_hz (double hz)
void set_horn_accel_s (double seconds)
 Seconds for the horn to close kSettleFraction of a speed change.
void set_horn_decel_s (double seconds)
void set_drum_accel_s (double seconds)
void set_drum_decel_s (double seconds)
void set_crossover_hz (double hz)
void set_horn_radius_m (double metres)
 Doppler depth lives here, not in a depth knob: the peak fractional pitch shift is r·ω/c, so the SAME radius gives an order of magnitude different depth at chorale and at tremolo purely from the rate.
void set_drum_radius_m (double metres)
void set_mic_distance_m (double metres)
 Mic distance trades Doppler against tremolo.
void set_mic_angle_deg (double degrees)
 Stereo width IS the mic angle: 0° puts both mics on the same facing phase and collapses the image, 90° puts them in quadrature for the widest ping-pong.
void set_am_depth (double depth)
void set_dir_depth_db (double db)
void set_drum_dir_depth_db (double db)
void set_dir_corner_hz (double hz)
void set_d_bias_ms (double ms)
void set_reflection_db (double db)
 The "box".
void set_num_reflections (int taps)
void set_refl_delay_ms (double ms)
void set_refl_spacing_ms (double ms)
void set_refl_corner_hz (double hz)
void set_drift_cents (double cents)
 Motor wow, in cents of rate (1σ). 0 disables the walk.
void set_seed (std::uint32_t seed)
 Construction or preset choice only, never automated (series law 2).
void set_mix (double mix01)
double horn_rate_hz () const
 The rotors' CURRENT rates, mid-ramp included.
double drum_rate_hz () const
double target_horn_hz () const
 The rates the switch is currently asking for.
double target_drum_hz () const
double horn_phase () const
 Rotor phases in cycles, [0, 1).
double drum_phase () const
double mic_face_offset () const
 The facing phase of each mic, in cycles either side of the cabinet axis.
double horn_delay_seconds (double phase_cycles, bool right_mic) const
 The delay a rotor presents at a given phase and mic, in seconds — the modelled acoustic path, so a test can predict the Doppler rather than only observe it.
double drum_delay_seconds (double phase_cycles, bool right_mic) const
void process (SampleType in_left, SampleType in_right, SampleType &out_left, SampleType &out_right)
void process (SampleType mono_in, SampleType &out_left, SampleType &out_right)
void process_block (const SampleType *in_left, const SampleType *in_right, SampleType *out_left, SampleType *out_right, int n)
void process_block (const SampleType *mono_in, SampleType *out_left, SampleType *out_right, int n)

Static Public Member Functions

static constexpr int latency_samples ()
 Zero, and honestly so: every delay in this model is a modelled acoustic path, not processing latency to be compensated.
static int worst_case_delay_samples (double sample_rate)
 The longest read any legal parameter set can produce, in samples.

Static Public Attributes

static constexpr double kHornSlowHz = 0.80
 [design parameter] horn chorale rate 0.80 Hz (≈48 RPM), range 0.6 .. 1.0.
static constexpr double kHornFastHz = 6.70
 [design parameter] horn tremolo rate 6.70 Hz (≈400 RPM), range 5.5 .. 7.5.
static constexpr double kDrumSlowHz = 0.60
 [design parameter] drum chorale rate 0.60 Hz (≈36 RPM), range 0.5 .. 0.9.
static constexpr double kDrumFastHz = 5.70
 [design parameter] drum tremolo rate 5.70 Hz (≈342 RPM), range 4.5 .. 6.5.
static constexpr double kHornAccelS = 1.0
 [design parameter] horn spin-up 1.0 s, range 0.3 .. 3.0 s.
static constexpr double kHornDecelS = 1.0
 [design parameter] horn spin-down 1.0 s, range 0.3 .. 3.0 s.
static constexpr double kDrumAccelS = 3.0
 [design parameter] drum spin-up 3.0 s, range 1.0 .. 8.0 s.
static constexpr double kDrumDecelS = 5.0
 [design parameter] drum spin-down 5.0 s, range 1.0 .
static constexpr double kSettleFraction = 0.95
 How much of a speed change the quoted accel/decel time covers.
static constexpr double kHornRadiusM = 0.18
 [design parameter] horn rotation radius 0.18 m, range 0.10 .. 0.25 m.
static constexpr double kDrumRadiusM = 0.12
 [design parameter] drum rotation radius 0.12 m, range 0.08 .
static constexpr double kMicDistanceM = 1.0
 [design parameter] mic distance 1.0 m, range 0.3 .
static constexpr double kMicAngleDeg = 45.0
 [design parameter] mic pair included angle 45°, range 0 .
static constexpr double kDBiasMs = 0.5
 Constant offset added to every modelled delay so the read pointer stays strictly inside the buffer even at the rotor phase where the path length is at its minimum.
static constexpr double kCrossoverHz = 800.0
 [design parameter] crossover 800 Hz, range 700 .
static constexpr double kAmDepth = 0.5
 [design parameter] tremolo depth 0.5, range 0 .
static constexpr double kDirDepthDb = 6.0
 [design parameter] horn brightness sweep 6 dB, range 0 .. 12 dB.
static constexpr double kDrumDirDepthDb = 2.0
 [design parameter] drum brightness sweep 2 dB, range 0 .
static constexpr double kDirCornerHz = 2000.0
 [design parameter] directivity shelf corner 2 kHz, range 1 .. 4 kHz.
static constexpr int kNumReflections = 2
 [design parameter] 2 reflection taps, range 1 .. 4.
static constexpr double kReflDelayMs = 3.5
 [design parameter] first reflection 3.5 ms, range 2.5 .. 6.0 ms.
static constexpr double kReflSpacingMs = 1.5
 [design parameter] inter-tap spacing 1.5 ms, range 1.0 .. 3.0 ms.
static constexpr double kReflCornerHz = 3000.0
 [design parameter] reflection low-pass 3 kHz, range 1 .. 8 kHz.
static constexpr double kReflLevelDb = -12.0
 [design parameter] reflection level −12 dB, range −60 .. −6 dB.
static constexpr double kReflectionOffDb = -60.0
 At or below this the reflections are switched off EXACTLY rather than left at a vanishing gain, so "reflections off" is a state a test can assert against rather than a very small number.
static constexpr double kDriftCents = 3.0
 [design parameter] motor wow 3 cents (1σ) of rate, range 0 .
static constexpr double kDriftCorrelationS = 4.0
 [design parameter] drift correlation time 4 s, range 0.5 .
static constexpr std::uint32_t kDefaultSeed = 0x1e511e00u
 Fixed seed installed by reset().
static constexpr double kMaxRadiusM = 0.25
static constexpr double kMaxDBiasMs = 1.0
static constexpr double kMaxReflDelayMs = 6.0
static constexpr double kMaxReflSpacingMs = 3.0
static constexpr int kMaxReflections = 4
static constexpr double kWorstCaseGain = 6.0
 The measured constructive-sum bound, in linear gain.

Detailed Description

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

A rotary speaker cabinet: two rotors, a crossover, a stereo mic pair and a reflective box.

Mono or stereo in, always stereo out.

Member Typedef Documentation

◆ Speed

template<typename SampleType = float>
using pulp::signal::LeslieRotaryT< SampleType >::Speed = LeslieSpeed

Constructor & Destructor Documentation

◆ LeslieRotaryT()

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

Member Function Documentation

◆ discard_history()

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

Constant-time audio fault recovery; retains controls and makes all old delay samples unreachable without walking the prepared allocations.

◆ drum_delay_seconds()

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::drum_delay_seconds ( double phase_cycles,
bool right_mic ) const
inline

◆ drum_phase()

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::drum_phase ( ) const
inline

◆ drum_rate_hz()

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::drum_rate_hz ( ) const
inline

◆ horn_delay_seconds()

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::horn_delay_seconds ( double phase_cycles,
bool right_mic ) const
inline

The delay a rotor presents at a given phase and mic, in seconds — the modelled acoustic path, so a test can predict the Doppler rather than only observe it.

◆ horn_phase()

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::horn_phase ( ) const
inline

Rotor phases in cycles, [0, 1).

◆ horn_rate_hz()

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::horn_rate_hz ( ) const
inline

The rotors' CURRENT rates, mid-ramp included.

Exposed because the inertia asymmetry is the module's headline behaviour and a meter that shows the two rotors converging at different times is worth having.

◆ latency_samples()

template<typename SampleType = float>
constexpr int pulp::signal::LeslieRotaryT< SampleType >::latency_samples ( )
inlinestaticconstexpr

Zero, and honestly so: every delay in this model is a modelled acoustic path, not processing latency to be compensated.

Reporting the horn's bias delay as latency would have a host pull the whole cabinet earlier in time, which is not what a cabinet does.

◆ mic_face_offset()

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::mic_face_offset ( ) const
inline

The facing phase of each mic, in cycles either side of the cabinet axis.

◆ prepare()

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

Sizes the delay lines and filter state. May allocate.

◆ process() [1/2]

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::process ( SampleType in_left,
SampleType in_right,
SampleType & out_left,
SampleType & out_right )
inline

◆ process() [2/2]

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::process ( SampleType mono_in,
SampleType & out_left,
SampleType & out_right )
inline

◆ process_block() [1/2]

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::process_block ( const SampleType * in_left,
const SampleType * in_right,
SampleType * out_left,
SampleType * out_right,
int n )
inline

◆ process_block() [2/2]

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::process_block ( const SampleType * mono_in,
SampleType * out_left,
SampleType * out_right,
int n )
inline

◆ reset()

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

Returns to a fresh, silent cabinet already turning at the selected speed.

The rotors are snapped to their target rate rather than started from rest, because reset() means "no history", and a spin-up ramp is history — one that would contaminate the first several seconds of every render made from a fresh state. Inertia is exercised by CHANGING speed, which is where it belongs and where the suite measures it.

◆ set_am_depth()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_am_depth ( double depth)
inline

◆ set_crossover_hz()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_crossover_hz ( double hz)
inline

◆ set_d_bias_ms()

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

◆ set_dir_corner_hz()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_dir_corner_hz ( double hz)
inline

◆ set_dir_depth_db()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_dir_depth_db ( double db)
inline

◆ set_drift_cents()

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

Motor wow, in cents of rate (1σ). 0 disables the walk.

◆ set_drum_accel_s()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_drum_accel_s ( double seconds)
inline

◆ set_drum_decel_s()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_drum_decel_s ( double seconds)
inline

◆ set_drum_dir_depth_db()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_drum_dir_depth_db ( double db)
inline

◆ set_drum_fast_hz()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_drum_fast_hz ( double hz)
inline

◆ set_drum_radius_m()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_drum_radius_m ( double metres)
inline

◆ set_drum_slow_hz()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_drum_slow_hz ( double hz)
inline

◆ set_horn_accel_s()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_horn_accel_s ( double seconds)
inline

Seconds for the horn to close kSettleFraction of a speed change.

◆ set_horn_decel_s()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_horn_decel_s ( double seconds)
inline

◆ set_horn_fast_hz()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_horn_fast_hz ( double hz)
inline

◆ set_horn_radius_m()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_horn_radius_m ( double metres)
inline

Doppler depth lives here, not in a depth knob: the peak fractional pitch shift is r·ω/c, so the SAME radius gives an order of magnitude different depth at chorale and at tremolo purely from the rate.

That is why the two speeds are voiced by speed alone and never by re-tuning a depth curve (series law 7 — one scale-invariant shape, not two fitted ones).

◆ set_horn_slow_hz()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_horn_slow_hz ( double hz)
inline

◆ set_mic_angle_deg()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_mic_angle_deg ( double degrees)
inline

Stereo width IS the mic angle: 0° puts both mics on the same facing phase and collapses the image, 90° puts them in quadrature for the widest ping-pong.

The tasteful default reads as two mics on the cabinet, which is exactly the classic recording setup.

◆ set_mic_distance_m()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_mic_distance_m ( double metres)
inline

Mic distance trades Doppler against tremolo.

A close mic sweeps through more of the beam, so it reads as more tremolo and relatively less pitch movement; a far mic is the reverse. "Subtle vintage" is a smaller radius with a farther mic; "in your face" is a larger radius up close.

◆ set_mix()

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

◆ set_num_reflections()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_num_reflections ( int taps)
inline

◆ set_refl_corner_hz()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_refl_corner_hz ( double hz)
inline

◆ set_refl_delay_ms()

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

◆ set_refl_spacing_ms()

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

◆ set_reflection_db()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_reflection_db ( double db)
inline

The "box".

Up around −8 dB the short cabinet taps comb the horn into the boxy resonance a close mic on a real cabinet picks up; at the −12 dB default it is a hint of room. A 3.5 ms first reflection cancels the direct signal at 1/(2·0.0035) ≈ 143 Hz and its odd multiples, which is where that boxiness actually comes from.

◆ set_seed()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_seed ( std::uint32_t seed)
inline

Construction or preset choice only, never automated (series law 2).

◆ set_speed()

template<typename SampleType = float>
void pulp::signal::LeslieRotaryT< SampleType >::set_speed ( Speed speed)
inline

The switch, and the most important control on the cabinet.

Automate THIS, not the individual rate parameters. The whole character lives in the transition: because the horn's inertia is shorter than the drum's, a change to tremolo arrives as a bright shimmer first with the low end smearing in behind it over the next couple of seconds, and a change back coasts down with the drum trailing furthest. Jumping the rates directly skips the effect entirely.

◆ speed()

template<typename SampleType = float>
Speed pulp::signal::LeslieRotaryT< SampleType >::speed ( ) const
inline

◆ target_drum_hz()

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::target_drum_hz ( ) const
inline

◆ target_horn_hz()

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::target_horn_hz ( ) const
inline

The rates the switch is currently asking for.

◆ worst_case_delay_samples()

template<typename SampleType = float>
int pulp::signal::LeslieRotaryT< SampleType >::worst_case_delay_samples ( double sample_rate)
inlinestatic

The longest read any legal parameter set can produce, in samples.

Public so the buffer-sizing test can check the shipped sizing against the declared ranges rather than against the current settings.

Member Data Documentation

◆ kAmDepth

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kAmDepth = 0.5
staticconstexpr

[design parameter] tremolo depth 0.5, range 0 .

. 0.9. Gain runs from 1 − depth facing away to 1 facing the mic, so it is bounded at or below unity and cannot build.

◆ kCrossoverHz

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kCrossoverHz = 800.0
staticconstexpr

[design parameter] crossover 800 Hz, range 700 .

. 900 Hz. The documented Leslie crossover network is around 800 Hz; the exact value is a constant, not a citation.

◆ kDBiasMs

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kDBiasMs = 0.5
staticconstexpr

Constant offset added to every modelled delay so the read pointer stays strictly inside the buffer even at the rotor phase where the path length is at its minimum.

[design parameter] default 0.5 ms, range 0.2 .. 1.0 ms.

◆ kDefaultSeed

template<typename SampleType = float>
std::uint32_t pulp::signal::LeslieRotaryT< SampleType >::kDefaultSeed = 0x1e511e00u
staticconstexpr

Fixed seed installed by reset().

A construction choice, never a parameter (series law 2).

◆ kDirCornerHz

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kDirCornerHz = 2000.0
staticconstexpr

[design parameter] directivity shelf corner 2 kHz, range 1 .. 4 kHz.

◆ kDirDepthDb

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kDirDepthDb = 6.0
staticconstexpr

[design parameter] horn brightness sweep 6 dB, range 0 .. 12 dB.

◆ kDriftCents

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kDriftCents = 3.0
staticconstexpr

[design parameter] motor wow 3 cents (1σ) of rate, range 0 .

. 10 cents. 0 disables the walk entirely. This is the "not perfectly regulated motor" life; it is off unless asked for, because a default-on stochastic process makes every other test's expectation a distribution.

◆ kDriftCorrelationS

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kDriftCorrelationS = 4.0
staticconstexpr

[design parameter] drift correlation time 4 s, range 0.5 .

. 30 s. Slow enough to read as wow rather than as noise on the rate.

◆ kDrumAccelS

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kDrumAccelS = 3.0
staticconstexpr

[design parameter] drum spin-up 3.0 s, range 1.0 .. 8.0 s.

◆ kDrumDecelS

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kDrumDecelS = 5.0
staticconstexpr

[design parameter] drum spin-down 5.0 s, range 1.0 .

. 12.0 s. Longer than its spin-up because a heavy drum coasts.

◆ kDrumDirDepthDb

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kDrumDirDepthDb = 2.0
staticconstexpr

[design parameter] drum brightness sweep 2 dB, range 0 .

. 6 dB. Weaker than the horn's — a bass baffle is far less directional.

◆ kDrumFastHz

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kDrumFastHz = 5.70
staticconstexpr

[design parameter] drum tremolo rate 5.70 Hz (≈342 RPM), range 4.5 .. 6.5.

◆ kDrumRadiusM

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kDrumRadiusM = 0.12
staticconstexpr

[design parameter] drum rotation radius 0.12 m, range 0.08 .

. 0.18 m. Smaller than the horn's, which is why the low end wobbles more gently than the top shimmers.

◆ kDrumSlowHz

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kDrumSlowHz = 0.60
staticconstexpr

[design parameter] drum chorale rate 0.60 Hz (≈36 RPM), range 0.5 .. 0.9.

◆ kHornAccelS

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kHornAccelS = 1.0
staticconstexpr

[design parameter] horn spin-up 1.0 s, range 0.3 .. 3.0 s.

◆ kHornDecelS

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kHornDecelS = 1.0
staticconstexpr

[design parameter] horn spin-down 1.0 s, range 0.3 .. 3.0 s.

◆ kHornFastHz

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kHornFastHz = 6.70
staticconstexpr

[design parameter] horn tremolo rate 6.70 Hz (≈400 RPM), range 5.5 .. 7.5.

◆ kHornRadiusM

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kHornRadiusM = 0.18
staticconstexpr

[design parameter] horn rotation radius 0.18 m, range 0.10 .. 0.25 m.

◆ kHornSlowHz

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kHornSlowHz = 0.80
staticconstexpr

[design parameter] horn chorale rate 0.80 Hz (≈48 RPM), range 0.6 .. 1.0.

◆ kMaxDBiasMs

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kMaxDBiasMs = 1.0
staticconstexpr

◆ kMaxRadiusM

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kMaxRadiusM = 0.25
staticconstexpr

◆ kMaxReflDelayMs

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kMaxReflDelayMs = 6.0
staticconstexpr

◆ kMaxReflections

template<typename SampleType = float>
int pulp::signal::LeslieRotaryT< SampleType >::kMaxReflections = 4
staticconstexpr

◆ kMaxReflSpacingMs

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kMaxReflSpacingMs = 3.0
staticconstexpr

◆ kMicAngleDeg

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kMicAngleDeg = 45.0
staticconstexpr

[design parameter] mic pair included angle 45°, range 0 .

. 90°. 0 is mono-ish (both mics see the same facing phase), 90 is wide ping-pong.

◆ kMicDistanceM

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kMicDistanceM = 1.0
staticconstexpr

[design parameter] mic distance 1.0 m, range 0.3 .

. 3.0 m. Trades Doppler against tremolo: a closer mic sweeps through more of the beam.

◆ kNumReflections

template<typename SampleType = float>
int pulp::signal::LeslieRotaryT< SampleType >::kNumReflections = 2
staticconstexpr

[design parameter] 2 reflection taps, range 1 .. 4.

◆ kReflCornerHz

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kReflCornerHz = 3000.0
staticconstexpr

[design parameter] reflection low-pass 3 kHz, range 1 .. 8 kHz.

◆ kReflDelayMs

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kReflDelayMs = 3.5
staticconstexpr

[design parameter] first reflection 3.5 ms, range 2.5 .. 6.0 ms.

◆ kReflectionOffDb

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kReflectionOffDb = -60.0
staticconstexpr

At or below this the reflections are switched off EXACTLY rather than left at a vanishing gain, so "reflections off" is a state a test can assert against rather than a very small number.

[design parameter] default −60 dB, range −80 .. −40 dB.

◆ kReflLevelDb

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kReflLevelDb = -12.0
staticconstexpr

[design parameter] reflection level −12 dB, range −60 .. −6 dB.

◆ kReflSpacingMs

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kReflSpacingMs = 1.5
staticconstexpr

[design parameter] inter-tap spacing 1.5 ms, range 1.0 .. 3.0 ms.

◆ kSettleFraction

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kSettleFraction = 0.95
staticconstexpr

How much of a speed change the quoted accel/decel time covers.

The inertia ramp is a one-pole, which approaches its target asymptotically and therefore has no finite "arrival" — but "the horn spins up in about a second" is a statement about arrival, not about a time constant. This constant is the bridge: the shipped seconds are the time to close this fraction of the distance, and the one-pole τ handed to SlewLimiterT is seconds / ln(1/(1−fraction)). At 0.95 that divisor is almost exactly 3, so a 3 s drum accel is a 1 s τ.

Reading the seconds as τ directly instead would make the drum take three times as long to arrive as its own datasheet-style figure claims, which is the kind of quiet factor-of-three that only shows up when someone compares against a real cabinet. [design parameter] default 0.95, range 0.90 .. 0.99.

◆ kWorstCaseGain

template<typename SampleType = float>
double pulp::signal::LeslieRotaryT< SampleType >::kWorstCaseGain = 6.0
staticconstexpr

The measured constructive-sum bound, in linear gain.

There is no feedback path, so this is not a loop gain — it is the worst case of horn + drum + reflections + dry all peaking together, which for a feedforward chain is a finite static number. The suite's parameter sweep measures the actual maximum across the whole space and asserts it stays under this; the Forge registry cites the sweep, not this ceiling.

The measured maximum is 5.12 (+14.2 dB), and most of it is one term: the directivity shelf is a BOOST, running from 0 dB off-axis up to dir_depth_db on-axis, so at that parameter's 12 dB maximum the shelf alone contributes a factor of four before horn, drum, reflections and dry are summed. Anyone budgeting this number from the topology alone will underestimate it badly unless they count that shelf. [design parameter] default 6.0 (+15.6 dB), range 2 .. 12.


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