mmus2mid.c 25 KB

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