// Audio.h - MP3 playlist playback (Windows Media Foundation backend) + SDL3 stream #pragma once #include #include #include #include #include #include #include #include #include "../core/interfaces/IAudioSystem.h" struct AudioTrack { std::string path; std::vector pcm; int channels = 2; int rate = 44100; size_t cursor = 0; bool ok = false; }; class Audio : public IAudioSystem { public: static Audio& instance(); // IAudioSystem interface implementation void playSound(const std::string& name) override; void playMusic(const std::string& name) override; void stopMusic() override; void setMasterVolume(float volume) override; void setMusicVolume(float volume) override; void setSoundVolume(float volume) override; bool isMusicPlaying() const override; // Existing Audio class methods bool init(); // initialize backend (MF on Windows) void addTrack(const std::string& path); // decode MP3 -> PCM16 stereo 44100 void addTrackAsync(const std::string& path); // add track for background loading void startBackgroundLoading(); // start background thread for loading void waitForLoadingComplete(); // wait for all tracks to finish loading bool isLoadingComplete() const; // check if background loading is done int getLoadedTrackCount() const; // get number of tracks loaded so far void shuffle(); // randomize order void start(); // begin playback void skipToNextTrack(); // advance to the next music track void toggleMute(); void setMuted(bool m); bool isMuted() const { return muted; } // Menu music support void setMenuTrack(const std::string& path); void playMenuMusic(); void playGameMusic(); // Queue a sound effect to mix over the music (pcm can be mono/stereo, any rate; will be converted) void playSfx(const std::vector& pcm, int channels, int rate, float volume); void shutdown(); private: Audio()=default; ~Audio()=default; Audio(const Audio&)=delete; Audio& operator=(const Audio&)=delete; static void SDLCALL streamCallback(void* userdata, SDL_AudioStream* stream, int additional, int total); void feed(Uint32 bytesWanted, SDL_AudioStream* stream); void nextTrack(); bool ensureStream(); void backgroundLoadingThread(); // background thread function std::vector tracks; AudioTrack menuTrack; bool isMenuMusic = false; int current=-1; bool playing=false; bool muted=false; std::mt19937 rng{std::random_device{}()}; SDL_AudioStream* audioStream=nullptr; SDL_AudioSpec outSpec{}; int outChannels=2; int outRate=44100; bool mfStarted=false; // Threading support std::vector pendingTracks; std::thread loadingThread; std::mutex tracksMutex; std::mutex pendingTracksMutex; std::atomic loadingComplete{false}; std::atomic loadingAbort{false}; std::atomic loadedCount{0}; // SFX mixing support struct SfxPlay { std::vector pcm; size_t cursor=0; }; std::vector activeSfx; std::mutex sfxMutex; // Volume control float m_masterVolume = 1.0f; float m_musicVolume = 1.0f; float m_sfxVolume = 1.0f; };