]> 4ch.mooo.com Git - 16.git/blob - src/imfplay.c
p16 is being worked on a bunch by me wwww [16_ca needs huge amounts of work and I...
[16.git] / src / imfplay.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 "src/lib/16_head.h"
16 #include "src/lib/16_tail.h"
17 #include "src/lib/16_pm.h"
18 #include "src/lib/16_ca.h"
19 #include "src/lib/16_mm.h"
20 #include "src/lib/16_hc.h"
21 #include "src/lib/16_dbg.h"
22 // #include <stdio.h>
23 // #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
24 // #include <stdlib.h>
25 // #include <string.h>
26 // #include <unistd.h>
27 // #include <malloc.h>
28 // #include <ctype.h>
29 // #include <fcntl.h>
30 // #include <math.h>
31 // #include <dos.h>
32
33 #include <hw/vga/vga.h>
34 #include <hw/dos/dos.h>
35 #include <hw/8254/8254.h>               /* 8254 timer */
36 #include <hw/8259/8259.h>
37 #include <hw/adlib/adlib.h>
38
39 static void (interrupt *old_irq0)();
40 static volatile unsigned long irq0_ticks=0;
41 static volatile unsigned int irq0_cnt=0,irq0_add=0,irq0_max=0;
42
43 #pragma pack(push,1)
44 struct imf_entry {
45         uint8_t         reg,data;
46         uint16_t        delay;
47 };
48 #pragma pack(pop)
49
50 static struct imf_entry*        imf_music=NULL;
51 static struct imf_entry*        imf_play_ptr=NULL;
52 static struct imf_entry*        imf_music_end=NULL;
53 static uint16_t                 imf_delay_countdown=0;
54
55 #define PRINTBB {\
56         printf("-------------------------------------------------------------------------------\n");\
57         printf("buffer:\n");\
58         printf("bigbuffer       %Fp\t", gvar->ca.audiosegs[0]);\
59         printf("&%Fp\n", MEMPTR gvar->ca.audiosegs[0]);\
60         printf("imf_music       %Fp\t", imf_music);\
61         printf("&%Fp\n", imf_music);\
62         printf("imf_play_ptr    %Fp\t", imf_play_ptr);\
63         printf("&%Fp\n", imf_play_ptr);\
64         printf("imf_music_end   %Fp\t", imf_music_end);\
65         printf("&%Fp\n", imf_music_end);\
66         printf("-------------------------------------------------------------------------------\n");\
67 }
68
69 void imf_free_music(global_game_variables_t *gvar) {
70         if (imf_music) free(imf_music);
71         MM_FreePtr(MEMPTR gvar->ca.audiosegs[0], gvar);
72         imf_music = imf_play_ptr = imf_music_end = NULL;
73         imf_delay_countdown = 0;
74 }
75
76 int imf_load_music(const char *path, global_game_variables_t *gvar) {
77         unsigned long len;
78         unsigned char buf[8];
79         int fd;
80
81         imf_free_music(gvar);
82
83         fd = open(path,O_RDONLY|O_BINARY);
84         if (fd < 0) return 0;
85
86         len = lseek(fd,0,SEEK_END);
87         lseek(fd,0,SEEK_SET);
88         read(fd,buf,2);
89         if (buf[0] != 0 || buf[1] != 0) // type 1 IMF
90                 len = *((uint16_t*)buf);
91         else
92                 lseek(fd,0,SEEK_SET);
93
94         if (len == 0 || len > 65535UL) {
95                 close(fd);
96                 return 0;
97         }
98         len -= len & 3;
99
100 //      imf_music = malloc(len);
101         MM_GetPtr(MEMPTR gvar->ca.audiosegs[0],len, gvar);
102         imf_music = (struct imf_entry *)gvar->ca.audiosegs[0];
103         if (imf_music == NULL) {
104                 close(fd);
105                 return 0;
106         }
107         read(fd,imf_music,len);
108         close(fd);
109
110         imf_play_ptr = imf_music;
111         imf_music_end = imf_music + (len >> 2UL);
112         PRINTBB;
113         return 1;
114 }
115
116 /* WARNING: subroutine call in interrupt handler. make sure you compile with -zu flag for large/compact memory models */
117 void interrupt irq0() {
118         irq0_ticks++;
119         if ((irq0_cnt += irq0_add) >= irq0_max) {
120                 irq0_cnt -= irq0_max;
121                 old_irq0();
122         }
123         else {
124                 p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
125         }
126 }
127
128 void imf_tick() {
129         if (imf_delay_countdown == 0) {
130                 do {
131                         adlib_write(imf_play_ptr->reg,imf_play_ptr->data);
132                         imf_delay_countdown = imf_play_ptr->delay;
133                         imf_play_ptr++;
134                         if (imf_play_ptr == imf_music_end)
135                         {
136                                 printf("replay\n");
137                                 imf_play_ptr = imf_music;
138                         }
139                 } while (imf_delay_countdown == 0);
140         }
141         else {
142                 imf_delay_countdown--;
143         }
144 }
145
146 void adlib_shut_up() {
147         int i;
148
149         memset(adlib_fm,0,sizeof(adlib_fm));
150         memset(&adlib_reg_bd,0,sizeof(adlib_reg_bd));
151         for (i=0;i < adlib_fm_voices;i++) {
152                 struct adlib_fm_operator *f;
153                 f = &adlib_fm[i].mod;
154                 f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
155                 f = &adlib_fm[i].car;
156                 f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
157         }
158
159         for (i=0;i < adlib_fm_voices;i++) {
160                 struct adlib_fm_operator *f;
161
162                 f = &adlib_fm[i].mod;
163                 f->mod_multiple = 1;
164                 f->total_level = 63 - 16;
165                 f->attack_rate = 15;
166                 f->decay_rate = 4;
167                 f->sustain_level = 0;
168                 f->release_rate = 8;
169                 f->f_number = 400;
170                 f->sustain = 1;
171                 f->octave = 4;
172                 f->key_on = 0;
173
174                 f = &adlib_fm[i].car;
175                 f->mod_multiple = 1;
176                 f->total_level = 63 - 16;
177                 f->attack_rate = 15;
178                 f->decay_rate = 4;
179                 f->sustain_level = 0;
180                 f->release_rate = 8;
181                 f->f_number = 0;
182                 f->sustain = 1;
183                 f->octave = 0;
184                 f->key_on = 0;
185         }
186
187         adlib_apply_all();
188 }
189
190 void main(int argc,char **argv) {
191         static global_game_variables_t gvar;
192         unsigned long tickrate = 700;
193         unsigned long ptick;
194         int c;
195 #ifdef __DEBUG_CA__
196         dbg_debugca=1;
197 #endif
198 #ifdef __DEBUG_MM_
199         dbg_debugmm=1;
200 #endif
201         MM_Startup(&gvar);
202         PM_Startup(&gvar); PM_CheckMainMem(&gvar); PM_UnlockMainMem(&gvar);
203         CA_Startup(&gvar);
204         printf("ADLIB FM test program IMFPLAY\n");
205         if (argc < 2) {
206                 printf("You must specify an IMF file to play\n");
207                 return;
208         }
209
210         if (!init_adlib()) {
211                 printf("Cannot init library\n");
212                 return;
213         }
214         if (!probe_8254()) { /* we need the timer to keep time with the music */
215                 printf("8254 timer not found\n");
216                 return;
217         }
218
219         if (!imf_load_music(argv[1], &gvar)) {
220                 printf("Failed to load IMF Music\n");
221                 return;
222         }
223
224         write_8254_system_timer(T8254_REF_CLOCK_HZ / tickrate);
225         irq0_cnt = 0;
226         irq0_add = 182;
227         irq0_max = 1000; /* about 18.2Hz */
228         old_irq0 = _dos_getvect(8);/*IRQ0*/
229         _dos_setvect(8,irq0);
230
231         adlib_shut_up();
232         shutdown_adlib_opl3(); // NTS: Apparently the music won't play otherwise
233         _cli();
234         irq0_ticks = ptick = 0;
235         _sti();
236
237         while (1) {
238                 unsigned long adv;
239
240                 _cli();
241                 adv = irq0_ticks - ptick;
242                 if (adv >= 100UL) adv = 100UL;
243                 ptick = irq0_ticks;
244                 _sti();
245
246                 while (adv != 0) {
247                         imf_tick();
248                         adv--;
249                 }
250
251                 if (kbhit()) {
252                         c = getch();
253                         if (c == 0) c = getch() << 8;
254
255                         if (c == 27) {
256                                 break;
257                         }
258                 }
259         }
260 //      printf("contents of the imf_music\n[\n%s\n]\n", imf_music);
261
262         imf_free_music(&gvar);
263         adlib_shut_up();
264         shutdown_adlib();
265         _dos_setvect(8,old_irq0);
266         write_8254_system_timer(0);/* back to normal 18.2Hz */
267         PM_Shutdown(&gvar);
268         CA_Shutdown(&gvar);
269         MM_Shutdown(&gvar);
270 }