]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/allg_snd/allg_snd.c
keep Changelog in cvs (and use --accum)
[btb/d2x.git] / arch / dos / allg_snd / allg_snd.c
1 /*
2  * Allegro Sound library support routines
3  * Arne de Bruijn
4  */
5
6 #include <go32.h>
7 #include <dpmi.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "cfile.h"
11 #include "internal.h"
12 #include <sys/stat.h>
13 #include "error.h"
14 #include "timer.h"
15 #include "d_io.h"
16
17 extern int digi_timer_rate;
18 int retrace_count;
19 char allegro_error[80]="";
20
21 #define TIMERS_PER_SECOND     1193181L
22 #define MSEC_TO_TIMER(x)      ((long)(x) * (TIMERS_PER_SECOND / 1000))
23 #define MAX_TIMERS      16
24 static struct {                           /* list of active callbacks */
25    void ((*proc)());
26    long speed;
27    long counter;
28 } my_int_queue[MAX_TIMERS];
29 static int find_timer_slot(void (*proc)())
30 {
31    int x;
32
33    for (x=0; x<MAX_TIMERS; x++)
34       if (my_int_queue[x].proc == proc)
35          return x;
36
37    return -1;
38 }
39 int install_int_ex(void (*proc)(), long speed)
40 {
41    int x;
42 #if 0
43    if (!timer_installed) {
44       /* we are not alive yet: flag this callback to be started later */
45       if (waiting_list_size >= MAX_TIMERS)
46          return -1;
47
48       waiting_list[waiting_list_size].proc = proc;
49       waiting_list[waiting_list_size].speed = speed;
50       waiting_list_size++;
51       return 0;
52    }
53 #endif
54    x = find_timer_slot(proc);          /* find the handler position */
55
56    if (x < 0)                          /* if not there, find free slot */
57       x = find_timer_slot(NULL);
58
59    if (x < 0)                          /* are there any free slots? */
60       return -1;
61
62    if (proc != my_int_queue[x].proc) { /* add new entry */
63       my_int_queue[x].counter = speed;
64       my_int_queue[x].proc = proc; 
65    }
66    else {                              /* alter speed of existing entry */
67       my_int_queue[x].counter -= my_int_queue[x].speed;
68       my_int_queue[x].counter += speed;
69    }
70
71    my_int_queue[x].speed = speed;
72
73    return 0;
74 }
75 int install_int(void (*proc)(), long speed)
76 {
77    return install_int_ex(proc, MSEC_TO_TIMER(speed));
78 }
79 void remove_int(void (*proc)())
80 {
81    int x = find_timer_slot(proc);
82
83    if (x >= 0) {
84       my_int_queue[x].proc = NULL;
85       my_int_queue[x].speed = 0;
86       my_int_queue[x].counter = 0;
87    }
88 }
89
90 void allg_snd_timer() {
91         int x;
92         for (x=0; x<MAX_TIMERS; x++) {
93                 my_int_queue[x].counter -= digi_timer_rate;
94                 while ((my_int_queue[x].proc) && (my_int_queue[x].counter <= 0)) {
95                            my_int_queue[x].counter += my_int_queue[x].speed;
96                            my_int_queue[x].proc();
97                 }
98         }
99         retrace_count++;
100 }
101 END_OF_FUNCTION(allg_snd_timer)
102
103 void _add_exit_func(void (*func)()) {
104         atexit(func);
105 }
106 void _remove_exit_func(void (*func)()) {
107 }
108 void _unlock_dpmi_data(void *addr, int size)
109 {
110    unsigned long baseaddr;
111    __dpmi_meminfo mem;
112
113    __dpmi_get_segment_base_address(_go32_my_ds(), &baseaddr);
114
115    mem.address = baseaddr + (unsigned long)addr;
116    mem.size = size;
117
118    __dpmi_unlock_linear_region(&mem );
119 }
120
121 struct oldirq {
122         int intnum;
123         _go32_dpmi_seginfo old;
124         _go32_dpmi_seginfo new;
125 };
126
127 //added/killed on 10/27/98 by adb.  moved to comm/irq.c
128 //-killed- struct oldirq saveirq={-1};
129
130 //-killed- int _install_irq(int intnum, int (*func)()) {
131 //-killed-     if (saveirq.intnum != -1)
132 //-killed-         return 1;
133 //-killed-     saveirq.intnum=intnum;
134 //-killed-     saveirq.new.pm_offset = (int)func;
135 //-killed-     saveirq.new.pm_selector = _my_cs();
136 //-killed-     _go32_dpmi_get_protected_mode_interrupt_vector(intnum, &saveirq.old);
137 //-killed-     _go32_dpmi_allocate_iret_wrapper(&saveirq.new);
138 //-killed-     _go32_dpmi_set_protected_mode_interrupt_vector(intnum, &saveirq.new);
139 //-killed-     return 0;
140 //-killed- }
141 //-killed- 
142 //-killed- void _remove_irq(int intnum) {
143 //-killed-            _go32_dpmi_set_protected_mode_interrupt_vector(intnum, &saveirq.old);
144 //-killed-            _go32_dpmi_free_iret_wrapper(&saveirq.new);
145 //-killed-            saveirq.intnum = -1;
146 //-killed- }
147 //end this section kill - adb
148
149 static unsigned char *conv_delta(unsigned char *data, unsigned char *dataend) {
150     unsigned char *p;
151     unsigned long delta = 0;
152     int shift = 0;
153
154     p = data;
155     while ((p < dataend) && !(*p & 0x80)) {
156         delta += *(p++) << shift;
157         shift += 7;
158     }
159     if (p == dataend)
160         return NULL;
161     delta += (*(p++) & 0x7f) << shift;
162
163     data = p;
164     shift = 0;
165     while ((delta > 0) || (shift == 0)) {
166         *(--p) = (delta & 127) | shift;
167         delta >>= 7;
168         shift = 128;
169     }
170     return data;
171 }
172
173 /*
174  * read a MIDI type variabele length number
175  */
176 static unsigned char *read_var(unsigned char *data, unsigned char *dataend,
177  unsigned long *value) {
178     unsigned long v = 0;
179
180     while ((data < dataend) && (*data & 0x80))
181         v = (v << 7) + (*(data++) & 0x7f);
182     if (data == dataend)
183         return NULL;
184     v = (v << 7) + *(data++);
185     if (value) *value = v;
186     return data;
187 }
188
189 static int trans_data(unsigned char *data, int size) {
190     static int cmdlen[7]={3,3,3,3,2,2,3};
191     unsigned char *dataend = data + size;
192     unsigned long v;
193
194     while (data < dataend) {
195         if (!(data = conv_delta(data, dataend)))
196             return 1;
197
198         if (data == dataend)
199             return 1; /* need something after delta */
200
201         if (*data < 0x80)
202             return 1; /* invalid command */
203         if (*data < 0xf0) {
204             data += cmdlen[((*data) >> 4) - 8];
205         } else if (*data == 0xff) {
206             data += 2;
207             if (data >= dataend)
208                 return 1;
209             if (!(data = read_var(data, dataend, &v)))
210                 return 1;
211             data += v;
212         } else /* sysex -> error */
213             return 1;
214     }
215     return (data != dataend); /* processed as many as received? */
216 }
217
218 /*
219  * load HMP file into Allegro MIDI structure by translating the deltas
220  * and adding tempo information
221  */
222 MIDI *load_hmp(char *filename) {
223     static unsigned char hmp_tempo[7] =
224      {0x00, 0xff, 0x51, 0x03, 0x0f, 0x42, 0x40};
225     int c;
226     char buf[256];
227     long data;
228     CFILE *fp;
229     MIDI *midi;
230     int num_tracks;
231     unsigned char *p;
232
233     // try .mid first
234     removeext(filename, buf);
235     strcat(buf, ".mid");
236     if ((midi = load_midi(buf)))
237         return midi;
238     if (!(fp = cfopen(filename, "rb")))
239             return NULL;
240
241     midi = malloc(sizeof(MIDI));              /* get some memory */
242     if (!midi) {
243         cfclose(fp);
244         return NULL;
245     }
246
247     for (c=0; c<MIDI_TRACKS; c++) {
248         midi->track[c].data = NULL;
249         midi->track[c].len = 0;
250     }
251
252     if ((cfread(buf, 1, 8, fp) != 8) || (memcmp(buf, "HMIMIDIP", 8)))
253         goto err;
254
255     if (cfseek(fp, 0x30, SEEK_SET))
256         goto err;
257
258     if (cfread(&num_tracks, 4, 1, fp) != 1)
259         goto err;
260
261     if ((num_tracks < 1) || (num_tracks > MIDI_TRACKS))
262         goto err;
263
264     midi->divisions = 120;
265
266     if (cfseek(fp, 0x308, SEEK_SET))
267         goto err;
268
269     for (c=0; c<num_tracks; c++) {            /* read each track */
270         if ((cfseek(fp, 4, SEEK_CUR)) || (cfread(&data, 4, 1, fp) != 1))
271             goto err;
272
273         data -= 12;
274
275         if (c == 0)  /* track 0: reserve length for tempo */
276             data += sizeof(hmp_tempo);
277
278         midi->track[c].len = data;
279
280         if (!(p = midi->track[c].data = malloc(data)))  /* allocate memory */
281             goto err;
282
283         if (c == 0) { /* track 0: add tempo */
284             memcpy(p, hmp_tempo, sizeof(hmp_tempo));
285             p += sizeof(hmp_tempo);
286             data -= sizeof(hmp_tempo);
287         }
288                                              /* finally, read track data */
289         if ((cfseek(fp, 4, SEEK_CUR)) || (cfread(p, data, 1, fp) != 1))
290             goto err;
291
292         if (trans_data(p, data)) /* translate deltas hmp -> midi */
293             goto err;
294    }
295
296    cfclose(fp);
297    lock_midi(midi);
298    return midi;
299
300 err:
301    cfclose(fp);
302    destroy_midi(midi);
303    return NULL;
304 }
305
306 char *pack_fgets(char *p, int max, PACKFILE *f) {
307    int c;
308
309    if (pack_feof(f)) {
310       p[0] = 0;
311       return NULL;
312    }
313
314    for (c=0; c<max-1; c++) {
315       p[c] = pack_getc(f);
316       if (p[c] == '\r')
317          c--;
318       else if (p[c] == '\n')
319          break;
320    }
321
322    p[c] = 0;
323
324    if (ferror(f))
325       return NULL;
326    else
327       return p;
328 }
329
330 char *get_extension(const char *s) {
331     char *p;
332     if ((p = strrchr(s, '.')))
333         return p+1;
334     return strchr(s, 0);
335 }
336 char *get_filename(const char *s) {
337     char *p;
338     if ((p = strrchr(s, '\\')))
339         return p+1;
340     if ((p = strrchr(s, '/')))
341         return p+1;
342     return (char *)s;
343 }
344 long file_size(const char *n) {
345         struct stat st;
346         if (stat(n, &st))
347                 return -1;
348         return st.st_size;
349 }
350 void put_backslash(char *n) {
351         char *p;
352         if(((p=strchr(n,0))>=p) && (*(p-1)!='/') && (*(p-1)!='\\')
353          && (*(p-1)!=':')) { *(p++)='/'; *p=0;}
354 }
355
356 void allg_snd_init() {
357     if (LOCK_VARIABLE(my_int_queue) ||
358         LOCK_VARIABLE(digi_timer_rate) ||
359         LOCK_VARIABLE(retrace_count) ||
360         LOCK_FUNCTION(allg_snd_timer))
361         Error("Error locking sound timer");
362     timer_set_function(allg_snd_timer);
363 }
364
365 // return true if using the digmid driver
366 int allegro_using_digmid() {
367     return get_config_int("sound", "midi_card", MIDI_AUTODETECT) == MIDI_DIGMID;
368 }