OSDN Git Service

added dro2imf to .gitignore
[proj16/16.git] / src / i0fplay.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 <stdio.h>
16 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <malloc.h>
21 #include <ctype.h>
22 #include <fcntl.h>
23 #include <math.h>
24 #include <dos.h>
25
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>
31
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;
35
36 #pragma pack(push,1)
37 struct imf_entry {
38         uint8_t         reg,data;
39         uint16_t        delay;
40 };
41 #pragma pack(pop)
42
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;
47
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;
52 }
53
54 int imf_load_music(const char *path) {
55         unsigned char buf[8];
56         unsigned long len;
57         int fd;
58
59         imf_free_music();
60
61         fd = open(path,O_RDONLY|O_BINARY);
62         if (fd < 0) return 0;
63
64         len = lseek(fd,0,SEEK_END);
65         lseek(fd,0,SEEK_SET);
66         read(fd,buf,2);
67         if (buf[0] != 0 || buf[1] != 0) // type 1 IMF
68                 len = *((uint16_t*)buf);
69         else
70                 lseek(fd,0,SEEK_SET);
71
72         if (len == 0 || len > 65535UL) {
73                 close(fd);
74                 return 0;
75         }
76         len -= len & 3;
77
78         imf_music = malloc(len);
79         if (imf_music == NULL) {
80                 close(fd);
81                 return 0;
82         }
83         read(fd,imf_music,len);
84         close(fd);
85
86         imf_play_ptr = imf_music;
87         imf_music_end = imf_music + (len >> 2UL);
88         return 1;
89 }
90
91 /* WARNING: subroutine call in interrupt handler. make sure you compile with -zu flag for large/compact memory models */
92 void interrupt irq0() {
93         irq0_ticks++;
94         if ((irq0_cnt += irq0_add) >= irq0_max) {
95                 irq0_cnt -= irq0_max;
96                 old_irq0();
97         }
98         else {
99                 p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
100         }
101 }
102
103 void imf_tick() {
104         if (imf_delay_countdown == 0) {
105                 do {
106                         adlib_write(imf_play_ptr->reg,imf_play_ptr->data);
107                         imf_delay_countdown = imf_play_ptr->delay;
108                         imf_play_ptr++;
109                         if (imf_play_ptr == imf_music_end)
110                                 imf_play_ptr = imf_music;
111                 } while (imf_delay_countdown == 0);
112         }
113         else {
114                 imf_delay_countdown--;
115         }
116 }
117
118 void adlib_shut_up() {
119         int i;
120
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;
129         }
130
131         for (i=0;i < adlib_fm_voices;i++) {
132                 struct adlib_fm_operator *f;
133
134                 f = &adlib_fm[i].mod;
135                 f->mod_multiple = 1;
136                 f->total_level = 63 - 16;
137                 f->attack_rate = 15;
138                 f->decay_rate = 4;
139                 f->sustain_level = 0;
140                 f->release_rate = 8;
141                 f->f_number = 400;
142                 f->sustain = 1;
143                 f->octave = 4;
144                 f->key_on = 0;
145
146                 f = &adlib_fm[i].car;
147                 f->mod_multiple = 1;
148                 f->total_level = 63 - 16;
149                 f->attack_rate = 15;
150                 f->decay_rate = 4;
151                 f->sustain_level = 0;
152                 f->release_rate = 8;
153                 f->f_number = 0;
154                 f->sustain = 1;
155                 f->octave = 0;
156                 f->key_on = 0;
157         }
158
159         adlib_apply_all();
160 }
161
162 int main(int argc,char **argv) {
163         unsigned long tickrate = 700;
164         unsigned long ptick;
165         int c;
166
167         printf("ADLIB FM test program IMFPLAY\n");
168         if (argc < 2) {
169                 printf("You must specify an IMF file to play\n");
170                 return 1;
171         }
172
173         if (!init_adlib()) {
174                 printf("Cannot init library\n");
175                 return 1;
176         }
177         if (!probe_8254()) { /* we need the timer to keep time with the music */
178                 printf("8254 timer not found\n");
179                 return 1;
180         }
181
182         if (!imf_load_music(argv[1])) {
183                 printf("Failed to load IMF Music\n");
184                 return 1;
185         }
186
187         write_8254_system_timer(T8254_REF_CLOCK_HZ / tickrate);
188         irq0_cnt = 0;
189         irq0_add = 182;
190         irq0_max = 1000; /* about 18.2Hz */
191         old_irq0 = _dos_getvect(8);/*IRQ0*/
192         _dos_setvect(8,irq0);
193
194         adlib_shut_up();
195         shutdown_adlib_opl3(); // NTS: Apparently the music won't play otherwise
196         _cli();
197         irq0_ticks = ptick = 0;
198         _sti();
199
200         while (1) {
201                 unsigned long adv;
202
203                 _cli();
204                 adv = irq0_ticks - ptick;
205                 if (adv >= 100UL) adv = 100UL;
206                 ptick = irq0_ticks;
207                 _sti();
208
209                 while (adv != 0) {
210                         imf_tick();
211                         adv--;
212                 }
213
214                 if (kbhit()) {
215                         c = getch();
216                         if (c == 0) c = getch() << 8;
217
218                         if (c == 27) {
219                                 break;
220                         }
221                 }
222         }
223
224         imf_free_music();
225         adlib_shut_up();
226         shutdown_adlib();
227         _dos_setvect(8,old_irq0);
228         write_8254_system_timer(0); /* back to normal 18.2Hz */
229         return 0;
230 }
231