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.
master
Holger Wirtz 5 years ago
parent 9cad9262d5
commit a06ebe76fe
  1. 9
      MicroMDAEPiano.ino
  2. 5
      config.h
  3. 59
      effect_modulated_delay.cpp
  4. 19
      effect_modulated_delay.h

@ -57,14 +57,16 @@ AudioAmplifier inverter;
AudioEffectModulatedDelay modchorus_r; AudioEffectModulatedDelay modchorus_r;
AudioEffectModulatedDelay modchorus_l; AudioEffectModulatedDelay modchorus_l;
AudioSynthWaveform modulator; AudioSynthWaveform modulator;
AudioFilterStateVariable modulator_filter;
AudioConnection patchCord0(queue_r, peak_r); AudioConnection patchCord0(queue_r, peak_r);
AudioConnection patchCord1(queue_l, peak_l); AudioConnection patchCord1(queue_l, peak_l);
AudioConnection patchCord2(queue_r, freeverb_r); AudioConnection patchCord2(queue_r, freeverb_r);
AudioConnection patchCord3(queue_l, freeverb_l); AudioConnection patchCord3(queue_l, freeverb_l);
AudioConnection patchCord4(queue_r, 0, modchorus_r, 0); AudioConnection patchCord4(queue_r, 0, modchorus_r, 0);
AudioConnection patchCord5(queue_l, 0, modchorus_l, 0); AudioConnection patchCord5(queue_l, 0, modchorus_l, 0);
AudioConnection patchCord6(modulator, 0, modchorus_r, 1); AudioConnection patchCord6(modulator, 0, modulator_filter, 1);
AudioConnection patchCord8(modulator, inverter); AudioConnection patchCord7(modulator_filter, 0, modchorus_r, 1);
AudioConnection patchCord8(modulator_filter, 0, inverter, 0);
AudioConnection patchCord9(inverter, 0, modchorus_l, 1); AudioConnection patchCord9(inverter, 0, modchorus_l, 1);
AudioConnection patchCord10(queue_r, 0, mixer_r, 0); AudioConnection patchCord10(queue_r, 0, mixer_r, 0);
AudioConnection patchCord11(queue_l, 0, mixer_l, 0); AudioConnection patchCord11(queue_l, 0, mixer_l, 0);
@ -234,6 +236,9 @@ void setup()
modulator.amplitude(1.0); modulator.amplitude(1.0);
modulator.offset(0.0); modulator.offset(0.0);
inverter.gain(-1.0); // change phase for second modulated delay (faked stereo mode) 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_r.offset(15.0);
modchorus_l.offset(15.0); modchorus_l.offset(15.0);

@ -56,10 +56,7 @@
#define USE_XFADE_DATA 1 #define USE_XFADE_DATA 1
// CHORUS parameters // CHORUS parameters
#define CHORUS_DELAY_LENGTH_SAMPLES (15*AUDIO_BLOCK_SAMPLES) // one AUDIO_BLOCK_SAMPLES = 2.902ms #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_WAVEFORM WAVEFORM_SINE // 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
//************************************************************************************************* //*************************************************************************************************
//* DEBUG OUTPUT SETTINGS //* DEBUG OUTPUT SETTINGS
//************************************************************************************************* //*************************************************************************************************

@ -46,7 +46,7 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length)
_delayline = NULL; _delayline = NULL;
_delay_length = 0; _delay_length = 0;
_delay_offset = 0.0; _delay_offset = 0.0;
_circ_idx = 0; _cb_index = 0;
if (delayline == NULL) { if (delayline == NULL) {
return (false); return (false);
@ -58,17 +58,6 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length)
_delayline = delayline; _delayline = delayline;
_delay_length = d_length; _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); return (true);
} }
@ -87,7 +76,7 @@ void AudioEffectModulatedDelay::update(void)
{ {
int16_t *bp; int16_t *bp;
float *mp; float *mp;
float mod_idx; float mod_index;
float mod_number; float mod_number;
float mod_fraction; float mod_fraction;
float modulation_f32[AUDIO_BLOCK_SAMPLES]; float modulation_f32[AUDIO_BLOCK_SAMPLES];
@ -95,51 +84,29 @@ void AudioEffectModulatedDelay::update(void)
bp = block->data; bp = block->data;
arm_q15_to_float(modulation->data, modulation_f32, AUDIO_BLOCK_SAMPLES); arm_q15_to_float(modulation->data, modulation_f32, AUDIO_BLOCK_SAMPLES);
mp = modulation_f32; 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++) for (uint16_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
{ {
// write data into circular buffer (delayline) // write data into circular buffer (delayline)
if (_circ_idx >= _delay_length) if (_cb_index >= _delay_length)
_circ_idx = 0; _cb_index = 0;
_delayline[_circ_idx] = *bp; _delayline[_cb_index] = *bp;
// Calculate the modulation-index as a floating point number for interpolation // Calculate the modulation-index as a floating point number for interpolation
mod_idx = *mp * (1 - MODULATION_MAX_FACTOR) * _delay_length; 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_idx, &mod_number); 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 // calculate modulation index into circular buffer
c_mod_idx = (_circ_idx - _delay_offset - int(mod_number)) % _delay_length; cb_mod_index = (_cb_index - (_delay_offset + int(mod_index))) % _delay_length;
if (c_mod_idx < 0) // check for negative offsets and correct them if (cb_mod_index < 0) // check for negative offsets and correct them
c_mod_idx += _delay_length; cb_mod_index += _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);
*bp = round(float(_delayline[cb_mod_index]) * mod_fraction + float(_delayline[cb_mod_index + 1]) * (1.0 - mod_fraction));
// push the pointers forward // push the pointers forward
bp++; // next audio data bp++; // next audio data
mp++; // next modulation data mp++; // next modulation data
_circ_idx++; // next circular buffer index _cb_index++; // next circular buffer index
} }
} }

@ -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 // 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 // Written by Pete (El Supremo) Jan 2014
// 140219 - correct storage class (not static) // 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 : class AudioEffectModulatedDelay :
public AudioStream public AudioStream
@ -50,18 +50,11 @@ class AudioEffectModulatedDelay :
private: private:
audio_block_t *inputQueueArray[2]; audio_block_t *inputQueueArray[2];
int16_t *_delayline; int16_t *_delayline; // pointer for the circular buffer
uint16_t _circ_idx; uint16_t _cb_index; // current write pointer of the circular buffer
uint16_t _delay_offset; uint16_t _delay_offset; // number of samples for the read offset of the modulation inside the circular buffer
uint16_t _delay_length; uint16_t _delay_length; // calculated number of samples of the delay
int16_t c_mod_idx; int16_t cb_mod_index; // current read pointer with modulation for the circular buffer
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
}; };
#endif #endif

Loading…
Cancel
Save