3 * ALSA digital audio support
10 #include <alsa/asoundlib.h>
17 #include "gr.h" // needed for piggy.h
25 //edited 05/17/99 Matt Mueller - added ifndef NO_ASM
26 //added on 980905 by adb to add inline fixmul for mixer on i386
29 #define do_fixmul(x,y) \
32 asm("imull %2\n\tshrdl %3,%1,%0" \
33 : "=a"(_ax), "=d"(_dx) \
34 : "rm"(y), "i"(16), "0"(x)); \
37 extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); }
43 //changed on 980905 by adb to increase number of concurrent sounds
44 #define MAX_SOUND_SLOTS 32
46 #define SOUND_BUFFER_SIZE 512
50 /* This table is used to add two sound values together and pin
51 * the value to avoid overflow. (used with permission from ARDI)
52 * DPH: Taken from SDL/src/SDL_mixer.c.
54 static const ubyte mix8[] =
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, 0x01, 0x02, 0x03,
68 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
69 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
70 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
71 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
72 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
73 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
74 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
75 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
76 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
77 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
78 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
79 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
80 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
81 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
82 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
83 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
84 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
85 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
86 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
87 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
88 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
89 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
90 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF,
91 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
92 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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,
105 //added/changed on 980905 by adb to make sfx volume work, on 990221 by adb changed F1_0 to F1_0 / 2
106 #define SOUND_MAX_VOLUME (F1_0 / 2)
108 int digi_volume = SOUND_MAX_VOLUME;
111 static int digi_initialised = 0;
115 int playing; // Is there a sample playing on this channel?
116 int looped; // Play this sample looped?
117 fix pan; // 0 = far left, 1 = far right
118 fix volume; // 0 = nothing, 1 = fully on
119 //changed on 980905 by adb from char * to unsigned char *
120 unsigned char *samples;
122 unsigned int length; // Length of the sample
123 unsigned int position; // Position we are at at the moment.
124 int soundobj; // Which soundobject is on this channel
125 int persistent; // This can't be pre-empted
126 } SoundSlots[MAX_SOUND_SLOTS];
128 static int digi_max_channels = 16;
130 static int next_channel = 0;
132 /* Threading/ALSA stuff */
133 #define LOCK() pthread_mutex_lock(&mutex)
134 #define UNLOCK() pthread_mutex_unlock(&mutex)
135 snd_pcm_t *snd_devhandle;
137 pthread_mutex_t mutex;
140 /* Audio mixing callback */
141 //changed on 980905 by adb to cleanup, add pan support and optimize mixer
142 static void audio_mixcallback(void *userdata, ubyte *stream, int len)
144 ubyte *streamend = stream + len;
145 struct sound_slot *sl;
147 for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++)
151 ubyte *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
157 if ((x = sl->pan) & 0x8000)
159 vl = 0x20000 - x * 2;
167 vl = fixmul(vl, (x = sl->volume));
169 while (sp < streamend)
178 sldata = sl->samples;
180 v = *(sldata++) - 0x80;
181 *sp = mix8[*sp + fixmul(v, vl) + 0x80];
183 *sp = mix8[*sp + fixmul(v, vr) + 0x80];
186 sl->position = sldata - sl->samples;
192 void *mixer_thread(void *data)
195 ubyte buffer[SOUND_BUFFER_SIZE];
197 /* Allow ourselves to be asynchronously cancelled */
198 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
201 memset(buffer, 0x80, SOUND_BUFFER_SIZE);
203 audio_mixcallback(NULL,buffer,512);
206 err = snd_pcm_writei(snd_devhandle, buffer, SOUND_BUFFER_SIZE / 2);
210 // Sound buffer underrun
211 err = snd_pcm_prepare(snd_devhandle);
214 fprintf(stderr, "Can't recover from underrun: %s\n", snd_strerror(err));
217 else if (err == -EAGAIN)
221 else if (err != SOUND_BUFFER_SIZE / 2)
223 // Each frame has size 2 bytes - hence we expect SOUND_BUFFER_SIZE/2
224 // frames to be written.
225 fprintf(stderr, "Unknown err %d: %s\n", err, snd_strerror(err));
232 /* Initialise audio devices. */
236 char *device = "plughw:0,0";
237 snd_pcm_hw_params_t *params;
239 pthread_mutexattr_t mutexattr;
241 //added on 980905 by adb to init sound kill system
242 memset(SampleHandles, 255, sizeof(SampleHandles));
245 /* Open the ALSA sound device */
246 if ((err = snd_pcm_open(&snd_devhandle, device, SND_PCM_STREAM_PLAYBACK)) < 0)
248 fprintf(stderr, "open failed: %s\n", snd_strerror( err ));
252 snd_pcm_hw_params_alloca(¶ms);
253 err = snd_pcm_hw_params_any(snd_devhandle, params);
256 printf("ALSA: Error %s\n", snd_strerror(err));
259 err = snd_pcm_hw_params_set_access(snd_devhandle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
262 printf("ALSA: Error %s\n", snd_strerror(err));
265 err = snd_pcm_hw_params_set_format(snd_devhandle, params, SND_PCM_FORMAT_U8);
268 printf("ALSA: Error %s\n", snd_strerror(err));
271 err = snd_pcm_hw_params_set_channels(snd_devhandle, params, 2);
274 printf("ALSA: Error %s\n", snd_strerror(err));
278 err = snd_pcm_hw_params_set_rate_near(snd_devhandle, params, &tmp, NULL);
281 printf("ALSA: Error %s\n", snd_strerror(err));
284 snd_pcm_hw_params_set_periods(snd_devhandle, params, 3, 0);
285 snd_pcm_hw_params_set_buffer_size(snd_devhandle,params, (SOUND_BUFFER_SIZE*3)/2);
287 err = snd_pcm_hw_params(snd_devhandle, params);
290 printf("ALSA: Error %s\n", snd_strerror(err));
294 /* Start the mixer thread */
296 /* We really should check the results of these */
297 pthread_mutexattr_init(&mutexattr);
298 pthread_mutex_init(&mutex,&mutexattr);
299 pthread_mutexattr_destroy(&mutexattr);
301 if (pthread_attr_init(&attr) != 0) {
302 fprintf(stderr, "failed to init attr\n");
303 snd_pcm_close( snd_devhandle );
307 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
309 pthread_create(&thread_id,&attr,mixer_thread,NULL);
310 pthread_attr_destroy(&attr);
313 digi_initialised = 1;
318 void digi_reset() { }
320 /* Shut down audio */
323 if (!digi_initialised) return;
324 pthread_cancel(thread_id);
325 digi_initialised = 0;
326 pthread_mutex_destroy(&mutex);
327 snd_pcm_close(snd_devhandle);
330 void digi_stop_all_channels()
334 for (i = 0; i < MAX_SOUND_SLOTS; i++)
339 extern void digi_end_soundobj(int channel);
340 extern int SoundQ_channel;
341 extern void SoundQ_end();
342 int verify_sound_channel_free(int channel);
345 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
347 int i, starting_channel;
349 if (!digi_initialised) return -1;
351 if (soundnum < 0) return -1;
354 Assert(GameSounds[soundnum].data != (void *)-1);
356 starting_channel = next_channel;
360 if (!SoundSlots[next_channel].playing)
363 if (!SoundSlots[next_channel].persistent)
364 break; // use this channel!
367 if (next_channel >= digi_max_channels)
369 if (next_channel == starting_channel)
371 mprintf((1, "OUT OF SOUND CHANNELS!!!\n"));
376 if (SoundSlots[next_channel].playing)
378 SoundSlots[next_channel].playing = 0;
379 if (SoundSlots[next_channel].soundobj > -1)
381 digi_end_soundobj(SoundSlots[next_channel].soundobj);
383 if (SoundQ_channel == next_channel)
388 verify_sound_channel_free(next_channel);
391 SoundSlots[next_channel].soundno = soundnum;
392 SoundSlots[next_channel].samples = GameSounds[soundnum].data;
393 SoundSlots[next_channel].length = GameSounds[soundnum].length;
394 SoundSlots[next_channel].volume = fixmul(digi_volume, volume);
395 SoundSlots[next_channel].pan = pan;
396 SoundSlots[next_channel].position = 0;
397 SoundSlots[next_channel].looped = looping;
398 SoundSlots[next_channel].playing = 1;
399 SoundSlots[next_channel].soundobj = soundobj;
400 SoundSlots[next_channel].persistent = 0;
401 if ((soundobj > -1) || (looping) || (volume > F1_0))
402 SoundSlots[next_channel].persistent = 1;
406 if (next_channel >= digi_max_channels)
413 // Returns the channel a sound number is playing on, or
415 int digi_find_channel(int soundno)
417 if (!digi_initialised)
423 if (GameSounds[soundno].data == NULL)
429 //FIXME: not implemented
434 //added on 980905 by adb from original source to make sfx volume work
435 void digi_set_digi_volume( int dvolume )
437 dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
438 if ( dvolume > SOUND_MAX_VOLUME )
439 digi_volume = SOUND_MAX_VOLUME;
440 else if ( dvolume < 0 )
443 digi_volume = dvolume;
445 if ( !digi_initialised ) return;
451 void digi_set_volume(int dvolume, int mvolume)
453 digi_set_digi_volume(dvolume);
454 digi_set_midi_volume(mvolume);
455 // mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume ));
458 int digi_is_sound_playing(int soundno)
462 soundno = digi_xlat_sound(soundno);
465 for (i = 0; i < MAX_SOUND_SLOTS; i++)
466 //changed on 980905 by adb: added SoundSlots[i].playing &&
467 if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
469 { UNLOCK(); return 1; }
475 //added on 980905 by adb to make sound channel setting work
476 void digi_set_max_channels(int n) {
477 digi_max_channels = n;
479 if ( digi_max_channels < 1 )
480 digi_max_channels = 1;
481 if (digi_max_channels > MAX_SOUND_SLOTS)
482 digi_max_channels = MAX_SOUND_SLOTS;
484 if ( !digi_initialised ) return;
486 digi_stop_all_channels();
489 int digi_get_max_channels() {
490 return digi_max_channels;
494 int digi_is_channel_playing(int channel)
496 if (!digi_initialised)
500 if (SoundSlots[channel].playing)
509 void digi_set_channel_volume(int channel, int volume)
511 if (!digi_initialised)
515 if (SoundSlots[channel].playing)
516 SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
520 void digi_set_channel_pan(int channel, int pan)
522 if (!digi_initialised)
526 if (SoundSlots[channel].playing)
527 SoundSlots[channel].pan = pan;
531 void digi_stop_sound(int channel)
534 SoundSlots[channel].playing = 0;
535 SoundSlots[channel].soundobj = -1;
536 SoundSlots[channel].persistent = 0;
540 void digi_end_sound(int channel)
542 if (!digi_initialised)
546 if (SoundSlots[channel].playing)
548 SoundSlots[channel].soundobj = -1;
549 SoundSlots[channel].persistent = 0;
555 // MIDI stuff follows.
556 //added/killed on 11/25/98 by Matthew Mueller
557 //void digi_set_midi_volume( int mvolume ) { }
558 //void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) {}
559 //void digi_stop_current_song()
568 //end this section kill - MM