mmus2mid.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. /* Emacs style mode select -*- C++ -*-
  2. *-----------------------------------------------------------------------------
  3. *
  4. *
  5. * PrBoom: a Doom port merged with LxDoom and LSDLDoom
  6. * based on BOOM, a modified and improved DOOM engine
  7. * Copyright (C) 1999 by
  8. * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
  9. * Copyright (C) 1999-2000 by
  10. * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
  11. * Copyright 2005, 2006 by
  12. * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License
  16. * as published by the Free Software Foundation; either version 2
  17. * of the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  27. * 02111-1307, USA.
  28. *
  29. * DESCRIPTION:
  30. * This file supports conversion of MUS format music in memory
  31. * to MIDI format 1 music in memory.
  32. *
  33. * The primary routine, mmus2mid, converts a block of memory in MUS format
  34. * to an Allegro MIDI structure. This supports playing MUS lumps in a wad
  35. * file with BOOM.
  36. *
  37. * Another routine, Midi2MIDI, converts a block of memory in MIDI format 1 to
  38. * an Allegro MIDI structure. This supports playing MIDI lumps in a wad
  39. * file with BOOM.
  40. *
  41. * For testing purposes, and to make a utility if desired, if the symbol
  42. * STANDALONE is defined by uncommenting the definition below, a main
  43. * routine is compiled that will convert a possibly wildcarded set of MUS
  44. * files to a similarly named set of MIDI files.
  45. *
  46. * Much of the code here is thanks to S. Bacquet's source for QMUS2MID.C
  47. *
  48. *-----------------------------------------------------------------------------
  49. */
  50. #include <ctype.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54. #include <sys/types.h>
  55. #include <sys/stat.h>
  56. #include <stdlib.h>
  57. #ifdef MSDOS /* proff: I don't use allegro in windows */
  58. #include <allegro.h>
  59. #endif /* !MSDOS */
  60. #include "mmus2mid.h"
  61. #include "lprintf.h" // jff 08/03/98 - declaration of lprintf
  62. //#define STANDALONE /* uncomment this to make MMUS2MID.EXE */
  63. #ifndef STANDALONE
  64. #include "m_swap.h"
  65. #include "z_zone.h"
  66. #endif
  67. // some macros to decode mus event bit fields
  68. #define last(e) ((UBYTE)((e) & 0x80))
  69. #define event_type(e) ((UBYTE)(((e) & 0x7F) >> 4))
  70. #define channel(e) ((UBYTE)((e) & 0x0F))
  71. // event types
  72. typedef enum
  73. {
  74. RELEASE_NOTE,
  75. PLAY_NOTE,
  76. BEND_NOTE,
  77. SYS_EVENT,
  78. CNTL_CHANGE,
  79. UNKNOWN_EVENT1,
  80. SCORE_END,
  81. UNKNOWN_EVENT2,
  82. } mus_event_t;
  83. // MUS format header structure
  84. typedef struct
  85. {
  86. char ID[4]; // identifier "MUS"0x1A
  87. UWORD ScoreLength; // length of music portion
  88. UWORD ScoreStart; // offset of music portion
  89. UWORD channels; // count of primary channels
  90. UWORD SecChannels; // count of secondary channels
  91. UWORD InstrCnt; // number of instruments
  92. } PACKEDATTR MUSheader;
  93. // to keep track of information in a MIDI track
  94. typedef struct Track
  95. {
  96. char velocity;
  97. long deltaT;
  98. UBYTE lastEvt;
  99. long alloced;
  100. } TrackInfo;
  101. // array of info about tracks
  102. static TrackInfo track[MIDI_TRACKS];
  103. // initial track size allocation
  104. #define TRACKBUFFERSIZE 1024
  105. // lookup table MUS -> MID controls
  106. static UBYTE MUS2MIDcontrol[15] =
  107. {
  108. 0, // Program change - not a MIDI control change
  109. 0x00, // Bank select
  110. 0x01, // Modulation pot
  111. 0x07, // Volume
  112. 0x0A, // Pan pot
  113. 0x0B, // Expression pot
  114. 0x5B, // Reverb depth
  115. 0x5D, // Chorus depth
  116. 0x40, // Sustain pedal
  117. 0x43, // Soft pedal
  118. 0x78, // All sounds off
  119. 0x7B, // All notes off
  120. 0x7E, // Mono
  121. 0x7F, // Poly
  122. 0x79 // Reset all controllers
  123. };
  124. // some strings of bytes used in the midi format
  125. static UBYTE midikey[] =
  126. {0x00,0xff,0x59,0x02,0x00,0x00}; // C major
  127. static UBYTE miditempo[] =
  128. {0x00,0xff,0x51,0x03,0x09,0xa3,0x1a}; // uS/qnote
  129. static UBYTE midihdr[] =
  130. {'M','T','h','d',0,0,0,6,0,1,0,0,0,0}; // header (length 6, format 1)
  131. static UBYTE trackhdr[] =
  132. {'M','T','r','k'}; // track header
  133. // static routine prototypes
  134. static int TWriteByte(MIDI *mididata, int MIDItrack, UBYTE byte);
  135. static int TWriteVarLen(MIDI *mididata, int MIDItrack, register ULONG value);
  136. static ULONG ReadTime(const UBYTE **musptrp);
  137. static int FirstChannelAvailable(int MUS2MIDchannel[]);
  138. static UBYTE MidiEvent(MIDI *mididata,UBYTE midicode,UBYTE MIDIchannel,
  139. UBYTE MIDItrack,int nocomp);
  140. //
  141. // TWriteByte()
  142. //
  143. // write one byte to the selected MIDItrack, update current position
  144. // if track allocation exceeded, double it
  145. // if track not allocated, initially allocate TRACKBUFFERSIZE bytes
  146. //
  147. // Passed pointer to Allegro MIDI structure, number of the MIDI track being
  148. // written, and the byte to write.
  149. //
  150. // Returns 0 on success, MEMALLOC if a memory allocation error occurs
  151. //
  152. static int TWriteByte(MIDI *mididata, int MIDItrack, UBYTE byte)
  153. {
  154. ULONG pos ;
  155. pos = mididata->track[MIDItrack].len;
  156. if (pos >= (ULONG)track[MIDItrack].alloced)
  157. {
  158. track[MIDItrack].alloced = // double allocation
  159. track[MIDItrack].alloced? // or set initial TRACKBUFFERSIZE
  160. 2*track[MIDItrack].alloced :
  161. TRACKBUFFERSIZE;
  162. if (!(mididata->track[MIDItrack].data = // attempt to reallocate
  163. realloc(mididata->track[MIDItrack].data,
  164. track[MIDItrack].alloced)))
  165. return MEMALLOC;
  166. }
  167. mididata->track[MIDItrack].data[pos] = byte;
  168. mididata->track[MIDItrack].len++;
  169. return 0;
  170. }
  171. //
  172. // TWriteVarLen()
  173. //
  174. // write the ULONG value to tracknum-th track, in midi format, which is
  175. // big endian, 7 bits per byte, with all bytes but the last flagged by
  176. // bit 8 being set, allowing the length to vary.
  177. //
  178. // Passed the Allegro MIDI structure, the track number to write,
  179. // and the ULONG value to encode in midi format there
  180. //
  181. // Returns 0 if sucessful, MEMALLOC if a memory allocation error occurs
  182. //
  183. static int TWriteVarLen(MIDI *mididata, int tracknum, register ULONG value)
  184. {
  185. register ULONG buffer;
  186. buffer = value & 0x7f;
  187. while ((value >>= 7)) // terminates because value unsigned
  188. {
  189. buffer <<= 8; // note first value shifted in has bit 8 clear
  190. buffer |= 0x80; // all succeeding values do not
  191. buffer += (value & 0x7f);
  192. }
  193. while (1) // write bytes out in opposite order
  194. {
  195. if (TWriteByte(mididata, tracknum, (UBYTE)(buffer&0xff))) // insure buffer masked
  196. return MEMALLOC;
  197. if (buffer & 0x80)
  198. buffer >>= 8;
  199. else // terminate on the byte with bit 8 clear
  200. break;
  201. }
  202. return 0;
  203. }
  204. //
  205. // ReadTime()
  206. //
  207. // Read a time value from the MUS buffer, advancing the position in it
  208. //
  209. // A time value is a variable length sequence of 8 bit bytes, with all
  210. // but the last having bit 8 set.
  211. //
  212. // Passed a pointer to the pointer to the MUS buffer
  213. // Returns the integer unsigned long time value there and advances the pointer
  214. //
  215. static ULONG ReadTime(const UBYTE **musptrp)
  216. {
  217. register ULONG timeval = 0;
  218. int byte;
  219. do // shift each byte read up in the result until a byte with bit 8 clear
  220. {
  221. byte = *(*musptrp)++;
  222. timeval = (timeval << 7) + (byte & 0x7F);
  223. }
  224. while(byte & 0x80);
  225. return timeval;
  226. }
  227. //
  228. // FirstChannelAvailable()
  229. //
  230. // Return the next unassigned MIDI channel number
  231. //
  232. // The assignment for MUS channel 15 is not counted in the caculation, that
  233. // being percussion and always assigned to MIDI channel 9 (base 0).
  234. //
  235. // Passed the array of MIDI channels assigned to MUS channels
  236. // Returns the maximum channel number unassigned unless that is 9 in which
  237. // case 10 is returned.
  238. //
  239. // killough 10/7/98: changed char parameter, return values to int
  240. static int FirstChannelAvailable(int MUS2MIDchannel[])
  241. {
  242. int i ;
  243. int max = -1 ;
  244. // find the largest MIDI channel assigned so far
  245. for (i = 0; i < 15; i++)
  246. if (MUS2MIDchannel[i] > max)
  247. max = MUS2MIDchannel[i];
  248. return (max == 8 ? 10 : max+1); // skip MIDI channel 9 (percussion)
  249. }
  250. //
  251. // MidiEvent()
  252. //
  253. // Constructs a MIDI event code, and writes it to the current MIDI track
  254. // unless its the same as the last event code and compressio is enabled
  255. // in which case nothing is written.
  256. //
  257. // Passed the Allegro MIDI structure, the midi event code, the current
  258. // MIDI channel number, the current MIDI track number, and whether compression
  259. // (running status) is enabled.
  260. //
  261. // Returns the new event code if successful, 0 if a memory allocation error
  262. //
  263. static UBYTE MidiEvent(MIDI *mididata,UBYTE midicode,UBYTE MIDIchannel,
  264. UBYTE MIDItrack,int nocomp)
  265. {
  266. UBYTE newevent;
  267. newevent = midicode | MIDIchannel;
  268. if ((newevent != track[MIDItrack].lastEvt) || nocomp)
  269. {
  270. if (TWriteByte(mididata,MIDItrack, newevent))
  271. return 0; // indicates MEMALLOC error
  272. track[MIDItrack].lastEvt = newevent;
  273. }
  274. return newevent;
  275. }
  276. //
  277. // mmus2mid()
  278. //
  279. // Convert a memory buffer contain MUS data to an Allegro MIDI structure
  280. // with specified time division and compression.
  281. //
  282. // Passed a pointer to the buffer containing MUS data, a pointer to the
  283. // Allegro MIDI structure, the divisions, and a flag whether to compress.
  284. //
  285. // Returns 0 if successful, otherwise an error code (see mmus2mid.h).
  286. //
  287. int mmus2mid(const UBYTE *mus, MIDI *mididata, UWORD division, int nocomp)
  288. {
  289. UWORD TrackCnt = 0;
  290. UBYTE evt, MUSchannel, MIDIchannel, MIDItrack=0, NewEvent;
  291. int i, event, data;
  292. const UBYTE *musptr;
  293. size_t muslen;
  294. static MUSheader MUSh;
  295. UBYTE MIDIchan2track[MIDI_TRACKS]; // killough 10/7/98: fix too small array
  296. int MUS2MIDchannel[MIDI_TRACKS]; // killough 10/7/98: fix too small array
  297. // copy the MUS header from the MUS buffer to the MUSh header structure
  298. memcpy(&MUSh,mus,sizeof(MUSheader));
  299. MUSh.ScoreLength = doom_wtohs(MUSh.ScoreLength);
  300. MUSh.ScoreStart = doom_wtohs(MUSh.ScoreStart);
  301. MUSh.channels = doom_wtohs(MUSh.channels);
  302. MUSh.SecChannels = doom_wtohs(MUSh.SecChannels);
  303. MUSh.InstrCnt = doom_wtohs(MUSh.InstrCnt);
  304. // check some things and set length of MUS buffer from internal data
  305. if (!(muslen = MUSh.ScoreLength + MUSh.ScoreStart))
  306. return MUSDATAMT; // MUS file empty
  307. if (MUSh.channels > 15) // MUSchannels + drum channel > 16
  308. return TOOMCHAN ;
  309. musptr = mus+MUSh.ScoreStart; // init musptr to start of score
  310. for (i = 0; i < MIDI_TRACKS; i++) // init the track structure's tracks
  311. {
  312. MUS2MIDchannel[i] = -1; // flag for channel not used yet
  313. track[i].velocity = 64;
  314. track[i].deltaT = 0;
  315. track[i].lastEvt = 0;
  316. //free(mididata->track[i].data);//jff 3/5/98 remove old allocations
  317. mididata->track[i].data=NULL;
  318. track[i].alloced = 0;
  319. mididata->track[i].len = 0;
  320. }
  321. if (!division)
  322. division = 70;
  323. // allocate the first track which is a special tempo/key track
  324. // note multiple tracks means midi format 1
  325. // set the divisions (ticks per quarter note)
  326. mididata->divisions = division;
  327. // allocate for midi tempo/key track, allow for end of track
  328. if (!(mididata->track[0].data =
  329. realloc(mididata->track[0].data,sizeof(midikey)+sizeof(miditempo)+4)))
  330. return MEMALLOC;
  331. // key C major
  332. memcpy(mididata->track[0].data,midikey,sizeof(midikey));
  333. // tempo uS/qnote
  334. memcpy(mididata->track[0].data+sizeof(midikey),miditempo,sizeof(miditempo));
  335. mididata->track[0].len = sizeof(midikey)+sizeof(miditempo);
  336. TrackCnt++; // music tracks start at 1
  337. // process the MUS events in the MUS buffer
  338. do
  339. {
  340. // get a mus event, decode its type and channel fields
  341. event = *musptr++;
  342. if ((evt = event_type(event)) == SCORE_END) //jff 1/23/98 use symbol
  343. break; // if end of score event, leave
  344. MUSchannel = channel(event);
  345. // if this channel not initialized, do so
  346. if (MUS2MIDchannel[MUSchannel] == -1)
  347. {
  348. // set MIDIchannel and MIDItrack
  349. MIDIchannel = MUS2MIDchannel[MUSchannel] =
  350. (MUSchannel == 15 ? 9 : FirstChannelAvailable(MUS2MIDchannel));
  351. MIDItrack = MIDIchan2track[MIDIchannel] = (UBYTE)TrackCnt++;
  352. }
  353. else // channel already allocated as a track, use those values
  354. {
  355. MIDIchannel = MUS2MIDchannel[MUSchannel];
  356. MIDItrack = MIDIchan2track[MIDIchannel];
  357. }
  358. if (TWriteVarLen(mididata, MIDItrack, track[MIDItrack].deltaT))
  359. return MEMALLOC;
  360. track[MIDItrack].deltaT = 0;
  361. switch(evt)
  362. {
  363. case RELEASE_NOTE:
  364. // killough 10/7/98: Fix noise problems by not allowing compression
  365. if (!(NewEvent=MidiEvent(mididata,0x90,MIDIchannel,MIDItrack,1)))
  366. return MEMALLOC;
  367. data = *musptr++;
  368. if (TWriteByte(mididata, MIDItrack, (UBYTE)(data & 0x7F)))
  369. return MEMALLOC;
  370. if (TWriteByte(mididata, MIDItrack, 0))
  371. return MEMALLOC;
  372. break;
  373. case PLAY_NOTE:
  374. if (!(NewEvent=MidiEvent(mididata,0x90,MIDIchannel,MIDItrack,nocomp)))
  375. return MEMALLOC;
  376. data = *musptr++;
  377. if (TWriteByte(mididata, MIDItrack, (UBYTE)(data & 0x7F)))
  378. return MEMALLOC;
  379. if( data & 0x80 )
  380. track[MIDItrack].velocity = (*musptr++) & 0x7f;
  381. if (TWriteByte(mididata, MIDItrack, track[MIDItrack].velocity))
  382. return MEMALLOC;
  383. break;
  384. case BEND_NOTE:
  385. if (!(NewEvent=MidiEvent(mididata,0xE0,MIDIchannel,MIDItrack,nocomp)))
  386. return MEMALLOC;
  387. data = *musptr++;
  388. if (TWriteByte(mididata, MIDItrack, (UBYTE)((data & 1) << 6)))
  389. return MEMALLOC;
  390. if (TWriteByte(mididata, MIDItrack, (UBYTE)(data >> 1)))
  391. return MEMALLOC;
  392. break;
  393. case SYS_EVENT:
  394. if (!(NewEvent=MidiEvent(mididata,0xB0,MIDIchannel,MIDItrack,nocomp)))
  395. return MEMALLOC;
  396. data = *musptr++;
  397. if (data<10 || data>14)
  398. return BADSYSEVT;
  399. if (TWriteByte(mididata, MIDItrack, MUS2MIDcontrol[data]))
  400. return MEMALLOC;
  401. if (data == 12)
  402. {
  403. if (TWriteByte(mididata, MIDItrack, (UBYTE)(MUSh.channels+1)))
  404. return MEMALLOC;
  405. }
  406. else
  407. if (TWriteByte(mididata, MIDItrack, 0))
  408. return MEMALLOC;
  409. break;
  410. case CNTL_CHANGE:
  411. data = *musptr++;
  412. if (data>9)
  413. return BADCTLCHG;
  414. if (data)
  415. {
  416. if (!(NewEvent=MidiEvent(mididata,0xB0,MIDIchannel,MIDItrack,nocomp)))
  417. return MEMALLOC;
  418. if (TWriteByte(mididata, MIDItrack, MUS2MIDcontrol[data]))
  419. return MEMALLOC;
  420. }
  421. else
  422. {
  423. if (!(NewEvent=MidiEvent(mididata,0xC0,MIDIchannel,MIDItrack,nocomp)))
  424. return MEMALLOC;
  425. }
  426. data = *musptr++;
  427. if (TWriteByte(mididata, MIDItrack, (UBYTE)(data & 0x7F)))
  428. return MEMALLOC;
  429. break;
  430. case UNKNOWN_EVENT1: // mus events 5 and 7
  431. case UNKNOWN_EVENT2: // meaning not known
  432. return BADMUSCTL;
  433. case SCORE_END:
  434. break;
  435. default:
  436. return BADMUSCTL; // exit with error
  437. }
  438. if (last(event))
  439. {
  440. ULONG DeltaTime = ReadTime(&musptr); // killough 10/7/98: make local
  441. for (i = 0;i < MIDI_TRACKS; i++) //jff 3/13/98 update all tracks
  442. track[i].deltaT += DeltaTime; //whether allocated yet or not
  443. }
  444. }
  445. while ((evt != SCORE_END) && ((size_t)(musptr-mus) < muslen));
  446. if (evt!=SCORE_END)
  447. return MUSDATACOR;
  448. // Now add an end of track to each mididata track, correct allocation
  449. for (i = 0; i < MIDI_TRACKS; i++)
  450. if (mididata->track[i].len)
  451. { // killough 10/7/98: simplify code
  452. if (TWriteByte(mididata, i, 0x00) || // midi end of track code
  453. TWriteByte(mididata, i, 0xFF) ||
  454. TWriteByte(mididata, i, 0x2F) ||
  455. TWriteByte(mididata, i, 0x00))
  456. return MEMALLOC;
  457. // jff 1/23/98 fix failure to set data NULL, len 0 for unused tracks
  458. // shorten allocation to proper length (important for Allegro)
  459. if (!(mididata->track[i].data =
  460. realloc(mididata->track[i].data,mididata->track[i].len)))
  461. return MEMALLOC;
  462. }
  463. else
  464. {
  465. free(mididata->track[i].data);
  466. mididata->track[i].data = NULL;
  467. }
  468. return 0;
  469. }
  470. void free_mididata(MIDI *mid)
  471. {
  472. int i;
  473. for (i = 0; i < MIDI_TRACKS; i++)
  474. if (mid->track[i].data)
  475. free(mid->track[i].data);
  476. }
  477. //
  478. // ReadLength()
  479. //
  480. // Reads the length of a chunk in a midi buffer, advancing the pointer
  481. // 4 bytes, bigendian
  482. //
  483. // Passed a pointer to the pointer to a MIDI buffer
  484. // Returns the chunk length at the pointer position
  485. //
  486. static size_t ReadLength(UBYTE **mid)
  487. {
  488. UBYTE *midptr = *mid;
  489. size_t length = (*midptr++)<<24;
  490. length += (*midptr++)<<16;
  491. length += (*midptr++)<<8;
  492. length += *midptr++;
  493. *mid = midptr;
  494. return length;
  495. }
  496. //
  497. // MidiToMIDI()
  498. //
  499. // Convert an in-memory copy of a MIDI format 0 or 1 file to
  500. // an Allegro MIDI structure, that is valid or has been zeroed
  501. //
  502. // Passed a pointer to a memory buffer with MIDI format music in it and a
  503. // pointer to an Allegro MIDI structure.
  504. //
  505. // Returns 0 if successful, BADMIDHDR if the buffer is not MIDI format
  506. //
  507. int MidiToMIDI(UBYTE *mid,MIDI *mididata)
  508. {
  509. int i;
  510. int ntracks;
  511. // read the midi header
  512. if (memcmp(mid,midihdr,4))
  513. return BADMIDHDR;
  514. mididata->divisions = (mid[12]<<8)+mid[13];
  515. ntracks = (mid[10]<<8)+mid[11];
  516. if (ntracks>=MIDI_TRACKS)
  517. return BADMIDHDR;
  518. mid += 4;
  519. { // killough 10/7/98: fix mid from being modified twice before sequence pt.
  520. size_t t = ReadLength(&mid); // seek past header
  521. mid += t;
  522. }
  523. // now read each track
  524. for (i=0;i<ntracks;i++)
  525. {
  526. while (memcmp(mid,trackhdr,4)) // simply skip non-track data
  527. {
  528. mid += 4;
  529. {
  530. size_t t = ReadLength(&mid); // seek past header
  531. mid += t; // killough 10/7/98: prevent mid undefined behavior
  532. }
  533. }
  534. mid += 4;
  535. mididata->track[i].len = ReadLength(&mid); // get length, move mid past it
  536. // read a track
  537. mididata->track[i].data = realloc(mididata->track[i].data,mididata->track[i].len);
  538. memcpy(mididata->track[i].data,mid,mididata->track[i].len);
  539. mid += mididata->track[i].len;
  540. }
  541. for (;i<MIDI_TRACKS;i++)
  542. if (mididata->track[i].len)
  543. {
  544. free(mididata->track[i].data);
  545. mididata->track[i].data = NULL;
  546. mididata->track[i].len = 0;
  547. }
  548. return 0;
  549. }
  550. //#ifdef STANDALONE /* this code unused by BOOM provided for future portability */
  551. // /* it also provides a MUS to MID file converter*/
  552. // proff: I moved this down, because I need MIDItoMidi
  553. static void TWriteLength(UBYTE **midiptr,ULONG length);
  554. //
  555. // TWriteLength()
  556. //
  557. // Write the length of a MIDI chunk to a midi buffer. The length is four
  558. // bytes and is written byte-reversed for bigendian. The pointer to the
  559. // midi buffer is advanced.
  560. //
  561. // Passed a pointer to the pointer to a midi buffer, and the length to write
  562. // Returns nothing
  563. //
  564. static void TWriteLength(UBYTE **midiptr,ULONG length)
  565. {
  566. // proff: Added typecast to avoid warning
  567. *(*midiptr)++ = (unsigned char)((length>>24)&0xff);
  568. *(*midiptr)++ = (unsigned char)((length>>16)&0xff);
  569. *(*midiptr)++ = (unsigned char)((length>>8)&0xff);
  570. *(*midiptr)++ = (unsigned char)((length)&0xff);
  571. }
  572. //
  573. // MIDIToMidi()
  574. //
  575. // This routine converts an Allegro MIDI structure to a midi 1 format file
  576. // in memory. It is used to support memory MUS -> MIDI conversion
  577. //
  578. // Passed a pointer to an Allegro MIDI structure, a pointer to a pointer to
  579. // a buffer containing midi data, and a pointer to a length return.
  580. // Returns 0 if successful, MEMALLOC if a memory allocation error occurs
  581. //
  582. int MIDIToMidi(MIDI *mididata,UBYTE **mid,int *midlen)
  583. {
  584. size_t total;
  585. int i,ntrks;
  586. UBYTE *midiptr;
  587. // calculate how long the mid buffer must be, and allocate
  588. total = sizeof(midihdr);
  589. for (i=0,ntrks=0;i<MIDI_TRACKS;i++)
  590. if (mididata->track[i].len)
  591. {
  592. total += 8 + mididata->track[i].len; // Track hdr + track length
  593. ntrks++;
  594. }
  595. if ((*mid = malloc(total))==NULL)
  596. return MEMALLOC;
  597. // fill in number of tracks and bigendian divisions (ticks/qnote)
  598. midihdr[10] = 0;
  599. midihdr[11] = (UBYTE)ntrks; // set number of tracks in header
  600. midihdr[12] = (mididata->divisions>>8) & 0x7f;
  601. midihdr[13] = (mididata->divisions) & 0xff;
  602. // write the midi header
  603. midiptr = *mid;
  604. memcpy(midiptr,midihdr,sizeof(midihdr));
  605. midiptr += sizeof(midihdr);
  606. // write the tracks
  607. for (i=0;i<MIDI_TRACKS;i++)
  608. {
  609. if (mididata->track[i].len)
  610. {
  611. memcpy(midiptr,trackhdr,sizeof(trackhdr)); // header
  612. midiptr += sizeof(trackhdr);
  613. TWriteLength(&midiptr,mididata->track[i].len); // track length
  614. // data
  615. memcpy(midiptr,mididata->track[i].data,mididata->track[i].len);
  616. midiptr += mididata->track[i].len;
  617. }
  618. }
  619. // return length information
  620. *midlen = midiptr - *mid;
  621. return 0;
  622. }
  623. #ifdef STANDALONE /* this code unused by BOOM provided for future portability */
  624. /* it also provides a MUS to MID file converter*/
  625. // proff: I moved this down, because I need MIDItoMidi
  626. //
  627. // main()
  628. //
  629. // Main routine that will convert a globbed set of MUS files to the
  630. // correspondingly named MID files using mmus2mid(). Only compiled
  631. // if the STANDALONE symbol is defined.
  632. //
  633. // Passed the command line arguments, returns 0 if successful
  634. //
  635. int main(int argc,char **argv)
  636. {
  637. FILE *musst,*midst;
  638. char musfile[FILENAME_MAX],midfile[FILENAME_MAX];
  639. MUSheader MUSh;
  640. UBYTE *mus,*mid;
  641. static MIDI mididata;
  642. int err,midlen;
  643. char *p,*q;
  644. int i;
  645. if (argc<2)
  646. {
  647. //jff 8/3/98 use logical output routine
  648. lprintf(LO_INFO,"Usage: MMUS2MID musfile[.MUS]\n");
  649. lprintf(LO_INFO,"writes musfile.MID as output\n");
  650. lprintf(LO_INFO,"musfile may contain wildcards\n");
  651. exit(1);
  652. }
  653. for (i=1;i<argc;i++)
  654. {
  655. strcpy(musfile,argv[i]);
  656. p = strrchr(musfile,'.');
  657. q = strrchr(musfile,'\\');
  658. if (p && (!q || q<p)) *p='\0';
  659. strcpy(midfile,musfile);
  660. strcat(musfile,".MUS");
  661. strcat(midfile,".MID");
  662. musst = fopen(musfile,"rb");
  663. if (musst)
  664. {
  665. fread(&MUSh,sizeof(MUSheader),1,musst);
  666. mus = malloc(MUSh.ScoreLength+MUSh.ScoreStart);
  667. if (mus)
  668. {
  669. fseek(musst,0,SEEK_SET);
  670. if (!fread(mus,MUSh.ScoreLength+MUSh.ScoreStart,1,musst))
  671. {
  672. //jff 8/3/98 use logical output routine
  673. lprintf(LO_FATAL,"Error reading MUS file\n");
  674. free(mus);
  675. exit(1);
  676. }
  677. fclose(musst);
  678. }
  679. else
  680. {
  681. //jff 8/3/98 use logical output routine
  682. lprintf(LO_FATAL,"Out of memory\n");
  683. free(mus);
  684. exit(1);
  685. }
  686. err = mmus2mid(mus,&mididata,89,1);
  687. if (err)
  688. {
  689. //jff 8/3/98 use logical output routine
  690. lprintf(LO_FATAL,"Error converting MUS file to MIDI: %d\n",err);
  691. exit(1);
  692. }
  693. free(mus);
  694. MIDIToMidi(&mididata,&mid,&midlen);
  695. midst = fopen(midfile,"wb");
  696. if (midst)
  697. {
  698. if (!fwrite(mid,midlen,1,midst))
  699. {
  700. //jff 8/3/98 use logical output routine
  701. lprintf(LO_FATAL,"Error writing MIDI file\n");
  702. FreeTracks(&mididata);
  703. free(mid);
  704. exit(1);
  705. }
  706. fclose(midst);
  707. }
  708. else
  709. {
  710. //jff 8/3/98 use logical output routine
  711. lprintf(LO_FATAL,"Can't open MIDI file for output: %s\n", midfile);
  712. FreeTracks(&mididata);
  713. free(mid);
  714. exit(1);
  715. }
  716. }
  717. else
  718. {
  719. //jff 8/3/98 use logical output routine
  720. lprintf(LO_FATAL,"Can't open MUS file for input: %s\n", midfile);
  721. exit(1);
  722. }
  723. //jff 8/3/98 use logical output routine
  724. lprintf(LO_CONFIRM,"MUS file %s converted to MIDI file %s\n",musfile,midfile);
  725. FreeTracks(&mididata);
  726. free(mid);
  727. }
  728. exit(0);
  729. }
  730. #endif