1 /* $Id: alsadigi.c,v 1.4 2005-02-25 10:49:48 btb Exp $ */
4 * ALSA digital audio support
11 #include <alsa/asoundlib.h>
18 #include "gr.h" // needed for piggy.h
26 //edited 05/17/99 Matt Mueller - added ifndef NO_ASM
27 //added on 980905 by adb to add inline fixmul for mixer on i386
30 #define do_fixmul(x,y) \
33 asm("imull %2\n\tshrdl %3,%1,%0" \
34 : "=a"(_ax), "=d"(_dx) \
35 : "rm"(y), "i"(16), "0"(x)); \
38 extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); }
44 //changed on 980905 by adb to increase number of concurrent sounds
45 #define MAX_SOUND_SLOTS 32
47 #define SOUND_BUFFER_SIZE 512
51 /* This table is used to add two sound values together and pin
52 * the value to avoid overflow. (used with permission from ARDI)
53 * DPH: Taken from SDL/src/SDL_mixer.c.
55 static const ubyte mix8[] =
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, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
69 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
70 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
71 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
72 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
73 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
74 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
75 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
76 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
77 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
78 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
79 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
80 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
81 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
82 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
83 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
84 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
85 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
86 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
87 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
88 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
89 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
90 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
91 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
103 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
106 //added/changed on 980905 by adb to make sfx volume work, on 990221 by adb changed F1_0 to F1_0 / 2
107 #define SOUND_MAX_VOLUME (F1_0 / 2)
109 int digi_volume = SOUND_MAX_VOLUME;
112 static int digi_initialised = 0;
116 int playing; // Is there a sample playing on this channel?
117 int looped; // Play this sample looped?
118 fix pan; // 0 = far left, 1 = far right
119 fix volume; // 0 = nothing, 1 = fully on
120 //changed on 980905 by adb from char * to unsigned char *
121 unsigned char *samples;
123 unsigned int length; // Length of the sample
124 unsigned int position; // Position we are at at the moment.
125 int soundobj; // Which soundobject is on this channel
126 int persistent; // This can't be pre-empted
127 } SoundSlots[MAX_SOUND_SLOTS];
129 static int digi_max_channels = 16;
131 static int next_channel = 0;
133 /* Threading/ALSA stuff */
134 #define LOCK() pthread_mutex_lock(&mutex)
135 #define UNLOCK() pthread_mutex_unlock(&mutex)
136 snd_pcm_t *snd_devhandle;
138 pthread_mutex_t mutex;
141 /* Audio mixing callback */
142 //changed on 980905 by adb to cleanup, add pan support and optimize mixer
143 static void audio_mixcallback(void *userdata, ubyte *stream, int len)
145 ubyte *streamend = stream + len;
146 struct sound_slot *sl;
148 for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++)
152 ubyte *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
158 if ((x = sl->pan) & 0x8000)
160 vl = 0x20000 - x * 2;
168 vl = fixmul(vl, (x = sl->volume));
170 while (sp < streamend)
179 sldata = sl->samples;
181 v = *(sldata++) - 0x80;
182 *sp = mix8[*sp + fixmul(v, vl) + 0x80];
184 *sp = mix8[*sp + fixmul(v, vr) + 0x80];
187 sl->position = sldata - sl->samples;
193 void *mixer_thread(void *data)
196 ubyte buffer[SOUND_BUFFER_SIZE];
198 /* Allow ourselves to be asynchronously cancelled */
199 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
202 memset(buffer, 0x80, SOUND_BUFFER_SIZE);
204 audio_mixcallback(NULL,buffer,512);
207 err = snd_pcm_writei(snd_devhandle, buffer, SOUND_BUFFER_SIZE / 2);
211 // Sound buffer underrun
212 err = snd_pcm_prepare(snd_devhandle);
215 fprintf(stderr, "Can't recover from underrun: %s\n", snd_strerror(err));
218 else if (err == -EAGAIN)
222 else if (err != SOUND_BUFFER_SIZE / 2)
224 // Each frame has size 2 bytes - hence we expect SOUND_BUFFER_SIZE/2
225 // frames to be written.
226 fprintf(stderr, "Unknown err %d: %s\n", err, snd_strerror(err));
233 /* Initialise audio devices. */
237 char *device = "plughw:0,0";
238 snd_pcm_hw_params_t *params;
240 pthread_mutexattr_t mutexattr;
242 //added on 980905 by adb to init sound kill system
243 memset(SampleHandles, 255, sizeof(SampleHandles));
246 /* Open the ALSA sound device */
247 if ((err = snd_pcm_open(&snd_devhandle, device, SND_PCM_STREAM_PLAYBACK)) < 0)
249 fprintf(stderr, "open failed: %s\n", snd_strerror( err ));
253 snd_pcm_hw_params_alloca(¶ms);
254 err = snd_pcm_hw_params_any(snd_devhandle, params);
257 printf("ALSA: Error %s\n", snd_strerror(err));
260 err = snd_pcm_hw_params_set_access(snd_devhandle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
263 printf("ALSA: Error %s\n", snd_strerror(err));
266 err = snd_pcm_hw_params_set_format(snd_devhandle, params, SND_PCM_FORMAT_U8);
269 printf("ALSA: Error %s\n", snd_strerror(err));
272 err = snd_pcm_hw_params_set_channels(snd_devhandle, params, 2);
275 printf("ALSA: Error %s\n", snd_strerror(err));
279 err = snd_pcm_hw_params_set_rate_near(snd_devhandle, params, &tmp, NULL);
282 printf("ALSA: Error %s\n", snd_strerror(err));
285 snd_pcm_hw_params_set_periods(snd_devhandle, params, 3, 0);
286 snd_pcm_hw_params_set_buffer_size(snd_devhandle,params, (SOUND_BUFFER_SIZE*3)/2);
288 err = snd_pcm_hw_params(snd_devhandle, params);
291 printf("ALSA: Error %s\n", snd_strerror(err));
295 /* Start the mixer thread */
297 /* We really should check the results of these */
298 pthread_mutexattr_init(&mutexattr);
299 pthread_mutex_init(&mutex,&mutexattr);
300 pthread_mutexattr_destroy(&mutexattr);
302 if (pthread_attr_init(&attr) != 0) {
303 fprintf(stderr, "failed to init attr\n");
304 snd_pcm_close( snd_devhandle );
308 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
310 pthread_create(&thread_id,&attr,mixer_thread,NULL);
311 pthread_attr_destroy(&attr);
314 digi_initialised = 1;
319 void digi_reset() { }
321 /* Shut down audio */
324 if (!digi_initialised) return;
325 pthread_cancel(thread_id);
326 digi_initialised = 0;
327 pthread_mutex_destroy(&mutex);
328 snd_pcm_close(snd_devhandle);
331 void digi_stop_all_channels()
335 for (i = 0; i < MAX_SOUND_SLOTS; i++)
340 extern void digi_end_soundobj(int channel);
341 extern int SoundQ_channel;
342 extern void SoundQ_end();
343 int verify_sound_channel_free(int channel);
346 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
348 int i, starting_channel;
350 if (!digi_initialised) return -1;
352 if (soundnum < 0) return -1;
355 Assert(GameSounds[soundnum].data != (void *)-1);
357 starting_channel = next_channel;
361 if (!SoundSlots[next_channel].playing)
364 if (!SoundSlots[next_channel].persistent)
365 break; // use this channel!
368 if (next_channel >= digi_max_channels)
370 if (next_channel == starting_channel)
372 mprintf((1, "OUT OF SOUND CHANNELS!!!\n"));
377 if (SoundSlots[next_channel].playing)
379 SoundSlots[next_channel].playing = 0;
380 if (SoundSlots[next_channel].soundobj > -1)
382 digi_end_soundobj(SoundSlots[next_channel].soundobj);
384 if (SoundQ_channel == next_channel)
389 verify_sound_channel_free(next_channel);
392 SoundSlots[next_channel].soundno = soundnum;
393 SoundSlots[next_channel].samples = GameSounds[soundnum].data;
394 SoundSlots[next_channel].length = GameSounds[soundnum].length;
395 SoundSlots[next_channel].volume = fixmul(digi_volume, volume);
396 SoundSlots[next_channel].pan = pan;
397 SoundSlots[next_channel].position = 0;
398 SoundSlots[next_channel].looped = looping;
399 SoundSlots[next_channel].playing = 1;
400 SoundSlots[next_channel].soundobj = soundobj;
401 SoundSlots[next_channel].persistent = 0;
402 if ((soundobj > -1) || (looping) || (volume > F1_0))
403 SoundSlots[next_channel].persistent = 1;
407 if (next_channel >= digi_max_channels)
414 // Returns the channel a sound number is playing on, or
416 int digi_find_channel(int soundno)
418 if (!digi_initialised)
424 if (GameSounds[soundno].data == NULL)
430 //FIXME: not implemented
435 //added on 980905 by adb from original source to make sfx volume work
436 void digi_set_digi_volume( int dvolume )
438 dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
439 if ( dvolume > SOUND_MAX_VOLUME )
440 digi_volume = SOUND_MAX_VOLUME;
441 else if ( dvolume < 0 )
444 digi_volume = dvolume;
446 if ( !digi_initialised ) return;
452 void digi_set_volume(int dvolume, int mvolume)
454 digi_set_digi_volume(dvolume);
455 digi_set_midi_volume(mvolume);
456 // mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume ));
459 int digi_is_sound_playing(int soundno)
463 soundno = digi_xlat_sound(soundno);
466 for (i = 0; i < MAX_SOUND_SLOTS; i++)
467 //changed on 980905 by adb: added SoundSlots[i].playing &&
468 if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
470 { UNLOCK(); return 1; }
476 //added on 980905 by adb to make sound channel setting work
477 void digi_set_max_channels(int n) {
478 digi_max_channels = n;
480 if ( digi_max_channels < 1 )
481 digi_max_channels = 1;
482 if (digi_max_channels > MAX_SOUND_SLOTS)
483 digi_max_channels = MAX_SOUND_SLOTS;
485 if ( !digi_initialised ) return;
487 digi_stop_all_channels();
490 int digi_get_max_channels() {
491 return digi_max_channels;
495 int digi_is_channel_playing(int channel)
497 if (!digi_initialised)
501 if (SoundSlots[channel].playing)
510 void digi_set_channel_volume(int channel, int volume)
512 if (!digi_initialised)
516 if (SoundSlots[channel].playing)
517 SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
521 void digi_set_channel_pan(int channel, int pan)
523 if (!digi_initialised)
527 if (SoundSlots[channel].playing)
528 SoundSlots[channel].pan = pan;
532 void digi_stop_sound(int channel)
535 SoundSlots[channel].playing = 0;
536 SoundSlots[channel].soundobj = -1;
537 SoundSlots[channel].persistent = 0;
541 void digi_end_sound(int channel)
543 if (!digi_initialised)
547 if (SoundSlots[channel].playing)
549 SoundSlots[channel].soundobj = -1;
550 SoundSlots[channel].persistent = 0;
556 // MIDI stuff follows.
557 //added/killed on 11/25/98 by Matthew Mueller
558 //void digi_set_midi_volume( int mvolume ) { }
559 //void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) {}
560 //void digi_stop_current_song()
569 //end this section kill - MM