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 
digi_xlat_sound(int soundno)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 
digi_unxlat_sound(int soundno)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 
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)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 
digi_play_sample_once(int soundno,fix max_volume)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 
digi_play_sample(int soundno,fix max_volume)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 
digi_play_sample_3d(int soundno,int angle,int volume,int no_dups)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 
digi_init_sounds()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 
digi_play_sample_looping_sub()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 
digi_play_sample_looping(int soundno,fix max_volume,int loop_start,int loop_end)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 
digi_change_looping_volume(fix volume)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 
digi_stop_looping_sound()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 
digi_pause_looping_sound()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 
digi_unpause_looping_sound()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 
digi_start_sound_object(int i)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 
digi_link_sound_to_object3(int org_soundnum,short objnum,int forever,fix max_volume,fix max_distance,int loop_start,int loop_end)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 
digi_link_sound_to_object2(int org_soundnum,short objnum,int forever,fix max_volume,fix max_distance)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 
digi_link_sound_to_object(int soundnum,short objnum,int forever,fix max_volume)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 
digi_link_sound_to_pos2(int org_soundnum,short segnum,short sidenum,vms_vector * pos,int forever,fix max_volume,fix max_distance)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 
digi_link_sound_to_pos(int soundnum,short segnum,short sidenum,vms_vector * pos,int forever,fix max_volume)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
digi_kill_sound_linked_to_segment(int segnum,int sidenum,int soundnum)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 
digi_kill_sound_linked_to_object(int objnum)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.
digi_record_sound_objects()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 
digi_sync_sounds()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 
digi_pause_digi_sounds()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 
digi_pause_all()730 void digi_pause_all()
731 {
732 	digi_pause_midi();
733 	digi_pause_digi_sounds();
734 }
735 
digi_resume_digi_sounds()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 
digi_resume_all()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.
digi_end_soundobj(int i)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 
digi_stop_digi_sounds()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 
digi_stop_all()781 void digi_stop_all()
782 {
783 	digi_stop_current_song();
784 
785 	digi_stop_digi_sounds();
786 }
787 
788 #ifndef NDEBUG
verify_sound_channel_free(int channel)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 
digi_sound_debug()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 
SoundQ_init()834 void SoundQ_init()
835 {
836 	SoundQ_head = SoundQ_tail = 0;
837 	SoundQ_num = 0;
838 	SoundQ_channel = -1;
839 }
840 
SoundQ_pause()841 void SoundQ_pause()
842 {
843 	SoundQ_channel = -1;
844 }
845 
SoundQ_end()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 
SoundQ_process()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 
digi_start_sound_queued(short soundnum,fix volume)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 
911