Merge branch 'dev-modulated-delay'

master
Holger Wirtz 5 years ago
commit ce694ac9bb
  1. 26
      EEPROMAnything.h
  2. 8
      Encoder4.h
  3. 385
      MicroMDAEPiano.ino
  4. 746
      UI.hpp
  5. 107
      config.h
  6. 134
      effect_modulated_delay.cpp
  7. 58
      effect_modulated_delay.h
  8. 70
      mdaEPiano.cpp
  9. 10
      mdaEPiano.h
  10. 42244
      mdaEPianoData.h
  11. 42244
      mdaEPianoDataXfade.h
  12. 456
      midi_devices.hpp
  13. 6
      midinotes.h
  14. 8
      name.c
  15. 2
      utility/gen_xfade.sh

@ -21,7 +21,7 @@
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
// Idea from: https://playground.arduino.cc/Code/EEPROMWriteAnything/ // Idea from: https://playground.arduino.cc/Code/EEPROMWriteAnything/
#include <EEPROM.h> #include <EEPROM.h>
#include <Arduino.h> // for type definitions #include <Arduino.h> // for type definitions
@ -30,22 +30,22 @@ uint32_t crc32(uint8_t* calc_start, uint16_t calc_bytes);
template <class T> int EEPROM_writeAnything(int ee, const T& value) template <class T> int EEPROM_writeAnything(int ee, const T& value)
{ {
uint8_t* p = (uint8_t*)(const void*)&value; uint8_t* p = (uint8_t*)(const void*)&value;
uint16_t i; uint16_t i;
uint32_t checksum=crc32(p+4,sizeof(value)-4); uint32_t checksum = crc32(p + 4, sizeof(value) - 4);
*p=checksum; *p = checksum;
for (i = 0; i < sizeof(value); i++) for (i = 0; i < sizeof(value); i++)
EEPROM.update(ee++, *p++); EEPROM.update(ee++, *p++);
return i; return i;
} }
template <class T> int EEPROM_readAnything(int ee, T& value) template <class T> int EEPROM_readAnything(int ee, T& value)
{ {
uint8_t* p = (uint8_t*)(void*)&value; uint8_t* p = (uint8_t*)(void*)&value;
unsigned int i; unsigned int i;
for (i = 0; i < sizeof(value); i++) for (i = 0; i < sizeof(value); i++)
*p++ = EEPROM.read(ee++); *p++ = EEPROM.read(ee++);
return i; return i;
} }

