audio: clear mixer routes on destruction

This commit is contained in:
2026-04-14 16:48:39 +08:00
parent ee03f7035b
commit a4c48c1b3f
6 changed files with 241 additions and 8 deletions

View File

@@ -1,18 +1,40 @@
#include <XCEngine/Audio/AudioMixer.h>
#include <XCEngine/Audio/AudioSystem.h>
#include <XCEngine/Audio/IAudioEffect.h>
#include <algorithm>
#include <cmath>
namespace XCEngine {
namespace Audio {
namespace {
AudioChannel ResolveChannel(uint32 channelIndex) {
switch (channelIndex) {
case 0: return AudioChannel::FrontLeft;
case 1: return AudioChannel::FrontRight;
case 2: return AudioChannel::FrontCenter;
case 3: return AudioChannel::LFE;
case 4: return AudioChannel::BackLeft;
case 5: return AudioChannel::BackRight;
case 6: return AudioChannel::SideLeft;
case 7: return AudioChannel::SideRight;
default: return AudioChannel::FrontLeft;
}
}
} // namespace
AudioMixer::AudioMixer()
{
AudioSystem::Get().RegisterMixer(this);
for (int i = 0; i < static_cast<int>(AudioChannel::SideRight) + 1; ++i) {
m_channelVolumes[static_cast<AudioChannel>(i)] = ChannelVolume{1.0f, false};
}
}
AudioMixer::~AudioMixer() {
AudioSystem::Get().UnregisterMixer(this);
}
void AudioMixer::SetVolume(float volume) {
@@ -24,7 +46,7 @@ void AudioMixer::SetMute(bool mute) {
}
void AudioMixer::AddEffect(IAudioEffect* effect) {
if (effect) {
if (effect && std::find(m_effects.begin(), m_effects.end(), effect) == m_effects.end()) {
m_effects.push_back(effect);
}
}
@@ -41,19 +63,37 @@ void AudioMixer::ClearEffects() {
m_effects.clear();
}
void AudioMixer::ProcessAudio(float* buffer, uint32 sampleCount, uint32 channels) {
if (!buffer || sampleCount == 0) {
void AudioMixer::ProcessAudio(float* buffer, uint32 frameCount, uint32 channels, uint32 sampleRate) {
if (!buffer || frameCount == 0 || channels == 0) {
return;
}
float effectiveVolume = m_mute ? 0.0f : m_volume;
const size_t sampleCount = static_cast<size_t>(frameCount) * channels;
if (effectiveVolume < 0.001f) {
std::fill(buffer, buffer + sampleCount, 0.0f);
return;
}
for (size_t i = 0; i < sampleCount * channels; ++i) {
buffer[i] *= effectiveVolume;
for (uint32 frame = 0; frame < frameCount; ++frame) {
for (uint32 ch = 0; ch < channels; ++ch) {
const AudioChannel channel = ResolveChannel(ch);
const auto it = m_channelVolumes.find(channel);
const ChannelVolume channelVolume = (it != m_channelVolumes.end())
? it->second
: ChannelVolume{};
const float channelGain = channelVolume.mute ? 0.0f : channelVolume.volume;
buffer[frame * channels + ch] *= effectiveVolume * channelGain;
}
}
for (IAudioEffect* effect : m_effects) {
if (effect != nullptr && effect->IsEnabled()) {
effect->SetSampleRate(sampleRate);
effect->ProcessAudio(buffer, frameCount, channels);
}
}
}

View File

@@ -1,5 +1,6 @@
#include <XCEngine/Audio/AudioSystem.h>
#include <XCEngine/Audio/WindowsAudioBackend.h>
#include <XCEngine/Components/AudioListenerComponent.h>
#include <XCEngine/Components/AudioSourceComponent.h>
#include <algorithm>
#include <iostream>
@@ -113,6 +114,9 @@ void AudioSystem::Shutdown() {
m_backend->Shutdown();
m_backend.reset();
}
m_registeredMixers.clear();
m_registeredSourceComponents.clear();
m_registeredListenerComponents.clear();
m_activeSources.clear();
m_listenerReverbMixer = nullptr;
m_listenerReverbLevel = 1.0f;
@@ -249,6 +253,70 @@ void AudioSystem::RegisterSource(Components::AudioSourceComponent* source) {
}
}
void AudioSystem::RegisterSourceComponent(Components::AudioSourceComponent* source) {
if (!source) {
return;
}
if (std::find(m_registeredSourceComponents.begin(), m_registeredSourceComponents.end(), source) ==
m_registeredSourceComponents.end()) {
m_registeredSourceComponents.push_back(source);
}
}
void AudioSystem::UnregisterSourceComponent(Components::AudioSourceComponent* source) {
if (!source) {
return;
}
UnregisterSource(source);
m_registeredSourceComponents.erase(
std::remove(m_registeredSourceComponents.begin(), m_registeredSourceComponents.end(), source),
m_registeredSourceComponents.end());
}
void AudioSystem::RegisterListenerComponent(Components::AudioListenerComponent* listener) {
if (!listener) {
return;
}
if (std::find(m_registeredListenerComponents.begin(), m_registeredListenerComponents.end(), listener) ==
m_registeredListenerComponents.end()) {
m_registeredListenerComponents.push_back(listener);
}
}
void AudioSystem::UnregisterListenerComponent(Components::AudioListenerComponent* listener) {
if (!listener) {
return;
}
m_registeredListenerComponents.erase(
std::remove(m_registeredListenerComponents.begin(), m_registeredListenerComponents.end(), listener),
m_registeredListenerComponents.end());
}
void AudioSystem::RegisterMixer(AudioMixer* mixer) {
if (!mixer) {
return;
}
if (std::find(m_registeredMixers.begin(), m_registeredMixers.end(), mixer) == m_registeredMixers.end()) {
m_registeredMixers.push_back(mixer);
}
}
void AudioSystem::UnregisterMixer(AudioMixer* mixer) {
if (!mixer) {
return;
}
m_registeredMixers.erase(
std::remove(m_registeredMixers.begin(), m_registeredMixers.end(), mixer),
m_registeredMixers.end());
DetachMixerReferences(mixer);
}
void AudioSystem::UnregisterSource(Components::AudioSourceComponent* source) {
if (!source) {
return;
@@ -259,6 +327,34 @@ void AudioSystem::UnregisterSource(Components::AudioSourceComponent* source) {
m_activeSources.end());
}
void AudioSystem::DetachMixerReferences(AudioMixer* mixer) {
if (!mixer) {
return;
}
if (m_listenerReverbMixer == mixer) {
m_listenerReverbMixer = nullptr;
}
for (Components::AudioListenerComponent* listener : m_registeredListenerComponents) {
if (listener != nullptr && listener->GetReverb() == mixer) {
listener->SetReverb(nullptr);
}
}
for (Components::AudioSourceComponent* source : m_registeredSourceComponents) {
if (source != nullptr && source->GetOutputMixer() == mixer) {
source->SetOutputMixer(nullptr);
}
}
for (AudioMixer* registeredMixer : m_registeredMixers) {
if (registeredMixer != nullptr && registeredMixer->GetOutputMixer() == mixer) {
registeredMixer->SetOutputMixer(nullptr);
}
}
}
void AudioSystem::ProcessSource(Components::AudioSourceComponent* source, float* buffer, uint32 frameCount, uint32 channels, uint32 sampleRate) {
if (!source || !buffer) {
return;

View File

@@ -1,15 +1,19 @@
#include <XCEngine/Components/AudioListenerComponent.h>
#include <XCEngine/Audio/AudioSystem.h>
#include <algorithm>
#include <cmath>
#include <sstream>
namespace XCEngine {
namespace Components {
AudioListenerComponent::AudioListenerComponent()
{
Audio::AudioSystem::Get().RegisterListenerComponent(this);
}
AudioListenerComponent::~AudioListenerComponent() {
Audio::AudioSystem::Get().UnregisterListenerComponent(this);
}
void AudioListenerComponent::SetMasterVolume(float volume) {
@@ -24,18 +28,22 @@ void AudioListenerComponent::SetMute(bool mute) {
void AudioListenerComponent::SetDopplerLevel(float level) {
m_dopplerLevel = std::max(0.0f, std::min(5.0f, level));
Audio::AudioSystem::Get().SetListenerDopplerLevel(m_dopplerLevel);
}
void AudioListenerComponent::SetSpeedOfSound(float metersPerSecond) {
m_speedOfSound = std::max(1.0f, metersPerSecond);
Audio::AudioSystem::Get().SetSpeedOfSound(m_speedOfSound);
}
void AudioListenerComponent::SetReverbLevel(float level) {
m_reverbLevel = std::max(0.0f, std::min(1.0f, level));
Audio::AudioSystem::Get().SetListenerReverbLevel(m_reverbLevel);
}
void AudioListenerComponent::SetReverb(Audio::AudioMixer* reverb) {
m_reverb = reverb;
Audio::AudioSystem::Get().SetListenerReverbMixer(m_reverb);
}
void AudioListenerComponent::Update(float deltaTime) {
@@ -43,10 +51,62 @@ void AudioListenerComponent::Update(float deltaTime) {
return;
}
Math::Vector3 position = transform().GetPosition();
Math::Quaternion rotation = transform().GetRotation();
const Math::Vector3 position = transform().GetPosition();
const Math::Quaternion rotation = transform().GetRotation();
Math::Vector3 velocity = Math::Vector3::Zero();
if (m_hasLastPosition && deltaTime > 0.0f) {
velocity = (position - m_lastPosition) / deltaTime;
}
Audio::AudioSystem::Get().SetListenerTransform(position, rotation);
Audio::AudioSystem::Get().SetListenerVelocity(velocity);
m_lastPosition = position;
m_hasLastPosition = true;
}
void AudioListenerComponent::Serialize(std::ostream& os) const {
os << "masterVolume=" << m_masterVolume << ";";
os << "mute=" << (m_mute ? 1 : 0) << ";";
os << "dopplerLevel=" << m_dopplerLevel << ";";
os << "speedOfSound=" << m_speedOfSound << ";";
os << "reverbLevel=" << m_reverbLevel << ";";
}
void AudioListenerComponent::Deserialize(std::istream& is) {
SetMasterVolume(1.0f);
SetMute(false);
SetDopplerLevel(1.0f);
SetSpeedOfSound(343.0f);
SetReverbLevel(1.0f);
std::string token;
while (std::getline(is, token, ';')) {
if (token.empty()) {
continue;
}
const size_t eqPos = token.find('=');
if (eqPos == std::string::npos) {
continue;
}
const std::string key = token.substr(0, eqPos);
const std::string value = token.substr(eqPos + 1);
if (key == "masterVolume") {
SetMasterVolume(std::stof(value));
} else if (key == "mute") {
SetMute(std::stoi(value) != 0);
} else if (key == "dopplerLevel") {
SetDopplerLevel(std::stof(value));
} else if (key == "speedOfSound") {
SetSpeedOfSound(std::stof(value));
} else if (key == "reverbLevel") {
SetReverbLevel(std::stof(value));
}
}
}
} // namespace Components

View File

@@ -146,9 +146,12 @@ void ApplyPanToBuffer(float* buffer, Audio::uint32 frameCount, Audio::uint32 cha
} // namespace
AudioSourceComponent::AudioSourceComponent() = default;
AudioSourceComponent::AudioSourceComponent() {
Audio::AudioSystem::Get().RegisterSourceComponent(this);
}
AudioSourceComponent::~AudioSourceComponent() {
Audio::AudioSystem::Get().UnregisterSourceComponent(this);
if (m_playState == Audio::PlayState::Playing) {
Audio::AudioSystem::Get().UnregisterSource(this);
}