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