]> icculus.org git repositories - btb/d2x.git/blob - main/digiobj.c
remove rcs tags
[btb/d2x.git] / main / digiobj.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14
15 #ifdef HAVE_CONFIG_H
16 #include <conf.h>
17 #endif
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <fcntl.h> 
22
23 #ifdef __MSDOS__
24 # include <dos.h>
25 # include <bios.h>
26 # include <io.h>
27 # include <conio.h> 
28 #endif
29
30 #include <string.h>
31 #include <ctype.h>
32
33 #include "fix.h"
34 #include "object.h"
35 #include "mono.h"
36 #include "timer.h"
37 #include "joy.h"
38 #include "digi.h"
39 #include "sounds.h"
40 #include "args.h"
41 #include "key.h"
42 #include "newdemo.h"
43 #include "game.h"
44 #ifdef __MSDOS__
45 #include "dpmi.h"
46 #endif
47 #include "error.h"
48 #include "wall.h"
49 #include "cfile.h"
50 #include "piggy.h"
51 #include "text.h"
52 #include "kconfig.h"
53
54 #define SOF_USED                                1               // Set if this sample is used
55 #define SOF_PLAYING                     2               // Set if this sample is playing on a channel
56 #define SOF_LINK_TO_OBJ         4               // Sound is linked to a moving object. If object dies, then finishes play and quits.
57 #define SOF_LINK_TO_POS         8               // Sound is linked to segment, pos
58 #define SOF_PLAY_FOREVER        16              // Play forever (or until level is stopped), otherwise plays once
59 #define SOF_PERMANENT           32              // Part of the level, like a waterfall or fan
60
61 typedef struct sound_object {
62         short                   signature;              // A unique signature to this sound
63         ubyte                   flags;                  // Used to tell if this slot is used and/or currently playing, and how long.
64         ubyte                   pad;                            //      Keep alignment
65         fix                     max_volume;             // Max volume that this sound is playing at
66         fix                     max_distance;   // The max distance that this sound can be heard at...
67         int                     volume;                 // Volume that this sound is playing at
68         int                     pan;                            // Pan value that this sound is playing at
69         int                     channel;                        // What channel this is playing on, -1 if not playing
70         short                   soundnum;               // The sound number that is playing
71         int                     loop_start;             // The start point of the loop. -1 means no loop
72         int                     loop_end;               // The end point of the loop
73         union { 
74                 struct {
75                         short                   segnum;                         // Used if SOF_LINK_TO_POS field is used
76                         short                   sidenum;                                
77                         vms_vector      position;
78                 } pos;
79                 struct {
80                         short                   objnum;                         // Used if SOF_LINK_TO_OBJ field is used
81                         short                   objsignature;
82                 } obj;
83         } link_type;
84 } sound_object;
85
86 #define MAX_SOUND_OBJECTS 150
87 sound_object SoundObjects[MAX_SOUND_OBJECTS];
88 short next_signature=0;
89
90 int N_active_sound_objects=0;
91
92 int digi_sounds_initialized=0;
93
94 int digi_lomem                                          = 0;
95
96 /* Find the sound which actually equates to a sound number */
97 int digi_xlat_sound(int soundno)
98 {
99         if (soundno < 0)
100                 return -1;
101
102         if (digi_lomem)
103         {
104                 soundno = AltSounds[soundno];
105                 if (soundno == 255)
106                         return -1;
107         }
108
109         Assert(Sounds[soundno] != 255); //if hit this, probably using undefined sound
110
111         return Sounds[soundno];
112 }
113
114 int digi_unxlat_sound(int soundno)
115 {
116         int i;
117         ubyte *table = (digi_lomem?AltSounds:Sounds);
118
119         if ( soundno < 0 ) return -1;
120
121         for (i=0;i<MAX_SOUNDS;i++)
122                 if (table[i] == soundno)
123                         return i;
124
125         Int3();
126         return 0;
127 }
128
129
130 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 )   
131 {         
132
133         vms_vector      vector_to_sound;
134         fix angle_from_ear, cosang,sinang;
135         fix distance;
136         fix path_distance;
137
138         *volume = 0;
139         *pan = 0;
140
141         max_distance = (max_distance*5)/4;              // Make all sounds travel 1.25 times as far.
142
143         //      Warning: Made the vm_vec_normalized_dir be vm_vec_normalized_dir_quick and got illegal values to acos in the fang computation.
144         distance = vm_vec_normalized_dir_quick( &vector_to_sound, sound_pos, listener_pos );
145                 
146         if (distance < max_distance )   {
147                 int num_search_segs = f2i(max_distance/20);
148                 if ( num_search_segs < 1 ) num_search_segs = 1;
149
150                 path_distance = find_connected_distance(listener_pos, listener_seg, sound_pos, sound_seg, num_search_segs, WID_RENDPAST_FLAG+WID_FLY_FLAG );
151                 if ( path_distance > -1 )       {
152                         *volume = max_volume - fixdiv(path_distance,max_distance);
153                         //mprintf( (0, "Sound path distance %.2f, volume is %d / %d\n", f2fl(distance), *volume, max_volume ));
154                         if (*volume > 0 )       {
155                                 angle_from_ear = vm_vec_delta_ang_norm(&listener->rvec,&vector_to_sound,&listener->uvec);
156                                 fix_sincos(angle_from_ear,&sinang,&cosang);
157                                 //mprintf( (0, "volume is %.2f\n", f2fl(*volume) ));
158                                 if (Config_channels_reversed.intval) cosang *= -1;
159                                 *pan = (cosang + F1_0)/2;
160                         } else {
161                                 *volume = 0;
162                         }
163                 }
164         }                                                                                                                                                                         
165
166 }
167
168 void digi_play_sample_once( int soundno, fix max_volume )       
169 {
170         int channel;
171
172 #ifdef NEWDEMO
173         if ( Newdemo_state == ND_STATE_RECORDING )
174                 newdemo_record_sound( soundno );
175 #endif
176         soundno = digi_xlat_sound(soundno);
177
178         if (soundno < 0 ) return;
179
180         channel=digi_find_channel(soundno);
181         if ( channel > -1 )
182                 digi_stop_sound( channel );
183                 
184    // start the sample playing
185         digi_start_sound( soundno, max_volume, 0xffff/2, 0, -1, -1, -1 );
186 }
187
188
189 void digi_play_sample( int soundno, fix max_volume )
190 {
191 #ifdef NEWDEMO
192         if ( Newdemo_state == ND_STATE_RECORDING )
193                 newdemo_record_sound( soundno );
194 #endif
195         soundno = digi_xlat_sound(soundno);
196
197         if (soundno < 0 ) return;
198
199    // start the sample playing
200         digi_start_sound( soundno, max_volume, 0xffff/2, 0, -1, -1, -1 );
201 }
202
203
204 void digi_play_sample_3d( int soundno, int angle, int volume, int no_dups )     
205 {
206
207         no_dups = 1;
208
209 #ifdef NEWDEMO
210         if ( Newdemo_state == ND_STATE_RECORDING )              {
211                 if ( no_dups )
212                         newdemo_record_sound_3d_once( soundno, angle, volume );
213                 else
214                         newdemo_record_sound_3d( soundno, angle, volume );
215         }
216 #endif
217         soundno = digi_xlat_sound(soundno);
218
219         if (soundno < 0 ) return;
220
221         if (volume < 10 ) return;
222
223    // start the sample playing
224         digi_start_sound( soundno, volume, angle, 0, -1, -1, -1 );
225 }
226
227
228 void SoundQ_init();
229 void SoundQ_process();
230 void SoundQ_pause();
231
232 void digi_init_sounds()
233 {
234         int i;
235
236         SoundQ_init();
237
238         digi_stop_all_channels();
239
240         digi_stop_looping_sound();
241         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
242                 SoundObjects[i].channel = -1;
243                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
244         }
245         N_active_sound_objects = 0;
246         digi_sounds_initialized = 1;
247 }
248
249 extern int digi_max_channels;
250
251 // plays a sample that loops forever.  
252 // Call digi_stop_channe(channel) to stop it.
253 // Call digi_set_channel_volume(channel, volume) to change volume.
254 // if loop_start is -1, entire sample loops
255 // Returns the channel that sound is playing on, or -1 if can't play.
256 // This could happen because of no sound drivers loaded or not enough channels.
257 int digi_looping_sound = -1;
258 int digi_looping_volume = 0;
259 int digi_looping_start = -1;
260 int digi_looping_end = -1;
261 int digi_looping_channel = -1;
262
263 void digi_play_sample_looping_sub()
264 {
265         if ( digi_looping_sound > -1 )
266                 digi_looping_channel  = digi_start_sound( digi_looping_sound, digi_looping_volume, 0xFFFF/2, 1, digi_looping_start, digi_looping_end, -1 );
267 }
268
269 void digi_play_sample_looping( int soundno, fix max_volume,int loop_start, int loop_end )
270 {
271         soundno = digi_xlat_sound(soundno);
272
273         if (soundno < 0 ) return;
274
275         if (digi_looping_channel>-1)
276                 digi_stop_sound( digi_looping_channel );
277
278         digi_looping_sound = soundno;
279         digi_looping_volume = max_volume;
280         digi_looping_start = loop_start;
281         digi_looping_end = loop_end;
282         digi_play_sample_looping_sub();
283 }
284
285 void digi_change_looping_volume( fix volume )
286 {
287         if ( digi_looping_channel > -1 )
288                 digi_set_channel_volume( digi_looping_channel, volume );
289         digi_looping_volume = volume;
290 }
291
292 void digi_stop_looping_sound()
293 {
294         if ( digi_looping_channel > -1 )
295                 digi_stop_sound( digi_looping_channel );
296         digi_looping_channel = -1;
297         digi_looping_sound = -1;
298 }
299         
300 void digi_pause_looping_sound()
301 {
302         if ( digi_looping_channel > -1 )
303                 digi_stop_sound( digi_looping_channel );
304         digi_looping_channel = -1;
305 }
306
307 void digi_unpause_looping_sound()
308 {
309         digi_play_sample_looping_sub();
310 }
311
312 //hack to not start object when loading level
313 int Dont_start_sound_objects = 0;
314
315 void digi_start_sound_object(int i)
316 {
317         // start sample structures 
318         SoundObjects[i].channel =  -1;
319
320         if ( SoundObjects[i].volume <= 0 )
321                 return;
322
323         if ( Dont_start_sound_objects )
324                 return;
325
326 // -- MK, 2/22/96 --    if ( Newdemo_state == ND_STATE_RECORDING )
327 // -- MK, 2/22/96 --            newdemo_record_sound_3d_once( digi_unxlat_sound(SoundObjects[i].soundnum), SoundObjects[i].pan, SoundObjects[i].volume );
328
329         // only use up to half the sound channels for "permanent" sounts
330         if ((SoundObjects[i].flags & SOF_PERMANENT) && (N_active_sound_objects >= max(1, digi_get_max_channels() / 4)))
331                 return;
332
333         // start the sample playing
334
335         SoundObjects[i].channel = digi_start_sound( SoundObjects[i].soundnum, 
336                                                                                 SoundObjects[i].volume, 
337                                                                                 SoundObjects[i].pan, 
338                                                                                 SoundObjects[i].flags & SOF_PLAY_FOREVER, 
339                                                                                 SoundObjects[i].loop_start, 
340                                                                                 SoundObjects[i].loop_end, i );
341
342         if (SoundObjects[i].channel > -1 )
343                 N_active_sound_objects++;
344 }
345
346 //sounds longer than this get their 3d aspects updated
347 #define SOUND_3D_THRESHHOLD  (digi_sample_rate * 3 / 2) //1.5 seconds
348
349 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 )
350 {
351
352         int i,volume,pan;
353         object * objp;
354         int soundnum;
355
356         soundnum = digi_xlat_sound(org_soundnum);
357
358         if ( max_volume < 0 ) return -1;
359 //      if ( max_volume > F1_0 ) max_volume = F1_0;
360
361         if (soundnum < 0 ) return -1;
362         if (GameSounds[soundnum].data==NULL) {
363                 Int3();
364                 return -1;
365         }
366         if ((objnum<0)||(objnum>Highest_object_index))
367                 return -1;
368
369         if ( !forever ) {               // && GameSounds[soundnum - SOUND_OFFSET].length < SOUND_3D_THRESHHOLD) {
370                 // Hack to keep sounds from building up...
371                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, &Objects[objnum].pos, Objects[objnum].segnum, max_volume,&volume, &pan, max_distance );
372                 digi_play_sample_3d( org_soundnum, pan, volume, 0 );
373                 return -1;
374         }
375
376 #ifdef NEWDEMO
377         if ( Newdemo_state == ND_STATE_RECORDING )              {
378                 newdemo_record_link_sound_to_object3( org_soundnum, objnum, max_volume, max_distance, loop_start, loop_end );
379         }
380 #endif
381
382         for (i=0; i<MAX_SOUND_OBJECTS; i++ )
383                 if (SoundObjects[i].flags==0)
384                         break;
385         
386         if (i==MAX_SOUND_OBJECTS) {
387                 mprintf((1, "Too many sound objects!\n" ));
388                 return -1;
389         }
390
391         SoundObjects[i].signature=next_signature++;
392         SoundObjects[i].flags = SOF_USED | SOF_LINK_TO_OBJ;
393         if ( forever )
394                 SoundObjects[i].flags |= SOF_PLAY_FOREVER;
395         SoundObjects[i].link_type.obj.objnum = objnum;
396         SoundObjects[i].link_type.obj.objsignature = Objects[objnum].signature;
397         SoundObjects[i].max_volume = max_volume;
398         SoundObjects[i].max_distance = max_distance;
399         SoundObjects[i].volume = 0;
400         SoundObjects[i].pan = 0;
401         SoundObjects[i].soundnum = soundnum;
402         SoundObjects[i].loop_start = loop_start;
403         SoundObjects[i].loop_end = loop_end;
404
405         if (Dont_start_sound_objects) {                 //started at level start
406
407                 SoundObjects[i].flags |= SOF_PERMANENT;
408                 SoundObjects[i].channel =  -1;
409         }
410         else {
411                 objp = &Objects[SoundObjects[i].link_type.obj.objnum];
412                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
413                        &objp->pos, objp->segnum, SoundObjects[i].max_volume,
414                        &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
415
416                 digi_start_sound_object(i);
417
418                 // If it's a one-shot sound effect, and it can't start right away, then
419                 // just cancel it and be done with it.
420                 if ( (SoundObjects[i].channel < 0) && (!(SoundObjects[i].flags & SOF_PLAY_FOREVER)) )    {
421                         SoundObjects[i].flags = 0;
422                         return -1;
423                 }
424         }
425
426         return SoundObjects[i].signature;
427 }
428
429 int digi_link_sound_to_object2( int org_soundnum, short objnum, int forever, fix max_volume, fix  max_distance )
430 {               
431         return digi_link_sound_to_object3( org_soundnum, objnum, forever, max_volume, max_distance, -1, -1 );
432 }
433
434
435 int digi_link_sound_to_object( int soundnum, short objnum, int forever, fix max_volume )
436 {               
437         return digi_link_sound_to_object2( soundnum, objnum, forever, max_volume, 256*F1_0  );
438 }
439
440 int digi_link_sound_to_pos2( int org_soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume, fix max_distance )
441 {
442
443         int i, volume, pan;
444         int soundnum;
445
446         soundnum = digi_xlat_sound(org_soundnum);
447
448         if ( max_volume < 0 ) return -1;
449 //      if ( max_volume > F1_0 ) max_volume = F1_0;
450
451         if (soundnum < 0 ) return -1;
452         if (GameSounds[soundnum].data==NULL) {
453                 Int3();
454                 return -1;
455         }
456
457         if ((segnum<0)||(segnum>Highest_segment_index))
458                 return -1;
459
460         if ( !forever ) {       //&& GameSounds[soundnum - SOUND_OFFSET].length < SOUND_3D_THRESHHOLD)  {
461                 // Hack to keep sounds from building up...
462                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, pos, segnum, max_volume, &volume, &pan, max_distance );
463                 digi_play_sample_3d( org_soundnum, pan, volume, 0 );
464                 return -1;
465         }
466
467         for (i=0; i<MAX_SOUND_OBJECTS; i++ )
468                 if (SoundObjects[i].flags==0)
469                         break;
470         
471         if (i==MAX_SOUND_OBJECTS) {
472                 mprintf((1, "Too many sound objects!\n" ));
473                 return -1;
474         }
475
476
477         SoundObjects[i].signature=next_signature++;
478         SoundObjects[i].flags = SOF_USED | SOF_LINK_TO_POS;
479         if ( forever )
480                 SoundObjects[i].flags |= SOF_PLAY_FOREVER;
481         SoundObjects[i].link_type.pos.segnum = segnum;
482         SoundObjects[i].link_type.pos.sidenum = sidenum;
483         SoundObjects[i].link_type.pos.position = *pos;
484         SoundObjects[i].soundnum = soundnum;
485         SoundObjects[i].max_volume = max_volume;
486         SoundObjects[i].max_distance = max_distance;
487         SoundObjects[i].volume = 0;
488         SoundObjects[i].pan = 0;
489         SoundObjects[i].loop_start = SoundObjects[i].loop_end = -1;
490
491         if (Dont_start_sound_objects) {         //started at level start
492
493                 SoundObjects[i].flags |= SOF_PERMANENT;
494
495                 SoundObjects[i].channel =  -1;
496         }
497         else {
498
499                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
500                        &SoundObjects[i].link_type.pos.position, SoundObjects[i].link_type.pos.segnum, SoundObjects[i].max_volume,
501                        &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
502
503                 digi_start_sound_object(i);
504
505                 // If it's a one-shot sound effect, and it can't start right away, then
506                 // just cancel it and be done with it.
507                 if ( (SoundObjects[i].channel < 0) && (!(SoundObjects[i].flags & SOF_PLAY_FOREVER)) )    {
508                         SoundObjects[i].flags = 0;
509                         return -1;
510                 }
511         }
512
513         return SoundObjects[i].signature;
514 }
515
516 int digi_link_sound_to_pos( int soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume )
517 {
518         return digi_link_sound_to_pos2( soundnum, segnum, sidenum, pos, forever, max_volume, F1_0 * 256 );
519 }
520
521 //if soundnum==-1, kill any sound
522 void digi_kill_sound_linked_to_segment( int segnum, int sidenum, int soundnum )
523 {
524         int i,killed;
525
526         if (soundnum != -1)
527                 soundnum = digi_xlat_sound(soundnum);
528
529
530         killed = 0;
531
532         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
533                 if ( (SoundObjects[i].flags & SOF_USED) && (SoundObjects[i].flags & SOF_LINK_TO_POS) )  {
534                         if ((SoundObjects[i].link_type.pos.segnum == segnum) && (SoundObjects[i].link_type.pos.sidenum==sidenum) && (soundnum==-1 || SoundObjects[i].soundnum==soundnum ))      {
535                                 if ( SoundObjects[i].channel > -1 )     {
536                                         digi_stop_sound( SoundObjects[i].channel );
537                                         N_active_sound_objects--;
538                                 }
539                                 SoundObjects[i].channel = -1;
540                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
541                                 killed++;
542                         }
543                 }
544         }
545         // If this assert happens, it means that there were 2 sounds
546         // that got deleted. Weird, get John.
547         if ( killed > 1 )       {
548                 mprintf( (1, "ERROR: More than 1 sounds were deleted from seg %d\n", segnum ));
549         }
550 }
551
552 void digi_kill_sound_linked_to_object( int objnum )
553 {
554
555         int i,killed;
556
557         killed = 0;
558
559 #ifdef NEWDEMO
560         if ( Newdemo_state == ND_STATE_RECORDING )              {
561                 newdemo_record_kill_sound_linked_to_object( objnum );
562         }
563 #endif
564
565         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
566                 if ( (SoundObjects[i].flags & SOF_USED) && (SoundObjects[i].flags & SOF_LINK_TO_OBJ ) ) {
567                         if (SoundObjects[i].link_type.obj.objnum == objnum)     {
568                                 if ( SoundObjects[i].channel > -1 )     {
569                                         digi_stop_sound( SoundObjects[i].channel );
570                                         N_active_sound_objects--;
571                                 }
572                                 SoundObjects[i].channel = -1;
573                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
574                                 killed++;
575                         }
576                 }
577         }
578         // If this assert happens, it means that there were 2 sounds
579         // that got deleted. Weird, get John.
580         if ( killed > 1 )       {
581                 mprintf( (1, "ERROR: More than 1 sounds were deleted from object %d\n", objnum ));
582         }
583
584 }
585
586 //      John's new function, 2/22/96.
587 void digi_record_sound_objects()
588 {
589         int i;
590
591         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
592                 if ( (SoundObjects[i].flags & SOF_USED)&&
593                      (SoundObjects[i].flags & SOF_LINK_TO_OBJ)&&        
594                      (SoundObjects[i].flags & SOF_PLAY_FOREVER)
595                    )
596                 {
597
598                         newdemo_record_link_sound_to_object3( digi_unxlat_sound(SoundObjects[i].soundnum), SoundObjects[i].link_type.obj.objnum, 
599                                 SoundObjects[i].max_volume, SoundObjects[i].max_distance, SoundObjects[i].loop_start, SoundObjects[i].loop_end );
600                 }
601         }
602 }
603
604 int was_recording = 0;
605
606 void digi_sync_sounds()
607 {
608         int i;
609         int oldvolume, oldpan;
610
611         if ( Newdemo_state == ND_STATE_RECORDING)       {
612                 if ( !was_recording )   {
613                         digi_record_sound_objects();
614                 }
615                 was_recording = 1;
616         } else {
617                 was_recording = 0;
618         }
619
620         SoundQ_process();
621
622         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
623                 if ( SoundObjects[i].flags & SOF_USED ) {
624                         oldvolume = SoundObjects[i].volume;
625                         oldpan = SoundObjects[i].pan;
626
627                         if ( !(SoundObjects[i].flags & SOF_PLAY_FOREVER) )      {
628                                 // Check if its done.
629                                 if (SoundObjects[i].channel > -1 ) {
630                                         if ( !digi_is_channel_playing(SoundObjects[i].channel) )        {
631                                                 digi_end_sound( SoundObjects[i].channel );
632                                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
633                                                 N_active_sound_objects--;
634                                                 continue;               // Go on to next sound...
635                                         }
636                                 }
637                         }                       
638                 
639                         if ( SoundObjects[i].flags & SOF_LINK_TO_POS )  {
640                                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
641                                 &SoundObjects[i].link_type.pos.position, SoundObjects[i].link_type.pos.segnum, SoundObjects[i].max_volume,
642                                 &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
643
644                         } else if ( SoundObjects[i].flags & SOF_LINK_TO_OBJ )   {
645                                 object * objp;
646
647
648                                 if ( Newdemo_state == ND_STATE_PLAYBACK )       {
649                                         int objnum;
650                                         objnum = newdemo_find_object( SoundObjects[i].link_type.obj.objsignature );
651                                         if ( objnum > -1 )      {
652                                                 objp = &Objects[objnum];
653                                         } else {
654                                                 objp = &Objects[0];
655                                         }
656                                 } else {
657                                         objp = &Objects[SoundObjects[i].link_type.obj.objnum];
658                                 }
659                                                 
660                                 if ((objp->type==OBJ_NONE) || (objp->signature!=SoundObjects[i].link_type.obj.objsignature))    {
661                                         // The object that this is linked to is dead, so just end this sound if it is looping.
662                                         if ( SoundObjects[i].channel>-1 )       {
663                                                 if (SoundObjects[i].flags & SOF_PLAY_FOREVER)
664                                                         digi_stop_sound( SoundObjects[i].channel );
665                                                 else
666                                                         digi_end_sound( SoundObjects[i].channel );
667                                                 N_active_sound_objects--;
668                                         }
669                                         SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
670                                         continue;               // Go on to next sound...
671                                 } else {
672                                         digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
673                                         &objp->pos, objp->segnum, SoundObjects[i].max_volume,
674                                    &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
675                                 }
676                         }
677                          
678                         if (oldvolume != SoundObjects[i].volume)        {
679                                 if ( SoundObjects[i].volume < 1 )       {
680                                         // Sound is too far away, so stop it from playing.
681
682                                         if ( SoundObjects[i].channel>-1 )       {
683                                                 if (SoundObjects[i].flags & SOF_PLAY_FOREVER)
684                                                         digi_stop_sound( SoundObjects[i].channel );
685                                                 else
686                                                         digi_end_sound( SoundObjects[i].channel );
687                                                 N_active_sound_objects--;
688                                                 SoundObjects[i].channel = -1;
689                                         }
690
691                                         if (! (SoundObjects[i].flags & SOF_PLAY_FOREVER)) {
692                                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
693                                                 continue;
694                                         }
695
696                                 } else {
697                                         if (SoundObjects[i].channel<0)  {
698                                                 digi_start_sound_object(i);
699                                         } else {
700                                                 digi_set_channel_volume( SoundObjects[i].channel, SoundObjects[i].volume );
701                                         }
702                                 }
703                         }
704                                 
705                         if (oldpan != SoundObjects[i].pan)      {
706                                 if (SoundObjects[i].channel>-1)
707                                         digi_set_channel_pan( SoundObjects[i].channel, SoundObjects[i].pan );
708                         }
709
710                 }
711         }
712         
713 #ifndef NDEBUG
714 //      digi_sound_debug();
715 #endif
716 }
717
718 void digi_pause_digi_sounds()
719 {
720
721         int i;
722
723         digi_pause_looping_sound();
724
725         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
726                 if ( (SoundObjects[i].flags & SOF_USED) && (SoundObjects[i].channel>-1) )       {
727                         digi_stop_sound( SoundObjects[i].channel );
728                         if (! (SoundObjects[i].flags & SOF_PLAY_FOREVER))
729                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
730                         N_active_sound_objects--;
731                         SoundObjects[i].channel = -1;
732                 }                       
733         }
734
735         digi_stop_all_channels();
736         SoundQ_pause();
737 }
738
739 void digi_pause_all()
740 {
741         digi_pause_midi();
742         digi_pause_digi_sounds();
743 }
744
745 void digi_resume_digi_sounds()
746 {
747         digi_sync_sounds();     //don't think we really need to do this, but can't hurt
748         digi_unpause_looping_sound();
749 }
750
751 extern void digi_resume_midi();
752
753 void digi_resume_all()
754 {
755         digi_resume_midi();
756         digi_unpause_looping_sound();
757 }
758
759 // Called by the code in digi.c when another sound takes this sound object's
760 // slot because the sound was done playing.
761 void digi_end_soundobj(int i)
762 {
763         Assert( SoundObjects[i].flags & SOF_USED );
764         Assert( SoundObjects[i].channel > -1 );
765         
766         N_active_sound_objects--;
767         SoundObjects[i].channel = -1;
768 }
769
770 void digi_stop_digi_sounds()
771 {
772         int i;
773
774         digi_stop_looping_sound();
775
776         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
777                 if ( SoundObjects[i].flags & SOF_USED ) {
778                         if ( SoundObjects[i].channel > -1 )     {
779                                 digi_stop_sound( SoundObjects[i].channel );
780                                 N_active_sound_objects--;
781                         }
782                         SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
783                 }
784         }
785
786         digi_stop_all_channels();
787         SoundQ_init();
788 }
789
790 void digi_stop_all()
791 {
792         digi_stop_current_song();
793
794         digi_stop_digi_sounds();
795 }
796
797 #ifndef NDEBUG
798 int verify_sound_channel_free( int channel )
799 {
800         int i;
801         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
802                 if ( SoundObjects[i].flags & SOF_USED ) {
803                         if ( SoundObjects[i].channel == channel )       {
804                                 mprintf(( 0, "ERROR STARTING SOUND CHANNEL ON USED SLOT!!\n" ));
805                                 Int3(); // Get John!
806                         }
807                 }
808         }
809         return 0;
810 }
811
812 void digi_sound_debug()
813 {
814         int i;
815         int n_active_sound_objs=0;
816         int n_sound_objs=0;
817
818         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
819                 if ( SoundObjects[i].flags & SOF_USED )         {
820                         n_sound_objs++;
821                         if ( SoundObjects[i].channel > -1 )
822                                 n_active_sound_objs++;
823                 }
824         }
825         mprintf_at(( 0, 0, 0, "DIGI: Active Sound Objects:  %d,%d/%d (%d max)             \n", n_active_sound_objs,N_active_sound_objects, n_sound_objs, MAX_SOUND_OBJECTS ));
826         mprintf_at(( 0, 1, 0, "DIGI: Looping sound:  %s, snd=%d, vol=%d, ch=%d            \n", (digi_looping_sound>-1?"ON":"OFF"), digi_looping_sound, digi_looping_volume, digi_looping_channel  ));
827
828         digi_debug();
829 }
830 #endif
831
832 typedef struct sound_q {
833         fix time_added;
834         int soundnum;
835 } sound_q;
836
837 #define MAX_Q 32
838 #define MAX_LIFE F1_0*30                // After being queued for 30 seconds, don't play it
839 sound_q SoundQ[MAX_Q];
840 int SoundQ_head, SoundQ_tail, SoundQ_num;
841 int SoundQ_channel;
842
843 void SoundQ_init()
844 {
845         SoundQ_head = SoundQ_tail = 0;
846         SoundQ_num = 0;
847         SoundQ_channel = -1;
848 }
849
850 void SoundQ_pause()
851 {       
852         SoundQ_channel = -1;
853 }
854
855 void SoundQ_end()
856 {
857         // Current playing sound is stopped, so take it off the Queue
858         SoundQ_head = (SoundQ_head+1);
859         if ( SoundQ_head >= MAX_Q ) SoundQ_head = 0;
860         SoundQ_num--;
861         SoundQ_channel = -1;
862 }
863
864 void SoundQ_process()
865 {       
866         fix curtime = timer_get_approx_seconds();
867
868         if ( SoundQ_channel > -1 )      {
869                 if ( digi_is_channel_playing(SoundQ_channel) )
870                         return;
871                 SoundQ_end();
872         }
873
874         if ( SoundQ_num > 0 )   {
875                 mprintf(( 0, "SQ:%d ", SoundQ_num ));
876         }
877
878         while ( SoundQ_head != SoundQ_tail )    {
879                 sound_q * q = &SoundQ[SoundQ_head];
880         
881                 if ( q->time_added+MAX_LIFE > curtime ) {
882                         SoundQ_channel = digi_start_sound(q->soundnum, F1_0+1, 0xFFFF/2, 0, -1, -1, -1 );
883                         return;
884                 } else {
885                         // expired; remove from Queue
886                         SoundQ_end();
887                 }
888         }
889 }
890
891
892 void digi_start_sound_queued( short soundnum, fix volume )
893 {
894         int i;
895
896         soundnum = digi_xlat_sound(soundnum);
897
898         if (soundnum < 0 ) return;
899
900         i = SoundQ_tail+1;
901         if ( i>=MAX_Q ) i = 0;
902
903         // Make sure its loud so it doesn't get cancelled!
904         if ( volume < F1_0+1 )
905                 volume = F1_0 + 1;
906
907         if ( i != SoundQ_head ) {
908                 SoundQ[SoundQ_tail].time_added = timer_get_approx_seconds();
909                 SoundQ[SoundQ_tail].soundnum = soundnum;
910                 SoundQ_num++;
911                 SoundQ_tail = i;
912         } else {
913                 mprintf(( 0, "Sound Q full!\n" ));
914         }
915
916         // Try to start it!
917         SoundQ_process();
918 }
919