Several fixes.

Hopefully working interpolation (Catmull currently does not work because of too high CPU usage and xruns).
master
Holger Wirtz 5 years ago
parent 9efd4e6f03
commit 0027b62530
  1. 21
      MicroMDAEPiano.ino
  2. 5
      UI.hpp
  3. 11
      config.h
  4. 51
      effect_modulated_delay.cpp
  5. 13
      effect_modulated_delay.h
  6. 6
      mdaEPiano.cpp

@ -150,6 +150,10 @@ elapsedMillis eeprom_master_volume_update_timer;
elapsedMillis cpu_mem_millis; elapsedMillis cpu_mem_millis;
#endif #endif
#ifdef DEBUG_AUDIO
elapsedMillis debug_audio_timer;
#endif
// Allocate the delay lines for left and right channels // Allocate the delay lines for left and right channels
short l_delayline[CHORUS_DELAY_LENGTH_SAMPLES]; short l_delayline[CHORUS_DELAY_LENGTH_SAMPLES];
short r_delayline[CHORUS_DELAY_LENGTH_SAMPLES]; short r_delayline[CHORUS_DELAY_LENGTH_SAMPLES];
@ -232,6 +236,10 @@ void setup()
modulator.offset(0.0); modulator.offset(0.0);
modulator_filter.setLowpass(0, CHORUS_MODULATOR_FILTER_FRQ, CHORUS_MODULATOR_FILTER_Q); modulator_filter.setLowpass(0, CHORUS_MODULATOR_FILTER_FRQ, CHORUS_MODULATOR_FILTER_Q);
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)
modchorus_r.offset(15.0);
modchorus_r.intensity(1.0);
modchorus_l.offset(15.0);
modchorus_l.intensity(1.0);
// 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);
@ -244,6 +252,9 @@ void setup()
// set master volume // set master volume
set_master_volume(master_volume); set_master_volume(master_volume);
// init random generator
srand(analogRead(A0));
Serial.println(F("<setup end>")); Serial.println(F("<setup end>"));
#if defined (SHOW_DEBUG) && defined (SHOW_CPU_LOAD_MSEC) #if defined (SHOW_DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
@ -319,9 +330,17 @@ void loop()
if ( eeprom_config_update_flag > 0 && ep->getActiveVoices() == 0) // write only to eeprom when no voice is active if ( eeprom_config_update_flag > 0 && ep->getActiveVoices() == 0) // write only to eeprom when no voice is active
eeprom_config_update(); eeprom_config_update();
if (eeprom_master_volume_update_flag == true && eeprom_master_volume_update_timer > STORE_MASTER_VOLUME_MS) if (eeprom_master_volume_update_flag == true && eeprom_master_volume_update_timer > STORE_MASTER_VOLUME_MS && ep->getActiveVoices() == 0)
eeprom_master_volume_update(); eeprom_master_volume_update();
} }
#ifdef DEBUG_AUDIO
if (debug_audio_timer > DEBUG_AUDIO)
{
ep->noteOn(60 + rand() % 108, rand() % 128);
debug_audio_timer = 0;
}
#endif
} }
//************************************************************************************************* //*************************************************************************************************

@ -45,6 +45,7 @@
#define UI_HPP_INCLUDED #define UI_HPP_INCLUDED
#include <LiquidCrystal_I2C.h> #include <LiquidCrystal_I2C.h>
#include <LiquidMenu.h> #include <LiquidMenu.h>
#define BOUNCE_WITH_PROMPT_DETECTION
#include <Bounce.h> #include <Bounce.h>
#include "Encoder4.h" #include "Encoder4.h"
#include "config.h" #include "config.h"
@ -2046,8 +2047,8 @@ void set_chorus_delay(uint8_t value)
Serial.print(F("Set CHORUS_DELAY ")); Serial.print(F("Set CHORUS_DELAY "));
Serial.println(value); Serial.println(value);
#endif #endif
modchorus_r.setDelay(float(value / 10)); modchorus_r.offset(20.0);
modchorus_l.setDelay(float(value / 10)); modchorus_l.intensity(1.0);
configuration.chorus_delay = value; configuration.chorus_delay = value;
} }

