code: Cleanups around added code

> related to #1
This commit is contained in:
[ ]
2025-05-28 00:27:46 +09:00
parent 0b6986e12c
commit f0855d9b53
5 changed files with 145 additions and 161 deletions
+1 -1
View File
@@ -464,7 +464,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
hooks/audio/implementations/wave_out.cpp hooks/audio/implementations/wave_out.cpp
hooks/audio/implementations/none.cpp hooks/audio/implementations/none.cpp
hooks/audio/implementations/pipewire.cpp hooks/audio/implementations/pipewire.cpp
hooks/bmsbhook.cpp hooks/sndbhook.cpp
hooks/avshook.cpp hooks/avshook.cpp
hooks/cfgmgr32hook.cpp hooks/cfgmgr32hook.cpp
hooks/debughook.cpp hooks/debughook.cpp
+3 -3
View File
@@ -17,7 +17,7 @@
#endif #endif
#include "hooks/setupapihook.h" #include "hooks/setupapihook.h"
#include "hooks/sleephook.h" #include "hooks/sleephook.h"
#include "hooks/bmsbhook.h" #include "hooks/sndbhook.h"
#include "launcher/options.h" #include "launcher/options.h"
#include "touch/touch.h" #include "touch/touch.h"
#include "misc/wintouchemu.h" #include "misc/wintouchemu.h"
@@ -376,7 +376,7 @@ namespace games::iidx {
cfgmgr32hook_init(avs::game::DLL_INSTANCE); cfgmgr32hook_init(avs::game::DLL_INSTANCE);
// wine fixes // 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() { void IIDXGame::detach() {
hooks::bmsb::deinit(avs::game::DLL_INSTANCE); hooks::soundbank::deinit(avs::game::DLL_INSTANCE);
Game::detach(); Game::detach();
+1 -1
View File
@@ -106,7 +106,7 @@ HRESULT PipewireBackend::on_initialize(AUDCLNT_SHAREMODE *ShareMode, DWORD *Stre
*hnsPeriodicity = wrt_; *hnsPeriodicity = wrt_;
//_TODO: Init info //_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", "... hnsBufferDuration : {}", *hnsBufferDuration);
log_info("audio::pipewire", "... hnsPeriodicity : {}", *hnsPeriodicity); log_info("audio::pipewire", "... hnsPeriodicity : {}", *hnsPeriodicity);
+138 -154
View File
@@ -1,4 +1,4 @@
#include "bmsbhook.h" #include "sndbhook.h"
#include "util/logging.h" #include "util/logging.h"
#include "util/memutils.h" #include "util/memutils.h"
#include "util/sigscan.h" #include "util/sigscan.h"
@@ -8,37 +8,8 @@
#include <cstring> #include <cstring>
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) // 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 enum pcm_resampler : int8_t
{ {
@@ -59,7 +30,7 @@ static BmswTranscoderAsfToWav_t BmswTranscoderAsfToWav;
static HMODULE bmsw_ = nullptr; static HMODULE bmsw_ = nullptr;
bool init() bool init()
{ {
log_info("hooks::bmsb::avcodec", "{}", __FUNCTION__); log_info("hooks::soundbank::avcodec", "{}", __FUNCTION__);
// Initialize bmsound-wine.dll once // Initialize bmsound-wine.dll once
if (!bmsw_ && (bmsw_ = libutils::try_library(MODULE_PATH / "bmsound-wine.dll"))) if (!bmsw_ && (bmsw_ = libutils::try_library(MODULE_PATH / "bmsound-wine.dll")))
@@ -73,13 +44,12 @@ bool init()
return true; return true;
} }
log_fatal("audio::pipewire", "Library not found: '{}'", (MODULE_PATH / "bmsound-wine.dll").string()); log_warning("hooks::soundbank", "Library not found: '{}'", (MODULE_PATH / "bmsound-wine.dll").string());
return true; return false;
} }
void deinit() void deinit()
{ {
log_info("hooks::bmsb::avcodec", "{}", __FUNCTION__); log_info("hooks::soundbank::avcodec", "{}", __FUNCTION__);
} }
} }
@@ -89,7 +59,7 @@ void deinit()
#include <mfreadwrite.h> #include <mfreadwrite.h>
#include <mfobjects.h> #include <mfobjects.h>
#include <shlwapi.h> #include <shlwapi.h>
namespace hooks::bmsb::mf_broken namespace hooks::soundbank::mf_broken
{ {
typedef HRESULT (*MFCreateMFByteStreamOnStream_t)(IStream *, IMFByteStream **); typedef HRESULT (*MFCreateMFByteStreamOnStream_t)(IStream *, IMFByteStream **);
typedef HRESULT (*MFCreateSourceReaderFromByteStream_t)(IMFByteStream *, IMFAttributes *, IMFSourceReader **); 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); hr = srcreader->ReadSample((DWORD) MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, &flags, nullptr, &samples);
if (FAILED(hr)) if (FAILED(hr))
{ {
log_warning("hooks::bmsb", "ReadSample() failure, skipping.."); log_warning("hooks::soundbank", "ReadSample() failure, skipping..");
break; break;
} }
if (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) if (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
{ {
log_warning("hooks::bmsb", "Unsupported WAVE format, skipping.."); log_warning("hooks::soundbank", "Unsupported WAVE format, skipping..");
samples->Release(); samples->Release();
break; break;
} }
@@ -148,13 +118,13 @@ HRESULT asf_unpack_pcm_s16le(BYTE *dst, IMFSourceReader *srcreader, uint32_t szm
} }
if (samples == nullptr) if (samples == nullptr)
{ {
log_warning("hooks::bmsb", "Missing samples"); log_warning("hooks::soundbank", "Missing samples");
continue; continue;
} }
hr = samples->ConvertToContiguousBuffer(&mediabuf); hr = samples->ConvertToContiguousBuffer(&mediabuf);
if (FAILED(hr)) if (FAILED(hr))
{ {
log_warning("hooks::bmsb", "ConvertToContiguousBuffer() failure, skipping.."); log_warning("hooks::soundbank", "ConvertToContiguousBuffer() failure, skipping..");
samples->Release(); samples->Release();
break; break;
} }
@@ -255,17 +225,16 @@ void deinit()
{ {
MFShutdown(); MFShutdown();
} }
} }
namespace hooks::bmsb namespace hooks::soundbank
{ {
constexpr char SNDPATHFMT[] = "%05d/%05d"; constexpr char SNDPATHFMT[] = "%05d/%05d";
constexpr size_t SNDPATHFMTMAX = sizeof(SNDPATHFMT) - 1; constexpr size_t SNDPATHFMTMAX = sizeof(SNDPATHFMT) - 1;
constexpr size_t MNTPATHMAX = sizeof("/sdAABBB/AABBB/AABBBC_pre.2dx"); constexpr size_t MNTPATHMAX = sizeof("/sdAABBB/AABBB/AABBBC_pre.2dx");
constexpr size_t AVSPATHMAX = sizeof("/data/sound/AABBB/AABBBC_pre.2dx"); constexpr size_t AVSPATHMAX = sizeof("/data/sound/AABBB/AABBBC_pre.2dx");
constexpr uint8_t CACHEMAX = 16; constexpr uint8_t CACHEMAX = 8;
typedef struct soundbank soundbank; typedef struct snd_bank snd_bank;
typedef struct snd_s3p snd_s3p; typedef struct snd_s3p snd_s3p;
typedef struct snd_2dx snd_2dx; typedef struct snd_2dx snd_2dx;
typedef void (*BmsbEnumValidSoundbanks_t)(void *, int32_t, int32_t); 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) resampler = (resampler > 1 || resampler == -1) ? 2 : 1; // resampler ratio multiplier (see pcm_resampler enum, original data is float)
return static_cast<size_t>(static_cast<double>(sz) * 14.8) * resampler + WAVHDRSIZE; // 0.wma is consistent 180 therefore VBR Q90, sometimes 160 though, but samples are all over the place return static_cast<size_t>(static_cast<double>(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 [[nodiscard]] constexpr const decltype(bank::header) *header() const noexcept
{ {
return &this->bank_->header; return &this->bank_->header;
} }
[[nodiscard]] constexpr bank::voice_ptr *voice_ptr(size_t i) const noexcept [[nodiscard]] constexpr bank::voice_ptr *voice_ptr(size_t i) const noexcept
{ {
return &bank_->table + i; return &bank_->table + i;
} }
[[nodiscard]] constexpr bank::voice_hdr *voice(size_t i) const noexcept [[nodiscard]] constexpr bank::voice_hdr *voice(size_t i) const noexcept
{ {
return (bank::voice_hdr *) ((char *) this->bank_ + this->voice_ptr(i)->fbegin); return (bank::voice_hdr *) ((char *) this->bank_ + this->voice_ptr(i)->fbegin);
} }
[[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_*()
//_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
{ {
// memory space assertion // memory space assertion
if (this->voice_ptr(this->bank_->header.voice_cnt)->fbegin + assertsz >= banksz_) 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; banksz_ += assertsz + ALLOCSIZE;
bank_ = (bank *) realloc(bank_, banksz_); bank_ = (bank *) realloc(bank_, banksz_);
} }
@@ -364,9 +328,9 @@ public:
voice_hdr->unk2 = 0x0; voice_hdr->unk2 = 0x0;
return this->bank_->header.voice_cnt++; return this->bank_->header.voice_cnt++;
} }
static snd_2dx *unpack(char *refbank) = delete; static snd_2dx *unpack(char *refbank) = delete;
static snd_2dx *pack(int id); static snd_2dx *pack(int id);
bank *serialize(bool trim); bank *serialize(bool trim);
~snd_2dx(); ~snd_2dx();
@@ -413,7 +377,6 @@ snd_2dx::~snd_2dx()
free(bank_); free(bank_);
} }
struct snd_s3p struct snd_s3p
{ {
public: public:
@@ -466,7 +429,6 @@ private:
size_t banksz_; //_TODO: keep track of allocated memory size_t banksz_; //_TODO: keep track of allocated memory
explicit snd_s3p(uint8_t *bindbank); explicit snd_s3p(uint8_t *bindbank);
}; };
snd_s3p::snd_s3p(uint8_t *bindbank) : bank_(reinterpret_cast<struct bank *>(bindbank)), banksz_(0) snd_s3p::snd_s3p(uint8_t *bindbank) : bank_(reinterpret_cast<struct bank *>(bindbank)), banksz_(0)
{ {
@@ -480,16 +442,17 @@ snd_s3p *snd_s3p::unpack(uint8_t *refbank)
return refbank ? new snd_s3p(refbank) : nullptr; return refbank ? new snd_s3p(refbank) : nullptr;
} }
struct soundbank struct snd_bank
{ {
public: public:
static soundbank *new_instance(int id); static snd_bank *new_instance(int id);
static void flush_cache(); static void flush_cache();
static void pop_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 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 bool has_format(const char *avspath, const char *ext);
static avs::core::avs_file_t map_ifs(char *avspath); 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; int id;
char avspath[AVSPATHMAX]; char avspath[AVSPATHMAX];
@@ -518,43 +481,27 @@ public:
private: private:
static constexpr avs::core::avs_file_t E_NOT_FOUND = 0x80070002; static constexpr avs::core::avs_file_t E_NOT_FOUND = 0x80070002;
static constexpr uint8_t UID_INVALID = 0x00; static constexpr uint8_t UID_INVALID = 0x00;
static soundbank *cache_; static snd_bank *cache_;
static size_t cachesz_; static size_t cachesz_;
uint8_t uid_; uint8_t uid_;
uint32_t mnt_; uint32_t mnt_;
soundbank *next_; snd_bank *next_;
soundbank(); snd_bank();
~soundbank(); ~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 FILE *fh = fopen(path, "wb");
intptr_t RD_05d_c_s3p; // %05d/%05d%c.s3p fwrite(src, sz, 1, fh);
intptr_t RD_05d_2dx; // %05d/%05d.2dx fclose(fh);
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::new_instance(int id)
soundbank *soundbank::cache_ = nullptr;
size_t soundbank::cachesz_ = 0;
static BmsbEnumValidSoundbanks_t BmsbEnumValidSoundbanks;
soundbank *soundbank::new_instance(int id)
{ {
soundbank *prev, *instance; snd_bank *prev, *instance;
// Latest entry should always be head // Latest entry should always be head
instance = new soundbank(); instance = new snd_bank();
instance->id = id; instance->id = id;
instance->next_ = cache_; instance->next_ = cache_;
cache_ = instance; cache_ = instance;
@@ -563,16 +510,16 @@ soundbank *soundbank::new_instance(int id)
// Clean cache (last entry indexing target excluded, cache limit reached) // Clean cache (last entry indexing target excluded, cache limit reached)
if (instance->next_ && instance->next_->uid_ == UID_INVALID) if (instance->next_ && instance->next_->uid_ == UID_INVALID)
{ {
log_info("hooks::bmsb", "Cache prune"); log_info("hooks::soundbank", "Cache prune");
prev = instance->next_; prev = instance->next_;
instance->next_ = prev->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; delete prev;
cachesz_ -= 1; cachesz_ -= 1;
} }
if (cachesz_ > CACHEMAX) if (cachesz_ > CACHEMAX)
{ {
log_info("hooks::bmsb", "Cache full"); log_info("hooks::soundbank", "Cache full");
for (uint8_t i = 0; i < CACHEMAX; i += 2) for (uint8_t i = 0; i < CACHEMAX; i += 2)
{ {
prev = nullptr; prev = nullptr;
@@ -590,12 +537,12 @@ soundbank *soundbank::new_instance(int id)
return cache_; 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 // Update struct using next free cache uid
if (uid_ == UID_INVALID) if (uid_ == UID_INVALID)
{ {
soundbank *it = cache_; snd_bank *it = cache_;
while (it) while (it)
{ {
if (uid_ == UID_INVALID || (uid_ == it->uid_ && it != this)) 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 // Store file
char path[AVSPATHMAX]; char path[AVSPATHMAX];
snprintf(path, sizeof(path), "%s.2dx", this->avspath); snprintf(path, sizeof(path), "%s.2dx", this->avspath);
log_info("hooks::bmsb", "Storing as intermediate soundbank at '{}'", (const char *) path); log_info("hooks::soundbank", "Storing as intermediate soundbank at '{}'", (const char *) path);
dump_(path, sndbuf, sz); 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) if (uid_ != UID_INVALID)
{ {
char path[AVSPATHMAX]; char path[AVSPATHMAX];
snprintf(path, sizeof(path), "data/sound/system/%02x.2dx", uid_); 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); remove(path);
} }
if (mnt_ != E_NOT_FOUND) 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_); avs::core::avs_fs_umount(mnt_);
} }
} }
snd_bank *snd_bank::get_bank(int id)
soundbank *soundbank::get_bank(int id)
{ {
// Find in cache (latest=>oldest) // 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; if (it->id == id) return it;
// Find in avs (has valid s3p/.2dx resource at data/sound/AABBB/AABBB.2dx) // 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); snprintf(bank->avspath, AVSPATHMAX, "data/sound/%05d", id);
if (has_format(bank->avspath, ".ifs")) if (has_format(bank->avspath, ".ifs"))
bank->mnt_ = map_ifs(bank->avspath); bank->mnt_ = map_ifs(bank->avspath);
@@ -655,9 +601,9 @@ soundbank *soundbank::get_bank(int id)
return bank; return bank;
} }
void soundbank::flush_cache() void snd_bank::flush_cache()
{ {
soundbank *prev; snd_bank *prev;
while (cache_) while (cache_)
{ {
prev = cache_; prev = cache_;
@@ -665,13 +611,13 @@ void soundbank::flush_cache()
delete prev; delete prev;
} }
} }
void soundbank::pop_cache() void snd_bank::pop_cache()
{ {
soundbank *prev = cache_; snd_bank *prev = cache_;
cache_ = cache_->next_; cache_ = cache_->next_;
delete prev; 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 constexpr uint16_t O_RDONLY = 1; // rw:12 consistent across versions with s3p support
uint8_t *r = nullptr; uint8_t *r = nullptr;
@@ -692,16 +638,16 @@ uint8_t *soundbank::read_bank_any(const char *avspath, const char *ext, size_t *
} }
return r; 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] = ""; char path[AVSPATHMAX] = "";
snprintf(path, sizeof(path), "%s%s", avspath, ext); snprintf(path, sizeof(path), "%s%s", avspath, ext);
avs::core::avs_stat st; // NOLINT(cppcoreguidelines-pro-type-member-init) avs::core::avs_stat st; // NOLINT(cppcoreguidelines-pro-type-member-init)
bool r = static_cast<bool>(avs::core::avs_fs_lstat(path, &st)); // lstat should be faster than open bool r = static_cast<bool>(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<bool>(r); return static_cast<bool>(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} // Map */${name}.ifs => /sc${name}
char ifspath[AVSPATHMAX]; char ifspath[AVSPATHMAX];
@@ -720,35 +666,73 @@ avs::core::avs_file_t soundbank::map_ifs(char *avspath)
if (r != E_NOT_FOUND) if (r != E_NOT_FOUND)
{ {
snprintf(mntpath + strlen(mntpath), strlen(it) + 2, "/%s", it); snprintf(mntpath + strlen(mntpath), strlen(it) + 2, "/%s", it);
log_info("hooks::bmsb", "'{}' => '{}'", avspath, mntpath); log_info("hooks::soundbank", "'{}' => '{}'", avspath, mntpath);
strcpy(avspath, mntpath); strcpy(avspath, mntpath);
} }
return r; 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) 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 // 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 // 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 *titlel = (const char *) song + offset_.DAT_song_titlel;
const char *artistl = (const char *) song + offset_.DAT_song_artistl; const char *artistl = (const char *) song + offset_.DAT_song_artistl;
const int32_t id = *(int32_t *) ((const char *) song + offset_.DAT_song_id); 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); log_info("hooks::soundbank", "Processing s3p->2dx transcoding routine for [{}]({} - {})", id, artistl, titlel);
if (!(keysounds = soundbank::get_bank(id))) 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<void *>(offset_.RD_05d_2dx), "%05d/%05d", SNDPATHFMTMAX); memcpy(reinterpret_cast<void *>(offset_.RD_05d_2dx), "%05d/%05d", SNDPATHFMTMAX);
BmsbEnumValidSoundbanks(song, difficulty, unk2); BmsbEnumValidSoundbanks(song, difficulty, unk2);
return; 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 // Get s3p and process into s3p soundbank for intermediate wma voice storage
size_t szs3p; 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); snd_s3p *snds3p = snd_s3p::unpack(bufs3p);
// Process wma voices into wav voices stored directly into 2dx soundbank // 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 // Resume execution
const char *t = keysounds->sndpath(); const char *t = keysounds->sndpath();
memcpy(reinterpret_cast<void *>(offset_.RD_05d_2dx), t, SNDPATHFMTMAX); memcpy(reinterpret_cast<void *>(offset_.RD_05d_2dx), t, SNDPATHFMTMAX);
log_info("hooks::bmsb", "RD_05d_2dx set to '{}'", reinterpret_cast<const char *>(offset_.RD_05d_2dx)); //_REM: tests log_info("hooks::soundbank", "RD_05d_2dx set to '{}'", reinterpret_cast<const char *>(offset_.RD_05d_2dx));
log_info("hooks::bmsb", "Processing completed"); log_info("hooks::soundbank", "Processing completed");
BmsbEnumValidSoundbanks(song, difficulty, unk2); BmsbEnumValidSoundbanks(song, difficulty, unk2);
} }
void run_tests() void run_tests()
{ {
size_t szs3p; size_t szs3p;
@@ -791,17 +774,19 @@ void run_tests()
int id = 25073; int id = 25073;
if (!mf_broken::init()) if (!mf_broken::init())
{ {
log_warning("hooks::bmsb", "MF initialization failed, skipping.."); log_warning("hooks::soundbank", "MF initialization failed, skipping..");
} }
detour::trampoline(reinterpret_cast<void *>(avs::core::avs_fs_lstat), reinterpret_cast<void *>(on_avs_fs_lstat), reinterpret_cast<void **>(&avs_fs_lstat_));
detour::trampoline(reinterpret_cast<void *>(avs::core::avs_fs_mount), reinterpret_cast<void *>(on_avs_fs_mount), reinterpret_cast<void **>(&avs_fs_mount_));
// Filesystem tests, s3p unpacking // Filesystem tests, s3p unpacking
snprintf(avspath, sizeof(avspath), "data/sound/%05d", id); 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); snprintf(avspath + strlen(avspath), 7, "/%05d", id);
soundbank::has_format(avspath, ".s3p"); snd_bank::has_format(avspath, ".s3p");
soundbank::has_format(avspath, ".2dx"); snd_bank::has_format(avspath, ".2dx");
soundbank::has_format(avspath, "_pre.2dx"); snd_bank::has_format(avspath, "_pre.2dx");
uint8_t *bufs3p = soundbank::read_bank_any(avspath, ".s3p", &szs3p); uint8_t *bufs3p = snd_bank::read_bank_any(avspath, ".s3p", &szs3p);
snd_s3p *snds3p = snd_s3p::unpack(bufs3p); snd_s3p *snds3p = snd_s3p::unpack(bufs3p);
if (avsmnt) avs::core::avs_fs_umount(avsmnt); if (avsmnt) avs::core::avs_fs_umount(avsmnt);
@@ -810,17 +795,17 @@ void run_tests()
{ {
// S3P/S3V metadata // S3P/S3V metadata
memcpy(sig, snds3p->header()->sig, 4); memcpy(sig, snds3p->header()->sig, 4);
log_info("hooks:bmsb", "{}::Bank[S3P]::Signature {}", id, sig); log_info("hooks::soundbank", "{}::Bank[S3P]::Signature {}", id, sig);
log_info("hooks:bmsb", "{}::Bank[S3P]::Size {}", id, szs3p); log_info("hooks::soundbank", "{}::Bank[S3P]::Size {}", id, szs3p);
log_info("hooks:bmsb", "{}::Bank[S3P]::VoiceCount {}", id, snds3p->header()->voice_cnt); log_info("hooks::soundbank", "{}::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]::Voice[0]::Size {}", id, snds3p->voice_ptr(0)->sz);
memcpy(sig, snds3p->voice(0)->sig, 4); memcpy(sig, snds3p->voice(0)->sig, 4);
log_info("hooks:bmsb", "{}::Bank[S3P]::Voice[0]::Signature {}", id, sig); log_info("hooks::soundbank", "{}::Bank[S3P]::Voice[0]::Signature {}", id, sig);
dump_("raw_wma.wma", snds3p->voice(0)->asf(), snds3p->voice(0)->sz); snd_bank::dump("raw_wma.wma", snds3p->voice(0)->asf(), snds3p->voice(0)->sz);
// MF codec (tainted PCM data, bad) // MF codec (tainted PCM data, bad)
mf_broken::asf_to_wav(snds3p->voice(0)->asf(), snds3p->voice(0)->sz, &wav, &wavsz); 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); free(wav);
wav = nullptr; wav = nullptr;
wavsz = 0; wavsz = 0;
@@ -828,7 +813,7 @@ void run_tests()
// AV codec (1:1 unmodified PCM data, other than resampling if enabled) // 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)); 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); 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); free(wav);
wav = nullptr; wav = nullptr;
wavsz = 0; wavsz = 0;
@@ -836,7 +821,7 @@ void run_tests()
// S3P=>2DX (max 4076 voices) // S3P=>2DX (max 4076 voices)
size_t i, j; size_t i, j;
snd_2dx *snd2dx = snd_2dx::pack(id); 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++) for (i = 0; i < snds3p->header()->voice_cnt; i++)
{ {
// WMA=>WAV transcode // WMA=>WAV transcode
@@ -851,19 +836,18 @@ void run_tests()
} }
// Valid 2DX (trim is not necessary) // 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); snd_2dx::bank *buf2dx = snd2dx->serialize(false);
dump_("ac_soundbank.2dx", reinterpret_cast<const uint8_t *>(buf2dx), buf2dx->sz()); snd_bank::dump("ac_soundbank.2dx", reinterpret_cast<const uint8_t *>(buf2dx), buf2dx->sz());
} }
else else
{ {
log_info("hooks:bmsb", "Tests failed"); log_info("hooks::soundbank", "Tests failed");
} }
// Caching and intermediate 2dx storage detection // Caching and intermediate 2dx storage detection
BmsbEnumValidSoundbanks_t t = BmsbEnumValidSoundbanks; 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)); char *tmp = (char *) malloc(0x3b0 + sizeof(int32_t));
int arr[6] = {25073, 24016, 26057, 25073, 26087, 29095}; int arr[6] = {25073, 24016, 26057, 25073, 26087, 29095};
strcpy(tmp, "SJISTITLE"); strcpy(tmp, "SJISTITLE");
@@ -876,23 +860,23 @@ void run_tests()
free(tmp); free(tmp);
BmsbEnumValidSoundbanks = t; BmsbEnumValidSoundbanks = t;
soundbank::flush_cache(); snd_bank::flush_cache();
mf_broken::deinit(); mf_broken::deinit();
} }
void init(HINSTANCE hmodule, const char *ext) void init(HINSTANCE hmodule, const char *ext)
{ {
if (false && IsDebuggerPresent()) if (false && IsDebuggerPresent())
{ {
log_warning("hooks::bmsb", "Debugger detected, skipping.."); log_warning("hooks::soundbank", "Debugger detected, skipping..");
return; return;
} }
if (!avcodec::init()) 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_titlel = 0x00;
offset_.DAT_song_artistl = 0xc0; offset_.DAT_song_artistl = 0xc0;
offset_.DAT_song_id = 0x3b0; offset_.DAT_song_id = 0x3b0;
@@ -922,11 +906,14 @@ void init(HINSTANCE hmodule, const char *ext)
case offset_t::by_ext("2023090500"): case offset_t::by_ext("2023090500"):
offset_.TX_BmsbEnumValidSoundbanks = (intptr_t) hmodule + 0xafd780; offset_.TX_BmsbEnumValidSoundbanks = (intptr_t) hmodule + 0xafd780;
break; break;
case offset_t::by_ext("2024082600"):
offset_.TX_BmsbEnumValidSoundbanks = (intptr_t) hmodule + 0x81dd40;
break;
default: default:
log_warning("hooks::bmsb", "Unsupported game version({}), skipping..", ext); log_warning("hooks::soundbank", "Unsupported game version({}), skipping..", ext);
return; return;
} }
log_info("hooks::bmsb", "Supported game version({})", ext); log_info("hooks::soundbank", "Supported game version({})", ext);
// Override .rdata // Override .rdata
offset_.RD_05d_s3p = replace_pattern(hmodule, "253035642f253035642e73337000", "003035642f253035642e73337000", 0, 0); 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); 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)) 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; return;
} }
@@ -943,21 +930,18 @@ void init(HINSTANCE hmodule, const char *ext)
offset_.guard = new memutils::VProtectGuard((void *) offset_.RD_05d_2dx, SNDPATHFMTMAX); offset_.guard = new memutils::VProtectGuard((void *) offset_.RD_05d_2dx, SNDPATHFMTMAX);
detour::trampoline(reinterpret_cast<void *>(offset_.TX_BmsbEnumValidSoundbanks), reinterpret_cast<void *>(on_enum_valid_soundbanks), reinterpret_cast<void **>(&BmsbEnumValidSoundbanks)); detour::trampoline(reinterpret_cast<void *>(offset_.TX_BmsbEnumValidSoundbanks), reinterpret_cast<void *>(on_enum_valid_soundbanks), reinterpret_cast<void **>(&BmsbEnumValidSoundbanks));
log_info("hooks::bmsb", "Soundbank preprocessor ready"); log_info("hooks::soundbank", "Soundbank preprocessor ready");
// Tests _REM: tests // Tests
detour::trampoline(reinterpret_cast<void *>(avs::core::avs_fs_lstat), reinterpret_cast<void *>(on_avs_fs_lstat), reinterpret_cast<void **>(&avs_fs_lstat_));
detour::trampoline(reinterpret_cast<void *>(avs::core::avs_fs_mount), reinterpret_cast<void *>(on_avs_fs_mount), reinterpret_cast<void **>(&avs_fs_mount_));
if (getenv("SPICE_TESTING") && offset_t::by_ext(ext) == offset_t::by_ext("2023090500")) if (getenv("SPICE_TESTING") && offset_t::by_ext(ext) == offset_t::by_ext("2023090500"))
run_tests(); run_tests();
} }
void deinit(HINSTANCE hmodule) 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; delete offset_.guard;
avcodec::deinit();
} }
} }
+1 -1
View File
@@ -2,7 +2,7 @@
#include <windows.h> #include <windows.h>
namespace hooks::bmsb namespace hooks::soundbank
{ {
void init(HINSTANCE hmodule, const char *ext); void init(HINSTANCE hmodule, const char *ext);
void deinit(HINSTANCE hmodule); void deinit(HINSTANCE hmodule);