Precision Timing for Midi Sequencer

I've been working on programming a midi sequencer with the arduino. My arduino set up is very simple, the same schematic as the arduino midi tutorial and I'm using an Uno. I already have an idea of how I'm going to set up my program, but I'm having difficulty syncing even the most basic midi sequencer to a particular bpm. To start, I'm trying to sync to 120 bpm (a delay of .5 seconds between notes). What I actually do is turn on a note, wait .25 seconds, turn it off, and wait .25 more seconds. So, here's what I've tried in order of what's been closest to 120bpm:

  1. Manually adjusting settings of Timer1 using CTC mode and a 256 prescaler and ISRs (see code below)
  2. Using Timer1 Library and attachInterrupt
  3. Using micros() and noInterrupts()
  4. Using millis()
  5. Using delay()

I'm only including the code from 1) since I think it's been the closest. I've also been doing a lot of research. Here are the articles I've been using:

Timers 101
This series of blog posts about timers
This article as a code starting point

And more! So what I've been doing is running my midi sequencer and then running a logic 120 bpm click track. Every time, my sequencer phases out with the click track after 15-30 seconds (the bpm of the sequencer is always a little slower than the click). I also use this youtube bpm counter, which I've verified syncs well with the logic click track.

Needless to say, this problem is driving me crazy. I'm starting to think that 120 bpm isn't a real thing.

Do you have any suggestions about 1) how to do precision timing with arduinos, 2) where my lag is coming from (maybe it's from the midi or maybe it's my hardware) 3) any code examples of precision timing with an arduino?

Any help would be greatly appreciated!

// Includes
#include <avr/io.h>
#include <avr/interrupt.h>

int last_action=0;

void setup()
{
    //  Set MIDI baud rate:
    Serial.begin(31250);

    // initialize Timer1
    cli();          // disable global interrupts
    TCCR1A = 0;     // set entire TCCR1A register to 0
    TCCR1B = 0;     // same for TCCR1B

    // set compare match register to desired timer count:
    OCR1A = 15624;
    // turn on CTC mode:
    TCCR1B |= (1 << WGM12);
    // Set CS12 bits for 256 prescaler:
    TCCR1B |= (1 << CS12);
    // enable timer compare interrupt:
    TIMSK1 |= (1 << OCIE1A);
    // enable global interrupts:
    sei();
}

void loop()
{
    // do some crazy stuff while my midi notes are playing
}

ISR(TIMER1_COMPA_vect)
{
  // Turn notes on
  if (last_action == 0) {
    send_note(0x90, 60, 0x45);
    last_action = 1;

  // Turn notes off
  } else {
    send_note(0x90, 60, 0x00);
    last_action = 0;
  }
}

//  plays a MIDI note
void send_note(int cmd, int pitch, int velocity) {
  Serial.write(cmd);
  Serial.write(pitch);
  Serial.write(velocity);
}

Your clock is fine. You don't need to tink a lot, arduino precision is more than enough. It won't be an atomic clock obviously.
You have another problem, you can't sync two sources by just starting them manually at the same time.
Just try with other thing, that 120bpm clock from youtube and a real metronome. They will go out of phase eventually. That's why midi clock was invented, MTC, wordclock, SMPTE, etc. The only way to have two sources in sync is by connecting them with any of this sync options. The easiest is MIDI CLOCK. It sends a 24 pulses per 1/4 note. So, don't worry, your timer is fine.
I'm also designing a midi sequencer, already started 6 months ago, and I was trying to measure the time with that 120bpm clock from youtube too :slight_smile: . Then i said "wait, i have an oscilloscope" checked it, and it was 500ms.
Arduino is good enough. I have lot of multiplexers, more than 30 pots, 20 switches, and more, and when i slave a machine(arduino sending midi clock) it's always tight at a defined BPM, it doesn't drift. And if it drift, both instruments will drift together

Well this is definitely good to hear. I was losing sleep over this problem. Here's the thing, I literally have been trying to figure out how to sync all of my (music) hardware for 6 months, but maybe I never did the right google search. So yeah, thanks for that response.

However, I still don't understand why these bpms can't line up, maybe you can shed some light on it. A minute is an absolute measure of time. 120 beats per minute always should mean the same thing (that a note should occur at seconds 0, .5, 1, 1.5 etc.). Why could two devices at 120 bpm be different? Maybe our timers and the crystals that we use to measure time just aren't that precise?

In anycase, I do believe what you're saying. I've had synthesizers in the past that have whack tempos. Maybe I'll try to hook this up to a midi clock and see if that does the trick.

brain_deer:
Well this is definitely good to hear. I was losing sleep over this problem. Here's the thing, I literally have been trying to figure out how to sync all of my (music) hardware for 6 months, but maybe I never did the right google search. So yeah, thanks for that response.

However, I still don't understand why these bpms can't line up, maybe you can shed some light on it. A minute is an absolute measure of time. 120 beats per minute always should mean the same thing (that a note should occur at seconds 0, .5, 1, 1.5 etc.). Why could two devices at 120 bpm be different? Maybe our timers and the crystals that we use to measure time just aren't that precise?

In anycase, I do believe what you're saying. I've had synthesizers in the past that have whack tempos. Maybe I'll try to hook this up to a midi clock and see if that does the trick.

Even if you try to start two clocks at the same time, they'll lose sync.
Time is something really hard to control I guess.
I just know that it's impossible to sync two sources with just your hands. I don't know the real reasons, but I can guess, maybe the crystals have different specs, one device is doing millions of other things, they have different temperatures and different drifts. I measured a few devices, and it's impossible that they're counting exactly 500ms. They suerly have +/- 2ms of fluctuation.

I suppose the only way to have two exact clocks is with atomic clocks.

I'll do some more investigating, and in the meantime, I'm going to try to turn this midi step sequencer into a slave machine.

check this one Syncuino - Stability at different MIDI master clock speeds - YouTube

For testing purpose, connect the MIDI out of your Arduino to a PC midi in and use Midi Sync Transport of MIDI OX to check the BPM (Menu View->Midi Sync).

I have built my own midi master clock wit an Arduino Uno. It is accurate from 30 to 300 bpm.

You do realise you're replying to a post that's more than 4 years old? They may have worked it out by now...or given up.

Steve

Certainly brain_deer is departed this forum. This is shown by the status "Guest" underneath his name. This means he will never get notification of your post.