1 /* $Id: digi.c,v 1.20 2004-11-29 07:34:27 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;
233 void digi_stop_all_channels()
237 for (i = 0; i < MAX_SOUND_SLOTS; i++)
242 extern void digi_end_soundobj(int channel);
243 extern int SoundQ_channel;
244 extern void SoundQ_end();
245 int verify_sound_channel_free(int channel);
248 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
250 int i, starting_channel;
252 if (!digi_initialised) return -1;
254 if (soundnum < 0) return -1;
256 Assert(GameSounds[soundnum].data != (void *)-1);
258 starting_channel = next_channel;
262 if (!SoundSlots[next_channel].playing)
265 if (!SoundSlots[next_channel].persistent)
266 break; // use this channel!
269 if (next_channel >= digi_max_channels)
271 if (next_channel == starting_channel)
273 mprintf((1, "OUT OF SOUND CHANNELS!!!\n"));
277 if (SoundSlots[next_channel].playing)
279 SoundSlots[next_channel].playing = 0;
280 if (SoundSlots[next_channel].soundobj > -1)
282 digi_end_soundobj(SoundSlots[next_channel].soundobj);
284 if (SoundQ_channel == next_channel)
289 verify_sound_channel_free(next_channel);
292 SoundSlots[next_channel].soundno = soundnum;
293 SoundSlots[next_channel].samples = GameSounds[soundnum].data;
294 SoundSlots[next_channel].length = GameSounds[soundnum].length;
295 SoundSlots[next_channel].volume = fixmul(digi_volume, volume);
296 SoundSlots[next_channel].pan = pan;
297 SoundSlots[next_channel].position = 0;
298 SoundSlots[next_channel].looped = looping;
299 SoundSlots[next_channel].playing = 1;
300 SoundSlots[next_channel].soundobj = soundobj;
301 SoundSlots[next_channel].persistent = 0;
302 if ((soundobj > -1) || (looping) || (volume > F1_0))
303 SoundSlots[next_channel].persistent = 1;
307 if (next_channel >= digi_max_channels)
313 // Returns the channel a sound number is playing on, or
315 int digi_find_channel(int soundno)
317 if (!digi_initialised)
323 if (GameSounds[soundno].data == NULL)
329 //FIXME: not implemented
334 //added on 980905 by adb from original source to make sfx volume work
335 void digi_set_digi_volume( int dvolume )
337 dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
338 if ( dvolume > SOUND_MAX_VOLUME )
339 digi_volume = SOUND_MAX_VOLUME;
340 else if ( dvolume < 0 )
343 digi_volume = dvolume;
345 if ( !digi_initialised ) return;
351 void digi_set_volume( int dvolume, int mvolume )
353 digi_set_digi_volume(dvolume);
354 digi_set_midi_volume(mvolume);
355 // mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume ));
358 int digi_is_sound_playing(int soundno)
362 soundno = digi_xlat_sound(soundno);
364 for (i = 0; i < MAX_SOUND_SLOTS; i++)
365 //changed on 980905 by adb: added SoundSlots[i].playing &&
366 if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
373 //added on 980905 by adb to make sound channel setting work
374 void digi_set_max_channels(int n) {
375 digi_max_channels = n;
377 if ( digi_max_channels < 1 )
378 digi_max_channels = 1;
379 if (digi_max_channels > MAX_SOUND_SLOTS)
380 digi_max_channels = MAX_SOUND_SLOTS;
382 if ( !digi_initialised ) return;
384 digi_stop_all_channels();
387 int digi_get_max_channels() {
388 return digi_max_channels;
392 int digi_is_channel_playing(int channel)
394 if (!digi_initialised)
397 return SoundSlots[channel].playing;
400 void digi_set_channel_volume(int channel, int volume)
402 if (!digi_initialised)
405 if (!SoundSlots[channel].playing)
408 SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
411 void digi_set_channel_pan(int channel, int pan)
413 if (!digi_initialised)
416 if (!SoundSlots[channel].playing)
419 SoundSlots[channel].pan = pan;
422 void digi_stop_sound(int channel)
424 SoundSlots[channel].playing=0;
425 SoundSlots[channel].soundobj = -1;
426 SoundSlots[channel].persistent = 0;
429 void digi_end_sound(int channel)
431 if (!digi_initialised)
434 if (!SoundSlots[channel].playing)
437 SoundSlots[channel].soundobj = -1;
438 SoundSlots[channel].persistent = 0;
443 // MIDI stuff follows.
444 void digi_set_midi_volume( int mvolume ) { }
445 void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) {}
446 void digi_stop_current_song()
455 void digi_pause_midi() {}
456 void digi_resume_midi() {}
465 if (!digi_initialised)
468 for (i = 0; i < digi_max_channels; i++)
470 if (digi_is_channel_playing(i))
474 mprintf_at((0, 2, 0, "DIGI: Active Sound Channels: %d/%d (HMI says %d/32) ", n_voices, digi_max_channels, -1));
475 //mprintf_at((0, 3, 0, "DIGI: Number locked sounds: %d ", digi_total_locks ));