audio: narrow render locking to snapshots
This commit is contained in:
@@ -2,9 +2,10 @@
|
||||
|
||||
#include <XCEngine/Audio/AudioTypes.h>
|
||||
#include <XCEngine/Core/Math/Vector3.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Audio {
|
||||
@@ -17,19 +18,28 @@ public:
|
||||
~AudioMixer();
|
||||
|
||||
void SetVolume(float volume);
|
||||
float GetVolume() const { return m_volume; }
|
||||
float GetVolume() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_volume;
|
||||
}
|
||||
|
||||
void SetMute(bool mute);
|
||||
bool IsMute() const { return m_mute; }
|
||||
bool IsMute() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_mute;
|
||||
}
|
||||
|
||||
void AddEffect(IAudioEffect* effect);
|
||||
void RemoveEffect(IAudioEffect* effect);
|
||||
void ClearEffects();
|
||||
|
||||
void ProcessAudio(float* buffer, uint32 sampleCount, uint32 channels);
|
||||
void ProcessAudio(float* buffer, uint32 frameCount, uint32 channels, uint32 sampleRate = 48000);
|
||||
|
||||
void SetOutputMixer(AudioMixer* mixer);
|
||||
AudioMixer* GetOutputMixer() const { return m_outputMixer; }
|
||||
AudioMixer* GetOutputMixer() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_outputMixer;
|
||||
}
|
||||
|
||||
void Set3DParams(const Audio3DParams& params);
|
||||
const Audio3DParams& Get3DParams() const { return m_3DParams; }
|
||||
@@ -40,8 +50,12 @@ public:
|
||||
};
|
||||
void SetChannelVolume(AudioChannel channel, float volume);
|
||||
float GetChannelVolume(AudioChannel channel) const;
|
||||
[[nodiscard]] std::unique_lock<std::recursive_mutex> AcquireStateLock() const {
|
||||
return std::unique_lock<std::recursive_mutex>(m_stateMutex);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::recursive_mutex m_stateMutex;
|
||||
float m_volume = 1.0f;
|
||||
bool m_mute = false;
|
||||
|
||||
|
||||
@@ -85,18 +85,40 @@ public:
|
||||
const Stats& GetStats() const { return m_stats; }
|
||||
|
||||
private:
|
||||
struct RenderStateSnapshot {
|
||||
Math::Vector3 listenerPosition = Math::Vector3::Zero();
|
||||
Math::Quaternion listenerRotation = Math::Quaternion::Identity();
|
||||
Math::Vector3 listenerVelocity = Math::Vector3::Zero();
|
||||
AudioMixer* listenerReverbMixer = nullptr;
|
||||
float listenerReverbLevel = 1.0f;
|
||||
float listenerDopplerLevel = 1.0f;
|
||||
float speedOfSound = 343.0f;
|
||||
};
|
||||
|
||||
AudioSystem();
|
||||
~AudioSystem();
|
||||
|
||||
AudioSystem(const AudioSystem&) = delete;
|
||||
AudioSystem& operator=(const AudioSystem&) = delete;
|
||||
|
||||
void ProcessSource(Components::AudioSourceComponent* source, float* buffer, uint32 frameCount, uint32 channels, uint32 sampleRate);
|
||||
void RenderAudioBlock(uint32 frameCount, uint32 channels, uint32 sampleRate);
|
||||
void CaptureRenderState(RenderStateSnapshot& snapshot);
|
||||
void ProcessSource(
|
||||
Components::AudioSourceComponent* source,
|
||||
float* buffer,
|
||||
uint32 frameCount,
|
||||
uint32 channels,
|
||||
uint32 sampleRate,
|
||||
const RenderStateSnapshot& snapshot);
|
||||
void RenderAudioBlock(
|
||||
uint32 frameCount,
|
||||
uint32 channels,
|
||||
uint32 sampleRate,
|
||||
const RenderStateSnapshot& snapshot);
|
||||
void DetachMixerReferences(AudioMixer* mixer);
|
||||
void UpdateStats();
|
||||
|
||||
private:
|
||||
mutable std::recursive_mutex m_renderMutex;
|
||||
mutable std::recursive_mutex m_stateMutex;
|
||||
std::unique_ptr<IAudioBackend> m_backend;
|
||||
AudioMixer m_masterMixer;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <XCEngine/Components/Component.h>
|
||||
#include <XCEngine/Components/TransformComponent.h>
|
||||
#include <XCEngine/Audio/AudioTypes.h>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -17,33 +18,60 @@ public:
|
||||
AudioListenerComponent();
|
||||
~AudioListenerComponent() override;
|
||||
|
||||
float GetEnergy() const { return m_energy; }
|
||||
float GetEnergy() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_energy;
|
||||
}
|
||||
const float* GetFrequencyData() const { return m_frequencyData.data(); }
|
||||
size_t GetFrequencyDataSize() const { return m_frequencyData.size(); }
|
||||
|
||||
void SetMasterVolume(float volume);
|
||||
float GetMasterVolume() const { return m_masterVolume; }
|
||||
float GetMasterVolume() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_masterVolume;
|
||||
}
|
||||
|
||||
void SetMute(bool mute);
|
||||
bool IsMute() const { return m_mute; }
|
||||
bool IsMute() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_mute;
|
||||
}
|
||||
|
||||
void SetDopplerLevel(float level);
|
||||
float GetDopplerLevel() const { return m_dopplerLevel; }
|
||||
float GetDopplerLevel() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_dopplerLevel;
|
||||
}
|
||||
|
||||
void SetSpeedOfSound(float metersPerSecond);
|
||||
float GetSpeedOfSound() const { return m_speedOfSound; }
|
||||
float GetSpeedOfSound() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_speedOfSound;
|
||||
}
|
||||
|
||||
void SetReverbLevel(float level);
|
||||
float GetReverbLevel() const { return m_reverbLevel; }
|
||||
float GetReverbLevel() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_reverbLevel;
|
||||
}
|
||||
|
||||
void SetReverb(Audio::AudioMixer* reverb);
|
||||
Audio::AudioMixer* GetReverb() const { return m_reverb; }
|
||||
Audio::AudioMixer* GetReverb() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_reverb;
|
||||
}
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
void Serialize(std::ostream& os) const override;
|
||||
void Deserialize(std::istream& is) override;
|
||||
|
||||
std::string GetName() const override { return "AudioListener"; }
|
||||
[[nodiscard]] std::unique_lock<std::recursive_mutex> AcquireStateLock() const {
|
||||
return std::unique_lock<std::recursive_mutex>(m_stateMutex);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::recursive_mutex m_stateMutex;
|
||||
float m_masterVolume = 1.0f;
|
||||
bool m_mute = false;
|
||||
float m_dopplerLevel = 1.0f;
|
||||
@@ -52,6 +80,9 @@ private:
|
||||
|
||||
Audio::AudioMixer* m_reverb = nullptr;
|
||||
|
||||
Math::Vector3 m_lastPosition = Math::Vector3::Zero();
|
||||
bool m_hasLastPosition = false;
|
||||
|
||||
float m_energy = 0.0f;
|
||||
std::vector<float> m_frequencyData;
|
||||
};
|
||||
|
||||
@@ -9,9 +9,10 @@
|
||||
#include <XCEngine/Resources/AudioClip/AudioClip.h>
|
||||
#include <XCEngine/Core/Math/Vector3.h>
|
||||
#include <XCEngine/Core/Math/Quaternion.h>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Audio {
|
||||
@@ -28,61 +29,112 @@ public:
|
||||
void Play();
|
||||
void Pause();
|
||||
void Stop(Audio::StopMode mode = Audio::StopMode::Immediate);
|
||||
bool IsPlaying() const { return m_playState == Audio::PlayState::Playing; }
|
||||
bool IsPaused() const { return m_playState == Audio::PlayState::Paused; }
|
||||
bool IsPlaying() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_playState == Audio::PlayState::Playing;
|
||||
}
|
||||
bool IsPaused() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_playState == Audio::PlayState::Paused;
|
||||
}
|
||||
|
||||
void SetClip(Resources::AudioClip* clip);
|
||||
Resources::AudioClip* GetClip() const { return m_clip; }
|
||||
Resources::AudioClip* GetClip() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_clip;
|
||||
}
|
||||
void SetClipPath(const std::string& clipPath);
|
||||
void ClearClip();
|
||||
const std::string& GetClipPath() const { return m_clipPath; }
|
||||
const Resources::AssetRef& GetClipAssetRef() const { return m_clipRef; }
|
||||
|
||||
void SetVolume(float volume);
|
||||
float GetVolume() const { return m_volume; }
|
||||
float GetVolume() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_volume;
|
||||
}
|
||||
|
||||
void SetPitch(float pitch);
|
||||
float GetPitch() const { return m_pitch; }
|
||||
float GetPitch() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_pitch;
|
||||
}
|
||||
|
||||
void SetPan(float pan);
|
||||
float GetPan() const { return m_pan; }
|
||||
float GetPan() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_pan;
|
||||
}
|
||||
|
||||
void SetHRTFEnabled(bool enabled);
|
||||
bool IsHRTFEnabled() const { return m_useHRTF; }
|
||||
bool IsHRTFEnabled() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_useHRTF;
|
||||
}
|
||||
void SetHRTFCrossFeed(float crossFeed);
|
||||
float GetHRTFCrossFeed() const { return m_hrtf.GetCrossFeed(); }
|
||||
float GetHRTFCrossFeed() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_hrtf.GetCrossFeed();
|
||||
}
|
||||
void SetHRTFQuality(Audio::uint32 level);
|
||||
Audio::uint32 GetHRTFQuality() const { return m_hrtf.GetQualityLevel(); }
|
||||
Audio::uint32 GetHRTFQuality() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_hrtf.GetQualityLevel();
|
||||
}
|
||||
|
||||
void SetLooping(bool loop);
|
||||
bool IsLooping() const { return m_isLooping; }
|
||||
bool IsLooping() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_isLooping;
|
||||
}
|
||||
|
||||
void SetSpatialize(bool spatialize);
|
||||
bool IsSpatialize() const { return m_spatialize; }
|
||||
bool IsSpatialize() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_spatialize;
|
||||
}
|
||||
|
||||
void Set3DParams(const Audio::Audio3DParams& params);
|
||||
const Audio::Audio3DParams& Get3DParams() const { return m_3DParams; }
|
||||
|
||||
void SetDopplerLevel(float level);
|
||||
float GetDopplerLevel() const { return m_3DParams.dopplerLevel; }
|
||||
float GetDopplerLevel() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_3DParams.dopplerLevel;
|
||||
}
|
||||
|
||||
void SetSpread(float spread);
|
||||
float GetSpread() const { return m_3DParams.spread; }
|
||||
float GetSpread() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_3DParams.spread;
|
||||
}
|
||||
|
||||
void SetReverbZoneMix(float mix);
|
||||
float GetReverbZoneMix() const { return m_3DParams.reverbZoneMix; }
|
||||
float GetReverbZoneMix() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_3DParams.reverbZoneMix;
|
||||
}
|
||||
|
||||
void SetOutputMixer(Audio::AudioMixer* mixer);
|
||||
Audio::AudioMixer* GetOutputMixer() const { return m_outputMixer; }
|
||||
Audio::AudioMixer* GetOutputMixer() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_outputMixer;
|
||||
}
|
||||
|
||||
void SetTime(float seconds);
|
||||
float GetTime() const;
|
||||
float GetDuration() const;
|
||||
|
||||
float GetEnergy() const { return m_energy; }
|
||||
float GetEnergy() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_energy;
|
||||
}
|
||||
void StartEnergyDetect();
|
||||
void StopEnergyDetect();
|
||||
bool IsEnergyDetecting() const { return m_isEnergyDetecting; }
|
||||
bool IsEnergyDetecting() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
|
||||
return m_isEnergyDetecting;
|
||||
}
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
void OnEnable() override;
|
||||
@@ -100,6 +152,9 @@ public:
|
||||
Audio::uint32 outputSampleRate = 0);
|
||||
|
||||
std::string GetName() const override { return "AudioSource"; }
|
||||
[[nodiscard]] std::unique_lock<std::recursive_mutex> AcquireStateLock() const {
|
||||
return std::unique_lock<std::recursive_mutex>(m_stateMutex);
|
||||
}
|
||||
|
||||
private:
|
||||
float Compute3DAttenuation(const Math::Vector3& listenerPosition) const;
|
||||
@@ -112,6 +167,7 @@ private:
|
||||
void UpdateEnergy(const float* buffer, Audio::uint32 sampleCount);
|
||||
|
||||
private:
|
||||
mutable std::recursive_mutex m_stateMutex;
|
||||
Resources::ResourceHandle<Resources::AudioClip> m_clipHandle;
|
||||
Resources::AudioClip* m_clip = nullptr;
|
||||
std::string m_clipPath;
|
||||
|
||||
Reference in New Issue
Block a user