Commit 518f628f authored by David Reid's avatar David Reid

Exploratory work on the OpenAL backend.

parent f8daea07
...@@ -183,6 +183,9 @@ extern "C" { ...@@ -183,6 +183,9 @@ extern "C" {
#if !defined(MAL_NO_OPENSLES) && defined(MAL_ANDROID) #if !defined(MAL_NO_OPENSLES) && defined(MAL_ANDROID)
#define MAL_ENABLE_OPENSLES #define MAL_ENABLE_OPENSLES
#endif #endif
#if !defined(MAL_NO_OPENAL)
#define MAL_ENABLE_OPENAL
#endif
#if !defined(MAL_NO_NULL) #if !defined(MAL_NO_NULL)
#define MAL_ENABLE_NULL #define MAL_ENABLE_NULL
#endif #endif
...@@ -215,6 +218,7 @@ typedef mal_int32 mal_bool32; ...@@ -215,6 +218,7 @@ typedef mal_int32 mal_bool32;
typedef void* mal_handle; typedef void* mal_handle;
typedef void* mal_ptr; typedef void* mal_ptr;
typedef void (* mal_proc)();
#ifdef MAL_WIN32 #ifdef MAL_WIN32
typedef mal_handle mal_thread; typedef mal_handle mal_thread;
...@@ -234,6 +238,9 @@ typedef void* mal_ptr; ...@@ -234,6 +238,9 @@ typedef void* mal_ptr;
#ifdef MAL_ENABLE_DSOUND #ifdef MAL_ENABLE_DSOUND
#define MAL_MAX_PERIODS_DSOUND 4 #define MAL_MAX_PERIODS_DSOUND 4
#endif #endif
#ifdef MAL_ENABLE_OPENAL
#define MAL_MAX_PERIODS_OPENAL 4
#endif
typedef int mal_result; typedef int mal_result;
#define MAL_SUCCESS 0 #define MAL_SUCCESS 0
...@@ -284,7 +291,8 @@ typedef enum ...@@ -284,7 +291,8 @@ typedef enum
mal_backend_wasapi, mal_backend_wasapi,
mal_backend_dsound, mal_backend_dsound,
mal_backend_alsa, mal_backend_alsa,
mal_backend_sles mal_backend_sles,
mal_backend_openal
} mal_backend; } mal_backend;
typedef enum typedef enum
...@@ -307,10 +315,22 @@ typedef enum ...@@ -307,10 +315,22 @@ typedef enum
typedef union typedef union
{ {
// Just look at this shit... // Just look at this shit...
#if defined(MAL_ENABLE_OPENSLES)
mal_uint32 id32; // OpenSL|ES uses a 32-bit unsigned integer for identification. mal_uint32 id32; // OpenSL|ES uses a 32-bit unsigned integer for identification.
#endif
#if defined(MAL_ENABLE_ALSA)
char str[32]; // ALSA uses a name string for identification. char str[32]; // ALSA uses a name string for identification.
wchar_t wstr[64]; // WASAPI uses a wchar_t string for identification which is also annoyingly long... #endif
#if defined(MAL_ENABLE_DSOUND)
mal_uint8 guid[16]; // DirectSound uses a GUID for identification. mal_uint8 guid[16]; // DirectSound uses a GUID for identification.
#endif
#if defined(MAL_ENABLE_WASAPI)
wchar_t wstr[64]; // WASAPI uses a wchar_t string for identification which is also annoyingly long...
#endif
#if defined(MAL_ENABLE_OPENAL)
char openal[256]; // OpenAL uses human-readable device names as the ID which is so flippin' stupid...
#endif
int null; // <-- Just to ensure compilation works when no backends are enabled.
} mal_device_id; } mal_device_id;
typedef struct typedef struct
...@@ -372,6 +392,105 @@ typedef struct ...@@ -372,6 +392,105 @@ typedef struct
} sles; } sles;
#endif #endif
#ifdef MAL_ENABLE_OPENAL
struct
{
/*HMODULE*/ mal_handle hOpenAL; // OpenAL32.dll, etc.
mal_proc alcCreateContext;
mal_proc alcMakeContextCurrent;
mal_proc alcProcessContext;
mal_proc alcSuspendContext;
mal_proc alcDestroyContext;
mal_proc alcGetCurrentContext;
mal_proc alcGetContextsDevice;
mal_proc alcOpenDevice;
mal_proc alcCloseDevice;
mal_proc alcGetError;
mal_proc alcIsExtensionPresent;
mal_proc alcGetProcAddress;
mal_proc alcGetEnumValue;
mal_proc alcGetString;
mal_proc alcGetIntegerv;
mal_proc alcCaptureOpenDevice;
mal_proc alcCaptureCloseDevice;
mal_proc alcCaptureStart;
mal_proc alcCaptureStop;
mal_proc alcCaptureSamples;
mal_proc alEnable;
mal_proc alDisable;
mal_proc alIsEnabled;
mal_proc alGetString;
mal_proc alGetBooleanv;
mal_proc alGetIntegerv;
mal_proc alGetFloatv;
mal_proc alGetDoublev;
mal_proc alGetBoolean;
mal_proc alGetInteger;
mal_proc alGetFloat;
mal_proc alGetDouble;
mal_proc alGetError;
mal_proc alIsExtensionPresent;
mal_proc alGetProcAddress;
mal_proc alGetEnumValue;
mal_proc alListenerf;
mal_proc alListener3f;
mal_proc alListenerfv;
mal_proc alListeneri;
mal_proc alListener3i;
mal_proc alListeneriv;
mal_proc alGetListenerf;
mal_proc alGetListener3f;
mal_proc alGetListenerfv;
mal_proc alGetListeneri;
mal_proc alGetListener3i;
mal_proc alGetListeneriv;
mal_proc alGenSources;
mal_proc alDeleteSources;
mal_proc alIsSource;
mal_proc alSourcef;
mal_proc alSource3f;
mal_proc alSourcefv;
mal_proc alSourcei;
mal_proc alSource3i;
mal_proc alSourceiv;
mal_proc alGetSourcef;
mal_proc alGetSource3f;
mal_proc alGetSourcefv;
mal_proc alGetSourcei;
mal_proc alGetSource3i;
mal_proc alGetSourceiv;
mal_proc alSourcePlayv;
mal_proc alSourceStopv;
mal_proc alSourceRewindv;
mal_proc alSourcePausev;
mal_proc alSourcePlay;
mal_proc alSourceStop;
mal_proc alSourceRewind;
mal_proc alSourcePause;
mal_proc alSourceQueueBuffers;
mal_proc alSourceUnqueueBuffers;
mal_proc alGenBuffers;
mal_proc alDeleteBuffers;
mal_proc alIsBuffer;
mal_proc alBufferData;
mal_proc alBufferf;
mal_proc alBuffer3f;
mal_proc alBufferfv;
mal_proc alBufferi;
mal_proc alBuffer3i;
mal_proc alBufferiv;
mal_proc alGetBufferf;
mal_proc alGetBuffer3f;
mal_proc alGetBufferfv;
mal_proc alGetBufferi;
mal_proc alGetBuffer3i;
mal_proc alGetBufferiv;
mal_uint32 isFloat32Supported;
} openal;
#endif
#ifdef MAL_ENABLE_NULL #ifdef MAL_ENABLE_NULL
struct struct
{ {
...@@ -464,6 +583,16 @@ struct mal_device ...@@ -464,6 +583,16 @@ struct mal_device
} sles; } sles;
#endif #endif
#ifdef MAL_ENABLE_OPENAL
struct
{
/*ALCcontext**/ mal_ptr pContextALC;
/*ALCdevice**/ mal_ptr pDeviceALC;
/*ALuint*/ mal_uint32 sourceAL;
/*ALuint*/ mal_uint32 buffersAL[MAL_MAX_PERIODS_OPENAL];
} openal;
#endif
#ifdef MAL_ENABLE_NULL #ifdef MAL_ENABLE_NULL
struct struct
{ {
...@@ -492,6 +621,7 @@ struct mal_device ...@@ -492,6 +621,7 @@ struct mal_device
// - WASAPI // - WASAPI
// - ALSA // - ALSA
// - OpenSL|ES // - OpenSL|ES
// - OpenAL
// - Null // - Null
// //
// Return Value: // Return Value:
...@@ -756,6 +886,7 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format); ...@@ -756,6 +886,7 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format);
#ifdef MAL_POSIX #ifdef MAL_POSIX
#include <unistd.h> #include <unistd.h>
#include <dlfcn.h>
#endif #endif
#ifdef MAL_ENABLE_ALSA #ifdef MAL_ENABLE_ALSA
...@@ -1031,6 +1162,39 @@ double mal_timer_get_time_in_seconds(mal_timer* pTimer) ...@@ -1031,6 +1162,39 @@ double mal_timer_get_time_in_seconds(mal_timer* pTimer)
#endif #endif
///////////////////////////////////////////////////////////////////////////////
//
// Dynamic Linking
//
///////////////////////////////////////////////////////////////////////////////
mal_handle mal_dlopen(const char* filename)
{
#ifdef _WIN32
return (mal_handle)LoadLibraryA(filename);
#else
return (mal_handle)dlopen(filename, RTLD_NOW);
#endif
}
void mal_dlclose(mal_handle handle)
{
#ifdef _WIN32
CloseHandle((HANDLE)handle);
#else
dlclose((void*)handle);
#endif
}
mal_proc mal_dlsym(mal_handle handle, const char* symbol)
{
#ifdef _WIN32
return (mal_proc)GetProcAddress((HMODULE)handle, symbol);
#else
return (mal_proc)dlsym((void*)handle, symbol);
#endif
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// //
// Threading // Threading
...@@ -3899,8 +4063,426 @@ static mal_result mal_device__stop_backend__sles(mal_device* pDevice) ...@@ -3899,8 +4063,426 @@ static mal_result mal_device__stop_backend__sles(mal_device* pDevice)
return MAL_SUCCESS; return MAL_SUCCESS;
} }
#endif // OpenSL|ES
///////////////////////////////////////////////////////////////////////////////
//
// OpenAL Backend
//
///////////////////////////////////////////////////////////////////////////////
#ifdef MAL_ENABLE_OPENAL
#ifdef MAL_APPLE
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif #endif
#ifdef MAL_WIN32
#define MAL_AL_APIENTRY __cdecl
#else
#define MAL_AL_APIENTRY
#endif
#define MAL_AL_FORMAT_MONO_FLOAT32 0x10010
#define MAL_AL_FORMAT_STEREO_FLOAT32 0x10011
// TODO: Remove unused APIs.
typedef ALCcontext* (MAL_AL_APIENTRY * MAL_LPALCCREATECONTEXT) (ALCdevice *device, const ALCint *attrlist);
typedef ALCboolean (MAL_AL_APIENTRY * MAL_LPALCMAKECONTEXTCURRENT)(ALCcontext *context);
typedef void (MAL_AL_APIENTRY * MAL_LPALCPROCESSCONTEXT) (ALCcontext *context);
typedef void (MAL_AL_APIENTRY * MAL_LPALCSUSPENDCONTEXT) (ALCcontext *context);
typedef void (MAL_AL_APIENTRY * MAL_LPALCDESTROYCONTEXT) (ALCcontext *context);
typedef ALCcontext* (MAL_AL_APIENTRY * MAL_LPALCGETCURRENTCONTEXT) (void);
typedef ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCGETCONTEXTSDEVICE) (ALCcontext *context);
typedef ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCOPENDEVICE) (const ALCchar *devicename);
typedef ALCboolean (MAL_AL_APIENTRY * MAL_LPALCCLOSEDEVICE) (ALCdevice *device);
typedef ALCenum (MAL_AL_APIENTRY * MAL_LPALCGETERROR) (ALCdevice *device);
typedef ALCboolean (MAL_AL_APIENTRY * MAL_LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname);
typedef void* (MAL_AL_APIENTRY * MAL_LPALCGETPROCADDRESS) (ALCdevice *device, const ALCchar *funcname);
typedef ALCenum (MAL_AL_APIENTRY * MAL_LPALCGETENUMVALUE) (ALCdevice *device, const ALCchar *enumname);
typedef const ALCchar* (MAL_AL_APIENTRY * MAL_LPALCGETSTRING) (ALCdevice *device, ALCenum param);
typedef void (MAL_AL_APIENTRY * MAL_LPALCGETINTEGERV) (ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values);
typedef ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCCAPTUREOPENDEVICE) (const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize);
typedef ALCboolean (MAL_AL_APIENTRY * MAL_LPALCCAPTURECLOSEDEVICE)(ALCdevice *device);
typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESTART) (ALCdevice *device);
typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESTOP) (ALCdevice *device);
typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESAMPLES) (ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
typedef void (MAL_AL_APIENTRY * MAL_LPALENABLE) (ALenum capability);
typedef void (MAL_AL_APIENTRY * MAL_LPALDISABLE) (ALenum capability);
typedef ALboolean (MAL_AL_APIENTRY * MAL_LPALISENABLED) (ALenum capability);
typedef const ALchar* (MAL_AL_APIENTRY * MAL_LPALGETSTRING) (ALenum param);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBOOLEANV) (ALenum param, ALboolean *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETINTEGERV) (ALenum param, ALint *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETFLOATV) (ALenum param, ALfloat *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETDOUBLEV) (ALenum param, ALdouble *values);
typedef ALboolean (MAL_AL_APIENTRY * MAL_LPALGETBOOLEAN) (ALenum param);
typedef ALint (MAL_AL_APIENTRY * MAL_LPALGETINTEGER) (ALenum param);
typedef ALfloat (MAL_AL_APIENTRY * MAL_LPALGETFLOAT) (ALenum param);
typedef ALdouble (MAL_AL_APIENTRY * MAL_LPALGETDOUBLE) (ALenum param);
typedef ALenum (MAL_AL_APIENTRY * MAL_LPALGETERROR) (void);
typedef ALboolean (MAL_AL_APIENTRY * MAL_LPALISEXTENSIONPRESENT) (const ALchar *extname);
typedef void* (MAL_AL_APIENTRY * MAL_LPALGETPROCADDRESS) (const ALchar *fname);
typedef ALenum (MAL_AL_APIENTRY * MAL_LPALGETENUMVALUE) (const ALchar *ename);
typedef void (MAL_AL_APIENTRY * MAL_LPALLISTENERF) (ALenum param, ALfloat value);
typedef void (MAL_AL_APIENTRY * MAL_LPALLISTENER3F) (ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALLISTENERFV) (ALenum param, const ALfloat *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALLISTENERI) (ALenum param, ALint value);
typedef void (MAL_AL_APIENTRY * MAL_LPALLISTENER3I) (ALenum param, ALint value1, ALint value2, ALint value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALLISTENERIV) (ALenum param, const ALint *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETLISTENERF) (ALenum param, ALfloat *value);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETLISTENER3F) (ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETLISTENERFV) (ALenum param, ALfloat *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETLISTENERI) (ALenum param, ALint *value);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETLISTENER3I) (ALenum param, ALint *value1, ALint *value2, ALint *value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETLISTENERIV) (ALenum param, ALint *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGENSOURCES) (ALsizei n, ALuint *sources);
typedef void (MAL_AL_APIENTRY * MAL_LPALDELETESOURCES) (ALsizei n, const ALuint *sources);
typedef ALboolean (MAL_AL_APIENTRY * MAL_LPALISSOURCE) (ALuint source);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEF) (ALuint source, ALenum param, ALfloat value);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCE3F) (ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEFV) (ALuint source, ALenum param, const ALfloat *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEI) (ALuint source, ALenum param, ALint value);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCE3I) (ALuint source, ALenum param, ALint value1, ALint value2, ALint value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEIV) (ALuint source, ALenum param, const ALint *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEF) (ALuint source, ALenum param, ALfloat *value);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCE3F) (ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEFV) (ALuint source, ALenum param, ALfloat *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEI) (ALuint source, ALenum param, ALint *value);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCE3I) (ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEIV) (ALuint source, ALenum param, ALint *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPLAYV) (ALsizei n, const ALuint *sources);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCESTOPV) (ALsizei n, const ALuint *sources);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEREWINDV) (ALsizei n, const ALuint *sources);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPAUSEV) (ALsizei n, const ALuint *sources);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPLAY) (ALuint source);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCESTOP) (ALuint source);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEREWIND) (ALuint source);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPAUSE) (ALuint source);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEQUEUEBUFFERS) (ALuint source, ALsizei nb, const ALuint *buffers);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEUNQUEUEBUFFERS)(ALuint source, ALsizei nb, ALuint *buffers);
typedef void (MAL_AL_APIENTRY * MAL_LPALGENBUFFERS) (ALsizei n, ALuint *buffers);
typedef void (MAL_AL_APIENTRY * MAL_LPALDELETEBUFFERS) (ALsizei n, const ALuint *buffers);
typedef ALboolean (MAL_AL_APIENTRY * MAL_LPALISBUFFER) (ALuint buffer);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERDATA) (ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERF) (ALuint buffer, ALenum param, ALfloat value);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFER3F) (ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERFV) (ALuint buffer, ALenum param, const ALfloat *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERI) (ALuint buffer, ALenum param, ALint value);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFER3I) (ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERIV) (ALuint buffer, ALenum param, const ALint *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERF) (ALuint buffer, ALenum param, ALfloat *value);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFER3F) (ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERFV) (ALuint buffer, ALenum param, ALfloat *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERI) (ALuint buffer, ALenum param, ALint *value);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFER3I) (ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERIV) (ALuint buffer, ALenum param, ALint *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALDOPPLERFACTOR) (ALfloat value);
typedef void (MAL_AL_APIENTRY * MAL_LPALDOPPLERVELOCITY) (ALfloat value);
typedef void (MAL_AL_APIENTRY * MAL_LPALSPEEDOFSOUND) (ALfloat value);
typedef void (MAL_AL_APIENTRY * MAL_LPALDISTANCEMODEL) (ALenum distanceModel);
mal_result mal_context_init__openal(mal_context* pContext)
{
mal_assert(pContext != NULL);
const char* libName =
#ifdef MAL_WIN32
"OpenAL32.dll";
#endif
#ifdef MAL_LINUX
"libopenal.so";
#endif
#ifdef MAL_APPLE
// I don't own a Mac so a contribution here would be much appreciated!
#endif
pContext->openal.hOpenAL = mal_dlopen(libName);
#ifdef MAL_WIN32
// Special case for Win32 - try "soft_oal.dll" for OpenAL Soft drop-ins.
if (pContext->openal.hOpenAL == NULL) {
pContext->openal.hOpenAL = mal_dlopen("soft_oal.dll");
}
#endif
if (pContext->openal.hOpenAL == NULL) {
return MAL_FAILED_TO_INIT_BACKEND;
}
pContext->openal.alcCreateContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCreateContext");
pContext->openal.alcMakeContextCurrent = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcMakeContextCurrent");
pContext->openal.alcProcessContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcProcessContext");
pContext->openal.alcSuspendContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcSuspendContext");
pContext->openal.alcDestroyContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcDestroyContext");
pContext->openal.alcGetCurrentContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetCurrentContext");
pContext->openal.alcGetContextsDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetContextsDevice");
pContext->openal.alcOpenDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcOpenDevice");
pContext->openal.alcCloseDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCloseDevice");
pContext->openal.alcGetError = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetError");
pContext->openal.alcIsExtensionPresent = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcIsExtensionPresent");
pContext->openal.alcGetProcAddress = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetProcAddress");
pContext->openal.alcGetEnumValue = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetEnumValue");
pContext->openal.alcGetString = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetString");
pContext->openal.alcGetIntegerv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetIntegerv");
pContext->openal.alcCaptureOpenDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureOpenDevice");
pContext->openal.alcCaptureCloseDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureCloseDevice");
pContext->openal.alcCaptureStart = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureStart");
pContext->openal.alcCaptureStop = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureStop");
pContext->openal.alcCaptureSamples = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureSamples");
pContext->openal.alEnable = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alEnable");
pContext->openal.alDisable = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alDisable");
pContext->openal.alIsEnabled = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsEnabled");
pContext->openal.alGetString = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetString");
pContext->openal.alGetBooleanv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBooleanv");
pContext->openal.alGetIntegerv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetIntegerv");
pContext->openal.alGetFloatv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetFloatv");
pContext->openal.alGetDoublev = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetDoublev");
pContext->openal.alGetBoolean = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBoolean");
pContext->openal.alGetInteger = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetInteger");
pContext->openal.alGetFloat = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetFloat");
pContext->openal.alGetDouble = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetDouble");
pContext->openal.alGetError = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetError");
pContext->openal.alIsExtensionPresent = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsExtensionPresent");
pContext->openal.alGetProcAddress = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetProcAddress");
pContext->openal.alGetEnumValue = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetEnumValue");
pContext->openal.alListenerf = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alListenerf");
pContext->openal.alListener3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alListener3f");
pContext->openal.alListenerfv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alListenerfv");
pContext->openal.alListeneri = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alListeneri");
pContext->openal.alListener3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alListener3i");
pContext->openal.alListeneriv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alListeneriv");
pContext->openal.alGetListenerf = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetListenerf");
pContext->openal.alGetListener3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetListener3f");
pContext->openal.alGetListenerfv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetListenerfv");
pContext->openal.alGetListeneri = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetListeneri");
pContext->openal.alGetListener3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetListener3i");
pContext->openal.alGetListeneriv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetListeneriv");
pContext->openal.alGenSources = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGenSources");
pContext->openal.alDeleteSources = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alDeleteSources");
pContext->openal.alIsSource = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsSource");
pContext->openal.alSourcef = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcef");
pContext->openal.alSource3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSource3f");
pContext->openal.alSourcefv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcefv");
pContext->openal.alSourcei = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcei");
pContext->openal.alSource3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSource3i");
pContext->openal.alSourceiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceiv");
pContext->openal.alGetSourcef = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourcef");
pContext->openal.alGetSource3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSource3f");
pContext->openal.alGetSourcefv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourcefv");
pContext->openal.alGetSourcei = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourcei");
pContext->openal.alGetSource3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSource3i");
pContext->openal.alGetSourceiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourceiv");
pContext->openal.alSourcePlayv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePlayv");
pContext->openal.alSourceStopv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceStopv");
pContext->openal.alSourceRewindv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceRewindv");
pContext->openal.alSourcePausev = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePausev");
pContext->openal.alSourcePlay = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePlay");
pContext->openal.alSourceStop = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceStop");
pContext->openal.alSourceRewind = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceRewind");
pContext->openal.alSourcePause = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePause");
pContext->openal.alSourceQueueBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceQueueBuffers");
pContext->openal.alSourceUnqueueBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceUnqueueBuffers");
pContext->openal.alGenBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGenBuffers");
pContext->openal.alDeleteBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alDeleteBuffers");
pContext->openal.alIsBuffer = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsBuffer");
pContext->openal.alBufferData = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferData");
pContext->openal.alBufferf = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferf");
pContext->openal.alBuffer3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBuffer3f");
pContext->openal.alBufferfv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferfv");
pContext->openal.alBufferi = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferi");
pContext->openal.alBuffer3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBuffer3i");
pContext->openal.alBufferiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferiv");
pContext->openal.alGetBufferf = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferf");
pContext->openal.alGetBuffer3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBuffer3f");
pContext->openal.alGetBufferfv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferfv");
pContext->openal.alGetBufferi = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferi");
pContext->openal.alGetBuffer3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBuffer3i");
pContext->openal.alGetBufferiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferiv");
// We depend on the ALC_ENUMERATION_EXT extension.
if (!((MAL_LPALCISEXTENSIONPRESENT)pContext->openal.alcIsExtensionPresent)(NULL, "ALC_ENUMERATION_EXT")) {
mal_dlclose(pContext->openal.hOpenAL);
return MAL_FAILED_TO_INIT_BACKEND;
}
pContext->openal.isFloat32Supported = ((MAL_LPALISEXTENSIONPRESENT)pContext->openal.alIsExtensionPresent)("AL_EXT_float32");
return MAL_SUCCESS;
}
mal_result mal_context_uninit__openal(mal_context* pContext)
{
mal_assert(pContext != NULL);
mal_assert(pContext->backend == mal_backend_openal);
mal_dlclose(pContext->openal.hOpenAL);
return MAL_SUCCESS;
}
mal_result mal_enumerate_devices__openal(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo)
{
mal_uint32 infoCapacity = *pCount;
*pCount = 0;
const ALCchar* pDeviceNames = ((MAL_LPALCGETSTRING)pContext->openal.alcGetString)(NULL, (type == mal_device_type_playback) ? ALC_DEVICE_SPECIFIER : ALC_CAPTURE_DEVICE_SPECIFIER);
if (pDeviceNames == NULL) {
return MAL_NO_DEVICE;
}
// Each device is stored in pDeviceNames, separated by a null-terminator. The string itself is double-null-terminated.
const ALCchar* pNextDeviceName = pDeviceNames;
for (;;) {
*pCount += 1;
if (pInfo != NULL && infoCapacity > 0) {
mal_strncpy_s(pInfo->id.openal, sizeof(pInfo->id.openal), (const char*)pNextDeviceName, (size_t)-1);
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), (const char*)pNextDeviceName, (size_t)-1);
pInfo += 1;
infoCapacity -= 1;
}
// Move to the next device name.
while (*pNextDeviceName != '\0') {
pNextDeviceName += 1;
}
// If we've reached the double-null-terminator, we're done.
pNextDeviceName += 1;
if (*pNextDeviceName == '\0') {
break;
}
};
return MAL_SUCCESS;
}
static void mal_device_uninit__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
((MAL_LPALCDESTROYCONTEXT)pDevice->pContext->openal.alcDestroyContext)(pDevice->openal.pContextALC);
if (pDevice->type == mal_device_type_playback) {
((MAL_LPALCCLOSEDEVICE)pDevice->pContext->openal.alcCloseDevice)(pDevice->openal.pDeviceALC);
} else {
((MAL_LPALCCAPTURECLOSEDEVICE)pDevice->pContext->openal.alcCaptureCloseDevice)(pDevice->openal.pDeviceALC);
}
}
static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, mal_device_config* pConfig, mal_device* pDevice)
{
if (pDevice->periods > MAL_MAX_PERIODS_OPENAL) {
pDevice->periods = MAL_MAX_PERIODS_OPENAL;
}
ALCsizei bufferSizeInSamplesAL = pConfig->bufferSizeInFrames;
ALCuint frequencyAL = pConfig->sampleRate;
// OpenAL supports only mono and stereo.
ALCenum formatAL = 0;
if (pConfig->channels == 1) {
// Mono.
if (pConfig->format == mal_format_f32) {
if (pContext->openal.isFloat32Supported) {
formatAL = MAL_AL_FORMAT_MONO_FLOAT32;
} else {
return MAL_FORMAT_NOT_SUPPORTED;
}
} else if (pConfig->format == mal_format_s32) {
return MAL_FORMAT_NOT_SUPPORTED;
} else if (pConfig->format == mal_format_s24) {
return MAL_FORMAT_NOT_SUPPORTED;
} else if (pConfig->format == mal_format_s16) {
formatAL = AL_FORMAT_MONO16;
} else if (pConfig->format == mal_format_u8) {
formatAL = AL_FORMAT_MONO8;
}
} else {
// Stereo.
bufferSizeInSamplesAL *= 2;
if (pConfig->format == mal_format_f32) {
if (pContext->openal.isFloat32Supported) {
formatAL = MAL_AL_FORMAT_STEREO_FLOAT32;
} else {
return MAL_FORMAT_NOT_SUPPORTED;
}
} else if (pConfig->format == mal_format_s32) {
return MAL_FORMAT_NOT_SUPPORTED;
} else if (pConfig->format == mal_format_s24) {
return MAL_FORMAT_NOT_SUPPORTED;
} else if (pConfig->format == mal_format_s16) {
formatAL = AL_FORMAT_STEREO16;
} else if (pConfig->format == mal_format_u8) {
formatAL = AL_FORMAT_STEREO8;
}
}
if (formatAL == 0) {
return MAL_FORMAT_NOT_SUPPORTED;
}
// OpenAL feels a bit unintuitive to me... The global object is a device, and it would appear that each device can have
// many context's...
ALCdevice* pDeviceALC = NULL;
if (type == mal_device_type_playback) {
pDeviceALC = ((MAL_LPALCOPENDEVICE)pContext->openal.alcOpenDevice)((pDeviceID == NULL) ? NULL : pDeviceID->openal);
} else {
pDeviceALC = ((MAL_LPALCCAPTUREOPENDEVICE)pContext->openal.alcCaptureOpenDevice)((pDeviceID == NULL) ? NULL : pDeviceID->openal, frequencyAL, formatAL, bufferSizeInSamplesAL);
}
if (pDeviceALC == NULL) {
return MAL_FAILED_TO_INIT_BACKEND;
}
ALCcontext* pContextALC = ((MAL_LPALCCREATECONTEXT)pContext->openal.alcCreateContext)(pDeviceALC, NULL);
if (pContextALC == NULL) {
if (pDevice->type == mal_device_type_playback) {
((MAL_LPALCCLOSEDEVICE)pDevice->pContext->openal.alcCloseDevice)(pDeviceALC);
} else {
((MAL_LPALCCAPTURECLOSEDEVICE)pDevice->pContext->openal.alcCaptureCloseDevice)(pDeviceALC);
}
return MAL_FAILED_TO_INIT_BACKEND;
}
((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)(pContextALC);
ALuint sourceAL;
((MAL_LPALGENSOURCES)pDevice->pContext->openal.alGenSources)(1, &sourceAL);
pDevice->openal.sourceAL = sourceAL;
// We create the buffers, but only fill and queue them when the device is started.
ALuint buffersAL[MAL_MAX_PERIODS_OPENAL];
((MAL_LPALGENBUFFERS)pDevice->pContext->openal.alGenBuffers)(pDevice->periods, buffersAL);
for (mal_uint32 i = 0; i < pDevice->periods; ++i) {
pDevice->openal.buffersAL[i] = buffersAL[i];
}
return MAL_SUCCESS;
}
#if 0
static mal_result mal_device__start_backend__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
return MAL_SUCCESS;
}
static mal_result mal_device__stop_backend__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
return MAL_SUCCESS;
}
#endif
#endif // OpenAL
static mal_result mal_device__start_backend(mal_device* pDevice) static mal_result mal_device__start_backend(mal_device* pDevice)
{ {
...@@ -4104,6 +4686,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal ...@@ -4104,6 +4686,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal
mal_zero_object(pContext); mal_zero_object(pContext);
static mal_backend defaultBackends[] = { static mal_backend defaultBackends[] = {
mal_backend_openal, // TODO: Move this below all platform-specific backends.
mal_backend_dsound, mal_backend_dsound,
mal_backend_wasapi, mal_backend_wasapi,
mal_backend_alsa, mal_backend_alsa,
...@@ -4162,6 +4745,16 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal ...@@ -4162,6 +4745,16 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal
} }
} break; } break;
#endif #endif
#ifdef MAL_ENABLE_OPENAL
case mal_backend_openal:
{
mal_result result = mal_context_init__openal(pContext);
if (result == MAL_SUCCESS) {
pContext->backend = mal_backend_openal;
return result;
}
} break;
#endif
#ifdef MAL_ENABLE_NULL #ifdef MAL_ENABLE_NULL
case mal_backend_null: case mal_backend_null:
{ {
...@@ -4210,6 +4803,12 @@ mal_result mal_context_uninit(mal_context* pContext) ...@@ -4210,6 +4803,12 @@ mal_result mal_context_uninit(mal_context* pContext)
return mal_context_uninit__sles(pContext); return mal_context_uninit__sles(pContext);
} break; } break;
#endif #endif
#ifdef MAL_ENABLE_OPENAL
case mal_backend_openal:
{
return mal_context_uninit__openal(pContext);
} break;
#endif
#ifdef MAL_ENABLE_NULL #ifdef MAL_ENABLE_NULL
case mal_backend_null: case mal_backend_null:
{ {
...@@ -4255,6 +4854,12 @@ mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, ma ...@@ -4255,6 +4854,12 @@ mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, ma
return mal_enumerate_devices__sles(pContext, type, pCount, pInfo); return mal_enumerate_devices__sles(pContext, type, pCount, pInfo);
} break; } break;
#endif #endif
#ifdef MAL_ENABLE_OPENAL
case mal_backend_openal:
{
return mal_enumerate_devices__openal(pContext, type, pCount, pInfo);
} break;
#endif
#ifdef MAL_ENABLE_NULL #ifdef MAL_ENABLE_NULL
case mal_backend_null: case mal_backend_null:
{ {
...@@ -4360,6 +4965,12 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi ...@@ -4360,6 +4965,12 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi
result = mal_device_init__sles(pContext, type, pDeviceID, pConfig, pDevice); result = mal_device_init__sles(pContext, type, pDeviceID, pConfig, pDevice);
} break; } break;
#endif #endif
#ifdef MAL_ENABLE_OPENAL
case mal_backend_openal:
{
result = mal_device_init__openal(pContext, type, pDeviceID, pConfig, pDevice);
} break;
#endif
#ifdef MAL_ENABLE_NULL #ifdef MAL_ENABLE_NULL
case mal_backend_null: case mal_backend_null:
{ {
...@@ -4636,6 +5247,7 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format) ...@@ -4636,6 +5247,7 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format)
// - Requires a large suite of conversion routines including channel shuffling, SRC and format conversion. // - Requires a large suite of conversion routines including channel shuffling, SRC and format conversion.
// - Look into event callbacks: AUDCLNT_STREAMFLAGS_EVENTCALLBACK // - Look into event callbacks: AUDCLNT_STREAMFLAGS_EVENTCALLBACK
// - Link to ole32.lib at run time. // - Link to ole32.lib at run time.
// - Clean up that terrible "__cplusplus" mess by implementing wrapper functions.
// //
// //
// ALSA // ALSA
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment