38#include "SDL_thread.h"
43#include "physfsrwops.h"
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)
74typedef struct alSound_ {
87typedef enum voice_state_ {
101typedef struct alVoice_ {
116typedef struct alGroup_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 );
230static void al_pausev( ALint n, ALuint *s );
250static size_t ovpack_read(
void *ptr,
size_t size,
size_t nmemb,
void *datasource )
252 SDL_RWops *rw = datasource;
253 return (
size_t) SDL_RWread( rw, ptr, size, nmemb );
255static int ovpack_seek(
void *datasource, ogg_int64_t offset,
int whence )
257 SDL_RWops *rw = datasource;
258 return SDL_RWseek( rw, offset, whence );
260static int ovpack_close(
void *datasource )
262 SDL_RWops *rw = datasource;
263 return SDL_RWclose( rw );
265static int ovpack_closeFake(
void *datasource )
270static long ovpack_tell(
void *datasource )
272 SDL_RWops *rw = datasource;
273 return SDL_RWseek( rw, 0, SEEK_CUR );
276 .read_func = ovpack_read,
277 .seek_func = ovpack_seek,
278 .close_func = ovpack_close,
279 .tell_func = ovpack_tell
282 .read_func = ovpack_read,
283 .seek_func = ovpack_seek,
284 .close_func = ovpack_closeFake,
285 .tell_func = ovpack_tell
295 int ret, nattribs = 0;
297 ALint attribs[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
309 WARN(_(
"Unable to open default sound device"));
315 attribs[0] = ALC_MONO_SOURCES;
317 attribs[2] = ALC_STEREO_SOURCES;
325 attribs[nattribs+0] = ALC_MAX_AUXILIARY_SENDS;
326 attribs[nattribs+1] = 4;
336 attribs[nattribs+0] = ALC_OUTPUT_LIMITER_SOFT;
337 attribs[nattribs+1] = ALC_TRUE;
344 WARN(_(
"Unable to create OpenAL context"));
350 if (alcMakeContextCurrent(
al_context )==AL_FALSE) {
351 WARN(_(
"Failure to set default context"));
362 alcGetIntegerv(
al_device, ALC_OUTPUT_LIMITER_SOFT, 1, &limiter );
363 if (limiter != ALC_TRUE)
364 WARN(_(
"Failed to set ALC_OUTPUT_LIMITER_SOFT"));
389 alGenSources( 1, &s );
422 alSourcef( s, AL_REFERENCE_DISTANCE, SOUND_REFERENCE_DISTANCE );
423 alSourcef( s, AL_MAX_DISTANCE, SOUND_MAX_DISTANCE );
424 alSourcef( s, AL_ROLLOFF_FACTOR, 1. );
431 if (alGetError() == AL_NO_ERROR)
438 WARN( _(
"OpenAL failed to initialize sources" ) );
459 alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED );
470 DEBUG(_(
"Renderer: %s"), alGetString(AL_RENDERER));
472 DEBUG(_(
"Version: %s with EFX %d.%d"), alGetString(AL_VERSION),
475 DEBUG(_(
"Version: %s without EFX"), alGetString(AL_VERSION));
505 if (strcmp(alGetString(AL_VERSION),
"1.1 ALSOFT 1.19.1")==0) {
506 DEBUG(_(
"Crashing ALSOFT version detected, disabling EFX"));
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."));
560 nalEffecti(
efx_reverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB );
561 if (alGetError() != AL_NO_ERROR) {
562 DEBUG(_(
"OpenAL Reverb not found, disabling."));
575 nalEffecti(
efx_echo, AL_EFFECT_TYPE, AL_EFFECT_ECHO );
576 if (alGetError() != AL_NO_ERROR) {
577 DEBUG(_(
"OpenAL Echo not found, disabling."));
585 nalEffectf(
efx_echo, AL_ECHO_DELAY, 0.207 );
589 alListenerf( AL_METERS_PER_UNIT, 5. );
621 WARN(_(
"Sound disabled."));
628 WARN(_(
"Unable to create voice mutex."));
637 WARN(_(
"Sound has invalid value, clamping to [0:1]."));
649 WARN(_(
"Music disabled."));
736 alcMakeContextCurrent(NULL);
765 WARN(_(
"Sound '%s' not found in sound list"), name);
845 if (target && (p != NULL)) {
852 dist =
pow2(px - cx) +
pow2(py - cy);
910 unsigned int t = SDL_GetTicks();
928 if (f < SOUND_FADEOUT) {
930 d = 1. - (ALfloat) f / (ALfloat) SOUND_FADEOUT;
935 for (
int j=0; j<g->nsources; j++)
936 alSourcef( g->sources[j], AL_GAIN, v );
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 );
984 if (tv->
next != NULL)
1057 if (v->source != 0) {
1060 alSourceStop( v->source );
1088 if (v->source != 0) {
1090 alSourceStop( v->source );
1110 double vx,
double vy )
1112 ALfloat ori[6], pos[3], vel[3];
1129 alListenerfv( AL_ORIENTATION, ori );
1133 alListenerfv( AL_POSITION, pos );
1137 alListenerfv( AL_VELOCITY, vel );
1162 v =
CLAMP( 0, 1., (s-2)/10. );
1191 for (
int j=0; j<g->nsources; j++)
1192 alSourcef( g->sources[j], AL_PITCH, s*g->pitch );
1211 files = PHYSFS_enumerateFiles( SOUND_PATH );
1218 for (
size_t i=0; files[i]!=NULL; i++) {
1222 int flen = strlen(files[i]);
1234 snprintf( path,
sizeof(path), SOUND_PATH
"%s", files[i] );
1235 rw = PHYSFSRWOPS_openRead( path );
1238 len = flen - suflen;
1239 files[i][len] =
'\0';
1248 PHYSFS_freeList( files );
1267 svolume = (ALfloat) 1. / pow(2., (1. - vol) * 8.);
1317 alDeleteBuffers( 1, &snd->
buf );
1352 g->sources = calloc( size,
sizeof(ALuint) );
1356 for (
int i=0; i<size; i++) {
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 );
1422 for (
int j=0; j<g->nsources; j++) {
1425 alGetSourcei( g->sources[j], AL_SOURCE_STATE, &state );
1428 if (j == g->nsources-1) {
1429 if (state != AL_STOPPED)
1430 alSourceStop( g->sources[j] );
1433 else if ((state == AL_PLAYING) || (state == AL_PAUSED))
1437 alSourcei( g->sources[j], AL_BUFFER, s->
buf );
1440 alSourcei( g->sources[j], AL_SOURCE_RELATIVE, AL_TRUE );
1443 alSourcei( g->sources[j], AL_LOOPING, (once) ? AL_FALSE : AL_TRUE );
1449 alSourcef( g->sources[j], AL_GAIN, v );
1452 alSourcePlay( g->sources[j] );
1464 WARN(_(
"Group '%d' has no free sounds."), group );
1468 WARN(_(
"Group '%d' not found."), group);
1489 g->fade_timer = SDL_GetTicks();
1536static void groupSpeedReset(
alGroup_t *g )
1538 for (
int i=0; i<g->nsources; i++) {
1540 alSourcef( g->sources[i], AL_PITCH,
sound_speed*g->pitch );
1542 alSourcef( g->sources[i], AL_PITCH, 1. );
1593 for (
int j=0; j<g->nsources; j++)
1594 alSourcef( g->sources[j], AL_GAIN, v );
1623void sound_setAbsorption(
double value )
1636 alSourcef( s, AL_AIR_ABSORPTION_FACTOR, value );
1658 case SOUND_ENV_NORMAL:
1660 alSpeedOfSound( 3433. );
1661 alDopplerFactor( 0.3 );
1666 AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL );
1669 sound_setAbsorption( 0. );
1673 case SOUND_ENV_NEBULA:
1677 alSpeedOfSound( 3433./(1. + f*2.) );
1678 alDopplerFactor( 1.0 );
1683 nalEffectf(
efx_reverb, AL_REVERB_DECAY_TIME, 10. );
1684 nalEffectf(
efx_reverb, AL_REVERB_DECAY_HFRATIO, 0.5 );
1692 sound_setAbsorption( 3.*f );
1716 v = calloc( 1,
sizeof(
alVoice) );
1737 if (v->prev != NULL) {
1740 if (tv->
next != NULL)
1741 tv->
next->prev = tv;
1795 memset( &snd, 0,
sizeof(
alSound) );
1796 ret =
al_load( &snd, rw, name );
1801 memcpy( sndl, &snd,
sizeof(
alSound) );
1802 sndl->
name = strdup( name );
1812 SDL_RWops *rw = PHYSFSRWOPS_openRead( filename );
1823 for (
int i=0; i<n; i++) {
1825 alGetSourcei( s[i], AL_SOURCE_STATE, &state );
1826 if (state == AL_PLAYING)
1827 alSourcePause( s[i] );
1836 for (
int i=0; i<n; i++) {
1838 alGetSourcei( s[i], AL_SOURCE_STATE, &state );
1839 if (state == AL_PAUSED)
1840 alSourcePlay( s[i] );
1854 WARN(_(
"Group '%d' not found."), group);
1868 SDL_AudioSpec wav_spec;
1873 SDL_RWseek( rw, 0, SEEK_SET );
1876 if (SDL_LoadWAV_RW( rw, 0, &wav_spec, &wav_buffer, &wav_length) == NULL) {
1877 WARN(_(
"SDL_LoadWav_RW failed: %s"), SDL_GetError());
1882 switch (wav_spec.format) {
1885 format = (wav_spec.channels==1) ? AL_FORMAT_MONO8 : AL_FORMAT_STEREO8;
1889 format = (wav_spec.channels==1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
1893 WARN( _(
"Big endian WAVs unsupported!") );
1896 WARN( _(
"Invalid WAV format!") );
1903 alGenBuffers( 1, buf );
1905 alBufferData( *buf, format, wav_buffer, wav_length, wav_spec.freq );
1910 SDL_FreeWAV( wav_buffer );
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.");
1930 default:
return _(
"Unknown vorbisfile error.");
1952 ret = ov_test_open(vf);
1954 WARN(_(
"Failed to finish loading Ogg file: %s"),
vorbis_getErr(ret) );
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);
1964 data = malloc( len );
1969 while (bytes_read > 0) {
1971 bytes_read = ov_read( vf, &data[i], 4096, (SDL_BYTEORDER == SDL_BIG_ENDIAN), 2, 1, §ion );
1972 if (bytes_read==OV_HOLE || bytes_read==OV_EBADLINK || bytes_read==OV_EINVAL) {
1973 WARN(_(
"Error reading from OGG file!"));
1981 alGenBuffers( 1, buf );
1983 alBufferData( *buf, format, data, len, info->rate );
2021 WARN(_(
"Failed to load sound file '%s'."), name);
2044 ALint freq, bits, channels, size;
2047 WARN(_(
"Failed to load sound file '%s'."), name);
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);
2063 snd->
length = (double)size / (
double)(freq * (bits/8) * channels);
2089 for (
int j=0; j<g->nsources; j++)
2090 alSourcef( g->sources[j], AL_GAIN, v );
2103 ALfloat px, ALfloat py, ALfloat vx, ALfloat vy, ALint relative )
2125 alSourcei( v->source, AL_BUFFER, v->buffer );
2128 alSourcei( v->source, AL_SOURCE_RELATIVE, relative );
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 );
2145 alSourcefv( v->source, AL_POSITION, v->pos );
2146 alSourcefv( v->source, AL_VELOCITY, v->vel );
2149 alSourcei( v->source, AL_LOOPING, AL_FALSE );
2152 alSourcePlay( v->source );
2166 double px,
double py,
double vx,
double vy )
2185 if (v->source == 0) {
2193 alGetSourcei( v->source, AL_SOURCE_STATE, &state );
2194 if (state == AL_STOPPED) {
2197 alSourcei( v->source, AL_BUFFER, AL_NONE );
2216 alSourcefv( v->source, AL_POSITION, v->pos );
2217 alSourcefv( v->source, AL_VELOCITY, v->vel );
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
void cam_getPos(double *x, double *y)
Gets the camera position.
int cam_getTarget(void)
Returns the camera's current target.
void music_update(double dt)
Updates the music.
int music_init(void)
Initializes the music subsystem.
Header file with generic functions and naev-specifics.
void spfxL_setSpeedVolume(double v)
Sets the speed volume due to autonav and the likes.
Pilot * pilot_get(unsigned int id)
Pulls a pilot out of the pilot_stack based on ID.
double pilot_sensorRange(void)
Returns the default sensor range for the current system.
int pilot_inRange(const Pilot *p, double x, double y)
Check to see if a position is in range of the pilot.
static int al_load(alSound *snd, SDL_RWops *rw, const char *name)
Loads the sound.
int sound_createGroup(int size)
Creates a sound group.
static alGroup_t * al_groups
static void al_resumev(ALint n, ALuint *s)
Acts like alSourcePlayv but with proper checks to just resume.
double sound_getVolumeLog(void)
Gets the current sound volume (logarithmic).
int sound_al_buffer(ALuint *buf, SDL_RWops *rw, const char *name)
Loads the sound.
double sound_getLength(int sound)
Gets the length of the sound buffer.
static int al_loadOgg(ALuint *buf, OggVorbis_File *vf)
Loads an ogg file from a tested format if possible.
static void al_updateVoice(alVoice *v)
Updates the voice.
static double snd_compression_gain
void sound_pitchGroup(int group, double pitch)
Sets the pitch of a group.
void sound_resume(void)
Resumes all the sounds.
static void sound_free(alSound *snd)
Frees the sound.
static ALCcontext * al_context
void sound_resumeGroup(int group)
Resumes all the sounds in a group.
double sound_getVolume(void)
Gets the current sound volume (linear).
static int snd_compression
void sound_speedGroup(int group, int enable)
Sets whether or not the speed affects a group.
static ALfloat svolume_speed
static int al_loadWav(ALuint *buf, SDL_RWops *rw)
Loads a wav file from the rw if possible.
int source_newRW(SDL_RWops *rw, const char *name, unsigned int flags)
Loads a new sound source from a RWops.
static int sound_makeList(void)
Makes the list of available sounds.
static ALuint * source_total
static alVoice * voice_new(void)
Gets a new voice ready to be used.
static const char * vorbis_getErr(int err)
Gets the vorbisfile error in human readable form..
static alVoice * voice_pool
static alGroup_t * al_getGroup(int group)
Gets a group by ID.
static alVoice * voice_active
int sound_updateListener(double dir, double px, double py, double vx, double vy)
Updates the sound listener.
int sound_playPos(int sound, double px, double py, double vx, double vy)
Plays a sound based on position.
int sound_playGroup(int group, int sound, int once)
Plays a sound in a group.
static double sound_speed
void sound_exit(void)
Cleans up after the sound subsytem.
static ALuint * source_stack
void sound_stopGroup(int group)
Stops all the sounds in a group.
int sound_update(double dt)
Updates the sounds removing obsolete ones and such.
void sound_stopAll(void)
Stops all the playing voices.
int source_new(const char *filename, unsigned int flags)
Loads a new source from a file.
static int al_enableEFX(void)
Enables the OpenAL EFX extension.
static ALfloat svolume_lin
ov_callbacks sound_al_ovcall_noclose
static ALCdevice * al_device
int sound_init(void)
Initializes the sound subsystem.
void sound_pause(void)
Pauses all the sounds.
voice_state_t
The state of a voice.
int sound_get(const char *name)
Gets the buffer to sound of name.
static SDL_mutex * voice_mutex
int sound_env(SoundEnv_t env_type, double param)
Sets up the sound environment.
void sound_pauseGroup(int group)
Pauses all the sounds in a group.
static void al_volumeUpdate(void)
Internal volume update function.
ALuint sound_efx_directSlot
static alVoice * voice_get(int id)
Gets a voice by identifier.
static int sound_initialized
void sound_stop(int voice)
Stops a voice from playing.
ov_callbacks sound_al_ovcall
int sound_updatePos(int voice, double px, double py, double vx, double vy)
Updates the position of a voice.
int sound_al_updatePos(alVoice *v, double px, double py, double vx, double vy)
Updates the position of the sound.
static int voice_add(alVoice *v)
Adds a voice to the active voice stack.
int sound_play(int sound)
Plays the sound in the first available channel.
static alSound * sound_list
static ALuint * source_all
int sound_volume(const double vol)
Sets the volume.
static void al_pausev(ALint n, ALuint *s)
Acts like alSourcePausev but with proper checks.
static int sound_al_init(void)
Initializes the sound subsystem.
void sound_volumeGroup(int group, double volume)
Sets the volume of a group.
void sound_setSpeed(double s)
Sets the speed to play the sound at.
static int snd_compressionG
static int al_playVoice(alVoice *v, alSound *s, ALfloat px, ALfloat py, ALfloat vx, ALfloat vy, ALint relative)
Plays a voice.
The representation of an in-game pilot.
Represents a voice in the game.