Merge branch 'feature/openal-hrtf' of https://github.com/envision3d/FlaxEngine into envision3d-feature/openal-hrtf

This commit is contained in:
Wojtek Figat
2023-04-19 11:41:40 +02:00
15 changed files with 480 additions and 247 deletions

View File

@@ -57,6 +57,7 @@ namespace
float Volume = 1.0f;
int32 ActiveDeviceIndex = -1;
bool MuteOnFocusLoss = true;
bool UseHRTFWhenAvailable = true;
}
class AudioService : public EngineService
@@ -94,6 +95,7 @@ void AudioSettings::Apply()
if (AudioBackend::Instance != nullptr)
{
Audio::SetDopplerFactor(DopplerFactor);
Audio::SetUseHRTFWhenAvailable(UseHRTFWhenAvailable);
}
}
@@ -141,6 +143,17 @@ void Audio::SetDopplerFactor(float value)
AudioBackend::SetDopplerFactor(value);
}
bool Audio::GetUseHRTFWhenAvailable()
{
return UseHRTFWhenAvailable;
}
void Audio::SetUseHRTFWhenAvailable(bool value)
{
UseHRTFWhenAvailable = value;
AudioBackend::Listener::ReinitializeAll();
}
void Audio::OnAddListener(AudioListener* listener)
{
ASSERT(!Listeners.Contains(listener));

View File

@@ -13,7 +13,7 @@
/// </summary>
API_CLASS(Static) class FLAXENGINE_API Audio
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Audio);
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Audio);
friend class AudioStreamingHandler;
friend class AudioClip;
@@ -90,6 +90,17 @@ public:
/// <param name="value">The value.</param>
API_PROPERTY() static void SetDopplerFactor(float value);
/// <summary>
/// Gets the preference to use HRTF audio when available. Default is true.
/// </summary>
API_PROPERTY() static bool GetUseHRTFWhenAvailable();
/// <summary>
/// Sets the preference to use HRTF audio when available. Default is true.
/// </summary>
/// <param name="value">The value.</param>
API_PROPERTY() static void SetUseHRTFWhenAvailable(bool value);
public:
static void OnAddListener(AudioListener* listener);

View File

@@ -25,6 +25,7 @@ private:
virtual void Listener_OnRemove(AudioListener* listener) = 0;
virtual void Listener_VelocityChanged(AudioListener* listener) = 0;
virtual void Listener_TransformChanged(AudioListener* listener) = 0;
virtual void Listener_ReinitializeAll() = 0;
// Source
virtual void Source_OnAdd(AudioSource* source) = 0;
@@ -94,6 +95,11 @@ public:
{
Instance->Listener_TransformChanged(listener);
}
FORCE_INLINE static void ReinitializeAll()
{
Instance->Listener_ReinitializeAll();
}
};
class Source

View File

@@ -31,6 +31,14 @@ public:
API_FIELD(Attributes="EditorOrder(200), DefaultValue(true), EditorDisplay(\"General\", \"Mute On Focus Loss\")")
bool MuteOnFocusLoss = true;
/// <summary>
/// Enables/disables HRTF audio for in-engine processing of 3d audio.
/// If enabled, the user should be using two-channel/headphones audio output and have all other surround virtualization disabled (Atmos, DTS:X, vendor specific, etc.)
/// Note: this is currently only available with the OpenAL audio backend.
/// </summary>
API_FIELD(Attributes="EditorOrder(300), DefaultValue(true), EditorDisplay(\"Spatial Audio\")")
bool UseHRTFWhenAvailable = true;
public:
/// <summary>
@@ -46,5 +54,6 @@ public:
DESERIALIZE(DisableAudio);
DESERIALIZE(DopplerFactor);
DESERIALIZE(MuteOnFocusLoss);
DESERIALIZE(UseHRTFWhenAvailable);
}
};

View File