@ -60,8 +60,10 @@
#define CHORUS_WAVEFORM WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE #define CHORUS_WAVEFORM WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE
#define CHORUS_MODULATOR_FILTER_FRQ 1000 #define CHORUS_MODULATOR_FILTER_FRQ 1000
#define CHORUS_MODULATOR_FILTER_Q 0.7 #define CHORUS_MODULATOR_FILTER_Q 0.7
#define CHORUS_INTERPOLATION_MODE Catmull //#define CHORUS_INTERPOLATION_MODE 0 // no interpolation
#define CHORUS_INTERPOLATION_WINDOW_SIZE 11 #define CHORUS_INTERPOLATION_MODE 1 // linear interpolation
//#define CHORUS_INTERPOLATION_MODE Catmull // spline interpolation
#define CHORUS_INTERPOLATION_WINDOW_SIZE 3 // only uneven numbers bigger than 3!!!
//************************************************************************************************* //*************************************************************************************************
//* DEBUG OUTPUT SETTINGS //* DEBUG OUTPUT SETTINGS
@ -71,6 +73,7 @@
#define SERIAL_SPEED 38400 #define SERIAL_SPEED 38400
#define SHOW_XRUN 1 #define SHOW_XRUN 1
#define SHOW_CPU_LOAD_MSEC 5000 #define SHOW_CPU_LOAD_MSEC 5000
#define DEBUG_AUDIO 50
//************************************************************************************************* //*************************************************************************************************
//* HARDWARE SETTINGS //* HARDWARE SETTINGS
@ -138,7 +141,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.4" #define MICRO_MDAEPIANO_VERSION "0.9.5"
#define MAX_SOUNDS min(99,int((4096-EEPROM_CONFIGURATIONS)/sizeof(config_t))) #define MAX_SOUNDS min(99,int((4096-EEPROM_CONFIGURATIONS)/sizeof(config_t)))
@ -301,7 +304,7 @@
// Engine // Engine
#if defined(__MK66FX1M0__) #if defined(__MK66FX1M0__)
// Teensy-3.6 settings // Teensy-3.6 settings
#define NVOICES 48 #define NVOICES 40
#else #else
#define NVOICES 32 #define NVOICES 32
#endif #endif

@ -46,6 +46,8 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length)
_delayline = NULL; _delayline = NULL;
_delay_length = 0; _delay_length = 0;
_delay_offset = 0.0;
_modulation_intensity = 0.0;
_circ_idx = 0; _circ_idx = 0;
if (delayline == NULL) { if (delayline == NULL) {
@ -56,7 +58,13 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length)
} }
_delayline = delayline; _delayline = delayline;
_delay_length = _max_delay_length = d_length; _delay_length = d_length;
#ifdef CHORUS_INTERPOLATION_MODE
spline = new Spline;
spline->setPoints(x, y, int(CHORUS_INTERPOLATION_WINDOW_SIZE));
spline->setDegree(CHORUS_INTERPOLATION_MODE);
#endif
return (true); return (true);
} }
@ -81,9 +89,7 @@ void AudioEffectModulatedDelay::update(void)
float mod_fraction; float mod_fraction;
#ifdef CHORUS_INTERPOLATION_MODE #ifdef CHORUS_INTERPOLATION_MODE
int8_t j; int8_t j;
float x[CHORUS_INTERPOLATION_WINDOW_SIZE]; uint8_t c;
float y[CHORUS_INTERPOLATION_WINDOW_SIZE];
Spline spline(x, y, CHORUS_INTERPOLATION_WINDOW_SIZE, CHORUS_INTERPOLATION_MODE);
#endif #endif
bp = block->data; bp = block->data;
@ -96,16 +102,15 @@ void AudioEffectModulatedDelay::update(void)
_circ_idx = 0; _circ_idx = 0;
_delayline[_circ_idx] = *bp; _delayline[_circ_idx] = *bp;
// Calculate modulation index as a float, for interpolation later. // Calculate the modulation index as a float in the interval [-1.0,1.0] for interpolation later.
// The index is located around the half of the delay length multiplied by the current amount of the modulator // The index is located around the half of the delay length multiplied by the current amount of the modulator
mod_idx = *mp * float(_delay_length >> 1); mod_idx = _delay_offset + ((float(*mp) / SHRT_MAX) * _modulation_intensity);
mod_fraction = modff(mod_idx, &mod_number); mod_fraction = modff(mod_idx, &mod_number);
#ifdef CHORUS_INTERPOLATION_MODE #ifdef CHORUS_INTERPOLATION_MODE
// Spline interpolation // Spline interpolation
// Generate a an array with the size of CHORUS_INTERPOLATION_WINDOW_SIZE of x/y values around mod_idx for interpolation // Generate a an array with the size of CHORUS_INTERPOLATION_WINDOW_SIZE of x/y values around mod_idx for interpolation
uint8_t c = 0;
int16_t c_mod_idx = _circ_idx - int(round(mod_idx)); // This is the pointer to the value in the circular buffer at the current modulation index int16_t c_mod_idx = _circ_idx - int(round(mod_idx)); // This is the pointer to the value in the circular buffer at the current modulation index
for (j = (CHORUS_INTERPOLATION_WINDOW_SIZE / -2); j <= (CHORUS_INTERPOLATION_WINDOW_SIZE / 2); j++) for (j = (CHORUS_INTERPOLATION_WINDOW_SIZE / -2), c = 0; j <= (CHORUS_INTERPOLATION_WINDOW_SIZE / 2); j++, c++)
{ {
int16_t jc_mod_idx = (c_mod_idx + j) % _delay_length; // The modulation index pointer plus the value of the current window pointer int16_t jc_mod_idx = (c_mod_idx + j) % _delay_length; // The modulation index pointer plus the value of the current window pointer
if (jc_mod_idx < 0) // check for negative offsets and correct them if (jc_mod_idx < 0) // check for negative offsets and correct them
@ -113,9 +118,8 @@ void AudioEffectModulatedDelay::update(void)
else else
y[c] = float(_delayline[jc_mod_idx]); y[c] = float(_delayline[jc_mod_idx]);
x[c] = float(j); x[c] = float(j);
c++;
} }
*bp = int(round(spline.value(mod_fraction))); // use spline interpolated value *bp = int(round(spline->value(mod_fraction))); // use spline interpolated value
#else #else
// Simple interpolation // Simple interpolation
int16_t c_mod_idx = (_circ_idx + int(round(mod_idx))) % _delay_length; int16_t c_mod_idx = (_circ_idx + int(round(mod_idx))) % _delay_length;
@ -131,7 +135,12 @@ void AudioEffectModulatedDelay::update(void)
value1 = _delayline[c_mod_idx - 1]; value1 = _delayline[c_mod_idx - 1];
value2 = _delayline[c_mod_idx]; value2 = _delayline[c_mod_idx];
} }
if (mod_fraction < 0)
*bp = int(round((1.0 + mod_fraction) * value1 + fabs(mod_fraction) * value2));
else
*bp = int(round(mod_fraction * value1 + (1.0 - mod_fraction) * value2)); *bp = int(round(mod_fraction * value1 + (1.0 - mod_fraction) * value2));
#endif #endif
bp++; // next audio data bp++; // next audio data
mp++; // next modulation data mp++; // next modulation data
@ -149,7 +158,25 @@ void AudioEffectModulatedDelay::update(void)
} }
} }
void AudioEffectModulatedDelay::setDelay(float milliseconds) float AudioEffectModulatedDelay::offset(float offset_value)
{ {
_delay_length = min(AUDIO_SAMPLE_RATE * milliseconds / 500, _max_delay_length); uint16_t offset_frames = (offset_value / 1000) * AUDIO_SAMPLE_RATE;
if (offset_frames > _delay_length * MODULATION_MAX_FACTOR)
_delay_offset = _delay_length * MODULATION_MAX_FACTOR;
else if (offset_frames <= _delay_length * (1 - MODULATION_MAX_FACTOR))
_delay_offset = _delay_length * (1 - MODULATION_MAX_FACTOR);
else
_delay_offset = offset_frames;
return (offset_frames / AUDIO_SAMPLE_RATE * 1000);
}
void AudioEffectModulatedDelay::intensity(float intensity_value)
{
if (intensity_value > 1.0)
intensity_value = 1.0;
else if (intensity_value < 0.0)
intensity_value = 0.0;
_modulation_intensity = intensity_value * (1 - MODULATION_MAX_FACTOR) * 2 * _delay_length;
} }

