2026-03-20 20:31:24 +08:00
|
|
|
#include <XCEngine/Audio/AudioSystem.h>
|
2026-03-24 16:14:05 +08:00
|
|
|
#include <XCEngine/Audio/WindowsAudioBackend.h>
|
2026-03-20 20:31:24 +08:00
|
|
|
#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();
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 20:48:09 +08:00
|
|
|
m_backend = std::make_unique<Audio::WASAPI::WASAPIBackend>();
|
2026-03-20 20:31:24 +08:00
|
|
|
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
|