1

I need to get the tempo value from midi file. I found out, that the set_tempo command has value 0x51, so i have this piece of code:

    for (int i = 0; i < tracks[0].size(); i++) {
        MidiEvent event = tracks[0].get(i);
        MidiMessage message = event.getMessage();
        if (message instanceof MetaMessage) {
            MetaMessage mm = (MetaMessage) message;
            if(mm.getType()==SET_TEMPO){
                // now what?
                mm.getData();
            }
        }
    }

But the method getData() returns an array of bytes! How can I convert it to normal human form, a.k.a. integer? I have read it is stored in format like this: "tt tt tt", but the whole big/little endian, signed/unsigned, and variable length things make it too confusing.

Filburt
  • 17,626
  • 12
  • 64
  • 115
Leprechaun
  • 852
  • 6
  • 25

2 Answers2

8

Tempo is a 3-byte big-endian integer and Bits Per Minute is calculated as
BPM = 60,000,000 / (tt tt tt)

byte[] data = mm.getData();
int tempo = (data[0] & 0xff) << 16 | (data[1] & 0xff) << 8 | (data[2] & 0xff);
int bpm = 60000000 / tempo;
apangin
  • 92,924
  • 10
  • 193
  • 247
1

I use:

mpq = ((data[0] & 0x7f) << 14) | ((data[1] & 0x7f) << 7) | (data[2] & 0x7f);

Where mpq represents microseconds per quarter note or microseconds per beat.

The reasoning for this is that Midi messages only use 7 bits in each byte to represent data. It should also be noted that, in Java, a byte data type (of which data is an array) is a signed integer and only has room for 7 data bits.

Since making this post I have had the following response from the MIDI Association:

The parameter number (tttttt) is a 24 bit unsigned integer, in big endian format.

"Set tempo" is a meta-event, belonging to the SMF specification. It applies only to Standard MIDI Files, and like the other meta-events are not supposed to be transmitted over the wires on real time. On the other hand, the Data Byte description that is confusing you applies to the over-the-wire protocol.

The original answer to this topic is therefore correct.

  • Don't both solutions provide the same results? If that's so, I don't understand what's the advantage of your solution. – Leprechaun Aug 09 '17 at 14:06
  • The results will differ by approximately a factor of 4. Even if the first result is divided by 4 it will differ from the second result by up to 3% depending on the pattern of bits and the presence of the sign bit in each data item. The way to test this is to check the duration of a piece of music played back or recorded at various tempos. – user8182116 Aug 09 '17 at 18:30
  • That's weird. I actually used the accepted answer in my bachelor's thesis few years ago. It provided correct results when printing and evaluating some midi data correlated to estimated fundamentals. And the lengths of recordings were also equal to the plotted and evaluated midi signals. The tracks were up to a few minutes, so a difference in factor of 4 would be noticed immediately. If what you are saying is true, the only way I can explain it is it can be observed only at specific tempo values. Is that correct? – Leprechaun Aug 09 '17 at 20:31
  • The discrepancy can vary from 0 to about 3% depending on the tempo. You can work it out if you look at the bit pattern. A tempo of 120 bpm represents an mpq of 500000. This in binary is – user8182116 Aug 09 '17 at 21:15
  • The discrepancy can vary from 0 to about 3% depending on the tempo. You can work it out if you look at the bit pattern. A tempo of 120 bpm represents an mpq of 500000. This in binary is 001111010000100100000. If you split this into three groups of seven bits and convert to decimal you get 30 66 32. If you have this tempo in your program and do System.out.println(data[0] + " " + data[1] + " " + data[2]); you will get 30 66 32. I can't find anything in the Midi specification that says binary variables should be signed or unsigned but it does look like Java is using signed variables. – user8182116 Aug 09 '17 at 21:33
  • I will look into this when I will have some spare time. If it is really the case, I will change the accepted answer. – Leprechaun Aug 10 '17 at 13:52
  • I have just had the following response from the MIDI Association: "The parameter number (tttttt) is a 24 bit unsigned integer, in big endian format. "Set tempo" is a meta-event, belonging to the SMF specification. It applies only to Standard MIDI Files, and like the other meta-events are not supposed to be transmitted over the wires on real time. On the other hand, the Data Byte description that is confusing you applies to the over-the-wire protocol.". The accepted answer to your post is the correct one and I apologise for any confusion i caused you. – user8182116 Aug 12 '17 at 07:03
  • Oh, OK then. Nevertheless, if your provided piece of code is corect for a similar (over the wire) protocol / standard, you can point that out in your answer and leave it there. It may be helpful to others. Still, thank you for your time and efforts. – Leprechaun Aug 12 '17 at 08:38