mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-24 15:01:16 +01:00
OpenAL: load DLL dynamically
This commit is contained in:
parent
18e70cdf91
commit
c882d52f4a
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@ -14,45 +15,115 @@
|
|||||||
#include "Common/Thread.h"
|
#include "Common/Thread.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
static HMODULE s_openal_dll = nullptr;
|
||||||
#pragma comment(lib, "openal32.lib")
|
|
||||||
#endif
|
#define OPENAL_API_VISIT(X) \
|
||||||
|
X(alBufferData) \
|
||||||
|
X(alcCloseDevice) \
|
||||||
|
X(alcCreateContext) \
|
||||||
|
X(alcDestroyContext) \
|
||||||
|
X(alcGetContextsDevice) \
|
||||||
|
X(alcGetCurrentContext) \
|
||||||
|
X(alcGetString) \
|
||||||
|
X(alcIsExtensionPresent) \
|
||||||
|
X(alcMakeContextCurrent) \
|
||||||
|
X(alcOpenDevice) \
|
||||||
|
X(alDeleteBuffers) \
|
||||||
|
X(alDeleteSources) \
|
||||||
|
X(alGenBuffers) \
|
||||||
|
X(alGenSources) \
|
||||||
|
X(alGetError) \
|
||||||
|
X(alGetSourcei) \
|
||||||
|
X(alGetString) \
|
||||||
|
X(alIsExtensionPresent) \
|
||||||
|
X(alSourcef) \
|
||||||
|
X(alSourcei) \
|
||||||
|
X(alSourcePlay) \
|
||||||
|
X(alSourceQueueBuffers) \
|
||||||
|
X(alSourceStop) \
|
||||||
|
X(alSourceUnqueueBuffers)
|
||||||
|
|
||||||
|
// Create func_t function pointer type and declare a nullptr-initialized static variable of that
|
||||||
|
// type named "pfunc".
|
||||||
|
#define DYN_FUNC_DECLARE(func) \
|
||||||
|
typedef decltype(&func) func##_t; \
|
||||||
|
static func##_t p##func = nullptr;
|
||||||
|
|
||||||
|
// Attempt to load the function from the given module handle.
|
||||||
|
#define OPENAL_FUNC_LOAD(func) \
|
||||||
|
p##func = (func##_t)::GetProcAddress(s_openal_dll, #func); \
|
||||||
|
if (!p##func) \
|
||||||
|
{ \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
|
OPENAL_API_VISIT(DYN_FUNC_DECLARE);
|
||||||
|
|
||||||
|
static bool InitFunctions()
|
||||||
|
{
|
||||||
|
OPENAL_API_VISIT(OPENAL_FUNC_LOAD);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool InitLibrary()
|
||||||
|
{
|
||||||
|
if (s_openal_dll)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
s_openal_dll = ::LoadLibrary(TEXT("openal32.dll"));
|
||||||
|
if (!s_openal_dll)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!InitFunctions())
|
||||||
|
{
|
||||||
|
::FreeLibrary(s_openal_dll);
|
||||||
|
s_openal_dll = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenALStream::isValid()
|
||||||
|
{
|
||||||
|
return InitLibrary();
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// AyuanX: Spec says OpenAL1.1 is thread safe already
|
// AyuanX: Spec says OpenAL1.1 is thread safe already
|
||||||
//
|
//
|
||||||
bool OpenALStream::Start()
|
bool OpenALStream::Start()
|
||||||
{
|
{
|
||||||
if (!alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
|
if (!palcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
|
||||||
{
|
{
|
||||||
PanicAlertT("OpenAL: can't find sound devices");
|
PanicAlertT("OpenAL: can't find sound devices");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* defaultDeviceName = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
|
const char* defaultDeviceName = palcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||||
INFO_LOG(AUDIO, "Found OpenAL device %s", defaultDeviceName);
|
INFO_LOG(AUDIO, "Found OpenAL device %s", defaultDeviceName);
|
||||||
|
|
||||||
ALCdevice* pDevice = alcOpenDevice(defaultDeviceName);
|
ALCdevice* pDevice = palcOpenDevice(defaultDeviceName);
|
||||||
if (!pDevice)
|
if (!pDevice)
|
||||||
{
|
{
|
||||||
PanicAlertT("OpenAL: can't open device %s", defaultDeviceName);
|
PanicAlertT("OpenAL: can't open device %s", defaultDeviceName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALCcontext* pContext = alcCreateContext(pDevice, nullptr);
|
ALCcontext* pContext = palcCreateContext(pDevice, nullptr);
|
||||||
if (!pContext)
|
if (!pContext)
|
||||||
{
|
{
|
||||||
alcCloseDevice(pDevice);
|
palcCloseDevice(pDevice);
|
||||||
PanicAlertT("OpenAL: can't create context for device %s", defaultDeviceName);
|
PanicAlertT("OpenAL: can't create context for device %s", defaultDeviceName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to determine an appropriate period size (2x period = total buffer size)
|
// Used to determine an appropriate period size (2x period = total buffer size)
|
||||||
// ALCint refresh;
|
// ALCint refresh;
|
||||||
// alcGetIntegerv(pDevice, ALC_REFRESH, 1, &refresh);
|
// palcGetIntegerv(pDevice, ALC_REFRESH, 1, &refresh);
|
||||||
// period_size_in_millisec = 1000 / refresh;
|
// period_size_in_millisec = 1000 / refresh;
|
||||||
|
|
||||||
alcMakeContextCurrent(pContext);
|
palcMakeContextCurrent(pContext);
|
||||||
m_run_thread.Set();
|
m_run_thread.Set();
|
||||||
thread = std::thread(&OpenALStream::SoundLoop, this);
|
thread = std::thread(&OpenALStream::SoundLoop, this);
|
||||||
return true;
|
return true;
|
||||||
@ -66,20 +137,20 @@ void OpenALStream::Stop()
|
|||||||
|
|
||||||
thread.join();
|
thread.join();
|
||||||
|
|
||||||
alSourceStop(uiSource);
|
palSourceStop(uiSource);
|
||||||
alSourcei(uiSource, AL_BUFFER, 0);
|
palSourcei(uiSource, AL_BUFFER, 0);
|
||||||
|
|
||||||
// Clean up buffers and sources
|
// Clean up buffers and sources
|
||||||
alDeleteSources(1, &uiSource);
|
palDeleteSources(1, &uiSource);
|
||||||
uiSource = 0;
|
uiSource = 0;
|
||||||
alDeleteBuffers(numBuffers, uiBuffers);
|
palDeleteBuffers(numBuffers, uiBuffers);
|
||||||
|
|
||||||
ALCcontext* pContext = alcGetCurrentContext();
|
ALCcontext* pContext = palcGetCurrentContext();
|
||||||
ALCdevice* pDevice = alcGetContextsDevice(pContext);
|
ALCdevice* pDevice = palcGetContextsDevice(pContext);
|
||||||
|
|
||||||
alcMakeContextCurrent(nullptr);
|
palcMakeContextCurrent(nullptr);
|
||||||
alcDestroyContext(pContext);
|
palcDestroyContext(pContext);
|
||||||
alcCloseDevice(pDevice);
|
palcCloseDevice(pDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenALStream::SetVolume(int volume)
|
void OpenALStream::SetVolume(int volume)
|
||||||
@ -87,7 +158,7 @@ void OpenALStream::SetVolume(int volume)
|
|||||||
fVolume = (float)volume / 100.0f;
|
fVolume = (float)volume / 100.0f;
|
||||||
|
|
||||||
if (uiSource)
|
if (uiSource)
|
||||||
alSourcef(uiSource, AL_GAIN, fVolume);
|
palSourcef(uiSource, AL_GAIN, fVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenALStream::Update()
|
void OpenALStream::Update()
|
||||||
@ -101,17 +172,17 @@ void OpenALStream::Clear(bool mute)
|
|||||||
|
|
||||||
if (m_muted)
|
if (m_muted)
|
||||||
{
|
{
|
||||||
alSourceStop(uiSource);
|
palSourceStop(uiSource);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
alSourcePlay(uiSource);
|
palSourcePlay(uiSource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ALenum CheckALError(const char* desc)
|
static ALenum CheckALError(const char* desc)
|
||||||
{
|
{
|
||||||
ALenum err = alGetError();
|
ALenum err = palGetError();
|
||||||
|
|
||||||
if (err != AL_NO_ERROR)
|
if (err != AL_NO_ERROR)
|
||||||
{
|
{
|
||||||
@ -147,15 +218,15 @@ static ALenum CheckALError(const char* desc)
|
|||||||
|
|
||||||
static bool IsCreativeXFi()
|
static bool IsCreativeXFi()
|
||||||
{
|
{
|
||||||
return strstr(alGetString(AL_RENDERER), "X-Fi") != nullptr;
|
return strstr(palGetString(AL_RENDERER), "X-Fi") != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenALStream::SoundLoop()
|
void OpenALStream::SoundLoop()
|
||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("Audio thread - openal");
|
Common::SetCurrentThreadName("Audio thread - openal");
|
||||||
|
|
||||||
bool float32_capable = alIsExtensionPresent("AL_EXT_float32") != 0;
|
bool float32_capable = palIsExtensionPresent("AL_EXT_float32") != 0;
|
||||||
bool surround_capable = alIsExtensionPresent("AL_EXT_MCFORMATS") || IsCreativeXFi();
|
bool surround_capable = palIsExtensionPresent("AL_EXT_MCFORMATS") || IsCreativeXFi();
|
||||||
bool use_surround = SConfig::GetInstance().bDPL2Decoder && surround_capable;
|
bool use_surround = SConfig::GetInstance().bDPL2Decoder && surround_capable;
|
||||||
|
|
||||||
// As there is no extension to check for 32-bit fixed point support
|
// As there is no extension to check for 32-bit fixed point support
|
||||||
@ -170,18 +241,18 @@ void OpenALStream::SoundLoop()
|
|||||||
uiSource = 0;
|
uiSource = 0;
|
||||||
|
|
||||||
// Clear error state before querying or else we get false positives.
|
// Clear error state before querying or else we get false positives.
|
||||||
ALenum err = alGetError();
|
ALenum err = palGetError();
|
||||||
|
|
||||||
// Generate some AL Buffers for streaming
|
// Generate some AL Buffers for streaming
|
||||||
alGenBuffers(numBuffers, (ALuint*)uiBuffers);
|
palGenBuffers(numBuffers, (ALuint*)uiBuffers);
|
||||||
err = CheckALError("generating buffers");
|
err = CheckALError("generating buffers");
|
||||||
|
|
||||||
// Generate a Source to playback the Buffers
|
// Generate a Source to playback the Buffers
|
||||||
alGenSources(1, &uiSource);
|
palGenSources(1, &uiSource);
|
||||||
err = CheckALError("generating sources");
|
err = CheckALError("generating sources");
|
||||||
|
|
||||||
// Set the default sound volume as saved in the config file.
|
// Set the default sound volume as saved in the config file.
|
||||||
alSourcef(uiSource, AL_GAIN, fVolume);
|
palSourcef(uiSource, AL_GAIN, fVolume);
|
||||||
|
|
||||||
// TODO: Error handling
|
// TODO: Error handling
|
||||||
// ALenum err = alGetError();
|
// ALenum err = alGetError();
|
||||||
@ -194,7 +265,7 @@ void OpenALStream::SoundLoop()
|
|||||||
{
|
{
|
||||||
// Block until we have a free buffer
|
// Block until we have a free buffer
|
||||||
int numBuffersProcessed;
|
int numBuffersProcessed;
|
||||||
alGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &numBuffersProcessed);
|
palGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &numBuffersProcessed);
|
||||||
if (numBuffers == numBuffersQueued && !numBuffersProcessed)
|
if (numBuffers == numBuffersQueued && !numBuffersProcessed)
|
||||||
{
|
{
|
||||||
soundSyncEvent.Wait();
|
soundSyncEvent.Wait();
|
||||||
@ -205,7 +276,7 @@ void OpenALStream::SoundLoop()
|
|||||||
if (numBuffersProcessed)
|
if (numBuffersProcessed)
|
||||||
{
|
{
|
||||||
ALuint unqueuedBufferIds[OAL_MAX_BUFFERS];
|
ALuint unqueuedBufferIds[OAL_MAX_BUFFERS];
|
||||||
alSourceUnqueueBuffers(uiSource, numBuffersProcessed, unqueuedBufferIds);
|
palSourceUnqueueBuffers(uiSource, numBuffersProcessed, unqueuedBufferIds);
|
||||||
err = CheckALError("unqueuing buffers");
|
err = CheckALError("unqueuing buffers");
|
||||||
|
|
||||||
numBuffersQueued -= numBuffersProcessed;
|
numBuffersQueued -= numBuffersProcessed;
|
||||||
@ -235,7 +306,7 @@ void OpenALStream::SoundLoop()
|
|||||||
|
|
||||||
if (float32_capable)
|
if (float32_capable)
|
||||||
{
|
{
|
||||||
alBufferData(uiBuffers[nextBuffer], AL_FORMAT_51CHN32, dpl2,
|
palBufferData(uiBuffers[nextBuffer], AL_FORMAT_51CHN32, dpl2,
|
||||||
numSamples * FRAME_SURROUND_FLOAT, ulFrequency);
|
numSamples * FRAME_SURROUND_FLOAT, ulFrequency);
|
||||||
}
|
}
|
||||||
else if (fixed32_capable)
|
else if (fixed32_capable)
|
||||||
@ -256,7 +327,7 @@ void OpenALStream::SoundLoop()
|
|||||||
surround_int32[i] = (int)dpl2[i];
|
surround_int32[i] = (int)dpl2[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
alBufferData(uiBuffers[nextBuffer], AL_FORMAT_51CHN32, surround_int32,
|
palBufferData(uiBuffers[nextBuffer], AL_FORMAT_51CHN32, surround_int32,
|
||||||
numSamples * FRAME_SURROUND_INT32, ulFrequency);
|
numSamples * FRAME_SURROUND_INT32, ulFrequency);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -274,7 +345,7 @@ void OpenALStream::SoundLoop()
|
|||||||
surround_short[i] = (int)dpl2[i];
|
surround_short[i] = (int)dpl2[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
alBufferData(uiBuffers[nextBuffer], AL_FORMAT_51CHN16, surround_short,
|
palBufferData(uiBuffers[nextBuffer], AL_FORMAT_51CHN16, surround_short,
|
||||||
numSamples * FRAME_SURROUND_SHORT, ulFrequency);
|
numSamples * FRAME_SURROUND_SHORT, ulFrequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,7 +371,7 @@ void OpenALStream::SoundLoop()
|
|||||||
|
|
||||||
if (float32_capable)
|
if (float32_capable)
|
||||||
{
|
{
|
||||||
alBufferData(uiBuffers[nextBuffer], AL_FORMAT_STEREO_FLOAT32, sampleBuffer,
|
palBufferData(uiBuffers[nextBuffer], AL_FORMAT_STEREO_FLOAT32, sampleBuffer,
|
||||||
numSamples * FRAME_STEREO_FLOAT, ulFrequency);
|
numSamples * FRAME_STEREO_FLOAT, ulFrequency);
|
||||||
|
|
||||||
err = CheckALError("buffering float32 data");
|
err = CheckALError("buffering float32 data");
|
||||||
@ -316,7 +387,7 @@ void OpenALStream::SoundLoop()
|
|||||||
for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i)
|
for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i)
|
||||||
stereo_int32[i] = (int)((float)sampleBuffer[i] * (INT64_C(1) << 31));
|
stereo_int32[i] = (int)((float)sampleBuffer[i] * (INT64_C(1) << 31));
|
||||||
|
|
||||||
alBufferData(uiBuffers[nextBuffer], AL_FORMAT_STEREO32, stereo_int32,
|
palBufferData(uiBuffers[nextBuffer], AL_FORMAT_STEREO32, stereo_int32,
|
||||||
numSamples * FRAME_STEREO_INT32, ulFrequency);
|
numSamples * FRAME_STEREO_INT32, ulFrequency);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -326,22 +397,22 @@ void OpenALStream::SoundLoop()
|
|||||||
for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i)
|
for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i)
|
||||||
stereo[i] = (short)((float)sampleBuffer[i] * (1 << 15));
|
stereo[i] = (short)((float)sampleBuffer[i] * (1 << 15));
|
||||||
|
|
||||||
alBufferData(uiBuffers[nextBuffer], AL_FORMAT_STEREO16, stereo,
|
palBufferData(uiBuffers[nextBuffer], AL_FORMAT_STEREO16, stereo,
|
||||||
numSamples * FRAME_STEREO_SHORT, ulFrequency);
|
numSamples * FRAME_STEREO_SHORT, ulFrequency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
alSourceQueueBuffers(uiSource, 1, &uiBuffers[nextBuffer]);
|
palSourceQueueBuffers(uiSource, 1, &uiBuffers[nextBuffer]);
|
||||||
err = CheckALError("queuing buffers");
|
err = CheckALError("queuing buffers");
|
||||||
|
|
||||||
numBuffersQueued++;
|
numBuffersQueued++;
|
||||||
nextBuffer = (nextBuffer + 1) % numBuffers;
|
nextBuffer = (nextBuffer + 1) % numBuffers;
|
||||||
|
|
||||||
alGetSourcei(uiSource, AL_SOURCE_STATE, &iState);
|
palGetSourcei(uiSource, AL_SOURCE_STATE, &iState);
|
||||||
if (iState != AL_PLAYING)
|
if (iState != AL_PLAYING)
|
||||||
{
|
{
|
||||||
// Buffer underrun occurred, resume playback
|
// Buffer underrun occurred, resume playback
|
||||||
alSourcePlay(uiSource);
|
palSourcePlay(uiSource);
|
||||||
err = CheckALError("occurred resuming playback");
|
err = CheckALError("occurred resuming playback");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,8 @@ public:
|
|||||||
void Clear(bool mute) override;
|
void Clear(bool mute) override;
|
||||||
void Update() override;
|
void Update() override;
|
||||||
|
|
||||||
static bool isValid() { return true; }
|
static bool isValid();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::thread thread;
|
std::thread thread;
|
||||||
Common::Flag m_run_thread;
|
Common::Flag m_run_thread;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user