Code:
/* [translatM1] one tool to rule theM 1. - | copy left | M1Addict 2023
*
* a KORG M1 [CC] -> [SYSEX] Translator + Midi repeater
*
Midi CH | function
1 single osclillator untestet
2 double osclillator part 1 untestet
3 double osclillator part 2 untestet
4 effects single osclillator TODO
5 effects double osclillator TODO
6 translatM1 Settings
CC6 | value: 1 (default)
- disable duplicate value supression enable FULL_CHAOS_MODE
On MPC Live using the automation leads to redundant
CC Message sending.
value: 127
- Setting this enables nice drone sounds
by spamming the Korg M1.
7 preset control channel
CC1 | value: 100
- send preset array tested, only a single preset array for now.
Avoid MPC live automation repeating midi cc messages from spamming the M1.
!!! ATTENTIONE !!!
Using this tool may completly reset the M1 preset memory!!!
by using this work_in_progress "tool". basically what you get when
the battery dies. only one piano preset left :)
So do have a SYSEX_preset file ready and be prepared for reloading the preset!
This can of course be done with this tool.
May lead to hangs, unresponsivnes, or disabling of SYSEX_RECEIVE on the Korg M1.
Enabling SYSEX via SYSEX is kind of a chickidi eggidi problem.
Upon this follows one must manually reenable SYSEX for regaining control over the Korg M1!
*/
#include "korg-M1_sysex.h" // arrays with sysex data
#include "valhala_sysex.h" // arrays with presets
static uint8_t SYSEX_START = 0xF0; // start of system exclusive message
static uint8_t SYSEX_END = 0xF7; // end of system exclusive message
static uint8_t KORG_ID = 0x42; // Korg
static uint8_t KORG_CHANNEL = 0x30;
static uint8_t KORG_MODEL = 0x19; // Korg M1
static uint8_t KORG_PARAM_CHANGE = 0x41;
static uint8_t NEGATIVE_VALUE = 0x7F;
static uint8_t POSITIVE_VALUE = 0x00;
uint8_t positive_or_negative = POSITIVE_VALUE;
uint8_t parameter_page = 0;
uint8_t parameter_position=0;
char* parameter_name;
byte last_cc_message[128];
bool CHAOS_MODE=0;
bool UNUSED_CHANNEL=0;
bool PRESET_SELECT=0;
uint8_t midi_buffer[256];
//sysex presets - get lenghts of the sysexdata and the midi buffer
static uint16_t SYSEX_PRESET_LENGTH = sizeof(Valhala_B102)/sizeof(Valhala_B102[0]);
static uint16_t MIDI_BUFFER_LENGTH = sizeof(midi_buffer)/sizeof(midi_buffer[0]);
uint16_t sysex_preset_offset=0;
void setup() {
usbMIDI.setHandleControlChange(HandleControllMessage); // set handle control messages
usbMIDI.setHandleProgramChange(HandleProgramChange);
usbMIDI.setHandleNoteOn(HandleNoteOnMessage);
usbMIDI.setHandleNoteOff(HandleNoteOffMessage);
Serial.begin(115200); while (!Serial) {;} // wait for serial
Serial.println("");
}
void loop() { usbMIDI.read(); } // read the USB MIDI bus every loop
void HandleControllMessage(byte channel, byte controller, byte value) {
// check for CHAOS_MODE Setting
if (channel == 6 && controller == 66){
switch (value) {
case 127:
CHAOS_MODE = 1;
Serial.println("CHAOS MODE ACTIVATED !!!!");
break;
default:
CHAOS_MODE = 0;
Serial.println("CHAOS MODE OFF");
}
}
// filter out cc 120 - 127 and forward it
if (controller >= 120 || controller == 64){
usbMIDI.sendControlChange(0x01, controller, value);
}
else if (last_cc_message[controller] == value && !CHAOS_MODE){
Serial.print(channel); Serial.print(" ");
Serial.print(controller); Serial.print(" ");
Serial.print(value); Serial.print(" ");
Serial.println("DUPLICATE MESSAGE");
}
else if (channel == 7 && controller == 1){
switch (value) {
case 100:
Serial.println("Uploading SYSEX PRESETS - STARTs in");
Serial.println("5");
delay(1000);
Serial.println("4");
delay(1000);
Serial.println("3");
delay(1000);
Serial.println("2");
delay(1000);
Serial.println("1");
delay(1000);
//fill up the midi buffer array for batch working usbMIDI.sendSysEx
while ( sysex_preset_offset < SYSEX_PRESET_LENGTH)
{
memcpy(midi_buffer, Valhala_B102 + sysex_preset_offset, MIDI_BUFFER_LENGTH);
sysex_preset_offset = sysex_preset_offset + MIDI_BUFFER_LENGTH;
if ( (sysex_preset_offset - SYSEX_PRESET_LENGTH) > 0)
{
int padding_bytes = sysex_preset_offset - SYSEX_PRESET_LENGTH;
int padding_offset = MIDI_BUFFER_LENGTH - padding_bytes;
while (padding_offset < MIDI_BUFFER_LENGTH)
{
midi_buffer[padding_offset]=0x00;
padding_offset = padding_offset + 1;
}
}
usbMIDI.sendSysEx(MIDI_BUFFER_LENGTH, midi_buffer, 1);
delay(100);
}
sysex_preset_offset = 0;
Serial.println("Uploading SYSEX PRESETS - DONE");
break;
default:
Serial.println("TURN TO ~100 for Preset transfer.");
}
}
else {
last_cc_message[controller] = value;
Serial.print(channel); Serial.print(" ");
Serial.print(controller); Serial.print(" ");
Serial.print(value); Serial.print(" = ");
controller = (controller - 1); // cc1 == array[0], cc128 == array[127]
switch (channel) {
case 1: // single osclillator
parameter_name = sysex_single_name[controller];
parameter_page = sysex_single_parameter_page[controller];
parameter_position = sysex_single_parameter_position[controller];
// -/+ controller negativ value
if (sysex_single_val_start[controller] == NEGATIVE_VALUE && value < 63)
{
value = map(value, 0, 62, sysex_single_val_end[controller], 0);
value = 128 - value;
positive_or_negative = NEGATIVE_VALUE;
}
// -/+ controller positiv value
else if (sysex_single_val_start[controller] == NEGATIVE_VALUE) {
value = map(value, 63, 127, 0, sysex_single_val_end[controller]);
positive_or_negative = POSITIVE_VALUE;
}
// full range 0-x controller
else if (sysex_single_val_start[controller] == POSITIVE_VALUE) {
value = map(value, 0, 127, 0, sysex_single_val_end[controller]);
positive_or_negative = POSITIVE_VALUE;
}
break;
case 3: // double osclillator part 1
parameter_name = sysex_double1_name[controller];
parameter_page = sysex_double1_parameter_page[controller];
parameter_position = sysex_double1_parameter_position[controller];
// -/+ controller negativ value
if (sysex_double1_val_start[controller] == NEGATIVE_VALUE && value < 63)
{
value = map(value, 0, 62, sysex_double1_val_end[controller], 0);
value = 128 - value;
positive_or_negative = NEGATIVE_VALUE;
}
// -/+ controller positiv value
else if (sysex_double1_val_start[controller] == NEGATIVE_VALUE) {
value = map(value, 63, 127, 0, sysex_double1_val_end[controller]);
positive_or_negative = POSITIVE_VALUE;
}
// full range 0-x controller
else if (sysex_double1_val_start[controller] == POSITIVE_VALUE) {
value = map(value, 0, 127, 0, sysex_double1_val_end[controller]);
positive_or_negative = POSITIVE_VALUE;
}
break;
case 4: // double osclillator part 2
parameter_name = sysex_double2_name[controller];
parameter_page = sysex_double2_parameter_page[controller];
parameter_position = sysex_double2_parameter_position[controller];
// -/+ controller negativ value
if (sysex_double2_val_start[controller] == NEGATIVE_VALUE && value < 63)
{
value = map(value, 0, 62, sysex_double2_val_end[controller], 0);
value = 128 - value;
positive_or_negative = NEGATIVE_VALUE;
}
// -/+ controller positiv value
else if (sysex_double2_val_start[controller] == NEGATIVE_VALUE) {
value = map(value, 63, 127, 0, sysex_double2_val_end[controller]);
positive_or_negative = POSITIVE_VALUE;
}
// full range 0-x controller
else if (sysex_double2_val_start[controller] == POSITIVE_VALUE) {
value = map(value, 0, 127, 0, sysex_double2_val_end[controller]);
positive_or_negative = POSITIVE_VALUE;
}
break;
default:
UNUSED_CHANNEL=1;
break;
}
if (UNUSED_CHANNEL){
Serial.print("Channel not in use!");
UNUSED_CHANNEL=0;
}
else
{
uint8_t sysex[] = {SYSEX_START, \
KORG_ID, \
KORG_CHANNEL, \
KORG_MODEL, \
KORG_PARAM_CHANGE,\
parameter_page, \
parameter_position,\
value, \
positive_or_negative, \
SYSEX_END};
for (int element : sysex){Serial.print(element < 16 ? "0" : "");Serial.print(element, HEX);Serial.print(" ");}
Serial.print(" ::: ");
Serial.println(parameter_name);
usbMIDI.sendSysEx(10, sysex);
//delay(1); // 1ms pause to not stress out the receiver, just a random value, lower may work - untested delayMicroseconds(100)
}
}
}
void HandleProgramChange(byte channel, byte program) { usbMIDI.sendProgramChange(program, 0x01); }
void HandleNoteOnMessage(byte channel, byte pitch, byte velocity) { usbMIDI.sendNoteOn(pitch, velocity, 0x01); }
void HandleNoteOffMessage(byte channel, byte pitch, byte velocity) { usbMIDI.sendNoteOff(pitch, velocity, 0x01);}