Added modulated_delay as chorus.

Added reverb.
Extended delay as stereo delay.
Small fixes.
pull/3/head
Holger Wirtz 5 years ago
parent f59d810343
commit 95f5334a58
  1. 172
      MicroDexed.ino
  2. 2
      UI.hpp
  3. 22
      config.h
  4. 134
      effect_modulated_delay.cpp
  5. 58
      effect_modulated_delay.h

@ -35,41 +35,87 @@
#include "midi_devices.hpp" #include "midi_devices.hpp"
#include "dexed.h" #include "dexed.h"
#include "dexed_sysex.h" #include "dexed_sysex.h"
#include "effect_modulated_delay.h"
#include "PluginFx.h" #include "PluginFx.h"
AudioPlayQueue queue1; AudioPlayQueue dexed1;
AudioAnalyzePeak peak1; AudioAnalyzePeak peak1;
AudioEffectDelay delay1; AudioEffectDelay delay_r;
AudioMixer4 mixer1; AudioEffectDelay delay_l;
AudioMixer4 mixer2; AudioEffectFreeverb freeverb_r;
AudioEffectFreeverb freeverb_l;
AudioEffectModulatedDelay modchorus_r;
AudioEffectModulatedDelay modchorus_l;
#if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT
AudioFilterBiquad modchorus_filter_r;
AudioFilterBiquad modchorus_filter_l;
#endif
AudioSynthWaveform modulator;
AudioAmplifier inverter;
AudioMixer4 chorus_mixer_r;
AudioMixer4 chorus_mixer_l;
AudioMixer4 delay_mixer_r;
AudioMixer4 delay_mixer_l;
AudioMixer4 delay_fb_mixer_r;
AudioMixer4 delay_fb_mixer_l;
AudioMixer4 reverb_mixer_r;
AudioMixer4 reverb_mixer_l;
AudioAmplifier volume_r; AudioAmplifier volume_r;
AudioAmplifier volume_l; AudioAmplifier volume_l;
AudioOutputUSB usb1; AudioOutputUSB usb1;
AudioConnection patchCord0(queue1, peak1); AudioConnection patchCord0(dexed1, peak1);
AudioConnection patchCord1(queue1, 0, mixer1, 0); AudioConnection patchCord1(dexed1, 0, chorus_mixer_r, 0);
AudioConnection patchCord2(queue1, 0, mixer2, 0); AudioConnection patchCord2(dexed1, 0, chorus_mixer_l, 0);
AudioConnection patchCord3(delay1, 0, mixer1, 1); AudioConnection patchCord3(dexed1, 0, delay_mixer_r, 0);
AudioConnection patchCord4(delay1, 0, mixer2, 2); AudioConnection patchCord4(dexed1, 0, delay_mixer_l, 0);
AudioConnection patchCord5(mixer1, delay1); AudioConnection patchCord5(dexed1, 0, delay_fb_mixer_r, 0);
AudioConnection patchCord6(mixer1, 0, mixer2, 1); AudioConnection patchCord6(dexed1, 0, delay_fb_mixer_l, 0);
AudioConnection patchCord7(mixer2, volume_r); AudioConnection patchCord7(dexed1, 0, reverb_mixer_r, 0);
AudioConnection patchCord8(mixer2, volume_l); AudioConnection patchCord8(dexed1, 0, reverb_mixer_l, 0);
AudioConnection patchCord9(mixer2, 0, usb1, 0); AudioConnection patchCord9(dexed1, 0, modchorus_r, 0);
AudioConnection patchCord10(mixer2, 0, usb1, 1); AudioConnection patchCord10(dexed1, 0, modchorus_l, 0);
AudioConnection patchCord11(modulator, 0, modchorus_r, 1);
AudioConnection patchCord12(modulator, inverter);
AudioConnection patchCord13(inverter, 0, modchorus_l, 1);
#if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT
AudioConnection patchCord14(modchorus_r, modchorus_filter_r);
AudioConnection patchCord15(modchorus_l, modchorus_filter_l);
AudioConnection patchCord16(modchorus_filter_r, 0, chorus_mixer_r, 1);
AudioConnection patchCord17(modchorus_filter_l, 0, chorus_mixer_l, 1);
#else
AudioConnection patchCord14(modchorus_r, 0, chorus_mixer_r, 1);
AudioConnection patchCord15(modchorus_l, 0, chorus_mixer_l, 1);
#endif
AudioConnection patchCord18(chorus_mixer_r, 0, delay_mixer_r, 1);
AudioConnection patchCord19(chorus_mixer_l, 0, delay_mixer_l, 1);
AudioConnection patchCord20(delay_fb_mixer_r, 0, delay_mixer_r, 1);
AudioConnection patchCord21(delay_fb_mixer_l, 0, delay_mixer_l, 1);
AudioConnection patchCord22(delay_mixer_r, 0, reverb_mixer_r, 1);
AudioConnection patchCord23(delay_mixer_l, 0, reverb_mixer_l, 1);
AudioConnection patchCord24(delay_r, 0, delay_mixer_r, 2);
AudioConnection patchCord25(delay_l, 0, delay_mixer_l, 2);
AudioConnection patchCord26(delay_fb_mixer_r, delay_r);
AudioConnection patchCord27(delay_fb_mixer_l, delay_l);
AudioConnection patchCord28(freeverb_r, 0, reverb_mixer_r, 1);
AudioConnection patchCord29(freeverb_l, 0, reverb_mixer_l, 1);
AudioConnection patchCord30(reverb_mixer_r, volume_r);
AudioConnection patchCord31(reverb_mixer_l, volume_l);
AudioConnection patchCord32(volume_r, 0, usb1, 0);
AudioConnection patchCord33(volume_l, 0, usb1, 1);
#if defined(TEENSY_AUDIO_BOARD) #if defined(TEENSY_AUDIO_BOARD)
AudioOutputI2S i2s1; AudioOutputI2S i2s1;
AudioConnection patchCord11(volume_r, 0, i2s1, 0); AudioConnection patchCord34(volume_r, 0, i2s1, 0);
AudioConnection patchCord12(volume_l, 0, i2s1, 1); AudioConnection patchCord35(volume_l, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1; AudioControlSGTL5000 sgtl5000_1;
#elif defined(TGA_AUDIO_BOARD) #elif defined(TGA_AUDIO_BOARD)
AudioOutputI2S i2s1; AudioOutputI2S i2s1;
AudioConnection patchCord11(volume_r, 0, i2s1, 0); AudioConnection patchCord34(volume_r, 0, i2s1, 0);
AudioConnection patchCord12(volume_l, 0, i2s1, 1); AudioConnection patchCord35(volume_l, 0, i2s1, 1);
AudioControlWM8731master wm8731_1; AudioControlWM8731master wm8731_1;
#else #else
AudioOutputPT8211 pt8211_1; AudioOutputPT8211 pt8211_1;
AudioConnection patchCord11(volume_r, 0, pt8211_1, 0); AudioConnection patchCord34(volume_r, 0, pt8211_1, 0);
AudioConnection patchCord12(volume_l, 0, pt8211_1, 1); AudioConnection patchCord35(volume_l, 0, pt8211_1, 1);
#endif #endif
Dexed* dexed = new Dexed(SAMPLE_RATE); Dexed* dexed = new Dexed(SAMPLE_RATE);
@ -106,6 +152,10 @@ value_change_t soften_volume = {0.0, 0};
value_change_t soften_filter_res = {0.0, 0}; value_change_t soften_filter_res = {0.0, 0};
value_change_t soften_filter_cut = {0.0, 0}; value_change_t soften_filter_cut = {0.0, 0};
// Allocate the delay lines for left and right channels
short l_delayline[MOD_DELAY_SAMPLE_BUFFER];
short r_delayline[MOD_DELAY_SAMPLE_BUFFER];
#ifdef ENABLE_LCD_UI #ifdef ENABLE_LCD_UI
/*********************************************************************** /***********************************************************************
LCDMenuLib2 LCDMenuLib2
@ -247,13 +297,63 @@ void setup()
} }
// Init effects // Init effects
////delay1.delay(0, mapfloat(effect_delay_feedback, 0, ENC_DELAY_TIME_STEPS, 0.0, DELAY_MAX_TIME)); if (!modchorus_r.begin(r_delayline, MOD_DELAY_SAMPLE_BUFFER)) {
// mixer1 is the feedback-adding mixer, mixer2 the whole delay (with/without feedback) mixer Serial.println(F("AudioEffectModulatedDelay - right channel begin failed"));
mixer1.gain(0, 1.0); // original signal while (1);
////mixer1.gain(1, mapfloat(effect_delay_feedback, 0, ENC_DELAY_FB_STEPS, 0.0, 1.0)); // amount of feedback }
////mixer2.gain(0, 1.0 - mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // original signal if (!modchorus_l.begin(l_delayline, MOD_DELAY_SAMPLE_BUFFER)) {
////mixer2.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delayed signal (including feedback) Serial.println(F("AudioEffectModulatedDelay - left channel begin failed"));
////mixer2.gain(2, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // only delayed signal (without feedback) while (1);
}
#ifdef DEBUG
Serial.print(F("MOD_DELAY_SAMPLE_BUFFER="));
Serial.print(MOD_DELAY_SAMPLE_BUFFER, DEC);
Serial.println(F(" samples"));
#endif
modulator.begin(MOD_WAVEFORM);
modulator.phase(0);
modulator.amplitude(0.5);
modulator.offset(0.0);
#if MOD_FILTER_OUTPUT == MOD_BUTTERWORTH_FILTER_OUTPUT
// Butterworth filter, 12 db/octave
modchorus_filter_r.setLowpass(0, MOD_FILTER_CUTOFF_HZ, 0.707);
modchorus_filter_l.setLowpass(0, MOD_FILTER_CUTOFF_HZ, 0.707);
#elif MOD_FILTER_OUTPUT == MOD_LINKWITZ_RILEY_FILTER_OUTPUT
// Linkwitz-Riley filter, 48 dB/octave
modchorus_filter_r.setLowpass(0, MOD_FILTER_CUTOFF_HZ, 0.54);
modchorus_filter_r.setLowpass(1, MOD_FILTER_CUTOFF_HZ, 1.3);
modchorus_filter_r.setLowpass(2, MOD_FILTER_CUTOFF_HZ, 0.54);
modchorus_filter_r.setLowpass(3, MOD_FILTER_CUTOFF_HZ, 1.3);
modchorus_filter_l.setLowpass(0, MOD_FILTER_CUTOFF_HZ, 0.54);
modchorus_filter_l.setLowpass(1, MOD_FILTER_CUTOFF_HZ, 1.3);
modchorus_filter_l.setLowpass(2, MOD_FILTER_CUTOFF_HZ, 0.54);
modchorus_filter_l.setLowpass(3, MOD_FILTER_CUTOFF_HZ, 1.3);
#endif
chorus_mixer_r.gain(0, 1.0);
chorus_mixer_l.gain(0, 1.0);
chorus_mixer_r.gain(1, 0.0);
chorus_mixer_l.gain(1, 0.0);
delay_r.delay(0, mapfloat(effect_delay_feedback, 0, ENC_DELAY_TIME_STEPS, 0.0, DELAY_MAX_TIME));
delay_l.delay(0, mapfloat(effect_delay_feedback, 0, ENC_DELAY_TIME_STEPS, 0.0, DELAY_MAX_TIME));
// delay_fb_mixer_r is the feedback-adding mixer, delay_mixer_r the whole delay (with/without feedback) mixer
delay_fb_mixer_r.gain(0, 1.0); // original signal
delay_fb_mixer_l.gain(0, 1.0); // original signal
delay_fb_mixer_r.gain(1, mapfloat(effect_delay_feedback, 0, ENC_DELAY_FB_STEPS, 0.0, 1.0)); // amount of feedback
delay_fb_mixer_l.gain(1, mapfloat(effect_delay_feedback, 0, ENC_DELAY_FB_STEPS, 0.0, 1.0)); // amount of feedback
delay_mixer_r.gain(0, 1.0 - mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // original signal
delay_mixer_l.gain(0, 1.0 - mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // original signal
delay_mixer_r.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delayed signal (including feedback)
delay_mixer_l.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delayed signal (including feedback)
delay_mixer_r.gain(2, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // only delayed signal (without feedback)
delay_mixer_l.gain(2, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // only delayed signal (without feedback)
reverb_mixer_r.gain(0, 1.0);
reverb_mixer_l.gain(0, 1.0);
reverb_mixer_r.gain(1, 0.0);
reverb_mixer_l.gain(1, 0.0);
dexed->fx.Gain = 1.0; dexed->fx.Gain = 1.0;
dexed->fx.Reso = 1.0 - float(effect_filter_resonance) / ENC_FILTER_RES_STEPS; dexed->fx.Reso = 1.0 - float(effect_filter_resonance) / ENC_FILTER_RES_STEPS;
dexed->fx.Cutoff = 1.0 - float(effect_filter_cutoff) / ENC_FILTER_CUT_STEPS; dexed->fx.Cutoff = 1.0 - float(effect_filter_cutoff) / ENC_FILTER_CUT_STEPS;
@ -299,11 +399,11 @@ void loop()
while (42 == 42) while (42 == 42)
{ {
// Main sound calculation // Main sound calculation
if (queue1.available() && fill_audio_buffer > audio_block_time_us - 10) if (dexed1.available() && fill_audio_buffer > audio_block_time_us - 10)
{ {
fill_audio_buffer = 0; fill_audio_buffer = 0;
audio_buffer = queue1.getBuffer(); audio_buffer = dexed1.getBuffer();
elapsedMicros t1; elapsedMicros t1;
dexed->getSamples(AUDIO_BLOCK_SAMPLES, audio_buffer); dexed->getSamples(AUDIO_BLOCK_SAMPLES, audio_buffer);
@ -320,7 +420,7 @@ void loop()
for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++) for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
audio_buffer[i] *= configuration.vol; audio_buffer[i] *= configuration.vol;
#endif #endif
queue1.playBuffer(); dexed1.playBuffer();
} }
// EEPROM update handling // EEPROM update handling
@ -488,15 +588,15 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue)
break; break;
case 105: // CC 105: delay time case 105: // CC 105: delay time
effect_delay_time = map(inValue, 0, 127, 0, ENC_DELAY_TIME_STEPS); effect_delay_time = map(inValue, 0, 127, 0, ENC_DELAY_TIME_STEPS);
////delay1.delay(0, mapfloat(effect_delay_time, 0, ENC_DELAY_TIME_STEPS, 0.0, DELAY_MAX_TIME)); ////delay_r.delay(0, mapfloat(effect_delay_time, 0, ENC_DELAY_TIME_STEPS, 0.0, DELAY_MAX_TIME));
break; break;
case 106: // CC 106: delay feedback case 106: // CC 106: delay feedback
effect_delay_feedback = map(inValue, 0, 127, 0, ENC_DELAY_FB_STEPS); effect_delay_feedback = map(inValue, 0, 127, 0, ENC_DELAY_FB_STEPS);
////mixer1.gain(1, mapfloat(float(effect_delay_feedback), 0, ENC_DELAY_FB_STEPS, 0.0, 1.0)); ////delay_mixer_r.gain(1, mapfloat(float(effect_delay_feedback), 0, ENC_DELAY_FB_STEPS, 0.0, 1.0));
break; break;
case 107: // CC 107: delay volume case 107: // CC 107: delay volume
effect_delay_volume = map(inValue, 0, 127, 0, ENC_DELAY_VOLUME_STEPS); effect_delay_volume = map(inValue, 0, 127, 0, ENC_DELAY_VOLUME_STEPS);
////mixer2.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delay tap1 signal (with added feedback) ////delay_mixer_l.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delay tap1 signal (with added feedback)
break; break;
case 120: case 120:
dexed->panic(); dexed->panic();
@ -820,7 +920,7 @@ void set_volume(float v, float p)
{ {
configuration.vol = v; configuration.vol = v;
configuration.pan = p; configuration.pan = p;
dexed->fx.Gain = v; dexed->fx.Gain = v;
uint16_t tmp = v * 1023.0 + 0.5; uint16_t tmp = v * 1023.0 + 0.5;
@ -845,7 +945,7 @@ void set_volume(float v, float p)
// http://files.csound-tutorial.net/floss_manual/Release03/Cs_FM_03_ScrapBook/b-panning-and-spatialization.html // http://files.csound-tutorial.net/floss_manual/Release03/Cs_FM_03_ScrapBook/b-panning-and-spatialization.html
volume_r.gain(tmp3 * sinf(tmp2 * PI / 2)); volume_r.gain(tmp3 * sinf(tmp2 * PI / 2));
volume_l.gain(tmp3 * cosf(tmp2 * PI / 2)); volume_l.gain(tmp3 * cosf(tmp2 * PI / 2));
if (configuration.mono == 2) if (configuration.mono == 2)
volume_l.gain(0.0); volume_l.gain(0.0);
else if (configuration.mono == 3) else if (configuration.mono == 3)

@ -331,7 +331,7 @@ void encoder_right_up(void)
} }
break; break;
case MENU_VOICE_SOUND: case MENU_VOICE_SOUND:
if (configuration.voice < MAX_VOICES) if (configuration.voice < MAX_VOICES-1)
configuration.voice++; configuration.voice++;
else else
{ {

@ -45,7 +45,7 @@
//************************************************************************************************* //*************************************************************************************************
// MIDI // MIDI
#define MIDI_DEVICE_DIN Serial1 //#define MIDI_DEVICE_DIN Serial1
#define MIDI_DEVICE_USB 1 #define MIDI_DEVICE_USB 1
#define MIDI_DEVICE_USB_HOST 1 #define MIDI_DEVICE_USB_HOST 1
#define MIDI_DEVICE_NUMBER 0 #define MIDI_DEVICE_NUMBER 0
@ -71,6 +71,11 @@
// EFFECTS // EFFECTS
#define FILTER_MAX_FREQ 10000 #define FILTER_MAX_FREQ 10000
// CHORUS parameters
#define MOD_DELAY_SAMPLE_BUFFER int32_t(TIME_MS2SAMPLES(20.0)) // 20.0 ms delay buffer.
#define MOD_WAVEFORM WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE
#define MOD_FILTER_OUTPUT MOD_LINKWITZ_RILEY_FILTER_OUTPUT // MOD_LINKWITZ_RILEY_FILTER_OUTPUT MOD_BUTTERWORTH_FILTER_OUTPUT MOD_NO_FILTER_OUTPUT
#define MOD_FILTER_CUTOFF_HZ 3000
//************************************************************************************************* //*************************************************************************************************
//* AUDIO SETTINGS //* AUDIO SETTINGS
@ -112,7 +117,6 @@
//************************************************************************************************* //*************************************************************************************************
//* DEBUG OUTPUT SETTINGS //* DEBUG OUTPUT SETTINGS
//************************************************************************************************* //*************************************************************************************************
#define DEBUG 1 #define DEBUG 1
#define SERIAL_SPEED 38400 #define SERIAL_SPEED 38400
#define SHOW_XRUN 1 #define SHOW_XRUN 1
@ -196,6 +200,14 @@
#define USE_TEENSY_DSP 1 #define USE_TEENSY_DSP 1
#define SUM_UP_AS_INT 1 #define SUM_UP_AS_INT 1
/* HELPER MACROS */
#define TIME_MS2SAMPLES(x) floor(uint32_t(x) * AUDIO_SAMPLE_RATE / 1000)
#define SAMPLES2TIME_MS(x) float(uint32_t(x) * 1000 / AUDIO_SAMPLE_RATE)
// Modulated delay options
#define MOD_NO_FILTER_OUTPUT 0
#define MOD_BUTTERWORTH_FILTER_OUTPUT 1
#define MOD_LINKWITZ_RILEY_FILTER_OUTPUT 2
// struct for holding the current configuration // struct for holding the current configuration
struct config_t { struct config_t {
uint32_t checksum; uint32_t checksum;
@ -212,4 +224,10 @@ struct value_change_t {
float diff; float diff;
uint16_t steps; uint16_t steps;
}; };
inline float mapfloat(float val, float in_min, float in_max, float out_min, float out_max)
{
return (val - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
#endif // CONFIG_H_INCLUDED #endif // CONFIG_H_INCLUDED

@ -0,0 +1,134 @@
/* Audio Library for Teensy 3.X
Copyright (c) 2014, Pete (El Supremo)
Copyright (c) 2019, Holger Wirtz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <Arduino.h>
#include <Audio.h>
#include "arm_math.h"
#include "effect_modulated_delay.h"
#include "config.h"
extern config_t configuration;
/******************************************************************/
// Based on; A u d i o E f f e c t D e l a y
// Written by Pete (El Supremo) Jan 2014
// 140529 - change to handle mono stream - change modify() to voices()
// 140219 - correct storage class (not static)
// 190527 - added modulation input (by Holger Wirtz)
boolean AudioEffectModulatedDelay::begin(short *delayline, uint16_t d_length)
{
#if 0
Serial.print(F("AudioEffectModulatedDelay.begin(modulated-delay line length = "));
Serial.print(d_length);
Serial.println(F(")"));
#endif
_delayline = NULL;
_delay_length = 0;
_cb_index = 0;
_delay_offset = 0;
if (delayline == NULL)
return (false);
if (d_length < 10)
return (false);
_delayline = delayline;
_delay_length = d_length;
memset(_delayline, 0, _delay_length * sizeof(int16_t));
_delay_offset = _delay_length >> 1 ;
return (true);
}
uint16_t AudioEffectModulatedDelay::get_delay_length(void)
{
return (_delay_length);
}
void AudioEffectModulatedDelay::update(void)
{
audio_block_t *block;
audio_block_t *modulation;
if (_delayline == NULL)
return;
block = receiveWritable(0);
modulation = receiveReadOnly(1);
if (block && modulation)
{
int16_t *bp;
int16_t cb_mod_index_neighbor;
float *mp;
float mod_index;
float mod_number;
float mod_fraction;
float modulation_f32[AUDIO_BLOCK_SAMPLES];
bp = block->data;
arm_q15_to_float(modulation->data, modulation_f32, AUDIO_BLOCK_SAMPLES);
mp = modulation_f32;
for (uint16_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
{
// write data into circular buffer (delayline)
if (_cb_index >= _delay_length)
_cb_index = 0;
_delayline[_cb_index] = *bp;
// calculate the modulation-index as a floating point number for interpolation
mod_index = *mp * _delay_offset;
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 + mod_number);
if (cb_mod_index < 0) // check for negative offsets and correct them
cb_mod_index += _delay_length;
if (cb_mod_index == _delay_length - 1)
cb_mod_index_neighbor = 0;
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));
// push the pointers forward
bp++; // next audio data
mp++; // next modulation data
_cb_index++; // next circular buffer index
}
}
if (modulation)
release(modulation);
if (block)
{
transmit(block, 0);
release(block);
}
}

@ -0,0 +1,58 @@
/* Audio Library for Teensy 3.X
Copyright (c) 2014, Pete (El Supremo)
Copyright (c) 2019, Holger Wirtz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef effect_modulated_chorus_h_
#define effect_modulated_chorus_h_
#include "Arduino.h"
#include "AudioStream.h"
#include "config.h"
/*************************************************************************/
// 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 (Aug 2019 by Holger Wirtz)
class AudioEffectModulatedDelay :
public AudioStream
{
public:
AudioEffectModulatedDelay(void):
AudioStream(2, inputQueueArray)
{ }
boolean begin(short *delayline, uint16_t delay_length);
virtual void update(void);
virtual uint16_t get_delay_length(void);
private:
audio_block_t *inputQueueArray[2];
int16_t *_delayline; // pointer for the circular buffer
uint16_t _cb_index; // current write pointer of 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
uint16_t _delay_offset;
};
#endif
Loading…
Cancel
Save