]> icculus.org git repositories - btb/d2x.git/blob - arch/linux/alsadigi.c
more d1 level loading stuff
[btb/d2x.git] / arch / linux / alsadigi.c
1 // ALSA digital audio support
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <sys/asoundlib.h>
7 #include <pthread.h>
8
9 #include "error.h"
10 #include "mono.h"
11 #include "fix.h"
12 #include "vecmat.h"
13 #include "gr.h" // needed for piggy.h
14 #include "piggy.h"
15 #include "digi.h"
16 #include "sounds.h"
17 #include "wall.h"
18 #include "newdemo.h"
19 #include "kconfig.h"
20
21 //edited 05/17/99 Matt Mueller - added ifndef NO_ASM
22 //added on 980905 by adb to add inline fixmul for mixer on i386
23 #ifndef NO_ASM
24 #ifdef __i386__
25 #define do_fixmul(x,y)                          \
26 ({                                              \
27         int _ax, _dx;                           \
28         asm("imull %2\n\tshrdl %3,%1,%0"        \
29             : "=a"(_ax), "=d"(_dx)              \
30             : "rm"(y), "i"(16), "0"(x));        \
31         _ax;                                    \
32 })
33 extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); }
34 #endif
35 #endif
36 //end edit by adb
37 //end edit -MM
38
39 //changed on 980905 by adb to increase number of concurrent sounds
40 #define MAX_SOUND_SLOTS 32
41 //end changes by adb
42 #define SOUND_BUFFER_SIZE 512
43
44 #define MIN_VOLUME 10
45
46 /* This table is used to add two sound values together and pin
47  * the value to avoid overflow.  (used with permission from ARDI)
48  * DPH: Taken from SDL/src/SDL_mixer.c.
49  */
50 static const ubyte mix8[] =
51 {
52   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, 0x01, 0x02, 0x03,
64   0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
65   0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
66   0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
67   0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
68   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
69   0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
70   0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
71   0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
72   0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
73   0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
74   0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
75   0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
76   0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
77   0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
78   0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
79   0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
80   0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
81   0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
82   0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
83   0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
84   0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
85   0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
86   0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF,
87   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
88   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
89   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
90   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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,
99 };
100
101 #define SOF_USED                        1               // Set if this sample is used
102 #define SOF_PLAYING                     2               // Set if this sample is playing on a channel
103 #define SOF_LINK_TO_OBJ         4               // Sound is linked to a moving object. If object dies, then finishes play and quits.
104 #define SOF_LINK_TO_POS         8               // Sound is linked to segment, pos
105 #define SOF_PLAY_FOREVER        16              // Play forever (or until level is stopped), otherwise plays once
106
107 typedef struct sound_object {
108         short           signature;              // A unique signature to this sound
109         ubyte           flags;                  // Used to tell if this slot is used and/or currently playing, and how long.
110         fix             max_volume;             // Max volume that this sound is playing at
111         fix             max_distance;           // The max distance that this sound can be heard at...
112         int             volume;                 // Volume that this sound is playing at
113         int             pan;                    // Pan value that this sound is playing at
114         int             handle;                 // What handle this sound is playing on.  Valid only if SOF_PLAYING is set.
115         short           soundnum;               // The sound number that is playing
116         union { 
117                 struct {
118                         short           segnum;                         // Used if SOF_LINK_TO_POS field is used
119                         short           sidenum;
120                         vms_vector      position;
121                 }pos;
122                 struct {
123                         short            objnum;                         // Used if SOF_LINK_TO_OBJ field is used
124                         short            objsignature;
125                 }obj;
126         }link;
127 } sound_object;
128 #define lp_segnum link.pos.segnum
129 #define lp_sidenum link.pos.sidenum
130 #define lp_position link.pos.position
131
132 #define lo_objnum link.obj.objnum
133 #define lo_objsignature link.obj.objsignature
134
135 #define MAX_SOUND_OBJECTS 16
136 sound_object SoundObjects[MAX_SOUND_OBJECTS];
137 short next_signature=0;
138
139 //added/changed on 980905 by adb to make sfx volume work, on 990221 by adb changed F1_0 to F1_0 / 2
140 #define SOUND_MAX_VOLUME (F1_0 / 2)
141
142 int digi_volume = SOUND_MAX_VOLUME;
143 //end edit by adb
144
145 int digi_lomem = 0;
146
147 static int digi_initialised = 0;
148
149 struct sound_slot {
150  int soundno;
151  int playing;   // Is there a sample playing on this channel?
152  int looped;    // Play this sample looped?
153  fix pan;       // 0 = far left, 1 = far right
154  fix volume;    // 0 = nothing, 1 = fully on
155  //changed on 980905 by adb from char * to unsigned char * 
156  unsigned char *samples;
157  //end changes by adb
158  unsigned int length; // Length of the sample
159  unsigned int position; // Position we are at at the moment.
160 } SoundSlots[MAX_SOUND_SLOTS];
161
162 static int digi_sounds_initialized = 0;
163
164 //added on 980905 by adb to add rotating/volume based sound kill system
165 static int digi_max_channels = 16;
166 static int next_handle = 0;
167 int SampleHandles[32];
168 void reset_sounds_on_channel(int channel);
169 //end edit by adb
170
171 /* Threading/ALSA stuff */
172 #define LOCK() pthread_mutex_lock(&mutex)
173 #define UNLOCK() pthread_mutex_unlock(&mutex)
174 void *snd_devhandle;
175 pthread_t thread_id;
176 pthread_mutex_t mutex;
177
178
179 void digi_reset_digi_sounds(void);
180
181
182 /* Audio mixing callback */
183 //changed on 980905 by adb to cleanup, add pan support and optimize mixer
184 static void audio_mixcallback(void *userdata, ubyte *stream, int len)
185 {
186  ubyte *streamend = stream + len;
187  struct sound_slot *sl;
188
189  for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++)
190  {
191   if (sl->playing)
192   {
193    ubyte *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
194    ubyte *sp = stream;
195    signed char v;
196    fix vl, vr;
197    int x;
198
199    if ((x = sl->pan) & 0x8000)
200    {
201     vl = 0x20000 - x * 2;
202     vr = 0x10000;
203    }
204    else
205    {
206     vl = 0x10000;
207     vr = x * 2;
208    }
209    vl = fixmul(vl, (x = sl->volume));
210    vr = fixmul(vr, x);
211    while (sp < streamend) 
212    {
213     if (sldata == slend)
214     {
215      if (!sl->looped)
216      {
217       sl->playing = 0;
218       break;
219      }
220      sldata = sl->samples;
221     }
222     v = *(sldata++) - 0x80;
223     *(sp++) = mix8[ *sp + fixmul(v, vl) + 0x80 ];
224     *(sp++) = mix8[ *sp + fixmul(v, vr) + 0x80 ];
225    }
226    sl->position = sldata - sl->samples;
227   }
228  }
229 }
230 //end changes by adb
231
232 void *mixer_thread(void *data) {
233 // int i=0;
234  ubyte buffer[512];
235  /* Allow ourselves to be asynchronously cancelled */
236  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
237  while (1) {
238 //   printf("i=%d\n",i++);
239    memset(buffer, 0x80, 512);
240    LOCK();
241    audio_mixcallback(NULL,buffer,512);
242    UNLOCK();
243    snd_pcm_write(snd_devhandle, buffer, 512);
244  } 
245  return 0;
246 }
247
248
249 /* Initialise audio devices. */
250 int digi_init()
251 {
252  int card=0, device=0, err;
253  snd_pcm_format_t format;
254  snd_pcm_playback_params_t params;
255  pthread_attr_t attr;
256  pthread_mutexattr_t mutexattr;
257
258  //added on 980905 by adb to init sound kill system
259  memset(SampleHandles, 255, sizeof(SampleHandles));
260  //end edit by adb
261
262  /* Open the ALSA sound device */
263  if ((err = snd_pcm_open(&snd_devhandle, card, device, 
264      SND_PCM_OPEN_PLAYBACK)) < 0) {  
265      fprintf(stderr, "open failed: %s\n", snd_strerror( err ));  
266      return -1; 
267  } 
268
269  memset(&format, 0, sizeof(format));
270  format.format = SND_PCM_SFMT_U8;
271  format.rate = 11025;
272  format.channels = 2;
273  if ((err = snd_pcm_playback_format(snd_devhandle, &format)) < 0) { 
274     fprintf(stderr, "format setup failed: %s\n", snd_strerror( err ));
275     snd_pcm_close( snd_devhandle ); 
276     return -1; 
277  } 
278
279  memset(&params, 0, sizeof(params));
280  params.fragment_size=512;
281  params.fragments_max=2;
282  params.fragments_room=1;
283  if ((err = snd_pcm_playback_params(snd_devhandle, &params)) < 0) { 
284     fprintf(stderr, "params setup failed: %s\n", snd_strerror( err ));
285     snd_pcm_close( snd_devhandle ); 
286     return -1; 
287  }
288
289  /* Start the mixer thread */
290
291  /* We really should check the results of these */
292  pthread_mutexattr_init(&mutexattr);
293  pthread_mutex_init(&mutex,&mutexattr);
294  pthread_mutexattr_destroy(&mutexattr);
295  
296  if (pthread_attr_init(&attr) != 0) {
297   fprintf(stderr, "failed to init attr\n");
298   snd_pcm_close( snd_devhandle ); 
299   return -1;
300  }
301
302  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
303
304  pthread_create(&thread_id,&attr,mixer_thread,NULL);
305  pthread_attr_destroy(&attr);
306
307  atexit(digi_close);
308  digi_initialised = 1;
309  return 0;
310 }
311
312 /* Toggle audio */
313 void digi_reset() { }
314
315 /* Shut down audio */
316 void digi_close()
317 {
318  if (!digi_initialised) return;
319  digi_initialised = 0;
320  snd_pcm_close(snd_devhandle);
321  pthread_mutex_destroy(&mutex);
322  pthread_cancel(thread_id);
323 }
324
325 /* Find the sound which actually equates to a sound number */
326 int digi_xlat_sound(int soundno)
327 {
328         if ( soundno < 0 ) return -1;
329
330         if ( digi_lomem )       {
331                 soundno = AltSounds[soundno];
332                 if ( soundno == 255 ) return -1;
333         }
334         return Sounds[soundno];
335 }
336
337 static int get_free_slot()
338 {
339  int i;
340  for (i=0; i<MAX_SOUND_SLOTS; i++)
341  {
342   if (!SoundSlots[i].playing) return i;
343  }
344  return -1;
345 }
346
347 int digi_start_sound(int soundnum, fix volume, fix pan)
348 {
349  int ntries;
350  int slot;
351
352  if (!digi_initialised) return -1;
353  LOCK();
354  //added on 980905 by adb from original source to add sound kill system
355  // play at most digi_max_channel samples, if possible kill sample with low volume
356  ntries = 0;
357
358 TryNextChannel:
359  if ( (SampleHandles[next_handle] >= 0) && (SoundSlots[SampleHandles[next_handle]].playing)  )
360  {
361   if ( (SoundSlots[SampleHandles[next_handle]].volume > digi_volume) && (ntries<digi_max_channels) )
362   {
363    //mprintf(( 0, "Not stopping loud sound %d.\n", next_handle ));
364    next_handle++;
365    if ( next_handle >= digi_max_channels )
366     next_handle = 0;
367    ntries++;
368    goto TryNextChannel;
369   }
370   //mprintf(( 0, "[SS:%d]", next_handle ));
371   SoundSlots[SampleHandles[next_handle]].playing = 0;
372   SampleHandles[next_handle] = -1;
373  }
374  //end edit by adb
375
376  slot = get_free_slot();
377  if (slot<0) return -1;
378
379  SoundSlots[slot].soundno = soundnum;
380  SoundSlots[slot].samples = GameSounds[soundnum].data;
381  SoundSlots[slot].length = GameSounds[soundnum].length;
382  SoundSlots[slot].volume = fixmul(digi_volume, volume);
383  SoundSlots[slot].pan = pan;
384  SoundSlots[slot].position = 0;
385  SoundSlots[slot].looped = 0;
386  SoundSlots[slot].playing = 1;
387
388  //added on 980905 by adb to add sound kill system from original sos digi.c
389  reset_sounds_on_channel(slot);
390  SampleHandles[next_handle] = slot;
391  next_handle++;
392  if ( next_handle >= digi_max_channels )
393   next_handle = 0;
394  //end edit by adb
395  UNLOCK();
396  return slot;
397 }
398
399  //added on 980905 by adb to add sound kill system from original sos digi.c
400 void reset_sounds_on_channel( int channel )
401 {
402  int i;
403
404  for (i=0; i<digi_max_channels; i++)
405   if (SampleHandles[i] == channel)
406    SampleHandles[i] = -1;
407 }
408 //end edit by adb
409
410 int digi_start_sound_object(int obj)
411 {
412  int slot;
413
414  if (!digi_initialised) return -1;
415  LOCK();
416  slot = get_free_slot();
417
418  if (slot<0) { UNLOCK(); return -1; }
419
420
421  SoundSlots[slot].soundno = SoundObjects[obj].soundnum;
422  SoundSlots[slot].samples = GameSounds[SoundObjects[obj].soundnum].data;
423  SoundSlots[slot].length = GameSounds[SoundObjects[obj].soundnum].length;
424  SoundSlots[slot].volume = fixmul(digi_volume, SoundObjects[obj].volume);
425  SoundSlots[slot].pan = SoundObjects[obj].pan;
426  SoundSlots[slot].position = 0;
427  SoundSlots[slot].looped = (SoundObjects[obj].flags & SOF_PLAY_FOREVER);
428  SoundSlots[slot].playing = 1;
429
430  SoundObjects[obj].signature = next_signature++;
431  SoundObjects[obj].handle = slot;
432
433  SoundObjects[obj].flags |= SOF_PLAYING;
434  //added on 980905 by adb to add sound kill system from original sos digi.c
435  reset_sounds_on_channel(slot);
436  //end edit by adb
437  
438  UNLOCK();
439  return 0;
440 }
441
442
443 // Play the given sound number.
444 // Volume is max at F1_0.
445 void digi_play_sample( int soundno, fix max_volume )
446 {
447 #ifdef NEWDEMO
448         if ( Newdemo_state == ND_STATE_RECORDING )
449                 newdemo_record_sound( soundno );
450 #endif
451         soundno = digi_xlat_sound(soundno);
452
453         if (!digi_initialised) return;
454
455         if (soundno < 0 ) return;
456
457         digi_start_sound(soundno, max_volume, F0_5);
458 }
459
460 // Play the given sound number. If the sound is already playing,
461 // restart it.
462 void digi_play_sample_once( int soundno, fix max_volume )
463 {
464         int i;
465
466 #ifdef NEWDEMO
467         if ( Newdemo_state == ND_STATE_RECORDING )
468                 newdemo_record_sound( soundno );
469 #endif
470         soundno = digi_xlat_sound(soundno);
471
472         if (!digi_initialised) return;
473
474         if (soundno < 0 ) return;
475
476         LOCK();
477         for (i=0; i < MAX_SOUND_SLOTS; i++)
478           if (SoundSlots[i].soundno == soundno)
479             SoundSlots[i].playing = 0;
480         UNLOCK();
481         digi_start_sound(soundno, max_volume, F0_5);
482
483 }
484
485 void digi_play_sample_3d( int soundno, int angle, int volume, int no_dups ) // Volume from 0-0x7fff
486 {
487         no_dups = 1;
488
489 #ifdef NEWDEMO
490         if ( Newdemo_state == ND_STATE_RECORDING )              {
491                 if ( no_dups )
492                         newdemo_record_sound_3d_once( soundno, angle, volume );
493                 else
494                         newdemo_record_sound_3d( soundno, angle, volume );
495         }
496 #endif
497         soundno = digi_xlat_sound(soundno);
498
499         if (!digi_initialised) return;
500         if (soundno < 0 ) return;
501
502         if (volume < MIN_VOLUME ) return;
503         digi_start_sound(soundno, volume, angle);
504 }
505
506 void digi_get_sound_loc( vms_matrix * listener, vms_vector * listener_pos, int listener_seg, vms_vector * sound_pos, int sound_seg, fix max_volume, int *volume, int *pan, fix max_distance )
507 {         
508         vms_vector      vector_to_sound;
509         fix angle_from_ear, cosang,sinang;
510         fix distance;
511         fix path_distance;
512
513         *volume = 0;
514         *pan = 0;
515
516         max_distance = (max_distance*5)/4;              // Make all sounds travel 1.25 times as far.
517
518         //      Warning: Made the vm_vec_normalized_dir be vm_vec_normalized_dir_quick and got illegal values to acos in the fang computation.
519         distance = vm_vec_normalized_dir_quick( &vector_to_sound, sound_pos, listener_pos );
520                 
521         if (distance < max_distance )   {
522                 int num_search_segs = f2i(max_distance/20);
523                 if ( num_search_segs < 1 ) num_search_segs = 1;
524
525                 path_distance = find_connected_distance(listener_pos, listener_seg, sound_pos, sound_seg, num_search_segs, WID_RENDPAST_FLAG );
526                 if ( path_distance > -1 )       {
527                         *volume = max_volume - fixdiv(path_distance,max_distance);
528                         //mprintf( (0, "Sound path distance %.2f, volume is %d / %d\n", f2fl(distance), *volume, max_volume ));
529                         if (*volume > 0 )       {
530                                 angle_from_ear = vm_vec_delta_ang_norm(&listener->rvec,&vector_to_sound,&listener->uvec);
531                                 fix_sincos(angle_from_ear,&sinang,&cosang);
532                                 //mprintf( (0, "volume is %.2f\n", f2fl(*volume) ));
533                                 if (Config_channels_reversed) cosang *= -1;
534                                 *pan = (cosang + F1_0)/2;
535                         } else {
536                                 *volume = 0;
537                         }
538                 }
539         }                                                                                                                                                                         
540 }
541
542 int digi_link_sound_to_object2( int org_soundnum, short objnum, int forever, fix max_volume, fix  max_distance )
543 {
544         int i,volume,pan;
545         object * objp;
546         int soundnum;
547
548         soundnum = digi_xlat_sound(org_soundnum);
549
550         if ( max_volume < 0 ) return -1;
551 //      if ( max_volume > F1_0 ) max_volume = F1_0;
552
553         if (!digi_initialised) return -1;
554         if (soundnum < 0 ) return -1;
555         if (GameSounds[soundnum].data==NULL) {
556                 Int3();
557                 return -1;
558         }
559         if ((objnum<0)||(objnum>Highest_object_index))
560                 return -1;
561
562         if ( !forever ) {
563                 // Hack to keep sounds from building up...
564                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, &Objects[objnum].pos, Objects[objnum].segnum, max_volume,&volume, &pan, max_distance );
565                 digi_play_sample_3d( org_soundnum, pan, volume, 0 );
566                 return -1;
567         }
568
569         for (i=0; i<MAX_SOUND_OBJECTS; i++ )
570                 if (SoundObjects[i].flags==0)
571                    break;
572
573         if (i==MAX_SOUND_OBJECTS) {
574                 mprintf((1, "Too many sound objects!\n" ));
575                 return -1;
576         }
577
578         SoundObjects[i].signature=next_signature++;
579         SoundObjects[i].flags = SOF_USED | SOF_LINK_TO_OBJ;
580         if ( forever )
581                 SoundObjects[i].flags |= SOF_PLAY_FOREVER;
582         SoundObjects[i].lo_objnum = objnum;
583         SoundObjects[i].lo_objsignature = Objects[objnum].signature;
584         SoundObjects[i].max_volume = max_volume;
585         SoundObjects[i].max_distance = max_distance;
586         SoundObjects[i].volume = 0;
587         SoundObjects[i].pan = 0;
588         SoundObjects[i].soundnum = soundnum;
589
590         objp = &Objects[SoundObjects[i].lo_objnum];
591         digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
592                        &objp->pos, objp->segnum, SoundObjects[i].max_volume,
593                        &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
594
595         if (!forever || SoundObjects[i].volume >= MIN_VOLUME)
596                digi_start_sound_object(i);
597
598         return SoundObjects[i].signature;
599 }
600
601 int digi_link_sound_to_object( int soundnum, short objnum, int forever, fix max_volume )
602 { return digi_link_sound_to_object2( soundnum, objnum, forever, max_volume, 256*F1_0); }
603
604 int digi_link_sound_to_pos2( int org_soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume, fix max_distance )
605 {
606         int i, volume, pan;
607         int soundnum;
608
609         soundnum = digi_xlat_sound(org_soundnum);
610
611         if ( max_volume < 0 ) return -1;
612 //      if ( max_volume > F1_0 ) max_volume = F1_0;
613
614         if (!digi_initialised) return -1;
615         if (soundnum < 0 ) return -1;
616         if (GameSounds[soundnum].data==NULL) {
617                 Int3();
618                 return -1;
619         }
620
621         if ((segnum<0)||(segnum>Highest_segment_index))
622                 return -1;
623
624         if ( !forever ) {
625                 // Hack to keep sounds from building up...
626                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, pos, segnum, max_volume, &volume, &pan, max_distance );
627                 digi_play_sample_3d( org_soundnum, pan, volume, 0 );
628                 return -1;
629         }
630
631         for (i=0; i<MAX_SOUND_OBJECTS; i++ )
632                 if (SoundObjects[i].flags==0)
633                         break;
634         
635         if (i==MAX_SOUND_OBJECTS) {
636                 mprintf((1, "Too many sound objects!\n" ));
637                 return -1;
638         }
639
640
641         SoundObjects[i].signature=next_signature++;
642         SoundObjects[i].flags = SOF_USED | SOF_LINK_TO_POS;
643         if ( forever )
644                 SoundObjects[i].flags |= SOF_PLAY_FOREVER;
645         SoundObjects[i].lp_segnum = segnum;
646         SoundObjects[i].lp_sidenum = sidenum;
647         SoundObjects[i].lp_position = *pos;
648         SoundObjects[i].soundnum = soundnum;
649         SoundObjects[i].max_volume = max_volume;
650         SoundObjects[i].max_distance = max_distance;
651         SoundObjects[i].volume = 0;
652         SoundObjects[i].pan = 0;
653         digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
654                                            &SoundObjects[i].lp_position, SoundObjects[i].lp_segnum,
655                                            SoundObjects[i].max_volume,
656                        &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
657         
658         if (!forever || SoundObjects[i].volume >= MIN_VOLUME)
659                 digi_start_sound_object(i);
660
661         return SoundObjects[i].signature;
662 }
663
664 int digi_link_sound_to_pos( int soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume )
665 {
666         return digi_link_sound_to_pos2( soundnum, segnum, sidenum, pos, forever, max_volume, F1_0 * 256 );
667 }
668
669 void digi_kill_sound_linked_to_segment( int segnum, int sidenum, int soundnum )
670 {
671         int i,killed;
672
673         soundnum = digi_xlat_sound(soundnum);
674
675         if (!digi_initialised) return;
676
677         killed = 0;
678
679         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
680                 if ( (SoundObjects[i].flags & SOF_USED) && (SoundObjects[i].flags & SOF_LINK_TO_POS) )  {
681                         if ((SoundObjects[i].lp_segnum == segnum) && (SoundObjects[i].soundnum==soundnum ) && (SoundObjects[i].lp_sidenum==sidenum) ) {
682                                 if ( SoundObjects[i].flags & SOF_PLAYING )      {
683                                         LOCK();
684                                         SoundSlots[SoundObjects[i].handle].playing = 0;
685                                         UNLOCK();
686                                 }
687                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
688                                 killed++;
689                         }
690                 }
691         }
692         // If this assert happens, it means that there were 2 sounds
693         // that got deleted. Weird, get John.
694         if ( killed > 1 )       {
695                 mprintf( (1, "ERROR: More than 1 sounds were deleted from seg %d\n", segnum ));
696         }
697 }
698
699 void digi_kill_sound_linked_to_object( int objnum )
700 {
701         int i,killed;
702
703         if (!digi_initialised) return;
704
705         killed = 0;
706
707         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
708                 if ( (SoundObjects[i].flags & SOF_USED) && (SoundObjects[i].flags & SOF_LINK_TO_OBJ ) ) {
709                         if (SoundObjects[i].lo_objnum == objnum)   {
710                                 if ( SoundObjects[i].flags & SOF_PLAYING )      {
711                                      LOCK();
712                                      SoundSlots[SoundObjects[i].handle].playing = 0;
713                                      UNLOCK();
714                                 }
715                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
716                                 killed++;
717                         }
718                 }
719         }
720         // If this assert happens, it means that there were 2 sounds
721         // that got deleted. Weird, get John.
722         if ( killed > 1 )       {
723                 mprintf( (1, "ERROR: More than 1 sounds were deleted from object %d\n", objnum ));
724         }
725 }
726
727 void digi_sync_sounds()
728 {
729         int i;
730         int oldvolume, oldpan;
731
732         if (!digi_initialised) return;
733
734         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
735                 if ( SoundObjects[i].flags & SOF_USED ) {
736                         oldvolume = SoundObjects[i].volume;
737                         oldpan = SoundObjects[i].pan;
738
739                         if ( !(SoundObjects[i].flags & SOF_PLAY_FOREVER) )      {
740                                 // Check if its done.
741                                 if (SoundObjects[i].flags & SOF_PLAYING) {
742                                         LOCK();
743                                         if (!SoundSlots[SoundObjects[i].handle].playing) {
744                                                 UNLOCK();
745                                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
746                                                 continue;               // Go on to next sound...
747                                         }
748                                         UNLOCK();
749                                 }
750                         }                       
751                 
752                         if ( SoundObjects[i].flags & SOF_LINK_TO_POS )  {
753                                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
754                                                                 &SoundObjects[i].lp_position, SoundObjects[i].lp_segnum,
755                                                                 SoundObjects[i].max_volume,
756                                 &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
757
758                         } else if ( SoundObjects[i].flags & SOF_LINK_TO_OBJ )   {
759                                 object * objp;
760         
761                                 objp = &Objects[SoundObjects[i].lo_objnum];
762                 
763                                 if ((objp->type==OBJ_NONE) || (objp->signature!=SoundObjects[i].lo_objsignature))  {
764                                         // The object that this is linked to is dead, so just end this sound if it is looping.
765                                         if ( (SoundObjects[i].flags & SOF_PLAYING)  && (SoundObjects[i].flags & SOF_PLAY_FOREVER))      {
766                                              LOCK();
767                                              SoundSlots[SoundObjects[i].handle].playing = 0;
768                                              UNLOCK();
769                                         }
770                                         SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
771                                         continue;               // Go on to next sound...
772                                 } else {
773                                         digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
774                                         &objp->pos, objp->segnum, SoundObjects[i].max_volume,
775                                    &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
776                                 }
777                         }
778                          
779                         if (oldvolume != SoundObjects[i].volume)        {
780                                 if ( SoundObjects[i].volume < MIN_VOLUME )       {
781                                         // Sound is too far away, so stop it from playing.
782                                         if ((SoundObjects[i].flags & SOF_PLAYING)&&(SoundObjects[i].flags & SOF_PLAY_FOREVER))  {
783                                                 LOCK();
784                                                 SoundSlots[SoundObjects[i].handle].playing = 0;
785                                                 UNLOCK();
786                                                 SoundObjects[i].flags &= ~SOF_PLAYING;          // Mark sound as not playing
787                                         }
788                                 } else {
789                                         if (!(SoundObjects[i].flags & SOF_PLAYING))     {
790                                                 digi_start_sound_object(i);
791                                         } else {
792                                                 LOCK();
793                                                 SoundSlots[SoundObjects[i].handle].volume = fixmuldiv(SoundObjects[i].volume,digi_volume,F1_0);
794                                                 UNLOCK();
795                                         }
796                                 }
797                         }
798                                 
799                         if (oldpan != SoundObjects[i].pan)      {
800                                 if (SoundObjects[i].flags & SOF_PLAYING) {
801                                         LOCK();
802                                         SoundSlots[SoundObjects[i].handle].pan = SoundObjects[i].pan;
803                                         UNLOCK();
804                                 }
805                         }
806                 }
807         }
808 }
809
810 void digi_init_sounds()
811 {
812         int i;
813
814         if (!digi_initialised) return;
815
816         digi_reset_digi_sounds();
817
818         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
819                 if (digi_sounds_initialized) {
820                         if ( SoundObjects[i].flags & SOF_PLAYING )      {
821                                 LOCK();
822                                 SoundSlots[SoundObjects[i].handle].playing=0;
823                                 UNLOCK();
824                         }
825                 }
826                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
827         }
828         digi_sounds_initialized = 1;
829 }
830
831 //added on 980905 by adb from original source to make sfx volume work
832 void digi_set_digi_volume( int dvolume )
833 {
834         dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
835         if ( dvolume > SOUND_MAX_VOLUME )
836                 digi_volume = SOUND_MAX_VOLUME;
837         else if ( dvolume < 0 )
838                 digi_volume = 0;
839         else
840                 digi_volume = dvolume;
841
842         if ( !digi_initialised ) return;
843
844         digi_sync_sounds();
845 }
846 //end edit by adb
847
848 void digi_set_volume( int dvolume, int mvolume ) { }
849
850 int digi_is_sound_playing(int soundno)
851 {
852         int i;
853
854         soundno = digi_xlat_sound(soundno);
855
856         LOCK();
857         for (i = 0; i < MAX_SOUND_SLOTS; i++)
858                   //changed on 980905 by adb: added SoundSlots[i].playing &&
859                   if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
860                   //end changes by adb
861                   { UNLOCK();   return 1; }
862         UNLOCK();
863         return 0;
864 }
865
866
867 void digi_pause_all() { }
868 void digi_resume_all() { }
869 void digi_stop_all() { }
870
871  //added on 980905 by adb to make sound channel setting work
872 void digi_set_max_channels(int n) { 
873         digi_max_channels       = n;
874
875         if ( digi_max_channels < 1 ) 
876                 digi_max_channels = 1;
877         if ( digi_max_channels > (MAX_SOUND_SLOTS-MAX_SOUND_OBJECTS) ) 
878                 digi_max_channels = (MAX_SOUND_SLOTS-MAX_SOUND_OBJECTS);
879
880         if ( !digi_initialised ) return;
881
882         digi_reset_digi_sounds();
883 }
884
885 int digi_get_max_channels() { 
886         return digi_max_channels; 
887 }
888 // end edit by adb
889
890 void digi_reset_digi_sounds() {
891  int i;
892
893  LOCK();
894  for (i=0; i< MAX_SOUND_SLOTS; i++)
895   SoundSlots[i].playing=0;
896  UNLOCK();
897  
898  //added on 980905 by adb to reset sound kill system
899  memset(SampleHandles, 255, sizeof(SampleHandles));
900  next_handle = 0;
901  //end edit by adb
902 }
903
904
905 // MIDI stuff follows.
906 //added/killed on 11/25/98 by Matthew Mueller
907 //void digi_set_midi_volume( int mvolume ) { }
908 //void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) {}
909 //void digi_stop_current_song()
910 //{
911 //#ifdef HMIPLAY
912 //        char buf[10];
913 //    
914 //        sprintf(buf,"s");
915 //        send_ipc(buf);
916 //#endif
917 //}
918 //end this section kill - MM