200 lines
4.8 KiB
C++
200 lines
4.8 KiB
C++
#include "AudioManager.h"
|
|
#include "src/Core/Logger.h"
|
|
#include "src/FileSystem/FileSystem.h"
|
|
|
|
#include <soloud.h>
|
|
#include "soloud_speech.h"
|
|
#include "soloud_thread.h"
|
|
#include <dependencies/soloud/include/soloud_wav.h>
|
|
#include <dependencies/soloud/include/soloud_wavstream.h>
|
|
|
|
|
|
namespace Nuake {
|
|
|
|
AudioManager::AudioManager()
|
|
{
|
|
}
|
|
|
|
AudioManager::~AudioManager()
|
|
{
|
|
Deinitialize();
|
|
|
|
m_Soloud->deinit();
|
|
}
|
|
|
|
void AudioManager::Initialize()
|
|
{
|
|
m_Soloud = CreateRef<SoLoud::Soloud>();
|
|
|
|
// TODO: Sample rate, back end, buffer size, flags.
|
|
#ifdef NK_WIN
|
|
m_Soloud->init(SoLoud::Soloud::LEFT_HANDED_3D);
|
|
#else
|
|
m_Soloud->init(SoLoud::Soloud::CLIP_ROUNDOFF, SoLoud::Soloud::ALSA);
|
|
#endif
|
|
|
|
Logger::Log("Audio manager initialized", "audio", VERBOSE);
|
|
}
|
|
|
|
void AudioManager::Deinitialize()
|
|
{
|
|
m_WavSamples.clear();
|
|
m_ActiveClips.clear();
|
|
m_Soloud->deinit();
|
|
}
|
|
|
|
void AudioManager::SetListenerPosition(const Vector3& position, const Vector3& direction, const Vector3& up)
|
|
{
|
|
if (position != m_ListenerPosition || direction != m_ListenerDirection || up != m_ListenerUp)
|
|
{
|
|
m_ListenerPosition = position;
|
|
m_ListenerDirection = direction;
|
|
m_ListenerUp = up;
|
|
m_Soloud->set3dListenerParameters(m_ListenerPosition.x, m_ListenerPosition.y, m_ListenerPosition.z,
|
|
m_ListenerDirection.x, m_ListenerDirection.y, m_ListenerDirection.z,
|
|
m_ListenerUp.x, m_ListenerUp.y, m_ListenerUp.z
|
|
);
|
|
|
|
|
|
m_Soloud->update3dAudio();
|
|
}
|
|
}
|
|
|
|
void AudioManager::PlayTTS(const std::string& text)
|
|
{
|
|
|
|
}
|
|
|
|
void AudioManager::QueueWavAudio(const AudioRequest& request)
|
|
{
|
|
// Check if file exists and load
|
|
const bool fileExists = FileSystem::FileExists(request.audioFile, true);
|
|
if (fileExists && !IsWavLoaded(request.audioFile))
|
|
{
|
|
LoadWavAudio(request.audioFile);
|
|
}
|
|
|
|
m_AudioQueue.push(request);
|
|
}
|
|
|
|
void AudioManager::UpdateVoice(const AudioRequest& request)
|
|
{
|
|
auto& audioClip = m_ActiveClips[request.audioFile];
|
|
if (IsVoiceActive(request.audioFile))
|
|
{
|
|
if (!m_Soloud->isValidVoiceHandle(audioClip))
|
|
{
|
|
m_ActiveClips.erase(request.audioFile);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (request.spatialized)
|
|
{
|
|
m_Soloud->set3dSourcePosition(audioClip, request.position.x, request.position.y, request.position.z);
|
|
m_Soloud->set3dSourceMinMaxDistance(audioClip, request.MinDistance, request.MaxDistance);
|
|
m_Soloud->set3dSourceAttenuation(audioClip, 1, request.AttenuationFactor);
|
|
m_Soloud->update3dAudio();
|
|
}
|
|
else
|
|
{
|
|
m_Soloud->setPan(audioClip, request.pan);
|
|
}
|
|
|
|
m_Soloud->setLooping(audioClip, request.Loop);
|
|
m_Soloud->setRelativePlaySpeed(audioClip, request.speed);
|
|
}
|
|
|
|
void AudioManager::StopVoice(const std::string& filePath)
|
|
{
|
|
if (!IsVoiceActive(filePath))
|
|
{
|
|
return; // We can't stop a voice that isn't active.
|
|
}
|
|
|
|
SoLoud::handle& voice = m_ActiveClips[filePath];
|
|
m_Soloud->stop(voice);
|
|
}
|
|
|
|
void AudioManager::StopAll() const
|
|
{
|
|
m_Soloud->stopAll();
|
|
}
|
|
|
|
bool AudioManager::IsWavLoaded(const std::string& filePath) const
|
|
{
|
|
return m_WavSamples.find(filePath) != m_WavSamples.end();
|
|
}
|
|
|
|
bool AudioManager::IsVoiceActive(const std::string& voice) const
|
|
{
|
|
return m_ActiveClips.find(voice) != m_ActiveClips.end();
|
|
}
|
|
|
|
void AudioManager::LoadWavAudio(const std::string& filePath)
|
|
{
|
|
const bool STREAMING = false;
|
|
if (STREAMING)
|
|
{
|
|
Ref<SoLoud::WavStream> wavStream = CreateRef<SoLoud::WavStream>();
|
|
wavStream->load(filePath.c_str());
|
|
m_WavSamples[filePath] = wavStream;
|
|
}
|
|
else
|
|
{
|
|
auto wav = CreateRef<SoLoud::Wav>();
|
|
wav->load(filePath.c_str());
|
|
m_WavSamples[filePath] = wav;
|
|
}
|
|
}
|
|
|
|
void AudioManager::AudioUpdate()
|
|
{
|
|
// Check if we have audio queued
|
|
if (m_Soloud->getGlobalVolume() != m_GlobalVolume)
|
|
{
|
|
m_Soloud->setGlobalVolume(m_GlobalVolume);
|
|
}
|
|
|
|
while (!m_AudioQueue.empty())
|
|
{
|
|
AudioRequest& audioRequest = m_AudioQueue.front();
|
|
Ref<SoLoud::AudioSource> audio = m_WavSamples[audioRequest.audioFile];
|
|
|
|
SoLoud::handle handle;
|
|
if (!audioRequest.spatialized)
|
|
{
|
|
handle = m_Soloud->play(*audio);
|
|
m_Soloud->setVolume(handle, audioRequest.volume);
|
|
m_Soloud->setPan(handle, audioRequest.pan);
|
|
}
|
|
else
|
|
{
|
|
const Vector3& position = audioRequest.position;
|
|
handle = m_Soloud->play3d(*audio, position.x, position.y, position.z);
|
|
m_Soloud->set3dSourceMinMaxDistance(handle, audioRequest.MinDistance, audioRequest.MaxDistance);
|
|
m_Soloud->set3dSourceAttenuation(handle, SoLoud::AudioSource::ATTENUATION_MODELS::EXPONENTIAL_DISTANCE, audioRequest.AttenuationFactor);
|
|
}
|
|
|
|
m_Soloud->setRelativePlaySpeed(handle, audioRequest.speed);
|
|
m_Soloud->setLooping(handle, audioRequest.Loop);
|
|
|
|
m_ActiveClips[audioRequest.audioFile] = handle;
|
|
|
|
m_AudioQueue.pop();
|
|
}
|
|
}
|
|
|
|
void AudioManager::CleanupInactiveVoices()
|
|
{
|
|
if (m_ActiveClips.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
std::erase_if(m_ActiveClips, [this](const auto& item)
|
|
{
|
|
return !m_Soloud->isValidVoiceHandle(item.second);
|
|
});
|
|
}
|
|
} |