From 7ece8305b4d75f26c8f115720dab5c7fe1a96189 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Fri, 6 Sep 2019 14:54:48 +0200 Subject: [PATCH] Hopefully fixed the modulated delay. --- DCfilter.h | 89 -------------------------------------- MicroMDAEPiano.ino | 16 ++----- OnePoleLP.h | 44 ------------------- config.h | 6 +-- effect_modulated_delay.cpp | 87 ++++++++++++++----------------------- effect_modulated_delay.h | 8 ++-- 6 files changed, 41 insertions(+), 209 deletions(-) delete mode 100644 DCfilter.h delete mode 100644 OnePoleLP.h diff --git a/DCfilter.h b/DCfilter.h deleted file mode 100644 index 2b2dde7..0000000 --- a/DCfilter.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * DCfilter.h - * - * Copyright 2012 Tim Barrass. - * - * This file is part of Mozzi. - * - * Mozzi is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. - * - */ - -#ifndef DCFILTER_H -#define DCFILTER_H - -/* -tb2010 adapted from: -robert bristow-johnson, DSP Trick: Fixed-Point DC Blocking Filter with Noise-Shaping -http://www.dspguru.com/book/export/html/126 - -y[n] = x[n] - x[n-1] + a * y[n-1] - -Where y[n] is the output at the current time n, and x[n] is the input at the current time n. - -also, see DC Blocker Algorithms, http://www.ingelec.uns.edu.ar/pds2803/materiales/articulos/04472252.pdf - */ - -/** -A DC-blocking filter useful for highlighting changes in control signals. -The output of the filter settles to 0 if the incoming signal stays constant. If the input changes, the -filter output swings to track the change and eventually settles back to 0. -*/ -class DCfilter -{ -public: -/** -Instantiate a DC-blocking filter. -@param pole sets the responsiveness of the filter, -how long it takes to settle to 0 if the input signal levels out at a constant value. -*/ - DCfilter(float pole):acc(0),prev_x(0),prev_y(0) - { - A = (int)(32768.0*(1.0 - pole)); - } - -/* almost original - // timing: 20us - int next(int x) - { - setPin13High(); - acc -= prev_x; - prev_x = (long)x<<15; - acc += prev_x; - acc -= A*prev_y; - prev_y = acc>>15; // quantization happens here - int filtered = (int)prev_y; - // acc has y[n] in upper 17 bits and -e[n] in lower 15 bits - setPin13Low(); - return filtered; - } - */ - - /** - Filter the incoming value and return the result. - @param x the value to filter - @return filtered signal - */ - // timing :8us - inline - int next(int x) - { - acc += ((long)(x-prev_x)<<16)>>1; - prev_x = x; - acc -= (long)A*prev_y; // acc has y[n] in upper 17 bits and -e[n] in lower 15 bits - prev_y = (acc>>16)<<1; // faster than >>15 but loses bit 0 - if (acc & 32784) prev_y += 1; // adds 1 if it was in the 0 bit position lost in the shifts above - return prev_y; - } - -private: - long acc; - int prev_x, prev_y,A; -}; - -/** -@example 05.Control_Filters/DCFilter/DCFilter.ino -This example demonstrates the DCFilter class. -*/ - -#endif // #ifndef DCFILTER_H diff --git a/MicroMDAEPiano.ino b/MicroMDAEPiano.ino index 02518f0..29e1390 100644 --- a/MicroMDAEPiano.ino +++ b/MicroMDAEPiano.ino @@ -57,8 +57,6 @@ AudioAmplifier inverter; AudioEffectModulatedDelay modchorus_r; AudioEffectModulatedDelay modchorus_l; AudioSynthWaveform modulator; -//AudioFilterStateVariable chorus_filter_r; -//AudioFilterStateVariable chorus_filter_l; AudioConnection patchCord0(queue_r, peak_r); AudioConnection patchCord1(queue_l, peak_l); AudioConnection patchCord2(queue_r, freeverb_r); @@ -70,10 +68,6 @@ 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); -//AudioConnection patchCord13(modchorus_r, chorus_filter_r); -//AudioConnection patchCord14(modchorus_l, chorus_filter_l); -//AudioConnection patchCord15(chorus_filter_r, 0, mixer_r, 2); -//AudioConnection patchCord16(chorus_filter_l, 0, mixer_l, 2); AudioConnection patchCord15(modchorus_r, 0, mixer_r, 2); AudioConnection patchCord16(modchorus_l, 0, mixer_l, 2); AudioConnection patchCord17(freeverb_r, 0, mixer_r, 1); @@ -235,19 +229,15 @@ void setup() } // chorus modulation fixed - modulator.begin(CHORUS_WAVEFORM_MOD); + modulator.begin(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(1); - //chorus_filter_l.frequency(3500); - //chorus_filter_l.resonance(0.7); - //chorus_filter_l.octaveControl(1); modchorus_r.offset(15.0); modchorus_l.offset(15.0); + modchorus_r.feedback(0.25); + modchorus_l.feedback(0.25); // internal mixing of original signal(0), reverb(1) and chorus(2) mixer_r.gain(VOL_MAIN, 0.5); diff --git a/OnePoleLP.h b/OnePoleLP.h deleted file mode 100644 index c0ea171..0000000 --- a/OnePoleLP.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - ============================================================================== - This file is part of Tal-NoiseMaker by Patrick Kunz. - - Copyright(c) 2005-2010 Patrick Kunz, TAL - Togu Audio Line, Inc. - http://kunz.corrupt.ch - - This file may be licensed under the terms of of the - GNU General Public License Version 2 (the ``GPL''). - - Software distributed under the License is distributed - on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either - express or implied. See the GPL for the specific language - governing rights and limitations. - - You should have received a copy of the GPL along with this - program. If not, go to http://www.gnu.org/licenses/gpl.html - or write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - ============================================================================== - */ - -#if !defined(__OnePoleLP_h) -#define __OnePoleLP_h - -class OnePoleLP { -public: - float inputs, outputs, lastOutput; - - OnePoleLP() { - lastOutput = inputs = outputs = 0.0f; - } - - ~OnePoleLP() {} - - void tick(float *sample, float cutoff) { - float p = (cutoff * 0.98f) * (cutoff * 0.98f) * (cutoff * 0.98f) * (cutoff * 0.98f); - outputs = (1.0f - p) * (*sample) + p * outputs; - *sample = outputs; - } -}; - -#endif diff --git a/config.h b/config.h index a801768..522584c 100644 --- a/config.h +++ b/config.h @@ -55,8 +55,8 @@ #define REDUCE_LOUDNESS 0 #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_MOD WAVEFORM_SINE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE +#define CHORUS_DELAY_LENGTH_SAMPLES (16*AUDIO_BLOCK_SAMPLES) // one AUDIO_BLOCK_SAMPLES = 2.902ms +#define WAVEFORM_MOD WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE //************************************************************************************************* //* DEBUG OUTPUT SETTINGS //************************************************************************************************* @@ -133,7 +133,7 @@ //* DO NO CHANGE ANYTHING BEYOND IF YOU DON'T KNOW WHAT YOU ARE DOING !!! //************************************************************************************************* -#define MICRO_MDAEPIANO_VERSION "0.9.5" +#define MICRO_MDAEPIANO_VERSION "0.9.6" #define MAX_SOUNDS min(99,int((4096-EEPROM_CONFIGURATIONS)/sizeof(config_t))) diff --git a/effect_modulated_delay.cpp b/effect_modulated_delay.cpp index 8688394..7298a7b 100644 --- a/effect_modulated_delay.cpp +++ b/effect_modulated_delay.cpp @@ -29,6 +29,8 @@ extern config_t configuration; +#define MODULATION_MAX_FACTOR 0.5 // Not sure to put this into a var? + /******************************************************************/ // Based on; A u d i o E f f e c t D e l a y @@ -40,7 +42,7 @@ extern config_t configuration; boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length) { #if 0 - Serial.print(F("AudioEffectModulatedDelay.begin(Chorus delay line length = ")); + Serial.print(F("AudioEffectModulatedDelay.begin(modulated-delay line length = ")); Serial.print(d_length); Serial.println(F(")")); #endif @@ -49,6 +51,8 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length) _delay_length = 0; _delay_offset = 0.0; _cb_index = 0; + _feedback = 0.0; + _feedback_value = 0; if (delayline == NULL) { return (false); @@ -61,44 +65,31 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length) _delay_length = d_length; memset(_delayline, 0, d_length); - set_modulator_filter_coeffs(); - modulator_filter_data = {1, modulator_filter_state, modulator_filter_coeffs}; - return (true); } -void AudioEffectModulatedDelay::set_modulator_filter_coeffs(void) +float AudioEffectModulatedDelay::offset(float offset_value) // in ms +{ + uint16_t offset_frames = floor((offset_value / 1000) * AUDIO_SAMPLE_RATE); + + if (offset_frames > round(_delay_length * (1 - (MODULATION_MAX_FACTOR / 2)))) + _delay_offset = floor(_delay_length * (1 - (MODULATION_MAX_FACTOR / 2))); + else if (offset_frames <= round(_delay_length * (MODULATION_MAX_FACTOR / 2))) + _delay_offset = floor(_delay_length * (MODULATION_MAX_FACTOR) / 2); + else + _delay_offset = offset_frames; + + return (floor(offset_frames / AUDIO_SAMPLE_RATE * 1000)); +} + +void AudioEffectModulatedDelay::feedback(float feedback_level) { - // modulator filter - // "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 - // Coeeficients calculated with https://arachnoid.com/BiQuadDesigner/index.html - - double frequency = 20.0; - double q = 0.1; - - // low-pass - double w0 = frequency * (2 * M_PI / AUDIO_SAMPLE_RATE_EXACT); - double sinW0 = sin(w0); - double alpha = sinW0 / ((double)q * 2.0); - double cosW0 = cos(w0); - //double scale = 1073741824.0 / (1.0 + alpha); // for integers - double scale = 1.0 / (1.0 + alpha); - - modulator_filter_coeffs[0] = ((1.0 - cosW0) / 2.0) * scale; // b0 - modulator_filter_coeffs[1] = (1.0 - cosW0) * scale; // b1 - modulator_filter_coeffs[2] = modulator_filter_coeffs[0]; // b2 - modulator_filter_coeffs[3] = (2.0 * cosW0) * scale; // -a1 - modulator_filter_coeffs[4] = (-1.0 - alpha) * scale; // -a2 - - /* - // SR = 44110, Fc = 20 Hz; Q=0.707 - modulator_filter_coeffs[0] = 5.06973332e-7; // b0 - modulator_filter_coeffs[1] = 1.01394666e-6; // b1 - modulator_filter_coeffs[2] = modulator_filter_coeffs[0]; // b2 - modulator_filter_coeffs[3] = 1.99798478; // -a1 - modulator_filter_coeffs[4] = -0.99798681; // -a2 - */ + if (feedback_level < 0.0) + feedback_level = 0.0; + else if (feedback_level > 1.0) + feedback_level = 1.0; + + _feedback = feedback_level / 2; } void AudioEffectModulatedDelay::update(void) @@ -124,7 +115,6 @@ 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); mp = modulation_f32; for (uint16_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++) @@ -132,10 +122,10 @@ void AudioEffectModulatedDelay::update(void) // write data into circular buffer (delayline) if (_cb_index >= _delay_length) _cb_index = 0; - _delayline[_cb_index] = *bp; + _delayline[_cb_index] = (*bp * (1.0 - _feedback)) + (_feedback_value * _feedback); - // Calculate the modulation-index as a floating point number for interpolation - 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 + // calculate the modulation-index as a floating point number for interpolation + mod_index = *mp * MODULATION_MAX_FACTOR * _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 @@ -143,10 +133,10 @@ void AudioEffectModulatedDelay::update(void) if (cb_mod_index < 0) // check for negative offsets and correct them cb_mod_index += _delay_length; - if (cb_mod_index == 0) - cb_mod_index_neighbor = _delay_length; + if (cb_mod_index == _delay_length - 1) + cb_mod_index_neighbor = 0; else - cb_mod_index_neighbor = cb_mod_index - 1; + 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)); @@ -166,16 +156,3 @@ void AudioEffectModulatedDelay::update(void) release(block); } } - -float AudioEffectModulatedDelay::offset(float offset_value) // in ms -{ - uint16_t offset_frames = floor((offset_value / 1000) * AUDIO_SAMPLE_RATE); - if (offset_frames > round( _delay_length * MODULATION_MAX_FACTOR)) - _delay_offset = floor(_delay_length * MODULATION_MAX_FACTOR); - else if (offset_frames <= round(_delay_length * (1 - MODULATION_MAX_FACTOR))) - _delay_offset = floor(_delay_length * (1 - MODULATION_MAX_FACTOR)); - else - _delay_offset = offset_frames; - - return (floor(offset_frames / AUDIO_SAMPLE_RATE * 1000)); -} diff --git a/effect_modulated_delay.h b/effect_modulated_delay.h index 9ded4a1..33e431b 100644 --- a/effect_modulated_delay.h +++ b/effect_modulated_delay.h @@ -28,8 +28,6 @@ #include "AudioStream.h" #include "config.h" -#define MODULATION_MAX_FACTOR 0.75 - /*************************************************************************/ // 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 @@ -47,6 +45,7 @@ class AudioEffectModulatedDelay : boolean begin(short *delayline, int delay_length); virtual void update(void); virtual float offset(float offset_value); + virtual void feedback(float feedback_value); private: void set_modulator_filter_coeffs(void); @@ -55,10 +54,9 @@ class AudioEffectModulatedDelay : 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 + float32_t _feedback; + int16_t _feedback_value; 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[4]; - float32_t modulator_filter_coeffs[5]; }; #endif