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