Several fixes.

Hopefully working interpolation (Catmull currently does not work because of too high CPU usage and xruns).
dev
Holger Wirtz 5 years ago
parent 63762acd95
commit 9dec11226d
  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;
#endif
#ifdef DEBUG_AUDIO
elapsedMillis debug_audio_timer;
#endif
// Allocate the delay lines for left and right channels
short l_delayline[CHORUS_DELAY_LENGTH_SAMPLES];
short r_delayline[CHORUS_DELAY_LENGTH_SAMPLES];
@ -232,6 +236,10 @@ void setup()
modulator.offset(0.0);
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)
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)
mixer_r.gain(VOL_MAIN, 0.5);
@ -244,6 +252,9 @@ void setup()
// set master volume
set_master_volume(master_volume);
// init random generator
srand(analogRead(A0));
Serial.println(F("<setup end>"));
#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
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();
}
#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
#include <LiquidCrystal_I2C.h>
#include <LiquidMenu.h>
#define BOUNCE_WITH_PROMPT_DETECTION
#include <Bounce.h>
#include "Encoder4.h"
#include "config.h"
@ -2046,8 +2047,8 @@ void set_chorus_delay(uint8_t value)
Serial.print(F("Set CHORUS_DELAY "));
Serial.println(value);
#endif
modchorus_r.setDelay(float(value / 10));
modchorus_l.setDelay(float(value / 10));
modchorus_r.offset(20.0);
modchorus_l.intensity(1.0);
configuration.chorus_delay = value;
}

@ -60,8 +60,10 @@
#define CHORUS_WAVEFORM WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE
#define CHORUS_MODULATOR_FILTER_FRQ 1000
#define CHORUS_MODULATOR_FILTER_Q 0.7
#define CHORUS_INTERPOLATION_MODE Catmull
#define CHORUS_INTERPOLATION_WINDOW_SIZE 11
//#define CHORUS_INTERPOLATION_MODE 0 // no interpolation
#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
@ -71,6 +73,7 @@
#define SERIAL_SPEED 38400
#define SHOW_XRUN 1
#define SHOW_CPU_LOAD_MSEC 5000
#define DEBUG_AUDIO 50
//*************************************************************************************************
//* HARDWARE SETTINGS
@ -138,7 +141,7 @@
//* 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)))
@ -301,7 +304,7 @@
// Engine
#if defined(__MK66FX1M0__)
// Teensy-3.6 settings
#define NVOICES 48
#define NVOICES 40
#else
#define NVOICES 32
#endif

@ -46,6 +46,8 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length)
_delayline = NULL;
_delay_length = 0;
_delay_offset = 0.0;
_modulation_intensity = 0.0;
_circ_idx = 0;
if (delayline == NULL) {
@ -56,7 +58,13 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length)
}
_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);
}
@ -81,9 +89,7 @@ void AudioEffectModulatedDelay::update(void)
float mod_fraction;
#ifdef CHORUS_INTERPOLATION_MODE
int8_t j;
float x[CHORUS_INTERPOLATION_WINDOW_SIZE];
float y[CHORUS_INTERPOLATION_WINDOW_SIZE];
Spline spline(x, y, CHORUS_INTERPOLATION_WINDOW_SIZE, CHORUS_INTERPOLATION_MODE);
uint8_t c;
#endif
bp = block->data;
@ -96,16 +102,15 @@ void AudioEffectModulatedDelay::update(void)
_circ_idx = 0;
_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
mod_idx = *mp * float(_delay_length >> 1);
mod_idx = _delay_offset + ((float(*mp) / SHRT_MAX) * _modulation_intensity);
mod_fraction = modff(mod_idx, &mod_number);
#ifdef CHORUS_INTERPOLATION_MODE
// Spline 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
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
if (jc_mod_idx < 0) // check for negative offsets and correct them
@ -113,9 +118,8 @@ void AudioEffectModulatedDelay::update(void)
else
y[c] = float(_delayline[jc_mod_idx]);
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
// Simple interpolation
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];
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));
#endif
bp++; // next audio 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 "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
@ -44,14 +46,21 @@ class AudioEffectModulatedDelay :
boolean begin(short *delayline, int delay_length);
virtual void update(void);
virtual void setDelay(float milliseconds);
virtual float offset(float offset_value);
virtual void intensity(float intensity_value);
private:
audio_block_t *inputQueueArray[2];
int16_t *_delayline;
uint16_t _circ_idx;
uint16_t _max_delay_length;
uint16_t _delay_offset;
uint16_t _modulation_intensity;
uint16_t _delay_length;
#ifdef CHORUS_INTERPOLATION_MODE
float x[CHORUS_INTERPOLATION_WINDOW_SIZE];
float y[CHORUS_INTERPOLATION_WINDOW_SIZE];
Spline* spline;
#endif
};
#endif

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

Loading…
Cancel
Save