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