From 0027b62530b52843ad4a0c8a22f8eb22b1d95d08 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Thu, 11 Jul 2019 15:34:29 +0200 Subject: [PATCH] Several fixes. Hopefully working interpolation (Catmull currently does not work because of too high CPU usage and xruns). --- MicroMDAEPiano.ino | 29 +++++++++++++++++---- UI.hpp | 5 ++-- config.h | 11 +++++--- effect_modulated_delay.cpp | 53 ++++++++++++++++++++++++++++---------- effect_modulated_delay.h | 13 ++++++++-- mdaEPiano.cpp | 6 ++++- mdaEPiano.h | 2 +- 7 files changed, 91 insertions(+), 28 deletions(-) diff --git a/MicroMDAEPiano.ino b/MicroMDAEPiano.ino index 293924a..8ea1f7a 100644 --- a/MicroMDAEPiano.ino +++ b/MicroMDAEPiano.ino @@ -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,12 +252,15 @@ void setup() // set master volume set_master_volume(master_volume); - Serial.println(F("")); + // init random generator + srand(analogRead(A0)); + + Serial.println(F("")); #if defined (SHOW_DEBUG) && defined (SHOW_CPU_LOAD_MSEC) - Serial.println(); - show_cpu_and_mem_usage(); - cpu_mem_millis = 0; + Serial.println(); + show_cpu_and_mem_usage(); + cpu_mem_millis = 0; #endif } @@ -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 } //************************************************************************************************* diff --git a/UI.hpp b/UI.hpp index e4a40e9..ecea5d0 100644 --- a/UI.hpp +++ b/UI.hpp @@ -45,6 +45,7 @@ #define UI_HPP_INCLUDED #include #include +#define BOUNCE_WITH_PROMPT_DETECTION #include #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; } diff --git a/config.h b/config.h index c0bbabf..60a94cd 100644 --- a/config.h +++ b/config.h @@ -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 diff --git a/effect_modulated_delay.cpp b/effect_modulated_delay.cpp index 3e2a21a..9368585 100644 --- a/effect_modulated_delay.cpp +++ b/effect_modulated_delay.cpp @@ -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]; } - *bp = int(round(mod_fraction * value1 + (1.0 - mod_fraction) * value2)); + + 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; } diff --git a/effect_modulated_delay.h b/effect_modulated_delay.h index ed05478..a521d29 100644 --- a/effect_modulated_delay.h +++ b/effect_modulated_delay.h @@ -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 diff --git a/mdaEPiano.cpp b/mdaEPiano.cpp index b966250..45af0fe 100644 --- a/mdaEPiano.cpp +++ b/mdaEPiano.cpp @@ -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; } diff --git a/mdaEPiano.h b/mdaEPiano.h index f4f988b..143733d 100644 --- a/mdaEPiano.h +++ b/mdaEPiano.h @@ -128,7 +128,7 @@ class mdaEPiano uint8_t max_polyphony; KGRP kgrp[34]; VOICE voice[NVOICES]; - int32_t activevoices; + int32_t activevoices; short *waves; float width; int32_t size, sustain;