I am getting tired of deriving formulas for converting various MIDI data to real time. At the moment I’m wanting to make a standard MIDI file (SMF) to CSound .sco conversion utility. (Yes, I know there already is one) The most significant part of the task is to come up with some code that takes the time signature, tempo, and timing data and converts it to clock time (in seconds)
So here we go, with an attempt of memorializing this once and for all!
MIDI Division is the number of delta-times per quarter note. I’m calling the units of division [ticks/quarter-note]
MIDI Tempo is specified in [microsecond/quarter-note]
A MIDI quarter-note is 24 MIDI-clocks. (clocks are not ticks. Clocks are not delta-times)
Some quantities comprising a MIDI time signature (we don’t need this for the problem at hand but, while I’m documenting this stuff, I’ll include it): numerator (beats-per-bar), denominator – as a negative power of two, number of MIDI-clocks per metronome click [MIDI-clocks/beat] and number of 32nd notes per MIDI quarter (this last number I’m assuming is always constant equal to eight.
So, to convert a quantity of MIDI delta-times to seconds:
(numDeltaTimes[ticks] / division [ticks/quarter-note]) *tempo[microseconds/quarternote]*(1[second]/10^6[microseconds])
or with out all my ‘unit’ notation:
numTicks * tempo / (division * 10^6)
where numTicks, temp and division are the raw quantities from the events and header of the MIDI file.
I’ve had this idea of a beat-centric temporal model for a long time now. Originally, I wanted a system that would analyze rhthym patterns in terms of beats – as opposed to milliseconds, or standard notational conventions (quavers, semi-quavers etc…) Over the years, the essential parts of the model have remain unchanged:
- Beat Time – Represents an instant in a performance. Beat Time is a 3-tuple bar-number, beat-number, and beat-fraction e.g. (bar#, beat#, beatfraction) There’s an assumption that the beat-fraction is a proper fraction (less than 1) and that the beat-number doesn’t exceed the number beats per bar as specified in the current time signature.
- Time Signature List – Provides a context for Beat Times. In this model, each time signature contains a numerator and a denomenator just like the standard notation time signature plus, a beats-per-bar, specification. In the early prototyping, the API forced Beat Times to have a Time Signature associated with them. (This is restriction is removed in the present effort.) When we looking at a small temporal neigborhood – less than two or three beats – the issue of beats-per-bar is not so important but, when we look at longer passages, we need the beats-per-bar to help us with the book keeping.
Tonight I was looking at some code that would build a Time Signature List from a sequence of MIDI events. Up till now I had been feeling pretty good about this model but, I was reminded of it’s difficulty in dealing with compound meters (e.g. 5/8, 7/8 etc…)
Say we have a section that would be written in 5/8 and the meter of eight notes is like ONE-two THREE-four-five. An imaginary conductor would make two large gestures in each bar (Gesticulating each eighth note would be too frantic and not capture the essence of the meter.) In this case, in the spirit of beat-centric modeling we really want to say there are two, uneven, beats per bar. But, this model, as it is now, can’t deal with this. We are forced to model our example as five beats-per-bar cause we can only deal with even, regular beats.
Well before I get too bummed about this, I have to point out that the MIDI file format suffers from the same limitation. In MIDI files there is a parameter to the Time Signature Meta Event that specifies the number of MIDI clocks per metronome click.
The solution (I’m making this up right now) is to extend the constant beats-per-bar notion with some kind of map that specifies where the beats fall within each bar.