Refactor Audio Backend to not depend on AudioSource object
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "Audio.h"
|
||||
#include "AudioBackend.h"
|
||||
#include "AudioListener.h"
|
||||
#include "AudioSettings.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
@@ -149,45 +148,6 @@ void Audio::SetEnableHRTF(bool value)
|
||||
AudioBackend::Listener::ReinitializeAll();
|
||||
}
|
||||
|
||||
void Audio::OnAddListener(AudioListener* listener)
|
||||
{
|
||||
ASSERT(!Listeners.Contains(listener));
|
||||
|
||||
if (Listeners.Count() >= AUDIO_MAX_LISTENERS)
|
||||
{
|
||||
LOG(Error, "Unsupported amount of the audio listeners!");
|
||||
return;
|
||||
}
|
||||
|
||||
Listeners.Add(listener);
|
||||
AudioBackend::Listener::Reset();
|
||||
AudioBackend::Listener::TransformChanged(listener->GetPosition(), listener->GetOrientation());
|
||||
}
|
||||
|
||||
void Audio::OnRemoveListener(AudioListener* listener)
|
||||
{
|
||||
if (!Listeners.Remove(listener))
|
||||
{
|
||||
AudioBackend::Listener::Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::OnAddSource(AudioSource* source)
|
||||
{
|
||||
ASSERT(!Sources.Contains(source));
|
||||
|
||||
Sources.Add(source);
|
||||
AudioBackend::Source::OnAdd(source);
|
||||
}
|
||||
|
||||
void Audio::OnRemoveSource(AudioSource* source)
|
||||
{
|
||||
if (!Sources.Remove(source))
|
||||
{
|
||||
AudioBackend::Source::OnRemove(source);
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioService::Init()
|
||||
{
|
||||
PROFILE_CPU_NAMED("Audio.Init");
|
||||
|
||||
@@ -97,11 +97,4 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
API_PROPERTY() static void SetEnableHRTF(bool value);
|
||||
|
||||
public:
|
||||
static void OnAddListener(AudioListener* listener);
|
||||
static void OnRemoveListener(AudioListener* listener);
|
||||
|
||||
static void OnAddSource(AudioSource* source);
|
||||
static void OnRemoveSource(AudioSource* source);
|
||||
};
|
||||
|
||||
@@ -32,32 +32,30 @@ private:
|
||||
virtual void Listener_ReinitializeAll() = 0;
|
||||
|
||||
// Source
|
||||
virtual void Source_OnAdd(AudioSource* source) = 0;
|
||||
virtual void Source_OnRemove(AudioSource* source) = 0;
|
||||
virtual void Source_VelocityChanged(AudioSource* source) = 0;
|
||||
virtual void Source_TransformChanged(AudioSource* source) = 0;
|
||||
virtual void Source_VolumeChanged(AudioSource* source) = 0;
|
||||
virtual void Source_PitchChanged(AudioSource* source) = 0;
|
||||
virtual void Source_PanChanged(AudioSource* source) = 0;
|
||||
virtual void Source_IsLoopingChanged(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;
|
||||
virtual void Source_Pause(AudioSource* source) = 0;
|
||||
virtual void Source_Stop(AudioSource* source) = 0;
|
||||
virtual void Source_SetCurrentBufferTime(AudioSource* source, float value) = 0;
|
||||
virtual float Source_GetCurrentBufferTime(const AudioSource* source) = 0;
|
||||
virtual void Source_SetNonStreamingBuffer(AudioSource* source) = 0;
|
||||
virtual void Source_GetProcessedBuffersCount(AudioSource* source, int32& processedBuffersCount) = 0;
|
||||
virtual void Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount) = 0;
|
||||
virtual void Source_QueueBuffer(AudioSource* source, uint32 bufferId) = 0;
|
||||
virtual void Source_DequeueProcessedBuffers(AudioSource* source) = 0;
|
||||
virtual uint32 Source_Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler) = 0;
|
||||
virtual void Source_Remove(uint32 sourceID) = 0;
|
||||
virtual void Source_VelocityChanged(uint32 sourceID, const Vector3& velocity) = 0;
|
||||
virtual void Source_TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation) = 0;
|
||||
virtual void Source_VolumeChanged(uint32 sourceID, float volume) = 0;
|
||||
virtual void Source_PitchChanged(uint32 sourceID, float pitch) = 0;
|
||||
virtual void Source_PanChanged(uint32 sourceID, float pan) = 0;
|
||||
virtual void Source_IsLoopingChanged(uint32 sourceID, bool loop) = 0;
|
||||
virtual void Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler) = 0;
|
||||
virtual void Source_Play(uint32 sourceID) = 0;
|
||||
virtual void Source_Pause(uint32 sourceID) = 0;
|
||||
virtual void Source_Stop(uint32 sourceID) = 0;
|
||||
virtual void Source_SetCurrentBufferTime(uint32 sourceID, float value) = 0;
|
||||
virtual float Source_GetCurrentBufferTime(uint32 id) = 0;
|
||||
virtual void Source_SetNonStreamingBuffer(uint32 sourceID, uint32 bufferID) = 0;
|
||||
virtual void Source_GetProcessedBuffersCount(uint32 sourceID, int32& processedBuffersCount) = 0;
|
||||
virtual void Source_GetQueuedBuffersCount(uint32 sourceID, int32& queuedBuffersCount) = 0;
|
||||
virtual void Source_QueueBuffer(uint32 sourceID, uint32 bufferID) = 0;
|
||||
virtual void Source_DequeueProcessedBuffers(uint32 sourceID) = 0;
|
||||
|
||||
// Buffer
|
||||
virtual uint32 Buffer_Create() = 0;
|
||||
virtual void Buffer_Delete(uint32 bufferId) = 0;
|
||||
virtual void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) = 0;
|
||||
virtual void Buffer_Delete(uint32 bufferID) = 0;
|
||||
virtual void Buffer_Write(uint32 bufferID, byte* samples, const AudioDataInfo& info) = 0;
|
||||
|
||||
// Base
|
||||
virtual const Char* Base_Name() = 0;
|
||||
@@ -102,109 +100,99 @@ public:
|
||||
class Source
|
||||
{
|
||||
public:
|
||||
FORCE_INLINE static void OnAdd(AudioSource* source)
|
||||
FORCE_INLINE static uint32 Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler)
|
||||
{
|
||||
Instance->Source_OnAdd(source);
|
||||
return Instance->Source_Add(format, position, orientation, volume, pitch, pan, loop, spatial, attenuation, minDistance, doppler);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void OnRemove(AudioSource* source)
|
||||
FORCE_INLINE static void Remove(uint32 sourceID)
|
||||
{
|
||||
Instance->Source_OnRemove(source);
|
||||
Instance->Source_Remove(sourceID);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void VelocityChanged(AudioSource* source)
|
||||
FORCE_INLINE static void VelocityChanged(uint32 sourceID, const Vector3& velocity)
|
||||
{
|
||||
Instance->Source_VelocityChanged(source);
|
||||
Instance->Source_VelocityChanged(sourceID, velocity);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void TransformChanged(AudioSource* source)
|
||||
FORCE_INLINE static void TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation)
|
||||
{
|
||||
Instance->Source_TransformChanged(source);
|
||||
Instance->Source_TransformChanged(sourceID, position, orientation);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void VolumeChanged(AudioSource* source)
|
||||
FORCE_INLINE static void VolumeChanged(uint32 sourceID, float volume)
|
||||
{
|
||||
Instance->Source_VolumeChanged(source);
|
||||
Instance->Source_VolumeChanged(sourceID, volume);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void PitchChanged(AudioSource* source)
|
||||
FORCE_INLINE static void PitchChanged(uint32 sourceID, float pitch)
|
||||
{
|
||||
Instance->Source_PitchChanged(source);
|
||||
Instance->Source_PitchChanged(sourceID, pitch);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void PanChanged(AudioSource* source)
|
||||
FORCE_INLINE static void PanChanged(uint32 sourceID, float pan)
|
||||
{
|
||||
Instance->Source_PanChanged(source);
|
||||
Instance->Source_PanChanged(sourceID, pan);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void IsLoopingChanged(AudioSource* source)
|
||||
FORCE_INLINE static void IsLoopingChanged(uint32 sourceID, bool loop)
|
||||
{
|
||||
Instance->Source_IsLoopingChanged(source);
|
||||
Instance->Source_IsLoopingChanged(sourceID, loop);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void SpatialSetupChanged(AudioSource* source)
|
||||
FORCE_INLINE static void SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler)
|
||||
{
|
||||
Instance->Source_SpatialSetupChanged(source);
|
||||
Instance->Source_SpatialSetupChanged(sourceID, spatial, attenuation, minDistance, doppler);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void ClipLoaded(AudioSource* source)
|
||||
FORCE_INLINE static void Play(uint32 sourceID)
|
||||
{
|
||||
Instance->Source_ClipLoaded(source);
|
||||
Instance->Source_Play(sourceID);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void Cleanup(AudioSource* source)
|
||||
FORCE_INLINE static void Pause(uint32 sourceID)
|
||||
{
|
||||
Instance->Source_Cleanup(source);
|
||||
Instance->Source_Pause(sourceID);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void Play(AudioSource* source)
|
||||
FORCE_INLINE static void Stop(uint32 sourceID)
|
||||
{
|
||||
Instance->Source_Play(source);
|
||||
Instance->Source_Stop(sourceID);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void Pause(AudioSource* source)
|
||||
FORCE_INLINE static void SetCurrentBufferTime(uint32 sourceID, float value)
|
||||
{
|
||||
Instance->Source_Pause(source);
|
||||
Instance->Source_SetCurrentBufferTime(sourceID, value);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void Stop(AudioSource* source)
|
||||
FORCE_INLINE static float GetCurrentBufferTime(uint32 sourceID)
|
||||
{
|
||||
Instance->Source_Stop(source);
|
||||
return Instance->Source_GetCurrentBufferTime(sourceID);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void SetCurrentBufferTime(AudioSource* source, float value)
|
||||
FORCE_INLINE static void SetNonStreamingBuffer(uint32 sourceID, uint32 bufferID)
|
||||
{
|
||||
Instance->Source_SetCurrentBufferTime(source, value);
|
||||
Instance->Source_SetNonStreamingBuffer(sourceID, bufferID);
|
||||
}
|
||||
|
||||
FORCE_INLINE static float GetCurrentBufferTime(const AudioSource* source)
|
||||
FORCE_INLINE static void GetProcessedBuffersCount(uint32 sourceID, int32& processedBuffersCount)
|
||||
{
|
||||
return Instance->Source_GetCurrentBufferTime(source);
|
||||
Instance->Source_GetProcessedBuffersCount(sourceID, processedBuffersCount);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void SetNonStreamingBuffer(AudioSource* source)
|
||||
FORCE_INLINE static void GetQueuedBuffersCount(uint32 sourceID, int32& queuedBuffersCount)
|
||||
{
|
||||
Instance->Source_SetNonStreamingBuffer(source);
|
||||
Instance->Source_GetQueuedBuffersCount(sourceID, queuedBuffersCount);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void GetProcessedBuffersCount(AudioSource* source, int32& processedBuffersCount)
|
||||
FORCE_INLINE static void QueueBuffer(uint32 sourceID, uint32 bufferID)
|
||||
{
|
||||
Instance->Source_GetProcessedBuffersCount(source, processedBuffersCount);
|
||||
Instance->Source_QueueBuffer(sourceID, bufferID);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount)
|
||||
FORCE_INLINE static void DequeueProcessedBuffers(uint32 sourceID)
|
||||
{
|
||||
Instance->Source_GetQueuedBuffersCount(source, queuedBuffersCount);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void QueueBuffer(AudioSource* source, uint32 bufferId)
|
||||
{
|
||||
Instance->Source_QueueBuffer(source, bufferId);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void DequeueProcessedBuffers(AudioSource* source)
|
||||
{
|
||||
Instance->Source_DequeueProcessedBuffers(source);
|
||||
Instance->Source_DequeueProcessedBuffers(sourceID);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -216,14 +204,14 @@ public:
|
||||
return Instance->Buffer_Create();
|
||||
}
|
||||
|
||||
FORCE_INLINE static void Delete(uint32 bufferId)
|
||||
FORCE_INLINE static void Delete(uint32 bufferID)
|
||||
{
|
||||
Instance->Buffer_Delete(bufferId);
|
||||
Instance->Buffer_Delete(bufferID);
|
||||
}
|
||||
|
||||
FORCE_INLINE static void Write(uint32 bufferId, byte* samples, const AudioDataInfo& info)
|
||||
FORCE_INLINE static void Write(uint32 bufferID, byte* samples, const AudioDataInfo& info)
|
||||
{
|
||||
Instance->Buffer_Write(bufferId, samples, info);
|
||||
Instance->Buffer_Write(bufferID, samples, info);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -31,16 +31,16 @@ bool AudioClip::StreamingTask::Run()
|
||||
for (int32 i = 0; i < queue.Count(); i++)
|
||||
{
|
||||
const auto idx = queue[i];
|
||||
uint32& bufferId = clip->Buffers[idx];
|
||||
if (bufferId == 0)
|
||||
uint32& bufferID = clip->Buffers[idx];
|
||||
if (bufferID == 0)
|
||||
{
|
||||
bufferId = AudioBackend::Buffer::Create();
|
||||
bufferID = AudioBackend::Buffer::Create();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Release unused data
|
||||
AudioBackend::Buffer::Delete(bufferId);
|
||||
bufferId = 0;
|
||||
AudioBackend::Buffer::Delete(bufferID);
|
||||
bufferID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,8 +383,8 @@ Asset::LoadResult AudioClip::load()
|
||||
void AudioClip::unload(bool isReloading)
|
||||
{
|
||||
bool hasAnyBuffer = false;
|
||||
for (const uint32 bufferId : Buffers)
|
||||
hasAnyBuffer |= bufferId != 0;
|
||||
for (const uint32 bufferID : Buffers)
|
||||
hasAnyBuffer |= bufferID != 0;
|
||||
|
||||
// Stop any audio sources that are using this clip right now
|
||||
// TODO: find better way to collect audio sources using audio clip and impl it for AudioStreamingHandler too
|
||||
@@ -399,10 +399,10 @@ void AudioClip::unload(bool isReloading)
|
||||
StreamingQueue.Clear();
|
||||
if (hasAnyBuffer && AudioBackend::Instance)
|
||||
{
|
||||
for (uint32 bufferId : Buffers)
|
||||
for (uint32 bufferID : Buffers)
|
||||
{
|
||||
if (bufferId != 0)
|
||||
AudioBackend::Buffer::Delete(bufferId);
|
||||
if (bufferID != 0)
|
||||
AudioBackend::Buffer::Delete(bufferID);
|
||||
}
|
||||
}
|
||||
Buffers.Clear();
|
||||
@@ -413,8 +413,8 @@ void AudioClip::unload(bool isReloading)
|
||||
bool AudioClip::WriteBuffer(int32 chunkIndex)
|
||||
{
|
||||
// Ignore if buffer is not created
|
||||
const uint32 bufferId = Buffers[chunkIndex];
|
||||
if (bufferId == 0)
|
||||
const uint32 bufferID = Buffers[chunkIndex];
|
||||
if (bufferID == 0)
|
||||
return false;
|
||||
|
||||
// Ensure audio backend exists
|
||||
@@ -475,6 +475,6 @@ bool AudioClip::WriteBuffer(int32 chunkIndex)
|
||||
}
|
||||
|
||||
// Write samples to the audio buffer
|
||||
AudioBackend::Buffer::Write(bufferId, data.Get(), info);
|
||||
AudioBackend::Buffer::Write(bufferID, data.Get(), info);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "AudioListener.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Level/Scene/Scene.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "AudioBackend.h"
|
||||
#include "Audio.h"
|
||||
|
||||
@@ -36,9 +37,18 @@ void AudioListener::OnEnable()
|
||||
{
|
||||
_prevPos = GetPosition();
|
||||
_velocity = Vector3::Zero;
|
||||
|
||||
Audio::OnAddListener(this);
|
||||
GetScene()->Ticking.Update.AddTick<AudioListener, &AudioListener::Update>(this);
|
||||
if (Audio::Listeners.Count() >= AUDIO_MAX_LISTENERS)
|
||||
{
|
||||
LOG(Error, "Unsupported amount of the audio listeners!");
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(!Audio::Listeners.Contains(this));
|
||||
Audio::Listeners.Add(this);
|
||||
AudioBackend::Listener::Reset();
|
||||
AudioBackend::Listener::TransformChanged(GetPosition(), GetOrientation());
|
||||
GetScene()->Ticking.Update.AddTick<AudioListener, &AudioListener::Update>(this);
|
||||
}
|
||||
#if USE_EDITOR
|
||||
GetSceneRendering()->AddViewportIcon(this);
|
||||
#endif
|
||||
@@ -52,8 +62,11 @@ void AudioListener::OnDisable()
|
||||
#if USE_EDITOR
|
||||
GetSceneRendering()->RemoveViewportIcon(this);
|
||||
#endif
|
||||
GetScene()->Ticking.Update.RemoveTick(this);
|
||||
Audio::OnRemoveListener(this);
|
||||
if (!Audio::Listeners.Remove(this))
|
||||
{
|
||||
GetScene()->Ticking.Update.RemoveTick(this);
|
||||
AudioBackend::Listener::Reset();
|
||||
}
|
||||
|
||||
// Base
|
||||
Actor::OnDisable();
|
||||
|
||||
@@ -33,7 +33,7 @@ void AudioSource::SetVolume(float value)
|
||||
return;
|
||||
_volume = value;
|
||||
if (SourceID)
|
||||
AudioBackend::Source::VolumeChanged(this);
|
||||
AudioBackend::Source::VolumeChanged(SourceID, _volume);
|
||||
}
|
||||
|
||||
void AudioSource::SetPitch(float value)
|
||||
@@ -43,7 +43,7 @@ void AudioSource::SetPitch(float value)
|
||||
return;
|
||||
_pitch = value;
|
||||
if (SourceID)
|
||||
AudioBackend::Source::PitchChanged(this);
|
||||
AudioBackend::Source::PitchChanged(SourceID, _pitch);
|
||||
}
|
||||
|
||||
void AudioSource::SetPan(float value)
|
||||
@@ -53,7 +53,7 @@ void AudioSource::SetPan(float value)
|
||||
return;
|
||||
_pan = value;
|
||||
if (SourceID)
|
||||
AudioBackend::Source::PanChanged(this);
|
||||
AudioBackend::Source::PanChanged(SourceID, _pan);
|
||||
}
|
||||
|
||||
void AudioSource::SetIsLooping(bool value)
|
||||
@@ -64,7 +64,7 @@ void AudioSource::SetIsLooping(bool value)
|
||||
|
||||
// When streaming we handle looping manually by the proper buffers submission
|
||||
if (SourceID && !UseStreaming())
|
||||
AudioBackend::Source::IsLoopingChanged(this);
|
||||
AudioBackend::Source::IsLoopingChanged(SourceID, _loop);
|
||||
}
|
||||
|
||||
void AudioSource::SetPlayOnStart(bool value)
|
||||
@@ -84,7 +84,7 @@ void AudioSource::SetMinDistance(float value)
|
||||
return;
|
||||
_minDistance = value;
|
||||
if (SourceID)
|
||||
AudioBackend::Source::SpatialSetupChanged(this);
|
||||
AudioBackend::Source::SpatialSetupChanged(SourceID, Is3D(), _attenuation, _minDistance, _dopplerFactor);
|
||||
}
|
||||
|
||||
void AudioSource::SetAttenuation(float value)
|
||||
@@ -94,7 +94,7 @@ void AudioSource::SetAttenuation(float value)
|
||||
return;
|
||||
_attenuation = value;
|
||||
if (SourceID)
|
||||
AudioBackend::Source::SpatialSetupChanged(this);
|
||||
AudioBackend::Source::SpatialSetupChanged(SourceID, Is3D(), _attenuation, _minDistance, _dopplerFactor);
|
||||
}
|
||||
|
||||
void AudioSource::SetDopplerFactor(float value)
|
||||
@@ -104,7 +104,7 @@ void AudioSource::SetDopplerFactor(float value)
|
||||
return;
|
||||
_dopplerFactor = value;
|
||||
if (SourceID)
|
||||
AudioBackend::Source::SpatialSetupChanged(this);
|
||||
AudioBackend::Source::SpatialSetupChanged(SourceID, Is3D(), _attenuation, _minDistance, _dopplerFactor);
|
||||
}
|
||||
|
||||
void AudioSource::SetAllowSpatialization(bool value)
|
||||
@@ -113,7 +113,7 @@ void AudioSource::SetAllowSpatialization(bool value)
|
||||
return;
|
||||
_allowSpatialization = value;
|
||||
if (SourceID)
|
||||
AudioBackend::Source::SpatialSetupChanged(this);
|
||||
AudioBackend::Source::SpatialSetupChanged(SourceID, Is3D(), _attenuation, _minDistance, _dopplerFactor);
|
||||
}
|
||||
|
||||
void AudioSource::Play()
|
||||
@@ -121,19 +121,26 @@ void AudioSource::Play()
|
||||
auto state = _state;
|
||||
if (state == States::Playing)
|
||||
return;
|
||||
if (Clip == nullptr)
|
||||
if (Clip == nullptr || Clip->WaitForLoaded())
|
||||
{
|
||||
LOG(Warning, "Cannot play audio source without a clip ({0})", GetNamePath());
|
||||
return;
|
||||
}
|
||||
|
||||
if (SourceID == 0)
|
||||
{
|
||||
// Create audio source
|
||||
SourceID = AudioBackend::Source::Add(Clip->Info(), GetPosition(), GetOrientation(), GetVolume(), GetPitch(), GetPan(), GetIsLooping() && !UseStreaming(), Is3D(), GetAttenuation(), GetMinDistance(), GetDopplerFactor());
|
||||
if (SourceID == 0)
|
||||
{
|
||||
LOG(Warning, "Cannot create audio source ({0})", GetNamePath());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_state = States::Playing;
|
||||
_isActuallyPlayingSth = false;
|
||||
|
||||
// Don't block scripting if audio is not loaded or has missing streaming data
|
||||
if (!Clip->IsLoaded())
|
||||
return;
|
||||
|
||||
// Audio clips with disabled streaming are controlled by audio source, otherwise streaming manager will play it
|
||||
if (Clip->IsStreamable())
|
||||
{
|
||||
@@ -155,7 +162,7 @@ void AudioSource::Play()
|
||||
else if (SourceID)
|
||||
{
|
||||
// Play it right away
|
||||
SetNonStreamingBuffer();
|
||||
AudioBackend::Source::SetNonStreamingBuffer(SourceID, Clip->Buffers[0]);
|
||||
PlayInternal();
|
||||
}
|
||||
else
|
||||
@@ -171,10 +178,9 @@ void AudioSource::Pause()
|
||||
return;
|
||||
|
||||
_state = States::Paused;
|
||||
|
||||
if (_isActuallyPlayingSth)
|
||||
{
|
||||
AudioBackend::Source::Pause(this);
|
||||
AudioBackend::Source::Pause(SourceID);
|
||||
_isActuallyPlayingSth = false;
|
||||
}
|
||||
}
|
||||
@@ -188,7 +194,7 @@ void AudioSource::Stop()
|
||||
_isActuallyPlayingSth = false;
|
||||
_streamingFirstChunk = 0;
|
||||
if (SourceID)
|
||||
AudioBackend::Source::Stop(this);
|
||||
AudioBackend::Source::Stop(SourceID);
|
||||
}
|
||||
|
||||
float AudioSource::GetTime() const
|
||||
@@ -196,13 +202,13 @@ float AudioSource::GetTime() const
|
||||
if (_state == States::Stopped || SourceID == 0 || !Clip->IsLoaded())
|
||||
return 0.0f;
|
||||
|
||||
float time = AudioBackend::Source::GetCurrentBufferTime(this);
|
||||
float time = AudioBackend::Source::GetCurrentBufferTime(SourceID);
|
||||
|
||||
if (UseStreaming())
|
||||
{
|
||||
// Apply time offset to the first streaming buffer binded to the source including the already queued buffers
|
||||
int32 numProcessedBuffers = 0;
|
||||
AudioBackend::Source::GetProcessedBuffersCount(const_cast<AudioSource*>(this), numProcessedBuffers);
|
||||
AudioBackend::Source::GetProcessedBuffersCount(SourceID, numProcessedBuffers);
|
||||
time += Clip->GetBufferStartTime(_streamingFirstChunk + numProcessedBuffers);
|
||||
}
|
||||
|
||||
@@ -234,7 +240,7 @@ void AudioSource::SetTime(float time)
|
||||
time = relativeTime;
|
||||
}
|
||||
|
||||
AudioBackend::Source::SetCurrentBufferTime(this, time);
|
||||
AudioBackend::Source::SetCurrentBufferTime(SourceID, time);
|
||||
|
||||
// Restore state if was stopped
|
||||
if (isActuallyPlayingSth)
|
||||
@@ -258,31 +264,29 @@ void AudioSource::RequestStreamingBuffersUpdate()
|
||||
_needToUpdateStreamingBuffers = true;
|
||||
}
|
||||
|
||||
void AudioSource::Cleanup()
|
||||
void AudioSource::OnClipChanged()
|
||||
{
|
||||
_savedState = GetState();
|
||||
_savedTime = GetTime();
|
||||
Stop();
|
||||
|
||||
// Destroy current source (will be created on the next play), because clip might use different spatial options or audio data format
|
||||
if (SourceID)
|
||||
{
|
||||
AudioBackend::Source::Cleanup(this);
|
||||
AudioBackend::Source::Remove(SourceID);
|
||||
SourceID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSource::OnClipChanged()
|
||||
{
|
||||
Stop();
|
||||
_clipChanged = true;
|
||||
}
|
||||
|
||||
void AudioSource::OnClipLoaded()
|
||||
{
|
||||
AudioBackend::Source::ClipLoaded(this);
|
||||
if (!SourceID)
|
||||
return;
|
||||
|
||||
// Reset spatial and playback
|
||||
AudioBackend::Source::IsLoopingChanged(SourceID, _loop && !UseStreaming());
|
||||
AudioBackend::Source::SpatialSetupChanged(SourceID, Is3D(), _attenuation, _minDistance, _dopplerFactor);
|
||||
|
||||
// Start playing if source was waiting for the clip to load
|
||||
if (SourceID && _state == States::Playing && !_isActuallyPlayingSth)
|
||||
if (_state == States::Playing && !_isActuallyPlayingSth)
|
||||
{
|
||||
if (Clip->IsStreamable())
|
||||
{
|
||||
@@ -292,7 +296,7 @@ void AudioSource::OnClipLoaded()
|
||||
else
|
||||
{
|
||||
// Play it right away
|
||||
SetNonStreamingBuffer();
|
||||
AudioBackend::Source::SetNonStreamingBuffer(SourceID, Clip->Buffers[0]);
|
||||
PlayInternal();
|
||||
}
|
||||
}
|
||||
@@ -300,42 +304,14 @@ void AudioSource::OnClipLoaded()
|
||||
|
||||
bool AudioSource::UseStreaming() const
|
||||
{
|
||||
return Clip && Clip->IsLoaded() && Clip->IsStreamable();
|
||||
}
|
||||
|
||||
void AudioSource::Restore()
|
||||
{
|
||||
if (Clip)
|
||||
{
|
||||
if (_savedState != States::Stopped)
|
||||
Play();
|
||||
if (_savedState == States::Paused)
|
||||
Pause();
|
||||
|
||||
SetTime(_savedTime);
|
||||
|
||||
if (_savedState != States::Stopped && UseStreaming())
|
||||
RequestStreamingBuffersUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSource::SetNonStreamingBuffer()
|
||||
{
|
||||
ASSERT(Clip && !Clip->IsStreamable());
|
||||
|
||||
AudioBackend::Source::SetNonStreamingBuffer(this);
|
||||
if (Clip == nullptr || Clip->WaitForLoaded())
|
||||
return false;
|
||||
return Clip->IsStreamable();
|
||||
}
|
||||
|
||||
void AudioSource::PlayInternal()
|
||||
{
|
||||
if (_clipChanged && SourceID != 0)
|
||||
{
|
||||
// If clip was changed between source setup (OnEnable) and actual playback start then ensure to flush any runtime properties with the audio backend
|
||||
_clipChanged = false;
|
||||
AudioBackend::Source::SpatialSetupChanged(this);
|
||||
}
|
||||
AudioBackend::Source::Play(this);
|
||||
|
||||
AudioBackend::Source::Play(SourceID);
|
||||
_isActuallyPlayingSth = true;
|
||||
}
|
||||
|
||||
@@ -413,9 +389,9 @@ void AudioSource::Update()
|
||||
const auto prevVelocity = _velocity;
|
||||
_velocity = (pos - _prevPos) / dt;
|
||||
_prevPos = pos;
|
||||
if (_velocity != prevVelocity)
|
||||
if (_velocity != prevVelocity && Is3D())
|
||||
{
|
||||
AudioBackend::Source::VelocityChanged(this);
|
||||
AudioBackend::Source::VelocityChanged(SourceID, _velocity);
|
||||
}
|
||||
|
||||
// Skip other update logic if it's not valid streamable source
|
||||
@@ -429,17 +405,17 @@ void AudioSource::Update()
|
||||
{
|
||||
// Get buffers in a queue count
|
||||
int32 numQueuedBuffers;
|
||||
AudioBackend::Source::GetQueuedBuffersCount(this, numQueuedBuffers);
|
||||
AudioBackend::Source::GetQueuedBuffersCount(SourceID, numQueuedBuffers);
|
||||
|
||||
// Queue missing buffers
|
||||
uint32 bufferId;
|
||||
if (numQueuedBuffers < 1 && (bufferId = clip->Buffers[_streamingFirstChunk]) != 0)
|
||||
uint32 bufferID;
|
||||
if (numQueuedBuffers < 1 && (bufferID = clip->Buffers[_streamingFirstChunk]) != 0)
|
||||
{
|
||||
AudioBackend::Source::QueueBuffer(this, bufferId);
|
||||
AudioBackend::Source::QueueBuffer(SourceID, bufferID);
|
||||
}
|
||||
if (numQueuedBuffers < 2 && _streamingFirstChunk + 1 < clip->Buffers.Count() && (bufferId = clip->Buffers[_streamingFirstChunk + 1]) != 0)
|
||||
if (numQueuedBuffers < 2 && _streamingFirstChunk + 1 < clip->Buffers.Count() && (bufferID = clip->Buffers[_streamingFirstChunk + 1]) != 0)
|
||||
{
|
||||
AudioBackend::Source::QueueBuffer(this, bufferId);
|
||||
AudioBackend::Source::QueueBuffer(SourceID, bufferID);
|
||||
}
|
||||
|
||||
// Clear flag
|
||||
@@ -457,13 +433,13 @@ void AudioSource::Update()
|
||||
{
|
||||
// Get the processed buffers count
|
||||
int32 numProcessedBuffers = 0;
|
||||
AudioBackend::Source::GetProcessedBuffersCount(this, numProcessedBuffers);
|
||||
AudioBackend::Source::GetProcessedBuffersCount(SourceID, numProcessedBuffers);
|
||||
if (numProcessedBuffers > 0)
|
||||
{
|
||||
ASSERT(numProcessedBuffers <= ASSET_FILE_DATA_CHUNKS);
|
||||
|
||||
// Unbind processed buffers from the source
|
||||
AudioBackend::Source::DequeueProcessedBuffers(this);
|
||||
AudioBackend::Source::DequeueProcessedBuffers(SourceID);
|
||||
|
||||
// Move the chunk pointer (AudioStreamingHandler will request new chunks streaming)
|
||||
_streamingFirstChunk += numProcessedBuffers;
|
||||
@@ -500,27 +476,53 @@ void AudioSource::OnEnable()
|
||||
{
|
||||
_prevPos = GetPosition();
|
||||
_velocity = Vector3::Zero;
|
||||
_clipChanged = false;
|
||||
|
||||
Audio::OnAddSource(this);
|
||||
// Add source
|
||||
ASSERT_LOW_LAYER(!Audio::Sources.Contains(this));
|
||||
Audio::Sources.Add(this);
|
||||
GetScene()->Ticking.Update.AddTick<AudioSource, &AudioSource::Update>(this);
|
||||
#if USE_EDITOR
|
||||
GetSceneRendering()->AddViewportIcon(this);
|
||||
#endif
|
||||
|
||||
// Restore playback state
|
||||
if (Clip)
|
||||
{
|
||||
if (_savedState != States::Stopped)
|
||||
Play();
|
||||
if (_savedState == States::Paused)
|
||||
Pause();
|
||||
|
||||
SetTime(_savedTime);
|
||||
|
||||
if (_savedState != States::Stopped && UseStreaming())
|
||||
RequestStreamingBuffersUpdate();
|
||||
}
|
||||
|
||||
// Base
|
||||
Actor::OnEnable();
|
||||
}
|
||||
|
||||
void AudioSource::OnDisable()
|
||||
{
|
||||
// Cache playback state
|
||||
_savedState = GetState();
|
||||
_savedTime = GetTime();
|
||||
|
||||
// End playback
|
||||
Stop();
|
||||
|
||||
// Remove source
|
||||
#if USE_EDITOR
|
||||
GetSceneRendering()->RemoveViewportIcon(this);
|
||||
#endif
|
||||
GetScene()->Ticking.Update.RemoveTick(this);
|
||||
Audio::OnRemoveSource(this);
|
||||
if (SourceID)
|
||||
{
|
||||
AudioBackend::Source::Remove(SourceID);
|
||||
SourceID = 0;
|
||||
}
|
||||
Audio::Sources.Remove(this);
|
||||
|
||||
// Base
|
||||
Actor::OnDisable();
|
||||
@@ -534,9 +536,9 @@ void AudioSource::OnTransformChanged()
|
||||
_box = BoundingBox(_transform.Translation);
|
||||
_sphere = BoundingSphere(_transform.Translation, 0.0f);
|
||||
|
||||
if (IsActiveInHierarchy() && SourceID)
|
||||
if (IsActiveInHierarchy() && SourceID && Is3D())
|
||||
{
|
||||
AudioBackend::Source::TransformChanged(this);
|
||||
AudioBackend::Source::TransformChanged(SourceID, _transform.Translation, _transform.Orientation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ private:
|
||||
bool _playOnStart;
|
||||
float _startTime;
|
||||
bool _allowSpatialization;
|
||||
bool _clipChanged = false;
|
||||
|
||||
bool _isActuallyPlayingSth = false;
|
||||
bool _needToUpdateStreamingBuffers = false;
|
||||
@@ -270,11 +269,6 @@ public:
|
||||
/// </summary>
|
||||
API_PROPERTY() bool UseStreaming() const;
|
||||
|
||||
/// <summary>
|
||||
/// Restores the saved time position and resumes/pauses the playback based on the state before. Used to restore audio source state after data rebuild (eg. by audio backend).
|
||||
/// </summary>
|
||||
void Restore();
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Determines whether this audio source started playing audio via audio backend. After audio play it may wait for audio clip data to be loaded or streamed.
|
||||
@@ -289,20 +283,10 @@ public:
|
||||
/// </summary>
|
||||
void RequestStreamingBuffersUpdate();
|
||||
|
||||
/// <summary>
|
||||
/// Cleanups the cached data. Called by the Audio manager.
|
||||
/// </summary>
|
||||
void Cleanup();
|
||||
|
||||
private:
|
||||
void OnClipChanged();
|
||||
void OnClipLoaded();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the single buffer from the audio clip that is not using dynamic streaming
|
||||
/// </summary>
|
||||
void SetNonStreamingBuffer();
|
||||
|
||||
/// <summary>
|
||||
/// Plays the audio source. Should have buffer(s) binded before.
|
||||
/// </summary>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Config.h"
|
||||
#include "Engine/Content/Config.h"
|
||||
|
||||
// The maximum amount of listeners used at once
|
||||
#define AUDIO_MAX_LISTENERS 1
|
||||
|
||||
@@ -22,91 +22,82 @@ void AudioBackendNone::Listener_ReinitializeAll()
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_OnAdd(AudioSource* source)
|
||||
uint32 AudioBackendNone::Source_Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler)
|
||||
{
|
||||
source->Restore();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_OnRemove(AudioSource* source)
|
||||
{
|
||||
source->Cleanup();
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_VelocityChanged(AudioSource* source)
|
||||
void AudioBackendNone::Source_Remove(uint32 sourceID)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_TransformChanged(AudioSource* source)
|
||||
void AudioBackendNone::Source_VelocityChanged(uint32 sourceID, const Vector3& velocity)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_VolumeChanged(AudioSource* source)
|
||||
void AudioBackendNone::Source_TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_PitchChanged(AudioSource* source)
|
||||
void AudioBackendNone::Source_VolumeChanged(uint32 sourceID, float volume)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_PanChanged(AudioSource* source)
|
||||
void AudioBackendNone::Source_PitchChanged(uint32 sourceID, float pitch)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_IsLoopingChanged(AudioSource* source)
|
||||
void AudioBackendNone::Source_PanChanged(uint32 sourceID, float pan)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_SpatialSetupChanged(AudioSource* source)
|
||||
void AudioBackendNone::Source_IsLoopingChanged(uint32 sourceID, bool loop)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_ClipLoaded(AudioSource* source)
|
||||
void AudioBackendNone::Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_Cleanup(AudioSource* source)
|
||||
void AudioBackendNone::Source_Play(uint32 sourceID)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_Play(AudioSource* source)
|
||||
void AudioBackendNone::Source_Pause(uint32 sourceID)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_Pause(AudioSource* source)
|
||||
void AudioBackendNone::Source_Stop(uint32 sourceID)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_Stop(AudioSource* source)
|
||||
void AudioBackendNone::Source_SetCurrentBufferTime(uint32 sourceID, float value)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_SetCurrentBufferTime(AudioSource* source, float value)
|
||||
{
|
||||
}
|
||||
|
||||
float AudioBackendNone::Source_GetCurrentBufferTime(const AudioSource* source)
|
||||
float AudioBackendNone::Source_GetCurrentBufferTime(uint32 sourceID)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_SetNonStreamingBuffer(AudioSource* source)
|
||||
void AudioBackendNone::Source_SetNonStreamingBuffer(uint32 sourceID, uint32 bufferID)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_GetProcessedBuffersCount(AudioSource* source, int32& processedBuffersCount)
|
||||
void AudioBackendNone::Source_GetProcessedBuffersCount(uint32 sourceID, int32& processedBuffersCount)
|
||||
{
|
||||
processedBuffersCount = 0;
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount)
|
||||
void AudioBackendNone::Source_GetQueuedBuffersCount(uint32 sourceID, int32& queuedBuffersCount)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_QueueBuffer(AudioSource* source, uint32 bufferId)
|
||||
void AudioBackendNone::Source_QueueBuffer(uint32 sourceID, uint32 bufferID)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Source_DequeueProcessedBuffers(AudioSource* source)
|
||||
void AudioBackendNone::Source_DequeueProcessedBuffers(uint32 sourceID)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -115,11 +106,11 @@ uint32 AudioBackendNone::Buffer_Create()
|
||||
return 1;
|
||||
}
|
||||
|
||||
void AudioBackendNone::Buffer_Delete(uint32 bufferId)
|
||||
void AudioBackendNone::Buffer_Delete(uint32 bufferID)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioBackendNone::Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info)
|
||||
void AudioBackendNone::Buffer_Write(uint32 bufferID, byte* samples, const AudioDataInfo& info)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -17,30 +17,28 @@ public:
|
||||
void Listener_VelocityChanged(const Vector3& velocity) override;
|
||||
void Listener_TransformChanged(const Vector3& position, const Quaternion& orientation) override;
|
||||
void Listener_ReinitializeAll() override;
|
||||
void Source_OnAdd(AudioSource* source) override;
|
||||
void Source_OnRemove(AudioSource* source) override;
|
||||
void Source_VelocityChanged(AudioSource* source) override;
|
||||
void Source_TransformChanged(AudioSource* source) override;
|
||||
void Source_VolumeChanged(AudioSource* source) override;
|
||||
void Source_PitchChanged(AudioSource* source) override;
|
||||
void Source_PanChanged(AudioSource* source) override;
|
||||
void Source_IsLoopingChanged(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;
|
||||
void Source_Pause(AudioSource* source) override;
|
||||
void Source_Stop(AudioSource* source) override;
|
||||
void Source_SetCurrentBufferTime(AudioSource* source, float value) override;
|
||||
float Source_GetCurrentBufferTime(const AudioSource* source) override;
|
||||
void Source_SetNonStreamingBuffer(AudioSource* source) override;
|
||||
void Source_GetProcessedBuffersCount(AudioSource* source, int32& processedBuffersCount) override;
|
||||
void Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount) override;
|
||||
void Source_QueueBuffer(AudioSource* source, uint32 bufferId) override;
|
||||
void Source_DequeueProcessedBuffers(AudioSource* source) override;
|
||||
uint32 Source_Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler) override;
|
||||
void Source_Remove(uint32 sourceID) override;
|
||||
void Source_VelocityChanged(uint32 sourceID, const Vector3& velocity) override;
|
||||
void Source_TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation) override;
|
||||
void Source_VolumeChanged(uint32 sourceID, float volume) override;
|
||||
void Source_PitchChanged(uint32 sourceID, float pitch) override;
|
||||
void Source_PanChanged(uint32 sourceID, float pan) override;
|
||||
void Source_IsLoopingChanged(uint32 sourceID, bool loop) override;
|
||||
void Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler) override;
|
||||
void Source_Play(uint32 sourceID) override;
|
||||
void Source_Pause(uint32 sourceID) override;
|
||||
void Source_Stop(uint32 sourceID) override;
|
||||
void Source_SetCurrentBufferTime(uint32 sourceID, float value) override;
|
||||
float Source_GetCurrentBufferTime(uint32 sourceID) override;
|
||||
void Source_SetNonStreamingBuffer(uint32 sourceID, uint32 bufferID) override;
|
||||
void Source_GetProcessedBuffersCount(uint32 sourceID, int32& processedBuffersCount) override;
|
||||
void Source_GetQueuedBuffersCount(uint32 sourceID, int32& queuedBuffersCount) override;
|
||||
void Source_QueueBuffer(uint32 sourceID, uint32 bufferID) override;
|
||||
void Source_DequeueProcessedBuffers(uint32 sourceID) override;
|
||||
uint32 Buffer_Create() override;
|
||||
void Buffer_Delete(uint32 bufferId) override;
|
||||
void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) override;
|
||||
void Buffer_Delete(uint32 bufferID) override;
|
||||
void Buffer_Write(uint32 bufferID, byte* samples, const AudioDataInfo& info) override;
|
||||
const Char* Base_Name() override;
|
||||
FeatureFlags Base_Features() override;
|
||||
void Base_OnActiveDeviceChanged() override;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "AudioBackendOAL.h"
|
||||
#include "Engine/Platform/StringUtils.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Tools/AudioTool/AudioTool.h"
|
||||
#include "Engine/Engine/Units.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
@@ -42,6 +43,8 @@ namespace ALC
|
||||
ALCdevice* Device = nullptr;
|
||||
ALCcontext* Context = nullptr;
|
||||
AudioBackend::FeatureFlags Features = AudioBackend::FeatureFlags::None;
|
||||
CriticalSection Locker;
|
||||
Dictionary<uint32, AudioDataInfo> SourceIDtoFormat;
|
||||
|
||||
bool IsExtensionSupported(const char* extension)
|
||||
{
|
||||
@@ -75,32 +78,28 @@ namespace ALC
|
||||
|
||||
namespace Source
|
||||
{
|
||||
void Rebuild(AudioSource* source)
|
||||
void Rebuild(uint32& sourceID, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler)
|
||||
{
|
||||
ASSERT(source->SourceID == 0);
|
||||
const bool is3D = source->Is3D();
|
||||
const bool loop = source->GetIsLooping() && !source->UseStreaming();
|
||||
|
||||
uint32 sourceID = 0;
|
||||
ASSERT_LOW_LAYER(sourceID == 0);
|
||||
alGenSources(1, &sourceID);
|
||||
source->SourceID = sourceID;
|
||||
ASSERT_LOW_LAYER(sourceID != 0);
|
||||
|
||||
alSourcef(sourceID, AL_GAIN, source->GetVolume());
|
||||
alSourcef(sourceID, AL_PITCH, source->GetPitch());
|
||||
alSourcef(sourceID, AL_GAIN, volume);
|
||||
alSourcef(sourceID, AL_PITCH, pitch);
|
||||
alSourcef(sourceID, AL_SEC_OFFSET, 0.0f);
|
||||
alSourcei(sourceID, AL_LOOPING, loop);
|
||||
alSourcei(sourceID, AL_SOURCE_RELATIVE, !is3D);
|
||||
alSourcei(sourceID, AL_SOURCE_RELATIVE, !spatial);
|
||||
alSourcei(sourceID, AL_BUFFER, 0);
|
||||
if (is3D)
|
||||
if (spatial)
|
||||
{
|
||||
#ifdef AL_SOFT_source_spatialize
|
||||
alSourcei(sourceID, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE);
|
||||
#endif
|
||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation());
|
||||
alSourcef(sourceID, AL_DOPPLER_FACTOR, source->GetDopplerFactor());
|
||||
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()));
|
||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, attenuation);
|
||||
alSourcef(sourceID, AL_DOPPLER_FACTOR, doppler);
|
||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(minDistance));
|
||||
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
|
||||
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(Vector3::Zero));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -111,26 +110,23 @@ namespace ALC
|
||||
alSource3f(sourceID, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
#ifdef AL_EXT_STEREO_ANGLES
|
||||
const float panAngle = source->GetPan() * PI_HALF;
|
||||
const float panAngle = pan * PI_HALF;
|
||||
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
|
||||
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
|
||||
#endif
|
||||
|
||||
// Restore state after Cleanup
|
||||
source->Restore();
|
||||
}
|
||||
}
|
||||
|
||||
void RebuildContext(bool isChangingDevice)
|
||||
struct AudioSourceState
|
||||
{
|
||||
AudioSource::States State;
|
||||
float Time;
|
||||
};
|
||||
|
||||
void RebuildContext(const Array<AudioSourceState>& states)
|
||||
{
|
||||
LOG(Info, "Rebuilding audio contexts");
|
||||
|
||||
if (!isChangingDevice)
|
||||
{
|
||||
for (AudioSource* source : Audio::Sources)
|
||||
source->Cleanup();
|
||||
}
|
||||
|
||||
ClearContext();
|
||||
|
||||
if (Device == nullptr)
|
||||
@@ -150,8 +146,39 @@ namespace ALC
|
||||
for (AudioListener* listener : Audio::Listeners)
|
||||
Listener::Rebuild(listener);
|
||||
|
||||
for (AudioSource* source : Audio::Sources)
|
||||
Source::Rebuild(source);
|
||||
for (int32 i = 0; i < states.Count(); i++)
|
||||
{
|
||||
AudioSource* source = Audio::Sources[i];
|
||||
Source::Rebuild(source->SourceID, source->GetPosition(), source->GetOrientation(), source->GetVolume(), source->GetPitch(), source->GetPan(), source->GetIsLooping() && !source->UseStreaming(), source->Is3D(), source->GetAttenuation(), source->GetMinDistance(), source->GetDopplerFactor());
|
||||
|
||||
if (states.HasItems())
|
||||
{
|
||||
// Restore playback state
|
||||
auto& state = states[i];
|
||||
if (state.State != AudioSource::States::Stopped)
|
||||
source->Play();
|
||||
if (state.State == AudioSource::States::Paused)
|
||||
source->Pause();
|
||||
if (state.State != AudioSource::States::Stopped)
|
||||
source->SetTime(state.Time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RebuildContext(bool isChangingDevice)
|
||||
{
|
||||
Array<AudioSourceState> states;
|
||||
if (!isChangingDevice)
|
||||
{
|
||||
states.EnsureCapacity(Audio::Sources.Count());
|
||||
for (AudioSource* source : Audio::Sources)
|
||||
{
|
||||
states.Add({ source->GetState(), source->GetTime() });
|
||||
source->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
RebuildContext(states);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,74 +296,76 @@ void AudioBackendOAL::Listener_ReinitializeAll()
|
||||
ALC::RebuildContext(false);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_OnAdd(AudioSource* source)
|
||||
uint32 AudioBackendOAL::Source_Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler)
|
||||
{
|
||||
ALC::Source::Rebuild(source);
|
||||
uint32 sourceID = 0;
|
||||
ALC::Source::Rebuild(sourceID, position, orientation, volume, pitch, pan, loop, spatial, attenuation, minDistance, doppler);
|
||||
|
||||
// Cache audio data format assigned on source (used in Source_GetCurrentBufferTime)
|
||||
ALC::Locker.Lock();
|
||||
ALC::SourceIDtoFormat[sourceID] = format;
|
||||
ALC::Locker.Unlock();
|
||||
|
||||
return sourceID;
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_OnRemove(AudioSource* source)
|
||||
void AudioBackendOAL::Source_Remove(uint32 sourceID)
|
||||
{
|
||||
source->Cleanup();
|
||||
alSourcei(sourceID, AL_BUFFER, 0);
|
||||
ALC_CHECK_ERROR(alSourcei);
|
||||
alDeleteSources(1, &sourceID);
|
||||
ALC_CHECK_ERROR(alDeleteSources);
|
||||
|
||||
ALC::Locker.Lock();
|
||||
ALC::SourceIDtoFormat.Remove(sourceID);
|
||||
ALC::Locker.Unlock();
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_VelocityChanged(AudioSource* source)
|
||||
void AudioBackendOAL::Source_VelocityChanged(uint32 sourceID, const Vector3& velocity)
|
||||
{
|
||||
if (!source->Is3D())
|
||||
return;
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(source->GetVelocity()));
|
||||
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(velocity));
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_TransformChanged(AudioSource* source)
|
||||
void AudioBackendOAL::Source_TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation)
|
||||
{
|
||||
if (!source->Is3D())
|
||||
return;
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(source->GetPosition()));
|
||||
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_VolumeChanged(AudioSource* source)
|
||||
void AudioBackendOAL::Source_VolumeChanged(uint32 sourceID, float volume)
|
||||
{
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSourcef(sourceID, AL_GAIN, source->GetVolume());
|
||||
alSourcef(sourceID, AL_GAIN, volume);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_PitchChanged(AudioSource* source)
|
||||
void AudioBackendOAL::Source_PitchChanged(uint32 sourceID, float pitch)
|
||||
{
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSourcef(sourceID, AL_PITCH, source->GetPitch());
|
||||
alSourcef(sourceID, AL_PITCH, pitch);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_PanChanged(AudioSource* source)
|
||||
void AudioBackendOAL::Source_PanChanged(uint32 sourceID, float pan)
|
||||
{
|
||||
#ifdef AL_EXT_STEREO_ANGLES
|
||||
const float panAngle = source->GetPan() * PI_HALF;
|
||||
const float panAngle = pan * PI_HALF;
|
||||
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_IsLoopingChanged(AudioSource* source)
|
||||
void AudioBackendOAL::Source_IsLoopingChanged(uint32 sourceID, bool loop)
|
||||
{
|
||||
const bool loop = source->GetIsLooping() && !source->UseStreaming();
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSourcei(sourceID, AL_LOOPING, loop);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_SpatialSetupChanged(AudioSource* source)
|
||||
void AudioBackendOAL::Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler)
|
||||
{
|
||||
const bool is3D = source->Is3D();
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSourcei(sourceID, AL_SOURCE_RELATIVE, !is3D);
|
||||
if (is3D)
|
||||
alSourcei(sourceID, AL_SOURCE_RELATIVE, !spatial);
|
||||
if (spatial)
|
||||
{
|
||||
#ifdef AL_SOFT_source_spatialize
|
||||
alSourcei(sourceID, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE);
|
||||
#endif
|
||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation());
|
||||
alSourcef(sourceID, AL_DOPPLER_FACTOR, source->GetDopplerFactor());
|
||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(source->GetMinDistance()));
|
||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, attenuation);
|
||||
alSourcef(sourceID, AL_DOPPLER_FACTOR, doppler);
|
||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(minDistance));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -346,46 +375,20 @@ void AudioBackendOAL::Source_SpatialSetupChanged(AudioSource* source)
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_ClipLoaded(AudioSource* source)
|
||||
void AudioBackendOAL::Source_Play(uint32 sourceID)
|
||||
{
|
||||
if (source->SourceID == 0)
|
||||
return;
|
||||
const auto clip = source->Clip.Get();
|
||||
const bool is3D = source->Is3D();
|
||||
const bool loop = source->GetIsLooping() && !clip->IsStreamable();
|
||||
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSourcei(sourceID, AL_SOURCE_RELATIVE, !is3D);
|
||||
alSourcei(sourceID, AL_LOOPING, loop);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_Cleanup(AudioSource* source)
|
||||
{
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSourcei(sourceID, AL_BUFFER, 0);
|
||||
ALC_CHECK_ERROR(alSourcei);
|
||||
alDeleteSources(1, &sourceID);
|
||||
ALC_CHECK_ERROR(alDeleteSources);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_Play(AudioSource* source)
|
||||
{
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSourcePlay(sourceID);
|
||||
ALC_CHECK_ERROR(alSourcePlay);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_Pause(AudioSource* source)
|
||||
void AudioBackendOAL::Source_Pause(uint32 sourceID)
|
||||
{
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSourcePause(sourceID);
|
||||
ALC_CHECK_ERROR(alSourcePause);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_Stop(AudioSource* source)
|
||||
void AudioBackendOAL::Source_Stop(uint32 sourceID)
|
||||
{
|
||||
const uint32 sourceID = source->SourceID;
|
||||
|
||||
// Stop and rewind
|
||||
alSourceRewind(sourceID);
|
||||
ALC_CHECK_ERROR(alSourceRewind);
|
||||
@@ -396,67 +399,61 @@ void AudioBackendOAL::Source_Stop(AudioSource* source)
|
||||
ALC_CHECK_ERROR(alSourcei);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_SetCurrentBufferTime(AudioSource* source, float value)
|
||||
void AudioBackendOAL::Source_SetCurrentBufferTime(uint32 sourceID, float value)
|
||||
{
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSourcef(sourceID, AL_SEC_OFFSET, value);
|
||||
}
|
||||
|
||||
float AudioBackendOAL::Source_GetCurrentBufferTime(const AudioSource* source)
|
||||
float AudioBackendOAL::Source_GetCurrentBufferTime(uint32 sourceID)
|
||||
{
|
||||
#if 0
|
||||
float time;
|
||||
alGetSourcef(source->SourceID, AL_SEC_OFFSET, &time);
|
||||
alGetSourcef(sourceID, AL_SEC_OFFSET, &time);
|
||||
#else
|
||||
ASSERT(source->Clip && source->Clip->IsLoaded());
|
||||
const AudioDataInfo& clipInfo = source->Clip->AudioHeader.Info;
|
||||
ALC::Locker.Lock();
|
||||
AudioDataInfo clipInfo = ALC::SourceIDtoFormat[sourceID];
|
||||
ALC::Locker.Unlock();
|
||||
ALint samplesPlayed;
|
||||
alGetSourcei(source->SourceID, AL_SAMPLE_OFFSET, &samplesPlayed);
|
||||
alGetSourcei(sourceID, AL_SAMPLE_OFFSET, &samplesPlayed);
|
||||
const uint32 totalSamples = clipInfo.NumSamples / clipInfo.NumChannels;
|
||||
const float time = (samplesPlayed % totalSamples) / static_cast<float>(Math::Max(1U, clipInfo.SampleRate));
|
||||
if (totalSamples > 0)
|
||||
samplesPlayed %= totalSamples;
|
||||
const float time = samplesPlayed / static_cast<float>(Math::Max(1U, clipInfo.SampleRate));
|
||||
#endif
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_SetNonStreamingBuffer(AudioSource* source)
|
||||
void AudioBackendOAL::Source_SetNonStreamingBuffer(uint32 sourceID, uint32 bufferID)
|
||||
{
|
||||
const uint32 bufferId = source->Clip->Buffers[0];
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alSourcei(sourceID, AL_BUFFER, bufferId);
|
||||
alSourcei(sourceID, AL_BUFFER, bufferID);
|
||||
ALC_CHECK_ERROR(alSourcei);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_GetProcessedBuffersCount(AudioSource* source, int32& processedBuffersCount)
|
||||
void AudioBackendOAL::Source_GetProcessedBuffersCount(uint32 sourceID, int32& processedBuffersCount)
|
||||
{
|
||||
// Check the first context only
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alGetSourcei(sourceID, AL_BUFFERS_PROCESSED, &processedBuffersCount);
|
||||
ALC_CHECK_ERROR(alGetSourcei);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount)
|
||||
void AudioBackendOAL::Source_GetQueuedBuffersCount(uint32 sourceID, int32& queuedBuffersCount)
|
||||
{
|
||||
// Check the first context only
|
||||
const uint32 sourceID = source->SourceID;
|
||||
alGetSourcei(sourceID, AL_BUFFERS_QUEUED, &queuedBuffersCount);
|
||||
ALC_CHECK_ERROR(alGetSourcei);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_QueueBuffer(AudioSource* source, uint32 bufferId)
|
||||
void AudioBackendOAL::Source_QueueBuffer(uint32 sourceID, uint32 bufferID)
|
||||
{
|
||||
const uint32 sourceID = source->SourceID;
|
||||
|
||||
// Queue new buffer
|
||||
alSourceQueueBuffers(sourceID, 1, &bufferId);
|
||||
alSourceQueueBuffers(sourceID, 1, &bufferID);
|
||||
ALC_CHECK_ERROR(alSourceQueueBuffers);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Source_DequeueProcessedBuffers(AudioSource* source)
|
||||
void AudioBackendOAL::Source_DequeueProcessedBuffers(uint32 sourceID)
|
||||
{
|
||||
ALuint buffers[AUDIO_MAX_SOURCE_BUFFERS];
|
||||
const uint32 sourceID = source->SourceID;
|
||||
int32 numProcessedBuffers;
|
||||
ALuint buffers[AUDIO_MAX_SOURCE_BUFFERS];
|
||||
alGetSourcei(sourceID, AL_BUFFERS_PROCESSED, &numProcessedBuffers);
|
||||
alSourceUnqueueBuffers(sourceID, numProcessedBuffers, buffers);
|
||||
ALC_CHECK_ERROR(alSourceUnqueueBuffers);
|
||||
@@ -464,19 +461,19 @@ void AudioBackendOAL::Source_DequeueProcessedBuffers(AudioSource* source)
|
||||
|
||||
uint32 AudioBackendOAL::Buffer_Create()
|
||||
{
|
||||
uint32 bufferId;
|
||||
alGenBuffers(1, &bufferId);
|
||||
uint32 bufferID;
|
||||
alGenBuffers(1, &bufferID);
|
||||
ALC_CHECK_ERROR(alGenBuffers);
|
||||
return bufferId;
|
||||
return bufferID;
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Buffer_Delete(uint32 bufferId)
|
||||
void AudioBackendOAL::Buffer_Delete(uint32 bufferID)
|
||||
{
|
||||
alDeleteBuffers(1, &bufferId);
|
||||
alDeleteBuffers(1, &bufferID);
|
||||
ALC_CHECK_ERROR(alDeleteBuffers);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info)
|
||||
void AudioBackendOAL::Buffer_Write(uint32 bufferID, byte* samples, const AudioDataInfo& info)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
|
||||
@@ -495,7 +492,7 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
|
||||
AudioTool::ConvertToFloat(samples, info.BitDepth, sampleBufferFloat, info.NumSamples);
|
||||
|
||||
format = GetOpenALBufferFormat(info.NumChannels, 32);
|
||||
alBufferData(bufferId, format, sampleBufferFloat, bufferSize, info.SampleRate);
|
||||
alBufferData(bufferID, format, sampleBufferFloat, bufferSize, info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
Allocator::Free(sampleBufferFloat);
|
||||
}
|
||||
@@ -507,7 +504,7 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
|
||||
AudioTool::ConvertBitDepth(samples, info.BitDepth, sampleBuffer16, 16, info.NumSamples);
|
||||
|
||||
format = GetOpenALBufferFormat(info.NumChannels, 16);
|
||||
alBufferData(bufferId, format, sampleBuffer16, bufferSize, info.SampleRate);
|
||||
alBufferData(bufferID, format, sampleBuffer16, bufferSize, info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
Allocator::Free(sampleBuffer16);
|
||||
}
|
||||
@@ -520,13 +517,13 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
|
||||
for (uint32 i = 0; i < info.NumSamples; i++)
|
||||
sampleBuffer[i] = ((int8*)samples)[i] + 128;
|
||||
|
||||
alBufferData(bufferId, format, sampleBuffer, bufferSize, info.SampleRate);
|
||||
alBufferData(bufferID, format, sampleBuffer, bufferSize, info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
Allocator::Free(sampleBuffer);
|
||||
}
|
||||
else if (format)
|
||||
{
|
||||
alBufferData(bufferId, format, samples, info.NumSamples * (info.BitDepth / 8), info.SampleRate);
|
||||
alBufferData(bufferID, format, samples, info.NumSamples * (info.BitDepth / 8), info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
}
|
||||
}
|
||||
@@ -543,7 +540,7 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
|
||||
AudioTool::ConvertBitDepth(samples, info.BitDepth, sampleBuffer32, 32, info.NumSamples);
|
||||
|
||||
format = GetOpenALBufferFormat(info.NumChannels, 32);
|
||||
alBufferData(bufferId, format, sampleBuffer32, bufferSize, info.SampleRate);
|
||||
alBufferData(bufferID, format, sampleBuffer32, bufferSize, info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
|
||||
Allocator::Free(sampleBuffer32);
|
||||
@@ -558,14 +555,14 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
|
||||
sampleBuffer[i] = ((int8*)samples)[i] + 128;
|
||||
|
||||
format = GetOpenALBufferFormat(info.NumChannels, 16);
|
||||
alBufferData(bufferId, format, sampleBuffer, bufferSize, info.SampleRate);
|
||||
alBufferData(bufferID, format, sampleBuffer, bufferSize, info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
|
||||
Allocator::Free(sampleBuffer);
|
||||
}
|
||||
else if (format)
|
||||
{
|
||||
alBufferData(bufferId, format, samples, info.NumSamples * (info.BitDepth / 8), info.SampleRate);
|
||||
alBufferData(bufferID, format, samples, info.NumSamples * (info.BitDepth / 8), info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
}
|
||||
}
|
||||
@@ -589,8 +586,18 @@ AudioBackend::FeatureFlags AudioBackendOAL::Base_Features()
|
||||
void AudioBackendOAL::Base_OnActiveDeviceChanged()
|
||||
{
|
||||
// Cleanup
|
||||
Array<ALC::AudioSourceState> states;
|
||||
states.EnsureCapacity(Audio::Sources.Count());
|
||||
for (AudioSource* source : Audio::Sources)
|
||||
source->Cleanup();
|
||||
{
|
||||
states.Add({ source->GetState(), source->GetTime() });
|
||||
source->Stop();
|
||||
if (source->SourceID)
|
||||
{
|
||||
Source_Remove(source->SourceID);
|
||||
source->SourceID = 0;
|
||||
}
|
||||
}
|
||||
ALC::ClearContext();
|
||||
if (ALC::Device != nullptr)
|
||||
{
|
||||
@@ -608,7 +615,7 @@ void AudioBackendOAL::Base_OnActiveDeviceChanged()
|
||||
}
|
||||
|
||||
// Setup
|
||||
ALC::RebuildContext(true);
|
||||
ALC::RebuildContext(states);
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Base_SetDopplerFactor(float value)
|
||||
|
||||
@@ -17,30 +17,28 @@ public:
|
||||
void Listener_VelocityChanged(const Vector3& velocity) override;
|
||||
void Listener_TransformChanged(const Vector3& position, const Quaternion& orientation) override;
|
||||
void Listener_ReinitializeAll() override;
|
||||
void Source_OnAdd(AudioSource* source) override;
|
||||
void Source_OnRemove(AudioSource* source) override;
|
||||
void Source_VelocityChanged(AudioSource* source) override;
|
||||
void Source_TransformChanged(AudioSource* source) override;
|
||||
void Source_VolumeChanged(AudioSource* source) override;
|
||||
void Source_PitchChanged(AudioSource* source) override;
|
||||
void Source_PanChanged(AudioSource* source) override;
|
||||
void Source_IsLoopingChanged(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;
|
||||
void Source_Pause(AudioSource* source) override;
|
||||
void Source_Stop(AudioSource* source) override;
|
||||
void Source_SetCurrentBufferTime(AudioSource* source, float value) override;
|
||||
float Source_GetCurrentBufferTime(const AudioSource* source) override;
|
||||
void Source_SetNonStreamingBuffer(AudioSource* source) override;
|
||||
void Source_GetProcessedBuffersCount(AudioSource* source, int32& processedBuffersCount) override;
|
||||
void Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount) override;
|
||||
void Source_QueueBuffer(AudioSource* source, uint32 bufferId) override;
|
||||
void Source_DequeueProcessedBuffers(AudioSource* source) override;
|
||||
uint32 Source_Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler) override;
|
||||
void Source_Remove(uint32 sourceID) override;
|
||||
void Source_VelocityChanged(uint32 sourceID, const Vector3& velocity) override;
|
||||
void Source_TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation) override;
|
||||
void Source_VolumeChanged(uint32 sourceID, float volume) override;
|
||||
void Source_PitchChanged(uint32 sourceID, float pitch) override;
|
||||
void Source_PanChanged(uint32 sourceID, float pan) override;
|
||||
void Source_IsLoopingChanged(uint32 sourceID, bool loop) override;
|
||||
void Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler) override;
|
||||
void Source_Play(uint32 sourceID) override;
|
||||
void Source_Pause(uint32 sourceID) override;
|
||||
void Source_Stop(uint32 sourceID) override;
|
||||
void Source_SetCurrentBufferTime(uint32 sourceID, float value) override;
|
||||
float Source_GetCurrentBufferTime(uint32 sourceID) override;
|
||||
void Source_SetNonStreamingBuffer(uint32 sourceID, uint32 bufferID) override;
|
||||
void Source_GetProcessedBuffersCount(uint32 sourceID, int32& processedBuffersCount) override;
|
||||
void Source_GetQueuedBuffersCount(uint32 sourceID, int32& queuedBuffersCount) override;
|
||||
void Source_QueueBuffer(uint32 sourceID, uint32 bufferID) override;
|
||||
void Source_DequeueProcessedBuffers(uint32 sourceID) override;
|
||||
uint32 Buffer_Create() override;
|
||||
void Buffer_Delete(uint32 bufferId) override;
|
||||
void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) override;
|
||||
void Buffer_Delete(uint32 bufferID) override;
|
||||
void Buffer_Write(uint32 bufferID, byte* samples, const AudioDataInfo& info) override;
|
||||
const Char* Base_Name() override;
|
||||
FeatureFlags Base_Features() override;
|
||||
void Base_OnActiveDeviceChanged() override;
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "Engine/Core/Collections/ChunkedArray.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Audio/Audio.h"
|
||||
#include "Engine/Audio/AudioSource.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
@@ -76,7 +75,7 @@ namespace XAudio2
|
||||
}
|
||||
|
||||
public:
|
||||
AudioSource* Source;
|
||||
uint32 SourceID;
|
||||
|
||||
void PeekSamples();
|
||||
};
|
||||
@@ -85,6 +84,7 @@ namespace XAudio2
|
||||
{
|
||||
IXAudio2SourceVoice* Voice;
|
||||
WAVEFORMATEX Format;
|
||||
AudioDataInfo Info;
|
||||
XAUDIO2_SEND_DESCRIPTOR Destination;
|
||||
float StartTimeForQueueBuffer;
|
||||
float LastBufferStartTime;
|
||||
@@ -93,6 +93,8 @@ namespace XAudio2
|
||||
int32 Channels;
|
||||
bool IsDirty;
|
||||
bool IsPlaying;
|
||||
bool IsLoop;
|
||||
uint32 LastBufferID;
|
||||
VoiceCallback Callback;
|
||||
|
||||
Source()
|
||||
@@ -112,6 +114,8 @@ namespace XAudio2
|
||||
IsDirty = false;
|
||||
Is3D = false;
|
||||
IsPlaying = false;
|
||||
IsLoop = false;
|
||||
LastBufferID = 0;
|
||||
LastBufferStartSamplesPlayed = 0;
|
||||
BuffersProcessed = 0;
|
||||
}
|
||||
@@ -120,17 +124,6 @@ namespace XAudio2
|
||||
{
|
||||
return Voice == nullptr;
|
||||
}
|
||||
|
||||
void UpdateTransform(const AudioSource* source)
|
||||
{
|
||||
Position = source->GetPosition();
|
||||
Orientation = source->GetOrientation();
|
||||
}
|
||||
|
||||
void UpdateVelocity(const AudioSource* source)
|
||||
{
|
||||
Velocity = source->GetVelocity();
|
||||
}
|
||||
};
|
||||
|
||||
struct Buffer
|
||||
@@ -166,11 +159,11 @@ namespace XAudio2
|
||||
ChunkedArray<Buffer*, 64> Buffers; // TODO: use ChunkedArray for better performance or use buffers pool?
|
||||
EngineCallback Callback;
|
||||
|
||||
Source* GetSource(const AudioSource* source)
|
||||
Source* GetSource(uint32 sourceID)
|
||||
{
|
||||
if (source->SourceID == 0)
|
||||
if (sourceID == 0)
|
||||
return nullptr;
|
||||
return &Sources[source->SourceID - 1]; // 0 is invalid ID so shift them
|
||||
return &Sources[sourceID - 1]; // 0 is invalid ID so shift them
|
||||
}
|
||||
|
||||
void MarkAllDirty()
|
||||
@@ -178,9 +171,9 @@ namespace XAudio2
|
||||
ForceDirty = true;
|
||||
}
|
||||
|
||||
void QueueBuffer(Source* aSource, const AudioSource* source, const int32 bufferId, XAUDIO2_BUFFER& buffer)
|
||||
void QueueBuffer(Source* aSource, const int32 bufferID, XAUDIO2_BUFFER& buffer)
|
||||
{
|
||||
Buffer* aBuffer = Buffers[bufferId - 1];
|
||||
Buffer* aBuffer = Buffers[bufferID - 1];
|
||||
buffer.pAudioData = aBuffer->Data.Get();
|
||||
buffer.AudioBytes = aBuffer->Data.Count();
|
||||
|
||||
@@ -200,14 +193,14 @@ namespace XAudio2
|
||||
|
||||
void VoiceCallback::OnBufferEnd(void* pBufferContext)
|
||||
{
|
||||
auto aSource = GetSource(Source);
|
||||
auto aSource = GetSource(SourceID);
|
||||
if (aSource->IsPlaying)
|
||||
aSource->BuffersProcessed++;
|
||||
}
|
||||
|
||||
void VoiceCallback::PeekSamples()
|
||||
{
|
||||
auto aSource = GetSource(Source);
|
||||
auto aSource = GetSource(SourceID);
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
aSource->Voice->GetState(&state);
|
||||
aSource->LastBufferStartSamplesPlayed = state.SamplesPlayed;
|
||||
@@ -216,7 +209,7 @@ namespace XAudio2
|
||||
|
||||
void AudioBackendXAudio2::Listener_Reset()
|
||||
{
|
||||
XAudio2::Listener->Reset();
|
||||
XAudio2::Listener.Reset();
|
||||
XAudio2::MarkAllDirty();
|
||||
}
|
||||
|
||||
@@ -238,17 +231,13 @@ void AudioBackendXAudio2::Listener_ReinitializeAll()
|
||||
// TODO: Implement XAudio2 reinitialization; read HRTF audio value from Audio class
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
|
||||
uint32 AudioBackendXAudio2::Source_Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler)
|
||||
{
|
||||
// Skip if has no clip (needs audio data to create a source - needs data format information)
|
||||
if (source->Clip == nullptr || !source->Clip->IsLoaded())
|
||||
return;
|
||||
auto clip = source->Clip.Get();
|
||||
ScopeLock lock(XAudio2::Locker);
|
||||
|
||||
// Get first free source
|
||||
XAudio2::Source* aSource = nullptr;
|
||||
uint32 sourceID;
|
||||
uint32 sourceID = 0;
|
||||
for (int32 i = 0; i < XAudio2::Sources.Count(); i++)
|
||||
{
|
||||
if (XAudio2::Sources[i].IsFree())
|
||||
@@ -266,115 +255,124 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
|
||||
XAudio2::Sources.Add(src);
|
||||
aSource = &XAudio2::Sources[sourceID];
|
||||
}
|
||||
sourceID++; // 0 is invalid ID so shift them
|
||||
|
||||
// Initialize audio data format information (from clip)
|
||||
const auto& header = clip->AudioHeader;
|
||||
auto& format = aSource->Format;
|
||||
format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
format.nChannels = clip->Is3D() ? 1 : header.Info.NumChannels; // 3d audio is always mono (AudioClip auto-converts before buffer write if FeatureFlags::SpatialMultiChannel is unset)
|
||||
format.nSamplesPerSec = header.Info.SampleRate;
|
||||
format.wBitsPerSample = header.Info.BitDepth;
|
||||
format.nBlockAlign = (WORD)(format.nChannels * (format.wBitsPerSample / 8));
|
||||
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
|
||||
format.cbSize = 0;
|
||||
aSource->Info = format;
|
||||
auto& aFormat = aSource->Format;
|
||||
aFormat.wFormatTag = WAVE_FORMAT_PCM;
|
||||
aFormat.nChannels = spatial ? 1 : format.NumChannels; // 3d audio is always mono (AudioClip auto-converts before buffer write if FeatureFlags::SpatialMultiChannel is unset)
|
||||
aFormat.nSamplesPerSec = format.SampleRate;
|
||||
aFormat.wBitsPerSample = format.BitDepth;
|
||||
aFormat.nBlockAlign = (WORD)(aFormat.nChannels * (aFormat.wBitsPerSample / 8));
|
||||
aFormat.nAvgBytesPerSec = aFormat.nSamplesPerSec * aFormat.nBlockAlign;
|
||||
aFormat.cbSize = 0;
|
||||
|
||||
// Setup dry effect
|
||||
aSource->Destination.pOutputVoice = XAudio2::MasteringVoice;
|
||||
|
||||
// Create voice
|
||||
const XAUDIO2_VOICE_SENDS sendList =
|
||||
{
|
||||
1,
|
||||
&aSource->Destination
|
||||
};
|
||||
const XAUDIO2_VOICE_SENDS sendList = { 1, &aSource->Destination };
|
||||
HRESULT hr = XAudio2::Instance->CreateSourceVoice(&aSource->Voice, &aSource->Format, 0, 2.0f, &aSource->Callback, &sendList);
|
||||
XAUDIO2_CHECK_ERROR(CreateSourceVoice);
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
|
||||
source->SourceID = sourceID + 1; // 0 is invalid ID so shift them
|
||||
return 0;
|
||||
|
||||
// Prepare source state
|
||||
aSource->Callback.Source = source;
|
||||
aSource->Callback.SourceID = sourceID;
|
||||
aSource->IsDirty = true;
|
||||
aSource->Is3D = source->Is3D();
|
||||
aSource->Pitch = source->GetPitch();
|
||||
aSource->Pan = source->GetPan();
|
||||
aSource->DopplerFactor = source->GetDopplerFactor();
|
||||
aSource->Volume = source->GetVolume();
|
||||
aSource->MinDistance = source->GetMinDistance();
|
||||
aSource->Attenuation = source->GetAttenuation();
|
||||
aSource->Channels = format.nChannels;
|
||||
aSource->UpdateTransform(source);
|
||||
aSource->UpdateVelocity(source);
|
||||
hr = aSource->Voice->SetVolume(source->GetVolume());
|
||||
aSource->IsLoop = loop;
|
||||
aSource->Is3D = spatial;
|
||||
aSource->Pitch = pitch;
|
||||
aSource->Pan = pan;
|
||||
aSource->DopplerFactor = doppler;
|
||||
aSource->Volume = volume;
|
||||
aSource->MinDistance = minDistance;
|
||||
aSource->Attenuation = attenuation;
|
||||
aSource->Channels = aFormat.nChannels;
|
||||
aSource->Position = position;
|
||||
aSource->Orientation = orientation;
|
||||
aSource->Velocity = Vector3::Zero;
|
||||
hr = aSource->Voice->SetVolume(volume);
|
||||
XAUDIO2_CHECK_ERROR(SetVolume);
|
||||
|
||||
source->Restore();
|
||||
return sourceID;
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_OnRemove(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_Remove(uint32 sourceID)
|
||||
{
|
||||
ScopeLock lock(XAudio2::Locker);
|
||||
source->Cleanup();
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (!aSource)
|
||||
return;
|
||||
|
||||
// Free source
|
||||
if (aSource->Voice)
|
||||
{
|
||||
aSource->Voice->DestroyVoice();
|
||||
}
|
||||
aSource->Init();
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_VelocityChanged(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_VelocityChanged(uint32 sourceID, const Vector3& velocity)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource)
|
||||
{
|
||||
aSource->UpdateVelocity(source);
|
||||
aSource->Velocity = velocity;
|
||||
aSource->IsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_TransformChanged(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource)
|
||||
{
|
||||
aSource->UpdateTransform(source);
|
||||
aSource->Position = position;
|
||||
aSource->Orientation = orientation;
|
||||
aSource->IsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_VolumeChanged(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_VolumeChanged(uint32 sourceID, float volume)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource && aSource->Voice)
|
||||
{
|
||||
aSource->Volume = source->GetVolume();
|
||||
const HRESULT hr = aSource->Voice->SetVolume(source->GetVolume());
|
||||
aSource->Volume = volume;
|
||||
const HRESULT hr = aSource->Voice->SetVolume(volume);
|
||||
XAUDIO2_CHECK_ERROR(SetVolume);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_PitchChanged(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_PitchChanged(uint32 sourceID, float pitch)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource)
|
||||
{
|
||||
aSource->Pitch = source->GetPitch();
|
||||
aSource->Pitch = pitch;
|
||||
aSource->IsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_PanChanged(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_PanChanged(uint32 sourceID, float pan)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource)
|
||||
{
|
||||
aSource->Pan = source->GetPan();
|
||||
aSource->Pan = pan;
|
||||
aSource->IsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_IsLoopingChanged(uint32 sourceID, bool loop)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
ScopeLock lock(XAudio2::Locker);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (!aSource || !aSource->Voice)
|
||||
return;
|
||||
aSource->IsLoop = loop;
|
||||
|
||||
// Skip if has no buffers (waiting for data or sth)
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
@@ -382,15 +380,12 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
|
||||
if (state.BuffersQueued == 0)
|
||||
return;
|
||||
|
||||
// Looping is defined during buffer submission so reset source buffer (this is called only for non-streamable sources that ue single buffer)
|
||||
|
||||
XAudio2::Locker.Lock();
|
||||
const uint32 bufferId = source->Clip->Buffers[0];
|
||||
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
|
||||
XAudio2::Locker.Unlock();
|
||||
// Looping is defined during buffer submission so reset source buffer (this is called only for non-streamable sources that use a single buffer)
|
||||
const uint32 bufferID = aSource->LastBufferID;
|
||||
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferID - 1];
|
||||
|
||||
HRESULT hr;
|
||||
const bool isPlaying = source->IsActuallyPlayingSth();
|
||||
const bool isPlaying = aSource->IsPlaying;
|
||||
if (isPlaying)
|
||||
{
|
||||
hr = aSource->Voice->Stop();
|
||||
@@ -406,7 +401,7 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
|
||||
XAUDIO2_BUFFER buffer = { 0 };
|
||||
buffer.pContext = aBuffer;
|
||||
buffer.Flags = XAUDIO2_END_OF_STREAM;
|
||||
if (source->GetIsLooping())
|
||||
if (loop)
|
||||
buffer.LoopCount = XAUDIO2_LOOP_INFINITE;
|
||||
|
||||
// Restore play position
|
||||
@@ -415,7 +410,7 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
|
||||
buffer.PlayLength = totalSamples - buffer.PlayBegin;
|
||||
aSource->StartTimeForQueueBuffer = 0;
|
||||
|
||||
XAudio2::QueueBuffer(aSource, source, bufferId, buffer);
|
||||
XAudio2::QueueBuffer(aSource, bufferID, buffer);
|
||||
|
||||
if (isPlaying)
|
||||
{
|
||||
@@ -424,48 +419,22 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_SpatialSetupChanged(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource)
|
||||
{
|
||||
aSource->Is3D = source->Is3D();
|
||||
aSource->MinDistance = source->GetMinDistance();
|
||||
aSource->Attenuation = source->GetAttenuation();
|
||||
aSource->DopplerFactor = source->GetDopplerFactor();
|
||||
aSource->Is3D = spatial;
|
||||
aSource->MinDistance = minDistance;
|
||||
aSource->Attenuation = attenuation;
|
||||
aSource->DopplerFactor = doppler;
|
||||
aSource->IsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_ClipLoaded(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_Play(uint32 sourceID)
|
||||
{
|
||||
ScopeLock lock(XAudio2::Locker);
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
if (!aSource)
|
||||
{
|
||||
// Register source if clip was missing
|
||||
Source_OnAdd(source);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_Cleanup(AudioSource* source)
|
||||
{
|
||||
ScopeLock lock(XAudio2::Locker);
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
if (!aSource)
|
||||
return;
|
||||
|
||||
// Free source
|
||||
if (aSource->Voice)
|
||||
{
|
||||
aSource->Voice->DestroyVoice();
|
||||
}
|
||||
aSource->Init();
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_Play(AudioSource* source)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource && aSource->Voice && !aSource->IsPlaying)
|
||||
{
|
||||
// Play
|
||||
@@ -475,9 +444,9 @@ void AudioBackendXAudio2::Source_Play(AudioSource* source)
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_Pause(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_Pause(uint32 sourceID)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource && aSource->Voice && aSource->IsPlaying)
|
||||
{
|
||||
// Pause
|
||||
@@ -487,9 +456,9 @@ void AudioBackendXAudio2::Source_Pause(AudioSource* source)
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_Stop(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_Stop(uint32 sourceID)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource && aSource->Voice)
|
||||
{
|
||||
aSource->StartTimeForQueueBuffer = 0.0f;
|
||||
@@ -509,9 +478,9 @@ void AudioBackendXAudio2::Source_Stop(AudioSource* source)
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_SetCurrentBufferTime(AudioSource* source, float value)
|
||||
void AudioBackendXAudio2::Source_SetCurrentBufferTime(uint32 sourceID, float value)
|
||||
{
|
||||
const auto aSource = XAudio2::GetSource(source);
|
||||
const auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource)
|
||||
{
|
||||
// Store start time so next buffer submitted will start from here (assumes audio is stopped)
|
||||
@@ -519,60 +488,63 @@ void AudioBackendXAudio2::Source_SetCurrentBufferTime(AudioSource* source, float
|
||||
}
|
||||
}
|
||||
|
||||
float AudioBackendXAudio2::Source_GetCurrentBufferTime(const AudioSource* source)
|
||||
float AudioBackendXAudio2::Source_GetCurrentBufferTime(uint32 sourceID)
|
||||
{
|
||||
float time = 0;
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource)
|
||||
{
|
||||
ASSERT(source->Clip && source->Clip->IsLoaded());
|
||||
const auto& clipInfo = source->Clip->AudioHeader.Info;
|
||||
const auto& clipInfo = aSource->Info;
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
aSource->Voice->GetState(&state);
|
||||
const uint32 numChannels = clipInfo.NumChannels;
|
||||
const uint32 totalSamples = clipInfo.NumSamples / numChannels;
|
||||
const uint32 totalSamples = clipInfo.NumSamples / clipInfo.NumChannels;
|
||||
const uint32 sampleRate = clipInfo.SampleRate; // / clipInfo.NumChannels;
|
||||
state.SamplesPlayed -= aSource->LastBufferStartSamplesPlayed % totalSamples; // Offset by the last buffer start to get time relative to its begin
|
||||
time = aSource->LastBufferStartTime + (state.SamplesPlayed % totalSamples) / static_cast<float>(Math::Max(1U, sampleRate));
|
||||
uint64 lastBufferStartSamplesPlayed = aSource->LastBufferStartSamplesPlayed;
|
||||
if (totalSamples > 0)
|
||||
lastBufferStartSamplesPlayed %= totalSamples;
|
||||
state.SamplesPlayed -= lastBufferStartSamplesPlayed % totalSamples; // Offset by the last buffer start to get time relative to its begin
|
||||
if (totalSamples > 0)
|
||||
state.SamplesPlayed %= totalSamples;
|
||||
time = aSource->LastBufferStartTime + state.SamplesPlayed / static_cast<float>(Math::Max(1U, sampleRate));
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_SetNonStreamingBuffer(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_SetNonStreamingBuffer(uint32 sourceID, uint32 bufferID)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (!aSource)
|
||||
return;
|
||||
aSource->LastBufferID = bufferID; // Use for looping change
|
||||
|
||||
XAudio2::Locker.Lock();
|
||||
const uint32 bufferId = source->Clip->Buffers[0];
|
||||
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
|
||||
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferID - 1];
|
||||
XAudio2::Locker.Unlock();
|
||||
|
||||
XAUDIO2_BUFFER buffer = { 0 };
|
||||
buffer.pContext = aBuffer;
|
||||
buffer.Flags = XAUDIO2_END_OF_STREAM;
|
||||
if (source->GetIsLooping())
|
||||
if (aSource->IsLoop)
|
||||
buffer.LoopCount = XAUDIO2_LOOP_INFINITE;
|
||||
|
||||
// Queue single buffer
|
||||
XAudio2::QueueBuffer(aSource, source, bufferId, buffer);
|
||||
XAudio2::QueueBuffer(aSource, bufferID, buffer);
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_GetProcessedBuffersCount(AudioSource* source, int32& processedBuffersCount)
|
||||
void AudioBackendXAudio2::Source_GetProcessedBuffersCount(uint32 sourceID, int32& processedBuffersCount)
|
||||
{
|
||||
processedBuffersCount = 0;
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource && aSource->Voice)
|
||||
{
|
||||
processedBuffersCount = aSource->BuffersProcessed;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount)
|
||||
void AudioBackendXAudio2::Source_GetQueuedBuffersCount(uint32 sourceID, int32& queuedBuffersCount)
|
||||
{
|
||||
queuedBuffersCount = 0;
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource && aSource->Voice)
|
||||
{
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
@@ -581,23 +553,24 @@ void AudioBackendXAudio2::Source_GetQueuedBuffersCount(AudioSource* source, int3
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_QueueBuffer(AudioSource* source, uint32 bufferId)
|
||||
void AudioBackendXAudio2::Source_QueueBuffer(uint32 sourceID, uint32 bufferID)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (!aSource)
|
||||
return;
|
||||
aSource->LastBufferID = bufferID; // Use for looping change
|
||||
|
||||
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
|
||||
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferID - 1];
|
||||
|
||||
XAUDIO2_BUFFER buffer = { 0 };
|
||||
buffer.pContext = aBuffer;
|
||||
|
||||
XAudio2::QueueBuffer(aSource, source, bufferId, buffer);
|
||||
XAudio2::QueueBuffer(aSource, bufferID, buffer);
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_DequeueProcessedBuffers(AudioSource* source)
|
||||
void AudioBackendXAudio2::Source_DequeueProcessedBuffers(uint32 sourceID)
|
||||
{
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
auto aSource = XAudio2::GetSource(sourceID);
|
||||
if (aSource && aSource->Voice)
|
||||
{
|
||||
const HRESULT hr = aSource->Voice->FlushSourceBuffers();
|
||||
@@ -608,7 +581,7 @@ void AudioBackendXAudio2::Source_DequeueProcessedBuffers(AudioSource* source)
|
||||
|
||||
uint32 AudioBackendXAudio2::Buffer_Create()
|
||||
{
|
||||
uint32 bufferId;
|
||||
uint32 bufferID;
|
||||
ScopeLock lock(XAudio2::Locker);
|
||||
|
||||
// Get first free buffer slot
|
||||
@@ -619,7 +592,7 @@ uint32 AudioBackendXAudio2::Buffer_Create()
|
||||
{
|
||||
aBuffer = New<XAudio2::Buffer>();
|
||||
XAudio2::Buffers[i] = aBuffer;
|
||||
bufferId = i + 1;
|
||||
bufferID = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -628,28 +601,28 @@ uint32 AudioBackendXAudio2::Buffer_Create()
|
||||
// Add new slot
|
||||
aBuffer = New<XAudio2::Buffer>();
|
||||
XAudio2::Buffers.Add(aBuffer);
|
||||
bufferId = XAudio2::Buffers.Count();
|
||||
bufferID = XAudio2::Buffers.Count();
|
||||
}
|
||||
|
||||
aBuffer->Data.Resize(0);
|
||||
return bufferId;
|
||||
return bufferID;
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Buffer_Delete(uint32 bufferId)
|
||||
void AudioBackendXAudio2::Buffer_Delete(uint32 bufferID)
|
||||
{
|
||||
ScopeLock lock(XAudio2::Locker);
|
||||
XAudio2::Buffer*& aBuffer = XAudio2::Buffers[bufferId - 1];
|
||||
XAudio2::Buffer*& aBuffer = XAudio2::Buffers[bufferID - 1];
|
||||
aBuffer->Data.Resize(0);
|
||||
Delete(aBuffer);
|
||||
aBuffer = nullptr;
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info)
|
||||
void AudioBackendXAudio2::Buffer_Write(uint32 bufferID, byte* samples, const AudioDataInfo& info)
|
||||
{
|
||||
CHECK(info.NumChannels <= MAX_INPUT_CHANNELS);
|
||||
|
||||
XAudio2::Locker.Lock();
|
||||
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
|
||||
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferID - 1];
|
||||
XAudio2::Locker.Unlock();
|
||||
|
||||
const uint32 samplesLength = info.NumSamples * info.BitDepth / 8;
|
||||
@@ -735,7 +708,6 @@ bool AudioBackendXAudio2::Base_Init()
|
||||
void AudioBackendXAudio2::Base_Update()
|
||||
{
|
||||
// Update dirty voices
|
||||
const auto listener = XAudio2::GetListener();
|
||||
float outputMatrix[MAX_CHANNELS_MATRIX_SIZE];
|
||||
for (int32 i = 0; i < XAudio2::Sources.Count(); i++)
|
||||
{
|
||||
@@ -743,7 +715,7 @@ void AudioBackendXAudio2::Base_Update()
|
||||
if (source.IsFree() || !(source.IsDirty || XAudio2::ForceDirty))
|
||||
continue;
|
||||
|
||||
auto mix = AudioBackendTools::CalculateSoundMix(XAudio2::Settings, *listener, source, XAudio2::Channels);
|
||||
auto mix = AudioBackendTools::CalculateSoundMix(XAudio2::Settings, XAudio2::Listener, source, XAudio2::Channels);
|
||||
mix.VolumeIntoChannels();
|
||||
AudioBackendTools::MapChannels(source.Channels, XAudio2::Channels, mix.Channels, outputMatrix);
|
||||
|
||||
|
||||
@@ -17,30 +17,28 @@ public:
|
||||
void Listener_VelocityChanged(const Vector3& velocity) override;
|
||||
void Listener_TransformChanged(const Vector3& position, const Quaternion& orientation) override;
|
||||
void Listener_ReinitializeAll() override;
|
||||
void Source_OnAdd(AudioSource* source) override;
|
||||
void Source_OnRemove(AudioSource* source) override;
|
||||
void Source_VelocityChanged(AudioSource* source) override;
|
||||
void Source_TransformChanged(AudioSource* source) override;
|
||||
void Source_VolumeChanged(AudioSource* source) override;
|
||||
void Source_PitchChanged(AudioSource* source) override;
|
||||
void Source_PanChanged(AudioSource* source) override;
|
||||
void Source_IsLoopingChanged(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;
|
||||
void Source_Pause(AudioSource* source) override;
|
||||
void Source_Stop(AudioSource* source) override;
|
||||
void Source_SetCurrentBufferTime(AudioSource* source, float value) override;
|
||||
float Source_GetCurrentBufferTime(const AudioSource* source) override;
|
||||
void Source_SetNonStreamingBuffer(AudioSource* source) override;
|
||||
void Source_GetProcessedBuffersCount(AudioSource* source, int32& processedBuffersCount) override;
|
||||
void Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount) override;
|
||||
void Source_QueueBuffer(AudioSource* source, uint32 bufferId) override;
|
||||
void Source_DequeueProcessedBuffers(AudioSource* source) override;
|
||||
uint32 Source_Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler) override;
|
||||
void Source_Remove(uint32 sourceID) override;
|
||||
void Source_VelocityChanged(uint32 sourceID, const Vector3& velocity) override;
|
||||
void Source_TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation) override;
|
||||
void Source_VolumeChanged(uint32 sourceID, float volume) override;
|
||||
void Source_PitchChanged(uint32 sourceID, float pitch) override;
|
||||
void Source_PanChanged(uint32 sourceID, float pan) override;
|
||||
void Source_IsLoopingChanged(uint32 sourceID, bool loop) override;
|
||||
void Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler) override;
|
||||
void Source_Play(uint32 sourceID) override;
|
||||
void Source_Pause(uint32 sourceID) override;
|
||||
void Source_Stop(uint32 sourceID) override;
|
||||
void Source_SetCurrentBufferTime(uint32 sourceID, float value) override;
|
||||
float Source_GetCurrentBufferTime(uint32 sourceID) override;
|
||||
void Source_SetNonStreamingBuffer(uint32 sourceID, uint32 bufferID) override;
|
||||
void Source_GetProcessedBuffersCount(uint32 sourceID, int32& processedBuffersCount) override;
|
||||
void Source_GetQueuedBuffersCount(uint32 sourceID, int32& queuedBuffersCount) override;
|
||||
void Source_QueueBuffer(uint32 sourceID, uint32 bufferID) override;
|
||||
void Source_DequeueProcessedBuffers(uint32 sourceID) override;
|
||||
uint32 Buffer_Create() override;
|
||||
void Buffer_Delete(uint32 bufferId) override;
|
||||
void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) override;
|
||||
void Buffer_Delete(uint32 bufferID) override;
|
||||
void Buffer_Write(uint32 bufferID, byte* samples, const AudioDataInfo& info) override;
|
||||
const Char* Base_Name() override;
|
||||
FeatureFlags Base_Features() override;
|
||||
void Base_OnActiveDeviceChanged() override;
|
||||
|
||||
Reference in New Issue
Block a user