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.
8 * This code is licensed under the LGPL.
9 * <insert LGPL legal text here>
11 * Compiles for intended target environments:
12 * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
16 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
26 #include <hw/vga/vga.h>
27 #include <hw/dos/dos.h>
28 #include <hw/8254/8254.h> /* 8254 timer */
29 #include <hw/8259/8259.h>
30 #include <hw/adlib/adlib.h>
32 static void (interrupt *old_irq0)();
33 static volatile unsigned long irq0_ticks=0;
34 static volatile unsigned int irq0_cnt=0,irq0_add=0,irq0_max=0;
43 static struct imf_entry* imf_music=NULL;
44 static struct imf_entry* imf_play_ptr=NULL;
45 static struct imf_entry* imf_music_end=NULL;
46 static uint16_t imf_delay_countdown=0;
48 void imf_free_music() {
49 if (imf_music) free(imf_music);
50 imf_music = imf_play_ptr = imf_music_end = NULL;
51 imf_delay_countdown = 0;
54 int imf_load_music(const char *path) {
61 fd = open(path,O_RDONLY|O_BINARY);
64 len = lseek(fd,0,SEEK_END);
67 if (buf[0] != 0 || buf[1] != 0) // type 1 IMF
68 len = *((uint16_t*)buf);
72 if (len == 0 || len > 65535UL) {
78 imf_music = malloc(len);
79 if (imf_music == NULL) {
83 read(fd,imf_music,len);
86 imf_play_ptr = imf_music;
87 imf_music_end = imf_music + (len >> 2UL);
91 /* WARNING: subroutine call in interrupt handler. make sure you compile with -zu flag for large/compact memory models */
92 void interrupt irq0() {
94 if ((irq0_cnt += irq0_add) >= irq0_max) {
99 p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
104 if (imf_delay_countdown == 0) {
106 adlib_write(imf_play_ptr->reg,imf_play_ptr->data);
107 imf_delay_countdown = imf_play_ptr->delay;
109 if (imf_play_ptr == imf_music_end)
110 imf_play_ptr = imf_music;
111 } while (imf_delay_countdown == 0);
114 imf_delay_countdown--;
118 void adlib_shut_up() {
121 memset(adlib_fm,0,sizeof(adlib_fm));
122 memset(&adlib_reg_bd,0,sizeof(adlib_reg_bd));
123 for (i=0;i < adlib_fm_voices;i++) {
124 struct adlib_fm_operator *f;
125 f = &adlib_fm[i].mod;
126 f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
127 f = &adlib_fm[i].car;
128 f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
131 for (i=0;i < adlib_fm_voices;i++) {
132 struct adlib_fm_operator *f;
134 f = &adlib_fm[i].mod;
136 f->total_level = 63 - 16;
139 f->sustain_level = 0;
146 f = &adlib_fm[i].car;
148 f->total_level = 63 - 16;
151 f->sustain_level = 0;
162 int main(int argc,char **argv) {
163 unsigned long tickrate = 700;
167 printf("ADLIB FM test program IMFPLAY\n");
169 printf("You must specify an IMF file to play\n");
174 printf("Cannot init library\n");
177 if (!probe_8254()) { /* we need the timer to keep time with the music */
178 printf("8254 timer not found\n");
182 if (!imf_load_music(argv[1])) {
183 printf("Failed to load IMF Music\n");
187 write_8254_system_timer(T8254_REF_CLOCK_HZ / tickrate);
190 irq0_max = 1000; /* about 18.2Hz */
191 old_irq0 = _dos_getvect(8);/*IRQ0*/
192 _dos_setvect(8,irq0);
195 shutdown_adlib_opl3(); // NTS: Apparently the music won't play otherwise
197 irq0_ticks = ptick = 0;
204 adv = irq0_ticks - ptick;
205 if (adv >= 100UL) adv = 100UL;
216 if (c == 0) c = getch() << 8;
227 _dos_setvect(8,old_irq0);
228 write_8254_system_timer(0); /* back to normal 18.2Hz */