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