|
|
|
@ -30,7 +30,6 @@ |
|
|
|
|
#include <SD.h> |
|
|
|
|
#include <MIDI.h> |
|
|
|
|
#include <EEPROM.h> |
|
|
|
|
#include "EEPROMAnything.h" |
|
|
|
|
#include "midi_devices.hpp" |
|
|
|
|
#include "dexed.h" |
|
|
|
|
#include "dexed_sysex.h" |
|
|
|
@ -117,7 +116,11 @@ AudioOutputAnalogStereo dacOut; |
|
|
|
|
AudioConnection patchCord32(stereomono1, 0, dacOut, 0); |
|
|
|
|
AudioConnection patchCord33(stereomono1, 1, dacOut, 1); |
|
|
|
|
#endif |
|
|
|
|
#ifdef USE_REVERB |
|
|
|
|
AudioConnection * dynamicConnections[NUM_DEXED * 6]; |
|
|
|
|
#else |
|
|
|
|
AudioConnection * dynamicConnections[NUM_DEXED * 5]; |
|
|
|
|
#endif |
|
|
|
|
int nDynamic = 0; |
|
|
|
|
|
|
|
|
|
void create_audio_connections(AudioSourceMicroDexed &d) |
|
|
|
@ -130,10 +133,6 @@ void create_audio_connections(AudioSourceMicroDexed &d) |
|
|
|
|
#if defined(USE_REVERB) |
|
|
|
|
dynamicConnections[nDynamic++] = new AudioConnection(d, 0, freeverbs1, 0); |
|
|
|
|
#endif |
|
|
|
|
for (int i = 0; i < nDynamic; i++) { |
|
|
|
|
if (dynamicConnections[i] == NULL) |
|
|
|
|
Serial.printf ("Bad connection %d\n", i); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool sd_card_available = false; |
|
|
|
@ -195,14 +194,14 @@ void setup() |
|
|
|
|
pinMode(U8X8_CS_PIN, OUTPUT); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
delay(320); // necessary, because before this time no serial output is done :(
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_LCD_UI |
|
|
|
|
setup_ui(); |
|
|
|
|
#else |
|
|
|
|
Serial.println(F("NO LCD DISPLAY ENABLED!")); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
delay(220); // necessary, because before this time no serial output is done :(
|
|
|
|
|
|
|
|
|
|
Serial.println(F("MicroDexed based on https://github.com/asb2m10/dexed")); |
|
|
|
|
Serial.println(F("(c)2018,2019 H. Wirtz <wirtz@parasitstudio.de>")); |
|
|
|
|
Serial.println(F("https://codeberg.org/dcoredump/MicroDexed")); |
|
|
|
@ -214,14 +213,14 @@ void setup() |
|
|
|
|
|
|
|
|
|
for (uint8_t i = 0; i < NUM_DEXED; i++) |
|
|
|
|
{ |
|
|
|
|
AudioSourceMicroDexed* microdexed; |
|
|
|
|
|
|
|
|
|
Serial.print(F("Creating MicroDexed instance ")); |
|
|
|
|
Serial.print(i, DEC); |
|
|
|
|
microdexed = new AudioSourceMicroDexed(SAMPLE_RATE); |
|
|
|
|
create_audio_connections(*microdexed); |
|
|
|
|
MicroDexed[i] = microdexed; |
|
|
|
|
Serial.flush(); |
|
|
|
|
MicroDexed[i] = new AudioSourceMicroDexed(SAMPLE_RATE); |
|
|
|
|
//create_audio_connections(*MicroDexed[i]);
|
|
|
|
|
Serial.println(F("... created")); |
|
|
|
|
Serial.flush(); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Init EEPROM if both buttons are pressed at startup
|
|
|
|
@ -236,7 +235,7 @@ void setup() |
|
|
|
|
initial_values_from_eeprom(true); |
|
|
|
|
} |
|
|
|
|
else*/ |
|
|
|
|
initial_values_from_eeprom(true); |
|
|
|
|
initial_values_from_eeprom(false); |
|
|
|
|
|
|
|
|
|
#if defined(TEENSY_AUDIO_BOARD) |
|
|
|
|
sgtl5000_1.enable(); |
|
|
|
@ -281,6 +280,7 @@ void setup() |
|
|
|
|
#else |
|
|
|
|
Serial.println(F("Internal DAC enabled.")); |
|
|
|
|
#endif |
|
|
|
|
Serial.flush(); |
|
|
|
|
|
|
|
|
|
// start SD card
|
|
|
|
|
#ifndef TEENSY4 |
|
|
|
@ -326,6 +326,7 @@ void setup() |
|
|
|
|
Serial.print(F("[")); |
|
|
|
|
Serial.print(voice_names[instance_id][n]); |
|
|
|
|
Serial.println(F("]")); |
|
|
|
|
Serial.flush(); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
@ -491,19 +492,14 @@ void loop() |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
// EEPROM update handling
|
|
|
|
|
if (autostore >= AUTOSTORE_MS && active_voices == 0 && eeprom_update_flag == true) |
|
|
|
|
{ |
|
|
|
|
// only store configuration data to EEPROM when AUTOSTORE_MS is reached and no voices are activated anymore
|
|
|
|
|
eeprom_update(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// MIDI input handling
|
|
|
|
|
check_midi_devices(); |
|
|
|
|
|
|
|
|
|
// CONTROL-RATE-EVENT-HANDLING
|
|
|
|
|
if (control_rate > CONTROL_RATE_MS) |
|
|
|
|
{ |
|
|
|
|
control_rate = 0; |
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_LCD_UI |
|
|
|
|
// LCD Menu
|
|
|
|
|
LCDML.loop(); |
|
|
|
@ -515,7 +511,14 @@ void loop() |
|
|
|
|
UI_func_voice_selection(0); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
control_rate = 0; |
|
|
|
|
|
|
|
|
|
// EEPROM update handling
|
|
|
|
|
//if (autostore >= AUTOSTORE_MS && active_voices == 0 && eeprom_update_flag == true)
|
|
|
|
|
if (autostore >= AUTOSTORE_MS && eeprom_update_flag == true) |
|
|
|
|
{ |
|
|
|
|
// only store configuration data to EEPROM when AUTOSTORE_MS is reached and no voices are activated anymore
|
|
|
|
|
eeprom_update(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// check for value changes and unused voices
|
|
|
|
|
soften_volume.tick(); |
|
|
|
@ -1135,8 +1138,8 @@ void initial_values_from_eeprom(bool init) |
|
|
|
|
init_configuration(); |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
EEPROM_readAnything(EEPROM_START_ADDRESS, tmp_conf); |
|
|
|
|
checksum = crc32((byte*)&tmp_conf + 4, sizeof(tmp_conf) - 4); |
|
|
|
|
EEPROM.get(EEPROM_START_ADDRESS, tmp_conf); |
|
|
|
|
checksum = crc32((uint32_t*)&tmp_conf + 4, sizeof(tmp_conf) - 4); |
|
|
|
|
|
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.print(F("EEPROM checksum: 0x")); |
|
|
|
@ -1154,54 +1157,54 @@ void initial_values_from_eeprom(bool init) |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/*
|
|
|
|
|
configuration.instances = INSTANCES_MAX; |
|
|
|
|
configuration.instance_mode = INSTANCE_MODE_MAX; |
|
|
|
|
configuration.instance_splitpoint = INSTANCE_SPLITPOINT_MAX; |
|
|
|
|
configuration.vol = VOLUME_MAX; |
|
|
|
|
configuration.mono = MONO_MAX; |
|
|
|
|
configuration.reverb_roomsize = REVERB_ROOMSIZE_MAX; |
|
|
|
|
configuration.reverb_damping = REVERB_DAMPING_MAX; |
|
|
|
|
configuration.chorus_frequency = CHORUS_FREQUENCY_MAX; |
|
|
|
|
configuration.chorus_waveform = CHORUS_WAVEFORM_MAX; |
|
|
|
|
configuration.chorus_depth = CHORUS_DEPTH_MAX; |
|
|
|
|
configuration.delay_time = DELAY_TIME_MAX; |
|
|
|
|
configuration.delay_feedback = DELAY_FEEDBACK_MAX; */ |
|
|
|
|
EEPROM.get(EEPROM_START_ADDRESS, configuration); |
|
|
|
|
|
|
|
|
|
configuration.instances %= INSTANCES_MAX; |
|
|
|
|
configuration.instance_mode %= INSTANCE_MODE_MAX; |
|
|
|
|
configuration.instance_splitpoint %= INSTANCE_SPLITPOINT_MAX; |
|
|
|
|
configuration.vol %= VOLUME_MAX; |
|
|
|
|
configuration.mono %= MONO_MAX; |
|
|
|
|
configuration.reverb_roomsize %= REVERB_ROOMSIZE_MAX; |
|
|
|
|
configuration.reverb_damping %= REVERB_DAMPING_MAX; |
|
|
|
|
configuration.chorus_frequency %= CHORUS_FREQUENCY_MAX; |
|
|
|
|
configuration.chorus_waveform %= CHORUS_WAVEFORM_MAX; |
|
|
|
|
configuration.chorus_depth %= CHORUS_DEPTH_MAX; |
|
|
|
|
configuration.delay_time %= DELAY_TIME_MAX; |
|
|
|
|
configuration.delay_feedback %= DELAY_FEEDBACK_MAX; |
|
|
|
|
for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) |
|
|
|
|
{ |
|
|
|
|
/*
|
|
|
|
|
configuration.dexed[instance_id].midi_channel = MIDI_CHANNEL_MAX; |
|
|
|
|
configuration.dexed[instance_id].bank = MAX_BANKS; |
|
|
|
|
configuration.dexed[instance_id].voice = MAX_VOICES; |
|
|
|
|
configuration.dexed[instance_id].pan = PANORAMA_MAX; |
|
|
|
|
configuration.dexed[instance_id].reverb_level = REVERB_LEVEL_MAX; |
|
|
|
|
configuration.dexed[instance_id].chorus_level = CHORUS_LEVEL_MAX; |
|
|
|
|
configuration.dexed[instance_id].delay_level = DELAY_LEVEL_MAX; |
|
|
|
|
configuration.dexed[instance_id].filter_cutoff = FILTER_CUTOFF_MAX; |
|
|
|
|
configuration.dexed[instance_id].filter_resonance = FILTER_RESONANCE_MAX; |
|
|
|
|
configuration.dexed[instance_id].loudness = LOUDNESS_MAX; |
|
|
|
|
configuration.dexed[instance_id].polyphony = POLYPHONY_MAX; |
|
|
|
|
configuration.dexed[instance_id].engine = ENGINE_MAX; |
|
|
|
|
configuration.dexed[instance_id].monopoly = MONOPOLY_MAX; |
|
|
|
|
configuration.dexed[instance_id].pb_range = PB_RANGE_MAX; |
|
|
|
|
configuration.dexed[instance_id].pb_step = PB_STEP_MAX; |
|
|
|
|
configuration.dexed[instance_id].mw_range = MW_RANGE_MAX; |
|
|
|
|
configuration.dexed[instance_id].mw_assign = MW_ASSIGN_MAX; |
|
|
|
|
configuration.dexed[instance_id].fc_range = FC_RANGE_MAX; |
|
|
|
|
configuration.dexed[instance_id].fc_assign = FC_ASSIGN_MAX; |
|
|
|
|
configuration.dexed[instance_id].bc_range = BC_RANGE_MAX; |
|
|
|
|
configuration.dexed[instance_id].bc_assign = BC_ASSIGN_MAX; |
|
|
|
|
configuration.dexed[instance_id].at_range = AT_RANGE_MAX; |
|
|
|
|
configuration.dexed[instance_id].at_assign = AT_ASSIGN_MAX; |
|
|
|
|
configuration.dexed[instance_id].op_enabled = 0x3f; */ |
|
|
|
|
configuration.dexed[instance_id].midi_channel %= MIDI_CHANNEL_MAX; |
|
|
|
|
configuration.dexed[instance_id].bank %= MAX_BANKS; |
|
|
|
|
configuration.dexed[instance_id].voice %= MAX_VOICES; |
|
|
|
|
configuration.dexed[instance_id].pan %= PANORAMA_MAX; |
|
|
|
|
configuration.dexed[instance_id].reverb_level %= REVERB_LEVEL_MAX; |
|
|
|
|
configuration.dexed[instance_id].chorus_level %= CHORUS_LEVEL_MAX; |
|
|
|
|
configuration.dexed[instance_id].delay_level %= DELAY_LEVEL_MAX; |
|
|
|
|
configuration.dexed[instance_id].filter_cutoff %= FILTER_CUTOFF_MAX; |
|
|
|
|
configuration.dexed[instance_id].filter_resonance %= FILTER_RESONANCE_MAX; |
|
|
|
|
configuration.dexed[instance_id].loudness %= LOUDNESS_MAX; |
|
|
|
|
configuration.dexed[instance_id].polyphony %= POLYPHONY_MAX; |
|
|
|
|
configuration.dexed[instance_id].engine %= ENGINE_MAX; |
|
|
|
|
configuration.dexed[instance_id].monopoly %= MONOPOLY_MAX; |
|
|
|
|
configuration.dexed[instance_id].pb_range %= PB_RANGE_MAX; |
|
|
|
|
configuration.dexed[instance_id].pb_step %= PB_STEP_MAX; |
|
|
|
|
configuration.dexed[instance_id].mw_range %= MW_RANGE_MAX; |
|
|
|
|
configuration.dexed[instance_id].mw_assign %= MW_ASSIGN_MAX; |
|
|
|
|
configuration.dexed[instance_id].fc_range %= FC_RANGE_MAX; |
|
|
|
|
configuration.dexed[instance_id].fc_assign %= FC_ASSIGN_MAX; |
|
|
|
|
configuration.dexed[instance_id].bc_range %= BC_RANGE_MAX; |
|
|
|
|
configuration.dexed[instance_id].bc_assign %= BC_ASSIGN_MAX; |
|
|
|
|
configuration.dexed[instance_id].at_range %= AT_RANGE_MAX; |
|
|
|
|
configuration.dexed[instance_id].at_assign %= AT_ASSIGN_MAX; |
|
|
|
|
configuration.dexed[instance_id].op_enabled %= 0x3f; |
|
|
|
|
|
|
|
|
|
MicroDexed[instance_id]->setPBController(configuration.dexed[instance_id].pb_range, configuration.dexed[instance_id].pb_step); |
|
|
|
|
MicroDexed[instance_id]->setMWController(configuration.dexed[instance_id].mw_range, configuration.dexed[instance_id].mw_assign); |
|
|
|
|
MicroDexed[instance_id]->setFCController(configuration.dexed[instance_id].fc_range, configuration.dexed[instance_id].fc_assign); |
|
|
|
|
MicroDexed[instance_id]->setBCController(configuration.dexed[instance_id].bc_range, configuration.dexed[instance_id].bc_assign); |
|
|
|
|
MicroDexed[instance_id]->setATController(configuration.dexed[instance_id].at_range, configuration.dexed[instance_id].at_assign); |
|
|
|
|
|
|
|
|
|
MicroDexed[instance_id]-> setOPs(configuration.dexed[instance_id].op_enabled); |
|
|
|
|
MicroDexed[instance_id]->setOPs(configuration.dexed[instance_id].op_enabled); |
|
|
|
|
MicroDexed[instance_id]->doRefreshVoice(); |
|
|
|
|
} |
|
|
|
|
Serial.println(F("OK, loaded!")); |
|
|
|
|
} |
|
|
|
@ -1217,8 +1220,11 @@ void initial_values_from_eeprom(bool init) |
|
|
|
|
|
|
|
|
|
void init_configuration(void) |
|
|
|
|
{ |
|
|
|
|
configuration.checksum = 0xffff; |
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.print(F("Initializing configuration")); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
configuration.checksum = 0xffff; |
|
|
|
|
configuration.instances = INSTANCES_DEFAULT; |
|
|
|
|
configuration.instance_mode = INSTANCE_MODE_DEFAULT; |
|
|
|
|
configuration.instance_splitpoint = INSTANCE_SPLITPOINT_DEFAULT; |
|
|
|
@ -1258,6 +1264,7 @@ void init_configuration(void) |
|
|
|
|
configuration.dexed[instance_id].at_assign = AT_ASSIGN_DEFAULT; |
|
|
|
|
configuration.dexed[instance_id].op_enabled = OP_ENABLED_DEFAULT; |
|
|
|
|
} |
|
|
|
|
eeprom_update(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void eeprom_write(void) |
|
|
|
@ -1269,16 +1276,14 @@ void eeprom_write(void) |
|
|
|
|
void eeprom_update(void) |
|
|
|
|
{ |
|
|
|
|
eeprom_update_flag = false; |
|
|
|
|
configuration.checksum = crc32((byte*)&configuration + 4, sizeof(configuration) - 4); |
|
|
|
|
EEPROM_writeAnything(EEPROM_START_ADDRESS, configuration); |
|
|
|
|
Serial.println(F("Updating EEPROM with configuration data:")); |
|
|
|
|
#ifdef DEBUG |
|
|
|
|
show_configuration(); |
|
|
|
|
#endif |
|
|
|
|
configuration.checksum = crc32((uint32_t*)&configuration + 4, sizeof(configuration) - 4); |
|
|
|
|
EEPROM.put(EEPROM_START_ADDRESS, configuration); |
|
|
|
|
Serial.println(F("Updating EEPROM")); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
uint32_t crc32(byte * calc_start, uint16_t calc_bytes) // base code from https://www.arduino.cc/en/Tutorial/EEPROMCrc
|
|
|
|
|
uint32_t crc32(uint32_t* calc_start, uint16_t calc_bytes) // base code from https://www.arduino.cc/en/Tutorial/EEPROMCrc
|
|
|
|
|
{ |
|
|
|
|
uint32_t* index; |
|
|
|
|
const uint32_t crc_table[16] = |
|
|
|
|
{ |
|
|
|
|
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, |
|
|
|
@ -1288,7 +1293,7 @@ uint32_t crc32(byte * calc_start, uint16_t calc_bytes) // base code from https:/ |
|
|
|
|
}; |
|
|
|
|
uint32_t crc = ~0L; |
|
|
|
|
|
|
|
|
|
for (byte* index = calc_start ; index < (calc_start + calc_bytes) ; ++index) |
|
|
|
|
for (index = calc_start ; index < (calc_start + calc_bytes) ; ++index) |
|
|
|
|
{ |
|
|
|
|
crc = crc_table[(crc ^ *index) & 0x0f] ^ (crc >> 4); |
|
|
|
|
crc = crc_table[(crc ^ (*index >> 4)) & 0x0f] ^ (crc >> 4); |
|
|
|
@ -1337,6 +1342,7 @@ void show_cpu_and_mem_usage(void) |
|
|
|
|
Serial.print(F(" ACTIVE_VOICES: ")); |
|
|
|
|
Serial.print(active_voices, DEC); |
|
|
|
|
Serial.println(); |
|
|
|
|
Serial.flush(); |
|
|
|
|
AudioProcessorUsageMaxReset(); |
|
|
|
|
AudioMemoryUsageMaxReset(); |
|
|
|
|
} |
|
|
|
@ -1360,6 +1366,7 @@ void show_configuration(void) |
|
|
|
|
Serial.print(F("Chorus Depth ")); Serial.println(configuration.chorus_depth, DEC); |
|
|
|
|
Serial.print(F("Delay Time ")); Serial.println(configuration.delay_time, DEC); |
|
|
|
|
Serial.print(F("Delay Feedback ")); Serial.println(configuration.delay_feedback, DEC); |
|
|
|
|
Serial.flush(); |
|
|
|
|
for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) |
|
|
|
|
{ |
|
|
|
|
Serial.print(F("=== DEXED INSTANCE ")); |
|
|
|
@ -1389,6 +1396,7 @@ void show_configuration(void) |
|
|
|
|
Serial.print(F(" Aftertouch Range ")); Serial.println(configuration.dexed[instance_id].at_range, DEC); |
|
|
|
|
Serial.print(F(" Aftertouch Assign ")); Serial.println(configuration.dexed[instance_id].at_assign, DEC); |
|
|
|
|
Serial.print(F(" OP Enabled ")); Serial.println(configuration.dexed[instance_id].op_enabled, DEC); |
|
|
|
|
Serial.flush(); |
|
|
|
|
} |
|
|
|
|
Serial.println(); |
|
|
|
|
} |
|
|
|
@ -1450,6 +1458,7 @@ void show_patch(uint8_t instance_id) |
|
|
|
|
Serial.print(MicroDexed[instance_id]->data[(i * 21) + DEXED_OP_FREQ_FINE], DEC); |
|
|
|
|
Serial.print(F(" ")); |
|
|
|
|
Serial.println(MicroDexed[instance_id]->data[(i * 21) + DEXED_OP_OSC_DETUNE], DEC); |
|
|
|
|
Serial.flush(); |
|
|
|
|
} |
|
|
|
|
Serial.println(F("PR1 | PR2 | PR3 | PR4 | PL1 | PL2 | PL3 | PL4")); |
|
|
|
|
Serial.print(F(" ")); |
|
|
|
@ -1457,6 +1466,7 @@ void show_patch(uint8_t instance_id) |
|
|
|
|
{ |
|
|
|
|
Serial.print(MicroDexed[instance_id]->data[DEXED_VOICE_OFFSET + i], DEC); |
|
|
|
|
Serial.print(F(" ")); |
|
|
|
|
Serial.flush(); |
|
|
|
|
} |
|
|
|
|
Serial.println(); |
|
|
|
|
Serial.print(F("ALG: ")); |
|
|
|
@ -1486,11 +1496,13 @@ void show_patch(uint8_t instance_id) |
|
|
|
|
Serial.print(F("[")); |
|
|
|
|
Serial.print(voicename); |
|
|
|
|
Serial.println(F("]")); |
|
|
|
|
Serial.flush(); |
|
|
|
|
for (i = DEXED_GLOBAL_PARAMETER_OFFSET; i <= DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MAX_NOTES; i++) |
|
|
|
|
{ |
|
|
|
|
Serial.print(i, DEC); |
|
|
|
|
Serial.print(F(": ")); |
|
|
|
|
Serial.println(MicroDexed[instance_id]->data[i]); |
|
|
|
|
Serial.flush(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Serial.println(); |
|
|
|
|