Delphi 4 and 5 units MIDIRead.dcu, MIDIWrite.dcu Version 1.00
Copyright 2000: Alexei V. Gretchikha
E-mail:
[email protected]
LEGAL DISCLAIMER
It is your responsibility to make sure that the product is only used
for legal purposes and in a legal way. By using the demo or the full
version of this software product you agree that I am not responsible
for any consequences of such use. The product is provided "as is"
and comes without any explicit or implied warranty.
DESCRIPTION OF THE PRODUCT
MIDIRead and MIDIWrite Delphi units make it easy to read and write
standard MIDI files. The sample program block below illustrates how
they work. The program reads MIDI data from an input file, message
by message, and copies them into an output file:
ReadSMF(InputSMFName);
ReadSMFHeader(SMFType,Tracks,Ticks);
WriteSMFHeader(SMFType,Tracks,Ticks);
for trk := 1 to Tracks do
begin
ReadTrackHeader;
WriteTrackHeader;
repeat //until TrackEmpty//
ReadMIDIEvent(Delta,Status,Byte1,Byte2,Meta,MsgString);
WriteMIDIEvent(Delta,Status,Byte1,Byte2,Meta,MsgString);
VerifyEndOfTrack;
until TrackEmpty;
end;
VerifyEndOfSMF;
WriteSMF(OutputSMFName);
The above short program represents all the interface procedures
from the units. These procedures provide all the tools one needs
for efficient reading and writing MIDI files.
To better understand how the procedures work, it is useful to
recall the structure of a standard MIDI file.
STRUCTURE OF A STANDARD MIDI FILE
A standard MIDI file has the following structure:
<MIDI file header>
<MIDI track #1>
...
<MIDI track #n>
MIDI file header contains the information about the MIDI file type,
the number of MIDI tracks in it and the number of MIDI ticks per
quarternote it uses. (See below for more details.)
MIDI tracks, in turn, have the structure
<MIDI track header>
<Delta time #1>
<MIDI event #1>
...
<Delta time #k>
<MIDI Event #k>
<End of MIDI track>
Delta time -
shows time from the previous MIDI event and is expressed
in MIDI ticks. MIDI ticks are not milliseconds or metronome
clicks, they are just some integers. To convert them into
physical time, one needs to know two values:
- Number of MIDI ticks per quarternote
(contained in the MIDI file header).
- Tempo expressed in microseconds per quarternote.
(provided by the Set Tempo meta events; otherwise,
by default, tempo is assumed to be 125000.)
MIDI events -
fall into three categories:
- Channel events
- SysEx events
- Meta events
Channel events: They are "directly playable", i.e. they can be
sent to or received from a MIDI device and result
in sound being produced or changed.
Channel events have the following structure:
<Status byte> - type of channel event
<Byte 1> - MIDI event data
[<Byte 2> - MIDI event data]
In three-byte-long events, all three bytes are present.
In two-byte-long events, the Byte 2 is missing.
SysEx events: They contain hardware-specific MIDI data that can
be sent to or received from a MIDI device and result
in changing its MIDI characteristics.
SysEx events have the following structure:
<Status byte> - normally, $F0 or $F7
<Data length> - length of the following data chunk
written in the so-called variable
length format (the field can contain
one or several bytes, depending on
how large is this value).
<SysEx data> - the SysEx data chunk
Meta events: They are not supposed to be sent to or received from
MIDI devices. Instead, they contain information about
the MIDI sequence, including the information how the
sequence must be processed.
Meta events have the following structure:
<Status byte> - always $FF
<Type byte> - type of meta event
<Data length> - length of the following data chunk
written in the variable length format.
<Meta data> - the meta event data chunk. Can contain
text and binary data.
If we are interested in recording and playing back midi
events, the most frequently used meta event for us will
be the Set Tempo event:
<Status byte> = $FF
<Type byte> = $51
<Data length> = 3
<Meta data> = b1
b2
b3
where Tempo = b3+256*(b2+256*b1)
Now, we can describe the procedures themselves
DESCRIPTION OF THE INTERFACE PROCEDURES
********************************************************************
ReadSMF(InputSMFName:ansistring)
Reads the contents of a midi file to its raw image
in memory.
********************************************************************
ReadSMFHeader(var SMFType: byte; var Tracks: words; var Ticks: word)
Reads MIDI file header and assigns values to the
following three variables:
SMFType - MIDI File type. (Types 0 and 1 are supported.)
Tracks - Number of MIDI tracks in the file.
Ticks - Number of MIDI ticks per quarternote.
********************************************************************
WriteSMFHeader(SMFType: byte; Tracks,Ticks:word)
Writes these three values to the output MIDI
file header.
********************************************************************
ReadTrackHeader
Reads MIDI track header and remembers the track
length value stored in it.
********************************************************************
WriteTrackHeader
Writes a track header template and leaves space
for the track length value. WriteEndOfTrack will
write it later to the reserved space.
********************************************************************
ReadMIDIEvent(var Delta: cardinal; var Status: byte; var Byte1: byte;
var Byte2: byte; var Meta: byte; var MsgString: ansistring)
The central procedure, along with its opposite:
WriteMIDIEvent. Assigns values to the following
six variables:
Delta - Delta Time in MIDI ticks from the previous event.
Status - Status Byte of MIDI Event.
Byte1 - The second and the third bytes of a three-byte-long
Byte2 - channel MIDI event. For a two-byte-long channel event,
InByte2 = 0. For non-channel events (metaevents,
system exclusives), Byte1 = Byte2 = 0.
Meta - Meta event type byte. For other events, Meta = 0;
MsgString - SysEx or meta event data. For all other events,
MsgString='';
ReadMIDIEvent also verifies the read data. If something
is wrong, it shows an error message with the information
about the problem and aborts the reading.
**********************************************************************
WriteMIDIEvent(Delta: cardinal;Status,Byte1,Byte2,Meta: byte; MsgString: ansistring)
Writes delta time Delta followed by a MIDI event
specified by the above values. Depending on the Status
byte, only the relevant variables are processed. For
example, MsgString is ignored if Status byte corresponds
to a channel event. Alternatively, for meta events
(Status=$FF), then Byte1 and Byte2 are ignored.
***********************************************************************
VerifyEndOfTrack
Makes sure that the number of bytes left in the
MIDI track is not negative, shows an error message
otherwise.
***********************************************************************
TrackEmpty: boolean
True if no events are left in the processed MIDI track.
***********************************************************************
VerifyEndOfSMF
Makes sure that the input MIDI file length is equal
to the sum of the bytes read, shows an error message
otherwise.
***********************************************************************
WriteSMF(InputSMFName:ansistring)
Writes the built raw image of the output file to
the file with the specified name.
***********************************************************************
SAMPLE DELPHI PROJECTS
For your convenience, I am attaching two sample Delphi projects:
MIDI File Information Project : reads the MIDI file and shows information
about it.
MIDI File Transposition Project: transposes any MIDI file any number of
semitones up or down.
These projects, as well as the units MIDIRead and MIDIWrite, have both
Delphi4 and Delphi5 versions.
DEMO VERSION
The units MIDIRead and MIDIWrite are shareware. The demo version has
all the features of the full version, and only one limitation: it
cannot handle files more than 16K long.
PURCHASING FULL VERSION
You can purchase the full version for $24. Unless suggested otherwise
by the product distributor, send a check payable to
Alexei Gretchikha
to the following address:
Alexei Gretchikha,
369 Upson Hall,
Ithaca, NY 14853,
USA
with your e-mail address included. I will e-mail you the full version
units.