3 * SDL digital audio support
23 #include "gr.h" // needed for piggy.h
31 int digi_sample_rate = SAMPLE_RATE_11K;
33 //edited 05/17/99 Matt Mueller - added ifndef NO_ASM
34 //added on 980905 by adb to add inline fixmul for mixer on i386
37 #define do_fixmul(x,y) \
40 asm("imull %2\n\tshrdl %3,%1,%0" \
41 : "=a"(_ax), "=d"(_dx) \
42 : "rm"(y), "i"(16), "0"(x)); \
45 extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); }
51 //changed on 980905 by adb to increase number of concurrent sounds
52 #define MAX_SOUND_SLOTS 32
54 #define SOUND_BUFFER_SIZE 512
58 /* This table is used to add two sound values together and pin
59 * the value to avoid overflow. (used with permission from ARDI)
60 * DPH: Taken from SDL/src/SDL_mixer.c.
62 static const Uint8 mix8[] =
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, 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, 0x01, 0x02, 0x03,
76 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
77 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
78 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
79 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
80 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
81 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
82 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
83 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
84 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
85 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
86 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
87 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
88 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
89 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
90 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
91 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
92 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
93 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
94 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
95 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
96 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
97 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
98 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 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, 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,
114 //added/changed on 980905 by adb to make sfx volume work, on 990221 by adb changed F1_0 to F1_0 / 2
115 #define SOUND_MAX_VOLUME (F1_0 / 2)
117 int digi_volume = SOUND_MAX_VOLUME;
120 static int digi_initialised = 0;
124 int playing; // Is there a sample playing on this channel?
125 int looped; // Play this sample looped?
126 fix pan; // 0 = far left, 1 = far right
127 fix volume; // 0 = nothing, 1 = fully on
128 //changed on 980905 by adb from char * to unsigned char *
129 unsigned char *samples;
131 unsigned int length; // Length of the sample
132 unsigned int position; // Position we are at at the moment.
133 int soundobj; // Which soundobject is on this channel
134 int persistent; // This can't be pre-empted
135 } SoundSlots[MAX_SOUND_SLOTS];
137 static SDL_AudioSpec WaveSpec;
139 static int digi_max_channels = 16;
141 static int next_channel = 0;
143 /* Audio mixing callback */
144 //changed on 980905 by adb to cleanup, add pan support and optimize mixer
145 static void audio_mixcallback(void *userdata, Uint8 *stream, int len)
147 Uint8 *streamend = stream + len;
148 struct sound_slot *sl;
150 if (!digi_initialised)
153 memset(stream, 0x80, len); // fix "static" sound bug on Mac OS X
155 for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++) {
157 Uint8 *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
158 Uint8 *sp = stream, s;
163 if ((x = sl->pan) & 0x8000) {
164 vl = 0x20000 - x * 2;
170 vl = fixmul(vl, (x = sl->volume));
172 while (sp < streamend) {
173 if (sldata == slend) {
178 sldata = sl->samples;
180 v = *(sldata++) - 0x80;
182 *(sp++) = mix8[ s + fixmul(v, vl) + 0x80 ];
184 *(sp++) = mix8[ s + fixmul(v, vr) + 0x80 ];
186 sl->position = sldata - sl->samples;
192 /* Initialise audio devices. */
195 if (SDL_InitSubSystem(SDL_INIT_AUDIO)<0) {
196 Error("SDL audio initialisation failed: %s.",SDL_GetError());
199 WaveSpec.freq = digi_sample_rate;
200 //added/changed by Sam Lantinga on 12/01/98 for new SDL version
201 WaveSpec.format = AUDIO_U8;
202 WaveSpec.channels = 2;
203 //end this section addition/change - SL
204 WaveSpec.samples = SOUND_BUFFER_SIZE;
205 WaveSpec.callback = audio_mixcallback;
207 if ( SDL_OpenAudio(&WaveSpec, NULL) < 0 ) {
208 //edited on 10/05/98 by Matt Mueller - should keep running, just with no sound.
209 Warning("\nError: Couldn't open audio: %s\n", SDL_GetError());
217 digi_initialised = 1;
222 void digi_reset() { }
224 /* Shut down audio */
227 if (!digi_initialised) return;
228 digi_initialised = 0;
230 SDL_Delay(500); // CloseAudio hangs if it's called too soon after opening?
235 void digi_stop_all_channels()
239 for (i = 0; i < MAX_SOUND_SLOTS; i++)
244 extern void digi_end_soundobj(int channel);
245 extern int SoundQ_channel;
246 extern void SoundQ_end();
247 int verify_sound_channel_free(int channel);
250 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
252 int i, starting_channel;
254 if (!digi_initialised) return -1;
256 if (soundnum < 0) return -1;
258 Assert(GameSounds[soundnum].data != (void *)-1);
260 starting_channel = next_channel;
264 if (!SoundSlots[next_channel].playing)
267 if (!SoundSlots[next_channel].persistent)
268 break; // use this channel!
271 if (next_channel >= digi_max_channels)
273 if (next_channel == starting_channel)
275 mprintf((1, "OUT OF SOUND CHANNELS!!!\n"));
279 if (SoundSlots[next_channel].playing)
281 SoundSlots[next_channel].playing = 0;
282 if (SoundSlots[next_channel].soundobj > -1)
284 digi_end_soundobj(SoundSlots[next_channel].soundobj);
286 if (SoundQ_channel == next_channel)
291 verify_sound_channel_free(next_channel);
294 SoundSlots[next_channel].soundno = soundnum;
295 SoundSlots[next_channel].samples = GameSounds[soundnum].data;
296 SoundSlots[next_channel].length = GameSounds[soundnum].length;
297 SoundSlots[next_channel].volume = fixmul(digi_volume, volume);
298 SoundSlots[next_channel].pan = pan;
299 SoundSlots[next_channel].position = 0;
300 SoundSlots[next_channel].looped = looping;
301 SoundSlots[next_channel].playing = 1;
302 SoundSlots[next_channel].soundobj = soundobj;
303 SoundSlots[next_channel].persistent = 0;
304 if ((soundobj > -1) || (looping) || (volume > F1_0))
305 SoundSlots[next_channel].persistent = 1;
309 if (next_channel >= digi_max_channels)
315 // Returns the channel a sound number is playing on, or
317 int digi_find_channel(int soundno)
319 if (!digi_initialised)
325 if (GameSounds[soundno].data == NULL)
331 //FIXME: not implemented
336 //added on 980905 by adb from original source to make sfx volume work
337 void digi_set_digi_volume( int dvolume )
339 dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
340 if ( dvolume > SOUND_MAX_VOLUME )
341 digi_volume = SOUND_MAX_VOLUME;
342 else if ( dvolume < 0 )
345 digi_volume = dvolume;
347 if ( !digi_initialised ) return;
353 void digi_set_volume( int dvolume, int mvolume )
355 digi_set_digi_volume(dvolume);
356 digi_set_midi_volume(mvolume);
357 // mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume ));
360 int digi_is_sound_playing(int soundno)
364 soundno = digi_xlat_sound(soundno);
366 for (i = 0; i < MAX_SOUND_SLOTS; i++)
367 //changed on 980905 by adb: added SoundSlots[i].playing &&
368 if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
375 //added on 980905 by adb to make sound channel setting work
376 void digi_set_max_channels(int n) {
377 digi_max_channels = n;
379 if ( digi_max_channels < 1 )
380 digi_max_channels = 1;
381 if (digi_max_channels > MAX_SOUND_SLOTS)
382 digi_max_channels = MAX_SOUND_SLOTS;
384 if ( !digi_initialised ) return;
386 digi_stop_all_channels();
389 int digi_get_max_channels() {
390 return digi_max_channels;
394 int digi_is_channel_playing(int channel)
396 if (!digi_initialised)
399 return SoundSlots[channel].playing;
402 void digi_set_channel_volume(int channel, int volume)
404 if (!digi_initialised)
407 if (!SoundSlots[channel].playing)
410 SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
413 void digi_set_channel_pan(int channel, int pan)
415 if (!digi_initialised)
418 if (!SoundSlots[channel].playing)
421 SoundSlots[channel].pan = pan;
424 void digi_stop_sound(int channel)
426 SoundSlots[channel].playing=0;
427 SoundSlots[channel].soundobj = -1;
428 SoundSlots[channel].persistent = 0;
431 void digi_end_sound(int channel)
433 if (!digi_initialised)
436 if (!SoundSlots[channel].playing)
439 SoundSlots[channel].soundobj = -1;
440 SoundSlots[channel].persistent = 0;
445 // MIDI stuff follows.
446 void digi_set_midi_volume( int mvolume ) { }
447 void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) {}
448 void digi_stop_current_song()
457 void digi_pause_midi() {}
458 void digi_resume_midi() {}
467 if (!digi_initialised)
470 for (i = 0; i < digi_max_channels; i++)
472 if (digi_is_channel_playing(i))
476 mprintf_at((0, 2, 0, "DIGI: Active Sound Channels: %d/%d (HMI says %d/32) ", n_voices, digi_max_channels, -1));
477 //mprintf_at((0, 3, 0, "DIGI: Number locked sounds: %d ", digi_total_locks ));