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