diff --git a/.gitignore b/.gitignore index 34d8ad56..813d1a78 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,3 @@ ui_design_480x320land/cache ui_design_480x320land/autosave - diff --git a/MidiCommands.md b/MidiCommands.md index d5e118a8..1055d45c 100644 --- a/MidiCommands.md +++ b/MidiCommands.md @@ -116,4 +116,6 @@ This project uses a low-cost embedded controller (Espressif ESP32-S3) to form a | Cab Sim Bypass | 117 | On: 127, Off: 0 | | Global Tempo Source | 118 | Global: 127, Local: 0 | | Global Tuning Reference | 119 | 0-127 | +| Load Preset to Slot A | 120 | 0-19 | +| Load Preset to Slot B | 121 | 0-19 | | Select Preset | 127 | 0-19 | diff --git a/source/main/midi_helper.c b/source/main/midi_helper.c index 2b69290c..0b43a172 100644 --- a/source/main/midi_helper.c +++ b/source/main/midi_helper.c @@ -1229,16 +1229,34 @@ esp_err_t midi_helper_adjust_param_via_midi(uint8_t change_num, uint8_t midi_val case 120: { - // reserved for setting preset in slot A - ESP_LOGW(TAG, "CC Not implemented yet %d", change_num); - return ESP_FAIL; + // Load preset to Slot A without switching to it + if (midi_value >= (usb_get_max_presets_for_connected_modeller())) + { + ESP_LOGW(TAG, "Unsupported Midi CC 120 value %d (max %d)", midi_value, usb_get_max_presets_for_connected_modeller() - 1); + } + else + { + usb_load_preset_to_slot_a(midi_value); + } + + // no param change needed + return ESP_OK; } break; case 121: { - // reserved for setting preset in slot B - ESP_LOGW(TAG, "CC Not implemented yet %d", change_num); - return ESP_FAIL; + // Load preset to Slot B without switching to it + if (midi_value >= (usb_get_max_presets_for_connected_modeller())) + { + ESP_LOGW(TAG, "Unsupported Midi CC 121 value %d (max %d)", midi_value, usb_get_max_presets_for_connected_modeller() - 1); + } + else + { + usb_load_preset_to_slot_b(midi_value); + } + + // no param change needed + return ESP_OK; } break; case 122: diff --git a/source/main/usb_comms.c b/source/main/usb_comms.c index e3a15a5c..3efeefd5 100644 --- a/source/main/usb_comms.c +++ b/source/main/usb_comms.c @@ -441,6 +441,62 @@ void usb_modify_parameter(uint16_t index, float value) } } +/**************************************************************************** +* NAME: +* DESCRIPTION: +* PARAMETERS: +* RETURN: +* NOTES: +*****************************************************************************/ +void usb_load_preset_to_slot_a(uint32_t preset) +{ + tUSBMessage message; + + if (usb_input_queue == NULL) + { + ESP_LOGE(TAG, "usb_load_preset_to_slot_a queue null"); + } + else + { + message.Command = USB_COMMAND_LOAD_PRESET_TO_SLOT_A; + message.Payload = preset; + + // send to queue + if (xQueueSend(usb_input_queue, (void*)&message, 0) != pdPASS) + { + ESP_LOGE(TAG, "usb_load_preset_to_slot_a queue send failed!"); + } + } +} + +/**************************************************************************** +* NAME: +* DESCRIPTION: +* PARAMETERS: +* RETURN: +* NOTES: +*****************************************************************************/ +void usb_load_preset_to_slot_b(uint32_t preset) +{ + tUSBMessage message; + + if (usb_input_queue == NULL) + { + ESP_LOGE(TAG, "usb_load_preset_to_slot_b queue null"); + } + else + { + message.Command = USB_COMMAND_LOAD_PRESET_TO_SLOT_B; + message.Payload = preset; + + // send to queue + if (xQueueSend(usb_input_queue, (void*)&message, 0) != pdPASS) + { + ESP_LOGE(TAG, "usb_load_preset_to_slot_b queue send failed!"); + } + } +} + /**************************************************************************** * NAME: * DESCRIPTION: diff --git a/source/main/usb_comms.h b/source/main/usb_comms.h index 2aa311f6..9fdaf195 100644 --- a/source/main/usb_comms.h +++ b/source/main/usb_comms.h @@ -38,7 +38,9 @@ enum AmpModellers enum USB_Commands { USB_COMMAND_SET_PRESET, - USB_COMMAND_MODIFY_PARAMETER + USB_COMMAND_MODIFY_PARAMETER, + USB_COMMAND_LOAD_PRESET_TO_SLOT_A, + USB_COMMAND_LOAD_PRESET_TO_SLOT_B }; typedef struct @@ -61,6 +63,8 @@ void init_usb_comms(void); // thread safe public API void usb_set_preset(uint32_t preset); void usb_modify_parameter(uint16_t index, float value); +void usb_load_preset_to_slot_a(uint32_t preset); +void usb_load_preset_to_slot_b(uint32_t preset); uint8_t usb_get_max_presets_for_connected_modeller(void); uint8_t usb_get_first_preset_index_for_connected_modeller(void); diff --git a/source/main/usb_tonex_one.c b/source/main/usb_tonex_one.c index 9be9cfd7..78098457 100644 --- a/source/main/usb_tonex_one.c +++ b/source/main/usb_tonex_one.c @@ -431,6 +431,7 @@ static esp_err_t __attribute__((unused)) usb_tonex_one_set_active_slot(Slot newS return tonex_common_transmit(cdc_dev, FramedBuffer, framed_length, TONEX_USB_TX_BUFFER_SIZE); } + /**************************************************************************** * NAME: * DESCRIPTION: @@ -1316,6 +1317,38 @@ void usb_tonex_one_handle(class_driver_t* driver_obj) // failed return to queue? } } + } break; + + case USB_COMMAND_LOAD_PRESET_TO_SLOT_A: + { + if (message.Payload < MAX_PRESETS_TONEX_ONE) + { + ESP_LOGI(TAG, "Loading preset %d to Slot A via MIDI CC 120", (int)message.Payload); + if (usb_tonex_one_set_preset_in_slot(message.Payload, A, 0) != ESP_OK) + { + ESP_LOGE(TAG, "Failed to load preset %d to Slot A", (int)message.Payload); + } + } + else + { + ESP_LOGW(TAG, "Invalid preset index %d for Slot A (max %d)", (int)message.Payload, MAX_PRESETS_TONEX_ONE - 1); + } + } break; + + case USB_COMMAND_LOAD_PRESET_TO_SLOT_B: + { + if (message.Payload < MAX_PRESETS_TONEX_ONE) + { + ESP_LOGI(TAG, "Loading preset %d to Slot B via MIDI CC 121", (int)message.Payload); + if (usb_tonex_one_set_preset_in_slot(message.Payload, B, 0) != ESP_OK) + { + ESP_LOGE(TAG, "Failed to load preset %d to Slot B", (int)message.Payload); + } + } + else + { + ESP_LOGW(TAG, "Invalid preset index %d for Slot B (max %d)", (int)message.Payload, MAX_PRESETS_TONEX_ONE - 1); + } } break; case USB_COMMAND_MODIFY_PARAMETER: diff --git a/source/main/usb_tonex_one.h b/source/main/usb_tonex_one.h index bea26464..3eb678f9 100644 --- a/source/main/usb_tonex_one.h +++ b/source/main/usb_tonex_one.h @@ -30,6 +30,10 @@ void usb_tonex_one_init(class_driver_t* driver_obj, QueueHandle_t comms_queue); void usb_tonex_one_deinit(void); void usb_tonex_one_preallocate_memory(void); +// MIDI CC slot targeting functions +esp_err_t usb_tonex_one_load_preset_to_slot_a(uint16_t preset); +esp_err_t usb_tonex_one_load_preset_to_slot_b(uint16_t preset); + #ifdef __cplusplus } /*extern "C"*/ #endif