3 * SDL digital audio support
17 #include "SDL_mixer.h"
22 #include "gr.h" // needed for piggy.h
26 int digi_sample_rate = SAMPLE_RATE_11K;
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
32 #define do_fixmul(x,y) \
35 asm("imull %2\n\tshrdl %3,%1,%0" \
36 : "=a"(_ax), "=d"(_dx) \
37 : "rm"(y), "i"(16), "0"(x)); \
40 extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); }
46 //changed on 980905 by adb to increase number of concurrent sounds
47 #define MAX_SOUND_SLOTS 32
49 #define SOUND_BUFFER_SIZE 512
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.
57 static const Uint8 mix8[] =
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,
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)
112 int digi_volume = SOUND_MAX_VOLUME;
115 int Digi_initialized = 0;
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;
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];
132 static int digi_max_channels = 16;
134 static int next_channel = 0;
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)
140 Uint8 *streamend = stream + len;
141 struct sound_slot *sl;
143 if (!Digi_initialized)
146 memset(stream, 0x80, len); // fix "static" sound bug on Mac OS X
148 for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++) {
150 Uint8 *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
151 Uint8 *sp = stream, s;
156 if ((x = sl->pan) & 0x8000) {
157 vl = 0x20000 - x * 2;
163 vl = fixmul(vl, (x = sl->volume));
165 while (sp < streamend) {
166 if (sldata == slend) {
171 sldata = sl->samples;
173 v = *(sldata++) - 0x80;
175 *(sp++) = mix8[ s + fixmul(v, vl) + 0x80 ];
177 *(sp++) = mix8[ s + fixmul(v, vr) + 0x80 ];
179 sl->position = (int)(sldata - sl->samples);
185 /* Initialise audio devices. */
188 if (SDL_InitSubSystem(SDL_INIT_AUDIO)<0) {
189 Error("SDL audio initialisation failed: %s.",SDL_GetError());
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());
200 Mix_SetPostMix(audio_mixcallback, NULL);
205 Digi_initialized = 1;
210 void digi_reset() { }
212 /* Shut down audio */
215 if (!Digi_initialized) return;
217 digi_stop_current_song();
219 Digi_initialized = 0;
222 SDL_Delay(500); // CloseAudio hangs if it's called too soon after opening?
227 void digi_stop_all_channels()
231 for (i = 0; i < MAX_SOUND_SLOTS; i++)
236 extern void digi_end_soundobj(int channel);
237 extern int SoundQ_channel;
238 extern void SoundQ_end();
239 int verify_sound_channel_free(int channel);
242 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
244 int i, starting_channel;
246 if (!Digi_initialized) return -1;
248 if (soundnum < 0) return -1;
250 Assert(GameSounds[soundnum].data != (void *)-1);
252 starting_channel = next_channel;
256 if (!SoundSlots[next_channel].playing)
259 if (!SoundSlots[next_channel].persistent)
260 break; // use this channel!
263 if (next_channel >= digi_max_channels)
265 if (next_channel == starting_channel)
267 mprintf((1, "OUT OF SOUND CHANNELS!!!\n"));
271 if (SoundSlots[next_channel].playing)
273 SoundSlots[next_channel].playing = 0;
274 if (SoundSlots[next_channel].soundobj > -1)
276 digi_end_soundobj(SoundSlots[next_channel].soundobj);
278 if (SoundQ_channel == next_channel)
283 verify_sound_channel_free(next_channel);
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;
301 if (next_channel >= digi_max_channels)
307 // Returns the channel a sound number is playing on, or
309 int digi_find_channel(int soundno)
311 if (!Digi_initialized)
317 if (GameSounds[soundno].data == NULL)
323 //FIXME: not implemented
328 //added on 980905 by adb from original source to make sfx volume work
329 void digi_set_digi_volume( int dvolume )
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 )
337 digi_volume = dvolume;
339 if ( !Digi_initialized ) return;
345 void digi_set_volume( int dvolume, int mvolume )
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 ));
352 int digi_is_sound_playing(int soundno)
356 soundno = digi_xlat_sound(soundno);
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)
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;
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;
376 if ( !Digi_initialized ) return;
378 digi_stop_all_channels();
381 int digi_get_max_channels() {
382 return digi_max_channels;
386 int digi_is_channel_playing(int channel)
388 if (!Digi_initialized)
391 return SoundSlots[channel].playing;
394 void digi_set_channel_volume(int channel, int volume)
396 if (!Digi_initialized)
399 if (!SoundSlots[channel].playing)
402 SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
405 void digi_set_channel_pan(int channel, int pan)
407 if (!Digi_initialized)
410 if (!SoundSlots[channel].playing)
413 SoundSlots[channel].pan = pan;
416 void digi_stop_sound(int channel)
418 SoundSlots[channel].playing=0;
419 SoundSlots[channel].soundobj = -1;
420 SoundSlots[channel].persistent = 0;
423 void digi_end_sound(int channel)
425 if (!Digi_initialized)
428 if (!SoundSlots[channel].playing)
431 SoundSlots[channel].soundobj = -1;
432 SoundSlots[channel].persistent = 0;
442 if (!Digi_initialized)
445 for (i = 0; i < digi_max_channels; i++)
447 if (digi_is_channel_playing(i))
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 ));