3 * Adlib OPL2/OPL3 FM synthesizer chipset test program.
\r
4 * (C) 2010-2012 Jonathan Campbell.
\r
5 * Hackipedia DOS library.
\r
7 * This code is licensed under the LGPL.
\r
8 * <insert LGPL legal text here>
\r
10 * Compiles for intended target environments:
\r
11 * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
\r
13 * This test program uses a "text user interface" to allow you to play
\r
14 * with the OPL2/OPL3 chipset and it's parameters. Some "instruments"
\r
15 * are preset for you if you want to make noise faster.
\r
19 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
\r
28 #include <hw/vga/vga.h>
\r
29 #include <hw/dos/dos.h>
\r
30 #include <hw/8254/8254.h> /* 8254 timer */
\r
31 #include <hw/vga/vgagui.h>
\r
32 #include <hw/vga/vgatty.h>
\r
33 #include <hw/adlib/adlib.h>
\r
35 static unsigned int musical_scale[18] = {
\r
57 int main(int argc,char **argv) {
\r
58 int i,loop,redraw,c,cc,selector=0,redrawln=0,hselect=0,selectsub=0;
\r
62 printf("ADLIB FM test program\n");
\r
65 printf("Cannot init VGA\n");
\r
68 if (!init_adlib()) {
\r
69 printf("Cannot init library\n");
\r
75 /* for VGA: free up space if needed by going to 80x50 */
\r
76 if (adlib_fm_voices > 9)
\r
77 vga_bios_set_80x50_text();
\r
79 memset(adlib_fm,0,sizeof(adlib_fm));
\r
80 memset(&adlib_reg_bd,0,sizeof(adlib_reg_bd));
\r
81 for (i=0;i < adlib_fm_voices;i++) {
\r
82 struct adlib_fm_operator *f;
\r
83 f = &adlib_fm[i].mod;
\r
84 f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
\r
85 f = &adlib_fm[i].car;
\r
86 f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
\r
89 for (i=0;i < adlib_fm_voices;i++) {
\r
90 struct adlib_fm_operator *f;
\r
92 f = &adlib_fm[i].mod;
\r
93 f->mod_multiple = 1;
\r
94 f->total_level = 63 - 16;
\r
95 f->attack_rate = 15;
\r
97 f->sustain_level = 7;
\r
98 f->release_rate = 7;
\r
99 f->f_number = musical_scale[i%18];
\r
103 f = &adlib_fm[i].car;
\r
104 f->mod_multiple = 1;
\r
105 f->total_level = 63 - 16;
\r
106 f->attack_rate = 15;
\r
108 f->sustain_level = 7;
\r
109 f->release_rate = 7;
\r
117 vga_write_color(0x07);
\r
123 if (redraw || redrawln) {
\r
125 for (vga=vga_alpha_ram,cc=0;cc < (80*vga_height);cc++) *vga++ = 0x1E00 | 177;
\r
127 vga_write_color(0x1F);
\r
128 sprintf(tmp,"Adlib FM, %u-voice %s. Use Z & X to adj F10=PRESET F1=QUIET ",adlib_fm_voices,
\r
129 (adlib_flags & ADLIB_FM_OPL3) ? "OPL3" :
\r
130 (adlib_flags & ADLIB_FM_DUAL_OPL2) ? "Dual OPL2" : "OPL2");
\r
132 if (adlib_flags & ADLIB_FM_OPL3) vga_write("F2=OPL3 off ");
\r
135 if (redrawln || redraw) {
\r
136 struct adlib_reg_bd *bd = &adlib_reg_bd;
\r
137 static const char *hsel_str[18] = {
\r
138 "Amplitude modulatation",
\r
141 "Key scaling rate",
\r
142 "Modulator frequency multiple",
\r
143 "Level key scaling",
\r
153 "Connection (operator 1 -> operator 2)",
\r
155 "Channel mapping (OPL3)"
\r
158 vga_write_color(0x1A);
\r
161 sprintf(tmp,"AM=%u VB=%u RYTHM=%u BAS=%u SNA=%u TOM=%u CYM=%u HI=%u\n",
\r
175 vga_write(hsel_str[hselect]);
\r
178 vga_write_color(hselect == 0 ? 0x70 : 0x1E); vga_write("AM ");
\r
179 vga_write_color(hselect == 1 ? 0x70 : 0x1E); vga_write("VB ");
\r
180 vga_write_color(hselect == 2 ? 0x70 : 0x1E); vga_write("SUST ");
\r
181 vga_write_color(hselect == 3 ? 0x70 : 0x1E); vga_write("KSR ");
\r
182 vga_write_color(hselect == 4 ? 0x70 : 0x1E); vga_write("MMUL ");
\r
183 vga_write_color(hselect == 5 ? 0x70 : 0x1E); vga_write("LKS ");
\r
184 vga_write_color(hselect == 6 ? 0x70 : 0x1E); vga_write("TL ");
\r
185 vga_write_color(hselect == 7 ? 0x70 : 0x1E); vga_write("AR ");
\r
186 vga_write_color(hselect == 8 ? 0x70 : 0x1E); vga_write("DR ");
\r
187 vga_write_color(hselect == 9 ? 0x70 : 0x1E); vga_write("SL ");
\r
188 vga_write_color(hselect == 10 ? 0x70 : 0x1E); vga_write("RR ");
\r
189 vga_write_color(hselect == 11 ? 0x70 : 0x1E); vga_write("KEY ");
\r
190 vga_write_color(hselect == 12 ? 0x70 : 0x1E); vga_write("OCT ");
\r
191 vga_write_color(hselect == 13 ? 0x70 : 0x1E); vga_write("FNUM ");
\r
192 vga_write_color(hselect == 14 ? 0x70 : 0x1E); vga_write("FEED ");
\r
193 vga_write_color(hselect == 15 ? 0x70 : 0x1E); vga_write("CON ");
\r
194 vga_write_color(hselect == 16 ? 0x70 : 0x1E); vga_write("WV ");
\r
195 vga_write_color(hselect == 17 ? 0x70 : 0x1E); vga_write("ABCD ");
\r
197 for (i=0;i < adlib_fm_voices;i++) {
\r
198 struct adlib_fm_operator *f;
\r
201 f = &adlib_fm[i].mod;
\r
202 vga_moveto(0,5+i*2);
\r
203 freq = adlib_fm_op_to_freq(f);
\r
204 vga_write_color(i == selector && selectsub == 0 ? 0x70 : 0x1E);
\r
205 cc = sprintf(tmp,"%u %u %u %u %-2u %u %-2u %-2u %-2u %-2u %-2u %u %u %-4u %u %u %u %c%c%c%c %u %.1fHz ",
\r
206 f->am, f->vibrato, f->sustain, f->key_scaling_rate,
\r
207 f->mod_multiple, f->level_key_scale, f->total_level, f->attack_rate,
\r
208 f->decay_rate, f->sustain_level, f->release_rate, f->key_on,
\r
209 f->octave, f->f_number, f->feedback, f->connection,
\r
210 f->waveform, f->ch_a?'*':'-', f->ch_b?'*':'-', f->ch_c?'*':'-',
\r
211 f->ch_d?'*':'-', i+1, freq);
\r
214 f = &adlib_fm[i].car;
\r
215 vga_moveto(0,5+i*2+1);
\r
216 vga_write_color(i == selector && selectsub == 1 ? 0x70 : 0x1E);
\r
217 cc = sprintf(tmp,"%u %u %u %u %-2u %u %-2u %-2u %-2u %-2u %-2u %u CAR ",
\r
218 f->am, f->vibrato, f->sustain, f->key_scaling_rate,
\r
219 f->mod_multiple, f->level_key_scale, f->total_level, f->attack_rate,
\r
220 f->decay_rate, f->sustain_level, f->release_rate, f->waveform);
\r
231 if (c == 0) c = getch() << 8;
\r
236 else if (c == 0x3B00) { /* F1 */
\r
237 for (i=0;i < adlib_fm_voices;i++) {
\r
238 adlib_fm[i].mod.key_on = 0;
\r
239 adlib_fm[i].car.key_on = 0;
\r
240 adlib_update_groupA0(i,&adlib_fm[i]);
\r
244 else if (c == 0x3C00) { /* F2 */
\r
245 if (adlib_flags & ADLIB_FM_OPL3) {
\r
246 shutdown_adlib_opl3();
\r
251 else if (c == 0x4400) { /* F10 */
\r
252 unsigned short op = adlib_voice_to_op[selector];
\r
254 vga_write_color(0x07);
\r
258 vga_write("Choose an instrument to load into the channel:\n");
\r
259 vga_write(" 1. Violin 2. Piano 3. Harpsichord 4. Horn 5. Deep bass drum\n");
\r
260 vga_write(" 6. Small drum \n");
\r
266 adlib_fm[selector] =
\r
267 (adlib_flags & ADLIB_FM_OPL3 ?
\r
268 adlib_fm_preset_violin_opl3 : adlib_fm_preset_violin_opl2);
\r
270 adlib_fm[selector] = adlib_fm_preset_piano;
\r
272 adlib_fm[selector] = adlib_fm_preset_harpsichord;
\r
274 adlib_fm[selector] = adlib_fm_preset_horn;
\r
276 adlib_fm[selector] = adlib_fm_preset_deep_bass_drum;
\r
278 adlib_fm[selector] = adlib_fm_preset_small_drum;
\r
280 adlib_update_groupA0(selector,&adlib_fm[selector]);
\r
281 adlib_update_groupC0(selector,&adlib_fm[selector]);
\r
282 adlib_update_operator(op,&adlib_fm[selector].mod);
\r
283 adlib_update_operator(op+3,&adlib_fm[selector].car);
\r
287 else if (c == ' ') {
\r
288 adlib_fm[selector].mod.key_on ^= 1;
\r
289 adlib_update_groupA0(selector,&adlib_fm[selector]);
\r
292 else if (c == 'a') {
\r
293 if (hselect == 17) {
\r
294 struct adlib_fm_operator *f = &adlib_fm[selector].mod; f->ch_a ^= 1;
\r
295 adlib_update_groupC0(selector,&adlib_fm[selector]);
\r
298 adlib_reg_bd.am_depth ^= 1;
\r
299 adlib_update_bd(&adlib_reg_bd);
\r
303 else if (c == 'v') {
\r
304 adlib_reg_bd.vibrato_depth ^= 1;
\r
305 adlib_update_bd(&adlib_reg_bd);
\r
308 else if (c == 'r') {
\r
309 adlib_reg_bd.rythm_enable ^= 1;
\r
310 adlib_update_bd(&adlib_reg_bd);
\r
313 else if (c == 'b') {
\r
314 if (hselect == 17) {
\r
315 struct adlib_fm_operator *f = &adlib_fm[selector].mod; f->ch_b ^= 1;
\r
316 adlib_update_groupC0(selector,&adlib_fm[selector]);
\r
319 adlib_reg_bd.bass_drum_on ^= 1;
\r
320 adlib_update_bd(&adlib_reg_bd);
\r
324 else if (c == 's') {
\r
325 adlib_reg_bd.snare_drum_on ^= 1;
\r
326 adlib_update_bd(&adlib_reg_bd);
\r
329 else if (c == 't') {
\r
330 adlib_reg_bd.tom_tom_on ^= 1;
\r
331 adlib_update_bd(&adlib_reg_bd);
\r
334 else if (c == 'c') {
\r
335 if (hselect == 17) {
\r
336 struct adlib_fm_operator *f = &adlib_fm[selector].mod; f->ch_c ^= 1;
\r
337 adlib_update_groupC0(selector,&adlib_fm[selector]);
\r
340 adlib_reg_bd.cymbal_on ^= 1;
\r
341 adlib_update_bd(&adlib_reg_bd);
\r
345 else if (c == 'd') {
\r
346 if (hselect == 17) {
\r
347 struct adlib_fm_operator *f = &adlib_fm[selector].mod; f->ch_d ^= 1;
\r
348 adlib_update_groupC0(selector,&adlib_fm[selector]);
\r
354 else if (c == 'h') {
\r
355 adlib_reg_bd.hi_hat_on ^= 1;
\r
356 adlib_update_bd(&adlib_reg_bd);
\r
359 else if (c == 'z' || c == 'Z' || c == 'x' || c == 'X') {
\r
360 struct adlib_fm_operator *f;
\r
361 int dec = tolower(c) == 'z';
\r
362 unsigned short operator;
\r
365 case 11:selectsub = 0;
\r
369 if (selectsub) f = &adlib_fm[selector].car;
\r
370 else f = &adlib_fm[selector].mod;
\r
371 operator = adlib_voice_to_op[selector] + (selectsub*3);
\r
374 case 0: f->am ^= 1; adlib_update_group20(operator,f); break;
\r
375 case 11: f->key_on ^= 1; adlib_update_groupA0(selector,&adlib_fm[selector]); break;
\r
376 case 1: f->vibrato ^= 1; adlib_update_group20(operator,f); break;
\r
377 case 2: f->sustain ^= 1; adlib_update_group20(operator,f); break;
\r
378 case 15: f->connection ^= 1; adlib_update_group20(operator,f); break;
\r
379 case 3: f->key_scaling_rate ^= 1; adlib_update_group20(operator,f); break;
\r
381 case 4: if (dec) f->mod_multiple--; else f->mod_multiple++;
\r
382 adlib_update_group20(operator,f); break;
\r
383 case 5: if (dec) f->level_key_scale--; else f->level_key_scale++;
\r
384 adlib_update_group40(operator,f); break;
\r
385 case 6: if (dec) f->total_level--; else f->total_level++;
\r
386 adlib_update_group40(operator,f); break;
\r
387 case 7: if (dec) f->attack_rate--; else f->attack_rate++;
\r
388 adlib_update_group60(operator,f); break;
\r
389 case 8: if (dec) f->decay_rate--; else f->decay_rate++;
\r
390 adlib_update_group60(operator,f); break;
\r
391 case 9: if (dec) f->sustain_level--; else f->sustain_level++;
\r
392 adlib_update_group80(operator,f); break;
\r
393 case 10: if (dec) f->release_rate--; else f->release_rate++;
\r
394 adlib_update_group80(operator,f); break;
\r
395 case 12: if (dec) f->octave--; else f->octave++;
\r
396 adlib_update_groupA0(selector,&adlib_fm[selector]); break;
\r
397 case 13: if (dec) f->f_number--; else f->f_number++;
\r
398 adlib_update_groupA0(selector,&adlib_fm[selector]); break;
\r
399 case 14: if (dec) f->feedback--; else f->feedback++;
\r
400 adlib_update_groupC0(selector,&adlib_fm[selector]); break;
\r
401 case 16: if (dec) f->waveform--; else f->waveform++;
\r
402 adlib_update_groupE0(operator,f); break;
\r
407 else if (c == 0x4800) {
\r
408 if (selectsub && !(hselect >= 11 && hselect <= 15)) {
\r
412 else if (selector > 0) {
\r
413 selectsub = !(hselect >= 11 && hselect <= 15);
\r
418 else if (c == 0x4B00) {
\r
424 else if (c == 0x4D00) {
\r
425 if (hselect < 17) {
\r
430 else if (c == 0x5000) {
\r
431 if (selectsub == 0 && !(hselect >= 11 && hselect <= 15)) {
\r
435 else if ((selector+1) < adlib_fm_voices) {
\r