PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/tags/v1.11-final/arch/linux/hmpfile.c

https://github.com/simX/d2x-xl
C | 573 lines | 481 code | 57 blank | 35 comment | 127 complexity | 37cd6bd321eaa98759a0ebbba76936dd MD5 | raw file
Possible License(s): GPL-2.0
  1. /* This is HMP file playing code by Arne de Bruijn */
  2. #ifdef HAVE_CONFIG_H
  3. #include <conf.h>
  4. #endif
  5. #if defined (_WIN32) || USE_SDL_MIXER
  6. #include <stdio.h>
  7. #include <limits.h>
  8. #include <stdlib.h>
  9. #include "hmpfile.h"
  10. #include "cfile.h"
  11. #include "digi.h"
  12. #include "cfile.h"
  13. #include "u_mem.h"
  14. #include "error.h"
  15. #include "byteswap.h"
  16. #ifdef _WIN32
  17. extern void PumpMessages(void);
  18. #endif
  19. //------------------------------------------------------------------------------
  20. hmp_file *hmp_open(const char *filename, int bUseD1Hog)
  21. {
  22. int i;
  23. char buf [256];
  24. long data = 0;
  25. CFILE cf;
  26. hmp_file *hmp;
  27. int num_tracks, midi_div;
  28. unsigned char *p;
  29. if (!CFOpen(&cf, (char *)filename, gameFolders.szDataDir, "rb", bUseD1Hog))
  30. return NULL;
  31. hmp = D2_ALLOC(sizeof(hmp_file));
  32. if (!hmp) {
  33. CFClose(&cf);
  34. return NULL;
  35. }
  36. memset(hmp, 0, sizeof(*hmp));
  37. if ((CFRead (buf, 1, 8, &cf) != 8) || (memcmp(buf, "HMIMIDIP", 8)))
  38. goto err;
  39. if (CFSeek (&cf, 0x30, SEEK_SET))
  40. goto err;
  41. if (CFRead (&num_tracks, 4, 1, &cf) != 1)
  42. goto err;
  43. if (CFSeek (&cf, 0x38, SEEK_SET))
  44. goto err;
  45. if (CFRead (&midi_div, 4, 1, &cf) != 1)
  46. goto err;
  47. if ((num_tracks < 1) || (num_tracks > HMP_TRACKS))
  48. goto err;
  49. hmp->num_trks = num_tracks;
  50. hmp->midi_division = midi_div;
  51. hmp->tempo = 120;
  52. if (CFSeek(&cf, 0x308, SEEK_SET))
  53. goto err;
  54. for (i = 0; i < num_tracks; i++) {
  55. if ((CFSeek(&cf, 4, SEEK_CUR)) || (CFRead(&data, 4, 1, &cf) != 1))
  56. goto err;
  57. data -= 12;
  58. #if 0
  59. if (i == 0) /* track 0: reserve length for tempo */
  60. data += sizeof(hmp_tempo);
  61. #endif
  62. hmp->trks [i].len = data;
  63. if (!(p = hmp->trks [i].data = D2_ALLOC(data)))
  64. goto err;
  65. #if 0
  66. if (i == 0) { /* track 0: add tempo */
  67. memcpy(p, hmp_tempo, sizeof(hmp_tempo));
  68. p += sizeof(hmp_tempo);
  69. data -= sizeof(hmp_tempo);
  70. }
  71. #endif
  72. /* finally, read track data */
  73. if ((CFSeek(&cf, 4, SEEK_CUR)) || (CFRead(p, data, 1, &cf) != 1))
  74. goto err;
  75. }
  76. CFClose(&cf);
  77. return hmp;
  78. err:
  79. CFClose(&cf);
  80. hmp_close(hmp);
  81. return NULL;
  82. }
  83. //------------------------------------------------------------------------------
  84. void hmp_close(hmp_file *hmp)
  85. {
  86. int i;
  87. #ifdef _WIN32
  88. hmp_stop(hmp);
  89. #endif
  90. for (i = 0; i < hmp->num_trks; i++)
  91. if (hmp->trks [i].data)
  92. D2_FREE(hmp->trks [i].data);
  93. D2_FREE(hmp);
  94. }
  95. //------------------------------------------------------------------------------
  96. #ifdef _WIN32
  97. void hmp_stop(hmp_file *hmp)
  98. {
  99. MIDIHDR *mhdr;
  100. if (!hmp->stop) {
  101. hmp->stop = 1;
  102. //PumpMessages();
  103. midiStreamStop(hmp->hmidi);
  104. while (hmp->bufs_in_mm)
  105. {
  106. //PumpMessages();
  107. G3_SLEEP(0);
  108. }
  109. }
  110. while ((mhdr = hmp->evbuf)) {
  111. midiOutUnprepareHeader((HMIDIOUT)hmp->hmidi, mhdr, sizeof(MIDIHDR));
  112. hmp->evbuf = mhdr->lpNext;
  113. D2_FREE(mhdr);
  114. }
  115. if (hmp->hmidi) {
  116. midiStreamClose(hmp->hmidi);
  117. hmp->hmidi = NULL;
  118. }
  119. }
  120. //------------------------------------------------------------------------------
  121. /*
  122. * read a HMI nType variable length number
  123. */
  124. static int get_var_num_hmi(unsigned char *data, int datalen, unsigned long *value)
  125. {
  126. unsigned char *p;
  127. unsigned long v = 0;
  128. int shift = 0;
  129. p = data;
  130. while ((datalen > 0) && !(*p & 0x80)) {
  131. v += *(p++) << shift;
  132. shift += 7;
  133. datalen --;
  134. }
  135. if (!datalen)
  136. return 0;
  137. v += (*(p++) & 0x7f) << shift;
  138. if (value) *value = v;
  139. return (int) (p - data);
  140. }
  141. //------------------------------------------------------------------------------
  142. /*
  143. * read a MIDI nType variable length number
  144. */
  145. static int get_var_num(unsigned char *data, int datalen, unsigned long *value)
  146. {
  147. unsigned char *orgdata = data;
  148. unsigned long v = 0;
  149. while ((datalen > 0) && (*data & 0x80))
  150. v = (v << 7) + (*(data++) & 0x7f);
  151. if (!datalen)
  152. return 0;
  153. v = (v << 7) + *(data++);
  154. if (value) *value = v;
  155. return (int) (data - orgdata);
  156. }
  157. //------------------------------------------------------------------------------
  158. static int get_event(hmp_file *hmp, event *ev)
  159. {
  160. static int cmdlen [7] ={3,3,3,3,2,2,3};
  161. unsigned long got;
  162. unsigned long mindelta, delta;
  163. int i, ev_num;
  164. hmp_track *trk, *fndtrk;
  165. mindelta = INT_MAX;
  166. fndtrk = NULL;
  167. for (trk = hmp->trks, i = hmp->num_trks; (i--) > 0; trk++) {
  168. if (!trk->left)
  169. continue;
  170. if (!(got = get_var_num_hmi(trk->cur, trk->left, &delta)))
  171. return HMP_INVALID_FILE;
  172. if (trk->left > got + 2 && *(trk->cur + got) == 0xff
  173. && *(trk->cur + got + 1) == 0x2f) {/* end of track */
  174. trk->left = 0;
  175. continue;
  176. }
  177. delta += trk->curTime - hmp->curTime;
  178. if (delta < mindelta) {
  179. mindelta = delta;
  180. fndtrk = trk;
  181. }
  182. }
  183. if (!(trk = fndtrk))
  184. return HMP_EOF;
  185. got = get_var_num_hmi(trk->cur, trk->left, &delta);
  186. trk->curTime += delta;
  187. ev->delta = trk->curTime - hmp->curTime;
  188. hmp->curTime = trk->curTime;
  189. if ((trk->left -= got) < 3)
  190. return HMP_INVALID_FILE;
  191. trk->cur += got;
  192. /*memset(ev, 0, sizeof(*ev));*/ev->datalen = 0;
  193. ev->msg [0] = ev_num = *(trk->cur++);
  194. trk->left--;
  195. if (ev_num < 0x80)
  196. return HMP_INVALID_FILE; /* invalid command */
  197. if (ev_num < 0xf0) {
  198. ev->msg [1] = *(trk->cur++);
  199. trk->left--;
  200. if (cmdlen [((ev_num) >> 4) - 8] == 3) {
  201. ev->msg [2] = *(trk->cur++);
  202. trk->left--;
  203. }
  204. } else if (ev_num == 0xff) {
  205. ev->msg [1] = *(trk->cur++);
  206. trk->left--;
  207. if (!(got = get_var_num(ev->data = trk->cur,
  208. trk->left, (unsigned long *)&ev->datalen)))
  209. return HMP_INVALID_FILE;
  210. trk->cur += ev->datalen;
  211. if (trk->left <= ev->datalen)
  212. return HMP_INVALID_FILE;
  213. trk->left -= ev->datalen;
  214. } else /* sysex -> error */
  215. return HMP_INVALID_FILE;
  216. return 0;
  217. }
  218. //------------------------------------------------------------------------------
  219. static int fill_buffer(hmp_file *hmp)
  220. {
  221. MIDIHDR *mhdr = hmp->evbuf;
  222. unsigned int *p = (unsigned int *)(mhdr->lpData + mhdr->dwBytesRecorded);
  223. unsigned int *pend = (unsigned int *)(mhdr->lpData + mhdr->dwBufferLength);
  224. unsigned int i;
  225. event ev;
  226. while (p + 4 <= pend) {
  227. if (hmp->pending_size) {
  228. i = (int) (p - pend) * 4;
  229. if (i > hmp->pending_size)
  230. i = hmp->pending_size;
  231. *(p++) = hmp->pending_event | i;
  232. *(p++) = 0;
  233. memcpy((unsigned char *)p, hmp->pending, i);
  234. hmp->pending_size -= i;
  235. p += (i + 3) / 4;
  236. } else {
  237. if ((i = get_event(hmp, &ev))) {
  238. mhdr->dwBytesRecorded = (int) (((unsigned char *)p) - ((unsigned char *)mhdr->lpData));
  239. return i;
  240. }
  241. if (ev.datalen) {
  242. hmp->pending_size = ev.datalen;
  243. hmp->pending = ev.data;
  244. hmp->pending_event = ev.msg [0] << 24;
  245. } else {
  246. *(p++) = ev.delta;
  247. *(p++) = 0;
  248. *(p++) = (((DWORD)MEVT_SHORTMSG) << 24) |
  249. ((DWORD)ev.msg [0]) |
  250. (((DWORD)ev.msg [1]) << 8) |
  251. (((DWORD)ev.msg [2]) << 16);
  252. }
  253. }
  254. }
  255. mhdr->dwBytesRecorded = (int) (((unsigned char *)p) - ((unsigned char *)mhdr->lpData));
  256. return 0;
  257. }
  258. //------------------------------------------------------------------------------
  259. static int setup_buffers(hmp_file *hmp)
  260. {
  261. int i;
  262. MIDIHDR *buf, *lastbuf;
  263. lastbuf = NULL;
  264. for (i = 0; i < HMP_BUFFERS; i++) {
  265. if (!(buf = D2_ALLOC(HMP_BUFSIZE + sizeof(MIDIHDR))))
  266. return HMP_OUT_OF_MEM;
  267. memset(buf, 0, sizeof(MIDIHDR));
  268. buf->lpData = (unsigned char *)buf + sizeof(MIDIHDR);
  269. buf->dwBufferLength = HMP_BUFSIZE;
  270. buf->dwUser = (DWORD)(size_t)hmp;
  271. buf->lpNext = lastbuf;
  272. lastbuf = buf;
  273. }
  274. hmp->evbuf = lastbuf;
  275. return 0;
  276. }
  277. //------------------------------------------------------------------------------
  278. static void reset_tracks(struct hmp_file *hmp)
  279. {
  280. int i;
  281. for (i = 0; i < hmp->num_trks; i++) {
  282. hmp->trks [i].cur = hmp->trks [i].data;
  283. hmp->trks [i].left = hmp->trks [i].len;
  284. hmp->trks [i].curTime = 0;
  285. }
  286. hmp->curTime=0;
  287. }
  288. //------------------------------------------------------------------------------
  289. static void _stdcall midi_callback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
  290. {
  291. MIDIHDR *mhdr;
  292. hmp_file *hmp;
  293. int rc;
  294. if (uMsg != MOM_DONE)
  295. return;
  296. mhdr = ((MIDIHDR *)(size_t)dw1);
  297. mhdr->dwBytesRecorded = 0;
  298. hmp = (hmp_file *)(mhdr->dwUser);
  299. mhdr->lpNext = hmp->evbuf;
  300. hmp->evbuf = mhdr;
  301. hmp->bufs_in_mm--;
  302. if (!hmp->stop) {
  303. while (fill_buffer(hmp) == HMP_EOF)
  304. {
  305. if (!hmp->bLoop)
  306. {
  307. hmp->stop=1;
  308. }
  309. reset_tracks(hmp);
  310. }
  311. if ((rc = midiStreamOut(hmp->hmidi, hmp->evbuf,
  312. sizeof(MIDIHDR))) != MMSYSERR_NOERROR) {
  313. /* ??? */
  314. } else {
  315. hmp->evbuf = hmp->evbuf->lpNext;
  316. hmp->bufs_in_mm++;
  317. }
  318. }
  319. }
  320. //------------------------------------------------------------------------------
  321. static void setup_tempo(hmp_file *hmp, unsigned long tempo)
  322. {
  323. MIDIHDR *mhdr = hmp->evbuf;
  324. if (mhdr) {
  325. unsigned int *p = (unsigned int *)(mhdr->lpData + mhdr->dwBytesRecorded);
  326. *(p++) = 0;
  327. *(p++) = 0;
  328. *(p++) = (((DWORD)MEVT_TEMPO)<<24) | tempo;
  329. mhdr->dwBytesRecorded += 12;
  330. }
  331. }
  332. //------------------------------------------------------------------------------
  333. int hmp_play(hmp_file *hmp, int bLoop)
  334. {
  335. int rc;
  336. MIDIPROPTIMEDIV mptd;
  337. #if 1
  338. unsigned int numdevs;
  339. int i=0;
  340. numdevs=midiOutGetNumDevs();
  341. hmp->devid=-1;
  342. do
  343. {
  344. MIDIOUTCAPS devcaps;
  345. midiOutGetDevCaps(i,&devcaps,sizeof(MIDIOUTCAPS));
  346. if ((devcaps.wTechnology==MOD_FMSYNTH) || (devcaps.wTechnology==MOD_SYNTH))
  347. // if ((devcaps.dwSupport & (MIDICAPS_VOLUME | MIDICAPS_STREAM)) == (MIDICAPS_VOLUME | MIDICAPS_STREAM))
  348. hmp->devid=i;
  349. i++;
  350. } while ((i<(int)numdevs) && (hmp->devid==-1));
  351. if (hmp->devid == -1)
  352. #endif
  353. hmp->bLoop = bLoop;
  354. hmp->devid = MIDI_MAPPER;
  355. if ((rc = setup_buffers(hmp)))
  356. return rc;
  357. if ((midiStreamOpen(&hmp->hmidi, &hmp->devid,1, (DWORD) (size_t) midi_callback,
  358. 0, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) {
  359. hmp->hmidi = NULL;
  360. return HMP_MM_ERR;
  361. }
  362. mptd.cbStruct = sizeof(mptd);
  363. mptd.dwTimeDiv = hmp->tempo;
  364. if ((midiStreamProperty(hmp->hmidi,
  365. (LPBYTE)&mptd,
  366. MIDIPROP_SET|MIDIPROP_TIMEDIV)) != MMSYSERR_NOERROR) {
  367. /* FIXME: cleanup... */
  368. return HMP_MM_ERR;
  369. }
  370. reset_tracks(hmp);
  371. setup_tempo(hmp, 0x0f4240);
  372. hmp->stop = 0;
  373. while (hmp->evbuf) {
  374. if ((rc = fill_buffer(hmp))) {
  375. if (rc == HMP_EOF) {
  376. reset_tracks(hmp);
  377. continue;
  378. } else
  379. return rc;
  380. }
  381. #if 0
  382. { FILE *f = fopen("dump","wb"); fwrite(hmp->evbuf->lpData,
  383. hmp->evbuf->dwBytesRecorded,1,f); fclose(f); exit(1);}
  384. #endif
  385. if ((rc = midiOutPrepareHeader((HMIDIOUT)hmp->hmidi, hmp->evbuf,
  386. sizeof(MIDIHDR))) != MMSYSERR_NOERROR) {
  387. /* FIXME: cleanup... */
  388. return HMP_MM_ERR;
  389. }
  390. if ((rc = midiStreamOut(hmp->hmidi, hmp->evbuf,
  391. sizeof(MIDIHDR))) != MMSYSERR_NOERROR) {
  392. /* FIXME: cleanup... */
  393. return HMP_MM_ERR;
  394. }
  395. hmp->evbuf = hmp->evbuf->lpNext;
  396. hmp->bufs_in_mm++;
  397. }
  398. midiStreamRestart(hmp->hmidi);
  399. return 0;
  400. }
  401. #endif //_WIN32
  402. //------------------------------------------------------------------------------
  403. // ripped from the JJFFE project
  404. static int hmp_track_to_midi (ubyte* track, int size, FILE *f)
  405. {
  406. ubyte *pt = track;
  407. ubyte lc1 = 0,lastcom = 0;
  408. unsigned int t = 0, d;
  409. int n1, n2;
  410. int startOffs = ftell (f);
  411. while (track < pt + size) {
  412. if (track [0] &0x80) {
  413. ubyte b = track [0] & 0x7F;
  414. fwrite (&b, sizeof (b), 1, f);
  415. t+=b;
  416. }
  417. else {
  418. d = (track [0]) &0x7F;
  419. n1 = 0;
  420. while ((track [n1] &0x80) == 0) {
  421. n1++;
  422. d += (track [n1] &0x7F) << (n1 * 7);
  423. }
  424. t += d;
  425. n1 = 1;
  426. while((track [n1] & 0x80) == 0) {
  427. n1++;
  428. if (n1 == 4)
  429. return 0;
  430. }
  431. for(n2 = 0;n2 <= n1; n2++) {
  432. ubyte b = track [n1 - n2] & 0x7F;
  433. if (n2 != n1)
  434. b |= 0x80;
  435. fwrite (&b, sizeof (b), 1, f);
  436. }
  437. track += n1;
  438. }
  439. track++;
  440. if (*track == 0xFF) {//meta
  441. fwrite (track, 3 + track [2], 1, f);
  442. if (track [1] == 0x2F)
  443. break;
  444. }
  445. else {
  446. lc1=track [0] ;
  447. if ((lc1&0x80) == 0)
  448. return 0;
  449. switch (lc1 & 0xF0) {
  450. case 0x80:
  451. case 0x90:
  452. case 0xA0:
  453. case 0xB0:
  454. case 0xE0:
  455. if (lc1 != lastcom)
  456. fwrite (&lc1, sizeof (lc1), 1, f);
  457. fwrite (track + 1, 2, 1, f);
  458. track += 3;
  459. break;
  460. case 0xC0:
  461. case 0xD0:
  462. if (lc1 != lastcom)
  463. fwrite (&lc1, sizeof (lc1), 1, f);
  464. fwrite (track + 1, 1, 1, f);
  465. track += 2;
  466. break;
  467. default:
  468. return 0;
  469. }
  470. lastcom=lc1;
  471. }
  472. }
  473. return ftell (f) - startOffs;
  474. }
  475. //------------------------------------------------------------------------------
  476. ubyte midiSetTempo [19] = {'M','T','r','k',0,0,0,11,0,0xFF,0x51,0x03,0x18,0x80,0x00,0,0xFF,0x2F,0};
  477. int hmp_to_midi (hmp_file *hmp, char *pszFn)
  478. {
  479. FILE *f;
  480. int i, j, nLenPos;
  481. short s;
  482. if (!(f = fopen (pszFn, "wb")))
  483. return 0;
  484. // midi nSignature & header
  485. fwrite ("MThd", 4, 1, f);
  486. i = BE_INT (6);
  487. fwrite (&i, sizeof (i), 1, f);
  488. s = BE_SHORT (1);
  489. fwrite (&s, sizeof (s), 1, f); //format
  490. s = BE_SHORT (hmp->num_trks);
  491. fwrite (&s, sizeof (s), 1, f);
  492. i = 0xC0; //hmp->midi_division;
  493. s = BE_SHORT ((short) i);
  494. fwrite (&s, sizeof (s), 1, f); //tempo
  495. fwrite (midiSetTempo, sizeof (midiSetTempo), 1, f);
  496. for (j = 1; j < hmp->num_trks; j++) {
  497. // midi nSignature & track length & track data
  498. fwrite ("MTrk", 4, 1, f);
  499. nLenPos = ftell (f);
  500. i = 0;
  501. fwrite (&i, sizeof (i), 1, f);
  502. i = hmp_track_to_midi (hmp->trks [j].data, hmp->trks [j].len, f);
  503. i = BE_INT (i);
  504. fseek (f, nLenPos, SEEK_SET);
  505. fwrite (&i, sizeof (i), 1, f);
  506. fseek (f, 0, SEEK_END);
  507. }
  508. //return !fclose (f);
  509. if (!fclose (f))
  510. return 1;
  511. LogErr ("hmp_to_midi (%s) failed\n", pszFn);
  512. return 0;
  513. }
  514. #endif //defined (_WIN32) || USE_SDL_MIXER
  515. //------------------------------------------------------------------------------
  516. //eof