3 * Adlib OPL2/OPL3 FM synthesizer chipset controller library.
4 * (C) 2010-2012 Jonathan Campbell.
5 * Hackipedia DOS library.
7 * This code is licensed under the LGPL.
8 * <insert LGPL legal text here>
10 * Compiles for intended target environments:
11 * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
13 * On most Sound Blaster compatible cards all the way up to the late 1990s, a
14 * Yamaha OPL2 or OPL3 chipset exists (or may be emulated on PCI cards) that
15 * responds to ports 388h-389h. Through these I/O ports you control the FM
16 * synthesizer engine. On some cards, a second OPL2 may exist at 38A-38Bh,
17 * and on ISA PnP cards, the OPL3 may be located at 38C-38Dh if software
19 /* TODO: ISA PnP complementary library */
20 /* TODO: Modifications to the library to support OPL2/OPL3 chipsets at I/O ports
24 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
32 #include "src/lib/doslib/adlib.h"
34 unsigned short adlib_voice_to_op_opl2[9] = {0x00,0x01,0x02, 0x08,0x09,0x0A, 0x10,0x11,0x12};
35 /* NTS: There is a HOWTO out there stating that the registers line up 0,1,2,6,7,8,... == WRONG! */
36 unsigned short adlib_voice_to_op_opl3[18] = {0x00,0x01,0x02, 0x08,0x09,0x0A, 0x10,0x11,0x12, 0x100,0x101,0x102, 0x108,0x109,0x10A, 0x110,0x111,0x112};
37 unsigned short* adlib_voice_to_op = adlib_voice_to_op_opl2;
39 struct adlib_reg_bd adlib_reg_bd;
40 struct adlib_fm_channel adlib_fm[ADLIB_FM_VOICES];
41 int adlib_fm_voices = 0;
42 unsigned char adlib_flags = 0;
44 struct adlib_fm_channel adlib_fm_preset_violin_opl3 = {
45 .mod = {0, 1, 1, 1, 1, 1, 42, 6, 1, 1, 4, 0,
46 3, 456, 1, 1, 1, 1, 4, 0, 5},
47 .car = {0, 1, 1, 1, 1, 1, 63, 4, 1, 1, 4, 0,
48 3, 456, 1, 1, 1, 1, 0, 0, 2}
51 struct adlib_fm_channel adlib_fm_preset_violin_opl2 = {
52 .mod = {0, 1, 1, 1, 1, 1, 42, 6, 1, 1, 4, 0,
53 3, 456, 1, 1, 1, 1, 2, 0, 1},
54 .car = {0, 1, 1, 1, 1, 1, 63, 4, 1, 1, 4, 0,
55 3, 456, 1, 1, 1, 1, 0, 0, 2}
58 struct adlib_fm_channel adlib_fm_preset_piano = {
59 .mod = {0, 0, 1, 1, 1, 1, 42, 10, 4, 2, 3, 0,
60 4, 456, 1, 1, 1, 1, 4, 0, 0},
61 .car = {0, 0, 1, 1, 1, 1, 63, 10, 1, 8, 3, 0,
62 4, 456, 1, 1, 1, 1, 0, 0, 0}
65 struct adlib_fm_channel adlib_fm_preset_harpsichord = {
66 .mod = {0, 0, 1, 1, 1, 1, 42, 10, 3, 2, 3, 0,
67 4, 456, 1, 1, 1, 1, 2, 0, 3},
68 .car = {0, 0, 1, 1, 1, 1, 63, 10, 5, 3, 3, 0,
69 4, 456, 1, 1, 1, 1, 0, 0, 3}
72 /* NTS: adjust the modulator total level value to vary between muted (27) and open (47) with
73 * further adjustment if you want to mimick the change in sound when you blow harder */
74 struct adlib_fm_channel adlib_fm_preset_horn = {
75 .mod = {0, 0, 1, 0, 1, 0, 47, 6, 1, 1, 7, 0,
76 4, 514, 1, 1, 1, 1, 0, 0, 0},
77 .car = {0, 0, 1, 0, 1, 0, 47, 8, 2, 2, 7, 0,
78 4, 456, 1, 1, 1, 1, 0, 0, 0}
81 struct adlib_fm_channel adlib_fm_preset_deep_bass_drum = {
82 .mod = {0, 0, 0, 0, 1, 0, 13, 7, 1, 0, 1, 0,
83 2, 456, 1, 1, 1, 1, 7, 0, 1},
84 .car = {0, 0, 1, 1, 1, 1, 63, 15, 2, 6, 1, 0,
85 2, 456, 1, 1, 1, 1, 0, 0, 0}
88 /* NTS: You can simulate hitting software or harder by adjusting the modulator total volume
89 * as well as raising or lowering the frequency */
90 struct adlib_fm_channel adlib_fm_preset_small_drum = {
91 .mod = {0, 0, 0, 1, 1, 1, 54, 15, 10, 15, 15, 0,
92 3, 456, 1, 1, 1, 1, 1, 0, 0},
93 .car = {0, 0, 1, 1, 1, 1, 63, 15, 7, 15, 15, 0,
94 3, 456, 1, 1, 1, 1, 1, 0, 0}
97 unsigned char adlib_read(unsigned short i) {
99 outp(ADLIB_IO_INDEX+((i>>8)*2),(unsigned char)i);
101 c = inp(ADLIB_IO_DATA+((i>>8)*2));
106 void adlib_write(unsigned short i,unsigned char d) {
107 outp(ADLIB_IO_INDEX+((i>>8)*2),(unsigned char)i);
109 outp(ADLIB_IO_DATA+((i>>8)*2),d);
113 /* TODO: adlib_write_imm_1() and adlib_write_imm_2()
114 * this would allow DOS programs to use this ADLIB library from within
115 * an interrupt routine */
117 int probe_adlib(unsigned char sec) {
118 unsigned char a,b,retry=3;
119 unsigned short bas = sec ? 0x100 : 0;
121 /* this code uses the 8254 for timing */
126 adlib_write(0x04+bas,0x60); /* reset both timers */
127 adlib_write(0x04+bas,0x80); /* enable interrupts */
128 a = adlib_status(sec);
129 adlib_write(0x02+bas,0xFF); /* timer 1 */
130 adlib_write(0x04+bas,0x21); /* start timer 1 */
131 t8254_wait(t8254_us2ticks(100));
132 b = adlib_status(sec);
133 adlib_write(0x04+bas,0x60); /* reset both timers */
134 adlib_write(0x04+bas,0x00); /* disable interrupts */
136 if ((a&0xE0) == 0x00 && (b&0xE0) == 0xC0)
139 } while (--retry != 0);
149 adlib_write(0x01,0x20); /* enable waveform select */
150 adlib_voice_to_op = adlib_voice_to_op_opl2;
153 if (probe_adlib(1)) {
154 adlib_fm_voices = 18;
155 adlib_flags = ADLIB_FM_DUAL_OPL2;
158 /* NTS: "unofficial" method of detecting OPL3 */
159 if ((adlib_status(0) & 0x06) == 0) {
160 adlib_fm_voices = 18;
161 adlib_flags = ADLIB_FM_OPL3;
162 adlib_voice_to_op = adlib_voice_to_op_opl3;
164 /* init like an OPL3 */
165 adlib_write(0x105,0x01); /* set OPL3 bit */
167 adlib_write(0x104,0x00); /* disable any 4op connections */
174 void shutdown_adlib_opl3() {
175 if (adlib_flags & ADLIB_FM_OPL3) {
176 adlib_write(0x105,0x00); /* clear OPL3 bit */
179 adlib_voice_to_op = adlib_voice_to_op_opl2;
180 adlib_flags &= ~ADLIB_FM_OPL3;
184 void shutdown_adlib() {
185 shutdown_adlib_opl3();
188 void adlib_update_group20(unsigned int op,struct adlib_fm_operator *f) {
189 adlib_write(0x20+op, (f->am << 7) |
192 (f->key_scaling_rate << 4) |
193 (f->mod_multiple << 0));
196 void adlib_update_group40(unsigned int op,struct adlib_fm_operator *f) {
197 adlib_write(0x40+op, (f->level_key_scale << 6) |
198 ((f->total_level^63) << 0));
201 void adlib_update_group60(unsigned int op,struct adlib_fm_operator *f) {
202 adlib_write(0x60+op, (f->attack_rate << 4) |
203 (f->decay_rate << 0));
206 void adlib_update_group80(unsigned int op,struct adlib_fm_operator *f) {
207 adlib_write(0x80+op, (f->sustain_level << 4) |
208 (f->release_rate << 0));
211 void adlib_update_groupA0(unsigned int channel,struct adlib_fm_channel *ch) {
212 struct adlib_fm_operator *f = &ch->mod;
213 unsigned int x = (channel >= 9) ? 0x100 : 0;
214 adlib_write(0xA0+(channel%9)+x, f->f_number);
215 adlib_write(0xB0+(channel%9)+x, (f->key_on << 5) |
220 void adlib_update_groupC0(unsigned int channel,struct adlib_fm_channel *ch) {
221 struct adlib_fm_operator *f = &ch->mod;
222 unsigned int x = (channel >= 9) ? 0x100 : 0;
223 adlib_write(0xC0+(channel%9)+x, (f->feedback << 1) |
224 (f->connection << 0) |
231 void adlib_update_groupE0(unsigned int op,struct adlib_fm_operator *f) {
232 adlib_write(0xE0+op, (f->waveform << 0));
235 void adlib_update_operator(unsigned int op,struct adlib_fm_operator *f) {
236 adlib_update_group20(op,f);
237 adlib_update_group40(op,f);
238 adlib_update_group60(op,f);
239 adlib_update_group80(op,f);
240 adlib_update_groupE0(op,f);
243 void adlib_update_bd(struct adlib_reg_bd *b) {
244 adlib_write(0xBD, (b->am_depth << 7) |
245 (b->vibrato_depth << 6) |
246 (b->rythm_enable << 5) |
247 (b->bass_drum_on << 4) |
248 (b->snare_drum_on << 3) |
249 (b->tom_tom_on << 2) |
250 (b->cymbal_on << 1) |
251 (b->hi_hat_on << 0));
254 void adlib_apply_all() {
255 struct adlib_fm_operator *f;
259 for (ch=0;ch < adlib_fm_voices;ch++) {
260 f = &adlib_fm[ch].mod; op = adlib_voice_to_op[ch]; adlib_update_operator(op,f);
261 f = &adlib_fm[ch].car; op = adlib_voice_to_op[ch]+3; adlib_update_operator(op,f);
262 adlib_update_groupA0(ch,&adlib_fm[ch]);
263 adlib_update_groupC0(ch,&adlib_fm[ch]);
265 adlib_update_bd(&adlib_reg_bd);
268 double adlib_fm_op_to_freq(struct adlib_fm_operator *f) {
269 unsigned long t = (unsigned long)f->f_number * 49716UL;
270 return (double)t / (1UL << (20UL - (unsigned long)f->octave));
273 void adlib_freq_to_fm_op(struct adlib_fm_operator *f,double freq) {
276 freq *= (1UL << (20UL - (unsigned long)f->octave));
277 l = (unsigned long)freq / 49716UL;
283 while (l != 0UL && l < 256UL) {