Fixed storing and loading of sounds.

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

@ -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"));
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"));
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
*/
// 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("<setup end>"));
@ -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)

@ -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();
}

@ -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)

@ -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
}

@ -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

Loading…
Cancel
Save