audio: clear mixer routes on destruction
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user