diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dcb392..3b88a54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -464,7 +464,7 @@ set(SOURCE_FILES ${SOURCE_FILES} hooks/audio/implementations/wave_out.cpp hooks/audio/implementations/none.cpp hooks/audio/implementations/pipewire.cpp - hooks/bmsbhook.cpp + hooks/sndbhook.cpp hooks/avshook.cpp hooks/cfgmgr32hook.cpp hooks/debughook.cpp diff --git a/games/iidx/iidx.cpp b/games/iidx/iidx.cpp index a5fac16..481e5b1 100644 --- a/games/iidx/iidx.cpp +++ b/games/iidx/iidx.cpp @@ -17,7 +17,7 @@ #endif #include "hooks/setupapihook.h" #include "hooks/sleephook.h" -#include "hooks/bmsbhook.h" +#include "hooks/sndbhook.h" #include "launcher/options.h" #include "touch/touch.h" #include "misc/wintouchemu.h" @@ -376,7 +376,7 @@ namespace games::iidx { cfgmgr32hook_init(avs::game::DLL_INSTANCE); // wine fixes - hooks::bmsb::init(avs::game::DLL_INSTANCE, avs::game::EXT); + hooks::soundbank::init(avs::game::DLL_INSTANCE, avs::game::EXT); } @@ -427,7 +427,7 @@ namespace games::iidx { } void IIDXGame::detach() { - hooks::bmsb::deinit(avs::game::DLL_INSTANCE); + hooks::soundbank::deinit(avs::game::DLL_INSTANCE); Game::detach(); diff --git a/hooks/audio/implementations/pipewire.cpp b/hooks/audio/implementations/pipewire.cpp index 710bc4f..2851e21 100644 --- a/hooks/audio/implementations/pipewire.cpp +++ b/hooks/audio/implementations/pipewire.cpp @@ -106,7 +106,7 @@ HRESULT PipewireBackend::on_initialize(AUDCLNT_SHAREMODE *ShareMode, DWORD *Stre *hnsPeriodicity = wrt_; //_TODO: Init info - log_info("audio::asio", "Device Info:"); + log_info("audio::pipewire", "Device Info:"); log_info("audio::pipewire", "... hnsBufferDuration : {}", *hnsBufferDuration); log_info("audio::pipewire", "... hnsPeriodicity : {}", *hnsPeriodicity); diff --git a/hooks/bmsbhook.cpp b/hooks/sndbhook.cpp similarity index 82% rename from hooks/bmsbhook.cpp rename to hooks/sndbhook.cpp index 973d106..c6c5886 100644 --- a/hooks/bmsbhook.cpp +++ b/hooks/sndbhook.cpp @@ -1,4 +1,4 @@ -#include "bmsbhook.h" +#include "sndbhook.h" #include "util/logging.h" #include "util/memutils.h" #include "util/sigscan.h" @@ -8,37 +8,8 @@ #include -void dump_(const char *path, const uint8_t *src, size_t sz) -{ - FILE *fh = fopen(path, "wb"); - fwrite(src, sz, 1, fh); - fclose(fh); -} - - -static avs::core::AVS_FS_LSTAT_T avs_fs_lstat_; -int on_avs_fs_lstat(const char *path, struct avs::core::avs_stat *stat) -{ - if (strstr(path, "29095")) - { - log_info("hooks::bmsb", "avs_fs_lstat_({})", path); - } - return avs_fs_lstat_(path, stat); -} - -static avs::core::AVS_FS_MOUNT_T avs_fs_mount_; -avs::core::avs_file_t on_avs_fs_mount(const char *mountpoint, const char *fsroot, const char *fstype, void *data) -{ - if (strstr(fsroot, "29095")) - { - log_info("hooks::bmsb", "avs_fs_mount({}=>{}) @{} :nullptr data?{} ", fsroot, mountpoint, fstype, data == nullptr); - } - return avs_fs_mount_(mountpoint, fsroot, fstype, data); -} - - // This implementation outsources libavcodec from host ffmpeg (so that linking ffmpeg stack with spicetools isn't required) -namespace hooks::bmsb::avcodec +namespace hooks::soundbank::avcodec { enum pcm_resampler : int8_t { @@ -59,7 +30,7 @@ static BmswTranscoderAsfToWav_t BmswTranscoderAsfToWav; static HMODULE bmsw_ = nullptr; bool init() { - log_info("hooks::bmsb::avcodec", "{}", __FUNCTION__); + log_info("hooks::soundbank::avcodec", "{}", __FUNCTION__); // Initialize bmsound-wine.dll once if (!bmsw_ && (bmsw_ = libutils::try_library(MODULE_PATH / "bmsound-wine.dll"))) @@ -73,13 +44,12 @@ bool init() return true; } - log_fatal("audio::pipewire", "Library not found: '{}'", (MODULE_PATH / "bmsound-wine.dll").string()); - return true; + log_warning("hooks::soundbank", "Library not found: '{}'", (MODULE_PATH / "bmsound-wine.dll").string()); + return false; } - void deinit() { - log_info("hooks::bmsb::avcodec", "{}", __FUNCTION__); + log_info("hooks::soundbank::avcodec", "{}", __FUNCTION__); } } @@ -89,7 +59,7 @@ void deinit() #include #include #include -namespace hooks::bmsb::mf_broken +namespace hooks::soundbank::mf_broken { typedef HRESULT (*MFCreateMFByteStreamOnStream_t)(IStream *, IMFByteStream **); typedef HRESULT (*MFCreateSourceReaderFromByteStream_t)(IMFByteStream *, IMFAttributes *, IMFSourceReader **); @@ -133,12 +103,12 @@ HRESULT asf_unpack_pcm_s16le(BYTE *dst, IMFSourceReader *srcreader, uint32_t szm hr = srcreader->ReadSample((DWORD) MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, &flags, nullptr, &samples); if (FAILED(hr)) { - log_warning("hooks::bmsb", "ReadSample() failure, skipping.."); + log_warning("hooks::soundbank", "ReadSample() failure, skipping.."); break; } if (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) { - log_warning("hooks::bmsb", "Unsupported WAVE format, skipping.."); + log_warning("hooks::soundbank", "Unsupported WAVE format, skipping.."); samples->Release(); break; } @@ -148,13 +118,13 @@ HRESULT asf_unpack_pcm_s16le(BYTE *dst, IMFSourceReader *srcreader, uint32_t szm } if (samples == nullptr) { - log_warning("hooks::bmsb", "Missing samples"); + log_warning("hooks::soundbank", "Missing samples"); continue; } hr = samples->ConvertToContiguousBuffer(&mediabuf); if (FAILED(hr)) { - log_warning("hooks::bmsb", "ConvertToContiguousBuffer() failure, skipping.."); + log_warning("hooks::soundbank", "ConvertToContiguousBuffer() failure, skipping.."); samples->Release(); break; } @@ -255,17 +225,16 @@ void deinit() { MFShutdown(); } - } -namespace hooks::bmsb +namespace hooks::soundbank { constexpr char SNDPATHFMT[] = "%05d/%05d"; constexpr size_t SNDPATHFMTMAX = sizeof(SNDPATHFMT) - 1; constexpr size_t MNTPATHMAX = sizeof("/sdAABBB/AABBB/AABBBC_pre.2dx"); constexpr size_t AVSPATHMAX = sizeof("/data/sound/AABBB/AABBBC_pre.2dx"); -constexpr uint8_t CACHEMAX = 16; -typedef struct soundbank soundbank; +constexpr uint8_t CACHEMAX = 8; +typedef struct snd_bank snd_bank; typedef struct snd_s3p snd_s3p; typedef struct snd_2dx snd_2dx; typedef void (*BmsbEnumValidSoundbanks_t)(void *, int32_t, int32_t); @@ -322,29 +291,24 @@ public: resampler = (resampler > 1 || resampler == -1) ? 2 : 1; // resampler ratio multiplier (see pcm_resampler enum, original data is float) return static_cast(static_cast(sz) * 14.8) * resampler + WAVHDRSIZE; // 0.wma is consistent 180 therefore VBR Q90, sometimes 160 though, but samples are all over the place } - [[nodiscard]] constexpr const decltype(bank::header) *header() const noexcept { return &this->bank_->header; } - [[nodiscard]] constexpr bank::voice_ptr *voice_ptr(size_t i) const noexcept { return &bank_->table + i; } - [[nodiscard]] constexpr bank::voice_hdr *voice(size_t i) const noexcept { return (bank::voice_hdr *) ((char *) this->bank_ + this->voice_ptr(i)->fbegin); } - - //_INFO: assertsz guaranteed until serialize(true), overridden by voice_ptr::sz(v), compute value with assertsz_*() - [[nodiscard]] constexpr size_t voice_emplace(size_t assertsz) noexcept + [[nodiscard]] constexpr size_t voice_emplace(size_t assertsz) noexcept //_INFO: assertsz guaranteed until serialize(true), overridden by voice_ptr::sz(v), compute value with assertsz_*() { // memory space assertion if (this->voice_ptr(this->bank_->header.voice_cnt)->fbegin + assertsz >= banksz_) { - log_info("hooks::bmsb", "snd_2dx::voice_emplace({}=>{})", banksz_, banksz_ + assertsz + ALLOCSIZE); + log_info("hooks::soundbank", "snd_2dx::voice_emplace({}=>{})", banksz_, banksz_ + assertsz + ALLOCSIZE); banksz_ += assertsz + ALLOCSIZE; bank_ = (bank *) realloc(bank_, banksz_); } @@ -364,9 +328,9 @@ public: voice_hdr->unk2 = 0x0; return this->bank_->header.voice_cnt++; } - static snd_2dx *unpack(char *refbank) = delete; static snd_2dx *pack(int id); + bank *serialize(bool trim); ~snd_2dx(); @@ -413,7 +377,6 @@ snd_2dx::~snd_2dx() free(bank_); } - struct snd_s3p { public: @@ -466,7 +429,6 @@ private: size_t banksz_; //_TODO: keep track of allocated memory explicit snd_s3p(uint8_t *bindbank); }; - snd_s3p::snd_s3p(uint8_t *bindbank) : bank_(reinterpret_cast(bindbank)), banksz_(0) { @@ -480,16 +442,17 @@ snd_s3p *snd_s3p::unpack(uint8_t *refbank) return refbank ? new snd_s3p(refbank) : nullptr; } -struct soundbank +struct snd_bank { public: - static soundbank *new_instance(int id); + static snd_bank *new_instance(int id); static void flush_cache(); static void pop_cache(); - static soundbank *get_bank(int id); + static snd_bank *get_bank(int id); static uint8_t *read_bank_any(const char *avspath, const char *ext, size_t *sz); static bool has_format(const char *avspath, const char *ext); static avs::core::avs_file_t map_ifs(char *avspath); + static void dump(const char *path, const uint8_t *src, size_t sz); int id; char avspath[AVSPATHMAX]; @@ -518,43 +481,27 @@ public: private: static constexpr avs::core::avs_file_t E_NOT_FOUND = 0x80070002; static constexpr uint8_t UID_INVALID = 0x00; - static soundbank *cache_; + static snd_bank *cache_; static size_t cachesz_; uint8_t uid_; uint32_t mnt_; - soundbank *next_; - soundbank(); - ~soundbank(); + snd_bank *next_; + snd_bank(); + ~snd_bank(); }; -static struct offset_t +void snd_bank::dump(const char *path, const uint8_t *src, size_t sz) { - intptr_t RD_05d_s3p; // %05d/%05d.s3p - intptr_t RD_05d_c_s3p; // %05d/%05d%c.s3p - intptr_t RD_05d_2dx; // %05d/%05d.2dx - intptr_t RD_05d_c_2dx; // %05d/%05d%c.2dx - intptr_t TX_BmsbEnumValidSoundbanks; // enumerates above databank paths, simple exist check (lstat()/OPEN -> CLOSE_NOWRITE only) - intptr_t DAT_song_titlel; - intptr_t DAT_song_artistl; - intptr_t DAT_song_id; - memutils::VProtectGuard *guard; - - static constexpr unsigned int by_ext(const char *ext, int h = 0) - { - return !ext[h] ? 5381 : (by_ext(ext, h + 1) * 33) ^ ext[h]; - } -} offset_; - -soundbank *soundbank::cache_ = nullptr; -size_t soundbank::cachesz_ = 0; -static BmsbEnumValidSoundbanks_t BmsbEnumValidSoundbanks; - -soundbank *soundbank::new_instance(int id) + FILE *fh = fopen(path, "wb"); + fwrite(src, sz, 1, fh); + fclose(fh); +} +snd_bank *snd_bank::new_instance(int id) { - soundbank *prev, *instance; + snd_bank *prev, *instance; // Latest entry should always be head - instance = new soundbank(); + instance = new snd_bank(); instance->id = id; instance->next_ = cache_; cache_ = instance; @@ -563,16 +510,16 @@ soundbank *soundbank::new_instance(int id) // Clean cache (last entry indexing target excluded, cache limit reached) if (instance->next_ && instance->next_->uid_ == UID_INVALID) { - log_info("hooks::bmsb", "Cache prune"); + log_info("hooks::soundbank", "Cache prune"); prev = instance->next_; instance->next_ = prev->next_; - log_info("hooks::bmsb", "Removing {}::Bank[CACHE]::{}", prev->id, (uint32_t) prev->uid_); + log_info("hooks::soundbank", "Removing {}::Bank[CACHE]::{}", prev->id, (uint32_t) prev->uid_); delete prev; cachesz_ -= 1; } if (cachesz_ > CACHEMAX) { - log_info("hooks::bmsb", "Cache full"); + log_info("hooks::soundbank", "Cache full"); for (uint8_t i = 0; i < CACHEMAX; i += 2) { prev = nullptr; @@ -590,12 +537,12 @@ soundbank *soundbank::new_instance(int id) return cache_; } -void soundbank::cache_bank_any(const uint8_t *sndbuf, size_t sz) +void snd_bank::cache_bank_any(const uint8_t *sndbuf, size_t sz) { // Update struct using next free cache uid if (uid_ == UID_INVALID) { - soundbank *it = cache_; + snd_bank *it = cache_; while (it) { if (uid_ == UID_INVALID || (uid_ == it->uid_ && it != this)) @@ -612,37 +559,36 @@ void soundbank::cache_bank_any(const uint8_t *sndbuf, size_t sz) // Store file char path[AVSPATHMAX]; snprintf(path, sizeof(path), "%s.2dx", this->avspath); - log_info("hooks::bmsb", "Storing as intermediate soundbank at '{}'", (const char *) path); - dump_(path, sndbuf, sz); + log_info("hooks::soundbank", "Storing as intermediate soundbank at '{}'", (const char *) path); + dump(path, sndbuf, sz); } -soundbank::soundbank() : id(0), avspath(""), uid_(UID_INVALID), mnt_(E_NOT_FOUND), next_(nullptr) +snd_bank::snd_bank() : id(0), avspath(""), uid_(UID_INVALID), mnt_(E_NOT_FOUND), next_(nullptr) { } -soundbank::~soundbank() +snd_bank::~snd_bank() { if (uid_ != UID_INVALID) { char path[AVSPATHMAX]; snprintf(path, sizeof(path), "data/sound/system/%02x.2dx", uid_); - log_info("hooks::bmsb", "{}::Bank[CACHE]::Purge '{}'", this->id, (const char *) path); + log_info("hooks::soundbank", "{}::Bank[CACHE]::Purge '{}'", this->id, (const char *) path); remove(path); } if (mnt_ != E_NOT_FOUND) { - log_info("hooks::bmsb", "{}::Bank[CACHE]::Purge mount(0x{:08x})", this->id, mnt_); + log_info("hooks::soundbank", "{}::Bank[CACHE]::Purge mount(0x{:08x})", this->id, mnt_); avs::core::avs_fs_umount(mnt_); } } - -soundbank *soundbank::get_bank(int id) +snd_bank *snd_bank::get_bank(int id) { // Find in cache (latest=>oldest) - for (soundbank *it = cache_; it; it = it->next_) + for (snd_bank *it = cache_; it; it = it->next_) if (it->id == id) return it; // Find in avs (has valid s3p/.2dx resource at data/sound/AABBB/AABBB.2dx) - soundbank *bank = new_instance(id); + snd_bank *bank = new_instance(id); snprintf(bank->avspath, AVSPATHMAX, "data/sound/%05d", id); if (has_format(bank->avspath, ".ifs")) bank->mnt_ = map_ifs(bank->avspath); @@ -655,9 +601,9 @@ soundbank *soundbank::get_bank(int id) return bank; } -void soundbank::flush_cache() +void snd_bank::flush_cache() { - soundbank *prev; + snd_bank *prev; while (cache_) { prev = cache_; @@ -665,13 +611,13 @@ void soundbank::flush_cache() delete prev; } } -void soundbank::pop_cache() +void snd_bank::pop_cache() { - soundbank *prev = cache_; + snd_bank *prev = cache_; cache_ = cache_->next_; delete prev; } -uint8_t *soundbank::read_bank_any(const char *avspath, const char *ext, size_t *sz) +uint8_t *snd_bank::read_bank_any(const char *avspath, const char *ext, size_t *sz) { constexpr uint16_t O_RDONLY = 1; // rw:12 consistent across versions with s3p support uint8_t *r = nullptr; @@ -692,16 +638,16 @@ uint8_t *soundbank::read_bank_any(const char *avspath, const char *ext, size_t * } return r; } -bool soundbank::has_format(const char *avspath, const char *ext) +bool snd_bank::has_format(const char *avspath, const char *ext) { char path[AVSPATHMAX] = ""; snprintf(path, sizeof(path), "%s%s", avspath, ext); avs::core::avs_stat st; // NOLINT(cppcoreguidelines-pro-type-member-init) bool r = static_cast(avs::core::avs_fs_lstat(path, &st)); // lstat should be faster than open - log_info("hooks::bmsb", "'{}' exists? => {}", path, r); + log_info("hooks::soundbank", "'{}' exists? => {}", path, r); return static_cast(r); } -avs::core::avs_file_t soundbank::map_ifs(char *avspath) +avs::core::avs_file_t snd_bank::map_ifs(char *avspath) { // Map */${name}.ifs => /sc${name} char ifspath[AVSPATHMAX]; @@ -720,35 +666,73 @@ avs::core::avs_file_t soundbank::map_ifs(char *avspath) if (r != E_NOT_FOUND) { snprintf(mntpath + strlen(mntpath), strlen(it) + 2, "/%s", it); - log_info("hooks::bmsb", "'{}' => '{}'", avspath, mntpath); + log_info("hooks::soundbank", "'{}' => '{}'", avspath, mntpath); strcpy(avspath, mntpath); } return r; } +static struct offset_t +{ + intptr_t RD_05d_s3p; // %05d/%05d.s3p + intptr_t RD_05d_c_s3p; // %05d/%05d%c.s3p + intptr_t RD_05d_2dx; // %05d/%05d.2dx + intptr_t RD_05d_c_2dx; // %05d/%05d%c.2dx + intptr_t TX_BmsbEnumValidSoundbanks; // enumerates above databank paths, simple exist check (lstat()/OPEN -> CLOSE_NOWRITE only) + intptr_t DAT_song_titlel; + intptr_t DAT_song_artistl; + intptr_t DAT_song_id; + memutils::VProtectGuard *guard; + static constexpr unsigned int by_ext(const char *ext, int h = 0) + { + return !ext[h] ? 5381 : (by_ext(ext, h + 1) * 33) ^ ext[h]; + } +} offset_; +snd_bank *snd_bank::cache_ = nullptr; +size_t snd_bank::cachesz_ = 0; +static BmsbEnumValidSoundbanks_t BmsbEnumValidSoundbanks; +static avs::core::AVS_FS_LSTAT_T avs_fs_lstat_; +static avs::core::AVS_FS_MOUNT_T avs_fs_mount_; + +int on_avs_fs_lstat(const char *path, struct avs::core::avs_stat *stat) +{ + if (strstr(path, "29095")) + { + log_info("hooks::soundbank", "avs_fs_lstat_({})", path); + } + return avs_fs_lstat_(path, stat); +} +avs::core::avs_file_t on_avs_fs_mount(const char *mountpoint, const char *fsroot, const char *fstype, void *data) +{ + if (strstr(fsroot, "29095")) + { + log_info("hooks::soundbank", "avs_fs_mount({}=>{}) @{} :nullptr data?{} ", fsroot, mountpoint, fstype, data == nullptr); + } + return avs_fs_mount_(mountpoint, fsroot, fstype, data); +} void on_enum_valid_soundbanks(void *song, int32_t difficulty, int32_t unk2) { // Keysounds populated into CtrlSound::Bank[2][X] = [0:s3p][1:2dx][2:_pre.2dx], always uses lowest i databank for resource confirmed valid by this function // Struct memory layout 1:1 with data/info/(0/1)/music_*.bin - soundbank *keysounds = nullptr; + snd_bank *keysounds = nullptr; const char *titlel = (const char *) song + offset_.DAT_song_titlel; const char *artistl = (const char *) song + offset_.DAT_song_artistl; const int32_t id = *(int32_t *) ((const char *) song + offset_.DAT_song_id); - log_info("hooks::bmsb", "Processing s3p->2dx transcoding routine for [{}]({} - {})", id, artistl, titlel); - if (!(keysounds = soundbank::get_bank(id))) + log_info("hooks::soundbank", "Processing s3p->2dx transcoding routine for [{}]({} - {})", id, artistl, titlel); + if (!(keysounds = snd_bank::get_bank(id))) { - log_warning("hooks::bmsb", "soundbank::get_bank() was 0x0, this shouldn't happen.."); + log_warning("hooks::soundbank", "soundbank::get_bank() was 0x0, this shouldn't happen.."); memcpy(reinterpret_cast(offset_.RD_05d_2dx), "%05d/%05d", SNDPATHFMTMAX); BmsbEnumValidSoundbanks(song, difficulty, unk2); return; } - else if (!soundbank::has_format(keysounds->avspath, ".2dx")) + else if (!snd_bank::has_format(keysounds->avspath, ".2dx")) { // Get s3p and process into s3p soundbank for intermediate wma voice storage size_t szs3p; - uint8_t *bufs3p = soundbank::read_bank_any(keysounds->avspath, ".s3p", &szs3p); + uint8_t *bufs3p = snd_bank::read_bank_any(keysounds->avspath, ".s3p", &szs3p); snd_s3p *snds3p = snd_s3p::unpack(bufs3p); // Process wma voices into wav voices stored directly into 2dx soundbank @@ -775,11 +759,10 @@ void on_enum_valid_soundbanks(void *song, int32_t difficulty, int32_t unk2) // Resume execution const char *t = keysounds->sndpath(); memcpy(reinterpret_cast(offset_.RD_05d_2dx), t, SNDPATHFMTMAX); - log_info("hooks::bmsb", "RD_05d_2dx set to '{}'", reinterpret_cast(offset_.RD_05d_2dx)); //_REM: tests - log_info("hooks::bmsb", "Processing completed"); + log_info("hooks::soundbank", "RD_05d_2dx set to '{}'", reinterpret_cast(offset_.RD_05d_2dx)); + log_info("hooks::soundbank", "Processing completed"); BmsbEnumValidSoundbanks(song, difficulty, unk2); } - void run_tests() { size_t szs3p; @@ -791,17 +774,19 @@ void run_tests() int id = 25073; if (!mf_broken::init()) { - log_warning("hooks::bmsb", "MF initialization failed, skipping.."); + log_warning("hooks::soundbank", "MF initialization failed, skipping.."); } + detour::trampoline(reinterpret_cast(avs::core::avs_fs_lstat), reinterpret_cast(on_avs_fs_lstat), reinterpret_cast(&avs_fs_lstat_)); + detour::trampoline(reinterpret_cast(avs::core::avs_fs_mount), reinterpret_cast(on_avs_fs_mount), reinterpret_cast(&avs_fs_mount_)); // Filesystem tests, s3p unpacking snprintf(avspath, sizeof(avspath), "data/sound/%05d", id); - if (soundbank::has_format(avspath, ".ifs")) avsmnt = soundbank::map_ifs(avspath); + if (snd_bank::has_format(avspath, ".ifs")) avsmnt = snd_bank::map_ifs(avspath); snprintf(avspath + strlen(avspath), 7, "/%05d", id); - soundbank::has_format(avspath, ".s3p"); - soundbank::has_format(avspath, ".2dx"); - soundbank::has_format(avspath, "_pre.2dx"); - uint8_t *bufs3p = soundbank::read_bank_any(avspath, ".s3p", &szs3p); + snd_bank::has_format(avspath, ".s3p"); + snd_bank::has_format(avspath, ".2dx"); + snd_bank::has_format(avspath, "_pre.2dx"); + uint8_t *bufs3p = snd_bank::read_bank_any(avspath, ".s3p", &szs3p); snd_s3p *snds3p = snd_s3p::unpack(bufs3p); if (avsmnt) avs::core::avs_fs_umount(avsmnt); @@ -810,17 +795,17 @@ void run_tests() { // S3P/S3V metadata memcpy(sig, snds3p->header()->sig, 4); - log_info("hooks:bmsb", "{}::Bank[S3P]::Signature {}", id, sig); - log_info("hooks:bmsb", "{}::Bank[S3P]::Size {}", id, szs3p); - log_info("hooks:bmsb", "{}::Bank[S3P]::VoiceCount {}", id, snds3p->header()->voice_cnt); - log_info("hooks:bmsb", "{}::Bank[S3P]::Voice[0]::Size {}", id, snds3p->voice_ptr(0)->sz); + log_info("hooks::soundbank", "{}::Bank[S3P]::Signature {}", id, sig); + log_info("hooks::soundbank", "{}::Bank[S3P]::Size {}", id, szs3p); + log_info("hooks::soundbank", "{}::Bank[S3P]::VoiceCount {}", id, snds3p->header()->voice_cnt); + log_info("hooks::soundbank", "{}::Bank[S3P]::Voice[0]::Size {}", id, snds3p->voice_ptr(0)->sz); memcpy(sig, snds3p->voice(0)->sig, 4); - log_info("hooks:bmsb", "{}::Bank[S3P]::Voice[0]::Signature {}", id, sig); - dump_("raw_wma.wma", snds3p->voice(0)->asf(), snds3p->voice(0)->sz); + log_info("hooks::soundbank", "{}::Bank[S3P]::Voice[0]::Signature {}", id, sig); + snd_bank::dump("raw_wma.wma", snds3p->voice(0)->asf(), snds3p->voice(0)->sz); // MF codec (tainted PCM data, bad) mf_broken::asf_to_wav(snds3p->voice(0)->asf(), snds3p->voice(0)->sz, &wav, &wavsz); - dump_("mf_wav.wav", wav, wavsz); + snd_bank::dump("mf_wav.wav", wav, wavsz); free(wav); wav = nullptr; wavsz = 0; @@ -828,7 +813,7 @@ void run_tests() // AV codec (1:1 unmodified PCM data, other than resampling if enabled) wav = (BYTE *) malloc(snd_2dx::assertsz_asf(snds3p->voice(0)->sz, avcodec::bmswac_resampler_f32)); avcodec::BmswTranscoderAsfToWav(snds3p->voice(0)->asf(), snds3p->voice(0)->sz, &wav, &wavsz, avcodec::bmswac_resampler_f32); - dump_("ac_wav.wav", wav, wavsz); + snd_bank::dump("ac_wav.wav", wav, wavsz); free(wav); wav = nullptr; wavsz = 0; @@ -836,7 +821,7 @@ void run_tests() // S3P=>2DX (max 4076 voices) size_t i, j; snd_2dx *snd2dx = snd_2dx::pack(id); - log_info("hooks:bmsb", "{}::Bank[2DX]::Name {}", id, snd2dx->header()->name); + log_info("hooks::soundbank", "{}::Bank[2DX]::Name {}", id, snd2dx->header()->name); for (i = 0; i < snds3p->header()->voice_cnt; i++) { // WMA=>WAV transcode @@ -851,19 +836,18 @@ void run_tests() } // Valid 2DX (trim is not necessary) - log_info("hooks:bmsb", "{}::Bank[2DX]::Dumping", id); + log_info("hooks::soundbank", "{}::Bank[2DX]::Dumping", id); snd_2dx::bank *buf2dx = snd2dx->serialize(false); - dump_("ac_soundbank.2dx", reinterpret_cast(buf2dx), buf2dx->sz()); - + snd_bank::dump("ac_soundbank.2dx", reinterpret_cast(buf2dx), buf2dx->sz()); } else { - log_info("hooks:bmsb", "Tests failed"); + log_info("hooks::soundbank", "Tests failed"); } // Caching and intermediate 2dx storage detection BmsbEnumValidSoundbanks_t t = BmsbEnumValidSoundbanks; - BmsbEnumValidSoundbanks = [](void *, int32_t, int32_t) { log_info("hooks::bmsb", "BmsbEnumValidSoundbanks(fallback)"); }; + BmsbEnumValidSoundbanks = [](void *, int32_t, int32_t) { log_info("hooks::soundbank", "BmsbEnumValidSoundbanks(fallback)"); }; char *tmp = (char *) malloc(0x3b0 + sizeof(int32_t)); int arr[6] = {25073, 24016, 26057, 25073, 26087, 29095}; strcpy(tmp, "SJISTITLE"); @@ -876,23 +860,23 @@ void run_tests() free(tmp); BmsbEnumValidSoundbanks = t; - soundbank::flush_cache(); + snd_bank::flush_cache(); mf_broken::deinit(); } - void init(HINSTANCE hmodule, const char *ext) { if (false && IsDebuggerPresent()) { - log_warning("hooks::bmsb", "Debugger detected, skipping.."); + log_warning("hooks::soundbank", "Debugger detected, skipping.."); return; } if (!avcodec::init()) { - log_warning("hooks::bmsb", "AVCodec initialization failed, skipping.."); + log_warning("hooks::soundbank", "AVCodec initialization failed, skipping.."); + return; } - // Override .text .data per datacode _REV: prefer unique asm pattern offset lookup + // Override .text .data per datacode _REV: prefer runtime offset lookup based on universal asm pattern offset_.DAT_song_titlel = 0x00; offset_.DAT_song_artistl = 0xc0; offset_.DAT_song_id = 0x3b0; @@ -922,11 +906,14 @@ void init(HINSTANCE hmodule, const char *ext) case offset_t::by_ext("2023090500"): offset_.TX_BmsbEnumValidSoundbanks = (intptr_t) hmodule + 0xafd780; break; + case offset_t::by_ext("2024082600"): + offset_.TX_BmsbEnumValidSoundbanks = (intptr_t) hmodule + 0x81dd40; + break; default: - log_warning("hooks::bmsb", "Unsupported game version({}), skipping..", ext); + log_warning("hooks::soundbank", "Unsupported game version({}), skipping..", ext); return; } - log_info("hooks::bmsb", "Supported game version({})", ext); + log_info("hooks::soundbank", "Supported game version({})", ext); // Override .rdata offset_.RD_05d_s3p = replace_pattern(hmodule, "253035642f253035642e73337000", "003035642f253035642e73337000", 0, 0); @@ -935,7 +922,7 @@ void init(HINSTANCE hmodule, const char *ext) offset_.RD_05d_c_2dx = replace_pattern(hmodule, "253035642f2530356425632e32647800", "253035642f2530356425632e32647800", 0, 0); if (!(offset_.TX_BmsbEnumValidSoundbanks && offset_.RD_05d_s3p && offset_.RD_05d_c_s3p && offset_.RD_05d_2dx && offset_.RD_05d_c_2dx)) { - log_warning("hooks::bmsb", "Could not find valid offsets, skipping.."); + log_warning("hooks::soundbank", "Could not find valid offsets, skipping.."); return; } @@ -943,21 +930,18 @@ void init(HINSTANCE hmodule, const char *ext) offset_.guard = new memutils::VProtectGuard((void *) offset_.RD_05d_2dx, SNDPATHFMTMAX); detour::trampoline(reinterpret_cast(offset_.TX_BmsbEnumValidSoundbanks), reinterpret_cast(on_enum_valid_soundbanks), reinterpret_cast(&BmsbEnumValidSoundbanks)); - log_info("hooks::bmsb", "Soundbank preprocessor ready"); + log_info("hooks::soundbank", "Soundbank preprocessor ready"); - // Tests _REM: tests - detour::trampoline(reinterpret_cast(avs::core::avs_fs_lstat), reinterpret_cast(on_avs_fs_lstat), reinterpret_cast(&avs_fs_lstat_)); - detour::trampoline(reinterpret_cast(avs::core::avs_fs_mount), reinterpret_cast(on_avs_fs_mount), reinterpret_cast(&avs_fs_mount_)); + // Tests if (getenv("SPICE_TESTING") && offset_t::by_ext(ext) == offset_t::by_ext("2023090500")) run_tests(); } - void deinit(HINSTANCE hmodule) { - log_info("hooks::bmsb", "Releasing soundbank preprocessor"); + log_info("hooks::soundbank", "Releasing soundbank preprocessor"); - soundbank::flush_cache(); + snd_bank::flush_cache(); delete offset_.guard; + avcodec::deinit(); } - } \ No newline at end of file diff --git a/hooks/bmsbhook.h b/hooks/sndbhook.h similarity index 81% rename from hooks/bmsbhook.h rename to hooks/sndbhook.h index 45decda..c7acc35 100644 --- a/hooks/bmsbhook.h +++ b/hooks/sndbhook.h @@ -2,7 +2,7 @@ #include -namespace hooks::bmsb +namespace hooks::soundbank { void init(HINSTANCE hmodule, const char *ext); void deinit(HINSTANCE hmodule);