]> icculus.org git repositories - btb/d2x.git/blob - arch/sdl/digi.c
make function declarations into prototypes
[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         for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++) {
149                 if (sl->playing) {
150                         Uint8 *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
151                         Uint8 *sp = stream, s;
152                         signed char v;
153                         fix vl, vr;
154                         int x;
155
156                         if ((x = sl->pan) & 0x8000) {
157                                 vl = 0x20000 - x * 2;
158                                 vr = 0x10000;
159                         } else {
160                                 vl = 0x10000;
161                                 vr = x * 2;
162                         }
163                         vl = fixmul(vl, (x = sl->volume));
164                         vr = fixmul(vr, x);
165                         while (sp < streamend) {
166                                 if (sldata == slend) {
167                                         if (!sl->looped) {
168                                                 sl->playing = 0;
169                                                 break;
170                                         }
171                                         sldata = sl->samples;
172                                 }
173                                 v = *(sldata++) - 0x80;
174                                 s = *sp;
175                                 *(sp++) = mix8[ s + fixmul(v, vl) + 0x80 ];
176                                 s = *sp;
177                                 *(sp++) = mix8[ s + fixmul(v, vr) + 0x80 ];
178                         }
179                         sl->position = (int)(sldata - sl->samples);
180                 }
181         }
182 }
183 //end changes by adb
184
185 /* Initialise audio devices. */
186 int digi_init()
187 {
188         if (SDL_InitSubSystem(SDL_INIT_AUDIO)<0) {
189                 Error("SDL audio initialisation failed: %s.",SDL_GetError());
190         }
191
192         if ( Mix_OpenAudio(digi_sample_rate, AUDIO_U8, 2, SOUND_BUFFER_SIZE) < 0 ) {
193                 //edited on 10/05/98 by Matt Mueller - should keep running, just with no sound.
194                 Warning("\nError: Couldn't open audio: %s\n", SDL_GetError());
195                 //killed  exit(2);
196                 return 1;
197                 //end edit -MM
198         }
199
200         Mix_SetPostMix(audio_mixcallback, NULL);
201
202         Mix_Resume(-1);
203         
204         atexit(digi_close);
205         Digi_initialized = 1;
206         return 0;
207 }
208
209 /* Toggle audio */
210 void digi_reset() { }
211
212 /* Shut down audio */
213 void digi_close()
214 {
215         if (!Digi_initialized) return;
216
217         digi_stop_current_song();
218
219         Digi_initialized = 0;
220
221 #ifdef __MINGW32__
222         SDL_Delay(500); // CloseAudio hangs if it's called too soon after opening?
223 #endif
224         Mix_CloseAudio();
225 }
226
227 void digi_stop_all_channels()
228 {
229         int i;
230
231         for (i = 0; i < MAX_SOUND_SLOTS; i++)
232                 digi_stop_sound(i);
233 }
234
235
236 extern void digi_end_soundobj(int channel);     
237 extern int SoundQ_channel;
238 extern void SoundQ_end(void);
239 int verify_sound_channel_free(int channel);
240
241 // Volume 0-F1_0
242 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
243 {
244         int i, starting_channel;
245
246         if (!Digi_initialized) return -1;
247
248         if (soundnum < 0) return -1;
249
250         Assert(GameSounds[soundnum].data != (void *)-1);
251
252         starting_channel = next_channel;
253
254         while(1)
255         {
256                 if (!SoundSlots[next_channel].playing)
257                         break;
258
259                 if (!SoundSlots[next_channel].persistent)
260                         break;  // use this channel!    
261
262                 next_channel++;
263                 if (next_channel >= digi_max_channels)
264                         next_channel = 0;
265                 if (next_channel == starting_channel)
266                 {
267                         mprintf((1, "OUT OF SOUND CHANNELS!!!\n"));
268                         return -1;
269                 }
270         }
271         if (SoundSlots[next_channel].playing)
272         {
273                 SoundSlots[next_channel].playing = 0;
274                 if (SoundSlots[next_channel].soundobj > -1)
275                 {
276                         digi_end_soundobj(SoundSlots[next_channel].soundobj);
277                 }
278                 if (SoundQ_channel == next_channel)
279                         SoundQ_end();
280         }
281
282 #ifndef NDEBUG
283         verify_sound_channel_free(next_channel);
284 #endif
285
286         SoundSlots[next_channel].soundno = soundnum;
287         SoundSlots[next_channel].samples = GameSounds[soundnum].data;
288         SoundSlots[next_channel].length = GameSounds[soundnum].length;
289         SoundSlots[next_channel].volume = fixmul(digi_volume, volume);
290         SoundSlots[next_channel].pan = pan;
291         SoundSlots[next_channel].position = 0;
292         SoundSlots[next_channel].looped = looping;
293         SoundSlots[next_channel].playing = 1;
294         SoundSlots[next_channel].soundobj = soundobj;
295         SoundSlots[next_channel].persistent = 0;
296         if ((soundobj > -1) || (looping) || (volume > F1_0))
297                 SoundSlots[next_channel].persistent = 1;
298
299         i = next_channel;
300         next_channel++;
301         if (next_channel >= digi_max_channels)
302                 next_channel = 0;
303
304         return i;
305 }
306
307 // Returns the channel a sound number is playing on, or
308 // -1 if none.
309 int digi_find_channel(int soundno)
310 {
311         if (!Digi_initialized)
312                 return -1;
313
314         if (soundno < 0 )
315                 return -1;
316
317         if (GameSounds[soundno].data == NULL)
318         {
319                 Int3();
320                 return -1;
321         }
322
323         //FIXME: not implemented
324         return -1;
325 }
326
327
328 //added on 980905 by adb from original source to make sfx volume work
329 void digi_set_digi_volume( int dvolume )
330 {
331         dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
332         if ( dvolume > SOUND_MAX_VOLUME )
333                 digi_volume = SOUND_MAX_VOLUME;
334         else if ( dvolume < 0 )
335                 digi_volume = 0;
336         else
337                 digi_volume = dvolume;
338
339         if ( !Digi_initialized ) return;
340
341         digi_sync_sounds();
342 }
343 //end edit by adb
344
345 void digi_set_volume( int dvolume, int mvolume )
346 {
347         digi_set_digi_volume(dvolume);
348         digi_set_midi_volume(mvolume);
349 //      mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume ));
350 }
351
352 int digi_is_sound_playing(int soundno)
353 {
354         int i;
355
356         soundno = digi_xlat_sound(soundno);
357
358         for (i = 0; i < MAX_SOUND_SLOTS; i++)
359                   //changed on 980905 by adb: added SoundSlots[i].playing &&
360                   if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
361                   //end changes by adb
362                         return 1;
363         return 0;
364 }
365
366
367  //added on 980905 by adb to make sound channel setting work
368 void digi_set_max_channels(int n) { 
369         digi_max_channels       = n;
370
371         if ( digi_max_channels < 1 ) 
372                 digi_max_channels = 1;
373         if (digi_max_channels > MAX_SOUND_SLOTS) 
374                 digi_max_channels = MAX_SOUND_SLOTS;
375
376         if ( !Digi_initialized ) return;
377
378         digi_stop_all_channels();
379 }
380
381 int digi_get_max_channels() { 
382         return digi_max_channels; 
383 }
384 // end edit by adb
385
386 int digi_is_channel_playing(int channel)
387 {
388         if (!Digi_initialized)
389                 return 0;
390
391         return SoundSlots[channel].playing;
392 }
393
394 void digi_set_channel_volume(int channel, int volume)
395 {
396         if (!Digi_initialized)
397                 return;
398
399         if (!SoundSlots[channel].playing)
400                 return;
401
402         SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
403 }
404
405 void digi_set_channel_pan(int channel, int pan)
406 {
407         if (!Digi_initialized)
408                 return;
409
410         if (!SoundSlots[channel].playing)
411                 return;
412
413         SoundSlots[channel].pan = pan;
414 }
415
416 void digi_stop_sound(int channel)
417 {
418         SoundSlots[channel].playing=0;
419         SoundSlots[channel].soundobj = -1;
420         SoundSlots[channel].persistent = 0;
421 }
422
423 void digi_end_sound(int channel)
424 {
425         if (!Digi_initialized)
426                 return;
427
428         if (!SoundSlots[channel].playing)
429                 return;
430
431         SoundSlots[channel].soundobj = -1;
432         SoundSlots[channel].persistent = 0;
433 }
434
435
436 #ifndef NDEBUG
437 void digi_debug()
438 {
439         int i;
440         int n_voices = 0;
441
442         if (!Digi_initialized)
443                 return;
444
445         for (i = 0; i < digi_max_channels; i++)
446         {
447                 if (digi_is_channel_playing(i))
448                         n_voices++;
449         }
450
451         mprintf_at((0, 2, 0, "DIGI: Active Sound Channels: %d/%d (HMI says %d/32)      ", n_voices, digi_max_channels, -1));
452         //mprintf_at((0, 3, 0, "DIGI: Number locked sounds:  %d                          ", digi_total_locks ));
453 }
454 #endif