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