1 /* This is HMP file playing code by Arne de Bruijn */
12 #define cfclose fclose
17 extern void PumpMessages(void);
19 hmp_file *hmp_open(const char *filename) {
28 if (!(fp = cfopen((char *)filename, "rb")))
31 hmp = malloc(sizeof(hmp_file));
37 memset(hmp, 0, sizeof(*hmp));
39 if ((cfread(buf, 1, 8, fp) != 8) || (memcmp(buf, "HMIMIDIP", 8)))
42 if (cfseek(fp, 0x30, SEEK_SET))
45 if (cfread(&num_tracks, 4, 1, fp) != 1)
48 if ((num_tracks < 1) || (num_tracks > HMP_TRACKS))
51 hmp->num_trks = num_tracks;
54 if (cfseek(fp, 0x308, SEEK_SET))
57 for (i = 0; i < num_tracks; i++) {
58 if ((cfseek(fp, 4, SEEK_CUR)) || (cfread(&data, 4, 1, fp) != 1))
64 if (i == 0) /* track 0: reserve length for tempo */
65 data += sizeof(hmp_tempo);
68 hmp->trks[i].len = data;
70 if (!(p = hmp->trks[i].data = malloc(data)))
74 if (i == 0) { /* track 0: add tempo */
75 memcpy(p, hmp_tempo, sizeof(hmp_tempo));
76 p += sizeof(hmp_tempo);
77 data -= sizeof(hmp_tempo);
80 /* finally, read track data */
81 if ((cfseek(fp, 4, SEEK_CUR)) || (cfread(p, data, 1, fp) != 1))
93 void hmp_stop(hmp_file *hmp) {
98 midiStreamStop(hmp->hmidi);
99 while (hmp->bufs_in_mm)
105 while ((mhdr = hmp->evbuf)) {
106 midiOutUnprepareHeader((HMIDIOUT)hmp->hmidi, mhdr, sizeof(MIDIHDR));
107 hmp->evbuf = mhdr->lpNext;
112 midiStreamClose(hmp->hmidi);
117 void hmp_close(hmp_file *hmp) {
121 for (i = 0; i < hmp->num_trks; i++)
122 if (hmp->trks[i].data)
123 free(hmp->trks[i].data);
128 * read a HMI type variabele length number
130 static int get_var_num_hmi(unsigned char *data, int datalen, unsigned long *value) {
136 while ((datalen > 0) && !(*p & 0x80)) {
137 v += *(p++) << shift;
143 v += (*(p++) & 0x7f) << shift;
144 if (value) *value = v;
149 * read a MIDI type variabele length number
151 static int get_var_num(unsigned char *data, int datalen,
152 unsigned long *value) {
153 unsigned char *orgdata = data;
156 while ((datalen > 0) && (*data & 0x80))
157 v = (v << 7) + (*(data++) & 0x7f);
160 v = (v << 7) + *(data++);
161 if (value) *value = v;
162 return data - orgdata;
165 static int get_event(hmp_file *hmp, event *ev) {
166 static int cmdlen[7]={3,3,3,3,2,2,3};
168 unsigned long mindelta, delta;
170 hmp_track *trk, *fndtrk;
174 for (trk = hmp->trks, i = hmp->num_trks; (i--) > 0; trk++) {
177 if (!(got = get_var_num_hmi(trk->cur, trk->left, &delta)))
178 return HMP_INVALID_FILE;
179 if (trk->left > got + 2 && *(trk->cur + got) == 0xff
180 && *(trk->cur + got + 1) == 0x2f) {/* end of track */
184 delta += trk->cur_time - hmp->cur_time;
185 if (delta < mindelta) {
193 got = get_var_num_hmi(trk->cur, trk->left, &delta);
195 trk->cur_time += delta;
196 ev->delta = trk->cur_time - hmp->cur_time;
197 hmp->cur_time = trk->cur_time;
199 if ((trk->left -= got) < 3)
200 return HMP_INVALID_FILE;
202 /*memset(ev, 0, sizeof(*ev));*/ev->datalen = 0;
203 ev->msg[0] = ev_num = *(trk->cur++);
206 return HMP_INVALID_FILE; /* invalid command */
208 ev->msg[1] = *(trk->cur++);
210 if (cmdlen[((ev_num) >> 4) - 8] == 3) {
211 ev->msg[2] = *(trk->cur++);
214 } else if (ev_num == 0xff) {
215 ev->msg[1] = *(trk->cur++);
217 if (!(got = get_var_num(ev->data = trk->cur,
218 trk->left, (unsigned long *)&ev->datalen)))
219 return HMP_INVALID_FILE;
220 trk->cur += ev->datalen;
221 if (trk->left <= ev->datalen)
222 return HMP_INVALID_FILE;
223 trk->left -= ev->datalen;
224 } else /* sysex -> error */
225 return HMP_INVALID_FILE;
229 static int fill_buffer(hmp_file *hmp) {
230 MIDIHDR *mhdr = hmp->evbuf;
231 unsigned int *p = (unsigned int *)(mhdr->lpData + mhdr->dwBytesRecorded);
232 unsigned int *pend = (unsigned int *)(mhdr->lpData + mhdr->dwBufferLength);
236 while (p + 4 <= pend) {
237 if (hmp->pending_size) {
239 if (i > hmp->pending_size)
240 i = hmp->pending_size;
241 *(p++) = hmp->pending_event | i;
243 memcpy((unsigned char *)p, hmp->pending, i);
244 hmp->pending_size -= i;
247 if ((i = get_event(hmp, &ev))) {
248 mhdr->dwBytesRecorded = ((unsigned char *)p) - ((unsigned char *)mhdr->lpData);
252 hmp->pending_size = ev.datalen;
253 hmp->pending = ev.data;
254 hmp->pending_event = ev.msg[0] << 24;
258 *(p++) = (((DWORD)MEVT_SHORTMSG) << 24) |
260 (((DWORD)ev.msg[1]) << 8) |
261 (((DWORD)ev.msg[2]) << 16);
265 mhdr->dwBytesRecorded = ((unsigned char *)p) - ((unsigned char *)mhdr->lpData);
269 static int setup_buffers(hmp_file *hmp) {
271 MIDIHDR *buf, *lastbuf;
274 for (i = 0; i < HMP_BUFFERS; i++) {
275 if (!(buf = malloc(HMP_BUFSIZE + sizeof(MIDIHDR))))
276 return HMP_OUT_OF_MEM;
277 memset(buf, 0, sizeof(MIDIHDR));
278 buf->lpData = (unsigned char *)buf + sizeof(MIDIHDR);
279 buf->dwBufferLength = HMP_BUFSIZE;
280 buf->dwUser = (DWORD)hmp;
281 buf->lpNext = lastbuf;
284 hmp->evbuf = lastbuf;
288 static void reset_tracks(struct hmp_file *hmp) {
291 for (i = 0; i < hmp->num_trks; i++) {
292 hmp->trks[i].cur = hmp->trks[i].data;
293 hmp->trks[i].left = hmp->trks[i].len;
297 static void _stdcall midi_callback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) {
302 if (uMsg != MOM_DONE)
305 mhdr = ((MIDIHDR *)dw1);
306 mhdr->dwBytesRecorded = 0;
307 hmp = (hmp_file *)(mhdr->dwUser);
308 mhdr->lpNext = hmp->evbuf;
313 while (fill_buffer(hmp) == HMP_EOF)
315 if ((rc = midiStreamOut(hmp->hmidi, hmp->evbuf,
316 sizeof(MIDIHDR))) != MMSYSERR_NOERROR) {
319 hmp->evbuf = hmp->evbuf->lpNext;
326 static void setup_tempo(hmp_file *hmp, unsigned long tempo) {
327 MIDIHDR *mhdr = hmp->evbuf;
328 unsigned int *p = (unsigned int *)(mhdr->lpData + mhdr->dwBytesRecorded);
331 *(p++) = (((DWORD)MEVT_TEMPO)<<24) | tempo;
332 mhdr->dwBytesRecorded += 12;
335 int hmp_play(hmp_file *hmp) {
337 MIDIPROPTIMEDIV mptd;
339 unsigned int numdevs;
342 numdevs=midiOutGetNumDevs();
347 midiOutGetDevCaps(i,&devcaps,sizeof(MIDIOUTCAPS));
348 if ((devcaps.wTechnology==MOD_FMSYNTH) || (devcaps.wTechnology==MOD_SYNTH))
351 } while ((i<(int)numdevs) && (hmp->devid==-1));
353 hmp->devid = MIDI_MAPPER;
356 if ((rc = setup_buffers(hmp)))
358 if ((midiStreamOpen(&hmp->hmidi, &hmp->devid,1,(DWORD)midi_callback,
359 0, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) {
363 mptd.cbStruct = sizeof(mptd);
364 mptd.dwTimeDiv = hmp->tempo;
365 if ((midiStreamProperty(hmp->hmidi,
367 MIDIPROP_SET|MIDIPROP_TIMEDIV)) != MMSYSERR_NOERROR) {
368 /* FIXME: cleanup... */
373 setup_tempo(hmp, 0x0f4240);
377 if ((rc = fill_buffer(hmp))) {
385 { FILE *f = fopen("dump","wb"); fwrite(hmp->evbuf->lpData,
386 hmp->evbuf->dwBytesRecorded,1,f); fclose(f); exit(1);}
388 if ((rc = midiOutPrepareHeader((HMIDIOUT)hmp->hmidi, hmp->evbuf,
389 sizeof(MIDIHDR))) != MMSYSERR_NOERROR) {
390 /* FIXME: cleanup... */
393 if ((rc = midiStreamOut(hmp->hmidi, hmp->evbuf,
394 sizeof(MIDIHDR))) != MMSYSERR_NOERROR) {
395 /* FIXME: cleanup... */
398 hmp->evbuf = hmp->evbuf->lpNext;
401 midiStreamRestart(hmp->hmidi);