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