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