PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/v1.13.127/audio/linux/hmpfile.cpp

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