home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mididll.zip / midifile.INF (.txt) < prev    next >
OS/2 Help File  |  1994-01-02  |  46KB  |  1,374 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. Preface ΓòÉΓòÉΓòÉ
  3.  
  4. MIDI files are a very popular format for storing "musical performances" and 
  5. other related data.  Most professional music programs that deal with such data 
  6. use this standardized format.  Although the description of this file format is 
  7. available from the MIDI Manufacturers Association, I believe that a more 
  8. explicit and "down to earth" explanation (as well as a nicely organized, online 
  9. OS/2 book) would be appreciated by programmers who want to adapt their software 
  10. to read and write MIDI files.  This manual describes the internals of the MIDI 
  11. file format. 
  12.  
  13. Furthermore, although there are some code examples of reading and writing MIDI 
  14. files, I perceived a need for an OS/2 Dynamic Link library that handles all of 
  15. the generic "bookkeeping" required to read and write MIDI files.  Since there 
  16. are certain things that all programs must do when reading or writing a MIDI 
  17. file (ie, open it, read in or write out headers with a ChunkSize, read and 
  18. write variable length quantities, etc), it makes sense to have the code to do 
  19. these things shared by all applications.  A Dynamic Link Library (ie, DLL) 
  20. makes this possible under OS/2.  DLL's can simplify application development too 
  21. since a programmer need not compile and link this generic MIDI file 
  22. reading/writing code for each program.  For this reason, I created such a DLL. 
  23. It was designed to be flexible enough to accomodate a variety of needs and 
  24. programming algorithms.  The second half of this manual describes the DLL, and 
  25. the accompanying C examples demonstrate how to use it in applications. 
  26.  
  27. It's common practice (although not mandated by the format itself) to name MIDI 
  28. files with a .mid extension.  But, since the MIDI file format is an explicitly 
  29. defined format, the surest way to tell that you're dealing with a MIDI file is 
  30. to look at the data inside of it for the mandatory chunk headers. 
  31.  
  32. Some of the words in this manual are highlighted in colored text, such as 
  33. Channel Pressure. These are words that refer to types of MIDI messages (ie, 
  34. streams of bytes that are defined by the MIDI spec itself).  Of course, MIDI 
  35. messages (ie, data bytes) are usually found inside of a MIDI file.  Other words 
  36. are in italics such as Format.  These refer to data bytes inside of a MIDI file 
  37. that aren't defined by the MIDI spec itself, but are nevertheless found inside 
  38. of a MIDI file because they are important to a sequencer program.  Underlined 
  39. words, such as GM Sound Module, refer to hardware.  Of course, audio hardware 
  40. is used to "play" the music data stored in a MIDI file, but the MIDI file 
  41. itself isn't tied to any particular piece of hardware.  (ie, Most of the data 
  42. in a MIDI file could be played on an analog synth with oscillators just as 
  43. easily as a sample-playing computer sound card, although there is a provision 
  44. to store data for specific units).  Words that are in colored text such as Read 
  45. This are meant to be emphasized, or are headings in this manual. 
  46.  
  47. This manual was written by Jeff Glatt. 
  48.  
  49.  
  50. ΓòÉΓòÉΓòÉ 2. The MIDI File Format ΓòÉΓòÉΓòÉ
  51.  
  52. The Standard MIDI File (SMF) is a file format specifically designed to store 
  53. the data that a sequencer creates (whether that sequencer be software or 
  54. hardware based). 
  55.  
  56. Note:  For an explanation of what a sequencer is, read my other article on 
  57.        such.  Essentially, a sequencer is a software program or hardware unit 
  58.        that "plays" a musical performance complete with appropriate rhythmic 
  59.        and melodic inflections (ie, plays music in the context of a musical beat).
  60.  
  61.  This format stores the standard MIDI events (ie, status bytes with appropriate 
  62. data bytes) plus a time-stamp for each event (ie, a series of bytes that 
  63. represent how many clock pulses to wait before "playing" the event).  The 
  64. format allows saving information about tempo, pulses per quarter note 
  65. resolution (or resolution expressed in divisions per second, ie SMPTE setting), 
  66. time and key signatures, and names of tracks and patterns.  It can store 
  67. multiple patterns and tracks so that any application can preserve these 
  68. structures when loading the file. 
  69.  
  70. Note:  A track usually is analogous to one musical part, such as a Trumpet 
  71.        part.  A pattern would be analogous to all of the musical parts (ie, 
  72.        Trumpet, Drums, Piano, etc) for a song, or excerpt of a song.
  73.  
  74.  The format was designed to be generic so that any sequencer could read or 
  75. write such a file without losing the most important data, and flexible enough 
  76. for a particular application to store its own proprietary, "extra" data in such 
  77. a way that another application won't be confused when loading the file and can 
  78. safely ignore this extra stuff that it doesn't need.  Think of the MIDI file 
  79. format as a musical version of an ASCII text file (except that the MIDI file 
  80. contains binary data too), and the various sequencer programs as text editors 
  81. all capable of reading that file.  But, unlike ASCII, MIDI file format saves 
  82. data in chunks (ie, groups of bytes preceded by an ID and size) which can be 
  83. parsed, loaded, skipped, etc.  Therefore, it can be easily extended to include 
  84. a program's proprietary info.  For example, maybe a program wants to save a 
  85. "flag byte" that indicates whether the user has turned on an audible metronome 
  86. click.  The program can put this flag byte into a MIDI file in such a way that 
  87. another application can skip this byte without having to understand what that 
  88. byte is for.  In the future, the MIDI file format can also be extended to 
  89. include new "official" chunks that all sequencer programs may elect to load and 
  90. use.  This can be done without making old data files obsolete (ie, the format 
  91. is designed to be extensible in a backwardly compatible way). 
  92.  
  93.  
  94. ΓòÉΓòÉΓòÉ 2.1. What's a Chunk? ΓòÉΓòÉΓòÉ
  95.  
  96. Data is always saved within a chunk.  There can be many chunks inside of a MIDI 
  97. file.  Each chunk can be a different size (ie, where size refers to how many 
  98. bytes are contained in the chunk).  The data bytes in a chunk are related in 
  99. some way.  A chunk is simply a group of related bytes. 
  100.  
  101. Each chunk begins with a 4 character (ie, 4 ascii bytes) ID which tells what 
  102. "type" of chunk this is.  The next 4 bytes (all bytes are comprised of 8 bits) 
  103. form a 32-bit length (ie, size) of the chunk.  All chunks must begin with these 
  104. two fields (ie, 8 bytes), which are referred to as the chunk header. 
  105.  
  106. Note:  The Length does not include the 8 byte chunk header.  It simply tells 
  107.        you how many bytes of data are in the chunk following this header.
  108.  
  109. Here's an example header (with bytes expressed in hex): 
  110.  
  111. 4D 74 68 64 00 00 00 06 
  112.  
  113. Note that the first 4 bytes make up the ascii ID of Mthd (ie, the first four 
  114. bytes are the ascii values for 'M', 't', 'h', and 'd').  The next 4 bytes tell 
  115. us that there should be 6 more data bytes in the chunk (and after that we 
  116. should find the next chunk header or the end of the file). 
  117.  
  118. In fact, all MIDI files begin with this Mthd header (and that's how you know 
  119. that it's a MIDI file). 
  120.  
  121. Note:  The 4 bytes that make up the Length are stored in Motorola 68000 byte 
  122.        order, not Intel reverse byte order (ie, the 06 is the fourth byte 
  123.        instead of the first of the four).  All multiple byte fields in a MIDI 
  124.        file follow this standard, often called "Big Endian" form.
  125.  
  126.  
  127. ΓòÉΓòÉΓòÉ 2.2. MThd Chunk ΓòÉΓòÉΓòÉ
  128.  
  129. The MThd header has an ID of MThd, and a Length of 6. 
  130.  
  131. Let's examine the 6 data bytes (which follow the above, 8 byte header) in an 
  132. MThd chunk. 
  133.  
  134. The first two data bytes tell the Format (which I prefer to call Type).  There 
  135. are actually 3 different types (ie, formats) of MIDI files.  A type of 0 means 
  136. that the file contains one single track containing midi data on possibly all 16 
  137. midi channels.  If your sequencer sorts/stores all of its midi data in one 
  138. single block of memory with the data in the order that it's "played", then it 
  139. should read/write this type.  A type of 1 means that the file contains one or 
  140. more simultaneous (ie, all start from an assumed time of 0) tracks, perhaps 
  141. each on a single midi channel.  Together, all of these tracks are considered 
  142. one sequence or pattern.  If your sequencer separates its midi data (i.e. 
  143. tracks) into different blocks of memory but plays them back simultaneously (ie, 
  144. as one "pattern"), it will read/write this type.  A type of 2 means that the 
  145. file contains one or more sequentially independant single-track patterns.  If 
  146. your sequencer separates its midi data into different blocks of memory, but 
  147. plays only one block at a time (ie, each block is considered a different 
  148. "excerpt" or "song"), then it will read/write this type. 
  149.  
  150. The next 2 bytes tell how many tracks are stored in the file, NumTracks.  Of 
  151. course, for format type 0, this is always 1.  For the other 2 types, there can 
  152. be numerous tracks. 
  153.  
  154. The last two bytes indicate how many pulses (i.e. clocks) per quarter note 
  155. resolution the time-stamps are based upon, Division.  For example, if your 
  156. sequencer has 96 ppqn, this field would be (in hex): 
  157.  
  158. 00 60 
  159.  
  160. Alternately, if the first byte of Division is negative, then this represents 
  161. the division of a second that the time-stamps are based upon.  The first byte 
  162. will be -24, -25, -29, or -30, corresponding to the 4 SMPTE standards 
  163. representing frames per second.  The second byte (a positive number) is the 
  164. resolution within a frame (ie, subframe).  Typical values may be 4 (MIDI Time 
  165. Code), 8, 10, 80 (SMPTE bit resolution), or 100. 
  166.  
  167. Note:  You can specify millisecond-based timing by the data bytes of -25 and 40 subframes.
  168.  
  169. Here's an example of a complete MThd chunk (with header): 
  170.  
  171. 4D 54 68 64   MThd ID 
  172. 00 00 00 06   Length of the MThd chunk is always 6. 
  173. 00 01       The Format type is 1. 
  174. 00 02       There are 2 MTrk chunks in this file. 
  175. E7 28       Each increment of delta-time represents a millisecond. 
  176.  
  177.  
  178. ΓòÉΓòÉΓòÉ 2.3. MTrk Chunk ΓòÉΓòÉΓòÉ
  179.  
  180. After the MThd chunk, you should find an MTrk chunk, as this is the only other 
  181. currently defined chunk.  (If you find some other chunk ID, it must be 
  182. proprietary to some other program, so skip it by ignoring the following data 
  183. bytes indicated by the chunk's Length.) 
  184.  
  185. An MTrk chunk contains all of the midi data (with timing bytes), plus optional 
  186. non-midi data for one track.  Obviously, you should encounter as many MTrk 
  187. chunks in the file as the MThd chunk's NumTracks field indicated. 
  188.  
  189. The MTrk header begins with the ID of MTrk, followed by the Length (ie, number 
  190. of data bytes to read for this track).  The Length will likely be different for 
  191. each track.  (After all, a track containing the violin part for a Bach concerto 
  192. will likely contain more data than a track containing a simple 2 bar drum 
  193. beat). 
  194.  
  195.  
  196. ΓòÉΓòÉΓòÉ 2.3.1. Variable Length Quantities -- Event's Time ΓòÉΓòÉΓòÉ
  197.  
  198. Think of a track in the MIDI file in the same way that you normally think of a 
  199. track in a sequencer.  A sequencer track contains a series of events.  For 
  200. example, the first event in the track may be to sound a middle C note.  The 
  201. second event may be to sound the E above middle C.  These two events may both 
  202. happen at the same time.  The third event may be to release the middle C note. 
  203. This event may happen a few musical beats after the first two events (ie, the 
  204. middle C note is held down for a few musical beats).  Each event has a "time" 
  205. when it must occur, and the events are arranged within a "chunk" of memory in 
  206. the order that they occur. 
  207.  
  208. In a MIDI file, an event's "time" precedes the data bytes that make up that 
  209. event itself.  In other words, the bytes that make up the event's time-stamp 
  210. come first.  A given event's time-stamp is referenced from the previous event. 
  211. For example, if the first event occurs 4 clocks after the start of play, then 
  212. its "delta-time" is 04.  If the next event occurs simultaneously with that 
  213. first event, its time is 00.  So, a delta-time is the duration (in clocks) 
  214. between an event and the preceding event. 
  215.  
  216. Note:  Since all tracks start with an assumed time of 0, the first event's 
  217.        delta-time is referenced from 0 
  218.  
  219.  A delta-time is stored as a series of bytes which is called a variable length 
  220. quantity.  Only the first 7 bits of each byte is significant (right-justified; 
  221. sort of like an ASCII byte).  So, if you have a 32-bit delta-time, you have to 
  222. unpack it into a series of 7-bit bytes (ie, as if you were going to transmit it 
  223. over midi in a SYSEX message).  Of course, you will have a variable number of 
  224. bytes depending upon your delta-time.  To indicate which is the last byte of 
  225. the series, you leave bit #7 clear.  In all of the preceding bytes, you set bit 
  226. #7.  So, if a delta-time is between 0-127, it can be represented as one byte. 
  227. The largest delta-time allowed is 0FFFFFFF, which translates to 4 bytes 
  228. variable length.  Here are examples of delta-times as 32-bit values, and the 
  229. variable length quantities that they translate to: 
  230.  
  231.  NUMBER     VARIABLE QUANTITY 
  232.  00000000        00 
  233.  00000040        40 
  234.  0000007F        7F 
  235.  00000080       81 00 
  236.  00002000       C0 00 
  237.  00003FFF       FF 7F 
  238.  00004000      81 80 00 
  239.  00100000      C0 80 00 
  240.  001FFFFF      FF FF 7F 
  241.  00200000      81 80 80 00 
  242.  08000000      C0 80 80 00 
  243.  0FFFFFFF      FF FF FF 7F 
  244.  
  245. Here's some C routines to read and write variable length quantities such as 
  246. delta-times.  With WriteVarLen(), you pass a 32-bit value (ie, unsigned long) 
  247. and it spits out the correct series of bytes to a file.  ReadVarLen() reads a 
  248. series of bytes from a file until it reaches the last byte of a variable length 
  249. quantity, and returns a 32-bit value. 
  250.  
  251.  void WriteVarLen(register unsigned long value) 
  252.  { 
  253.   register unsigned long buffer; 
  254.  
  255.   buffer = value & 0x7F; 
  256.   while ( (value >>= 7) ) 
  257.   { 
  258.     buffer <<= 8; 
  259.     buffer |= ((value & 0x7F) | 0x80); 
  260.   } 
  261.   while (TRUE) 
  262.   { 
  263.     putc(buffer,outfile); 
  264.     if (buffer & 0x80) 
  265.       buffer >>= 8; 
  266.     else 
  267.       break; 
  268.    } 
  269.  } 
  270.  
  271.  doubleword ReadVarLen() 
  272.  { 
  273.    register doubleword value; 
  274.    register byte c; 
  275.  
  276.    if ( (value = getc(infile)) & 0x80 ) 
  277.    { 
  278.      value &= 0x7F; 
  279.      do 
  280.      { 
  281.       value - (value << 7) + ((c = getc(infile)) & 0x7F); 
  282.      } while (c & 0x80); 
  283.    } 
  284.    return(value); 
  285.   } 
  286.  
  287. Note:  The concept of variable length quantities (ie, breaking up a large value 
  288.        into a series of bytes) is used with other fields in a MIDI file besides 
  289.        delta-times, as you'll see later.
  290.  
  291.  
  292. ΓòÉΓòÉΓòÉ 2.3.2. Events ΓòÉΓòÉΓòÉ
  293.  
  294. The first (1 to 4) byte(s) in an MTrk will be the first event's delta-time as a 
  295. variable length quantity.  The next data byte is actually the first byte of 
  296. that event itself.  I'll refer to this as the event's Status.  For MIDI events, 
  297. this will be the actual MIDI Status byte (or the first midi data byte if 
  298. running status).  For example, if the byte is hex 90, then this event is a 
  299. Note-On upon midi channel 0.  If for example, the byte was hex 23, you'd have 
  300. to recall the previous event's status (ie, midi running status).  Obviously, 
  301. the first MIDI event in the MTrk must have a status byte.  After a midi status 
  302. byte comes its 1 or 2 data bytes (depending upon the status - some MIDI 
  303. messages only have 1 subsequent data byte).  After that you'll find the next 
  304. event's delta time (as a variable quantity) and start the process of reading 
  305. that next event. 
  306.  
  307. SYSEX (system exclusive) events (status = F0) are a special case because a 
  308. SYSEX event can be any length.  After the F0 status (which is always stored -- 
  309. no running status here), you'll find yet another series of variable length 
  310. bytes.  Combine them with ReadVarLen() and you'll come up with a 32-bit value 
  311. that tells you how many more bytes follow which make up this SYSEX event.  This 
  312. length doesn't include the F0 status. 
  313.  
  314. For example, consider the following SYSEX MIDI message: 
  315.  
  316. F0 7F 7F 04 01 7F 7F F7 
  317.  
  318. This would be stored in a MIDI file as the following series of bytes (minus the 
  319. delta-time bytes which would precede it): 
  320.  
  321. F0 06 7F 04 01 7F 7F F7 
  322.  
  323. Some midi units send a system exclusive message as a series of small "packets" 
  324. (with a time delay inbetween transmission of each packet).  The first packet 
  325. begins with an F0, but it doesn't end with an F7.  The subsequent packets don't 
  326. start with an F0 nor end with F7.  The last packet doesn't start with an F0, 
  327. but does end with the F7.  So, between the first packet's opening F0 and the 
  328. last packet's closing F7, there's 1 SYSEX message there.  (Note: only extremely 
  329. poor designs, such as the crap marketed by Casio exhibit these aberrations). 
  330. Of course, since a delay is needed inbetween each packet, you need to store 
  331. each packet as a separate event with its own time in the MTrk.  Also, you need 
  332. some way of knowing which events shouldn't begin with an F0 (ie, all of them 
  333. except the first packet).  So, the MIDI file spec redefines a midi status of F7 
  334. (normally used as an end mark for SYSEX packets) as a way to indicate an event 
  335. that doesn't begin with F0.  If such an event follows an F0 event, then it's 
  336. assumed that the F7 event is the second "packet" of a series.  In this context, 
  337. it's referred to as a SYSEX CONTINUATION event.  Just like the F0 type of 
  338. event, it has a variable length followed by data bytes.  On the other hand, the 
  339. F7 event could be used to store MIDI REALTIME or MIDI COMMON messages.  In this 
  340. case, after the variable length bytes, you should expect to find a MIDI Status 
  341. byte of F1, F2, F3, F6, F8, FA, FB, FC, or FE.  (Note that you wouldn't find 
  342. any such bytes inside of a SYSEX CONTINUATION event).  When used in this 
  343. manner, the F7 event is referred to as an ESCAPED event. 
  344.  
  345. A status of FF is reserved to indicate a special non-MIDI event.  (Note that FF 
  346. is used in MIDI to mean "reset", so it wouldn't be all that useful to store in 
  347. a data file.  Therefore, the MIDI file spec arbitrarily redefines the use of 
  348. this status).  After the FF status byte is another byte that tells you what 
  349. Type of non-MIDI event it is.  It's sort of like a second status byte.  Then 
  350. after this byte is another byte(s -- a variable length quantity again) that 
  351. tells how many more data bytes follow in this event (ie, its Length).  This 
  352. Length doesn't include the FF, Type byte, nor the Length byte.  These special, 
  353. non-MIDI events are called Meta-Events, and most are optional unless otherwise 
  354. noted.  What follows are some defined Meta-Events (including the FF Status and 
  355. Length).  Note that unless otherwise mentioned, more than one of these events 
  356. can be placed in an Mtrk (even the same Meta-Event) at any delta-time.  (Just 
  357. like all midi events, Meta-Events have a delta-time from the previous event 
  358. regardless of what type of event that may be.  So, you can freely intermix MIDI 
  359. and Meta events). 
  360.  
  361.  
  362. ΓòÉΓòÉΓòÉ 2.3.2.1. Sequence Number ΓòÉΓòÉΓòÉ
  363.  
  364. FF 00 02 ss ss 
  365.  
  366.      This optional event which must occur at the beginning of a MTrk (ie, 
  367.      before any non-zero delta-times and before any midi events) specifies the 
  368.      number of a sequence.  The two data bytes ss ss, are that number which 
  369.      corresponds to the MIDI Cue message.  In a format 2 MIDI file, this number 
  370.      identifies each "pattern" (ie, Mtrk) so that a "song" sequence can use the 
  371.      MIDI Cue message to refer to patterns.  If the ss ss numbers are omitted 
  372.      (ie, Length byte = 0 instead of 2), then the MTrk's location in the file 
  373.      is used (ie, the first MTrk chunk is the first pattern).  In format 0 or 
  374.      1, which contain only one "pattern" (even though format 2 contains several 
  375.      MTrks), this event is placed in only the first MTrk.  So, a group of 
  376.      format 1 files with different sequence numbers can comprise a "song 
  377.      collection". 
  378.  
  379.      There can be only one of these events per MTrk chunk. 
  380.  
  381.  
  382. ΓòÉΓòÉΓòÉ 2.3.2.2. Text ΓòÉΓòÉΓòÉ
  383.  
  384. FF 01 len text 
  385.  
  386.      Any amount of text (amount of bytes = len) for any purpose.  It's best to 
  387.      put this event at the beginning of an MTrk.  Although this text could be 
  388.      used for any purpose, there are other text-based Meta-Events for such 
  389.      things as orchestration, lyrics, track name, etc.  This event is primarily 
  390.      used to add "comments" to a MIDI file which a program would be expected to 
  391.      ignore when loading that file. 
  392.  
  393.      Note that len could be a series of bytes since it is expressed as a 
  394.      variable length quantity. 
  395.  
  396.  
  397. ΓòÉΓòÉΓòÉ 2.3.2.3. Copyright ΓòÉΓòÉΓòÉ
  398.  
  399. FF 02 len text 
  400.  
  401.      A copyright message (ie, text).  It's best to put this event at the 
  402.      beginning of an MTrk. 
  403.  
  404.      Note that len could be a series of bytes since it is expressed as a 
  405.      variable length quantity. 
  406.  
  407.  
  408. ΓòÉΓòÉΓòÉ 2.3.2.4. Sequence/Track Name ΓòÉΓòÉΓòÉ
  409.  
  410. FF 03 len text 
  411.  
  412.      The name of the sequence or track (ie, text).  It's best to put this event 
  413.      at the beginning of an MTrk. 
  414.  
  415.      Note that len could be a series of bytes since it is expressed as a 
  416.      variable length quantity. 
  417.  
  418.  
  419. ΓòÉΓòÉΓòÉ 2.3.2.5. Instrument ΓòÉΓòÉΓòÉ
  420.  
  421. FF 04 len text 
  422.  
  423.      The name of the instrument that the track plays (ie, text).  This might be 
  424.      different than the Sequence/Track Name.  For example, maybe the name of 
  425.      your sequence (ie, Mtrk) is "Butterfly", but since the track is played on 
  426.      a piano, you might also include an Instrument Name of "Piano". 
  427.  
  428.      It's best to put one (or more) of this event at the beginning of an MTrk 
  429.      to provide the user with identification of what instrument(s) is playing 
  430.      the track.  Usually, the instruments (ie, patches, tones, banks, etc) are 
  431.      setup on the audio devices via MIDI Program Change events within the MTrk, 
  432.      particularly in MIDI files that are intended for General MIDI Sound 
  433.      Modules.  So, this event exists merely to provide the user with visual 
  434.      feedback of the instrumentation for a track. 
  435.  
  436.      Note that len could be a series of bytes since it is expressed as a 
  437.      variable length quantity. 
  438.  
  439.  
  440. ΓòÉΓòÉΓòÉ 2.3.2.6. Lyric ΓòÉΓòÉΓòÉ
  441.  
  442. FF 05 len text 
  443.  
  444.      A song lyric (ie, text) which occurs on a given beat. 
  445.  
  446.      Note that len could be a series of bytes since it is expressed as a 
  447.      variable length quantity. 
  448.  
  449.  
  450. ΓòÉΓòÉΓòÉ 2.3.2.7. Marker ΓòÉΓòÉΓòÉ
  451.  
  452. FF 06 len text 
  453.  
  454.      A marker (ie, text) which occurs on a given beat.  Marker events might be 
  455.      used to denote a loop start and loop end (ie, where the sequence loops 
  456.      back to a previous event). 
  457.  
  458.      Note that len could be a series of bytes since it is expressed as a 
  459.      variable length quantity. 
  460.  
  461.  
  462. ΓòÉΓòÉΓòÉ 2.3.2.8. Cue Point ΓòÉΓòÉΓòÉ
  463.  
  464. FF 07 len text 
  465.  
  466.      A cue point (ie, text) which occurs on a given beat.  A Cue Point might be 
  467.      used to denote where a WAVE (ie, sampled sound) file starts playing, where 
  468.      the text would be the WAVE's filename. 
  469.  
  470.      Note that len could be a series of bytes since it is expressed as a 
  471.      variable length quantity. 
  472.  
  473.  
  474. ΓòÉΓòÉΓòÉ 2.3.2.9. End of Track ΓòÉΓòÉΓòÉ
  475.  
  476. FF 2F 00 
  477.  
  478.      This event is NOT optional.  It must be the last event in every MTrk. 
  479.      It's used as a definitive marking of the end of an MTrk.  Only 1 per MTrk. 
  480.  
  481.  
  482. ΓòÉΓòÉΓòÉ 2.3.2.10. Tempo ΓòÉΓòÉΓòÉ
  483.  
  484. FF 51 03 tt tt tt 
  485.  
  486.      Indicates a tempo change.  The 3 data bytes of tt tt tt are the tempo in 
  487.      microseconds per MIDI quarter note.  Another way of expressing "microsecs 
  488.      per quarter note" is "24ths of a microsecs per MIDI clock" since there are 
  489.      24 midi clocks in each quarter note.  Representing tempos as time per beat 
  490.      instead of beat per time allows exact, long-term synch with time-based 
  491.      protocols like SMPTE.  To convert this value to beats per minute: 
  492.  
  493.      TempoBPM = 60,000,000/(tt tt tt) 
  494.  
  495.      For example, a tempo of 120 BPM = 07 A1 20. 
  496.  
  497.  
  498. ΓòÉΓòÉΓòÉ 2.3.2.11. SMPTE Offset ΓòÉΓòÉΓòÉ
  499.  
  500. FF 54 05 hr mn se fr ff 
  501.  
  502.      Designates the SMPTE start time (hours, minutes, secs, frames, subframes) 
  503.      of the Mtrk.  It should be at the start of the MTrk.  The hour should not 
  504.      be encoded with the SMPTE format as it is in MIDI Time Code.  In a format 
  505.      1 file, the SMPTE OFFSET must be stored with the tempo map (ie, the first 
  506.      MTrk), and has no meaning in any other MTrk.  The ff field contains 
  507.      fractional frames in 100ths of a frame, even in SMPTE based MTrks which 
  508.      specify a different frame subdivision for delta-times (ie, different from 
  509.      the subframe setting in the MThd). 
  510.  
  511.  
  512. ΓòÉΓòÉΓòÉ 2.3.2.12. Time Signature ΓòÉΓòÉΓòÉ
  513.  
  514. FF 58 04 nn dd cc bb 
  515.  
  516.      Time signature is expressed as 4 numbers.  nn and dd represent the 
  517.      "numerator" and "denominator" of the signature as notated on sheet music. 
  518.      The denominator is a negative power of 2: 2 = quarter note, 3 = eighth, 
  519.      etc.  The cc expresses the number of MIDI clocks in a metronome click. 
  520.      The bb parameter expresses the number of notated 32nd notes in a MIDI 
  521.      quarter note (24 MIDI clocks).  This event allows a program to relate what 
  522.      MIDI thinks of as a quarter, to something entirely different.  For 
  523.      example, 6/8 time with a metronome click every 3 eighth notes and 24 
  524.      clocks per quarter note would be the following event: 
  525.  
  526.      FF 58 04 06 03 24 08 
  527.  
  528.  
  529. ΓòÉΓòÉΓòÉ 2.3.2.13. Key Signature ΓòÉΓòÉΓòÉ
  530.  
  531. FF 59 02 sf mi 
  532.  
  533.      sf = -7 for 7 flats, -1 for 1 flat, etc, 0 for key of c, 1 for 1 sharp, 
  534.      etc. 
  535.  
  536.      mi = 0 for major, 1 for minor 
  537.  
  538.  
  539. ΓòÉΓòÉΓòÉ 2.3.2.14. Proprietary Event ΓòÉΓòÉΓòÉ
  540.  
  541. FF 7F len data... 
  542.  
  543.      This can be used by a program to store proprietary data.  The first 
  544.      byte(s) should be a unique ID of some sort so that a program can identity 
  545.      whether the event belongs to it, or to some other program.  A 4 character 
  546.      (ie, ascii) ID is recommended for such. 
  547.  
  548.      Note that len could be a series of bytes since it is expressed as a 
  549.      variable length quantity. 
  550.  
  551.  
  552. ΓòÉΓòÉΓòÉ 2.4. Errata ΓòÉΓòÉΓòÉ
  553.  
  554. In a format 0 file, the tempo and time signature changes are scattered 
  555. throughout the one MTrk.  In format 1, the very first MTrk should consist of 
  556. just the tempo and time signature events so that it could be read by some 
  557. device capable of generating a "tempo map".  In format 2, each MTrk should 
  558. begin with at least one initial tempo and time signature event. 
  559.  
  560. Note:  If there are no tempo and time signature events in a MIDI file, assume 
  561.        120 BPM and 4/4.
  562.  
  563.  
  564. ΓòÉΓòÉΓòÉ 3. MIDIFILE.DLL ΓòÉΓòÉΓòÉ
  565.  
  566. MIDIFILE.DLL is an OS/2 2.X Dynamic Link Library (DLL) that a programmer can 
  567. use to simplify writing OS/2 applications that read and write MIDI files. 
  568. MIDIFILE.DLL does most of the generic "bookkeeping" duties of parsing MIDI 
  569. files in a way that allows some flexibility as to how the application 
  570. implements the particulars of reading in data or writing out data. 
  571.  
  572. Many programs can be using that one copy of the DLL simultaneously, thus 
  573. reducing redundant code that eats up RAM needlessly.  Furthermore, the DLL 
  574. helps to eliminate discrepancies and incompatibilities in the way that two 
  575. programs read and write MIDI files if both programs use this DLL, since both 
  576. will be using the same reader/writer "manager". 
  577.  
  578. MIDIFILE.DLL is freely distributable with any OS/2 application, be it 
  579. commercial or otherwise.  There are no pagan distribution charges, manipulative 
  580. licensing fees, or other blatant forms of capitalistic trickery associated with 
  581. the use of MIDIFILE.DLL and its examples. 
  582.  
  583. My intent is to provide OS/2 programmers with a versatile development aid that 
  584. will hopefully enjoy widespread use, and thus make OS/2 MIDI development more 
  585. standardized.  As long as they don't impede development, standards are very 
  586. important.  Applications that work well together make each other more useful. 
  587. Typically, an end-user will use two such programs with the same data files, 
  588. utilizing the strengths of one product to compensate for the weaknesses of the 
  589. other product.  He ends up with a more powerful system.  That helps everyone 
  590. from the end-users to the folks who sell software.  It's a simple concept, but 
  591. you'd be surprised how many businessmen latch onto the self-destructive notion 
  592. that they must fight and thwart their "competitors".  Often, this makes things 
  593. worse for even the end-users. 
  594.  
  595. The only thing that you can't do with MIDIFILE.DLL is to prevent someone else 
  596. from distributing it and using it. 
  597.  
  598.  
  599. ΓòÉΓòÉΓòÉ 3.1. Archive ΓòÉΓòÉΓòÉ
  600.  
  601. The MIDIFILE archive consists of the DLL and several example applications with 
  602. source code.  The DLL itself is named MIDIFILE.DLL, and must be copied to one 
  603. of the directories specified by the LIBPATH statement in your config.sys file. 
  604. Usually, one of the specified directories is .;, which means that the DLL can 
  605. be placed in the same directory as the applications.  The applications will not 
  606. run if the DLL isn't placed somewhere in your LIBPATH.  These applications are 
  607. designed to be run from an OS/2 command line. 
  608.  
  609. The applications are as follows.  In the Syntax, note that arguments within [ ] 
  610. are optional. 
  611.  
  612.      MfRead      Reads a MIDI file and displays information about its contents. 
  613.                  It lists the chunks found in a MIDI file, and the contents of 
  614.                  MThd and MTrk chunks.  For MTrk chunks, it can list 
  615.                  information about every event in the track, or just a count of 
  616.                  how many events of each type are found (if the /i switch is 
  617.                  specified).  You can use this utility to discover what Format 
  618.                  a MIDI file is, how many tracks are contained therein, what 
  619.                  kind of events are within the MTrks, etc.  You can also use it 
  620.                  to check MIDI files that your own programs create to ensure 
  621.                  that these files comply with the MIDI file spec.  This is an 
  622.                  example of how to write a program that uses MIDIFILE.DLL to 
  623.                  read in a MIDI file. 
  624.  
  625.                  Syntax: MfRead.exe filename [/i] 
  626.  
  627.      MfWrite     Writes a dummy MIDI file in one of the 3 MIDI Formats.  This 
  628.                  example has no practical use.  It exists just to show you how 
  629.                  to write a program that uses MIDIFILE.DLL to save a MIDI file. 
  630.  
  631.                  Syntax: MfWrite.exe filename [0, 1, or 2 (for the Format)] 
  632.  
  633.      MfToVlq     Takes the values typed in as numeric args, and shows each one 
  634.                  as a variable length quantity (ie, a series of bytes).  For 
  635.                  example, if you type: 
  636.  
  637.                  MfToVlq 13 0x4000 
  638.  
  639.                  then MfToVlq will show you 13 expressed as a variable length 
  640.                  quantity, and then hex 4000 as a variable length quantity. 
  641.                  Note that you indicate a hex value by prefacing it with a 0x. 
  642.  
  643.                  Syntax: MfToVlq.exe Value1 [Value2...] 
  644.  
  645.      MfVlq       Takes a variable length quantity (ie, a series of bytes) typed 
  646.                  in as numeric args, and combines them into one value.  This is 
  647.                  the opposite of MfToVlq.  To express a byte as hex, preface it 
  648.                  with a 0x. 
  649.  
  650.                  Syntax: MfVlq.exe variable length quantity bytes... 
  651.  
  652.      Each application has a MAKE file to compile it into an executable.  These 
  653.      executables were made with IBM's C/Set2 compiler, Link386, and NMAKE.EXE 
  654.      (the latter 2 come with the ToolKit).  The .def and .dep files are used by 
  655.      these development tools.  The MIDIFILE.LIB file is a link library that 
  656.      gets linked with your C application.  You should tell the linker that it 
  657.      needs to link with this library.  Note that the make files specify it as a 
  658.      link library to Link386. 
  659.  
  660.      Also, your C source code must include a reference to the C include file 
  661.      found in this archive, like so: 
  662.  
  663.      #include <midifile.h> 
  664.  
  665.      Put the above line after the reference to the standard os2.h include file. 
  666.  
  667.      Note:  If you need to make a MIDI file for test purposes, use MfWrite.
  668.  
  669.  
  670. ΓòÉΓòÉΓòÉ 3.2. MidiReadFile() and MidiWriteFile() ΓòÉΓòÉΓòÉ
  671.  
  672. The DLL has 2 functions to read and write a complete MIDI file, MidiReadFile() 
  673. and MidiWriteFile() respectively.  These 2 functions initiate and carry out 
  674. their respective operations with one call.  When you return from one of these 
  675. functions, you will have either read or written a complete MIDI file.  For 
  676. example, calling MidiWriteFile() creates and writes out all of the data to a 
  677. MIDI file. 
  678.  
  679. Before you call either of these functions, you must allocate and initialize 
  680. certain fields of 2 special structures of my own design.  These structures are 
  681. described in midifile.h. 
  682.  
  683.  
  684. ΓòÉΓòÉΓòÉ 3.3. Callbacks ΓòÉΓòÉΓòÉ
  685.  
  686. Let's say that you have a secretary.  You ask her (or him) to prepare a letter 
  687. to a certain customer.  From this request, the secretary automatically knows to 
  688. get a sheet of paper, type the return address, and type the customer's address, 
  689. because all letters have these standard features.  But, beyond this, the 
  690. secretary needs to get more feedback from you as to what to put into the body 
  691. of the letter. 
  692.  
  693. So too, the DLL automatically does certain things that all applications will 
  694. need to do with MIDI files.  For example, all MIDI files must be opened before 
  695. data can be read or written to them.  So, it makes sense to have the DLL do 
  696. that.  But, the DLL doesn't know what to do with data that it reads in, nor 
  697. does it know what data to write out to a MIDI file.  So, the DLL periodically 
  698. needs to get feedback from your program while it's reading or writing a file. 
  699. It does this using 2 special data structures, and callbacks. 
  700.  
  701. What's a callback?  A callback is simply a function in your C program that the 
  702. DLL itself calls.  You will most likely have several callbacks, and each will 
  703. be called by the DLL at a certain point while the DLL is reading or writing a 
  704. file. 
  705.  
  706. For example, your program calls MidiReadFile() to read in a MIDI file.  The DLL 
  707. automatically opens the MIDI file, locates the MThd chunk within it, and loads 
  708. the information contained in it.  All applications that read a MIDI file would 
  709. want to do that.  But now, the DLL doesn't know what to do with that MThd 
  710. information.  After all, it's likely that different programs will have 
  711. different "needs" for that data, and some programs might want to store that 
  712. data in global variables within the program.  So, the DLL calls a function in 
  713. your program, passing the loaded MThd data.  Since the function is part of your 
  714. program, you can assess all of your global variables, and call other functions 
  715. within your program (or functions in a DLL or OS/2 system functions, etc) just 
  716. like any other function in your program.  Perhaps this callback might inspect 
  717. the passed MThd data, and set certain global variables as a result.  When the 
  718. callback returns, control is returned to the DLL, and the DLL carries on with 
  719. the next generic step of reading in a MIDI file.  For example, at this point, 
  720. it makes sense that any application would want to read in the header for the 
  721. next chunk to see what kind of chunk it is.  So, the DLL does that.  Let's say 
  722. that the DLL finds an MTrk header.  Once again, the DLL doesn't know what the 
  723. application wants to do with this MTrk, so the DLL calls another function in 
  724. your program that expects to be called when an MTrk chunk is encountered. 
  725.  
  726. This process of the DLL calling your callback functions continues until the DLL 
  727. has read in all of the data within the MIDI file, and then MidiReadFile() 
  728. finally returns to where you made that call in your program. 
  729.  
  730. As a further illustration, look at the following code. 
  731.  
  732.  
  733. ULONG value; 
  734.  
  735.  
  736. VOID parent() 
  737.   child(); 
  738.   return; 
  739.  
  740.  
  741. VOID child() 
  742.   baby1(); 
  743.   baby2(); 
  744.   return; 
  745.  
  746.  
  747. VOID baby1() 
  748.   value=1; 
  749.   return; 
  750.  
  751.  
  752. VOID baby2() 
  753.   return; 
  754.  
  755. parent() calls child() which then calls baby1() and baby2().  This is fairly 
  756. obvious.  The call to child() doesn't return until child() itself returns, and 
  757. that's after baby1() and baby2() get executed.  Now let's assume that you put 
  758. child() in another source code module.  Does that mean that parent() can't call 
  759. child(), or that child() can't call baby1() and baby2()?  No.  Is the logic 
  760. changed at all?  No.  child() is simply in a different module.  Now think of 
  761. child() as being MidiReadFile().  Just because it's in the DLL doesn't mean 
  762. that parent() can't call it.  Neither does that mean that MidiReadFile() can't 
  763. call baby1() and baby2(), which I refer to as callbacks. 
  764.  
  765. All of your callbacks must be declared to be of type EXPENTRY and returning a 
  766. LONG (which is an error code).  For example, our baby2() callback would be: 
  767.  
  768.  
  769. LONG EXPENTRY baby2(MIDIFILE * mf) 
  770.   return; 
  771.  
  772. Usually, the DLL passes a MIDIFILE structure to your callback (ie, the same one 
  773. that you pass to MidiReadFile or MidiWriteFile) which will contain pertinent 
  774. data. 
  775.  
  776. The concept of callbacks is really quite simple, but since you can't "see" the 
  777. code to MidiReadFile() calling your callbacks, it may be harder to visualize 
  778. the logic.  Just remember that one of your functions calls MidiReadFile() which 
  779. then calls a series of your callbacks until the MIDI file is read in, and then 
  780. MidiReadFile() finally returns to your function that called it. 
  781.  
  782.  
  783. ΓòÉΓòÉΓòÉ 3.4. CALLBACK and MIDIFILE structures ΓòÉΓòÉΓòÉ
  784.  
  785. So, how does the DLL know which of your program's callbacks to call?  Well, 
  786. that's what one of these special structures is for.  You place pointers to your 
  787. functions into the CALLBACK structure.  Each of the fields in the CALLBACK is 
  788. for a pointer to a function in your program.  There's a field where you place a 
  789. pointer to a function that the DLL should call after it has located and loaded 
  790. an MThd chunk.  There's a field where you place a pointer to a function that 
  791. the DLL should call when it encounters a Time Signature Meta-Event within an 
  792. MTrk.  Etc.  For some of the CALLBACK fields, you could set them to 0 instead 
  793. of supplying a pointer to a callback.  In this case, the DLL will instead 
  794. perform some default action when it gets to the point where it should call that 
  795. "missing" callback. 
  796.  
  797. The other structure is a MIDIFILE.  Mostly, the MIDIFILE is used to maintain 
  798. variables that are used during the reading and writing of MIDI files.  Also, 
  799. while reading a MIDI file, it is often used to contain loaded data from the 
  800. MIDI file, which is then passed to one of your callbacks.  While writing a MIDI 
  801. file, your callbacks often place data into the MIDIFILE structure and then upon 
  802. return, the DLL writes that data out to the MIDI file. 
  803.  
  804. The midifile.h has comments that describe the fields of the MIDIFILE and 
  805. CALLBACK structures. 
  806.  
  807.  
  808. ΓòÉΓòÉΓòÉ 3.5. Initialization ΓòÉΓòÉΓòÉ
  809.  
  810. Before calling MidiReadFile() or MidiWriteFile(), you must setup certain fields 
  811. of the CALLBACK and MIDIFILE structures. 
  812.  
  813. All of the CALLBACK fields must be set either to a pointer to some callback, or 
  814. 0 (if you want the DLL's default action for that callback).  I'll discuss when 
  815. each callback gets called, and what it should do, later in the discussion of 
  816. reading and writing MIDI files.  The CALLBACK fields only need to be 
  817. initialized once when you first create the CALLBACK.  If your CALLBACK is a 
  818. declared global in your program, you could initialize the fields within the 
  819. declaration.  Unless you wish to later change a CALLBACK field to point to a 
  820. different function, you don't need to ever reset the CALLBACK fields.  It 
  821. should be noted that you can change a CALLBACK field at any time, even within a 
  822. callback function. 
  823.  
  824. Note:  Unless you want your program to do the actual reading and writing of 
  825.        bytes to disk, perhaps in order to use buffered file I/O routines such 
  826.        as fread(), fwrite(), etc, you'll set the CALLBACK's OpenMidi, 
  827.        ReadWriteMidi, SeekMidi, and CloseMidi fields to 0.
  828.  
  829.      Not all of the MIDIFILE fields need to be initialized.  Many fields are 
  830.      setup and maintained by the DLL.  The fields that you must setup are 
  831.      Handle, Flags, and Callbacks. 
  832.  
  833.      Callbacks is simply a pointer to your CALLBACK structure.  (ie, You pass 
  834.      the MIDIFILE structure to MidiReadFile() or MidiWriteFile() and the DLL 
  835.      gets your CALLBACK from the MIDIFILE). 
  836.  
  837.      Flags is a USHORT.  There are 16 bits in this USHORT, each one being a 
  838.      flag that is either "on" (set) or "off" (clear).  These flags give you 
  839.      choices as to how the DLL processes data, or sometimes indicate the 
  840.      "state" of something.  See midifile.h for details.  Typically, you will 
  841.      simply clear these bits for default operation. 
  842.  
  843.      Finally, Handle is a pointer to the null-terminated MIDI filename that you 
  844.      want the DLL to open for reading or writing.  For example, you might 
  845.      initialize it as so: 
  846.  
  847.       struct MIDIFILE mfs; 
  848.       UCHAR name[] = "C\:MyFile.mid"; 
  849.  
  850.       mfs.Handle = (ULONG)&name[0]; 
  851.  
  852.      The ULONG cast is just to prevent a compiler warning message.  (After the 
  853.      DLL opens the file, it then uses the Handle field to store the file 
  854.      handle). 
  855.  
  856.  
  857. ΓòÉΓòÉΓòÉ 3.6. Fixed/Variable Length Events ΓòÉΓòÉΓòÉ
  858.  
  859. Within an MTrk chunk, I differentiate between fixed and variable length events. 
  860.  
  861. What's a fixed length event ?  That's simply an event that always has the same 
  862. number of bytes in it.  For example, a MIDI Note-On event always has 3 bytes; 
  863. the status, the note number (ie, pitch), and the velocity.  (The DLL resolves 
  864. running status, always providing you with a Status byte for each event).  A 
  865. MIDI Program Change event always has 2 bytes; the status, and the program 
  866. number.  A Tempo Meta-Event always has 6 bytes; 0xFF, 0x51, 0x03, and the 3 
  867. bytes that comprise the micros per quarter note.  The following are considered 
  868. to be fixed length events: 
  869.  
  870.       1. MIDI events with a Status less than 0xF0.  These include MIDI 
  871.          Note-Off, Note-On, Program Change, Aftertouch, Polyphonic Pressure, 
  872.          Controllers, and Pitch Wheel events on any of the 16 channels.  All of 
  873.          these have 3 bytes, except Program and Pressure which have 2. 
  874.  
  875.       2. MIDI REALTIME and SYSTEM COMMON events except for SYSTEM EXCLUSIVE. 
  876.          These include events with a Status of 0xF1 to 0xFE, except 0xF7. 
  877.          (0xFF is interpreted as a Meta-Event status). 
  878.  
  879.       3. The Meta-Events of Sequence Number, End Of Track, Tempo, SMPTE Offset, 
  880.          Time Signature, and Key Signature.  Each one has its own defined 
  881.          length. 
  882.  
  883.      What's a variable length event ?  That's simply an event that may have any 
  884.      number of bytes in it.  For example, a MIDI SYSTEM EXCLUSIVE event for a 
  885.      Roland RAP-10 audio card may be a different length than a SYSEX event for 
  886.      an EMU Proteus.  Furthermore, the following Meta-Events all can be various 
  887.      lengths depending upon the text stored in each: Text, Copyright, Track 
  888.      Name, Instrument Name, Lyric, Marker, and Cue Point. 
  889.  
  890.  
  891. ΓòÉΓòÉΓòÉ 3.7. Reading a file ΓòÉΓòÉΓòÉ
  892.  
  893. Let's discuss the procedure for reading a file.  First, you'll initialize the 
  894. CALLBACK and MIDIFILE structures as described in Initialization, and then call 
  895. MidiReadFile(), passing it your MIDIFILE structure.  The DLL will open the 
  896. file, locate the MThd chunk, and read that info into the MIDIFILE's Format, 
  897. NumTracks, and Division fields.  These fields directly correspond to the values 
  898. in an MThd, except that these fields are arranged in Intel reverse byte order. 
  899. (ie, Your C program can read the Format as a USHORT, and not have to flip the 
  900. two bytes).  The MIDIWRITE bit of Flags will be cleared by the DLL. 
  901.  
  902. Then, the DLL will call your StartMThd callback if supplied, passing a pointer 
  903. to your MIDIFILE structure.  Your callback might want to inspect the Format, 
  904. and perhaps adjust certain global variables (or CALLBACK pointers) depending 
  905. upon whether Format 0, 1, or 2.  Or, you might need to allocate as many 
  906. structures as are needed to hold NumTrack number of MTrks.  The Format, 
  907. NumTracks, and Division of the MIDIFILE remain in the structure all of the way 
  908. through MidiReadFile(), so you don't necessarily need to copy these values 
  909. anywhere else.  The MIDIFILE's FileSize always reflects how many more bytes 
  910. still need to be read from the file.  This is maintained by the DLL and should 
  911. not be altered.  Likewise, the ChunkSize field reflects how many more bytes 
  912. still need to be read from the current chunk.  (This will be 0 at this point 
  913. since the entire MThd was read in).  The TrackNum field always tells you what 
  914. MTrk number has last been read in.  (This will be 0xFF right now since no MTrk 
  915. chunks have yet been read).  This number is also maintained by the DLL (ie, it 
  916. is incremented each time that the DLL encounters an MTrk).  The DLL maintains 
  917. the Handle field, and this should not be altered.  Your callback should return 
  918. a 0 for success (to let the DLL continue reading the file).  Otherwise, your 
  919. DLL should return a non-zero number to abort the read.  This number will then 
  920. be returned from MidiReadFile(). 
  921.  
  922. Note:  All callbacks return 0 for success, or non-zero for an error.  All are 
  923.        passed one argument; your MIDIFILE (which is sometimes redeclared to be 
  924.        another structure similiar to the MIDIFILE, but it's really always a MIDIFILE).
  925.  
  926.      After your StartMThd callback successfully returns, the DLL reads in the 
  927.      next chunk.  If this is not an MTrk chunk, your UnknownChunk callback is 
  928.      called.  The ID of the chunk is in the MIDIFILE's ID.  Note that the 4 
  929.      bytes are stored as a ULONG for easy comparison to a CONSTANT, but the 
  930.      byte order is Big Endian (ie, Motorola).  You could use the DLL function 
  931.      MidiFlipLong() to switch it to Intel order.  ChunkSize indicates the 
  932.      number of data bytes contained in the chunk.  The DLL has not loaded these 
  933.      bytes.  If you want to load them, your callback must do that now.  You 
  934.      must use the DLL function MidiReadBytes() to load data from the MIDI file. 
  935.      If you don't supply an UnknownChunk, the DLL skips unknown chunks. 
  936.  
  937.      Note:  Never read bytes using some OS or C library function.  Always use 
  938.             MidiReadBytes(), which is used in much the same manner as you might 
  939.             use DosRead().
  940.  
  941.      Alternately, if you simply want the DLL to skip over this chunk's data, 
  942.      your callback need do nothing more than return.  The DLL will skip ahead 
  943.      to the next chunk.  You could even read some, but not all, bytes from the 
  944.      chunk, and then return to let the DLL skip the remaining bytes. 
  945.  
  946.      On the other hand, if the chunk is an MTrk, then the DLL begins the 
  947.      process of calling a series of your callbacks to read in the events within 
  948.      the chunk. 
  949.  
  950.      First, the DLL calls your StartMTrk callback, if supplied.  The DLL will 
  951.      have incremented the MIDIFILE's TrackNum.  (For the first MTrk, this will 
  952.      be 0).  You might use the StartMTrk callback to initialize global 
  953.      variables for reading in a track.  If you want the library to read in the 
  954.      entire MTrk chunk into a buffer, and then return this to you, your 
  955.      callback should allocate a buffer to contain ChunkSize bytes, and store 
  956.      the pointer in the MIDIFILE's Time field.  In this case, upon return, the 
  957.      DLL will load the chunk, and then call your StandardEvt callback (which 
  958.      you must supply in this case), which can then process the buffer as you 
  959.      see fit.  If you want the DLL to load one event at a time, your StartMTrk 
  960.      should return with the Time field left at 0 (ie, the DLL initially sets it 
  961.      to 0).  At this point, the DLL will load the first event, and then call 
  962.      one of your callbacks, depending upon what type of event it is (and if you 
  963.      have supplied a callback for that type of event). 
  964.  
  965.      The following discussion of the individual callbacks is for when the DLL 
  966.      loads one event at a time.  The basic idea is that the DLL loads one event 
  967.      (or for a variable length event, just its Status and Length), figures out 
  968.      what type of event it is, and calls your respective callback which is 
  969.      expected to store the data somewhere.  When your callback returns, the DLL 
  970.      loads the next event, etc, until all events in the MTrk have been loaded. 
  971.      If you don't supply a callback for that event type, the DLL skips that one 
  972.      event. 
  973.  
  974.      For all event types, the DLL always stores the event's time in the 
  975.      MIDIFILE's Time field.  In other words, the DLL converts the event's 
  976.      variable length quantity timestamp into 1 ULONG and stores it in the 
  977.      MIDIFILE's Time.  This time is referenced from 0, rather than the previous 
  978.      event like within the MIDI file, unless you set the MIDIDELTA Flag. 
  979.  
  980.      For MIDI events with status 0x80 to 0xEF, the DLL will load the event 
  981.      entirely into the MIDIFILE.  The MIDI Status byte will be placed into the 
  982.      MIDIFILE's Status field, and the 1 or 2 MIDI data bytes will be placed in 
  983.      MIDIFILE's Data1 and Data2.  (If the event is a PROGRAM CHANGE or 
  984.      POLYPHONIC PRESSURE, which have only 1 data byte, the second byte is set 
  985.      to 0xFF).  The DLL always provides a Status, resolving MIDI running status 
  986.      on your behalf.  Then, the DLL calls your StandardEvt callback, if 
  987.      supplied.  Typically, your callback will extract those fields, along with 
  988.      the Time, and store the bytes in some "track memory". 
  989.  
  990.      If the event is a SYSEX, SYSEX CONTINUATION, or ESCAPE, then the DLL calls 
  991.      your SysexEvt callback, if supplied.  Since these events can have an 
  992.      arbitrary number of data bytes, the DLL only loads the Status (ie, 0xF0 or 
  993.      0xF7) into the MIDIFILE's Status, and sets MIDIFILE's EventSize to the 
  994.      number of data bytes that need to be read in.  Your callback is expected 
  995.      to read in those data bytes using MidiReadBytes().  Typically, you'll 
  996.      load/store the data in some allocated memory.  Alternately, you can choose 
  997.      to have the DLL skip over those bytes by simply returning.  The DLL sets 
  998.      the MIDISYSEX Flag when it first encounters an F0 event, and clears this 
  999.      flag when it later encounters an event that would definitely indicate that 
  1000.      no more SYSEX CONTINUATION "packets" follow. 
  1001.  
  1002.      For a Sequence Number Meta-Event, the DLL redefines the MIDIFILE as a 
  1003.      METASEQ structure.  If you compare the 2 structures, you'll note that 
  1004.      they're both the same size, and have most of the same fields.  They really 
  1005.      are the same.  It's just that the MIDIFILE's Data fields have been 
  1006.      redefined specifically for a Sequence Number Meta-Event.  (Many of the 
  1007.      other type of Meta-Events also use some sort of redefinition of a 
  1008.      MIDIFILE).  The DLL loads the sequence number into the METASEQ's SeqNum 
  1009.      field.  The byte order is Intel form, so the field can be read as a 
  1010.      USHORT.  Then, the DLL calls your MetaSeqNum callback if supplied, passing 
  1011.      the METASEQ. 
  1012.  
  1013.      For a Tempo Meta-Event, the DLL redefines the MIDIFILE as a METATEMPO 
  1014.      structure.  The DLL loads the micros per second into Tempo using Intel 
  1015.      byte order so that it can be read as a ULONG.  The DLL also calculates the 
  1016.      tempo in beats per minute and stores that in the METATEMPO's TempoBPM. 
  1017.      Then, the DLL calls your MetaTempo callback if supplied. 
  1018.  
  1019.      For a SMPTE Offset Meta-Event, the DLL redefines the MIDIFILE as a 
  1020.      METASMPTE structure.  The DLL loads the hours, minutes, seconds, frames, 
  1021.      and subframes fields into the respective METASMPTE fields.  Then, the DLL 
  1022.      calls your MetaSmpte callback if supplied. 
  1023.  
  1024.      For a Time Signature Meta-Event, the DLL redefines the MIDIFILE as a 
  1025.      METATIME structure.  The DLL loads the nom, denom, etc, into the 
  1026.      respective METATIME fields.  The DLL will express the denom as the actual 
  1027.      denom of the time signature (instead of a power of 2) if you have set your 
  1028.      MIDIFILE's MIDIDENOM Flag.  Then, the DLL calls your MetaTimeSig callback 
  1029.      if supplied. 
  1030.  
  1031.      For a Key Signature Meta-Event, the DLL redefines the MIDIFILE as a 
  1032.      METAKEY structure.  The DLL loads the key and minor fields into the 
  1033.      METAKEY.  Then, the DLL calls your MetaKeySig callback if supplied. 
  1034.  
  1035.      For an End of Track Meta-Event, the DLL redefines the MIDIFILE as a 
  1036.      METAEND structure.  Then, the DLL calls your MetaEOT callback if supplied. 
  1037.      Note that this will always be the last event in an MTrk. 
  1038.  
  1039.      For Meta-Events of types 0x01 to 0x0F (ie, Text, Copyright, Instrument, 
  1040.      Track Name, Marker, Lyric, Cue Point), 0x7F (Proprietary), and any other 
  1041.      currently undefined Meta-Events, these can be of arbitrary length.  So, 
  1042.      the DLL loads the meta Type byte into the MIDIFILE's Status field, and 
  1043.      sets the MIDIFILE's EventSize to the number of data bytes that need to be 
  1044.      read in.  Then, the DLL calls your MetaText callback if supplied.  Your 
  1045.      callback is expected to read in those data bytes using MidiReadBytes(). 
  1046.      Typically, you'll load/store the data in some allocated memory. 
  1047.      Alternately, you can choose to have the DLL skip over those bytes by 
  1048.      simply returning. 
  1049.  
  1050.      If you didn't supply a callback for a particular event type (ie, you set 
  1051.      the respective CALLBACK field to 0), then the DLL will skip loading that 
  1052.      event.  For example, if you set the CALLBACK's MetaTempo field to 0, then 
  1053.      the DLL will skip over all Tempo Meta-Events. 
  1054.  
  1055.      The DLL continues reading in the next event (unless your callback returns 
  1056.      non-zero to abort), and calls your respective callback for that event, 
  1057.      until all events, including the End Of Track, are read in. 
  1058.  
  1059.      Then the DLL reads in the next chunk header, and the process repeats, 
  1060.      until the remainder of the file has been parsed, at which time 
  1061.      MidiReadFile() returns.  MidiReadFile() itself returns a 0 if there were 
  1062.      no errors reading the file. 
  1063.  
  1064.      Note:  The DLL resolves MIDI running status, always supplying a status 
  1065.             byte in the MIDIFILE's Status field for each event.  If you don't 
  1066.             want to store those extra Status bytes (ie, you want to implement 
  1067.             running status in your track memory), then you can compare the 
  1068.             MIDIFILE's RunStatus field with the Status field in your 
  1069.             StandardEvt callback.  If both are the same, then you've got an 
  1070.             event whose status was resolved (ie, it should be running status). 
  1071.             Note that Meta-Events have nothing to do with running status since 
  1072.             these aren't real MIDI events.  Furthermore SYSEX never have 
  1073.             running status.  So, don't check for running status in any Meta 
  1074.             callback or the SysexEvt callback.
  1075.  
  1076.  
  1077. ΓòÉΓòÉΓòÉ 3.8. Writing a file ΓòÉΓòÉΓòÉ
  1078.  
  1079. Let's discuss the procedure for writing (creating) a file.  First, you'll 
  1080. initialize the CALLBACK and MIDIFILE structures as described in Initialization, 
  1081. and then call MidiWriteFile(), passing it your MIDIFILE structure.  The DLL 
  1082. will open the file.  It also sets the MIDIWRITE Flag. 
  1083.  
  1084. Then, the DLL will call your StartMThd callback, passing a pointer to your 
  1085. MIDIFILE structure.  Your callback should initialize the MIDIFILE's Format, 
  1086. NumTracks, and Division fields.  These fields directly correspond to the values 
  1087. in an MThd, except that these fields are arranged in Intel reverse byte order. 
  1088. (ie, Your C program can write the Format as a USHORT, and not have to flip the 
  1089. two bytes to Big Endian).  Upon return, the DLL will write out the MThd chunk. 
  1090. Alternately, you could initialize these MIDIFILE fields before calling 
  1091. MidiWriteFile(), in which case you don't need the StartMThd callback (ie, set 
  1092. that CALLBACK field to 0). 
  1093.  
  1094. Then, the DLL starts calling various callbacks to write out the MTrk chunks. 
  1095. It repeats the following process for as many times as your MIDIFILE's 
  1096. NumTracks.  Your callbacks should return a 0 for success (to let the DLL 
  1097. continue writing the file).  Otherwise, your DLL should return a non-zero 
  1098. number to abort the write.  This number will then be returned from 
  1099. MidiWriteFile(). 
  1100.  
  1101. The DLL increments the TrackNum field for each MTrk to be written out.  (The 
  1102. first MTrk is 0).  It also writes out the MTrk header.  (The DLL takes care of 
  1103. setting the chunk's size properly).  The DLL maintains the FileSize field as 
  1104. the number of bytes written out to the file (including chunk headers).  This 
  1105. should not be altered.  The DLL also maintains the ChunkSize field, which 
  1106. should not be altered (and not used as a reflection of how many bytes have been 
  1107. written to a chunk).  The DLL maintains the Handle field, and this should not 
  1108. be altered. 
  1109.  
  1110. First, the DLL calls your StartMTrk callback, if supplied.  Typically, you 
  1111. might use this to set up some globals associated with the MTrk to be written. 
  1112. Optionally, you could write out some proprietary chunks before this MTrk, using 
  1113. MidiWriteHeader(), 1 or more calls to MidiWriteBytes(), and MidiCloseChunk(). 
  1114. If you want to supply a buffer that is already formatted with an entire MTrk's 
  1115. data (ie, minus the header), place a pointer to the buffer in the MIDIFILE's 
  1116. Time field.  Upon return, the DLL will write out that entire buffer, and then 
  1117. call your StandardEvt callback once, if supplied.  Alternately, if you want to 
  1118. write out the MTrk data one event at a time, then return with Time left at 0. 
  1119.  
  1120. The following discussion of the individual callbacks is for when the DLL writes 
  1121. one event at a time.  The basic idea is that the DLL calls your StandardEvt 
  1122. callback for each event to be written out.  Your callback stuffs the data for 
  1123. one event into the MIDIFILE (or for a variable length event, just its Status 
  1124. and Length), and returns to the DLL which writes out that event (perhaps 
  1125. calling another callback for a variable length event).  The DLL continues 
  1126. calling StandardEvt until you return an End Of Track event to write out.  Then, 
  1127. the process repeats for the next MTrk chunk. 
  1128.  
  1129. Before calling StandardEvt initially, the DLL calls your MetaSeqNum callback 
  1130. once, if supplied.  Typically, this is used to write out a Sequence Number 
  1131. Meta-Event (which must be first in the MTrk if desired), and any other events 
  1132. that need to written once at the start of the MTrk.  The DLL redefines the 
  1133. MIDIFILE as a METASEQ, passing that to your callback.  At the least, your 
  1134. callback should return the METASEQ with the SeqNum and NamePtr set as desired. 
  1135. SeqNum is in Intel format, and can be written as a USHORT.  If you also want 
  1136. the DLL to write out a Sequence Name event, place a pointer to the 
  1137. null-terminated name in the METASEQ's NamePtr field.  Otherwise, if you don't 
  1138. want a name event, set this to 0.  Upon return, the DLL writes out that 
  1139. event(s).  Optionally, your callback can write additional events before 
  1140. returning, using MidiWriteEvt(), but the callback must return at least one 
  1141. event in the METASEQ for the DLL to write out.  You need to set up the METASEQ 
  1142. (which is really a MIDIFILE and so can be recast as any of the structures in 
  1143. midifile.h) before calling MidiWriteEvt(), and the manner that you do so is the 
  1144. same as your StandardEvt callback described below. 
  1145.  
  1146. For all events that you wish to return to the DLL for writing out, StandardEvt 
  1147. must store the event's time in the MIDIFILE's Time field.  This time is 
  1148. referenced from 0, rather than the previous event like within the MIDI file, 
  1149. unless you set the MIDIDELTA Flag.  The DLL will write out the event's time as 
  1150. a variable length quantity timestamp to the MIDI file. 
  1151.  
  1152. For MIDI events with status 0x80 to 0xEF, 0xF1, 0xF2, 0xF3, 0xF6, 0xF8, 0xFA, 
  1153. 0xFB, 0xFC, or 0xFE, your callback stores the event entirely into the MIDIFILE. 
  1154. The MIDI Status byte must be placed into the MIDIFILE's Status field, and any 
  1155. MIDI data bytes must be placed in MIDIFILE's Data1 and Data2.  Upon return, the 
  1156. DLL writes out the entire event. 
  1157.  
  1158. If the event is a SYSEX or SYSEX CONTINUATION (0xF0 or 0xF7), then you must 
  1159. store that Status in the MIDIFILE's Status, and set the EventSize to the number 
  1160. of data bytes that will follow the Status.  Finally, set the ULONG starting at 
  1161. Data[2] to 0.  Upon return, the DLL writes out the Status and the size as a 
  1162. variable length quantity.  Then it calls your SysexEvt callback, which should 
  1163. write out the expected data bytes using MidiWriteBytes(). 
  1164.  
  1165. Note:  Never write bytes using some OS or C library function.  Always use 
  1166.        MidiWriteBytes(), which is used in much the same manner as you might use DosWrite().
  1167.  
  1168.      Alternately, StandardEvt could store the F0 or F7 Status, the EventSize, 
  1169.      and then set the ULONG at Data[2] to be a pointer to a buffer to write 
  1170.      out.  Upon return, the DLL will write out the event entirely, with the 
  1171.      data in the buffer.  Your SysexEvt callback will not be called (and need 
  1172.      not be supplied). 
  1173.  
  1174.      For a Tempo Meta-Event, your StandardEvt callback should redefine the 
  1175.      MIDIFILE as a METATEMPO, store an 0xFF in the Type field, store 0x51 in 
  1176.      the WriteType field, and store the micros per quarter in the Tempo field. 
  1177.      Tempo is a ULONG in Intel format (ie, the DLL writes out the proper Big 
  1178.      Endian bytes).  Alternately, if you've set the MIDIBPM Flag, you set the 
  1179.      TempoBPM field instead, and the DLL will calculate the Tempo field. 
  1180.  
  1181.      For a SMPTE Offset Meta-Event, your StandardEvt callback should redefine 
  1182.      the MIDIFILE as a METASMPTE, store an 0xFF in the Type field, store 0x54 
  1183.      in the WriteType field, and store the hours, minutes, seconds, frames, and 
  1184.      subframes fields. 
  1185.  
  1186.      For a Time Signature Meta-Event, your StandardEvt callback should redefine 
  1187.      the MIDIFILE as a METATIME, store an 0xFF in the Type field, store 0x58 in 
  1188.      the WriteType field, and store the nom, denom, etc, fields.  If you've set 
  1189.      the MIDIDENOM Flag, you store the denom field as the true time signature 
  1190.      denominator, and the DLL will convert it to a power of 2. 
  1191.  
  1192.      For a Key Signature Meta-Event, your StandardEvt callback should redefine 
  1193.      the MIDIFILE as a METAKEY, store an 0xFF in the Type field, store 0x59 in 
  1194.      the WriteType field, and store the key and minor fields. 
  1195.  
  1196.      For an End Of Track Meta-Event, your StandardEvt callback should redefine 
  1197.      the MIDIFILE as a METAEND, store an 0xFF in the Type field, and store 0x2F 
  1198.      in the WriteType field.  Note that this will be the last event in the 
  1199.      MTrk.  Returning this event to the DLL for writing signals that the MTrk 
  1200.      chunk is finished. 
  1201.  
  1202.      For a Sequence Number Meta-Event, your StandardEvt callback should 
  1203.      redefine the MIDIFILE as a METASEQ, store an 0xFF in the Type field, store 
  1204.      0x00 in the WriteType field, and store the SeqNum field.  Set the NamePtr 
  1205.      field to 0 if you don't want a Sequence Name event also written out. 
  1206.      Otherwise, set this to point to a null-terminated name. 
  1207.  
  1208.      For Meta-Events of types 0x01 to 0x0F (ie, Text, Copyright, Instrument, 
  1209.      Track Name, Marker, Lyric, Cue Point), 0x7F (Proprietary), and any other 
  1210.      currently undefined Meta-Events, set the MIDIFILE's Status to 0xFF, and 
  1211.      set Data[0] to the meta type.  If you want the DLL to write out the 
  1212.      subsequent data bytes, set the ULONG at Data[2] to point to a buffer 
  1213.      containing the data to write out, and set EventSize to the number of data 
  1214.      bytes to write.  If you set EventSize to 0, then the DLL assumes that the 
  1215.      buffer contains a null-terminated string, and calculates the length.  In 
  1216.      these cases, the DLL writes out the event entirely.  Alternately, if you 
  1217.      set the ULONG at Data[2] to 0, then you must set the EventSize to the 
  1218.      number of subsequent bytes that you intend to write out.  In this case, 
  1219.      the DLL calls your MetaText callback which will write out those bytes 
  1220.      using MidiWriteBytes(). 
  1221.  
  1222.      The DLL continues calling StandardEvt (and perhaps SysexEvt or MetaText) 
  1223.      to write out each event (unless your callback returns non-zero to abort), 
  1224.      until an End Of Track event is written. 
  1225.  
  1226.      Then the DLL starts the process again with the next MTrk chunk, until all 
  1227.      MTrks have been written (ie, NumTracks). 
  1228.  
  1229.      Lastly, the DLL calls your UnknownChunk callback, if supplied.  This 
  1230.      callback could write out some proprietary chunks at the end of the file, 
  1231.      using MidiWriteHeader(), 1 or more calls to MidiWriteBytes(), and 
  1232.      MidiCloseChunk(). 
  1233.  
  1234.      After this, MidiWriteFile() returns.  MidiWriteFile() itself returns a 0 
  1235.      if there were no errors writing the file. 
  1236.  
  1237.  
  1238. ΓòÉΓòÉΓòÉ 3.9. Errors ΓòÉΓòÉΓòÉ
  1239.  
  1240. Your callbacks return 0 for success, or non-zero for an error.  The error 
  1241. numbers that might be returned by the DLL itself are listed in midifile.h. 
  1242. Note that the DLL returns positive numbers for any errors.  You may wish to 
  1243. have your callbacks return negative numbers to help you differentiate between 
  1244. an error that happened within the DLL, and an error occuring within your 
  1245. callbacks.  The only limitation that is imposed is that, if you supply a 
  1246. MidiReadWrite callback, it can't return -1. 
  1247.  
  1248. The DLL has a routine, MidiGetErr(), which can return a null-terminated string 
  1249. that describes one of the error numbers defined in midifile.h (ie, for display 
  1250. to the end-user).  It copies the string to a buffer that you supply, and 
  1251. returns the string length.  If the error number that you pass is not one of the 
  1252. ones defined by the DLL, the buffer is nulled, and 0 returned.  In this case, 
  1253. the error was obviously one that a callback returned. 
  1254.  
  1255.  
  1256. ΓòÉΓòÉΓòÉ 3.10. Dual function callbacks ΓòÉΓòÉΓòÉ
  1257.  
  1258. Both MidiReadFile() and MidiWriteFile() require MIDIFILE and CALLBACK 
  1259. structures.  Both functions call some of the same callbacks.  For example, 
  1260. MidiWriteFile() calls your StandardEvt callback, expecting it to return info 
  1261. about the next event to write out.  MidiReadFile() also calls your StandardEvt 
  1262. callback, but it expects it to store the info that the DLL has loaded into the 
  1263. MIDIFILE.  If your application both reads and writes MIDI files, you could use 
  1264. the same MIDIFILE structure for calls to MidiReadFile() and MidiWriteFile(), 
  1265. but you would need 2 CALLBACK structures.  One would have pointers to callbacks 
  1266. that expect to be writing out a MIDI file.  Before calling MidiWriteFile(), you 
  1267. would place a pointer to this CALLBACK into the MIDIFILE's Callbacks.  The 
  1268. other CALLBACK would have pointers to callbacks that expect to be reading a 
  1269. MIDI file.  Before calling MidiReadFile(), you would place a pointer to this 
  1270. CALLBACK into the MIDIFILE's Callbacks. 
  1271.  
  1272. Alternately, you could use one CALLBACK and dual function callbacks.  These are 
  1273. simply callbacks that inspect the MIDIWRITE bit of MIDIFILE's Flags in order to 
  1274. decide whether a read or write operation needs to be performed.  Remember that 
  1275. the DLL always sets this for a write operation, and clears it for a read 
  1276. operation.  So, for example, your StandardEvt callback could inspect this Flag, 
  1277. and know whether it was being called via MidiReadFile() or MidiWriteFile().  In 
  1278. this case, you only need to initialize the MIDIFILE's Callbacks once at the 
  1279. start of the program. 
  1280.  
  1281. Not all callbacks would need to inspect this flag.  Although MidiReadFile() 
  1282. might call all of your supplied callbacks, MidiWriteFile() never calls the 
  1283. MetaTempo, MetaSmpte, MetaTimeSig, MetaKeySig, and MetaEOT callbacks.  These 
  1284. callbacks should always assume that they're doing a read operation. 
  1285. Furthermore, MidiWriteFile() may never call your SysexEvt and MetaText 
  1286. callbacks if your StandardEvt callback always supplies a pointer to a data 
  1287. buffer for SYSEX and variable length meta events. 
  1288.  
  1289.  
  1290. ΓòÉΓòÉΓòÉ 3.11. File I/O ΓòÉΓòÉΓòÉ
  1291.  
  1292. Usually, the DLL takes care of actually reading and writing bytes to a file. 
  1293. The DLL's reading and writing routines are not buffered (although the DLL has 
  1294. been designed to implement as efficient an unbuffered scheme as possible with 
  1295. MIDI files).  If you wish to instead use your own, buffered file I/O routines 
  1296. to read/write to the file (such as fread(), fwrite(), fseek(), etc), instead of 
  1297. letting the DLL do that, then you need to supply the callbacks for MidiOpen, 
  1298. MidiReadWrite, MidiSeek, and MidiClose. 
  1299.  
  1300. When initializing the MIDIFILE before calling MidiReadFile() or 
  1301. MidiWriteFile(), you don't need to place a pointer to the filename in the 
  1302. Handle.  Instead, when your MidiOpen callback is called, it should open the 
  1303. user's filename and store the fileHandle for later use.  (You'll probably use 
  1304. the MIDIFILE's Handle field for storage).  Remember that the MIDIWRITE Flag is 
  1305. set if the DLL is writing out a MIDI file, and clear if the DLL is loading a 
  1306. file.  So, your callback can determine whether it needs to open a file for 
  1307. reading or writing.  For loading, you should also set the MIDIFILE's FileSize 
  1308. to the number of bytes that the DLL has to parse (ie, usually the size of the 
  1309. file itself).  For writing, you should set the FileSize to where the current 
  1310. file pointer is located (ie, 0 if you're at the beginning of the file).  If 
  1311. you're using the DLL to load a MIDI file that is buried inside of a larger file 
  1312. that you've already read some initial data from, you should set FileSize to the 
  1313. remaining bytes after the current file pointer position.  If you're writing out 
  1314. a MIDI file inside of a larger file that you've already written some initial 
  1315. data to, you should set FileSize to the amount of bytes already written out. 
  1316.  
  1317. Note:  It's possible to open the file, and setup the MIDIFILE's FileSize field 
  1318.        before calling MidiReadFile() or MidiWriteFile(), but you still need a 
  1319.        MidiOpen callback, which should simply return 0.
  1320.  
  1321.      Your MidiReadWrite callback is passed a pointer to your MIDIFILE 
  1322.      structure, a pointer to a buffer, and a length argument.  The first thing 
  1323.      that your callback should do is examine the MIDIWRITE Flag bit to see if 
  1324.      you need to perform a read or write operation.  For a write operation, the 
  1325.      buffer pointer contains the data to be written out, and the length is the 
  1326.      number of bytes to write.  For a read operation, the length is the number 
  1327.      of bytes to read in, and the buffer is where to read those bytes. 
  1328.  
  1329.      Note:  None of your other callbacks should ever call your MidiReadWrite 
  1330.             callback directly.  Your callbacks should use either 
  1331.             MidiReadBytes() or MidiWriteBytes(), which indirectly call your 
  1332.             MidiReadWrite callback to do the actual reading/writing of bytes.
  1333.  
  1334.      Your MidiSeek callback should expect to do a seek.  It is passed a pointer 
  1335.      to the MIDIFILE, a signed long representing the amount of bytes to seek, 
  1336.      and the ulMoveType as described by OS/2's DosSetFilePtr().  (The DLL only 
  1337.      ever passes FILE_CURRENT as the movement type). 
  1338.  
  1339.      Note:  None of your other callbacks should ever call your MidiSeek 
  1340.             callback directly.  Your callbacks should use the DLL's MidiSeek(), 
  1341.             which indirectly calls your MidiSeek callback to do the actual seek 
  1342.             operation.  MidiSeek() only allows seeking from the current file 
  1343.             pointer position.
  1344.  
  1345.      Your MidiClose callback should expect to close the file that you opened. 
  1346.      Of course, you could chose to not close it at this time, and then after 
  1347.      returning from MidiWriteFile() or MidiReadFile(), do some more 
  1348.      reading/writing to the file.  But, it's recommended that you instead 
  1349.      read/write any final bytes in your UnknownChunk callback.  If your 
  1350.      MidiClose callback closes the file, then you can be assured that the file 
  1351.      will be properly closed, even if an error occurs and the read/write is 
  1352.      aborted. 
  1353.  
  1354.  
  1355. ΓòÉΓòÉΓòÉ 3.12. Limitations ΓòÉΓòÉΓòÉ
  1356.  
  1357. Since MidiReadFile() and MidiWriteFile() carry out the desired operation in 
  1358. entirety before returning, it's not possible to have one thread read in data 
  1359. from one MIDI file at the same time that it's writing out data to another MIDI 
  1360. file.  You'd have to read in one file entirely into memory, and then write it 
  1361. back out.  Alternately, you could have two threads; one to call MidiReadFile() 
  1362. and one to call MidiWriteFile(), and have the callbacks of one thread wait for 
  1363. semaphores or messages from the other thread's respective callbacks to 
  1364. synchronize reading/writing.  You'd need separate MIDIFILE structures.