#include "SDL_mixer.h" #include "SDLSoundSystem.h" SDLSoundSystem::SDLSoundSystem() { if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) { std::cerr << "SDL_mixer could not initialize! SDL_mixer Error: " << Mix_GetError() << std::endl; } m_Thread = std::thread(&SDLSoundSystem::LoadingThread, this); } void SDLSoundSystem::LoadingThread() { while (m_IsRunning) { Sound_Id soundToLoad{ USHRT_MAX }; { std::unique_lock lock(m_LoadQueueMutex); m_LoadConditionVariable.wait(lock, [this] { return !m_IsRunning || !m_LoadQueue.empty(); }); if (!m_IsRunning) break; if (!m_LoadQueue.empty()) { soundToLoad = m_LoadQueue.front().first; std::get<2>(m_Sounds[soundToLoad]) = SoundStatus::Loading; m_LoadQueue.pop(); } } if (soundToLoad != USHRT_MAX) { Load(m_Sounds[soundToLoad]); std::get<2>(m_Sounds[soundToLoad]) = SoundStatus::Loaded; // Check and play if this sound is in the play-after-load queue if (std::find(m_PlayAfterLoadQueue.begin(), m_PlayAfterLoadQueue.end(), soundToLoad) != m_PlayAfterLoadQueue.end()) { Play(soundToLoad, 1.0f); m_PlayAfterLoadQueue.remove(soundToLoad); } } } } SDLSoundSystem::~SDLSoundSystem() { { std::lock_guard lock(m_LoadQueueMutex); m_IsRunning = false; } m_LoadConditionVariable.notify_one(); m_Thread.join(); for (auto& sound : m_Sounds) { Mix_FreeChunk(std::get<1>(sound.second)); std::get<1>(sound.second) = nullptr; } for (auto& music : m_Music) { Mix_FreeMusic(music.second.second); music.second.second = nullptr; } Mix_CloseAudio(); } void SDLSoundSystem::RegisterMusic(const Sound_Id musicId, const std::string& filepath) { m_Music[musicId].second = Mix_LoadMUS(filepath.c_str()); if (m_Music[musicId].second == nullptr) { std::cerr << "Error loading music: " << Mix_GetError() << std::endl; } } void SDLSoundSystem::StopMusic() { if (Mix_PlayingMusic() == 1) { Mix_HaltMusic(); } } void SDLSoundSystem::PlayMusic(const Sound_Id musicId, const float volume, const int loops) { if (m_Music.count(musicId) == 0) { std::cerr << "Music with ID " << musicId << " not registered." << std::endl; return; } if (Mix_PlayingMusic() == 1) { Mix_HaltMusic(); } volume; if (Mix_PlayMusic(m_Music[musicId].second, loops) == -1) { std::cerr << "Error playing music: " << Mix_GetError() << std::endl; return; } } void SDLSoundSystem::Play(const Sound_Id soundId, const float volume) { auto soundStatus = std::get<2>(m_Sounds[soundId]); switch (soundStatus) { case SoundStatus::Loaded: { //std::lock_guard playLock(m_PlayMutex); Mix_VolumeChunk(std::get<1>(m_Sounds[soundId]), int(MIX_MAX_VOLUME * volume)); if (Mix_PlayChannel(-1, std::get<1>(m_Sounds[soundId]), 0) == -1) { std::cerr << "Error playing sound: " << Mix_GetError() << std::endl; } } break; case SoundStatus::Unloaded: { std::unique_lock lock(m_LoadQueueMutex); m_LoadQueue.emplace(soundId, volume); // Also add it to the play-after-load queue m_PlayAfterLoadQueue.push_back(soundId); lock.unlock(); m_LoadConditionVariable.notify_one(); } break; case SoundStatus::Loading: // Just ensure it will play once loaded m_PlayAfterLoadQueue.push_back(soundId); break; } } void SDLSoundSystem::Load(std::tuple& sound) { std::get<1>(sound) = Mix_LoadWAV(std::get<0>(sound).c_str()); } void SDLSoundSystem::RegisterSound(const Sound_Id soundId, const std::string& filepath) { std::tuple soundData(filepath, nullptr, SoundStatus::Unloaded); m_Sounds[soundId] = soundData; }