2 * $Logfile: /Freespace2/code/Object/ObjectSnd.cpp $
7 * C module for managing object-linked persistant sounds
10 * Revision 1.3 2002/06/05 08:05:29 relnev
11 * stub/warning removal.
13 * reworked the sound code.
15 * Revision 1.2 2002/05/07 03:16:48 theoddone33
16 * The Great Newline Fix
18 * Revision 1.1.1.1 2002/05/03 03:28:10 root
22 * 11 9/08/99 8:56a Mikek
23 * Blast. Suppress a debug warning.
25 * 10 9/08/99 8:56a Mikek
26 * Whoops, broke the build with debug code.
28 * 9 9/08/99 8:42a Mikek
29 * Make flyby sounds a lot easier to trigger. Decrease some thresholds
30 * and remove the dot product check. This is handled by the delta
33 * 8 7/01/99 4:23p Dave
34 * Full support for multiple linked ambient engine sounds. Added "big
37 * 7 7/01/99 11:44a Dave
38 * Updated object sound system to allow multiple obj sounds per ship.
39 * Added hit-by-beam sound. Added killed by beam sound.
41 * 6 6/25/99 3:08p Dave
42 * Multiple flyby sounds.
44 * 5 5/23/99 8:11p Alanl
45 * Added support for EAX
47 * 4 5/18/99 11:50a Andsager
48 * Remove unused object type OBJ_GHOST_SAVE
50 * 3 4/23/99 12:01p Johnson
53 * 2 10/07/98 10:53a Dave
56 * 1 10/07/98 10:50a Dave
58 * 59 5/15/98 5:16p Dave
59 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
60 * status for team vs. team. Put in asserts to check for invalid team vs.
63 * 58 5/07/98 12:24a Hoffoss
64 * Finished up sidewinder force feedback support.
66 * 57 5/06/98 1:29p Dan
67 * AL: allow engine sounds to play polyphonically
69 * 56 5/06/98 10:27a Dan
70 * AL: Fix bug with object sounds and Aureal
72 * 55 4/19/98 9:32p Lawrance
73 * Add support for Shivan flyby sound
75 * 54 4/18/98 9:12p Lawrance
76 * Added Aureal support.
78 * 53 4/12/98 5:31p Lawrance
79 * use timer_get_milliseconds() instead of gettime()
81 * 52 4/08/98 8:33p Lawrance
82 * increase distance at which flyby sound is heard
84 * 51 4/01/98 9:21p John
85 * Made NDEBUG, optimized build with no warnings or errors.
87 * 50 3/21/98 3:36p Lawrance
88 * Don't change frequency unless a threshold change has been reached.
90 * 49 3/19/98 5:34p Lawrance
91 * Only play flyby sound if both ships involved are above a minimum speed
93 * 48 3/18/98 9:49a Lawrance
94 * fix uninitialized data bug
96 * 47 3/17/98 5:55p Lawrance
97 * Support object-linked sounds for asteroids.
99 * 46 3/14/98 4:59p Lawrance
100 * Fix bug with object sounds not getting cleared
102 * 45 2/22/98 2:48p John
103 * More String Externalization Classification
105 * 44 2/20/98 8:32p Lawrance
106 * Add radius parm to sound_play_3d()
108 * 43 2/12/98 11:53p Lawrance
109 * move engine pos closer to center of ship, ensure flyby sounds only play
110 * when flying past a small ship
112 * 42 2/11/98 5:38p Dave
113 * Put in a global inited flag for objsound.
115 * 41 2/11/98 11:30a Dan
116 * AL: fix DirectSound3D bug
118 * 40 2/11/98 10:28a Lawrance
119 * Fix attenuation problems related to engine position.
121 * 39 2/09/98 9:09p Lawrance
122 * ensure we don't get two flyby sounds too close together
124 * 38 2/02/98 8:23p Lawrance
125 * double distance at which a flyby sound is played
127 * 37 1/29/98 10:31a Lawrance
128 * Don't play doppler effect for cruisers and capital ships
130 * 36 1/20/98 10:04a Lawrance
131 * fix volume bug, do obj_snd_do_frame at 10Hz
133 * 35 1/20/98 9:47a Mike
134 * Suppress optimized compiler warnings.
135 * Some secondary weapon work.
137 * 34 1/10/98 1:14p John
138 * Added explanation to debug console commands
140 * 33 12/21/97 4:33p John
141 * Made debug console functions a class that registers itself
142 * automatically, so you don't need to add the function to
143 * debugfunctions.cpp.
145 * 32 11/20/97 6:45p Lawrance
146 * allow two looping debris sounds to play
148 * 31 11/04/97 10:18a Dan
149 * initialize closest_obj to NULL
151 * 30 11/03/97 11:09p Lawrance
152 * Only play flyby sound for ships (ie not debris).
154 * 29 10/26/97 3:22p Lawrance
155 * use volume and not distance when deciding which engine sounds to play
157 * 28 10/22/97 10:37a Johnson
158 * ALAN: ensure that object sounds are only deleted once
160 * 27 10/10/97 7:43p Lawrance
161 * use SF_ENGINES_ON flag
163 * 26 10/06/97 4:13p Lawrance
164 * use engine pos when updating volume for object sounds
166 * 25 10/01/97 5:55p Lawrance
167 * change call to snd_play_3d() to allow for arbitrary listening position
169 * 24 9/18/97 7:58a Lawrance
170 * use rear of ship when deciding where to play the engine sound
172 * 23 9/11/97 5:01p Dave
173 * Minor changes to handle ingame joining/dropping for multiplayer.
175 * 22 9/03/97 5:02p Lawrance
176 * add engine stuttering when a ship is dying
178 * 21 8/29/97 5:04p Dave
179 * Made sure ghost objects are handled correctly.
181 * 20 7/28/97 11:38a Lawrance
182 * let ship engine scale with speed for DirectSound3D engine sounds too
184 * 19 7/27/97 5:14p Lawrance
185 * add afterburners to the player control info
187 * 18 7/14/97 12:04a Lawrance
188 * make Obj_snd_enabled visible
190 * 17 7/09/97 12:07a Mike
191 * Changes in ship_info struct.
193 * 16 7/08/97 11:38a Lawrance
194 * added SIF_BIG_SHIP flag (used for object-linked engine sounds)
196 * 15 6/23/97 10:15a Lawrance
197 * fix bug with object linked sounds not stopping playing sounds
199 * 14 6/19/97 2:05p Lawrance
200 * when stopping a linked sound, stop it right away
202 * 13 6/09/97 11:50p Lawrance
203 * integrating DirectSound3D
205 * 12 6/08/97 5:59p Lawrance
206 * comment out ds3d stuff for now
208 * 11 6/06/97 4:13p Lawrance
209 * use an index instead of a pointer for object-linked sounds
211 * 10 6/05/97 1:37a Lawrance
212 * change to support snd_get_vol_and_pan()
214 * 9 6/05/97 1:07a Lawrance
215 * changes to support sound interface
217 * 8 6/02/97 1:50p Lawrance
218 * supporting integration with Direct3D
220 * 7 5/18/97 2:40p Lawrance
221 * added debug function to toggle doppler effect
223 * 6 5/15/97 9:05a Lawrance
224 * comment out some debugging nprintf()'s
226 * 5 5/14/97 10:47a Lawrance
227 * only play external engine sound for loudest ship
229 * 4 5/09/97 4:33p Lawrance
232 * 3 5/09/97 9:41a Lawrance
235 * 2 5/08/97 4:30p Lawrance
236 * split off object sound stuff into separate file
243 #include "objectsnd.h"
244 #include "linklist.h"
253 // Persistant sounds for objects (pointer to obj_snd is in object struct)
254 typedef struct _obj_snd {
255 _obj_snd *next, *prev;
256 int objnum; // object index of object that contains this sound
257 int id; // Index into Snds[] array
258 int instance; // handle of currently playing sound (a ds3d handle if USES_DS3D flag set)
259 int next_update; // timestamp that marks next allowed vol/pan change
260 float vol; // volume of sound (range: 0.0 -> 1.0)
261 float pan; // pan of sound (range: -1.0 -> 1.0)
262 int freq; // valid range: 100 -> 100000 Hz
264 vector offset; // offset from the center of the object where the sound lives
267 #define VOL_PAN_UPDATE 50 // time in ms to update a persistant sound vol/pan
268 #define MIN_PERSISTANT_VOL 0.10f
269 #define MIN_FORWARD_SPEED 5
270 #define SPEED_SOUND 600.0f // speed of sound in FreeSpace
272 #define MAX_OBJ_SOUNDS_PLAYING 5
273 static int Num_obj_sounds_playing;
275 #define OBJSND_CHANGE_FREQUENCY_THRESHOLD 10
277 static obj_snd obj_snd_list; // head of linked list of object sound structs
278 static int Doppler_enabled = TRUE;
280 #define MAX_OBJ_SNDS 256
281 obj_snd Objsnds[MAX_OBJ_SNDS];
283 int Obj_snd_enabled = TRUE;
284 int Obj_snd_last_update; // timer used to run object sound updates at fixed time intervals
285 int Obj_snd_level_inited=0;
288 #define FLYBY_MIN_DISTANCE 90
289 #define FLYBY_MIN_SPEED 50
290 #define FLYBY_MIN_RELATIVE_SPEED 100
291 #define FLYBY_MIN_NEXT_TIME 1000 // in ms
292 #define FLYBY_MIN_REPEAT_TIME 4000 // in ms
293 int Flyby_next_sound;
294 int Flyby_next_repeat;
295 object *Flyby_last_objp;
297 // return the world pos of the sound source on a ship.
298 void obj_snd_source_pos(vector *sound_pos, obj_snd *osp)
301 object *objp = &Objects[osp->objnum];
303 // get sound pos in world coords
304 vm_vec_unrotate(&offset_world, &osp->offset, &objp->orient);
305 vm_vec_add(sound_pos, &objp->pos, &offset_world);
308 // ---------------------------------------------------------------------------------------
311 // Debug console function for object linked persistant sounds
314 DCF(objsnd, "Persistant sound stuff" )
316 char buf1[16], buf2[64];
320 dc_get_arg(ARG_STRING|ARG_NONE);
322 if ( Dc_arg_type & ARG_NONE ) {
323 if ( Obj_snd_enabled == TRUE ) {
325 Obj_snd_enabled = FALSE;
328 Obj_snd_enabled = TRUE;
331 if ( !stricmp( Dc_arg, "list" )) {
332 for ( osp = GET_FIRST(&obj_snd_list); osp !=END_OF_LIST(&obj_snd_list); osp = GET_NEXT(osp) ) {
334 if ( osp->instance == -1 ) {
336 //sprintf(buf1,"OFF");
341 if ( Objects[osp->objnum].type == OBJ_SHIP ) {
342 sprintf(buf2, Ships[Objects[osp->objnum].instance].ship_name);
344 else if ( Objects[osp->objnum].type == OBJ_DEBRIS ) {
345 sprintf(buf2, "Debris");
348 sprintf(buf2, "Unknown");
354 obj_snd_source_pos(&source_pos, osp);
355 distance = vm_vec_dist_quick( &source_pos, &View_position );
357 dc_printf("Object %d => name: %s vol: %.2f pan: %.2f dist: %.2f status: %s\n", osp->objnum, buf2, osp->vol, osp->pan, distance, buf1);
359 dc_printf("Number object-linked sounds playing: %d\n", Num_obj_sounds_playing);
364 dc_printf ("Usage: objsnd [list]\n");
365 dc_printf ("[list] -- displays status of all objects with linked sounds\n");
366 dc_printf ("with no parameters, object sounds are toggled on/off\n");
371 dc_printf( "Object sounds are: %s\n", (Obj_snd_enabled?"ON":"OFF") );
376 // ---------------------------------------------------------------------------------------
377 // Debug console function for toggling doppler effection on/off
379 DCF_BOOL( doppler, Doppler_enabled )
382 // ---------------------------------------------------------------------------------------
383 // obj_snd_get_slot()
385 // Get a free slot in the Objsnds[] array
387 // returns -1 if no slot is available
388 int obj_snd_get_slot()
392 for ( i = 0; i < MAX_OBJ_SNDS; i++ ) {
393 if ( !(Objsnds[i].flags & OS_USED) )
400 // ---------------------------------------------------------------------------------------
403 // Called once at level start to initialize the persistant object sound system
405 void obj_snd_level_init()
409 list_init(&obj_snd_list);
410 for ( i = 0; i < MAX_OBJ_SNDS; i++ ) {
411 Objsnds[i].flags = 0;
414 Num_obj_sounds_playing = 0;
415 Flyby_next_sound = 1;
416 Flyby_next_repeat = 1;
417 Flyby_last_objp = NULL;
418 Obj_snd_last_update=0;
420 Obj_snd_level_inited=1;
424 // ---------------------------------------------------------------------------------------
427 // Stop a persistant sound from playing.
429 // parameters: objp => pointer to object that sound is to be stopped for
432 void obj_snd_stop(object *objp, int index)
438 if(index >= MAX_OBJECT_SOUNDS){
443 // if index is -1, kill all sounds for this guy
445 // kill all sounds for this guy
446 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
447 if ( objp->objsnd_num[idx] == -1 ){
451 osp = &Objsnds[objp->objsnd_num[idx]];
453 if ( osp->instance != -1 ) {
454 snd_stop(osp->instance);
461 Num_obj_sounds_playing--;
462 Assert(Num_obj_sounds_playing >= 0);
472 if ( objp->objsnd_num[index] == -1 ){
476 osp = &Objsnds[objp->objsnd_num[index]];
478 if ( osp->instance != -1 ) {
479 snd_stop(osp->instance);
486 Num_obj_sounds_playing--;
487 Assert(Num_obj_sounds_playing >= 0);
498 // ---------------------------------------------------------------------------------------
499 // obj_snd_stop_all()
501 // Stop all object-linked persistant sounds from playing
504 void obj_snd_stop_all()
508 for ( A = GET_FIRST(&obj_used_list); A !=END_OF_LIST(&obj_used_list); A = GET_NEXT(A) ) {
515 // ---------------------------------------------------------------------------------------
516 // obj_snd_get_freq()
518 // Calculate the frequency of a sound to be played, based on the relative velocities
519 // of the source and observor
521 // returns: frequency of the sound
523 int obj_snd_get_freq(int source_freq, object* source, object* observor, vector *source_pos)
525 vector v_os, v_so; // os == observor to source, so == source to observor
528 vm_vec_normalized_dir(&v_os, source_pos, &observor->pos);
529 vm_vec_normalized_dir(&v_so, &observor->pos, source_pos);
531 vo = vm_vec_dotprod(&v_os, &observor->phys_info.vel);
532 vs = vm_vec_dotprod(&v_so, &source->phys_info.vel);
534 freq = source_freq * ( (SPEED_SOUND + vo) / (SPEED_SOUND - vs) );
539 // ---------------------------------------------------------------------------------------
540 // obj_snd_stop_lowest_vol()
542 // Stop a playing object sound, if it is quieter than sound at new_distance
544 // input: new_vol => volume of requested sound to play
546 // returns: TRUE => A sound was stopped
547 // FALSE => A sound was not stopped
549 int obj_snd_stop_lowest_vol(float new_vol)
553 obj_snd *lowest_vol_osp = NULL;
555 int obj_snd_index = -1;
558 lowest_vol = 1000.0f;
559 for ( osp = GET_FIRST(&obj_snd_list); osp !=END_OF_LIST(&obj_snd_list); osp = GET_NEXT(osp) ) {
560 Assert(osp->objnum != -1);
561 objp = &Objects[osp->objnum];
563 if ( (osp->instance != -1) && (osp->vol < lowest_vol) ) {
564 lowest_vol = osp->vol;
565 lowest_vol_osp = osp;
569 Assert(lowest_vol_osp != NULL);
570 objp = &Objects[lowest_vol_osp->objnum];
572 if ( (lowest_vol < new_vol) && (objp != NULL) ) {
573 // determine what index in this guy the sound is
574 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
575 if(objp->objsnd_num[idx] == (lowest_vol_osp - Objsnds)){
581 if((obj_snd_index == -1) || (obj_snd_index >= MAX_OBJECT_SOUNDS)){
584 obj_snd_stop(objp, obj_snd_index);
593 //int Debug_1 = 0, Debug_2 = 0;
595 // ---------------------------------------------------------------------------------------
596 // maybe_play_flyby_snd()
598 // Based on how close the object is to the player ship (and relative speed), maybe
599 // play a flyby sound. Only play flyby sound for OBJ_SHIP objects.
601 // NOTE: global data Flyby_last_objp, Flyby_next_sound, Flyby_next_repeat are
604 void maybe_play_flyby_snd(float closest_dist, object *closest_objp)
606 if ( closest_objp == NULL || closest_objp->type != OBJ_SHIP ) {
607 goto play_no_flyby_sound;
610 if ( closest_dist < FLYBY_MIN_DISTANCE ) {
611 float relative_speed;
613 vm_vec_sub(&diff, &Player_obj->phys_info.vel, &closest_objp->phys_info.vel);
616 relative_speed = vm_vec_mag_quick(&diff);
617 if ( relative_speed > FLYBY_MIN_RELATIVE_SPEED ) {
618 if ( timestamp_elapsed(Flyby_next_sound) ) {
620 if ( closest_objp == Flyby_last_objp ) {
621 if ( timestamp_elapsed(Flyby_next_repeat) ) {
622 Flyby_next_repeat = timestamp(FLYBY_MIN_REPEAT_TIME);
625 goto play_no_flyby_sound;
628 Assert(closest_objp->type == OBJ_SHIP);
629 if(closest_objp->type != OBJ_SHIP){
633 // pick a random species-based sound
634 ship_info *sip = &Ship_info[Ships[closest_objp->instance].ship_info_index];
635 int species = SPECIES_TERRAN;
636 if((sip->species >= 0) && (sip->species < MAX_SPECIES_NAMES)){
637 species = sip->species;
639 int ship_size = 0; // fighter
640 if(sip->flags & SIF_BOMBER){
645 snd_play_3d(&Snds_flyby[species][ship_size], &closest_objp->pos, &View_position);
646 //snd_play_3d(&Snds_flyby[Debug_1][Debug_2], &closest_objp->pos, &View_position);
648 //float dist = vm_vec_dist(&closest_objp->pos, &View_position);
649 //nprintf(("AI", "Frame %i: Playing flyby sound, species = %i, size = %i, dist = %7.3f\n", Framecount, species, ship_size, dist));
650 // nprintf(("AI", "Frame %i: Playing flyby sound, species = %i, size = %i, dist = %7.3f\n", Framecount, Debug_1, Debug_2, dist));
651 //Debug_1 = (Debug_1+1)%3;
652 //Debug_2 = (Debug_2+1)%2;
654 joy_ff_fly_by(100 - (int) (100.0f * closest_dist / FLYBY_MIN_DISTANCE));
656 Flyby_next_sound = timestamp(FLYBY_MIN_NEXT_TIME);
657 Flyby_last_objp = closest_objp;
666 // ---------------------------------------------------------------------------------------
667 // obj_snd_do_frame()
669 // Called once per frame to process the persistant sound objects
671 void obj_snd_do_frame()
673 float closest_dist, distance, speed_vol_multiplier, percent_max;
675 object *objp, *closest_objp;
678 int channel, go_ahead_flag;
682 if ( Obj_snd_enabled == FALSE )
685 int now = timer_get_milliseconds();
686 if ( (now - Obj_snd_last_update) > 100 ) {
687 Obj_snd_last_update=now;
692 closest_dist = 1000000.0f;
695 for ( osp = GET_FIRST(&obj_snd_list); osp !=END_OF_LIST(&obj_snd_list); osp = GET_NEXT(osp) ) {
697 objp = &Objects[osp->objnum];
698 if ( Player_obj == objp ) {
704 obj_snd_source_pos(&source_pos, osp);
705 distance = vm_vec_dist_quick( &source_pos, &View_position );
707 // how much extra distance do we add before attentuation?
709 if(osp->flags & OS_MAIN){
710 add_distance = objp->radius;
713 distance -= add_distance;
714 if ( distance < 0 ) {
718 // save closest distance (used for flyby sound) if this is a small ship
719 if ( (objp->type == OBJ_SHIP) && (distance < closest_dist) ) {
720 if ( Ship_info[Ships[objp->instance].ship_info_index].flags & SIF_SMALL_SHIP ) {
721 closest_dist = distance;
726 // If the object is a ship, we don't want to start the engine sound unless the ship is
727 // moving (unless flag SIF_BIG_SHIP is set)
728 speed_vol_multiplier = 1.0f;
729 if ( objp->type == OBJ_SHIP ) {
730 if ( !(Ship_info[Ships[objp->instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) ) {
731 if ( objp->phys_info.max_vel.z <= 0 ) {
735 percent_max = objp->phys_info.fspeed / objp->phys_info.max_vel.z;
737 if ( percent_max >= 0.5 )
738 speed_vol_multiplier = 1.0f;
740 speed_vol_multiplier = 0.5f + (percent_max); // linear interp: 0.5->1.0 when 0.0->0.5
745 go_ahead_flag = TRUE;
746 float max_vol,new_vol;
747 if ( osp->instance == -1 ) {
748 if ( distance < Snds[osp->id].max ) {
749 max_vol = Snds[osp->id].default_volume;
750 if ( distance <= Snds[osp->id].min ) {
754 new_vol = max_vol - (distance - Snds[osp->id].min) * max_vol / (Snds[osp->id].max - Snds[osp->id].min);
757 if ( new_vol < 0.1 ) {
761 switch( objp->type ) {
765 if ( Num_obj_sounds_playing >= MAX_OBJ_SOUNDS_PLAYING ) {
766 go_ahead_flag = obj_snd_stop_lowest_vol(new_vol);
775 if ( go_ahead_flag ) {
776 if ( ds_using_ds3d() ) {
777 osp->instance = snd_play_3d(gs, &source_pos, &View_position, add_distance, &objp->phys_info.vel, 1, 1.0f, SND_PRIORITY_TRIPLE_INSTANCE);
778 if ( osp->instance != -1 ) {
779 Num_obj_sounds_playing++;
783 snd_get_3d_vol_and_pan(gs, &source_pos, &osp->vol, &osp->pan, add_distance);
784 osp->instance = snd_play_looping( gs, osp->pan, 0, 0, (osp->vol*speed_vol_multiplier)/gs->default_volume, SND_PRIORITY_TRIPLE_INSTANCE );
785 if ( osp->instance != -1 ) {
786 osp->freq = snd_get_pitch(osp->instance);
787 Num_obj_sounds_playing++;
791 Assert(Num_obj_sounds_playing <= MAX_OBJ_SOUNDS_PLAYING);
793 } // end if ( distance < Snds[osp->id].max )
794 } // if ( osp->instance == -1 )
796 if ( distance > Snds[osp->id].max ) {
797 int sound_index = -1;
800 // determine which sound index it is for this guy
801 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
802 if(objp->objsnd_num[idx] == (osp - Objsnds)){
808 Assert(sound_index != -1);
809 obj_snd_stop(objp, sound_index); // currently playing sound has gone past maximum
813 if ( osp->instance == -1 )
817 if ( objp->type == OBJ_SHIP )
818 sp = &Ships[objp->instance];
820 if (ds_using_ds3d()) {
821 channel = ds_get_channel(osp->instance);
822 // for DirectSound3D sounds, re-establish the maximum speed based on the
823 // speed_vol_multiplier
824 if ( sp == NULL || ( (sp != NULL) && (sp->flags & SF_ENGINES_ON) ) ) {
825 snd_set_volume( osp->instance, gs->default_volume*speed_vol_multiplier );
828 // engine sound is disabled
829 snd_set_volume( osp->instance, 0.0f );
833 vel = &objp->phys_info.vel;
835 // Don't play doppler effect for cruisers or captials
837 if ( ship_get_SIF(sp) & (SIF_BIG_SHIP | SIF_HUGE_SHIP) ) {
842 ds3d_update_buffer(channel, i2fl(gs->min), i2fl(gs->max), &source_pos, vel);
843 snd_get_3d_vol_and_pan(gs, &source_pos, &osp->vol, &osp->pan, add_distance);
846 if ( sp == NULL || (sp != NULL && (sp->flags & SF_ENGINES_ON) ) ) {
847 snd_get_3d_vol_and_pan(gs, &source_pos, &osp->vol, &osp->pan, add_distance);
848 snd_set_volume( osp->instance, osp->vol*speed_vol_multiplier );
849 snd_set_pan( osp->instance, osp->pan );
850 // Don't play doppler effect for cruisers or captials
851 if ( objp->type == OBJ_SHIP && Doppler_enabled == TRUE ) {
852 if ( !(ship_get_SIF(sp) & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) ) {
854 // calc doppler effect
855 new_freq = obj_snd_get_freq(osp->freq, objp, Player_obj, &source_pos);
856 if ( abs(new_freq - osp->freq) > OBJSND_CHANGE_FREQUENCY_THRESHOLD ) {
857 snd_set_pitch( osp->instance, new_freq);
863 snd_set_volume( osp->instance, 0.0f );
867 // see if we want to play a flyby sound
868 maybe_play_flyby_snd(closest_dist, closest_objp);
871 // ---------------------------------------------------------------------------------------
874 // Assign a persistant sound to an object.
876 // parameters: objnum => index of object that sound is being assigned to
877 // i => Index into Snds[] array
878 // fname => filename of sound to play ( so DS3D can load the sound )
880 // returns: -1 => sound could not be assigned (possible, since only MAX_OBJECT_SOUNDS persistant
881 // sound can be assigned per object).
882 // 0 => sound was successfully assigned
884 int obj_snd_assign(int objnum, int i, vector *pos, int main)
888 int idx, sound_index;
890 objp = &Objects[objnum];
892 if ( Obj_snd_enabled == FALSE )
895 // try and find a valid objsound index
897 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
898 if(objp->objsnd_num[idx] == -1){
905 if ( sound_index == -1 ){
909 objp->objsnd_num[sound_index] = (short)obj_snd_get_slot();
910 if ( objp->objsnd_num[sound_index] == -1 ) {
911 nprintf(("Sound", "SOUND ==> No free object-linked sounds left\n"));
914 snd = &Objsnds[objp->objsnd_num[sound_index]];
915 snd->flags = OS_USED;
918 snd->flags |= OS_MAIN;
928 snd->objnum = OBJ_INDEX(objp);
929 snd->next_update = 1;
931 // vm_vec_sub(&snd->offset, pos, &objp->pos);
933 // add objp to the obj_snd_list
934 list_append( &obj_snd_list, snd );
940 // ---------------------------------------------------------------------------------------
943 // Remove a persistant sound that has been assigned to an object.
945 // parameters: objnum => index of object that sound is being removed from.
948 void obj_snd_delete(int objnum, int sndnum)
954 Assert(objnum >= 0 && objnum < MAX_OBJECTS);
955 objp = &Objects[objnum];
957 // delete all object sounds for this guy
958 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
960 if ( objp->objsnd_num[idx] == -1 ){
964 osp = &Objsnds[objp->objsnd_num[idx]];
966 // if we're just deleting a specific sound type
967 // and this is not one of them. skip it.
968 if((sndnum != -1) && (osp->id != sndnum)){
972 obj_snd_stop(objp, -1);
974 // remove objp from the obj_snd_list
975 list_remove( &obj_snd_list, osp );
979 objp->objsnd_num[idx] = -1;
983 // ---------------------------------------------------------------------------------------
984 // obj_snd_delete_all()
986 // Remove all persistant sounds
988 void obj_snd_delete_all()
993 osp = GET_FIRST(&obj_snd_list);
994 while( (osp != NULL) && (osp !=END_OF_LIST(&obj_snd_list)) ) {
995 temp = GET_NEXT(osp);
996 Assert( osp->objnum != -1 );
998 obj_snd_delete( osp->objnum );
1005 for(idx=0; idx<MAX_OBJ_SNDS; idx++){
1006 if(Objsnds[idx].flags & OS_USED){
1007 obj_snd_delete(Objsnds[idx].objnum);
1012 // ---------------------------------------------------------------------------------------
1015 // Called once at game close to de-initialize the persistant object sound system
1017 void obj_snd_level_close()
1019 if ( !Obj_snd_level_inited ) {
1022 obj_snd_delete_all();
1023 Obj_snd_level_inited=0;
1026 // ---------------------------------------------------------------------------------------
1027 // obj_snd_is_playing()
1029 // Determines if a given object-linked sound is currently playing
1031 int obj_snd_is_playing(int index)
1038 Assert( index >= 0 && index < MAX_OBJ_SNDS );
1040 osp = &Objsnds[index];
1041 if ( osp->instance == -1 )
1047 // ---------------------------------------------------------------------------------------
1048 // obj_snd_return_instance()
1050 // Returns the sound instance for a given object-linked sound
1052 int obj_snd_return_instance(int index)
1057 Assert( index >= 0 && index < MAX_OBJ_SNDS );
1059 return Objsnds[index].instance;