Refactor 3d audio for good spatial sound quality
This commit is contained in:
@@ -335,6 +335,7 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Skybox/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Skyboxes/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=slerp/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Spatialization/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=splatmap/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=splatmaps/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=SRGB/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
@@ -31,19 +31,6 @@
|
||||
#include "XAudio2/AudioBackendXAudio2.h"
|
||||
#endif
|
||||
|
||||
const Char* ToString(AudioFormat value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case AudioFormat::Raw:
|
||||
return TEXT("Raw");
|
||||
case AudioFormat::Vorbis:
|
||||
return TEXT("Vorbis");
|
||||
default:
|
||||
return TEXT("");
|
||||
}
|
||||
}
|
||||
|
||||
float AudioDataInfo::GetLength() const
|
||||
{
|
||||
return (float)NumSamples / (float)Math::Max(1U, SampleRate * NumChannels);
|
||||
|
||||
@@ -35,8 +35,7 @@ private:
|
||||
virtual void Source_VolumeChanged(AudioSource* source) = 0;
|
||||
virtual void Source_PitchChanged(AudioSource* source) = 0;
|
||||
virtual void Source_IsLoopingChanged(AudioSource* source) = 0;
|
||||
virtual void Source_MinDistanceChanged(AudioSource* source) = 0;
|
||||
virtual void Source_AttenuationChanged(AudioSource* source) = 0;
|
||||
virtual void Source_SpatialSetupChanged(AudioSource* source) = 0;
|
||||
virtual void Source_ClipLoaded(AudioSource* source) = 0;
|
||||
virtual void Source_Cleanup(AudioSource* source) = 0;
|
||||
virtual void Source_Play(AudioSource* source) = 0;
|
||||
@@ -141,14 +140,9 @@ public:
|
||||
Instance->Source_IsLoopingChanged(source);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void MinDistanceChanged(AudioSource* source)
|
||||
FORCE_INLINE static void SpatialSetupChanged(AudioSource* source)
|
||||
{
|
||||
Instance->Source_MinDistanceChanged(source);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void AttenuationChanged(AudioSource* source)
|
||||
{
|
||||
Instance->Source_AttenuationChanged(source);
|
||||
Instance->Source_SpatialSetupChanged(source);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void ClipLoaded(AudioSource* source)
|
||||
|
||||
@@ -16,7 +16,7 @@ AudioSource::AudioSource(const SpawnParams& params)
|
||||
, _velocity(Vector3::Zero)
|
||||
, _volume(1.0f)
|
||||
, _pitch(1.0f)
|
||||
, _minDistance(1.0f)
|
||||
, _minDistance(1000.0f)
|
||||
, _attenuation(1.0f)
|
||||
, _loop(false)
|
||||
, _playOnStart(false)
|
||||
@@ -30,13 +30,9 @@ void AudioSource::SetVolume(float value)
|
||||
value = Math::Saturate(value);
|
||||
if (Math::NearEqual(_volume, value))
|
||||
return;
|
||||
|
||||
_volume = value;
|
||||
|
||||
if (SourceIDs.HasItems())
|
||||
{
|
||||
AudioBackend::Source::VolumeChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSource::SetPitch(float value)
|
||||
@@ -44,27 +40,20 @@ void AudioSource::SetPitch(float value)
|
||||
value = Math::Clamp(value, 0.5f, 2.0f);
|
||||
if (Math::NearEqual(_pitch, value))
|
||||
return;
|
||||
|
||||
_pitch = value;
|
||||
|
||||
if (SourceIDs.HasItems())
|
||||
{
|
||||
AudioBackend::Source::PitchChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSource::SetIsLooping(bool value)
|
||||
{
|
||||
if (_loop == value)
|
||||
return;
|
||||
|
||||
_loop = value;
|
||||
|
||||
// When streaming we handle looping manually by the proper buffers submission
|
||||
if (SourceIDs.HasItems() && !UseStreaming())
|
||||
{
|
||||
AudioBackend::Source::IsLoopingChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSource::SetPlayOnStart(bool value)
|
||||
@@ -77,13 +66,9 @@ void AudioSource::SetMinDistance(float value)
|
||||
value = Math::Max(0.0f, value);
|
||||
if (Math::NearEqual(_minDistance, value))
|
||||
return;
|
||||
|
||||
_minDistance = value;
|
||||
|
||||
if (SourceIDs.HasItems())
|
||||
{
|
||||
AudioBackend::Source::MinDistanceChanged(this);
|
||||
}
|
||||
AudioBackend::Source::SpatialSetupChanged(this);
|
||||
}
|
||||
|
||||
void AudioSource::SetAttenuation(float value)
|
||||
@@ -91,13 +76,10 @@ void AudioSource::SetAttenuation(float value)
|
||||
value = Math::Max(0.0f, value);
|
||||
if (Math::NearEqual(_attenuation, value))
|
||||
return;
|
||||
|
||||
_attenuation = value;
|
||||
|
||||
if (SourceIDs.HasItems())
|
||||
{
|
||||
AudioBackend::Source::AttenuationChanged(this);
|
||||
}
|
||||
AudioBackend::Source::SpatialSetupChanged(this);
|
||||
}
|
||||
|
||||
void AudioSource::Play()
|
||||
@@ -313,6 +295,22 @@ void AudioSource::PlayInternal()
|
||||
_isActuallyPlayingSth = true;
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "Engine/Debug/DebugDraw.h"
|
||||
|
||||
void AudioSource::OnDebugDrawSelected()
|
||||
{
|
||||
// Draw influence range
|
||||
if (_allowSpatialization)
|
||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(_transform.Translation, _minDistance), Color::CornflowerBlue, 0, true);
|
||||
|
||||
// Base
|
||||
Actor::OnDebugDrawSelected();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void AudioSource::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
{
|
||||
// Base
|
||||
|
||||
@@ -138,8 +138,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the minimum distance at which audio attenuation starts. When the listener is closer to the source than this value, audio is heard at full volume. Once farther away the audio starts attenuating.
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(60), DefaultValue(1.0f), Limit(0, float.MaxValue, 0.1f), EditorDisplay(\"Audio Source\")")
|
||||
API_PROPERTY(Attributes="EditorOrder(60), DefaultValue(1000.0f), Limit(0, float.MaxValue, 0.1f), EditorDisplay(\"Audio Source\")")
|
||||
FORCE_INLINE float GetMinDistance() const
|
||||
{
|
||||
return _minDistance;
|
||||
@@ -160,7 +159,7 @@ public:
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the attenuation that controls how quickly does audio volume drop off as the listener moves further from the source.
|
||||
/// Sets the attenuation that controls how quickly does audio volume drop off as the listener moves further from the source. At 0, no distance attenuation ever occurs.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetAttenuation(float value);
|
||||
|
||||
@@ -257,6 +256,9 @@ public:
|
||||
const Vector3 size(50);
|
||||
return BoundingBox(_transform.Translation - size, _transform.Translation + size);
|
||||
}
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
void OnDebugDrawSelected() override;
|
||||
#endif
|
||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||
|
||||
@@ -56,11 +56,7 @@ void AudioBackendNone::Source_IsLoopingChanged(AudioSource* source)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_MinDistanceChanged(AudioSource* source)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_AttenuationChanged(AudioSource* source)
|
||||
void AudioBackendNone::Source_SpatialSetupChanged(AudioSource* source)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -26,8 +26,7 @@ public:
|
||||
void Source_VolumeChanged(AudioSource* source) override;
|
||||
void Source_PitchChanged(AudioSource* source) override;
|
||||
void Source_IsLoopingChanged(AudioSource* source) override;
|
||||
void Source_MinDistanceChanged(AudioSource* source) override;
|
||||
void Source_AttenuationChanged(AudioSource* source) override;
|
||||
void Source_SpatialSetupChanged(AudioSource* source) override;
|
||||
void Source_ClipLoaded(AudioSource* source) override;
|
||||
void Source_Cleanup(AudioSource* source) override;
|
||||
void Source_Play(AudioSource* source) override;
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
|
||||
#define ALC_MULTIPLE_LISTENERS 0
|
||||
|
||||
#define FLAX_COORD_SCALE 0.01f
|
||||
#define FLAX_COORD_SCALE 0.01f // units are meters
|
||||
#define FLAX_DST_TO_OAL(x) x * FLAX_COORD_SCALE
|
||||
#define FLAX_POS_TO_OAL(vec) ((ALfloat)vec.X * -FLAX_COORD_SCALE), ((ALfloat)vec.Y * FLAX_COORD_SCALE), ((ALfloat)vec.Z * FLAX_COORD_SCALE)
|
||||
#define FLAX_VEL_TO_OAL(vec) ((ALfloat)vec.X * -(FLAX_COORD_SCALE*FLAX_COORD_SCALE)), ((ALfloat)vec.Y * (FLAX_COORD_SCALE*FLAX_COORD_SCALE)), ((ALfloat)vec.Z * (FLAX_COORD_SCALE*FLAX_COORD_SCALE))
|
||||
#if BUILD_RELEASE
|
||||
@@ -102,7 +103,7 @@ namespace ALC
|
||||
{
|
||||
alcMakeContextCurrent(nullptr);
|
||||
|
||||
for (auto& context : Contexts)
|
||||
for (ALCcontext* context : Contexts)
|
||||
alcDestroyContext(context);
|
||||
Contexts.Clear();
|
||||
}
|
||||
@@ -113,7 +114,7 @@ namespace ALC
|
||||
{
|
||||
AudioBackend::Listener::TransformChanged(listener);
|
||||
|
||||
const auto& velocity = listener->GetVelocity();
|
||||
const Vector3 velocity = listener->GetVelocity();
|
||||
alListener3f(AL_VELOCITY, FLAX_VEL_TO_OAL(velocity));
|
||||
alListenerf(AL_GAIN, Audio::GetVolume());
|
||||
}
|
||||
@@ -146,13 +147,14 @@ namespace ALC
|
||||
if (is3D)
|
||||
{
|
||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation());
|
||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, source->GetMinDistance());
|
||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(source->GetMinDistance()));
|
||||
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(source->GetPosition()));
|
||||
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(source->GetVelocity()));
|
||||
}
|
||||
else
|
||||
{
|
||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, 0.0f);
|
||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, 0.0f);
|
||||
alSource3f(sourceID, AL_POSITION, 0.0f, 0.0f, 0.0f);
|
||||
alSource3f(sourceID, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
@@ -169,7 +171,7 @@ namespace ALC
|
||||
|
||||
if (!isChangingDevice)
|
||||
{
|
||||
for (auto& source : Audio::Sources)
|
||||
for (AudioSource* source : Audio::Sources)
|
||||
source->Cleanup();
|
||||
}
|
||||
|
||||
@@ -204,10 +206,10 @@ namespace ALC
|
||||
// Audio listeners and sources will avoid excessive context switching in such case.
|
||||
alcMakeContextCurrent(Contexts[0]);
|
||||
|
||||
for (auto& listener : Audio::Listeners)
|
||||
for (AudioListener* listener : Audio::Listeners)
|
||||
Listener::Rebuild(listener);
|
||||
|
||||
for (auto& source : Audio::Sources)
|
||||
for (AudioSource* source : Audio::Sources)
|
||||
Source::Rebuild(source);
|
||||
}
|
||||
}
|
||||
@@ -293,7 +295,7 @@ void AudioBackendOAL::Listener_OnAdd(AudioListener* listener)
|
||||
ALC::RebuildContexts(false);
|
||||
#else
|
||||
AudioBackend::Listener::TransformChanged(listener);
|
||||
const auto& velocity = listener->GetVelocity();
|
||||
const Vector3 velocity = listener->GetVelocity();
|
||||
alListener3f(AL_VELOCITY, FLAX_VEL_TO_OAL(velocity));
|
||||
alListenerf(AL_GAIN, Audio::GetVolume());
|
||||
#endif
|
||||
@@ -310,7 +312,7 @@ void AudioBackendOAL::Listener_VelocityChanged(AudioListener* listener)
|
||||
{
|
||||
ALC_GET_LISTENER_CONTEXT(listener)
|
||||
|
||||
const auto& velocity = listener->GetVelocity();
|
||||
const Vector3 velocity = listener->GetVelocity();
|
||||
alListener3f(AL_VELOCITY, FLAX_VEL_TO_OAL(velocity));
|
||||
}
|
||||
|
||||
@@ -318,11 +320,10 @@ void AudioBackendOAL::Listener_TransformChanged(AudioListener* listener)
|
||||
{
|
||||
ALC_GET_LISTENER_CONTEXT(listener)
|
||||
|
||||
const Vector3& position = listener->GetPosition();
|
||||
const Quaternion& orientation = listener->GetOrientation();
|
||||
const Vector3& flipX = Vector3(-1, 1, 1);
|
||||
|
||||
Vector3 alOrientation[2] =
|
||||
const Vector3 position = listener->GetPosition();
|
||||
const Quaternion orientation = listener->GetOrientation();
|
||||
const Vector3 flipX(-1, 1, 1);
|
||||
const Vector3 alOrientation[2] =
|
||||
{
|
||||
// Forward
|
||||
orientation * Vector3::Forward * flipX,
|
||||
@@ -394,23 +395,22 @@ void AudioBackendOAL::Source_IsLoopingChanged(AudioSource* source)
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_MinDistanceChanged(AudioSource* source)
|
||||
void AudioBackendOAL::Source_SpatialSetupChanged(AudioSource* source)
|
||||
{
|
||||
if (!source->Is3D())
|
||||
return;
|
||||
const bool is3D = source->Is3D();
|
||||
ALC_FOR_EACH_CONTEXT()
|
||||
const uint32 sourceID = source->SourceIDs[i];
|
||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, source->GetMinDistance());
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_AttenuationChanged(AudioSource* source)
|
||||
{
|
||||
if (!source->Is3D())
|
||||
return;
|
||||
ALC_FOR_EACH_CONTEXT()
|
||||
const uint32 sourceID = source->SourceIDs[i];
|
||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation());
|
||||
alSourcei(sourceID, AL_SOURCE_RELATIVE, !is3D);
|
||||
if (is3D)
|
||||
{
|
||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation());
|
||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(source->GetMinDistance()));
|
||||
}
|
||||
else
|
||||
{
|
||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, 0.0f);
|
||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,7 +496,7 @@ float AudioBackendOAL::Source_GetCurrentBufferTime(const AudioSource* source)
|
||||
alGetSourcef(source->SourceIDs[0], AL_SEC_OFFSET, &time);
|
||||
#else
|
||||
ASSERT(source->Clip && source->Clip->IsLoaded());
|
||||
const auto& clipInfo = source->Clip->AudioHeader.Info;
|
||||
const AudioDataInfo& clipInfo = source->Clip->AudioHeader.Info;
|
||||
ALint samplesPlayed;
|
||||
alGetSourcei(source->SourceIDs[0], AL_SAMPLE_OFFSET, &samplesPlayed);
|
||||
const uint32 totalSamples = clipInfo.NumSamples / clipInfo.NumChannels;
|
||||
@@ -686,7 +686,7 @@ const Char* AudioBackendOAL::Base_Name()
|
||||
void AudioBackendOAL::Base_OnActiveDeviceChanged()
|
||||
{
|
||||
// Cleanup
|
||||
for (auto& source : Audio::Sources)
|
||||
for (AudioSource* source : Audio::Sources)
|
||||
source->Cleanup();
|
||||
ALC::ClearContexts();
|
||||
if (ALC::Device != nullptr)
|
||||
@@ -696,7 +696,7 @@ void AudioBackendOAL::Base_OnActiveDeviceChanged()
|
||||
}
|
||||
|
||||
// Open device
|
||||
const auto& name = Audio::GetActiveDevice()->InternalName;
|
||||
const StringAnsi& name = Audio::GetActiveDevice()->InternalName;
|
||||
ALC::Device = alcOpenDevice(name.Get());
|
||||
if (ALC::Device == nullptr)
|
||||
{
|
||||
@@ -817,6 +817,7 @@ bool AudioBackendOAL::Base_Init()
|
||||
|
||||
// Init
|
||||
SetDopplerFactor(AudioSettings::Get()->DopplerFactor);
|
||||
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); // Default attenuation model
|
||||
ALC::RebuildContexts(true);
|
||||
Audio::SetActiveDeviceIndex(activeDeviceIndex);
|
||||
|
||||
|
||||
@@ -26,8 +26,7 @@ public:
|
||||
void Source_VolumeChanged(AudioSource* source) override;
|
||||
void Source_PitchChanged(AudioSource* source) override;
|
||||
void Source_IsLoopingChanged(AudioSource* source) override;
|
||||
void Source_MinDistanceChanged(AudioSource* source) override;
|
||||
void Source_AttenuationChanged(AudioSource* source) override;
|
||||
void Source_SpatialSetupChanged(AudioSource* source) override;
|
||||
void Source_ClipLoaded(AudioSource* source) override;
|
||||
void Source_Cleanup(AudioSource* source) override;
|
||||
void Source_Play(AudioSource* source) override;
|
||||
|
||||
@@ -25,8 +25,6 @@ API_ENUM() enum class AudioFormat
|
||||
Vorbis,
|
||||
};
|
||||
|
||||
const Char* ToString(AudioFormat value);
|
||||
|
||||
/// <summary>
|
||||
/// Meta-data describing a chunk of audio.
|
||||
/// </summary>
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
#define MAX_OUTPUT_CHANNELS 8
|
||||
#define MAX_CHANNELS_MATRIX_SIZE (MAX_INPUT_CHANNELS*MAX_OUTPUT_CHANNELS)
|
||||
|
||||
#define FLAX_COORD_SCALE 0.01f
|
||||
#define FLAX_COORD_SCALE 0.01f // units are meters
|
||||
#define FLAX_DST_TO_XAUDIO(x) x * FLAX_COORD_SCALE
|
||||
#define FLAX_POS_TO_XAUDIO(vec) X3DAUDIO_VECTOR(vec.X * FLAX_COORD_SCALE, vec.Y * FLAX_COORD_SCALE, vec.Z * FLAX_COORD_SCALE)
|
||||
#define FLAX_VEL_TO_XAUDIO(vec) X3DAUDIO_VECTOR(vec.X * (FLAX_COORD_SCALE*FLAX_COORD_SCALE), vec.Y * (FLAX_COORD_SCALE*FLAX_COORD_SCALE), vec.Z * (FLAX_COORD_SCALE*FLAX_COORD_SCALE))
|
||||
#define FLAX_VEC_TO_XAUDIO(vec) (*((X3DAUDIO_VECTOR*)&vec))
|
||||
@@ -105,7 +106,6 @@ namespace XAudio2
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
AudioSource* Source;
|
||||
|
||||
void PeekSamples();
|
||||
@@ -200,13 +200,11 @@ namespace XAudio2
|
||||
DWORD ChannelMask;
|
||||
UINT32 SampleRate;
|
||||
UINT32 Channels;
|
||||
bool UseRedirectToLFE;
|
||||
bool ForceDirty = true;
|
||||
Listener Listeners[AUDIO_MAX_LISTENERS];
|
||||
Array<Source> Sources(32); // TODO: use ChunkedArray for better performance
|
||||
Array<Buffer*> Buffers(64); // TODO: use ChunkedArray for better performance or use buffers pool?
|
||||
EngineCallback Callback;
|
||||
float MatrixCoefficients[MAX_CHANNELS_MATRIX_SIZE];
|
||||
|
||||
Listener* GetListener()
|
||||
{
|
||||
@@ -397,9 +395,9 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
|
||||
aSource->Callback.Source = source;
|
||||
aSource->IsDirty = true;
|
||||
aSource->Data.ChannelCount = header.Info.NumChannels;
|
||||
aSource->Data.InnerRadius = FLAX_DST_TO_XAUDIO(source->GetMinDistance());
|
||||
aSource->Is3D = source->Is3D();
|
||||
aSource->Pitch = source->GetPitch();
|
||||
aSource->Data.InnerRadius = source->GetMinDistance();
|
||||
aSource->UpdateTransform(source);
|
||||
aSource->UpdateVelocity(source);
|
||||
|
||||
@@ -498,21 +496,17 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
|
||||
aSource->Voice->Start();
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_MinDistanceChanged(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_SpatialSetupChanged(AudioSource* source)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
if (aSource)
|
||||
{
|
||||
aSource->Data.InnerRadius = source->GetMinDistance();
|
||||
// TODO: implement attenuation settings for 3d audio
|
||||
aSource->Data.InnerRadius = FLAX_DST_TO_XAUDIO(source->GetMinDistance());
|
||||
aSource->IsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_AttenuationChanged(AudioSource* source)
|
||||
{
|
||||
// TODO: implement it
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_ClipLoaded(AudioSource* source)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
@@ -769,7 +763,6 @@ bool AudioBackendXAudio2::Base_Init()
|
||||
LOG(Error, "Failed to get XAudio2 mastering voice channel mask. Error: 0x{0:x}", hr);
|
||||
return true;
|
||||
}
|
||||
XAudio2::UseRedirectToLFE = ((XAudio2::ChannelMask & SPEAKER_LOW_FREQUENCY) != 0);
|
||||
|
||||
// Initialize spatial audio subsystem
|
||||
DWORD dwChannelMask;
|
||||
@@ -794,19 +787,13 @@ bool AudioBackendXAudio2::Base_Init()
|
||||
|
||||
void AudioBackendXAudio2::Base_Update()
|
||||
{
|
||||
// Note: only one listener is supported for now
|
||||
const auto listener = XAudio2::GetListener();
|
||||
if (!listener)
|
||||
{
|
||||
// How can we play audio when no one is listening
|
||||
return;
|
||||
}
|
||||
|
||||
// Update dirty voices
|
||||
const auto listener = XAudio2::GetListener();
|
||||
const float dopplerFactor = AudioSettings::Get()->DopplerFactor;
|
||||
float matrixCoefficients[MAX_CHANNELS_MATRIX_SIZE];
|
||||
X3DAUDIO_DSP_SETTINGS dsp = { 0 };
|
||||
dsp.DstChannelCount = XAudio2::Channels;
|
||||
dsp.pMatrixCoefficients = XAudio2::MatrixCoefficients;
|
||||
dsp.pMatrixCoefficients = matrixCoefficients;
|
||||
for (int32 i = 0; i < XAudio2::Sources.Count(); i++)
|
||||
{
|
||||
auto& source = XAudio2::Sources[i];
|
||||
@@ -814,7 +801,7 @@ void AudioBackendXAudio2::Base_Update()
|
||||
continue;
|
||||
|
||||
dsp.SrcChannelCount = source.Data.ChannelCount;
|
||||
if (source.Is3D)
|
||||
if (source.Is3D && listener)
|
||||
{
|
||||
X3DAudioCalculate(XAudio2::X3DInstance, &listener->Data, &source.Data, X3DAUDIO_CALCULATE_MATRIX | X3DAUDIO_CALCULATE_DOPPLER, &dsp);
|
||||
}
|
||||
@@ -822,7 +809,7 @@ void AudioBackendXAudio2::Base_Update()
|
||||
{
|
||||
// Stereo
|
||||
dsp.DopplerFactor = 1.0f;
|
||||
Platform::MemoryClear(dsp.pMatrixCoefficients, sizeof(XAudio2::MatrixCoefficients));
|
||||
Platform::MemoryClear(dsp.pMatrixCoefficients, sizeof(matrixCoefficients));
|
||||
dsp.pMatrixCoefficients[0] = 1.0f;
|
||||
if (source.Format.nChannels == 1)
|
||||
{
|
||||
|
||||
@@ -26,8 +26,7 @@ public:
|
||||
void Source_VolumeChanged(AudioSource* source) override;
|
||||
void Source_PitchChanged(AudioSource* source) override;
|
||||
void Source_IsLoopingChanged(AudioSource* source) override;
|
||||
void Source_MinDistanceChanged(AudioSource* source) override;
|
||||
void Source_AttenuationChanged(AudioSource* source) override;
|
||||
void Source_SpatialSetupChanged(AudioSource* source) override;
|
||||
void Source_ClipLoaded(AudioSource* source) override;
|
||||
void Source_Cleanup(AudioSource* source) override;
|
||||
void Source_Play(AudioSource* source) override;
|
||||
|
||||
@@ -18,25 +18,11 @@
|
||||
#include "Engine/Tools/AudioTool/OggVorbisDecoder.h"
|
||||
#include "Engine/Tools/AudioTool/OggVorbisEncoder.h"
|
||||
#include "Engine/Serialization/JsonWriters.h"
|
||||
|
||||
ImportAudio::Options::Options()
|
||||
{
|
||||
Format = AudioFormat::Vorbis;
|
||||
DisableStreaming = false;
|
||||
Is3D = false;
|
||||
Quality = 0.4f;
|
||||
BitDepth = 16;
|
||||
}
|
||||
#include "Engine/Scripting/Enums.h"
|
||||
|
||||
String ImportAudio::Options::ToString() const
|
||||
{
|
||||
return String::Format(TEXT("Format:{}, DisableStreaming:{}, Is3D:{}, Quality:{}, BitDepth:{}"),
|
||||
::ToString(Format),
|
||||
DisableStreaming,
|
||||
Is3D,
|
||||
Quality,
|
||||
BitDepth
|
||||
);
|
||||
return String::Format(TEXT("Format:{}, DisableStreaming:{}, Is3D:{}, Quality:{}, BitDepth:{}"), ScriptingEnum::ToString(Format), DisableStreaming, Is3D, Quality, BitDepth);
|
||||
}
|
||||
|
||||
void ImportAudio::Options::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
@@ -59,11 +45,9 @@ void ImportAudio::Options::Deserialize(DeserializeStream& stream, ISerializeModi
|
||||
DESERIALIZE(BitDepth);
|
||||
}
|
||||
|
||||
bool ImportAudio::TryGetImportOptions(String path, Options& options)
|
||||
bool ImportAudio::TryGetImportOptions(const String& path, Options& options)
|
||||
{
|
||||
#if IMPORT_AUDIO_CACHE_OPTIONS
|
||||
|
||||
// Check if target asset file exists
|
||||
if (FileSystem::FileExists(path))
|
||||
{
|
||||
// Try to load asset file and asset info
|
||||
@@ -88,7 +72,6 @@ bool ImportAudio::TryGetImportOptions(String path, Options& options)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -123,9 +106,7 @@ CreateAssetResult ImportAudio::Import(CreateAssetContext& context, AudioDecoder&
|
||||
Array<byte> audioData;
|
||||
if (decoder.Convert(stream, info, audioData))
|
||||
return CreateAssetResult::Error;
|
||||
|
||||
const float length = info.NumSamples / static_cast<float>(Math::Max(1U, info.SampleRate * info.NumChannels));
|
||||
LOG(Info, "Audio: {0}kHz, channels: {1}, Bit depth: {2}, Length: {3}s", info.SampleRate / 1000.0f, info.NumChannels, info.BitDepth, length);
|
||||
LOG(Info, "Audio: {0}kHz, channels: {1}, Bit depth: {2}, Length: {3}s", info.SampleRate / 1000.0f, info.NumChannels, info.BitDepth, info.GetLength());
|
||||
|
||||
// Load the whole audio data
|
||||
uint32 bytesPerSample = info.BitDepth / 8;
|
||||
@@ -222,7 +203,7 @@ CreateAssetResult ImportAudio::Import(CreateAssetContext& context, AudioDecoder&
|
||||
{
|
||||
// Split audio data into a several chunks (uniform data spread)
|
||||
const int32 MinChunkSize = 1 * 1024 * 1024; // 1 MB
|
||||
const int32 chunkSize = Math::Max<int32>(MinChunkSize, Math::AlignUp<uint32>(bufferSize / ASSET_FILE_DATA_CHUNKS, 256));
|
||||
const int32 chunkSize = Math::Max<int32>(MinChunkSize, (int32)Math::AlignUp<uint32>(bufferSize / ASSET_FILE_DATA_CHUNKS, 256));
|
||||
const int32 chunksCount = Math::CeilToInt((float)bufferSize / chunkSize);
|
||||
ASSERT(chunksCount > 0 && chunksCount <= ASSET_FILE_DATA_CHUNKS);
|
||||
|
||||
|
||||
@@ -25,24 +25,14 @@ public:
|
||||
/// </summary>
|
||||
struct Options : public ISerializable
|
||||
{
|
||||
AudioFormat Format;
|
||||
bool DisableStreaming;
|
||||
bool Is3D;
|
||||
int32 BitDepth;
|
||||
float Quality;
|
||||
AudioFormat Format = AudioFormat::Vorbis;
|
||||
bool DisableStreaming = false;
|
||||
bool Is3D = false;
|
||||
int32 BitDepth = 16;
|
||||
float Quality = 0.4f;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Options"/> struct.
|
||||
/// </summary>
|
||||
Options();
|
||||
|
||||
/// <summary>
|
||||
/// Gets string that contains information about options
|
||||
/// </summary>
|
||||
/// <returns>String</returns>
|
||||
String ToString() const;
|
||||
|
||||
public:
|
||||
// [ISerializable]
|
||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||
@@ -55,7 +45,7 @@ public:
|
||||
/// <param name="path">The asset path.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>True if success, otherwise false.</returns>
|
||||
static bool TryGetImportOptions(String path, Options& options);
|
||||
static bool TryGetImportOptions(const String& path, Options& options);
|
||||
|
||||
/// <summary>
|
||||
/// Imports the audio data (with given audio decoder).
|
||||
@@ -80,14 +70,12 @@ public:
|
||||
static CreateAssetResult ImportMp3(CreateAssetContext& context);
|
||||
|
||||
#if COMPILE_WITH_OGG_VORBIS
|
||||
|
||||
/// <summary>
|
||||
/// Imports the .ogg audio file.
|
||||
/// </summary>
|
||||
/// <param name="context">The importing context.</param>
|
||||
/// <returns>Result.</returns>
|
||||
static CreateAssetResult ImportOgg(CreateAssetContext& context);
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user