]> icculus.org git repositories - btb/d2x.git/blob - arch/sdl/digi.c
ripped object stuff out of digi.c, now using digiobj.c. get rid of a bunch of kludges...
[btb/d2x.git] / arch / sdl / digi.c
1 /* $Id: digi.c,v 1.18 2004-11-29 05:25:58 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 } SoundSlots[MAX_SOUND_SLOTS];
135
136 static SDL_AudioSpec WaveSpec;
137
138 //added on 980905 by adb to add rotating/volume based sound kill system
139 static int digi_max_channels = 16;
140 static int next_handle = 0;
141 int SampleHandles[32];
142 void reset_sounds_on_channel(int channel);
143 //end edit by adb
144
145 void digi_reset_digi_sounds(void);
146
147 /* Audio mixing callback */
148 //changed on 980905 by adb to cleanup, add pan support and optimize mixer
149 static void audio_mixcallback(void *userdata, Uint8 *stream, int len)
150 {
151         Uint8 *streamend = stream + len;
152         struct sound_slot *sl;
153
154         if (!digi_initialised)
155                 return;
156
157         memset(stream, 0x80, len); // fix "static" sound bug on Mac OS X
158
159         for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++) {
160                 if (sl->playing) {
161                         Uint8 *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
162                         Uint8 *sp = stream, s;
163                         signed char v;
164                         fix vl, vr;
165                         int x;
166
167                         if ((x = sl->pan) & 0x8000) {
168                                 vl = 0x20000 - x * 2;
169                                 vr = 0x10000;
170                         } else {
171                                 vl = 0x10000;
172                                 vr = x * 2;
173                         }
174                         vl = fixmul(vl, (x = sl->volume));
175                         vr = fixmul(vr, x);
176                         while (sp < streamend) {
177                                 if (sldata == slend) {
178                                         if (!sl->looped) {
179                                                 sl->playing = 0;
180                                                 break;
181                                         }
182                                         sldata = sl->samples;
183                                 }
184                                 v = *(sldata++) - 0x80;
185                                 s = *sp;
186                                 *(sp++) = mix8[ s + fixmul(v, vl) + 0x80 ];
187                                 s = *sp;
188                                 *(sp++) = mix8[ s + fixmul(v, vr) + 0x80 ];
189                         }
190                         sl->position = sldata - sl->samples;
191                 }
192         }
193 }
194 //end changes by adb
195
196 /* Initialise audio devices. */
197 int digi_init()
198 {
199         if (SDL_InitSubSystem(SDL_INIT_AUDIO)<0) {
200                 Error("SDL audio initialisation failed: %s.",SDL_GetError());
201         }
202         //added on 980905 by adb to init sound kill system
203         memset(SampleHandles, 255, sizeof(SampleHandles));
204         //end edit by adb
205         
206         WaveSpec.freq = digi_sample_rate;
207         //added/changed by Sam Lantinga on 12/01/98 for new SDL version
208         WaveSpec.format = AUDIO_U8;
209         WaveSpec.channels = 2;
210         //end this section addition/change - SL
211         WaveSpec.samples = SOUND_BUFFER_SIZE;
212         WaveSpec.callback = audio_mixcallback;
213         
214         if ( SDL_OpenAudio(&WaveSpec, NULL) < 0 ) {
215                 //edited on 10/05/98 by Matt Mueller - should keep running, just with no sound.
216                 Warning("\nError: Couldn't open audio: %s\n", SDL_GetError());
217                 //killed  exit(2);
218                 return 1;
219                 //end edit -MM
220         }
221         SDL_PauseAudio(0);
222         
223         atexit(digi_close);
224         digi_initialised = 1;
225         return 0;
226 }
227
228 /* Toggle audio */
229 void digi_reset() { }
230
231 /* Shut down audio */
232 void digi_close()
233 {
234         if (!digi_initialised) return;
235         digi_initialised = 0;
236         SDL_CloseAudio();
237 }
238
239 void digi_stop_all_channels()
240 {
241         int i;
242
243         for (i = 0; i < MAX_SOUND_SLOTS; i++)
244                 digi_stop_sound(i);
245 }
246
247 static int get_free_slot()
248 {
249         int i;
250         for (i=0; i<MAX_SOUND_SLOTS; i++) {
251                 if (!SoundSlots[i].playing) return i;
252         }
253         return -1;
254 }
255
256 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int persistent)
257 {
258         int ntries;
259         int slot;
260
261         if (!digi_initialised) return -1;
262
263         if (soundnum < 0) return -1;
264
265         //added on 980905 by adb from original source to add sound kill system
266         // play at most digi_max_channel samples, if possible kill sample with low volume
267         ntries = 0;
268
269 TryNextChannel:
270         if ( (SampleHandles[next_handle] >= 0) && (SoundSlots[SampleHandles[next_handle]].playing)  ) {
271                 if ( (SoundSlots[SampleHandles[next_handle]].volume > digi_volume) && (ntries<digi_max_channels) ) {
272                         //mprintf(( 0, "Not stopping loud sound %d.\n", next_handle ));
273                         next_handle++;
274                         if ( next_handle >= digi_max_channels )
275                                 next_handle = 0;
276                         ntries++;
277                         goto TryNextChannel;
278                 }
279                 //mprintf(( 0, "[SS:%d]", next_handle ));
280                 SoundSlots[SampleHandles[next_handle]].playing = 0;
281                 SampleHandles[next_handle] = -1;
282         }
283         //end edit by adb
284
285         slot = get_free_slot();
286         if (slot<0) return -1;
287
288         SoundSlots[slot].soundno = soundnum;
289         SoundSlots[slot].samples = GameSounds[soundnum].data;
290         SoundSlots[slot].length = GameSounds[soundnum].length;
291         SoundSlots[slot].volume = fixmul(digi_volume, volume);
292         SoundSlots[slot].pan = pan;
293         SoundSlots[slot].position = 0;
294         SoundSlots[slot].looped = looping;
295         SoundSlots[slot].playing = 1;
296
297         //added on 980905 by adb to add sound kill system from original sos digi.c
298         reset_sounds_on_channel(slot);
299         SampleHandles[next_handle] = slot;
300         next_handle++;
301         if ( next_handle >= digi_max_channels )
302                 next_handle = 0;
303         //end edit by adb
304
305         return slot;
306 }
307
308 // Returns the channel a sound number is playing on, or
309 // -1 if none.
310 int digi_find_channel(int soundno)
311 {
312         if (!digi_initialised)
313                 return -1;
314
315         if (soundno < 0 )
316                 return -1;
317
318         if (GameSounds[soundno].data == NULL)
319         {
320                 Int3();
321                 return -1;
322         }
323
324         //FIXME: not implemented
325         return -1;
326 }
327
328  //added on 980905 by adb to add sound kill system from original sos digi.c
329 void reset_sounds_on_channel( int channel )
330 {
331         int i;
332
333         for (i=0; i<digi_max_channels; i++)
334                 if (SampleHandles[i] == channel)
335                         SampleHandles[i] = -1;
336 }
337 //end edit by adb
338
339
340 //added on 980905 by adb from original source to make sfx volume work
341 void digi_set_digi_volume( int dvolume )
342 {
343         dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
344         if ( dvolume > SOUND_MAX_VOLUME )
345                 digi_volume = SOUND_MAX_VOLUME;
346         else if ( dvolume < 0 )
347                 digi_volume = 0;
348         else
349                 digi_volume = dvolume;
350
351         if ( !digi_initialised ) return;
352
353         digi_sync_sounds();
354 }
355 //end edit by adb
356
357 void digi_set_volume( int dvolume, int mvolume )
358 {
359         digi_set_digi_volume(dvolume);
360         digi_set_midi_volume(mvolume);
361 //      mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume ));
362 }
363
364 int digi_is_sound_playing(int soundno)
365 {
366         int i;
367
368         soundno = digi_xlat_sound(soundno);
369
370         for (i = 0; i < MAX_SOUND_SLOTS; i++)
371                   //changed on 980905 by adb: added SoundSlots[i].playing &&
372                   if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
373                   //end changes by adb
374                         return 1;
375         return 0;
376 }
377
378
379  //added on 980905 by adb to make sound channel setting work
380 void digi_set_max_channels(int n) { 
381         digi_max_channels       = n;
382
383         if ( digi_max_channels < 1 ) 
384                 digi_max_channels = 1;
385         if (digi_max_channels > MAX_SOUND_SLOTS) 
386                 digi_max_channels = MAX_SOUND_SLOTS;
387
388         if ( !digi_initialised ) return;
389
390         digi_reset_digi_sounds();
391 }
392
393 int digi_get_max_channels() { 
394         return digi_max_channels; 
395 }
396 // end edit by adb
397
398 int digi_is_channel_playing(int channel)
399 {
400         if (!digi_initialised)
401                 return 0;
402
403         return SoundSlots[channel].playing;
404 }
405
406 void digi_set_channel_volume(int channel, int volume)
407 {
408         if (!digi_initialised)
409                 return;
410
411         if (!SoundSlots[channel].playing)
412                 return;
413
414         SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
415 }
416
417 void digi_set_channel_pan(int channel, int pan)
418 {
419         if (!digi_initialised)
420                 return;
421
422         if (!SoundSlots[channel].playing)
423                 return;
424
425         SoundSlots[channel].pan = pan;
426 }
427
428 void digi_stop_sound(int channel)
429 {
430         SoundSlots[channel].playing=0;
431 }
432
433 void digi_end_sound(int channel)
434 {
435         if (!digi_initialised)
436                 return;
437
438         if (!SoundSlots[channel].playing)
439                 return;
440 }
441
442 void digi_reset_digi_sounds() {
443         int i;
444
445         for (i=0; i< MAX_SOUND_SLOTS; i++)
446                 SoundSlots[i].playing=0;
447  
448         //added on 980905 by adb to reset sound kill system
449         memset(SampleHandles, 255, sizeof(SampleHandles));
450         next_handle = 0;
451         //end edit by adb
452 }
453
454
455 #ifndef _WIN32
456 // MIDI stuff follows.
457 void digi_set_midi_volume( int mvolume ) { }
458 void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) {}
459 void digi_stop_current_song()
460 {
461 #ifdef HMIPLAY
462         char buf[10];
463     
464         sprintf(buf,"s");
465         send_ipc(buf);
466 #endif
467 }
468 void digi_pause_midi() {}
469 void digi_resume_midi() {}
470 #endif
471
472 #ifndef NDEBUG
473 void digi_debug()
474 {
475         int i;
476         int n_voices = 0;
477
478         if (!digi_initialised)
479                 return;
480
481         for (i = 0; i < digi_max_channels; i++)
482         {
483                 if (digi_is_channel_playing(i))
484                         n_voices++;
485         }
486
487         mprintf_at((0, 2, 0, "DIGI: Active Sound Channels: %d/%d (HMI says %d/32)      ", n_voices, digi_max_channels, -1));
488         //mprintf_at((0, 3, 0, "DIGI: Number locked sounds:  %d                          ", digi_total_locks ));
489 }
490 #endif