1 /* $Id: digiobj.c,v 1.1 2004-11-29 05:25:58 btb Exp $ */
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.
17 static char rcsid[] = "$Id: digiobj.c,v 1.1 2004-11-29 05:25:58 btb Exp $";
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
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
80 short segnum; // Used if SOF_LINK_TO_POS field is used
85 short objnum; // Used if SOF_LINK_TO_OBJ field is used
91 #define MAX_SOUND_OBJECTS 150
92 sound_object SoundObjects[MAX_SOUND_OBJECTS];
93 short next_signature=0;
95 int N_active_sound_objects=0;
97 int digi_sounds_initialized=0;
101 /* Find the sound which actually equates to a sound number */
102 int digi_xlat_sound(int soundno)
109 soundno = AltSounds[soundno];
114 Assert(Sounds[soundno] != 255); //if hit this, probably using undefined sound
116 return Sounds[soundno];
119 int digi_unxlat_sound(int soundno)
122 ubyte *table = (digi_lomem?AltSounds:Sounds);
124 if ( soundno < 0 ) return -1;
126 for (i=0;i<MAX_SOUNDS;i++)
127 if (table[i] == soundno)
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 )
138 vms_vector vector_to_sound;
139 fix angle_from_ear, cosang,sinang;
146 max_distance = (max_distance*5)/4; // Make all sounds travel 1.25 times as far.
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 );
151 if (distance < max_distance ) {
152 int num_search_segs = f2i(max_distance/20);
153 if ( num_search_segs < 1 ) num_search_segs = 1;
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 ));
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;
173 void digi_play_sample_once( int soundno, fix max_volume )
178 if ( Newdemo_state == ND_STATE_RECORDING )
179 newdemo_record_sound( soundno );
181 soundno = digi_xlat_sound(soundno);
183 if (soundno < 0 ) return;
185 channel=digi_find_channel(soundno);
187 digi_stop_sound( channel );
189 // start the sample playing
190 digi_start_sound( soundno, max_volume, 0xffff/2, 0, -1, -1, -1 );
194 void digi_play_sample( int soundno, fix max_volume )
197 if ( Newdemo_state == ND_STATE_RECORDING )
198 newdemo_record_sound( soundno );
200 soundno = digi_xlat_sound(soundno);
202 if (soundno < 0 ) return;
204 // start the sample playing
205 digi_start_sound( soundno, max_volume, 0xffff/2, 0, -1, -1, -1 );
209 void digi_play_sample_3d( int soundno, int angle, int volume, int no_dups )
215 if ( Newdemo_state == ND_STATE_RECORDING ) {
217 newdemo_record_sound_3d_once( soundno, angle, volume );
219 newdemo_record_sound_3d( soundno, angle, volume );
222 soundno = digi_xlat_sound(soundno);
224 if (soundno < 0 ) return;
226 if (volume < 10 ) return;
228 // start the sample playing
229 digi_start_sound( soundno, volume, angle, 0, -1, -1, -1 );
234 void SoundQ_process();
237 void digi_init_sounds()
243 digi_stop_all_channels();
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
250 N_active_sound_objects = 0;
251 digi_sounds_initialized = 1;
254 extern int digi_max_channels;
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;
268 void digi_play_sample_looping_sub()
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 );
274 void digi_play_sample_looping( int soundno, fix max_volume,int loop_start, int loop_end )
276 soundno = digi_xlat_sound(soundno);
278 if (soundno < 0 ) return;
280 if (digi_looping_channel>-1)
281 digi_stop_sound( digi_looping_channel );
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();
290 void digi_change_looping_volume( fix volume )
292 if ( digi_looping_channel > -1 )
293 digi_set_channel_volume( digi_looping_channel, volume );
294 digi_looping_volume = volume;
297 void digi_stop_looping_sound()
299 if ( digi_looping_channel > -1 )
300 digi_stop_sound( digi_looping_channel );
301 digi_looping_channel = -1;
302 digi_looping_sound = -1;
305 void digi_pause_looping_sound()
307 if ( digi_looping_channel > -1 )
308 digi_stop_sound( digi_looping_channel );
309 digi_looping_channel = -1;
312 void digi_unpause_looping_sound()
314 digi_play_sample_looping_sub();
317 //hack to not start object when loading level
318 int Dont_start_sound_objects = 0;
320 void digi_start_sound_object(int i)
322 // start sample structures
323 SoundObjects[i].channel = -1;
325 if ( SoundObjects[i].volume <= 0 )
328 if ( Dont_start_sound_objects )
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 );
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)))
338 // start the sample playing
340 SoundObjects[i].channel = digi_start_sound( SoundObjects[i].soundnum,
341 SoundObjects[i].volume,
343 SoundObjects[i].flags & SOF_PLAY_FOREVER,
344 SoundObjects[i].loop_start,
345 SoundObjects[i].loop_end, i );
347 if (SoundObjects[i].channel > -1 )
348 N_active_sound_objects++;
351 //sounds longer than this get their 3d aspects updated
352 #define SOUND_3D_THRESHHOLD (digi_sample_rate * 3 / 2) //1.5 seconds
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 )
361 soundnum = digi_xlat_sound(org_soundnum);
363 if ( max_volume < 0 ) return -1;
364 // if ( max_volume > F1_0 ) max_volume = F1_0;
366 if (soundnum < 0 ) return -1;
367 if (GameSounds[soundnum].data==NULL) {
371 if ((objnum<0)||(objnum>Highest_object_index))
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 );
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 );
387 for (i=0; i<MAX_SOUND_OBJECTS; i++ )
388 if (SoundObjects[i].flags==0)
391 if (i==MAX_SOUND_OBJECTS) {
392 mprintf((1, "Too many sound objects!\n" ));
396 SoundObjects[i].signature=next_signature++;
397 SoundObjects[i].flags = SOF_USED | SOF_LINK_TO_OBJ;
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;
410 if (Dont_start_sound_objects) { //started at level start
412 SoundObjects[i].flags |= SOF_PERMANENT;
413 SoundObjects[i].channel = -1;
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 );
421 digi_start_sound_object(i);
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;
431 return SoundObjects[i].signature;
434 int digi_link_sound_to_object2( int org_soundnum, short objnum, int forever, fix max_volume, fix max_distance )
436 return digi_link_sound_to_object3( org_soundnum, objnum, forever, max_volume, max_distance, -1, -1 );
440 int digi_link_sound_to_object( int soundnum, short objnum, int forever, fix max_volume )
442 return digi_link_sound_to_object2( soundnum, objnum, forever, max_volume, 256*F1_0 );
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 )
451 soundnum = digi_xlat_sound(org_soundnum);
453 if ( max_volume < 0 ) return -1;
454 // if ( max_volume > F1_0 ) max_volume = F1_0;
456 if (soundnum < 0 ) return -1;
457 if (GameSounds[soundnum].data==NULL) {
462 if ((segnum<0)||(segnum>Highest_segment_index))
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 );
472 for (i=0; i<MAX_SOUND_OBJECTS; i++ )
473 if (SoundObjects[i].flags==0)
476 if (i==MAX_SOUND_OBJECTS) {
477 mprintf((1, "Too many sound objects!\n" ));
482 SoundObjects[i].signature=next_signature++;
483 SoundObjects[i].flags = SOF_USED | SOF_LINK_TO_POS;
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;
496 if (Dont_start_sound_objects) { //started at level start
498 SoundObjects[i].flags |= SOF_PERMANENT;
500 SoundObjects[i].channel = -1;
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 );
508 digi_start_sound_object(i);
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;
518 return SoundObjects[i].signature;
521 int digi_link_sound_to_pos( int soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume )
523 return digi_link_sound_to_pos2( soundnum, segnum, sidenum, pos, forever, max_volume, F1_0 * 256 );
526 //if soundnum==-1, kill any sound
527 void digi_kill_sound_linked_to_segment( int segnum, int sidenum, int soundnum )
532 soundnum = digi_xlat_sound(soundnum);
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--;
544 SoundObjects[i].channel = -1;
545 SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound
550 // If this assert happens, it means that there were 2 sounds
551 // that got deleted. Weird, get John.
553 mprintf( (1, "ERROR: More than 1 sounds were deleted from seg %d\n", segnum ));
557 void digi_kill_sound_linked_to_object( int objnum )
565 if ( Newdemo_state == ND_STATE_RECORDING ) {
566 newdemo_record_kill_sound_linked_to_object( objnum );
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--;
577 SoundObjects[i].channel = -1;
578 SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound
583 // If this assert happens, it means that there were 2 sounds
584 // that got deleted. Weird, get John.
586 mprintf( (1, "ERROR: More than 1 sounds were deleted from object %d\n", objnum ));
591 // John's new function, 2/22/96.
592 void digi_record_sound_objects()
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)
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 );
609 int was_recording = 0;
611 void digi_sync_sounds()
614 int oldvolume, oldpan;
616 if ( Newdemo_state == ND_STATE_RECORDING) {
617 if ( !was_recording ) {
618 digi_record_sound_objects();
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;
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...
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 );
649 } else if ( SoundObjects[i].flags & SOF_LINK_TO_OBJ ) {
653 if ( Newdemo_state == ND_STATE_PLAYBACK ) {
655 objnum = newdemo_find_object( SoundObjects[i].link_type.obj.objsignature );
657 objp = &Objects[objnum];
662 objp = &Objects[SoundObjects[i].link_type.obj.objnum];
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 );
671 digi_end_sound( SoundObjects[i].channel );
672 N_active_sound_objects--;
674 SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound
675 continue; // Go on to next sound...
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 );
683 if (oldvolume != SoundObjects[i].volume) {
684 if ( SoundObjects[i].volume < 1 ) {
685 // Sound is too far away, so stop it from playing.
687 if ( SoundObjects[i].channel>-1 ) {
688 if (SoundObjects[i].flags & SOF_PLAY_FOREVER)
689 digi_stop_sound( SoundObjects[i].channel );
691 digi_end_sound( SoundObjects[i].channel );
692 N_active_sound_objects--;
693 SoundObjects[i].channel = -1;
696 if (! (SoundObjects[i].flags & SOF_PLAY_FOREVER)) {
697 SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound
702 if (SoundObjects[i].channel<0) {
703 digi_start_sound_object(i);
705 digi_set_channel_volume( SoundObjects[i].channel, SoundObjects[i].volume );
710 if (oldpan != SoundObjects[i].pan) {
711 if (SoundObjects[i].channel>-1)
712 digi_set_channel_pan( SoundObjects[i].channel, SoundObjects[i].pan );
719 // digi_sound_debug();
723 void digi_pause_digi_sounds()
728 digi_pause_looping_sound();
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;
740 digi_stop_all_channels();
744 void digi_pause_all()
747 digi_pause_digi_sounds();
750 void digi_resume_digi_sounds()
752 digi_sync_sounds(); //don't think we really need to do this, but can't hurt
753 digi_unpause_looping_sound();
756 extern void digi_resume_midi();
758 void digi_resume_all()
761 digi_unpause_looping_sound();
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)
768 Assert( SoundObjects[i].flags & SOF_USED );
769 Assert( SoundObjects[i].channel > -1 );
771 N_active_sound_objects--;
772 SoundObjects[i].channel = -1;
775 void digi_stop_digi_sounds()
779 digi_stop_looping_sound();
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--;
787 SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound
791 digi_stop_all_channels();
797 digi_stop_current_song();
799 digi_stop_digi_sounds();
803 int verify_sound_channel_free( int channel )
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" ));
817 void digi_sound_debug()
820 int n_active_sound_objs=0;
823 for (i=0; i<MAX_SOUND_OBJECTS; i++ ) {
824 if ( SoundObjects[i].flags & SOF_USED ) {
826 if ( SoundObjects[i].channel > -1 )
827 n_active_sound_objs++;
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 ));
837 typedef struct sound_q {
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;
850 SoundQ_head = SoundQ_tail = 0;
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;
869 void SoundQ_process()
871 fix curtime = timer_get_approx_seconds();
873 if ( SoundQ_channel > -1 ) {
874 if ( digi_is_channel_playing(SoundQ_channel) )
879 if ( SoundQ_num > 0 ) {
880 mprintf(( 0, "SQ:%d ", SoundQ_num ));
883 while ( SoundQ_head != SoundQ_tail ) {
884 sound_q * q = &SoundQ[SoundQ_head];
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 );
890 // expired; remove from Queue
897 void digi_start_sound_queued( short soundnum, fix volume )
901 soundnum = digi_xlat_sound(soundnum);
903 if (soundnum < 0 ) return;
906 if ( i>=MAX_Q ) i = 0;
908 // Make sure its loud so it doesn't get cancelled!
909 if ( volume < F1_0+1 )
912 if ( i != SoundQ_head ) {
913 SoundQ[SoundQ_tail].time_added = timer_get_approx_seconds();
914 SoundQ[SoundQ_tail].soundnum = soundnum;
918 mprintf(( 0, "Sound Q full!\n" ));