Calculate Tempo from external MIDI Clock pulses.

Status
Not open for further replies.

SteveO

Member
I need advice about calculating tempo from an external MIDI clock source.

I am using my Teensy as part of a MIDI foot controller to control another MIDI device. My intention is to read an external MIDI clock via a serial MIDI IN, calculate the tempo, and send the tempo value to the MIDI device I’m controlling. The device I'm controlling does not accept external MIDI clock in but it will accept a tempo value.

I can read the external clock, but accuracy is a problem. My tempo calculation is off as seen in the examples below.

Example:
Clock source 49 serial; calculated tempo 48
Clock source 132 serial; calculated tempo 133
Clock source 246 serial; calculated tempo 250

The code below is what I came up with, but I’m sure there must be a better way to accomplish what I’m trying to do. Also, the full sketch I’m using about 1700 lines long and I believe the time calculation may be affected by the time it takes to run the rest of the code which varies depending on button presses and other things. The values above were calculated using the code below not the entire 1700 line sketch.


I am not a very experienced programmer. Any suggestions would be helpful. Thank you.

Code:
#include <MIDI.h>
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
unsigned long MidiClockTime = 0;
unsigned long LastClkRead = 0;
unsigned long extTempo = 0;
int countClk = 0;
unsigned long deltaT[24];
unsigned long AvgClkTime = 0;
unsigned long TotalTime = 0;
unsigned long avgTime = 0;
unsigned long oldTemp = 0;

void setup() {
  Serial1.begin(31250);
  MIDI.setHandleClock(handleClock);
  MIDI.begin(MIDI_CHANNEL_OMNI);
}

void loop() {
  MIDI.read();
}

void handleClock() {
  MidiClockTime = (micros() - LastClkRead) ;
  LastClkRead = micros();
  deltaT[countClk] = MidiClockTime;
  countClk = countClk + 1;

  if (countClk == 24) {
    for (byte k = 2; k <= 24; k++) {
      avgTime = (deltaT[k] + deltaT[k - 1]) / 2; // find the time between 2 ticks
      TotalTime = TotalTime + avgTime;
    }
    AvgClkTime = TotalTime / 23;  // find the average difference in time between 24 ticks for better stability
    // Tempo (BPM) = (60 sec * 1/24 ticks * 10^6 microseconds)/ time between ticks in micro secs
    // minus two just because it got me closer the the clock in value
    extTempo = (2500000 / AvgClkTime) -2 ;
    TotalTime = 0;
    countClk = 0;
  }
  Serial.print("extTempo: ");
  Serial.println(extTempo);
}


I also get the error below when compiling and am not sure how to deal with it:

Code:
midiClockRead: In function 'handleClock()':
midiClockRead:31: warning: iteration 22 invokes undefined behavior 
       avgTime = (deltaT[k] + deltaT[k - 1]) / 2; // find the time between 2 ticks
                          ^
/var/folders/hh/fnqdklxx6z9__mzlchz0505r0000gn/T/arduino_modified_sketch_342107/midiClockRead.ino:30:24: note: containing loop
     for (byte k = 2; k <= 24; k++) {
 
Status
Not open for further replies.
Back
Top