How to get Exact Time of a MIDI event
Asked Answered
A

2

8

I'm trying to read a MIDI file and I want to determine the exact time of a NoteOn event from it in C#.
I tried to use absolute time, but the output was something like 256632.
What is this number ? This is the line of my code that returns the time :

(note as NoteOnEvent).AbsoluteTime
Aldas answered 14/4, 2014 at 21:11 Comment(0)
T
16

A MIDI file only contains incremental times. Included as a variable length value between 1 and 4 bytes before each MIDI event. The library you are using is being helpful in providing you with the AbsoluteTime property. Simply calculated by summing the incremental times for each event.

The unit is "delta ticks". The length of a delta tick is not a fixed value, it is specified in the MIDI file header. NAudio exposes it as the MidiFile.DeltaTicksPerQuarterNote property. So you'll need to divide the value you get from AbsoluteTime by this value to get the note position from the start of the song.

This is of course still a relative value, it depends on the tempo of the song. The rate at which you play quarter notes. The recommended tempo is included in the file as well, it is the TempoEvent in NAudio. Its MicrosecondsPerQuarterNote property tells you how long a quarter note should be for subsequent events. Beware that there can be more than one tempo event in a song.

Thecla answered 14/4, 2014 at 21:52 Comment(2)
Thanks a lot so I have to do this : ((note as NoteOnEvent).AbsoluteTime/midi.DeltaTicksPerQuarterNote)*tempo ?Aldas
That calculation is right only if the tempo does not change. If it does, you have to compute the time relative from the last tempo change: ((note.AbsTime - lastTempoEvent.AbsTime) / midi.ticksPerQuarterNote) * tempo + lastTempoEvent.RealTime. (The formula above is a special case where the tempo event is at time 0.)Op
B
3

Delta-times

Time attached to every event in a MIDI file is an offset from the previous event. This offset is called delta-time.

As said by Hans Passant it is stored in a file before an event in special form called variable-length quantity (VLQ). Yes, standard says that VLQ representations must fit in 32 bits (4 bytes). But, theoretically (and there are some real files on the web), larger numbers are possible, so it is much better if a library which provides MIDI file parsing uses integer type bigger than regular int. long for the AbsoluteTime in NAudio is a good choice.

Absolute time

AbsoluteTime property returns just sum of all preceding delta-times and the current event's one.

Meaning of time

What every delta-time or an absolute one actually means depends on time division of a MIDI file. There are two different types of time division:

  • Ticks Per Quarter Note
  • SMPTE Time Division

In first case all times expressed as number of ticks. For example, if division is 96, then a delta-time of 48 defines interval of an eighth-note. As also said by Hans Passant NAudio exposes it as the MidiFile.DeltaTicksPerQuarterNote property

In second case all times expressed as number of subdivisions of a second in a way consistent with SMPTE and MIDI Time Code. In practice it is very very very rare type of time division.

"Understandable" representations of time

I think the most "understandable" format for time is metric time (hours, minutes, seconds). As said by Hans Passant and CL you need to know changes of tempo through a MIDI file to calculate metric time of a MIDi event.

There are some libraries that do this calculation for you. For example, with DryWetMIDI you can get metric time of an event with this code:

MidiFile midiFile = MidiFile.Read("Some MIDI file.mid");
TempoMap tempoMap = midiFile.GetTempoMap();

MetricTimeSpan timeOf10thEvent = midiFile.GetTimedEvents()
                                         .Skip(9)
                                         .First()
                                         .TimeAs<MetricTimeSpan>(tempoMap);

With this library you can also get time as bars, beats (using BarBeatTicksTimeSpan or BarBeatFractionTimeSpan) or a fraction of the whole note's length (using MusicalTimeSpan).

Calculation of musical time uses changes of time signature. Both tempo and time signature changes provided by tempo map of a MIDI file that can be obtained with GetTempoMap extension method for MidiFile.

Besot answered 8/7, 2017 at 5:35 Comment(5)
Nice answer! Aside: If I am reading the bytestring representation of a .mid file, how do I know when I have stumbled across a byte that is the first byte of a sequence of delta time bytes?Brawny
@Brawny Just follow by Standard MIDI file spec. You read MIDI events. Once MIDI event read, next byte is the first byte of delta-time bytes. Or you reached the end of a track chunk or entire MIDI file.Besot
Thank you @Maxim. So: (1) read the 1st byte of delta time; continue reading bytes until the one contains the termination bit. (2) Next byte is either the first event byte (the command byte, yes?), based on the command byte there will be one or two data bytes after when return to step 1, or then next byte will signal the end of the midi track. Is that about right?Brawny
There can be more than two data bytes in case of meta events or system exclusive ones. Please read MIDI file spec: midi.org/specifications-old/item/standard-midi-files-smf.Besot
Yes... I am specifically thinking just about MIDI events, but you are right to remind me of SYSEX and meta also.Brawny

© 2022 - 2024 — McMap. All rights reserved.