Fixed storing and loading of sounds.

Fixed Interpolation code for chorus.
Small fixes.
master
Holger Wirtz 6 years ago
parent 369b135c8f
commit 19c9fbc24e
  1. 67
      MicroMDAEPiano.ino
  2. 13
      UI.hpp
  3. 2
      config.h
  4. 108
      effect_modulated_chorus.cpp
  5. 14
      effect_modulated_chorus.h

@ -54,8 +54,8 @@ AudioMixer4 mixer_r;
AudioMixer4 mixer_l; AudioMixer4 mixer_l;
AudioAmplifier volume_r; AudioAmplifier volume_r;
AudioAmplifier volume_l; AudioAmplifier volume_l;
AudioModulatedEffectChorus modchorus_r; AudioEffectModulatedDelay modchorus_r;
AudioModulatedEffectChorus modchorus_l; AudioEffectModulatedDelay modchorus_l;
AudioSynthWaveform modulator; AudioSynthWaveform modulator;
AudioConnection patchCord0(queue_r, peak_r); AudioConnection patchCord0(queue_r, peak_r);
AudioConnection patchCord1(queue_l, peak_l); AudioConnection patchCord1(queue_l, peak_l);
@ -183,7 +183,7 @@ void setup()
// create EPiano object // create EPiano object
ep = new mdaEPiano(); ep = new mdaEPiano();
//set_complete_configuration(); set_complete_configuration();
initial_values_from_eeprom(); initial_values_from_eeprom();
setup_midi_devices(); setup_midi_devices();
@ -213,46 +213,44 @@ void setup()
Serial.println(F("PT8211 enabled.")); Serial.println(F("PT8211 enabled."));
#endif #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) #if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
// Initialize processor and memory measurements // Initialize processor and memory measurements
AudioProcessorUsageMaxReset(); AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset(); AudioMemoryUsageMaxReset();
#endif #endif
AudioInterrupts();
Serial.print(F("AUDIO_BLOCK_SAMPLES=")); Serial.print(F("AUDIO_BLOCK_SAMPLES="));
Serial.print(AUDIO_BLOCK_SAMPLES); Serial.print(AUDIO_BLOCK_SAMPLES);
Serial.print(F(" (Time per block=")); Serial.print(F(" (Time per block="));
Serial.print(audio_block_time_us); Serial.print(audio_block_time_us);
Serial.println(F("ms)")); Serial.println(F("ms)"));
if (!modchorus_r.begin(r_delayline, CHORUS_DELAY_LENGTH)) { /*
Serial.println(F("AudioModulatedEffectChorus - right channel begin failed")); if (!modchorus_r.begin(r_delayline, CHORUS_DELAY_LENGTH)) {
while (1); Serial.println(F("AudioEffectModulatedDelay - right channel begin failed"));
} while (1);
if (!modchorus_l.begin(l_delayline, CHORUS_DELAY_LENGTH)) { }
Serial.println(F("AudioModulatedEffectChorus - left channel begin failed")); if (!modchorus_l.begin(l_delayline, CHORUS_DELAY_LENGTH)) {
while (1); Serial.println(F("AudioEffectModulatedDelay - left channel begin failed"));
} while (1);
}
// chorus modulation fixed // chorus modulation fixed
memset(r_delayline, 0, sizeof(short)*CHORUS_DELAY_LENGTH); modulator.begin(CHORUS_WAVEFORM);
memset(l_delayline, 0, sizeof(short)*CHORUS_DELAY_LENGTH); modulator.amplitude(0.1);
modulator.begin(CHORUS_WAVEFORM); modulator.frequency(1.0);
modulator.amplitude(0.1); modulator.phase(0);
modulator.frequency(1.0); */
modulator.phase(0); // internal mixing of original signal(0), reverb(1) and chorus(2)
// chorus level fixed mixer_r.gain(0, 1.0);
mixer_l.gain(0, 1.0);
mixer_r.gain(2, 0.5); mixer_r.gain(2, 0.5);
mixer_l.gain(2, 0.5); mixer_l.gain(2, 0.5);
AudioInterrupts(); // set master volume
set_master_volume(master_volume);
Serial.println(F("<setup end>")); Serial.println(F("<setup end>"));
@ -534,7 +532,11 @@ void config_from_eeprom(void)
checksum = crc32((byte*)&tmp_conf + 4, sizeof(tmp_conf) - 4); checksum = crc32((byte*)&tmp_conf + 4, sizeof(tmp_conf) - 4);
#ifdef DEBUG #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(tmp_conf.checksum, HEX);
Serial.print(F(" / 0x")); Serial.print(F(" / 0x"));
Serial.print(checksum, HEX); Serial.print(checksum, HEX);
@ -543,8 +545,7 @@ void config_from_eeprom(void)
if (checksum == tmp_conf.checksum) if (checksum == tmp_conf.checksum)
{ {
EEPROM_readAnything(EEPROM_CONFIGURATIONS + sizeof(config_t) * (sound - 1), configuration); EEPROM_readAnything(EEPROM_CONFIGURATIONS + sizeof(config_t) * (sound - 1), configuration);
Serial.print(F(" - OK -> loading sound.")); Serial.print(F(" - OK"));
Serial.print(sound, DEC);
} }
else else
{ {
@ -552,6 +553,7 @@ void config_from_eeprom(void)
Serial.println(F(" - mismatch -> loading initial configuration.")); Serial.println(F(" - mismatch -> loading initial configuration."));
#endif #endif
set_complete_configuration(); set_complete_configuration();
EEPROM.update(EEPROM_SOUND, sound);
} }
show_sound(); show_sound();
} }
@ -571,12 +573,15 @@ void eeprom_config_write(uint8_t value)
void eeprom_config_update(void) void eeprom_config_update(void)
{ {
configuration.checksum = crc32((byte*)&configuration + 4, sizeof(configuration) - 4); 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(F("Updating EEPROM configuration for sound "));
Serial.print(eeprom_config_update_flag, DEC); Serial.print(eeprom_config_update_flag, DEC);
Serial.print(F(" with checksum 0x"));
Serial.print(configuration.checksum, HEX);
Serial.print(F(" at 0x")); Serial.print(F(" at 0x"));
Serial.println(EEPROM_CONFIGURATIONS + sizeof(config_t) * (eeprom_config_update_flag - 1), HEX); 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_config_update_flag = 0;
EEPROM.update(EEPROM_SOUND, sound);
} }
void eeprom_master_volume_write(void) void eeprom_master_volume_write(void)

