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