Midi problem

Hi!

I’m new to this board, so greetings to everybody!

I have a problem with midi. I use an Arduino Uno with Tom Scarff’s midi interface and all i wanna do is to “simply” transmit midi messages from my FCB1010 pedalboard to my keyboard.
I wrote my own programm to deal with it, because i don’t understand most of the midi libraries due to my insufficient knowledge of C/C++. So I kept it very simple and without System Exclusive receive.

I implemented an option to replace midi messages, for example ControlChange 14 with Databyte2 = 0 is replaced by a SystemExclusive message to add more possibilities to control my keyboard.
Actually, that works fine if I monitor the serial port via the aduino software. But when i connect it to my pedalboard and my keyboard, it works sometimes, but often there are errors. For example, one expression pedal controls volume (CC#7) and when i start to move it, it works fine until i move it a little bit faster or too long. If so, my sound is interrupted.

I have no idea why, so if you guys have any idea, please let me know!

Here is my code:

// Note Off
#define NoteOff 0
// Note On
#define NoteOn 1
// AfterTouch Poly
#define ATPoly 2
// Control Change
#define CC 3
// Program Change
#define PC 4
// AfterTouch Channel
#define ATChannel 5
// Pitch Bend
#define PitchBend 6
// System Exclusive
#define SysEx 7

// Variables
int Channel = 0;
int Type = 0;
int Switch = 0;
int Replaced = 0;

byte MIDIchannel;
byte Status = 0;
byte Running = 0;
byte currentByte = 0;
byte Data = 0;
byte Data1 = 0;
byte Data2 = 0;


void setup() {

  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  digitalWrite(3, LOW); // GND 0 Volt supply to opto-coupler
  digitalWrite(2, HIGH); // +5 Volt supply to opto-coupler

  pinMode(4, INPUT); // Set Inputs for 4 way DIP Switch
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(7, INPUT);
  digitalWrite(4, HIGH); // Set inputs Pull-up resistors High
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);

  // Read 4-way DIP switch
  MIDIchannel=digitalRead(4) + (digitalRead(5)<<1) + (digitalRead(6)<<2) + (digitalRead(7)<<3);

  Serial.begin(31250);

  Serial.flush();

}


// Loop begin
void loop () {

  getStatus();



  switch (Type) {
  case 4: // 1 Byte Message
  case 5:
    if (Data == 0) {
      getData();
    }
    Data1 = Data;
    if (Running == 0) {
      replacer(Status, Data1, Data2);
      if (Replaced == 0) {
        sndMSG1(Status, Data1);
        Running = Status;
        Status = 0;
        Data1 = 0;
        Data2 = 0;
      }
    }
    else {
      replacer(Status, Data1, Data2);
      if (Replaced == 0) {
        sndMSG1_run(Status, Data1);
        Running = Status;
        Status = 0;
        Data1 = 0;
        Data2 = 0;
      }
    }
    break;
  case 0: // 2 Bytes Message
  case 1:
  case 2:
  case 3:
  case 6:
    if (Data == 0) {
      getData();
    }
    Data1 = Data;
    getData();
    Data2 = Data;
    if (Running == 0) {
      replacer(Status, Data1, Data2);
      if (Replaced == 0) {
        sndMSG2(Status, Data1, Data2);
        Running = Status;
        Status = 0;
        Data1 = 0;
        Data2 = 0;
      }
    }
    else {
      replacer(Status, Data1, Data2);
      if (Replaced == 0) {
        sndMSG2_run(Status, Data1, Data2);
        Running = Status;
        Status = 0;
        Data1 = 0;
        Data2 = 0;
      }
    }
    break;
  }

}
// Loop end


// MIDI-Routing
void replacer(byte Status, byte Data1, byte Data2) {
  Replaced = 0;
  // Replace CC-14-0 with Karma On / Off
  if (Status == 176 && Data1 == 14 && Data2 == 0 && Switch == 0) {
    // Karma On
    Switch = 1;
    Replaced = 1;

    Serial.print(0xF0, BYTE);
    Serial.print(0x42, BYTE);
    Serial.print(0x30, BYTE);
    Serial.print(0x75, BYTE);
    Serial.print(0x41, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x0D, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x04, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x01, BYTE);
    Serial.print(0xF7, BYTE);

    Running = Status;
    Status = 0;
    Data = 0;
    Data1 = 0;
    Data2 = 0;
  }
  else if (Status == 176 && Data1 == 14 && Data2 == 0 && Switch == 1) {
    // Karma On
    Switch = 0;
    Replaced = 1;

    Serial.print(0xF0, BYTE);
    Serial.print(0x42, BYTE);
    Serial.print(0x30, BYTE);
    Serial.print(0x75, BYTE);
    Serial.print(0x41, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x0D, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x04, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0x00, BYTE);
    Serial.print(0xF7, BYTE);

    Running = Status;
    Status = 0;
    Data = 0;
    Data1 = 0;
    Data2 = 0;
  }



  // Replace NoteOn-C0-100 with Sustain
  if (Status == 144 && Data1 == 0 && Data2 == 100) {
    Replaced = 1;

    Serial.print(176, BYTE);
    Serial.print(64, BYTE);
    Serial.print(110, BYTE);

    Running = Status;
    Status = 0;
    Data = 0;
    Data1 = 0;
    Data2 = 0;

  }
  else if (Status == 144 && Data1 == 0 && Data2 == 0) {
    Replaced = 1;

    Serial.print(176, BYTE);
    Serial.print(64, BYTE);
    Serial.print(10, BYTE);

    Running = Status;
    Status = 0;
    Data = 0;
    Data1 = 0;
    Data2 = 0;
  }
}

