diff --git a/client/CMusicHandler.cpp b/client/CMusicHandler.cpp index 273404229..9d64e37ba 100644 --- a/client/CMusicHandler.cpp +++ b/client/CMusicHandler.cpp @@ -142,6 +142,30 @@ Mix_Chunk *CSoundHandler::GetSoundChunk(const AudioPath & sound, bool cache) } } +Mix_Chunk *CSoundHandler::GetSoundChunk(std::pair, si64> & data, bool cache) +{ + try + { + std::vector startBytes = std::vector(data.first.get(), data.first.get() + 100); + + if (cache && soundChunksRaw.find(startBytes) != soundChunksRaw.end()) + return soundChunksRaw[startBytes].first; + + SDL_RWops *ops = SDL_RWFromMem(data.first.get(), (int)data.second); + Mix_Chunk *chunk = Mix_LoadWAV_RW(ops, 1); // will free ops + + if (cache) + soundChunksRaw.insert({startBytes, std::make_pair (chunk, std::move (data.first))}); + + return chunk; + } + catch(std::exception &e) + { + logGlobal->warn("Cannot get sound chunk: %s", e.what()); + return nullptr; + } +} + int CSoundHandler::ambientDistToVolume(int distance) const { const auto & distancesVector = ambientConfig["distances"].Vector(); @@ -197,6 +221,31 @@ int CSoundHandler::playSound(const AudioPath & sound, int repeats, bool cache) return channel; } +int CSoundHandler::playSound(std::pair, si64> & data, int repeats, bool cache) +{ + int channel; + Mix_Chunk *chunk = GetSoundChunk(data, cache); + + if (chunk) + { + channel = Mix_PlayChannel(-1, chunk, repeats); + if (channel == -1) + { + logGlobal->error("Unable to play sound, error %s", Mix_GetError()); + if (!cache) + Mix_FreeChunk(chunk); + } + else if (cache) + initCallback(channel); + else + initCallback(channel, [chunk](){ Mix_FreeChunk(chunk);}); + } + else + channel = -1; + + return channel; +} + // Helper. Randomly select a sound from an array and play it int CSoundHandler::playSoundFromSet(std::vector &sound_vec) { diff --git a/client/CMusicHandler.h b/client/CMusicHandler.h index 56e1e3d7e..28daaf97a 100644 --- a/client/CMusicHandler.h +++ b/client/CMusicHandler.h @@ -41,8 +41,10 @@ private: using CachedChunk = std::pair>; std::map soundChunks; + std::map, CachedChunk> soundChunksRaw; Mix_Chunk *GetSoundChunk(const AudioPath & sound, bool cache); + Mix_Chunk *GetSoundChunk(std::pair, si64> & data, bool cache); /// have entry for every currently active channel /// vector will be empty if callback was not set @@ -76,6 +78,7 @@ public: // Sounds int playSound(soundBase::soundID soundID, int repeats=0); int playSound(const AudioPath & sound, int repeats=0, bool cache=false); + int playSound(std::pair, si64> & data, int repeats, bool cache=false); int playSoundFromSet(std::vector &sound_vec); void stopSound(int handler);