Add audio module foundation: AudioTypes, AudioConfig, IAudioBackend, WASAPIBackend, AudioSystem, AudioSourceComponent, AudioListenerComponent, and third-party KissFFT library

This commit is contained in:
2026-03-20 20:31:24 +08:00
parent 00f70eccf1
commit 47808f5f90
18 changed files with 2134 additions and 0 deletions

View File

@@ -0,0 +1,157 @@
#include <XCEngine/Audio/AudioSystem.h>
#include <XCEngine/Components/AudioSourceComponent.h>
#include <iostream>
namespace XCEngine {
namespace Audio {
AudioSystem& AudioSystem::Get() {
static AudioSystem instance;
return instance;
}
void AudioSystem::Initialize(const AudioConfig& config) {
if (m_backend) {
Shutdown();
}
m_backend = std::make_unique<WASAPI::WASAPIBackend>();
if (m_backend->Initialize(config)) {
m_backend->Start();
std::cout << "AudioSystem initialized successfully" << std::endl;
} else {
std::cout << "Failed to initialize AudioSystem" << std::endl;
m_backend.reset();
}
}
void AudioSystem::Shutdown() {
if (m_backend) {
m_backend->Stop();
m_backend->Shutdown();
m_backend.reset();
}
m_activeSources.clear();
}
void AudioSystem::Update(float deltaTime) {
m_deltaTime = deltaTime;
if (!m_backend || !m_backend->IsRunning()) {
return;
}
const auto& config = m_backend->GetConfig();
uint32 sampleCount = config.bufferSize * config.channels;
std::vector<float> mixBuffer(sampleCount, 0.0f);
for (auto* source : m_activeSources) {
if (source && source->IsEnabled() && source->IsPlaying()) {
ProcessSource(source, mixBuffer.data(), sampleCount, config.channels);
}
}
m_backend->ProcessAudio(mixBuffer.data(), sampleCount, config.channels, config.sampleRate);
uint32 activeCount = 0;
for (auto* source : m_activeSources) {
if (source && source->IsPlaying()) {
activeCount++;
}
}
m_stats.activeSources = activeCount;
m_stats.totalSources = static_cast<uint32>(m_activeSources.size());
}
void AudioSystem::SetBackend(std::unique_ptr<IAudioBackend> backend) {
m_backend = std::move(backend);
}
std::string AudioSystem::GetCurrentDevice() const {
if (m_backend) {
return m_backend->GetDeviceName();
}
return "";
}
void AudioSystem::SetDevice(const std::string& deviceName) {
if (m_backend) {
m_backend->SetDevice(deviceName);
}
}
void AudioSystem::GetAvailableDevices(std::vector<std::string>& devices) {
if (m_backend) {
m_backend->GetAvailableDevices(devices);
}
}
float AudioSystem::GetMasterVolume() const {
if (m_backend) {
return m_backend->GetMasterVolume();
}
return 1.0f;
}
void AudioSystem::SetMasterVolume(float volume) {
if (m_backend) {
m_backend->SetMasterVolume(volume);
}
}
bool AudioSystem::IsMuted() const {
if (m_backend) {
return m_backend->IsMuted();
}
return false;
}
void AudioSystem::SetMuted(bool muted) {
if (m_backend) {
m_backend->SetMuted(muted);
}
}
void AudioSystem::ProcessAudio(float* buffer, uint32 sampleCount, uint32 channels) {
if (m_backend) {
m_backend->ProcessAudio(buffer, sampleCount, channels, 48000);
}
}
void AudioSystem::SetListenerTransform(const Math::Vector3& position, const Math::Quaternion& rotation) {
m_listenerPosition = position;
m_listenerRotation = rotation;
}
void AudioSystem::SetListenerVelocity(const Math::Vector3& velocity) {
m_listenerVelocity = velocity;
}
void AudioSystem::RegisterSource(Components::AudioSourceComponent* source) {
if (source) {
m_activeSources.push_back(source);
}
}
void AudioSystem::UnregisterSource(Components::AudioSourceComponent* source) {
if (!source) {
return;
}
auto it = std::find(m_activeSources.begin(), m_activeSources.end(), source);
if (it != m_activeSources.end()) {
m_activeSources.erase(it);
}
}
void AudioSystem::ProcessSource(Components::AudioSourceComponent* source, float* buffer, uint32 sampleCount, uint32 channels) {
if (!source || !buffer) {
return;
}
source->ProcessAudio(buffer, sampleCount, channels, m_listenerPosition, m_listenerRotation);
}
} // namespace Audio
} // namespace XCEngine