2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Object/ObjectSnd.cpp $
15 * C module for managing object-linked persistant sounds
18 * Revision 1.5 2002/06/17 06:33:10 relnev
19 * ryan's struct patch for gcc 2.95
21 * Revision 1.4 2002/06/09 04:41:24 relnev
22 * added copyright header
24 * Revision 1.3 2002/06/05 08:05:29 relnev
25 * stub/warning removal.
27 * reworked the sound code.
29 * Revision 1.2 2002/05/07 03:16:48 theoddone33
30 * The Great Newline Fix
32 * Revision 1.1.1.1 2002/05/03 03:28:10 root
36 * 11 9/08/99 8:56a Mikek
37 * Blast. Suppress a debug warning.
39 * 10 9/08/99 8:56a Mikek
40 * Whoops, broke the build with debug code.
42 * 9 9/08/99 8:42a Mikek
43 * Make flyby sounds a lot easier to trigger. Decrease some thresholds
44 * and remove the dot product check. This is handled by the delta
47 * 8 7/01/99 4:23p Dave
48 * Full support for multiple linked ambient engine sounds. Added "big
51 * 7 7/01/99 11:44a Dave
52 * Updated object sound system to allow multiple obj sounds per ship.
53 * Added hit-by-beam sound. Added killed by beam sound.
55 * 6 6/25/99 3:08p Dave
56 * Multiple flyby sounds.
58 * 5 5/23/99 8:11p Alanl
59 * Added support for EAX
61 * 4 5/18/99 11:50a Andsager
62 * Remove unused object type OBJ_GHOST_SAVE
64 * 3 4/23/99 12:01p Johnson
67 * 2 10/07/98 10:53a Dave
70 * 1 10/07/98 10:50a Dave
72 * 59 5/15/98 5:16p Dave
73 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
74 * status for team vs. team. Put in asserts to check for invalid team vs.
77 * 58 5/07/98 12:24a Hoffoss
78 * Finished up sidewinder force feedback support.
80 * 57 5/06/98 1:29p Dan
81 * AL: allow engine sounds to play polyphonically
83 * 56 5/06/98 10:27a Dan
84 * AL: Fix bug with object sounds and Aureal
86 * 55 4/19/98 9:32p Lawrance
87 * Add support for Shivan flyby sound
89 * 54 4/18/98 9:12p Lawrance
90 * Added Aureal support.
92 * 53 4/12/98 5:31p Lawrance
93 * use timer_get_milliseconds() instead of gettime()
95 * 52 4/08/98 8:33p Lawrance
96 * increase distance at which flyby sound is heard
98 * 51 4/01/98 9:21p John
99 * Made NDEBUG, optimized build with no warnings or errors.
101 * 50 3/21/98 3:36p Lawrance
102 * Don't change frequency unless a threshold change has been reached.
104 * 49 3/19/98 5:34p Lawrance
105 * Only play flyby sound if both ships involved are above a minimum speed
107 * 48 3/18/98 9:49a Lawrance
108 * fix uninitialized data bug
110 * 47 3/17/98 5:55p Lawrance
111 * Support object-linked sounds for asteroids.
113 * 46 3/14/98 4:59p Lawrance
114 * Fix bug with object sounds not getting cleared
116 * 45 2/22/98 2:48p John
117 * More String Externalization Classification
119 * 44 2/20/98 8:32p Lawrance
120 * Add radius parm to sound_play_3d()
122 * 43 2/12/98 11:53p Lawrance
123 * move engine pos closer to center of ship, ensure flyby sounds only play
124 * when flying past a small ship
126 * 42 2/11/98 5:38p Dave
127 * Put in a global inited flag for objsound.
129 * 41 2/11/98 11:30a Dan
130 * AL: fix DirectSound3D bug
132 * 40 2/11/98 10:28a Lawrance
133 * Fix attenuation problems related to engine position.
135 * 39 2/09/98 9:09p Lawrance
136 * ensure we don't get two flyby sounds too close together
138 * 38 2/02/98 8:23p Lawrance
139 * double distance at which a flyby sound is played
141 * 37 1/29/98 10:31a Lawrance
142 * Don't play doppler effect for cruisers and capital ships
144 * 36 1/20/98 10:04a Lawrance
145 * fix volume bug, do obj_snd_do_frame at 10Hz
147 * 35 1/20/98 9:47a Mike
148 * Suppress optimized compiler warnings.
149 * Some secondary weapon work.
151 * 34 1/10/98 1:14p John
152 * Added explanation to debug console commands
154 * 33 12/21/97 4:33p John
155 * Made debug console functions a class that registers itself
156 * automatically, so you don't need to add the function to
157 * debugfunctions.cpp.
159 * 32 11/20/97 6:45p Lawrance
160 * allow two looping debris sounds to play
162 * 31 11/04/97 10:18a Dan
163 * initialize closest_obj to NULL
165 * 30 11/03/97 11:09p Lawrance
166 * Only play flyby sound for ships (ie not debris).
168 * 29 10/26/97 3:22p Lawrance
169 * use volume and not distance when deciding which engine sounds to play
171 * 28 10/22/97 10:37a Johnson
172 * ALAN: ensure that object sounds are only deleted once
174 * 27 10/10/97 7:43p Lawrance
175 * use SF_ENGINES_ON flag
177 * 26 10/06/97 4:13p Lawrance
178 * use engine pos when updating volume for object sounds
180 * 25 10/01/97 5:55p Lawrance
181 * change call to snd_play_3d() to allow for arbitrary listening position
183 * 24 9/18/97 7:58a Lawrance
184 * use rear of ship when deciding where to play the engine sound
186 * 23 9/11/97 5:01p Dave
187 * Minor changes to handle ingame joining/dropping for multiplayer.
189 * 22 9/03/97 5:02p Lawrance
190 * add engine stuttering when a ship is dying
192 * 21 8/29/97 5:04p Dave
193 * Made sure ghost objects are handled correctly.
195 * 20 7/28/97 11:38a Lawrance
196 * let ship engine scale with speed for DirectSound3D engine sounds too
198 * 19 7/27/97 5:14p Lawrance
199 * add afterburners to the player control info
201 * 18 7/14/97 12:04a Lawrance
202 * make Obj_snd_enabled visible
204 * 17 7/09/97 12:07a Mike
205 * Changes in ship_info struct.
207 * 16 7/08/97 11:38a Lawrance
208 * added SIF_BIG_SHIP flag (used for object-linked engine sounds)
210 * 15 6/23/97 10:15a Lawrance
211 * fix bug with object linked sounds not stopping playing sounds
213 * 14 6/19/97 2:05p Lawrance
214 * when stopping a linked sound, stop it right away
216 * 13 6/09/97 11:50p Lawrance
217 * integrating DirectSound3D
219 * 12 6/08/97 5:59p Lawrance
220 * comment out ds3d stuff for now
222 * 11 6/06/97 4:13p Lawrance
223 * use an index instead of a pointer for object-linked sounds
225 * 10 6/05/97 1:37a Lawrance
226 * change to support snd_get_vol_and_pan()
228 * 9 6/05/97 1:07a Lawrance
229 * changes to support sound interface
231 * 8 6/02/97 1:50p Lawrance
232 * supporting integration with Direct3D
234 * 7 5/18/97 2:40p Lawrance
235 * added debug function to toggle doppler effect
237 * 6 5/15/97 9:05a Lawrance
238 * comment out some debugging nprintf()'s
240 * 5 5/14/97 10:47a Lawrance
241 * only play external engine sound for loudest ship
243 * 4 5/09/97 4:33p Lawrance
246 * 3 5/09/97 9:41a Lawrance
249 * 2 5/08/97 4:30p Lawrance
250 * split off object sound stuff into separate file
257 #include "objectsnd.h"
258 #include "linklist.h"
266 // Persistant sounds for objects (pointer to obj_snd is in object struct)
267 typedef struct _obj_snd {
268 _obj_snd *next, *prev;
269 int objnum; // object index of object that contains this sound
270 int id; // Index into Snds[] array
271 int instance; // handle of currently playing sound (a ds3d handle if USES_DS3D flag set)
272 int next_update; // timestamp that marks next allowed vol/pan change
273 float vol; // volume of sound (range: 0.0 -> 1.0)
274 float pan; // pan of sound (range: -1.0 -> 1.0)
275 int freq; // valid range: 100 -> 100000 Hz
277 vector offset; // offset from the center of the object where the sound lives
280 #define VOL_PAN_UPDATE 50 // time in ms to update a persistant sound vol/pan
281 #define MIN_PERSISTANT_VOL 0.10f
282 #define MIN_FORWARD_SPEED 5
283 #define SPEED_SOUND 600.0f // speed of sound in FreeSpace
285 #define MAX_OBJ_SOUNDS_PLAYING 5
286 static int Num_obj_sounds_playing;
288 #define OBJSND_CHANGE_FREQUENCY_THRESHOLD 10
290 static obj_snd obj_snd_list; // head of linked list of object sound structs
291 static int Doppler_enabled = TRUE;
293 #define MAX_OBJ_SNDS 256
294 obj_snd Objsnds[MAX_OBJ_SNDS];
296 int Obj_snd_enabled = TRUE;
297 int Obj_snd_last_update; // timer used to run object sound updates at fixed time intervals
298 int Obj_snd_level_inited=0;
301 #define FLYBY_MIN_DISTANCE 90
302 #define FLYBY_MIN_SPEED 50
303 #define FLYBY_MIN_RELATIVE_SPEED 100
304 #define FLYBY_MIN_NEXT_TIME 1000 // in ms
305 #define FLYBY_MIN_REPEAT_TIME 4000 // in ms
306 int Flyby_next_sound;
307 int Flyby_next_repeat;
308 object *Flyby_last_objp;
310 // return the world pos of the sound source on a ship.
311 void obj_snd_source_pos(vector *sound_pos, obj_snd *osp)
314 object *objp = &Objects[osp->objnum];
316 // get sound pos in world coords
317 vm_vec_unrotate(&offset_world, &osp->offset, &objp->orient);
318 vm_vec_add(sound_pos, &objp->pos, &offset_world);
321 // ---------------------------------------------------------------------------------------
324 // Debug console function for object linked persistant sounds
327 DCF(objsnd, "Persistant sound stuff" )
329 char buf1[16], buf2[64];
333 dc_get_arg(ARG_STRING|ARG_NONE);
335 if ( Dc_arg_type & ARG_NONE ) {
336 if ( Obj_snd_enabled == TRUE ) {
338 Obj_snd_enabled = FALSE;
341 Obj_snd_enabled = TRUE;
344 if ( !SDL_strcasecmp( Dc_arg, "list" )) {
345 for ( osp = GET_FIRST(&obj_snd_list); osp !=END_OF_LIST(&obj_snd_list); osp = GET_NEXT(osp) ) {
346 SDL_assert(osp != NULL);
347 if ( osp->instance == -1 ) {
349 //strcpy(buf1,"OFF");
351 SDL_strlcpy(buf1, "ON", SDL_arraysize(buf1));
354 if ( Objects[osp->objnum].type == OBJ_SHIP ) {
355 SDL_strlcpy(buf2, Ships[Objects[osp->objnum].instance].ship_name, SDL_arraysize(buf2));
357 else if ( Objects[osp->objnum].type == OBJ_DEBRIS ) {
358 SDL_strlcpy(buf2, "Debris", SDL_arraysize(buf2));
361 SDL_strlcpy(buf2, "Unknown", SDL_arraysize(buf2));
367 obj_snd_source_pos(&source_pos, osp);
368 distance = vm_vec_dist_quick( &source_pos, &View_position );
370 dc_printf("Object %d => name: %s vol: %.2f pan: %.2f dist: %.2f status: %s\n", osp->objnum, buf2, osp->vol, osp->pan, distance, buf1);
372 dc_printf("Number object-linked sounds playing: %d\n", Num_obj_sounds_playing);
377 dc_printf ("Usage: objsnd [list]\n");
378 dc_printf ("[list] -- displays status of all objects with linked sounds\n");
379 dc_printf ("with no parameters, object sounds are toggled on/off\n");
384 dc_printf( "Object sounds are: %s\n", (Obj_snd_enabled?"ON":"OFF") );
389 // ---------------------------------------------------------------------------------------
390 // Debug console function for toggling doppler effection on/off
392 DCF_BOOL( doppler, Doppler_enabled )
395 // ---------------------------------------------------------------------------------------
396 // obj_snd_get_slot()
398 // Get a free slot in the Objsnds[] array
400 // returns -1 if no slot is available
401 int obj_snd_get_slot()
405 for ( i = 0; i < MAX_OBJ_SNDS; i++ ) {
406 if ( !(Objsnds[i].flags & OS_USED) )
413 // ---------------------------------------------------------------------------------------
416 // Called once at level start to initialize the persistant object sound system
418 void obj_snd_level_init()
422 list_init(&obj_snd_list);
423 for ( i = 0; i < MAX_OBJ_SNDS; i++ ) {
424 Objsnds[i].flags = 0;
427 Num_obj_sounds_playing = 0;
428 Flyby_next_sound = 1;
429 Flyby_next_repeat = 1;
430 Flyby_last_objp = NULL;
431 Obj_snd_last_update=0;
433 Obj_snd_level_inited=1;
437 // ---------------------------------------------------------------------------------------
440 // Stop a persistant sound from playing.
442 // parameters: objp => pointer to object that sound is to be stopped for
445 void obj_snd_stop(object *objp, int index)
451 if(index >= MAX_OBJECT_SOUNDS){
456 // if index is -1, kill all sounds for this guy
458 // kill all sounds for this guy
459 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
460 if ( objp->objsnd_num[idx] == -1 ){
464 osp = &Objsnds[objp->objsnd_num[idx]];
466 if ( osp->instance != -1 ) {
467 snd_stop(osp->instance);
474 Num_obj_sounds_playing--;
475 SDL_assert(Num_obj_sounds_playing >= 0);
485 if ( objp->objsnd_num[index] == -1 ){
489 osp = &Objsnds[objp->objsnd_num[index]];
491 if ( osp->instance != -1 ) {
492 snd_stop(osp->instance);
499 Num_obj_sounds_playing--;
500 SDL_assert(Num_obj_sounds_playing >= 0);
511 // ---------------------------------------------------------------------------------------
512 // obj_snd_stop_all()
514 // Stop all object-linked persistant sounds from playing
517 void obj_snd_stop_all()
521 for ( A = GET_FIRST(&obj_used_list); A && A !=END_OF_LIST(&obj_used_list); A = GET_NEXT(A) ) {
526 // ---------------------------------------------------------------------------------------
527 // obj_snd_get_freq()
529 // Calculate the frequency of a sound to be played, based on the relative velocities
530 // of the source and observor
532 // returns: frequency of the sound
534 int obj_snd_get_freq(int source_freq, object* source, object* observor, vector *source_pos)
536 vector v_os, v_so; // os == observor to source, so == source to observor
539 vm_vec_normalized_dir(&v_os, source_pos, &observor->pos);
540 vm_vec_normalized_dir(&v_so, &observor->pos, source_pos);
542 vo = vm_vec_dotprod(&v_os, &observor->phys_info.vel);
543 vs = vm_vec_dotprod(&v_so, &source->phys_info.vel);
545 freq = source_freq * ( (SPEED_SOUND + vo) / (SPEED_SOUND - vs) );
550 // ---------------------------------------------------------------------------------------
551 // obj_snd_stop_lowest_vol()
553 // Stop a playing object sound, if it is quieter than sound at new_distance
555 // input: new_vol => volume of requested sound to play
557 // returns: TRUE => A sound was stopped
558 // FALSE => A sound was not stopped
560 int obj_snd_stop_lowest_vol(float new_vol)
564 obj_snd *lowest_vol_osp = NULL;
566 int obj_snd_index = -1;
569 lowest_vol = 1000.0f;
570 for ( osp = GET_FIRST(&obj_snd_list); osp !=END_OF_LIST(&obj_snd_list); osp = GET_NEXT(osp) ) {
571 SDL_assert(osp->objnum != -1);
573 if ( (osp->instance != -1) && (osp->vol < lowest_vol) ) {
574 lowest_vol = osp->vol;
575 lowest_vol_osp = osp;
579 if (lowest_vol_osp == NULL) {
584 objp = &Objects[lowest_vol_osp->objnum];
586 if ( (lowest_vol < new_vol) && (objp != NULL) ) {
587 // determine what index in this guy the sound is
588 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
589 if(objp->objsnd_num[idx] == (lowest_vol_osp - Objsnds)){
595 if((obj_snd_index == -1) || (obj_snd_index >= MAX_OBJECT_SOUNDS)){
598 obj_snd_stop(objp, obj_snd_index);
607 //int Debug_1 = 0, Debug_2 = 0;
609 // ---------------------------------------------------------------------------------------
610 // maybe_play_flyby_snd()
612 // Based on how close the object is to the player ship (and relative speed), maybe
613 // play a flyby sound. Only play flyby sound for OBJ_SHIP objects.
615 // NOTE: global data Flyby_last_objp, Flyby_next_sound, Flyby_next_repeat are
618 void maybe_play_flyby_snd(float closest_dist, object *closest_objp)
620 if ( closest_objp == NULL || closest_objp->type != OBJ_SHIP ) {
621 goto play_no_flyby_sound;
624 if ( closest_dist < FLYBY_MIN_DISTANCE ) {
625 float relative_speed;
627 vm_vec_sub(&diff, &Player_obj->phys_info.vel, &closest_objp->phys_info.vel);
630 relative_speed = vm_vec_mag_quick(&diff);
631 if ( relative_speed > FLYBY_MIN_RELATIVE_SPEED ) {
632 if ( timestamp_elapsed(Flyby_next_sound) ) {
634 if ( closest_objp == Flyby_last_objp ) {
635 if ( timestamp_elapsed(Flyby_next_repeat) ) {
636 Flyby_next_repeat = timestamp(FLYBY_MIN_REPEAT_TIME);
639 goto play_no_flyby_sound;
642 SDL_assert(closest_objp->type == OBJ_SHIP);
643 if(closest_objp->type != OBJ_SHIP){
647 // pick a random species-based sound
648 ship_info *sip = &Ship_info[Ships[closest_objp->instance].ship_info_index];
649 int species = SPECIES_TERRAN;
650 if((sip->species >= 0) && (sip->species < MAX_SPECIES_NAMES)){
651 species = sip->species;
653 int ship_size = 0; // fighter
654 if(sip->flags & SIF_BOMBER){
659 snd_play_3d(&Snds_flyby[species][ship_size], &closest_objp->pos, &View_position);
660 //snd_play_3d(&Snds_flyby[Debug_1][Debug_2], &closest_objp->pos, &View_position);
662 //float dist = vm_vec_dist(&closest_objp->pos, &View_position);
663 //nprintf(("AI", "Frame %i: Playing flyby sound, species = %i, size = %i, dist = %7.3f\n", Framecount, species, ship_size, dist));
664 // nprintf(("AI", "Frame %i: Playing flyby sound, species = %i, size = %i, dist = %7.3f\n", Framecount, Debug_1, Debug_2, dist));
665 //Debug_1 = (Debug_1+1)%3;
666 //Debug_2 = (Debug_2+1)%2;
668 joy_ff_fly_by(100 - (int) (100.0f * closest_dist / FLYBY_MIN_DISTANCE));
670 Flyby_next_sound = timestamp(FLYBY_MIN_NEXT_TIME);
671 Flyby_last_objp = closest_objp;
680 // ---------------------------------------------------------------------------------------
681 // obj_snd_do_frame()
683 // Called once per frame to process the persistant sound objects
685 void obj_snd_do_frame()
687 float closest_dist, distance, speed_vol_multiplier, percent_max;
689 object *objp, *closest_objp;
696 if ( Obj_snd_enabled == FALSE )
699 int now = timer_get_milliseconds();
700 if ( (now - Obj_snd_last_update) > 100 ) {
701 Obj_snd_last_update=now;
706 closest_dist = 1000000.0f;
709 for ( osp = GET_FIRST(&obj_snd_list); osp !=END_OF_LIST(&obj_snd_list); osp = GET_NEXT(osp) ) {
710 SDL_assert(osp != NULL);
711 objp = &Objects[osp->objnum];
712 if ( Player_obj == objp ) {
718 obj_snd_source_pos(&source_pos, osp);
719 distance = vm_vec_dist_quick( &source_pos, &View_position );
721 // how much extra distance do we add before attentuation?
723 if(osp->flags & OS_MAIN){
724 add_distance = objp->radius;
727 distance -= add_distance;
728 if ( distance < 0 ) {
732 // save closest distance (used for flyby sound) if this is a small ship
733 if ( (objp->type == OBJ_SHIP) && (distance < closest_dist) ) {
734 if ( Ship_info[Ships[objp->instance].ship_info_index].flags & SIF_SMALL_SHIP ) {
735 closest_dist = distance;
740 // If the object is a ship, we don't want to start the engine sound unless the ship is
741 // moving (unless flag SIF_BIG_SHIP is set)
742 speed_vol_multiplier = 1.0f;
743 if ( objp->type == OBJ_SHIP ) {
744 if ( !(Ship_info[Ships[objp->instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) ) {
745 if ( objp->phys_info.max_vel.xyz.z <= 0 ) {
749 percent_max = objp->phys_info.fspeed / objp->phys_info.max_vel.xyz.z;
751 if ( percent_max >= 0.5 )
752 speed_vol_multiplier = 1.0f;
754 speed_vol_multiplier = 0.5f + (percent_max); // linear interp: 0.5->1.0 when 0.0->0.5
759 go_ahead_flag = TRUE;
760 float max_vol,new_vol;
761 if ( osp->instance == -1 ) {
762 if ( distance < Snds[osp->id].max ) {
763 max_vol = Snds[osp->id].default_volume;
764 if ( distance <= Snds[osp->id].min ) {
768 new_vol = max_vol - (distance - Snds[osp->id].min) * max_vol / (Snds[osp->id].max - Snds[osp->id].min);
771 if ( new_vol < 0.1 ) {
775 switch( objp->type ) {
779 if ( Num_obj_sounds_playing >= MAX_OBJ_SOUNDS_PLAYING ) {
780 go_ahead_flag = obj_snd_stop_lowest_vol(new_vol);
789 if ( go_ahead_flag ) {
790 osp->instance = snd_play_3d(gs, &source_pos, &View_position, add_distance, &objp->phys_info.vel, 1, 1.0f, SND_PRIORITY_TRIPLE_INSTANCE);
791 if ( osp->instance != -1 ) {
792 Num_obj_sounds_playing++;
795 SDL_assert(Num_obj_sounds_playing <= MAX_OBJ_SOUNDS_PLAYING);
797 } // end if ( distance < Snds[osp->id].max )
798 } // if ( osp->instance == -1 )
800 if ( distance > Snds[osp->id].max ) {
801 int sound_index = -1;
804 // determine which sound index it is for this guy
805 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
806 if(objp->objsnd_num[idx] == (osp - Objsnds)){
812 SDL_assert(sound_index != -1);
813 obj_snd_stop(objp, sound_index); // currently playing sound has gone past maximum
817 if ( osp->instance == -1 )
821 if ( objp->type == OBJ_SHIP )
822 sp = &Ships[objp->instance];
824 // for 3D sounds, re-establish the maximum speed based on the
825 // speed_vol_multiplier
826 if ( sp == NULL || ( (sp != NULL) && (sp->flags & SF_ENGINES_ON) ) ) {
827 snd_set_volume( osp->instance, gs->default_volume*speed_vol_multiplier );
830 // engine sound is disabled
831 snd_set_volume( osp->instance, 0.0f );
835 vel = &objp->phys_info.vel;
837 // Don't play doppler effect for cruisers or captials
839 if ( ship_get_SIF(sp) & (SIF_BIG_SHIP | SIF_HUGE_SHIP) ) {
844 snd_update_source(osp->instance, gs->min, gs->max, &source_pos, vel);
845 snd_get_3d_vol_and_pan(gs, &source_pos, &osp->vol, &osp->pan, add_distance);
848 // see if we want to play a flyby sound
849 maybe_play_flyby_snd(closest_dist, closest_objp);
852 // ---------------------------------------------------------------------------------------
855 // Assign a persistant sound to an object.
857 // parameters: objnum => index of object that sound is being assigned to
858 // i => Index into Snds[] array
859 // fname => filename of sound to play ( so DS3D can load the sound )
861 // returns: -1 => sound could not be assigned (possible, since only MAX_OBJECT_SOUNDS persistant
862 // sound can be assigned per object).
863 // 0 => sound was successfully assigned
865 int obj_snd_assign(int objnum, int i, vector *pos, int main)
869 int idx, sound_index;
871 objp = &Objects[objnum];
873 if ( Obj_snd_enabled == FALSE )
876 // try and find a valid objsound index
878 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
879 if(objp->objsnd_num[idx] == -1){
886 if ( sound_index == -1 ){
890 objp->objsnd_num[sound_index] = (short)obj_snd_get_slot();
891 if ( objp->objsnd_num[sound_index] == -1 ) {
892 nprintf(("Sound", "SOUND ==> No free object-linked sounds left\n"));
895 snd = &Objsnds[objp->objsnd_num[sound_index]];
896 snd->flags = OS_USED;
899 snd->flags |= OS_MAIN;
909 snd->objnum = OBJ_INDEX(objp);
910 snd->next_update = 1;
912 // vm_vec_sub(&snd->offset, pos, &objp->pos);
914 // add objp to the obj_snd_list
915 list_append( &obj_snd_list, snd );
921 // ---------------------------------------------------------------------------------------
924 // Remove a persistant sound that has been assigned to an object.
926 // parameters: objnum => index of object that sound is being removed from.
929 void obj_snd_delete(int objnum, int sndnum)
935 SDL_assert(objnum >= 0 && objnum < MAX_OBJECTS);
936 objp = &Objects[objnum];
938 // delete all object sounds for this guy
939 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
941 if ( objp->objsnd_num[idx] == -1 ){
945 osp = &Objsnds[objp->objsnd_num[idx]];
947 // if we're just deleting a specific sound type
948 // and this is not one of them. skip it.
949 if((sndnum != -1) && (osp->id != sndnum)){
953 obj_snd_stop(objp, -1);
955 // remove objp from the obj_snd_list
956 list_remove( &obj_snd_list, osp );
960 objp->objsnd_num[idx] = -1;
964 // ---------------------------------------------------------------------------------------
965 // obj_snd_delete_all()
967 // Remove all persistant sounds
969 void obj_snd_delete_all()
974 osp = GET_FIRST(&obj_snd_list);
975 while( (osp != NULL) && (osp !=END_OF_LIST(&obj_snd_list)) ) {
976 temp = GET_NEXT(osp);
977 SDL_assert( osp->objnum != -1 );
979 obj_snd_delete( osp->objnum );
986 for(idx=0; idx<MAX_OBJ_SNDS; idx++){
987 if(Objsnds[idx].flags & OS_USED){
988 obj_snd_delete(Objsnds[idx].objnum);
993 // ---------------------------------------------------------------------------------------
996 // Called once at game close to de-initialize the persistant object sound system
998 void obj_snd_level_close()
1000 if ( !Obj_snd_level_inited ) {
1003 obj_snd_delete_all();
1004 Obj_snd_level_inited=0;
1007 // ---------------------------------------------------------------------------------------
1008 // obj_snd_is_playing()
1010 // Determines if a given object-linked sound is currently playing
1012 int obj_snd_is_playing(int index)
1019 SDL_assert( index >= 0 && index < MAX_OBJ_SNDS );
1021 osp = &Objsnds[index];
1022 if ( osp->instance == -1 )
1028 // ---------------------------------------------------------------------------------------
1029 // obj_snd_return_instance()
1031 // Returns the sound instance for a given object-linked sound
1033 int obj_snd_return_instance(int index)
1038 SDL_assert( index >= 0 && index < MAX_OBJ_SNDS );
1040 return Objsnds[index].instance;