Understanding MIDI clock with arduino

Hey everyone,

So I'm building a sequencer that sends out CV to one of my synthesizers. I want this sequencer to be the master clock with all of my gear, so this is where things get a little confusing for me.

In my code, my sequencer is basically just running on a counter, and the BPM is configured by the delay times between each step. I don't know a lot about millis() but by running the counter that I am running, is this different from arduinos clock? is it the same thing? does it matter? (haha).

I'm just trying to figure out the best way to approach this because my sequencer is already finished, I just am trying to implement MIDI now... (but maybe I'm doing this in the wrong order?)

okay then....
So let's say I can still use my sequencer's counter that I've built, and it's just a matter of adding a few lines of "midi code" to each step, would I just include Serial.write(248) 24 times for each step and send it out to the pin hooked up to the midi connector? (because of the 24 pulses per quarter note).

int counter;
int cv_pin = 2;
int beat = 1000;
int gate_pin = 3;
int midiclock = 1;

//4 - 11 are the LED's

void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);

  //LEDs

  pinMode(12, OUTPUT); digitalWrite(12, LOW);
  pinMode(11, OUTPUT); digitalWrite(11, LOW);
  pinMode(10, OUTPUT); digitalWrite(10, LOW);
  pinMode(9, OUTPUT); digitalWrite(9, LOW);
  pinMode(8, OUTPUT); digitalWrite(8, LOW);
  pinMode(7, OUTPUT); digitalWrite(7, LOW);
  pinMode(6, OUTPUT); digitalWrite(6, LOW);
  pinMode(5, OUTPUT); digitalWrite(5, LOW);
  pinMode(4, OUTPUT); digitalWrite(4, LOW);
  pinMode(3, OUTPUT); digitalWrite(3, HIGH); ///GATE PIN
  pinMode(cv_pin, OUTPUT); digitalWrite(cv_pin, 0); //cv pin
  pinMode(midiclock,OUTPUT); digitalWrite(midiclock, 0);



}

void loop() {
  // put your main code here, to run repeatedly:
  int knob1 = analogRead(A0);
  int knob2 = analogRead(A1);
  int knob3 = analogRead(A2);
  int knob4 = analogRead(A3);
  int knob5 = analogRead(A4);
  int knob6 = analogRead(A8);
  int knob7 = analogRead(A6);
  int knob8 = analogRead(A7);
  int tempo_knob = analogRead(A8);


  //knob mapping
  float tempo = map(tempo_knob, 0, 1024, 1800, 500);
  float cv_value = map(knob1, 0, 1024, 0, 255);
  float cv_value2 = map(knob2, 0, 1024, 0, 255);
  float cv_value3 = map(knob3, 0, 1024, 0, 255);
  float cv_value4 = map(knob4, 0, 1024, 0, 255);
  float cv_value5 = map(knob5, 0, 1024, 0, 255);
  float cv_value6 = map(knob6, 0, 1024, 0, 255);
  float cv_value7 = map(knob7, 0, 1024, 0, 255);
  float cv_value8 = map(knob8, 0, 1024, 0, 255);

  //Serial.println(tempo);


  //counter,sequencer
  if (counter == 0) {
    counter++;
    Serial.println("ONE");

    //LEDs
    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
    digitalWrite(4, HIGH);



    analogWrite(cv_pin, cv_value);
    Serial.println(cv_value);



    //KNOB CODE GOES HERE

    digitalWrite(gate_pin, LOW);
    delay(tempo / 2);
    digitalWrite(gate_pin, HIGH);
    delay(tempo / 2);
  }

  else if ( counter == 1) {
    counter++;

    Serial.println("TWO");


    //LEDs


    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, HIGH);
    digitalWrite(4, LOW);

    //KNOB
    analogWrite(cv_pin, cv_value2);
    Serial.println(cv_value2);




    //gate

       digitalWrite(gate_pin, LOW);
    delay(tempo / 2);
    digitalWrite(gate_pin, HIGH);
    delay(tempo / 2);

  }

  else if ( counter == 2) {
    counter++;
    Serial.println("THREE");

    //LEDs

    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, HIGH);
    digitalWrite(5, LOW);
    digitalWrite(4, LOW);

    //knob
    analogWrite(cv_pin, cv_value3);
    Serial.println(cv_value3);


    //gate
     digitalWrite(gate_pin, LOW);
    delay(tempo / 2);
    digitalWrite(gate_pin, HIGH);
    delay(tempo / 2);
  }

  else if ( counter == 3) {
    counter++;
    Serial.println("FOUR");

    //LED
    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, HIGH);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
    digitalWrite(4, LOW);

    //LED
    analogWrite(cv_pin, cv_value4);
    Serial.println(cv_value4);

    //knob
     digitalWrite(gate_pin, LOW);
    delay(tempo / 2);
    digitalWrite(gate_pin, HIGH);
    delay(tempo / 2);
  }

  else if ( counter == 4) {
    counter++;
    Serial.println("FIVE");

    //LED
    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, HIGH);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
    digitalWrite(4, LOW);

    //knob
    analogWrite(cv_pin, cv_value5);
    Serial.println(cv_value5);

    //gate
      digitalWrite(gate_pin, LOW);
    delay(tempo / 2);
    digitalWrite(gate_pin, HIGH);
    delay(tempo / 2);
  }

  else if ( counter == 5) {
    counter++;
    Serial.println("SIX");

    //LED
    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, HIGH);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
    digitalWrite(4, LOW);

    //knob
    analogWrite(cv_pin, cv_value6);
    Serial.println(cv_value6);

    //LED
    digitalWrite(gate_pin, LOW);
    delay(tempo / 2);
    digitalWrite(gate_pin, HIGH);
    delay(tempo / 2);
  }

  else if ( counter == 6) {
    counter++;
    Serial.println("SE7EN");

    //LED
    digitalWrite(12, LOW);
    digitalWrite(11, HIGH);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
    digitalWrite(4, LOW);

    analogWrite(cv_pin, cv_value7);
    Serial.println(cv_value7);



     digitalWrite(gate_pin, LOW);
    delay(tempo / 2);
    digitalWrite(gate_pin, HIGH);
    delay(tempo / 2);
  }

  else if ( counter == 7) {
    counter = 0;
    Serial.println("EIGHT");

    //led
    digitalWrite(12, HIGH);
    digitalWrite(11, LOW);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
    digitalWrite(4, LOW);
  
    //knob
    analogWrite(cv_pin, cv_value8);
    Serial.println(cv_value8 );

    //gate
    digitalWrite(gate_pin, LOW);
    delay(tempo / 2);
    digitalWrite(gate_pin, HIGH);
    delay(tempo / 2);
  }

}

