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
150 for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++) {
152 Uint8 *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
153 Uint8 *sp = stream, s;
158 if ((x = sl->pan) & 0x8000) {
159 vl = 0x20000 - x * 2;
165 vl = fixmul(vl, (x = sl->volume));
167 while (sp < streamend) {
168 if (sldata == slend) {
173 sldata = sl->samples;
175 v = *(sldata++) - 0x80;
177 *(sp++) = mix8[ s + fixmul(v, vl) + 0x80 ];
179 *(sp++) = mix8[ s + fixmul(v, vr) + 0x80 ];
181 sl->position = (int)(sldata - sl->samples);
188 /* Initialise audio devices. */
191 if (SDL_InitSubSystem(SDL_INIT_AUDIO)<0) {
192 Error("SDL audio initialisation failed: %s.",SDL_GetError());
195 if ( Mix_OpenAudio(digi_sample_rate, AUDIO_U8, 2, SOUND_BUFFER_SIZE) < 0 ) {
196 //edited on 10/05/98 by Matt Mueller - should keep running, just with no sound.
197 Warning("\nError: Couldn't open audio: %s\n", SDL_GetError());
203 Mix_SetPostMix(audio_mixcallback, NULL);
208 Digi_initialized = 1;
213 void digi_reset() { }
215 /* Shut down audio */
218 if (!Digi_initialized) return;
220 digi_stop_current_song();
222 Digi_initialized = 0;
225 SDL_Delay(500); // CloseAudio hangs if it's called too soon after opening?
230 void digi_stop_all_channels()
234 for (i = 0; i < MAX_SOUND_SLOTS; i++)
239 extern void digi_end_soundobj(int channel);
240 extern int SoundQ_channel;
241 extern void SoundQ_end(void);
242 int verify_sound_channel_free(int channel);
245 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
247 int i, starting_channel;
249 if (!Digi_initialized) return -1;
251 if (soundnum < 0) return -1;
253 Assert(GameSounds[soundnum].data != (void *)-1);
255 starting_channel = next_channel;
259 if (!SoundSlots[next_channel].playing)
262 if (!SoundSlots[next_channel].persistent)
263 break; // use this channel!
266 if (next_channel >= digi_max_channels)
268 if (next_channel == starting_channel)
270 mprintf((1, "OUT OF SOUND CHANNELS!!!\n"));
274 if (SoundSlots[next_channel].playing)
276 SoundSlots[next_channel].playing = 0;
277 if (SoundSlots[next_channel].soundobj > -1)
279 digi_end_soundobj(SoundSlots[next_channel].soundobj);
281 if (SoundQ_channel == next_channel)
286 verify_sound_channel_free(next_channel);
289 SoundSlots[next_channel].soundno = soundnum;
290 SoundSlots[next_channel].samples = GameSounds[soundnum].data;
291 SoundSlots[next_channel].length = GameSounds[soundnum].length;
292 SoundSlots[next_channel].volume = fixmul(digi_volume, volume);
293 SoundSlots[next_channel].pan = pan;
294 SoundSlots[next_channel].position = 0;
295 SoundSlots[next_channel].looped = looping;
296 SoundSlots[next_channel].playing = 1;
297 SoundSlots[next_channel].soundobj = soundobj;
298 SoundSlots[next_channel].persistent = 0;
299 if ((soundobj > -1) || (looping) || (volume > F1_0))
300 SoundSlots[next_channel].persistent = 1;
304 if (next_channel >= digi_max_channels)
310 // Returns the channel a sound number is playing on, or
312 int digi_find_channel(int soundno)
314 if (!Digi_initialized)
320 if (GameSounds[soundno].data == NULL)
326 //FIXME: not implemented
331 //added on 980905 by adb from original source to make sfx volume work
332 void digi_set_digi_volume( int dvolume )
334 dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
335 if ( dvolume > SOUND_MAX_VOLUME )
336 digi_volume = SOUND_MAX_VOLUME;
337 else if ( dvolume < 0 )
340 digi_volume = dvolume;
342 if ( !Digi_initialized ) return;
348 void digi_set_volume( int dvolume, int mvolume )
350 digi_set_digi_volume(dvolume);
351 digi_set_midi_volume(mvolume);
352 // mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume ));
355 int digi_is_sound_playing(int soundno)
359 soundno = digi_xlat_sound(soundno);
361 for (i = 0; i < MAX_SOUND_SLOTS; i++)
362 //changed on 980905 by adb: added SoundSlots[i].playing &&
363 if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
370 //added on 980905 by adb to make sound channel setting work
371 void digi_set_max_channels(int n) {
372 digi_max_channels = n;
374 if ( digi_max_channels < 1 )
375 digi_max_channels = 1;
376 if (digi_max_channels > MAX_SOUND_SLOTS)
377 digi_max_channels = MAX_SOUND_SLOTS;
379 if ( !Digi_initialized ) return;
381 digi_stop_all_channels();
384 int digi_get_max_channels() {
385 return digi_max_channels;
389 int digi_is_channel_playing(int channel)
391 if (!Digi_initialized)
394 return SoundSlots[channel].playing;
397 void digi_set_channel_volume(int channel, int volume)
399 if (!Digi_initialized)
402 if (!SoundSlots[channel].playing)
405 SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
408 void digi_set_channel_pan(int channel, int pan)
410 if (!Digi_initialized)
413 if (!SoundSlots[channel].playing)
416 SoundSlots[channel].pan = pan;
419 void digi_stop_sound(int channel)
421 SoundSlots[channel].playing=0;
422 SoundSlots[channel].soundobj = -1;
423 SoundSlots[channel].persistent = 0;
426 void digi_end_sound(int channel)
428 if (!Digi_initialized)
431 if (!SoundSlots[channel].playing)
434 SoundSlots[channel].soundobj = -1;
435 SoundSlots[channel].persistent = 0;
445 if (!Digi_initialized)
448 for (i = 0; i < digi_max_channels; i++)
450 if (digi_is_channel_playing(i))
454 mprintf_at((0, 2, 0, "DIGI: Active Sound Channels: %d/%d (HMI says %d/32) ", n_voices, digi_max_channels, -1));
455 //mprintf_at((0, 3, 0, "DIGI: Number locked sounds: %d ", digi_total_locks ));