diff options
Diffstat (limited to 'src/libs/sound/openal/audiodrv_openal.c')
-rw-r--r-- | src/libs/sound/openal/audiodrv_openal.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/src/libs/sound/openal/audiodrv_openal.c b/src/libs/sound/openal/audiodrv_openal.c new file mode 100644 index 0000000..eee1cd1 --- /dev/null +++ b/src/libs/sound/openal/audiodrv_openal.c @@ -0,0 +1,420 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* OpenAL audio driver + */ + +#ifdef HAVE_OPENAL + + +#include "audiodrv_openal.h" +#include "../sndintrn.h" +#include "libs/log.h" +#include "libs/memlib.h" +#include <stdlib.h> + + +ALCcontext *alcContext = NULL; +ALCdevice *alcDevice = NULL; +ALfloat defaultPos[] = {0.0f, 0.0f, -1.0f}; +ALfloat listenerPos[] = {0.0f, 0.0f, 0.0f}; +ALfloat listenerVel[] = {0.0f, 0.0f, 0.0f}; +ALfloat listenerOri[] = {0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f}; + +static const audio_Driver openAL_Driver = +{ + openAL_Uninit, + openAL_GetError, + audio_DRIVER_OPENAL, + { + /* Errors */ + AL_FALSE, + AL_INVALID_NAME, + AL_INVALID_ENUM, + AL_INVALID_VALUE, + AL_INVALID_OPERATION, + AL_OUT_OF_MEMORY, + audio_DRIVER_FAILURE, + + /* Source properties */ + AL_POSITION, + AL_LOOPING, + AL_BUFFER, + AL_GAIN, + AL_SOURCE_STATE, + AL_BUFFERS_QUEUED, + AL_BUFFERS_PROCESSED, + + /* Source state information */ + AL_INITIAL, + AL_STOPPED, + AL_PLAYING, + AL_PAUSED, + + /* Sound buffer properties */ + AL_FREQUENCY, + AL_BITS, + AL_CHANNELS, + AL_SIZE, + AL_FORMAT_MONO16, + AL_FORMAT_STEREO16, + AL_FORMAT_MONO8, + AL_FORMAT_STEREO8 + }, + + /* Sources */ + openAL_GenSources, + openAL_DeleteSources, + openAL_IsSource, + openAL_Sourcei, + openAL_Sourcef, + openAL_Sourcefv, + openAL_GetSourcei, + openAL_GetSourcef, + openAL_SourceRewind, + openAL_SourcePlay, + openAL_SourcePause, + openAL_SourceStop, + openAL_SourceQueueBuffers, + openAL_SourceUnqueueBuffers, + + /* Buffers */ + openAL_GenBuffers, + openAL_DeleteBuffers, + openAL_IsBuffer, + openAL_GetBufferi, + openAL_BufferData +}; + + +/* + * Initialization + */ + +sint32 +openAL_Init (audio_Driver *driver, sint32 flags) +{ + int i; + TFB_DecoderFormats formats = + { + MIX_IS_BIG_ENDIAN, MIX_WANT_BIG_ENDIAN, + audio_FORMAT_MONO8, audio_FORMAT_STEREO8, + audio_FORMAT_MONO16, audio_FORMAT_STEREO16 + }; + + log_add (log_Info, "Initializing OpenAL."); + alcDevice = alcOpenDevice (NULL); + + if (!alcDevice) + { + log_add (log_Error, "Couldn't initialize OpenAL: %d", + alcGetError (NULL)); + return -1; + } + + *driver = openAL_Driver; + + alcContext = alcCreateContext (alcDevice, NULL); + if (!alcContext) + { + log_add (log_Error, "Couldn't create OpenAL context: %d", + alcGetError (alcDevice)); + alcCloseDevice (alcDevice); + alcDevice = NULL; + return -1; + } + + alcMakeContextCurrent (alcContext); + + log_add (log_Info, "OpenAL initialized.\n" + " version: %s\n" + " vendor: %s\n" + " renderer: %s\n" + " device: %s", + alGetString (AL_VERSION), alGetString (AL_VENDOR), + alGetString (AL_RENDERER), + alcGetString (alcDevice, ALC_DEFAULT_DEVICE_SPECIFIER)); + //log_add (log_Info, " extensions: %s", alGetString (AL_EXTENSIONS)); + + log_add (log_Info, "Initializing sound decoders."); + if (SoundDecoder_Init (flags, &formats)) + { + log_add (log_Error, "Sound decoders initialization failed."); + alcMakeContextCurrent (NULL); + alcDestroyContext (alcContext); + alcContext = NULL; + alcCloseDevice (alcDevice); + alcDevice = NULL; + return -1; + } + log_add (log_Error, "Sound decoders initialized."); + + alListenerfv (AL_POSITION, listenerPos); + alListenerfv (AL_VELOCITY, listenerVel); + alListenerfv (AL_ORIENTATION, listenerOri); + + for (i = 0; i < NUM_SOUNDSOURCES; ++i) + { + float zero[3] = {0.0f, 0.0f, 0.0f}; + + alGenSources (1, &soundSource[i].handle); + alSourcei (soundSource[i].handle, AL_LOOPING, AL_FALSE); + alSourcefv (soundSource[i].handle, AL_POSITION, defaultPos); + alSourcefv (soundSource[i].handle, AL_VELOCITY, zero); + alSourcefv (soundSource[i].handle, AL_DIRECTION, zero); + + soundSource[i].stream_mutex = CreateMutex ("OpenAL stream mutex", SYNC_CLASS_AUDIO); + } + + if (InitStreamDecoder ()) + { + log_add (log_Error, "Stream decoder initialization failed."); + // TODO: cleanup source mutexes [or is it "muti"? :) ] + SoundDecoder_Uninit (); + alcMakeContextCurrent (NULL); + alcDestroyContext (alcContext); + alcContext = NULL; + alcCloseDevice (alcDevice); + alcDevice = NULL; + return -1; + } + + alDistanceModel (AL_INVERSE_DISTANCE); + + (void) driver; // eat compiler warning + + return 0; +} + +void +openAL_Uninit (void) +{ + int i; + + UninitStreamDecoder (); + + for (i = 0; i < NUM_SOUNDSOURCES; ++i) + { + if (soundSource[i].sample && soundSource[i].sample->decoder) + { + StopStream (i); + } + if (soundSource[i].sbuffer) + { + void *sbuffer = soundSource[i].sbuffer; + soundSource[i].sbuffer = NULL; + HFree (sbuffer); + } + DestroyMutex (soundSource[i].stream_mutex); + } + + alcMakeContextCurrent (NULL); + alcDestroyContext (alcContext); + alcContext = NULL; + alcCloseDevice (alcDevice); + alcDevice = NULL; + + SoundDecoder_Uninit (); +} + + +/* + * General + */ + +sint32 +openAL_GetError (void) +{ + ALint value = alGetError (); + switch (value) + { + case AL_FALSE: + return audio_NO_ERROR; + case AL_INVALID_NAME: + return audio_INVALID_NAME; + case AL_INVALID_ENUM: + return audio_INVALID_ENUM; + case AL_INVALID_VALUE: + return audio_INVALID_VALUE; + case AL_INVALID_OPERATION: + return audio_INVALID_OPERATION; + case AL_OUT_OF_MEMORY: + return audio_OUT_OF_MEMORY; + default: + log_add (log_Debug, "openAL_GetError: unknown value %x", value); + return audio_DRIVER_FAILURE; + break; + } +} + + +/* + * Sources + */ + +void +openAL_GenSources (uint32 n, audio_Object *psrcobj) +{ + alGenSources ((ALsizei) n, (ALuint *) psrcobj); +} + +void +openAL_DeleteSources (uint32 n, audio_Object *psrcobj) +{ + alDeleteSources ((ALsizei) n, (ALuint *) psrcobj); +} + +bool +openAL_IsSource (audio_Object srcobj) +{ + return alIsSource ((ALuint) srcobj); +} + +void +openAL_Sourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal value) + +{ + alSourcei ((ALuint) srcobj, (ALenum) pname, (ALint) value); +} + +void +openAL_Sourcef (audio_Object srcobj, audio_SourceProp pname, + float value) +{ + alSourcef ((ALuint) srcobj, (ALenum) pname, (ALfloat) value); +} + +void +openAL_Sourcefv (audio_Object srcobj, audio_SourceProp pname, + float *value) +{ + alSourcefv ((ALuint) srcobj, (ALenum) pname, (ALfloat *) value); +} + +void +openAL_GetSourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal *value) +{ + alGetSourcei ((ALuint) srcobj, (ALenum) pname, (ALint *) value); + if (pname == AL_SOURCE_STATE) + { + switch (*value) + { + case AL_INITIAL: + *value = audio_INITIAL; + break; + case AL_STOPPED: + *value = audio_STOPPED; + break; + case AL_PLAYING: + *value = audio_PLAYING; + break; + case AL_PAUSED: + *value = audio_PAUSED; + break; + default: + log_add (log_Debug, "openAL_GetSourcei(): unknown value %x", + *value); + *value = audio_DRIVER_FAILURE; + } + } +} + +void +openAL_GetSourcef (audio_Object srcobj, audio_SourceProp pname, + float *value) +{ + alGetSourcef ((ALuint) srcobj, (ALenum) pname, (ALfloat *) value); +} + +void +openAL_SourceRewind (audio_Object srcobj) +{ + alSourceRewind ((ALuint) srcobj); +} + +void +openAL_SourcePlay (audio_Object srcobj) +{ + alSourcePlay ((ALuint) srcobj); +} + +void +openAL_SourcePause (audio_Object srcobj) +{ + alSourcePause ((ALuint) srcobj); +} + +void +openAL_SourceStop (audio_Object srcobj) +{ + alSourceStop ((ALuint) srcobj); +} + +void +openAL_SourceQueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj) +{ + alSourceQueueBuffers ((ALuint) srcobj, (ALsizei) n, (ALuint *) pbufobj); +} + +void +openAL_SourceUnqueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj) +{ + alSourceUnqueueBuffers ((ALuint) srcobj, (ALsizei) n, (ALuint *) pbufobj); +} + + +/* + * Buffers + */ + +void +openAL_GenBuffers (uint32 n, audio_Object *pbufobj) +{ + alGenBuffers ((ALsizei) n, (ALuint *) pbufobj); +} + +void +openAL_DeleteBuffers (uint32 n, audio_Object *pbufobj) +{ + alDeleteBuffers ((ALsizei) n, (ALuint *) pbufobj); +} + +bool +openAL_IsBuffer (audio_Object bufobj) +{ + return alIsBuffer ((ALuint) bufobj); +} + +void +openAL_GetBufferi (audio_Object bufobj, audio_BufferProp pname, + audio_IntVal *value) +{ + alGetBufferi ((ALuint) bufobj, (ALenum) pname, (ALint *) value); +} + +void +openAL_BufferData (audio_Object bufobj, uint32 format, void* data, + uint32 size, uint32 freq) +{ + alBufferData ((ALuint) bufobj, (ALenum) format, (ALvoid *) data, + (ALsizei) size, (ALsizei) freq); +} + +#endif |