mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-15 08:34:40 +00:00
fix a few issues and add more info
more info for the device is printed out, along with hrtf detection fix levelinfo sending the distance model
This commit is contained in:
parent
be872a26b4
commit
345ce3f1d3
6 changed files with 565 additions and 268 deletions
|
|
@ -217,7 +217,7 @@ U32 LevelInfo::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
|
||||||
mathWrite( *stream, mAmbientLightBlendCurve );
|
mathWrite( *stream, mAmbientLightBlendCurve );
|
||||||
|
|
||||||
sfxWrite( stream, mSoundAmbience );
|
sfxWrite( stream, mSoundAmbience );
|
||||||
stream->writeInt( mSoundDistanceModel, 1 );
|
stream->writeInt( mSoundDistanceModel, 4 );
|
||||||
|
|
||||||
PACK_ASSET_REFACTOR(conn, AccuTexture);
|
PACK_ASSET_REFACTOR(conn, AccuTexture);
|
||||||
|
|
||||||
|
|
@ -251,7 +251,7 @@ void LevelInfo::unpackUpdate(NetConnection *conn, BitStream *stream)
|
||||||
String errorStr;
|
String errorStr;
|
||||||
if( !sfxReadAndResolve( stream, &mSoundAmbience, errorStr ) )
|
if( !sfxReadAndResolve( stream, &mSoundAmbience, errorStr ) )
|
||||||
Con::errorf( "%s", errorStr.c_str() );
|
Con::errorf( "%s", errorStr.c_str() );
|
||||||
mSoundDistanceModel = ( SFXDistanceModel ) stream->readInt( 1 );
|
mSoundDistanceModel = ( SFXDistanceModel ) stream->readInt( 4 );
|
||||||
|
|
||||||
if( isProperlyAdded() )
|
if( isProperlyAdded() )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,14 @@
|
||||||
#define FUNCTION_CAST(T, ptr) (T)(ptr)
|
#define FUNCTION_CAST(T, ptr) (T)(ptr)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SFX_LOAD_AL_PROC(T, x) \
|
||||||
|
(x) = FUNCTION_CAST(T, alGetProcAddress(#x)); \
|
||||||
|
if (!(x)) Con::warnf("SFXALDevice - Failed to load " #x);
|
||||||
|
|
||||||
|
#define SFX_LOAD_ALC_PROC(T, x) \
|
||||||
|
(x) = FUNCTION_CAST(T, alcGetProcAddress(mDevice, #x)); \
|
||||||
|
if (!(x)) Con::warnf("SFXALDevice - Failed to load " #x);
|
||||||
|
|
||||||
/* Effect object functions */
|
/* Effect object functions */
|
||||||
static LPALGENFILTERS alGenFilters{ nullptr };
|
static LPALGENFILTERS alGenFilters{ nullptr };
|
||||||
static LPALDELETEFILTERS alDeleteFilters{ nullptr };
|
static LPALDELETEFILTERS alDeleteFilters{ nullptr };
|
||||||
|
|
@ -107,58 +115,288 @@ SFXDevice* SFXALDevice::createInstance(U32 providerIndex)
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SFXALDevice::_initExtensions()
|
||||||
|
{
|
||||||
|
// Device-level soft extensions — must be loaded before context creation
|
||||||
|
if (alcIsExtensionPresent(mDevice, "ALC_SOFT_reopen_device"))
|
||||||
|
{
|
||||||
|
SFX_LOAD_ALC_PROC(LPALCREOPENDEVICESOFT, alcReopenDeviceSOFT);
|
||||||
|
SFX_LOAD_ALC_PROC(LPALCRESETDEVICESOFT, alcResetDeviceSOFT);
|
||||||
|
if (alcReopenDeviceSOFT && alcResetDeviceSOFT)
|
||||||
|
{
|
||||||
|
mHasSoftReopen = true;
|
||||||
|
mCaps |= CAPS_HotReconnect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF"))
|
||||||
|
{
|
||||||
|
SFX_LOAD_ALC_PROC(LPALCGETSTRINGISOFT, alcGetStringiSOFT);
|
||||||
|
if (alcGetStringiSOFT)
|
||||||
|
{
|
||||||
|
mHasSoftHRTF = true;
|
||||||
|
mCaps |= CAPS_HRTF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alcIsExtensionPresent(mDevice, "ALC_SOFT_device_clock"))
|
||||||
|
{
|
||||||
|
SFX_LOAD_ALC_PROC(LPALCGETINTEGER64VSOFT, alcGetInteger64vSOFT);
|
||||||
|
if (alcGetInteger64vSOFT)
|
||||||
|
mCaps |= CAPS_DeviceClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alcIsExtensionPresent(mDevice, "ALC_EXT_disconnect"))
|
||||||
|
mCaps |= CAPS_DisconnectDetect;
|
||||||
|
|
||||||
|
// Context-level AL extensions — loaded after context is current
|
||||||
|
if (alIsExtensionPresent("AL_EXT_float32"))
|
||||||
|
mCaps |= CAPS_Float32;
|
||||||
|
if (alIsExtensionPresent("AL_EXT_MCFORMATS"))
|
||||||
|
mCaps |= CAPS_MonoStereo;
|
||||||
|
if (alIsExtensionPresent("AL_SOFT_source_spatialize"))
|
||||||
|
mCaps |= CAPS_SourceSpatialize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXALDevice::_initEFX()
|
||||||
|
{
|
||||||
|
if (alcIsExtensionPresent(mDevice, "ALC_EXT_EFX") != AL_TRUE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Load all EFX procs
|
||||||
|
SFX_LOAD_AL_PROC(LPALGENEFFECTS, alGenEffects);
|
||||||
|
SFX_LOAD_AL_PROC(LPALDELETEEFFECTS, alDeleteEffects);
|
||||||
|
SFX_LOAD_AL_PROC(LPALISEFFECT, alIsEffect);
|
||||||
|
SFX_LOAD_AL_PROC(LPALEFFECTI, alEffecti);
|
||||||
|
SFX_LOAD_AL_PROC(LPALEFFECTIV, alEffectiv);
|
||||||
|
SFX_LOAD_AL_PROC(LPALEFFECTF, alEffectf);
|
||||||
|
SFX_LOAD_AL_PROC(LPALEFFECTFV, alEffectfv);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGETEFFECTI, alGetEffecti);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGETEFFECTIV, alGetEffectiv);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGETEFFECTF, alGetEffectf);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGETEFFECTFV, alGetEffectfv);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGENAUXILIARYEFFECTSLOTS, alGenAuxiliaryEffectSlots);
|
||||||
|
SFX_LOAD_AL_PROC(LPALDELETEAUXILIARYEFFECTSLOTS, alDeleteAuxiliaryEffectSlots);
|
||||||
|
SFX_LOAD_AL_PROC(LPALISAUXILIARYEFFECTSLOT, alIsAuxiliaryEffectSlot);
|
||||||
|
SFX_LOAD_AL_PROC(LPALAUXILIARYEFFECTSLOTI, alAuxiliaryEffectSloti);
|
||||||
|
SFX_LOAD_AL_PROC(LPALAUXILIARYEFFECTSLOTIV, alAuxiliaryEffectSlotiv);
|
||||||
|
SFX_LOAD_AL_PROC(LPALAUXILIARYEFFECTSLOTF, alAuxiliaryEffectSlotf);
|
||||||
|
SFX_LOAD_AL_PROC(LPALAUXILIARYEFFECTSLOTFV, alAuxiliaryEffectSlotfv);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGETAUXILIARYEFFECTSLOTI, alGetAuxiliaryEffectSloti);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGETAUXILIARYEFFECTSLOTIV, alGetAuxiliaryEffectSlotiv);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGETAUXILIARYEFFECTSLOTF, alGetAuxiliaryEffectSlotf);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGETAUXILIARYEFFECTSLOTFV, alGetAuxiliaryEffectSlotfv);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGENFILTERS, alGenFilters);
|
||||||
|
SFX_LOAD_AL_PROC(LPALDELETEFILTERS, alDeleteFilters);
|
||||||
|
SFX_LOAD_AL_PROC(LPALISFILTER, alIsFilter);
|
||||||
|
SFX_LOAD_AL_PROC(LPALFILTERI, alFilteri);
|
||||||
|
SFX_LOAD_AL_PROC(LPALFILTERIV, alFilteriv);
|
||||||
|
SFX_LOAD_AL_PROC(LPALFILTERF, alFilterf);
|
||||||
|
SFX_LOAD_AL_PROC(LPALFILTERFV, alFilterfv);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGETFILTERI, alGetFilteri);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGETFILTERIV, alGetFilteriv);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGETFILTERF, alGetFilterf);
|
||||||
|
SFX_LOAD_AL_PROC(LPALGETFILTERFV, alGetFilterfv);
|
||||||
|
|
||||||
|
// Verify the minimum set we can't live without
|
||||||
|
if (!alGenEffects || !alDeleteEffects ||
|
||||||
|
!alGenAuxiliaryEffectSlots || !alDeleteAuxiliaryEffectSlots ||
|
||||||
|
!alAuxiliaryEffectSloti)
|
||||||
|
{
|
||||||
|
Con::warnf("SFXALDevice - EFX proc loading incomplete, disabling reverb");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCaps |= CAPS_Reverb | CAPS_Occlusion;
|
||||||
|
|
||||||
|
// Filters require their own procs
|
||||||
|
if (alGenFilters && alDeleteFilters && alFilteri && alFilterf)
|
||||||
|
mCaps |= CAPS_SourceFilters;
|
||||||
|
|
||||||
|
// Probe individual effect type support and slot count
|
||||||
|
_probeEFXEffectCaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFXALDevice::_probeEFXEffectCaps()
|
||||||
|
{
|
||||||
|
// Probe which effect types this driver actually supports
|
||||||
|
// by attempting to set each type on a temporary effect object.
|
||||||
|
// Some drivers report ALC_EXT_EFX but don't implement all types.
|
||||||
|
|
||||||
|
struct EffectProbe { ALenum alType; U32 cap; const char* name; };
|
||||||
|
static const EffectProbe probes[] =
|
||||||
|
{
|
||||||
|
{ AL_EFFECT_EAXREVERB, CAPS_Reverb | CAPS_EXTReverb, "EAX Reverb" },
|
||||||
|
{ AL_EFFECT_REVERB, CAPS_Reverb, "EAXReverb" },
|
||||||
|
{ AL_EFFECT_EQUALIZER, CAPS_EFX_EQ, "Equalizer" },
|
||||||
|
{ AL_EFFECT_COMPRESSOR, CAPS_EFX_Compressor,"Compressor" },
|
||||||
|
{ AL_EFFECT_ECHO, CAPS_EFX_Echo, "Echo" },
|
||||||
|
{ AL_EFFECT_CHORUS, CAPS_EFX_Chorus, "Chorus" },
|
||||||
|
{ AL_EFFECT_DISTORTION, CAPS_EFX_Distortion,"Distortion" },
|
||||||
|
{ AL_EFFECT_FLANGER, CAPS_EFX_Flanger, "Flanger" },
|
||||||
|
};
|
||||||
|
|
||||||
|
ALuint testEffect = 0;
|
||||||
|
alGenEffects(1, &testEffect);
|
||||||
|
|
||||||
|
for (const EffectProbe& probe : probes)
|
||||||
|
{
|
||||||
|
alGetError();
|
||||||
|
alEffecti(testEffect, AL_EFFECT_TYPE, probe.alType);
|
||||||
|
if (alGetError() == AL_NO_ERROR)
|
||||||
|
mCaps |= probe.cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
alDeleteEffects(1, &testEffect);
|
||||||
|
alGetError();
|
||||||
|
|
||||||
|
// Probe aux slot count
|
||||||
|
Vector<ALuint> slots;
|
||||||
|
alGetError();
|
||||||
|
while (slots.size() < 64)
|
||||||
|
{
|
||||||
|
ALuint slot = 0;
|
||||||
|
alGenAuxiliaryEffectSlots(1, &slot);
|
||||||
|
if (alGetError() != AL_NO_ERROR)
|
||||||
|
break;
|
||||||
|
slots.push_back(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
Con::setIntVariable("$pref::SFX::maxEffectSlots", (S32)slots.size());
|
||||||
|
|
||||||
|
ALCint sends = 0;
|
||||||
|
alcGetIntegerv(mDevice, ALC_MAX_AUXILIARY_SENDS, 1, &sends);
|
||||||
|
Con::setIntVariable("$pref::SFX::maxSendsPerSource", (S32)sends);
|
||||||
|
|
||||||
|
for (ALuint slot : slots)
|
||||||
|
alDeleteAuxiliaryEffectSlots(1, &slot);
|
||||||
|
alGetError();
|
||||||
|
|
||||||
|
// Allocate the device-level global reverb slot
|
||||||
|
alGenAuxiliaryEffectSlots(1, &mAuxSlot);
|
||||||
|
if (alGetError() != AL_NO_ERROR)
|
||||||
|
{
|
||||||
|
Con::warnf("SFXALDevice - Failed to create primary EFX slot");
|
||||||
|
mCaps &= ~(CAPS_Reverb | CAPS_Occlusion);
|
||||||
|
mAuxSlot = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// STATIC OPENAL FUNCTIONS
|
// STATIC OPENAL FUNCTIONS
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void SFXALDevice::printALInfo(ALCdevice* device)
|
void SFXALDevice::printALInfo(ALCdevice* device)
|
||||||
{
|
{
|
||||||
|
if (!device)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Con::printBlankLine();
|
||||||
|
Con::printf("SFX Device Info:");
|
||||||
|
Con::printf("|------------------------------------------------");
|
||||||
|
|
||||||
|
// --- Device name ---
|
||||||
|
const ALCchar* devname = alcIsExtensionPresent(device, "ALC_ENUMERATE_ALL_EXT")
|
||||||
|
? alcGetString(device, ALC_ALL_DEVICES_SPECIFIER)
|
||||||
|
: alcGetString(device, ALC_DEVICE_SPECIFIER);
|
||||||
|
Con::printf("| Device: %s", devname);
|
||||||
|
|
||||||
|
// --- OpenAL version ---
|
||||||
ALCint major, minor;
|
ALCint major, minor;
|
||||||
if (device)
|
|
||||||
{
|
|
||||||
const ALCchar* devname = NULL;
|
|
||||||
Con::printBlankLine();
|
|
||||||
|
|
||||||
if (alcIsExtensionPresent(device, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
|
|
||||||
{
|
|
||||||
devname = alcGetString(device, ALC_ALL_DEVICES_SPECIFIER);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
devname = alcGetString(device, ALC_DEVICE_SPECIFIER);
|
|
||||||
}
|
|
||||||
|
|
||||||
Con::printf("| Device info for: %s ", devname);
|
|
||||||
}
|
|
||||||
|
|
||||||
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
|
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
|
||||||
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
|
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
|
||||||
Con::printf("| OpenAL Version: %d.%d", major, minor);
|
Con::printf("| OpenAL: %d.%d", major, minor);
|
||||||
|
|
||||||
if (device)
|
// --- Audio format ---
|
||||||
|
ALCint freq = 0;
|
||||||
|
alcGetIntegerv(device, ALC_FREQUENCY, 1, &freq);
|
||||||
|
Con::printf("| Sample Rate: %d Hz", freq > 0 ? freq : 44100);
|
||||||
|
Con::printf("| Bit Depth: %d-bit", (mCaps & CAPS_Float32) ? 32 : 16);
|
||||||
|
Con::printf("| Max Voices: %d", mMaxBuffers);
|
||||||
|
|
||||||
|
Con::printf("|------------------------------------------------");
|
||||||
|
Con::printf("| Capabilities:");
|
||||||
|
|
||||||
|
// --- Hot reconnect ---
|
||||||
|
Con::printf("| Hot Reconnect: %s", (mCaps & CAPS_HotReconnect) ? "Yes" : "No");
|
||||||
|
Con::printf("| Disconnect Detect: %s", (mCaps & CAPS_DisconnectDetect) ? "Yes" : "No");
|
||||||
|
Con::printf("| Device Clock: %s", (mCaps & CAPS_DeviceClock) ? "Yes" : "No");
|
||||||
|
Con::printf("| Multi-Listener: %s", (mCaps & CAPS_MultiListener) ? "Yes" : "No");
|
||||||
|
Con::printf("| Float32 Playback: %s", (mCaps & CAPS_Float32) ? "Yes" : "No");
|
||||||
|
Con::printf("| Multi-Channel: %s", (mCaps & CAPS_MonoStereo) ? "Yes" : "No");
|
||||||
|
Con::printf("| Spatialize: %s", (mCaps & CAPS_SourceSpatialize) ? "Yes" : "No");
|
||||||
|
|
||||||
|
// --- HRTF ---
|
||||||
|
Con::printf("| HRTF: %s", (mCaps & CAPS_HRTF) ? "Yes" : "No");
|
||||||
|
if (mCaps & CAPS_HRTF)
|
||||||
{
|
{
|
||||||
const ALchar* extStr = alcGetString(device, ALC_EXTENSIONS);
|
ALCint hrtfStatus = 0;
|
||||||
if (extStr)
|
alcGetIntegerv(device, ALC_HRTF_STATUS_SOFT, 1, &hrtfStatus);
|
||||||
|
|
||||||
|
const char* statusStr = "Unknown";
|
||||||
|
switch (hrtfStatus)
|
||||||
{
|
{
|
||||||
Con::printf("| SFXALDevice - Supported ALC extensions:");
|
case ALC_HRTF_DISABLED_SOFT: statusStr = "Disabled"; break;
|
||||||
|
case ALC_HRTF_ENABLED_SOFT: statusStr = "Enabled"; break;
|
||||||
// Copy to a modifiable string.
|
case ALC_HRTF_DENIED_SOFT: statusStr = "Denied by device"; break;
|
||||||
char* extCopy = dStrdup(extStr);
|
case ALC_HRTF_REQUIRED_SOFT: statusStr = "Required by device"; break;
|
||||||
char* token = dStrtok(extCopy, " ");
|
case ALC_HRTF_HEADPHONES_DETECTED_SOFT: statusStr = "Headphones detected"; break;
|
||||||
while (token)
|
case ALC_HRTF_UNSUPPORTED_FORMAT_SOFT: statusStr = "Unsupported format"; break;
|
||||||
{
|
|
||||||
Con::printf("| %s", token);
|
|
||||||
token = dStrtok(NULL, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
dFree(extCopy);
|
|
||||||
}
|
}
|
||||||
|
Con::printf("| Status: %s", statusStr);
|
||||||
|
|
||||||
U32 err = alcGetError(device);
|
ALCint profileCount = 0;
|
||||||
if (err != ALC_NO_ERROR)
|
alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &profileCount);
|
||||||
Con::errorf("SFXALDevice - Error Retrieving ALC Extensions: %s", alcGetString(device, err));
|
Con::printf("| Profiles: %d", profileCount);
|
||||||
|
|
||||||
|
if (alcGetStringiSOFT && profileCount > 0)
|
||||||
|
for (ALCint i = 0; i < profileCount; i++)
|
||||||
|
Con::printf("| [%d] %s", i,
|
||||||
|
alcGetStringiSOFT(device, ALC_HRTF_SPECIFIER_SOFT, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- EFX ---
|
||||||
|
Con::printf("| EFX Reverb: %s", (mCaps & CAPS_Reverb) ? "Yes" : "No");
|
||||||
|
if (mCaps & CAPS_Reverb)
|
||||||
|
{
|
||||||
|
Con::printf("| EQ: %s", (mCaps & CAPS_EFX_EQ) ? "Yes" : "No");
|
||||||
|
Con::printf("| Compressor: %s", (mCaps & CAPS_EFX_Compressor) ? "Yes" : "No");
|
||||||
|
Con::printf("| Echo: %s", (mCaps & CAPS_EFX_Echo) ? "Yes" : "No");
|
||||||
|
Con::printf("| Chorus: %s", (mCaps & CAPS_EFX_Chorus) ? "Yes" : "No");
|
||||||
|
Con::printf("| Distortion: %s", (mCaps & CAPS_EFX_Distortion) ? "Yes" : "No");
|
||||||
|
Con::printf("| Flanger: %s", (mCaps & CAPS_EFX_Flanger) ? "Yes" : "No");
|
||||||
|
Con::printf("| Filters: %s", (mCaps & CAPS_SourceFilters) ? "Yes" : "No");
|
||||||
|
|
||||||
|
Con::printf("| Effect Slots: %d",
|
||||||
|
Con::getIntVariable("$pref::SFX::maxEffectSlots"));
|
||||||
|
Con::printf("| Sends/Source: %d",
|
||||||
|
Con::getIntVariable("$pref::SFX::maxSendsPerSource"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Con::printf("|------------------------------------------------");
|
||||||
|
|
||||||
|
// --- Full extension list last so it doesn't bury the important info ---
|
||||||
|
const ALchar* extStr = alcGetString(device, ALC_EXTENSIONS);
|
||||||
|
if (extStr)
|
||||||
|
{
|
||||||
|
Con::printf("| ALC Extensions:");
|
||||||
|
char* extCopy = dStrdup(extStr);
|
||||||
|
char* token = dStrtok(extCopy, " ");
|
||||||
|
while (token)
|
||||||
|
{
|
||||||
|
Con::printf("| %s", token);
|
||||||
|
token = dStrtok(NULL, " ");
|
||||||
|
}
|
||||||
|
dFree(extCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
Con::printf("|------------------------------------------------");
|
||||||
|
Con::printBlankLine();
|
||||||
|
|
||||||
|
U32 err = alcGetError(device);
|
||||||
|
if (err != ALC_NO_ERROR)
|
||||||
|
Con::errorf("SFXALDevice - ALC error after info query: %s",
|
||||||
|
alcGetString(device, err));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
S32 SFXALDevice::getMaxSources()
|
S32 SFXALDevice::getMaxSources()
|
||||||
|
|
@ -210,95 +448,56 @@ SFXALDevice::SFXALDevice(U32 providerIndex)
|
||||||
mRolloffFactor(1.0f),
|
mRolloffFactor(1.0f),
|
||||||
mUserRolloffFactor(1.0f),
|
mUserRolloffFactor(1.0f),
|
||||||
mHasEFX(false),
|
mHasEFX(false),
|
||||||
|
mHasSoftReopen(false),
|
||||||
|
mHasSoftHRTF(false),
|
||||||
mEffect(0),
|
mEffect(0),
|
||||||
mAuxSlot(0)
|
mAuxSlot(0)
|
||||||
{
|
{
|
||||||
SFXProvider* p = SFXSystem::getProvider(providerIndex);
|
SFXProvider* p = SFXSystem::getProvider(providerIndex);
|
||||||
|
|
||||||
mDevice = alcOpenDevice(p->getName());
|
mDevice = alcOpenDevice(p->getName());
|
||||||
|
if (!mDevice)
|
||||||
U32 err = alcGetError(mDevice);
|
|
||||||
if (err != ALC_NO_ERROR)
|
|
||||||
Con::errorf("SFXALDevice - Device Initialization Error: %s", alcGetString(mDevice, err));
|
|
||||||
|
|
||||||
if (mDevice)
|
|
||||||
{
|
{
|
||||||
mContext = alcCreateContext(mDevice, NULL);
|
Con::errorf("SFXALDevice - Failed to open '%s'", p->getName());
|
||||||
|
return;
|
||||||
if (mContext)
|
|
||||||
alcMakeContextCurrent(mContext);
|
|
||||||
|
|
||||||
if( err != ALC_NO_ERROR )
|
|
||||||
Con::errorf( "SFXALDevice - Context Initialization Error: %s", alcGetString( mDevice, err ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AssertFatal( mDevice != NULL && mContext != NULL, "Failed to create OpenAL device and/or context!" );
|
// Extensions that must be loaded before context creation
|
||||||
|
_initExtensions();
|
||||||
|
|
||||||
// Start the update thread.
|
mContext = alcCreateContext(mDevice, NULL);
|
||||||
// TODO AsyncPeriodicUpdateThread support for Linux/Mac
|
if (!mContext)
|
||||||
#ifdef TORQUE_OS_WIN
|
|
||||||
if( !Con::getBoolVariable( "$_forceAllMainThread" ) )
|
|
||||||
{
|
{
|
||||||
SFXInternal::gUpdateThread = new AsyncPeriodicUpdateThread
|
Con::errorf("SFXALDevice - Failed to create context (error %d)",
|
||||||
( "OpenAL Update Thread", SFXInternal::gBufferUpdateList,
|
alcGetError(mDevice));
|
||||||
Con::getIntVariable( "$pref::SFX::updateInterval", SFXInternal::DEFAULT_UPDATE_INTERVAL ) );
|
alcCloseDevice(mDevice);
|
||||||
|
mDevice = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
alcMakeContextCurrent(mContext);
|
||||||
|
|
||||||
|
#ifdef TORQUE_OS_WIN
|
||||||
|
|
||||||
|
if (!Con::getBoolVariable("$_forceAllMainThread"))
|
||||||
|
{
|
||||||
|
SFXInternal::gUpdateThread = new AsyncPeriodicUpdateThread(
|
||||||
|
"OpenAL Update Thread", SFXInternal::gBufferUpdateList,
|
||||||
|
Con::getIntVariable("$pref::SFX::updateInterval",
|
||||||
|
SFXInternal::DEFAULT_UPDATE_INTERVAL));
|
||||||
SFXInternal::gUpdateThread->start();
|
SFXInternal::gUpdateThread->start();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --- Capabilities ---
|
// Context is current — load context-level extensions and EFX
|
||||||
if (alcIsExtensionPresent(mDevice, "ALC_EXT_EFX") == AL_TRUE)
|
_initExtensions(); // second pass picks up AL_* extensions now context is current
|
||||||
mCaps |= CAPS_Reverb | CAPS_Occlusion;
|
_initEFX();
|
||||||
if (alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF") == AL_TRUE)
|
|
||||||
mCaps |= CAPS_HRTF;
|
|
||||||
if (alIsExtensionPresent("AL_EXT_float32") == AL_TRUE)
|
|
||||||
mCaps |= CAPS_Float32;
|
|
||||||
if (alIsExtensionPresent("AL_EXT_MCFORMATS") == AL_TRUE)
|
|
||||||
mCaps |= CAPS_MonoStereo;
|
|
||||||
|
|
||||||
if (mCaps & CAPS_Reverb)
|
// Read back what the device actually settled on
|
||||||
{
|
|
||||||
#define LOAD_PROC(T, x) ((x) = FUNCTION_CAST(T, alGetProcAddress(#x)))
|
|
||||||
LOAD_PROC(LPALGENEFFECTS, alGenEffects);
|
|
||||||
LOAD_PROC(LPALDELETEEFFECTS, alDeleteEffects);
|
|
||||||
LOAD_PROC(LPALISEFFECT, alIsEffect);
|
|
||||||
LOAD_PROC(LPALEFFECTI, alEffecti);
|
|
||||||
LOAD_PROC(LPALEFFECTIV, alEffectiv);
|
|
||||||
LOAD_PROC(LPALEFFECTF, alEffectf);
|
|
||||||
LOAD_PROC(LPALEFFECTFV, alEffectfv);
|
|
||||||
LOAD_PROC(LPALGETEFFECTI, alGetEffecti);
|
|
||||||
LOAD_PROC(LPALGETEFFECTIV, alGetEffectiv);
|
|
||||||
LOAD_PROC(LPALGETEFFECTF, alGetEffectf);
|
|
||||||
LOAD_PROC(LPALGETEFFECTFV, alGetEffectfv);
|
|
||||||
|
|
||||||
LOAD_PROC(LPALGENAUXILIARYEFFECTSLOTS, alGenAuxiliaryEffectSlots);
|
|
||||||
LOAD_PROC(LPALDELETEAUXILIARYEFFECTSLOTS, alDeleteAuxiliaryEffectSlots);
|
|
||||||
LOAD_PROC(LPALISAUXILIARYEFFECTSLOT, alIsAuxiliaryEffectSlot);
|
|
||||||
LOAD_PROC(LPALAUXILIARYEFFECTSLOTI, alAuxiliaryEffectSloti);
|
|
||||||
LOAD_PROC(LPALAUXILIARYEFFECTSLOTIV, alAuxiliaryEffectSlotiv);
|
|
||||||
LOAD_PROC(LPALAUXILIARYEFFECTSLOTF, alAuxiliaryEffectSlotf);
|
|
||||||
LOAD_PROC(LPALAUXILIARYEFFECTSLOTFV, alAuxiliaryEffectSlotfv);
|
|
||||||
LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTI, alGetAuxiliaryEffectSloti);
|
|
||||||
LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTIV, alGetAuxiliaryEffectSlotiv);
|
|
||||||
LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTF, alGetAuxiliaryEffectSlotf);
|
|
||||||
LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTFV, alGetAuxiliaryEffectSlotfv);
|
|
||||||
#undef LOAD_PROC
|
|
||||||
|
|
||||||
// generate our auxiliary slot for the effects.
|
|
||||||
alGenAuxiliaryEffectSlots(1, &mAuxSlot);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Device frequency ---
|
|
||||||
ALCint freq = 0;
|
ALCint freq = 0;
|
||||||
alcGetIntegerv(mDevice, ALC_FREQUENCY, 1, &freq);
|
alcGetIntegerv(mDevice, ALC_FREQUENCY, 1, &freq);
|
||||||
if (freq > 0)
|
Con::setIntVariable("$pref::SFX::frequency", freq > 0 ? freq : 44100);
|
||||||
Con::setIntVariable("$pref::SFX::frequency", freq);
|
Con::setIntVariable("$pref::SFX::bitrate", (mCaps & CAPS_Float32) ? 32 : 16);
|
||||||
else
|
|
||||||
Con::setIntVariable("$pref::SFX::frequency", 44100); // default
|
|
||||||
|
|
||||||
// --- Bitrate approximation ---
|
|
||||||
U32 bitrate = (mCaps & CAPS_Float32) ? 32 : 16;
|
|
||||||
Con::setIntVariable("$pref::SFX::bitrate", bitrate);
|
|
||||||
|
|
||||||
printALInfo(mDevice);
|
printALInfo(mDevice);
|
||||||
|
|
||||||
|
|
@ -463,8 +662,6 @@ void SFXALDevice::setReverb(const SFXReverbProperties& r)
|
||||||
if (!(mCaps & CAPS_Reverb))
|
if (!(mCaps & CAPS_Reverb))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ALenum err;
|
|
||||||
|
|
||||||
/* Clear error state. */
|
/* Clear error state. */
|
||||||
alGetError();
|
alGetError();
|
||||||
|
|
||||||
|
|
@ -473,70 +670,74 @@ void SFXALDevice::setReverb(const SFXReverbProperties& r)
|
||||||
|
|
||||||
/* Create the effect object and check if we can do EAX reverb. */
|
/* Create the effect object and check if we can do EAX reverb. */
|
||||||
alGenEffects(1, &mEffect);
|
alGenEffects(1, &mEffect);
|
||||||
alEffecti(mEffect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
|
|
||||||
err = alGetError();
|
|
||||||
|
|
||||||
// Map your engine's properties to EFX parameters.
|
// Map your engine's properties to EFX parameters.
|
||||||
// Using EAX Reverb as an example:
|
// Using EAX Reverb as an example:
|
||||||
if (err == AL_NO_ERROR)
|
if (mCaps & CAPS_EXTReverb)
|
||||||
{
|
{
|
||||||
alEffectf(mEffect, AL_EAXREVERB_DENSITY, r.flDensity);
|
// Full EAX parameter set — panning vectors, LF params, modulation etc.
|
||||||
alEffectf(mEffect, AL_EAXREVERB_DIFFUSION, r.flDiffusion);
|
alEffecti(mEffect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
|
||||||
alEffectf(mEffect, AL_EAXREVERB_GAIN, r.flGain);
|
if (alGetError() == AL_NO_ERROR)
|
||||||
alEffectf(mEffect, AL_EAXREVERB_GAINHF, r.flGainHF);
|
{
|
||||||
alEffectf(mEffect, AL_EAXREVERB_GAINLF, r.flGainLF);
|
alEffectf(mEffect, AL_EAXREVERB_DENSITY, r.flDensity);
|
||||||
alEffectf(mEffect, AL_EAXREVERB_DECAY_TIME, r.flDecayTime);
|
alEffectf(mEffect, AL_EAXREVERB_DIFFUSION, r.flDiffusion);
|
||||||
alEffectf(mEffect, AL_EAXREVERB_DECAY_HFRATIO, r.flDecayHFRatio);
|
alEffectf(mEffect, AL_EAXREVERB_GAIN, r.flGain);
|
||||||
alEffectf(mEffect, AL_EAXREVERB_DECAY_LFRATIO, r.flDecayLFRatio);
|
alEffectf(mEffect, AL_EAXREVERB_GAINHF, r.flGainHF);
|
||||||
|
alEffectf(mEffect, AL_EAXREVERB_GAINLF, r.flGainLF);
|
||||||
|
alEffectf(mEffect, AL_EAXREVERB_DECAY_TIME, r.flDecayTime);
|
||||||
|
alEffectf(mEffect, AL_EAXREVERB_DECAY_HFRATIO, r.flDecayHFRatio);
|
||||||
|
alEffectf(mEffect, AL_EAXREVERB_DECAY_LFRATIO, r.flDecayLFRatio);
|
||||||
|
|
||||||
alEffectf(mEffect, AL_EAXREVERB_REFLECTIONS_GAIN, r.flReflectionsGain);
|
alEffectf(mEffect, AL_EAXREVERB_REFLECTIONS_GAIN, r.flReflectionsGain);
|
||||||
alEffectf(mEffect, AL_EAXREVERB_REFLECTIONS_DELAY, r.flReflectionsDelay);
|
alEffectf(mEffect, AL_EAXREVERB_REFLECTIONS_DELAY, r.flReflectionsDelay);
|
||||||
alEffectfv(mEffect, AL_EAXREVERB_REFLECTIONS_PAN, r.flReflectionsPan);
|
alEffectfv(mEffect, AL_EAXREVERB_REFLECTIONS_PAN, r.flReflectionsPan);
|
||||||
|
|
||||||
alEffectf(mEffect, AL_EAXREVERB_LATE_REVERB_GAIN, r.flLateReverbGain);
|
alEffectf(mEffect, AL_EAXREVERB_LATE_REVERB_GAIN, r.flLateReverbGain);
|
||||||
alEffectf(mEffect, AL_EAXREVERB_LATE_REVERB_DELAY, r.flLateReverbDelay);
|
alEffectf(mEffect, AL_EAXREVERB_LATE_REVERB_DELAY, r.flLateReverbDelay);
|
||||||
alEffectfv(mEffect, AL_EAXREVERB_LATE_REVERB_PAN, r.flLateReverbPan);
|
alEffectfv(mEffect, AL_EAXREVERB_LATE_REVERB_PAN, r.flLateReverbPan);
|
||||||
|
|
||||||
alEffectf(mEffect, AL_EAXREVERB_ECHO_TIME, r.flEchoTime);
|
alEffectf(mEffect, AL_EAXREVERB_ECHO_TIME, r.flEchoTime);
|
||||||
alEffectf(mEffect, AL_EAXREVERB_ECHO_DEPTH, r.flEchoDepth);
|
alEffectf(mEffect, AL_EAXREVERB_ECHO_DEPTH, r.flEchoDepth);
|
||||||
alEffectf(mEffect, AL_EAXREVERB_MODULATION_TIME, r.flModulationTime);
|
alEffectf(mEffect, AL_EAXREVERB_MODULATION_TIME, r.flModulationTime);
|
||||||
alEffectf(mEffect, AL_EAXREVERB_MODULATION_DEPTH, r.flModulationDepth);
|
alEffectf(mEffect, AL_EAXREVERB_MODULATION_DEPTH, r.flModulationDepth);
|
||||||
|
|
||||||
alEffectf(mEffect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, r.flAirAbsorptionGainHF);
|
alEffectf(mEffect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, r.flAirAbsorptionGainHF);
|
||||||
alEffectf(mEffect, AL_EAXREVERB_HFREFERENCE, r.flHFReference);
|
alEffectf(mEffect, AL_EAXREVERB_HFREFERENCE, r.flHFReference);
|
||||||
alEffectf(mEffect, AL_EAXREVERB_LFREFERENCE, r.flLFReference);
|
alEffectf(mEffect, AL_EAXREVERB_LFREFERENCE, r.flLFReference);
|
||||||
alEffectf(mEffect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, r.flRoomRolloffFactor);
|
alEffectf(mEffect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, r.flRoomRolloffFactor);
|
||||||
alEffecti(mEffect, AL_EAXREVERB_DECAY_HFLIMIT, r.iDecayHFLimit);
|
alEffecti(mEffect, AL_EAXREVERB_DECAY_HFLIMIT, r.iDecayHFLimit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Standard reverb — subset of EAX, no panning/LF/modulation params
|
||||||
alEffecti(mEffect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
|
alEffecti(mEffect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
|
||||||
|
if (alGetError() == AL_NO_ERROR)
|
||||||
alEffectf(mEffect, AL_REVERB_DENSITY, r.flDensity);
|
{
|
||||||
alEffectf(mEffect, AL_REVERB_DIFFUSION, r.flDiffusion);
|
alEffectf(mEffect, AL_REVERB_DENSITY, r.flDensity);
|
||||||
alEffectf(mEffect, AL_REVERB_GAIN, r.flGain);
|
alEffectf(mEffect, AL_REVERB_DIFFUSION, r.flDiffusion);
|
||||||
alEffectf(mEffect, AL_REVERB_GAINHF, r.flGainHF);
|
alEffectf(mEffect, AL_REVERB_GAIN, r.flGain);
|
||||||
alEffectf(mEffect, AL_REVERB_DECAY_TIME, r.flDecayTime);
|
alEffectf(mEffect, AL_REVERB_GAINHF, r.flGainHF);
|
||||||
alEffectf(mEffect, AL_REVERB_DECAY_HFRATIO, r.flDecayHFRatio);
|
alEffectf(mEffect, AL_REVERB_DECAY_TIME, r.flDecayTime);
|
||||||
alEffectf(mEffect, AL_REVERB_REFLECTIONS_GAIN, r.flReflectionsGain);
|
alEffectf(mEffect, AL_REVERB_DECAY_HFRATIO, r.flDecayHFRatio);
|
||||||
alEffectf(mEffect, AL_REVERB_REFLECTIONS_DELAY, r.flReflectionsDelay);
|
alEffectf(mEffect, AL_REVERB_REFLECTIONS_GAIN, r.flReflectionsGain);
|
||||||
alEffectf(mEffect, AL_REVERB_LATE_REVERB_GAIN, r.flLateReverbGain);
|
alEffectf(mEffect, AL_REVERB_REFLECTIONS_DELAY, r.flReflectionsDelay);
|
||||||
alEffectf(mEffect, AL_REVERB_LATE_REVERB_DELAY, r.flLateReverbDelay);
|
alEffectf(mEffect, AL_REVERB_LATE_REVERB_GAIN, r.flLateReverbGain);
|
||||||
alEffectf(mEffect, AL_REVERB_AIR_ABSORPTION_GAINHF, r.flAirAbsorptionGainHF);
|
alEffectf(mEffect, AL_REVERB_LATE_REVERB_DELAY, r.flLateReverbDelay);
|
||||||
alEffectf(mEffect, AL_REVERB_ROOM_ROLLOFF_FACTOR, r.flRoomRolloffFactor);
|
alEffectf(mEffect, AL_REVERB_AIR_ABSORPTION_GAINHF, r.flAirAbsorptionGainHF);
|
||||||
alEffecti(mEffect, AL_REVERB_DECAY_HFLIMIT, r.iDecayHFLimit);
|
alEffectf(mEffect, AL_REVERB_ROOM_ROLLOFF_FACTOR, r.flRoomRolloffFactor);
|
||||||
|
alEffecti(mEffect, AL_REVERB_DECAY_HFLIMIT, r.iDecayHFLimit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = alGetError();
|
if (alGetError() == AL_NO_ERROR)
|
||||||
if (err != AL_NO_ERROR)
|
alAuxiliaryEffectSloti(mAuxSlot, AL_EFFECTSLOT_EFFECT, (ALint)mEffect);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
|
Con::warnf("SFXALDevice::setReverb - failed applying reverb parameters");
|
||||||
if (alIsEffect(mEffect))
|
if (alIsEffect(mEffect))
|
||||||
alDeleteEffects(1, &mEffect);
|
alDeleteEffects(1, &mEffect);
|
||||||
}
|
mEffect = 0;
|
||||||
else
|
|
||||||
{
|
|
||||||
// Bind updated effect to slot
|
|
||||||
alAuxiliaryEffectSloti(mAuxSlot, AL_EFFECTSLOT_EFFECT, (ALint)mEffect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -547,8 +748,6 @@ void SFXALDevice::setDopplerFactor( F32 factor )
|
||||||
alDopplerFactor( factor );
|
alDopplerFactor( factor );
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void SFXALDevice::_setRolloffFactor( F32 factor )
|
void SFXALDevice::_setRolloffFactor( F32 factor )
|
||||||
{
|
{
|
||||||
mRolloffFactor = factor;
|
mRolloffFactor = factor;
|
||||||
|
|
@ -573,3 +772,79 @@ void SFXALDevice::setSpeedOfSound(F32 speedOfSound)
|
||||||
{
|
{
|
||||||
alSpeedOfSound(speedOfSound);
|
alSpeedOfSound(speedOfSound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SFXALDevice::isDeviceConnected()
|
||||||
|
{
|
||||||
|
if (!mDevice)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// ALC_CONNECTED is a standard-ish extension, check it first
|
||||||
|
if (alcIsExtensionPresent(mDevice, "ALC_EXT_disconnect") == AL_TRUE)
|
||||||
|
{
|
||||||
|
ALCint connected = ALC_FALSE;
|
||||||
|
alcGetIntegerv(mDevice, ALC_CONNECTED, 1, &connected);
|
||||||
|
|
||||||
|
if (connected == ALC_FALSE)
|
||||||
|
{
|
||||||
|
//SFXSystem::removeProvider(mDevice->getProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (connected == ALC_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the extension isn't available, assume connected
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SFXALDevice::reconnectDevice(U32 providerIndex)
|
||||||
|
{
|
||||||
|
if (!mDevice || !mContext)
|
||||||
|
{
|
||||||
|
Con::errorf("SFXALDevice::reconnectDevice - no active device/context to reconnect");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SFXProvider* p = SFXSystem::getProvider(providerIndex);
|
||||||
|
|
||||||
|
// If no new name given, reuse the current device name (i.e. reconnect same device)
|
||||||
|
if (!p->getName() || p->getName()[0] == '\0')
|
||||||
|
{
|
||||||
|
Con::errorf("SFXALDevice::reconnectDevice - unsupported provider given.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Con::printf("SFXALDevice::reconnectDevice - reconnecting to '%s'", p->getName());
|
||||||
|
|
||||||
|
// Fast path: use ALC_SOFT_reopen_device to swap device without losing context.
|
||||||
|
// All sources/buffers remain valid, playback resumes automatically.
|
||||||
|
if (mHasSoftReopen && alcReopenDeviceSOFT)
|
||||||
|
{
|
||||||
|
// Build attribute list matching current device settings
|
||||||
|
ALCint attribs[] =
|
||||||
|
{
|
||||||
|
ALC_FREQUENCY, smDeviceFrequency,
|
||||||
|
ALC_MONO_SOURCES, mMaxBuffers,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (alcReopenDeviceSOFT(mDevice, p->getName(), attribs) == ALC_TRUE)
|
||||||
|
{
|
||||||
|
Con::printf("SFXALDevice::reconnectDevice - soft reopen succeeded");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Con::warnf("SFXALDevice::reconnectDevice - soft reopen failed (error %d), "
|
||||||
|
"falling back to full recreate", alcGetError(mDevice));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slow path: destroy context and reopen device from scratch.
|
||||||
|
// SFXSystem::createDevice will handle transitioning sounds to virtual playback.
|
||||||
|
Con::printf("SFXALDevice::reconnectDevice - performing full device recreate");
|
||||||
|
|
||||||
|
alcMakeContextCurrent(NULL);
|
||||||
|
alcDestroyContext(mContext);
|
||||||
|
mContext = NULL;
|
||||||
|
alcCloseDevice(mDevice);
|
||||||
|
mDevice = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,58 +49,64 @@
|
||||||
|
|
||||||
class SFXALDevice : public SFXDevice
|
class SFXALDevice : public SFXDevice
|
||||||
{
|
{
|
||||||
public:
|
private:
|
||||||
|
void _initExtensions();
|
||||||
|
void _initEFX();
|
||||||
|
void _probeEFXEffectCaps();
|
||||||
|
public:
|
||||||
|
|
||||||
typedef SFXDevice Parent;
|
typedef SFXDevice Parent;
|
||||||
friend class SFXALVoice; // mDistanceFactor, mRolloffFactor
|
friend class SFXALVoice; // mDistanceFactor, mRolloffFactor
|
||||||
|
|
||||||
static SFXDevice* createInstance(U32 adapterIndex);
|
static SFXDevice* createInstance(U32 adapterIndex);
|
||||||
|
|
||||||
void printALInfo(ALCdevice* device);
|
void printALInfo(ALCdevice* device);
|
||||||
void printHRTFInfo(ALCdevice* device);
|
S32 getMaxSources();
|
||||||
void getEFXInfo(ALCdevice* device);
|
|
||||||
S32 getMaxSources();
|
|
||||||
|
|
||||||
// Compatibility with pre openal 1.2
|
// Compatibility with pre openal 1.2
|
||||||
S32 getMaxSourcesOld();
|
S32 getMaxSourcesOld();
|
||||||
|
|
||||||
SFXALDevice(U32 providerIndex);
|
SFXALDevice(U32 providerIndex);
|
||||||
|
|
||||||
virtual ~SFXALDevice();
|
virtual ~SFXALDevice();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static SFXProvider::CreateProviderInstanceDelegate mCreateDeviceInstance;
|
static SFXProvider::CreateProviderInstanceDelegate mCreateDeviceInstance;
|
||||||
OPENALFNTABLE mOpenAL;
|
OPENALFNTABLE mOpenAL;
|
||||||
|
|
||||||
ALCcontext *mContext;
|
ALCcontext *mContext;
|
||||||
|
|
||||||
ALCdevice *mDevice;
|
ALCdevice *mDevice;
|
||||||
|
|
||||||
SFXDistanceModel mDistanceModel;
|
SFXDistanceModel mDistanceModel;
|
||||||
F32 mDistanceFactor;
|
F32 mDistanceFactor;
|
||||||
F32 mRolloffFactor;
|
F32 mRolloffFactor;
|
||||||
F32 mUserRolloffFactor;
|
F32 mUserRolloffFactor;
|
||||||
|
|
||||||
ALuint mEffect;
|
ALuint mEffect;
|
||||||
ALuint mAuxSlot;
|
ALuint mAuxSlot;
|
||||||
bool mHasEFX;
|
bool mHasEFX;
|
||||||
|
bool mHasSoftHRTF;
|
||||||
|
bool mHasSoftReopen;
|
||||||
|
|
||||||
void _setRolloffFactor( F32 factor );
|
void _setRolloffFactor( F32 factor );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void enumerateProviders(Vector<SFXProvider*>& providerList);
|
static void enumerateProviders(Vector<SFXProvider*>& providerList);
|
||||||
// SFXDevice.
|
// SFXDevice.
|
||||||
SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description ) override;
|
SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description ) override;
|
||||||
SFXVoice* createVoice( bool is3D, SFXBuffer *buffer ) override;
|
SFXVoice* createVoice( bool is3D, SFXBuffer *buffer ) override;
|
||||||
void setListener( U32 index, const SFXListenerProperties& listener ) override;
|
void setListener( U32 index, const SFXListenerProperties& listener ) override;
|
||||||
void setDistanceModel( SFXDistanceModel model ) override;
|
void setDistanceModel( SFXDistanceModel model ) override;
|
||||||
void setDopplerFactor( F32 factor ) override;
|
void setDopplerFactor( F32 factor ) override;
|
||||||
void setReverb(const SFXReverbProperties& reverb) override;
|
void setReverb(const SFXReverbProperties& reverb) override;
|
||||||
void setRolloffFactor( F32 factor ) override;
|
void setRolloffFactor( F32 factor ) override;
|
||||||
void resetReverb() override {}
|
void resetReverb() override {}
|
||||||
void setSpeedOfSound(F32 speedOfSound) override;
|
void setSpeedOfSound(F32 speedOfSound) override;
|
||||||
|
bool isDeviceConnected() override;
|
||||||
|
bool reconnectDevice(U32 providerIndex) override;
|
||||||
|
|
||||||
ALuint getDeviceAuxSlot() { return mAuxSlot; }
|
ALuint getDeviceAuxSlot() { return mAuxSlot; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _SFXALDEVICE_H_
|
#endif // _SFXALDEVICE_H_
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
S32 SFXDevice::smUpdateInterval = SFXInternal::DEFAULT_UPDATE_INTERVAL;
|
S32 SFXDevice::smUpdateInterval = SFXInternal::DEFAULT_UPDATE_INTERVAL;
|
||||||
S32 SFXDevice::smDeviceFrequency = 44100;
|
S32 SFXDevice::smDeviceFrequency = 44100;
|
||||||
|
S32 SFXDevice::smMaxSendsPerSource = 4;
|
||||||
|
S32 SFXDevice::smMaxEffectSlots = 4;
|
||||||
S8 SFXDevice::smDeviceBitrate = 16;
|
S8 SFXDevice::smDeviceBitrate = 16;
|
||||||
bool SFXDevice::smDeviceHRTF = false;
|
bool SFXDevice::smDeviceHRTF = false;
|
||||||
|
|
||||||
|
|
@ -52,12 +54,23 @@ void SFXDevice::initConsole()
|
||||||
Con::addVariable("$pref::SFX::updateInterval", TypeS32, &smUpdateInterval,
|
Con::addVariable("$pref::SFX::updateInterval", TypeS32, &smUpdateInterval,
|
||||||
"The update interval.\n"
|
"The update interval.\n"
|
||||||
"@ingroup SFX\n");
|
"@ingroup SFX\n");
|
||||||
|
|
||||||
|
Con::addVariable("$pref::SFX::maxSendsPerSource", TypeS32, &smMaxSendsPerSource,
|
||||||
|
"The maximum number sends allowed per source.\n"
|
||||||
|
"@ingroup SFX\n");
|
||||||
|
|
||||||
|
Con::addVariable("$pref::SFX::maxEffectSlots", TypeS32, &smMaxEffectSlots,
|
||||||
|
"The maximum number of effect slots supported by this device.\n"
|
||||||
|
"@ingroup SFX\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SFXDevice::SFXDevice()
|
SFXDevice::SFXDevice()
|
||||||
: mStatNumBuffers( 0 ),
|
: mStatNumBuffers( 0 ),
|
||||||
mStatNumVoices( 0 ),
|
mStatNumVoices( 0 ),
|
||||||
mStatNumBufferBytes( 0 )
|
mStatNumBufferBytes( 0 ),
|
||||||
|
mMaxBuffers(16),
|
||||||
|
mUseHardware(false),
|
||||||
|
mCaps(0)
|
||||||
{
|
{
|
||||||
VECTOR_SET_ASSOCIATION( mBuffers );
|
VECTOR_SET_ASSOCIATION( mBuffers );
|
||||||
VECTOR_SET_ASSOCIATION( mVoices );
|
VECTOR_SET_ASSOCIATION( mVoices );
|
||||||
|
|
|
||||||
|
|
@ -55,13 +55,25 @@ class SFXDevice
|
||||||
enum ECaps
|
enum ECaps
|
||||||
{
|
{
|
||||||
CAPS_Reverb = BIT(0), ///< Device supports reverb environments.
|
CAPS_Reverb = BIT(0), ///< Device supports reverb environments.
|
||||||
CAPS_VoiceManagement = BIT(1), ///< Device manages voices on its own; deactivates virtualization code in SFX system.
|
CAPS_EXTReverb = BIT(1), ///< Device supports extended reverb environments.
|
||||||
CAPS_Occlusion = BIT(2), ///< Device has its own sound occlusion handling (SFXOcclusionManager).
|
CAPS_VoiceManagement = BIT(2), ///< Device manages voices on its own; deactivates virtualization code in SFX system.
|
||||||
CAPS_DSPEffects = BIT(3), ///< Device implements DSP effects (SFXDSPManager).
|
CAPS_Occlusion = BIT(3), ///< Device has its own sound occlusion handling (SFXOcclusionManager).
|
||||||
CAPS_MultiListener = BIT(4), ///< Device supports multiple listeners.
|
CAPS_DSPEffects = BIT(4), ///< Device implements DSP effects (SFXDSPManager).
|
||||||
CAPS_HRTF = BIT(5), ///< Device supports HRTF (3D audio positioning).
|
CAPS_MultiListener = BIT(5), ///< Device supports multiple listeners.
|
||||||
CAPS_Float32 = BIT(6), ///< Device supports 32-bit float playback.
|
CAPS_HRTF = BIT(6), ///< Device supports HRTF (3D audio positioning).
|
||||||
CAPS_MonoStereo = BIT(7), ///< Device supports mono/stereo output modes.
|
CAPS_Float32 = BIT(7), ///< Device supports 32-bit float playback.
|
||||||
|
CAPS_MonoStereo = BIT(8), ///< Device supports mono/stereo output modes.
|
||||||
|
CAPS_EFX_EQ = BIT(9), ///< Device Supports Equalizer effect
|
||||||
|
CAPS_EFX_Compressor = BIT(10), ///< Device Supports Compressor effect
|
||||||
|
CAPS_EFX_Echo = BIT(11), ///< Device Supports Echo effect
|
||||||
|
CAPS_EFX_Chorus = BIT(12), ///< Device Supports Chorus effect
|
||||||
|
CAPS_EFX_Distortion = BIT(13), ///< Device Supports Distortion effect
|
||||||
|
CAPS_EFX_Flanger = BIT(14), ///< Device Supports Flanger effect
|
||||||
|
CAPS_SourceFilters = BIT(15), ///< Device Supports Per-source send filters (low/high/band pass)
|
||||||
|
CAPS_SourceSpatialize = BIT(16), ///< Device Supports Explicit per-source spatialize control
|
||||||
|
CAPS_HotReconnect = BIT(17), ///< Device Supports Device can be reopened without destroying context
|
||||||
|
CAPS_DeviceClock = BIT(18), ///< Device Supports High precision device clock
|
||||||
|
CAPS_DisconnectDetect = BIT(19), ///< Device Can detect hardware disconnection
|
||||||
};
|
};
|
||||||
|
|
||||||
static void initConsole();
|
static void initConsole();
|
||||||
|
|
@ -73,7 +85,10 @@ class SFXDevice
|
||||||
static S8 smDeviceBitrate;
|
static S8 smDeviceBitrate;
|
||||||
/// Does the device use hrtf
|
/// Does the device use hrtf
|
||||||
static bool smDeviceHRTF;
|
static bool smDeviceHRTF;
|
||||||
|
/// How many effect slots does this device support.
|
||||||
|
static S32 smMaxEffectSlots;
|
||||||
|
/// How many sends can each source have.
|
||||||
|
static S32 smMaxSendsPerSource;
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
typedef Vector< SFXBuffer* > BufferVector;
|
typedef Vector< SFXBuffer* > BufferVector;
|
||||||
|
|
@ -83,7 +98,7 @@ class SFXDevice
|
||||||
typedef VoiceVector::iterator VoiceIterator;
|
typedef VoiceVector::iterator VoiceIterator;
|
||||||
|
|
||||||
/// The provider which created this device.
|
/// The provider which created this device.
|
||||||
SFXProvider mProvider;
|
SFXProvider* mProvider;
|
||||||
|
|
||||||
/// Should the device try to use hardware processing.
|
/// Should the device try to use hardware processing.
|
||||||
bool mUseHardware;
|
bool mUseHardware;
|
||||||
|
|
@ -133,8 +148,8 @@ public:
|
||||||
virtual ~SFXDevice();
|
virtual ~SFXDevice();
|
||||||
|
|
||||||
/// Returns the provider which created this device.
|
/// Returns the provider which created this device.
|
||||||
virtual const SFXProvider& getProvider() { return mProvider; }
|
virtual SFXProvider* getProvider() { return mProvider; }
|
||||||
virtual void setProvider(const SFXProvider& provider) { mProvider = provider; }
|
virtual void setProvider(SFXProvider* provider) { mProvider = provider; }
|
||||||
|
|
||||||
/// Is the device set to use hardware processing.
|
/// Is the device set to use hardware processing.
|
||||||
bool getUseHardware() const { return mUseHardware; }
|
bool getUseHardware() const { return mUseHardware; }
|
||||||
|
|
@ -143,7 +158,7 @@ public:
|
||||||
S32 getMaxBuffers() const { return mMaxBuffers; }
|
S32 getMaxBuffers() const { return mMaxBuffers; }
|
||||||
|
|
||||||
/// Returns the name of this device.
|
/// Returns the name of this device.
|
||||||
const String& getName() const { return mProvider.getName(); }
|
const String& getName() const { return mProvider->getName(); }
|
||||||
|
|
||||||
/// Return the device capability flags.
|
/// Return the device capability flags.
|
||||||
U32 getCaps() const { return mCaps; }
|
U32 getCaps() const { return mCaps; }
|
||||||
|
|
@ -192,6 +207,9 @@ public:
|
||||||
/// Set the global reverb environment.
|
/// Set the global reverb environment.
|
||||||
virtual void setReverb( const SFXReverbProperties& reverb ) {}
|
virtual void setReverb( const SFXReverbProperties& reverb ) {}
|
||||||
|
|
||||||
|
virtual bool isDeviceConnected() { return true; }
|
||||||
|
virtual bool reconnectDevice(U32 provider) { return false; }
|
||||||
|
|
||||||
/// Reset the global reverb environment to its default.
|
/// Reset the global reverb environment to its default.
|
||||||
virtual void resetReverb() {}
|
virtual void resetReverb() {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -305,60 +305,60 @@ SFXProvider* SFXSystem::getProviderByTypeAndName(SFXProviderType type, const cha
|
||||||
|
|
||||||
SFXProvider* SFXSystem::getBestProviderChoice()
|
SFXProvider* SFXSystem::getBestProviderChoice()
|
||||||
{
|
{
|
||||||
const String provider = Con::getVariable("$pref::SFX::provider");
|
const String preferredProvider = Con::getVariable("$pref::SFX::provider");
|
||||||
const String device = Con::getVariable("$pref::SFX::device");
|
const String preferredDevice = Con::getVariable("$pref::SFX::device");
|
||||||
|
|
||||||
|
// Resolve provider type.
|
||||||
SFXProviderType providerType = OpenAL;
|
SFXProviderType providerType = OpenAL;
|
||||||
|
|
||||||
if (provider.isEmpty() || device.isEmpty())
|
if (!preferredProvider.isEmpty())
|
||||||
{
|
{
|
||||||
for (U32 i = 0; i < smProviders.size(); i++)
|
|
||||||
{
|
|
||||||
if (smProviders[i]->mType == OpenAL)
|
|
||||||
{
|
|
||||||
if (smProviders[i]->mDefault)
|
|
||||||
return smProviders[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
S32 ret = -1;
|
|
||||||
for (U32 i = 0; i < SFXProviderType_Count; i++)
|
for (U32 i = 0; i < SFXProviderType_Count; i++)
|
||||||
{
|
{
|
||||||
if (!dStrcmp(getProviderNameFromType((SFXProviderType)i), provider))
|
if (!dStrcmp(getProviderNameFromType((SFXProviderType)i),preferredProvider))
|
||||||
{
|
{
|
||||||
ret = i;
|
providerType = (SFXProviderType)i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == -1)
|
|
||||||
providerType = OpenAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 i = 0;
|
if (!preferredDevice.isEmpty())
|
||||||
for (i = 0; i < smProviders.size(); i++)
|
|
||||||
{
|
{
|
||||||
if (smProviders[i]->mType == providerType)
|
for (U32 i = 0; i < smProviders.size(); i++)
|
||||||
{
|
{
|
||||||
if (String::compare(smProviders[i]->getName(), device.c_str()) == 0)
|
SFXProvider* provider = smProviders[i];
|
||||||
|
|
||||||
|
if (provider->mType != providerType)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (String::compare(provider->getName(), preferredDevice.c_str()) == 0)
|
||||||
{
|
{
|
||||||
return smProviders[i];
|
return provider;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < smProviders.size(); i++)
|
for (U32 i = 0; i < smProviders.size(); i++)
|
||||||
{
|
{
|
||||||
if (smProviders[i]->mType == providerType)
|
SFXProvider* provider = smProviders[i];
|
||||||
{
|
|
||||||
if (smProviders[i]->mDefault)
|
if (provider->mType != providerType)
|
||||||
return smProviders[i];
|
continue;
|
||||||
}
|
|
||||||
|
if (provider->mDefault)
|
||||||
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (U32 i = 0; i < smProviders.size(); i++)
|
||||||
|
{
|
||||||
|
SFXProvider* provider = smProviders[i];
|
||||||
|
|
||||||
|
if (provider->mType != providerType)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -649,27 +649,10 @@ bool SFXSystem::createDevice(SFXProvider* provider)
|
||||||
Con::errorf( "SFXSystem::createDevice - failed creating device '%s'", provider->getName());
|
Con::errorf( "SFXSystem::createDevice - failed creating device '%s'", provider->getName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mDevice->setProvider(*provider);
|
|
||||||
|
|
||||||
// Print capabilities.
|
mDevice->setProvider(provider);
|
||||||
Con::printf( "\nSFXSystem::createDevice - created device '%s'", provider->getName());
|
|
||||||
Con::printf("| Device Update Interval: %d ms", SFXDevice::smUpdateInterval);
|
// device is responsible for printing its information.
|
||||||
Con::printf("| Device Sample rate: %d Hz", SFXDevice::smDeviceFrequency);
|
|
||||||
Con::printf("| Device Bitrate: %d", SFXDevice::smDeviceBitrate);
|
|
||||||
if (mDevice->getCaps() & SFXDevice::CAPS_Reverb)
|
|
||||||
Con::printf("| CAPS_Reverb");
|
|
||||||
if (mDevice->getCaps() & SFXDevice::CAPS_VoiceManagement)
|
|
||||||
Con::printf("| CAPS_VoiceManagement");
|
|
||||||
if (mDevice->getCaps() & SFXDevice::CAPS_Occlusion)
|
|
||||||
Con::printf("| CAPS_Occlusion");
|
|
||||||
if (mDevice->getCaps() & SFXDevice::CAPS_MultiListener)
|
|
||||||
Con::printf("| CAPS_MultiListener");
|
|
||||||
if (mDevice->getCaps() & SFXDevice::CAPS_HRTF)
|
|
||||||
Con::printf("| CAPS_HRTF");
|
|
||||||
if (mDevice->getCaps() & SFXDevice::CAPS_Float32)
|
|
||||||
Con::printf("| CAPS_Float32");
|
|
||||||
if (mDevice->getCaps() & SFXDevice::CAPS_MonoStereo)
|
|
||||||
Con::printf("| CAPS_MonoStereo");
|
|
||||||
|
|
||||||
// Set defaults.
|
// Set defaults.
|
||||||
mDevice->setNumListeners( getNumListeners() );
|
mDevice->setNumListeners( getNumListeners() );
|
||||||
|
|
@ -696,8 +679,8 @@ String SFXSystem::getDeviceInfoString()
|
||||||
return String();
|
return String();
|
||||||
|
|
||||||
return String::ToString( "%s\t%s\t%s\t%d\t%d",
|
return String::ToString( "%s\t%s\t%s\t%d\t%d",
|
||||||
getProviderNameFromType(mDevice->getProvider().mType),
|
getProviderNameFromType(mDevice->getProvider()->mType),
|
||||||
mDevice->getProvider().getName(),
|
mDevice->getProvider()->getName(),
|
||||||
mDevice->getUseHardware() ? "1" : "0",
|
mDevice->getUseHardware() ? "1" : "0",
|
||||||
mDevice->getMaxBuffers(),
|
mDevice->getMaxBuffers(),
|
||||||
mDevice->getCaps() );
|
mDevice->getCaps() );
|
||||||
|
|
@ -1017,8 +1000,10 @@ void SFXSystem::_update()
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a device then update it.
|
// If we have a device then update it.
|
||||||
if( mDevice )
|
if (mDevice)
|
||||||
|
{
|
||||||
mDevice->update();
|
mDevice->update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue