]> 4ch.mooo.com Git - 16.git/blob - src/lib/midi.c
wwww
[16.git] / src / lib / midi.c
1 /* midi.c
2  *
3  * Adlib OPL2/OPL3 FM synthesizer chipset test program.
4  * Play MIDI file using the OPLx synthesizer (well, poorly anyway)
5  * (C) 2010-2012 Jonathan Campbell.
6  * Hackipedia DOS library.
7  *
8  * This code is licensed under the LGPL.
9  * <insert LGPL legal text here>
10  *
11  * Compiles for intended target environments:
12  *   - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
13  */
14
15 #include "src/lib/midi.h"
16
17 static unsigned int             midi_trk_count=0;
18 struct midi_note                midi_notes[ADLIB_FM_VOICES];
19 struct midi_channel             midi_ch[MIDI_MAX_CHANNELS];
20 struct midi_track               midi_trk[MIDI_MAX_TRACKS];
21
22 /* MIDI params. Nobody ever said it was a straightforward standard!
23  * NTS: These are for reading reference. Internally we convert everything to 100Hz time base. */
24 static unsigned int ticks_per_quarter_note=0;   /* "Ticks per beat" */
25
26 #if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
27 static inline unsigned long farptr2phys(unsigned char far *p) { /* take 16:16 pointer convert to physical memory address */
28         return ((unsigned long)FP_SEG(p) << 4UL) + ((unsigned long)FP_OFF(p));
29 }
30 #endif
31
32 static inline unsigned char midi_trk_read(struct midi_track *t) {
33         unsigned char c;
34
35         /* NTS: 16-bit large/compact builds MUST compare pointers as unsigned long to compare FAR pointers correctly! */
36         if (t->read == NULL || (unsigned long)t->read >= (unsigned long)t->fence) {
37                 t->eof = 1;
38                 return 0xFF;
39         }
40
41         c = *(t->read);
42 #if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
43         if (FP_OFF(t->read) >= 0xF) /* 16:16 far pointer aware (NTS: Programs reassigning this pointer MUST normalize the FAR pointer) */
44                 t->read = MK_FP(FP_SEG(t->read)+0x1,0);
45         else
46                 t->read++;
47 #else
48         t->read++;
49 #endif
50         return c;
51 }
52
53 void midi_trk_end(struct midi_track *t) {
54         t->wait = ~0UL;
55         t->read = t->fence;
56 }
57
58 void midi_trk_skip(struct midi_track *t,unsigned long len) {
59         unsigned long rem;
60
61         /* NTS: 16-bit large/compact builds MUST compare pointers as unsigned long to compare FAR pointers correctly! */
62         if (t->read == NULL || (unsigned long)t->read >= (unsigned long)t->fence)
63                 return;
64
65         if (len > 0xFFF0UL) {
66                 midi_trk_end(t);
67                 return;
68         }
69 #if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
70         {
71                 unsigned long tt;
72
73                 tt = farptr2phys(t->read);
74                 rem = farptr2phys(t->fence) - tt;
75                 if (rem > len) rem = len;
76                 tt += rem;
77                 t->read = MK_FP(tt>>4,tt&0xF);
78         }
79 #else
80         rem = (unsigned long)(t->fence - t->read);
81         if (len > rem) len = rem;
82         t->read += len;
83 #endif
84 }
85
86 static const uint32_t midikeys_freqs[0x80] = {
87         0x00082d01,     /* key 0 = 8.17579891564371Hz */
88         0x0008a976,     /* key 1 = 8.66195721802725Hz */
89         0x00092d51,     /* key 2 = 9.17702399741899Hz */
90         0x0009b904,     /* key 3 = 9.72271824131503Hz */
91         0x000a4d05,     /* key 4 = 10.3008611535272Hz */
92         0x000ae9d3,     /* key 5 = 10.9133822322814Hz */
93         0x000b8ff4,     /* key 6 = 11.5623257097386Hz */
94         0x000c3ff6,     /* key 7 = 12.2498573744297Hz */
95         0x000cfa70,     /* key 8 = 12.9782717993733Hz */
96         0x000dc000,     /* key 9 = 13.75Hz */
97         0x000e914f,     /* key 10 = 14.5676175474403Hz */
98         0x000f6f11,     /* key 11 = 15.4338531642539Hz */
99         0x00105a02,     /* key 12 = 16.3515978312874Hz */
100         0x001152ec,     /* key 13 = 17.3239144360545Hz */
101         0x00125aa2,     /* key 14 = 18.354047994838Hz */
102         0x00137208,     /* key 15 = 19.4454364826301Hz */
103         0x00149a0a,     /* key 16 = 20.6017223070544Hz */
104         0x0015d3a6,     /* key 17 = 21.8267644645627Hz */
105         0x00171fe9,     /* key 18 = 23.1246514194771Hz */
106         0x00187fed,     /* key 19 = 24.4997147488593Hz */
107         0x0019f4e0,     /* key 20 = 25.9565435987466Hz */
108         0x001b8000,     /* key 21 = 27.5Hz */
109         0x001d229e,     /* key 22 = 29.1352350948806Hz */
110         0x001ede22,     /* key 23 = 30.8677063285078Hz */
111         0x0020b404,     /* key 24 = 32.7031956625748Hz */
112         0x0022a5d8,     /* key 25 = 34.647828872109Hz */
113         0x0024b545,     /* key 26 = 36.7080959896759Hz */
114         0x0026e410,     /* key 27 = 38.8908729652601Hz */
115         0x00293414,     /* key 28 = 41.2034446141087Hz */
116         0x002ba74d,     /* key 29 = 43.6535289291255Hz */
117         0x002e3fd2,     /* key 30 = 46.2493028389543Hz */
118         0x0030ffda,     /* key 31 = 48.9994294977187Hz */
119         0x0033e9c0,     /* key 32 = 51.9130871974931Hz */
120         0x00370000,     /* key 33 = 55Hz */
121         0x003a453d,     /* key 34 = 58.2704701897612Hz */
122         0x003dbc44,     /* key 35 = 61.7354126570155Hz */
123         0x00416809,     /* key 36 = 65.4063913251497Hz */
124         0x00454bb0,     /* key 37 = 69.295657744218Hz */
125         0x00496a8b,     /* key 38 = 73.4161919793519Hz */
126         0x004dc820,     /* key 39 = 77.7817459305202Hz */
127         0x00526829,     /* key 40 = 82.4068892282175Hz */
128         0x00574e9b,     /* key 41 = 87.307057858251Hz */
129         0x005c7fa4,     /* key 42 = 92.4986056779086Hz */
130         0x0061ffb5,     /* key 43 = 97.9988589954373Hz */
131         0x0067d380,     /* key 44 = 103.826174394986Hz */
132         0x006e0000,     /* key 45 = 110Hz */
133         0x00748a7b,     /* key 46 = 116.540940379522Hz */
134         0x007b7888,     /* key 47 = 123.470825314031Hz */
135         0x0082d012,     /* key 48 = 130.812782650299Hz */
136         0x008a9760,     /* key 49 = 138.591315488436Hz */
137         0x0092d517,     /* key 50 = 146.832383958704Hz */
138         0x009b9041,     /* key 51 = 155.56349186104Hz */
139         0x00a4d053,     /* key 52 = 164.813778456435Hz */
140         0x00ae9d36,     /* key 53 = 174.614115716502Hz */
141         0x00b8ff49,     /* key 54 = 184.997211355817Hz */
142         0x00c3ff6a,     /* key 55 = 195.997717990875Hz */
143         0x00cfa700,     /* key 56 = 207.652348789973Hz */
144         0x00dc0000,     /* key 57 = 220Hz */
145         0x00e914f6,     /* key 58 = 233.081880759045Hz */
146         0x00f6f110,     /* key 59 = 246.941650628062Hz */
147         0x0105a025,     /* key 60 = 261.625565300599Hz */
148         0x01152ec0,     /* key 61 = 277.182630976872Hz */
149         0x0125aa2e,     /* key 62 = 293.664767917408Hz */
150         0x01372082,     /* key 63 = 311.126983722081Hz */
151         0x0149a0a7,     /* key 64 = 329.62755691287Hz */
152         0x015d3a6d,     /* key 65 = 349.228231433004Hz */
153         0x0171fe92,     /* key 66 = 369.994422711634Hz */
154         0x0187fed4,     /* key 67 = 391.995435981749Hz */
155         0x019f4e00,     /* key 68 = 415.304697579945Hz */
156         0x01b80000,     /* key 69 = 440Hz */
157         0x01d229ec,     /* key 70 = 466.16376151809Hz */
158         0x01ede220,     /* key 71 = 493.883301256124Hz */
159         0x020b404a,     /* key 72 = 523.251130601197Hz */
160         0x022a5d81,     /* key 73 = 554.365261953744Hz */
161         0x024b545c,     /* key 74 = 587.329535834815Hz */
162         0x026e4104,     /* key 75 = 622.253967444162Hz */
163         0x0293414f,     /* key 76 = 659.25511382574Hz */
164         0x02ba74da,     /* key 77 = 698.456462866008Hz */
165         0x02e3fd24,     /* key 78 = 739.988845423269Hz */
166         0x030ffda9,     /* key 79 = 783.990871963499Hz */
167         0x033e9c01,     /* key 80 = 830.60939515989Hz */
168         0x03700000,     /* key 81 = 880Hz */
169         0x03a453d8,     /* key 82 = 932.32752303618Hz */
170         0x03dbc440,     /* key 83 = 987.766602512248Hz */
171         0x04168094,     /* key 84 = 1046.50226120239Hz */
172         0x0454bb03,     /* key 85 = 1108.73052390749Hz */
173         0x0496a8b8,     /* key 86 = 1174.65907166963Hz */
174         0x04dc8208,     /* key 87 = 1244.50793488832Hz */
175         0x0526829e,     /* key 88 = 1318.51022765148Hz */
176         0x0574e9b5,     /* key 89 = 1396.91292573202Hz */
177         0x05c7fa49,     /* key 90 = 1479.97769084654Hz */
178         0x061ffb53,     /* key 91 = 1567.981743927Hz */
179         0x067d3802,     /* key 92 = 1661.21879031978Hz */
180         0x06e00000,     /* key 93 = 1760Hz */
181         0x0748a7b1,     /* key 94 = 1864.65504607236Hz */
182         0x07b78880,     /* key 95 = 1975.5332050245Hz */
183         0x082d0128,     /* key 96 = 2093.00452240479Hz */
184         0x08a97607,     /* key 97 = 2217.46104781498Hz */
185         0x092d5171,     /* key 98 = 2349.31814333926Hz */
186         0x09b90410,     /* key 99 = 2489.01586977665Hz */
187         0x0a4d053c,     /* key 100 = 2637.02045530296Hz */
188         0x0ae9d36b,     /* key 101 = 2793.82585146403Hz */
189         0x0b8ff493,     /* key 102 = 2959.95538169308Hz */
190         0x0c3ff6a7,     /* key 103 = 3135.96348785399Hz */
191         0x0cfa7005,     /* key 104 = 3322.43758063956Hz */
192         0x0dc00000,     /* key 105 = 3520Hz */
193         0x0e914f62,     /* key 106 = 3729.31009214472Hz */
194         0x0f6f1100,     /* key 107 = 3951.06641004899Hz */
195         0x105a0250,     /* key 108 = 4186.00904480958Hz */
196         0x1152ec0e,     /* key 109 = 4434.92209562995Hz */
197         0x125aa2e3,     /* key 110 = 4698.63628667852Hz */
198         0x13720820,     /* key 111 = 4978.03173955329Hz */
199         0x149a0a79,     /* key 112 = 5274.04091060592Hz */
200         0x15d3a6d6,     /* key 113 = 5587.65170292806Hz */
201         0x171fe927,     /* key 114 = 5919.91076338615Hz */
202         0x187fed4e,     /* key 115 = 6271.92697570799Hz */
203         0x19f4e00a,     /* key 116 = 6644.87516127912Hz */
204         0x1b800000,     /* key 117 = 7040Hz */
205         0x1d229ec4,     /* key 118 = 7458.62018428944Hz */
206         0x1ede2200,     /* key 119 = 7902.13282009799Hz */
207         0x20b404a1,     /* key 120 = 8372.01808961916Hz */
208         0x22a5d81c,     /* key 121 = 8869.84419125991Hz */
209         0x24b545c7,     /* key 122 = 9397.27257335704Hz */
210         0x26e41040,     /* key 123 = 9956.06347910659Hz */
211         0x293414f2,     /* key 124 = 10548.0818212118Hz */
212         0x2ba74dac,     /* key 125 = 11175.3034058561Hz */
213         0x2e3fd24f,     /* key 126 = 11839.8215267723Hz */
214         0x30ffda9c      /* key 127 = 12543.853951416Hz */
215 };
216
217 static uint32_t midi_note_freq(struct midi_channel *ch,unsigned char key) {
218         return midikeys_freqs[key&0x7F];
219 }
220
221 static struct midi_note *get_fm_note(struct midi_track *t,struct midi_channel *ch,unsigned char key,unsigned char do_alloc) {
222         unsigned int tch = (unsigned int)(t - midi_trk); /* pointer math */
223         unsigned int ach = (unsigned int)(ch - midi_ch); /* pointer math */
224         unsigned int i,freen=~0;
225
226         for (i=0;i < ADLIB_FM_VOICES;i++) {
227                 if (midi_notes[i].busy) {
228                         if (midi_notes[i].note_channel == ach && midi_notes[i].note_track == tch && midi_notes[i].note_number == key)
229                                 return &midi_notes[i];
230                 }
231                 else {
232                         if (freen == ~0) freen = i;
233                 }
234         }
235
236         if (do_alloc && freen != ~0) return &midi_notes[freen];
237         return NULL;
238 }
239
240 static void drop_fm_note(struct midi_channel *ch,unsigned char key) {
241         unsigned int ach = (unsigned int)(ch - midi_ch); /* pointer math */
242         unsigned int i;
243
244         for (i=0;i < ADLIB_FM_VOICES;i++) {
245                 if (midi_notes[i].busy && midi_notes[i].note_channel == ach) {
246                         midi_notes[i].busy = 0;
247                         break;
248                 }
249         }
250 }
251
252 static inline void on_key_aftertouch(struct midi_track *t,struct midi_channel *ch,unsigned char key,unsigned char vel) {
253         struct midi_note *note = get_fm_note(t,ch,key,/*do_alloc*/0);
254         uint32_t freq = midi_note_freq(ch,key);
255         unsigned int ach;
256
257         if (note == NULL) return;
258
259         note->busy = 1;
260         note->note_number = key;
261         note->note_velocity = vel;
262         note->note_track = (unsigned int)(t - midi_trk);
263         note->note_channel = (unsigned int)(ch - midi_ch);
264         ach = (unsigned int)(note - midi_notes); /* which FM channel? */
265         adlib_freq_to_fm_op(&adlib_fm[ach].mod,(double)freq / 65536);
266         adlib_fm[ach].mod.attack_rate = vel >> 3; /* 0-127 to 0-15 */
267         adlib_fm[ach].mod.sustain_level = vel >> 3;
268         adlib_fm[ach].mod.key_on = 1;
269         adlib_update_groupA0(ach,&adlib_fm[ach]);
270 }
271
272 static inline void on_key_on(struct midi_track *t,struct midi_channel *ch,unsigned char key,unsigned char vel) {
273         struct midi_note *note = get_fm_note(t,ch,key,/*do_alloc*/1);
274         uint32_t freq = midi_note_freq(ch,key);
275         unsigned int ach;
276
277         /* HACK: Ignore percussion */
278         if ((ch->program >= 8 && ch->program <= 15)/*Chromatic percussion*/ ||
279                 (ch->program >= 112 && ch->program <= 119)/*Percussive*/ ||
280                 ch == &midi_ch[9]/*MIDI channel 10 (DAMN YOU 1-BASED COUNTING)*/)
281                 return;
282
283         if (note == NULL) {
284                 /* then we'll have to knock one off to make room */
285                 drop_fm_note(ch,key);
286                 note = get_fm_note(t,ch,key,1);
287                 if (note == NULL) return;
288         }
289
290         note->busy = 1;
291         note->note_number = key;
292         note->note_velocity = vel;
293         note->note_track = (unsigned int)(t - midi_trk);
294         note->note_channel = (unsigned int)(ch - midi_ch);
295         ach = (unsigned int)(note - midi_notes); /* which FM channel? */
296         adlib_freq_to_fm_op(&adlib_fm[ach].mod,(double)freq / 65536);
297         adlib_fm[ach].mod.attack_rate = vel >> 3; /* 0-127 to 0-15 */
298         adlib_fm[ach].mod.sustain_level = vel >> 3;
299         adlib_fm[ach].mod.key_on = 1;
300         adlib_update_groupA0(ach,&adlib_fm[ach]);
301 }
302
303 static inline void on_key_off(struct midi_track *t,struct midi_channel *ch,unsigned char key,unsigned char vel) {
304         struct midi_note *note = get_fm_note(t,ch,key,/*do_alloc*/0);
305         uint32_t freq = midi_note_freq(ch,key);
306         unsigned int ach;
307
308         if (note == NULL) return;
309
310         note->busy = 0;
311         ach = (unsigned int)(note - midi_notes); /* which FM channel? */
312         adlib_freq_to_fm_op(&adlib_fm[ach].mod,(double)freq / 65536);
313         adlib_fm[ach].mod.attack_rate = vel >> 3; /* 0-127 to 0-15 */
314         adlib_fm[ach].mod.sustain_level = vel >> 3;
315         adlib_fm[ach].mod.key_on = 0;
316         adlib_update_groupA0(ach,&adlib_fm[ach]);
317 }
318
319 static inline void on_control_change(struct midi_track *t,struct midi_channel *ch,unsigned char num,unsigned char val) {
320 }
321
322 static inline void on_program_change(struct midi_track *t,struct midi_channel *ch,unsigned char inst) {
323         ch->program = inst;
324 }
325
326 static inline void on_channel_aftertouch(struct midi_track *t,struct midi_channel *ch,unsigned char velocity) {
327 }
328
329 static inline void on_pitch_bend(struct midi_track *t,struct midi_channel *ch,int bend/*-8192 to 8192*/) {
330 }
331
332 unsigned long midi_trk_read_delta(struct midi_track *t) {
333         unsigned long tc = 0;
334         unsigned char c = 0,b;
335
336         /* NTS: 16-bit large/compact builds MUST compare pointers as unsigned long to compare FAR pointers correctly! */
337         if (t->read == NULL || (unsigned long)t->read >= (unsigned long)t->fence)
338                 return tc;
339
340         while (c < 4) {
341                 b = midi_trk_read(t);
342                 tc = (tc << 7UL) + (unsigned long)(b&0x7F);
343                 if (!(b&0x80)) break;
344                 c++;
345         }
346
347         return tc;
348 }
349
350 void midi_tick_track(unsigned int i) {
351         struct midi_track *t = midi_trk + i;
352         struct midi_channel *ch;
353         unsigned char b,c,d;
354         int cnt=0;
355
356         /* NTS: 16-bit large/compact builds MUST compare pointers as unsigned long to compare FAR pointers correctly! */
357         if (t->read == NULL || (unsigned long)t->read >= (unsigned long)t->fence) {
358                 t->eof = 1;
359                 return;
360         }
361
362         t->us_tick_cnt_mtpq += 10000UL * (unsigned long)ticks_per_quarter_note;
363         while (t->us_tick_cnt_mtpq >= t->us_per_quarter_note) {
364                 t->us_tick_cnt_mtpq -= t->us_per_quarter_note;
365                 cnt++;
366
367                 while (t->wait == 0) {
368                         if ((unsigned long)t->read >= (unsigned long)t->fence) {
369                                 t->eof = 1;
370                                 break;
371                         }
372
373                         /* read pointer should be pointing at MIDI event bytes, just after the time delay */
374                         b = midi_trk_read(t);
375                         if (b&0x80) {
376                                 if (b < 0xF8) {
377                                         if (b >= 0xF0)
378                                                 t->last_status = 0;
379                                         else
380                                                 t->last_status = b;
381                                 }
382                                 if (b != 0x00 && ((b&0xF8) != 0xF0))
383                                         c = midi_trk_read(t);
384                         }
385                         else {
386                                 /* blegh. last status */
387                                 c = b;
388                                 b = t->last_status;
389                         }
390                         switch (b>>4) {
391                                 case 0x8: { /* note off */
392                                         d = midi_trk_read(t);
393                                         ch = midi_ch + (b&0xF); /* c=key d=velocity */
394                                         on_key_off(t,ch,c,d);
395                                         } break;
396                                 case 0x9: { /* note on */
397                                         d = midi_trk_read(t);
398                                         ch = midi_ch + (b&0xF); /* c=key d=velocity */
399                                         if (d != 0) on_key_on(t,ch,c,d); /* "A Note On with a velocity of 0 is actually a note off" Bleh, really? */
400                                         else on_key_off(t,ch,c,d);
401                                         } break;
402                                 case 0xA: { /* polyphonic aftertouch */
403                                         d = midi_trk_read(t);
404                                         ch = midi_ch + (b&0xF); /* c=key d=velocity */
405                                         on_key_aftertouch(t,ch,c,d);
406                                         } break;
407                                 case 0xB: { /* control change */
408                                         d = midi_trk_read(t);
409                                         ch = midi_ch + (b&0xF); /* c=key d=velocity */
410                                         on_control_change(t,ch,c,d);
411                                         } break;
412                                 case 0xC: { /* program change */
413                                         on_program_change(t,ch,c); /* c=instrument d=not used */
414                                         } break;
415                                 case 0xD: { /* channel aftertouch */
416                                         on_channel_aftertouch(t,ch,c); /* c=velocity d=not used */
417                                         } break;
418                                 case 0xE: { /* pitch bend */
419                                         d = midi_trk_read(t);
420                                         on_pitch_bend(t,ch,((c&0x7F)|((d&0x7F)<<7))-8192); /* c=LSB d=MSB */
421                                         } break;
422                                 case 0xF: { /* event */
423                                         if (b == 0xFF) {
424                                                 if (c == 0x7F) { /* c=type d=len */
425                                                         unsigned long len = midi_trk_read_delta(t);
426 //====
427                                                         fprintf(stderr,"Type 0x7F len=%lu %p/%p/%p\n",len,t->raw,t->read,t->fence);
428 //====
429                                                         if (len < 512UL) {
430                                                                 /* unknown */
431                                                                 midi_trk_skip(t,len);
432                                                         }
433                                                         else {
434                                                                 midi_trk_end(t);
435                                                         }
436                                                 }
437                                                 else if (c < 0x7F) {
438                                                         d = midi_trk_read(t);
439
440                                                         if (c == 0x51 && d >= 3) {
441                                                                 d -= 3;
442                                                                 t->us_per_quarter_note = ((unsigned long)midi_trk_read(t)<<16UL)+
443                                                                         ((unsigned long)midi_trk_read(t)<<8UL)+
444                                                                         ((unsigned long)midi_trk_read(t)<<0UL);
445
446                                                                 if (1/*TODO: If format 0 or format 1*/) {
447                                                                         /* Ugh. Unless format 2, the tempo applies to all tracks */
448                                                                         int j;
449
450                                                                         for (j=0;j < midi_trk_count;j++) {
451                                                                                 if (j != i) midi_trk[j].us_per_quarter_note =
452                                                                                         t->us_per_quarter_note;
453                                                                         }
454                                                                 }
455                                                         }
456                                                         else {
457 //====
458                                                                 fprintf(stderr,"Type 0x%02x len=%lu %p/%p/%p\n",c,d,t->raw,t->read,t->fence);
459 //====
460                                                         }
461
462                                                         midi_trk_skip(t,d);
463                                                 }
464                                                 else {
465                                                         fprintf(stderr,"t=%u Unknown MIDI f message 0x%02x 0x%02x %p/%p/%p\n",i,b,c,t->raw,t->read,t->fence);
466                                                 }
467                                         }
468                                         else {
469                                                 unsigned long len = midi_trk_read_delta(t);
470 //====
471                                                 fprintf(stderr,"Sysex len=%lu %p/%p/%p\n",len,t->raw,t->read,t->fence);
472 //====
473                                                 midi_trk_skip(t,len);
474                                         }
475                                         } break;
476                                 default:
477                                         if (b != 0x00) {
478                                                 fprintf(stderr,"t=%u Unknown MIDI message 0x%02x at %p/%p/%p\n",i,b,t->raw,t->read,t->fence);
479                                                 midi_trk_end(t);
480                                         }
481                                         break;
482                         };
483
484                         /* and then read the next event */
485                         t->wait = midi_trk_read_delta(t);
486                 }
487                 if (t->wait != 0) {
488                         t->wait--;
489                 }
490         }
491 }
492
493 //void adlib_shut_up();
494 void midi_reset_tracks();
495 void midi_reset_channels();
496
497 void midi_tick() {
498         if (midi_playing) {
499                 unsigned int i;
500                 int eof=0;
501
502                 for (i=0;i < midi_trk_count;i++) {
503                         midi_tick_track(i);
504                         eof += midi_trk[i].eof?1:0;
505                 }
506
507                 if (eof >= midi_trk_count) {
508                         adlib_shut_up();
509                         midi_reset_tracks();
510                         midi_reset_channels();
511                 }
512         }
513 }
514
515 /* WARNING: subroutine call in interrupt handler. make sure you compile with -zu flag for large/compact memory models */
516 void interrupt irq0() {
517 //      midi_tick();
518         irq0_ticks++;
519         if ((irq0_cnt += irq0_add) >= irq0_max) {
520                 irq0_cnt -= irq0_max;
521                 old_irq0();
522         }
523         else {
524                 p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
525         }
526 }
527
528 void adlib_shut_up() {
529         int i;
530
531         memset(adlib_fm,0,sizeof(adlib_fm));
532         memset(&adlib_reg_bd,0,sizeof(adlib_reg_bd));
533         for (i=0;i < adlib_fm_voices;i++) {
534                 struct adlib_fm_operator *f;
535                 f = &adlib_fm[i].mod;
536                 f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
537                 f = &adlib_fm[i].car;
538                 f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
539         }
540
541         for (i=0;i < adlib_fm_voices;i++) {
542                 struct adlib_fm_operator *f;
543
544                 midi_notes[i].busy = 0;
545                 midi_notes[i].note_channel = 0;
546
547                 f = &adlib_fm[i].mod;
548                 f->mod_multiple = 1;
549                 f->total_level = 63 - 16;
550                 f->attack_rate = 15;
551                 f->decay_rate = 4;
552                 f->sustain_level = 0;
553                 f->release_rate = 8;
554                 f->f_number = 400;
555                 f->sustain = 1;
556                 f->octave = 4;
557                 f->key_on = 0;
558
559                 f = &adlib_fm[i].car;
560                 f->mod_multiple = 1;
561                 f->total_level = 63 - 16;
562                 f->attack_rate = 15;
563                 f->decay_rate = 4;
564                 f->sustain_level = 0;
565                 f->release_rate = 8;
566                 f->f_number = 0;
567                 f->sustain = 1;
568                 f->octave = 0;
569                 f->key_on = 0;
570         }
571
572         adlib_apply_all();
573 }
574
575 void midi_reset_track(unsigned int i) {
576         struct midi_track *t;
577
578         if (i >= MIDI_MAX_TRACKS) return;
579         t = &midi_trk[i];
580         t->eof = 0;
581         t->last_status = 0;
582         t->us_tick_cnt_mtpq = 0;
583         t->us_per_quarter_note = (60000000UL / 120UL); /* 120BPM */
584         t->read = midi_trk[i].raw;
585         t->wait = midi_trk_read_delta(t); /* and then the read pointer will point at the MIDI event when wait counts down */
586 }
587
588 void midi_reset_tracks() {
589         int i;
590
591         for (i=0;i < midi_trk_count;i++)
592                 midi_reset_track(i);
593 }
594
595 void midi_reset_channels() {
596         int i;
597
598         for (i=0;i < MIDI_MAX_CHANNELS;i++) {
599                 midi_ch[i].program = 0;
600         }
601 }
602
603 int load_midi_file(const char *path) {
604         unsigned char tmp[256];
605         unsigned int tracks=0;
606         unsigned int tracki=0;
607         int fd;
608
609         fd = open(path,O_RDONLY|O_BINARY);
610         if (fd < 0) {
611                 printf("Failed to load file %s\n",path);
612                 return 0;
613         }
614
615         ticks_per_quarter_note = 0;
616         while (read(fd,tmp,8) == 8) {
617                 uint32_t sz;
618
619                 sz =    ((uint32_t)tmp[4] << (uint32_t)24) |
620                         ((uint32_t)tmp[5] << (uint32_t)16) |
621                         ((uint32_t)tmp[6] << (uint32_t)8) |
622                         ((uint32_t)tmp[7] << (uint32_t)0);
623                 if (!memcmp(tmp,"MThd",4)) {
624                         unsigned short t,tdiv;
625
626                         if (sz < 6 || sz > 255) {
627                                 fprintf(stderr,"Invalid MThd size %lu\n",(unsigned long)sz);
628                                 goto err;
629                         }
630                         if (read(fd,tmp,(int)sz) != (int)sz) {
631                                 fprintf(stderr,"MThd read error\n");
632                                 goto err;
633                         }
634
635                         /* byte 0-1 = format type (0,1 or 2) */
636                         /* byte 2-3 = number of tracks */
637                         /* byte 4-5 = time divison */
638                         t = tmp[1] | (tmp[0] << 8);
639                         if (t > 1) {
640                                 fprintf(stderr,"MThd type %u not supported\n",t);
641                                 goto err; /* we only take type 0 or 1, don't support 2 */
642                         }
643                         tracks = tmp[3] | (tmp[2] << 8);
644                         if (tracks > MIDI_MAX_TRACKS) {
645                                 fprintf(stderr,"MThd too many (%u) tracks\n",tracks);
646                                 goto err;
647                         }
648                         tdiv = tmp[5] | (tmp[4] << 8);
649                         if (tdiv & 0x8000) {
650                                 fprintf(stderr,"MThd SMPTE time division not supported\n");
651                                 goto err; /* we do not support the SMPTE form */
652                         }
653                         if (tdiv == 0) {
654                                 fprintf(stderr,"MThd time division == 0\n");
655                                 goto err;
656                         }
657                         ticks_per_quarter_note = tdiv;
658                 }
659                 else if (!memcmp(tmp,"MTrk",4)) {
660                         if (sz == 0UL) continue;
661 #if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
662                         if (sz > (640UL << 10UL)) goto err; /* 640KB */
663 #elif TARGET_MSDOS == 32
664                         if (sz > (1UL << 20UL)) goto err; /* 1MB */
665 #else
666                         if (sz > (60UL << 10UL)) goto err; /* 60KB */
667 #endif
668                         if (tracki >= MIDI_MAX_TRACKS) goto err;
669 #if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
670                         {
671                                 unsigned segv;
672
673                                 /* NTS: _fmalloc() is still limited to 64KB sizes */
674                                 if (_dos_allocmem((unsigned)((sz+15UL)>>4UL),&segv) != 0) goto err;
675                                 midi_trk[tracki].raw = MK_FP(segv,0);
676                         }
677 #else
678                         midi_trk[tracki].raw = malloc(sz);
679 #endif
680                         if (midi_trk[tracki].raw == NULL) goto err;
681                         midi_trk[tracki].read = midi_trk[tracki].raw;
682 #if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
683                         {
684                                 unsigned char far *p = midi_trk[tracki].raw;
685                                 unsigned long rem = (unsigned long)sz;
686                                 unsigned long cando;
687                                 unsigned read;
688
689                                 while (rem != 0UL) {
690                                         read = 0;
691
692                                         cando = 0x10000UL - (unsigned long)FP_OFF(p);
693                                         if (cando > rem) cando = rem;
694                                         if (cando > 0xFFFFUL) cando = 0xFFFFUL; /* we're limited to 64KB-1 of reading */
695
696                                         if (_dos_read(fd,p,(unsigned)cando,&read) != 0) goto err;
697                                         if (read != (unsigned)cando) goto err;
698
699                                         rem -= cando;
700                                         if ((((unsigned long)FP_OFF(p))+cando) == 0x10000UL)
701                                                 p = MK_FP(FP_SEG(p)+0x1000,0);
702                                         else
703                                                 p += (unsigned)cando;
704                                 }
705
706                                 cando = farptr2phys(p);
707                                 midi_trk[tracki].fence = MK_FP(cando>>4,cando&0xF);
708                         }
709 #else
710                         midi_trk[tracki].fence = midi_trk[tracki].raw + (unsigned)sz;
711                         if (read(fd,midi_trk[tracki].raw,(unsigned)sz) != (int)sz) goto err;
712 #endif
713                         tracki++;
714                 }
715                 else {
716                         fprintf(stderr,"Unknown MIDI chunk %c%c%c%c\n",tmp[0],tmp[1],tmp[2],tmp[3]);
717                         goto err;
718                 }
719         }
720         if (tracki == 0 || ticks_per_quarter_note == 0) goto err;
721         midi_trk_count = tracki;
722
723         fprintf(stderr,"Ticks per quarter note: %u\n",ticks_per_quarter_note);
724
725         close(fd);
726         return 1;
727 err:
728         close(fd);
729         return 0;
730 }