1 /* $Id: digi.c,v 1.21 2004-11-29 08:01:47 btb Exp $ */
4 * SDL digital audio support
24 #include "gr.h" // needed for piggy.h
32 int digi_sample_rate = SAMPLE_RATE_11K;
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
38 #define do_fixmul(x,y) \
41 asm("imull %2\n\tshrdl %3,%1,%0" \
42 : "=a"(_ax), "=d"(_dx) \
43 : "rm"(y), "i"(16), "0"(x)); \
46 extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); }
52 //changed on 980905 by adb to increase number of concurrent sounds
53 #define MAX_SOUND_SLOTS 32
55 #define SOUND_BUFFER_SIZE 512
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.
63 static const Uint8 mix8[] =
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,
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)
118 int digi_volume = SOUND_MAX_VOLUME;
121 static int digi_initialised = 0;
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;
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];
138 static SDL_AudioSpec WaveSpec;
140 static int digi_max_channels = 16;
142 static int next_channel = 0;
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)
148 Uint8 *streamend = stream + len;
149 struct sound_slot *sl;
151 if (!digi_initialised)
154 memset(stream, 0x80, len); // fix "static" sound bug on Mac OS X
156 for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++) {
158 Uint8 *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
159 Uint8 *sp = stream, s;
164 if ((x = sl->pan) & 0x8000) {
165 vl = 0x20000 - x * 2;
171 vl = fixmul(vl, (x = sl->volume));
173 while (sp < streamend) {
174 if (sldata == slend) {
179 sldata = sl->samples;
181 v = *(sldata++) - 0x80;
183 *(sp++) = mix8[ s + fixmul(v, vl) + 0x80 ];
185 *(sp++) = mix8[ s + fixmul(v, vr) + 0x80 ];
187 sl->position = sldata - sl->samples;
193 /* Initialise audio devices. */
196 if (SDL_InitSubSystem(SDL_INIT_AUDIO)<0) {
197 Error("SDL audio initialisation failed: %s.",SDL_GetError());
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;
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());
218 digi_initialised = 1;
223 void digi_reset() { }
225 /* Shut down audio */
228 if (!digi_initialised) return;
229 digi_initialised = 0;
231 SDL_Delay(500); // CloseAudio hangs if it's called too soon after opening?
236 void digi_stop_all_channels()
240 for (i = 0; i < MAX_SOUND_SLOTS; i++)
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);
251 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
253 int i, starting_channel;
255 if (!digi_initialised) return -1;
257 if (soundnum < 0) return -1;
259 Assert(GameSounds[soundnum].data != (void *)-1);
261 starting_channel = next_channel;
265 if (!SoundSlots[next_channel].playing)
268 if (!SoundSlots[next_channel].persistent)
269 break; // use this channel!
272 if (next_channel >= digi_max_channels)
274 if (next_channel == starting_channel)
276 mprintf((1, "OUT OF SOUND CHANNELS!!!\n"));
280 if (SoundSlots[next_channel].playing)
282 SoundSlots[next_channel].playing = 0;
283 if (SoundSlots[next_channel].soundobj > -1)
285 digi_end_soundobj(SoundSlots[next_channel].soundobj);
287 if (SoundQ_channel == next_channel)
292 verify_sound_channel_free(next_channel);
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;
310 if (next_channel >= digi_max_channels)
316 // Returns the channel a sound number is playing on, or
318 int digi_find_channel(int soundno)
320 if (!digi_initialised)
326 if (GameSounds[soundno].data == NULL)
332 //FIXME: not implemented
337 //added on 980905 by adb from original source to make sfx volume work
338 void digi_set_digi_volume( int dvolume )
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 )
346 digi_volume = dvolume;
348 if ( !digi_initialised ) return;
354 void digi_set_volume( int dvolume, int mvolume )
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 ));
361 int digi_is_sound_playing(int soundno)
365 soundno = digi_xlat_sound(soundno);
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)
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;
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;
385 if ( !digi_initialised ) return;
387 digi_stop_all_channels();
390 int digi_get_max_channels() {
391 return digi_max_channels;
395 int digi_is_channel_playing(int channel)
397 if (!digi_initialised)
400 return SoundSlots[channel].playing;
403 void digi_set_channel_volume(int channel, int volume)
405 if (!digi_initialised)
408 if (!SoundSlots[channel].playing)
411 SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
414 void digi_set_channel_pan(int channel, int pan)
416 if (!digi_initialised)
419 if (!SoundSlots[channel].playing)
422 SoundSlots[channel].pan = pan;
425 void digi_stop_sound(int channel)
427 SoundSlots[channel].playing=0;
428 SoundSlots[channel].soundobj = -1;
429 SoundSlots[channel].persistent = 0;
432 void digi_end_sound(int channel)
434 if (!digi_initialised)
437 if (!SoundSlots[channel].playing)
440 SoundSlots[channel].soundobj = -1;
441 SoundSlots[channel].persistent = 0;
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()
458 void digi_pause_midi() {}
459 void digi_resume_midi() {}
468 if (!digi_initialised)
471 for (i = 0; i < digi_max_channels; i++)
473 if (digi_is_channel_playing(i))
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 ));