1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <math.h>
6
7 #include "matrixmath.h"
8 #include "sound.h"
9 #include "obj.h"
10 #include "objsound.h"
11 #include "sar.h"
12 #include "config.h"
13
14
15 #ifdef __MSW__
16 static double rint(double x);
17 #endif /* __MSW__ */
18
19
20 sar_sound_source_struct *SARSoundSourceNew(
21 const char *name,
22 const char *filename,
23 const char *filename_far,
24 float range, /* In meters */
25 float range_far, /* In meters */
26 const sar_position_struct *pos,
27 float cutoff, /* In radians */
28 const sar_direction_struct *dir,
29 int sample_rate_limit /* In Hz */
30 );
31 void SARSoundSourceDelete(sar_sound_source_struct *sndsrc);
32 int SARSoundSourceMatchFromList(
33 sar_sound_source_struct **list, int total,
34 const char *name
35 );
36 void SARSoundSourcePlayFromList(
37 snd_recorder_struct *recorder,
38 sar_sound_source_struct **list, int total,
39 const char *name,
40 const sar_position_struct *pos, /* Object position */
41 const sar_direction_struct *dir, /* Object direction */
42 const sar_position_struct *ear_pos
43 );
44 snd_play_struct *SARSoundSourcePlayFromListRepeating(
45 snd_recorder_struct *recorder,
46 sar_sound_source_struct **list, int total,
47 const char *name, int *sndsrc_num
48 );
49
50 void SARSoundEngineMute(
51 snd_recorder_struct *recorder,
52 snd_play_struct *inside_snd_play,
53 snd_play_struct *outside_snd_play
54 );
55 void SARSoundEngineUpdate(
56 snd_recorder_struct *recorder,
57 sar_sound_source_struct **list, int total,
58 snd_play_struct *inside_snd_play,
59 int inside_sndsrc_num,
60 snd_play_struct *outside_snd_play,
61 int outside_sndsrc_num,
62 char ear_in_cockpit,
63 sar_engine_state engine_state,
64 float throttle,
65 float distance_to_camera
66 );
67 int SARSoundStallUpdate(
68 snd_recorder_struct *recorder,
69 sar_sound_source_struct **list, int total,
70 void **stall_snd_play,
71 int stall_sndsrc_num,
72 char ear_in_cockpit,
73 sar_flight_model_type flight_model_type,
74 char is_landed,
75 float speed, float speed_stall
76 );
77 void SARSoundOverSpeedUpdate(
78 snd_recorder_struct *recorder,
79 sar_sound_source_struct **list, int total,
80 void **overspeed_snd_play,
81 int overspeed_sndsrc_num,
82 char ear_in_cockpit, char is_overspeed
83 );
84
85
86 #define POW(x,y) (((x) > 0.0f) ? pow(x,y) : 0.0f)
87
88 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
89 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
90 #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h)))
91 #define STRDUP(s) (((s) != NULL) ? strdup(s) : NULL)
92
93
94 #ifdef __MSW__
rint(double x)95 static double rint(double x)
96 {
97 if((double)((double)x - (int)x) > (double)0.5)
98 return((double)((int)x + (int)1));
99 else
100 return((double)((int)x));
101 }
102 #endif /* __MSW__ */
103
104
105
106 /*
107 * Creates a new sound source structure.
108 */
SARSoundSourceNew(const char * name,const char * filename,const char * filename_far,float range,float range_far,const sar_position_struct * pos,float cutoff,const sar_direction_struct * dir,int sample_rate_limit)109 sar_sound_source_struct *SARSoundSourceNew(
110 const char *name,
111 const char *filename,
112 const char *filename_far,
113 float range, /* In meters */
114 float range_far, /* In meters */
115 const sar_position_struct *pos,
116 float cutoff, /* In radians */
117 const sar_direction_struct *dir,
118 int sample_rate_limit /* In Hz */
119 )
120 {
121 sar_sound_source_struct *sndsrc = SAR_SOUND_SOURCE(
122 calloc(1, sizeof(sar_sound_source_struct))
123 );
124 if(sndsrc == NULL)
125 return(NULL);
126
127 sndsrc->name = STRDUP(name);
128
129 sndsrc->filename = STRDUP(filename);
130 sndsrc->filename_far = STRDUP(filename_far);
131
132 sndsrc->range = range;
133 sndsrc->range_far = range_far;
134
135 if(pos != NULL)
136 memcpy(&sndsrc->pos, pos, sizeof(sar_position_struct));
137
138 sndsrc->cutoff = cutoff;
139
140 if(dir != NULL)
141 memcpy(&sndsrc->dir, dir, sizeof(sar_direction_struct));
142
143 sndsrc->sample_rate_limit = sample_rate_limit;
144
145 return(sndsrc);
146 }
147
148 /*
149 * Deletes the given sound source structure.
150 */
SARSoundSourceDelete(sar_sound_source_struct * sndsrc)151 void SARSoundSourceDelete(sar_sound_source_struct *sndsrc)
152 {
153 if(sndsrc == NULL)
154 return;
155
156 free(sndsrc->name);
157 free(sndsrc->filename);
158 free(sndsrc->filename_far);
159 free(sndsrc);
160 }
161
162 /*
163 * Returns the index of the sound source found in the given list
164 * that matches the given name.
165 *
166 * Can return -1 on failed match.
167 */
SARSoundSourceMatchFromList(sar_sound_source_struct ** list,int total,const char * name)168 int SARSoundSourceMatchFromList(
169 sar_sound_source_struct **list, int total,
170 const char *name
171 )
172 {
173 int i;
174 sar_sound_source_struct *sndsrc;
175
176
177 if((list == NULL) || (total <= 0) || (name == NULL))
178 return(-1);
179
180 for(i = 0; i < total; i++)
181 {
182 sndsrc = list[i];
183 if(sndsrc == NULL)
184 continue;
185
186 if(sndsrc->name == NULL)
187 continue;
188
189 if(!strcmp(sndsrc->name, name))
190 return(i);
191 }
192
193 return(-1);
194 }
195
196 /*
197 * Searches the given list of sound sources for a sound source
198 * who's name matches the given name.
199 *
200 * If it is matched then it will be played once.
201 */
SARSoundSourcePlayFromList(snd_recorder_struct * recorder,sar_sound_source_struct ** list,int total,const char * name,const sar_position_struct * pos,const sar_direction_struct * dir,const sar_position_struct * ear_pos)202 void SARSoundSourcePlayFromList(
203 snd_recorder_struct *recorder,
204 sar_sound_source_struct **list, int total,
205 const char *name,
206 const sar_position_struct *pos, /* Object position */
207 const sar_direction_struct *dir, /* Object direction */
208 const sar_position_struct *ear_pos
209 )
210 {
211 int i;
212 double a[3 * 1], b[3 * 1];
213 float r;
214 sar_sound_source_struct *sndsrc;
215 sar_position_struct snd_pos;
216
217
218 if(recorder == NULL)
219 return;
220
221 i = SARSoundSourceMatchFromList(list, total, name);
222 sndsrc = (i > -1) ? list[i] : NULL;
223 if(sndsrc == NULL)
224 return;
225
226 if(sndsrc->filename == NULL)
227 return;
228
229
230 /* Found sound source to play */
231
232 /* Calculate world coordinates of sound as snd_pos */
233 if((pos != NULL) && (dir != NULL))
234 {
235 a[0] = sndsrc->pos.x;
236 a[1] = sndsrc->pos.y;
237 a[2] = sndsrc->pos.z;
238
239 /* Rotate matrix a into b */
240 MatrixRotateBank3(a, -dir->bank, b); /* Our bank is negative,
241 * so pass as flipped
242 */
243 MatrixRotatePitch3(b, dir->pitch, a);
244 MatrixRotateHeading3(a, dir->heading, b);
245
246 snd_pos.x = (float)(pos->x + b[0]);
247 snd_pos.y = (float)(pos->y + b[1]);
248 snd_pos.z = (float)(pos->z + b[2]);
249 }
250 else if(pos != NULL)
251 {
252 snd_pos.x = pos->x;
253 snd_pos.y = pos->y;
254 snd_pos.z = pos->z;
255 }
256 else
257 {
258 memset(&snd_pos, 0x00, sizeof(sar_position_struct));
259 }
260
261
262 /* Calculate 3d distance r of source to ear */
263 if(ear_pos != NULL)
264 r = (float)SFMHypot3(
265 snd_pos.x - ear_pos->x,
266 snd_pos.y - ear_pos->y,
267 snd_pos.z - ear_pos->z
268 );
269 else
270 r = 0.0f;
271
272
273 /* Calculate volume due to distance r relative to the
274 * maximum range of the sound source.
275 */
276 if(sndsrc->range > 0.0)
277 {
278 if(r < sndsrc->range)
279 {
280 float vol = (float)MAX(
281 1.0 - (r / sndsrc->range), 0.0
282 );
283 SoundStartPlayVoid(
284 recorder,
285 sndsrc->filename,
286 vol, vol,
287 0, 0
288 );
289 }
290 }
291 else
292 {
293 float vol = 1.0f;
294 SoundStartPlayVoid(
295 recorder,
296 sndsrc->filename,
297 vol, vol,
298 0, 0
299 );
300 }
301 }
302
303 /*
304 * Searches the given list of sound sources for a sound source
305 * who's name matches the given name.
306 *
307 * If it is matched then it will be played repeatedly.
308 *
309 * Returns the pointer to the new sound object play structure
310 * or NULL on failure.
311 */
SARSoundSourcePlayFromListRepeating(snd_recorder_struct * recorder,sar_sound_source_struct ** list,int total,const char * name,int * sndsrc_num)312 snd_play_struct *SARSoundSourcePlayFromListRepeating(
313 snd_recorder_struct *recorder,
314 sar_sound_source_struct **list, int total,
315 const char *name, int *sndsrc_num
316 )
317 {
318 int i;
319 sar_sound_source_struct *sndsrc;
320
321 if(sndsrc_num != NULL)
322 *sndsrc_num = -1;
323
324 if(recorder == NULL)
325 return(NULL);
326
327 i = SARSoundSourceMatchFromList(list, total, name);
328 sndsrc = (i > -1) ? list[i] : NULL;
329 if(sndsrc == NULL)
330 return(NULL);
331
332 if(sndsrc->filename == NULL)
333 return(NULL);
334
335 if(sndsrc_num != NULL)
336 *sndsrc_num = i;
337
338 /* Start playing the sound object repeatedly, the volume
339 * should be initially 0.0 (muted). The calling function
340 * is responsible for increasing the volume of the returned
341 * sound play object.
342 */
343 return(SoundStartPlay(
344 recorder,
345 sndsrc->filename, /* Full path to object */
346 0.0, 0.0, /* Volume, from 0.0 to 1.0 */
347 0, /* Applied sample rate, can be 0 */
348 SND_PLAY_OPTION_REPEATING /* Options */
349 ));
350 }
351
352
353 /*
354 * Calls SARSoundEngineUpdate() with throttle set to 0.0
355 * and the engine_state set to SAR_ENGINE_OFF.
356 *
357 * This effectively mutes the engine sound.
358 */
SARSoundEngineMute(snd_recorder_struct * recorder,snd_play_struct * inside_snd_play,snd_play_struct * outside_snd_play)359 void SARSoundEngineMute(
360 snd_recorder_struct *recorder,
361 snd_play_struct *inside_snd_play,
362 snd_play_struct *outside_snd_play
363 )
364 {
365 SARSoundEngineUpdate(
366 recorder,
367 NULL, 0, /* No sound sources needed */
368 inside_snd_play,
369 -1,
370 outside_snd_play,
371 -1,
372 0, /* In cockpit? */
373 SAR_ENGINE_OFF, /* Engine state */
374 0.0f, /* Throttle */
375 0.0f /* Distance to camera */
376 );
377 }
378
379 /*
380 * Adjusts the engine volume and sample rate.
381 */
SARSoundEngineUpdate(snd_recorder_struct * recorder,sar_sound_source_struct ** list,int total,snd_play_struct * inside_snd_play,int inside_sndsrc_num,snd_play_struct * outside_snd_play,int outside_sndsrc_num,char ear_in_cockpit,sar_engine_state engine_state,float throttle,float distance_to_camera)382 void SARSoundEngineUpdate(
383 snd_recorder_struct *recorder,
384 sar_sound_source_struct **list, int total,
385 snd_play_struct *inside_snd_play,
386 int inside_sndsrc_num,
387 snd_play_struct *outside_snd_play,
388 int outside_sndsrc_num,
389 char ear_in_cockpit,
390 sar_engine_state engine_state, /* One of SAR_ENGINE_* */
391 float throttle, /* Throttle coeff 0.0 to 1.0 */
392 float distance_to_camera /* In meters */
393 )
394 {
395 int sample_rate, new_sample_rate, sample_rate_limit; /* In Hz */
396 float volume; /* 0.0 to 1.0 */
397 float audiable_radius = 2000.0f;
398 sar_sound_source_struct *inside_sndsrc = NULL,
399 *outside_sndsrc = NULL;
400
401 /* Not connected to sound server? */
402 if(recorder == NULL)
403 return;
404
405 /* If the engine is off then mute all sound volumes, this
406 * improves efficiency since no sound would be mixed by
407 * the sound server if volume is 0.0 but the sound object will
408 * still remain valid.
409 */
410 if(engine_state != SAR_ENGINE_ON)
411 {
412 SoundChangePlayVolume(
413 recorder, inside_snd_play,
414 0.0f, 0.0f
415 );
416 SoundChangePlayVolume(
417 recorder, outside_snd_play,
418 0.0f, 0.0f
419 );
420 return;
421 }
422
423
424 /* Get pointers to sound source structures (if possible) */
425 if(list != NULL)
426 {
427 if((inside_sndsrc_num >= 0) &&
428 (inside_sndsrc_num < total)
429 )
430 inside_sndsrc = list[inside_sndsrc_num];
431
432 if((outside_sndsrc_num >= 0) &&
433 (outside_sndsrc_num < total)
434 )
435 outside_sndsrc = list[outside_sndsrc_num];
436 }
437
438
439 /* Begin calculating sample rate based on the throttle position,
440 * increase to a faster sample rate as throttle increases.
441 */
442
443 /* Get lower and upper sample rate bounds and ranges */
444 sample_rate_limit = sample_rate = recorder->sample_rate;
445 if(ear_in_cockpit && inside_sndsrc != NULL)
446 {
447 sample_rate_limit = inside_sndsrc->sample_rate_limit;
448 audiable_radius = inside_sndsrc->range;
449 }
450 else if(outside_sndsrc != NULL)
451 {
452 sample_rate_limit = outside_sndsrc->sample_rate_limit;
453 audiable_radius = outside_sndsrc->range;
454 }
455
456 /* Calculate new sample rate based on throttle position */
457 new_sample_rate = (int)rint(
458 ((MAX(sample_rate_limit - sample_rate, 0) * throttle) +
459 sample_rate) / 1000
460 );
461 new_sample_rate = (int)(new_sample_rate * 1000);
462
463
464 /* Calculate volume based on (1 - (x^0.5)) curve */
465 volume = (float)CLIP(1.0 -
466 POW(distance_to_camera / audiable_radius, 0.5),
467 0.0, 1.0
468 );
469
470 /* Is ear inside cockpit? */
471 if(ear_in_cockpit)
472 {
473 /* Inside cockpit */
474 SoundChangePlayVolume(
475 recorder, inside_snd_play,
476 volume, volume
477 );
478 SoundChangePlaySampleRate(
479 recorder, inside_snd_play,
480 new_sample_rate
481 );
482 SoundChangePlayVolume(
483 recorder, outside_snd_play,
484 0.0f, 0.0f
485 );
486 SoundChangePlaySampleRate(
487 recorder, outside_snd_play,
488 new_sample_rate
489 );
490 }
491 else
492 {
493 /* Outside */
494 SoundChangePlayVolume(
495 recorder, inside_snd_play,
496 0.0f, 0.0f
497 );
498 SoundChangePlaySampleRate(
499 recorder, inside_snd_play,
500 new_sample_rate
501 );
502 SoundChangePlayVolume(
503 recorder, outside_snd_play,
504 volume, volume
505 );
506 SoundChangePlaySampleRate(
507 recorder, outside_snd_play,
508 new_sample_rate
509 );
510 }
511 }
512
513 /*
514 * Plays or stops the repeating stall warning sound
515 *
516 * The speed_stall should have modifications (ie flaps) already
517 * applied to it.
518 *
519 * Returns 1 if sound was turned on or 0 if it was not.
520 */
SARSoundStallUpdate(snd_recorder_struct * recorder,sar_sound_source_struct ** list,int total,void ** stall_snd_play,int stall_sndsrc_num,char ear_in_cockpit,sar_flight_model_type flight_model_type,char is_landed,float speed,float speed_stall)521 int SARSoundStallUpdate(
522 snd_recorder_struct *recorder,
523 sar_sound_source_struct **list, int total,
524 void **stall_snd_play,
525 int stall_sndsrc_num,
526 char ear_in_cockpit,
527 sar_flight_model_type flight_model_type,
528 char is_landed,
529 float speed, float speed_stall
530 )
531 {
532 Boolean stalling = False;
533 float speed_threshold;
534
535 if((recorder == NULL) || (stall_snd_play == NULL))
536 return(0);
537
538 /* Calculate the speed at which the sound should be turned on
539 * if the speed is lower than this value
540 */
541 speed_threshold = speed_stall * 0.78f;
542
543 /* Stall warning sound should be turned on? */
544 if(!is_landed && (flight_model_type == SAR_FLIGHT_MODEL_AIRPLANE))
545 {
546 if((speed < speed_threshold) && (speed_threshold > 0.0f))
547 stalling = True;
548 }
549
550 /* Check if the sound needs to be played or stopped? */
551 if(stalling && (*stall_snd_play == NULL))
552 {
553 /* Need to start playing stall sound */
554 int i = stall_sndsrc_num;
555 sar_sound_source_struct *sndsrc;
556
557 if((i >= 0) && (i < total))
558 sndsrc = list[i];
559 else
560 sndsrc = NULL;
561
562 if(sndsrc != NULL)
563 *stall_snd_play = (void *)SoundStartPlay(
564 recorder,
565 sndsrc->filename,
566 1.0f, 1.0f,
567 0,
568 SND_PLAY_OPTION_REPEATING
569 );
570 }
571 else if(!stalling && (*stall_snd_play != NULL))
572 {
573 /* Need to stop playing stall sound */
574 SoundStopPlay(
575 recorder,
576 (snd_play_struct *)(*stall_snd_play)
577 );
578 *stall_snd_play = NULL;
579 }
580
581 return(stalling ? 1 : 0);
582 }
583
584 /*
585 * Plays or stops the repeating overspeed warning sound.
586 */
SARSoundOverSpeedUpdate(snd_recorder_struct * recorder,sar_sound_source_struct ** list,int total,void ** overspeed_snd_play,int overspeed_sndsrc_num,char ear_in_cockpit,char is_overspeed)587 void SARSoundOverSpeedUpdate(
588 snd_recorder_struct *recorder,
589 sar_sound_source_struct **list, int total,
590 void **overspeed_snd_play,
591 int overspeed_sndsrc_num,
592 char ear_in_cockpit, char is_overspeed
593 )
594 {
595 if((recorder == NULL) || (overspeed_snd_play == NULL))
596 return;
597
598 /* Check if the sound needs to be played or stopped? */
599 if(is_overspeed && (*overspeed_snd_play == NULL))
600 {
601 /* Need to start playing overspeed sound */
602 int i = overspeed_sndsrc_num;
603 sar_sound_source_struct *sndsrc;
604
605 if((i >= 0) && (i < total))
606 sndsrc = list[i];
607 else
608 sndsrc = NULL;
609
610 if(sndsrc != NULL)
611 *overspeed_snd_play = (void *)SoundStartPlay(
612 recorder,
613 sndsrc->filename,
614 1.0f, 1.0f,
615 0,
616 SND_PLAY_OPTION_REPEATING
617 );
618 }
619 else if(!is_overspeed && (*overspeed_snd_play != NULL))
620 {
621 /* Need to stop playing overspeed sound */
622 SoundStopPlay(
623 recorder,
624 (snd_play_struct *)(*overspeed_snd_play)
625 );
626 *overspeed_snd_play = NULL;
627 }
628 }
629