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