24 stages_[i].
reset(reset_mask);
34 post_multiply_ = 0.0f;
50 poly_float current_post_multiply = post_multiply_;
55 current_stage_scales[i] = stage_scales_[i];
67 current_resonance =
utils::maskLoad(current_resonance, resonance_, reset_mask);
69 current_post_multiply =
utils::maskLoad(current_post_multiply, post_multiply_, reset_mask);
71 current_stage_scales[i] =
utils::maskLoad(current_stage_scales[i], stage_scales_[i], reset_mask);
75 mono_float tick_increment = 1.0f / num_samples;
76 poly_float delta_resonance = (resonance_ - current_resonance) * tick_increment;
77 poly_float delta_drive = (drive_ - current_drive) * tick_increment;
78 poly_float delta_post_multiply = (post_multiply_ - current_post_multiply) * tick_increment;
82 delta_stage_scales[i] = (stage_scales_[i] - current_stage_scales[i]) * tick_increment;
91 poly_float base_midi = midi_cutoff_buffer[num_samples - 1];
96 for (
int i = 0; i < num_samples; ++i) {
98 poly_float midi_delta = midi_cutoff_buffer[i] - base_midi;
103 current_resonance += delta_resonance;
104 current_drive += delta_drive;
105 current_post_multiply += delta_post_multiply;
106 for (
int stage = 0; stage <=
kNumStages; ++stage)
107 current_stage_scales[stage] += delta_stage_scales[stage];
110 tick(audio_in[i], coefficient, current_resonance, current_drive);
113 poly_float total = current_stage_scales[0] * filter_input_;
114 for (
int stage = 0; stage <
kNumStages; ++stage)
115 total += current_stage_scales[stage + 1] * stages_[stage].getCurrentState();
118 audio_out[i] = total * current_post_multiply;
129 poly_float resonance_adjust = resonance_percent;
130 if (filter_state.
style) {
132 resonance_adjust =
utils::sin(resonance_percent * (0.5f *
kPi));
141 setStageScales(filter_state);
151 void LadderFilter::setStageScales(
const FilterState& filter_state) {
161 poly_float blend =
utils::clamp(filter_state.pass_blend - 1.0f, -1.0f, 1.0f);
163 poly_float band_pass =
utils::sqrt(-blend * blend + 1.0f);
167 poly_float low_pass = (-blend) & blend_mask;
168 poly_float high_pass = blend & ~blend_mask;
171 poly_float resonance_percent =
utils::clamp(filter_state.resonance_percent, 0.0f, 1.0f);
172 poly_float drive_mult = resonance_percent + 1.0f;
173 if (filter_state.style)
174 drive_mult =
utils::sin(resonance_percent) + 1.0f;
177 drive_ = filter_state.drive * resonance_scale;
180 post_multiply_ = poly_float(1.0f)
181 /
utils::sqrt((filter_state.drive - 1.0f) * 0.5f + 1.0f);
184 if (filter_state.style ==
k12Db) {
186 stage_scales_[i] = (low_pass * low_pass12[i]
187 + band_pass * band_pass12[i]
188 + high_pass * high_pass12[i]);
190 else if (filter_state.style ==
k24Db) {
193 post_multiply_ = poly_float(1.0f)
194 /
utils::sqrt((filter_state.drive - 1.0f) * 0.25f + 1.0f);
197 stage_scales_[i] = (low_pass * low_pass24[i]
198 + band_pass * band_pass24[i]
199 + high_pass * high_pass24[i]);
203 drive_ = filter_state.drive;
204 poly_float low_pass_fade =
utils::min(blend + 1.0f, 1.0f);
205 poly_float high_pass_fade =
utils::min(-blend + 1.0f, 1.0f);
207 stage_scales_[0] = low_pass_fade;
208 stage_scales_[1] = low_pass_fade * -4.0f;
209 stage_scales_[2] = high_pass_fade * 4.0f + low_pass_fade * 8.0f;
210 stage_scales_[3] = high_pass_fade * -8.0f - low_pass_fade * 8.0f;
211 stage_scales_[4] = high_pass_fade * 4.0f + low_pass_fade * 4.0f;
214 post_multiply_ = poly_float(1.0f)
215 /
utils::sqrt((filter_state.drive - 1.0f) * 0.5f + 1.0f);
217 poly_float low_pass_fade =
utils::min(blend + 1.0f, 1.0f);
218 poly_float low_pass_fade2 = low_pass_fade * low_pass_fade;
219 poly_float high_pass_fade =
utils::min(-blend + 1.0f, 1.0f);
220 poly_float high_pass_fade2 = high_pass_fade * high_pass_fade;
221 poly_float low_high_pass_fade = low_pass_fade * high_pass_fade;
223 stage_scales_[0] = low_pass_fade2;
224 stage_scales_[1] = low_pass_fade2 * -4.0f;
225 stage_scales_[2] = low_pass_fade2 * 6.0f + low_high_pass_fade * 2.0f;
226 stage_scales_[3] = low_pass_fade2 * -4.0f - low_high_pass_fade * 4.0f;
227 stage_scales_[4] = low_pass_fade2 + high_pass_fade2 + low_high_pass_fade * 2.0f;
234 poly_float drive_inv_t = -drive_t + 1.0f;
235 poly_float mult =
utils::sqrt((drive_inv_t * drive_inv_t) * 0.5f + 0.5f);
236 poly_float peak_band_value = -
utils::max(-blend, 0.0f);
237 poly_float low_high = mult * (peak_band_value + 1.0f);
238 poly_float band = mult * (peak_band_value - blend + 1.0f) * 2.0f;
241 stage_scales_[i] = (low_high * low_pass12[i]
242 + band * band_pass12[i]
243 + low_high * high_pass12[i]);
273 poly_float stage_out = stages_[0].
tick(filter_input_, coefficient);
274 stage_out = stages_[1].
tick(stage_out, coefficient);
275 stage_out = stages_[2].
tick(stage_out, coefficient);
276 stages_[3].
tick(stage_out, coefficient);
A classic transistor ladder-style filter for the Vital synthesizer.
Definition ladder_filter.h:19
static constexpr mono_float kMinResonance
Minimum resonance value.
Definition ladder_filter.h:34
static constexpr int kNumStages
Number of filter stages in the ladder (4-pole ladder).
Definition ladder_filter.h:24
void reset(poly_mask reset_mask) override
Resets internal states of each filter stage according to the given mask.
Definition ladder_filter.cpp:18
static constexpr mono_float kMaxResonance
Maximum resonance value.
Definition ladder_filter.h:39
static constexpr mono_float kDriveResonanceBoost
Boost factor added to the resonance based on drive.
Definition ladder_filter.h:49
static constexpr mono_float kResonanceTuning
Resonance tuning factor to align the filter’s internal response with musical expectations.
Definition ladder_filter.h:29
void setupFilter(const FilterState &filter_state) override
Configures the filter parameters based on a FilterState.
Definition ladder_filter.cpp:126
force_inline void tick(poly_float audio_in, poly_float coefficient, poly_float resonance, poly_float drive)
Processes a single sample through the ladder filter stages.
Definition ladder_filter.cpp:254
LadderFilter()
Constructs a new LadderFilter.
Definition ladder_filter.cpp:10
static constexpr mono_float kMaxCutoff
Maximum cutoff frequency in Hz (used internally).
Definition ladder_filter.h:59
virtual void process(int num_samples) override
Processes the input audio buffer through this ladder filter.
Definition ladder_filter.cpp:44
void hardReset() override
Performs a hard reset of all filter states.
Definition ladder_filter.cpp:30
A one-dimensional lookup table for a given function with a specified resolution.
Definition lookup_table.h:31
force_inline poly_float cubicLookup(poly_float value) const
Performs a cubic interpolation lookup on the precomputed data.
Definition lookup_table.h:61
force_inline poly_float tick(poly_float audio_in, poly_float coefficient)
Processes a single sample, applying the saturation function at each step.
Definition one_pole_filter.h:73
Base class for all signal-processing units in Vital.
Definition processor.h:212
force_inline Input * input(unsigned int index=0) const
Retrieves the Input pointer at a given index.
Definition processor.h:587
force_inline int getSampleRate() const
Retrieves the current (effective) sample rate.
Definition processor.h:326
bool inputMatchesBufferSize(int input=0)
Checks whether the buffer size of a particular input matches the size needed by this Processor.
Definition processor.cpp:42
force_inline poly_mask getResetMask(int input_index) const
Retrieves a mask indicating which voices triggered a note-on event. Compares the input's trigger_valu...
Definition processor.h:360
force_inline Output * output(unsigned int index=0) const
Retrieves the Output pointer at a given index.
Definition processor.h:616
Holds the parameters necessary to configure a SynthFilter at runtime.
Definition synth_filter.h:92
void loadSettings(Processor *processor)
Loads state from a Processor’s input signals (MIDI cutoff, drive, style, etc.).
Definition synth_filter.cpp:30
const poly_float * midi_cutoff_buffer
Pointer to the buffer storing per-sample MIDI cutoff.
Definition synth_filter.h:111
poly_float drive_percent
Normalized drive parameter in [0..1].
Definition synth_filter.h:114
int style
Filter style enum (e.g., k12Db, k24Db)
Definition synth_filter.h:116
poly_float resonance_percent
Resonance parameter in [0..1].
Definition synth_filter.h:112
@ kReset
Reset signal.
Definition synth_filter.h:56
@ kAudio
Audio input index.
Definition synth_filter.h:55
FilterState filter_state_
Internal storage of the most recent FilterState, used by derived filters.
Definition synth_filter.h:151
static const CoefficientLookup * getCoefficientLookup()
Retrieves a pointer to the static coefficient lookup table.
Definition synth_filter.h:48
@ kBandPeakNotch
Definition synth_filter.h:79
@ kNotchPassSwap
Definition synth_filter.h:77
@ k24Db
Definition synth_filter.h:76
@ k12Db
Definition synth_filter.h:75
@ kDualNotchBand
Definition synth_filter.h:78
#define VITAL_ASSERT(x)
Definition common.h:11
#define force_inline
Definition common.h:23
Contains faster but less accurate versions of utility math functions, such as exponential,...
const poly_mask kFullMask
A mask covering all lanes of a poly_float vector.
Definition synth_constants.h:257
force_inline poly_float midiOffsetToRatio(poly_float note_offset)
Converts a MIDI note offset to a frequency ratio.
Definition futils.h:184
force_inline poly_float tanh(poly_float value)
Approximates tanh function using a complex polynomial.
Definition futils.h:347
force_inline poly_float clamp(poly_float value, mono_float min, mono_float max)
Clamps each lane of a vector to [min, max].
Definition poly_utils.h:306
force_inline poly_float mulAdd(poly_float a, poly_float b, poly_float c)
Performs a fused multiply-add on SIMD data: (a * b) + c.
Definition poly_utils.h:61
force_inline poly_float min(poly_float left, poly_float right)
Returns the minimum of two poly_floats lane-by-lane.
Definition poly_utils.h:334
force_inline poly_float max(poly_float left, poly_float right)
Returns the maximum of two poly_floats lane-by-lane.
Definition poly_utils.h:327
force_inline poly_float maskLoad(poly_float zero_value, poly_float one_value, poly_mask reset_mask)
Selects between two values (zero_value or one_value) based on a mask in each lane.
Definition poly_utils.h:351
force_inline poly_float midiNoteToFrequency(poly_float value)
Converts a MIDI note to a frequency (vectorized).
Definition poly_utils.h:123
force_inline poly_float sqrt(poly_float value)
Computes the square root of each element in a poly_float.
Definition poly_utils.h:169
force_inline poly_float sin(poly_float value)
Computes the sine of each element (in radians).
Definition poly_utils.h:159
force_inline poly_float interpolate(poly_float from, poly_float to, mono_float t)
Performs a linear interpolation between two poly_floats using a scalar t in [0..1].
Definition poly_utils.h:182
Contains classes and functions used within the Vital synthesizer framework.
constexpr mono_float kPi
Pi constant.
Definition common.h:36
poly_int poly_mask
Alias for clarity; used as a mask type in poly_float.
Definition poly_values.h:590
float mono_float
Definition common.h:33
poly_float * buffer
Pointer to the output buffer.
Definition processor.h:110
Represents a vector of floating-point values using SIMD instructions.
Definition poly_values.h:600
static force_inline poly_mask vector_call lessThan(poly_float one, poly_float two)
Definition poly_values.h:1105
static force_inline simd_type vector_call min(simd_type one, simd_type two)
Returns the element-wise minimum of two SIMD float registers.
Definition poly_values.h:920
static force_inline simd_type vector_call abs(simd_type value)
Computes the absolute value of each element in the SIMD float register.
Definition poly_values.h:935
Represents a vector of integer values using SIMD instructions.
Definition poly_values.h:56
static force_inline uint32_t vector_call anyMask(simd_type value)
Returns a bitmask that indicates which bytes/elements in the register are non-zero.
Definition poly_values.h:352