]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/allg_snd/sound/drv/adlib.c
This commit was generated by cvs2svn to compensate for changes in r2,
[btb/d2x.git] / arch / dos / allg_snd / sound / drv / adlib.c
1 /*         ______   ___    ___ 
2  *        /\  _  \ /\_ \  /\_ \ 
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *      By Shawn Hargreaves,
11  *      1 Salisbury Road,
12  *      Market Drayton,
13  *      Shropshire,
14  *      England, TF9 1AJ.
15  *
16  *      Adlib/FM driver for the MIDI player.
17  *
18  *      See readme.txt for copyright information.
19  */
20
21
22 #ifndef DJGPP
23 #error This file should only be used by the djgpp version of Allegro
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <dos.h>
29
30 #include "allegro.h"
31 #include "internal.h"
32
33
34 /* external interface to the Adlib driver */
35 static int fm_detect();
36 static int fm_init(int voices);
37 static void fm_exit();
38 static int fm_mixer_volume(int volume);
39 static int fm_load_patches(char *patches, char *drums);
40 static void fm_key_on(int inst, int note, int bend, int vol, int pan);
41 static void fm_key_off(int voice);
42 static void fm_set_volume(int voice, int vol);
43 static void fm_set_pitch(int voice, int note, int bend);
44
45 static char adlib_desc[80] = "not initialised";
46
47
48 MIDI_DRIVER midi_adlib =
49 {
50    "Adlib", 
51    adlib_desc,
52    0, 0, 0, 0, -1, -1,
53    fm_detect,
54    fm_init,
55    fm_exit,
56    fm_mixer_volume,
57    NULL,
58    fm_load_patches,
59    _dummy_adjust_patches,
60    fm_key_on,
61    fm_key_off,
62    fm_set_volume,
63    fm_set_pitch,
64    _dummy_noop2,
65    _dummy_noop2
66 };
67
68
69 typedef struct FM_INSTRUMENT
70 {
71    unsigned char characteristic1;
72    unsigned char characteristic2;
73    unsigned char level1;
74    unsigned char level2;
75    unsigned char attackdecay1;
76    unsigned char attackdecay2;
77    unsigned char sustainrelease1;
78    unsigned char sustainrelease2;
79    unsigned char wave1;
80    unsigned char wave2;
81    unsigned char feedback;
82    unsigned char freq;
83    unsigned char key;
84    unsigned char type;
85 } FM_INSTRUMENT;
86
87
88 #define FM_HH     1
89 #define FM_CY     2
90 #define FM_TT     4
91 #define FM_SD     8
92 #define FM_BD     16
93
94
95 /* include the GM patch set (static data) */
96 #include "fm_instr.h"
97
98
99 /* is the OPL in percussion mode? */
100 static int fm_drum_mode = FALSE;
101
102 /* delays when writing to OPL registers */
103 static int fm_delay_1 = 6;
104 static int fm_delay_2 = 35;
105
106 /* register offsets for each voice */
107 static int fm_offset[18] = {
108    0x000, 0x001, 0x002, 0x008, 0x009, 0x00A, 0x010, 0x011, 0x012, 
109    0x100, 0x101, 0x102, 0x108, 0x109, 0x10A, 0x110, 0x111, 0x112
110 };
111
112 /* for converting midi note numbers to FM frequencies */
113 static int fm_freq[13] = {
114    0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA,
115    0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE
116 };
117
118 /* logarithmic relationship between midi and FM volumes */
119 static int fm_vol_table[128] = {
120    0,  11, 16, 19, 22, 25, 27, 29, 32, 33, 35, 37, 39, 40, 42, 43,
121    45, 46, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
122    64, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77,
123    78, 79, 80, 80, 81, 82, 83, 83, 84, 85, 86, 86, 87, 88, 89, 89,
124    90, 91, 91, 92, 93, 93, 94, 95, 96, 96, 97, 97, 98, 99, 99, 100,
125    101, 101, 102, 103, 103, 104, 104, 105, 106, 106, 107, 107, 108,
126    109, 109, 110, 110, 111, 112, 112, 113, 113, 114, 114, 115, 115,
127    116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122,
128    123, 123, 124, 124, 125, 125, 126, 126, 127
129 };
130
131 /* drum channel tables:          BD       SD       TT       CY       HH    */
132 static int fm_drum_channel[] = { 6,       7,       8,       8,       7     };
133 static int fm_drum_op1[] =     { TRUE,    FALSE,   TRUE,    FALSE,   TRUE  };
134 static int fm_drum_op2[] =     { TRUE,    TRUE,    FALSE,   TRUE,    FALSE };
135 static int fm_drum_pitch[] =   { TRUE,    TRUE,    TRUE,    FALSE,   FALSE };
136
137 /* cached information about the state of the drum channels */
138 static FM_INSTRUMENT *fm_drum_cached_inst1[5];
139 static FM_INSTRUMENT *fm_drum_cached_inst2[5];
140 static int fm_drum_cached_vol1[5];
141 static int fm_drum_cached_vol2[5];
142 static long fm_drum_cached_time[5];
143
144 /* various bits of information about the current state of the FM chip */
145 static unsigned char fm_drum_mask;
146 static unsigned char fm_key[18];
147 static unsigned char fm_keyscale[18];
148 static unsigned char fm_feedback[18];
149 static int fm_level[18];
150 static int fm_patch[18];
151
152 #define VOICE_OFFSET(x)     ((x < 9) ? x : 0x100+x-9)
153
154
155
156 /* fm_write:
157  *  Writes a byte to the specified register on the FM chip.
158  */
159 static void fm_write(int reg, unsigned char data)
160 {
161    int i;
162    int port = (reg & 0x100) ? _fm_port+2 : _fm_port;
163
164    outportb(port, reg & 0xFF);      /* write the register */
165
166    for (i=0; i<fm_delay_1; i++)     /* delay */
167       inportb(port);
168
169    outportb(port+1, data);          /* write the data */
170
171    for (i=0; i<fm_delay_2; i++)     /* delay */
172       inportb(port);
173 }
174
175 static END_OF_FUNCTION(fm_write);
176
177
178
179 /* fm_reset:
180  *  Resets the FM chip. If enable is set, puts OPL3 cards into OPL3 mode,
181  *  otherwise puts them into OPL2 emulation mode.
182  */
183 static void fm_reset(int enable)
184 {
185    int i;
186
187    for (i=0xF5; i>0; i--)
188       fm_write(i, 0);
189
190    if (midi_card == MIDI_OPL3) {          /* if we have an OPL3... */
191       fm_delay_1 = 1;
192       fm_delay_2 = 2;
193
194       fm_write(0x105, 1);                 /* enable OPL3 mode */
195
196       for (i=0x1F5; i>0x105; i--)
197          fm_write(i, 0);
198
199       for (i=0x104; i>0x100; i--)
200          fm_write(i, 0);
201
202       if (!enable)
203          fm_write(0x105, 0);              /* turn OPL3 mode off again */
204    }
205    else {
206       fm_delay_1 = 6;
207       fm_delay_2 = 35;
208
209       if (midi_card == MIDI_2XOPL2) {     /* if we have a second OPL2... */
210          for (i=0x1F5; i>0x100; i--)
211             fm_write(i, 0);
212
213          fm_write(0x101, 0x20); 
214          fm_write(0x1BD, 0xC0); 
215       }
216    }
217
218    for (i=0; i<midi_adlib.voices; i++) {
219       fm_key[i] = 0;
220       fm_keyscale[i] = 0;
221       fm_feedback[i] = 0;
222       fm_level[i] = 0;
223       fm_patch[i] = -1;
224       fm_write(0x40+fm_offset[i], 63);
225       fm_write(0x43+fm_offset[i], 63);
226    }
227
228    for (i=0; i<5; i++) {
229       fm_drum_cached_inst1[i] = NULL;
230       fm_drum_cached_inst2[i] = NULL;
231       fm_drum_cached_vol1[i] = -1;
232       fm_drum_cached_vol2[i] = -1;
233       fm_drum_cached_time[i] = 0;
234    }
235
236    fm_write(0x01, 0x20);                  /* turn on wave form control */
237
238    fm_drum_mode = FALSE;
239    fm_drum_mask = 0xC0;
240    fm_write(0xBD, fm_drum_mask);          /* set AM and vibrato to high */
241
242    midi_adlib.xmin = -1;
243    midi_adlib.xmax = -1;
244 }
245
246 static END_OF_FUNCTION(fm_reset);
247
248
249
250 /* fm_set_drum_mode:
251  *  Switches the OPL synth between normal and percussion modes.
252  */
253 static void fm_set_drum_mode(int usedrums)
254 {
255    int i;
256
257    fm_drum_mode = usedrums;
258    fm_drum_mask = usedrums ? 0xE0 : 0xC0;
259
260    midi_adlib.xmin = usedrums ? 6 : -1;
261    midi_adlib.xmax = usedrums ? 8 : -1;
262
263    for (i=6; i<9; i++)
264       if (midi_card == MIDI_OPL3)
265          fm_write(0xC0+VOICE_OFFSET(i), 0x30);
266       else
267          fm_write(0xC0+VOICE_OFFSET(i), 0);
268
269    fm_write(0xBD, fm_drum_mask);
270 }
271
272 static END_OF_FUNCTION(fm_set_drum_mode);
273
274
275
276 /* fm_set_voice:
277  *  Sets the sound to be used for the specified voice, from a structure
278  *  containing eleven bytes of FM operator data. Note that it doesn't
279  *  actually set the volume: it just stores volume data in the fm_level
280  *  arrays for fm_set_volume() to use.
281  */
282 static inline void fm_set_voice(int voice, FM_INSTRUMENT *inst)
283 {
284    /* store some info */
285    fm_keyscale[voice] = inst->level2 & 0xC0;
286    fm_level[voice] = 63 - (inst->level2 & 63);
287    fm_feedback[voice] = inst->feedback;
288
289    /* write the new data */
290    fm_write(0x20+fm_offset[voice], inst->characteristic1);
291    fm_write(0x23+fm_offset[voice], inst->characteristic2);
292    fm_write(0x60+fm_offset[voice], inst->attackdecay1);
293    fm_write(0x63+fm_offset[voice], inst->attackdecay2);
294    fm_write(0x80+fm_offset[voice], inst->sustainrelease1);
295    fm_write(0x83+fm_offset[voice], inst->sustainrelease2);
296    fm_write(0xE0+fm_offset[voice], inst->wave1);
297    fm_write(0xE3+fm_offset[voice], inst->wave2);
298
299    /* don't set operator1 level for additive synthesis sounds */
300    if (!(inst->feedback & 1))
301       fm_write(0x40+fm_offset[voice], inst->level1);
302
303    /* on OPL3, 0xC0 contains pan info, so don't set it until fm_key_on() */
304    if (midi_card != MIDI_OPL3)
305       fm_write(0xC0+VOICE_OFFSET(voice), inst->feedback);
306 }
307
308
309
310 /* fm_set_drum_op1:
311  *  Sets the sound for operator #1 of a drum channel.
312  */
313 static inline void fm_set_drum_op1(int voice, FM_INSTRUMENT *inst)
314 {
315    fm_write(0x20+fm_offset[voice], inst->characteristic1);
316    fm_write(0x60+fm_offset[voice], inst->attackdecay1);
317    fm_write(0x80+fm_offset[voice], inst->sustainrelease1);
318    fm_write(0xE0+fm_offset[voice], inst->wave1);
319 }
320
321
322
323 /* fm_set_drum_op2:
324  *  Sets the sound for operator #2 of a drum channel.
325  */
326 static inline void fm_set_drum_op2(int voice, FM_INSTRUMENT *inst)
327 {
328    fm_write(0x23+fm_offset[voice], inst->characteristic2);
329    fm_write(0x63+fm_offset[voice], inst->attackdecay2);
330    fm_write(0x83+fm_offset[voice], inst->sustainrelease2);
331    fm_write(0xE3+fm_offset[voice], inst->wave2);
332 }
333
334
335
336 /* fm_set_drum_vol_op1:
337  *  Sets the volume for operator #1 of a drum channel.
338  */
339 static inline void fm_set_drum_vol_op1(int voice, int vol)
340 {
341    vol = 63 * fm_vol_table[vol] / 128;
342    fm_write(0x40+fm_offset[voice], (63-vol));
343 }
344
345
346
347 /* fm_set_drum_vol_op2:
348  *  Sets the volume for operator #2 of a drum channel.
349  */
350 static inline void fm_set_drum_vol_op2(int voice, int vol)
351 {
352    vol = 63 * fm_vol_table[vol] / 128;
353    fm_write(0x43+fm_offset[voice], (63-vol));
354 }
355
356
357
358 /* fm_set_drum_pitch:
359  *  Sets the pitch of a drum channel.
360  */
361 static inline void fm_set_drum_pitch(int voice, FM_INSTRUMENT *drum)
362 {
363    fm_write(0xA0+VOICE_OFFSET(voice), drum->freq);
364    fm_write(0xB0+VOICE_OFFSET(voice), drum->key & 0x1F);
365 }
366
367
368
369 /* fm_trigger_drum:
370  *  Triggers a note on a drum channel.
371  */
372 static inline void fm_trigger_drum(int inst, int vol)
373 {
374    FM_INSTRUMENT *drum = fm_drum+inst;
375    int d;
376
377    if (!fm_drum_mode)
378       fm_set_drum_mode(TRUE);
379
380    if (drum->type == FM_BD)
381       d = 0;
382    else if (drum->type == FM_SD)
383       d = 1;
384    else if (drum->type == FM_TT)
385       d = 2;
386    else if (drum->type == FM_CY)
387       d = 3;
388    else
389       d = 4;
390
391    /* don't let drum sounds come too close together */
392    if (fm_drum_cached_time[d] == _midi_tick)
393       return;
394
395    fm_drum_cached_time[d] = _midi_tick;
396
397    fm_drum_mask &= (~drum->type);
398    fm_write(0xBD, fm_drum_mask);
399
400    vol = vol*3/4;
401
402    if (fm_drum_op1[d]) {
403       if (fm_drum_cached_inst1[d] != drum) {
404          fm_drum_cached_inst1[d] = drum;
405          fm_set_drum_op1(fm_drum_channel[d], drum);
406       }
407
408       if (fm_drum_cached_vol1[d] != vol) {
409          fm_drum_cached_vol1[d] = vol;
410          fm_set_drum_vol_op1(fm_drum_channel[d], vol);
411       }
412    }
413
414    if (fm_drum_op2[d]) {
415       if (fm_drum_cached_inst2[d] != drum) {
416          fm_drum_cached_inst2[d] = drum;
417          fm_set_drum_op2(fm_drum_channel[d], drum);
418       }
419
420       if (fm_drum_cached_vol2[d] != vol) {
421          fm_drum_cached_vol2[d] = vol;
422          fm_set_drum_vol_op2(fm_drum_channel[d], vol);
423       }
424    }
425
426    fm_set_drum_pitch(fm_drum_channel[d], drum);
427
428    fm_drum_mask |= drum->type;
429    fm_write(0xBD, fm_drum_mask);
430 }
431
432
433
434 /* fm_key_on:
435  *  Triggers the specified voice. The instrument is specified as a GM
436  *  patch number, pitch as a midi note number, and volume from 0-127.
437  *  The bend parameter is _not_ expressed as a midi pitch bend value.
438  *  It ranges from 0 (no pitch change) to 0xFFF (almost a semitone sharp).
439  *  Drum sounds are indicated by passing an instrument number greater than
440  *  128, in which case the sound is GM percussion key #(inst-128).
441  */
442 static void fm_key_on(int inst, int note, int bend, int vol, int pan)
443 {
444    int voice;
445
446    if (inst > 127) {                               /* drum sound? */
447       inst -= 163;
448       if (inst < 0)
449          inst = 0;
450       else if (inst > 46)
451          inst = 46;
452
453       fm_trigger_drum(inst, vol);
454    }
455    else {                                          /* regular instrument */
456       if (midi_card == MIDI_2XOPL2) {
457          /* the SB Pro-1 has fixed pan positions per voice... */
458          if (pan < 64)
459             voice = _midi_allocate_voice(0, 5);
460          else
461             voice = _midi_allocate_voice(9, midi_driver->voices-1);
462       }
463       else
464          /* on other cards we can use any voices */
465          voice = _midi_allocate_voice(-1, -1);
466
467       if (voice < 0)
468          return;
469
470       /* make sure the voice isn't sounding */
471       fm_write(0x43+fm_offset[voice], 63);
472       if (fm_feedback[voice] & 1)
473          fm_write(0x40+fm_offset[voice], 63);
474
475       /* make sure the voice is set up with the right sound */
476       if (inst != fm_patch[voice]) {
477          fm_set_voice(voice, fm_instrument+inst);
478          fm_patch[voice] = inst;
479       }
480
481       /* set pan position */
482       if (midi_card == MIDI_OPL3) {
483          if (pan < 48)
484             pan = 0x10;
485          else if (pan >= 80)
486             pan = 0x20;
487          else
488             pan = 0x30;
489
490          fm_write(0xC0+VOICE_OFFSET(voice), pan | fm_feedback[voice]);
491       }
492
493       /* and play the note */
494       fm_set_pitch(voice, note, bend);
495       fm_set_volume(voice, vol);
496    }
497 }
498
499 static END_OF_FUNCTION(fm_key_on);
500
501
502
503 /* fm_key_off:
504  *  Hey, guess what this does :-)
505  */
506 static void fm_key_off(int voice)
507 {
508    fm_write(0xB0+VOICE_OFFSET(voice), fm_key[voice] & 0xDF);
509 }
510
511 static END_OF_FUNCTION(fm_key_off);
512
513
514
515 /* fm_set_volume:
516  *  Sets the volume of the specified voice (vol range 0-127).
517  */
518 static void fm_set_volume(int voice, int vol)
519 {
520    vol = fm_level[voice] * fm_vol_table[vol] / 128;
521    fm_write(0x43+fm_offset[voice], (63-vol) | fm_keyscale[voice]);
522    if (fm_feedback[voice] & 1)
523       fm_write(0x40+fm_offset[voice], (63-vol) | fm_keyscale[voice]);
524 }
525
526 static END_OF_FUNCTION(fm_set_volume);
527
528
529
530 /* fm_set_pitch:
531  *  Sets the pitch of the specified voice.
532  */
533 static void fm_set_pitch(int voice, int note, int bend)
534 {
535    int oct = 1;
536    int freq;
537
538    note -= 24;
539    while (note >= 12) {
540       note -= 12;
541       oct++;
542    }
543
544    freq = fm_freq[note];
545    if (bend)
546       freq += (fm_freq[note+1] - fm_freq[note]) * bend / 0x1000;
547
548    fm_key[voice] = (oct<<2) | (freq >> 8);
549
550    fm_write(0xA0+VOICE_OFFSET(voice), freq & 0xFF); 
551    fm_write(0xB0+VOICE_OFFSET(voice), fm_key[voice] | 0x20);
552 }
553
554 static END_OF_FUNCTION(fm_set_pitch);
555
556
557
558 /* fm_load_patches:
559  *  Called before starting to play a MIDI file, to check if we need to be
560  *  in rhythm mode or not.
561  */
562 static int fm_load_patches(char *patches, char *drums)
563 {
564    int i;
565    int usedrums = FALSE;
566
567    for (i=6; i<9; i++) {
568       fm_key[i] = 0;
569       fm_keyscale[i] = 0;
570       fm_feedback[i] = 0;
571       fm_level[i] = 0;
572       fm_patch[i] = -1;
573       fm_write(0x40+fm_offset[i], 63);
574       fm_write(0x43+fm_offset[i], 63);
575    }
576
577    for (i=0; i<5; i++) {
578       fm_drum_cached_inst1[i] = NULL;
579       fm_drum_cached_inst2[i] = NULL;
580       fm_drum_cached_vol1[i] = -1;
581       fm_drum_cached_vol2[i] = -1;
582       fm_drum_cached_time[i] = 0;
583    }
584
585    for (i=0; i<128; i++) {
586       if (drums[i]) {
587          usedrums = TRUE;
588          break;
589       }
590    }
591
592    fm_set_drum_mode(usedrums);
593
594    return 0;
595 }
596
597 static END_OF_FUNCTION(fm_load_patches);
598
599
600
601 /* fm_mixer_volume:
602  *  For SB-Pro cards, sets the mixer volume for FM output.
603  */
604 static int fm_mixer_volume(int volume)
605 {
606    return _sb_set_mixer(-1, volume);
607 }
608
609
610
611 /* fm_is_there:
612  *  Checks for the presence of an OPL synth at the current port.
613  */
614 static int fm_is_there()
615 {
616    fm_write(1, 0);                        /* init test register */
617
618    fm_write(4, 0x60);                     /* reset both timers */
619    fm_write(4, 0x80);                     /* enable interrupts */
620
621    if (inportb(_fm_port) & 0xE0)
622       return FALSE;
623
624    fm_write(2, 0xFF);                     /* write 0xFF to timer 1 */
625    fm_write(4, 0x21);                     /* start timer 1 */
626
627    rest(100);
628
629    if ((inportb(_fm_port) & 0xE0) != 0xC0)
630       return FALSE;
631
632    fm_write(4, 0x60);                     /* reset both timers */
633    fm_write(4, 0x80);                     /* enable interrupts */
634
635    return TRUE;
636 }
637
638
639
640 /* fm_detect:
641  *  Adlib detection routine.
642  */
643 static int fm_detect()
644 {
645    static int ports[] = 
646          { 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x388, 0 };
647    int i;
648    char *s;
649    int opl_type;
650
651    if (_fm_port < 0) {
652       if (midi_card == MIDI_OPL2) {
653          _fm_port = 0x388;
654          if (fm_is_there())
655             goto found_it;
656       }
657
658       for (i=0; ports[i]; i++) {          /* find the card */
659          _fm_port = ports[i];
660          if (fm_is_there())
661             goto found_it;
662       }
663    }
664
665    if (!fm_is_there()) {
666       strcpy(allegro_error, "OPL synth not found");
667       return FALSE;
668    }
669
670    found_it:
671
672    if ((inportb(_fm_port) & 6) == 0) {    /* check for OPL3 */
673       opl_type = MIDI_OPL3;
674       _sb_read_dsp_version();
675    }
676    else {                                 /* check for second OPL2 */
677       if (_sb_read_dsp_version() >= 0x300)
678          opl_type = MIDI_2XOPL2;
679       else
680          opl_type = MIDI_OPL2;
681    }
682
683    if (midi_card == MIDI_OPL3) {
684       if (opl_type != MIDI_OPL3) {
685          strcpy(allegro_error, "OPL3 synth not found");
686          return FALSE;
687       }
688    }
689    else if (midi_card == MIDI_2XOPL2) {
690       if (opl_type != MIDI_2XOPL2) {
691          strcpy(allegro_error, "Second OPL2 synth not found");
692          return FALSE;
693       }
694    }
695    else if (midi_card != MIDI_OPL2)
696       midi_card = opl_type;
697
698    if (midi_card == MIDI_OPL2)
699       s = "OPL2 synth";
700    else if (midi_card == MIDI_2XOPL2)
701       s = "Dual OPL2 synths";
702    else
703       s = "OPL3 synth";
704
705    sprintf(adlib_desc, "%s on port %X", s, _fm_port);
706
707    midi_adlib.voices = (midi_card == MIDI_OPL2) ? 9 : 18;
708    midi_adlib.def_voices = midi_adlib.max_voices = midi_adlib.voices;
709
710    return TRUE;
711 }
712
713
714
715 /* load_ibk:
716  *  Reads in a .IBK patch set file, for use by the Adlib driver.
717  */
718 int load_ibk(char *filename, int drums)
719 {
720    char sig[4];
721    FM_INSTRUMENT *inst;
722    int c, note, oct, skip, count;
723
724    PACKFILE *f = pack_fopen(filename, F_READ);
725    if (!f)
726       return -1;
727
728    pack_fread(sig, 4, f);
729    if (memcmp(sig, "IBK\x1A", 4) != 0) {
730       pack_fclose(f);
731       return -1;
732    }
733
734    if (drums) {
735       inst = fm_drum;
736       skip = 35;
737       count = 47;
738    }
739    else {
740       inst = fm_instrument;
741       skip = 0;
742       count = 128;
743    }
744
745    for (c=0; c<skip*16; c++)
746       pack_getc(f);
747
748    for (c=0; c<count; c++) {
749       inst->characteristic1 = pack_getc(f);
750       inst->characteristic2 = pack_getc(f);
751       inst->level1 = pack_getc(f);
752       inst->level2 = pack_getc(f);
753       inst->attackdecay1 = pack_getc(f);
754       inst->attackdecay2 = pack_getc(f);
755       inst->sustainrelease1 = pack_getc(f);
756       inst->sustainrelease2 = pack_getc(f);
757       inst->wave1 = pack_getc(f);
758       inst->wave2 = pack_getc(f);
759       inst->feedback = pack_getc(f);
760
761       if (drums) {
762          switch (pack_getc(f)) {
763             case 6:  inst->type = FM_BD;  break;
764             case 7:  inst->type = FM_HH;  break;
765             case 8:  inst->type = FM_TT;  break;
766             case 9:  inst->type = FM_SD;  break;
767             case 10: inst->type = FM_CY;  break;
768             default: inst->type = 0;      break;
769          }
770
771          pack_getc(f);
772
773          note = pack_getc(f) - 24;
774          oct = 1;
775
776          while (note >= 12) {
777             note -= 12;
778             oct++;
779          }
780
781          inst->freq = fm_freq[note];
782          inst->key = (oct<<2) | (fm_freq[note] >> 8);
783       }
784       else {
785          inst->type = 0;
786          inst->freq = 0;
787          inst->key = 0;
788
789          pack_getc(f);
790          pack_getc(f);
791          pack_getc(f);
792       }
793
794       pack_getc(f);
795       pack_getc(f);
796
797       inst++;
798    }
799
800    pack_fclose(f);
801    return 0;
802 }
803
804
805
806 /* fm_init:
807  *  Setup the adlib driver.
808  */
809 static int fm_init(int voices)
810 {
811    char *s;
812    int i;
813
814    fm_reset(1);
815
816    for (i=0; i<2; i++) {
817       s = get_config_string("sound", ((i == 0) ? "ibk_file" : "ibk_drum_file"), NULL);
818       if ((s) && (s[0])) {
819          if (load_ibk(s, (i > 0)) != 0) {
820             sprintf(allegro_error, "Error reading .IBK file '%s'", s);
821             return -1;
822          }
823       }
824    }
825
826    LOCK_VARIABLE(midi_adlib);
827    LOCK_VARIABLE(fm_instrument);
828    LOCK_VARIABLE(fm_drum);
829    LOCK_VARIABLE(_fm_port);
830    LOCK_VARIABLE(fm_offset);
831    LOCK_VARIABLE(fm_freq);
832    LOCK_VARIABLE(fm_vol_table);
833    LOCK_VARIABLE(fm_drum_channel);
834    LOCK_VARIABLE(fm_drum_op1);
835    LOCK_VARIABLE(fm_drum_op2);
836    LOCK_VARIABLE(fm_drum_pitch);
837    LOCK_VARIABLE(fm_drum_cached_inst1);
838    LOCK_VARIABLE(fm_drum_cached_inst2);
839    LOCK_VARIABLE(fm_drum_cached_vol1);
840    LOCK_VARIABLE(fm_drum_cached_vol2);
841    LOCK_VARIABLE(fm_drum_cached_time);
842    LOCK_VARIABLE(fm_drum_mask);
843    LOCK_VARIABLE(fm_drum_mode);
844    LOCK_VARIABLE(fm_key);
845    LOCK_VARIABLE(fm_keyscale);
846    LOCK_VARIABLE(fm_feedback);
847    LOCK_VARIABLE(fm_level);
848    LOCK_VARIABLE(fm_patch);
849    LOCK_VARIABLE(fm_delay_1);
850    LOCK_VARIABLE(fm_delay_2);
851    LOCK_FUNCTION(fm_write);
852    LOCK_FUNCTION(fm_reset);
853    LOCK_FUNCTION(fm_set_drum_mode);
854    LOCK_FUNCTION(fm_key_on);
855    LOCK_FUNCTION(fm_key_off);
856    LOCK_FUNCTION(fm_set_volume);
857    LOCK_FUNCTION(fm_set_pitch);
858    LOCK_FUNCTION(fm_load_patches);
859
860    return 0;
861 }
862
863
864
865 /* fm_exit:
866  *  Cleanup when we are finished.
867  */
868 static void fm_exit()
869 {
870    fm_reset(0);
871 }
872