From 8fb5c2658df916767b9f1d5b7f178868206d3ecc Mon Sep 17 00:00:00 2001 From: Ghabry Date: Wed, 13 Sep 2023 17:23:40 +0200 Subject: [PATCH] Ineluki MP3 patch Only consider files as links when they are small (< 500 Byte). "Les aventures d'un avatar 6" uses files with such names for real audio files. Support of links for sound effects with the same logic as BGM. Note that the "loop" statement is not supported. Fix #2598 Fix #2609 --- src/filesystem_stream.cpp | 10 ++++++ src/filesystem_stream.h | 3 ++ src/game_system.cpp | 68 ++++++++++++++++++++++++++++----------- src/game_system.h | 3 ++ 4 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/filesystem_stream.cpp b/src/filesystem_stream.cpp index ff04ae47ae..cadf97d4a4 100644 --- a/src/filesystem_stream.cpp +++ b/src/filesystem_stream.cpp @@ -45,6 +45,16 @@ StringView Filesystem_Stream::InputStream::GetName() const { return name; } +std::streampos Filesystem_Stream::InputStream::GetSize() const { + if (!size_cached) { + size_cached = true; + auto cur_pos = rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::in); + size = rdbuf()->pubseekoff(0, std::ios_base::end, std::ios_base::in); + rdbuf()->pubseekoff(cur_pos, std::ios_base::beg, std::ios_base::in); + } + return size; +} + void Filesystem_Stream::InputStream::Close() { delete rdbuf(); set_rdbuf(nullptr); diff --git a/src/filesystem_stream.h b/src/filesystem_stream.h index 6a39a7bda4..4a0d76bc7d 100644 --- a/src/filesystem_stream.h +++ b/src/filesystem_stream.h @@ -37,6 +37,7 @@ namespace Filesystem_Stream { InputStream& operator=(InputStream&& is) noexcept; StringView GetName() const; + std::streampos GetSize() const; void Close(); template @@ -47,6 +48,8 @@ namespace Filesystem_Stream { bool Read0(T& obj); std::string name; + mutable bool size_cached = false; + mutable std::streampos size = 0; }; class OutputStream final : public std::ostream { diff --git a/src/game_system.cpp b/src/game_system.cpp index ce75a748fd..130b6a5553 100644 --- a/src/game_system.cpp +++ b/src/game_system.cpp @@ -245,7 +245,6 @@ void Game_System::ResetSystemGraphic() { ReloadSystemGraphic(); } - template static const T& GetAudio(const T& save, const T& db) { return save.name.empty() ? db : save; @@ -509,6 +508,21 @@ void Game_System::SetTransition(int which, int transition) { } } +std::string Game_System::InelukiReadLink(Filesystem_Stream::InputStream& stream) { + // The first line contains the path to the actual audio file to play + std::string line; + if (!Utils::ReadLine(stream, line)) { + Output::Warning("Ineluki MP3: Link file is empty: {}", stream.GetName()); + return {}; + } + line = lcf::ReaderUtil::Recode(line, Player::encoding); + + Output::Debug("Ineluki MP3: Link file: {} -> {}", stream.GetName(), line); + std::string line_canonical = FileFinder::MakeCanonical(line, 1); + + return line_canonical; +} + void Game_System::OnBgmReady(FileRequestResult* result) { // Take from current_music, params could have changed over time bgm_pending = false; @@ -522,27 +536,13 @@ void Game_System::OnBgmReady(FileRequestResult* result) { return; } - if (StringView(result->file).ends_with(".link")) { + if (Player::IsPatchKeyPatch() && StringView(result->file).ends_with(".link") && stream.GetSize() < 500) { // Handle Ineluki's MP3 patch - if (!stream) { - Output::Warning("Ineluki MP3: Link read error: {}", stream.GetName()); - return; - } - - // The first line contains the path to the actual audio file to play - std::string line; - if (!Utils::ReadLine(stream, line)) { - Output::Warning("Ineluki MP3: Link file is empty: {}", stream.GetName()); - return; - } - line = lcf::ReaderUtil::Recode(line, Player::encoding); - - Output::Debug("Ineluki MP3: Link file: {} -> {}", stream.GetName(), line); - std::string line_canonical = FileFinder::MakeCanonical(line, 1); + std::string line = InelukiReadLink(stream); // Needs another Async roundtrip bgm_pending = true; - FileRequestAsync *request = AsyncHandler::RequestFile(line_canonical); + FileRequestAsync *request = AsyncHandler::RequestFile(line); music_request_id = request->Bind(&Game_System::OnBgmInelukiReady, this); request->Start(); return; @@ -580,6 +580,38 @@ void Game_System::OnSeReady(FileRequestResult* result, lcf::rpg::Sound se, bool Output::Debug("Sound not found: {}", result->file); return; } + + if (Player::IsPatchKeyPatch() && StringView(result->file).ends_with(".link") && stream.GetSize() < 500) { + // Handle Ineluki's MP3 patch + std::string line = InelukiReadLink(stream); + + // Needs another Async roundtrip + FileRequestAsync* request = AsyncHandler::RequestFile(line); + se_request_ids[line] = request->Bind(&Game_System::OnSeInelukiReady, this, se); + request->Start(); + return; + } + + se_cache = AudioSeCache::Create(std::move(stream), result->file); + } + + if (!se_cache) { + Output::Warning("Sound {}: Format not supported", result->file); + return; + } + + Audio().SE_Play(std::move(se_cache), se.volume, se.tempo); +} + +void Game_System::OnSeInelukiReady(FileRequestResult* result, lcf::rpg::Sound se) { + auto item = se_request_ids.find(result->file); + if (item != se_request_ids.end()) { + se_request_ids.erase(item); + } + + auto se_cache = AudioSeCache::GetCachedSe(result->file); + if (!se_cache) { + auto stream = FileFinder::Game().OpenFile(result->file); se_cache = AudioSeCache::Create(std::move(stream), result->file); } diff --git a/src/game_system.h b/src/game_system.h index e982fe3517..4feee2ce17 100644 --- a/src/game_system.h +++ b/src/game_system.h @@ -437,9 +437,12 @@ class Game_System { bool IsLoadedThisFrame() const; private: + std::string InelukiReadLink(Filesystem_Stream::InputStream& stream); + void OnBgmReady(FileRequestResult* result); void OnBgmInelukiReady(FileRequestResult* result); void OnSeReady(FileRequestResult* result, lcf::rpg::Sound se, bool stop_sounds); + void OnSeInelukiReady(FileRequestResult* result, lcf::rpg::Sound se); void OnChangeSystemGraphicReady(FileRequestResult* result); private: lcf::rpg::SaveSystem data;