]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/digi.c
use the orientation parameter of g3_draw_bitmap
[btb/d2x.git] / arch / dos / digi.c
1 /*
2  *
3  * DOS digital audio support
4  *
5  *
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include <conf.h>
10 #endif
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15
16 #include "pstypes.h"
17 #include "dxxerror.h"
18 #include "mono.h"
19 #include "fix.h"
20 #include "gr.h" // needed for piggy.h
21 #include "inferno.h"
22
23
24 int digi_sample_rate = SAMPLE_RATE_11K;
25 int digi_timer_rate                                     = 9943;                 // rate for the timer to go off to handle the driver system (120 Hz)
26
27 //edited 05/17/99 Matt Mueller - added ifndef NO_ASM
28 //added on 980905 by adb to add inline fixmul for mixer on i386
29 #ifndef NO_ASM
30 #ifdef __i386__
31 #define do_fixmul(x,y)                          \
32 ({                                              \
33         int _ax, _dx;                           \
34         asm("imull %2\n\tshrdl %3,%1,%0"        \
35             : "=a"(_ax), "=d"(_dx)              \
36             : "rm"(y), "i"(16), "0"(x));        \
37         _ax;                                    \
38 })
39 extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); }
40 #endif
41 #endif
42 //end edit by adb
43 //end edit -MM
44
45 //changed on 980905 by adb to increase number of concurrent sounds
46 #define MAX_SOUND_SLOTS 32
47 //end changes by adb
48 #define SOUND_BUFFER_SIZE 512
49
50 #define MIN_VOLUME 10
51
52 /* This table is used to add two sound values together and pin
53  * the value to avoid overflow.  (used with permission from ARDI)
54  * DPH: Taken from SDL/src/SDL_mixer.c.
55  */
56 static const unsigned char mix8[] =
57 {
58   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
70   0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
71   0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
72   0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
73   0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
74   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
75   0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
76   0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
77   0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
78   0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
79   0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
80   0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
81   0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
82   0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
83   0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
84   0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
85   0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
86   0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
87   0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
88   0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
89   0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
90   0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
91   0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
92   0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF,
93   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
94   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
95   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
96   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
97   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
98   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
99   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
100   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
101   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
102   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
103   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
104   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
105 };
106
107
108 //added/changed on 980905 by adb to make sfx volume work, on 990221 by adb changed F1_0 to F1_0 / 2
109 #define SOUND_MAX_VOLUME (F1_0 / 2)
110
111 int digi_volume = SOUND_MAX_VOLUME;
112 //end edit by adb
113
114 static int Digi_initialized = 0;
115
116 struct sound_slot {
117  int soundno;
118  int playing;   // Is there a sample playing on this channel?
119  int looped;    // Play this sample looped?
120  fix pan;       // 0 = far left, 1 = far right
121  fix volume;    // 0 = nothing, 1 = fully on
122  //changed on 980905 by adb from char * to unsigned char * 
123  unsigned char *samples;
124  //end changes by adb
125  unsigned int length; // Length of the sample
126  unsigned int position; // Position we are at at the moment.
127         int soundobj;   // Which soundobject is on this channel
128         int persistent; // This can't be pre-empted
129 } SoundSlots[MAX_SOUND_SLOTS];
130
131 static int digi_max_channels = 16;
132
133 static int next_channel = 0;
134
135 /* Audio mixing callback */
136 //changed on 980905 by adb to cleanup, add pan support and optimize mixer
137 static void audio_mixcallback(void *userdata, unsigned char *stream, int len)
138 {
139  unsigned char *streamend = stream + len;
140  struct sound_slot *sl;
141   
142  for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++)
143  {
144   if (sl->playing)
145   {
146    unsigned char *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
147    unsigned char *sp = stream;
148    signed char v;
149    fix vl, vr;
150    int x;
151
152    if ((x = sl->pan) & 0x8000)
153    {
154     vl = 0x20000 - x * 2;
155     vr = 0x10000;
156    }
157    else
158    {
159     vl = 0x10000;
160     vr = x * 2;
161    }
162    vl = fixmul(vl, (x = sl->volume));
163    vr = fixmul(vr, x);
164    while (sp < streamend) 
165    {
166     if (sldata == slend)
167     {
168      if (!sl->looped)
169      {
170       sl->playing = 0;
171       break;
172      }
173      sldata = sl->samples;
174     }
175     v = *(sldata++) - 0x80;
176     *(sp++) = mix8[ *sp + fixmul(v, vl) + 0x80 ];
177     *(sp++) = mix8[ *sp + fixmul(v, vr) + 0x80 ];
178    }
179    sl->position = sldata - sl->samples;
180   }
181  }
182 }
183 //end changes by adb
184
185 /* Initialise audio devices. */
186 int digi_init()
187 {
188     /* this is just here now to stop gcc from complaining about 
189      * audio_mixcallback being declared static and not used...
190      */
191     if (0) audio_mixcallback(NULL,NULL,0);
192
193  return 1;
194 }
195
196 /* Toggle audio */
197 void digi_reset() { }
198
199 /* Shut down audio */
200 void digi_close()
201 {
202  if (!Digi_initialized) return;
203  Digi_initialized = 0;
204 }
205
206 void digi_stop_all_channels()
207 {
208         int i;
209
210         for (i = 0; i < MAX_SOUND_SLOTS; i++)
211                 digi_stop_sound(i);
212 }
213
214
215 extern void digi_end_soundobj(int channel);     
216 extern int SoundQ_channel;
217 extern void SoundQ_end();
218 int verify_sound_channel_free(int channel);
219
220 // Volume 0-F1_0
221 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
222 {
223         int i, starting_channel;
224
225         if (!Digi_initialized) return -1;
226
227         if (soundnum < 0) return -1;
228
229         Assert(GameSounds[soundnum].data != (void *)-1);
230
231         starting_channel = next_channel;
232
233         while(1)
234         {
235                 if (!SoundSlots[next_channel].playing)
236                         break;
237
238                 if (!SoundSlots[next_channel].persistent)
239                         break;  // use this channel!    
240
241                 next_channel++;
242                 if (next_channel >= digi_max_channels)
243                         next_channel = 0;
244                 if (next_channel == starting_channel)
245                 {
246                         mprintf((1, "OUT OF SOUND CHANNELS!!!\n"));
247                         return -1;
248                 }
249         }
250         if (SoundSlots[next_channel].playing)
251         {
252                 SoundSlots[next_channel].playing = 0;
253                 if (SoundSlots[next_channel].soundobj > -1)
254                 {
255                         digi_end_soundobj(SoundSlots[next_channel].soundobj);
256                 }
257                 if (SoundQ_channel == next_channel)
258                         SoundQ_end();
259         }
260
261 #ifndef NDEBUG
262         verify_sound_channel_free(next_channel);
263 #endif
264
265         SoundSlots[next_channel].soundno = soundnum;
266         SoundSlots[next_channel].samples = GameSounds[soundnum].data;
267         SoundSlots[next_channel].length = GameSounds[soundnum].length;
268         SoundSlots[next_channel].volume = fixmul(digi_volume, volume);
269         SoundSlots[next_channel].pan = pan;
270         SoundSlots[next_channel].position = 0;
271         SoundSlots[next_channel].looped = looping;
272         SoundSlots[next_channel].playing = 1;
273         SoundSlots[next_channel].soundobj = soundobj;
274         SoundSlots[next_channel].persistent = 0;
275         if ((soundobj > -1) || (looping) || (volume > F1_0))
276                 SoundSlots[next_channel].persistent = 1;
277
278         i = next_channel;
279         next_channel++;
280         if (next_channel >= digi_max_channels)
281                 next_channel = 0;
282
283         return i;
284 }
285
286
287 // Returns the channel a sound number is playing on, or
288 // -1 if none.
289 int digi_find_channel(int soundno)
290 {
291         if (!Digi_initialized)
292                 return -1;
293
294         if (soundno < 0 )
295                 return -1;
296
297         if (GameSounds[soundno].data == NULL)
298         {
299                 Int3();
300                 return -1;
301         }
302
303         //FIXME: not implemented
304         return -1;
305 }
306
307
308 //added on 980905 by adb from original source to make sfx volume work
309 void digi_set_digi_volume( int dvolume )
310 {
311         dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
312         if ( dvolume > SOUND_MAX_VOLUME )
313                 digi_volume = SOUND_MAX_VOLUME;
314         else if ( dvolume < 0 )
315                 digi_volume = 0;
316         else
317                 digi_volume = dvolume;
318
319         if ( !Digi_initialized ) return;
320
321         digi_sync_sounds();
322 }
323 //end edit by adb
324
325 void digi_set_volume( int dvolume, int mvolume ) { }
326
327 int digi_is_sound_playing(int soundno)
328 {
329         int i;
330
331         soundno = digi_xlat_sound(soundno);
332
333         for (i = 0; i < MAX_SOUND_SLOTS; i++)
334                   //changed on 980905 by adb: added SoundSlots[i].playing &&
335                   if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
336                   //end changes by adb
337                         return 1;
338         return 0;
339 }
340
341
342  //added on 980905 by adb to make sound channel setting work
343 void digi_set_max_channels(int n) { 
344         digi_max_channels       = n;
345
346         if ( digi_max_channels < 1 ) 
347                 digi_max_channels = 1;
348         if (digi_max_channels > MAX_SOUND_SLOTS)
349                 digi_max_channels = MAX_SOUND_SLOTS;
350
351         if ( !Digi_initialized ) return;
352
353         digi_stop_all_channels();
354 }
355
356 int digi_get_max_channels() { 
357         return digi_max_channels; 
358 }
359 // end edit by adb
360
361 int digi_is_channel_playing(int channel)
362 {
363         if (!Digi_initialized)
364                 return 0;
365
366         return SoundSlots[channel].playing;
367 }
368
369 void digi_set_channel_volume(int channel, int volume)
370 {
371         if (!Digi_initialized)
372                 return;
373
374         if (!SoundSlots[channel].playing)
375                 return;
376
377         SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
378 }
379
380 void digi_set_channel_pan(int channel, int pan)
381 {
382         if (!Digi_initialized)
383                 return;
384
385         if (!SoundSlots[channel].playing)
386                 return;
387
388         SoundSlots[channel].pan = pan;
389 }
390
391 void digi_stop_sound(int channel)
392 {
393         SoundSlots[channel].playing = 0;
394         SoundSlots[channel].soundobj = -1;
395         SoundSlots[channel].persistent = 0;
396 }
397
398 void digi_end_sound(int channel)
399 {
400         if (!Digi_initialized)
401                 return;
402
403         if (!SoundSlots[channel].playing)
404                 return;
405
406         SoundSlots[channel].soundobj = -1;
407         SoundSlots[channel].persistent = 0;
408 }
409
410 void digi_reset_digi_sounds() {
411  int i;
412
413  for (i=0; i< MAX_SOUND_SLOTS; i++)
414   SoundSlots[i].playing=0;
415  
416  //added on 980905 by adb to reset sound kill system
417  memset(SampleHandles, 255, sizeof(SampleHandles));
418  next_handle = 0;
419  //end edit by adb
420 }
421
422
423 // MIDI stuff follows.
424 //added/killed on 11/25/98 by Matthew Mueller
425 //void digi_set_midi_volume( int mvolume ) { }
426 //void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) {}
427 //void digi_stop_current_song()
428 //{
429 //#ifdef HMIPLAY
430 //        char buf[10];
431 //    
432 //        sprintf(buf,"s");
433 //        send_ipc(buf);
434 //#endif
435 //}
436 //void digi_pause_midi() {}
437 //void digi_resume_midi() {}
438 //end this section kill - MM
439
440 #ifndef NDEBUG
441 void digi_debug()
442 {
443         int i;
444         int n_voices = 0;
445
446         if (!Digi_initialized)
447                 return;
448
449         for (i = 0; i < digi_max_channels; i++)
450         {
451                 if (digi_is_channel_playing(i))
452                         n_voices++;
453         }
454
455         mprintf_at((0, 2, 0, "DIGI: Active Sound Channels: %d/%d (HMI says %d/32)      ", n_voices, digi_max_channels, -1));
456         //mprintf_at((0, 3, 0, "DIGI: Number locked sounds:  %d                          ", digi_total_locks ));
457 }
458 #endif