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