From bafeeb0cc26d568d0071a4a79ec4c87009181ac5 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Tue, 4 Jun 2019 11:46:35 +0200 Subject: [PATCH] Fixed storing and loading of sounds. Fixed Interpolation code for chorus. Small fixes. --- MicroMDAEPiano.ino | 67 +++++++++++----------- UI.hpp | 13 +++-- config.h | 2 +- effect_modulated_chorus.cpp | 108 ++++++++++++++++++------------------ effect_modulated_chorus.h | 14 ++--- 5 files changed, 105 insertions(+), 99 deletions(-) diff --git a/MicroMDAEPiano.ino b/MicroMDAEPiano.ino index 51337b3..d4fe8bc 100644 --- a/MicroMDAEPiano.ino +++ b/MicroMDAEPiano.ino @@ -54,8 +54,8 @@ AudioMixer4 mixer_r; AudioMixer4 mixer_l; AudioAmplifier volume_r; AudioAmplifier volume_l; -AudioModulatedEffectChorus modchorus_r; -AudioModulatedEffectChorus modchorus_l; +AudioEffectModulatedDelay modchorus_r; +AudioEffectModulatedDelay modchorus_l; AudioSynthWaveform modulator; AudioConnection patchCord0(queue_r, peak_r); AudioConnection patchCord1(queue_l, peak_l); @@ -183,7 +183,7 @@ void setup() // create EPiano object ep = new mdaEPiano(); - //set_complete_configuration(); + set_complete_configuration(); initial_values_from_eeprom(); setup_midi_devices(); @@ -213,46 +213,44 @@ void setup() Serial.println(F("PT8211 enabled.")); #endif - // set master volume - set_master_volume(master_volume); - - // internal mixing of original signal(0), reverb(1) and chorus(2) - mixer_r.gain(0, 1.0); - mixer_l.gain(0, 1.0); - #if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) // Initialize processor and memory measurements AudioProcessorUsageMaxReset(); AudioMemoryUsageMaxReset(); #endif + AudioInterrupts(); + Serial.print(F("AUDIO_BLOCK_SAMPLES=")); Serial.print(AUDIO_BLOCK_SAMPLES); Serial.print(F(" (Time per block=")); Serial.print(audio_block_time_us); Serial.println(F("ms)")); - if (!modchorus_r.begin(r_delayline, CHORUS_DELAY_LENGTH)) { - Serial.println(F("AudioModulatedEffectChorus - right channel begin failed")); - while (1); - } - if (!modchorus_l.begin(l_delayline, CHORUS_DELAY_LENGTH)) { - Serial.println(F("AudioModulatedEffectChorus - left channel begin failed")); - while (1); - } + /* + if (!modchorus_r.begin(r_delayline, CHORUS_DELAY_LENGTH)) { + Serial.println(F("AudioEffectModulatedDelay - right channel begin failed")); + while (1); + } + if (!modchorus_l.begin(l_delayline, CHORUS_DELAY_LENGTH)) { + Serial.println(F("AudioEffectModulatedDelay - left channel begin failed")); + while (1); + } - // chorus modulation fixed - memset(r_delayline, 0, sizeof(short)*CHORUS_DELAY_LENGTH); - memset(l_delayline, 0, sizeof(short)*CHORUS_DELAY_LENGTH); - modulator.begin(CHORUS_WAVEFORM); - modulator.amplitude(0.1); - modulator.frequency(1.0); - modulator.phase(0); - // chorus level fixed + // chorus modulation fixed + modulator.begin(CHORUS_WAVEFORM); + modulator.amplitude(0.1); + modulator.frequency(1.0); + modulator.phase(0); + */ + // internal mixing of original signal(0), reverb(1) and chorus(2) + mixer_r.gain(0, 1.0); + mixer_l.gain(0, 1.0); mixer_r.gain(2, 0.5); mixer_l.gain(2, 0.5); - AudioInterrupts(); + // set master volume + set_master_volume(master_volume); Serial.println(F("")); @@ -534,7 +532,11 @@ void config_from_eeprom(void) checksum = crc32((byte*)&tmp_conf + 4, sizeof(tmp_conf) - 4); #ifdef DEBUG - Serial.print(F("EEPROM checksum: 0x")); + Serial.print(F("Reading sound ")); + Serial.print(sound, DEC); + Serial.print(F(" from 0x")); + Serial.print(EEPROM_CONFIGURATIONS + sizeof(config_t) * (sound - 1), HEX); + Serial.print(F(" EEPROM checksum: 0x")); Serial.print(tmp_conf.checksum, HEX); Serial.print(F(" / 0x")); Serial.print(checksum, HEX); @@ -543,8 +545,7 @@ void config_from_eeprom(void) if (checksum == tmp_conf.checksum) { EEPROM_readAnything(EEPROM_CONFIGURATIONS + sizeof(config_t) * (sound - 1), configuration); - Serial.print(F(" - OK -> loading sound.")); - Serial.print(sound, DEC); + Serial.print(F(" - OK")); } else { @@ -552,6 +553,7 @@ void config_from_eeprom(void) Serial.println(F(" - mismatch -> loading initial configuration.")); #endif set_complete_configuration(); + EEPROM.update(EEPROM_SOUND, sound); } show_sound(); } @@ -571,12 +573,15 @@ void eeprom_config_write(uint8_t value) void eeprom_config_update(void) { configuration.checksum = crc32((byte*)&configuration + 4, sizeof(configuration) - 4); - EEPROM_writeAnything(EEPROM_CONFIGURATIONS + sizeof(config_t) * (eeprom_config_update_flag - 1), configuration); Serial.print(F("Updating EEPROM configuration for sound ")); Serial.print(eeprom_config_update_flag, DEC); + Serial.print(F(" with checksum 0x")); + Serial.print(configuration.checksum, HEX); Serial.print(F(" at 0x")); Serial.println(EEPROM_CONFIGURATIONS + sizeof(config_t) * (eeprom_config_update_flag - 1), HEX); + EEPROM_writeAnything(EEPROM_CONFIGURATIONS + sizeof(config_t) * (eeprom_config_update_flag - 1), configuration); eeprom_config_update_flag = 0; + EEPROM.update(EEPROM_SOUND, sound); } void eeprom_master_volume_write(void) diff --git a/UI.hpp b/UI.hpp index f15e62c..ee328fc 100644 --- a/UI.hpp +++ b/UI.hpp @@ -22,7 +22,8 @@ */ -/* Don't forget to change in MAX_FUNCTIONS to 24 in ../libraries/LiquidMenu/src/LiquidMenu_config.h +/* Don't forget to change parameters in ../libraries/LiquidMenu/src/LiquidMenu_config.h + /// Configures the number of available variables per line. const uint8_t MAX_VARIABLES = 5; ///< @note Default: 5 @@ -33,10 +34,10 @@ const uint8_t MAX_LINES = 20; ///< @note Default: 12 /// Configures the number of available screens per menu. - const uint8_t MAX_SCREENS = 14; ///< @note Default: 14 + const uint8_t MAX_SCREENS = 2; ///< @note Default: 14 /// Configures the number of available menus per menus system. - const uint8_t MAX_MENUS = 44; ///< @note Default: 8 + const uint8_t MAX_MENUS = 42; ///< @note Default: 8 */ @@ -597,7 +598,7 @@ LiquidMenu chorus_delay_menu(lcd); CHORUS_INTENSITY MENU ******************************************/ #define NUM_CHORUS_INTENSITY_MENUS 1 -const char chorus_intensity_text1[] PROGMEM = "Chorus Intensity"; +const char chorus_intensity_text1[] PROGMEM = "Chorus Intens."; LiquidLine chorus_intensity_line1(1, 0, chorus_intensity_text1); LiquidLine chorus_intensity_line2(1, 1, configuration.chorus_intensity); LiquidScreen chorus_intensity_screen; @@ -1766,9 +1767,9 @@ void load_sound(void) { #ifdef DEBUG Serial.print(F("Load sound ")); - Serial.println(sound); + Serial.println(sound, DEC); #endif - EEPROM.write(EEPROM_SOUND, sound); + EEPROM.update(EEPROM_SOUND, sound); config_from_eeprom(); } diff --git a/config.h b/config.h index d829b51..c171b99 100644 --- a/config.h +++ b/config.h @@ -62,7 +62,7 @@ #define USE_XFADE_DATA 1 // CHORUS parameters #define INTERPOLATION_WINDOW_SIZE 7 // For chorus, only odd numbers,please! -#define INTERPOLATE QUADRATIC // LINEAR COSINE QUADRATIC CUBIC LAGRANGE +#define INTERPOLATE LAGRANGE // LINEAR QUADRATIC COSINE CUBIC LAGRANGE #define CHORUS_WAVEFORM WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE WAVEFORM_SQUARE WAVEFORM_TRIANGLE #define CHORUS_DELAY_LENGTH (16*AUDIO_BLOCK_SAMPLES) diff --git a/effect_modulated_chorus.cpp b/effect_modulated_chorus.cpp index 1d25bdb..8059488 100644 --- a/effect_modulated_chorus.cpp +++ b/effect_modulated_chorus.cpp @@ -33,19 +33,19 @@ // Written by Pete (El Supremo) Jan 2014 // 140529 - change to handle mono stream - change modify() to voices() // 140219 - correct storage class (not static) -// 190527 - adding modulation input (by Holger Wirtz) +// 190527 - added modulation input handling (by Holger Wirtz) -boolean AudioModulatedEffectChorus::begin(short *delayline, int d_length) +boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length) { #if 0 - Serial.print("AudioModulatedEffectChorus.begin(Chorus delay line length = "); + Serial.print("AudioEffectModulatedDelay.begin(Chorus delay line length = "); Serial.print(d_length); Serial.println(")"); #endif - l_delayline = NULL; - delay_length = 0; - l_circ_idx = 0; + _delayline = NULL; + _delay_length = 0; + _circ_idx = 0; if (delayline == NULL) { return (false); @@ -54,43 +54,47 @@ boolean AudioModulatedEffectChorus::begin(short *delayline, int d_length) return (false); } - l_delayline = delayline; - delay_length = d_length; - delay_length_half = d_length / 2; + _delayline = delayline; + _delay_length = d_length; + _delay_length_half = d_length / 2; + + memset(_delayline, 0, sizeof(short)*_delay_length); return (true); } //int last_idx = 0; -void AudioModulatedEffectChorus::update(void) +void AudioEffectModulatedDelay::update(void) { audio_block_t *block; audio_block_t *modulation; + short *bp; short *mp; float mod_idx; + if (_delayline == NULL) + return; + #ifdef INTERPOLATE - interpolation* modulation_interpolate; - modulation_interpolate = new interpolation; + interpolation modulation_interpolate; #endif - if (l_delayline == NULL) - return; - block = receiveWritable(0); modulation = receiveReadOnly(1); if (block && modulation) { #ifdef INTERPOLATE - uint8_t j; - int16_t interpolation_idx; + int8_t j; float x[INTERPOLATION_WINDOW_SIZE]; float y[INTERPOLATION_WINDOW_SIZE]; - modulation_interpolate->valuelenXY(INTERPOLATION_WINDOW_SIZE); - modulation_interpolate->valueX(x); - modulation_interpolate->valueY(y); + modulation_interpolate.valuelenXY(INTERPOLATION_WINDOW_SIZE); + modulation_interpolate.valueX(x); + modulation_interpolate.valueY(y); + + for (j = 0; j < INTERPOLATION_WINDOW_SIZE; j++) + x[j] = j; #endif bp = block->data; @@ -99,64 +103,60 @@ void AudioModulatedEffectChorus::update(void) for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { // write data into circular buffer - if (l_circ_idx >= delay_length) - l_circ_idx = 0; - l_delayline[l_circ_idx] = *bp; // write signal into circular buffer + if (_circ_idx >= _delay_length) + _circ_idx = 0; + _delayline[_circ_idx] = *bp; // calculate modulation index - mod_idx = float(*mp) / SHRT_MAX * delay_length_half + l_circ_idx; // calculate index with modulation as a float - if (mod_idx > float(delay_length - 1)) - mod_idx = mod_idx - float(delay_length - 1); + mod_idx = float(*mp) / SHRT_MAX * _delay_length_half + _circ_idx; // calculate index with modulation as a float(!!!) + if (mod_idx > float(_delay_length - 1)) + mod_idx = mod_idx - float(_delay_length - 1); else if (mod_idx < 0.0) - mod_idx = float(delay_length - 1) + mod_idx; + mod_idx = float(_delay_length - 1) + mod_idx; #ifdef INTERPOLATE - // get value with interpolation - interpolation_idx = int(mod_idx + 0.5) + (INTERPOLATION_WINDOW_SIZE / -2); - for (j = interpolation_idx; j < INTERPOLATION_WINDOW_SIZE; j++) + // get x/y values around mod_idx + uint16_t i_mod_idx = int(mod_idx + 0.5); + for (j = INTERPOLATION_WINDOW_SIZE / -2; j <= INTERPOLATION_WINDOW_SIZE / 2; j++) { - x[j] = interpolation_idx; - - if (j >= delay_length) - y[j] = l_delayline[j - delay_length]; - else if (j < 0) - y[j] = l_delayline[delay_length + j]; + int16_t ji_mod_idx = i_mod_idx + j; + if (ji_mod_idx > _delay_length) + y[j] = _delayline[ji_mod_idx - _delay_length - 1]; + else if (ji_mod_idx < 0) + y[j] = _delayline[_delay_length + j + 1]; + else + y[j] = _delayline[ji_mod_idx]; } - modulation_interpolate->valueI(mod_idx); + modulation_interpolate.valueI(mod_idx); #if INTERPOLATE == CUBIC - *bp = int(modulation_interpolate->CubicInterpolate() + 0.5); + *bp = int(modulation_interpolate.CubicInterpolate() + 0.5); #elif INTERPOLATE == LINEAR - *bp = int(modulation_interpolate->LinearInterpolate() + 0.5); + *bp = int(modulation_interpolate.LinearInterpolate() + 0.5); #elif INTERPOLATE == COSINE - *bp = int(modulation_interpolate->CosineInterpolate() + 0.5); + *bp = int(modulation_interpolate.CosineInterpolate() + 0.5); #elif INTERPOLATE == LAGRANGE - *bp = int(modulation_interpolate->LagrangeInterpolate() + 0.5); + *bp = int(modulation_interpolate.LagrangeInterpolate() + 0.5); #elif INTERPOLATE == QUDRATIC - *bp = int(modulation_interpolate->QuadraticInterpolate() + 0.5); + *bp = int(modulation_interpolate.QuadraticInterpolate() + 0.5); #else // No interpolation - should sound really bad... - *bp = l_delayline[int(mod_idx + 0.5)]; + *bp = _delayline[int(mod_idx + 0.5)]; #endif #else // No interpolation - should sound really bad... - *bp = l_delayline[int(mod_idx + 0.5)]; + *bp = _delayline[int(mod_idx + 0.5)]; #endif bp++; mp++; - l_circ_idx++; + _circ_idx++; } - - // transmit the block - transmit(block, 0); - release(block); - release(modulation); } -#ifdef INTERPOLATION - if (modulation_interpolate) - delete(modulation_interpolate); -#endif + // transmit the block + transmit(block, 0); + release(block); + release(modulation); } diff --git a/effect_modulated_chorus.h b/effect_modulated_chorus.h index 93698d1..6c26759 100644 --- a/effect_modulated_chorus.h +++ b/effect_modulated_chorus.h @@ -32,15 +32,15 @@ // A u d i o E f f e c t C h o r u s // Written by Pete (El Supremo) Jan 2014 // 140219 - correct storage class (not static) -// 190527 - adding modulation input (by Holger Wirtz) +// 190527 - added modulation input handling (by Holger Wirtz) #define CHORUS_DELAY_PASSTHRU -1 -class AudioModulatedEffectChorus : +class AudioEffectModulatedDelay : public AudioStream { public: - AudioModulatedEffectChorus(void): + AudioEffectModulatedDelay(void): AudioStream(2, inputQueueArray) { } @@ -50,10 +50,10 @@ class AudioModulatedEffectChorus : private: audio_block_t *inputQueueArray[2]; - short *l_delayline; - short l_circ_idx; - int delay_length; - int delay_length_half; + short *_delayline; + short _circ_idx; + int _delay_length; + int _delay_length_half; }; #endif