]> icculus.org git repositories - btb/d2x.git/blob - arch/linux/alsadigi.c
remove rcs tags
[btb/d2x.git] / arch / linux / alsadigi.c
1 /*
2  *
3  * ALSA digital audio support
4  *
5  */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <alsa/asoundlib.h>
11 #include <pthread.h>
12
13 #include "error.h"
14 #include "mono.h"
15 #include "fix.h"
16 #include "vecmat.h"
17 #include "gr.h" // needed for piggy.h
18 #include "piggy.h"
19 #include "digi.h"
20 #include "sounds.h"
21 #include "wall.h"
22 #include "newdemo.h"
23 #include "kconfig.h"
24
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
27 #ifndef NO_ASM
28 #ifdef __i386__
29 #define do_fixmul(x,y)                          \
30 ({                                              \
31         int _ax, _dx;                           \
32         asm("imull %2\n\tshrdl %3,%1,%0"        \
33             : "=a"(_ax), "=d"(_dx)              \
34             : "rm"(y), "i"(16), "0"(x));        \
35         _ax;                                    \
36 })
37 extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); }
38 #endif
39 #endif
40 //end edit by adb
41 //end edit -MM
42
43 //changed on 980905 by adb to increase number of concurrent sounds
44 #define MAX_SOUND_SLOTS 32
45 //end changes by adb
46 #define SOUND_BUFFER_SIZE 512
47
48 #define MIN_VOLUME 10
49
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.
53  */
54 static const ubyte mix8[] =
55 {
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,
103 };
104
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)
107
108 int digi_volume = SOUND_MAX_VOLUME;
109 //end edit by adb
110
111 static int digi_initialised = 0;
112
113 struct sound_slot {
114  int soundno;
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;
121  //end changes by adb
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];
127
128 static int digi_max_channels = 16;
129
130 static int next_channel = 0;
131
132 /* Threading/ALSA stuff */
133 #define LOCK() pthread_mutex_lock(&mutex)
134 #define UNLOCK() pthread_mutex_unlock(&mutex)
135 snd_pcm_t *snd_devhandle;
136 pthread_t thread_id;
137 pthread_mutex_t mutex;
138
139
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)
143 {
144  ubyte *streamend = stream + len;
145  struct sound_slot *sl;
146
147  for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++)
148  {
149   if (sl->playing)
150   {
151    ubyte *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
152    ubyte *sp = stream;
153    signed char v;
154    fix vl, vr;
155    int x;
156
157    if ((x = sl->pan) & 0x8000)
158    {
159     vl = 0x20000 - x * 2;
160     vr = 0x10000;
161    }
162    else
163    {
164     vl = 0x10000;
165     vr = x * 2;
166    }
167    vl = fixmul(vl, (x = sl->volume));
168    vr = fixmul(vr, x);
169    while (sp < streamend) 
170    {
171     if (sldata == slend)
172     {
173      if (!sl->looped)
174      {
175       sl->playing = 0;
176       break;
177      }
178      sldata = sl->samples;
179     }
180     v = *(sldata++) - 0x80;
181                                 *sp = mix8[*sp + fixmul(v, vl) + 0x80];
182                                 sp++;
183                                 *sp = mix8[*sp + fixmul(v, vr) + 0x80];
184                                 sp++;
185    }
186    sl->position = sldata - sl->samples;
187   }
188  }
189 }
190 //end changes by adb
191
192 void *mixer_thread(void *data)
193 {
194         int err;
195         ubyte buffer[SOUND_BUFFER_SIZE];
196
197         /* Allow ourselves to be asynchronously cancelled */
198         pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
199         while (1)
200         {
201                 memset(buffer, 0x80, SOUND_BUFFER_SIZE);
202                 LOCK();
203                 audio_mixcallback(NULL,buffer,512);
204                 UNLOCK();
205         again:
206                 err = snd_pcm_writei(snd_devhandle, buffer, SOUND_BUFFER_SIZE / 2);
207
208                 if (err == -EPIPE)
209                 {
210                         // Sound buffer underrun
211                         err = snd_pcm_prepare(snd_devhandle);
212                         if (err < 0)
213                         {
214                                 fprintf(stderr, "Can't recover from underrun: %s\n", snd_strerror(err));
215                         }
216                 }
217                 else if (err == -EAGAIN)
218                 {
219                         goto again;
220                 }
221                 else if (err != SOUND_BUFFER_SIZE / 2)
222                 {
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));
226                 }
227         }
228         return 0;
229 }
230
231
232 /* Initialise audio devices. */
233 int digi_init()
234 {
235         int err, tmp;
236         char *device = "plughw:0,0";
237         snd_pcm_hw_params_t *params;
238  pthread_attr_t attr;
239  pthread_mutexattr_t mutexattr;
240
241  //added on 980905 by adb to init sound kill system
242  memset(SampleHandles, 255, sizeof(SampleHandles));
243  //end edit by adb
244
245  /* Open the ALSA sound device */
246         if ((err = snd_pcm_open(&snd_devhandle, device, SND_PCM_STREAM_PLAYBACK)) < 0)
247         {
248      fprintf(stderr, "open failed: %s\n", snd_strerror( err ));  
249      return -1; 
250         }
251
252         snd_pcm_hw_params_alloca(&params);
253         err = snd_pcm_hw_params_any(snd_devhandle, params);
254         if (err < 0)
255         {
256                 printf("ALSA: Error %s\n", snd_strerror(err));
257                 return -1;
258         }
259         err = snd_pcm_hw_params_set_access(snd_devhandle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
260         if (err < 0)
261         {
262                 printf("ALSA: Error %s\n", snd_strerror(err));
263                 return -1;
264         }
265         err = snd_pcm_hw_params_set_format(snd_devhandle, params, SND_PCM_FORMAT_U8);
266         if (err < 0)
267         {
268                 printf("ALSA: Error %s\n", snd_strerror(err));
269                 return -1;
270         }
271         err = snd_pcm_hw_params_set_channels(snd_devhandle, params, 2);
272         if (err < 0)
273         {
274                 printf("ALSA: Error %s\n", snd_strerror(err));
275                 return -1;
276         }
277         tmp = 11025;
278         err = snd_pcm_hw_params_set_rate_near(snd_devhandle, params, &tmp, NULL);
279         if (err < 0)
280         {
281                 printf("ALSA: Error %s\n", snd_strerror(err));
282                 return -1;
283         }
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);
286
287         err = snd_pcm_hw_params(snd_devhandle, params);
288         if (err < 0)
289         {
290                 printf("ALSA: Error %s\n", snd_strerror(err));
291                 return -1;
292         }
293
294  /* Start the mixer thread */
295
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);
300  
301  if (pthread_attr_init(&attr) != 0) {
302   fprintf(stderr, "failed to init attr\n");
303   snd_pcm_close( snd_devhandle ); 
304   return -1;
305  }
306
307  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
308
309  pthread_create(&thread_id,&attr,mixer_thread,NULL);
310  pthread_attr_destroy(&attr);
311
312  atexit(digi_close);
313  digi_initialised = 1;
314  return 0;
315 }
316
317 /* Toggle audio */
318 void digi_reset() { }
319
320 /* Shut down audio */
321 void digi_close()
322 {
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);
328 }
329
330 void digi_stop_all_channels()
331 {
332         int i;
333
334         for (i = 0; i < MAX_SOUND_SLOTS; i++)
335                 digi_stop_sound(i);
336 }
337
338
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);
343
344 // Volume 0-F1_0
345 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
346 {
347         int i, starting_channel;
348
349         if (!digi_initialised) return -1;
350
351         if (soundnum < 0) return -1;
352
353         LOCK();
354         Assert(GameSounds[soundnum].data != (void *)-1);
355
356         starting_channel = next_channel;
357
358         while(1)
359         {
360                 if (!SoundSlots[next_channel].playing)
361                         break;
362
363                 if (!SoundSlots[next_channel].persistent)
364                         break;  // use this channel!    
365
366                 next_channel++;
367                 if (next_channel >= digi_max_channels)
368                         next_channel = 0;
369                 if (next_channel == starting_channel)
370                 {
371                         mprintf((1, "OUT OF SOUND CHANNELS!!!\n"));
372                         UNLOCK();
373                         return -1;
374                 }
375         }
376         if (SoundSlots[next_channel].playing)
377         {
378                 SoundSlots[next_channel].playing = 0;
379                 if (SoundSlots[next_channel].soundobj > -1)
380                 {
381                         digi_end_soundobj(SoundSlots[next_channel].soundobj);
382                 }
383                 if (SoundQ_channel == next_channel)
384                         SoundQ_end();
385         }
386
387 #ifndef NDEBUG
388         verify_sound_channel_free(next_channel);
389 #endif
390
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;
403
404         i = next_channel;
405         next_channel++;
406         if (next_channel >= digi_max_channels)
407                 next_channel = 0;
408         UNLOCK();
409
410         return i;
411 }
412
413 // Returns the channel a sound number is playing on, or
414 // -1 if none.
415 int digi_find_channel(int soundno)
416 {
417         if (!digi_initialised)
418                 return -1;
419
420         if (soundno < 0 )
421                 return -1;
422
423         if (GameSounds[soundno].data == NULL)
424         {
425                 Int3();
426                 return -1;
427         }
428
429         //FIXME: not implemented
430         return -1;
431 }
432
433
434 //added on 980905 by adb from original source to make sfx volume work
435 void digi_set_digi_volume( int dvolume )
436 {
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 )
441                 digi_volume = 0;
442         else
443                 digi_volume = dvolume;
444
445         if ( !digi_initialised ) return;
446
447         digi_sync_sounds();
448 }
449 //end edit by adb
450
451 void digi_set_volume(int dvolume, int mvolume)
452 {
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 ));
456 }
457
458 int digi_is_sound_playing(int soundno)
459 {
460         int i;
461
462         soundno = digi_xlat_sound(soundno);
463
464         LOCK();
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)
468                   //end changes by adb
469                   { UNLOCK();   return 1; }
470         UNLOCK();
471         return 0;
472 }
473
474
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;
478
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;
483
484         if ( !digi_initialised ) return;
485
486         digi_stop_all_channels();
487 }
488
489 int digi_get_max_channels() { 
490         return digi_max_channels; 
491 }
492 // end edit by adb
493
494 int digi_is_channel_playing(int channel)
495 {
496         if (!digi_initialised)
497                 return 0;
498
499         LOCK();
500         if (SoundSlots[channel].playing)
501         {
502                 UNLOCK();
503                 return 1;
504         }
505         UNLOCK();
506         return 0;
507 }
508
509 void digi_set_channel_volume(int channel, int volume)
510 {
511         if (!digi_initialised)
512                 return;
513
514         LOCK();
515         if (SoundSlots[channel].playing)
516                 SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
517         UNLOCK();
518 }
519
520 void digi_set_channel_pan(int channel, int pan)
521 {
522         if (!digi_initialised)
523                 return;
524
525         LOCK();
526         if (SoundSlots[channel].playing)
527                 SoundSlots[channel].pan = pan;
528         UNLOCK();
529 }
530
531 void digi_stop_sound(int channel)
532 {
533         LOCK();
534         SoundSlots[channel].playing = 0;
535         SoundSlots[channel].soundobj = -1;
536         SoundSlots[channel].persistent = 0;
537         UNLOCK();
538 }
539
540 void digi_end_sound(int channel)
541 {
542         if (!digi_initialised)
543                 return;
544
545         LOCK();
546         if (SoundSlots[channel].playing)
547         {
548                 SoundSlots[channel].soundobj = -1;
549                 SoundSlots[channel].persistent = 0;
550         }
551         UNLOCK();
552 }
553
554
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()
560 //{
561 //#ifdef HMIPLAY
562 //        char buf[10];
563 //    
564 //        sprintf(buf,"s");
565 //        send_ipc(buf);
566 //#endif
567 //}
568 //end this section kill - MM