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