@ -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. /// Configures the number of available variables per line.
const uint8_t MAX_VARIABLES = 5; ///< @note Default: 5 const uint8_t MAX_VARIABLES = 5; ///< @note Default: 5
@ -33,10 +34,10 @@
const uint8_t MAX_LINES = 20; ///< @note Default: 12 const uint8_t MAX_LINES = 20; ///< @note Default: 12
/// Configures the number of available screens per menu. /// 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. /// 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 CHORUS_INTENSITY MENU
******************************************/ ******************************************/
#define NUM_CHORUS_INTENSITY_MENUS 1 #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_line1(1, 0, chorus_intensity_text1);
LiquidLine chorus_intensity_line2(1, 1, configuration.chorus_intensity); LiquidLine chorus_intensity_line2(1, 1, configuration.chorus_intensity);
LiquidScreen chorus_intensity_screen; LiquidScreen chorus_intensity_screen;
@ -1766,9 +1767,9 @@ void load_sound(void)
{ {
#ifdef DEBUG #ifdef DEBUG
Serial.print(F("Load sound ")); Serial.print(F("Load sound "));
Serial.println(sound); Serial.println(sound, DEC);
#endif #endif
EEPROM.write(EEPROM_SOUND, sound); EEPROM.update(EEPROM_SOUND, sound);
config_from_eeprom(); config_from_eeprom();
} }

@ -62,7 +62,7 @@
#define USE_XFADE_DATA 1 #define USE_XFADE_DATA 1
// CHORUS parameters // CHORUS parameters
#define INTERPOLATION_WINDOW_SIZE 7 // For chorus, only odd numbers,please! #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_WAVEFORM WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE WAVEFORM_SQUARE WAVEFORM_TRIANGLE
#define CHORUS_DELAY_LENGTH (16*AUDIO_BLOCK_SAMPLES) #define CHORUS_DELAY_LENGTH (16*AUDIO_BLOCK_SAMPLES)

