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 !=END_OF_LIST(&obj_used_list); A = GET_NEXT(A) ) {
528 // ---------------------------------------------------------------------------------------
529 // obj_snd_get_freq()
531 // Calculate the frequency of a sound to be played, based on the relative velocities
532 // of the source and observor
534 // returns: frequency of the sound
536 int obj_snd_get_freq(int source_freq, object* source, object* observor, vector *source_pos)
538 vector v_os, v_so; // os == observor to source, so == source to observor
541 vm_vec_normalized_dir(&v_os, source_pos, &observor->pos);
542 vm_vec_normalized_dir(&v_so, &observor->pos, source_pos);
544 vo = vm_vec_dotprod(&v_os, &observor->phys_info.vel);
545 vs = vm_vec_dotprod(&v_so, &source->phys_info.vel);
547 freq = source_freq * ( (SPEED_SOUND + vo) / (SPEED_SOUND - vs) );
552 // ---------------------------------------------------------------------------------------
553 // obj_snd_stop_lowest_vol()
555 // Stop a playing object sound, if it is quieter than sound at new_distance
557 // input: new_vol => volume of requested sound to play
559 // returns: TRUE => A sound was stopped
560 // FALSE => A sound was not stopped
562 int obj_snd_stop_lowest_vol(float new_vol)
566 obj_snd *lowest_vol_osp = NULL;
568 int obj_snd_index = -1;
571 lowest_vol = 1000.0f;
572 for ( osp = GET_FIRST(&obj_snd_list); osp !=END_OF_LIST(&obj_snd_list); osp = GET_NEXT(osp) ) {
573 SDL_assert(osp->objnum != -1);
574 objp = &Objects[osp->objnum];
576 if ( (osp->instance != -1) && (osp->vol < lowest_vol) ) {
577 lowest_vol = osp->vol;
578 lowest_vol_osp = osp;
582 SDL_assert(lowest_vol_osp != NULL);
583 objp = &Objects[lowest_vol_osp->objnum];
585 if ( (lowest_vol < new_vol) && (objp != NULL) ) {
586 // determine what index in this guy the sound is
587 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
588 if(objp->objsnd_num[idx] == (lowest_vol_osp - Objsnds)){
594 if((obj_snd_index == -1) || (obj_snd_index >= MAX_OBJECT_SOUNDS)){
597 obj_snd_stop(objp, obj_snd_index);
606 //int Debug_1 = 0, Debug_2 = 0;
608 // ---------------------------------------------------------------------------------------
609 // maybe_play_flyby_snd()
611 // Based on how close the object is to the player ship (and relative speed), maybe
612 // play a flyby sound. Only play flyby sound for OBJ_SHIP objects.
614 // NOTE: global data Flyby_last_objp, Flyby_next_sound, Flyby_next_repeat are
617 void maybe_play_flyby_snd(float closest_dist, object *closest_objp)
619 if ( closest_objp == NULL || closest_objp->type != OBJ_SHIP ) {
620 goto play_no_flyby_sound;
623 if ( closest_dist < FLYBY_MIN_DISTANCE ) {
624 float relative_speed;
626 vm_vec_sub(&diff, &Player_obj->phys_info.vel, &closest_objp->phys_info.vel);
629 relative_speed = vm_vec_mag_quick(&diff);
630 if ( relative_speed > FLYBY_MIN_RELATIVE_SPEED ) {
631 if ( timestamp_elapsed(Flyby_next_sound) ) {
633 if ( closest_objp == Flyby_last_objp ) {
634 if ( timestamp_elapsed(Flyby_next_repeat) ) {
635 Flyby_next_repeat = timestamp(FLYBY_MIN_REPEAT_TIME);
638 goto play_no_flyby_sound;
641 SDL_assert(closest_objp->type == OBJ_SHIP);
642 if(closest_objp->type != OBJ_SHIP){
646 // pick a random species-based sound
647 ship_info *sip = &Ship_info[Ships[closest_objp->instance].ship_info_index];
648 int species = SPECIES_TERRAN;
649 if((sip->species >= 0) && (sip->species < MAX_SPECIES_NAMES)){
650 species = sip->species;
652 int ship_size = 0; // fighter
653 if(sip->flags & SIF_BOMBER){
658 snd_play_3d(&Snds_flyby[species][ship_size], &closest_objp->pos, &View_position);
659 //snd_play_3d(&Snds_flyby[Debug_1][Debug_2], &closest_objp->pos, &View_position);
661 //float dist = vm_vec_dist(&closest_objp->pos, &View_position);
662 //nprintf(("AI", "Frame %i: Playing flyby sound, species = %i, size = %i, dist = %7.3f\n", Framecount, species, ship_size, dist));
663 // nprintf(("AI", "Frame %i: Playing flyby sound, species = %i, size = %i, dist = %7.3f\n", Framecount, Debug_1, Debug_2, dist));
664 //Debug_1 = (Debug_1+1)%3;
665 //Debug_2 = (Debug_2+1)%2;
667 joy_ff_fly_by(100 - (int) (100.0f * closest_dist / FLYBY_MIN_DISTANCE));
669 Flyby_next_sound = timestamp(FLYBY_MIN_NEXT_TIME);
670 Flyby_last_objp = closest_objp;
679 // ---------------------------------------------------------------------------------------
680 // obj_snd_do_frame()
682 // Called once per frame to process the persistant sound objects
684 void obj_snd_do_frame()
686 float closest_dist, distance, speed_vol_multiplier, percent_max;
688 object *objp, *closest_objp;
695 if ( Obj_snd_enabled == FALSE )
698 int now = timer_get_milliseconds();
699 if ( (now - Obj_snd_last_update) > 100 ) {
700 Obj_snd_last_update=now;
705 closest_dist = 1000000.0f;
708 for ( osp = GET_FIRST(&obj_snd_list); osp !=END_OF_LIST(&obj_snd_list); osp = GET_NEXT(osp) ) {
709 SDL_assert(osp != NULL);
710 objp = &Objects[osp->objnum];
711 if ( Player_obj == objp ) {
717 obj_snd_source_pos(&source_pos, osp);
718 distance = vm_vec_dist_quick( &source_pos, &View_position );
720 // how much extra distance do we add before attentuation?
722 if(osp->flags & OS_MAIN){
723 add_distance = objp->radius;
726 distance -= add_distance;
727 if ( distance < 0 ) {
731 // save closest distance (used for flyby sound) if this is a small ship
732 if ( (objp->type == OBJ_SHIP) && (distance < closest_dist) ) {
733 if ( Ship_info[Ships[objp->instance].ship_info_index].flags & SIF_SMALL_SHIP ) {
734 closest_dist = distance;
739 // If the object is a ship, we don't want to start the engine sound unless the ship is
740 // moving (unless flag SIF_BIG_SHIP is set)
741 speed_vol_multiplier = 1.0f;
742 if ( objp->type == OBJ_SHIP ) {
743 if ( !(Ship_info[Ships[objp->instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) ) {
744 if ( objp->phys_info.max_vel.xyz.z <= 0 ) {
748 percent_max = objp->phys_info.fspeed / objp->phys_info.max_vel.xyz.z;
750 if ( percent_max >= 0.5 )
751 speed_vol_multiplier = 1.0f;
753 speed_vol_multiplier = 0.5f + (percent_max); // linear interp: 0.5->1.0 when 0.0->0.5
758 go_ahead_flag = TRUE;
759 float max_vol,new_vol;
760 if ( osp->instance == -1 ) {
761 if ( distance < Snds[osp->id].max ) {
762 max_vol = Snds[osp->id].default_volume;
763 if ( distance <= Snds[osp->id].min ) {
767 new_vol = max_vol - (distance - Snds[osp->id].min) * max_vol / (Snds[osp->id].max - Snds[osp->id].min);
770 if ( new_vol < 0.1 ) {
774 switch( objp->type ) {
778 if ( Num_obj_sounds_playing >= MAX_OBJ_SOUNDS_PLAYING ) {
779 go_ahead_flag = obj_snd_stop_lowest_vol(new_vol);
788 if ( go_ahead_flag ) {
789 osp->instance = snd_play_3d(gs, &source_pos, &View_position, add_distance, &objp->phys_info.vel, 1, 1.0f, SND_PRIORITY_TRIPLE_INSTANCE);
790 if ( osp->instance != -1 ) {
791 Num_obj_sounds_playing++;
794 SDL_assert(Num_obj_sounds_playing <= MAX_OBJ_SOUNDS_PLAYING);
796 } // end if ( distance < Snds[osp->id].max )
797 } // if ( osp->instance == -1 )
799 if ( distance > Snds[osp->id].max ) {
800 int sound_index = -1;
803 // determine which sound index it is for this guy
804 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
805 if(objp->objsnd_num[idx] == (osp - Objsnds)){
811 SDL_assert(sound_index != -1);
812 obj_snd_stop(objp, sound_index); // currently playing sound has gone past maximum
816 if ( osp->instance == -1 )
820 if ( objp->type == OBJ_SHIP )
821 sp = &Ships[objp->instance];
823 // for 3D sounds, re-establish the maximum speed based on the
824 // speed_vol_multiplier
825 if ( sp == NULL || ( (sp != NULL) && (sp->flags & SF_ENGINES_ON) ) ) {
826 snd_set_volume( osp->instance, gs->default_volume*speed_vol_multiplier );
829 // engine sound is disabled
830 snd_set_volume( osp->instance, 0.0f );
834 vel = &objp->phys_info.vel;
836 // Don't play doppler effect for cruisers or captials
838 if ( ship_get_SIF(sp) & (SIF_BIG_SHIP | SIF_HUGE_SHIP) ) {
843 snd_update_source(osp->instance, gs->min, gs->max, &source_pos, vel);
844 snd_get_3d_vol_and_pan(gs, &source_pos, &osp->vol, &osp->pan, add_distance);
847 // see if we want to play a flyby sound
848 maybe_play_flyby_snd(closest_dist, closest_objp);
851 // ---------------------------------------------------------------------------------------
854 // Assign a persistant sound to an object.
856 // parameters: objnum => index of object that sound is being assigned to
857 // i => Index into Snds[] array
858 // fname => filename of sound to play ( so DS3D can load the sound )
860 // returns: -1 => sound could not be assigned (possible, since only MAX_OBJECT_SOUNDS persistant
861 // sound can be assigned per object).
862 // 0 => sound was successfully assigned
864 int obj_snd_assign(int objnum, int i, vector *pos, int main)
868 int idx, sound_index;
870 objp = &Objects[objnum];
872 if ( Obj_snd_enabled == FALSE )
875 // try and find a valid objsound index
877 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
878 if(objp->objsnd_num[idx] == -1){
885 if ( sound_index == -1 ){
889 objp->objsnd_num[sound_index] = (short)obj_snd_get_slot();
890 if ( objp->objsnd_num[sound_index] == -1 ) {
891 nprintf(("Sound", "SOUND ==> No free object-linked sounds left\n"));
894 snd = &Objsnds[objp->objsnd_num[sound_index]];
895 snd->flags = OS_USED;
898 snd->flags |= OS_MAIN;
908 snd->objnum = OBJ_INDEX(objp);
909 snd->next_update = 1;
911 // vm_vec_sub(&snd->offset, pos, &objp->pos);
913 // add objp to the obj_snd_list
914 list_append( &obj_snd_list, snd );
920 // ---------------------------------------------------------------------------------------
923 // Remove a persistant sound that has been assigned to an object.
925 // parameters: objnum => index of object that sound is being removed from.
928 void obj_snd_delete(int objnum, int sndnum)
934 SDL_assert(objnum >= 0 && objnum < MAX_OBJECTS);
935 objp = &Objects[objnum];
937 // delete all object sounds for this guy
938 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
940 if ( objp->objsnd_num[idx] == -1 ){
944 osp = &Objsnds[objp->objsnd_num[idx]];
946 // if we're just deleting a specific sound type
947 // and this is not one of them. skip it.
948 if((sndnum != -1) && (osp->id != sndnum)){
952 obj_snd_stop(objp, -1);
954 // remove objp from the obj_snd_list
955 list_remove( &obj_snd_list, osp );
959 objp->objsnd_num[idx] = -1;
963 // ---------------------------------------------------------------------------------------
964 // obj_snd_delete_all()
966 // Remove all persistant sounds
968 void obj_snd_delete_all()
973 osp = GET_FIRST(&obj_snd_list);
974 while( (osp != NULL) && (osp !=END_OF_LIST(&obj_snd_list)) ) {
975 temp = GET_NEXT(osp);
976 SDL_assert( osp->objnum != -1 );
978 obj_snd_delete( osp->objnum );
985 for(idx=0; idx<MAX_OBJ_SNDS; idx++){
986 if(Objsnds[idx].flags & OS_USED){
987 obj_snd_delete(Objsnds[idx].objnum);
992 // ---------------------------------------------------------------------------------------
995 // Called once at game close to de-initialize the persistant object sound system
997 void obj_snd_level_close()
999 if ( !Obj_snd_level_inited ) {
1002 obj_snd_delete_all();
1003 Obj_snd_level_inited=0;
1006 // ---------------------------------------------------------------------------------------
1007 // obj_snd_is_playing()
1009 // Determines if a given object-linked sound is currently playing
1011 int obj_snd_is_playing(int index)
1018 SDL_assert( index >= 0 && index < MAX_OBJ_SNDS );
1020 osp = &Objsnds[index];
1021 if ( osp->instance == -1 )
1027 // ---------------------------------------------------------------------------------------
1028 // obj_snd_return_instance()
1030 // Returns the sound instance for a given object-linked sound
1032 int obj_snd_return_instance(int index)
1037 SDL_assert( index >= 0 && index < MAX_OBJ_SNDS );
1039 return Objsnds[index].instance;