[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Mockingboard
jboothbee@gmail.com wrote:
Or, since MIDI is already a merged stream of note beginning and ending
times, it would be more straightforward (and maybe just as easy) to
simply write a "player" for MIDI files that would read in a MIDI file
and stuff Mockingboard registers directly--or, better, construct a
circular buffer of registers to stuff under IRQ control.
BTW, a correction to my statement: a MIDI file is a collection of
one or more "tracks". Each track is a time-merged series of sequential
events. If there are two or more tracks, then the track events must be
merged to create a single timeline.
it might be easier to write a player, but I think real-time conversion
will
tax the CPU too much in a game.
Probably so. Still, I think that a real time-player is the first
thing to get working. Then it's easy to capture the Mockingboard
event list to a file and play it with an IRQ routine.
Debugging will be much easier for a real-time player.
do you have in your notes a "disassembled" MIDI file, commented?
IE:
pos in file MIDI FILE DATA what it is
+00 $08 header,
indicates ?tracks? in file
+01 header,
indicates ?voices? in file
+02
+03
+04 $45 start of music
data, play note = 45
+05 $56
stop note = 45
If you have anything like this from your work with the converter,
it would be extremely helpful.
I covered lots of sheets of paper with things like this, all of
a very "transitory" nature, and all done by looking at hex dumps
of MIDI files and referring to a good MIDI definition document:
http://www.borg.com/~jglatt/tech/midifile.htm
http://www.sonicspot.com/guide/midifiles.html
http://jedi.ks.uiuc.edu/~johns/links/music/midifile.html
I began top-down, by recognizing the "MThd" header and the "MTrk"
headers, then wrote case statements for the meta-events, and
then the track events. I threw in PRINT statements liberally
in new code so I could be sure of what it was doing, and left
the more informative (and not *too* verbose) statements in under
control of a debug conditional.
The result was that as the program developed, it could display
the parse of the MIDI file to a useful level of detail.
The high bit of each byte can be very significant (!) in a MIDI
stream. It is used to mark the start of a (big-endian) variable
length quantity, like a time delta. It also marks a new status
byte for a message. Generally, only the low-order seven bits
of a byte are used for data.
You will find that there are several "styles" of MIDI files, and
what looks like a stable convention in one set of files will be
done differently in another set. For example, MIDI specifies
both "key down" and "key up" events to start and end notes, but
each "key down" also has a "velocity" field which specifies how
hard the key was struck. Some MIDI files use "key down" events
exclusively, but set the velocity to 0 to signify note end.
Another example is "running status", which allows some data
compression by factoring out the last event type and channel,
and just providing notes and velocities for several events that
occur at the same time. Some MIDI files use running status,
and some do not.
If you look at MIDI.CVT, a central data structure is the array
TNT, which holds the time of the next event in each track. Time
is kept in units of 92 cycles (1 RT.SYNTH sample time). Each
time the next event is needed, this array is searched for the
nearest time and the event is chosen from that track. If more
than one track have events at the same time, then the order in
which they are processed is irrelevant, but is set by the search
order.
-michael
Music synthesis for 8-bit Apple II's!
Home page: http://members.aol.com/MJMahon/
"The wastebasket is our most important design
tool--and it is seriously underused."