The midi connector is hooked up to pin 1

Looks like you have to send the 'clock tick' byte (decimal 248) 24 times per beat. At 120 BPM (2 beats per second) that would be 48 bytes per second. At 3225 bytes per second you have plenty of bandwidth to spare. There are 'start', 'stop', and 'continue' bytes to synchronize devices.

Okay that makes sense. Do I need to use a library or change my Serial.begin(9600) or declare anything specific?

EDIT: Also - if im sending 24 ticks a beat, for 120 thats 48 but for a number like 73 where its 29.20, will MIDI accept floats like that?

Two things that will help, but you'll have to learn a little -
Eliminate the delay() calls, and use millis() timers which you create in code.

Secondly, digitalWrite() is notoriously slow. Without looking too closely, you should be able to shrink and speed those blocks with 2-3 lines of code to write directly to the output pins (as ports).

With understanding those changes, it will become apparent how to implement a continuous MIDI Heartbeat, with other user payload at intervals that you decide.

sk8r24t:
Do I need to use a library or change my Serial.begin(9600) or declare anything specific?

The MIDI baud rate is 32250 so you should use that if you want to send MIDI data.

sk8r24t:
Also - if im sending 24 ticks a beat, for 120 thats 48 but for a number like 73 where its 29.20, will MIDI accept floats like that?

The interval between characters is not something MIDI deals with. You have to time the intervals.

Divide by 60 to get BPS.
Multiply by 24 to get TPS (Ticks Per Second).
Divide into 1,000,000 to get microseconds between ticks.

120 BPM is 2.0 BPS is 48 TPS is a tick every 20833 microseconds.

73 BPM is 1.21666... BPS is 29.2 TPS is a tick every 34247 microseconds.

johnwasser:
The MIDI baud rate is 32250 so you should use that if you want to send MIDI data.

The interval between characters is not something MIDI deals with. You have to time the intervals.

Divide by 60 to get BPS.
Multiply by 24 to get TPS (Ticks Per Second).
Divide into 1,000,000 to get microseconds between ticks.

120 BPM is 2.0 BPS is 48 TPS is a tick every 20833 microseconds.

73 BPM is 1.21666... BPS is 29.2 TPS is a tick every 34247 microseconds.

Hello John,

I'm using the following formula to calculate the tick in a loop program. Could you check it?

bpm | bpm | bpm | sec | bps | microsec | Tick

120 / (120 * ((120 / 60 * 24 ) / 1,000,000 )) = 20833.33333

73 / ( 73 * (( 73 / 60 * 24 ) / 1,000,000 )) = 34246.57534

Correction (this will matter): The MIDI baud rate is not 32250, its 31250, which is 1000000/32

jisv48:
I'm using the following formula to calculate the tick in a loop program. Could you check it?

Yup.

You need to get your timing using micros(), and account properly for elapsed time in the code,
which means using something like:

unsigned long us_per_tick = (unsigned long) (1e6 / (bpm * 24.0 / 60.0)) ;
unsigned long last_tick = 0UL ;

void loop()
{
  if ((micros () - last_tick) >= us_per_tick)
  {
    last_tick += us_per_tick ; // schedule next tick
    send_midi (0xF8) ; // clock byte
  }
  ...
}

What's the clock source for your sequencer?

[edit] just from your initial description, I can't tell if you want the Arduino to be slave to an existing clock, or if the Arduino is providing the master clock.