@@ -22,6 +22,10 @@ void AudioBackendNone::Listener_TransformChanged(AudioListener* listener)
{
}
void AudioBackendNone::Listener_ReinitializeAll()
{
}
void AudioBackendNone::Source_OnAdd(AudioSource* source)
{
source->Restore();

View File

@@ -18,6 +18,7 @@ public:
void Listener_OnRemove(AudioListener* listener) override;
void Listener_VelocityChanged(AudioListener* listener) override;
void Listener_TransformChanged(AudioListener* listener) override;
void Listener_ReinitializeAll() override;
void Source_OnAdd(AudioSource* source) override;
void Source_OnRemove(AudioSource* source) override;
void Source_VelocityChanged(AudioSource* source) override;

View File

@@ -17,10 +17,11 @@
//#define AL_LIBTYPE_STATIC
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#include <OpenAL/alext.h>
#define ALC_MULTIPLE_LISTENERS 0
#define FLAX_POS_TO_OAL(vec) ((ALfloat)vec.X * -0.01f), ((ALfloat)vec.Y * 0.01f), ((ALfloat)vec.Z * -0.01f)
#define FLAX_POS_TO_OAL(vec) ((ALfloat)vec.X * -0.01f), ((ALfloat)vec.Y * 0.01f), ((ALfloat)vec.Z * 0.01f)
#if BUILD_RELEASE
#define ALC_CHECK_ERROR(method)
#else
@@ -55,7 +56,6 @@
namespace ALC
{
ALCdevice* Device = nullptr;
bool AL_EXT_float32 = false;
Array<ALCcontext*, FixedAllocation<AUDIO_MAX_LISTENERS>> Contexts;
bool IsExtensionSupported(const char* extension)
@@ -156,7 +156,7 @@ namespace ALC
void RebuildContexts(bool isChangingDevice)
{
LOG(Info, "Rebuild audio contexts");
LOG(Info, "Audio: Rebuilding audio contexts");
if (!isChangingDevice)
{
@@ -180,7 +180,18 @@ namespace ALC
}
#else
Contexts.Resize(1);
Contexts[0] = alcCreateContext(Device, nullptr);
if (Audio::GetUseHRTFWhenAvailable())
{
LOG(Info, "Audio: Enabling OpenAL HRTF");
ALCint attrs[] = { ALC_HRTF_SOFT, ALC_TRUE };
Contexts[0] = alcCreateContext(Device, attrs);
}
else
{
Contexts[0] = alcCreateContext(Device, nullptr);
}
#endif
// If only one context is available keep it active as an optimization.
@@ -303,18 +314,25 @@ void AudioBackendOAL::Listener_TransformChanged(AudioListener* listener)
const Vector3& position = listener->GetPosition();
const Quaternion& orientation = listener->GetOrientation();
const Vector3& flipX = Vector3(-1, 1, 1);
Vector3 alOrientation[2] =
{
// Forward
orientation * Vector3::Forward,
orientation * Vector3::Forward * flipX,
// Up
orientation * Vector3::Up
orientation * Vector3::Up * flipX
};
alListenerfv(AL_ORIENTATION, (float*)alOrientation);
alListener3f(AL_POSITION, FLAX_POS_TO_OAL(position));
}
void AudioBackendOAL::Listener_ReinitializeAll()
{
ALC::RebuildContexts(false);
}
void AudioBackendOAL::Source_OnAdd(AudioSource* source)
{
ALC::Source::Rebuild(source);
@@ -567,7 +585,7 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
{
if (info.BitDepth > 16)
{
if (ALC::AL_EXT_float32)
if (ALC::IsExtensionSupported("AL_EXT_float32"))
{
const uint32 bufferSize = info.NumSamples * sizeof(float);
float* sampleBufferFloat = (float*)Allocator::Allocate(bufferSize);
@@ -688,7 +706,6 @@ void AudioBackendOAL::Base_OnActiveDeviceChanged()
}
// Setup
ALC::AL_EXT_float32 = ALC::IsExtensionSupported("AL_EXT_float32");
ALC::RebuildContexts(true);
}
@@ -800,7 +817,6 @@ bool AudioBackendOAL::Base_Init()
}
// Init
ALC::AL_EXT_float32 = ALC::IsExtensionSupported("AL_EXT_float32");
SetDopplerFactor(AudioSettings::Get()->DopplerFactor);
ALC::RebuildContexts(true);
Audio::SetActiveDeviceIndex(activeDeviceIndex);

View File

@@ -18,6 +18,7 @@ public:
void Listener_OnRemove(AudioListener* listener) override;
void Listener_VelocityChanged(AudioListener* listener) override;
void Listener_TransformChanged(AudioListener* listener) override;
void Listener_ReinitializeAll() override;
void Source_OnAdd(AudioSource* source) override;
void Source_OnRemove(AudioSource* source) override;
void Source_VelocityChanged(AudioSource* source) override;

View File

@@ -331,6 +331,11 @@ void AudioBackendXAudio2::Listener_TransformChanged(AudioListener* listener)
}
}
void AudioBackendXAudio2::Listener_ReinitializeAll()
{
// TODO: Implement XAudio2 reinitialization; read HRTF audio value from Audio class
}
void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
{
// Skip if has no clip (needs audio data to create a source - needs data format information)

View File

@@ -18,6 +18,7 @@ public:
void Listener_OnRemove(AudioListener* listener) override;
void Listener_VelocityChanged(AudioListener* listener) override;
void Listener_TransformChanged(AudioListener* listener) override;
void Listener_ReinitializeAll() override;
void Source_OnAdd(AudioSource* source) override;
void Source_OnRemove(AudioSource* source) override;
void Source_VelocityChanged(AudioSource* source) override;