Vital
Loading...
Searching...
No Matches
digital_svf.cpp
Go to the documentation of this file.
1#include "digital_svf.h"
2
3#include "futils.h"
4
5namespace vital {
13
18 min_resonance_(kDefaultMinResonance), max_resonance_(kDefaultMaxResonance),
19 basic_(false), drive_compensation_(true) {
20 hardReset();
21 }
22
34
41 void DigitalSvf::processWithInput(const poly_float* audio_in, int num_samples) {
42 // Copy local state for interpolation
43 FilterValues blends1 = blends1_;
44 FilterValues blends2 = blends2_;
45 poly_float current_resonance = resonance_;
46 poly_float current_drive = drive_;
47 poly_float current_post_multiply = post_multiply_;
48
49 // Load updated filter state parameters
52
53 // Check reset mask
54 poly_mask reset_mask = getResetMask(kReset);
55 if (reset_mask.anyMask()) {
56 reset(reset_mask);
57 blends1.reset(reset_mask, blends1_);
58 blends2.reset(reset_mask, blends2_);
59 current_resonance = utils::maskLoad(current_resonance, resonance_, reset_mask);
60 current_drive = utils::maskLoad(current_drive, drive_, reset_mask);
61 current_post_multiply = utils::maskLoad(current_post_multiply, post_multiply_, reset_mask);
62 }
63
64 // Branch based on filter style
65 if (filter_state_.style == kShelving || basic_)
66 processBasic12(audio_in, num_samples, current_resonance, current_drive, current_post_multiply, blends1);
68 processDual(audio_in, num_samples, current_resonance, current_drive, current_post_multiply, blends1, blends2);
69 }
70 else if (filter_state_.style == k12Db)
71 process12(audio_in, num_samples, current_resonance, current_drive, current_post_multiply, blends1);
72 else
73 process24(audio_in, num_samples, current_resonance, current_drive, current_post_multiply, blends1);
74 }
75
76 void DigitalSvf::process12(const poly_float* audio_in, int num_samples,
77 poly_float current_resonance, poly_float current_drive,
78 poly_float current_post_multiply, FilterValues& blends) {
79 mono_float sample_inc = 1.0f / num_samples;
80 FilterValues delta_blends = blends.getDelta(blends1_, sample_inc);
81 poly_float delta_resonance = (resonance_ - current_resonance) * sample_inc;
82 poly_float delta_drive = (drive_ - current_drive) * sample_inc;
83 poly_float delta_post_multiply = (post_multiply_ - current_post_multiply) * sample_inc;
84
85 poly_float* audio_out = output()->buffer;
86 const SvfCoefficientLookup* coefficient_lookup = getSvfCoefficientLookup();
87 const poly_float* midi_cutoff_buffer = filter_state_.midi_cutoff_buffer;
88 poly_float base_midi = midi_cutoff_buffer[num_samples - 1];
89 poly_float base_frequency = utils::midiNoteToFrequency(base_midi) * (1.0f / getSampleRate());
90
91 for (int i = 0; i < num_samples; ++i) {
92 poly_float midi_delta = utils::max(midi_cutoff_buffer[i], 0.0f) - base_midi;
93 poly_float frequency = utils::min(base_frequency * futils::midiOffsetToRatio(midi_delta), 1.0f);
94 poly_float coefficient = coefficient_lookup->cubicLookup(frequency);
95
96 blends.increment(delta_blends);
97 current_resonance += delta_resonance;
98 current_drive += delta_drive;
99 current_post_multiply += delta_post_multiply;
100
101 audio_out[i] = tick(audio_in[i], coefficient, current_resonance, current_drive, blends) * current_post_multiply;
102 VITAL_ASSERT(utils::isFinite(audio_out[i]));
103 }
104 }
105
106 void DigitalSvf::processBasic12(const poly_float* audio_in, int num_samples,
107 poly_float current_resonance, poly_float current_drive,
108 poly_float current_post_multiply, FilterValues& blends) {
109 mono_float sample_inc = 1.0f / num_samples;
110 FilterValues delta_blends = blends.getDelta(blends1_, sample_inc);
111 poly_float delta_resonance = (resonance_ - current_resonance) * sample_inc;
112 poly_float delta_drive = (drive_ - current_drive) * sample_inc;
113 poly_float delta_post_multiply = (post_multiply_ - current_post_multiply) * sample_inc;
114
115 poly_float* audio_out = output()->buffer;
116 const SvfCoefficientLookup* coefficient_lookup = getSvfCoefficientLookup();
117 const poly_float* midi_cutoff_buffer = filter_state_.midi_cutoff_buffer;
118 poly_float base_midi = midi_cutoff_buffer[num_samples - 1];
119 poly_float base_frequency = utils::midiNoteToFrequency(base_midi) * (1.0f / getSampleRate());
120
121 for (int i = 0; i < num_samples; ++i) {
122 poly_float midi_delta = midi_cutoff_buffer[i] - base_midi;
123 poly_float frequency = utils::min(base_frequency * futils::midiOffsetToRatio(midi_delta), 1.0f);
124 poly_float coefficient = coefficient_lookup->cubicLookup(frequency);
125
126 blends.increment(delta_blends);
127 current_resonance += delta_resonance;
128 current_drive += delta_drive;
129 current_post_multiply += delta_post_multiply;
130
131 audio_out[i] = tickBasic(audio_in[i], coefficient, current_resonance, current_drive, blends) * current_post_multiply;
132 VITAL_ASSERT(utils::isFinite(audio_out[i]));
133 }
134 }
135
136 void DigitalSvf::process24(const poly_float* audio_in, int num_samples,
137 poly_float current_resonance, poly_float current_drive,
138 poly_float current_post_multiply, FilterValues& blends) {
139 mono_float sample_inc = 1.0f / num_samples;
140 FilterValues delta_blends = blends.getDelta(blends1_, sample_inc);
141 poly_float delta_resonance = (resonance_ - current_resonance) * sample_inc;
142 poly_float delta_drive = (drive_ - current_drive) * sample_inc;
143 poly_float delta_post_multiply = (post_multiply_ - current_post_multiply) * sample_inc;
144
145 poly_float* audio_out = output()->buffer;
146 const SvfCoefficientLookup* coefficient_lookup = getSvfCoefficientLookup();
147 const poly_float* midi_cutoff_buffer = filter_state_.midi_cutoff_buffer;
148 poly_float base_midi = midi_cutoff_buffer[num_samples - 1];
149 poly_float base_frequency = utils::midiNoteToFrequency(base_midi) * (1.0f / getSampleRate());
150
151 for (int i = 0; i < num_samples; ++i) {
152 poly_float midi_delta = midi_cutoff_buffer[i] - base_midi;
153 poly_float frequency = utils::min(base_frequency * futils::midiOffsetToRatio(midi_delta), 1.0f);
154 poly_float coefficient = coefficient_lookup->cubicLookup(frequency);
155
156 blends.increment(delta_blends);
157 current_resonance += delta_resonance;
158 current_drive += delta_drive;
159 current_post_multiply += delta_post_multiply;
160
161 poly_float result = tick24(audio_in[i], coefficient, current_resonance, current_drive, blends);
162 audio_out[i] = result * current_post_multiply;
163 VITAL_ASSERT(utils::isFinite(audio_out[i]));
164 }
165 }
166
167 void DigitalSvf::processBasic24(const poly_float* audio_in, int num_samples,
168 poly_float current_resonance, poly_float current_drive,
169 poly_float current_post_multiply, FilterValues& blends) {
170 mono_float sample_inc = 1.0f / num_samples;
171 FilterValues delta_blends = blends.getDelta(blends1_, sample_inc);
172 poly_float delta_resonance = (resonance_ - current_resonance) * sample_inc;
173 poly_float delta_drive = (drive_ - current_drive) * sample_inc;
174 poly_float delta_post_multiply = (post_multiply_ - current_post_multiply) * sample_inc;
175
176 poly_float* audio_out = output()->buffer;
177 const SvfCoefficientLookup* coefficient_lookup = getSvfCoefficientLookup();
178 const poly_float* midi_cutoff_buffer = filter_state_.midi_cutoff_buffer;
179 poly_float base_midi = midi_cutoff_buffer[num_samples - 1];
180 poly_float base_frequency = utils::midiNoteToFrequency(base_midi) * (1.0f / getSampleRate());
181
182 for (int i = 0; i < num_samples; ++i) {
183 poly_float midi_delta = midi_cutoff_buffer[i] - base_midi;
184 poly_float frequency = utils::min(base_frequency * futils::midiOffsetToRatio(midi_delta), 1.0f);
185 poly_float coefficient = coefficient_lookup->cubicLookup(frequency);
186
187 blends.increment(delta_blends);
188 current_resonance += delta_resonance;
189 current_drive += delta_drive;
190 current_post_multiply += delta_post_multiply;
191
192 poly_float result = tickBasic24(audio_in[i], coefficient, current_resonance, current_drive, blends);
193 audio_out[i] = result * current_post_multiply;
194 VITAL_ASSERT(utils::isFinite(audio_out[i]));
195 }
196 }
197
198 void DigitalSvf::processDual(const poly_float* audio_in, int num_samples,
199 poly_float current_resonance, poly_float current_drive,
200 poly_float current_post_multiply,
201 FilterValues& blends1, FilterValues& blends2) {
202 mono_float sample_inc = 1.0f / num_samples;
203 FilterValues delta_blends1 = blends1.getDelta(blends1_, sample_inc);
204 FilterValues delta_blends2 = blends2.getDelta(blends2_, sample_inc);
205 poly_float delta_resonance = (resonance_ - current_resonance) * sample_inc;
206 poly_float delta_drive = (drive_ - current_drive) * sample_inc;
207 poly_float delta_post_multiply = (post_multiply_ - current_post_multiply) * sample_inc;
208
209 poly_float* audio_out = output()->buffer;
210 const SvfCoefficientLookup* coefficient_lookup = getSvfCoefficientLookup();
211 const poly_float* midi_cutoff_buffer = filter_state_.midi_cutoff_buffer;
212 poly_float base_midi = midi_cutoff_buffer[num_samples - 1];
213 poly_float base_frequency = utils::midiNoteToFrequency(base_midi) * (1.0f / getSampleRate());
214
215 for (int i = 0; i < num_samples; ++i) {
216 poly_float midi_delta = midi_cutoff_buffer[i] - base_midi;
217 poly_float frequency = utils::min(base_frequency * futils::midiOffsetToRatio(midi_delta), 1.0f);
218 poly_float coefficient = coefficient_lookup->cubicLookup(frequency);
219
220 blends1.increment(delta_blends1);
221 blends2.increment(delta_blends2);
222 current_resonance += delta_resonance;
223 current_drive += delta_drive;
224 current_post_multiply += delta_post_multiply;
225
226 poly_float result = tickDual(audio_in[i], coefficient, current_resonance, current_drive, blends1, blends2);
227 audio_out[i] = result * current_post_multiply;
228 VITAL_ASSERT(utils::isFinite(audio_out[i]));
229 }
230 }
231
237 void DigitalSvf::setupFilter(const FilterState& filter_state) {
238 // Basic parameter clamping and conversions
239 midi_cutoff_ = filter_state.midi_cutoff;
241 float min_nyquist = getSampleRate() * kMinNyquistMult;
242 cutoff = utils::clamp(cutoff, kMinCutoff, min_nyquist);
243
244 poly_float gain_decibels = utils::clamp(filter_state.gain, kMinGain, kMaxGain);
245 poly_float gain_amplitude = utils::dbToMagnitude(gain_decibels);
246
247 poly_float resonance_percent = utils::clamp(filter_state.resonance_percent, 0.0f, 1.0f);
248 poly_float resonance_adjust = resonance_percent * resonance_percent * resonance_percent;
249 poly_float resonance = utils::interpolate(min_resonance_, max_resonance_, resonance_adjust);
250 if (drive_compensation_)
251 drive_ = filter_state.drive / (resonance_adjust * 2.0f + 1.0f);
252 else
253 drive_ = filter_state.drive;
254
255 post_multiply_ = gain_amplitude / utils::sqrt(filter_state.drive);
256 resonance_ = poly_float(1.0f) / resonance;
257
258 // Blend is typically in [-1..1], controlling low/band/high distribution
259 poly_float blend = utils::clamp(filter_state.pass_blend - 1.0f, -1.0f, 1.0f);
260
261 // Compute amounts for low_amount_, band_amount_, high_amount_ based on style
262 // (some styles have specialized logic, e.g. dual notch band).
263 if (filter_state.style == kDualNotchBand) {
264 poly_float t = blend * 0.5f + 0.5f;
265 poly_float drive_t = poly_float::min(-blend + 1.0f, 1.0f);
266 poly_float drive_mult = -t + 2.0f;
267 drive_ = utils::interpolate(filter_state.drive, drive_ * drive_mult, drive_t);
268
269 low_amount_ = t;
270 band_amount_ = 0.0f;
271 high_amount_ = 1.0f;
272 }
273 else if (filter_state.style == kNotchPassSwap) {
274 poly_float drive_t = poly_float::abs(blend);
275 drive_ = utils::interpolate(filter_state.drive, drive_, drive_t);
276
277 low_amount_ = utils::min(-blend + 1.0f, 1.0f);
278 band_amount_ = 0.0f;
279 high_amount_ = utils::min(blend + 1.0f, 1.0f);
280 }
281 else if (filter_state.style == kBandPeakNotch) {
282 poly_float drive_t = poly_float::min(-blend + 1.0f, 1.0f);
283 drive_ = utils::interpolate(filter_state.drive, drive_, drive_t);
284
285 poly_float drive_inv_t = -drive_t + 1.0f;
286 poly_float mult = utils::sqrt((drive_inv_t * drive_inv_t) * 0.5f + 0.5f);
287 poly_float peak_band_value = -utils::max(-blend, 0.0f);
288 low_amount_ = mult * (peak_band_value + 1.0f);
289 band_amount_ = mult * (peak_band_value - blend + 1.0f) * 2.0f;
290 high_amount_ = low_amount_;
291 }
292 else if (filter_state.style == kShelving) {
293 drive_ = 1.0f;
294 post_multiply_ = 1.0f;
295 poly_float low_bell_t = utils::clamp(blend + 1.0f, 0.0f, 1.0f);
296 poly_float bell_high_t = utils::clamp(blend, 0.0f, 1.0f);
297 poly_float band_t = poly_float(1.0f) - blend * blend;
298
299 poly_float amplitude_sqrt = utils::sqrt(gain_amplitude);
300 poly_float amplitude_quartic = utils::sqrt(amplitude_sqrt);
301 poly_float mult_adjust = futils::pow(amplitude_quartic, blend);
302
303 low_amount_ = utils::interpolate(gain_amplitude, 1.0f, low_bell_t);
304 high_amount_ = utils::interpolate(1.0f, gain_amplitude, bell_high_t);
305 band_amount_ = resonance_ * amplitude_sqrt * utils::interpolate(1.0f, amplitude_sqrt, band_t);
306 midi_cutoff_ += utils::ratioToMidiTranspose(mult_adjust);
307 }
308 else {
309 band_amount_ = utils::sqrt(-blend * blend + 1.0f);
310 poly_mask blend_mask = poly_float::lessThan(blend, 0.0f);
311 low_amount_ = (-blend) & blend_mask;
312 high_amount_ = blend & ~blend_mask;
313 }
314
315 blends1_.v0 = 0.0f;
316 blends1_.v1 = band_amount_;
317 blends1_.v2 = low_amount_;
318
319 blends2_.v0 = 0.0f;
320 blends2_.v1 = band_amount_;
321 blends2_.v2 = high_amount_;
322
323 blends1_.v0 += high_amount_;
324 blends1_.v1 += -resonance_ * high_amount_;
325 blends1_.v2 += -high_amount_;
326
327 blends2_.v0 += low_amount_;
328 blends2_.v1 += -resonance_ * low_amount_;
329 blends2_.v2 += -low_amount_;
330 }
331
333 min_resonance_ = min;
334 max_resonance_ = max;
335 }
336
349 return futils::hardTanh(tickBasic(audio_in, coefficient, resonance, drive, blends));
350 }
351
364 poly_float coefficient_squared = coefficient * coefficient;
365 poly_float coefficient_0 = poly_float(1.0f) / (coefficient_squared + coefficient * resonance + 1.0f);
366 poly_float coefficient_1 = coefficient_0 * coefficient;
367 poly_float coefficient_2 = coefficient_0 * coefficient_squared;
368 poly_float in = drive * audio_in;
369
370 poly_float v3 = in - ic2eq_;
371 poly_float v1 = utils::mulAdd(coefficient_0 * ic1eq_, coefficient_1, v3);
372 poly_float v2 = utils::mulAdd(utils::mulAdd(ic2eq_, coefficient_1, ic1eq_), coefficient_2, v3);
373 ic1eq_ = v1 * 2.0f - ic1eq_;
374 ic2eq_ = v2 * 2.0f - ic2eq_;
375
376 return utils::mulAdd(utils::mulAdd(blends.v0 * in, blends.v1, v1), blends.v2, v2);
377 }
378
391 poly_float coefficient_squared = coefficient * coefficient;
392 poly_float pre_coefficient_0 = poly_float(1.0f) / (coefficient_squared + coefficient + 1.0f);
393 poly_float pre_coefficient_1 = pre_coefficient_0 * coefficient;
394 poly_float pre_coefficient_2 = pre_coefficient_0 * coefficient_squared;
395
396 poly_float in = drive * audio_in;
397
398 poly_float v3_pre = in - ic2eq_pre_;
399 poly_float v1_pre = utils::mulAdd(pre_coefficient_0 * ic1eq_pre_, pre_coefficient_1, v3_pre);
400 poly_float v2_pre = utils::mulAdd(utils::mulAdd(ic2eq_pre_, pre_coefficient_1, ic1eq_pre_),
401 pre_coefficient_2, v3_pre);
402 ic1eq_pre_ = v1_pre * 2.0f - ic1eq_pre_;
403 ic2eq_pre_ = v2_pre * 2.0f - ic2eq_pre_;
404 poly_float out_pre = utils::mulAdd(utils::mulAdd(blends.v0 * in, blends.v1, v1_pre), blends.v2, v2_pre);
405
406 poly_float distort = futils::hardTanh(out_pre);
407
408 return tick(distort, coefficient, resonance, 1.0f, blends);
409 }
410
423 poly_float coefficient_squared = coefficient * coefficient;
424 poly_float pre_coefficient_0 = poly_float(1.0f) / (coefficient_squared + coefficient + 1.0f);
425 poly_float pre_coefficient_1 = pre_coefficient_0 * coefficient;
426 poly_float pre_coefficient_2 = pre_coefficient_0 * coefficient_squared;
427
428 poly_float v3_pre = audio_in - ic2eq_pre_;
429 poly_float v1_pre = utils::mulAdd(pre_coefficient_0 * ic1eq_pre_, pre_coefficient_1, v3_pre);
430 poly_float v2_pre = utils::mulAdd(utils::mulAdd(ic2eq_pre_, pre_coefficient_1, ic1eq_pre_),
431 pre_coefficient_2, v3_pre);
432 ic1eq_pre_ = v1_pre * 2.0f - ic1eq_pre_;
433 ic2eq_pre_ = v2_pre * 2.0f - ic2eq_pre_;
434 poly_float out_pre = utils::mulAdd(utils::mulAdd(blends.v0 * audio_in, blends.v1, v1_pre), blends.v2, v2_pre);
435
436 return tickBasic(out_pre, coefficient, resonance, drive, blends);
437 }
438
452 FilterValues& blends1, FilterValues& blends2) {
453 poly_float coefficient_squared = coefficient * coefficient;
454 poly_float pre_coefficient_0 = poly_float(1.0f) / (coefficient_squared + coefficient + 1.0f);
455 poly_float pre_coefficient_1 = pre_coefficient_0 * coefficient;
456 poly_float pre_coefficient_2 = pre_coefficient_0 * coefficient_squared;
457 poly_float coefficient_0 = poly_float(1.0f) / (coefficient_squared + coefficient * resonance + 1.0f);
458 poly_float coefficient_1 = coefficient_0 * coefficient;
459 poly_float coefficient_2 = coefficient_0 * coefficient_squared;
460
461 poly_float in = drive * audio_in;
462
463 poly_float v3_pre = in - ic2eq_pre_;
464 poly_float v1_pre = utils::mulAdd(pre_coefficient_0 * ic1eq_pre_, pre_coefficient_1, v3_pre);
465 poly_float v2_pre = utils::mulAdd(utils::mulAdd(ic2eq_pre_, pre_coefficient_1, ic1eq_pre_),
466 pre_coefficient_2, v3_pre);
467 ic1eq_pre_ = v1_pre * 2.0f - ic1eq_pre_;
468 ic2eq_pre_ = v2_pre * 2.0f - ic2eq_pre_;
469 poly_float out_pre = utils::mulAdd(utils::mulAdd(blends1.v0 * in, blends1.v1, v1_pre), blends1.v2, v2_pre);
470
471 poly_float distort = futils::hardTanh(out_pre);
472
473 poly_float v3 = distort - ic2eq_;
474 poly_float v1 = utils::mulAdd(coefficient_0 * ic1eq_, coefficient_1, v3);
475 poly_float v2 = utils::mulAdd(utils::mulAdd(ic2eq_, coefficient_1, ic1eq_), coefficient_2, v3);
476 ic1eq_ = v1 * 2.0f - ic1eq_;
477 ic2eq_ = v2 * 2.0f - ic2eq_;
478
479 return futils::hardTanh(utils::mulAdd(utils::mulAdd(blends2.v0 * distort, blends2.v1, v1), blends2.v2, v2));
480 }
481
487 void DigitalSvf::reset(poly_mask reset_mask) {
488 ic1eq_pre_ = utils::maskLoad(ic1eq_pre_, 0.0f, reset_mask);
489 ic2eq_pre_ = utils::maskLoad(ic2eq_pre_, 0.0f, reset_mask);
490 ic1eq_ = utils::maskLoad(ic1eq_, 0.0f, reset_mask);
491 ic2eq_ = utils::maskLoad(ic2eq_, 0.0f, reset_mask);
492 }
493
499 resonance_ = 1.0f;
500 blends1_.hardReset();
501 blends2_.hardReset();
502
503 low_amount_ = 0.0f;
504 band_amount_ = 0.0f;
505 high_amount_ = 0.0f;
506
507 drive_ = 0.0f;
508 post_multiply_ = 0.0f;
509 }
510} // namespace vital
A state-variable filter (SVF) implementation, supporting multiple filter types (12/24 dB,...
Definition digital_svf.h:17
void processDual(const poly_float *audio_in, int num_samples, poly_float current_resonance, poly_float current_drive, poly_float current_post_multiply, FilterValues &blends1, FilterValues &blends2)
Processes a dual filter mode, e.g., dual notch + band pass.
Definition digital_svf.cpp:198
force_inline poly_float tick(poly_float audio_in, poly_float coefficient, poly_float resonance, poly_float drive, FilterValues &blends)
Applies advanced distortion to the input while performing a single SVF tick (12 dB).
Definition digital_svf.cpp:347
static constexpr mono_float kMinCutoff
Minimum allowed cutoff frequency in Hz for the filter.
Definition digital_svf.h:32
static const SvfCoefficientLookup svf_coefficient_lookup_
A static global lookup table instance for SVF coefficients.
Definition digital_svf.h:66
void processBasic24(const poly_float *audio_in, int num_samples, poly_float current_resonance, poly_float current_drive, poly_float current_post_multiply, FilterValues &blends)
Processes a simpler 24 dB filter style, skipping advanced processing.
Definition digital_svf.cpp:167
force_inline poly_float tickBasic24(poly_float audio_in, poly_float coefficient, poly_float resonance, poly_float drive, FilterValues &blends)
A simpler 24 dB tick function without advanced distortion or color.
Definition digital_svf.cpp:421
static constexpr mono_float kMaxGain
Maximum gain in dB for shelf or gain-based operations.
Definition digital_svf.h:37
DigitalSvf()
Constructor that initializes the filter’s internal states.
Definition digital_svf.cpp:17
static const SvfCoefficientLookup * getSvfCoefficientLookup()
Retrieves a pointer to the global SVF coefficient lookup table.
Definition digital_svf.h:73
virtual void process(int num_samples) override
Processes a block of samples by pulling from the primary audio input and computing the SVF output....
Definition digital_svf.cpp:29
void setupFilter(const FilterState &filter_state) override
Configures this SVF based on a FilterState (cutoff, resonance, style, etc.).
Definition digital_svf.cpp:237
static constexpr mono_float kMinGain
Minimum gain in dB for shelf or gain-based operations.
Definition digital_svf.h:42
void processWithInput(const poly_float *audio_in, int num_samples) override
Processes a block of samples using a provided input buffer.
Definition digital_svf.cpp:41
void processBasic12(const poly_float *audio_in, int num_samples, poly_float current_resonance, poly_float current_drive, poly_float current_post_multiply, FilterValues &blends)
Processes a simpler 12 dB filter style, skipping extra color or overshoot logic.
Definition digital_svf.cpp:106
OneDimLookup< computeSvfOnePoleFilterCoefficient, 2048 > SvfCoefficientLookup
A lookup table type for quickly converting frequency ratios into filter coefficients.
Definition digital_svf.h:61
void reset(poly_mask reset_masks) override
Resets internal filter states for voices specified by the reset_masks.
Definition digital_svf.cpp:487
force_inline poly_float tickBasic(poly_float audio_in, poly_float coefficient, poly_float resonance, poly_float drive, FilterValues &blends)
A basic (non-distorting) single SVF tick for a 12 dB filter style.
Definition digital_svf.cpp:362
void process24(const poly_float *audio_in, int num_samples, poly_float current_resonance, poly_float current_drive, poly_float current_post_multiply, FilterValues &blends)
Processes a 24 dB filter style, adding additional stages.
Definition digital_svf.cpp:136
void hardReset() override
Performs a complete reset of the filter states for all voices.
Definition digital_svf.cpp:497
void setResonanceBounds(mono_float min, mono_float max)
Sets the minimum and maximum resonance for the filter (used in resonance interpolation).
Definition digital_svf.cpp:332
void process12(const poly_float *audio_in, int num_samples, poly_float current_resonance, poly_float current_drive, poly_float current_post_multiply, FilterValues &blends)
Processes a 12 dB filter style, iterating through the block.
Definition digital_svf.cpp:76
force_inline poly_float tick24(poly_float audio_in, poly_float coefficient, poly_float resonance, poly_float drive, FilterValues &blends)
Tick function for a 24 dB multi-stage filter, adding an additional pre-stage.
Definition digital_svf.cpp:389
force_inline poly_float tickDual(poly_float audio_in, poly_float coefficient, poly_float resonance, poly_float drive, FilterValues &blends1, FilterValues &blends2)
Tick function for a dual filter approach, e.g. notch + band, etc.
Definition digital_svf.cpp:450
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
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 pass_blend
Blend parameter in [0..2], controlling pass type.
Definition synth_filter.h:117
poly_float drive
Drive in linear magnitude.
Definition synth_filter.h:113
int style
Filter style enum (e.g., k12Db, k24Db)
Definition synth_filter.h:116
poly_float gain
Additional gain parameter.
Definition synth_filter.h:115
poly_float midi_cutoff
MIDI note-based cutoff value.
Definition synth_filter.h:110
poly_float resonance_percent
Resonance parameter in [0..1].
Definition synth_filter.h:112
@ kMidiCutoff
MIDI-based cutoff parameter.
Definition synth_filter.h:57
@ 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
@ kBandPeakNotch
Definition synth_filter.h:79
@ kNotchPassSwap
Definition synth_filter.h:77
@ kShelving
Definition synth_filter.h:80
@ 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
cr::Value resonance
Resonance factor for this formant.
Definition formant_filter.cpp:18
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 hardTanh(poly_float value)
Another saturation function using half-range tanh.
Definition futils.h:373
force_inline poly_float midiOffsetToRatio(poly_float note_offset)
Converts a MIDI note offset to a frequency ratio.
Definition futils.h:184
force_inline mono_float pow(mono_float base, mono_float exponent)
Definition futils.h:141
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 bool isFinite(poly_float value)
Checks if all lanes in a poly_float are finite.
Definition poly_utils.h:610
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 dbToMagnitude(poly_float value)
Converts a dB value to linear magnitude (vectorized).
Definition poly_utils.h:149
force_inline poly_float ratioToMidiTranspose(poly_float value)
Converts a ratio to MIDI transpose (vectorized).
Definition poly_utils.h:109
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 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 kMinNyquistMult
Minimum ratio relative to Nyquist frequency.
Definition common.h:42
float mono_float
Definition common.h:33
Stores three filter state variables (v0, v1, v2) used for multi-mode mixing.
Definition digital_svf.h:79
FilterValues getDelta(const FilterValues &target, mono_float increment)
Computes the per-sample increments needed to move from this FilterValues state to target over a certa...
Definition digital_svf.h:114
poly_float v1
Typically the band or mid portion.
Definition digital_svf.h:81
poly_float v0
Additional mixing or amplitude value.
Definition digital_svf.h:80
poly_float v2
Typically the low or high portion.
Definition digital_svf.h:82
void reset(poly_mask reset_mask, const FilterValues &other)
Selectively resets values for voices specified by reset_mask, otherwise keeps the current values.
Definition digital_svf.h:100
void hardReset()
Resets all filter values to zero (for all voices).
Definition digital_svf.h:87
force_inline void increment(const FilterValues &delta)
Increments the filter values by the amounts specified in delta.
Definition digital_svf.h:127
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