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