Hopefully fixed the modulated delay.

master
Holger Wirtz 5 years ago
parent 81ce42ec63
commit 7ece8305b4
  1. 89
      DCfilter.h
  2. 16
      MicroMDAEPiano.ino
  3. 44
      OnePoleLP.h
  4. 6
      config.h
  5. 87
      effect_modulated_delay.cpp
  6. 8
      effect_modulated_delay.h

@ -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

@ -57,8 +57,6 @@ AudioAmplifier inverter;
AudioEffectModulatedDelay modchorus_r; AudioEffectModulatedDelay modchorus_r;
AudioEffectModulatedDelay modchorus_l; AudioEffectModulatedDelay modchorus_l;
AudioSynthWaveform modulator; AudioSynthWaveform modulator;
//AudioFilterStateVariable chorus_filter_r;
//AudioFilterStateVariable chorus_filter_l;
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);
@ -70,10 +68,6 @@ AudioConnection patchCord9(modulator, inverter);
AudioConnection patchCord10(inverter, 0, modchorus_l, 1); AudioConnection patchCord10(inverter, 0, modchorus_l, 1);
AudioConnection patchCord11(queue_r, 0, mixer_r, 0); AudioConnection patchCord11(queue_r, 0, mixer_r, 0);
AudioConnection patchCord12(queue_l, 0, mixer_l, 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 patchCord15(modchorus_r, 0, mixer_r, 2);
AudioConnection patchCord16(modchorus_l, 0, mixer_l, 2); AudioConnection patchCord16(modchorus_l, 0, mixer_l, 2);
AudioConnection patchCord17(freeverb_r, 0, mixer_r, 1); AudioConnection patchCord17(freeverb_r, 0, mixer_r, 1);
@ -235,19 +229,15 @@ void setup()
} }
// chorus modulation fixed // chorus modulation fixed
modulator.begin(CHORUS_WAVEFORM_MOD); modulator.begin(WAVEFORM_MOD);
modulator.phase(0); modulator.phase(0);
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)
//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_r.offset(15.0);
modchorus_l.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) // internal mixing of original signal(0), reverb(1) and chorus(2)
mixer_r.gain(VOL_MAIN, 0.5); mixer_r.gain(VOL_MAIN, 0.5);

@ -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

@ -55,8 +55,8 @@
#define REDUCE_LOUDNESS 0 #define REDUCE_LOUDNESS 0
#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 (16*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 WAVEFORM_MOD WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE
//************************************************************************************************* //*************************************************************************************************
//* DEBUG OUTPUT SETTINGS //* DEBUG OUTPUT SETTINGS
//************************************************************************************************* //*************************************************************************************************
@ -133,7 +133,7 @@
//* DO NO CHANGE ANYTHING BEYOND IF YOU DON'T KNOW WHAT YOU ARE DOING !!! //* 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))) #define MAX_SOUNDS min(99,int((4096-EEPROM_CONFIGURATIONS)/sizeof(config_t)))

@ -29,6 +29,8 @@
extern config_t configuration; 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 // 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) boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length)
{ {
#if 0 #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.print(d_length);
Serial.println(F(")")); Serial.println(F(")"));
#endif #endif
@ -49,6 +51,8 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length)
_delay_length = 0; _delay_length = 0;
_delay_offset = 0.0; _delay_offset = 0.0;
_cb_index = 0; _cb_index = 0;
_feedback = 0.0;
_feedback_value = 0;
if (delayline == NULL) { if (delayline == NULL) {
return (false); return (false);
@ -61,44 +65,31 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length)
_delay_length = d_length; _delay_length = d_length;
memset(_delayline, 0, d_length); memset(_delayline, 0, d_length);
set_modulator_filter_coeffs();
modulator_filter_data = {1, modulator_filter_state, modulator_filter_coeffs};
return (true); return (true);
} }
void AudioEffectModulatedDelay::set_modulator_filter_coeffs(void) float AudioEffectModulatedDelay::offset(float offset_value) // in ms
{ {
// modulator filter uint16_t offset_frames = floor((offset_value / 1000) * AUDIO_SAMPLE_RATE);
// "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 if (offset_frames > round(_delay_length * (1 - (MODULATION_MAX_FACTOR / 2))))
// Coeeficients calculated with https://arachnoid.com/BiQuadDesigner/index.html _delay_offset = floor(_delay_length * (1 - (MODULATION_MAX_FACTOR / 2)));
else if (offset_frames <= round(_delay_length * (MODULATION_MAX_FACTOR / 2)))
double frequency = 20.0; _delay_offset = floor(_delay_length * (MODULATION_MAX_FACTOR) / 2);
double q = 0.1; else
_delay_offset = offset_frames;
// low-pass
double w0 = frequency * (2 * M_PI / AUDIO_SAMPLE_RATE_EXACT); return (floor(offset_frames / AUDIO_SAMPLE_RATE * 1000));
double sinW0 = sin(w0); }
double alpha = sinW0 / ((double)q * 2.0);
double cosW0 = cos(w0); void AudioEffectModulatedDelay::feedback(float feedback_level)
//double scale = 1073741824.0 / (1.0 + alpha); // for integers {
double scale = 1.0 / (1.0 + alpha); if (feedback_level < 0.0)
feedback_level = 0.0;
modulator_filter_coeffs[0] = ((1.0 - cosW0) / 2.0) * scale; // b0 else if (feedback_level > 1.0)
modulator_filter_coeffs[1] = (1.0 - cosW0) * scale; // b1 feedback_level = 1.0;
modulator_filter_coeffs[2] = modulator_filter_coeffs[0]; // b2
modulator_filter_coeffs[3] = (2.0 * cosW0) * scale; // -a1 _feedback = feedback_level / 2;
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
*/
} }
void AudioEffectModulatedDelay::update(void) void AudioEffectModulatedDelay::update(void)
@ -124,7 +115,6 @@ 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);
arm_biquad_cascade_df1_f32(&modulator_filter_data, modulation_f32, modulation_f32, AUDIO_BLOCK_SAMPLES);
mp = modulation_f32; mp = modulation_f32;
for (uint16_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++) for (uint16_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
@ -132,10 +122,10 @@ void AudioEffectModulatedDelay::update(void)
// write data into circular buffer (delayline) // write data into circular buffer (delayline)
if (_cb_index >= _delay_length) if (_cb_index >= _delay_length)
_cb_index = 0; _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 // 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 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 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
@ -143,10 +133,10 @@ void AudioEffectModulatedDelay::update(void)
if (cb_mod_index < 0) // check for negative offsets and correct them if (cb_mod_index < 0) // check for negative offsets and correct them
cb_mod_index += _delay_length; cb_mod_index += _delay_length;
if (cb_mod_index == 0) if (cb_mod_index == _delay_length - 1)
cb_mod_index_neighbor = _delay_length; cb_mod_index_neighbor = 0;
else 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)); *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); 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));
}

@ -28,8 +28,6 @@
#include "AudioStream.h" #include "AudioStream.h"
#include "config.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 // 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
@ -47,6 +45,7 @@ class AudioEffectModulatedDelay :
boolean begin(short *delayline, int delay_length); boolean begin(short *delayline, int delay_length);
virtual void update(void); virtual void update(void);
virtual float offset(float offset_value); virtual float offset(float offset_value);
virtual void feedback(float feedback_value);
private: private:
void set_modulator_filter_coeffs(void); 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 _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_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 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 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 #endif

Loading…
Cancel
Save