From 60f3ff7a7e8c3d6a31c36925fc021d34e0fd0a2d Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Thu, 28 May 2020 14:09:43 +0200 Subject: [PATCH] Added sending of a single voice via MIDI sysex. --- UI.hpp | 128 ++++++++++++++++++++++++++++++++++++++++++++--- UI_FX.h | 17 ++++--- UI_NO_FX.h | 17 ++++--- dexed.cpp | 15 +++--- dexed.h | 2 +- dexed_sd.cpp | 2 +- midi_devices.hpp | 27 +++++----- 7 files changed, 160 insertions(+), 48 deletions(-) diff --git a/UI.hpp b/UI.hpp index 5fb5858..8c5c3b3 100644 --- a/UI.hpp +++ b/UI.hpp @@ -93,6 +93,8 @@ extern char sd_string[LCD_cols + 1]; extern char g_voice_name[NUM_DEXED][VOICE_NAME_LEN]; extern char g_bank_name[NUM_DEXED][BANK_NAME_LEN]; +extern void send_sysex_voice(uint8_t midi_channel, uint8_t* data); + /*********************************************************************** GLOBAL ************************************************************************/ @@ -248,7 +250,6 @@ void UI_func_velocity_level(uint8_t param); void UI_func_voice_select(uint8_t param); void UI_func_sysex_send_voice(uint8_t param); void UI_func_sysex_receive_voice(uint8_t param); -void UI_func_save_voice(uint8_t param); void UI_func_sysex_receive_bank(uint8_t param); void UI_func_sysex_send_bank(uint8_t param); void UI_func_eq_bass(uint8_t param); @@ -4935,7 +4936,7 @@ void UI_func_sysex_send_bank(uint8_t param) { encoderDir[ENC_R].reset(); - if (bank_number != 0xff) + if (bank_number < 0xff) { lcd.setCursor(0, 1); lcd.print(F("Canceled. ")); @@ -4946,33 +4947,144 @@ void UI_func_sysex_send_bank(uint8_t param) void UI_func_sysex_send_voice(uint8_t param) { + static uint8_t mode; + static uint8_t bank_number; + static uint8_t voice_number; + if (LCDML.FUNC_setup()) // ****** SETUP ********* { encoderDir[ENC_R].reset(); + mode = 0; + bank_number = configuration.performance.bank[selected_instance_id]; + voice_number = configuration.performance.voice[selected_instance_id]; + + char bank_name[BANK_NAME_LEN]; + + if (!get_bank_name(bank_number, bank_name, sizeof(bank_name))) + strcpy(bank_name, "*ERROR*"); lcd.setCursor(0, 0); lcd.print(F("MIDI Send Voice")); - lcd.setCursor(0, 1); - lcd.print(F("Not implemented.")); + lcd.show(1, 0, 2, bank_number); + lcd.show(1, 4, 10, bank_name); + lcd.show(1, 2, 2, " ["); + lcd.show(1, 14, 1, "]"); } if (LCDML.FUNC_loop()) // ****** LOOP ********* { + char bank_name[BANK_NAME_LEN]; + char voice_name[VOICE_NAME_LEN]; + if ((LCDML.BT_checkDown() && encoderDir[ENC_R].Down()) || (LCDML.BT_checkUp() && encoderDir[ENC_R].Up())) { - if (LCDML.BT_checkDown()) + switch (mode) { - ; + case 0: // Bank selection + if (LCDML.BT_checkDown()) + bank_number = constrain(bank_number + ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + else if (LCDML.BT_checkUp() && bank_number > 0) + bank_number = constrain(bank_number - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1); + + if (!get_bank_name(bank_number, bank_name, sizeof(bank_name))) + strcpy(bank_name, "*ERROR*"); + + lcd.show(1, 0, 2, bank_number); + lcd.show(1, 4, 10, bank_name); + break; + case 1: // Voice selection + if (LCDML.BT_checkDown() && voice_number < MAX_VOICES - 1) + voice_number = constrain(voice_number + ENCODER[ENC_R].speed(), 0, MAX_VOICES - 1); + else if (LCDML.BT_checkUp() && voice_number > 0) + voice_number = constrain(voice_number - ENCODER[ENC_R].speed(), 0, MAX_VOICES - 1); + if (!get_bank_name(bank_number, bank_name, sizeof(bank_name))) + strncpy(bank_name, "*ERROR*", sizeof(bank_name)); + if (!get_voice_by_bank_name(bank_number, bank_name, voice_number, voice_name, sizeof(voice_name))) + strncpy(voice_name, "*ERROR*", sizeof(voice_name)); + + lcd.show(1, 0, 2, voice_number + 1); + lcd.show(1, 4, 10, voice_name); + break; } - else if (LCDML.BT_checkUp()) + } + else if (LCDML.BT_checkEnter()) + { + if (encoderDir[ENC_R].ButtonShort()) + mode++; + switch (mode) { - ; + case 1: + if (!get_bank_name(bank_number, bank_name, sizeof(bank_name))) + strncpy(bank_name, "*ERROR*", sizeof(bank_name)); + if (!get_voice_by_bank_name(bank_number, bank_name, voice_number, voice_name, sizeof(voice_name))) + strncpy(voice_name, "*ERROR*", sizeof(voice_name)); + + lcd.show(1, 0, 2, voice_number + 1); + lcd.show(1, 4, 10, voice_name); + break; + case 2: + File sysex; + char filename[FILENAME_LEN]; + + if (get_bank_name(bank_number, bank_name, sizeof(bank_name))) + { + sprintf(filename, "/%d/%s.syx", bank_number, bank_name); +#ifdef DEBUG + Serial.print(F("Send voice ")); + Serial.print(voice_number); + Serial.print(F(" of ")); + Serial.print(filename); + Serial.println(F(" from SD.")); +#endif + sysex = SD.open(filename); + if (!sysex) + { +#ifdef DEBUG + Serial.println(F("Connot read from SD.")); +#endif + lcd.show(1, 0, 16, "Read error."); + bank_number = 0xff; + } + else + { + uint8_t voice_data[155]; + uint8_t encoded_voice_data[128]; + + sysex.seek(6 + (voice_number * 128)); + sysex.read(encoded_voice_data, 128); + + MicroDexed[selected_instance_id]->decodeVoice(encoded_voice_data, voice_data); + + lcd.show(1, 0, 16, "Sending..."); + send_sysex_voice(configuration.dexed[selected_instance_id].midi_channel, voice_data); + lcd.show(1, 0, 16, "Done."); + sysex.close(); + + bank_number = 0xff; + } + } + else + { + lcd.show(1, 0, 16, "No voice."); + bank_number = 0xff; + } + + mode = 0xff; + delay(MESSAGE_WAIT_TIME); + LCDML.FUNC_goBackToMenu(); + + break; } } } if (LCDML.FUNC_close()) // ****** STABLE END ********* { + if (mode < 0xff) + { + lcd.show(1, 0, 16, "Canceled."); + delay(MESSAGE_WAIT_TIME); + } encoderDir[ENC_R].reset(); } } diff --git a/UI_FX.h b/UI_FX.h index aa158b1..3b9bf22 100644 --- a/UI_FX.h +++ b/UI_FX.h @@ -104,12 +104,13 @@ LCDML_add(75, LCDML_0_3_3, 1, "Load Effects", UI_func_load_fx); LCDML_add(76, LCDML_0_3_3, 2, "Save Effects", UI_func_save_fx); LCDML_add(77, LCDML_0_3, 5, "MIDI", NULL); LCDML_add(78, LCDML_0_3_5, 1, "MIDI Recv Bank", UI_func_sysex_receive_bank); -LCDML_add(79, LCDML_0_3_5, 2, "MIDI Send Bank", UI_func_sysex_send_bank); -LCDML_add(80, LCDML_0, 4, "System", NULL); -LCDML_add(81, LCDML_0_4, 1, "Volume", UI_func_volume); -LCDML_add(82, LCDML_0_4, 2, "Stereo/Mono", UI_func_stereo_mono); -LCDML_add(83, LCDML_0_4, 3, "MIDI Soft THRU", UI_func_midi_soft_thru); -LCDML_add(84, LCDML_0_4, 4, "EEPROM Reset", UI_func_eeprom_reset); -LCDML_add(85, LCDML_0, 6, "Info", UI_func_information); -#define _LCDML_DISP_cnt 85 +LCDML_add(79, LCDML_0_3_5, 2, "MIDI Snd Bank", UI_func_sysex_send_bank); +LCDML_add(80, LCDML_0_3_5, 3, "MIDI Snd Voice", UI_func_sysex_send_voice); +LCDML_add(81, LCDML_0, 4, "System", NULL); +LCDML_add(82, LCDML_0_4, 1, "Volume", UI_func_volume); +LCDML_add(83, LCDML_0_4, 2, "Stereo/Mono", UI_func_stereo_mono); +LCDML_add(84, LCDML_0_4, 3, "MIDI Soft THRU", UI_func_midi_soft_thru); +LCDML_add(85, LCDML_0_4, 4, "EEPROM Reset", UI_func_eeprom_reset); +LCDML_add(86, LCDML_0, 6, "Info", UI_func_information); +#define _LCDML_DISP_cnt 86 #endif diff --git a/UI_NO_FX.h b/UI_NO_FX.h index ce9a80a..345d8cc 100644 --- a/UI_NO_FX.h +++ b/UI_NO_FX.h @@ -80,13 +80,14 @@ LCDML_add(51, LCDML_0_2_2, 1, "Load Voice Cfg", UI_func_load_voiceconfig); LCDML_add(52, LCDML_0_2_2, 2, "Save Voice Cfg", UI_func_save_voiceconfig); LCDML_add(53, LCDML_0_2, 4, "MIDI", NULL); LCDML_add(54, LCDML_0_2_4, 1, "MIDI Recv Bank", UI_func_sysex_receive_bank); -LCDML_add(55, LCDML_0_2_4, 2, "MIDI Send Bank", UI_func_sysex_send_bank); -LCDML_add(56, LCDML_0, 3, "System", NULL); -LCDML_add(57, LCDML_0_3, 1, "Volume", UI_func_volume); -LCDML_add(58, LCDML_0_3, 2, "Stereo/Mono", UI_func_stereo_mono); -LCDML_add(59, LCDML_0_3, 3, "MIDI Soft THRU", UI_func_midi_soft_thru); -LCDML_add(60, LCDML_0_3, 4, "EEPROM Reset", UI_func_eeprom_reset); -LCDML_add(61, LCDML_0, 4, "Info", UI_func_information); -#define _LCDML_DISP_cnt 61 +LCDML_add(55, LCDML_0_2_4, 2, "MIDI Snd Bank", UI_func_sysex_send_bank); +LCDML_add(56, LCDML_0_2_4, 3, "MIDI Snd Voice", UI_func_sysex_send_voice); +LCDML_add(57, LCDML_0, 3, "System", NULL); +LCDML_add(58, LCDML_0_3, 1, "Volume", UI_func_volume); +LCDML_add(59, LCDML_0_3, 2, "Stereo/Mono", UI_func_stereo_mono); +LCDML_add(60, LCDML_0_3, 3, "MIDI Soft THRU", UI_func_midi_soft_thru); +LCDML_add(61, LCDML_0_3, 4, "EEPROM Reset", UI_func_eeprom_reset); +LCDML_add(62, LCDML_0, 4, "Info", UI_func_information); +#define _LCDML_DISP_cnt 62 #endif diff --git a/dexed.cpp b/dexed.cpp index b4f8056..33236a0 100644 --- a/dexed.cpp +++ b/dexed.cpp @@ -510,9 +510,9 @@ uint8_t Dexed::getNumNotesPlaying(void) return (count_playing_voices); } -bool Dexed::decodeVoice(uint8_t* encoded_data) +bool Dexed::decodeVoice(uint8_t* encoded_data,uint8_t* new_data) { - uint8_t* p_data = data; + uint8_t* p_data = new_data; uint8_t op; uint8_t tmp; char dexed_voice_name[11]; @@ -532,7 +532,7 @@ bool Dexed::decodeVoice(uint8_t* encoded_data) // DEXED_OP_LEV_SCL_BRK_PT, // 8 // DEXED_OP_SCL_LEFT_DEPTH, // 9 // DEXED_OP_SCL_RGHT_DEPTH, // 10 - memcpy(&data[op * 21], &encoded_data[op * 17], 11); + memcpy(&new_data[op * 21], &encoded_data[op * 17], 11); tmp = encoded_data[(op * 17) + 11]; *(p_data + DEXED_OP_SCL_LEFT_CURVE + (op * 21)) = (tmp & 0x03); *(p_data + DEXED_OP_SCL_RGHT_CURVE + (op * 21)) = (tmp & 0x0c) >> 2; @@ -556,7 +556,7 @@ bool Dexed::decodeVoice(uint8_t* encoded_data) // DEXED_PITCH_EG_L2, // 5 // DEXED_PITCH_EG_L3, // 6 // DEXED_PITCH_EG_L4, // 7 - memcpy(&data[DEXED_VOICE_OFFSET], &encoded_data[102], 8); + memcpy(&new_data[DEXED_VOICE_OFFSET], &encoded_data[102], 8); tmp = encoded_data[110]; *(p_data + DEXED_VOICE_OFFSET + DEXED_ALGORITHM) = (tmp & 0x1f); tmp = encoded_data[111]; @@ -566,23 +566,22 @@ bool Dexed::decodeVoice(uint8_t* encoded_data) // DEXED_LFO_DELAY, // 12 // DEXED_LFO_PITCH_MOD_DEP, // 13 // DEXED_LFO_AMP_MOD_DEP, // 14 - memcpy(&data[DEXED_VOICE_OFFSET + DEXED_LFO_SPEED], &encoded_data[112], 4); + memcpy(&new_data[DEXED_VOICE_OFFSET + DEXED_LFO_SPEED], &encoded_data[112], 4); tmp = encoded_data[116]; *(p_data + DEXED_VOICE_OFFSET + DEXED_LFO_PITCH_MOD_SENS) = (tmp & 0x30) >> 4; *(p_data + DEXED_VOICE_OFFSET + DEXED_LFO_WAVE) = (tmp & 0x0e) >> 1; *(p_data + DEXED_VOICE_OFFSET + DEXED_LFO_SYNC) = (tmp & 0x01); *(p_data + DEXED_VOICE_OFFSET + DEXED_TRANSPOSE) = encoded_data[117]; - memcpy(&data[DEXED_VOICE_OFFSET + DEXED_NAME], &encoded_data[118], 10); + memcpy(&new_data[DEXED_VOICE_OFFSET + DEXED_NAME], &encoded_data[118], 10); panic(); doRefreshVoice(); - //activate(); strncpy(dexed_voice_name, (char *)&encoded_data[118], sizeof(dexed_voice_name) - 1); dexed_voice_name[10] = '\0'; #ifdef DEBUG Serial.print(F("Voice [")); Serial.print(dexed_voice_name); - Serial.println(F("] loaded.")); + Serial.println(F("] decoded.")); #endif return (true); diff --git a/dexed.h b/dexed.h index 439f4cc..66b6bec 100644 --- a/dexed.h +++ b/dexed.h @@ -158,7 +158,7 @@ class Dexed uint8_t getMaxNotes(void); void doRefreshVoice(void); void setOPs(uint8_t ops); - bool decodeVoice(uint8_t* encoded_data); + bool decodeVoice(uint8_t* encoded_data, uint8_t* data); bool encodeVoice(uint8_t* encoded_data); bool getVoiceData(uint8_t* data_copy); bool loadVoiceParameters(uint8_t* data); diff --git a/dexed_sd.cpp b/dexed_sd.cpp index 309cde8..d9f1054 100644 --- a/dexed_sd.cpp +++ b/dexed_sd.cpp @@ -71,7 +71,7 @@ bool load_sd_voice(uint8_t b, uint8_t v, uint8_t instance_id) Serial.print(voice_name); Serial.println(F("]")); #endif - bool ret = MicroDexed[instance_id]->decodeVoice(data); + bool ret = MicroDexed[instance_id]->decodeVoice(data,MicroDexed[instance_id]->data); #ifdef DEBUG show_patch(instance_id); #endif diff --git a/midi_devices.hpp b/midi_devices.hpp index 184f496..ba9c67a 100644 --- a/midi_devices.hpp +++ b/midi_devices.hpp @@ -1674,27 +1674,26 @@ void check_midi_devices(void) void send_sysex_voice(uint8_t midi_channel, uint8_t* data) { uint8_t checksum = 0; - uint8_t voice_data[161]; + uint8_t vd[161]; // Send SYSEX data also via MIDI - //voice_data[0] = 0xF0; // SysEx start - voice_data[0] = 0x43; // ID=Yamaha - voice_data[1] = midi_channel; // Sub-status and MIDI channel - voice_data[2] = 0x00; // Format number (0=1 voice) - voice_data[3] = 0x01; // Byte count MSB - voice_data[4] = 0x1B; // Byte count LSB + //vd[0] = 0xF0; // SysEx start + vd[0] = 0x43; // ID=Yamaha + vd[1] = midi_channel; // Sub-status and MIDI channel + vd[2] = 0x00; // Format number (0=1 voice) + vd[3] = 0x01; // Byte count MSB + vd[4] = 0x1B; // Byte count LSB for (uint8_t n = 0; n < 155; n++) { checksum -= data[n]; - voice_data[5 + n] = data[n]; + vd[5 + n] = data[n]; } - checksum &= 0x7f; - voice_data[160] = checksum; // Checksum - //voice_data[162] = 0xF7; // SysEx end + vd[160] = checksum & 0x7f; // Checksum + //vd[162] = 0xF7; // SysEx end - midi_serial.sendSysEx(161, voice_data); // Send to DIN MIDI - midi_usb.sendSysEx(161, voice_data); // Send to USB MIDI - usbMIDI.sendSysEx(161, voice_data); // Send to USB-HOST MIDI + midi_serial.sendSysEx(161, vd); // Send to DIN MIDI + midi_usb.sendSysEx(161, vd); // Send to USB MIDI + usbMIDI.sendSysEx(161, vd); // Send to USB-HOST MIDI } void send_sysex_bank(uint8_t midi_channel, uint8_t* bank_data)