#pragma once #include #include #include #include #include #include #include #include #include namespace frostbite2D { class BinaryFileStreamReader; struct AudioRef { std::string path; std::string npkFile; uint32 offset = 0; uint32 size = 0; bool loaded = false; }; struct CachedAudioData { std::vector data; uint64 lastUseTime = 0; size_t memoryUsage = 0; }; class SoundPackArchive { public: static SoundPackArchive& get(); SoundPackArchive(const SoundPackArchive&) = delete; SoundPackArchive& operator=(const SoundPackArchive&) = delete; SoundPackArchive(SoundPackArchive&&) = delete; SoundPackArchive& operator=(SoundPackArchive&&) = delete; void setSoundPackDirectory(const std::string& dir); const std::string& getSoundPackDirectory() const; void init(); void close(); bool isOpen() const; bool hasAudio(const std::string& path) const; std::optional getAudio(const std::string& path); std::vector listAudios() const; std::optional> getAudioData(const AudioRef& audio); void setCacheSize(size_t maxBytes); void clearCache(); size_t getCacheUsage() const; void setDefaultAudio(const std::string& audioPath); const std::string& getDefaultAudioPath() const; private: SoundPackArchive() = default; ~SoundPackArchive() = default; std::string normalizePath(const std::string& path) const; void scanNpkFiles(); bool parseNpkFile(const std::string& npkPath); bool loadAudioData(AudioRef& audio); void evictCacheIfNeeded(size_t requiredSize); void updateCacheUsage(const std::string& audioPath); std::string readNpkInfoString(BinaryFileStreamReader& reader); static const uint8 NPK_KEY[256]; std::string soundPackDirectory_ = "SoundPacks"; bool initialized_ = false; std::map audioIndex_; std::map audioCache_; std::list lruList_; size_t maxCacheSize_ = 256 * 1024 * 1024; size_t currentCacheSize_ = 0; std::string defaultAudioPath_; }; }