26 force_inline poly_float saturateLarge(poly_float value) {
27 static constexpr float kRatio = 8.0f;
28 static constexpr float kMult = 1.0f / kRatio;
42 template<
class MemoryType>
56 template<
class MemoryType>
58 memory_ = std::make_unique<MemoryType>(max_samples);
59 period_ =
utils::min(period_, max_samples - 1);
67 template<
class MemoryType>
70 processWithInput(input(kAudio)->source->buffer, num_samples);
82 template<
class MemoryType>
92 poly_float current_low_coefficient = low_coefficient_;
93 poly_float current_high_coefficient = high_coefficient_;
96 poly_float target_frequency = input(kFrequency)->at(0);
97 Style style =
static_cast<Style>(
static_cast<int>(input(kStyle)->at(0)[0]));
100 if (style == kStereo || style == kPingPong || style == kMidPingPong)
111 feedback_ =
utils::clamp(input(kFeedback)->at(0), -1.0f, 1.0f);
117 if (style == kMidPingPong)
119 if (style == kPingPong) {
125 period_ =
utils::clamp(samples, 3.0f, memory_->getMaxPeriod());
130 poly_float filter_cutoff = input(kFilterCutoff)->at(0);
131 poly_float filter_radius = getFilterRadius(input(kFilterSpread)->at(0));
135 low_frequency =
utils::clamp(low_frequency, 1.0f, min_nyquist);
139 high_frequency =
utils::clamp(high_frequency, 1.0f, min_nyquist);
142 filter_gain_ = high_frequency / low_frequency + 1.0f;
153 process(audio_in, num_samples, current_period, current_feedback, current_filter_gain,
154 current_low_coefficient, current_high_coefficient, current_wet, current_dry);
157 processMonoPingPong(audio_in, num_samples, current_period, current_feedback, current_filter_gain,
158 current_low_coefficient, current_high_coefficient, current_wet, current_dry);
161 processPingPong(audio_in, num_samples, current_period, current_feedback, current_filter_gain,
162 current_low_coefficient, current_high_coefficient, current_wet, current_dry);
164 case kClampedDampened:
165 damping_frequency =
utils::clamp(damping_frequency, 1.0f, min_nyquist);
167 processDamped(audio_in, num_samples, current_period, current_feedback,
168 current_low_coefficient, current_wet, current_dry);
170 case kUnclampedUnfiltered:
171 processCleanUnfiltered(audio_in, num_samples, current_period, current_feedback, current_wet, current_dry);
174 processUnfiltered(audio_in, num_samples, current_period, current_feedback, current_wet, current_dry);
182 template<
class MemoryType>
186 mono_float tick_increment = 1.0f / num_samples;
187 poly_float delta_wet = (wet_ - current_wet) * tick_increment;
188 poly_float delta_dry = (dry_ - current_dry) * tick_increment;
189 poly_float delta_feedback = (feedback_ - current_feedback) * tick_increment;
190 poly_float delta_period = (period_ - current_period) * tick_increment;
194 for (
int i = 0; i < num_samples; ++i) {
195 current_feedback += delta_feedback;
196 current_wet += delta_wet;
197 current_dry += delta_dry;
199 dest[i] = tickCleanUnfiltered(audio_in[i], current_period, current_feedback, current_wet, current_dry);
200 current_period += delta_period;
207 template<
class MemoryType>
211 mono_float tick_increment = 1.0f / num_samples;
212 poly_float delta_wet = (wet_ - current_wet) * tick_increment;
213 poly_float delta_dry = (dry_ - current_dry) * tick_increment;
214 poly_float delta_feedback = (feedback_ - current_feedback) * tick_increment;
215 poly_float delta_period = (period_ - current_period) * tick_increment;
219 for (
int i = 0; i < num_samples; ++i) {
220 current_feedback += delta_feedback;
221 current_wet += delta_wet;
222 current_dry += delta_dry;
224 dest[i] = tickUnfiltered(audio_in[i], current_period, current_feedback, current_wet, current_dry);
225 current_period += delta_period;
232 template<
class MemoryType>
238 mono_float tick_increment = 1.0f / num_samples;
239 poly_float delta_wet = (wet_ - current_wet) * tick_increment;
240 poly_float delta_dry = (dry_ - current_dry) * tick_increment;
241 poly_float delta_feedback = (feedback_ - current_feedback) * tick_increment;
242 poly_float delta_period = (period_ - current_period) * tick_increment;
243 poly_float delta_filter_gain = (filter_gain_ - current_filter_gain) * tick_increment;
244 poly_float delta_low_coefficient = (low_coefficient_ - current_low_coefficient) * tick_increment;
245 poly_float delta_high_coefficient = (high_coefficient_ - current_high_coefficient) * tick_increment;
249 for (
int i = 0; i < num_samples; ++i) {
250 current_feedback += delta_feedback;
251 current_wet += delta_wet;
252 current_dry += delta_dry;
253 current_filter_gain += delta_filter_gain;
254 current_low_coefficient += delta_low_coefficient;
255 current_high_coefficient += delta_high_coefficient;
257 dest[i] = tick(audio_in[i], current_period, current_feedback, current_filter_gain,
258 current_low_coefficient, current_high_coefficient, current_wet, current_dry);
260 current_period += delta_period;
267 template<
class MemoryType>
272 mono_float tick_increment = 1.0f / num_samples;
273 poly_float delta_wet = (wet_ - current_wet) * tick_increment;
274 poly_float delta_dry = (dry_ - current_dry) * tick_increment;
275 poly_float delta_feedback = (feedback_ - current_feedback) * tick_increment;
276 poly_float delta_period = (period_ - current_period) * tick_increment;
277 poly_float delta_low_coefficient = (low_coefficient_ - current_low_coefficient) * tick_increment;
281 for (
int i = 0; i < num_samples; ++i) {
282 current_feedback += delta_feedback;
283 current_wet += delta_wet;
284 current_dry += delta_dry;
285 current_low_coefficient += delta_low_coefficient;
287 dest[i] = tickDamped(audio_in[i], current_period, current_feedback,
288 current_low_coefficient, current_wet, current_dry);
290 current_period += delta_period;
297 template<
class MemoryType>
303 mono_float tick_increment = 1.0f / num_samples;
304 poly_float delta_wet = (wet_ - current_wet) * tick_increment;
305 poly_float delta_dry = (dry_ - current_dry) * tick_increment;
306 poly_float delta_feedback = (feedback_ - current_feedback) * tick_increment;
307 poly_float delta_period = (period_ - current_period) * tick_increment;
308 poly_float delta_filter_gain = (filter_gain_ - current_filter_gain) * tick_increment;
309 poly_float delta_low_coefficient = (low_coefficient_ - current_low_coefficient) * tick_increment;
310 poly_float delta_high_coefficient = (high_coefficient_ - current_high_coefficient) * tick_increment;
314 for (
int i = 0; i < num_samples; ++i) {
315 current_feedback += delta_feedback;
316 current_wet += delta_wet;
317 current_dry += delta_dry;
318 current_filter_gain += delta_filter_gain;
319 current_low_coefficient += delta_low_coefficient;
320 current_high_coefficient += delta_high_coefficient;
322 dest[i] = tickPingPong(audio_in[i], current_period, current_feedback, current_filter_gain,
323 current_low_coefficient, current_high_coefficient, current_wet, current_dry);
325 current_period += delta_period;
332 template<
class MemoryType>
338 mono_float tick_increment = 1.0f / num_samples;
339 poly_float delta_wet = (wet_ - current_wet) * tick_increment;
340 poly_float delta_dry = (dry_ - current_dry) * tick_increment;
341 poly_float delta_feedback = (feedback_ - current_feedback) * tick_increment;
342 poly_float delta_period = (period_ - current_period) * tick_increment;
343 poly_float delta_filter_gain = (filter_gain_ - current_filter_gain) * tick_increment;
344 poly_float delta_low_coefficient = (low_coefficient_ - current_low_coefficient) * tick_increment;
345 poly_float delta_high_coefficient = (high_coefficient_ - current_high_coefficient) * tick_increment;
349 for (
int i = 0; i < num_samples; ++i) {
350 current_feedback += delta_feedback;
351 current_wet += delta_wet;
352 current_dry += delta_dry;
353 current_filter_gain += delta_filter_gain;
354 current_low_coefficient += delta_low_coefficient;
355 current_high_coefficient += delta_high_coefficient;
357 dest[i] = tickMonoPingPong(audio_in[i], current_period, current_feedback, current_filter_gain,
358 current_low_coefficient, current_high_coefficient, current_wet, current_dry);
360 current_period += delta_period;
367 template<
class MemoryType>
372 memory_->push(audio_in + read * feedback);
373 return dry * audio_in + wet * read;
379 template<
class MemoryType>
384 memory_->push(saturate(audio_in + read * feedback));
385 return dry * audio_in + wet * read;
391 template<
class MemoryType>
397 poly_float write_raw_value = saturateLarge(audio_in + read * feedback);
398 poly_float low_pass_result = low_pass_.tickBasic(write_raw_value * filter_gain, low_coefficient);
399 poly_float second_pass_result = high_pass_.tickBasic(low_pass_result, high_coefficient);
400 memory_->push(low_pass_result - second_pass_result);
401 return dry * audio_in + wet * read;
407 template<
class MemoryType>
412 poly_float write_raw_value = saturateLarge(audio_in + read * feedback);
413 poly_float low_pass_result = low_pass_.tickBasic(write_raw_value, low_coefficient);
414 memory_->push(low_pass_result);
415 return dry * audio_in + wet * read;
421 template<
class MemoryType>
428 poly_float low_pass_result = low_pass_.tickBasic(write_raw_value * filter_gain, low_coefficient);
429 poly_float second_pass_result = high_pass_.tickBasic(low_pass_result, high_coefficient);
430 memory_->push(low_pass_result - second_pass_result);
431 return dry * audio_in + wet * read;
437 template<
class MemoryType>
446 poly_float low_pass_result = low_pass_.tickBasic(write_raw_value * filter_gain, low_coefficient);
447 poly_float second_pass_result = high_pass_.tickBasic(low_pass_result, high_coefficient);
448 memory_->push(low_pass_result - second_pass_result);
449 return dry * audio_in + wet * read;
A flexible delay line effect processor that can operate in various styles and apply filtering.
Definition delay.h:47
poly_float tickCleanUnfiltered(poly_float audio_in, poly_float period, poly_float feedback, poly_float wet, poly_float dry)
A single-sample tick for a clean, unfiltered delay line.
Definition delay.cpp:368
void processCleanUnfiltered(const poly_float *audio_in, int num_samples, poly_float current_period, poly_float current_feedback, poly_float current_wet, poly_float current_dry)
Processes a clean, unfiltered delay without clamping or filtering.
Definition delay.cpp:183
poly_float tickMonoPingPong(poly_float audio_in, poly_float period, poly_float feedback, poly_float filter_gain, poly_float low_coefficient, poly_float high_coefficient, poly_float wet, poly_float dry)
A single-sample tick for a mono ping-pong delay line.
Definition delay.cpp:438
Style
Styles of delay.
Definition delay.h:81
void processPingPong(const poly_float *audio_in, int num_samples, poly_float current_period, poly_float current_feedback, poly_float current_filter_gain, poly_float current_low_coefficient, poly_float current_high_coefficient, poly_float current_wet, poly_float current_dry)
Processes a ping-pong delay, alternating the delayed signal between channels.
Definition delay.cpp:298
virtual void processWithInput(const poly_float *audio_in, int num_samples) override
Processes a block of audio from a given input buffer.
Definition delay.cpp:83
poly_float tick(poly_float audio_in, poly_float period, poly_float feedback, poly_float filter_gain, poly_float low_coefficient, poly_float high_coefficient, poly_float wet, poly_float dry)
A single-sample tick for a filtered delay line.
Definition delay.cpp:392
void processMonoPingPong(const poly_float *audio_in, int num_samples, poly_float current_period, poly_float current_feedback, poly_float current_filter_gain, poly_float current_low_coefficient, poly_float current_high_coefficient, poly_float current_wet, poly_float current_dry)
Processes a mono ping-pong delay, collapsing input before ping-ponging.
Definition delay.cpp:333
virtual void process(int num_samples) override
Processes a block of audio using the connected inputs.
Definition delay.cpp:68
poly_float tickDamped(poly_float audio_in, poly_float period, poly_float feedback, poly_float low_coefficient, poly_float wet, poly_float dry)
A single-sample tick for a damped delay line using a low-pass filter.
Definition delay.cpp:408
void hardReset() override
Hard-resets the delay line and internal filters.
Definition delay.cpp:43
void processUnfiltered(const poly_float *audio_in, int num_samples, poly_float current_period, poly_float current_feedback, poly_float current_wet, poly_float current_dry)
Processes an unfiltered delay with possible feedback saturation.
Definition delay.cpp:208
void setMaxSamples(int max_samples)
Sets the maximum number of samples for the delay.
Definition delay.cpp:57
poly_float tickUnfiltered(poly_float audio_in, poly_float period, poly_float feedback, poly_float wet, poly_float dry)
A single-sample tick for an unfiltered delay line with saturation.
Definition delay.cpp:380
void processDamped(const poly_float *audio_in, int num_samples, poly_float current_period, poly_float current_feedback, poly_float current_low_coefficient, poly_float current_wet, poly_float current_dry)
Processes a damped delay line using a low-pass filter for damping.
Definition delay.cpp:268
poly_float tickPingPong(poly_float audio_in, poly_float period, poly_float feedback, poly_float filter_gain, poly_float low_coefficient, poly_float high_coefficient, poly_float wet, poly_float dry)
A single-sample tick for a ping-pong delay line.
Definition delay.cpp:422
static force_inline poly_float computeCoefficient(poly_float cutoff_frequency, int sample_rate)
Computes the filter coefficient for a given cutoff frequency and sample rate.
Definition one_pole_filter.h:131
#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,...
Declares classes for time-domain memory storage and retrieval with cubic interpolation.
const poly_mask kFullMask
A mask covering all lanes of a poly_float vector.
Definition synth_constants.h:257
const poly_mask kRightMask
A mask identifying the right channel when comparing to kRightOne.
Definition synth_constants.h:263
const poly_mask kLeftMask
A mask identifying the left channel when comparing to kLeftOne.
Definition synth_constants.h:260
force_inline poly_float hardTanh(poly_float value)
Another saturation function using half-range tanh.
Definition futils.h:373
force_inline poly_float equalPowerFadeInverse(poly_float t)
The inverse equal-power fade from t to t+1.0.
Definition futils.h:448
force_inline poly_float equalPowerFade(poly_float t)
Produces an equal-power crossfade (sin-based) between 0.0 and 1.0.
Definition futils.h:436
force_inline mono_float exp_half(mono_float exponent)
Definition futils.h:138
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 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 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 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
force_inline poly_float swapStereo(poly_float value)
Swaps the left and right channels of a stereo poly_float.
Definition poly_utils.h:411
Contains classes and functions used within the Vital synthesizer framework.
constexpr mono_float kSqrt2
Square root of 2.
Definition common.h:37
constexpr mono_float kMinNyquistMult
Minimum ratio relative to Nyquist frequency.
Definition common.h:42
float mono_float
Definition common.h:33
Represents a vector of floating-point values using SIMD instructions.
Definition poly_values.h:600