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