- Originally published April 13, 2014.
Part 5 of a Series
Exploring Notes in MIDI Files.
Sample MIDI File
I’m using Bach’s "Two-Part Invention No. 1" in this series. Here is a PDF of the sheet music and a MIDI file for the piece.
MIDI Notes
In Part 4 of this series we extracted the notes from the sample MIDI file. I listed them for the first measure like this for the treble clef.
First Measure Treble Clef
Note - timestamp: 0.250, channel: 0, note: 60, velocity: 90, release velocity: 0, duration: 0.250
Note - timestamp: 0.500, channel: 0, note: 62, velocity: 90, release velocity: 0, duration: 0.250
Note - timestamp: 0.750, channel: 0, note: 64, velocity: 90, release velocity: 0, duration: 0.250
Note - timestamp: 1.000, channel: 0, note: 65, velocity: 90, release velocity: 0, duration: 0.250
Note - timestamp: 1.250, channel: 0, note: 62, velocity: 90, release velocity: 0, duration: 0.250
Note - timestamp: 1.500, channel: 0, note: 64, velocity: 90, release velocity: 0, duration: 0.250
Note - timestamp: 1.750, channel: 0, note: 60, velocity: 90, release velocity: 0, duration: 0.250
Note - timestamp: 2.000, channel: 0, note: 67, velocity: 90, release velocity: 0, duration: 0.500
Note - timestamp: 2.500, channel: 0, note: 72, velocity: 90, release velocity: 0, duration: 0.500
Note - timestamp: 3.000, channel: 0, note: 71, velocity: 90, release velocity: 0, duration: 0.500
Note - timestamp: 3.500, channel: 0, note: 72, velocity: 90, release velocity: 0, duration: 0.500
Let’s look at what these notes are in more detail and at how Core MIDI lets us work with them. MIDI is a streaming control protocol. It was intended for playing music live and is action based. A MIDI device, like a keyboard controller, would send these events to a computer to play a quarter note that is middle C (C4).
- Start playing C4 at timestamp 0.0
- Stop playing C4 at timestamp 1.0

Core MIDI simplifies this for us by combining the Note On and the balancing Note Off message into one MIDINoteMessage
struct. When we get a note and cast the data into a note message we have all the information for one note.
Getting One Note
MusicEventIteratorGetEventInfo(iterator, ×tamp, &eventType, &eventData, &eventDataSize);
if (eventType == kMusicEventType_MIDINoteMessage) {
MIDINoteMessage *noteMessage = (MIDINoteMessage*)eventData;
}
Here’s the MIDINoteMessage
struct.
MIDINoteMessage
typedef struct MIDINoteMessage {
UInt8 channel;
UInt8 note;
UInt8 velocity;
UInt8 releaseVelocity;
Float32 duration;
} MIDINoteMessage;
The data for our note would look like this.
Middle C Quarter Note
Note - timestamp: 0.0, channel: 0, note: 60, velocity: 90, release velocity: 0, duration: 1.0
What does a duration
of 1.0 mean?
MIDI timestamps are a relative time indicator, not an absolute time. The default value of a quarter note is 1.0. A MIDI file starts with a timestamp of 0.0. All the notes will have a timestamp relative to 0.0. Here is a list of some of the common notes and their default duration
values.
- Whole Note: 4.0
- Half Note: 2.0
- Quarter Note: 1.0
- Eighth Note: 0.5
- Sixteenth Note: 0.25
The duration
is the only data we have in MIDI about the length of a note. We do not have a flag saying what type of note it is in the score.
What about tied or dotted notes?
It’s very common in music scores to have tied notes like this:

or dotted notes like this:

How are these done in MIDI? They aren’t. There is no way in MIDI to do these notes. It is not a notation language, it is a streaming protocol. When a note is played all we hear is how long it was played, we have no information on how it was scored in the sheet music. The tied note would have this information in the MIDINoteMessage
duration
: 2.25
The dotted note would be
duration
: 0.75
What about notes that could be either tied or dotted? We don’t have enough information to distinguish between them unless the note extends over a measure boundary. We can’t make a fully accurate score from a MIDI file, there is not enough information.
What about rests?
There is no MIDI event for a rest in a music score. To MIDI, a rest is the absence of a note. Our sample piece gives a good example of this. Here is the first measure.

The treble clef starts with a sixteenth note rest. The timestamp for the first note event is 0.25. This implies that there is a rest before the first note of 0.25, which is a sixteenth note rest.
First Three Notes – Treble Clef
Note - timestamp: 0.250, channel: 0, note: 60, velocity: 90, release velocity: 0, duration: 0.250
Note - timestamp: 0.500, channel: 0, note: 62, velocity: 90, release velocity: 0, duration: 0.250
Note - timestamp: 0.750, channel: 0, note: 64, velocity: 90, release velocity: 0, duration: 0.250
In the bass clef the first note starts at 2.25. That is a half note and a sixteenth note into the measure. We can assume there are rests in the score for that length, but we can only guess as to how it has been notated.
First Three Notes – Bass Clef
Note - timestamp: 2.250, channel: 1, note: 48, velocity: 90, release velocity: 0, duration: 0.250
Note - timestamp: 2.500, channel: 1, note: 50, velocity: 90, release velocity: 0, duration: 0.250
Note - timestamp: 2.750, channel: 1, note: 52, velocity: 90, release velocity: 0, duration: 0.250
Human Readable Notes?
Can we convert the MIDI data for a note into a human readable music note? We can finally answer yes to a question. The data for the note value can be from 0–127. Middle C (261.6 Hz) is 60. Every half step is a value of 1 away from the notes next to it. This gives us this chart for note translation.
MIDI Value to Music Note (sharps)
A0 A#0 B0 C1 C#1 D1 D#1 E1 F1 F#1 G1 G#1 A1 A#1 B1 C2 C#2 D2 D#2 E2 F2 F#2 G2 G#2 A2 A#2 B2 C3 C#3 D3 D#3 E3 F3 F#3 G3 G#3 A3 A#3 B3 C4 C#4 D4 D#4 E4 F4 F#4 G4 G#4 A4 A#4 B4 C5 C#5 D5 D#5 E5 F5 F#5 G5 G#5 A5 A#5 B5 C6 C#6 D6 D#6 E6 F6 F#6 G6 G#6 A6 A#6 B6 C7 C#7 D7 D#7 E7 F7 F#7 G7 G#7 A7 A#7 B7 C8
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
The sharped notes can also be flatted notes depending on the key. We also know the key signature of each measure so we can accurately translate notes. You can use a simple array to translate as in this C function.
noteForMidiNumber()
const char * noteForMidiNumber(int midiNumber) {
const char * const noteArraySharps[] = {"", "", "", "", "", "", "", "", "", "", "", "",
"C0", "C#0", "D0", "D#0", "E0", "F0", "F#0", "G0", "G#0", "A0", "A#0", "B0",
"C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", "G#1", "A1", "A#1", "B1",
"C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2",
"C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3",
"C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4",
"C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5",
"C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6",
"C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", "G#7", "A7", "A#7", "B7",
"C8", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
return noteArraySharps[midiNumber];
}
Wrap Up
That’s all we do in this post in the series. The next logical step is to combine notes into measures. That will be the next entry.
Just keep coding,
-Eric