Sending 32kb SYSEX data via usbMIDI

Interestingly, weeding out the 100Ms case, 65Ms worked on one JV but not the older other (have two). Presumably newer firmware has more efficient handlers.

Just dive in and analyze what the synth sends.
 
what do you mean by "weeding out the 100Ms case, 65Ms"?

as i said, i dont listen i dont care what the M1 might want to tell me :)
at least for now.

diving in is what i do ;)

after the preset loading works i gonna clean up the errors
hidden in some parameters. then add the control for the effects.
at last switching between PROG & EDIT PROG mode.
maybe also add the WRITE TO MEM function....
 
a now i got it ;) i took a left turn into eletronics land an thought you changed some resistors :)
Timing issues ;)
 
Sounds like good news.
The 8K or so of Roland sysex arrives in 70 or so blocks ranging in size from 16 to 140 bytes. Two named Patch Common and Perform Common contain data pertaining to setting up one of 38 EFX types. Both need enough time to instantiate before following blocks are received.
65Ms here worked for one synth. My code is unlikely to yield exactly 65Ms each time, can prob do better with silicon and solder.
 
what do you mean by "weeding out the 100Ms case, 65Ms"?

as i said, i dont listen i dont care what the M1 might want to tell me :)
at least for now.

diving in is what i do ;)

after the preset loading works i gonna clean up the errors
hidden in some parameters. then add the control for the effects.
at last switching between PROG & EDIT PROG mode.
maybe also add the WRITE TO MEM function....

Why are you talking in units of Mega seconds?
 
Last edited:
Hehe :) That was my thinking too. And since writings of resistor values
often skip the Ohm i thought MatrixRat has fixed some timing issues by
changing some resistors from 100Mega Ohm to 65Mega Ohm :)

some intersting facts by google calc:
one 1Ms (Mega second) equals 11,5740741 days ;)
 
Sysex file transfer works!

NEWSFLASH

Sysex file transfer works!

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);}
 

Attachments

  • cc2sysex_0702.ino
    10 KB · Views: 17
  • korg-M1_sysex.h
    9.1 KB · Views: 33
  • valhala_sysex.h
    187.8 KB · Views: 19
Back
Top