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