audio: narrow render locking to snapshots

This commit is contained in:
2026-04-14 19:15:23 +08:00
parent 5a938935e1
commit 78556ea683
8 changed files with 420 additions and 188 deletions

View File

@@ -7,17 +7,6 @@
namespace XCEngine {
namespace Components {
namespace {
std::unique_lock<std::recursive_mutex> LockAudioState() {
if (Audio::AudioSystem* audioSystem = Audio::AudioSystem::TryGetExisting()) {
return audioSystem->AcquireStateLock();
}
return std::unique_lock<std::recursive_mutex>();
}
} // namespace
AudioListenerComponent::AudioListenerComponent()
{
Audio::AudioSystem::Get().RegisterListenerComponent(this);
@@ -28,43 +17,66 @@ AudioListenerComponent::~AudioListenerComponent() {
}
void AudioListenerComponent::SetMasterVolume(float volume) {
auto audioStateLock = LockAudioState();
m_masterVolume = std::max(0.0f, std::min(1.0f, volume));
Audio::AudioSystem::Get().SetMasterVolume(m_masterVolume);
float masterVolume = 0.0f;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_masterVolume = std::max(0.0f, std::min(1.0f, volume));
masterVolume = m_masterVolume;
}
Audio::AudioSystem::Get().SetMasterVolume(masterVolume);
}
void AudioListenerComponent::SetMute(bool mute) {
auto audioStateLock = LockAudioState();
m_mute = mute;
Audio::AudioSystem::Get().SetMuted(m_mute);
bool isMute = false;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_mute = mute;
isMute = m_mute;
}
Audio::AudioSystem::Get().SetMuted(isMute);
}
void AudioListenerComponent::SetDopplerLevel(float level) {
auto audioStateLock = LockAudioState();
m_dopplerLevel = std::max(0.0f, std::min(5.0f, level));
Audio::AudioSystem::Get().SetListenerDopplerLevel(m_dopplerLevel);
float dopplerLevel = 1.0f;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_dopplerLevel = std::max(0.0f, std::min(5.0f, level));
dopplerLevel = m_dopplerLevel;
}
Audio::AudioSystem::Get().SetListenerDopplerLevel(dopplerLevel);
}
void AudioListenerComponent::SetSpeedOfSound(float metersPerSecond) {
auto audioStateLock = LockAudioState();
m_speedOfSound = std::max(1.0f, metersPerSecond);
Audio::AudioSystem::Get().SetSpeedOfSound(m_speedOfSound);
float speedOfSound = 343.0f;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_speedOfSound = std::max(1.0f, metersPerSecond);
speedOfSound = m_speedOfSound;
}
Audio::AudioSystem::Get().SetSpeedOfSound(speedOfSound);
}
void AudioListenerComponent::SetReverbLevel(float level) {
auto audioStateLock = LockAudioState();
m_reverbLevel = std::max(0.0f, std::min(1.0f, level));
Audio::AudioSystem::Get().SetListenerReverbLevel(m_reverbLevel);
float reverbLevel = 1.0f;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_reverbLevel = std::max(0.0f, std::min(1.0f, level));
reverbLevel = m_reverbLevel;
}
Audio::AudioSystem::Get().SetListenerReverbLevel(reverbLevel);
}
void AudioListenerComponent::SetReverb(Audio::AudioMixer* reverb) {
auto audioStateLock = LockAudioState();
m_reverb = reverb;
Audio::AudioSystem::Get().SetListenerReverbMixer(m_reverb);
Audio::AudioMixer* reverbMixer = nullptr;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_reverb = reverb;
reverbMixer = m_reverb;
}
Audio::AudioSystem::Get().SetListenerReverbMixer(reverbMixer);
}
void AudioListenerComponent::Update(float deltaTime) {
auto audioStateLock = LockAudioState();
if (!m_gameObject) {
return;
}
@@ -73,19 +85,21 @@ void AudioListenerComponent::Update(float deltaTime) {
const Math::Quaternion rotation = transform().GetRotation();
Math::Vector3 velocity = Math::Vector3::Zero();
if (m_hasLastPosition && deltaTime > 0.0f) {
velocity = (position - m_lastPosition) / deltaTime;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
if (m_hasLastPosition && deltaTime > 0.0f) {
velocity = (position - m_lastPosition) / deltaTime;
}
m_lastPosition = position;
m_hasLastPosition = true;
}
Audio::AudioSystem::Get().SetListenerTransform(position, rotation);
Audio::AudioSystem::Get().SetListenerVelocity(velocity);
m_lastPosition = position;
m_hasLastPosition = true;
}
void AudioListenerComponent::Serialize(std::ostream& os) const {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
os << "masterVolume=" << m_masterVolume << ";";
os << "mute=" << (m_mute ? 1 : 0) << ";";
os << "dopplerLevel=" << m_dopplerLevel << ";";
@@ -94,7 +108,6 @@ void AudioListenerComponent::Serialize(std::ostream& os) const {
}
void AudioListenerComponent::Deserialize(std::istream& is) {
auto audioStateLock = LockAudioState();
SetMasterVolume(1.0f);
SetMute(false);
SetDopplerLevel(1.0f);

View File

@@ -144,13 +144,6 @@ void ApplyPanToBuffer(float* buffer, Audio::uint32 frameCount, Audio::uint32 cha
}
}
std::unique_lock<std::recursive_mutex> LockAudioState() {
if (Audio::AudioSystem* audioSystem = Audio::AudioSystem::TryGetExisting()) {
return audioSystem->AcquireStateLock();
}
return std::unique_lock<std::recursive_mutex>();
}
} // namespace
AudioSourceComponent::AudioSourceComponent() {
@@ -158,68 +151,96 @@ AudioSourceComponent::AudioSourceComponent() {
}
AudioSourceComponent::~AudioSourceComponent() {
bool wasPlaying = false;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
wasPlaying = (m_playState == Audio::PlayState::Playing);
m_playState = Audio::PlayState::Stopped;
}
Audio::AudioSystem::Get().UnregisterSourceComponent(this);
if (m_playState == Audio::PlayState::Playing) {
if (wasPlaying) {
Audio::AudioSystem::Get().UnregisterSource(this);
}
}
void AudioSourceComponent::Play() {
auto audioStateLock = LockAudioState();
if (!m_clip || !m_clip->IsValid()) {
return;
bool registerSource = false;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
if (!m_clip || !m_clip->IsValid()) {
return;
}
if (m_playState == Audio::PlayState::Playing) {
m_samplePosition = 0;
m_playbackPosition = 0.0;
m_lastingTime = 0.0;
m_velocity = Math::Vector3::Zero();
m_hasLastPosition = false;
m_hrtf.ResetState();
return;
}
if (m_playState == Audio::PlayState::Paused) {
m_playState = Audio::PlayState::Playing;
registerSource = true;
} else {
m_samplePosition = 0;
m_playbackPosition = 0.0;
m_lastingTime = 0.0;
m_velocity = Math::Vector3::Zero();
m_hasLastPosition = false;
m_hrtf.ResetState();
m_playState = Audio::PlayState::Playing;
registerSource = true;
}
}
if (m_playState == Audio::PlayState::Playing) {
m_samplePosition = 0;
m_playbackPosition = 0.0;
m_lastingTime = 0.0;
m_velocity = Math::Vector3::Zero();
m_hasLastPosition = false;
m_hrtf.ResetState();
return;
}
if (m_playState == Audio::PlayState::Paused) {
m_playState = Audio::PlayState::Playing;
if (registerSource) {
Audio::AudioSystem::Get().RegisterSource(this);
return;
}
m_samplePosition = 0;
m_playbackPosition = 0.0;
m_lastingTime = 0.0;
m_velocity = Math::Vector3::Zero();
m_hasLastPosition = false;
m_hrtf.ResetState();
m_playState = Audio::PlayState::Playing;
Audio::AudioSystem::Get().RegisterSource(this);
}
void AudioSourceComponent::Pause() {
auto audioStateLock = LockAudioState();
if (m_playState == Audio::PlayState::Playing) {
m_playState = Audio::PlayState::Paused;
bool unregisterSource = false;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
if (m_playState == Audio::PlayState::Playing) {
m_playState = Audio::PlayState::Paused;
unregisterSource = true;
}
}
if (unregisterSource) {
Audio::AudioSystem::Get().UnregisterSource(this);
}
}
void AudioSourceComponent::Stop(Audio::StopMode mode) {
auto audioStateLock = LockAudioState();
if (m_playState != Audio::PlayState::Stopped) {
m_playState = Audio::PlayState::Stopped;
m_samplePosition = 0;
m_playbackPosition = 0.0;
m_lastingTime = 0.0;
m_velocity = Math::Vector3::Zero();
m_hasLastPosition = false;
m_hrtf.ResetState();
(void)mode;
bool unregisterSource = false;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
if (m_playState != Audio::PlayState::Stopped) {
m_playState = Audio::PlayState::Stopped;
m_samplePosition = 0;
m_playbackPosition = 0.0;
m_lastingTime = 0.0;
m_velocity = Math::Vector3::Zero();
m_hasLastPosition = false;
m_hrtf.ResetState();
unregisterSource = true;
}
}
if (unregisterSource) {
Audio::AudioSystem::Get().UnregisterSource(this);
}
}
void AudioSourceComponent::SetClip(Resources::AudioClip* clip) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_clipHandle = Resources::ResourceHandle<Resources::AudioClip>(clip);
m_clip = clip;
m_clipPath.clear();
@@ -246,7 +267,7 @@ void AudioSourceComponent::SetClip(Resources::AudioClip* clip) {
}
void AudioSourceComponent::SetClipPath(const std::string& clipPath) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_clipRef.Reset();
m_clipPath = clipPath;
if (!m_clipPath.empty() &&
@@ -278,29 +299,29 @@ void AudioSourceComponent::SetClipPath(const std::string& clipPath) {
}
void AudioSourceComponent::ClearClip() {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_clipRef.Reset();
m_clipPath.clear();
SetClip(nullptr);
}
void AudioSourceComponent::SetVolume(float volume) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_volume = std::max(0.0f, std::min(1.0f, volume));
}
void AudioSourceComponent::SetPitch(float pitch) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_pitch = std::max(0.0f, std::min(3.0f, pitch));
}
void AudioSourceComponent::SetPan(float pan) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_pan = std::max(-1.0f, std::min(1.0f, pan));
}
void AudioSourceComponent::SetHRTFEnabled(bool enabled) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_useHRTF = enabled;
if (!enabled) {
m_hrtf.ResetState();
@@ -308,27 +329,27 @@ void AudioSourceComponent::SetHRTFEnabled(bool enabled) {
}
void AudioSourceComponent::SetHRTFCrossFeed(float crossFeed) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_hrtf.SetCrossFeed(crossFeed);
}
void AudioSourceComponent::SetHRTFQuality(Audio::uint32 level) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_hrtf.SetQualityLevel(level);
}
void AudioSourceComponent::SetLooping(bool loop) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_isLooping = loop;
}
void AudioSourceComponent::SetSpatialize(bool spatialize) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_spatialize = spatialize;
}
void AudioSourceComponent::Set3DParams(const Audio::Audio3DParams& params) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_3DParams = params;
m_3DParams.dopplerLevel = std::max(0.0f, m_3DParams.dopplerLevel);
m_3DParams.speedOfSound = std::max(1.0f, m_3DParams.speedOfSound);
@@ -340,27 +361,27 @@ void AudioSourceComponent::Set3DParams(const Audio::Audio3DParams& params) {
}
void AudioSourceComponent::SetDopplerLevel(float level) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_3DParams.dopplerLevel = std::max(0.0f, level);
}
void AudioSourceComponent::SetSpread(float spread) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_3DParams.spread = std::max(0.0f, std::min(1.0f, spread));
}
void AudioSourceComponent::SetReverbZoneMix(float mix) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_3DParams.reverbZoneMix = std::max(0.0f, std::min(1.0f, mix));
}
void AudioSourceComponent::SetOutputMixer(Audio::AudioMixer* mixer) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_outputMixer = mixer;
}
void AudioSourceComponent::SetTime(float seconds) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
if (!m_clip || !m_clip->IsValid()) {
return;
}
@@ -386,10 +407,12 @@ void AudioSourceComponent::SetTime(float seconds) {
}
float AudioSourceComponent::GetTime() const {
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
return static_cast<float>(m_lastingTime);
}
float AudioSourceComponent::GetDuration() const {
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
if (!m_clip || !m_clip->IsValid()) {
return 0.0f;
}
@@ -397,18 +420,18 @@ float AudioSourceComponent::GetDuration() const {
}
void AudioSourceComponent::StartEnergyDetect() {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_isEnergyDetecting = true;
m_energyHistory.clear();
}
void AudioSourceComponent::StopEnergyDetect() {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
m_isEnergyDetecting = false;
}
void AudioSourceComponent::Update(float deltaTime) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
if (m_gameObject) {
const Math::Vector3 position = transform().GetPosition();
if (m_hasLastPosition && deltaTime > 0.0f) {
@@ -433,15 +456,23 @@ void AudioSourceComponent::Update(float deltaTime) {
}
void AudioSourceComponent::OnEnable() {
auto audioStateLock = LockAudioState();
if (m_playState == Audio::PlayState::Playing) {
bool registerSource = false;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
registerSource = (m_playState == Audio::PlayState::Playing);
}
if (registerSource) {
Audio::AudioSystem::Get().RegisterSource(this);
}
}
void AudioSourceComponent::OnDisable() {
auto audioStateLock = LockAudioState();
if (m_playState == Audio::PlayState::Playing) {
bool unregisterSource = false;
{
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
unregisterSource = (m_playState == Audio::PlayState::Playing);
}
if (unregisterSource) {
Audio::AudioSystem::Get().UnregisterSource(this);
}
}
@@ -451,7 +482,7 @@ void AudioSourceComponent::OnDestroy() {
}
void AudioSourceComponent::Serialize(std::ostream& os) const {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
Resources::AssetRef serializedClipRef = m_clipRef;
std::string serializedClipPath = m_clipPath;
if (serializedClipPath.empty() && m_clip != nullptr) {
@@ -491,7 +522,7 @@ void AudioSourceComponent::Serialize(std::ostream& os) const {
}
void AudioSourceComponent::Deserialize(std::istream& is) {
auto audioStateLock = LockAudioState();
std::lock_guard<std::recursive_mutex> lock(m_stateMutex);
ClearClip();
SetVolume(1.0f);
SetPitch(1.0f);
@@ -589,7 +620,7 @@ void AudioSourceComponent::ProcessAudio(float* buffer, Audio::uint32 frameCount,
float listenerDopplerLevel,
float speedOfSound,
Audio::uint32 outputSampleRate) {
auto audioStateLock = LockAudioState();
std::unique_lock<std::recursive_mutex> lock(m_stateMutex);
if (m_playState != Audio::PlayState::Playing || !m_clip) {
return;
}
@@ -654,6 +685,7 @@ void AudioSourceComponent::ProcessAudio(float* buffer, Audio::uint32 frameCount,
double playbackPosition = m_playbackPosition;
bool reachedClipEnd = false;
Audio::uint32 renderedFrameCount = 0;
bool unregisterSource = false;
for (Audio::uint32 i = 0; i < frameCount; ++i) {
if (!m_isLooping && playbackPosition >= static_cast<double>(totalFrames)) {
@@ -779,13 +811,25 @@ void AudioSourceComponent::ProcessAudio(float* buffer, Audio::uint32 frameCount,
m_samplePosition = static_cast<Audio::uint64>(m_playbackPosition);
m_lastingTime = m_playbackPosition / static_cast<double>(clipSampleRate);
} else {
Stop();
m_playState = Audio::PlayState::Stopped;
m_samplePosition = 0;
m_playbackPosition = 0.0;
m_lastingTime = 0.0;
m_velocity = Math::Vector3::Zero();
m_hasLastPosition = false;
m_hrtf.ResetState();
unregisterSource = true;
}
}
if (m_isEnergyDetecting) {
UpdateEnergy(buffer, renderedFrameCount * channels);
}
lock.unlock();
if (unregisterSource) {
Audio::AudioSystem::Get().UnregisterSource(this);
}
}
float AudioSourceComponent::Compute3DAttenuation(const Math::Vector3& listenerPosition) const {