FS2_Open
Open source remastering of the Freespace 2 engine
objectsnd.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
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 the
6  * source.
7  *
8 */
9 
10 
11 
12 
13 #include "cmdline/cmdline.h"
14 #include "debugconsole/console.h"
15 #include "gamesnd/gamesnd.h"
16 #include "globalincs/linklist.h"
17 #include "io/joy_ff.h"
18 #include "io/timer.h"
19 #include "object/object.h"
20 #include "object/objectsnd.h"
21 #include "render/3d.h"
22 #include "ship/ship.h"
23 #include "sound/ds.h"
24 #include "sound/ds3d.h"
26 
27 
28 // // --mharris port hack--
29 // int ds_using_ds3d();
30 // int ds_get_channel(int);
31 // int ds3d_update_buffer(int, float, float, vec3d *, vec3d *);
32 // --end hack--
33 
34 
35 // Persistent sounds for objects (pointer to obj_snd is in object struct)
36 typedef struct _obj_snd {
38  int objnum; // object index of object that contains this sound
39  int id; // Index into Snds[] array
40  int instance; // handle of currently playing sound (a ds3d handle if USES_DS3D flag set)
41  int next_update; // timestamp that marks next allowed vol/pan change
42  float vol; // volume of sound (range: 0.0 -> 1.0)
43  float pan; // pan of sound (range: -1.0 -> 1.0)
44  int freq; // valid range: 100 -> 100000 Hz
45  int flags;
46  vec3d offset; // offset from the center of the object where the sound lives
47  ship_subsys *ss; //Associated subsystem
48 } obj_snd;
49 
50 #define VOL_PAN_UPDATE 50 // time in ms to update a persistent sound vol/pan
51 #define MIN_PERSISTANT_VOL 0.10f
52 #define MIN_FORWARD_SPEED 5
53 #define SPEED_SOUND 600.0f // speed of sound in FreeSpace
54 
55 static int MAX_OBJ_SOUNDS_PLAYING = -1; // initialized in obj_snd_level_init()
56 static int Num_obj_sounds_playing;
57 
58 #define OBJSND_CHANGE_FREQUENCY_THRESHOLD 10
59 
60 static obj_snd obj_snd_list; // head of linked list of object sound structs
61 static int Doppler_enabled = TRUE;
62 
63 #define MAX_OBJ_SNDS 256
65 
67 int Obj_snd_last_update; // timer used to run object sound updates at fixed time intervals
69 
70 // ship flyby data
71 #define FLYBY_MIN_DISTANCE 90
72 #define FLYBY_MIN_SPEED 50
73 #define FLYBY_MIN_RELATIVE_SPEED 100
74 #define FLYBY_MIN_NEXT_TIME 1000 // in ms
75 #define FLYBY_MIN_REPEAT_TIME 4000 // in ms
79 
80 // return the world pos of the sound source on a ship.
81 void obj_snd_source_pos(vec3d *sound_pos, obj_snd *osp)
82 {
83  vec3d offset_world;
84  object *objp = &Objects[osp->objnum];
85 
86  // get sound pos in world coords
87  vm_vec_unrotate(&offset_world, &osp->offset, &objp->orient);
88  vm_vec_add(sound_pos, &objp->pos, &offset_world);
89 }
90 
91 // ---------------------------------------------------------------------------------------
92 // dcf_objsnd()
93 //
94 // Debug console function for object linked persistent sounds
95 //
96 //XSTR:OFF
97 DCF(objsnd, "Persistent sound stuff" )
98 {
99  char buf1[4];
100  char buf2[MAX_NAME_LEN];
101  obj_snd *osp;
102  SCP_string arg;
103 
104  if (dc_optional_string_either("help", "--help")) {
105  dc_printf ("Usage: objsnd [-list]\n");
106  dc_printf ("[-list] -- displays status of all objects with linked sounds\n");
107  dc_printf ("with no parameters, object sounds are toggled on/off\n");
108  return;
109  }
110 
111  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
112  dc_printf( "Object sounds are: %s\n", (Obj_snd_enabled?"ON":"OFF") );
113  }
114 
115  if (dc_optional_string("-list")) {
116  for ( osp = GET_FIRST(&obj_snd_list); osp !=END_OF_LIST(&obj_snd_list); osp = GET_NEXT(osp) ) {
117  vec3d source_pos;
118  float distance;
119 
120  Assert(osp != NULL);
121  if ( osp->instance == -1 ) {
122  continue;
123  //sprintf(buf1,"OFF");
124  } else {
125  sprintf(buf1,"ON");
126  }
127 
128  if ( Objects[osp->objnum].type == OBJ_SHIP ) {
130  }
131  else if ( Objects[osp->objnum].type == OBJ_DEBRIS ) {
132  sprintf(buf2, "Debris");
133  }
134  else {
135  sprintf(buf2, "Unknown");
136  }
137 
138  obj_snd_source_pos(&source_pos, osp);
139  distance = vm_vec_dist_quick( &source_pos, &View_position );
140 
141  dc_printf("Object %d => name: %s vol: %.2f pan: %.2f dist: %.2f status: %s\n", osp->objnum, buf2, osp->vol, osp->pan, distance, buf1);
142  } // end for
143 
144  dc_printf("Number object-linked sounds playing: %d\n", Num_obj_sounds_playing);
145  return;
146  }
147 
148  if (!dc_maybe_stuff_string_white(arg)) {
149  // No arguments, toggle snd on/off
150  if ( Obj_snd_enabled == TRUE ) {
153  } else {
155  }
156  } else {
157  dc_printf("Unknown argument '%s'\n", arg.c_str());
158  }
159 }
160 //XSTR:ON
161 
162 // ---------------------------------------------------------------------------------------
163 // Debug console function for toggling doppler effection on/off
164 //
165 DCF_BOOL( doppler, Doppler_enabled )
166 
167 
168 // ---------------------------------------------------------------------------------------
169 // obj_snd_get_slot()
170 //
171 // Get a free slot in the Objsnds[] array
172 //
173 // returns -1 if no slot is available
175 {
176  int i;
177 
178  for ( i = 0; i < MAX_OBJ_SNDS; i++ ) {
179  if ( !(Objsnds[i].flags & OS_USED) )
180  return i;
181  }
182 
183  return -1;
184 }
185 
186 // ---------------------------------------------------------------------------------------
187 // obj_snd_init()
188 //
189 // Called once at level start to initialize the persistent object sound system
190 //
192 {
193  int i;
194 
195  if (MAX_OBJ_SOUNDS_PLAYING < 0)
196  {
197  MAX_OBJ_SOUNDS_PLAYING = Cmdline_no_enhanced_sound ? 5 : 12;
198  }
199 
200  list_init(&obj_snd_list);
201  for ( i = 0; i < MAX_OBJ_SNDS; i++ ) {
202  Objsnds[i].flags = 0;
203  }
204 
205  Num_obj_sounds_playing = 0;
206  Flyby_next_sound = 1;
207  Flyby_next_repeat = 1;
208  Flyby_last_objp = NULL;
210 
211  if ( !snd_is_inited() ) {
213  return;
214  }
215 
217 }
218 
219 
220 // ---------------------------------------------------------------------------------------
221 // obj_snd_stop()
222 //
223 // Stop a persistent sound from playing.
224 //
225 // parameters: objp => pointer to object that sound is to be stopped for
226 //
227 //
228 void obj_snd_stop(object *objp, int index)
229 {
230  obj_snd *osp;
231 
232  // sanity
233  if(index >= (int) objp->objsnd_num.size()){
234  Error(LOCATION, "Object sound index %d is bigger than the actual size %d!", index, (int) objp->objsnd_num.size());
235  return;
236  }
237 
238  // if index is -1, kill all sounds for this guy
239  if(index == -1){
240  // kill all sounds for this guy
241  for(SCP_vector<int>::iterator iter = objp->objsnd_num.begin(); iter != objp->objsnd_num.end(); ++iter){
242  if ( *iter == -1 ){
243  continue;
244  }
245 
246  osp = &Objsnds[*iter];
247 
248  if ( osp->instance != -1 ) {
249  snd_stop(osp->instance);
250  osp->instance = -1;
251  switch(objp->type) {
252  case OBJ_SHIP:
253  case OBJ_GHOST:
254  case OBJ_DEBRIS:
255  case OBJ_ASTEROID:
256  Num_obj_sounds_playing--;
257  Assert(Num_obj_sounds_playing >= 0);
258  break;
259 
260  default:
261  Int3(); // get Alan
262  break;
263  }
264  }
265  }
266  } else {
267  if ( objp->objsnd_num[index] == -1 ){
268  return;
269  }
270 
271  osp = &Objsnds[objp->objsnd_num[index]];
272 
273  if ( osp->instance != -1 ) {
274  snd_stop(osp->instance);
275  osp->instance = -1;
276  switch(objp->type) {
277  case OBJ_SHIP:
278  case OBJ_GHOST:
279  case OBJ_DEBRIS:
280  case OBJ_ASTEROID:
281  Num_obj_sounds_playing--;
282  Assert(Num_obj_sounds_playing >= 0);
283  break;
284 
285  default:
286  Int3(); // get Alan
287  break;
288  }
289  }
290  }
291 }
292 
293 // ---------------------------------------------------------------------------------------
294 // obj_snd_stop_all()
295 //
296 // Stop all object-linked persistent sounds from playing
297 //
298 //
300 {
301  object* A;
302 
303  for ( A = GET_FIRST(&obj_used_list); A !=END_OF_LIST(&obj_used_list); A = GET_NEXT(A) ) {
304  obj_snd_stop(A, -1);
305  }
306 }
307 
308 // ---------------------------------------------------------------------------------------
309 // obj_snd_get_freq()
310 //
311 // Calculate the frequency of a sound to be played, based on the relative velocities
312 // of the source and observor
313 //
314 // returns: frequency of the sound
315 //
316 int obj_snd_get_freq(int source_freq, object* source, object* observor, vec3d *source_pos)
317 {
318  vec3d v_os, v_so; // os == observor to source, so == source to observor
319  float vo, vs, freq;
320 
321  vm_vec_normalized_dir(&v_os, source_pos, &observor->pos);
322  vm_vec_normalized_dir(&v_so, &observor->pos, source_pos);
323 
324  vo = vm_vec_dot(&v_os, &observor->phys_info.vel);
325  vs = vm_vec_dot(&v_so, &source->phys_info.vel);
326 
327  freq = source_freq * ( (SPEED_SOUND + vo) / (SPEED_SOUND - vs) );
328  return fl2i(freq);
329 }
330 
331 
340 int obj_snd_stop_lowest_vol(float new_vol)
341 {
342  obj_snd *osp;
343  object *objp = NULL;
344  obj_snd *lowest_vol_osp = NULL;
345  float lowest_vol;
346  int obj_snd_index = -1;
347 
348  lowest_vol = 1000.0f;
349  for ( osp = GET_FIRST(&obj_snd_list); osp !=END_OF_LIST(&obj_snd_list); osp = GET_NEXT(osp) ) {
350  Assert(osp->objnum != -1);
351  objp = &Objects[osp->objnum];
352 
353  if ( (osp->instance != -1) && (osp->vol < lowest_vol) ) {
354  lowest_vol = osp->vol;
355  lowest_vol_osp = osp;
356  }
357  }
358 
359  if (lowest_vol_osp != NULL)
360  objp = &Objects[lowest_vol_osp->objnum];
361 
362  if ( (lowest_vol < new_vol) && (objp != NULL) ) {
363  int idx = 0;
364  // determine what index in this guy the sound is
365  for(SCP_vector<int>::iterator iter = objp->objsnd_num.begin(); iter != objp->objsnd_num.end(); ++iter, ++idx){
366  if(*iter == (lowest_vol_osp - Objsnds)){
367  obj_snd_index = idx;
368  break;
369  }
370  }
371 
372  if((obj_snd_index == -1) || (obj_snd_index >= (int) objp->objsnd_num.size())){
373  Int3(); // get dave
374  } else {
375  obj_snd_stop(objp, obj_snd_index);
376  }
377 
378  return TRUE;
379  }
380 
381  return FALSE;
382 }
383 
384 //int Debug_1 = 0, Debug_2 = 0;
385 
386 // ---------------------------------------------------------------------------------------
387 // maybe_play_flyby_snd()
388 //
389 // Based on how close the object is to the camera (and relative speed), maybe
390 // play a flyby sound. Only play flyby sound for OBJ_SHIP objects.
391 //
392 // NOTE: global data Flyby_last_objp, Flyby_next_sound, Flyby_next_repeat are
393 // used.
394 //
395 void maybe_play_flyby_snd(float closest_dist, object *closest_objp, object *listener_objp)
396 {
397  if ( closest_objp == NULL || closest_objp->type != OBJ_SHIP || closest_objp == listener_objp ) {
398  return;
399  }
400 
401  if ( closest_dist < FLYBY_MIN_DISTANCE ) {
402  float relative_speed;
403  vec3d diff;
404  vm_vec_sub(&diff, &listener_objp->phys_info.vel, &closest_objp->phys_info.vel);
405 
406 
407  relative_speed = vm_vec_mag_quick(&diff);
408  if ( relative_speed > FLYBY_MIN_RELATIVE_SPEED ) {
410 
411  if ( closest_objp == Flyby_last_objp ) {
414  }
415  else
416  return;
417  }
418 
419  Assert(closest_objp->type == OBJ_SHIP);
420  if(closest_objp->type != OBJ_SHIP){
421  return;
422  }
423 
424  // pick a random species-based sound
425 
426  ship_info *sip = &Ship_info[Ships[closest_objp->instance].ship_info_index];
427  game_snd *snd;
428 
429  if (sip->flags & SIF_BOMBER)
430  snd = &Species_info[sip->species].snd_flyby_bomber;
431  else
432  snd = &Species_info[sip->species].snd_flyby_fighter;
433 
434  // play da sound
435  snd_play_3d(snd, &closest_objp->pos, &View_position);
436 
437  //float dist = vm_vec_dist(&closest_objp->pos, &View_position);
438  //nprintf(("AI", "Frame %i: Playing flyby sound, species = %i, size = %i, dist = %7.3f\n", Framecount, species, ship_size, dist));
439 // nprintf(("AI", "Frame %i: Playing flyby sound, species = %i, size = %i, dist = %7.3f\n", Framecount, Debug_1, Debug_2, dist));
440 //Debug_1 = (Debug_1+1)%3;
441 //Debug_2 = (Debug_2+1)%2;
442 
443  joy_ff_fly_by(100 - (int) (100.0f * closest_dist / FLYBY_MIN_DISTANCE));
444 
446  Flyby_last_objp = closest_objp;
447  }
448  }
449  }
450 }
451 
452 // ---------------------------------------------------------------------------------------
453 // obj_snd_do_frame()
454 //
455 // Called once per frame to process the persistent sound objects
456 //
458 {
459  float closest_dist, distance, speed_vol_multiplier, rot_vol_mult, percent_max, alive_vol_mult;
460  obj_snd *osp;
461  object *objp, *closest_objp;
462  game_snd *gs;
463  ship *sp;
464  int channel, go_ahead_flag;
465  vec3d source_pos;
466  float add_distance;
467 
468  if ( Obj_snd_enabled == FALSE )
469  return;
470 
471  int now = timer_get_milliseconds();
472  if ( (now - Obj_snd_last_update) > 100 ) {
474  } else {
475  return;
476  }
477 
478  closest_dist = 1000000.0f;
479  closest_objp = NULL;
480 
481  object *observer_obj = NULL;
482  if (Viewer_obj != NULL) {
483  observer_obj = Viewer_obj;
484  } else if (Viewer_mode & VM_OTHER_SHIP && Player_ai->target_objnum != -1) {
485  // apparently Viewer_obj is still null when Viewing Other Ship externally
486  observer_obj = &Objects[Player_ai->target_objnum];
487  } else {
488  observer_obj = Player_obj;
489  }
490 
491  for ( osp = GET_FIRST(&obj_snd_list); osp !=END_OF_LIST(&obj_snd_list); osp = GET_NEXT(osp) ) {
492  Assert(osp != NULL);
493  objp = &Objects[osp->objnum];
494  if ( Player_obj == objp && observer_obj == Player_obj ) {
495  // we don't play the engine sound if the view is from the player
496  continue;
497  }
498 
499  gs = &Snds[osp->id];
500 
501  obj_snd_source_pos(&source_pos, osp);
502  distance = vm_vec_dist_quick( &source_pos, &View_position );
503 
504  // how much extra distance do we add before attentuation?
505  add_distance = 0.0f;
506  if(osp->flags & OS_MAIN){
507  add_distance = objp->radius;
508  }
509 
510  distance -= add_distance;
511  if ( distance < 0.0f ) {
512  distance = 0.0f;
513  }
514 
515  // save closest distance (used for flyby sound) if this is a small ship (and not the observer)
516  if ( (objp->type == OBJ_SHIP) && (distance < closest_dist) && (objp != observer_obj) ) {
517  if ( Ship_info[Ships[objp->instance].ship_info_index].flags & SIF_SMALL_SHIP ) {
518  closest_dist = distance;
519  closest_objp = objp;
520  }
521  }
522 
523  // If the object is a ship, we don't want to start the engine sound unless the ship is
524  // moving (unless flag SIF_BIG_SHIP is set)
525  speed_vol_multiplier = 1.0f;
526  rot_vol_mult = 1.0f;
527  alive_vol_mult = 1.0f;
528  if ( objp->type == OBJ_SHIP ) {
530  if ( !(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) ) {
531  if ( objp->phys_info.max_vel.xyz.z <= 0.0f ) {
532  percent_max = 0.0f;
533  }
534  else
535  percent_max = objp->phys_info.fspeed / objp->phys_info.max_vel.xyz.z;
536 
537  if ( sip->min_engine_vol == -1.0f) {
538  // Retail behavior: volume ramps from 0.5 (when stationary) to 1.0 (when at half speed)
539  if ( percent_max >= 0.5f ) {
540  speed_vol_multiplier = 1.0f;
541  } else {
542  speed_vol_multiplier = 0.5f + (percent_max); // linear interp: 0.5->1.0 when 0.0->0.5
543  }
544  } else {
545  // Volume ramps from min_engine_vol (when stationary) to 1.0 (when at full speed)
546  speed_vol_multiplier = sip->min_engine_vol + ((1.0f - sip->min_engine_vol) * percent_max);
547  }
548  }
549  if (osp->ss != NULL)
550  {
551  if (osp->flags & OS_TURRET_BASE_ROTATION)
552  {
553  if (osp->ss->base_rotation_rate_pct > 0.0f)
554  rot_vol_mult = ((0.25f + (0.75f * osp->ss->base_rotation_rate_pct)) * osp->ss->system_info->turret_base_rotation_snd_mult);
555  else
556  rot_vol_mult = 0.0f;
557  }
558  if (osp->flags & OS_TURRET_GUN_ROTATION)
559  {
560  if (osp->ss->gun_rotation_rate_pct > 0.0f)
561  rot_vol_mult = ((0.25f + (0.75f * osp->ss->gun_rotation_rate_pct)) * osp->ss->system_info->turret_gun_rotation_snd_mult);
562  else
563  rot_vol_mult = 0.0f;
564  }
565  if (osp->flags & OS_SUBSYS_ROTATION )
566  {
567  if (osp->ss->flags & SSF_ROTATES) {
568  rot_vol_mult = 1.0f;
569  } else {
570  rot_vol_mult = 0.0f;
571  }
572  }
573  if (osp->flags & OS_SUBSYS_ALIVE)
574  {
575  if (osp->ss->current_hits > 0.0f) {
576  alive_vol_mult = 1.0f;
577  } else {
578  alive_vol_mult = 0.0f;
579  }
580  }
581  if (osp->flags & OS_SUBSYS_DEAD)
582  {
583  if (osp->ss->current_hits <= 0.0f) {
584  alive_vol_mult = 1.0f;
585  } else {
586  alive_vol_mult = 0.0f;
587  }
588  }
589  if (osp->flags & OS_SUBSYS_DAMAGED)
590  {
591  alive_vol_mult = osp->ss->current_hits / osp->ss->max_hits;
592  CLAMP(alive_vol_mult, 0.0f, 1.0f);
593  }
594 
595  }
596  }
597 
598  go_ahead_flag = TRUE;
599  float max_vol,new_vol;
600  if ( osp->instance == -1 ) {
601  if ( distance < Snds[osp->id].max ) {
602  max_vol = Snds[osp->id].default_volume;
603  if ( distance <= Snds[osp->id].min ) {
604  new_vol = max_vol;
605  }
606  else {
607  new_vol = max_vol - (distance - Snds[osp->id].min) * max_vol / (Snds[osp->id].max - Snds[osp->id].min);
608  }
609 
610  if ( new_vol < 0.1f ) {
611  continue;
612  }
613 
614  switch( objp->type ) {
615  case OBJ_SHIP:
616  case OBJ_DEBRIS:
617  case OBJ_ASTEROID:
618  if ( Num_obj_sounds_playing >= MAX_OBJ_SOUNDS_PLAYING ) {
619  go_ahead_flag = obj_snd_stop_lowest_vol(new_vol);
620  }
621  break;
622 
623  default:
624  Int3(); // get Alan
625  break;
626  } // end switch
627 
628  if ( go_ahead_flag ) {
629  osp->instance = snd_play_3d(gs, &source_pos, &View_position, add_distance, &objp->phys_info.vel, 1, 1.0f, SND_PRIORITY_TRIPLE_INSTANCE, NULL, 1.0f, 0, true);
630  if ( osp->instance != -1 ) {
631  Num_obj_sounds_playing++;
632  }
633  }
634  Assert(Num_obj_sounds_playing <= MAX_OBJ_SOUNDS_PLAYING);
635 
636  } // end if ( distance < Snds[osp->id].max )
637  } // if ( osp->instance == -1 )
638  else {
639  if ( distance > Snds[osp->id].max ) {
640  int sound_index = -1;
641  int idx = 0;
642 
643  // determine which sound index it is for this guy
644  for(SCP_vector<int>::iterator iter = objp->objsnd_num.begin(); iter != objp->objsnd_num.end(); ++iter, ++idx){
645  if(*iter == (osp - Objsnds)){
646  sound_index = idx;
647  break;
648  }
649  }
650 
651  Assert(sound_index != -1);
652  obj_snd_stop(objp, sound_index); // currently playing sound has gone past maximum
653  }
654  }
655 
656  if ( osp->instance == -1 )
657  continue;
658 
659  sp = NULL;
660  if ( objp->type == OBJ_SHIP )
661  sp = &Ships[objp->instance];
662 
663 
664  channel = ds_get_channel(osp->instance);
665  // for DirectSound3D sounds, re-establish the maximum speed based on the
666  // speed_vol_multiplier
667  if ( sp == NULL || ( (sp != NULL) && (sp->flags & SF_ENGINES_ON) ) ) {
668  snd_set_volume( osp->instance, gs->default_volume*speed_vol_multiplier*rot_vol_mult*alive_vol_mult );
669  }
670  else {
671  // engine sound is disabled
672  snd_set_volume( osp->instance, 0.0f );
673  }
674 
675  vec3d vel = objp->phys_info.vel;
676 
677  // Don't play doppler effect for cruisers or capitals
678  if ( sp ) {
679  if ( ship_get_SIF(sp) & (SIF_BIG_SHIP | SIF_HUGE_SHIP) ) {
680  vel = vmd_zero_vector;
681  }
682  }
683 
684  ds3d_update_buffer(channel, i2fl(gs->min), i2fl(gs->max), &source_pos, &vel);
685  snd_get_3d_vol_and_pan(gs, &source_pos, &osp->vol, &osp->pan, add_distance);
686  } // end for
687 
688  // see if we want to play a flyby sound
689  maybe_play_flyby_snd(closest_dist, closest_objp, observer_obj);
690 }
691 
692 // ---------------------------------------------------------------------------------------
693 // obj_snd_assign()
694 //
695 // Assign a persistent sound to an object.
696 //
697 // parameters: objnum => index of object that sound is being assigned to
698 // i => Index into Snds[] array
699 // fname => filename of sound to play ( so DS3D can load the sound )
700 //
701 // returns: -1 => sound could not be assigned (possible, since only MAX_OBJECT_SOUNDS persistent
702 // sound can be assigned per object).
703 // >= 0 => sound was successfully assigned
704 //
705 int obj_snd_assign(int objnum, int sndnum, vec3d *pos, int main, int flags, ship_subsys *associated_sub)
706 {
707  if(objnum < 0 || objnum > MAX_OBJECTS)
708  return -1;
709 
710  if(sndnum < 0)
711  return -1;
712 
713  if ( Obj_snd_enabled == FALSE )
714  return -1;
715 
716  //Initialize object sound list, if not initialized
719 
720  obj_snd *snd = NULL;
721  object *objp = &Objects[objnum];
722  int sound_index;
723  int idx = 0;
724 
725  // try and find a valid objsound index
726  sound_index = -1;
727  for(SCP_vector<int>::iterator iter = objp->objsnd_num.begin(); iter != objp->objsnd_num.end(); ++iter, ++idx){
728  if(*iter == -1){
729  sound_index = idx;
730  break;
731  }
732  }
733 
734  // no sound slot free, make a new one!
735  if ( sound_index == -1 ){
736  sound_index = (int) objp->objsnd_num.size();
737  objp->objsnd_num.push_back(-1);
738  }
739 
740  objp->objsnd_num[sound_index] = obj_snd_get_slot();
741  if ( objp->objsnd_num[sound_index] == -1 ) {
742  nprintf(("Sound", "SOUND ==> No free object-linked sounds left\n"));
743  return -1;
744  }
745  snd = &Objsnds[objp->objsnd_num[sound_index]];
746  snd->flags = OS_USED;
747 
748  if(main){
749  snd->flags |= OS_MAIN;
750  }
751 
752  if(flags > 0){
753  snd->flags |= flags;
754  }
755 
756  snd->id = sndnum;
757 
758  snd->instance = -1;
759  snd->vol = 0.0f;
760  snd->objnum = OBJ_INDEX(objp);
761  snd->next_update = 1;
762  snd->offset = *pos;
763  snd->ss = associated_sub;
764  // vm_vec_sub(&snd->offset, pos, &objp->pos);
765 
766  // add objp to the obj_snd_list
767  list_append( &obj_snd_list, snd );
768 
769  return sound_index;
770 }
771 
772 // ---------------------------------------------------------------------------------------
773 // obj_snd_delete()
774 //
775 // Remove a persistent sound that has been assigned to an object.
776 //
777 // parameters: objnum => index of object that sound is being removed from.
778 // index => index of sound in objsnd_num
779 //
780 void obj_snd_delete(int objnum, int index)
781 {
782  //Sanity checking
783  Assert(objnum > -1 && objnum < MAX_OBJECTS);
784 
785  object *objp = &Objects[objnum];
786 
787  Assert(index > -1 && index < (int) objp->objsnd_num.size());
788 
789  obj_snd *osp = &Objsnds[objp->objsnd_num[index]];
790 
791  //Stop the sound
792  obj_snd_stop(objp, index);
793 
794  // remove objp from the obj_snd_list
795  list_remove( &obj_snd_list, osp );
796  osp->objnum = -1;
797  osp->flags = 0;
798  osp = NULL;
799  objp->objsnd_num[index] = -1;
800 }
801 
802 // ---------------------------------------------------------------------------------------
803 // obj_snd_delete_type()
804 //
805 // Remove every similar persistent sound that has been assigned to an object.
806 //
807 // parameters: objnum => index of object that sound is being removed from.
808 // sndnum => index of sound that we're trying to completely get rid of
809 // -1 to delete all persistent sounds on ship.
810 //
811 //
812 void obj_snd_delete_type(int objnum, int sndnum, ship_subsys *ss)
813 {
814  object *objp;
815  obj_snd *osp;
816 
817  if(objnum < 0 || objnum >= MAX_OBJECTS)
818  return;
819 
820  objp = &Objects[objnum];
821 
822  size_t idx = 0;
823  //Go through the list and get sounds that match criteria
824  for(SCP_vector<int>::iterator iter = objp->objsnd_num.begin(); iter != objp->objsnd_num.end(); ++iter, ++idx){
825  // no sound
826  if ( *iter == -1 ){
827  continue;
828  }
829 
830  osp = &Objsnds[*iter];
831 
832  // if we're just deleting a specific sound type
833  // and this is not one of them. skip it.
834  //Also check if this is assigned to the right subsystem, if one has been given.
835  if(((sndnum != -1) && (osp->id != sndnum))
836  || ((ss != NULL) && (osp->ss != ss))){
837  continue;
838  }
839 
840  obj_snd_delete(objnum, idx);
841  }
842 }
843 
844 // ---------------------------------------------------------------------------------------
845 // obj_snd_delete_all()
846 //
847 // Remove all persistent sounds
848 //
850 {
851  int idx;
852  for(idx=0; idx<MAX_OBJ_SNDS; idx++){
853  if(Objsnds[idx].flags & OS_USED){
854  obj_snd_delete_type(Objsnds[idx].objnum);
855  }
856  }
857 }
858 
859 // ---------------------------------------------------------------------------------------
860 // obj_snd_close()
861 //
862 // Called once at game close to de-initialize the persistent object sound system
863 //
865 {
866  if ( !Obj_snd_level_inited ) {
867  return;
868  }
871 }
872 
873 // ---------------------------------------------------------------------------------------
874 // obj_snd_is_playing()
875 //
876 // Determines if a given object-linked sound is currently playing
877 //
878 int obj_snd_is_playing(int object, int index)
879 {
880  if ( obj_snd_return_instance(object, index) < 0 )
881  return 0;
882 
883  return 1;
884 }
885 
886 // ---------------------------------------------------------------------------------------
887 // obj_snd_return_instance()
888 //
889 // Returns the sound instance for a given object-linked sound
890 //
891 int obj_snd_return_instance(int objnum, int index)
892 {
893  if ( objnum < 0 || objnum >= MAX_OBJECTS)
894  return -1;
895 
897  return -1;
898 
899  object *objp = &Objects[objnum];
900  obj_snd *osp = &Objsnds[objp->objsnd_num[index]];
901 
902  return osp->instance;
903 }
904 
905 // ---------------------------------------------------------------------------------------
906 // obj_snd_update_offset()
907 //
908 // Updates offset of the given object sound
909 //
910 int obj_snd_update_offset(int objnum, int index, vec3d *new_offset)
911 {
912  if ( objnum < 0 || objnum >= MAX_OBJECTS)
913  return 0;
914 
916  return 0;
917 
918  object *objp = &Objects[objnum];
919  obj_snd *osp = &Objsnds[objp->objsnd_num[index]];
920  osp->offset = *new_offset;
921 
922  return 1;
923 }
#define SSF_ROTATES
Definition: ship.h:292
void obj_snd_level_close()
Definition: objectsnd.cpp:864
int timestamp(int delta_ms)
Definition: timer.cpp:226
int Flyby_next_repeat
Definition: objectsnd.cpp:77
int i
Definition: multi_pxo.cpp:466
void obj_snd_do_frame()
Definition: objectsnd.cpp:457
model_subsystem * system_info
Definition: ship.h:314
ai_info * Player_ai
Definition: ai.cpp:24
float vm_vec_mag_quick(const vec3d *v)
Definition: vecmat.cpp:371
vec3d View_position
Definition: 3dsetup.cpp:20
int snd_is_inited()
Definition: sound.cpp:1073
int Obj_snd_last_update
Definition: objectsnd.cpp:67
LOCAL state_stack gs[GS_STACK_SIZE]
SCP_vector< game_snd > Snds
Definition: gamesnd.cpp:19
GLuint index
Definition: Glext.h:5608
physics_info phys_info
Definition: object.h:157
void obj_snd_delete(int objnum, int index)
Definition: objectsnd.cpp:780
float max_hits
Definition: ship.h:320
int min
distance at which sound will stop getting louder
Definition: sound.h:79
int Cmdline_no_enhanced_sound
Definition: cmdline.cpp:392
Assert(pm!=NULL)
int target_objnum
Definition: ai.h:339
Definition: pstypes.h:88
#define FLYBY_MIN_DISTANCE
Definition: objectsnd.cpp:71
#define OBJ_ASTEROID
Definition: object.h:44
void obj_snd_delete_type(int objnum, int sndnum, ship_subsys *ss)
Definition: objectsnd.cpp:812
vec3d offset
Definition: objectsnd.cpp:46
struct vec3d::@225::@227 xyz
#define SPEED_SOUND
Definition: objectsnd.cpp:53
vec3d max_vel
Definition: physics.h:49
GLclampf f
Definition: Glext.h:7097
#define MAX_OBJECTS
Definition: globals.h:83
#define TRUE
Definition: pstypes.h:399
int obj_snd_return_instance(int objnum, int index)
Definition: objectsnd.cpp:891
obj_snd Objsnds[MAX_OBJ_SNDS]
Definition: objectsnd.cpp:64
object obj_used_list
Definition: object.cpp:53
int obj_snd_is_playing(int object, int index)
Definition: objectsnd.cpp:878
#define SF_ENGINES_ON
Definition: ship.h:454
int obj_snd_update_offset(int objnum, int index, vec3d *new_offset)
Definition: objectsnd.cpp:910
uint flags
Definition: ship.h:644
std::basic_string< char, std::char_traits< char >, std::allocator< char > > SCP_string
Definition: vmallocator.h:21
object * objp
Definition: lua.cpp:3105
#define Int3()
Definition: pstypes.h:292
struct channel channel
_obj_snd * prev
Definition: objectsnd.cpp:37
vec3d pos
Definition: object.h:152
#define OS_SUBSYS_DEAD
Definition: objectsnd.h:21
void maybe_play_flyby_snd(float closest_dist, object *closest_objp, object *listener_objp)
Definition: objectsnd.cpp:395
float base_rotation_rate_pct
Definition: ship.h:379
float turret_base_rotation_snd_mult
Definition: model.h:196
int obj_snd_assign(int objnum, int sndnum, vec3d *pos, int main, int flags, ship_subsys *associated_sub)
Definition: objectsnd.cpp:705
#define CLAMP(x, min, max)
Definition: pstypes.h:488
int species
Definition: ship.h:1166
int ds3d_update_buffer(int channel_id, float min, float max, vec3d *pos, vec3d *vel)
Definition: ds3d.cpp:35
float vol
Definition: objectsnd.cpp:42
#define SIF_BOMBER
Definition: ship.h:886
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int instance
Definition: object.h:150
int flags
Definition: ship.h:322
void joy_ff_fly_by(int mag)
Definition: joy-unix.cpp:605
#define SIF_BIG_SHIP
Definition: ship.h:944
int ds_get_channel(int sig)
Definition: ds.cpp:1870
#define nprintf(args)
Definition: pstypes.h:239
ship_subsys * ss
Definition: objectsnd.cpp:47
#define OS_TURRET_BASE_ROTATION
Definition: objectsnd.h:18
int flags
Definition: ship.h:1227
#define SIF_SMALL_SHIP
Definition: ship.h:943
int snd_play_3d(game_snd *gs, vec3d *source_pos, vec3d *listen_pos, float radius, vec3d *source_vel, int looping, float vol_scale, int priority, vec3d *sound_fvec, float range_factor, int force, bool is_ambient)
Definition: sound.cpp:594
float min_engine_vol
Definition: ship.h:1419
int ship_get_SIF(ship *shipp)
Definition: ship.cpp:16096
#define OS_USED
Definition: objectsnd.h:15
#define OBJ_DEBRIS
Definition: object.h:37
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
void obj_snd_stop_all()
Definition: objectsnd.cpp:299
DCF(objsnd,"Persistent sound stuff")
Definition: objectsnd.cpp:97
object * Viewer_obj
Definition: object.cpp:57
#define MAX_OBJ_SNDS
Definition: objectsnd.cpp:63
float vm_vec_normalized_dir(vec3d *dest, const vec3d *end, const vec3d *start)
Definition: vecmat.cpp:591
struct _obj_snd obj_snd
#define OS_MAIN
Definition: objectsnd.h:17
bool dc_optional_string_either(const char *str1, const char *str2)
Searches for an optional string and it's alias.
float current_hits
Definition: ship.h:319
Definition: ship.h:534
int idx
Definition: multiui.cpp:761
vec3d * vm_vec_unrotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:959
float turret_gun_rotation_snd_mult
Definition: model.h:198
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
#define OBJ_INDEX(objp)
Definition: object.h:235
matrix orient
Definition: object.h:153
int snd_get_3d_vol_and_pan(game_snd *gs, vec3d *pos, float *vol, float *pan, float radius, float range_factor)
Definition: sound.cpp:759
#define FLYBY_MIN_RELATIVE_SPEED
Definition: objectsnd.cpp:73
int max
distance at which sound is inaudible
Definition: sound.h:80
#define OBJ_SHIP
Definition: object.h:32
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
float pan
Definition: objectsnd.cpp:43
int obj_snd_get_freq(int source_freq, object *source, object *observor, vec3d *source_pos)
Definition: objectsnd.cpp:316
int obj_snd_stop_lowest_vol(float new_vol)
Definition: objectsnd.cpp:340
GLbitfield flags
Definition: Glext.h:6722
#define SIF_HUGE_SHIP
Definition: ship.h:945
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
float gun_rotation_rate_pct
Definition: ship.h:380
vec3d vel
Definition: physics.h:77
float fspeed
Definition: physics.h:80
int main(int argc, char *argv[])
#define FLYBY_MIN_REPEAT_TIME
Definition: objectsnd.cpp:75
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
#define DCF_BOOL(function_name, bool_variable)
Definition: console.h:71
int flags
Definition: objectsnd.cpp:45
float vm_vec_dist_quick(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:417
void obj_snd_delete_all()
Definition: objectsnd.cpp:849
#define OS_SUBSYS_ALIVE
Definition: objectsnd.h:20
#define fl2i(fl)
Definition: floating.h:33
int objnum
Definition: objectsnd.cpp:38
int ship_info_index
Definition: ship.h:539
An overhauled/updated debug console to allow monitoring, testing, and general debugging of new featur...
void snd_set_volume(int sig, float volume)
Definition: sound.cpp:920
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
int Viewer_mode
Definition: systemvars.cpp:28
#define timestamp_elapsed(stamp)
Definition: timer.h:102
SCP_vector< species_info > Species_info
hull_check pos
Definition: lua.cpp:5050
#define SND_PRIORITY_TRIPLE_INSTANCE
Definition: sound.h:29
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
#define i2fl(i)
Definition: floating.h:32
GLsizei GLsizei GLchar * source
Definition: Glext.h:5625
int next_update
Definition: objectsnd.cpp:41
matrix * A
Definition: lua.cpp:444
int Flyby_next_sound
Definition: objectsnd.cpp:76
bool dc_optional_string(const char *pstr)
Searches for an optional string.
object * Player_obj
Definition: object.cpp:56
void dc_printf(const char *format,...)
Prints the given char string to the debug console.
Definition: console.cpp:358
int Obj_snd_level_inited
Definition: objectsnd.cpp:68
#define OS_TURRET_GUN_ROTATION
Definition: objectsnd.h:19
#define VM_OTHER_SHIP
Definition: systemvars.h:35
#define OS_SUBSYS_ROTATION
Definition: objectsnd.h:23
#define FLYBY_MIN_NEXT_TIME
Definition: objectsnd.cpp:74
object * Flyby_last_objp
Definition: objectsnd.cpp:78
int freq
Definition: objectsnd.cpp:44
float radius
Definition: object.h:154
void snd_stop(int sig)
Definition: sound.cpp:875
int Obj_snd_enabled
Definition: objectsnd.cpp:66
void obj_snd_level_init()
Definition: objectsnd.cpp:191
char type
Definition: object.h:146
int instance
Definition: objectsnd.cpp:40
vec3d vmd_zero_vector
Definition: vecmat.cpp:24
SCP_vector< int > objsnd_num
Definition: object.h:162
float default_volume
range: 0.0 -> 1.0
Definition: sound.h:78
#define FALSE
Definition: pstypes.h:400
#define MAX_NAME_LEN
Definition: model.h:29
void obj_snd_stop(object *objp, int index)
Definition: objectsnd.cpp:228
int timer_get_milliseconds()
Definition: timer.cpp:150
void vm_vec_add(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:159
#define OBJ_GHOST
Definition: object.h:39
char ship_name[NAME_LENGTH]
Definition: ship.h:604
_obj_snd * next
Definition: objectsnd.cpp:37
#define OS_SUBSYS_DAMAGED
Definition: objectsnd.h:22
int obj_snd_get_slot()
Definition: objectsnd.cpp:174
bool dc_maybe_stuff_string_white(char *str, size_t len)
Tries to stuff a whitespace delimited string to out_str from the command line, stopping at the end of...
#define strcpy_s(...)
Definition: safe_strings.h:67
Definition: sound.h:72
void obj_snd_source_pos(vec3d *sound_pos, obj_snd *osp)
Definition: objectsnd.cpp:81