Arduino MIDI Library - get "tempo"

Hi,

I’m using the Arduino MIDI Library from https://github.com/FortySevenEffects/arduino_midi_library

I connected to arduino micro and tried the MidiUSB example:

#include <MIDI.h>

#if defined(USBCON)
#include <midi_UsbTransport.h>

static const unsigned sUsbTransportBufferSize = 16;
typedef midi::UsbTransport<sUsbTransportBufferSize> UsbTransport;

UsbTransport sUsbTransport;

MIDI_CREATE_INSTANCE(UsbTransport, sUsbTransport, MIDI);

#else // No USB available, fallback to Serial
MIDI_CREATE_DEFAULT_INSTANCE();
#endif

// --

void handleNoteOn(byte inChannel, byte inNumber, byte inVelocity)
{
    Serial.print("NoteOn  ");
    Serial.print(inNumber);
    Serial.print("\tvelocity: ");
    Serial.println(inVelocity);
}
void handleNoteOff(byte inChannel, byte inNumber, byte inVelocity)
{
    Serial.print("NoteOff ");
    Serial.print(inNumber);
    Serial.print("\tvelocity: ");
    Serial.println(inVelocity);
}

void setup() {
    Serial.begin(115200);
    while (!Serial);
    MIDI.begin();
    MIDI.setHandleNoteOn(handleNoteOn);
    MIDI.setHandleNoteOff(handleNoteOff);
    Serial.println("Arduino ready.");
}

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

I used MuseScore, threw some notes and the representation of the notes appear in the Serial Monitor.

Then i put all the callbacks in the code and tested again:

// not the full code, only the callbacks
    MIDI.setHandleAfterTouchPoly(OnAfterTouchPoly);
    MIDI.setHandleControlChange(OnControlChange);
    MIDI.setHandleProgramChange(OnProgramChange);
    MIDI.setHandleAfterTouchChannel(OnAfterTouchChannel);
    MIDI.setHandlePitchBend(OnPitchBend);
    MIDI.setHandleSystemExclusive(OnSystemExclusive);
    MIDI.setHandleTimeCodeQuarterFrame(OnTimeCodeQuarterFrame);
    MIDI.setHandleSongPosition(OnSongPosition);
    MIDI.setHandleSongSelect(OnSongSelect);
    MIDI.setHandleTuneRequest(OnTuneRequest);
    MIDI.setHandleClock(OnClock);
    MIDI.setHandleStart(OnStart);
    MIDI.setHandleContinue(OnContinue);
    MIDI.setHandleStop(OnStop);
    MIDI.setHandleActiveSensing(OnActiveSensing);
    MIDI.setHandleSystemReset(OnSystemReset);

As expected there was more info in the Serial Monitor, specially Control Changes…

So I started changing the music tempo on MuseScore but nothing changes on Serial Monitor…

Can anyone help me getting the music tempo from the midi, please?

Thanks in advanced!

Can anyone help me getting the music tempo from the midi, please?

Basically you can’t. There is no concept of tempo in MIDI. It is a real time messaging system, the only thing that defines the tempo is the device sending the messages.

All a receiving device can do is time the arrival of individual notes, but that is not the same thing as tempo.

You could get the sending system to send a timing clock message

11111000 Timing Clock. Sent 24 times per quarter note when synchronization is required.

But again that is not related to tempo.

Hi Grumpy_Mike, thank you for your answer!

I’ve been digging about this issue:

I saved 2 midi files wich the only diference between them is tempo (80bpm and 120bpm)

I installed an hex editor on notepad++ and open both files - i attach a print highlighting the diference between the two.

Then i read here that this is a meta message with the prefix FF5103 - like in both files and the highlighted hex numbers were the tempo in microseconds.

Following simple math:

0b71b0HEX → 750000DEC (60000000/750000 = 80)
07a120HEX → 500000DEC (60000000/500000 = 120)

So there is definitely the tempo information on a midi file (maybe not midi compliance) set as meta messages.

So my new question: Can you tell me if there is a way to read meta messages with the arduíno midi library?

Thank you for your time!

The tempo in the MIDI file is used by the sending device to make sure the timing is correct. The actual tempo is not sent as a MIDI message.

Can you tell me if there is a way to read meta messages with the arduíno midi library?

Sorry it is still a no.

Hugo- Like Mike mentioned, you need the sending system to send CLOCK to synchronize ‘tempo’ across devices.
Sadly, it doesn’t look like MuseScore supports MIDI CLOCK output. If they were to add that support, you should be able to sync with any modern midi device.

You could ~maybe~ write some code that would convert that Meta-Data tempo value to clock… but it almost certainly wouldn’t be N’SYNC, you know? You will probably end up with your receiving device playing 1/8 of a beat late or something dumb. Though… it might be worth trying. I have never done it, but I would think it would go something like this, although it is with a different library:

Step one: use the incoming metadata to define a variable.
Step two: generate clock as below (which is just an example from the lib)

https://github.com/midilab/uClock

#include <uClock.h>

// MIDI clock, start and stop byte definitions - based on MIDI 1.0 Standards.
#define MIDI_CLOCK 0xF8
#define MIDI_START 0xFA
#define MIDI_STOP  0xFC

// The callback function wich will be called by Clock each Pulse of 96PPQN clock resolution.
void ClockOut96PPQN(uint32_t * tick) {
  // Send MIDI_CLOCK to external gears
  Serial.write(MIDI_CLOCK);
}

// The callback function wich will be called when clock starts by using Clock.start() method.
void onClockStart() {
  Serial.write(MIDI_START);
}

// The callback function wich will be called when clock stops by using Clock.stop() method.
void onClockStop() {
  Serial.write(MIDI_STOP);
}

void setup() {

  // Initialize serial communication at 31250 bits per second, the default MIDI serial speed communication:
  Serial.begin(31250);

  // Inits the clock
  uClock.init();
  // Set the callback function for the clock output to send MIDI Sync message.
  uClock.setClock96PPQNOutput(ClockOut96PPQN);
  // Set the callback function for MIDI Start and Stop messages.
  uClock.setOnClockStartOutput(onClockStart);  
  uClock.setOnClockStopOutput(onClockStop);
  // Set the clock BPM to METADATA VARIABLE
  uClock.setTempo(***INSERT THE METADATA VARIABLE HERE***]);

  // Starts the clock, tick-tac-tick-tac...
  uClock.start();

}


void loop() {

}

Better coders can probably help you work out the details, and it still almost certainly will not be in sync.
Good luck!