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