3 * SDL digital audio support
21 #include "gr.h" // needed for piggy.h
25 int digi_sample_rate = SAMPLE_RATE_11K;
27 //edited 05/17/99 Matt Mueller - added ifndef NO_ASM
28 //added on 980905 by adb to add inline fixmul for mixer on i386
31 #define do_fixmul(x,y) \
34 asm("imull %2\n\tshrdl %3,%1,%0" \
35 : "=a"(_ax), "=d"(_dx) \
36 : "rm"(y), "i"(16), "0"(x)); \
39 extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); }
45 //changed on 980905 by adb to increase number of concurrent sounds
46 #define MAX_SOUND_SLOTS 32
48 #define SOUND_BUFFER_SIZE 512
52 /* This table is used to add two sound values together and pin
53 * the value to avoid overflow. (used with permission from ARDI)
54 * DPH: Taken from SDL/src/SDL_mixer.c.
56 static const Uint8 mix8[] =
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, 0x01, 0x02, 0x03,
70 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
71 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
72 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
73 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
74 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
75 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
76 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
77 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
78 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
79 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
80 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
81 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
82 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
83 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
84 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
85 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
86 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
87 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
88 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
89 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
90 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
91 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
92 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF,
93 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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,
108 //added/changed on 980905 by adb to make sfx volume work, on 990221 by adb changed F1_0 to F1_0 / 2
109 #define SOUND_MAX_VOLUME (F1_0 / 2)
111 int digi_volume = SOUND_MAX_VOLUME;
114 static int Digi_initialized = 0;
118 int playing; // Is there a sample playing on this channel?
119 int looped; // Play this sample looped?
120 fix pan; // 0 = far left, 1 = far right
121 fix volume; // 0 = nothing, 1 = fully on
122 //changed on 980905 by adb from char * to unsigned char *
123 unsigned char *samples;
125 unsigned int length; // Length of the sample
126 unsigned int position; // Position we are at at the moment.
127 int soundobj; // Which soundobject is on this channel
128 int persistent; // This can't be pre-empted
129 } SoundSlots[MAX_SOUND_SLOTS];
131 static SDL_AudioSpec WaveSpec;
133 static int digi_max_channels = 16;
135 static int next_channel = 0;
137 /* Audio mixing callback */
138 //changed on 980905 by adb to cleanup, add pan support and optimize mixer
139 static void audio_mixcallback(void *userdata, Uint8 *stream, int len)
141 Uint8 *streamend = stream + len;
142 struct sound_slot *sl;
144 if (!Digi_initialized)
147 memset(stream, 0x80, len); // fix "static" sound bug on Mac OS X
149 for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++) {
151 Uint8 *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
152 Uint8 *sp = stream, s;
157 if ((x = sl->pan) & 0x8000) {
158 vl = 0x20000 - x * 2;
164 vl = fixmul(vl, (x = sl->volume));
166 while (sp < streamend) {
167 if (sldata == slend) {
172 sldata = sl->samples;
174 v = *(sldata++) - 0x80;
176 *(sp++) = mix8[ s + fixmul(v, vl) + 0x80 ];
178 *(sp++) = mix8[ s + fixmul(v, vr) + 0x80 ];
180 sl->position = (int)(sldata - sl->samples);
186 /* Initialise audio devices. */
189 if (SDL_InitSubSystem(SDL_INIT_AUDIO)<0) {
190 Error("SDL audio initialisation failed: %s.",SDL_GetError());
193 WaveSpec.freq = digi_sample_rate;
194 //added/changed by Sam Lantinga on 12/01/98 for new SDL version
195 WaveSpec.format = AUDIO_U8;
196 WaveSpec.channels = 2;
197 //end this section addition/change - SL
198 WaveSpec.samples = SOUND_BUFFER_SIZE;
199 WaveSpec.callback = audio_mixcallback;
201 if ( SDL_OpenAudio(&WaveSpec, NULL) < 0 ) {
202 //edited on 10/05/98 by Matt Mueller - should keep running, just with no sound.
203 Warning("\nError: Couldn't open audio: %s\n", SDL_GetError());
211 Digi_initialized = 1;
216 void digi_reset() { }
218 /* Shut down audio */
221 if (!Digi_initialized) return;
222 Digi_initialized = 0;
224 SDL_Delay(500); // CloseAudio hangs if it's called too soon after opening?
229 void digi_stop_all_channels()
233 for (i = 0; i < MAX_SOUND_SLOTS; i++)
238 extern void digi_end_soundobj(int channel);
239 extern int SoundQ_channel;
240 extern void SoundQ_end();
241 int verify_sound_channel_free(int channel);
244 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
246 int i, starting_channel;
248 if (!Digi_initialized) return -1;
250 if (soundnum < 0) return -1;
252 Assert(GameSounds[soundnum].data != (void *)-1);
254 starting_channel = next_channel;
258 if (!SoundSlots[next_channel].playing)
261 if (!SoundSlots[next_channel].persistent)
262 break; // use this channel!
265 if (next_channel >= digi_max_channels)
267 if (next_channel == starting_channel)
269 mprintf((1, "OUT OF SOUND CHANNELS!!!\n"));
273 if (SoundSlots[next_channel].playing)
275 SoundSlots[next_channel].playing = 0;
276 if (SoundSlots[next_channel].soundobj > -1)
278 digi_end_soundobj(SoundSlots[next_channel].soundobj);
280 if (SoundQ_channel == next_channel)
285 verify_sound_channel_free(next_channel);
288 SoundSlots[next_channel].soundno = soundnum;
289 SoundSlots[next_channel].samples = GameSounds[soundnum].data;
290 SoundSlots[next_channel].length = GameSounds[soundnum].length;
291 SoundSlots[next_channel].volume = fixmul(digi_volume, volume);
292 SoundSlots[next_channel].pan = pan;
293 SoundSlots[next_channel].position = 0;
294 SoundSlots[next_channel].looped = looping;
295 SoundSlots[next_channel].playing = 1;
296 SoundSlots[next_channel].soundobj = soundobj;
297 SoundSlots[next_channel].persistent = 0;
298 if ((soundobj > -1) || (looping) || (volume > F1_0))
299 SoundSlots[next_channel].persistent = 1;
303 if (next_channel >= digi_max_channels)
309 // Returns the channel a sound number is playing on, or
311 int digi_find_channel(int soundno)
313 if (!Digi_initialized)
319 if (GameSounds[soundno].data == NULL)
325 //FIXME: not implemented
330 //added on 980905 by adb from original source to make sfx volume work
331 void digi_set_digi_volume( int dvolume )
333 dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
334 if ( dvolume > SOUND_MAX_VOLUME )
335 digi_volume = SOUND_MAX_VOLUME;
336 else if ( dvolume < 0 )
339 digi_volume = dvolume;
341 if ( !Digi_initialized ) return;
347 void digi_set_volume( int dvolume, int mvolume )
349 digi_set_digi_volume(dvolume);
350 digi_set_midi_volume(mvolume);
351 // mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume ));
354 int digi_is_sound_playing(int soundno)
358 soundno = digi_xlat_sound(soundno);
360 for (i = 0; i < MAX_SOUND_SLOTS; i++)
361 //changed on 980905 by adb: added SoundSlots[i].playing &&
362 if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
369 //added on 980905 by adb to make sound channel setting work
370 void digi_set_max_channels(int n) {
371 digi_max_channels = n;
373 if ( digi_max_channels < 1 )
374 digi_max_channels = 1;
375 if (digi_max_channels > MAX_SOUND_SLOTS)
376 digi_max_channels = MAX_SOUND_SLOTS;
378 if ( !Digi_initialized ) return;
380 digi_stop_all_channels();
383 int digi_get_max_channels() {
384 return digi_max_channels;
388 int digi_is_channel_playing(int channel)
390 if (!Digi_initialized)
393 return SoundSlots[channel].playing;
396 void digi_set_channel_volume(int channel, int volume)
398 if (!Digi_initialized)
401 if (!SoundSlots[channel].playing)
404 SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
407 void digi_set_channel_pan(int channel, int pan)
409 if (!Digi_initialized)
412 if (!SoundSlots[channel].playing)
415 SoundSlots[channel].pan = pan;
418 void digi_stop_sound(int channel)
420 SoundSlots[channel].playing=0;
421 SoundSlots[channel].soundobj = -1;
422 SoundSlots[channel].persistent = 0;
425 void digi_end_sound(int channel)
427 if (!Digi_initialized)
430 if (!SoundSlots[channel].playing)
433 SoundSlots[channel].soundobj = -1;
434 SoundSlots[channel].persistent = 0;
439 // MIDI stuff follows.
440 void digi_set_midi_volume( int mvolume ) { }
441 void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) {}
442 void digi_stop_current_song()
451 void digi_pause_midi() {}
452 void digi_resume_midi() {}
461 if (!Digi_initialized)
464 for (i = 0; i < digi_max_channels; i++)
466 if (digi_is_channel_playing(i))
470 mprintf_at((0, 2, 0, "DIGI: Active Sound Channels: %d/%d (HMI says %d/32) ", n_voices, digi_max_channels, -1));
471 //mprintf_at((0, 3, 0, "DIGI: Number locked sounds: %d ", digi_total_locks ));