// get Statusbyte
void getStatus() {
  currentByte = 0; // Reset
  if (Serial.available() == 128) { 
    Serial.flush(); 
  }      
  while (!Serial.available()) {
  }
  if (Serial.available() > 0) {
    currentByte = Serial.read();
  }
  while (currentByte == 254) { // Active Sensing
    Serial.print(currentByte, BYTE);
    while (!Serial.available()) {
    }
    if (Serial.available() > 0) {
      currentByte = Serial.read();
    }
  }
  if (currentByte == Running && Running != 0) {
    Status = Running;
    return;
  }
  while (currentByte < 128) { // Statusbyte?
    while (!Serial.available()) {
    }
    if (Serial.available() > 0) {
      currentByte = Serial.read();
    }
  }
  Status = currentByte;
  Channel = (Status&0x0F)+1;
  Type = ((Status&0x70)>>4)&0x07;
  Running = 0;
}

// get Databyte
void getData() {
  currentByte = 0; // Reset
  if (Serial.available() == 128) { 
    Serial.flush(); 
  }      
  while (!Serial.available()) {
  }
  if (Serial.available() > 0) {
    currentByte = Serial.read();
  }
  while (currentByte == 254) { // Active Sensing
    Serial.print(currentByte, BYTE);
    while (!Serial.available()) {
    }
    if (Serial.available() > 0) {
      currentByte = Serial.read();
    }
  }
  while (currentByte > 127) { // Databyte?
    while (!Serial.available()) {
    }
    if (Serial.available() > 0) {
      currentByte = Serial.read();
    }
  }
  Data = currentByte;
}

// send Messages
void sndMSG1(byte Status, byte Data1) {
  // Send, save Status for Running Status and delete
  Serial.print(Status, BYTE);
  Serial.print(Data1, BYTE);
  Running = Status;
  Status = 0;
  Data = 0;
  Data1 = 0;
  Data2 = 0;
}

void sndMSG2(byte Status, byte Data1, byte Data2) {
  // Send, save Status for Running Status and delete
  Serial.print(Status, BYTE);
  Serial.print(Data1, BYTE);
  Serial.print(Data2, BYTE);
  Running = Status;
  Status = 0;
  Data = 0;
  Data1 = 0;
  Data2 = 0;
}

void sndMSG1_run(byte Status, byte Data1) {
  // Send, save Status for Running Status and delete
  Serial.print(Data1, BYTE);
  Running = Status;
  Status = 0;
  Data = 0;
  Data1 = 0;
  Data2 = 0;
}

void sndMSG2_run(byte Status, byte Data1, byte Data2) {
  // Send, save Status for Running Status and delete
  Serial.print(Data1, BYTE);
  Serial.print(Data2, BYTE);
  Running = Status;
  Status = 0;
  Data = 0;
  Data1 = 0;
  Data2 = 0;
}

First thing I'd try is hook up MIDI Monitor or MIDIpipe or a similar program that will allow you to read the MIDI stream. And see if your program is actually putting out what you expected -- using running status instead of sending the full CC each time the controller is moved, making sure it isn't accidentally sending a bunch of SysEx messages all the time, etc.

Hi!

I checked it with the internal Arduino serial monitor. The midi output seems to be in order, especially when i only use the switches. And my program uses running status. I have no midi-to-usb interface, so i use a little trick to display the outgoing midi-messages via the serial monitor: In debug-mode, everytime my program sends a byte i replaced the normal Serial.print(). For example:

   /*
   Serial.print(Status, BYTE);
   Serial.print(Data1, BYTE);
   */
  Serial.begin(38400);
  Serial.println(Status, DEC);
  Serial.println(Data1, DEC);
  Serial.begin(31250);

I got an idea. I think it may be your synth can't keep up at the current granularity. As a first experiment, try turning down the sampling rate or adding a hysteresis function. If that pans out, you might see if you can write a routine that decreases the granularity during faster CC moves (since you don't really need all those sub-steps when you are shoving the CC controller up from 10 to 127).

Had this inspiration whilst reading a description of the control loops in the Apollo LM, of all things!

Great idea!

Check this out:

void loop () {
  Serial.print(176, BYTE);
  delay(3);
  
  for (int i=0; i<128; i++) {
    Serial.print(7, BYTE);
    //Serial.print("\t");
    Serial.print(i, BYTE);
    //Serial.print("\n");
    delay(3);
  }
  for (int i=127; i>=0; i--) {
    Serial.print(7, BYTE);
    //Serial.print("\t");
    Serial.print(i, BYTE);
    //Serial.print("\n");
    delay(3);
  }
}

This is an easy volume changer, going from zero to full and back and so on…
This only works when i set the delay between the bytes to three or higher!
I don’t understand it, because i thought the baudrate (31250) determines the transmissionspeed.
But it’s defintively a problem of the speed of transmission.

Okay, problem solved! Thanks nomuse!

I added a delay(3); after every message and now it works quite well!