diff --git a/MicroMDAEPiano.ino b/MicroMDAEPiano.ino index e087e8e..610be67 100644 --- a/MicroMDAEPiano.ino +++ b/MicroMDAEPiano.ino @@ -56,9 +56,7 @@ AudioAmplifier volume_l; AudioAmplifier inverter; AudioEffectModulatedDelay modchorus_r; AudioEffectModulatedDelay modchorus_l; -AudioSynthWaveform modulator1; -AudioSynthWaveform modulator2; -AudioMixer4 modulator_mixer; +AudioSynthWaveform modulator; AudioFilterStateVariable chorus_filter_r; AudioFilterStateVariable chorus_filter_l; AudioConnection patchCord0(queue_r, peak_r); @@ -67,10 +65,8 @@ 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(modulator1, 0, modulator_mixer, 0); -AudioConnection patchCord7(modulator2, 0, modulator_mixer, 1); -AudioConnection patchCord8(modulator_mixer, 0, modchorus_r, 1); -AudioConnection patchCord9(modulator_mixer, inverter); +AudioConnection patchCord8(modulator, 0, modchorus_r, 1); +AudioConnection patchCord9(modulator, inverter); AudioConnection patchCord10(inverter, 0, modchorus_l, 1); AudioConnection patchCord11(queue_r, 0, mixer_r, 0); AudioConnection patchCord12(queue_l, 0, mixer_l, 0); @@ -237,26 +233,17 @@ void setup() } // chorus modulation fixed - modulator1.begin(CHORUS_WAVEFORM_MOD1); - modulator1.phase(0); - modulator1.amplitude(1.0); - modulator1.offset(0.0); - modulator2.begin(CHORUS_WAVEFORM_MOD2); - modulator2.phase(0); - modulator2.amplitude(1.0); - modulator2.offset(0.0); - modulator_mixer.gain(0, 0.5); - modulator_mixer.gain(1, 0.5); - inverter.gain(1.0); // change phase for second modulated delay (faked stereo mode) - //modulator_filter.frequency(15000); - //modulator_filter.resonance(0.7); - //modulator_filter.octaveControl(1); + modulator.begin(CHORUS_WAVEFORM_MOD); + modulator.phase(0); + modulator.amplitude(1.0); + modulator.offset(0.0); + inverter.gain(-1.0); // change phase for second modulated delay (faked stereo mode) chorus_filter_r.frequency(3500); chorus_filter_r.resonance(0.7); - chorus_filter_r.octaveControl(2); + chorus_filter_r.octaveControl(1); chorus_filter_l.frequency(3500); chorus_filter_l.resonance(0.7); - chorus_filter_l.octaveControl(2); + chorus_filter_l.octaveControl(1); modchorus_r.offset(15.0); modchorus_l.offset(15.0); diff --git a/UI.hpp b/UI.hpp index da8bbca..084d28e 100644 --- a/UI.hpp +++ b/UI.hpp @@ -121,8 +121,7 @@ extern void eeprom_config_write(uint8_t value); extern AudioControlSGTL5000 sgtl5000_1; extern AudioEffectFreeverb freeverb_r; extern AudioEffectFreeverb freeverb_l; -extern AudioSynthWaveform modulator1; -extern AudioSynthWaveform modulator2; +extern AudioSynthWaveform modulator; extern AudioEffectModulatedDelay modchorus_r; extern AudioEffectModulatedDelay modchorus_l; extern AudioMixer4 mixer_r; @@ -2038,8 +2037,7 @@ void set_chorus_frequency(uint8_t value) Serial.print(F("Set CHORUS_FREQUENCY ")); Serial.println(value); #endif - modulator1.frequency(float(value) / 10); - modulator2.frequency(float(value) / 10); + modulator.frequency(float(value) / 10); configuration.chorus_frequency = value; } @@ -2059,8 +2057,7 @@ void set_chorus_intensity(uint8_t value) Serial.print(F("Set CHORUS_INTENSITY ")); Serial.println(value); #endif - modulator1.amplitude(mapfloat(float(value), ENC_CHORUS_INTENSITY_MIN, ENC_CHORUS_INTENSITY_MAX, 0.0, 1.0)); - modulator2.amplitude(mapfloat(float(value), ENC_CHORUS_INTENSITY_MIN, ENC_CHORUS_INTENSITY_MAX, 0.0, 1.0)); + modulator.amplitude(mapfloat(float(value), ENC_CHORUS_INTENSITY_MIN, ENC_CHORUS_INTENSITY_MAX, 0.0, 1.0)); configuration.chorus_intensity = value; } diff --git a/config.h b/config.h index 6eb1a4b..cfed6ec 100644 --- a/config.h +++ b/config.h @@ -56,8 +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_MOD1 WAVEFORM_SINE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE -#define CHORUS_WAVEFORM_MOD2 WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE +#define CHORUS_WAVEFORM_MOD WAVEFORM_TRIANGLE // 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 cdd509d..f5a74d8 100644 --- a/effect_modulated_delay.cpp +++ b/effect_modulated_delay.cpp @@ -60,37 +60,25 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length) _delayline = delayline; _delay_length = d_length; - set_modulator_filter_coeffs(1.0, configuration.chorus_frequency / 10, 1.0); // gain, center frerquency - modulator_filter_data = {1, &modulator_filter_state, modulator_filter_coeffs}; + set_modulator_filter_coeffs(); + modulator_filter_data = {1, modulator_filter_state, modulator_filter_coeffs}; return (true); } -void AudioEffectModulatedDelay::set_modulator_filter_coeffs(float gain, float fc, float width) +void AudioEffectModulatedDelay::set_modulator_filter_coeffs(void) { // modulator filter - // coefficients calculated with "IOWA Hills IIR Filter Designer 6.5", http://www.iowahills.com/8DownloadPage.html + // "IOWA Hills IIR Filter Designer 6.5", http://www.iowahills.com/8DownloadPage.html // Example: https://web.fhnw.ch/technik/projekte/eit/Fruehling2016/MuelZum/html/parametric_equalizer_example_8c-example.html - - /* float32_t A = sqrt(powf(10, gain / 20.0f)); - float32_t w0 = 2.0f * PI * fc / ((float32_t)AUDIO_SAMPLE_RATE_EXACT); - float32_t cosw0 = cosf(w0); - float32_t sinw0 = sinf(w0); - float32_t alpha = sinw0 / (2.0f * width); - float32_t a0 = 1.0f + alpha / A; - - modulator_filter_coeffs[0] = (1.0f + alpha * A) / a0; // b0 - modulator_filter_coeffs[1] = (-2.0f * cosw0) / a0; // b1 - modulator_filter_coeffs[2] = (1.0f - alpha * A) / a0; // b2 - modulator_filter_coeffs[3] = -(2.0f * cosw0) / -a0; // -a1 - modulator_filter_coeffs[4] = (1.0f - alpha / A) / -a0; // -a2 */ - - // OmegaC = 0.1, SR = 44117.64706, Fc = 2.21 kHz, N=2 - modulator_filter_coeffs[0] = 0.020727217357494492; // b0 - modulator_filter_coeffs[1] = 0.020727217357494492; // b1 - modulator_filter_coeffs[2] = 0.020727217357494492; // b2 - modulator_filter_coeffs[3] = 1.563046149664217620; // -a1 - modulator_filter_coeffs[4] = -0.642749223719756180; // -a2 + // Coeeficients calculated with https://arachnoid.com/BiQuadDesigner/index.html + + // SR = 44110, Fc = 400 Hz; Q=0.707 + modulator_filter_coeffs[0] = 7.80321719e-4; // b0 + modulator_filter_coeffs[1] = 0.00156064; // b1 + modulator_filter_coeffs[2] = 7.80321719e-4; // b2 + modulator_filter_coeffs[3] = 1.91943335; // -a1 + modulator_filter_coeffs[4] = -0.92255463; // -a2 } void AudioEffectModulatedDelay::update(void) @@ -116,7 +104,7 @@ void AudioEffectModulatedDelay::update(void) bp = block->data; arm_q15_to_float(modulation->data, modulation_f32, AUDIO_BLOCK_SAMPLES); - //arm_biquad_cascade_df1_f32(&modulator_filter_data, modulation_f32, modulation_f32, AUDIO_BLOCK_SAMPLES); + arm_biquad_cascade_df1_f32(&modulator_filter_data, modulation_f32, modulation_f32, AUDIO_BLOCK_SAMPLES); mp = modulation_f32; for (uint16_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++) @@ -131,9 +119,9 @@ void AudioEffectModulatedDelay::update(void) 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 - cb_mod_index = (_cb_index - (_delay_offset + int(mod_index))); - if (cb_mod_index >= _delay_length) - cb_mod_index -= _delay_length; + cb_mod_index = (_cb_index - (_delay_offset + mod_number)); + /* if (cb_mod_index >= _delay_length) + cb_mod_index -= _delay_length; */ if (cb_mod_index < 0) // check for negative offsets and correct them cb_mod_index += _delay_length; @@ -143,6 +131,7 @@ void AudioEffectModulatedDelay::update(void) cb_mod_index_neighbor = _delay_length; else cb_mod_index_neighbor = cb_mod_index - 1; + *bp = round(float(_delayline[cb_mod_index]) * mod_fraction + float(_delayline[cb_mod_index_neighbor]) * (1.0 - mod_fraction)); } else { @@ -150,13 +139,9 @@ void AudioEffectModulatedDelay::update(void) cb_mod_index_neighbor = 0; else cb_mod_index_neighbor = cb_mod_index + 1; - } - - if (*mp < 0.0) - *bp = round(float(_delayline[cb_mod_index]) * mod_fraction + float(_delayline[cb_mod_index_neighbor]) * (1.0 - mod_fraction)); - else *bp = round(float(_delayline[cb_mod_index_neighbor]) * mod_fraction + float(_delayline[cb_mod_index]) * (1.0 - mod_fraction)); - + } + // push the pointers forward bp++; // next audio data mp++; // next modulation data diff --git a/effect_modulated_delay.h b/effect_modulated_delay.h index c882ec4..9ded4a1 100644 --- a/effect_modulated_delay.h +++ b/effect_modulated_delay.h @@ -49,7 +49,7 @@ class AudioEffectModulatedDelay : virtual float offset(float offset_value); private: - void set_modulator_filter_coeffs(float gain, float fc, float width); + void set_modulator_filter_coeffs(void); audio_block_t *inputQueueArray[2]; int16_t *_delayline; // pointer for the circular buffer uint16_t _cb_index; // current write pointer of the circular buffer @@ -57,7 +57,7 @@ class AudioEffectModulatedDelay : 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 arm_biquad_casd_df1_inst_f32 modulator_filter_data; - float32_t modulator_filter_state; + float32_t modulator_filter_state[4]; float32_t modulator_filter_coeffs[5]; };