From 7e92a0b2681ad996e5840b37761dcd7ab45620f2 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Tue, 20 Aug 2019 11:30:25 +0200 Subject: [PATCH] Trying again with Chamberlin filter for modulation to smooth the used modulation waveform. Renamed some vars for better reading. Made the used core algorithm easier - hopefully it works and the sound is better than before. --- MicroMDAEPiano.ino | 9 ++++-- config.h | 5 +--- effect_modulated_delay.cpp | 59 +++++++++----------------------------- effect_modulated_delay.h | 19 ++++-------- 4 files changed, 27 insertions(+), 65 deletions(-) diff --git a/MicroMDAEPiano.ino b/MicroMDAEPiano.ino index 46b7675..990b59b 100644 --- a/MicroMDAEPiano.ino +++ b/MicroMDAEPiano.ino @@ -57,14 +57,16 @@ AudioAmplifier inverter; AudioEffectModulatedDelay modchorus_r; AudioEffectModulatedDelay modchorus_l; AudioSynthWaveform modulator; +AudioFilterStateVariable modulator_filter; AudioConnection patchCord0(queue_r, peak_r); AudioConnection patchCord1(queue_l, peak_l); AudioConnection patchCord2(queue_r, freeverb_r); AudioConnection patchCord3(queue_l, freeverb_l); AudioConnection patchCord4(queue_r, 0, modchorus_r, 0); AudioConnection patchCord5(queue_l, 0, modchorus_l, 0); -AudioConnection patchCord6(modulator, 0, modchorus_r, 1); -AudioConnection patchCord8(modulator, inverter); +AudioConnection patchCord6(modulator, 0, modulator_filter, 1); +AudioConnection patchCord7(modulator_filter, 0, modchorus_r, 1); +AudioConnection patchCord8(modulator_filter, 0, inverter, 0); AudioConnection patchCord9(inverter, 0, modchorus_l, 1); AudioConnection patchCord10(queue_r, 0, mixer_r, 0); AudioConnection patchCord11(queue_l, 0, mixer_l, 0); @@ -234,6 +236,9 @@ void setup() modulator.amplitude(1.0); modulator.offset(0.0); inverter.gain(-1.0); // change phase for second modulated delay (faked stereo mode) + modulator_filter.frequency(50); + modulator_filter.resonance(0.6); + modulator_filter.octaveControl(1); modchorus_r.offset(15.0); modchorus_l.offset(15.0); diff --git a/config.h b/config.h index 975d19b..bd5836c 100644 --- a/config.h +++ b/config.h @@ -56,10 +56,7 @@ #define USE_XFADE_DATA 1 // CHORUS parameters #define CHORUS_DELAY_LENGTH_SAMPLES (15*AUDIO_BLOCK_SAMPLES) // one AUDIO_BLOCK_SAMPLES = 2.902ms -#define CHORUS_WAVEFORM WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE -//#define CHORUS_MODULATOR_FILTER_FRQ 10 // see https://www.earlevel.com/main/2013/10/13/biquad-calculator-v2/ -//#define CHORUS_MODULATOR_FILTER_Q 0.7 -#define CHORUS_MODULATOR_BIQUAD 1 +#define CHORUS_WAVEFORM WAVEFORM_SINE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE //************************************************************************************************* //* DEBUG OUTPUT SETTINGS //************************************************************************************************* diff --git a/effect_modulated_delay.cpp b/effect_modulated_delay.cpp index 26267cd..79e32f9 100644 --- a/effect_modulated_delay.cpp +++ b/effect_modulated_delay.cpp @@ -46,7 +46,7 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length) _delayline = NULL; _delay_length = 0; _delay_offset = 0.0; - _circ_idx = 0; + _cb_index = 0; if (delayline == NULL) { return (false); @@ -58,17 +58,6 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length) _delayline = delayline; _delay_length = d_length; -#ifdef CHORUS_MODULATOR_BIQUAD - filter_lp_mod.numStages = 1; - filter_lp_mod.pState = filter_lp_state; - filter_lp_mod.pCoeffs = filter_lp_coeffs; - - filter_lp_coeffs[0] = 0.072959657268266670; - filter_lp_coeffs[1] = 0.072959657268266670; - filter_lp_coeffs[2] = 0.0; - filter_lp_coeffs[3] = 0.854080685463466605; - filter_lp_coeffs[4] = 0.0; -#endif return (true); } @@ -87,7 +76,7 @@ void AudioEffectModulatedDelay::update(void) { int16_t *bp; float *mp; - float mod_idx; + float mod_index; float mod_number; float mod_fraction; float modulation_f32[AUDIO_BLOCK_SAMPLES]; @@ -95,51 +84,29 @@ void AudioEffectModulatedDelay::update(void) bp = block->data; arm_q15_to_float(modulation->data, modulation_f32, AUDIO_BLOCK_SAMPLES); mp = modulation_f32; -#ifdef CHORUS_MODULATOR_BIQUAD - arm_biquad_cascade_df1_f32(&filter_lp_mod, modulation_f32, modulation_f32, AUDIO_BLOCK_SAMPLES); -#endif for (uint16_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { // write data into circular buffer (delayline) - if (_circ_idx >= _delay_length) - _circ_idx = 0; - _delayline[_circ_idx] = *bp; + if (_cb_index >= _delay_length) + _cb_index = 0; + _delayline[_cb_index] = *bp; // Calculate the modulation-index as a floating point number for interpolation - mod_idx = *mp * (1 - MODULATION_MAX_FACTOR) * _delay_length; - mod_fraction = modff(mod_idx, &mod_number); + mod_index = *mp * (1 - MODULATION_MAX_FACTOR) * _delay_length; // "(1 - MODULATION_MAX_FACTOR) * _delay_length" means: maximum bytes of modulation allowed by given delay length + mod_fraction = modff(mod_index, &mod_number); // split float of mod_index into integer (= mod_number) and fraction part // calculate modulation index into circular buffer - c_mod_idx = (_circ_idx - _delay_offset - int(mod_number)) % _delay_length; - if (c_mod_idx < 0) // check for negative offsets and correct them - c_mod_idx += _delay_length; - - // linear interpolation - if (c_mod_idx == 0) - { - idx[0] = _delay_length - 1; - idx[1] = 0; - } - else if (c_mod_idx == _delay_length - 1) - { - idx[0] = 0; - idx[1] = _delay_length - 1; - } - else - { - idx[0] = c_mod_idx; - idx[1] = c_mod_idx + 1; - } - if (mod_idx < 0.0) - *bp = round(float(_delayline[idx[0]]) * fabs(mod_fraction) + float(_delayline[idx[1]]) * (1.0 - fabs(mod_fraction))); - else - *bp = round(float(_delayline[idx[0]]) * (1.0 - mod_fraction) + float(_delayline[idx[1]]) * mod_fraction); + cb_mod_index = (_cb_index - (_delay_offset + int(mod_index))) % _delay_length; + if (cb_mod_index < 0) // check for negative offsets and correct them + cb_mod_index += _delay_length; + *bp = round(float(_delayline[cb_mod_index]) * mod_fraction + float(_delayline[cb_mod_index + 1]) * (1.0 - mod_fraction)); + // push the pointers forward bp++; // next audio data mp++; // next modulation data - _circ_idx++; // next circular buffer index + _cb_index++; // next circular buffer index } } diff --git a/effect_modulated_delay.h b/effect_modulated_delay.h index cce71e8..41d689b 100644 --- a/effect_modulated_delay.h +++ b/effect_modulated_delay.h @@ -34,7 +34,7 @@ // A u d i o E f f e c t M o d u l a t e d D e l a y // Written by Pete (El Supremo) Jan 2014 // 140219 - correct storage class (not static) -// 190527 - added modulation input handling (by Holger Wirtz) +// 190527 - added modulation input handling (Aug 2019 by Holger Wirtz) class AudioEffectModulatedDelay : public AudioStream @@ -50,18 +50,11 @@ class AudioEffectModulatedDelay : private: audio_block_t *inputQueueArray[2]; - int16_t *_delayline; - uint16_t _circ_idx; - uint16_t _delay_offset; - uint16_t _delay_length; - int16_t c_mod_idx; - uint16_t idx[2]; -#ifdef CHORUS_MODULATOR_BIQUAD - arm_biquad_casd_df1_inst_f32 filter_lp_mod; - float filter_lp_state[4]; - float filter_lp_coeffs[5]; -#endif - + int16_t *_delayline; // pointer for the circular buffer + uint16_t _cb_index; // current write pointer of the circular buffer + uint16_t _delay_offset; // number of samples for the read offset of the modulation inside the circular buffer + uint16_t _delay_length; // calculated number of samples of the delay + int16_t cb_mod_index; // current read pointer with modulation for the circular buffer }; #endif