@ -61,11 +61,11 @@ class Encoder4 : public Encoder
{ {
Encoder::write(p * 4); Encoder::write(p * 4);
} }
void write(int32_t p, int32_t min, int32_t max, bool wrap_around=false) void write(int32_t p, int32_t min, int32_t max, bool wrap_around = false)
{ {
_wrap_around=wrap_around; _wrap_around = wrap_around;
if (max < min) if (max < min)
{ {
_min = max; _min = max;

@ -21,15 +21,14 @@
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "config.h"
#include <Audio.h> #include <Audio.h>
#include <Wire.h> #include <Wire.h>
#include <SPI.h> #include <SPI.h>
#include <MIDI.h> #include <MIDI.h>
#include <EEPROM.h> #include <EEPROM.h>
#include "EEPROMAnything.h" #include "EEPROMAnything.h"
#include <limits.h>
#include "mdaEPiano.h" #include "mdaEPiano.h"
#include "effect_modulated_delay.h"
#ifdef USE_XFADE_DATA #ifdef USE_XFADE_DATA
#include "mdaEPianoDataXfade.h" #include "mdaEPianoDataXfade.h"
#else #else
@ -37,6 +36,7 @@
#endif #endif
#include "UI.hpp" #include "UI.hpp"
#include "midi_devices.hpp" #include "midi_devices.hpp"
#include "config.h"
//************************************************************************************************* //*************************************************************************************************
//* GLOBAL VARIABLES //* GLOBAL VARIABLES
@ -53,31 +53,47 @@ AudioMixer4 mixer_r;
AudioMixer4 mixer_l; AudioMixer4 mixer_l;
AudioAmplifier volume_r; AudioAmplifier volume_r;
AudioAmplifier volume_l; AudioAmplifier volume_l;
AudioAmplifier inverter;
AudioEffectModulatedDelay modchorus_r;
AudioEffectModulatedDelay modchorus_l;
#if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT
AudioFilterBiquad modchorus_filter_r;
AudioFilterBiquad modchorus_filter_l;
#endif
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);
AudioConnection patchCord4(queue_r, freeverb_r); AudioConnection patchCord2(queue_r, freeverb_r);
AudioConnection patchCord5(queue_l, freeverb_l); AudioConnection patchCord3(queue_l, freeverb_l);
AudioConnection patchCord6(queue_r, 0, mixer_r, 0); AudioConnection patchCord4(queue_r, 0, modchorus_r, 0);
AudioConnection patchCord7(queue_l, 0, mixer_l, 0); AudioConnection patchCord5(queue_l, 0, modchorus_l, 0);
AudioConnection patchCord8(freeverb_r, 0, mixer_r, 1); AudioConnection patchCord6(modulator, 0, modchorus_r, 1);
AudioConnection patchCord9(freeverb_l, 0, mixer_l, 1); AudioConnection patchCord7(modulator, inverter);
AudioConnection patchCord10(mixer_r, volume_r); AudioConnection patchCord8(inverter, 0, modchorus_l, 1);
AudioConnection patchCord11(mixer_l, volume_l); AudioConnection patchCord9(queue_r, 0, mixer_r, 0);
#if defined(TEENSY_AUDIO_BOARD) AudioConnection patchCord10(queue_l, 0, mixer_l, 0);
AudioOutputI2S i2s1; #if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT
AudioConnection patchCord12(volume_r, 0, i2s1, 0); AudioConnection patchCord11(modchorus_r, modchorus_filter_r);
AudioConnection patchCord13(volume_l, 0, i2s1, 1); AudioConnection patchCord12(modchorus_l, modchorus_filter_l);
AudioControlSGTL5000 sgtl5000_1; AudioConnection patchCord13(modchorus_filter_r, 0, mixer_r, 2);
#elif defined(TGA_AUDIO_BOARD) AudioConnection patchCord14(modchorus_filter_l, 0, mixer_l, 2);
AudioOutputI2S i2s1;
AudioConnection patchCord12(volume_r, 0, i2s1, 1);
AudioConnection patchCord13(volume_l, 0, i2s1, 0);
AudioControlWM8731master wm8731_1;
#else #else
AudioOutputPT8211 pt8211_1; AudioConnection patchCord11(modchorus_r, mixer_r);
AudioConnection patchCord12(volume_r, 0, pt8211_1, 1); AudioConnection patchCord12(modchorus_l, mixer_l);
AudioConnection patchCord13(volume_l, 0, pt8211_1, 0);
#endif #endif
AudioConnection patchCord15(freeverb_r, 0, mixer_r, 1);
AudioConnection patchCord16(freeverb_l, 0, mixer_l, 1);
AudioConnection patchCord17(mixer_r, volume_r);
AudioConnection patchCord18(mixer_l, volume_l);
#ifdef USB_AUDIO
AudioOutputUSB usb1;
AudioConnection patchCord19(volume_r, 0, usb1, 0);
AudioConnection patchCord20(volume_l, 0, usb1, 1);
#endif
AudioOutputI2S i2s1;
AudioConnection patchCord21(volume_r, 0, i2s1, 0);
AudioConnection patchCord22(volume_l, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1;
// Objects // Objects
mdaEPiano* ep; mdaEPiano* ep;
@ -119,7 +135,8 @@ config_t configuration = {
ENC_REVERB_DAMPING_DEFAULT, // reverb_damping ENC_REVERB_DAMPING_DEFAULT, // reverb_damping
ENC_REVERB_LEVEL_DEFAULT, // reverb_level ENC_REVERB_LEVEL_DEFAULT, // reverb_level
ENC_CHORUS_FREQUENCY_DEFAULT, // chorus_frequency ENC_CHORUS_FREQUENCY_DEFAULT, // chorus_frequency
ENC_CHORUS_DELAY_DEFAULT, // chorus_delay ENC_CHORUS_INTENSITY_DEFAULT, // chorus_intensity
ENC_CHORUS_WAVEFORM_DEFAULT, // chorus_waveform
ENC_CHORUS_LEVEL_DEFAULT, // chorus_level ENC_CHORUS_LEVEL_DEFAULT, // chorus_level
ENC_BASS_LR_LEVEL_DEFAULT, // bass_lr_level ENC_BASS_LR_LEVEL_DEFAULT, // bass_lr_level
ENC_BASS_MONO_LEVEL_DEFAULT, // bass_mono_level ENC_BASS_MONO_LEVEL_DEFAULT, // bass_mono_level
@ -129,10 +146,10 @@ config_t configuration = {
ENC_MIDI_CHANNEL_DEFAULT, // midi_channel ENC_MIDI_CHANNEL_DEFAULT, // midi_channel
ENC_MIDI_SOFT_THRU_DEFAULT, // midi_soft_thru ENC_MIDI_SOFT_THRU_DEFAULT, // midi_soft_thru
ENC_MAX_POLY_DEFAULT, // max_poly ENC_MAX_POLY_DEFAULT, // max_poly
0 // pan ENC_MONO_DEFAULT, // mono
ENC_MASTER_PAN_DEFAULT // pan
}; };
float _loudness = mapfloat(float(ENC_LOUDNESS_DEFAULT), ENC_LOUDNESS_MIN, ENC_LOUDNESS_MAX, 0.0, 1.0);
uint8_t master_volume = ENC_MASTER_VOLUME_DEFAULT; uint8_t master_volume = ENC_MASTER_VOLUME_DEFAULT;
int8_t pan = ENC_MASTER_PAN_DEFAULT; int8_t pan = ENC_MASTER_PAN_DEFAULT;
uint8_t eeprom_config_update_flag = 0; uint8_t eeprom_config_update_flag = 0;
@ -143,6 +160,15 @@ elapsedMillis eeprom_master_volume_update_timer;
elapsedMillis cpu_mem_millis; elapsedMillis cpu_mem_millis;
#endif #endif
#ifdef DEBUG_AUDIO
elapsedMillis debug_audio_timer;
#endif
// Allocate the delay lines for left and right channels
short l_delayline[MOD_DELAY_SAMPLE_BUFFER];
short r_delayline[MOD_DELAY_SAMPLE_BUFFER];
enum { VOL_MAIN, VOL_REVERB, VOL_CHORUS };
//************************************************************************************************* //*************************************************************************************************
//* SETUP FUNCTION //* SETUP FUNCTION
//************************************************************************************************* //*************************************************************************************************
@ -169,8 +195,8 @@ void setup()
// create EPiano object // create EPiano object
ep = new mdaEPiano(); ep = new mdaEPiano();
// set initial init configuration
set_complete_configuration(); set_complete_configuration();
initial_values_from_eeprom();
setup_midi_devices(); setup_midi_devices();
@ -178,7 +204,6 @@ void setup()
AudioNoInterrupts(); AudioNoInterrupts();
AudioMemory(AUDIO_MEM); AudioMemory(AUDIO_MEM);
#ifdef TEENSY_AUDIO_BOARD
sgtl5000_1.enable(); sgtl5000_1.enable();
sgtl5000_1.dacVolumeRamp(); sgtl5000_1.dacVolumeRamp();
sgtl5000_1.dacVolume(1.0); sgtl5000_1.dacVolume(1.0);
@ -191,33 +216,87 @@ void setup()
sgtl5000_1.autoVolumeEnable(); sgtl5000_1.autoVolumeEnable();
sgtl5000_1.enhanceBassEnable(); sgtl5000_1.enhanceBassEnable();
Serial.println(F("Teensy-Audio-Board enabled.")); Serial.println(F("Teensy-Audio-Board enabled."));
#elif defined(TGA_AUDIO_BOARD)
wm8731_1.enable();
wm8731_1.volume(1.0);
Serial.println(F("TGA board enabled."));
#else
Serial.println(F("PT8211 enabled."));
#endif
set_master_volume(master_volume);
#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) #if defined (SHOW_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("us)"));
AudioInterrupts(); if (!modchorus_r.begin(r_delayline, MOD_DELAY_SAMPLE_BUFFER)) {
Serial.println(F("AudioEffectModulatedDelay - right channel begin failed"));
while (1);
}
if (!modchorus_l.begin(l_delayline, MOD_DELAY_SAMPLE_BUFFER)) {
Serial.println(F("AudioEffectModulatedDelay - left channel begin failed"));
while (1);
}
#ifdef DEBUG
Serial.print(F("MOD_DELAY_SAMPLE_BUFFER="));
Serial.print(MOD_DELAY_SAMPLE_BUFFER, DEC);
Serial.println(F(" samples"));
#endif
// chorus modulation fixed
modulator.begin(MOD_WAVEFORM);
modulator.phase(0);
modulator.amplitude(0.5);
modulator.offset(0.0);
#if MOD_FILTER_OUTPUT == MOD_BUTTERWORTH_FILTER_OUTPUT
// Butterworth filter, 12 db/octave
modchorus_filter_r.setLowpass(0, MOD_FILTER_CUTOFF_HZ, 0.707);
modchorus_filter_l.setLowpass(0, MOD_FILTER_CUTOFF_HZ, 0.707);
#elif MOD_FILTER_OUTPUT == MOD_LINKWITZ_RILEY_FILTER_OUTPUT
// Linkwitz-Riley filter, 48 dB/octave
modchorus_filter_r.setLowpass(0, MOD_FILTER_CUTOFF_HZ, 0.54);
modchorus_filter_r.setLowpass(1, MOD_FILTER_CUTOFF_HZ, 1.3);
modchorus_filter_r.setLowpass(2, MOD_FILTER_CUTOFF_HZ, 0.54);
modchorus_filter_r.setLowpass(3, MOD_FILTER_CUTOFF_HZ, 1.3);
modchorus_filter_l.setLowpass(0, MOD_FILTER_CUTOFF_HZ, 0.54);
modchorus_filter_l.setLowpass(1, MOD_FILTER_CUTOFF_HZ, 1.3);
modchorus_filter_l.setLowpass(2, MOD_FILTER_CUTOFF_HZ, 0.54);
modchorus_filter_l.setLowpass(3, MOD_FILTER_CUTOFF_HZ, 1.3);
#endif
// internal mixing of original signal(0), reverb(1) and chorus(2)
mixer_r.gain(VOL_MAIN, 0.5);
mixer_l.gain(VOL_MAIN, 0.5);
mixer_r.gain(VOL_REVERB, 0.2);
mixer_l.gain(VOL_REVERB, 0.2);
mixer_r.gain(VOL_CHORUS, 0.2);
mixer_l.gain(VOL_CHORUS, 0.2);
// Stereo/Mono initial setup
if (configuration.mono == 0)
{
inverter.gain(-1.0); // change phase for second modulated delay (faked stereo mode)
}
else
{
inverter.gain(1.0);
configuration.pan = ENC_MASTER_PAN_DEFAULT;
}
// set master volume
set_master_volume(master_volume);
// load last configuration used
initial_values_from_eeprom();
// init random generator
srand(analogRead(A0));
Serial.println(F("<setup end>")); Serial.println(F("<setup end>"));
#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) #if defined (SHOW_DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
Serial.println(); Serial.println();
show_cpu_and_mem_usage(); show_cpu_and_mem_usage();
cpu_mem_millis = 0; cpu_mem_millis = 0;
@ -238,7 +317,7 @@ void loop()
{ {
fill_audio_buffer = 0; fill_audio_buffer = 0;
#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) #if defined (SHOW_DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
if (cpu_mem_millis > SHOW_CPU_LOAD_MSEC) if (cpu_mem_millis > SHOW_CPU_LOAD_MSEC)
{ {
show_cpu_and_mem_usage(); show_cpu_and_mem_usage();
@ -290,9 +369,17 @@ void loop()
if ( eeprom_config_update_flag > 0 && ep->getActiveVoices() == 0) // write only to eeprom when no voice is active if ( eeprom_config_update_flag > 0 && ep->getActiveVoices() == 0) // write only to eeprom when no voice is active
eeprom_config_update(); 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(); 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
} }
//************************************************************************************************* //*************************************************************************************************
@ -318,7 +405,107 @@ void handleControlChange(byte inChannel, byte inData1, byte inData2)
{ {
if (checkMidiChannel(inChannel)) if (checkMidiChannel(inChannel))
{ {
ep->processMidiController(inData1, inData2); switch (inData1)
{
// Standard MIDI-CC
case MIDI_CC_PANORAMA: // Panorama
configuration.pan = map(inData2, 0, 127, ENC_MASTER_PAN_MIN, ENC_MASTER_PAN_MAX);
break;
case MIDI_CC_REVERB_SEND: // Reverb level
set_reverb_level(map(inData2, 0, 127, ENC_REVERB_LEVEL_MIN, ENC_REVERB_LEVEL_MAX));
break;
case MIDI_CC_TREMOLO_DEPTH: // Tremolo level (same as modwheel)
inData1 = 1; // now it's modwheel and can be processd by ep->processMidiController :-)
break;
case MIDI_CC_CHORUS_SEND: // Chorus level
set_chorus_level(map(inData2, 0, 127, ENC_CHORUS_LEVEL_MIN, ENC_CHORUS_LEVEL_MAX));
break;
case MIDI_CC_DETUNE_DEPTH: // Detune level
ep->setDetune(mapfloat(float(inData2), 0, 127, 0.0, 1.0));
break;
// Own MIDI-CC mapping
case MIDI_CC_EP_DECAY:
ep->setDecay(mapfloat(float(inData2), 0, 127, 0.0, 1.0));
break;
case MIDI_CC_EP_RELEASE:
ep->setRelease(mapfloat(float(inData2), 0, 127, 0.0, 1.0));
break;
case MIDI_CC_EP_HARDNESS:
ep->setHardness(mapfloat(float(inData2), 0, 127, 0.0, 1.0));
break;
case MIDI_CC_EP_TREBLE:
ep->setTreble(mapfloat(float(inData2), 0, 127, 0.0, 1.0));
break;
case MIDI_CC_EP_STEREO:
ep->setStereo(mapfloat(float(inData2), 0, 127, 0.0, 1.0));
break;
case MIDI_CC_EP_TUNE:
ep->setTune(mapfloat(float(inData2), 0, 127, 0.0, 1.0));
break;
case MIDI_CC_EP_VELOCITY_SENSE:
ep->setVelocitySense(mapfloat(float(inData2), 0, 127, 0.0, 1.0));
break;
case MIDI_CC_EP_TREM_FRQ:
ep->setPanLFO(mapfloat(float(inData2), 0, 127, 0.0, 1.0));
break;
case MIDI_CC_EP_OVERDRIVE:
ep->setOverdrive(mapfloat(float(inData2), 0, 127, 0.0, 1.0));
break;
case MIDI_CC_COMP_GAIN:
set_comp_gain(map(inData2, 0, 127, ENC_COMP_GAIN_MIN, ENC_COMP_GAIN_MAX));
break;
case MIDI_CC_COMP_REPOSNE:
set_comp_response(map(inData2, 0, 127, ENC_COMP_RESPONSE_MIN, ENC_COMP_RESPONSE_MAX));
break;
case MIDI_CC_COMP_LIMIT:
set_comp_limit(map(inData2, 0, 127, ENC_COMP_LIMIT_MIN, ENC_COMP_LIMIT_MAX));
break;
case MIDI_CC_COMP_THRESHOLD:
set_comp_threshold(map(inData2, 0, 127, ENC_COMP_THRESHOLD_MIN, ENC_COMP_THRESHOLD_MAX));
break;
case MIDI_CC_COMP_ATTACK:
set_comp_attack(map(inData2, 0, 127, ENC_COMP_ATTACK_MIN, ENC_COMP_ATTACK_MAX));
break;
case MIDI_CC_COMP_DECAY:
set_comp_decay(map(inData2, 0, 127, ENC_COMP_DECAY_MIN, ENC_COMP_DECAY_MAX));
break;
case MIDI_CC_REVERB_ROOMSIZE:
set_reverb_roomsize(map(inData2, 0, 127, ENC_REVERB_ROOMSIZE_MIN, ENC_REVERB_ROOMSIZE_MAX));
break;
case MIDI_CC_REVERB_DAMPING:
set_reverb_damping(map(inData2, 0, 127, ENC_REVERB_DAMPING_MIN, ENC_REVERB_DAMPING_MAX));
break;
case MIDI_CC_CHORUS_FREQUENCY:
set_chorus_frequency(map(inData2, 0, 127, ENC_CHORUS_FREQUENCY_MIN, ENC_CHORUS_FREQUENCY_MAX));
break;
case MIDI_CC_CHORUS_INTENSITY:
set_chorus_intensity(map(inData2, 0, 127, ENC_CHORUS_INTENSITY_MIN, ENC_CHORUS_INTENSITY_MAX));
break;
case MIDI_CC_CHORUS_WAVEFORM:
set_chorus_waveform(map(inData2, 0, 127, ENC_CHORUS_WAVEFORM_MIN, ENC_CHORUS_WAVEFORM_MAX));
break;
case MIDI_CC_BASS_LR_LEVEL:
set_bass_lr_level(map(inData2, 0, 127, ENC_BASS_LR_LEVEL_MIN, ENC_BASS_LR_LEVEL_MAX));
break;
case MIDI_CC_BASS_MONO_LEVEL:
set_bass_mono_level(map(inData2, 0, 127, ENC_BASS_MONO_LEVEL_MIN, ENC_BASS_MONO_LEVEL_MAX));
break;
case MIDI_CC_EQ_BASS:
set_eq_bass(map(inData2, 0, 127, ENC_EQ_BASS_MIN, ENC_EQ_BASS_MAX));
break;
case MIDI_CC_EQ_TREBLE:
set_eq_treble(map(inData2, 0, 127, ENC_EQ_TREBLE_MIN, ENC_EQ_TREBLE_MAX));
break;
case MIDI_CC_MIDI_SOFT_THRU:
set_midi_soft_thru(map(inData2, 0, 127, ENC_MIDI_SOFT_THRU_MIN, ENC_MIDI_SOFT_THRU_MAX));
break;
case MIDI_CC_MONO:
set_mono(map(inData2, 0, 127, ENC_MONO_MIN, ENC_MONO_MAX));
break;
default:
ep->processMidiController(inData1, inData2);
break;
}
} }
} }
@ -334,15 +521,21 @@ void handlePitchBend(byte inChannel, int inPitch)
void handleProgramChange(byte inChannel, byte inProgram) void handleProgramChange(byte inChannel, byte inProgram)
{ {
; if (checkMidiChannel(inChannel))
{
sound = inProgram;
load_sound();
if (menu_system.get_currentScreen() == &load_sound_screen)
menu_system.update();
}
} }
void handleSystemExclusive(byte *data, uint len) void handleSystemExclusive(byte * data, uint len)
{ {
; ;
} }
void handleSystemExclusiveChunk(const byte *data, uint16_t len, bool last) void handleSystemExclusiveChunk(const byte * data, uint16_t len, bool last)
{ {
; ;
} }
@ -411,7 +604,7 @@ bool checkMidiChannel(byte inChannel)
} }
else if (inChannel != configuration.midi_channel) else if (inChannel != configuration.midi_channel)
{ {
#ifdef DEBUG #ifdef SHOW_DEBUG
Serial.print(F("Ignoring MIDI data on channel ")); Serial.print(F("Ignoring MIDI data on channel "));
Serial.print(inChannel); Serial.print(inChannel);
Serial.print(F("(listening on ")); Serial.print(F("(listening on "));
@ -425,11 +618,11 @@ bool checkMidiChannel(byte inChannel)
void set_master_volume(uint8_t value) void set_master_volume(uint8_t value)
{ {
configuration.pan = 0; // BAD HACK! //configuration.pan = 0; // BAD HACK!
uint16_t tmp = map(value, ENC_MASTER_VOLUME_MIN, ENC_MASTER_VOLUME_MAX, 0, 0x3ff); uint16_t tmp = map(value, ENC_MASTER_VOLUME_MIN, ENC_MASTER_VOLUME_MAX, 0, 0x3ff);
float tmp2 = mapfloat(configuration.pan, ENC_MASTER_PAN_MIN, ENC_MASTER_PAN_MAX, 0.0, 1.0); float tmp2 = mapfloat(configuration.pan, ENC_MASTER_PAN_MIN, ENC_MASTER_PAN_MAX, 0.0, 1.0);
float tmp3 = (float)(tmp * (tmp + 2)) / (float)(1 << 20); float tmp3 = (float)(tmp * (tmp + 2)) / (float)(1 << 20);
#ifdef DEBUG #ifdef SHOW_DEBUG
Serial.print(F("Setting volume: VOL=")); Serial.print(F("Setting volume: VOL="));
Serial.print(value, DEC); Serial.print(value, DEC);
Serial.print(F("[")); Serial.print(F("["));
@ -446,11 +639,18 @@ void set_master_volume(uint8_t value)
// float v = (float)(a * (a + 2))/(float)(1 << 20); // (pseudo-) logarithmic curve for volume control // float v = (float)(a * (a + 2))/(float)(1 << 20); // (pseudo-) logarithmic curve for volume control
// http://files.csound-tutorial.net/floss_manual/Release03/Cs_FM_03_ScrapBook/b-panning-and-spatialization.html // http://files.csound-tutorial.net/floss_manual/Release03/Cs_FM_03_ScrapBook/b-panning-and-spatialization.html
mixer_r.gain(0, tmp3 * sinf(tmp2 * PI / 2)); volume_r.gain(tmp3 * sinf(tmp2 * PI / 2));
mixer_l.gain(0, tmp3 * cosf(tmp2 * PI / 2)); volume_l.gain(tmp3 * cosf(tmp2 * PI / 2));
if (configuration.mono == 2)
volume_l.gain(0.0);
else if (configuration.mono == 3)
volume_r.gain(0.0);
eeprom_master_volume_update_flag = true; eeprom_master_volume_update_flag = true;
eeprom_master_volume_update_timer = 0; eeprom_master_volume_update_timer = 0;
if (menu_system.get_currentScreen() == &master_volume_screen)
menu_system.update();
} }
/****************************************************************************** /******************************************************************************
@ -465,8 +665,12 @@ void config_from_eeprom(void)
EEPROM_readAnything(EEPROM_CONFIGURATIONS + sizeof(config_t) * (sound - 1), tmp_conf); EEPROM_readAnything(EEPROM_CONFIGURATIONS + sizeof(config_t) * (sound - 1), tmp_conf);
checksum = crc32((byte*)&tmp_conf + 4, sizeof(tmp_conf) - 4); checksum = crc32((byte*)&tmp_conf + 4, sizeof(tmp_conf) - 4);
#ifdef DEBUG #ifdef SHOW_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);
@ -475,57 +679,29 @@ 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 config ")); #ifdef SHOW_DEBUG
Serial.print(sound, DEC); Serial.println(F(" - OK"));
#endif
} }
else else
#ifdef DEBUG
{ {
Serial.println(F(" - mismatch (or force) -> nothing done!")); #ifdef SHOW_DEBUG
Serial.println(F(" - mismatch -> loading initial configuration."));
#endif
EEPROM.update(EEPROM_SOUND, sound);
} }
set_complete_configuration();
#ifdef SHOW_DEBUG
show_sound(); show_sound();
#endif #endif
} }
void initial_values_from_eeprom(void) void initial_values_from_eeprom(void)
{ {
uint32_t checksum; master_volume = EEPROM.read(EEPROM_MASTER_VOLUME);
config_t tmp_conf; sound = EEPROM.read(EEPROM_SOUND);
load_sound();
EEPROM_readAnything(EEPROM_CONFIGURATIONS + sizeof(config_t) * (sound - 1), tmp_conf);
checksum = crc32((byte*)&tmp_conf + 4, sizeof(tmp_conf) - 4);
#ifdef DEBUG
Serial.print(F("EEPROM checksum: 0x"));
Serial.print(tmp_conf.checksum, HEX);
Serial.print(F(" / 0x"));
Serial.print(checksum, HEX);
#endif
if (checksum != tmp_conf.checksum || (but[0].read() == LOW && but[1].read() == LOW))
{
#ifdef DEBUG
Serial.println(F(" - mismatch (or force) -> initializing EEPROM!"));
#endif
eeprom_config_update_flag = sound;
eeprom_config_update();
}
else
{
sound = EEPROM.read(EEPROM_SOUND);
master_volume = EEPROM.read(EEPROM_MASTER_VOLUME);
EEPROM_readAnything(EEPROM_CONFIGURATIONS + sizeof(config_t) * (sound - 1), configuration);
Serial.print(F(" - OK, loading"));
}
#ifdef DEBUG
Serial.print(F(" - Master volume: "));
Serial.print(master_volume, DEC);
Serial.print(F(" - Sound: "));
Serial.println(sound, DEC);
Serial.print(F("Max configs in EEPROM: "));
Serial.println(MAX_SOUNDS);
show_sound();
#endif
} }
void eeprom_config_write(uint8_t value) void eeprom_config_write(uint8_t value)
@ -536,12 +712,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)
@ -581,7 +760,7 @@ uint32_t crc32(byte * calc_start, uint16_t calc_bytes) // base code from https:/
//* DEBUG FUNCTIONS //* DEBUG FUNCTIONS
//************************************************************************************************* //*************************************************************************************************
#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) #if defined (SHOW_DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
void show_cpu_and_mem_usage(void) void show_cpu_and_mem_usage(void)
{ {
Serial.print(F("CPU: ")); Serial.print(F("CPU: "));
@ -610,6 +789,7 @@ void show_cpu_and_mem_usage(void)
void show_sound(void) void show_sound(void)
{ {
Serial.println(F("======SHOW=SOUND=CONFIGURATION======"));
Serial.print(F("Master Volume: ")); Serial.print(F("Master Volume: "));
Serial.println(master_volume, DEC); Serial.println(master_volume, DEC);
Serial.print(F("Sound: ")); Serial.print(F("Sound: "));
@ -658,10 +838,12 @@ void show_sound(void)
Serial.println(configuration.reverb_damping, DEC); Serial.println(configuration.reverb_damping, DEC);
Serial.print(F("Reverb Level: ")); Serial.print(F("Reverb Level: "));
Serial.println(configuration.reverb_level, DEC); Serial.println(configuration.reverb_level, DEC);
Serial.print(F("CHorus Frequency: ")); Serial.print(F("Chorus Frequency: "));
Serial.println(configuration.chorus_frequency, DEC); Serial.println(configuration.chorus_frequency, DEC);
Serial.print(F("Chorus Delay: ")); Serial.print(F("Chorus Intensity: "));
Serial.println(configuration.chorus_delay, DEC); Serial.println(configuration.chorus_intensity, DEC);
Serial.print(F("Chorus Waveform: "));
Serial.println(configuration.chorus_waveform, DEC);
Serial.print(F("Chorus Level: ")); Serial.print(F("Chorus Level: "));
Serial.println(configuration.chorus_level, DEC); Serial.println(configuration.chorus_level, DEC);
Serial.print(F("Bass L/R Level: ")); Serial.print(F("Bass L/R Level: "));
@ -680,7 +862,10 @@ void show_sound(void)
Serial.println(configuration.midi_soft_thru, DEC); Serial.println(configuration.midi_soft_thru, DEC);
Serial.print(F("Maximum Polyphony: ")); Serial.print(F("Maximum Polyphony: "));
Serial.println(configuration.max_poly, DEC); Serial.println(configuration.max_poly, DEC);
Serial.print(F("Audio-Mono: "));
Serial.println(configuration.mono, DEC);
Serial.print(F("Panorama: ")); Serial.print(F("Panorama: "));
Serial.println(configuration.pan, DEC); Serial.println(configuration.pan, DEC);
Serial.println(F("======END=OF=SOUND=CONFIGURATION======="));
} }
#endif #endif

746
UI.hpp

File diff suppressed because it is too large Load Diff

@ -30,6 +30,13 @@
// ATTENTION! For better latency you have to redefine AUDIO_BLOCK_SAMPLES from // ATTENTION! For better latency you have to redefine AUDIO_BLOCK_SAMPLES from
// 128 to 64 in <ARDUINO-IDE-DIR>/cores/teensy3/AudioStream.h // 128 to 64 in <ARDUINO-IDE-DIR>/cores/teensy3/AudioStream.h
// If you want to test the system with Linux and withous any keyboard and/or audio equipment, you can do the following:
// 1. In Arduino-IDE enable "Tools->USB-Type->Serial + MIDI + Audio"
// 2. Build the firmware with "MIDI_DEVICE_USB" enabled in config.h.
// 3. Afterconnecting to a Linux system there should be a MIDI an audio device available that is called "MicroMDAEPiano", so you can start the following:
// $ aplaymidi -p 20:0 <MIDI-File> # e.g. test.mid
// $ arecord -f cd -Dhw:1,0 /tmp/bla.wav
//************************************************************************************************* //*************************************************************************************************
//* DEVICE SETTINGS //* DEVICE SETTINGS
//************************************************************************************************* //*************************************************************************************************
@ -39,11 +46,6 @@
#define MIDI_DEVICE_USB 1 #define MIDI_DEVICE_USB 1
#define MIDI_DEVICE_USB_HOST 1 #define MIDI_DEVICE_USB_HOST 1
// AUDIO
// If nothing is defined PT8211 is used as audio output device!
#define TEENSY_AUDIO_BOARD 1
//#define TGA_AUDIO_BOARD 1
//************************************************************************************************* //*************************************************************************************************
//* MIDI SETTINGS //* MIDI SETTINGS
//************************************************************************************************* //*************************************************************************************************
@ -55,26 +57,33 @@
//* AUDIO SETTINGS //* AUDIO SETTINGS
//************************************************************************************************* //*************************************************************************************************
#define VOLUME 0.8
#define VOLUME_CURVE 0.07
#define AUDIO_MEM 128 #define AUDIO_MEM 128
#define SAMPLE_RATE 44100 #define SAMPLE_RATE AUDIO_SAMPLE_RATE
#define REDUCE_LOUDNESS 0 #define REDUCE_LOUDNESS 0
#define USE_XFADE_DATA 1 #define USE_XFADE_DATA 1
// CHORUS parameters
#define MOD_DELAY_SAMPLE_BUFFER int32_t(TIME_MS2SAMPLES(20.0)) // 20.0 ms delay buffer.
#define MOD_WAVEFORM WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE
#define MOD_FILTER_OUTPUT MOD_LINKWITZ_RILEY_FILTER_OUTPUT // MOD_LINKWITZ_RILEY_FILTER_OUTPUT MOD_BUTTERWORTH_FILTER_OUTPUT MOD_NO_FILTER_OUTPUT
#define MOD_FILTER_CUTOFF_HZ 3000
//************************************************************************************************* //*************************************************************************************************
//* DEBUG OUTPUT SETTINGS //* DEBUG OUTPUT SETTINGS
//************************************************************************************************* //*************************************************************************************************
//#define DEBUG 1 #define SHOW_DEBUG 1
#define SERIAL_SPEED 38400 #define SERIAL_SPEED 38400
#define SHOW_XRUN 1 #define SHOW_XRUN 1
#define SHOW_CPU_LOAD_MSEC 5000 #define SHOW_CPU_LOAD_MSEC 5000
//#define DEBUG_AUDIO 50
//************************************************************************************************* //*************************************************************************************************
//* HARDWARE SETTINGS //* HARDWARE SETTINGS
//************************************************************************************************* //*************************************************************************************************
#define USB_AUDIO 1
// Teensy Audio Shield: // Teensy Audio Shield:
/* Values for SGTL5000_LINEOUT_LEVEL /* Values for SGTL5000_LINEOUT_LEVEL
13: 3.16 Volts p-p 13: 3.16 Volts p-p
@ -97,7 +106,7 @@
30: 1.22 Volts p-p 30: 1.22 Volts p-p
31: 1.16 Volts p-p 31: 1.16 Volts p-p
*/ */
#define SGTL5000_LINEOUT_LEVEL 28 #define SGTL5000_LINEOUT_LEVEL 17
//#define SDCARD_CS_PIN 10 //#define SDCARD_CS_PIN 10
//#define SDCARD_MOSI_PIN 7 //#define SDCARD_MOSI_PIN 7
//#define SDCARD_SCK_PIN 14 //#define SDCARD_SCK_PIN 14
@ -131,11 +140,53 @@
#define EEPROM_SOUND EEPROM_START_ADDRESS+1 #define EEPROM_SOUND EEPROM_START_ADDRESS+1
#define EEPROM_CONFIGURATIONS EEPROM_SOUND+1 #define EEPROM_CONFIGURATIONS EEPROM_SOUND+1
// MIDI-CC mapping
// free CCs: 102-119 / 85-90 / 52-63
#define MIDI_CC_PANORAMA 10
#define MIDI_CC_REVERB_SEND 91
#define MIDI_CC_TREMOLO_DEPTH 92
#define MIDI_CC_CHORUS_SEND 93
#define MIDI_CC_DETUNE_DEPTH 94
#define MIDI_CC_EP_DECAY 52
#define MIDI_CC_EP_RELEASE 53
#define MIDI_CC_EP_HARDNESS 54
#define MIDI_CC_EP_TREBLE 55
#define MIDI_CC_EP_STEREO 56
#define MIDI_CC_EP_TRANSPOSE 57
#define MIDI_CC_EP_TUNE 58
#define MIDI_CC_EP_VELOCITY_SENSE 59
#define MIDI_CC_EP_TREM_FRQ 60
#define MIDI_CC_EP_OVERDRIVE 61
#define MIDI_CC_COMP_GAIN 102
#define MIDI_CC_COMP_REPOSNE 103
#define MIDI_CC_COMP_LIMIT 104
#define MIDI_CC_COMP_THRESHOLD 105
#define MIDI_CC_COMP_ATTACK 106
#define MIDI_CC_COMP_DECAY 107
#define MIDI_CC_REVERB_ROOMSIZE 108
#define MIDI_CC_REVERB_DAMPING 109
#define MIDI_CC_CHORUS_FREQUENCY 111
#define MIDI_CC_CHORUS_INTENSITY 112
#define MIDI_CC_CHORUS_WAVEFORM 113
#define MIDI_CC_BASS_LR_LEVEL 114
#define MIDI_CC_BASS_MONO_LEVEL 115
#define MIDI_CC_EQ_BASS 116
#define MIDI_CC_EQ_TREBLE 117
#define MIDI_CC_MIDI_SOFT_THRU 118
#define MIDI_CC_MONO 119
//************************************************************************************************* //*************************************************************************************************
//* DO NO CHANGE ANYTHING BEYOND IF YOU DON'T KNOW WHAT YOU ARE DOING !!! //* DO NO CHANGE ANYTHING BEYOND IF YOU DON'T KNOW WHAT YOU ARE DOING !!!
//************************************************************************************************* //*************************************************************************************************
#define MICRO_MDAEPIANO_VERSION "0.9.0" #define MICRO_MDAEPIANO_VERSION "1.0.0 alpha"
/* HELPER MACROS */
#define TIME_MS2SAMPLES(x) floor(uint32_t(x) * AUDIO_SAMPLE_RATE / 1000)
#define SAMPLES2TIME_MS(x) float(uint32_t(x) * 1000 / AUDIO_SAMPLE_RATE)
#define MOD_NO_FILTER_OUTPUT 0
#define MOD_BUTTERWORTH_FILTER_OUTPUT 1
#define MOD_LINKWITZ_RILEY_FILTER_OUTPUT 2
#define MAX_SOUNDS min(99,int((4096-EEPROM_CONFIGURATIONS)/sizeof(config_t))) #define MAX_SOUNDS min(99,int((4096-EEPROM_CONFIGURATIONS)/sizeof(config_t)))
@ -146,19 +197,19 @@
// Encoder min/max values // Encoder min/max values
#define ENC_DECAY_MIN 0 #define ENC_DECAY_MIN 0
#define ENC_DECAY_MAX 99 #define ENC_DECAY_MAX 99
#define ENC_DECAY_DEFAULT 49 #define ENC_DECAY_DEFAULT 50
// //
#define ENC_RELEASE_MIN 0 #define ENC_RELEASE_MIN 0
#define ENC_RELEASE_MAX 99 #define ENC_RELEASE_MAX 99
#define ENC_RELEASE_DEFAULT 49 #define ENC_RELEASE_DEFAULT 50
// //
#define ENC_HARDNESS_MIN 0 #define ENC_HARDNESS_MIN 0
#define ENC_HARDNESS_MAX 99 #define ENC_HARDNESS_MAX 99
#define ENC_HARDNESS_DEFAULT 49 #define ENC_HARDNESS_DEFAULT 50
// //
#define ENC_TREBLE_MIN 0 #define ENC_TREBLE_MIN 0
#define ENC_TREBLE_MAX 99 #define ENC_TREBLE_MAX 99
#define ENC_TREBLE_DEFAULT 49 #define ENC_TREBLE_DEFAULT 50
// //
#define ENC_STEREO_MIN 0 #define ENC_STEREO_MIN 0
#define ENC_STEREO_MAX 99 #define ENC_STEREO_MAX 99
@ -224,17 +275,21 @@
#define ENC_REVERB_DAMPING_MAX 99 #define ENC_REVERB_DAMPING_MAX 99
#define ENC_REVERB_DAMPING_DEFAULT 50 #define ENC_REVERB_DAMPING_DEFAULT 50
// //
#define ENC_REVERB_LEVEL_MIN 0 #define ENC_REVERB_LEVEL_MIN 1
#define ENC_REVERB_LEVEL_MAX 99 #define ENC_REVERB_LEVEL_MAX 99
#define ENC_REVERB_LEVEL_DEFAULT 15 #define ENC_REVERB_LEVEL_DEFAULT 15
// //
#define ENC_CHORUS_FREQUENCY_MIN 0 #define ENC_CHORUS_FREQUENCY_MIN 0
#define ENC_CHORUS_FREQUENCY_MAX 20 #define ENC_CHORUS_FREQUENCY_MAX 200
#define ENC_CHORUS_FREQUENCY_DEFAULT 3 #define ENC_CHORUS_FREQUENCY_DEFAULT 30
// //
#define ENC_CHORUS_DELAY_MIN 0 #define ENC_CHORUS_INTENSITY_MIN 0
#define ENC_CHORUS_DELAY_MAX 20 #define ENC_CHORUS_INTENSITY_MAX 100
#define ENC_CHORUS_DELAY_DEFAULT 15 #define ENC_CHORUS_INTENSITY_DEFAULT 50
//
#define ENC_CHORUS_WAVEFORM_MIN 1
#define ENC_CHORUS_WAVEFORM_MAX 2
#define ENC_CHORUS_WAVEFORM_DEFAULT 1
// //
#define ENC_CHORUS_LEVEL_MIN 0 #define ENC_CHORUS_LEVEL_MIN 0
#define ENC_CHORUS_LEVEL_MAX 99 #define ENC_CHORUS_LEVEL_MAX 99
@ -272,6 +327,10 @@
#define ENC_MAX_POLY_MAX NVOICES #define ENC_MAX_POLY_MAX NVOICES
#define ENC_MAX_POLY_DEFAULT NVOICES #define ENC_MAX_POLY_DEFAULT NVOICES
// //
#define ENC_MONO_MIN 0 // 0=stereo
#define ENC_MONO_MAX 3 // 1=mono(r/l) 2=mono(r) 3=mono(l)
#define ENC_MONO_DEFAULT 0
//
#define ENC_MASTER_VOLUME_MIN 0 #define ENC_MASTER_VOLUME_MIN 0
#define ENC_MASTER_VOLUME_MAX 99 #define ENC_MASTER_VOLUME_MAX 99
#define ENC_MASTER_VOLUME_DEFAULT 80 #define ENC_MASTER_VOLUME_DEFAULT 80
@ -294,7 +353,7 @@
// Engine // Engine
#if defined(__MK66FX1M0__) #if defined(__MK66FX1M0__)
// Teensy-3.6 settings // Teensy-3.6 settings
#define NVOICES 48 #define NVOICES 40
#else #else
#define NVOICES 32 #define NVOICES 32
#endif #endif
@ -324,7 +383,8 @@ struct config_t {
uint8_t reverb_damping; uint8_t reverb_damping;
uint8_t reverb_level; uint8_t reverb_level;
uint8_t chorus_frequency; uint8_t chorus_frequency;
uint8_t chorus_delay; uint8_t chorus_intensity;
uint8_t chorus_waveform;
uint8_t chorus_level; uint8_t chorus_level;
uint8_t bass_lr_level; uint8_t bass_lr_level;
uint8_t bass_mono_level; uint8_t bass_mono_level;
@ -334,6 +394,7 @@ struct config_t {
uint8_t midi_channel; uint8_t midi_channel;
bool midi_soft_thru; bool midi_soft_thru;
uint8_t max_poly; uint8_t max_poly;
uint8_t mono;
int8_t pan; int8_t pan;
}; };

@ -0,0 +1,134 @@
/* Audio Library for Teensy 3.X
Copyright (c) 2014, Pete (El Supremo)
Copyright (c) 2019, Holger Wirtz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <Arduino.h>
#include <Audio.h>
#include "arm_math.h"
#include "effect_modulated_delay.h"
#include "config.h"
extern config_t configuration;
/******************************************************************/
// Based on; A u d i o E f f e c t D e l a y
// Written by Pete (El Supremo) Jan 2014
// 140529 - change to handle mono stream - change modify() to voices()
// 140219 - correct storage class (not static)
// 190527 - added modulation input (by Holger Wirtz)
boolean AudioEffectModulatedDelay::begin(short *delayline, uint16_t d_length)
{
#if 0
Serial.print(F("AudioEffectModulatedDelay.begin(modulated-delay line length = "));
Serial.print(d_length);
Serial.println(F(")"));
#endif
_delayline = NULL;
_delay_length = 0;
_cb_index = 0;
_delay_offset = 0;
if (delayline == NULL)
return (false);
if (d_length < 10)
return (false);
_delayline = delayline;
_delay_length = d_length;
memset(_delayline, 0, _delay_length * sizeof(int16_t));
_delay_offset = _delay_length >> 1 ;
return (true);
}
uint16_t AudioEffectModulatedDelay::get_delay_length(void)
{
return (_delay_length);
}
void AudioEffectModulatedDelay::update(void)
{
audio_block_t *block;
audio_block_t *modulation;
if (_delayline == NULL)
return;
block = receiveWritable(0);
modulation = receiveReadOnly(1);
if (block && modulation)
{
int16_t *bp;
int16_t cb_mod_index_neighbor;
float *mp;
float mod_index;
float mod_number;
float mod_fraction;
float modulation_f32[AUDIO_BLOCK_SAMPLES];
bp = block->data;
arm_q15_to_float(modulation->data, modulation_f32, AUDIO_BLOCK_SAMPLES);
mp = modulation_f32;
for (uint16_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
{
// write data into circular buffer (delayline)
if (_cb_index >= _delay_length)
_cb_index = 0;
_delayline[_cb_index] = *bp;
// calculate the modulation-index as a floating point number for interpolation
mod_index = *mp * _delay_offset;
mod_fraction = modff(mod_index, &mod_number); // split float of mod_index into integer (= mod_number) and fraction part
// calculate modulation index into circular buffer
cb_mod_index = _cb_index - (_delay_offset + mod_number);
if (cb_mod_index < 0) // check for negative offsets and correct them
cb_mod_index += _delay_length;
if (cb_mod_index == _delay_length - 1)
cb_mod_index_neighbor = 0;
else
cb_mod_index_neighbor = cb_mod_index + 1;
*bp = round(float(_delayline[cb_mod_index]) * mod_fraction + float(_delayline[cb_mod_index_neighbor]) * (1.0 - mod_fraction));
// push the pointers forward
bp++; // next audio data
mp++; // next modulation data
_cb_index++; // next circular buffer index
}
}
if (modulation)
release(modulation);
if (block)
{
transmit(block, 0);
release(block);
}
}

@ -0,0 +1,58 @@
/* Audio Library for Teensy 3.X
Copyright (c) 2014, Pete (El Supremo)
Copyright (c) 2019, Holger Wirtz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef effect_modulated_chorus_h_
#define effect_modulated_chorus_h_
#include "Arduino.h"
#include "AudioStream.h"
#include "config.h"
/*************************************************************************/
// 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
// 140219 - correct storage class (not static)
// 190527 - added modulation input handling (Aug 2019 by Holger Wirtz)
class AudioEffectModulatedDelay :
public AudioStream
{
public:
AudioEffectModulatedDelay(void):
AudioStream(2, inputQueueArray)
{ }
boolean begin(short *delayline, uint16_t delay_length);
virtual void update(void);
virtual uint16_t get_delay_length(void);
private:
audio_block_t *inputQueueArray[2];
int16_t *_delayline; // pointer for the circular buffer
uint16_t _cb_index; // current write pointer of the circular buffer
uint16_t _delay_length; // calculated number of samples of the delay
int16_t cb_mod_index; // current read pointer with modulation for the circular buffer
uint16_t _delay_offset;
};
#endif

@ -29,7 +29,9 @@
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
extern float _loudness; extern void set_master_volume(uint8_t value);
extern uint8_t master_volume;
extern config_t configuration;
mdaEPiano::mdaEPiano() // mdaEPiano::mdaEPiano(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, NPROGS, NPARAMS) mdaEPiano::mdaEPiano() // mdaEPiano::mdaEPiano(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, NPROGS, NPARAMS)
{ {
@ -55,10 +57,11 @@ mdaEPiano::mdaEPiano() // mdaEPiano::mdaEPiano(audioMasterCallback audioMaster)
setPanLFO(0.650f); setPanLFO(0.650f);
setVelocitySense(0.250f); setVelocitySense(0.250f);
setStereo(0.500f); setStereo(0.500f);
setMaxPolyphony(1.0f); setMaxPolyphony(NVOICES);
setTune(0.500f); setTune(0.500f);
setDetune(0.146f); setDetune(0.146f);
setOverdrive(0.000f); setOverdrive(0.000f);
setLoudness(0.64616f);
waves = (short*)epianoDataXfade; waves = (short*)epianoDataXfade;
@ -115,23 +118,39 @@ mdaEPiano::mdaEPiano() // mdaEPiano::mdaEPiano(audioMasterCallback audioMaster)
void mdaEPiano::reset_voices(void) // reset all voices void mdaEPiano::reset_voices(void) // reset all voices
{ {
//initialise...
for (int32_t v = 0; v < NVOICES; v++) for (int32_t v = 0; v < NVOICES; v++)
{ {
voice[v].env = 0.0f; voice[v].env = 0.0f;
voice[v].dec = 0.99f; //all notes off voice[v].dec = 0.99f; //all notes off
} }
volume = 0.2f; //volume = // 0.00002f * 127; // Fixing this level and using CC#7 as master_volume
muff = 160.0f; muff = 160.0f;
sustain = activevoices = 0; sustain = activevoices = 0;
tl = tr = lfo0 = dlfo = 0.0f; tl = tr = lfo0 = dlfo = 0.0f;
lfo1 = 1.0f; lfo1 = 1.0f;
vol = VOLUME;
update(); update();
// suspend();
} }
void mdaEPiano::reset_controllers(void) // reset controllers
{
tl = tr = lfo0 = dlfo = 0.0f;
lfo1 = 1.0f;
update();
}
void mdaEPiano::stop_voices(void) // all keys off, but no reset for sustain
{
for (int32_t v = 0; v < NVOICES; v++)
{
voice[v].env = 0.0f;
}
muff = 160.0f;
activevoices = 0;
update();
}
void mdaEPiano::update() //parameter change void mdaEPiano::update() //parameter change
{ {
@ -213,6 +232,10 @@ void mdaEPiano::setStereo(float value)
void mdaEPiano::setMaxPolyphony(uint8_t value) void mdaEPiano::setMaxPolyphony(uint8_t value)
{ {
if (value > NVOICES)
value = NVOICES;
if (value <= 0)
value = 1;
max_polyphony = value; max_polyphony = value;
} }
@ -231,9 +254,15 @@ void mdaEPiano::setOverdrive(float value)
setParameter(MDA_EP_OVERDRIVE, value); setParameter(MDA_EP_OVERDRIVE, value);
} }
void mdaEPiano::setLoudness(float value)
{
//volume = value * 0.32258; // 0.00002 * 127^2
volume = value * 0.16f;
}
void mdaEPiano::setParameter(int32_t index, float value) void mdaEPiano::setParameter(int32_t index, float value)
{ {
programs[ 0].param[index] = value; programs[0].param[index] = value;
update(); update();
} }
@ -296,8 +325,8 @@ void mdaEPiano::process(int16_t* outputs_r, int16_t* outputs_l)
l = 1.0; l = 1.0;
else if (l < -1.0) else if (l < -1.0)
l = -1.0; l = -1.0;
outputs_l[frame] = static_cast<int16_t>(l * _loudness * 0x7fff) >> REDUCE_LOUDNESS; outputs_l[frame] = static_cast<int16_t>(l * 0x7fff) >> REDUCE_LOUDNESS;
outputs_r[frame] = static_cast<int16_t>(r * _loudness * 0x7fff) >> REDUCE_LOUDNESS; outputs_r[frame] = static_cast<int16_t>(r * 0x7fff) >> REDUCE_LOUDNESS;
} }
if (fabs(tl) < 1.0e-10) tl = 0.0f; //anti-denormal if (fabs(tl) < 1.0e-10) tl = 0.0f; //anti-denormal
@ -401,7 +430,7 @@ bool mdaEPiano::processMidiController(uint8_t data1, uint8_t data2)
break; break;
case 0x07: //volume case 0x07: //volume
volume = 0.00002f * (float)(data2 * data2); set_master_volume(map(data2, 0, 127, ENC_MASTER_VOLUME_MIN, ENC_MASTER_VOLUME_MAX));
break; break;
case 0x40: //sustain pedal case 0x40: //sustain pedal
@ -413,13 +442,20 @@ bool mdaEPiano::processMidiController(uint8_t data1, uint8_t data2)
} }
break; break;
default: //all notes off case 0x78: // All Sound Off: mutes all sounding notes. It does so regardless of release time or sustain. (See MIDI CC 123)
if (data1 > 0x7A) reset_voices();
{ break;
for (int32_t v = 0; v < max_polyphony; v++) voice[v].dec = 0.99f; case 0x79: // Reset All Controllers: it will reset all controllers to their default.
sustain = 0; reset_controllers();
muff = 160.0f; break;
} case 0x7b: // All Notes Off: mutes all sounding notes. Release time will still be maintained, and notes held by sustain will not turn off until sustain pedal is depressed.
stop_voices();
break;
case 0x7e: // Mono Mode: sets device mode to Monophonic.
setMaxPolyphony(1);
break;
case 0x7f: // Poly Mode: sets device mode to Polyphonic.
setMaxPolyphony(configuration.max_poly);
break; break;
} }
return (true); return (true);

@ -98,6 +98,8 @@ class mdaEPiano
//virtual float getParameter(int32_t index); //virtual float getParameter(int32_t index);
virtual void resume(); virtual void resume();
void reset_voices(void); void reset_voices(void);
void reset_controllers(void);
void stop_voices(void);
void setDecay(float value); void setDecay(float value);
void setRelease(float value); void setRelease(float value);
void setHardness(float value); void setHardness(float value);
@ -110,8 +112,9 @@ class mdaEPiano
void setTune(float value); void setTune(float value);
void setDetune(float value); void setDetune(float value);
void setOverdrive(float value); void setOverdrive(float value);
void setLoudness(float value);
int32_t getActiveVoices(void); int32_t getActiveVoices(void);
private: private:
void update(); //my parameter update void update(); //my parameter update
void fillpatch(int32_t p, char *name, float p0, float p1, float p2, float p3, float p4, void fillpatch(int32_t p, char *name, float p0, float p1, float p2, float p3, float p4,
@ -125,14 +128,15 @@ class mdaEPiano
uint8_t max_polyphony; uint8_t max_polyphony;
KGRP kgrp[34]; KGRP kgrp[34];
VOICE voice[NVOICES]; VOICE voice[NVOICES];
int32_t activevoices; int32_t activevoices;
short *waves; short *waves;
float width; float width;
int32_t size, sustain; int32_t size, sustain;
float lfo0, lfo1, dlfo, lmod, rmod; float lfo0, lfo1, dlfo, lmod, rmod;
float treb, tfrq, tl, tr; float treb, tfrq, tl, tr;
float tune, fine, random, stretch, overdrive; float tune, fine, random, stretch, overdrive;
float muff, muffvel, sizevel, velsens, volume, modwhl; float muff, muffvel, sizevel, velsens, modwhl;
float volume;
float vol; float vol;
//uint8_t curProgram; //uint8_t curProgram;
}; };

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -22,7 +22,7 @@
*/ */
/************************************************* /*************************************************
* MIDI note values MIDI note values
*************************************************/ *************************************************/
#ifndef _MIDINOTES_H #ifndef _MIDINOTES_H
@ -37,7 +37,7 @@
#define MIDI_DIS1 27 #define MIDI_DIS1 27
#define MIDI_E1 28 #define MIDI_E1 28
#define MIDI_F1 29 #define MIDI_F1 29
#define MIDI_FIS1 30 #define MIDI_FIS1 30
#define MIDI_G1 31 #define MIDI_G1 31
#define MIDI_GIS1 32 #define MIDI_GIS1 32
#define MIDI_A1 33 #define MIDI_A1 33
@ -54,7 +54,7 @@
#define MIDI_GIS2 44 #define MIDI_GIS2 44
#define MIDI_A2 45 #define MIDI_A2 45
#define MIDI_AIS2 46 #define MIDI_AIS2 46
#define MIDI_B2 47 #define MIDI_B2 47
#define MIDI_C3 48 #define MIDI_C3 48
#define MIDI_CIS3 49 #define MIDI_CIS3 49
#define MIDI_D3 50 #define MIDI_D3 50

@ -1,11 +1,11 @@
#include "usb_names.h" #include "usb_names.h"
#define MIDI_NAME {'M','i','c','r','o','M','D','A','E','p','i','a','n','o'} #define MIDI_NAME {'M','i','c','r','o','M','D','A','E','P','i','a','n','o'}
#define MIDI_NAME_LEN 14 #define MIDI_NAME_LEN 14
// Do not change this part. This exact format is required by USB. // Do not change this part. This exact format is required by USB.
struct usb_string_descriptor_struct usb_string_product_name = { struct usb_string_descriptor_struct usb_string_product_name = {
2 + MIDI_NAME_LEN * 2, 2 + MIDI_NAME_LEN * 2,
3, 3,
MIDI_NAME MIDI_NAME
}; };

@ -5,5 +5,5 @@ sed -i 's/PROGMEM//' mdaEPianoData.h
sed -i 's/const//' mdaEPianoData.h sed -i 's/const//' mdaEPianoData.h
gcc -o xfade_generator xfade_generator.c gcc -o xfade_generator xfade_generator.c
rm mdaEPianoData.h rm mdaEPianoData.h
./xfade_generator >../mdaEPianoData_xfade.h ./xfade_generator >../mdaEPianoDataXfade.h
rm xfade_generator rm xfade_generator

Loading…
Cancel
Save