@ -33,19 +33,19 @@
// Written by Pete (El Supremo) Jan 2014 // Written by Pete (El Supremo) Jan 2014
// 140529 - change to handle mono stream - change modify() to voices() // 140529 - change to handle mono stream - change modify() to voices()
// 140219 - correct storage class (not static) // 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 #if 0
Serial.print("AudioModulatedEffectChorus.begin(Chorus delay line length = "); Serial.print("AudioEffectModulatedDelay.begin(Chorus delay line length = ");
Serial.print(d_length); Serial.print(d_length);
Serial.println(")"); Serial.println(")");
#endif #endif
l_delayline = NULL; _delayline = NULL;
delay_length = 0; _delay_length = 0;
l_circ_idx = 0; _circ_idx = 0;
if (delayline == NULL) { if (delayline == NULL) {
return (false); return (false);
@ -54,43 +54,47 @@ boolean AudioModulatedEffectChorus::begin(short *delayline, int d_length)
return (false); return (false);
} }
l_delayline = delayline; _delayline = delayline;
delay_length = d_length; _delay_length = d_length;
delay_length_half = d_length / 2; _delay_length_half = d_length / 2;
memset(_delayline, 0, sizeof(short)*_delay_length);
return (true); return (true);
} }
//int last_idx = 0; //int last_idx = 0;
void AudioModulatedEffectChorus::update(void) void AudioEffectModulatedDelay::update(void)
{ {
audio_block_t *block; audio_block_t *block;
audio_block_t *modulation; audio_block_t *modulation;
short *bp; short *bp;
short *mp; short *mp;
float mod_idx; float mod_idx;
if (_delayline == NULL)
return;
#ifdef INTERPOLATE #ifdef INTERPOLATE
interpolation* modulation_interpolate; interpolation modulation_interpolate;
modulation_interpolate = new interpolation;
#endif #endif
if (l_delayline == NULL)
return;
block = receiveWritable(0); block = receiveWritable(0);
modulation = receiveReadOnly(1); modulation = receiveReadOnly(1);
if (block && modulation) if (block && modulation)
{ {
#ifdef INTERPOLATE #ifdef INTERPOLATE
uint8_t j; int8_t j;
int16_t interpolation_idx;
float x[INTERPOLATION_WINDOW_SIZE]; float x[INTERPOLATION_WINDOW_SIZE];
float y[INTERPOLATION_WINDOW_SIZE]; float y[INTERPOLATION_WINDOW_SIZE];
modulation_interpolate->valuelenXY(INTERPOLATION_WINDOW_SIZE); modulation_interpolate.valuelenXY(INTERPOLATION_WINDOW_SIZE);
modulation_interpolate->valueX(x); modulation_interpolate.valueX(x);
modulation_interpolate->valueY(y); modulation_interpolate.valueY(y);
for (j = 0; j < INTERPOLATION_WINDOW_SIZE; j++)
x[j] = j;
#endif #endif
bp = block->data; bp = block->data;
@ -99,64 +103,60 @@ void AudioModulatedEffectChorus::update(void)
for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
{ {
// write data into circular buffer // write data into circular buffer
if (l_circ_idx >= delay_length) if (_circ_idx >= _delay_length)
l_circ_idx = 0; _circ_idx = 0;
l_delayline[l_circ_idx] = *bp; // write signal into circular buffer _delayline[_circ_idx] = *bp;
// calculate modulation index // calculate modulation index
mod_idx = float(*mp) / SHRT_MAX * delay_length_half + l_circ_idx; // calculate index with modulation as a float 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)) if (mod_idx > float(_delay_length - 1))
mod_idx = mod_idx - float(delay_length - 1); mod_idx = mod_idx - float(_delay_length - 1);
else if (mod_idx < 0.0) else if (mod_idx < 0.0)
mod_idx = float(delay_length - 1) + mod_idx; mod_idx = float(_delay_length - 1) + mod_idx;
#ifdef INTERPOLATE #ifdef INTERPOLATE
// get value with interpolation // get x/y values around mod_idx
interpolation_idx = int(mod_idx + 0.5) + (INTERPOLATION_WINDOW_SIZE / -2); uint16_t i_mod_idx = int(mod_idx + 0.5);
for (j = interpolation_idx; j < INTERPOLATION_WINDOW_SIZE; j++) for (j = INTERPOLATION_WINDOW_SIZE / -2; j <= INTERPOLATION_WINDOW_SIZE / 2; j++)
{ {
x[j] = interpolation_idx; int16_t ji_mod_idx = i_mod_idx + j;
if (ji_mod_idx > _delay_length)
if (j >= delay_length) y[j] = _delayline[ji_mod_idx - _delay_length - 1];
y[j] = l_delayline[j - delay_length]; else if (ji_mod_idx < 0)
else if (j < 0) y[j] = _delayline[_delay_length + j + 1];
y[j] = l_delayline[delay_length + j]; else
y[j] = _delayline[ji_mod_idx];
} }
modulation_interpolate->valueI(mod_idx); modulation_interpolate.valueI(mod_idx);
#if INTERPOLATE == CUBIC #if INTERPOLATE == CUBIC
*bp = int(modulation_interpolate->CubicInterpolate() + 0.5); *bp = int(modulation_interpolate.CubicInterpolate() + 0.5);
#elif INTERPOLATE == LINEAR #elif INTERPOLATE == LINEAR
*bp = int(modulation_interpolate->LinearInterpolate() + 0.5); *bp = int(modulation_interpolate.LinearInterpolate() + 0.5);
#elif INTERPOLATE == COSINE #elif INTERPOLATE == COSINE
*bp = int(modulation_interpolate->CosineInterpolate() + 0.5); *bp = int(modulation_interpolate.CosineInterpolate() + 0.5);
#elif INTERPOLATE == LAGRANGE #elif INTERPOLATE == LAGRANGE
*bp = int(modulation_interpolate->LagrangeInterpolate() + 0.5); *bp = int(modulation_interpolate.LagrangeInterpolate() + 0.5);
#elif INTERPOLATE == QUDRATIC #elif INTERPOLATE == QUDRATIC
*bp = int(modulation_interpolate->QuadraticInterpolate() + 0.5); *bp = int(modulation_interpolate.QuadraticInterpolate() + 0.5);
#else #else
// No interpolation - should sound really bad... // No interpolation - should sound really bad...
*bp = l_delayline[int(mod_idx + 0.5)]; *bp = _delayline[int(mod_idx + 0.5)];
#endif #endif
#else #else
// No interpolation - should sound really bad... // No interpolation - should sound really bad...
*bp = l_delayline[int(mod_idx + 0.5)]; *bp = _delayline[int(mod_idx + 0.5)];
#endif #endif
bp++; bp++;
mp++; mp++;
l_circ_idx++; _circ_idx++;
} }
// transmit the block
transmit(block, 0);
release(block);
release(modulation);
} }
#ifdef INTERPOLATION // transmit the block
if (modulation_interpolate) transmit(block, 0);
delete(modulation_interpolate); release(block);
#endif release(modulation);
} }

@ -32,15 +32,15 @@
// A u d i o E f f e c t C h o r u s // A u d i o E f f e c t C h o r u s
// Written by Pete (El Supremo) Jan 2014 // Written by Pete (El Supremo) Jan 2014
// 140219 - correct storage class (not static) // 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 #define CHORUS_DELAY_PASSTHRU -1
class AudioModulatedEffectChorus : class AudioEffectModulatedDelay :
public AudioStream public AudioStream
{ {
public: public:
AudioModulatedEffectChorus(void): AudioEffectModulatedDelay(void):
AudioStream(2, inputQueueArray) AudioStream(2, inputQueueArray)
{ } { }
@ -50,10 +50,10 @@ class AudioModulatedEffectChorus :
private: private:
audio_block_t *inputQueueArray[2]; audio_block_t *inputQueueArray[2];
short *l_delayline; short *_delayline;
short l_circ_idx; short _circ_idx;
int delay_length; int _delay_length;
int delay_length_half; int _delay_length_half;
}; };
#endif #endif

Loading…
Cancel
Save