@ -28,6 +28,8 @@
#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
@ -44,14 +46,21 @@ 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 void setDelay(float milliseconds); virtual float offset(float offset_value);
virtual void intensity(float intensity_value);
private: private:
audio_block_t *inputQueueArray[2]; audio_block_t *inputQueueArray[2];
int16_t *_delayline; int16_t *_delayline;
uint16_t _circ_idx; uint16_t _circ_idx;
uint16_t _max_delay_length; uint16_t _delay_offset;
uint16_t _modulation_intensity;
uint16_t _delay_length; uint16_t _delay_length;
#ifdef CHORUS_INTERPOLATION_MODE
float x[CHORUS_INTERPOLATION_WINDOW_SIZE];
float y[CHORUS_INTERPOLATION_WINDOW_SIZE];
Spline* spline;
#endif
}; };
#endif #endif

@ -57,7 +57,7 @@ mdaEPiano::mdaEPiano() // mdaEPiano::mdaEPiano(audioMasterCallback audioMaster)
setPanLFO(0.650f); setPanLFO(0.650f);
setVelocitySense(0.250f); setVelocitySense(0.250f);
setStereo(0.500f); setStereo(0.500f);
setMaxPolyphony(1.0f); setMaxPolyphony(NVOICES);
setTune(0.500f); setTune(0.500f);
setDetune(0.146f); setDetune(0.146f);
setOverdrive(0.000f); setOverdrive(0.000f);
@ -232,6 +232,10 @@ void mdaEPiano::setStereo(float value)
void mdaEPiano::setMaxPolyphony(uint8_t value) void mdaEPiano::setMaxPolyphony(uint8_t value)
{ {
if (value > NVOICES)
value = NVOICES;
if (value <= 0)
value = 1;
max_polyphony = value; max_polyphony = value;
} }

Loading…
Cancel
Save