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