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