2 * This code handles HMP files. It can:
3 * - Open/read/close HMP files
4 * - Play HMP via Windows MIDI
5 * - Convert HMP to MIDI for further use
6 * Based on work of Arne de Bruijn and the JFFEE project
24 #ifdef WORDS_BIGENDIAN
25 #define MIDIINT(x) (x)
26 #define MIDISHORT(x) (x)
28 #define MIDIINT(x) SWAPINT(x)
29 #define MIDISHORT(x) SWAPSHORT(x)
33 // READ/OPEN/CLOSE HMP
35 void hmp_close(hmp_file *hmp)
39 for (i = 0; i < hmp->num_trks; i++)
40 if (hmp->trks[i].data)
41 d_free(hmp->trks[i].data);
45 hmp_file *hmp_open(const char *filename) {
46 int i, data, num_tracks, tempo;
52 if (!(fp = cfopen((char *)filename, "rb")))
55 MALLOC(hmp, hmp_file, 1);
61 memset(hmp, 0, sizeof(*hmp));
63 if ((cfread(buf, 1, 8, fp) != 8) || (memcmp(buf, "HMIMIDIP", 8)))
70 if (cfseek(fp, 0x30, SEEK_SET))
77 if (cfread(&num_tracks, 4, 1, fp) != 1)
84 if ((num_tracks < 1) || (num_tracks > HMP_TRACKS))
90 hmp->num_trks = num_tracks;
92 if (cfseek(fp, 0x38, SEEK_SET))
98 if (cfread(&tempo, 4, 1, fp) != 1)
104 hmp->tempo = INTEL_INT(tempo);
106 if (cfseek(fp, 0x308, SEEK_SET))
113 for (i = 0; i < num_tracks; i++) {
114 if ((cfseek(fp, 4, SEEK_CUR)) || (cfread(&data, 4, 1, fp) != 1))
122 hmp->trks[i].len = data;
124 MALLOC(p, unsigned char, data);
125 if (!(hmp->trks[i].data = p))
132 /* finally, read track data */
133 if ((cfseek(fp, 4, SEEK_CUR)) || (cfread(p, data, 1, fp) != 1))
145 // CONVERSION FROM HMP TO MIDI
147 static unsigned int hmptrk2mid(ubyte* data, int size, unsigned char **midbuf, unsigned int *midlen)
150 ubyte lc1 = 0,last_com = 0;
153 unsigned int offset = *midlen;
155 while (data < dptr + size)
157 if (data[0] & 0x80) {
158 ubyte b = (data[0] & 0x7F);
159 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 1);
160 memcpy(&(*midbuf)[*midlen], &b, 1);
164 d = (data[0] & 0x7F);
166 while ((data[n1] & 0x80) == 0) {
168 d += (data[n1] & 0x7F) << (n1 * 7);
171 while ((data[n1] & 0x80) == 0) {
176 for(n2 = 0; n2 <= n1; n2++) {
177 ubyte b = (data[n1 - n2] & 0x7F);
181 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 1);
182 memcpy(&(*midbuf)[*midlen], &b, 1);
188 if (*data == 0xFF) { //meta?
189 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 3 + data[2]);
190 memcpy(&(*midbuf)[*midlen], data, 3 + data[2]);
191 *midlen += 3 + data[2];
199 switch (lc1 & 0xF0) {
207 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 1);
208 memcpy(&(*midbuf)[*midlen], &lc1, 1);
211 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 2);
212 memcpy(&(*midbuf)[*midlen], data + 1, 2);
220 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 1);
221 memcpy(&(*midbuf)[*midlen], &lc1, 1);
224 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 1);
225 memcpy(&(*midbuf)[*midlen], data + 1, 1);
235 return (*midlen - offset);
238 ubyte tempo [19] = {'M','T','r','k',0,0,0,11,0,0xFF,0x51,0x03,0x18,0x80,0x00,0,0xFF,0x2F,0};
240 void hmp2mid(char *hmp_name, unsigned char **midbuf, unsigned int *midlen)
243 short ms, time_div = 0xC0;
246 hmp = hmp_open(hmp_name);
251 time_div = hmp->tempo*1.6;
254 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 4);
255 memcpy(&(*midbuf)[*midlen], "MThd", 4);
258 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + sizeof(mi));
259 memcpy(&(*midbuf)[*midlen], &mi, sizeof(mi));
260 *midlen += sizeof(mi);
262 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + sizeof(ms));
263 memcpy(&(*midbuf)[*midlen], &ms, sizeof(ms));
264 *midlen += sizeof(ms);
265 ms = MIDISHORT(hmp->num_trks);
266 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + sizeof(ms));
267 memcpy(&(*midbuf)[*midlen], &ms, sizeof(ms));
268 *midlen += sizeof(ms);
269 ms = MIDISHORT(time_div);
270 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + sizeof(ms));
271 memcpy(&(*midbuf)[*midlen], &ms, sizeof(ms));
272 *midlen += sizeof(ms);
273 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + sizeof(tempo));
274 memcpy(&(*midbuf)[*midlen], &tempo, sizeof(tempo));
275 *midlen += sizeof(tempo);
278 for (i = 1; i < hmp->num_trks; i++)
280 int midtrklenpos = 0;
282 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 4);
283 memcpy(&(*midbuf)[*midlen], "MTrk", 4);
285 midtrklenpos = *midlen;
287 *midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + sizeof(mi));
288 *midlen += sizeof(mi);
289 mi = hmptrk2mid(hmp->trks[i].data, hmp->trks[i].len, midbuf, midlen);
291 memcpy(&(*midbuf)[midtrklenpos], &mi, 4);