1 /* This is HMP file playing code by Arne de Bruijn */
2 #include <stdio.h>
3 #include <limits.h>
4 #include <stdlib.h>
5 #include "hmpfile.h"
6 
7 #if 0
8 #define CFILE FILE
9 #define cfopen fopen
10 #define cfseek fseek
11 #define cfread fread
12 #define cfclose fclose
13 #else
14 #include "cfile.h"
15 #endif
16 
17 extern void PumpMessages(void);
18 
hmp_open(const char * filename)19 hmp_file *hmp_open(const char *filename) {
20 	int i;
21 	char buf[256];
22 	long data;
23 	CFILE *fp;
24 	hmp_file *hmp;
25 	int num_tracks;
26 	unsigned char *p;
27 
28 	if (!(fp = cfopen((char *)filename, "rb")))
29 		return NULL;
30 
31 	hmp = malloc(sizeof(hmp_file));
32 	if (!hmp) {
33 		cfclose(fp);
34 		return NULL;
35 	}
36 
37 	memset(hmp, 0, sizeof(*hmp));
38 
39 	if ((cfread(buf, 1, 8, fp) != 8) || (memcmp(buf, "HMIMIDIP", 8)))
40 		goto err;
41 
42 	if (cfseek(fp, 0x30, SEEK_SET))
43 		goto err;
44 
45 	if (cfread(&num_tracks, 4, 1, fp) != 1)
46 		goto err;
47 
48 	if ((num_tracks < 1) || (num_tracks > HMP_TRACKS))
49 		goto err;
50 
51 	hmp->num_trks = num_tracks;
52     hmp->tempo = 120;
53 
54 	if (cfseek(fp, 0x308, SEEK_SET))
55 		goto err;
56 
57     for (i = 0; i < num_tracks; i++) {
58 		if ((cfseek(fp, 4, SEEK_CUR)) || (cfread(&data, 4, 1, fp) != 1))
59 			goto err;
60 
61 		data -= 12;
62 
63 #if 0
64 		if (i == 0)  /* track 0: reserve length for tempo */
65 		    data += sizeof(hmp_tempo);
66 #endif
67 
68 		hmp->trks[i].len = data;
69 
70 		if (!(p = hmp->trks[i].data = malloc(data)))
71 			goto err;
72 
73 #if 0
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);
78 		}
79 #endif
80 					     /* finally, read track data */
81 		if ((cfseek(fp, 4, SEEK_CUR)) || (cfread(p, data, 1, fp) != 1))
82             goto err;
83    }
84    cfclose(fp);
85    return hmp;
86 
87 err:
88    cfclose(fp);
89    hmp_close(hmp);
90    return NULL;
91 }
92 
hmp_stop(hmp_file * hmp)93 void hmp_stop(hmp_file *hmp) {
94 	MIDIHDR *mhdr;
95 	if (!hmp->stop) {
96 		hmp->stop = 1;
97                 PumpMessages();
98 		midiStreamStop(hmp->hmidi);
99                 while (hmp->bufs_in_mm)
100                  {
101                         PumpMessages();
102 			Sleep(0);
103                  }
104 	}
105 	while ((mhdr = hmp->evbuf)) {
106 		midiOutUnprepareHeader((HMIDIOUT)hmp->hmidi, mhdr, sizeof(MIDIHDR));
107 		hmp->evbuf = mhdr->lpNext;
108 		free(mhdr);
109 	}
110 
111 	if (hmp->hmidi) {
112 		midiStreamClose(hmp->hmidi);
113 		hmp->hmidi = NULL;
114 	}
115 }
116 
hmp_close(hmp_file * hmp)117 void hmp_close(hmp_file *hmp) {
118 	int i;
119 
120 	hmp_stop(hmp);
121 	for (i = 0; i < hmp->num_trks; i++)
122 		if (hmp->trks[i].data)
123 			free(hmp->trks[i].data);
124 	free(hmp);
125 }
126 
127 /*
128  * read a HMI type variabele length number
129  */
get_var_num_hmi(unsigned char * data,int datalen,unsigned long * value)130 static int get_var_num_hmi(unsigned char *data, int datalen, unsigned long *value) {
131 	unsigned char *p;
132 	unsigned long v = 0;
133 	int shift = 0;
134 
135 	p = data;
136 	while ((datalen > 0) && !(*p & 0x80)) {
137 		v += *(p++) << shift;
138 		shift += 7;
139 		datalen --;
140     }
141 	if (!datalen)
142 		return 0;
143     v += (*(p++) & 0x7f) << shift;
144 	if (value) *value = v;
145     return p - data;
146 }
147 
148 /*
149  * read a MIDI type variabele length number
150  */
get_var_num(unsigned char * data,int datalen,unsigned long * value)151 static int get_var_num(unsigned char *data, int datalen,
152  unsigned long *value) {
153 	unsigned char *orgdata = data;
154 	unsigned long v = 0;
155 
156 	while ((datalen > 0) && (*data & 0x80))
157 		v = (v << 7) + (*(data++) & 0x7f);
158 	if (!datalen)
159 		return 0;
160     v = (v << 7) + *(data++);
161     if (value) *value = v;
162     return data - orgdata;
163 }
164 
get_event(hmp_file * hmp,event * ev)165 static int get_event(hmp_file *hmp, event *ev) {
166     static int cmdlen[7]={3,3,3,3,2,2,3};
167 	unsigned long got;
168 	unsigned long mindelta, delta;
169 	int i, ev_num;
170 	hmp_track *trk, *fndtrk;
171 
172 	mindelta = INT_MAX;
173 	fndtrk = NULL;
174 	for (trk = hmp->trks, i = hmp->num_trks; (i--) > 0; trk++) {
175 		if (!trk->left)
176 			continue;
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 */
181 			trk->left = 0;
182 			continue;
183 		}
184         delta += trk->cur_time - hmp->cur_time;
185 		if (delta < mindelta) {
186 			mindelta = delta;
187 			fndtrk = trk;
188 		}
189 	}
190 	if (!(trk = fndtrk))
191 			return HMP_EOF;
192 
193 	got = get_var_num_hmi(trk->cur, trk->left, &delta);
194 
195 	trk->cur_time += delta;
196 	ev->delta = trk->cur_time - hmp->cur_time;
197 	hmp->cur_time = trk->cur_time;
198 
199 	if ((trk->left -= got) < 3)
200 			return HMP_INVALID_FILE;
201 	trk->cur += got;
202 	/*memset(ev, 0, sizeof(*ev));*/ev->datalen = 0;
203 	ev->msg[0] = ev_num = *(trk->cur++);
204 	trk->left--;
205 	if (ev_num < 0x80)
206 	    return HMP_INVALID_FILE; /* invalid command */
207 	if (ev_num < 0xf0) {
208 		ev->msg[1] = *(trk->cur++);
209 		trk->left--;
210 		if (cmdlen[((ev_num) >> 4) - 8] == 3) {
211 			ev->msg[2] = *(trk->cur++);
212 			trk->left--;
213 		}
214 	} else if (ev_num == 0xff) {
215 		ev->msg[1] = *(trk->cur++);
216 		trk->left--;
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;
226 	return 0;
227 }
228 
fill_buffer(hmp_file * hmp)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);
233 	unsigned int i;
234 	event ev;
235 
236 	while (p + 4 <= pend) {
237 		if (hmp->pending_size) {
238 			i = (p - pend) * 4;
239 			if (i > hmp->pending_size)
240 				i = hmp->pending_size;
241 			*(p++) = hmp->pending_event | i;
242 			*(p++) = 0;
243 			memcpy((unsigned char *)p, hmp->pending, i);
244 			hmp->pending_size -= i;
245 			p += (i + 3) / 4;
246 		} else {
247 			if ((i = get_event(hmp, &ev))) {
248                                 mhdr->dwBytesRecorded = ((unsigned char *)p) - ((unsigned char *)mhdr->lpData);
249 				return i;
250 			}
251 			if (ev.datalen) {
252 				hmp->pending_size = ev.datalen;
253 				hmp->pending = ev.data;
254 				hmp->pending_event = ev.msg[0] << 24;
255 			} else {
256 				*(p++) = ev.delta;
257 				*(p++) = 0;
258 				*(p++) = (((DWORD)MEVT_SHORTMSG) << 24) |
259 					((DWORD)ev.msg[0]) |
260 					(((DWORD)ev.msg[1]) << 8) |
261 					(((DWORD)ev.msg[2]) << 16);
262 			}
263 		}
264 	}
265         mhdr->dwBytesRecorded = ((unsigned char *)p) - ((unsigned char *)mhdr->lpData);
266 	return 0;
267 }
268 
setup_buffers(hmp_file * hmp)269 static int setup_buffers(hmp_file *hmp) {
270 	int i;
271 	MIDIHDR *buf, *lastbuf;
272 
273 	lastbuf = NULL;
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;
282 		lastbuf = buf;
283 	}
284 	hmp->evbuf = lastbuf;
285 	return 0;
286 }
287 
reset_tracks(struct hmp_file * hmp)288 static void reset_tracks(struct hmp_file *hmp) {
289 	int i;
290 
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;
294 	}
295 }
296 
midi_callback(HMIDISTRM hms,UINT uMsg,DWORD dwUser,DWORD dw1,DWORD dw2)297 static void _stdcall midi_callback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) {
298 	MIDIHDR *mhdr;
299 	hmp_file *hmp;
300 	int rc;
301 
302 	if (uMsg != MOM_DONE)
303 		return;
304 
305 	mhdr = ((MIDIHDR *)dw1);
306 	mhdr->dwBytesRecorded = 0;
307 	hmp = (hmp_file *)(mhdr->dwUser);
308 	mhdr->lpNext = hmp->evbuf;
309 	hmp->evbuf = mhdr;
310 	hmp->bufs_in_mm--;
311 
312 	if (!hmp->stop) {
313 		while (fill_buffer(hmp) == HMP_EOF)
314 			reset_tracks(hmp);
315 		if ((rc = midiStreamOut(hmp->hmidi, hmp->evbuf,
316 			sizeof(MIDIHDR))) != MMSYSERR_NOERROR) {
317 			/* ??? */
318 		} else {
319 			hmp->evbuf = hmp->evbuf->lpNext;
320 			hmp->bufs_in_mm++;
321 		}
322 	}
323 
324 }
325 
setup_tempo(hmp_file * hmp,unsigned long tempo)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);
329 	*(p++) = 0;
330 	*(p++) = 0;
331 	*(p++) = (((DWORD)MEVT_TEMPO)<<24) | tempo;
332 	mhdr->dwBytesRecorded += 12;
333 }
334 
hmp_play(hmp_file * hmp)335 int hmp_play(hmp_file *hmp) {
336 	int rc;
337 	MIDIPROPTIMEDIV mptd;
338 #if 0
339         unsigned int    numdevs;
340         int i=0;
341 
342         numdevs=midiOutGetNumDevs();
343         hmp->devid=-1;
344         do
345         {
346          MIDIOUTCAPS devcaps;
347          midiOutGetDevCaps(i,&devcaps,sizeof(MIDIOUTCAPS));
348          if ((devcaps.wTechnology==MOD_FMSYNTH) || (devcaps.wTechnology==MOD_SYNTH))
349              hmp->devid=i;
350          i++;
351         } while ((i<(int)numdevs) && (hmp->devid==-1));
352 #else
353 	hmp->devid = MIDI_MAPPER;
354 #endif
355 
356 	if ((rc = setup_buffers(hmp)))
357 		return rc;
358 	if ((midiStreamOpen(&hmp->hmidi, &hmp->devid,1,(DWORD)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 
372 	reset_tracks(hmp);
373 	setup_tempo(hmp, 0x0f4240);
374 
375 	hmp->stop = 0;
376 	while (hmp->evbuf) {
377 		if ((rc = fill_buffer(hmp))) {
378 			if (rc == HMP_EOF) {
379 				reset_tracks(hmp);
380 				continue;
381 			} else
382 				return rc;
383 		}
384 #if 0
385 		{  FILE *f = fopen("dump","wb"); fwrite(hmp->evbuf->lpData,
386  hmp->evbuf->dwBytesRecorded,1,f); fclose(f); exit(1);}
387 #endif
388  		if ((rc = midiOutPrepareHeader((HMIDIOUT)hmp->hmidi, hmp->evbuf,
389 			sizeof(MIDIHDR))) != MMSYSERR_NOERROR) {
390 			/* FIXME: cleanup... */
391 			return HMP_MM_ERR;
392 		}
393 		if ((rc = midiStreamOut(hmp->hmidi, hmp->evbuf,
394 			sizeof(MIDIHDR))) != MMSYSERR_NOERROR) {
395 			/* FIXME: cleanup... */
396 			return HMP_MM_ERR;
397 		}
398 		hmp->evbuf = hmp->evbuf->lpNext;
399 		hmp->bufs_in_mm++;
400 	}
401 	midiStreamRestart(hmp->hmidi);
402 	return 0;
403 }
404 
405