naev 0.12.6
sound.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
34#include "SDL_mutex.h"
35#include "physfs.h"
36#include <sys/stat.h>
37
38#include "naev.h"
40
41#include "physfsrwops.h"
42
43#include "sound.h"
44
45#include "array.h"
46#include "camera.h"
47#include "conf.h"
48#include "log.h"
49#include "music.h"
50#include "ndata.h"
51#include "nlua_spfx.h"
52#include "nopenal.h"
53#include "pilot.h"
54
55#define SOUND_FADEOUT 100
56#define SOUND_VOICES \
57 64
58
59
60#define SOUND_SUFFIX_WAV ".wav"
61#define SOUND_SUFFIX_OGG ".ogg"
62
63#define voiceLock() SDL_LockMutex( voice_mutex )
64#define voiceUnlock() SDL_UnlockMutex( voice_mutex )
65
71typedef struct alSound_ {
72 char *filename;
73 char *name;
74 double length;
76 ALuint buf;
77} alSound;
78
90
98typedef struct alVoice_ {
99 struct alVoice_ *prev;
100 struct alVoice_ *next;
101
102 int id;
103
105 unsigned int flags;
106
107 ALfloat pos[3];
108 ALfloat vel[3];
109 ALuint source;
110 ALuint buffer;
111} alVoice;
112
113typedef struct alGroup_s {
114 int id;
115
116 /* Sources. */
117 ALuint *sources;
119
122 int speed;
123 double volume;
124 double pitch;
125} alGroup_t;
126
127/*
128 * Global sound properties.
129 */
131static int sound_initialized = 0;
132
133/*
134 * Sound list.
135 */
136static alSound *sound_list = NULL;
137
138/*
139 * Voices.
140 */
141static int voice_genid = 0;
142static alVoice *voice_active = NULL;
143static alVoice *voice_pool = NULL;
144static SDL_mutex *voice_mutex = NULL;
145
146/*
147 * Internally used sounds.
148 */
149static int snd_compression = -1;
150static int snd_compressionG = -1;
151static double snd_compression_gain = 0.;
152
153/*
154 * prototypes
155 */
156/* General. */
157static int sound_makeList( void );
158static void sound_free( alSound *snd );
159/* Voices. */
160
161/*
162 * Global sound lock.
163 */
164SDL_mutex *sound_lock = NULL;
166
167/*
168 * Global device and context.
169 */
170static ALCcontext *al_context = NULL;
171static ALCdevice *al_device = NULL;
172static ALfloat svolume = 1.;
173static ALfloat svolume_lin = 1.;
174static ALfloat svolume_speed =
175 1.;
177
178/*
179 * struct to hold all the sources and currently attached voice
180 */
181static ALuint *source_stack = NULL;
182static ALuint *source_total = NULL;
183static ALuint *source_all = NULL;
184static int source_nstack = 0;
185static int source_ntotal = 0;
186static int source_nall = 0;
187static int source_mstack = 0;
188
189/*
190 * EFX stuff.
191 */
193static ALuint efx_reverb = 0;
194static ALuint efx_echo = 0;
195
196/*
197 * Sound speed.
198 */
199static double sound_speed = 1.;
200
201/*
202 * Group management.
203 */
204static alGroup_t *al_groups = NULL;
205static int al_ngroups = 0;
206static int al_groupidgen = 0;
207
208/*
209 * Prototypes.
210 */
211/*
212 * Loading.
213 */
214static int sound_al_init( void );
215static const char *vorbis_getErr( int err );
216static int al_enableEFX( void );
217/*
218 * General.
219 */
220static int al_playVoice( alVoice *v, alSound *s, ALfloat px, ALfloat py,
221 ALfloat vx, ALfloat vy, ALint relative );
222static int al_load( alSound *snd, SDL_RWops *rw, const char *name );
223static int al_loadWav( ALuint *buf, SDL_RWops *rw );
224static int al_loadOgg( ALuint *buf, OggVorbis_File *vf );
225/*
226 * Pausing.
227 */
228static void al_pausev( ALint n, ALuint *s );
229static void al_resumev( ALint n, ALuint *s );
230/*
231 * Groups.
232 */
233static alGroup_t *al_getGroup( int group );
234/*
235 * Voice management.
236 */
237static alVoice *voice_new( void );
238static int voice_add( alVoice *v );
239static alVoice *voice_get( int id );
240/*
241 * Sound playing.
242 */
243static void al_updateVoice( alVoice *v );
244static void al_volumeUpdate( void );
245/*
246 * Vorbis stuff.
247 */
248static size_t ovpack_read( void *ptr, size_t size, size_t nmemb,
249 void *datasource )
250{
251 SDL_RWops *rw = datasource;
252 return (size_t)SDL_RWread( rw, ptr, size, nmemb );
253}
254static int ovpack_seek( void *datasource, ogg_int64_t offset, int whence )
255{
256 SDL_RWops *rw = datasource;
257 return SDL_RWseek( rw, offset, whence );
258}
259static int ovpack_close( void *datasource )
260{
261 SDL_RWops *rw = datasource;
262 return SDL_RWclose( rw );
263}
264static int ovpack_closeFake( void *datasource )
265{
266 (void)datasource;
267 return 0;
268}
269static long ovpack_tell( void *datasource )
270{
271 SDL_RWops *rw = datasource;
272 return SDL_RWseek( rw, 0, SEEK_CUR );
273}
274ov_callbacks sound_al_ovcall = {
275 .read_func = ovpack_read,
276 .seek_func = ovpack_seek,
277 .close_func = ovpack_close,
278 .tell_func = ovpack_tell };
279ov_callbacks sound_al_ovcall_noclose = { .read_func = ovpack_read,
280 .seek_func = ovpack_seek,
281 .close_func = ovpack_closeFake,
282 .tell_func =
283 ovpack_tell };
284
285
291static int sound_al_init( void )
292{
293 int ret, nattribs = 0;
294 ALuint s;
295 ALint attribs[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
296
297 /* Default values. */
298 ret = 0;
299
300 /* We'll need a mutex */
301 sound_lock = SDL_CreateMutex();
302 soundLock();
303
304 /* opening the default device */
305 al_device = alcOpenDevice( NULL );
306 if ( al_device == NULL ) {
307 WARN( _( "Unable to open default sound device" ) );
308 ret = -1;
309 goto snderr_dev;
310 }
311
312 /* Set good default for sources. */
313 attribs[0] = ALC_MONO_SOURCES;
314 attribs[1] = 512;
315 attribs[2] = ALC_STEREO_SOURCES;
316 attribs[3] = 32;
317 nattribs = 4;
318
319 /* Query EFX extension. */
320 if ( conf.al_efx ) {
321 al_info.efx = alcIsExtensionPresent( al_device, "ALC_EXT_EFX" );
322 if ( al_info.efx == AL_TRUE ) {
323 attribs[nattribs + 0] = ALC_MAX_AUXILIARY_SENDS;
324 attribs[nattribs + 1] = 4;
325 nattribs += 2;
326 }
327 } else
328 al_info.efx = AL_FALSE;
329
330 /* Check more extensions. */
331 al_info.output_limiter =
332 alcIsExtensionPresent( al_device, "ALC_SOFT_output_limiter" );
333 if ( al_info.output_limiter ) {
334 attribs[nattribs + 0] = ALC_OUTPUT_LIMITER_SOFT;
335 attribs[nattribs + 1] = ALC_TRUE;
336 nattribs += 2;
337 }
338
339 /* Create the OpenAL context */
340 al_context = alcCreateContext( al_device, attribs );
341 if ( al_context == NULL ) {
342 WARN( _( "Unable to create OpenAL context" ) );
343 ret = -2;
344 goto snderr_ctx;
345 }
346
347 /* Set active context */
348 if ( alcMakeContextCurrent( al_context ) == AL_FALSE ) {
349 WARN( _( "Failure to set default context" ) );
350 ret = -4;
351 goto snderr_act;
352 }
353
354 /* Clear the errors */
355 alGetError();
356
357 /* Query some extensions. */
358 if ( al_info.output_limiter ) {
359 ALint limiter;
360 alcGetIntegerv( al_device, ALC_OUTPUT_LIMITER_SOFT, 1, &limiter );
361 if ( limiter != ALC_TRUE )
362 WARN( _( "Failed to set ALC_OUTPUT_LIMITER_SOFT" ) );
363 }
364
365 /* Get context information. */
366 alcGetIntegerv( al_device, ALC_FREQUENCY, 1, &al_info.freq );
367 alcGetIntegerv( al_device, ALC_MONO_SOURCES, 1, &al_info.nmono );
368 alcGetIntegerv( al_device, ALC_STEREO_SOURCES, 1, &al_info.nstereo );
369
370 /* Try to enable EFX. */
371 if ( al_info.efx == AL_TRUE ) {
372 al_enableEFX();
373 } else {
374 al_info.efx_reverb = AL_FALSE;
375 al_info.efx_echo = AL_FALSE;
376 }
377
378 /* Check for errors. */
379 al_checkErr();
380
381 /* Start allocating the sources - music has already taken theirs */
382 source_nstack = 0;
384 source_stack = malloc( sizeof( ALuint ) * source_mstack );
385 while ( source_nstack < SOUND_VOICES ) {
386 alGenSources( 1, &s );
388
389 /* How OpenAL distance model works:
390 *
391 * Clamped:
392 * gain = distance_function( CLAMP( AL_REFERENCE_DISTANCE,
393 * AL_MAX_DISTANCE, distance ) );
394 *
395 * Distance functions:
396 * AL_REFERENCE_DISTANCE
397 * * Inverse =
398 * ------------------------------------------------------------------------------
399 * AL_REFERENCE_DISTANCE + AL_ROLLOFF_FACTOR ( distance -
400 * AL_REFERENCE_DISTANCE )
401 *
402 * 1 - AL_ROLLOFF_FACTOR ( distance - AL_REFERENCE_DISTANCE )
403 * * Linear = ----------------------------------------------------------
404 * AL_MAX_DISTANCE - AL_REFERENCE_DISTANCE
405 *
406 * / distance \ -AL_ROLLOFF_FACTOR
407 * * Exponential = | --------------------- |
408 * \ AL_REFERENCE_DISTANCE /
409 *
410 *
411 * Some values:
412 *
413 * model falloff reference 100 1000 5000 10000
414 * linear 1 500 1.000 0.947 0.526 0.000
415 * inverse 1 500 1.000 0.500 0.100 0.050
416 * exponent 1 500 1.000 0.500 0.100 0.050
417 * inverse 0.5 500 1.000 0.667 0.182 0.095
418 * exponent 0.5 500 1.000 0.707 0.316 0.223
419 * inverse 2 500 1.000 0.333 0.052 0.026
420 * exponent 2 500 1.000 0.250 0.010 0.003
421 */
422 alSourcef( s, AL_REFERENCE_DISTANCE,
423 SOUND_REFERENCE_DISTANCE ); /* Close distance to clamp at
424 (doesn't get louder). */
425 alSourcef( s, AL_MAX_DISTANCE,
426 SOUND_MAX_DISTANCE ); /* Max distance to clamp at (doesn't get
427 quieter). */
428 alSourcef( s, AL_ROLLOFF_FACTOR, 1. ); /* Determines how it drops off. */
429
430 /* Set the filter. */
431 if ( al_info.efx == AL_TRUE )
432 alSource3i( s, AL_AUXILIARY_SEND_FILTER, sound_efx_directSlot, 0,
433 AL_FILTER_NULL );
434
435 /* Check for error. */
436 if ( alGetError() == AL_NO_ERROR )
438 else
439 break;
440 }
441
442 if ( source_nstack == 0 ) {
443 WARN( _( "OpenAL failed to initialize sources" ) );
444 source_mstack = 0;
445 free( source_stack );
446 source_stack = NULL;
447 } else {
448 /* Reduce ram usage. */
450 source_stack = realloc( source_stack, sizeof( ALuint ) * source_mstack );
451 /* Copy allocated sources to total stack. */
453 source_total = malloc( sizeof( ALuint ) * source_mstack );
454 memcpy( source_total, source_stack, sizeof( ALuint ) * source_mstack );
455
456 /* Copy allocated sources to all stack. */
458 source_all = malloc( sizeof( ALuint ) * source_mstack );
459 memcpy( source_all, source_stack, sizeof( ALuint ) * source_mstack );
460 }
461
462 /* Set up how sound works. */
463 alDistanceModel(
464 AL_INVERSE_DISTANCE_CLAMPED ); /* Clamping is fundamental so it doesn't
465 sound like crap. */
466 sound_env( SOUND_ENV_NORMAL, 0. );
467
468 /* Check for errors. */
469 al_checkErr();
470
471 /* we can unlock now */
472 soundUnlock();
473
474 /* debug magic */
475 DEBUG( _( "OpenAL started: %d Hz" ), al_info.freq );
476 DEBUG( _( "Renderer: %s" ), alGetString( AL_RENDERER ) );
477 if ( al_info.efx )
478 DEBUG( _( "Version: %s with EFX %d.%d" ), alGetString( AL_VERSION ),
479 al_info.efx_major, al_info.efx_minor );
480 else
481 DEBUG( _( "Version: %s without EFX" ), alGetString( AL_VERSION ) );
482 DEBUG_BLANK();
483
484 return ret;
485
486 /*
487 * error handling
488 */
489snderr_act:
490 alcDestroyContext( al_context );
491snderr_ctx:
492 al_context = NULL;
493 alcCloseDevice( al_device );
494snderr_dev:
495 al_device = NULL;
496 soundUnlock();
497 SDL_DestroyMutex( sound_lock );
498 sound_lock = NULL;
499 return ret;
500}
501
507static int al_enableEFX( void )
508{
509 /* Issues with ALSOFT 1.19.1 crashes so we work around it.
510 * TODO: Disable someday. */
511 if ( strcmp( alGetString( AL_VERSION ), "1.1 ALSOFT 1.19.1" ) == 0 ) {
512 DEBUG( _( "Crashing ALSOFT version detected, disabling EFX" ) );
513 al_info.efx = AL_FALSE;
514 return -1;
515 }
516
517 /* Get general information. */
518 alcGetIntegerv( al_device, ALC_MAX_AUXILIARY_SENDS, 1,
519 &al_info.efx_auxSends );
520 alcGetIntegerv( al_device, ALC_EFX_MAJOR_VERSION, 1, &al_info.efx_major );
521 alcGetIntegerv( al_device, ALC_EFX_MINOR_VERSION, 1, &al_info.efx_minor );
522
523 /* Get function pointers. */
524 nalGenAuxiliaryEffectSlots = alGetProcAddress( "alGenAuxiliaryEffectSlots" );
525 nalDeleteAuxiliaryEffectSlots =
526 alGetProcAddress( "alDeleteAuxiliaryEffectSlots" );
527 nalIsAuxiliaryEffectSlot = alGetProcAddress( "alIsAuxiliaryEffectSlot" );
528 nalAuxiliaryEffectSloti = alGetProcAddress( "alAuxiliaryEffectSloti" );
529 nalAuxiliaryEffectSlotiv = alGetProcAddress( "alAuxiliaryEffectSlotiv" );
530 nalAuxiliaryEffectSlotf = alGetProcAddress( "alAuxiliaryEffectSlotf" );
531 nalAuxiliaryEffectSlotfv = alGetProcAddress( "alAuxiliaryEffectSlotfv" );
532 nalGetAuxiliaryEffectSloti = alGetProcAddress( "alGetAuxiliaryEffectSloti" );
533 nalGetAuxiliaryEffectSlotiv =
534 alGetProcAddress( "alGetAuxiliaryEffectSlotiv" );
535 nalGetAuxiliaryEffectSlotf = alGetProcAddress( "alGetAuxiliaryEffectSlotf" );
536 nalGetAuxiliaryEffectSlotfv =
537 alGetProcAddress( "alGetAuxiliaryEffectSlotfv" );
538 nalGenFilters = alGetProcAddress( "alGenFilters" );
539 nalDeleteFilters = alGetProcAddress( "alDeleteFilters" );
540 nalFilteri = alGetProcAddress( "alFilteri" );
541 nalFilteriv = alGetProcAddress( "alFilteriv" );
542 nalFilterf = alGetProcAddress( "alFilterf" );
543 nalFilterfv = alGetProcAddress( "alFilterfv" );
544 nalGenEffects = alGetProcAddress( "alGenEffects" );
545 nalDeleteEffects = alGetProcAddress( "alDeleteEffects" );
546 nalEffecti = alGetProcAddress( "alEffecti" );
547 nalEffectiv = alGetProcAddress( "alEffectiv" );
548 nalEffectf = alGetProcAddress( "alEffectf" );
549 nalEffectfv = alGetProcAddress( "alEffectfv" );
550 if ( !nalGenAuxiliaryEffectSlots || !nalDeleteAuxiliaryEffectSlots ||
551 !nalIsAuxiliaryEffectSlot || !nalAuxiliaryEffectSloti ||
552 !nalAuxiliaryEffectSlotiv || !nalAuxiliaryEffectSlotf ||
553 !nalAuxiliaryEffectSlotfv || !nalGetAuxiliaryEffectSloti ||
554 !nalGetAuxiliaryEffectSlotiv || !nalGetAuxiliaryEffectSlotf ||
555 !nalGetAuxiliaryEffectSlotfv || !nalGenFilters || !nalDeleteFilters ||
556 !nalFilteri || !nalFilteriv || !nalFilterf || !nalFilterfv ||
557 !nalGenEffects || !nalDeleteEffects || !nalEffecti || !nalEffectiv ||
558 !nalEffectf || !nalEffectfv ) {
559 DEBUG( _( "OpenAL EFX functions not found, disabling EFX." ) );
560 al_info.efx = AL_FALSE;
561 return -1;
562 }
563
564 /* Create auxiliary slot. */
565 nalGenAuxiliaryEffectSlots( 1, &sound_efx_directSlot );
566
567 /* Create reverb effect. */
568 nalGenEffects( 1, &efx_reverb );
569 nalEffecti( efx_reverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB );
570 if ( alGetError() != AL_NO_ERROR ) {
571 DEBUG( _( "OpenAL Reverb not found, disabling." ) );
572 al_info.efx_reverb = AL_FALSE;
573 nalDeleteEffects( 1, &efx_reverb );
574 } else {
575 al_info.efx_reverb = AL_TRUE;
576
577 /* Set Reverb parameters. */
578 /*nalEffectf( efx_reverb, AL_REVERB_DECAY_TIME, 15. );*/
579 }
580
581 /* Create echo effect. */
582 nalGenEffects( 1, &efx_echo );
583 nalEffecti( efx_echo, AL_EFFECT_TYPE, AL_EFFECT_ECHO );
584 if ( alGetError() != AL_NO_ERROR ) {
585 DEBUG( _( "OpenAL Echo not found, disabling." ) );
586 al_info.efx_echo = AL_FALSE;
587 nalDeleteEffects( 1, &efx_echo );
588 } else {
589 al_info.efx_echo = AL_TRUE;
590
591 /* Set Echo parameters. */
592 nalEffectf( efx_echo, AL_ECHO_DELAY, 0.207 );
593 }
594
595 /* Set up the listener. */
596 alListenerf( AL_METERS_PER_UNIT, 5. );
597
598 /* Check for errors. */
599 al_checkErr();
600
601 return 0;
602}
603
609int sound_init( void )
610{
611 int ret;
612
613 /* See if sound is disabled. */
614 if ( conf.nosound ) {
615 sound_disabled = 1;
616 music_disabled = 1;
617 }
618
619 /* Parse conf. */
621 return 0;
622
623 /* Initialize sound backend. */
624 ret = sound_al_init();
625 if ( ret != 0 ) {
626 sound_disabled = 1;
627 music_disabled = 1;
628 WARN( _( "Sound disabled." ) );
629 return ret;
630 }
631
632 /* Create voice lock. */
633 voice_mutex = SDL_CreateMutex();
634 if ( voice_mutex == NULL )
635 WARN( _( "Unable to create voice mutex." ) );
636
637 /* Load available sounds. */
639
640 /* Set volume. */
641 if ( ( conf.sound > 1. ) || ( conf.sound < 0. ) ) {
642 WARN( _( "Sound has invalid value, clamping to [0:1]." ) );
643 conf.sound = CLAMP( 0., 1., conf.sound );
644 }
645 sound_volume( conf.sound );
646
647 /* Initialized. */
649
650 /* Initialize music. */
651 ret = music_init();
652 if ( ret != 0 ) {
653 music_disabled = 1;
654 WARN( _( "Music disabled." ) );
655 }
656
657 /* Load compression noise. */
658 snd_compression = sound_get( "compression" );
659 if ( snd_compression >= 0 ) {
662 }
663
664 return 0;
665}
666
670void sound_exit( void )
671{
672 /* Nothing to disable. */
674 return;
675
676 if ( voice_mutex != NULL ) {
677 voiceLock();
678 /* free the voices. */
679 while ( voice_active != NULL ) {
681 voice_active = v->next;
682 free( v );
683 }
684 while ( voice_pool != NULL ) {
685 alVoice *v = voice_pool;
686 voice_pool = v->next;
687 free( v );
688 }
689 voiceUnlock();
690
691 /* Destroy voice lock. */
692 SDL_DestroyMutex( voice_mutex );
693 voice_mutex = NULL;
694 }
695
696 soundLock();
697
698 /* Free groups. */
699 for ( int i = 0; i < al_ngroups; i++ ) {
700 alGroup_t *g = &al_groups[i];
701 free( g->sources );
702 g->sources = NULL;
703 g->nsources = 0;
704 }
705 free( al_groups );
706 al_groups = NULL;
707 al_ngroups = 0;
708
709 /* Free stacks. */
710 if ( source_all != NULL ) {
711 alSourceStopv( source_nall, source_all );
712 alDeleteSources( source_nall, source_all );
713 free( source_all );
714 }
715 source_all = NULL;
716 source_nall = 0;
717 free( source_total );
718 source_total = NULL;
719 source_ntotal = 0;
720 free( source_stack );
721 source_stack = NULL;
722 source_nstack = 0;
723 source_mstack = 0;
724
725 /* free the sounds */
726 for ( int i = 0; i < array_size( sound_list ); i++ )
727 sound_free( &sound_list[i] );
729
730 /* Clean up EFX stuff. */
731 if ( al_info.efx == AL_TRUE ) {
732 nalDeleteAuxiliaryEffectSlots( 1, &sound_efx_directSlot );
733 if ( al_info.efx_reverb == AL_TRUE )
734 nalDeleteEffects( 1, &efx_reverb );
735 if ( al_info.efx_echo == AL_TRUE )
736 nalDeleteEffects( 1, &efx_echo );
737 }
738
739 /* Clean up global stuff. */
740 if ( al_context ) {
741 alcMakeContextCurrent( NULL );
742 alcDestroyContext( al_context );
743 }
744 if ( al_device )
745 alcCloseDevice( al_device );
746
747 soundUnlock();
748
749 SDL_DestroyMutex( sound_lock );
750
751 /* Sound is done. */
753}
754
761int sound_get( const char *name )
762{
763 if ( sound_disabled )
764 return 0;
765
766 for ( int i = 0; i < array_size( sound_list ); i++ )
767 if ( strcmp( name, sound_list[i].name ) == 0 )
768 return i;
769
770 WARN( _( "Sound '%s' not found in sound list" ), name );
771 return -1;
772}
773
780double sound_getLength( int sound )
781{
782 if ( sound_disabled )
783 return 0.;
784
785 return sound_list[sound].length;
786}
787
794int sound_play( int sound )
795{
796 alVoice *v;
797 alSound *s;
798
799 if ( sound_disabled )
800 return 0;
801
802 if ( ( sound < 0 ) || ( sound >= array_size( sound_list ) ) )
803 return -1;
804
805 /* Gets a new voice. */
806 v = voice_new();
807
808 /* Get the sound. */
809 s = &sound_list[sound];
810
811 /* Try to play the sound. */
812 if ( al_playVoice( v, s, 0., 0., 0., 0., AL_TRUE ) )
813 return -1;
814
815 /* Set state and add to list. */
816 v->state = VOICE_PLAYING;
817 v->id = ++voice_genid;
818 voice_add( v );
819 return v->id;
820}
821
832int sound_playPos( int sound, double px, double py, double vx, double vy )
833{
834 alVoice *v;
835 alSound *s;
836 Pilot *p;
837 double cx, cy;
838 int target;
839
840 if ( sound_disabled )
841 return 0;
842
843 if ( ( sound < 0 ) || ( sound >= array_size( sound_list ) ) )
844 return -1;
845
846 target = cam_getTarget();
847
848 /* Following a pilot. */
849 p = pilot_get( target );
850 if ( target && ( p != NULL ) ) {
851 if ( !pilot_inRange( p, px, py ) )
852 return 0;
853 }
854 /* Set to a position. */
855 else {
856 double dist;
857 cam_getPos( &cx, &cy );
858 dist = pow2( px - cx ) + pow2( py - cy );
859 if ( dist > pilot_sensorRange() )
860 return 0;
861 }
862
863 /* Gets a new voice. */
864 v = voice_new();
865
866 /* Get the sound. */
867 s = &sound_list[sound];
868
869 /* Try to play the sound. */
870 if ( al_playVoice( v, s, px, py, vx, vy, AL_FALSE ) )
871 return -1;
872
873 /* Actually add the voice to the list. */
874 v->state = VOICE_PLAYING;
875 v->id = ++voice_genid;
876 voice_add( v );
877
878 return v->id;
879}
880
890int sound_updatePos( int voice, double px, double py, double vx, double vy )
891{
892 alVoice *v;
893
894 if ( sound_disabled )
895 return 0;
896
897 v = voice_get( voice );
898 if ( v == NULL )
899 return 0;
900
901 /* Update the voice. */
902 v->pos[0] = px;
903 v->pos[1] = py;
904 v->vel[0] = vx;
905 v->vel[1] = vy;
906 return 0;
907}
908
914int sound_update( double dt )
915{
916 unsigned int t = SDL_GetTicks();
917
918 /* Update music if needed. */
919 music_update( dt );
920
921 if ( sound_disabled )
922 return 0;
923
924 /* System update. */
925 for ( int i = 0; i < al_ngroups; i++ ) {
926 unsigned int f;
927 alGroup_t *g = &al_groups[i];
928 /* Handle fadeout. */
929 if ( g->state != VOICE_FADEOUT )
930 continue;
931
932 /* Calculate fadeout. */
933 f = t - g->fade_timer;
934 if ( f < SOUND_FADEOUT ) {
935 ALfloat d, v;
936 d = 1. - (ALfloat)f / (ALfloat)SOUND_FADEOUT;
937 v = d * svolume * g->volume;
938 if ( g->speed )
939 v *= svolume_speed;
940 soundLock();
941 for ( int j = 0; j < g->nsources; j++ )
942 alSourcef( g->sources[j], AL_GAIN, v );
943 /* Check for errors. */
944 al_checkErr();
945 soundUnlock();
946 }
947 /* Fadeout done. */
948 else {
949 ALfloat v;
950 soundLock();
951 v = svolume * g->volume;
952 if ( g->speed )
953 v *= svolume_speed;
954 for ( int j = 0; j < g->nsources; j++ ) {
955 alSourceStop( g->sources[j] );
956 alSourcei( g->sources[j], AL_BUFFER, AL_NONE );
957 alSourcef( g->sources[j], AL_GAIN, v );
958 }
959 /* Check for errors. */
960 al_checkErr();
961 soundUnlock();
962
963 /* Mark as done. */
964 g->state = VOICE_PLAYING;
965 }
966 }
967
968 if ( voice_active == NULL )
969 return 0;
970
971 voiceLock();
972
973 /* The actual control loop. */
974 for ( alVoice *v = voice_active; v != NULL; v = v->next ) {
975
976 /* Run first to clear in same iteration. */
977 al_updateVoice( v );
978
979 /* Destroy and toss into pool. */
980 if ( ( v->state == VOICE_STOPPED ) || ( v->state == VOICE_DESTROY ) ) {
981 /* Remove from active list. */
982 alVoice *tv = v->prev;
983 if ( tv == NULL ) {
984 voice_active = v->next;
985 if ( voice_active != NULL )
986 voice_active->prev = NULL;
987 } else {
988 tv->next = v->next;
989 if ( tv->next != NULL )
990 tv->next->prev = tv;
991 }
992
993 /* Add to free pool. */
994 v->next = voice_pool;
995 v->prev = NULL;
996 voice_pool = v;
997 if ( v->next != NULL )
998 v->next->prev = v;
999
1000 /* Avoid loop blockage. */
1001 v = ( tv != NULL ) ? tv->next : voice_active;
1002 if ( v == NULL )
1003 break;
1004 }
1005 }
1006
1007 voiceUnlock();
1008
1009 return 0;
1010}
1011
1015void sound_pause( void )
1016{
1017 if ( sound_disabled )
1018 return;
1019
1020 soundLock();
1022 al_checkErr();
1023 soundUnlock();
1024
1025 if ( snd_compression >= 0 )
1027}
1028
1032void sound_resume( void )
1033{
1034 if ( sound_disabled )
1035 return;
1036
1037 soundLock();
1039 al_checkErr();
1040 soundUnlock();
1041
1042 if ( snd_compression >= 0 )
1044}
1045
1049void sound_stopAll( void )
1050{
1051 if ( sound_disabled )
1052 return;
1053
1054 /* Make sure there are voices. */
1055 if ( voice_active == NULL )
1056 return;
1057
1058 voiceLock();
1059 for ( alVoice *v = voice_active; v != NULL; v = v->next ) {
1060 if ( ( v->state == VOICE_STOPPED ) || ( v->state == VOICE_DESTROY ) )
1061 continue;
1062 if ( v->source != 0 ) {
1063 /* TODO not sure if we want to move the locks outside of the loop.
1064 * Worried it might deadlock somewhere. */
1065 soundLock();
1066 alSourceStop( v->source );
1067 al_checkErr();
1068 soundUnlock();
1069 }
1070 v->state = VOICE_STOPPED;
1071 }
1072 voiceUnlock();
1073}
1074
1080void sound_stop( int voice )
1081{
1082 alVoice *v;
1083
1084 if ( sound_disabled )
1085 return;
1086
1087 v = voice_get( voice );
1088 if ( v == NULL )
1089 return;
1090
1091 if ( ( v->state == VOICE_STOPPED ) || ( v->state == VOICE_DESTROY ) )
1092 return;
1093
1094 if ( v->source != 0 ) {
1095 soundLock();
1096 alSourceStop( v->source );
1097 al_checkErr();
1098 soundUnlock();
1099 }
1100 v->state = VOICE_STOPPED;
1101}
1102
1115int sound_updateListener( double dir, double px, double py, double vx,
1116 double vy )
1117{
1118 ALfloat ori[6], pos[3], vel[3];
1119 double c, s;
1120
1121 if ( sound_disabled )
1122 return 0;
1123
1124 c = cos( dir );
1125 s = sin( dir );
1126
1127 soundLock();
1128
1129 ori[0] = c;
1130 ori[1] = s;
1131 ori[2] = 0.;
1132 ori[3] = 0.;
1133 ori[4] = 0.;
1134 ori[5] = 1.;
1135 alListenerfv( AL_ORIENTATION, ori );
1136 pos[0] = px;
1137 pos[1] = py;
1138 pos[2] = 100.;
1139 alListenerfv( AL_POSITION, pos );
1140 vel[0] = vx;
1141 vel[1] = vy;
1142 vel[2] = 0.;
1143 alListenerfv( AL_VELOCITY, vel );
1144
1145 /* Check for errors. */
1146 al_checkErr();
1147
1148 soundUnlock();
1149
1150 return 0;
1151}
1152
1158void sound_setSpeed( double s )
1159{
1160 double v;
1161 int playing;
1162
1163 if ( sound_disabled )
1164 return;
1165
1166 /* We implement the brown noise here. */
1167 playing = ( snd_compression_gain > 0. );
1168 v = CLAMP( 0, 1., ( s - 2 ) / 10. );
1169
1170 if ( v > 0. ) {
1171 if ( snd_compression >= 0 ) {
1172 if ( !playing )
1174 0 ); /* Start playing only if it's not playing. */
1176 }
1177 svolume_speed = 1. - v;
1179 } else if ( playing ) {
1180 if ( snd_compression >= 0 )
1181 sound_stopGroup( snd_compressionG ); /* Stop compression sound. */
1182 svolume_speed = 1.;
1184 }
1186
1187 soundLock();
1188 sound_speed = s; /* Set the speed. */
1189 /* Do all the groupless. */
1190 for ( int i = 0; i < source_ntotal; i++ )
1191 alSourcef( source_total[i], AL_PITCH, s );
1192 /* Do specific groups. */
1193 for ( int i = 0; i < al_ngroups; i++ ) {
1194 alGroup_t *g = &al_groups[i];
1195 if ( !g->speed )
1196 continue;
1197 for ( int j = 0; j < g->nsources; j++ )
1198 alSourcef( g->sources[j], AL_PITCH, s * g->pitch );
1199 }
1200 /* Check for errors. */
1201 al_checkErr();
1202 soundUnlock();
1203}
1204
1208static int sound_makeList( void )
1209{
1210 char **files;
1211 int suflen;
1212
1213 if ( sound_disabled )
1214 return 0;
1215
1216 /* get the file list */
1217 files = PHYSFS_enumerateFiles( SOUND_PATH );
1218
1219 /* Create the list. */
1221
1222 /* load the profiles */
1223 suflen = strlen( SOUND_SUFFIX_WAV );
1224 for ( size_t i = 0; files[i] != NULL; i++ ) {
1225 int len;
1226 char path[PATH_MAX];
1227 SDL_RWops *rw;
1228 int flen = strlen( files[i] );
1229
1230 /* Must be longer than suffix. */
1231 if ( flen < suflen )
1232 continue;
1233
1234 /* Make sure is wav or ogg. */
1235 if ( ( strncmp( &files[i][flen - suflen], SOUND_SUFFIX_WAV, suflen ) !=
1236 0 ) &&
1237 ( strncmp( &files[i][flen - suflen], SOUND_SUFFIX_OGG, suflen ) !=
1238 0 ) )
1239 continue;
1240
1241 /* Load the sound. */
1242 snprintf( path, sizeof( path ), SOUND_PATH "%s", files[i] );
1243 rw = PHYSFSRWOPS_openRead( path );
1244
1245 /* remove the suffix */
1246 len = flen - suflen;
1247 files[i][len] = '\0';
1248
1249 source_newRW( rw, files[i], 0 );
1250 SDL_RWclose( rw );
1251 }
1252
1253 DEBUG( n_( "Loaded %d Sound", "Loaded %d Sounds", array_size( sound_list ) ),
1255
1256 /* Clean up. */
1257 PHYSFS_freeList( files );
1258
1259 return 0;
1260}
1261
1268int sound_volume( const double vol )
1269{
1270 if ( sound_disabled )
1271 return 0;
1272
1273 /* Calculate volume level. */
1274 svolume_lin = vol;
1275 if ( vol > 0. ) /* Floor of -48 dB (0.00390625 amplitude) */
1276 svolume = (ALfloat)1. / pow( 2., ( 1. - vol ) * 8. );
1277 else
1278 svolume = 0.;
1279
1280 /* Update volume. */
1282
1283 return 0;
1284}
1285
1291double sound_getVolume( void )
1292{
1293 if ( sound_disabled )
1294 return 0.;
1295
1296 return svolume_lin;
1297}
1298
1305{
1306 if ( sound_disabled )
1307 return 0.;
1308
1309 return svolume;
1310}
1311
1317static void sound_free( alSound *snd )
1318{
1319 /* Free general stuff. */
1320 free( snd->name );
1321 free( snd->filename );
1322
1323 /* Free internals. */
1324 soundLock();
1325
1326 alDeleteBuffers( 1, &snd->buf );
1327 al_checkErr();
1328
1329 soundUnlock();
1330}
1331
1338int sound_createGroup( int size )
1339{
1340 alGroup_t *g;
1341 int id;
1342
1343 if ( sound_disabled )
1344 return 0;
1345
1346 /* Get new ID. */
1347 id = ++al_groupidgen;
1348
1349 /* Grow group list. */
1350 al_ngroups++;
1351 al_groups = realloc( al_groups, sizeof( alGroup_t ) * al_ngroups );
1352 g = &al_groups[al_ngroups - 1];
1353 memset( g, 0, sizeof( alGroup_t ) );
1354 g->id = id;
1355 g->state = VOICE_PLAYING;
1356 g->speed = 1;
1357 g->volume = 1.;
1358 g->pitch = 1.;
1359
1360 /* Allocate sources. */
1361 g->sources = calloc( size, sizeof( ALuint ) );
1362 g->nsources = size;
1363
1364 /* Add some sources. */
1365 for ( int i = 0; i < size; i++ ) {
1366 /* Make sure there's enough. */
1367 if ( source_nstack <= 0 )
1368 goto group_err;
1369
1370 /* Pull one off the stack. */
1371 source_nstack--;
1372 g->sources[i] = source_stack[source_nstack];
1373
1374 /* Disable EFX, they don't affect groups. */
1375 if ( al_info.efx_reverb == AL_TRUE ) {
1376 alSourcef( g->sources[i], AL_AIR_ABSORPTION_FACTOR, 0. );
1377 alSource3i( g->sources[i], AL_AUXILIARY_SEND_FILTER,
1378 AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL );
1379 }
1380
1381 /* Remove from total too. */
1382 for ( int j = 0; j < source_ntotal; j++ ) {
1383 if ( g->sources[i] == source_total[j] ) {
1384 source_ntotal--;
1385 memmove( &source_total[j], &source_total[j + 1],
1386 sizeof( ALuint ) * ( source_ntotal - j ) );
1387 break;
1388 }
1389 }
1390 }
1391
1392 al_checkErr();
1393 return id;
1394
1395group_err:
1396 free( g->sources );
1397 al_ngroups--;
1398 al_checkErr();
1399 return 0;
1400}
1401
1410int sound_playGroup( int group, int sound, int once )
1411{
1412 alSound *s;
1413
1414 if ( sound_disabled )
1415 return 0;
1416
1417 if ( ( sound < 0 ) || ( sound >= array_size( sound_list ) ) )
1418 return -1;
1419
1420 s = &sound_list[sound];
1421 for ( int i = 0; i < al_ngroups; i++ ) {
1422 alGroup_t *g;
1423
1424 /* Find group. */
1425 if ( al_groups[i].id != group )
1426 continue;
1427
1428 g = &al_groups[i];
1429 g->state = VOICE_PLAYING;
1430 soundLock();
1431 for ( int j = 0; j < g->nsources; j++ ) {
1432 double v;
1433 ALint state;
1434 alGetSourcei( g->sources[j], AL_SOURCE_STATE, &state );
1435
1436 /* No free ones, just smash the last one. */
1437 if ( j == g->nsources - 1 ) {
1438 if ( state != AL_STOPPED )
1439 alSourceStop( g->sources[j] );
1440 }
1441 /* Ignore playing/paused. */
1442 else if ( ( state == AL_PLAYING ) || ( state == AL_PAUSED ) )
1443 continue;
1444
1445 /* Attach buffer. */
1446 alSourcei( g->sources[j], AL_BUFFER, s->buf );
1447
1448 /* Do not do positional sound. */
1449 alSourcei( g->sources[j], AL_SOURCE_RELATIVE, AL_TRUE );
1450
1451 /* See if should loop. */
1452 alSourcei( g->sources[j], AL_LOOPING, ( once ) ? AL_FALSE : AL_TRUE );
1453
1454 /* Set volume. */
1455 v = svolume * g->volume;
1456 if ( g->speed )
1457 v *= svolume_speed;
1458 alSourcef( g->sources[j], AL_GAIN, v );
1459
1460 /* Start playing. */
1461 alSourcePlay( g->sources[j] );
1462
1463 /* Check for errors. */
1464 al_checkErr();
1465
1466 soundUnlock();
1467 return 0;
1468 }
1469 al_checkErr();
1470 soundUnlock();
1471
1472 /* Group matched but no free source found.. */
1473 WARN( _( "Group '%d' has no free sounds." ), group );
1474 return -1;
1475 }
1476
1477 WARN( _( "Group '%d' not found." ), group );
1478 return -1;
1479}
1480
1486void sound_stopGroup( int group )
1487{
1488 alGroup_t *g;
1489
1490 if ( sound_disabled )
1491 return;
1492
1493 g = al_getGroup( group );
1494 if ( g == NULL )
1495 return;
1496
1497 g->state = VOICE_FADEOUT;
1498 g->fade_timer = SDL_GetTicks();
1499}
1500
1506void sound_pauseGroup( int group )
1507{
1508 alGroup_t *g;
1509
1510 if ( sound_disabled )
1511 return;
1512
1513 g = al_getGroup( group );
1514 if ( g == NULL )
1515 return;
1516
1517 soundLock();
1518 al_pausev( g->nsources, g->sources );
1519 al_checkErr();
1520 soundUnlock();
1521}
1522
1528void sound_resumeGroup( int group )
1529{
1530 alGroup_t *g;
1531
1532 if ( sound_disabled )
1533 return;
1534
1535 g = al_getGroup( group );
1536 if ( g == NULL )
1537 return;
1538
1539 soundLock();
1540 al_resumev( g->nsources, g->sources );
1541 al_checkErr();
1542 soundUnlock();
1543}
1544
1545static void groupSpeedReset( alGroup_t *g )
1546{
1547 for ( int i = 0; i < g->nsources; i++ ) {
1548 if ( g->speed )
1549 alSourcef( g->sources[i], AL_PITCH, sound_speed * g->pitch );
1550 else
1551 alSourcef( g->sources[i], AL_PITCH, 1. );
1552 }
1553}
1560void sound_speedGroup( int group, int enable )
1561{
1562 alGroup_t *g;
1563
1564 if ( sound_disabled )
1565 return;
1566
1567 g = al_getGroup( group );
1568 if ( g == NULL )
1569 return;
1570
1571 soundLock();
1572 g->speed = enable;
1573 groupSpeedReset( g );
1574 al_checkErr();
1575 soundUnlock();
1576}
1577
1584void sound_volumeGroup( int group, double volume )
1585{
1586 double v;
1587 alGroup_t *g;
1588
1589 if ( sound_disabled )
1590 return;
1591
1592 g = al_getGroup( group );
1593 if ( g == NULL )
1594 return;
1595
1596 g->volume = volume;
1597
1598 soundLock();
1599 v = svolume * g->volume;
1600 if ( g->speed )
1601 v *= svolume_speed;
1602 for ( int j = 0; j < g->nsources; j++ )
1603 alSourcef( g->sources[j], AL_GAIN, v );
1604 al_checkErr();
1605 soundUnlock();
1606}
1607
1614void sound_pitchGroup( int group, double pitch )
1615{
1616 alGroup_t *g;
1617
1618 if ( sound_disabled )
1619 return;
1620
1621 g = al_getGroup( group );
1622 if ( g == NULL )
1623 return;
1624
1625 soundLock();
1626 g->pitch = pitch;
1627 groupSpeedReset( g );
1628 al_checkErr();
1629 soundUnlock();
1630}
1631
1632void sound_setAbsorption( double value )
1633{
1634 if ( sound_disabled )
1635 return;
1636
1637 soundLock();
1638 for ( int i = 0; i < source_ntotal; i++ ) {
1639 ALuint s = source_total[i];
1640 /* Value is from 0. (normal) to 10..
1641 * It represents the attenuation per meter. In this case it decreases by
1642 * 0.05*AB_FACTOR dB/meter where AB_FACTOR is the air absorption factor.
1643 * In our case each pixel represents 5 meters.
1644 */
1645 alSourcef( s, AL_AIR_ABSORPTION_FACTOR, value );
1646 }
1647 al_checkErr();
1648 soundUnlock();
1649}
1650
1658int sound_env( SoundEnv_t env_type, double param )
1659{
1660 ALfloat f;
1661
1662 if ( sound_disabled )
1663 return 0;
1664
1665 soundLock();
1666 switch ( env_type ) {
1667 case SOUND_ENV_NORMAL:
1668 /* Set global parameters. */
1669 alSpeedOfSound( 3433. );
1670 alDopplerFactor( 0.3 );
1671
1672 if ( al_info.efx == AL_TRUE ) {
1673 /* Disconnect the effect. */
1674 nalAuxiliaryEffectSloti( sound_efx_directSlot, AL_EFFECTSLOT_EFFECT,
1675 AL_EFFECT_NULL );
1676
1677 /* Set per-source parameters. */
1678 sound_setAbsorption( 0. );
1679 }
1680 break;
1681
1682 case SOUND_ENV_NEBULA:
1683 f = param / 1000.;
1684
1685 /* Set global parameters. */
1686 alSpeedOfSound( 3433. / ( 1. + f * 2. ) );
1687 alDopplerFactor( 1.0 );
1688
1689 if ( al_info.efx == AL_TRUE ) {
1690 if ( al_info.efx_reverb == AL_TRUE ) {
1691 /* Tweak the reverb. */
1692 nalEffectf( efx_reverb, AL_REVERB_DECAY_TIME, 10. );
1693 nalEffectf( efx_reverb, AL_REVERB_DECAY_HFRATIO, 0.5 );
1694
1695 /* Connect the effect. */
1696 nalAuxiliaryEffectSloti( sound_efx_directSlot, AL_EFFECTSLOT_EFFECT,
1697 efx_reverb );
1698 }
1699
1700 /* Set per-source parameters. */
1701 sound_setAbsorption( 3. * f );
1702 }
1703 break;
1704 }
1705
1706 /* Check for errors. */
1707 al_checkErr();
1708
1709 soundUnlock();
1710
1711 return 0;
1712}
1713
1720{
1721 alVoice *v;
1722
1723 /* No free voices, allocate a new one. */
1724 if ( voice_pool == NULL ) {
1725 v = calloc( 1, sizeof( alVoice ) );
1726 voice_pool = v;
1727 return v;
1728 }
1729
1730 /* First free voice. */
1731 v = voice_pool; /* We do not touch the next nor prev, it's still in the pool.
1732 */
1733 return v;
1734}
1735
1743{
1744 alVoice *tv;
1745
1746 /* Remove from pool. */
1747 if ( v->prev != NULL ) {
1748 tv = v->prev;
1749 tv->next = v->next;
1750 if ( tv->next != NULL )
1751 tv->next->prev = tv;
1752 } else { /* Set pool to be the next. */
1753 voice_pool = v->next;
1754 if ( voice_pool != NULL )
1755 voice_pool->prev = NULL;
1756 }
1757
1758 /* Insert to the front of active voices. */
1759 voiceLock();
1760 tv = voice_active;
1761 v->next = tv;
1762 v->prev = NULL;
1763 voice_active = v;
1764 if ( tv != NULL )
1765 tv->prev = v;
1766 voiceUnlock();
1767 return 0;
1768}
1769
1777{
1778 alVoice *v;
1779 /* Make sure there are voices. */
1780 if ( voice_active == NULL )
1781 return NULL;
1782
1783 voiceLock();
1784 for ( v = voice_active; v != NULL; v = v->next )
1785 if ( v->id == id )
1786 break;
1787 voiceUnlock();
1788
1789 return v;
1790}
1791
1795int source_newRW( SDL_RWops *rw, const char *name, unsigned int flags )
1796{
1797 int ret;
1798 alSound snd, *sndl;
1799 (void)flags;
1800
1801 if ( sound_disabled )
1802 return -1;
1803
1804 memset( &snd, 0, sizeof( alSound ) );
1805 ret = al_load( &snd, rw, name );
1806 if ( ret )
1807 return -1;
1808
1809 sndl = &array_grow( &sound_list );
1810 memcpy( sndl, &snd, sizeof( alSound ) );
1811 sndl->name = strdup( name );
1812
1813 return sndl - sound_list;
1814}
1815
1819int source_new( const char *filename, unsigned int flags )
1820{
1821 SDL_RWops *rw = PHYSFSRWOPS_openRead( filename );
1822 int id = source_newRW( rw, filename, flags );
1823 SDL_RWclose( rw );
1824 return id;
1825}
1826
1830static void al_pausev( ALint n, ALuint *s )
1831{
1832 for ( int i = 0; i < n; i++ ) {
1833 ALint state;
1834 alGetSourcei( s[i], AL_SOURCE_STATE, &state );
1835 if ( state == AL_PLAYING )
1836 alSourcePause( s[i] );
1837 }
1838}
1839
1843static void al_resumev( ALint n, ALuint *s )
1844{
1845 for ( int i = 0; i < n; i++ ) {
1846 ALint state;
1847 alGetSourcei( s[i], AL_SOURCE_STATE, &state );
1848 if ( state == AL_PAUSED )
1849 alSourcePlay( s[i] );
1850 }
1851}
1852
1856static alGroup_t *al_getGroup( int group )
1857{
1858 for ( int i = 0; i < al_ngroups; i++ ) {
1859 if ( al_groups[i].id != group )
1860 continue;
1861 return &al_groups[i];
1862 }
1863 WARN( _( "Group '%d' not found." ), group );
1864 return NULL;
1865}
1866
1875static int al_loadWav( ALuint *buf, SDL_RWops *rw )
1876{
1877 SDL_AudioSpec wav_spec;
1878 Uint32 wav_length;
1879 Uint8 *wav_buffer;
1880 ALenum format;
1881
1882 SDL_RWseek( rw, 0, SEEK_SET );
1883
1884 /* Load WAV. */
1885 if ( SDL_LoadWAV_RW( rw, 0, &wav_spec, &wav_buffer, &wav_length ) == NULL ) {
1886 WARN( _( "SDL_LoadWav_RW failed: %s" ), SDL_GetError() );
1887 return -1;
1888 }
1889
1890 /* Handle format. */
1891 switch ( wav_spec.format ) {
1892 case AUDIO_U8:
1893 case AUDIO_S8:
1894 format = ( wav_spec.channels == 1 ) ? AL_FORMAT_MONO8 : AL_FORMAT_STEREO8;
1895 break;
1896 case AUDIO_U16LSB:
1897 case AUDIO_S16LSB:
1898 format =
1899 ( wav_spec.channels == 1 ) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
1900 break;
1901 case AUDIO_U16MSB:
1902 case AUDIO_S16MSB:
1903 WARN( _( "Big endian WAVs unsupported!" ) );
1904 return -1;
1905 default:
1906 WARN( _( "Invalid WAV format!" ) );
1907 return -1;
1908 }
1909
1910 /* Load into openal. */
1911 soundLock();
1912 /* Create new buffer. */
1913 alGenBuffers( 1, buf );
1914 /* Put into the buffer. */
1915 alBufferData( *buf, format, wav_buffer, wav_length, wav_spec.freq );
1916 al_checkErr();
1917 soundUnlock();
1918
1919 /* Clean up. */
1920 SDL_FreeWAV( wav_buffer );
1921 return 0;
1922}
1923
1927static const char *vorbis_getErr( int err )
1928{
1929 switch ( err ) {
1930 case OV_EREAD:
1931 return _( "A read from media returned an error." );
1932 case OV_EFAULT:
1933 return _(
1934 "Internal logic fault; indicates a bug or heap/stack corruption." );
1935 case OV_EIMPL:
1936 return _( "Feature not implemented." );
1937 case OV_EINVAL:
1938 return _( "Either an invalid argument, or incompletely initialized "
1939 "argument passed to libvorbisfile call" );
1940 case OV_ENOTVORBIS:
1941 return _( "Bitstream is not Vorbis data." );
1942 case OV_EBADHEADER:
1943 return _( "Invalid Vorbis bitstream header." );
1944 case OV_EVERSION:
1945 return _( "Vorbis version mismatch." );
1946 case OV_EBADLINK:
1947 return _( "The given link exists in the Vorbis data stream, but is not "
1948 "decipherable due to garbage or corruption." );
1949 case OV_ENOSEEK:
1950 return _( "The given stream is not seekable." );
1951
1952 default:
1953 return _( "Unknown vorbisfile error." );
1954 }
1955}
1956
1965void rg_filter( float **pcm, long channels, long samples, void *filter_param )
1966{
1967 const rg_filter_param_t *param = filter_param;
1968 float scale_factor = param->rg_scale_factor;
1969 float max_scale = param->rg_max_scale;
1970
1971 /* Apply the gain, and any limiting necessary */
1972 if ( scale_factor > max_scale ) {
1973 for ( int i = 0; i < channels; i++ )
1974 for ( int j = 0; j < samples; j++ ) {
1975 float cur_sample = pcm[i][j] * scale_factor;
1976 /*
1977 * This is essentially the scaled hard-limiting algorithm
1978 * It looks like the soft-knee to me
1979 * I haven't found a better limiting algorithm yet...
1980 */
1981 if ( cur_sample < -0.5 )
1982 cur_sample =
1983 tanh( ( cur_sample + 0.5 ) / ( 1 - 0.5 ) ) * ( 1 - 0.5 ) -
1984 0.5;
1985 else if ( cur_sample > 0.5 )
1986 cur_sample =
1987 tanh( ( cur_sample - 0.5 ) / ( 1 - 0.5 ) ) * ( 1 - 0.5 ) +
1988 0.5;
1989 pcm[i][j] = cur_sample;
1990 }
1991 } else if ( scale_factor > 0.0 )
1992 for ( int i = 0; i < channels; i++ )
1993 for ( int j = 0; j < samples; j++ )
1994 pcm[i][j] *= scale_factor;
1995}
1996
2003static int al_loadOgg( ALuint *buf, OggVorbis_File *vf )
2004{
2005 int ret;
2006 long i;
2007 int section;
2008 vorbis_info *info;
2009 ALenum format;
2010 ogg_int64_t len;
2011 char *data;
2012 long bytes_read;
2013 vorbis_comment *vc;
2014 ALfloat track_gain_db, track_peak;
2015 char *tag;
2016 rg_filter_param_t param;
2017
2018 /* Finish opening the file. */
2019 ret = ov_test_open( vf );
2020 if ( ret ) {
2021 WARN( _( "Failed to finish loading Ogg file: %s" ),
2022 vorbis_getErr( ret ) );
2023 return -1;
2024 }
2025
2026 /* Get file information. */
2027 info = ov_info( vf, -1 );
2028 format = ( info->channels == 1 ) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
2029 len = ov_pcm_total( vf, -1 ) * info->channels * sizeof( short );
2030
2031 /* Replaygain information. */
2032 vc = ov_comment( vf, -1 );
2033 track_gain_db = 0.;
2034 track_peak = 1.;
2035 if ( ( tag = vorbis_comment_query( vc, "replaygain_track_gain", 0 ) ) )
2036 track_gain_db = atof( tag );
2037 if ( ( tag = vorbis_comment_query( vc, "replaygain_track_peak", 0 ) ) )
2038 track_peak = atof( tag );
2039 param.rg_scale_factor = pow( 10.0, ( track_gain_db + RG_PREAMP_DB ) / 20.0 );
2040 param.rg_max_scale = 1.0 / track_peak;
2041
2042 /* Allocate memory. */
2043 data = malloc( len );
2044
2045 /* Fill buffer. */
2046 i = 0;
2047 bytes_read = 1;
2048 while ( bytes_read > 0 ) {
2049 /* Fill buffer with data ibytes_read the 16 bit signed samples format. */
2050 bytes_read = ov_read_filter( vf, &data[i], 4096,
2051 ( SDL_BYTEORDER == SDL_BIG_ENDIAN ), 2, 1,
2052 &section, rg_filter, &param );
2053 if ( bytes_read == OV_HOLE || bytes_read == OV_EBADLINK ||
2054 bytes_read == OV_EINVAL ) {
2055 WARN( _( "Error reading from OGG file!" ) );
2056 continue;
2057 }
2058 i += bytes_read;
2059 }
2060
2061 soundLock();
2062 /* Create new buffer. */
2063 alGenBuffers( 1, buf );
2064 /* Put into buffer. */
2065 alBufferData( *buf, format, data, len, info->rate );
2066 al_checkErr();
2067 soundUnlock();
2068
2069 /* Clean up. */
2070 free( data );
2071 ov_clear( vf );
2072
2073 return 0;
2074}
2075
2083int sound_al_buffer( ALuint *buf, SDL_RWops *rw, const char *name )
2084{
2085 int ret;
2086 OggVorbis_File vf;
2087
2088 /* Check to see if it's an Ogg. */
2089 if ( ov_test_callbacks( rw, &vf, NULL, 0, sound_al_ovcall_noclose ) == 0 )
2090 ret = al_loadOgg( buf, &vf );
2091
2092 /* Otherwise try WAV. */
2093 else {
2094 /* Destroy the partially loaded vorbisfile. */
2095 ov_clear( &vf );
2096
2097 /* Try to load Wav. */
2098 ret = al_loadWav( buf, rw );
2099 }
2100
2101 /* Failed to load. */
2102 if ( ret != 0 ) {
2103 WARN( _( "Failed to load sound file '%s'." ), name );
2104 return ret;
2105 }
2106
2107 soundLock();
2108
2109 /* Check for errors. */
2110 al_checkErr();
2111
2112 soundUnlock();
2113
2114 return 0;
2115}
2116
2124int al_load( alSound *snd, SDL_RWops *rw, const char *name )
2125{
2126 ALint freq, bits, channels, size;
2127 int ret = sound_al_buffer( &snd->buf, rw, name );
2128 if ( ret != 0 ) {
2129 WARN( _( "Failed to load sound file '%s'." ), name );
2130 return ret;
2131 }
2132
2133 soundLock();
2134
2135 /* Get the length of the sound. */
2136 alGetBufferi( snd->buf, AL_FREQUENCY, &freq );
2137 alGetBufferi( snd->buf, AL_BITS, &bits );
2138 alGetBufferi( snd->buf, AL_CHANNELS, &channels );
2139 alGetBufferi( snd->buf, AL_SIZE, &size );
2140 if ( ( freq == 0 ) || ( bits == 0 ) || ( channels == 0 ) ) {
2141 WARN( _( "Something went wrong when loading sound file '%s'." ), name );
2142 snd->length = 0;
2143 } else
2144 snd->length = (double)size / (double)( freq * ( bits / 8 ) * channels );
2145 snd->channels = channels;
2146
2147 /* Check for errors. */
2148 al_checkErr();
2149
2150 soundUnlock();
2151
2152 return 0;
2153}
2154
2158static void al_volumeUpdate( void )
2159{
2160 soundLock();
2161 /* Do generic ones. */
2162 for ( int i = 0; i < source_ntotal; i++ )
2163 alSourcef( source_total[i], AL_GAIN, svolume * svolume_speed );
2164 /* Do specific groups. */
2165 for ( int i = 0; i < al_ngroups; i++ ) {
2166 alGroup_t *g = &al_groups[i];
2167 double v = svolume * g->volume;
2168 if ( g->speed )
2169 v *= svolume_speed;
2170 for ( int j = 0; j < g->nsources; j++ )
2171 alSourcef( g->sources[j], AL_GAIN, v );
2172 }
2173 al_checkErr();
2174 soundUnlock();
2175
2176 /* Do special effects. */
2178}
2179
2183static int al_playVoice( alVoice *v, alSound *s, ALfloat px, ALfloat py,
2184 ALfloat vx, ALfloat vy, ALint relative )
2185{
2186 ALuint source;
2187
2188 /* Make sure there's enough. */
2189 if ( source_nstack <= 0 )
2190 return 0;
2191
2192 /* Pull one off the stack. */
2193 source_nstack--;
2194 source = source_stack[source_nstack];
2195
2196 /* Set up the source and buffer. */
2197 v->source = source;
2198
2199 if ( v->source == 0 )
2200 return -1;
2201 v->buffer = s->buf;
2202
2203 soundLock();
2204
2205 /* Attach buffer. */
2206 alSourcei( v->source, AL_BUFFER, v->buffer );
2207
2208 /* Enable positional sound. */
2209 alSourcei( v->source, AL_SOURCE_RELATIVE, relative );
2210
2211#if DEBUGGING
2212 if ( ( relative == AL_FALSE ) && ( s->channels > 1 ) )
2213 WARN( _( "Sound '%s' has %d channels but is being played as positional. "
2214 "It should be mono!" ),
2215 s->name, s->channels );
2216#endif /* DEBUGGING */
2217
2218 /* Update position. */
2219 v->pos[0] = px;
2220 v->pos[1] = py;
2221 v->pos[2] = 0.;
2222 v->vel[0] = vx;
2223 v->vel[1] = vy;
2224 v->vel[2] = 0.;
2225
2226 /* Set up properties. */
2227 alSourcef( v->source, AL_GAIN, svolume * svolume_speed );
2228 alSourcefv( v->source, AL_POSITION, v->pos );
2229 alSourcefv( v->source, AL_VELOCITY, v->vel );
2230
2231 /* Defaults just in case. */
2232 alSourcei( v->source, AL_LOOPING, AL_FALSE );
2233
2234 /* Start playing. */
2235 alSourcePlay( v->source );
2236
2237 /* Check for errors. */
2238 al_checkErr();
2239
2240 soundUnlock();
2241
2242 return 0;
2243}
2244
2248int sound_al_updatePos( alVoice *v, double px, double py, double vx, double vy )
2249{
2250 v->pos[0] = px;
2251 v->pos[1] = py;
2252 v->vel[0] = vx;
2253 v->vel[1] = vy;
2254 return 0;
2255}
2256
2263{
2264 ALint state;
2265
2266 /* Invalid source, mark to delete. */
2267 if ( v->source == 0 ) {
2268 v->state = VOICE_DESTROY;
2269 return;
2270 }
2271
2272 soundLock();
2273
2274 /* Get status. */
2275 alGetSourcei( v->source, AL_SOURCE_STATE, &state );
2276 if ( state == AL_STOPPED ) {
2277
2278 /* Remove buffer so it doesn't start up again if resume is called. */
2279 alSourcei( v->source, AL_BUFFER, AL_NONE );
2280
2281 /* Check for errors. */
2282 al_checkErr();
2283
2284 soundUnlock();
2285
2286 /* Put source back on the list. */
2287 source_stack[source_nstack] = v->source;
2288 source_nstack++;
2289 v->source = 0;
2290
2291 /* Mark as stopped - erased next iteration. */
2292 v->state = VOICE_STOPPED;
2293 return;
2294 }
2295
2296 /* Set up properties. */
2297 alSourcef( v->source, AL_GAIN, svolume * svolume_speed );
2298 alSourcefv( v->source, AL_POSITION, v->pos );
2299 alSourcefv( v->source, AL_VELOCITY, v->vel );
2300
2301 /* Check for errors. */
2302 al_checkErr();
2303
2304 soundUnlock();
2305}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:122
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void cam_getPos(double *x, double *y)
Gets the camera position.
Definition camera.c:122
int cam_getTarget(void)
Returns the camera's current target.
Definition camera.c:222
int music_disabled
Definition music.c:29
void music_update(double dt)
Updates the music.
Definition music.c:68
int music_init(void)
Initializes the music subsystem.
Definition music.c:119
Header file with generic functions and naev-specifics.
#define CLAMP(a, b, x)
Definition naev.h:41
#define pow2(x)
Definition naev.h:53
#define PATH_MAX
Definition naev.h:57
void spfxL_setSpeedVolume(double v)
Sets the speed volume due to autonav and the likes.
Definition nlua_spfx.c:590
Pilot * pilot_get(unsigned int id)
Pulls a pilot out of the pilot_stack based on ID.
Definition pilot.c:640
double pilot_sensorRange(void)
Returns the default sensor range for the current system.
Definition pilot_ew.c:218
int pilot_inRange(const Pilot *p, double x, double y)
Check to see if a position is in range of the pilot.
Definition pilot_ew.c:231
static const double c[]
Definition rng.c:256
static const double d[]
Definition rng.c:263
static int al_load(alSound *snd, SDL_RWops *rw, const char *name)
Loads the sound.
Definition sound.c:2124
int sound_createGroup(int size)
Creates a sound group.
Definition sound.c:1338
static alGroup_t * al_groups
Definition sound.c:204
static void al_resumev(ALint n, ALuint *s)
Acts like alSourcePlayv but with proper checks to just resume.
Definition sound.c:1843
double sound_getVolumeLog(void)
Gets the current sound volume (logarithmic).
Definition sound.c:1304
int sound_al_buffer(ALuint *buf, SDL_RWops *rw, const char *name)
Loads the sound.
Definition sound.c:2083
static int source_nstack
Definition sound.c:184
double sound_getLength(int sound)
Gets the length of the sound buffer.
Definition sound.c:780
static int al_loadOgg(ALuint *buf, OggVorbis_File *vf)
Loads an ogg file from a tested format if possible.
Definition sound.c:2003
static void al_updateVoice(alVoice *v)
Updates the voice.
Definition sound.c:2262
static double snd_compression_gain
Definition sound.c:151
void sound_pitchGroup(int group, double pitch)
Sets the pitch of a group.
Definition sound.c:1614
void sound_resume(void)
Resumes all the sounds.
Definition sound.c:1032
static void sound_free(alSound *snd)
Frees the sound.
Definition sound.c:1317
static ALCcontext * al_context
Definition sound.c:170
void rg_filter(float **pcm, long channels, long samples, void *filter_param)
This is the filter function for the decoded Ogg Vorbis stream.
Definition sound.c:1965
void sound_resumeGroup(int group)
Resumes all the sounds in a group.
Definition sound.c:1528
double sound_getVolume(void)
Gets the current sound volume (linear).
Definition sound.c:1291
static int snd_compression
Definition sound.c:149
void sound_speedGroup(int group, int enable)
Sets whether or not the speed affects a group.
Definition sound.c:1560
static ALfloat svolume_speed
Definition sound.c:174
static int source_nall
Definition sound.c:186
static int al_loadWav(ALuint *buf, SDL_RWops *rw)
Loads a wav file from the rw if possible.
Definition sound.c:1875
static ALuint efx_reverb
Definition sound.c:193
static int al_ngroups
Definition sound.c:205
static ALfloat svolume
Definition sound.c:172
int source_newRW(SDL_RWops *rw, const char *name, unsigned int flags)
Loads a new sound source from a RWops.
Definition sound.c:1795
static int al_groupidgen
Definition sound.c:206
#define SOUND_SUFFIX_OGG
Definition sound.c:61
int sound_disabled
Definition sound.c:130
static int sound_makeList(void)
Makes the list of available sounds.
Definition sound.c:1208
static ALuint * source_total
Definition sound.c:182
static int source_mstack
Definition sound.c:187
static alVoice * voice_new(void)
Gets a new voice ready to be used.
Definition sound.c:1719
static const char * vorbis_getErr(int err)
Gets the vorbisfile error in human readable form..
Definition sound.c:1927
static alVoice * voice_pool
Definition sound.c:143
static alGroup_t * al_getGroup(int group)
Gets a group by ID.
Definition sound.c:1856
static alVoice * voice_active
Definition sound.c:142
int sound_updateListener(double dir, double px, double py, double vx, double vy)
Updates the sound listener.
Definition sound.c:1115
SDL_mutex * sound_lock
Definition sound.c:164
#define SOUND_SUFFIX_WAV
Definition sound.c:60
int sound_playPos(int sound, double px, double py, double vx, double vy)
Plays a sound based on position.
Definition sound.c:832
int sound_playGroup(int group, int sound, int once)
Plays a sound in a group.
Definition sound.c:1410
static double sound_speed
Definition sound.c:199
void sound_exit(void)
Cleans up after the sound subsytem.
Definition sound.c:670
static ALuint * source_stack
Definition sound.c:181
void sound_stopGroup(int group)
Stops all the sounds in a group.
Definition sound.c:1486
int sound_update(double dt)
Updates the sounds removing obsolete ones and such.
Definition sound.c:914
void sound_stopAll(void)
Stops all the playing voices.
Definition sound.c:1049
int source_new(const char *filename, unsigned int flags)
Loads a new source from a file.
Definition sound.c:1819
static int al_enableEFX(void)
Enables the OpenAL EFX extension.
Definition sound.c:507
static ALuint efx_echo
Definition sound.c:194
static ALfloat svolume_lin
Definition sound.c:173
ov_callbacks sound_al_ovcall_noclose
Definition sound.c:279
static ALCdevice * al_device
Definition sound.c:171
int sound_init(void)
Initializes the sound subsystem.
Definition sound.c:609
void sound_pause(void)
Pauses all the sounds.
Definition sound.c:1015
voice_state_t
The state of a voice.
Definition sound.c:84
@ VOICE_STOPPED
Definition sound.c:85
@ VOICE_FADEOUT
Definition sound.c:87
@ VOICE_DESTROY
Definition sound.c:88
@ VOICE_PLAYING
Definition sound.c:86
int sound_get(const char *name)
Gets the buffer to sound of name.
Definition sound.c:761
static SDL_mutex * voice_mutex
Definition sound.c:144
int sound_env(SoundEnv_t env_type, double param)
Sets up the sound environment.
Definition sound.c:1658
void sound_pauseGroup(int group)
Pauses all the sounds in a group.
Definition sound.c:1506
static int voice_genid
Definition sound.c:141
static void al_volumeUpdate(void)
Internal volume update function.
Definition sound.c:2158
ALuint sound_efx_directSlot
Definition sound.c:192
static alVoice * voice_get(int id)
Gets a voice by identifier.
Definition sound.c:1776
static int source_ntotal
Definition sound.c:185
alInfo_t al_info
Definition sound.c:176
static int sound_initialized
Definition sound.c:131
void sound_stop(int voice)
Stops a voice from playing.
Definition sound.c:1080
ov_callbacks sound_al_ovcall
Definition sound.c:274
#define SOUND_VOICES
Definition sound.c:56
int sound_updatePos(int voice, double px, double py, double vx, double vy)
Updates the position of a voice.
Definition sound.c:890
int sound_al_updatePos(alVoice *v, double px, double py, double vx, double vy)
Updates the position of the sound.
Definition sound.c:2248
static int voice_add(alVoice *v)
Adds a voice to the active voice stack.
Definition sound.c:1742
int sound_play(int sound)
Plays the sound in the first available channel.
Definition sound.c:794
static alSound * sound_list
Definition sound.c:136
static ALuint * source_all
Definition sound.c:183
int sound_volume(const double vol)
Sets the volume.
Definition sound.c:1268
static void al_pausev(ALint n, ALuint *s)
Acts like alSourcePausev but with proper checks.
Definition sound.c:1830
static int sound_al_init(void)
Initializes the sound subsystem.
Definition sound.c:291
void sound_volumeGroup(int group, double volume)
Sets the volume of a group.
Definition sound.c:1584
void sound_setSpeed(double s)
Sets the speed to play the sound at.
Definition sound.c:1158
static int snd_compressionG
Definition sound.c:150
static int al_playVoice(alVoice *v, alSound *s, ALfloat px, ALfloat py, ALfloat vx, ALfloat vy, ALint relative)
Plays a voice.
Definition sound.c:2183
The representation of an in-game pilot.
Definition pilot.h:263
int id
Definition sound.c:114
int fade_timer
Definition sound.c:121
double volume
Definition sound.c:123
int speed
Definition sound.c:122
int nsources
Definition sound.c:118
voice_state_t state
Definition sound.c:120
ALuint * sources
Definition sound.c:117
double pitch
Definition sound.c:124
Contains a sound buffer.
Definition sound.c:71
ALuint buf
Definition sound.c:76
char * filename
Definition sound.c:72
double length
Definition sound.c:74
int channels
Definition sound.c:75
char * name
Definition sound.c:73
Represents a voice in the game.
Definition sound.c:98
unsigned int flags
Definition sound.c:105
ALfloat pos[3]
Definition sound.c:107
ALuint buffer
Definition sound.c:110
ALuint source
Definition sound.c:109
int id
Definition sound.c:102
struct alVoice_ * prev
Definition sound.c:99
ALfloat vel[3]
Definition sound.c:108
voice_state_t state
Definition sound.c:104
struct alVoice_ * next
Definition sound.c:100