naev 0.11.5
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
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 /* We'll need a mutex */
303 sound_lock = SDL_CreateMutex();
304 soundLock();
305
306 /* opening the default device */
307 al_device = alcOpenDevice(NULL);
308 if (al_device == NULL) {
309 WARN(_("Unable to open default sound device"));
310 ret = -1;
311 goto snderr_dev;
312 }
313
314 /* Set good default for sources. */
315 attribs[0] = ALC_MONO_SOURCES;
316 attribs[1] = 512;
317 attribs[2] = ALC_STEREO_SOURCES;
318 attribs[3] = 32;
319 nattribs = 4;
320
321 /* Query EFX extension. */
322 if (conf.al_efx) {
323 al_info.efx = alcIsExtensionPresent( al_device, "ALC_EXT_EFX" );
324 if (al_info.efx == AL_TRUE) {
325 attribs[nattribs+0] = ALC_MAX_AUXILIARY_SENDS;
326 attribs[nattribs+1] = 4;
327 nattribs += 2;
328 }
329 }
330 else
331 al_info.efx = AL_FALSE;
332
333 /* Check more extensions. */
334 al_info.output_limiter = alcIsExtensionPresent( al_device, "ALC_SOFT_output_limiter" );
336 attribs[nattribs+0] = ALC_OUTPUT_LIMITER_SOFT;
337 attribs[nattribs+1] = ALC_TRUE;
338 nattribs += 2;
339 }
340
341 /* Create the OpenAL context */
342 al_context = alcCreateContext( al_device, attribs );
343 if (al_context == NULL) {
344 WARN(_("Unable to create OpenAL context"));
345 ret = -2;
346 goto snderr_ctx;
347 }
348
349 /* Set active context */
350 if (alcMakeContextCurrent( al_context )==AL_FALSE) {
351 WARN(_("Failure to set default context"));
352 ret = -4;
353 goto snderr_act;
354 }
355
356 /* Clear the errors */
357 alGetError();
358
359 /* Query some extensions. */
361 ALint limiter;
362 alcGetIntegerv( al_device, ALC_OUTPUT_LIMITER_SOFT, 1, &limiter );
363 if (limiter != ALC_TRUE)
364 WARN(_("Failed to set ALC_OUTPUT_LIMITER_SOFT"));
365 }
366
367 /* Get context information. */
368 alcGetIntegerv( al_device, ALC_FREQUENCY, 1, &al_info.freq );
369 alcGetIntegerv( al_device, ALC_MONO_SOURCES, 1, &al_info.nmono );
370 alcGetIntegerv( al_device, ALC_STEREO_SOURCES, 1, &al_info.nstereo );
371
372 /* Try to enable EFX. */
373 if (al_info.efx == AL_TRUE) {
374 al_enableEFX();
375 }
376 else {
377 al_info.efx_reverb = AL_FALSE;
378 al_info.efx_echo = AL_FALSE;
379 }
380
381 /* Check for errors. */
382 al_checkErr();
383
384 /* Start allocating the sources - music has already taken theirs */
385 source_nstack = 0;
387 source_stack = malloc( sizeof( ALuint ) * source_mstack );
388 while (source_nstack < SOUND_VOICES) {
389 alGenSources( 1, &s );
391
392 /* How OpenAL distance model works:
393 *
394 * Clamped:
395 * gain = distance_function( CLAMP( AL_REFERENCE_DISTANCE, AL_MAX_DISTANCE, distance ) );
396 *
397 * Distance functions:
398 * AL_REFERENCE_DISTANCE
399 * * Inverse = ------------------------------------------------------------------------------
400 * AL_REFERENCE_DISTANCE + AL_ROLLOFF_FACTOR ( distance - 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, SOUND_REFERENCE_DISTANCE ); /* Close distance to clamp at (doesn't get louder). */
423 alSourcef( s, AL_MAX_DISTANCE, SOUND_MAX_DISTANCE ); /* Max distance to clamp at (doesn't get quieter). */
424 alSourcef( s, AL_ROLLOFF_FACTOR, 1. ); /* Determines how it drops off. */
425
426 /* Set the filter. */
427 if (al_info.efx == AL_TRUE)
428 alSource3i( s, AL_AUXILIARY_SEND_FILTER, sound_efx_directSlot, 0, AL_FILTER_NULL );
429
430 /* Check for error. */
431 if (alGetError() == AL_NO_ERROR)
433 else
434 break;
435 }
436
437 if ( source_nstack == 0 ) {
438 WARN( _( "OpenAL failed to initialize sources" ) );
439 source_mstack = 0;
440 free( source_stack );
441 source_stack = NULL;
442 }
443 else {
444 /* Reduce ram usage. */
446 source_stack = realloc( source_stack, sizeof( ALuint ) * source_mstack );
447 /* Copy allocated sources to total stack. */
449 source_total = malloc( sizeof( ALuint ) * source_mstack );
450 memcpy( source_total, source_stack, sizeof( ALuint ) * source_mstack );
451
452 /* Copy allocated sources to all stack. */
454 source_all = malloc( sizeof( ALuint ) * source_mstack );
455 memcpy( source_all, source_stack, sizeof( ALuint ) * source_mstack );
456 }
457
458 /* Set up how sound works. */
459 alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED ); /* Clamping is fundamental so it doesn't sound like crap. */
460 sound_env( SOUND_ENV_NORMAL, 0. );
461
462 /* Check for errors. */
463 al_checkErr();
464
465 /* we can unlock now */
466 soundUnlock();
467
468 /* debug magic */
469 DEBUG(_("OpenAL started: %d Hz"), al_info.freq);
470 DEBUG(_("Renderer: %s"), alGetString(AL_RENDERER));
471 if (al_info.efx)
472 DEBUG(_("Version: %s with EFX %d.%d"), alGetString(AL_VERSION),
474 else
475 DEBUG(_("Version: %s without EFX"), alGetString(AL_VERSION));
476 DEBUG_BLANK();
477
478 return ret;
479
480 /*
481 * error handling
482 */
483snderr_act:
484 alcDestroyContext( al_context );
485snderr_ctx:
486 al_context = NULL;
487 alcCloseDevice( al_device );
488snderr_dev:
489 al_device = NULL;
490 soundUnlock();
491 SDL_DestroyMutex( sound_lock );
492 sound_lock = NULL;
493 return ret;
494}
495
501static int al_enableEFX (void)
502{
503 /* Issues with ALSOFT 1.19.1 crashes so we work around it.
504 * TODO: Disable someday. */
505 if (strcmp(alGetString(AL_VERSION), "1.1 ALSOFT 1.19.1")==0) {
506 DEBUG(_("Crashing ALSOFT version detected, disabling EFX"));
507 al_info.efx = AL_FALSE;
508 return -1;
509 }
510
511 /* Get general information. */
512 alcGetIntegerv( al_device, ALC_MAX_AUXILIARY_SENDS, 1, &al_info.efx_auxSends );
513 alcGetIntegerv( al_device, ALC_EFX_MAJOR_VERSION, 1, &al_info.efx_major );
514 alcGetIntegerv( al_device, ALC_EFX_MINOR_VERSION, 1, &al_info.efx_minor );
515
516 /* Get function pointers. */
517 nalGenAuxiliaryEffectSlots = alGetProcAddress( "alGenAuxiliaryEffectSlots" );
518 nalDeleteAuxiliaryEffectSlots = alGetProcAddress( "alDeleteAuxiliaryEffectSlots" );
519 nalIsAuxiliaryEffectSlot = alGetProcAddress( "alIsAuxiliaryEffectSlot" );
520 nalAuxiliaryEffectSloti = alGetProcAddress( "alAuxiliaryEffectSloti" );
521 nalAuxiliaryEffectSlotiv = alGetProcAddress( "alAuxiliaryEffectSlotiv" );
522 nalAuxiliaryEffectSlotf = alGetProcAddress( "alAuxiliaryEffectSlotf" );
523 nalAuxiliaryEffectSlotfv = alGetProcAddress( "alAuxiliaryEffectSlotfv" );
524 nalGetAuxiliaryEffectSloti = alGetProcAddress( "alGetAuxiliaryEffectSloti" );
525 nalGetAuxiliaryEffectSlotiv = alGetProcAddress( "alGetAuxiliaryEffectSlotiv" );
526 nalGetAuxiliaryEffectSlotf = alGetProcAddress( "alGetAuxiliaryEffectSlotf" );
527 nalGetAuxiliaryEffectSlotfv = alGetProcAddress( "alGetAuxiliaryEffectSlotfv" );
528 nalGenFilters = alGetProcAddress( "alGenFilters" );
529 nalDeleteFilters = alGetProcAddress( "alDeleteFilters" );
530 nalFilteri = alGetProcAddress( "alFilteri" );
531 nalFilteriv = alGetProcAddress( "alFilteriv" );
532 nalFilterf = alGetProcAddress( "alFilterf" );
533 nalFilterfv = alGetProcAddress( "alFilterfv" );
534 nalGenEffects = alGetProcAddress( "alGenEffects" );
535 nalDeleteEffects = alGetProcAddress( "alDeleteEffects" );
536 nalEffecti = alGetProcAddress( "alEffecti" );
537 nalEffectiv = alGetProcAddress( "alEffectiv" );
538 nalEffectf = alGetProcAddress( "alEffectf" );
539 nalEffectfv = alGetProcAddress( "alEffectfv" );
540 if (!nalGenAuxiliaryEffectSlots || !nalDeleteAuxiliaryEffectSlots ||
541 !nalIsAuxiliaryEffectSlot ||
542 !nalAuxiliaryEffectSloti || !nalAuxiliaryEffectSlotiv ||
543 !nalAuxiliaryEffectSlotf || !nalAuxiliaryEffectSlotfv ||
544 !nalGetAuxiliaryEffectSloti || !nalGetAuxiliaryEffectSlotiv ||
545 !nalGetAuxiliaryEffectSlotf || !nalGetAuxiliaryEffectSlotfv ||
546 !nalGenFilters || !nalDeleteFilters ||
547 !nalFilteri || !nalFilteriv || !nalFilterf || !nalFilterfv ||
548 !nalGenEffects || !nalDeleteEffects ||
549 !nalEffecti || !nalEffectiv || !nalEffectf || !nalEffectfv) {
550 DEBUG(_("OpenAL EFX functions not found, disabling EFX."));
551 al_info.efx = AL_FALSE;
552 return -1;
553 }
554
555 /* Create auxiliary slot. */
556 nalGenAuxiliaryEffectSlots( 1, &sound_efx_directSlot );
557
558 /* Create reverb effect. */
559 nalGenEffects( 1, &efx_reverb );
560 nalEffecti( efx_reverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB );
561 if (alGetError() != AL_NO_ERROR) {
562 DEBUG(_("OpenAL Reverb not found, disabling."));
563 al_info.efx_reverb = AL_FALSE;
564 nalDeleteEffects( 1, &efx_reverb );
565 }
566 else {
567 al_info.efx_reverb = AL_TRUE;
568
569 /* Set Reverb parameters. */
570 /*nalEffectf( efx_reverb, AL_REVERB_DECAY_TIME, 15. );*/
571 }
572
573 /* Create echo effect. */
574 nalGenEffects( 1, &efx_echo );
575 nalEffecti( efx_echo, AL_EFFECT_TYPE, AL_EFFECT_ECHO );
576 if (alGetError() != AL_NO_ERROR) {
577 DEBUG(_("OpenAL Echo not found, disabling."));
578 al_info.efx_echo = AL_FALSE;
579 nalDeleteEffects( 1, &efx_echo );
580 }
581 else {
582 al_info.efx_echo = AL_TRUE;
583
584 /* Set Echo parameters. */
585 nalEffectf( efx_echo, AL_ECHO_DELAY, 0.207 );
586 }
587
588 /* Set up the listener. */
589 alListenerf( AL_METERS_PER_UNIT, 5. );
590
591 /* Check for errors. */
592 al_checkErr();
593
594 return 0;
595}
596
602int sound_init (void)
603{
604 int ret;
605
606 /* See if sound is disabled. */
607 if (conf.nosound) {
608 sound_disabled = 1;
609 music_disabled = 1;
610 }
611
612 /* Parse conf. */
614 return 0;
615
616 /* Initialize sound backend. */
617 ret = sound_al_init();
618 if (ret != 0) {
619 sound_disabled = 1;
620 music_disabled = 1;
621 WARN(_("Sound disabled."));
622 return ret;
623 }
624
625 /* Create voice lock. */
626 voice_mutex = SDL_CreateMutex();
627 if (voice_mutex == NULL)
628 WARN(_("Unable to create voice mutex."));
629
630 /* Load available sounds. */
631 ret = sound_makeList();
632 if (ret != 0)
633 return ret;
634
635 /* Set volume. */
636 if ((conf.sound > 1.) || (conf.sound < 0.)) {
637 WARN(_("Sound has invalid value, clamping to [0:1]."));
638 conf.sound = CLAMP( 0., 1., conf.sound );
639 }
640 sound_volume(conf.sound);
641
642 /* Initialized. */
644
645 /* Initialize music. */
646 ret = music_init();
647 if (ret != 0) {
648 music_disabled = 1;
649 WARN(_("Music disabled."));
650 }
651
652 /* Load compression noise. */
653 snd_compression = sound_get( "compression" );
654 if (snd_compression >= 0) {
657 }
658
659 return 0;
660}
661
665void sound_exit (void)
666{
667 /* Nothing to disable. */
669 return;
670
671 if (voice_mutex != NULL) {
672 voiceLock();
673 /* free the voices. */
674 while (voice_active != NULL) {
676 voice_active = v->next;
677 free(v);
678 }
679 while (voice_pool != NULL) {
680 alVoice *v = voice_pool;
681 voice_pool = v->next;
682 free(v);
683 }
684 voiceUnlock();
685
686 /* Destroy voice lock. */
687 SDL_DestroyMutex(voice_mutex);
688 voice_mutex = NULL;
689 }
690
691 soundLock();
692
693 /* Free groups. */
694 for (int i=0; i<al_ngroups; i++) {
695 alGroup_t *g = &al_groups[i];
696 free(g->sources);
697 g->sources = NULL;
698 g->nsources = 0;
699 }
700 free(al_groups);
701 al_groups = NULL;
702 al_ngroups = 0;
703
704 /* Free stacks. */
705 if (source_all != NULL) {
706 alSourceStopv( source_nall, source_all );
707 alDeleteSources( source_nall, source_all );
708 free(source_all);
709 }
710 source_all = NULL;
711 source_nall = 0;
712 free(source_total);
713 source_total = NULL;
714 source_ntotal = 0;
715 free(source_stack);
716 source_stack = NULL;
717 source_nstack = 0;
718 source_mstack = 0;
719
720 /* free the sounds */
721 for (int i=0; i<array_size(sound_list); i++)
722 sound_free( &sound_list[i] );
724
725 /* Clean up EFX stuff. */
726 if (al_info.efx == AL_TRUE) {
727 nalDeleteAuxiliaryEffectSlots( 1, &sound_efx_directSlot );
728 if (al_info.efx_reverb == AL_TRUE)
729 nalDeleteEffects( 1, &efx_reverb );
730 if (al_info.efx_echo == AL_TRUE)
731 nalDeleteEffects( 1, &efx_echo );
732 }
733
734 /* Clean up global stuff. */
735 if (al_context) {
736 alcMakeContextCurrent(NULL);
737 alcDestroyContext( al_context );
738 }
739 if (al_device)
740 alcCloseDevice( al_device );
741
742 soundUnlock();
743
744 SDL_DestroyMutex( sound_lock );
745
746 /* Sound is done. */
748}
749
756int sound_get( const char* name )
757{
758 if (sound_disabled)
759 return 0;
760
761 for (int i=0; i<array_size(sound_list); i++)
762 if (strcmp(name, sound_list[i].name)==0)
763 return i;
764
765 WARN(_("Sound '%s' not found in sound list"), name);
766 return -1;
767}
768
775double sound_getLength( int sound )
776{
777 if (sound_disabled)
778 return 0.;
779
780 return sound_list[sound].length;
781}
782
789int sound_play( int sound )
790{
791 alVoice *v;
792 alSound *s;
793
794 if (sound_disabled)
795 return 0;
796
797 if ((sound < 0) || (sound >= array_size(sound_list)))
798 return -1;
799
800 /* Gets a new voice. */
801 v = voice_new();
802
803 /* Get the sound. */
804 s = &sound_list[sound];
805
806 /* Try to play the sound. */
807 if (al_playVoice( v, s, 0., 0., 0., 0., AL_TRUE ))
808 return -1;
809
810 /* Set state and add to list. */
811 v->state = VOICE_PLAYING;
812 v->id = ++voice_genid;
813 voice_add(v);
814 return v->id;
815}
816
827int sound_playPos( int sound, double px, double py, double vx, double vy )
828{
829 alVoice *v;
830 alSound *s;
831 Pilot *p;
832 double cx, cy, dist;
833 int target;
834
835 if (sound_disabled)
836 return 0;
837
838 if ((sound < 0) || (sound >= array_size(sound_list)))
839 return -1;
840
841 target = cam_getTarget();
842
843 /* Following a pilot. */
844 p = pilot_get(target);
845 if (target && (p != NULL)) {
846 if (!pilot_inRange( p, px, py ))
847 return 0;
848 }
849 /* Set to a position. */
850 else {
851 cam_getPos(&cx, &cy);
852 dist = pow2(px - cx) + pow2(py - cy);
853 if (dist > pilot_sensorRange())
854 return 0;
855 }
856
857 /* Gets a new voice. */
858 v = voice_new();
859
860 /* Get the sound. */
861 s = &sound_list[sound];
862
863 /* Try to play the sound. */
864 if (al_playVoice( v, s, px, py, vx, vy, AL_FALSE ))
865 return -1;
866
867 /* Actually add the voice to the list. */
868 v->state = VOICE_PLAYING;
869 v->id = ++voice_genid;
870 voice_add(v);
871
872 return v->id;
873}
874
884int sound_updatePos( int voice, double px, double py, double vx, double vy )
885{
886 alVoice *v;
887
888 if (sound_disabled)
889 return 0;
890
891 v = voice_get(voice);
892 if (v == NULL)
893 return 0;
894
895 /* Update the voice. */
896 v->pos[0] = px;
897 v->pos[1] = py;
898 v->vel[0] = vx;
899 v->vel[1] = vy;
900 return 0;
901}
902
908int sound_update( double dt )
909{
910 unsigned int t = SDL_GetTicks();
911
912 /* Update music if needed. */
913 music_update(dt);
914
915 if (sound_disabled)
916 return 0;
917
918 /* System update. */
919 for (int i=0; i<al_ngroups; i++) {
920 unsigned int f;
921 alGroup_t *g = &al_groups[i];
922 /* Handle fadeout. */
923 if (g->state != VOICE_FADEOUT)
924 continue;
925
926 /* Calculate fadeout. */
927 f = t - g->fade_timer;
928 if (f < SOUND_FADEOUT) {
929 ALfloat d, v;
930 d = 1. - (ALfloat) f / (ALfloat) SOUND_FADEOUT;
931 v = d * svolume * g->volume;
932 if (g->speed)
933 v *= svolume_speed;
934 soundLock();
935 for (int j=0; j<g->nsources; j++)
936 alSourcef( g->sources[j], AL_GAIN, v );
937 /* Check for errors. */
938 al_checkErr();
939 soundUnlock();
940 }
941 /* Fadeout done. */
942 else {
943 ALfloat v;
944 soundLock();
945 v = svolume * g->volume;
946 if (g->speed)
947 v *= svolume_speed;
948 for (int j=0; j<g->nsources; j++) {
949 alSourceStop( g->sources[j] );
950 alSourcei( g->sources[j], AL_BUFFER, AL_NONE );
951 alSourcef( g->sources[j], AL_GAIN, v );
952 }
953 /* Check for errors. */
954 al_checkErr();
955 soundUnlock();
956
957 /* Mark as done. */
958 g->state = VOICE_PLAYING;
959 }
960 }
961
962 if (voice_active == NULL)
963 return 0;
964
965 voiceLock();
966
967 /* The actual control loop. */
968 for (alVoice *v=voice_active; v!=NULL; v=v->next) {
969
970 /* Run first to clear in same iteration. */
971 al_updateVoice( v );
972
973 /* Destroy and toss into pool. */
974 if ((v->state == VOICE_STOPPED) || (v->state == VOICE_DESTROY)) {
975 /* Remove from active list. */
976 alVoice *tv = v->prev;
977 if (tv == NULL) {
978 voice_active = v->next;
979 if (voice_active != NULL)
980 voice_active->prev = NULL;
981 }
982 else {
983 tv->next = v->next;
984 if (tv->next != NULL)
985 tv->next->prev = tv;
986 }
987
988 /* Add to free pool. */
989 v->next = voice_pool;
990 v->prev = NULL;
991 voice_pool = v;
992 if (v->next != NULL)
993 v->next->prev = v;
994
995 /* Avoid loop blockage. */
996 v = (tv != NULL) ? tv->next : voice_active;
997 if (v == NULL)
998 break;
999 }
1000 }
1001
1002 voiceUnlock();
1003
1004 return 0;
1005}
1006
1010void sound_pause (void)
1011{
1012 if (sound_disabled)
1013 return;
1014
1015 soundLock();
1017 al_checkErr();
1018 soundUnlock();
1019
1020 if (snd_compression >= 0)
1022}
1023
1027void sound_resume (void)
1028{
1029 if (sound_disabled)
1030 return;
1031
1032 soundLock();
1034 al_checkErr();
1035 soundUnlock();
1036
1037 if (snd_compression >= 0)
1039}
1040
1044void sound_stopAll (void)
1045{
1046 if (sound_disabled)
1047 return;
1048
1049 /* Make sure there are voices. */
1050 if (voice_active==NULL)
1051 return;
1052
1053 voiceLock();
1054 for (alVoice *v=voice_active; v!=NULL; v=v->next) {
1055 if ((v->state == VOICE_STOPPED) || (v->state == VOICE_DESTROY))
1056 continue;
1057 if (v->source != 0) {
1058 /* TODO not sure if we want to move the locks outside of the loop. Worried it might deadlock somewhere. */
1059 soundLock();
1060 alSourceStop( v->source );
1061 al_checkErr();
1062 soundUnlock();
1063 }
1064 v->state = VOICE_STOPPED;
1065 }
1066 voiceUnlock();
1067}
1068
1074void sound_stop( int voice )
1075{
1076 alVoice *v;
1077
1078 if (sound_disabled)
1079 return;
1080
1081 v = voice_get(voice);
1082 if (v == NULL)
1083 return;
1084
1085 if ((v->state == VOICE_STOPPED) || (v->state == VOICE_DESTROY))
1086 return;
1087
1088 if (v->source != 0) {
1089 soundLock();
1090 alSourceStop( v->source );
1091 al_checkErr();
1092 soundUnlock();
1093 }
1094 v->state = VOICE_STOPPED;
1095}
1096
1109int sound_updateListener( double dir, double px, double py,
1110 double vx, double vy )
1111{
1112 ALfloat ori[6], pos[3], vel[3];
1113 double c, s;
1114
1115 if (sound_disabled)
1116 return 0;
1117
1118 c = cos(dir);
1119 s = sin(dir);
1120
1121 soundLock();
1122
1123 ori[0] = c;
1124 ori[1] = s;
1125 ori[2] = 0.;
1126 ori[3] = 0.;
1127 ori[4] = 0.;
1128 ori[5] = 1.;
1129 alListenerfv( AL_ORIENTATION, ori );
1130 pos[0] = px;
1131 pos[1] = py;
1132 pos[2] = 100.;
1133 alListenerfv( AL_POSITION, pos );
1134 vel[0] = vx;
1135 vel[1] = vy;
1136 vel[2] = 0.;
1137 alListenerfv( AL_VELOCITY, vel );
1138
1139 /* Check for errors. */
1140 al_checkErr();
1141
1142 soundUnlock();
1143
1144 return 0;
1145}
1146
1152void sound_setSpeed( double s )
1153{
1154 double v;
1155 int playing;
1156
1157 if (sound_disabled)
1158 return;
1159
1160 /* We implement the brown noise here. */
1161 playing = (snd_compression_gain > 0.);
1162 v = CLAMP( 0, 1., (s-2)/10. );
1163
1164 if (v > 0.) {
1165 if (snd_compression >= 0) {
1166 if (!playing)
1167 sound_playGroup( snd_compressionG, snd_compression, 0 ); /* Start playing only if it's not playing. */
1169 }
1170 svolume_speed = 1.-v;
1172 }
1173 else if (playing) {
1174 if (snd_compression >= 0)
1175 sound_stopGroup( snd_compressionG ); /* Stop compression sound. */
1176 svolume_speed = 1.;
1178 }
1180
1181 soundLock();
1182 sound_speed = s; /* Set the speed. */
1183 /* Do all the groupless. */
1184 for (int i=0; i<source_ntotal; i++)
1185 alSourcef( source_total[i], AL_PITCH, s );
1186 /* Do specific groups. */
1187 for (int i=0; i<al_ngroups; i++) {
1188 alGroup_t *g = &al_groups[i];
1189 if (!g->speed)
1190 continue;
1191 for (int j=0; j<g->nsources; j++)
1192 alSourcef( g->sources[j], AL_PITCH, s*g->pitch );
1193 }
1194 /* Check for errors. */
1195 al_checkErr();
1196 soundUnlock();
1197}
1198
1202static int sound_makeList (void)
1203{
1204 char** files;
1205 int suflen;
1206
1207 if (sound_disabled)
1208 return 0;
1209
1210 /* get the file list */
1211 files = PHYSFS_enumerateFiles( SOUND_PATH );
1212
1213 /* Create the list. */
1215
1216 /* load the profiles */
1217 suflen = strlen(SOUND_SUFFIX_WAV);
1218 for (size_t i=0; files[i]!=NULL; i++) {
1219 int len;
1220 char path[PATH_MAX];
1221 SDL_RWops *rw;
1222 int flen = strlen(files[i]);
1223
1224 /* Must be longer than suffix. */
1225 if (flen < suflen)
1226 continue;
1227
1228 /* Make sure is wav or ogg. */
1229 if ((strncmp( &files[i][flen - suflen], SOUND_SUFFIX_WAV, suflen)!=0) &&
1230 (strncmp( &files[i][flen - suflen], SOUND_SUFFIX_OGG, suflen)!=0))
1231 continue;
1232
1233 /* Load the sound. */
1234 snprintf( path, sizeof(path), SOUND_PATH"%s", files[i] );
1235 rw = PHYSFSRWOPS_openRead( path );
1236
1237 /* remove the suffix */
1238 len = flen - suflen;
1239 files[i][len] = '\0';
1240
1241 source_newRW( rw, files[i], 0 );
1242 SDL_RWclose( rw );
1243 }
1244
1245 DEBUG( n_("Loaded %d Sound", "Loaded %d Sounds", array_size(sound_list)), array_size(sound_list) );
1246
1247 /* Clean up. */
1248 PHYSFS_freeList( files );
1249
1250 return 0;
1251}
1252
1259int sound_volume( const double vol )
1260{
1261 if (sound_disabled)
1262 return 0;
1263
1264 /* Calculate volume level. */
1265 svolume_lin = vol;
1266 if (vol > 0.) /* Floor of -48 dB (0.00390625 amplitude) */
1267 svolume = (ALfloat) 1. / pow(2., (1. - vol) * 8.);
1268 else
1269 svolume = 0.;
1270
1271 /* Update volume. */
1273
1274 return 0;
1275}
1276
1282double sound_getVolume (void)
1283{
1284 if (sound_disabled)
1285 return 0.;
1286
1287 return svolume_lin;
1288}
1289
1296{
1297 if (sound_disabled)
1298 return 0.;
1299
1300 return svolume;
1301}
1302
1308static void sound_free( alSound *snd )
1309{
1310 /* Free general stuff. */
1311 free(snd->name);
1312 free(snd->filename);
1313
1314 /* Free internals. */
1315 soundLock();
1316
1317 alDeleteBuffers( 1, &snd->buf );
1318 al_checkErr();
1319
1320 soundUnlock();
1321}
1322
1329int sound_createGroup( int size )
1330{
1331 alGroup_t *g;
1332 int id;
1333
1334 if (sound_disabled)
1335 return 0;
1336
1337 /* Get new ID. */
1338 id = ++al_groupidgen;
1339
1340 /* Grow group list. */
1341 al_ngroups++;
1342 al_groups = realloc( al_groups, sizeof(alGroup_t) * al_ngroups );
1343 g = &al_groups[ al_ngroups-1 ];
1344 memset( g, 0, sizeof(alGroup_t) );
1345 g->id = id;
1346 g->state = VOICE_PLAYING;
1347 g->speed = 1;
1348 g->volume = 1.;
1349 g->pitch = 1.;
1350
1351 /* Allocate sources. */
1352 g->sources = calloc( size, sizeof(ALuint) );
1353 g->nsources = size;
1354
1355 /* Add some sources. */
1356 for (int i=0; i<size; i++) {
1357 /* Make sure there's enough. */
1358 if (source_nstack <= 0)
1359 goto group_err;
1360
1361 /* Pull one off the stack. */
1362 source_nstack--;
1363 g->sources[i] = source_stack[source_nstack];
1364
1365 /* Disable EFX, they don't affect groups. */
1366 if (al_info.efx_reverb == AL_TRUE) {
1367 alSourcef( g->sources[i], AL_AIR_ABSORPTION_FACTOR, 0. );
1368 alSource3i( g->sources[i], AL_AUXILIARY_SEND_FILTER,
1369 AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL );
1370 }
1371
1372 /* Remove from total too. */
1373 for (int j=0; j<source_ntotal; j++) {
1374 if (g->sources[i] == source_total[j]) {
1375 source_ntotal--;
1376 memmove( &source_total[j], &source_total[j+1],
1377 sizeof(ALuint) * (source_ntotal - j) );
1378 break;
1379 }
1380 }
1381 }
1382
1383 al_checkErr();
1384 return id;
1385
1386group_err:
1387 free(g->sources);
1388 al_ngroups--;
1389 al_checkErr();
1390 return 0;
1391}
1392
1401int sound_playGroup( int group, int sound, int once )
1402{
1403 alSound *s;
1404
1405 if (sound_disabled)
1406 return 0;
1407
1408 if ((sound < 0) || (sound >= array_size(sound_list)))
1409 return -1;
1410
1411 s = &sound_list[sound];
1412 for (int i=0; i<al_ngroups; i++) {
1413 alGroup_t *g;
1414
1415 /* Find group. */
1416 if (al_groups[i].id != group)
1417 continue;
1418
1419 g = &al_groups[i];
1420 g->state = VOICE_PLAYING;
1421 soundLock();
1422 for (int j=0; j<g->nsources; j++) {
1423 double v;
1424 ALint state;
1425 alGetSourcei( g->sources[j], AL_SOURCE_STATE, &state );
1426
1427 /* No free ones, just smash the last one. */
1428 if (j == g->nsources-1) {
1429 if (state != AL_STOPPED)
1430 alSourceStop( g->sources[j] );
1431 }
1432 /* Ignore playing/paused. */
1433 else if ((state == AL_PLAYING) || (state == AL_PAUSED))
1434 continue;
1435
1436 /* Attach buffer. */
1437 alSourcei( g->sources[j], AL_BUFFER, s->buf );
1438
1439 /* Do not do positional sound. */
1440 alSourcei( g->sources[j], AL_SOURCE_RELATIVE, AL_TRUE );
1441
1442 /* See if should loop. */
1443 alSourcei( g->sources[j], AL_LOOPING, (once) ? AL_FALSE : AL_TRUE );
1444
1445 /* Set volume. */
1446 v = svolume * g->volume;
1447 if (g->speed)
1448 v *= svolume_speed;
1449 alSourcef( g->sources[j], AL_GAIN, v );
1450
1451 /* Start playing. */
1452 alSourcePlay( g->sources[j] );
1453
1454 /* Check for errors. */
1455 al_checkErr();
1456
1457 soundUnlock();
1458 return 0;
1459 }
1460 al_checkErr();
1461 soundUnlock();
1462
1463 /* Group matched but no free source found.. */
1464 WARN(_("Group '%d' has no free sounds."), group );
1465 return -1;
1466 }
1467
1468 WARN(_("Group '%d' not found."), group);
1469 return -1;
1470}
1471
1477void sound_stopGroup( int group )
1478{
1479 alGroup_t *g;
1480
1481 if (sound_disabled)
1482 return;
1483
1484 g = al_getGroup( group );
1485 if (g == NULL)
1486 return;
1487
1488 g->state = VOICE_FADEOUT;
1489 g->fade_timer = SDL_GetTicks();
1490}
1491
1497void sound_pauseGroup( int group )
1498{
1499 alGroup_t *g;
1500
1501 if (sound_disabled)
1502 return;
1503
1504 g = al_getGroup( group );
1505 if (g == NULL)
1506 return;
1507
1508 soundLock();
1509 al_pausev( g->nsources, g->sources );
1510 al_checkErr();
1511 soundUnlock();
1512}
1513
1519void sound_resumeGroup( int group )
1520{
1521 alGroup_t *g;
1522
1523 if (sound_disabled)
1524 return;
1525
1526 g = al_getGroup( group );
1527 if (g == NULL)
1528 return;
1529
1530 soundLock();
1531 al_resumev( g->nsources, g->sources );
1532 al_checkErr();
1533 soundUnlock();
1534}
1535
1536static void groupSpeedReset( alGroup_t *g )
1537{
1538 for (int i=0; i<g->nsources; i++) {
1539 if (g->speed)
1540 alSourcef( g->sources[i], AL_PITCH, sound_speed*g->pitch );
1541 else
1542 alSourcef( g->sources[i], AL_PITCH, 1. );
1543 }
1544}
1551void sound_speedGroup( int group, int enable )
1552{
1553 alGroup_t *g;
1554
1555 if (sound_disabled)
1556 return;
1557
1558 g = al_getGroup( group );
1559 if (g == NULL)
1560 return;
1561
1562 soundLock();
1563 g->speed = enable;
1564 groupSpeedReset(g);
1565 al_checkErr();
1566 soundUnlock();
1567}
1568
1575void sound_volumeGroup( int group, double volume )
1576{
1577 double v;
1578 alGroup_t *g;
1579
1580 if (sound_disabled)
1581 return;
1582
1583 g = al_getGroup( group );
1584 if (g == NULL)
1585 return;
1586
1587 g->volume = volume;
1588
1589 soundLock();
1590 v = svolume * g->volume;
1591 if (g->speed)
1592 v *= svolume_speed;
1593 for (int j=0; j<g->nsources; j++)
1594 alSourcef( g->sources[j], AL_GAIN, v );
1595 al_checkErr();
1596 soundUnlock();
1597}
1598
1605void sound_pitchGroup( int group, double pitch )
1606{
1607 alGroup_t *g;
1608
1609 if (sound_disabled)
1610 return;
1611
1612 g = al_getGroup( group );
1613 if (g == NULL)
1614 return;
1615
1616 soundLock();
1617 g->pitch = pitch;
1618 groupSpeedReset(g);
1619 al_checkErr();
1620 soundUnlock();
1621}
1622
1623void sound_setAbsorption( double value )
1624{
1625 if (sound_disabled)
1626 return;
1627
1628 soundLock();
1629 for (int i=0; i<source_ntotal; i++) {
1630 ALuint s = source_total[i];
1631 /* Value is from 0. (normal) to 10..
1632 * It represents the attenuation per meter. In this case it decreases by
1633 * 0.05*AB_FACTOR dB/meter where AB_FACTOR is the air absorption factor.
1634 * In our case each pixel represents 5 meters.
1635 */
1636 alSourcef( s, AL_AIR_ABSORPTION_FACTOR, value );
1637 }
1638 al_checkErr();
1639 soundUnlock();
1640}
1641
1649int sound_env( SoundEnv_t env_type, double param )
1650{
1651 ALfloat f;
1652
1653 if (sound_disabled)
1654 return 0;
1655
1656 soundLock();
1657 switch (env_type) {
1658 case SOUND_ENV_NORMAL:
1659 /* Set global parameters. */
1660 alSpeedOfSound( 3433. );
1661 alDopplerFactor( 0.3 );
1662
1663 if (al_info.efx == AL_TRUE) {
1664 /* Disconnect the effect. */
1665 nalAuxiliaryEffectSloti( sound_efx_directSlot,
1666 AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL );
1667
1668 /* Set per-source parameters. */
1669 sound_setAbsorption( 0. );
1670 }
1671 break;
1672
1673 case SOUND_ENV_NEBULA:
1674 f = param / 1000.;
1675
1676 /* Set global parameters. */
1677 alSpeedOfSound( 3433./(1. + f*2.) );
1678 alDopplerFactor( 1.0 );
1679
1680 if (al_info.efx == AL_TRUE) {
1681 if (al_info.efx_reverb == AL_TRUE) {
1682 /* Tweak the reverb. */
1683 nalEffectf( efx_reverb, AL_REVERB_DECAY_TIME, 10. );
1684 nalEffectf( efx_reverb, AL_REVERB_DECAY_HFRATIO, 0.5 );
1685
1686 /* Connect the effect. */
1687 nalAuxiliaryEffectSloti( sound_efx_directSlot,
1688 AL_EFFECTSLOT_EFFECT, efx_reverb );
1689 }
1690
1691 /* Set per-source parameters. */
1692 sound_setAbsorption( 3.*f );
1693 }
1694 break;
1695 }
1696
1697 /* Check for errors. */
1698 al_checkErr();
1699
1700 soundUnlock();
1701
1702 return 0;
1703}
1704
1711{
1712 alVoice *v;
1713
1714 /* No free voices, allocate a new one. */
1715 if (voice_pool == NULL) {
1716 v = calloc( 1, sizeof(alVoice) );
1717 voice_pool = v;
1718 return v;
1719 }
1720
1721 /* First free voice. */
1722 v = voice_pool; /* We do not touch the next nor prev, it's still in the pool. */
1723 return v;
1724}
1725
1733{
1734 alVoice *tv;
1735
1736 /* Remove from pool. */
1737 if (v->prev != NULL) {
1738 tv = v->prev;
1739 tv->next = v->next;
1740 if (tv->next != NULL)
1741 tv->next->prev = tv;
1742 }
1743 else { /* Set pool to be the next. */
1744 voice_pool = v->next;
1745 if (voice_pool != NULL)
1746 voice_pool->prev = NULL;
1747 }
1748
1749 /* Insert to the front of active voices. */
1750 voiceLock();
1751 tv = voice_active;
1752 v->next = tv;
1753 v->prev = NULL;
1754 voice_active = v;
1755 if (tv != NULL)
1756 tv->prev = v;
1757 voiceUnlock();
1758 return 0;
1759}
1760
1768{
1769 alVoice *v;
1770 /* Make sure there are voices. */
1771 if (voice_active==NULL)
1772 return NULL;
1773
1774 voiceLock();
1775 for (v=voice_active; v!=NULL; v=v->next)
1776 if (v->id == id)
1777 break;
1778 voiceUnlock();
1779
1780 return v;
1781}
1782
1786int source_newRW( SDL_RWops *rw, const char *name, unsigned int flags )
1787{
1788 int ret;
1789 alSound snd, *sndl;
1790 (void) flags;
1791
1792 if (sound_disabled)
1793 return -1;
1794
1795 memset( &snd, 0, sizeof(alSound) );
1796 ret = al_load( &snd, rw, name );
1797 if (ret)
1798 return -1;
1799
1800 sndl = &array_grow( &sound_list );
1801 memcpy( sndl, &snd, sizeof(alSound) );
1802 sndl->name = strdup( name );
1803
1804 return sndl-sound_list;
1805}
1806
1810int source_new( const char* filename, unsigned int flags )
1811{
1812 SDL_RWops *rw = PHYSFSRWOPS_openRead( filename );
1813 int id = source_newRW( rw, filename, flags );
1814 SDL_RWclose( rw );
1815 return id;
1816}
1817
1821static void al_pausev( ALint n, ALuint *s )
1822{
1823 for (int i=0; i<n; i++) {
1824 ALint state;
1825 alGetSourcei( s[i], AL_SOURCE_STATE, &state );
1826 if (state == AL_PLAYING)
1827 alSourcePause( s[i] );
1828 }
1829}
1830
1834static void al_resumev( ALint n, ALuint *s )
1835{
1836 for (int i=0; i<n; i++) {
1837 ALint state;
1838 alGetSourcei( s[i], AL_SOURCE_STATE, &state );
1839 if (state == AL_PAUSED)
1840 alSourcePlay( s[i] );
1841 }
1842}
1843
1847static alGroup_t *al_getGroup( int group )
1848{
1849 for (int i=0; i<al_ngroups; i++) {
1850 if (al_groups[i].id != group)
1851 continue;
1852 return &al_groups[i];
1853 }
1854 WARN(_("Group '%d' not found."), group);
1855 return NULL;
1856}
1857
1866static int al_loadWav( ALuint *buf, SDL_RWops *rw )
1867{
1868 SDL_AudioSpec wav_spec;
1869 Uint32 wav_length;
1870 Uint8 *wav_buffer;
1871 ALenum format;
1872
1873 SDL_RWseek( rw, 0, SEEK_SET );
1874
1875 /* Load WAV. */
1876 if (SDL_LoadWAV_RW( rw, 0, &wav_spec, &wav_buffer, &wav_length) == NULL) {
1877 WARN(_("SDL_LoadWav_RW failed: %s"), SDL_GetError());
1878 return -1;
1879 }
1880
1881 /* Handle format. */
1882 switch (wav_spec.format) {
1883 case AUDIO_U8:
1884 case AUDIO_S8:
1885 format = (wav_spec.channels==1) ? AL_FORMAT_MONO8 : AL_FORMAT_STEREO8;
1886 break;
1887 case AUDIO_U16LSB:
1888 case AUDIO_S16LSB:
1889 format = (wav_spec.channels==1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
1890 break;
1891 case AUDIO_U16MSB:
1892 case AUDIO_S16MSB:
1893 WARN( _("Big endian WAVs unsupported!") );
1894 return -1;
1895 default:
1896 WARN( _("Invalid WAV format!") );
1897 return -1;
1898 }
1899
1900 /* Load into openal. */
1901 soundLock();
1902 /* Create new buffer. */
1903 alGenBuffers( 1, buf );
1904 /* Put into the buffer. */
1905 alBufferData( *buf, format, wav_buffer, wav_length, wav_spec.freq );
1906 al_checkErr();
1907 soundUnlock();
1908
1909 /* Clean up. */
1910 SDL_FreeWAV( wav_buffer );
1911 return 0;
1912}
1913
1917static const char* vorbis_getErr( int err )
1918{
1919 switch (err) {
1920 case OV_EREAD: return _("A read from media returned an error.");
1921 case OV_EFAULT: return _("Internal logic fault; indicates a bug or heap/stack corruption.");
1922 case OV_EIMPL: return _("Feature not implemented.");
1923 case OV_EINVAL: return _("Either an invalid argument, or incompletely initialized argument passed to libvorbisfile call");
1924 case OV_ENOTVORBIS: return _("Bitstream is not Vorbis data.");
1925 case OV_EBADHEADER: return _("Invalid Vorbis bitstream header.");
1926 case OV_EVERSION: return _("Vorbis version mismatch.");
1927 case OV_EBADLINK: return _("The given link exists in the Vorbis data stream, but is not decipherable due to garbage or corruption.");
1928 case OV_ENOSEEK: return _("The given stream is not seekable.");
1929
1930 default: return _("Unknown vorbisfile error.");
1931 }
1932}
1933
1940static int al_loadOgg( ALuint *buf, OggVorbis_File *vf )
1941{
1942 int ret;
1943 long i;
1944 int section;
1945 vorbis_info *info;
1946 ALenum format;
1947 ogg_int64_t len;
1948 char *data;
1949 long bytes_read;
1950
1951 /* Finish opening the file. */
1952 ret = ov_test_open(vf);
1953 if (ret) {
1954 WARN(_("Failed to finish loading Ogg file: %s"), vorbis_getErr(ret) );
1955 return -1;
1956 }
1957
1958 /* Get file information. */
1959 info = ov_info( vf, -1 );
1960 format = (info->channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
1961 len = ov_pcm_total( vf, -1 ) * info->channels * sizeof(short);
1962
1963 /* Allocate memory. */
1964 data = malloc( len );
1965
1966 /* Fill buffer. */
1967 i = 0;
1968 bytes_read = 1;
1969 while (bytes_read > 0) {
1970 /* Fill buffer with data ibytes_read the 16 bit signed samples format. */
1971 bytes_read = ov_read( vf, &data[i], 4096, (SDL_BYTEORDER == SDL_BIG_ENDIAN), 2, 1, &section );
1972 if (bytes_read==OV_HOLE || bytes_read==OV_EBADLINK || bytes_read==OV_EINVAL) {
1973 WARN(_("Error reading from OGG file!"));
1974 continue;
1975 }
1976 i += bytes_read;
1977 }
1978
1979 soundLock();
1980 /* Create new buffer. */
1981 alGenBuffers( 1, buf );
1982 /* Put into buffer. */
1983 alBufferData( *buf, format, data, len, info->rate );
1984 al_checkErr();
1985 soundUnlock();
1986
1987 /* Clean up. */
1988 free(data);
1989 ov_clear(vf);
1990
1991 return 0;
1992}
1993
2001int sound_al_buffer( ALuint *buf, SDL_RWops *rw, const char *name )
2002{
2003 int ret;
2004 OggVorbis_File vf;
2005
2006 /* Check to see if it's an Ogg. */
2007 if (ov_test_callbacks( rw, &vf, NULL, 0, sound_al_ovcall_noclose )==0)
2008 ret = al_loadOgg( buf, &vf );
2009
2010 /* Otherwise try WAV. */
2011 else {
2012 /* Destroy the partially loaded vorbisfile. */
2013 ov_clear(&vf);
2014
2015 /* Try to load Wav. */
2016 ret = al_loadWav( buf, rw );
2017 }
2018
2019 /* Failed to load. */
2020 if (ret != 0) {
2021 WARN(_("Failed to load sound file '%s'."), name);
2022 return ret;
2023 }
2024
2025 soundLock();
2026
2027 /* Check for errors. */
2028 al_checkErr();
2029
2030 soundUnlock();
2031
2032 return 0;
2033}
2034
2042int al_load( alSound *snd, SDL_RWops *rw, const char *name )
2043{
2044 ALint freq, bits, channels, size;
2045 int ret = sound_al_buffer( &snd->buf, rw, name );
2046 if (ret != 0) {
2047 WARN(_("Failed to load sound file '%s'."), name);
2048 return ret;
2049 }
2050
2051 soundLock();
2052
2053 /* Get the length of the sound. */
2054 alGetBufferi( snd->buf, AL_FREQUENCY, &freq );
2055 alGetBufferi( snd->buf, AL_BITS, &bits );
2056 alGetBufferi( snd->buf, AL_CHANNELS, &channels );
2057 alGetBufferi( snd->buf, AL_SIZE, &size );
2058 if ((freq==0) || (bits==0) || (channels==0)) {
2059 WARN(_("Something went wrong when loading sound file '%s'."), name);
2060 snd->length = 0;
2061 }
2062 else
2063 snd->length = (double)size / (double)(freq * (bits/8) * channels);
2064 snd->channels = channels;
2065
2066 /* Check for errors. */
2067 al_checkErr();
2068
2069 soundUnlock();
2070
2071 return 0;
2072}
2073
2077static void al_volumeUpdate (void)
2078{
2079 soundLock();
2080 /* Do generic ones. */
2081 for (int i=0; i<source_ntotal; i++)
2082 alSourcef( source_total[i], AL_GAIN, svolume*svolume_speed );
2083 /* Do specific groups. */
2084 for (int i=0; i<al_ngroups; i++) {
2085 alGroup_t *g = &al_groups[i];
2086 double v = svolume * g->volume;
2087 if (g->speed)
2088 v *= svolume_speed;
2089 for (int j=0; j<g->nsources; j++)
2090 alSourcef( g->sources[j], AL_GAIN, v );
2091 }
2092 al_checkErr();
2093 soundUnlock();
2094
2095 /* Do special effects. */
2097}
2098
2102static int al_playVoice( alVoice *v, alSound *s,
2103 ALfloat px, ALfloat py, ALfloat vx, ALfloat vy, ALint relative )
2104{
2105 ALuint source;
2106
2107 /* Make sure there's enough. */
2108 if (source_nstack <= 0)
2109 return 0;
2110
2111 /* Pull one off the stack. */
2112 source_nstack--;
2113 source = source_stack[source_nstack];
2114
2115 /* Set up the source and buffer. */
2116 v->source = source;
2117
2118 if (v->source == 0)
2119 return -1;
2120 v->buffer = s->buf;
2121
2122 soundLock();
2123
2124 /* Attach buffer. */
2125 alSourcei( v->source, AL_BUFFER, v->buffer );
2126
2127 /* Enable positional sound. */
2128 alSourcei( v->source, AL_SOURCE_RELATIVE, relative );
2129
2130#if DEBUGGING
2131 if ((relative==AL_FALSE) && (s->channels>1))
2132 WARN(_("Sound '%s' has %d channels but is being played as positional. It should be mono!"), s->name, s->channels );
2133#endif /* DEBUGGING */
2134
2135 /* Update position. */
2136 v->pos[0] = px;
2137 v->pos[1] = py;
2138 v->pos[2] = 0.;
2139 v->vel[0] = vx;
2140 v->vel[1] = vy;
2141 v->vel[2] = 0.;
2142
2143 /* Set up properties. */
2144 alSourcef( v->source, AL_GAIN, svolume*svolume_speed );
2145 alSourcefv( v->source, AL_POSITION, v->pos );
2146 alSourcefv( v->source, AL_VELOCITY, v->vel );
2147
2148 /* Defaults just in case. */
2149 alSourcei( v->source, AL_LOOPING, AL_FALSE );
2150
2151 /* Start playing. */
2152 alSourcePlay( v->source );
2153
2154 /* Check for errors. */
2155 al_checkErr();
2156
2157 soundUnlock();
2158
2159 return 0;
2160}
2161
2166 double px, double py, double vx, double vy )
2167{
2168 v->pos[0] = px;
2169 v->pos[1] = py;
2170 v->vel[0] = vx;
2171 v->vel[1] = vy;
2172 return 0;
2173}
2174
2181{
2182 ALint state;
2183
2184 /* Invalid source, mark to delete. */
2185 if (v->source == 0) {
2186 v->state = VOICE_DESTROY;
2187 return;
2188 }
2189
2190 soundLock();
2191
2192 /* Get status. */
2193 alGetSourcei( v->source, AL_SOURCE_STATE, &state );
2194 if (state == AL_STOPPED) {
2195
2196 /* Remove buffer so it doesn't start up again if resume is called. */
2197 alSourcei( v->source, AL_BUFFER, AL_NONE );
2198
2199 /* Check for errors. */
2200 al_checkErr();
2201
2202 soundUnlock();
2203
2204 /* Put source back on the list. */
2205 source_stack[source_nstack] = v->source;
2206 source_nstack++;
2207 v->source = 0;
2208
2209 /* Mark as stopped - erased next iteration. */
2210 v->state = VOICE_STOPPED;
2211 return;
2212 }
2213
2214 /* Set up properties. */
2215 alSourcef( v->source, AL_GAIN, svolume*svolume_speed );
2216 alSourcefv( v->source, AL_POSITION, v->pos );
2217 alSourcefv( v->source, AL_VELOCITY, v->vel );
2218
2219 /* Check for errors. */
2220 al_checkErr();
2221
2222 soundUnlock();
2223}
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 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:563
Pilot * pilot_get(unsigned int id)
Pulls a pilot out of the pilot_stack based on ID.
Definition pilot.c:620
double pilot_sensorRange(void)
Returns the default sensor range for the current system.
Definition pilot_ew.c:208
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:221
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:2042
int sound_createGroup(int size)
Creates a sound group.
Definition sound.c:1329
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:1834
double sound_getVolumeLog(void)
Gets the current sound volume (logarithmic).
Definition sound.c:1295
int sound_al_buffer(ALuint *buf, SDL_RWops *rw, const char *name)
Loads the sound.
Definition sound.c:2001
static int source_nstack
Definition sound.c:186
double sound_getLength(int sound)
Gets the length of the sound buffer.
Definition sound.c:775
static int al_loadOgg(ALuint *buf, OggVorbis_File *vf)
Loads an ogg file from a tested format if possible.
Definition sound.c:1940
static void al_updateVoice(alVoice *v)
Updates the voice.
Definition sound.c:2180
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:1605
void sound_resume(void)
Resumes all the sounds.
Definition sound.c:1027
static void sound_free(alSound *snd)
Frees the sound.
Definition sound.c:1308
static ALCcontext * al_context
Definition sound.c:173
void sound_resumeGroup(int group)
Resumes all the sounds in a group.
Definition sound.c:1519
double sound_getVolume(void)
Gets the current sound volume (linear).
Definition sound.c:1282
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:1551
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:1866
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:1786
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:1202
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:1710
static const char * vorbis_getErr(int err)
Gets the vorbisfile error in human readable form..
Definition sound.c:1917
static alVoice * voice_pool
Definition sound.c:146
static alGroup_t * al_getGroup(int group)
Gets a group by ID.
Definition sound.c:1847
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:1109
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:827
int sound_playGroup(int group, int sound, int once)
Plays a sound in a group.
Definition sound.c:1401
static double sound_speed
Definition sound.c:201
void sound_exit(void)
Cleans up after the sound subsytem.
Definition sound.c:665
static ALuint * source_stack
Definition sound.c:183
void sound_stopGroup(int group)
Stops all the sounds in a group.
Definition sound.c:1477
int sound_update(double dt)
Updates the sounds removing obsolete ones and such.
Definition sound.c:908
void sound_stopAll(void)
Stops all the playing voices.
Definition sound.c:1044
int source_new(const char *filename, unsigned int flags)
Loads a new source from a file.
Definition sound.c:1810
static int al_enableEFX(void)
Enables the OpenAL EFX extension.
Definition sound.c:501
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:602
void sound_pause(void)
Pauses all the sounds.
Definition sound.c:1010
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:756
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:1649
void sound_pauseGroup(int group)
Pauses all the sounds in a group.
Definition sound.c:1497
static int voice_genid
Definition sound.c:144
static void al_volumeUpdate(void)
Internal volume update function.
Definition sound.c:2077
ALuint sound_efx_directSlot
Definition sound.c:194
static alVoice * voice_get(int id)
Gets a voice by identifier.
Definition sound.c:1767
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:1074
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:884
int sound_al_updatePos(alVoice *v, double px, double py, double vx, double vy)
Updates the position of the sound.
Definition sound.c:2165
static int voice_add(alVoice *v)
Adds a voice to the active voice stack.
Definition sound.c:1732
int sound_play(int sound)
Plays the sound in the first available channel.
Definition sound.c:789
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:1259
static void al_pausev(ALint n, ALuint *s)
Acts like alSourcePausev but with proper checks.
Definition sound.c:1821
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:1575
void sound_setSpeed(double s)
Sets the speed to play the sound at.
Definition sound.c:1152
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:2102
The representation of an in-game pilot.
Definition pilot.h:217
int nosound
Definition conf.h:106
int al_efx
Definition conf.h:105
double sound
Definition conf.h:107
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
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