diff --git a/common/formatter/formatter.cpp b/common/formatter/formatter.cpp index 68114e2e11..a737b30def 100644 --- a/common/formatter/formatter.cpp +++ b/common/formatter/formatter.cpp @@ -34,6 +34,7 @@ void walk_tree(TSTreeCursor* cursor, std::string& output, const std::string& sou uint32_t start = ts_node_start_byte(curr_node); uint32_t end = ts_node_end_byte(curr_node); const char* type = ts_node_type(curr_node); + (void)type; // TODO - if it's a string literal, take out any newlines and reflow the string to the // line-length const auto contents = source_code.substr(start, end - start); @@ -109,7 +110,7 @@ void format_code(const std::string& source, return; } const std::string curr_node_type = ts_node_type(curr_node); - for (int i = 0; i < ts_node_child_count(curr_node); i++) { + for (size_t i = 0; i < ts_node_child_count(curr_node); i++) { auto child_node = ts_node_child(curr_node, i); // If we are opening a list, peek at the first element in the list // this is so we can properly handle indentation based on different forms diff --git a/common/global_profiler/GlobalProfiler.cpp b/common/global_profiler/GlobalProfiler.cpp index 04ce0e3c46..3000c46f36 100644 --- a/common/global_profiler/GlobalProfiler.cpp +++ b/common/global_profiler/GlobalProfiler.cpp @@ -59,6 +59,10 @@ void GlobalProfiler::instant_event(const char* name) { event(name, ProfNode::INSTANT); } +void GlobalProfiler::root_event() { + instant_event("ROOT"); +} + void GlobalProfiler::begin_event(const char* name) { event(name, ProfNode::BEGIN); } diff --git a/common/global_profiler/GlobalProfiler.h b/common/global_profiler/GlobalProfiler.h index e8fcb3407c..98b23c8c83 100644 --- a/common/global_profiler/GlobalProfiler.h +++ b/common/global_profiler/GlobalProfiler.h @@ -24,6 +24,7 @@ class GlobalProfiler { void clear(); void set_enable(bool en); void dump_to_json(const std::string& path); + void root_event(); private: std::atomic_bool m_enabled = false; diff --git a/common/util/FileUtil.cpp b/common/util/FileUtil.cpp index 9a59ddd327..f5aaf6ecd6 100644 --- a/common/util/FileUtil.cpp +++ b/common/util/FileUtil.cpp @@ -373,6 +373,19 @@ std::string convert_to_unix_path_separators(const std::string& path) { #endif } +/*! + * Convert an animation name to ISO name. + * The animation name is a bunch of dash separated words. + * The resulting ISO name has the same first two chars as the animation name, and one char from each + * remaining word. Once there are no more words but remaining chars in the ISO name, the ith extra + * char is the i+1 th char of the last word. A word ending in a number (or just a number) is turned + * into the number. The word "resolution" becomes z. The word "accept" becomes y. The word "reject" + * becomes n. Other words become the first char of the word. The result is uppercased and the file + * extension is STR Examples (animation name and disc file name, not ISO name): + * green-sagecage-outro-beat-boss-enough-cells -> GRSOBBEC.STR + * swamp-tetherrock-swamprockexplode-4 -> SWTS4.STR + * minershort-resolution-1-orbs -> MIZ1ORBS.STR + */ void ISONameFromAnimationName(char* dst, const char* src) { // The Animation Name is a bunch of words separated by dashes @@ -457,6 +470,15 @@ void ISONameFromAnimationName(char* dst, const char* src) { strcpy(dst + 8, "STR"); } +/*! + * Convert file name to "ISO Name" + * ISO names are upper case and 12 bytes long. + * xxxxxxxxyyy0 + * + * x - uppercase letter of file name, or space + * y - uppercase letter of file extension, or space + * 0 - null terminator (\0, not the character zero) + */ void MakeISOName(char* dst, const char* src) { int i = 0; const char* src_ptr = src; diff --git a/common/util/FontUtils.cpp b/common/util/FontUtils.cpp index 5b7901a3ca..9a9b6116fa 100644 --- a/common/util/FontUtils.cpp +++ b/common/util/FontUtils.cpp @@ -307,7 +307,7 @@ std::string GameTextFontBank::convert_game_to_utf8(const char* in) const { in++; } replace_to_utf8(temp); - for (int i = 0; i < temp.length(); ++i) { + for (size_t i = 0; i < temp.length(); ++i) { auto c = temp.at(i); if (c == '\n') { result += "\\n"; diff --git a/decompiler/util/sparticle_decompile.cpp b/decompiler/util/sparticle_decompile.cpp index b127e2b44b..1c0df9dfad 100644 --- a/decompiler/util/sparticle_decompile.cpp +++ b/decompiler/util/sparticle_decompile.cpp @@ -532,7 +532,7 @@ std::string decompile_sparticle_launcher_by_id(const std::vector& wo std::string decompile_sparticle_flags(const std::vector& words, const TypeSystem& ts, - const std::string& field_name, + const std::string& /*field_name*/, const std::string& flag_name) { assert_spec_flag_int_no_rand(words, flag_name); diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 49967d4f0f..65b0ce993e 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -108,20 +108,42 @@ set(RUNTIME_SOURCE mips2c/jak2_functions/merc_blend_shape.cpp mips2c/jak2_functions/ripple.cpp mips2c/jak2_functions/squid.cpp - overlord/dma.cpp - overlord/fake_iso.cpp - overlord/iso.cpp - overlord/iso_api.cpp - overlord/iso_cd.cpp - overlord/iso_queue.cpp - overlord/isocommon.cpp - overlord/overlord.cpp - overlord/ramdisk.cpp - overlord/sbank.cpp - overlord/soundcommon.cpp - overlord/srpc.cpp - overlord/ssound.cpp - overlord/stream.cpp + overlord/common/dma.cpp + overlord/common/iso.cpp + overlord/common/iso_api.cpp + overlord/common/isocommon.cpp + overlord/common/overlord.cpp + overlord/common/sbank.cpp + overlord/common/soundcommon.cpp + overlord/common/srpc.cpp + overlord/common/fake_iso.cpp + overlord/common/ssound.cpp + overlord/jak1/dma.cpp + overlord/jak1/fake_iso.cpp + overlord/jak1/iso.cpp + overlord/jak1/iso_api.cpp + overlord/jak1/iso_queue.cpp + overlord/jak1/isocommon.cpp + overlord/jak1/overlord.cpp + overlord/jak1/ramdisk.cpp + overlord/jak1/srpc.cpp + overlord/jak1/ssound.cpp + overlord/jak1/stream.cpp + overlord/jak2/dma.cpp + overlord/jak2/iso.cpp + overlord/jak2/iso_cd.cpp + overlord/jak2/iso_api.cpp + overlord/jak2/iso_queue.cpp + overlord/jak2/overlord.cpp + overlord/jak2/pages.cpp + overlord/jak2/list.cpp + overlord/jak2/streamlist.cpp + overlord/jak2/streamlfo.cpp + overlord/jak2/ssound.cpp + overlord/jak2/srpc.cpp + overlord/jak2/stream.cpp + overlord/jak2/vag.cpp + overlord/jak2/spustreams.cpp graphics/gfx.cpp graphics/jak2_texture_remap.cpp graphics/display.cpp diff --git a/game/common/game_common_types.h b/game/common/game_common_types.h index aa841d7a34..9e77282437 100644 --- a/game/common/game_common_types.h +++ b/game/common/game_common_types.h @@ -18,6 +18,6 @@ enum class Language { struct GameLaunchOptions { GameVersion game_version = GameVersion::Jak1; bool disable_display = false; - bool disable_debug_vm = false; + bool disable_debug_vm = true; int server_port = DECI2_PORT; }; diff --git a/game/graphics/gfx.cpp b/game/graphics/gfx.cpp index 462177d3a1..b1e16070a4 100644 --- a/game/graphics/gfx.cpp +++ b/game/graphics/gfx.cpp @@ -11,6 +11,7 @@ #include "display.h" +#include "common/global_profiler/GlobalProfiler.h" #include "common/log/log.h" #include "common/symbols.h" #include "common/util/FileUtil.h" @@ -326,6 +327,7 @@ u32 Init(GameVersion version) { void Loop(std::function f) { lg::info("GFX Loop"); while (f()) { + auto p = scoped_prof("gfx loop"); // check if we have a display if (Display::GetMainDisplay()) { // lg::debug("run display"); diff --git a/game/kernel/common/kmemcard.cpp b/game/kernel/common/kmemcard.cpp index dec84ecb3c..d4f64f2f91 100644 --- a/game/kernel/common/kmemcard.cpp +++ b/game/kernel/common/kmemcard.cpp @@ -100,7 +100,7 @@ inline fs::path mc_get_filename(GameVersion version, int ndx) { return file_util::get_user_memcard_dir(version) / mc_get_filename_no_dir(version, ndx); } -int mc_get_total_bank_size(GameVersion version) { +int mc_get_total_bank_size(GameVersion) { return BANK_SIZE[g_game_version] + sizeof(McHeader) * 2; } @@ -145,7 +145,8 @@ u32 mc_checksum(Ptr data, s32 size) { */ bool file_is_present(int id, int bank = 0) { auto bankname = mc_get_filename(g_game_version, 4 + id * 2 + bank); - if (!fs::exists(bankname) || fs::file_size(bankname) < mc_get_total_bank_size(g_game_version)) { + if (!fs::exists(bankname) || + int(fs::file_size(bankname)) < mc_get_total_bank_size(g_game_version)) { // file doesn't exist, or size is bad. we do not want to open files that will crash on read! return false; } diff --git a/game/kernel/common/ksound.cpp b/game/kernel/common/ksound.cpp index 35d49e4329..1c70e43b43 100644 --- a/game/kernel/common/ksound.cpp +++ b/game/kernel/common/ksound.cpp @@ -2,7 +2,7 @@ #include "common/common_types.h" -#include "game/overlord/srpc.h" +#include "game/overlord/common/srpc.h" #include "game/sound/989snd/ame_handler.h" /*! diff --git a/game/main.cpp b/game/main.cpp index cb011cefc9..4344a500db 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -88,7 +88,7 @@ int main(int argc, char** argv) { bool verbose_logging = false; bool disable_avx2 = false; bool disable_display = false; - bool disable_debug_vm = false; + bool enable_debug_vm = false; int port_number = -1; fs::path project_path_override; std::vector game_args; @@ -101,7 +101,7 @@ int main(int argc, char** argv) { "Specify port number for listener connection (default is 8112 for Jak 1 and 8113 for Jak 2)"); app.add_flag("--no-avx2", verbose_logging, "Disable AVX2 for testing"); app.add_flag("--no-display", disable_display, "Disable video display"); - app.add_flag("--no-vm", disable_debug_vm, "Disable debug PS2 VM (defaulted to on)"); + app.add_flag("--vm", enable_debug_vm, "Enable debug PS2 VM (defaulted to off)"); app.add_option("--proj-path", project_path_override, "Specify the location of the 'data/' folder"); app.footer(game_arg_documentation()); @@ -117,7 +117,7 @@ int main(int argc, char** argv) { // Create struct with all non-kmachine handled args to pass to the runtime GameLaunchOptions game_options; - game_options.disable_debug_vm = disable_debug_vm; + game_options.disable_debug_vm = !enable_debug_vm; game_options.disable_display = disable_display; game_options.game_version = game_name_to_version(game_name); game_options.server_port = diff --git a/game/mips2c/jak2_functions/generic_effect.cpp b/game/mips2c/jak2_functions/generic_effect.cpp index 6b449c97e7..f1da8f00a6 100644 --- a/game/mips2c/jak2_functions/generic_effect.cpp +++ b/game/mips2c/jak2_functions/generic_effect.cpp @@ -1658,7 +1658,7 @@ struct Cache { void* fake_scratchpad_data; // *fake-scratchpad-data* } cache; -u64 execute(void* ctxt) { +u64 execute(void*) { ASSERT(false); return 0; } @@ -2149,7 +2149,7 @@ struct Cache { u64 execute(void* ctxt) { auto* c = (ExecutionContext*)ctxt; bool bc = false; - u32 call_addr = 0; + // u32 call_addr = 0; c->daddiu(sp, sp, -96); // daddiu sp, sp, -96 c->sd(ra, 12432, at); // sd ra, 12432(at) c->sq(s2, 12448, at); // sq s2, 12448(at) @@ -2599,7 +2599,7 @@ u64 execute(void* ctxt) { // c->gprs[t0].du64[0] = 0; // or t0, r0, r0 - block_10: + // block_10: c->dsll(t0, a0, 4); // dsll t0, a0, 4 // c->sw(a3, 128, a2); // sw a3, 128(a2) sadr = c->sgpr64(a3); diff --git a/game/overlord/common/dma.cpp b/game/overlord/common/dma.cpp new file mode 100644 index 0000000000..2c866450cb --- /dev/null +++ b/game/overlord/common/dma.cpp @@ -0,0 +1,35 @@ +#include "dma.h" + +#include "game/sce/iop.h" + +using namespace iop; + +// note that jak 1 and 2 have different implementations, but we make them both instant. +// jak 2 has an EE dma semaphore, but we're going to ignore that. + +/*! + * Wait for an ongoing DMA transfer to finish. + * IOP DMAs are instant in this version, so we return immediately and clear dmaid. + */ +void DMA_Sync() {} + +/*! + * Start DMA transfer to the EE. + */ +void DMA_SendToEE(void* data, u32 size, void* dest) { + // finish previous DMA + DMA_Sync(); + + sceSifDmaData cmd; // DMA settings + + // setup command + cmd.mode = 0; + cmd.data = data; + cmd.addr = dest; + cmd.size = size; + + // start DMA (with disabled interrupts) + CpuDisableIntr(); + sceSifSetDma(&cmd, 1); + CpuEnableIntr(); +} \ No newline at end of file diff --git a/game/overlord/common/dma.h b/game/overlord/common/dma.h new file mode 100644 index 0000000000..9409d6f0de --- /dev/null +++ b/game/overlord/common/dma.h @@ -0,0 +1,6 @@ +#pragma once + +#include "common/common_types.h" + +void DMA_SendToEE(void* data, u32 size, void* dest); +void DMA_Sync(); diff --git a/game/overlord/common/fake_iso.cpp b/game/overlord/common/fake_iso.cpp new file mode 100644 index 0000000000..cbbeac333b --- /dev/null +++ b/game/overlord/common/fake_iso.cpp @@ -0,0 +1,153 @@ +/*! + * @file fake_iso.cpp + * This provides an implementation of IsoFs for reading a "fake iso". + * A "fake iso" is just a map file which maps 8.3 ISO file names to files in the source folder. + * This way we don't need to actually create an ISO. + * + * The game has this compilation unit, but there is nothing in it. Probably it is removed to save + * IOP memory and was only included on TOOL-only builds. So this is my interpretation of how it + * should work. + */ + +#include "fake_iso.h" + +#include + +#include "common/log/log.h" +#include "common/util/Assert.h" +#include "common/util/FileUtil.h" + +#include "game/common/overlord_common.h" +#include "game/overlord/common/isocommon.h" +#include "game/overlord/common/overlord.h" +#include "game/overlord/common/sbank.h" +#include "game/overlord/common/soundcommon.h" +#include "game/overlord/common/srpc.h" +#include "game/runtime.h" +#include "game/sce/iop.h" +#include "game/sound/sndshim.h" + +using namespace iop; + +/*! + * Map from iso file name to file path in the src folder. + */ +struct FakeIsoEntry { + char iso_name[16]; + char file_path[128]; +}; + +FakeIsoEntry fake_iso_entries[MAX_ISO_FILES]; //! List of all known files +static FileRecord sFiles[MAX_ISO_FILES]; //! List of "FileRecords" for IsoFs API consumers +u32 fake_iso_entry_count; //! Total count of fake iso files + +void fake_iso_init_globals() { + // init file lists + memset(fake_iso_entries, 0, sizeof(fake_iso_entries)); + memset(sFiles, 0, sizeof(sFiles)); + + fake_iso_entry_count = 0; +} + +/*! + * Initialize the file system. + */ +int fake_iso_FS_Init() { + for (const auto& f : fs::directory_iterator(file_util::get_jak_project_dir() / "out" / + game_version_names[g_game_version] / "iso")) { + if (f.is_regular_file()) { + ASSERT(fake_iso_entry_count < MAX_ISO_FILES); + FakeIsoEntry* e = &fake_iso_entries[fake_iso_entry_count]; + std::string file_name = f.path().filename().string(); + ASSERT(file_name.length() < 16); // should be 8.3. + strcpy(e->iso_name, file_name.c_str()); + strcpy(e->file_path, + fmt::format("out/{}/iso/{}", game_version_names[g_game_version], file_name).c_str()); + fake_iso_entry_count++; + } + } + + for (u32 i = 0; i < fake_iso_entry_count; i++) { + MakeISOName(sFiles[i].name, fake_iso_entries[i].iso_name); + // we don't figure out the size yet. + // this is so you can change the file without restarting the game. + sFiles[i].size = -1; + // repurpose "location" as the index. + sFiles[i].location = i; + } + + LoadMusicTweaks(); + + return 0; +} + +/*! + * Find a file on the disc and return a FileRecord. + * Find using a "normal" 8.3 name. + * This is an ISO FS API Function + */ +FileRecord* FS_Find(const char* name) { + char name_buff[16]; + MakeISOName(name_buff, name); + return FS_FindIN(name_buff); +} + +/*! + * Find a file on the disc. Uses the "ISO name" of the file, which is different from the normal 8.3 + * name. This can be generated with MakeISOFile. + * This is an ISO FS API Function. + */ +FileRecord* FS_FindIN(const char* iso_name) { + const uint32_t* buff = (const uint32_t*)iso_name; + uint32_t count = 0; + while (count < fake_iso_entry_count) { + const uint32_t* ref = (uint32_t*)sFiles[count].name; + if (ref[0] == buff[0] && ref[1] == buff[1] && ref[2] == buff[2]) { + return sFiles + count; + } + count++; + } + printf("[FAKEISO] failed to find %s\n", iso_name); + return nullptr; +} + +/*! + * Build a full file path for a FileRecord. + */ +const char* get_file_path(FileRecord* fr) { + ASSERT(fr->location < fake_iso_entry_count); + static char path_buffer[1024]; + strcpy(path_buffer, file_util::get_jak_project_dir().string().c_str()); + strcat(path_buffer, "/"); + strcat(path_buffer, fake_iso_entries[fr->location].file_path); + return path_buffer; +} + +/*! + * Determine the length of a file. This isn't very fast, but nobody checks file sizes extremely + * quickly. This is an ISO FS API Function + */ +uint32_t FS_GetLength(FileRecord* fr) { + const char* path = get_file_path(fr); + file_util::assert_file_exists(path, "fake_iso FS_GetLength"); + FILE* fp = file_util::open_file(path, "rb"); + ASSERT(fp); + fseek(fp, 0, SEEK_END); + uint32_t len = ftell(fp); + rewind(fp); + fclose(fp); + return len; +} + +void LoadMusicTweaks() { + char tweakname[16]; + MakeISOName(tweakname, "TWEAKVAL.MUS"); + auto file = FS_FindIN(tweakname); + if (file) { + auto fp = file_util::open_file(get_file_path(file), "rb"); + fread(&gMusicTweakInfo, sizeof(gMusicTweakInfo), 1, fp); + fclose(fp); + } else { + gMusicTweakInfo.TweakCount = 0; + } +} diff --git a/game/overlord/fake_iso.h b/game/overlord/common/fake_iso.h similarity index 68% rename from game/overlord/fake_iso.h rename to game/overlord/common/fake_iso.h index 20c403b9ee..d772c6b71b 100644 --- a/game/overlord/fake_iso.h +++ b/game/overlord/common/fake_iso.h @@ -11,12 +11,13 @@ * should work. */ -#ifndef JAK_V2_FAKE_ISO_H -#define JAK_V2_FAKE_ISO_H - #include "isocommon.h" void fake_iso_init_globals(); -extern IsoFs fake_iso; - -#endif // JAK_V2_FAKE_ISO_H +int fake_iso_FS_Init(); +const char* get_file_path(FileRecord* fr); +FileRecord* FS_Find(const char* name); +FileRecord* FS_FindIN(const char* iso_name); +uint32_t FS_GetLength(FileRecord* fr); +void LoadMusicTweaks(); +extern u32 fake_iso_entry_count; diff --git a/game/overlord/common/iso.cpp b/game/overlord/common/iso.cpp new file mode 100644 index 0000000000..ba48b77ed7 --- /dev/null +++ b/game/overlord/common/iso.cpp @@ -0,0 +1,56 @@ +#include "iso.h" + +#include + +#include "common/util/Assert.h" + +#include "game/common/dgo_rpc_types.h" +#include "game/overlord/common/fake_iso.h" +#include "game/overlord/common/iso_api.h" +#include "game/overlord/jak1/dma.h" +#include "game/overlord/jak1/iso.h" +#include "game/overlord/jak1/ssound.h" +#include "game/overlord/jak1/stream.h" +#include "game/overlord/jak2/iso.h" +#include "game/overlord/jak2/stream.h" +#include "game/runtime.h" +#include "game/sce/iop.h" + +using namespace iop; + +static constexpr s32 LOOP_END = 1; +static constexpr s32 LOOP_REPEAT = 2; +static constexpr s32 LOOP_START = 4; + +// Empty ADPCM block with loop flags + +// clang-format off +u8 VAG_SilentLoop[0x60] = { + 0x0, LOOP_START | LOOP_REPEAT, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, LOOP_REPEAT, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, LOOP_END | LOOP_REPEAT, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; +// clang-format on + +void iso_init_globals() { + // memset(&gVagDir, 0, sizeof(gVagDir)); +} + +/*! + * Does the messagebox have a message in it? + */ +u32 LookMbx(s32 mbx) { + MsgPacket* msg_packet; + return PollMbx((&msg_packet), mbx) != KE_MBOX_NOMSG; +} + +/*! + * Wait for a messagebox to have a message. This is inefficient and polls with a 100 us wait. + * This is stupid because the IOP does have much better syncronization primitives so you don't have + * to do this. + */ +void WaitMbx(s32 mbx) { + while (!LookMbx(mbx)) { + DelayThread(100); + } +} diff --git a/game/overlord/common/iso.h b/game/overlord/common/iso.h new file mode 100644 index 0000000000..2399279d2c --- /dev/null +++ b/game/overlord/common/iso.h @@ -0,0 +1,11 @@ +#pragma once + +#include "common/common_types.h" +#include "common/versions/versions.h" + +#include "game/overlord/common/isocommon.h" + +void iso_init_globals(); +u32 LookMbx(s32 mbx); +void WaitMbx(s32 mbx); +extern u8 VAG_SilentLoop[0x60]; diff --git a/game/overlord/common/iso_api.cpp b/game/overlord/common/iso_api.cpp new file mode 100644 index 0000000000..57228d30e6 --- /dev/null +++ b/game/overlord/common/iso_api.cpp @@ -0,0 +1,6 @@ +#include "iso_api.h" + +#include "common/log/log.h" + +#include "game/overlord/common/iso.h" +#include "game/sce/iop.h" diff --git a/game/overlord/common/iso_api.h b/game/overlord/common/iso_api.h new file mode 100644 index 0000000000..8d6ffa84a4 --- /dev/null +++ b/game/overlord/common/iso_api.h @@ -0,0 +1,3 @@ +#pragma once + +#include "game/overlord/common/isocommon.h" diff --git a/game/overlord/common/isocommon.cpp b/game/overlord/common/isocommon.cpp new file mode 100644 index 0000000000..0879f0b6dc --- /dev/null +++ b/game/overlord/common/isocommon.cpp @@ -0,0 +1,49 @@ +#include "isocommon.h" + +void MakeISOName(char* dst, const char* src) { + int i = 0; + const char* src_ptr = src; + char* dst_ptr = dst; + + // copy name and upper case + while ((i < 8) && (*src_ptr) && (*src_ptr != '.')) { + char c = *src_ptr; + src_ptr++; + if (('`' < c) && (c < '{')) { // lower case + c -= 0x20; + } + *dst_ptr = c; + dst_ptr++; + i++; + } + + // pad out name with spaces + while (i < 8) { + *dst_ptr = ' '; + dst_ptr++; + i++; + } + + // increment past period + if (*src_ptr == '.') + src_ptr++; + + // same for extension + while (i < 11 && (*src_ptr)) { + char c = *src_ptr; + src_ptr++; + if (('`' < c) && (c < '{')) { // lower case + c -= 0x20; + } + *dst_ptr = c; + dst_ptr++; + i++; + } + + while (i < 11) { + *dst_ptr = ' '; + dst_ptr++; + i++; + } + *dst_ptr = 0; +} diff --git a/game/overlord/common/isocommon.h b/game/overlord/common/isocommon.h new file mode 100644 index 0000000000..94eef076fd --- /dev/null +++ b/game/overlord/common/isocommon.h @@ -0,0 +1,38 @@ +#pragma once + +#include "common/common_types.h" +#include "common/link_types.h" + +// was 350 in jak 1, 641 in jak 2, no reason not to go higher +constexpr int MAX_ISO_FILES = 999; // maximum files on FS +// was 16 in jak 1, 32 in jak 2. no reason not to increase for jak 1. +constexpr int MAX_OPEN_FILES = 32; // maximum number of open files at a time. + +constexpr u32 CMD_STATUS_READ_ERR = 8; // read encountered a problem or was canceled. +constexpr u32 CMD_STATUS_NULL_CB = 7; // status returned if you don't set a callback +constexpr u32 CMD_STATUS_FAILED_TO_OPEN = 6; // status if file couldn't be opened +constexpr u32 CMD_STATUS_FAILED_TO_QUEUE = 2; // status if we couldn't be queued +constexpr u32 CMD_STATUS_IN_PROGRESS = 0xffffffff; // status if command is running and healthy +constexpr u32 CMD_STATUS_DONE = 0; // status if command is done. + +constexpr int LOAD_TO_EE_CMD_ID = 0x100; // command to load file to ee +constexpr int LOAD_TO_IOP_CMD_ID = 0x101; // command to load to iop +constexpr int LOAD_TO_EE_OFFSET_CMD_ID = 0x102; // command to load file to ee with offset. + +constexpr int LOAD_DGO_CMD_ID = 0x200; // command to load DGO + +struct SoundBank; + +/*! + * Record for file. There is one for each file in the FS, and pointers to each FileRecord act as + * an identifier. + * The location/size can't be counted on to be anything meaningful as it depends on the IsoFs + * implementation being used. + */ +struct FileRecord { + char name[12]; + uint32_t location; + uint32_t size; +}; + +void MakeISOName(char* dst, const char* src); diff --git a/game/overlord/common/overlord.cpp b/game/overlord/common/overlord.cpp new file mode 100644 index 0000000000..c7f55c35a9 --- /dev/null +++ b/game/overlord/common/overlord.cpp @@ -0,0 +1,9 @@ +#include "overlord.h" + +/*! + * Loop endlessly and never return. + */ +void ExitIOP() { + while (true) { + } +} diff --git a/game/overlord/common/overlord.h b/game/overlord/common/overlord.h new file mode 100644 index 0000000000..ff276ac022 --- /dev/null +++ b/game/overlord/common/overlord.h @@ -0,0 +1,3 @@ +#pragma once + +void ExitIOP(); diff --git a/game/overlord/sbank.cpp b/game/overlord/common/sbank.cpp similarity index 100% rename from game/overlord/sbank.cpp rename to game/overlord/common/sbank.cpp diff --git a/game/overlord/sbank.h b/game/overlord/common/sbank.h similarity index 100% rename from game/overlord/sbank.h rename to game/overlord/common/sbank.h diff --git a/game/overlord/soundcommon.cpp b/game/overlord/common/soundcommon.cpp similarity index 100% rename from game/overlord/soundcommon.cpp rename to game/overlord/common/soundcommon.cpp diff --git a/game/overlord/soundcommon.h b/game/overlord/common/soundcommon.h similarity index 62% rename from game/overlord/soundcommon.h rename to game/overlord/common/soundcommon.h index affe166300..edc71c2e3a 100644 --- a/game/overlord/soundcommon.h +++ b/game/overlord/common/soundcommon.h @@ -1,13 +1,9 @@ #pragma once -#ifndef JAK_V2_SOUNDCOMMON_H -#define JAK_V2_SOUNDCOMMON_H #include "common/common_types.h" -#include "game/overlord/sbank.h" +#include "game/overlord/common/sbank.h" void strcpy_toupper(char* dest, const char* source); void PrintBankInfo(SoundBank* buffer); void ReadBankSoundInfo(SoundBank* bank, SoundBank* unk, s32 unk2); - -#endif // JAK_V2_SOUNDCOMMON_H diff --git a/game/overlord/common/srpc.cpp b/game/overlord/common/srpc.cpp new file mode 100644 index 0000000000..b14e3d3343 --- /dev/null +++ b/game/overlord/common/srpc.cpp @@ -0,0 +1,24 @@ +#include "srpc.h" + +#include + +// added +u32 gMusicFadeHack = 0; +MusicTweaks gMusicTweakInfo; +s32 gMusicTweak = 0x80; +int32_t gSoundEnable = 1; +s32 gMusic = 0; +s32 gMusicPause = 0; +s32 gSoundInUse = 0; +u8 gFPS = 60; +u32 gFrameNum = 0; +const char* gLanguage = nullptr; + +void srpc_init_globals() { + gMusicFadeHack = 0; + gSoundEnable = 1; + gMusic = 0; + gMusicPause = 0; + gSoundInUse = 0; + memset((void*)&gMusicTweakInfo, 0, sizeof(gMusicTweakInfo)); +} diff --git a/game/overlord/common/srpc.h b/game/overlord/common/srpc.h new file mode 100644 index 0000000000..1a1543e68c --- /dev/null +++ b/game/overlord/common/srpc.h @@ -0,0 +1,126 @@ +#pragma once +#include "common/common_types.h" + +#include "game/overlord/common/ssound.h" + +// added for PC port +extern u32 gMusicFadeHack; + +constexpr int MUSIC_TWEAK_COUNT = 32; + +struct MusicTweaks { + u32 TweakCount; + + struct { + char MusicName[12]; + s32 VolumeAdjust; + } MusicTweak[MUSIC_TWEAK_COUNT]; +}; + +struct SoundRpcGetIrxVersion { + u32 major; + u32 minor; + u32 ee_addr; +}; + +struct SoundRpcBankCommand { + u8 pad[12]; + char bank_name[16]; +}; + +struct SoundRpcSetLanguageCommand { + u32 langauge_id; // game_common_types.h, Language +}; + +struct SoundRpcPlayCommand { + u32 sound_id; + u32 pad[2]; + char name[16]; + SoundParams parms; +}; + +struct SoundRpcSetParamCommand { + u32 sound_id; + SoundParams parms; + s32 auto_time; + s32 auto_from; +}; + +struct SoundRpcSoundIdCommand { + u32 sound_id; +}; + +struct SoundRpcSetFlavaCommand { + u8 flava; +}; + +struct SoundRpcSetReverb { + u8 core; + s32 reverb; + u32 left; + u32 right; +}; + +struct SoundRpcSetEarTrans { + Vec3w ear_trans; + Vec3w cam_trans; + s32 cam_angle; +}; + +struct SoundRpc2SetEarTrans { + Vec3w ear_trans1; + Vec3w ear_trans0; + Vec3w cam_trans; + s32 cam_angle; +}; + +struct SoundRpcSetFPSCommand { + u8 fps; +}; + +struct SoundRpcSetFallof { + u8 pad[12]; + char name[16]; + s32 curve; + s32 min; + s32 max; +}; + +struct SoundRpcSetFallofCurve { + s32 curve; + s32 falloff; + s32 ease; +}; + +struct SoundRpcGroupCommand { + u8 group; +}; + +struct SoundRpcMasterVolCommand { + SoundRpcGroupCommand group; + s32 volume; +}; + +struct SoundRpcStereoMode { + s32 stereo_mode; +}; + +struct SoundRpcSetMidiReg { + s32 reg; + s32 value; +}; + +struct SoundRpcSetMirrror { + u8 value; +}; + +extern s32 gMusicTweak; +extern MusicTweaks gMusicTweakInfo; +extern int32_t gSoundEnable; +extern s32 gMusic; +extern s32 gMusicPause; +extern s32 gSoundInUse; +extern u8 gFPS; +extern const char* gLanguage; +extern u32 gFrameNum; +void srpc_init_globals(); \ No newline at end of file diff --git a/game/overlord/ssound.cpp b/game/overlord/common/ssound.cpp similarity index 74% rename from game/overlord/ssound.cpp rename to game/overlord/common/ssound.cpp index 90603892ee..756bcbc974 100644 --- a/game/overlord/ssound.cpp +++ b/game/overlord/common/ssound.cpp @@ -1,37 +1,21 @@ #include "ssound.h" -#include #include -#include "common/util/Assert.h" - -#include "game/overlord/iso.h" -#include "game/overlord/srpc.h" #include "game/runtime.h" #include "game/sound/sndshim.h" -using namespace iop; - +s32 gMusicFade = 0; +s32 gSema; Sound gSounds[64]; -Curve gCurve[16]; -VolumePair gPanTable[361]; - Vec3w gEarTrans[2]; Vec3w gCamTrans; -s32 gCamAngle; - -s32 gMusicVol = 0x400; -s32 gMusicFade = 0; s32 gMusicFadeDir = 0; - -u32 gStreamSRAM = 0; -u32 gTrapSRAM = 0; - +Curve gCurve[16]; +s32 gCamAngle; u8 gMirrorMode = 0; +u32 sLastTick = 0; -s32 gSema; - -static u32 sLastTick; static s32 sqrt_table[256] = { 0, 4096, 5793, 7094, 8192, 9159, 10033, 10837, 11585, 12288, 12953, 13585, 14189, 14768, 15326, 15864, 16384, 16888, 17378, 17854, 18318, 18770, 19212, 19644, 20066, 20480, @@ -69,98 +53,9 @@ static s32 atan_table[257] = { 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, 44, 45, }; -void CatalogSRAM() {} - -static void* SndMemAlloc(); -static void SndMemFree(void* ptr); -void InitSound_Overlord() { - for (auto& s : gSounds) { - s.id = 0; - } - - if (g_game_version == GameVersion::Jak1) { - SetCurve(1, 0, 0); - SetCurve(2, 4096, 0); - SetCurve(3, 0, 4096); - SetCurve(4, 2048, 0); - SetCurve(5, 2048, 2048); - SetCurve(6, -4096, 0); - SetCurve(7, -2048, 0); - } else { - SetCurve(2, 0, 0); - SetCurve(9, 0, 0); - SetCurve(11, 0, 0); - SetCurve(10, 0, 0); - SetCurve(3, 4096, 0); - SetCurve(4, 0, 4096); - SetCurve(5, 2048, 0); - SetCurve(6, 2048, 2048); - SetCurve(7, -4096, 0); - SetCurve(8, -2048, 0); - } - - snd_StartSoundSystem(); - snd_RegisterIOPMemAllocator(SndMemAlloc, SndMemFree); - snd_LockVoiceAllocator(1); - u32 voice = snd_ExternVoiceAlloc(2, 0x7f); - snd_UnlockVoiceAllocator(); - - // The voice allocator returns a number in the range 0-47 where voices - // 0-23 are on SPU Core 0 and 24-47 are on core 2. - // For some reason we convert it to this format where 0-47 alternate core every step. - voice = voice / 24 + ((voice % 24) * 2); - - // Allocate SPU RAM for our streams. - // (Which we don't need on PC) - gStreamSRAM = snd_SRAMMalloc(0xc030); - gTrapSRAM = gStreamSRAM + 0xC000; - - snd_SetMixerMode(0, 0); - - for (int i = 0; i < 8; i++) { - snd_SetGroupVoiceRange(i, 0x10, 0x2f); - } - - snd_SetGroupVoiceRange(1, 0, 0xf); - snd_SetGroupVoiceRange(2, 0, 0xf); - - snd_SetReverbDepth(SND_CORE_0 | SND_CORE_1, 0, 0); - snd_SetReverbType(SND_CORE_0, SD_REV_MODE_OFF); - snd_SetReverbType(SND_CORE_1, SD_REV_MODE_OFF); - - CatalogSRAM(); - - for (int i = 0; i < 91; i++) { - s16 opposing_front = static_cast(((i * 0x33ff) / 0x5a) + 0xc00); - - s16 rear_right = static_cast(((i * -0x2800) / 0x5a) + 0x3400); - s16 rear_left = static_cast(((i * -0xbff) / 0x5a) + 0x3fff); - - gPanTable[90 - i].left = 0x3FFF; - gPanTable[180 - i].left = opposing_front; - gPanTable[270 - i].left = rear_right; - gPanTable[360 - i].left = rear_left; - - gPanTable[i].right = opposing_front; - gPanTable[90 + i].right = 0x3FFF; - gPanTable[180 + i].right = rear_left; - gPanTable[270 + i].right = rear_right; - } - - snd_SetPanTable((s16*)gPanTable); - snd_SetPlayBackMode(2); - - SemaParam sema; - sema.attr = SA_THPRI; - sema.init_count = 1; - sema.max_count = 1; - sema.option = 0; - - gSema = CreateSema(&sema); - if (gSema < 0) { - while (true) - ; - } +void ssound_init_globals() { + gMusicFade = 0; + gSema = 0; } Sound* LookupSound(s32 id) { @@ -198,37 +93,65 @@ void CleanSounds() { } } -void KillSoundsInGroup(u8 group) { - for (auto& s : gSounds) { - if (s.id != 0) { - s32 sndid = snd_SoundIsStillPlaying(s.sound_handle); - s.sound_handle = sndid; +s32 CalculateAngle(Vec3w* trans) { + s32 diffX = gCamTrans.x - trans->x; + s32 diffZ = gCamTrans.z - trans->z; + s32 angle; - if (sndid == 0) { - s.id = 0; - } else if (s.params.group & group) { - snd_StopSound(s.sound_handle); - s.id = 0; + s32 lookupX = diffX; + s32 lookupZ = diffZ; + + if (diffX < 0) { + lookupX = trans->x - gCamTrans.x; + } + + if (diffZ < 0) { + lookupZ = trans->z - gCamTrans.z; + } + + if (lookupX == 0 && lookupZ == 0) { + return 0; + } + + if (lookupZ >= lookupX) { + angle = atan_table[(lookupX << 8) / lookupZ]; + + if (diffZ >= 0) { + if (diffX < 0) { + angle = 360 - angle; } + } else if (diffX >= 0) { + angle = 180 - angle; + } else { + angle += 180; + } + } else { + angle = atan_table[(lookupZ << 8) / lookupX]; + + if (diffX >= 0) { + if (diffZ >= 0) { + angle = 90 - angle; + } else { + angle = angle + 90; + } + } else if (diffZ >= 0) { + angle = angle + 270; + } else { + angle = 270 - angle; } } + + angle = (angle - gCamAngle + 720) % 360; + + if (gMirrorMode) { + angle = ((180 - angle) + 180) % 360; + } + + return angle; } -Sound* AllocateSound() { - for (auto& s : gSounds) { - if (s.id == 0) { - return &s; - } - } - - CleanSounds(); - for (auto& s : gSounds) { - if (s.id == 0) { - return &s; - } - } - - return nullptr; +s32 GetPan(Sound* sound) { + return CalculateAngle(&sound->params.trans); } s32 CalculateFallofVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 fo_max) { @@ -350,73 +273,56 @@ s32 CalculateFallofVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 return ret; } -s32 CalculateAngle(Vec3w* trans) { - s32 diffX = gCamTrans.x - trans->x; - s32 diffZ = gCamTrans.z - trans->z; - s32 angle; - - s32 lookupX = diffX; - s32 lookupZ = diffZ; - - if (diffX < 0) { - lookupX = trans->x - gCamTrans.x; - } - - if (diffZ < 0) { - lookupZ = trans->z - gCamTrans.z; - } - - if (lookupX == 0 && lookupZ == 0) { - return 0; - } - - if (lookupZ >= lookupX) { - angle = atan_table[(lookupX << 8) / lookupZ]; - - if (diffZ >= 0) { - if (diffX < 0) { - angle = 360 - angle; - } - } else if (diffX >= 0) { - angle = 180 - angle; - } else { - angle += 180; - } - } else { - angle = atan_table[(lookupZ << 8) / lookupX]; - - if (diffX >= 0) { - if (diffZ >= 0) { - angle = 90 - angle; - } else { - angle = angle + 90; - } - } else if (diffZ >= 0) { - angle = angle + 270; - } else { - angle = 270 - angle; - } - } - - angle = (angle - gCamAngle + 720) % 360; - - if (gMirrorMode) { - angle = ((180 - angle) + 180) % 360; - } - - return angle; -} - s32 GetVolume(Sound* sound) { return CalculateFallofVolume(&sound->params.trans, sound->params.volume, sound->params.fo_curve, sound->params.fo_min, sound->params.fo_max); } -s32 GetPan(Sound* sound) { - return CalculateAngle(&sound->params.trans); +void UpdateVolume(Sound* sound) { + s32 id = snd_SoundIsStillPlaying(sound->sound_handle); + sound->sound_handle = id; + if (sound->sound_handle == 0) { + sound->id = 0; + } else { + s32 volume = GetVolume(sound); + snd_SetSoundVolPan(id, volume, -2); + } } -static void UpdateLocation(Sound* sound) { +Sound* AllocateSound() { + for (auto& s : gSounds) { + if (s.id == 0) { + return &s; + } + } + + CleanSounds(); + for (auto& s : gSounds) { + if (s.id == 0) { + return &s; + } + } + + return nullptr; +} + +void KillSoundsInGroup(u8 group) { + for (auto& s : gSounds) { + if (s.id != 0) { + s32 sndid = snd_SoundIsStillPlaying(s.sound_handle); + s.sound_handle = sndid; + + if (sndid == 0) { + s.id = 0; + } else if (s.params.group & group) { + snd_StopSound(s.sound_handle); + s.id = 0; + } + } + } +} + +void UpdateLocation(Sound* sound) { if (sound->id == 0) { return; } @@ -442,7 +348,7 @@ static void UpdateLocation(Sound* sound) { } } -static void UpdateAutoVol(Sound* sound, s32 ticks) { +void UpdateAutoVol(Sound* sound, s32 ticks) { if (ticks < sound->auto_time) { s32 nvol = sound->new_volume; if (nvol == -4) { @@ -483,39 +389,6 @@ static void UpdateAutoVol(Sound* sound, s32 ticks) { sound->auto_time = 0; } -void UpdateVolume(Sound* sound) { - s32 id = snd_SoundIsStillPlaying(sound->sound_handle); - sound->sound_handle = id; - if (sound->sound_handle == 0) { - sound->id = 0; - } else { - s32 volume = GetVolume(sound); - snd_SetSoundVolPan(id, volume, -2); - } -} - -void SetEarTrans(Vec3w* ear_trans0, Vec3w* ear_trans1, Vec3w* cam_trans, s32 cam_angle) { - s32 tick = snd_GetTick(); - u32 delta = tick - sLastTick; - sLastTick = tick; - - gEarTrans[0] = *ear_trans0; - gEarTrans[1] = *ear_trans1; - gCamTrans = *cam_trans; - gCamAngle = cam_angle; - - for (auto& s : gSounds) { - if (s.id != 0 && s.is_music == 0) { - if (s.auto_time != 0) { - UpdateAutoVol(&s, delta); - } - UpdateLocation(&s); - } - } - - SetVAGVol(); -} - void PrintActiveSounds() { char string[64]; @@ -549,17 +422,3 @@ void SetCurve(s32 curve, s32 falloff, s32 ease) { gCurve[curve].unk3 = ease - falloff - 0x1000; gCurve[curve].unk4 = 0x1000; } - -void SetMusicVol() { - s32 volume = (gMusicVol * gMusicFade >> 0x10) * gMusicTweak >> 7; - snd_SetMasterVolume(1, volume); - snd_SetMasterVolume(2, volume); -} - -// Do we even need/want these -// TODO void SetBufferMem() {} -// TODO void ReleaseBufferMem() {} -static void* SndMemAlloc() { - return nullptr; -} -static void SndMemFree(void* /*ptr*/) {} diff --git a/game/overlord/ssound.h b/game/overlord/common/ssound.h similarity index 73% rename from game/overlord/ssound.h rename to game/overlord/common/ssound.h index 7fdf4e0b40..1693541969 100644 --- a/game/overlord/ssound.h +++ b/game/overlord/common/ssound.h @@ -1,25 +1,17 @@ #pragma once -#ifndef JAK_V2_SSOUND_H -#define JAK_V2_SSOUND_H +#include "common/common_types.h" -#include "sbank.h" +#include "game/overlord/common/sbank.h" -#include "game/sce/iop.h" +extern s32 gMusicFade; +extern s32 gSema; +extern s32 gMusicFadeDir; struct VolumePair { s16 left; s16 right; }; -extern s32 gSema; -extern s32 gMusicFade; -extern s32 gMusicFadeDir; -extern s32 gMusicVol; -extern VolumePair gPanTable[361]; -extern u32 gStreamSRAM; -extern u32 gTrapSRAM; -extern u8 gMirrorMode; - struct Vec3w { s32 x; s32 y; @@ -58,18 +50,25 @@ struct Curve { s32 unk4; }; -void InitSound_Overlord(); -void SetCurve(s32 curve, s32 fallof, s32 ease); -void SetEarTrans(Vec3w* ear_trans1, Vec3w* ear_trans2, Vec3w* cam_trans, s32 cam_angle); -void KillSoundsInGroup(u8 group); -void PrintActiveSounds(); -void SetMusicVol(); +extern Sound gSounds[64]; +extern Vec3w gEarTrans[2]; +extern Curve gCurve[16]; +extern Vec3w gCamTrans; +extern u8 gMirrorMode; +extern s32 gCamAngle; +extern u32 sLastTick; + +void ssound_init_globals(); + Sound* LookupSound(s32 id); Sound* AllocateSound(); -void UpdateVolume(Sound* sound); s32 GetVolume(Sound* sound); -s32 GetPan(Sound* sound); +void UpdateVolume(Sound* sound); s32 CalculateFallofVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 fo_max); +s32 GetPan(Sound* sound); s32 CalculateAngle(Vec3w* trans); - -#endif // JAK_V2_SSOUND_H +void KillSoundsInGroup(u8 group); +void UpdateLocation(Sound* sound); +void UpdateAutoVol(Sound* sound, s32 ticks); +void PrintActiveSounds(); +void SetCurve(s32 curve, s32 fallof, s32 ease); diff --git a/game/overlord/dma.cpp b/game/overlord/dma.cpp deleted file mode 100644 index 3164927408..0000000000 --- a/game/overlord/dma.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/*! - * @file dma.cpp - * DMA Related functions for Overlord. - * This code is not great. - */ - -#include "dma.h" - -#include -#include - -#include "common/common_types.h" - -#include "game/sce/iop.h" -#include "game/sound/sdshim.h" -#include "game/sound/sndshim.h" - -using namespace iop; - -u32 dmaid; // ID of in-progress DMA. 0 if no DMA in progress -sceSifDmaData cmd; // DMA settings -u32 strobe; // ?? mysterious sound DMA flag. - -void dma_init_globals() { - dmaid = 0; - memset(&cmd, 0, sizeof(cmd)); - strobe = 0; -} - -/*! - * Wait for an ongoing DMA transfer to finish. - * IOP DMAs are instant in this version, so we return immediately and clear dmaid. - */ -void DMA_Sync() { - // The DMA is complete. Clear dmaid. - dmaid = 0; - - // for fun, the original code - // if(dmaid != 0) { - // if(sceSifDmaStat(dmaid) > 0) { - // u32 count = 10000; - // while(sceSifDmaStat(dmaid) > 0) { - // DelayThread(10); - // count--; - // if(count == 0) { - // u32 count = 10000; - // } - // } - // } - // - // // better do that again, just to be sure i did it the first time. - // u32 count = 10000; - // while(sceSifDmaStat(dmaid) > 0) { - // DelayThread(10); - // count--; - // if(count == 0) { - // u32 count = 10000; - // } - // } - // dmaid = 0; - // } -} - -/*! - * Start DMA transfer to the EE. - */ -void DMA_SendToEE(void* data, u32 size, void* dest) { - // finish previous DMA - DMA_Sync(); - - // setup command - cmd.mode = 0; - cmd.data = data; - cmd.addr = dest; - cmd.size = size; - - // start DMA (with disabled interrupts) - CpuDisableIntr(); - dmaid = sceSifSetDma(&cmd, 1); - CpuEnableIntr(); - - if (dmaid == 0) { - do { - printf("Got a bad DMA ID!\n"); // added - } while (true); - } -} - -/*! - * SPU DMA interrupt handler. - - */ -s32 intr(s32 /*channel*/, void* /*userdata*/) { - strobe = 1; - return 0; -} - -bool DMA_SendToSPUAndSync(void* src_addr, u32 size, u32 dst_addr) { - s32 channel = snd_GetFreeSPUDMA(); - if (channel == -1) - return false; - strobe = 0; - sceSdSetTransIntrHandler(channel, intr, nullptr); - // Skip this, we end up memcpy's from OOB (which trips asan) - // u32 size_aligned = (size + 63) & 0xFFFFFFF0; - u32 size_aligned = size; - u32 transferred = sceSdVoiceTrans(channel, 0, src_addr, dst_addr, size_aligned); - while (!strobe) - ; - sceSdSetTransIntrHandler(channel, nullptr, nullptr); - snd_FreeSPUDMA(channel); - return transferred >= size_aligned; -} diff --git a/game/overlord/fake_iso.cpp b/game/overlord/fake_iso.cpp deleted file mode 100644 index a7e107f9b9..0000000000 --- a/game/overlord/fake_iso.cpp +++ /dev/null @@ -1,444 +0,0 @@ -/*! - * @file fake_iso.cpp - * This provides an implementation of IsoFs for reading a "fake iso". - * A "fake iso" is just a map file which maps 8.3 ISO file names to files in the source folder. - * This way we don't need to actually create an ISO. - * - * The game has this compilation unit, but there is nothing in it. Probably it is removed to save - * IOP memory and was only included on TOOL-only builds. So this is my interpretation of how it - * should work. - */ - -#if defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#elif defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif - -#include "fake_iso.h" - -#include - -#include "isocommon.h" -#include "overlord.h" - -#include "common/log/log.h" -#include "common/util/Assert.h" -#include "common/util/FileUtil.h" - -#include "game/overlord/sbank.h" -#include "game/overlord/soundcommon.h" -#include "game/overlord/srpc.h" -#include "game/runtime.h" -#include "game/sce/iop.h" -#include "game/sound/sndshim.h" - -using namespace iop; - -IsoFs fake_iso; - -/*! - * Map from iso file name to file path in the src folder. - */ -struct FakeIsoEntry { - char iso_name[16]; - char file_path[128]; -}; - -static LoadStackEntry sLoadStack[MAX_OPEN_FILES]; //! List of all files that are "open" -FakeIsoEntry fake_iso_entries[MAX_ISO_FILES]; //! List of all known files -static FileRecord sFiles[MAX_ISO_FILES]; //! List of "FileRecords" for IsoFs API consumers -u32 fake_iso_entry_count; //! Total count of fake iso files -static LoadStackEntry* sReadInfo; // LoadStackEntry for currently reading file - -static int FS_Init(u8* buffer); -static FileRecord* FS_Find(const char* name); -static FileRecord* FS_FindIN(const char* iso_name); -static uint32_t FS_GetLength(FileRecord* fr); -static LoadStackEntry* FS_Open(FileRecord* fr, int32_t offset); -static LoadStackEntry* FS_OpenWad(FileRecord* fr, int32_t offset); -static void FS_Close(LoadStackEntry* fd); -static uint32_t FS_BeginRead(LoadStackEntry* fd, void* buffer, int32_t len); -static uint32_t FS_SyncRead(); -static uint32_t FS_LoadSoundBank(char*, void*); -static uint32_t FS_LoadMusic(char*, void*); - -static uint32_t FS_LoadSoundBank2(char*, void*); -static uint32_t FS_LoadMusic2(char*, void*); - -static void FS_PollDrive(); -static void LoadMusicTweaks(); - -void fake_iso_init_globals() { - // init file lists - memset(fake_iso_entries, 0, sizeof(fake_iso_entries)); - memset(sFiles, 0, sizeof(sFiles)); - memset(sLoadStack, 0, sizeof(sLoadStack)); - fake_iso_entry_count = 0; - - // init API struct - fake_iso.init = FS_Init; - fake_iso.find = FS_Find; - fake_iso.find_in = FS_FindIN; - fake_iso.get_length = FS_GetLength; - fake_iso.open = FS_Open; - fake_iso.open_wad = FS_OpenWad; - fake_iso.close = FS_Close; - fake_iso.begin_read = FS_BeginRead; - fake_iso.sync_read = FS_SyncRead; - fake_iso.poll_drive = FS_PollDrive; - - if (g_game_version == GameVersion::Jak1) { - fake_iso.load_sound_bank = FS_LoadSoundBank; - fake_iso.load_music = FS_LoadMusic; - } else { - fake_iso.load_sound_bank = FS_LoadSoundBank2; - fake_iso.load_music = FS_LoadMusic2; - } - - sReadInfo = nullptr; -} - -/*! - * Initialize the file system. - */ -int FS_Init(u8* buffer) { - (void)buffer; - - for (const auto& f : fs::directory_iterator(file_util::get_jak_project_dir() / "out" / - game_version_names[g_game_version] / "iso")) { - if (f.is_regular_file()) { - ASSERT(fake_iso_entry_count < MAX_ISO_FILES); - FakeIsoEntry* e = &fake_iso_entries[fake_iso_entry_count]; - std::string file_name = f.path().filename().string(); - ASSERT(file_name.length() < 16); // should be 8.3. - strcpy(e->iso_name, file_name.c_str()); - strcpy(e->file_path, - fmt::format("out/{}/iso/{}", game_version_names[g_game_version], file_name).c_str()); - fake_iso_entry_count++; - } - } - - for (u32 i = 0; i < fake_iso_entry_count; i++) { - MakeISOName(sFiles[i].name, fake_iso_entries[i].iso_name); - // we don't figure out the size yet. - // this is so you can change the file without restarting the game. - sFiles[i].size = -1; - // repurpose "location" as the index. - sFiles[i].location = i; - } - - LoadMusicTweaks(); - - return 0; -} - -/*! - * Find a file on the disc and return a FileRecord. - * Find using a "normal" 8.3 name. - * This is an ISO FS API Function - */ -FileRecord* FS_Find(const char* name) { - char name_buff[16]; - MakeISOName(name_buff, name); - return FS_FindIN(name_buff); -} - -/*! - * Find a file on the disc. Uses the "ISO name" of the file, which is different from the normal 8.3 - * name. This can be generated with MakeISOFile. - * This is an ISO FS API Function. - */ -FileRecord* FS_FindIN(const char* iso_name) { - const uint32_t* buff = (const uint32_t*)iso_name; - uint32_t count = 0; - while (count < fake_iso_entry_count) { - const uint32_t* ref = (uint32_t*)sFiles[count].name; - if (ref[0] == buff[0] && ref[1] == buff[1] && ref[2] == buff[2]) { - return sFiles + count; - } - count++; - } - printf("[FAKEISO] failed to find %s\n", iso_name); - return nullptr; -} - -/*! - * Build a full file path for a FileRecord. - */ -static const char* get_file_path(FileRecord* fr) { - ASSERT(fr->location < fake_iso_entry_count); - static char path_buffer[1024]; - strcpy(path_buffer, file_util::get_jak_project_dir().string().c_str()); - strcat(path_buffer, "/"); - strcat(path_buffer, fake_iso_entries[fr->location].file_path); - return path_buffer; -} - -/*! - * Determine the length of a file. This isn't very fast, but nobody checks file sizes extremely - * quickly. This is an ISO FS API Function - */ -uint32_t FS_GetLength(FileRecord* fr) { - const char* path = get_file_path(fr); - file_util::assert_file_exists(path, "fake_iso FS_GetLength"); - FILE* fp = file_util::open_file(path, "rb"); - ASSERT(fp); - fseek(fp, 0, SEEK_END); - uint32_t len = ftell(fp); - rewind(fp); - fclose(fp); - return len; -} - -/*! - * Open a file by putting it on the load stack. - * Set the offset to 0 or -1 if you do not want to have an offset. - * This is an ISO FS API Function - */ -LoadStackEntry* FS_Open(FileRecord* fr, int32_t offset) { - lg::debug("[OVERLORD] FS Open {}", fr->name); - LoadStackEntry* selected = nullptr; - // find first unused spot on load stack. - for (uint32_t i = 0; i < MAX_OPEN_FILES; i++) { - if (!sLoadStack[i].fr) { - selected = sLoadStack + i; - selected->fr = fr; - selected->location = 0; - if (offset != -1) { - selected->location += offset; - } - return selected; - } - } - lg::warn("[OVERLORD] Failed to FS Open {}", fr->name); - ExitIOP(); - return nullptr; -} - -/*! - * Open a file by putting it on the load stack. - * Like Open, but allows an offset of -1 to be applied. - * This is an ISO FS API Function - */ -LoadStackEntry* FS_OpenWad(FileRecord* fr, int32_t offset) { - lg::debug("[OVERLORD] FS_OpenWad {}", fr->name); - LoadStackEntry* selected = nullptr; - for (uint32_t i = 0; i < MAX_OPEN_FILES; i++) { - if (!sLoadStack[i].fr) { - selected = sLoadStack + i; - selected->fr = fr; - selected->location = offset; - return selected; - } - } - lg::warn("[OVERLORD] Failed to FS_OpenWad {}", fr->name); - ExitIOP(); - return nullptr; -} - -/*! - * Close an open file. - * This is an ISO FS API Function - */ -void FS_Close(LoadStackEntry* fd) { - lg::debug("[OVERLORD] FS_Close {} @ {}/{}", fd->fr->name, fd->fr->location, fd->location); - - // close the FD - fd->fr = nullptr; - if (fd == sReadInfo) { - sReadInfo = nullptr; - } -} - -/*! - * Begin reading! Returns FS_READ_OK on success (always) - * This is an ISO FS API Function - * - * Idea: do the fopen in FS_Open and keep the file open? It would be faster. - */ -uint32_t FS_BeginRead(LoadStackEntry* fd, void* buffer, int32_t len) { - ASSERT(fd->fr->location < fake_iso_entry_count); - - int32_t real_size = len; - if (len < 0) { - // not sure what this is about... - lg::warn("[OVERLORD ISO CD] Negative length warning!"); - real_size = len + 0x7ff; - } - - u32 sectors = real_size / SECTOR_SIZE; - real_size = sectors * SECTOR_SIZE; - u32 offset_into_file = SECTOR_SIZE * fd->location; - - const char* path = get_file_path(fd->fr); - FILE* fp = file_util::open_file(path, "rb"); - if (!fp) { - lg::error("[OVERLORD] fake iso could not open the file \"{}\"", path); - } - ASSERT(fp); - fseek(fp, 0, SEEK_END); - uint32_t file_len = ftell(fp); - rewind(fp); - - if (offset_into_file < file_len) { - if (offset_into_file) { - fseek(fp, offset_into_file, SEEK_SET); - } - - if (offset_into_file + real_size > file_len) { - real_size = (file_len - offset_into_file); - } - - if (fread(buffer, real_size, 1, fp) != 1) { - ASSERT(false); - } - } - - if (len < 0) { - len = len + 0x7ff; - } - - fd->location += (len / SECTOR_SIZE); - sReadInfo = fd; - - fclose(fp); - - return CMD_STATUS_IN_PROGRESS; -} - -/*! - * Block until read completes. - */ -uint32_t FS_SyncRead() { - // FS_BeginRead is blocking, so this is useless. - if (sReadInfo) { - sReadInfo = nullptr; - return CMD_STATUS_IN_PROGRESS; - } else { - return CMD_STATUS_READ_ERR; - } -} - -/*! - * Poll drive - */ -void FS_PollDrive() {} - -uint32_t FS_LoadMusic(char* name, void* buffer) { - s32* bank_handle = (s32*)buffer; - char namebuf[16]; - strcpy(namebuf, name); - namebuf[8] = 0; - strcat(namebuf, ".mus"); - auto file = FS_Find(namebuf); - if (!file) - return CMD_STATUS_FAILED_TO_OPEN; - - *bank_handle = snd_BankLoadEx(get_file_path(file), 0, 0, 0); - snd_ResolveBankXREFS(); - - return 0; -} - -uint32_t FS_LoadSoundBank(char* name, void* buffer) { - SoundBank* bank = (SoundBank*)buffer; - char namebuf[16]; - - int offset = 10 * 2048; - if (bank->sound_count == 101) { - offset = 1 * 2048; - } - - strcpy(namebuf, name); - namebuf[8] = 0; - strcat(namebuf, ".sbk"); - - auto file = FS_Find(namebuf); - if (!file) { - file = FS_Find("empty1.sbk"); - if (!file) // Might have no files when running tests. - return 0; - } - - auto fp = file_util::open_file(get_file_path(file), "rb"); - fread(buffer, offset, 1, fp); - fclose(fp); - - s32 handle = snd_BankLoadEx(get_file_path(file), offset, 0, 0); - snd_ResolveBankXREFS(); - PrintBankInfo(bank); - bank->bank_handle = handle; - - return 0; -} - -uint32_t FS_LoadMusic2(char* name, void* buffer) { - FileRecord* file = nullptr; - u32* bank_handle = (u32*)buffer; - char namebuf[16]; - char isoname[16]; - u32 handle; - - strncpy(namebuf, name, 12); - namebuf[8] = 0; - strcat(namebuf, ".mus"); - - MakeISOName(isoname, namebuf); - - file = FS_FindIN(isoname); - if (!file) { - return 6; - } - - handle = snd_BankLoadEx(get_file_path(file), 0, 0xcfcc0, 0x61a80); - snd_ResolveBankXREFS(); - *bank_handle = handle; - - return 0; -} - -uint32_t FS_LoadSoundBank2(char* name, void* buffer) { - SoundBank* bank = (SoundBank*)buffer; - FileRecord* file = nullptr; - char namebuf[16]; - char isoname[16]; - u32 handle; - - strncpy(namebuf, name, 12); - namebuf[8] = 0; - strcat(namebuf, ".sbk"); - - MakeISOName(isoname, namebuf); - file = FS_FindIN(isoname); - if (!file) { - return 6; - } - - handle = snd_BankLoadEx(get_file_path(file), 0, bank->spu_loc, bank->spu_size); - snd_ResolveBankXREFS(); - bank->bank_handle = handle; - - return 0; -} - -void LoadMusicTweaks() { - char tweakname[16]; - MakeISOName(tweakname, "TWEAKVAL.MUS"); - auto file = FS_FindIN(tweakname); - if (file) { - auto fp = file_util::open_file(get_file_path(file), "rb"); - fread(&gMusicTweakInfo, sizeof(gMusicTweakInfo), 1, fp); - fclose(fp); - } else { - gMusicTweakInfo.TweakCount = 0; - } -} - -#if defined(__GNUC__) -#pragma GCC diagnostic pop -#elif defined(__clang__) -#pragma clang diagnostic pop -#endif diff --git a/game/overlord/iso_cd.cpp b/game/overlord/iso_cd.cpp deleted file mode 100644 index 17ca97acbf..0000000000 --- a/game/overlord/iso_cd.cpp +++ /dev/null @@ -1,990 +0,0 @@ -/*! - * @file iso_cd.cpp - * IsoFs API for accessing the CD/DVD drive. - */ - -#include "iso_cd.h" - -#include - -#include "isocommon.h" -#include "overlord.h" -#include "soundcommon.h" -#include "srpc.h" - -#include "common/log/log.h" - -#include "game/sce/iop.h" -#include "game/sce/stubs.h" - -// iso_cd is an implementation of the IsoFs API for loading files from a CD/DVD with an ISO and/or -// DUP filesystem. -// The DUP filesystem is a custom Naughty Dog filesystem which attempts to hide -// files. The DUP filesystem also stores all files twice on the disk and will try reading from the -// other copy if it reading the first copy encounters errors. The DUP filesystem is unused. - -using namespace iop; -typedef int (*mmode_func)(int); - -// Drive State -// sector to read from (for DUP files, sector of the first copy of the file) -u32 _sector; -// number of sectors to read -u32 _sectors; -// number of retries in the current read -u32 _retries; -// buffer to read into -void* _buffer; -// set to 0 or 1 to indicate if the first or second copy of DUP files should be used. -uint32_t _dupseg; -// the actual sector to read from (differs from _sector when reading second copy of DUP file) -uint32_t _real_sector; -// set 1 if the current read was continuous from the previous read (didn't require a seek) -uint32_t _continuous; -// time when the current read was started -SysClock _starttime; -// time when the current read has ended -SysClock _endtime; - -// Globals -u32 gDirtyCd; // set when we're waiting on a read which has errors -u32 gNoCD; // set when we believe the game disc has been removed. -static u32 sNumFiles; // number of files (includes both ISO and DUP files) -static u32 sArea1; // Sector where the first copy of DUP files live. -static u32 sAreaDiff; // Sectors in between the first and second copy of files. - -u32 pirated; // do we think the game is pirated? -mmode_func cdmmode = nullptr; // function to call to set the expected media (CD/DVD) -static sceCdRMode sNominalMode; // drive settings for "nominal" reading -static sceCdRMode sStreamMode; // drive settings for "streaming" reading -static sceCdRMode* sMode; // pointer to currently selected read mode -static LoadStackEntry* sReadInfo; // LoadStackEntry for currently reading file -static u8* sSecBuffer[3]; // Buffers for a single sector -u32 add_files; // Should we add files we discover to the sFiles list? -static FileRecord sFiles[MAX_ISO_FILES]; // Info for all files on the disc -u32 CD_ID_SectorNum; // Sector of the DISK.ID file -s32 CD_ID_Sector[SECTOR_SIZE / 4]; // Contents of the DISK.ID file -s32 CD_ID_SectorSum; // Sum of the CD_ID_SECTOR array -LoadStackEntry sLoadStack[MAX_OPEN_FILES]; // List of all files that are "open" -static u32 sound_bank_loads; // might be a static variable in a function? -IsoFs iso_cd_; // IsoFs function pointers - -constexpr int TIME_SIZE = 16; // how many samples for read timing -s32 _times[TIME_SIZE]; // read timing data -s32 _timesix; -s32 _tsamps[2]; -s32 _tkps[2]; - -s32 gLastSpeed; -s32 gDiskSpeed[2]; -s32 gDupSeg; - -u32 ReadU32(u8* buffer); -u32 ReadSectorsNow(uint32_t sector, uint32_t len, void* buffer); -u32 ReadDirectory(uint32_t sector, uint32_t size, uint32_t secBufID); -void DecodeDUP(u8* buffer); -void LoadMusicTweaks(u8* buffer); -void LoadDiscID(); -u32 CheckDiscID(); -void SetRealSector(); -void CD_WaitReturn(); - -static int FS_Init(u8* buffer); -static FileRecord* FS_Find(const char* name); -static FileRecord* FS_FindIN(const char* iso_name); -static uint32_t FS_GetLength(FileRecord* fr); -static LoadStackEntry* FS_Open(FileRecord* fr, int32_t offset); -static LoadStackEntry* FS_OpenWad(FileRecord* fr, int32_t offset); -static void FS_Close(LoadStackEntry* fd); -static uint32_t FS_BeginRead(LoadStackEntry* fd, void* buffer, int32_t len); -static uint32_t FS_SyncRead(); -static uint32_t FS_LoadSoundBank(char*, void*); -static uint32_t FS_LoadMusic(char*, void*); -static void FS_PollDrive(); - -void iso_cd_init_globals() { - _sector = 0; - _sectors = 0; - _retries = 0; - gDirtyCd = 0; - gNoCD = 0; - _dupseg = 0; - _real_sector = 0; - _continuous = 0; - _buffer = nullptr; - memset(&_starttime, 0, sizeof(SysClock)); - memset(&_endtime, 0, sizeof(SysClock)); - - sNumFiles = 0; - sArea1 = 0; - sAreaDiff = 0; - - pirated = 0; - cdmmode = nullptr; - - sNominalMode.trycount = 0; - sNominalMode.spindlctrl = 1; - sNominalMode.datapattern = 0; - sNominalMode.pad = 0; - - sStreamMode.trycount = 0xf; - sStreamMode.spindlctrl = 0; - sStreamMode.datapattern = 0; - sStreamMode.pad = 0; - - sMode = &sStreamMode; - sReadInfo = nullptr; - - memset(sSecBuffer, 0, sizeof(sSecBuffer)); - add_files = 0; - memset(sFiles, 0, sizeof(sFiles)); - - CD_ID_SectorNum = 0; - memset(CD_ID_Sector, 0, sizeof(CD_ID_Sector)); - CD_ID_SectorSum = 0; - memset(sLoadStack, 0, sizeof(sLoadStack)); - sound_bank_loads = 0; - - iso_cd_.init = FS_Init; - iso_cd_.find = FS_Find; - iso_cd_.find_in = FS_FindIN; - iso_cd_.get_length = FS_GetLength; - iso_cd_.open = FS_Open; - iso_cd_.open_wad = FS_OpenWad; - iso_cd_.close = FS_Close; - iso_cd_.begin_read = FS_BeginRead; - iso_cd_.sync_read = FS_SyncRead; - iso_cd_.load_sound_bank = FS_LoadSoundBank; - iso_cd_.load_music = FS_LoadMusic; - iso_cd_.poll_drive = FS_PollDrive; - - memset(_times, 0, sizeof(_times)); - memset(_tsamps, 0, sizeof(_tsamps)); - memset(_tkps, 0, sizeof(_tkps)); - _timesix = 0; - - memset(gDiskSpeed, 0, sizeof(gDiskSpeed)); - gLastSpeed = 0; - gDupSeg = 0; -} - -/*! - * Read unaligned uint32_t from buffer. ISO file systems may have 32-bit values that aren't word - * aligned. DONE, EXACT - */ -uint32_t ReadU32(u8* data) { - return (uint32_t)data[0] + (((uint32_t)data[1]) * 0x100) + (((uint32_t)data[2]) * 0x10000) + - (((uint32_t)data[3]) * 0x1000000); -} - -/*! - * Read from disc, immediately (blocking), into a local buffer. Will retry if needed, setting - * gDirtyCd. This does not use the DUP file system or drive state, so this should not be used - * outside of initialization. Will clear gDirtyCd on successful read. Returns 1 on success, 0 on - * sceCdRead failure, or otherwise retries forever until sceCdGetError is OK. - * The length is in terms of sectors. - * DONE, EXACT - */ -u32 ReadSectorsNow(uint32_t sector, uint32_t len, void* buffer) { - // reset the sector state to break any continuous reads in progress - _sector = 0; - - // retry loop for read - while (true) { - // Start async read from DVD... - if (sceCdRead(sector, len, buffer, sMode) == 0) { - // if this fails, it indicates catastrophic failure of the DVD drive, so give up immediately. - return 0; - } - - // Wait for read to finish (0x00 is blocking) - sceCdSync(0); - - // check for error - if (sceCdGetError() == 0) { - // no error, we are good! - break; - } - // we got an error. Try again, and set a dirty flag so the EE knows we're having trouble - gDirtyCd = 1; - } - - // success! clear the dirty flag and return! - gDirtyCd = 0; - return 1; -} - -/*! - * Read ISO file systems directory tree, adding files to the filerecord table if add_files is set. - * Regardless of add_files is not set, it will be set for folders under NAUGHTY.DOG. - * This feature is used on demos with multiple games and Jak is in the NAUGHTY.DOG folder. - * Recursively walks the tree. - * There is a stack of single sector buffers used to recursively read the directories. - * Returns 1 on success and 0 on failure. - * Running out of sector buffers because of too many nested folders is considered success? - * DONE - */ -u32 ReadDirectory(uint32_t sector, uint32_t size, uint32_t secBufID) { - if (secBufID < 3) { - // grab our buffer from the stack - u8* buffer = sSecBuffer[secBufID]; - - uint32_t lsector = sector; - int32_t lsize = size; - - // loop over sector reads - while (lsize > 0) { - // ISO low-level read - if (!ReadSectorsNow(lsector, 1, buffer)) { - lg::info("[OVERLORD ISO CD] Failed to read sector in ReadDirectory!"); - return 0; - } - u8* lbuffer = buffer; - - // loop over stuff in the sector - while ((*lbuffer != 0) && (lbuffer < buffer + SECTOR_SIZE)) { - u8 dir_record_size = *lbuffer; - if ((lbuffer[0x21] != 0) && (lbuffer[0x21] != 1)) { // skip over whatever these things are - - uint32_t extent = ReadU32(lbuffer + 2); - uint32_t dir_size = ReadU32(lbuffer + 10); - uint32_t name_len = lbuffer[0x20]; - - bool is_directory = true; - if ((lbuffer[0x1f + name_len] == ';') && (lbuffer[0x20 + name_len] == '1')) { - is_directory = false; - } - - if (is_directory) { - if (!add_files) { - // don't add file by default, but add files if we recurse in the NAUGHTY.DOG folder - if (!memcmp(lbuffer + 0x21, "NAUGHTY.DOG", 0xb)) { - add_files = true; - ReadDirectory(extent, dir_size, secBufID + 1); - add_files = false; - } - } else { - // otherwise just recurse - ReadDirectory(extent, dir_size, secBufID + 1); - } - } else { - if (sNumFiles == MAX_ISO_FILES) { - lg::info("[OVERLORD ISO CD] There are too many files on the disc!"); - return 0; - } - - if (add_files) { - lbuffer[0x1f + name_len] = 0; // null terminate the name - MakeISOName(sFiles[sNumFiles].name, (char*)(lbuffer + 0x21)); - sFiles[sNumFiles].location = extent; - sFiles[sNumFiles].size = dir_size; - sNumFiles++; - } - } - } - lbuffer += dir_record_size; - } - lsector++; - lsize -= 0x800; - } - } else { - lg::info("[OVERLORD ISO CD] ReadDirectory ran out of sector buffers!"); - } - return 1; -} - -struct DupIndexEntry { - // 20 bytes - char name[12]; - u32 location; - u32 size; -}; - -/*! - * DUP code. The DUP files aren't on the disc, so this doesn't do anything. - * This would allow for hidden files that aren't in the standard ISO format, presumably to make - * pirating harder? The DUP files store the location of these hidden files. Also it support having - * two copies of some files. There are two areas, both of which are identical. But it was never - * used. - */ -void DecodeDUP(u8* buffer) { - (void)buffer; - - // set sArea1 to point to an impossibly large sector - if DUP initialization fails this means no - // file will be in the DUP zones. - sArea1 = 0x7fffffff; - - char iso_name[16]; - // all three of these will fail. - MakeISOName(iso_name, "Z1INDEX.DUP"); - FileRecord* index_file = FS_FindIN(iso_name); - MakeISOName(iso_name, "Z3AREA1.DUP"); - FileRecord* area1_file = FS_FindIN(iso_name); - MakeISOName(iso_name, "Z5AREA2.DUP"); - FileRecord* area2_file = FS_FindIN(iso_name); - - // Note - this reads 4 sectors, but the buffer only has enough room for 3 sectors. - // So this code would likely cause a crash if it was run. - // Maybe this is why it was removed? - // Or maybe there used to be 4 init buffers, but one was removed once they gave up on DUP? - if (index_file && area1_file && area2_file && ReadSectorsNow(index_file->location, 4, buffer)) { - sArea1 = area1_file->location; // marks start of 1st zone - sAreaDiff = area2_file->location - area1_file->location; // difference between zones - - // make sure we have enough room to store all entries - if (sNumFiles + *(s32*)(buffer) <= MAX_ISO_FILES) { - // read entries - DupIndexEntry* dup_entries = (DupIndexEntry*)(((u8*)buffer) + 4); - for (int i = 0; i < *(s32*)(buffer); i++) { - *(s32*)(&sFiles[sNumFiles].name) = *(s32*)(&dup_entries[i].name); - *(s32*)(&sFiles[sNumFiles].name + 4) = *(s32*)(&dup_entries[i].name + 4); - *(s32*)(&sFiles[sNumFiles].name + 8) = *(s32*)(&dup_entries[i].name + 8); - sFiles[sNumFiles].size = dup_entries[i].size; - sFiles[sNumFiles].location = dup_entries[i].location; - sNumFiles++; - } - } - } -} - -/*! - * Load the TWEAKVAL.MUS file into the gMusicTweakInfo file. - * Only works if the file is less than 1 sector long. - * If loading fails, writes a 0 to the first 32-bits of gMusicTweakInfo - * @param buffer a sector buffer which will be used - */ -void LoadMusicTweaks(u8* buffer) { - char iso_name[16]; - MakeISOName(iso_name, "TWEAKVAL.MUS"); - FileRecord* fr = FS_FindIN(iso_name); - if (!fr || !ReadSectorsNow(fr->location, 1, buffer)) { - gMusicTweakInfo.TweakCount = 0; - lg::warn("[OVERLORD ISO CD] Failed to load music tweaks!"); - } else { - memcpy((void*)&gMusicTweakInfo, buffer, sizeof(MusicTweaks)); - } -} - -/*! - * Load the DISK ID file and compute the sum. - * This is used as a checksum to make sure the disc is correct. - * A literal sum is not a great checksum - * Also, this function name and the file on the disc itself spell dis{c,k} differently. - * - * If there is no DISK_ID.DIZ file, uses whatever is stored at 0x400 instead. - */ -void LoadDiscID() { - char iso_name[16]; - MakeISOName(iso_name, "DISK_ID.DIZ"); - FileRecord* fr = FS_FindIN(iso_name); - if (!fr) { - lg::warn( - "[OVERLORD ISO CD] LoadDiscID failed to find DISK_ID.DIZ, using sector 0x400 instead!"); - CD_ID_SectorNum = 0x400; - } else { - CD_ID_SectorNum = fr->location; - } - - ReadSectorsNow(CD_ID_SectorNum, 1, &CD_ID_Sector); - CD_ID_SectorSum = 0; - for (uint32_t i = 0; i < SECTOR_SIZE / 4; i++) { - CD_ID_SectorSum += CD_ID_Sector[i]; - } - lg::info("[OVERLORD] DISK_ID.DIZ OK 0x{:x}", CD_ID_SectorSum); -} - -/*! - * Verify that the DISK ID file has not changed. Returns 1 if it is good. - */ -u32 CheckDiskID() { - if (ReadSectorsNow(CD_ID_SectorNum, 1, CD_ID_Sector) == 0) { - // failed to read CD ID data - return 0; - } - - int sum = 0; - for (uint32_t i = 0; i < SECTOR_SIZE / 4; i++) { - sum += CD_ID_Sector[i]; - } - return sum == CD_ID_SectorSum; -} - -/*! - * Set _real_sector in preparation for a read, based on the requested _sector. - * This has logic for a system which has a double copy of some data on the disc and can pick between - * two different copies. This selection is done with the dupseg flag. - */ -void SetRealSector() { - // if we are below sArea1, it's not a duplicated file, so ignore the dupseg flag and read directly - if (_sector < sArea1 || _dupseg == 0) { - _real_sector = _sector; - } else { - // it's a duplicated file, and duplicate read is enabled, so get the area 2 sector. - _real_sector = _sector + sAreaDiff; - lg::warn("[OVERLORD] Warning, adjusting real sector in SetRealSector"); - } - - // we suspect the game is pirated, load the wrong sector. - if (pirated) { - _real_sector += 3; - lg::warn("Pirated!"); - } -} - -/*! - * Initialize the ISO CD system and builds file record table. - * This is an ISO_FS API Function. - * Also loads music tweaks/DISK ID - * @param buffer : a buffer larger enough to hold 3 sectors - * this buffer can be freed immediately this returns - * Return 0 on success. - */ -int FS_Init(u8* buffer) { - // determine disk type - int disk_type = SCECdDETCT; - while (disk_type = sceCdGetDiskType(), disk_type == SCECdDETCT) { - // This SleepThread will cause the Overlord initialization to lock up. It's called with an - // argument of 10000, but SleepThread accepts no arguments. Probably they meant to call - // DelayThread. It ends up working because the drive already knows the disk type at this point. - SleepThread(); - } - - // what is this. it's crazy. why? - if (disk_type <= SCECdPS2DVD || disk_type < SCECdCDDA || disk_type <= SCECdDVDV || - disk_type != SCECdIllegalMedia) { - // we are actually using the CD drive, so set the mmode function to the SCE function. - // This is called in FS_LoadMusic. If you call this with the wrong media type, it locks up. - // I guess this is an attempt at making convoluted anti-piracy code so it's harder to find - // calls to sceCdMmode with static analysis. But they left in debug symbols and the variable - // is called "cdmmode", which is not a very sneaky way to hide it! (At least on the EE it's - // called aybabtu and is a GOAL symbol which is way harder to figure out.) Also it seems like - // the primary mode of piracy they were concerned with is somebody swapping a DVD with a CD? - cdmmode = sceCdMmode; - - // verify the disc is a DVD. - sceCdMmode(SCECdDVD); - - // set up sector buffers used for initialization reads. - for (int i = 0; i < 3; i++) { - sSecBuffer[i] = buffer + i * SECTOR_SIZE; - } - - // read primary volume descriptor into buffer - if (!ReadSectorsNow(0x10, 1, sSecBuffer[0])) { - lg::warn("[OVERLORD ISO CD] Failed to read primary volume descriptor"); - return 1; - } - - // check volume descriptor identifier - if (memcmp(sSecBuffer[0] + 1, "CD001", 5)) { - lg::warn("[OVERLORD ISO CD] Got the wrong volume descriptor identifier"); - char* cptr = (char*)sSecBuffer[0] + 1; - printf("%c%c%c%c%c\n", cptr[0], cptr[1], cptr[2], cptr[3], cptr[4]); - return 1; - } - - // read path table into buffer - uint32_t path_table_sector = ReadU32(sSecBuffer[0] + 0x8c); - - if (!ReadSectorsNow(path_table_sector, 1, sSecBuffer[0])) { - lg::warn("[OVERLORD ISO CD] Failed to read path"); - return 1; - } - - // read path table's extent into buffer - uint32_t path_table_extent = ReadU32(sSecBuffer[0] + 2); - - if (!ReadSectorsNow(path_table_extent, 1, sSecBuffer[0])) { - lg::warn("[OVERLORD ISO CD] Failed to read path table extent"); - } - - // read root directory - add_files = true; - uint32_t dir_size = ReadU32(sSecBuffer[0] + 10); - if (!ReadDirectory(path_table_extent, dir_size, 0)) { - lg::warn("[OVERLORD ISO CD] Failed to ReadDirectory"); - return 1; - } - - // load filesystem stuff - DecodeDUP(sSecBuffer[0]); - LoadMusicTweaks(sSecBuffer[0]); - LoadDiscID(); - - // there's some sort of weird loop here over all file that does nothing. - // my guess is its some commented out print thing? - - // empty load stack - for (int i = 0; i < MAX_OPEN_FILES; i++) { - sLoadStack[i].fr = nullptr; - } - - // kill sector buffers - for (int i = 0; i < 3; i++) { - sSecBuffer[i] = nullptr; - } - return 0; - } else { - lg::warn("[OVERLORD ISO CD] Bad Media Type!"); - return 1; - } -} - -/*! - * Find a file on the disc and return a FileRecord. - * This is an ISO FS API Function - */ -FileRecord* FS_Find(const char* name) { - char name_buff[16]; - MakeISOName(name_buff, name); - return FS_FindIN(name_buff); -} - -/*! - * Find a file on the disc. Uses the ISO name of the file. - * This can be generated with MakeISOFile - * This is an ISO FS API Function - * There is a weird anti-piracy thing in here to prevent people from making copies with less than - * 1 GB of data? I guess you could remove the audio in languages you don't care about and put in - * on a CD, and this would block this from happening. - */ -FileRecord* FS_FindIN(const char* iso_name) { - const uint32_t* buff = (const uint32_t*)iso_name; - for (;;) { // this loop will spin forever if you have < 1 GB of files - uint32_t size = 0; // total sum of file sizes - uint32_t count = 0; - while (count < sNumFiles) { - const uint32_t* ref = (uint32_t*)sFiles[count].name; - if (ref[0] == buff[0] && ref[1] == buff[1] && ref[2] == buff[2]) { - return sFiles + count; - } - size += sFiles[count].size; - count++; - } - // if we get here, we haven't found the file, we should return 0 to indicate we don't have it - // however, if we haven't found 1 GB of files after searching the whole thing - // we assume that we've pirated the game and should continue looping - // Note that the game attempts to load DUP files which will fails and will hit this condition. - buff += - 3; // to make this look less suspicious, lets increment buff. also will crash eventually. - if (0x3fffffff < size) { - return nullptr; // we got 1 GB of files, okay to return - } - - // we didn't get 1 GB of files, you're a pirate. - lg::warn("Pirated!"); - } -} - -/*! - * Determine the length of a file. - * This is an ISO FS API Function - */ -uint32_t FS_GetLength(FileRecord* fr) { - return fr->size; -} - -/*! - * Open a file by putting it on the load stack. - * Set the offset to 0 or -1 if you do not want to have an offset. - * This is an ISO FS API Function - */ -LoadStackEntry* FS_Open(FileRecord* fr, int32_t offset) { - lg::info("[OVERLORD] FS Open {}", fr->name); - LoadStackEntry* selected = nullptr; - // find first unused spot on load stack. - for (uint32_t i = 0; i < MAX_OPEN_FILES; i++) { - if (!sLoadStack[i].fr) { - selected = sLoadStack + i; - selected->fr = fr; - selected->location = fr->location; - if (offset != -1) { - selected->location += offset; - } - return selected; - } - } - lg::warn("[OVERLORD ISO CD] Failed to FS_Open {}", fr->name); - ExitIOP(); - return nullptr; -} - -/*! - * Open a file by putting it on the load stack. - * Like Open, but allows an offset of -1 to be applied. - * This is an ISO FS API Function - */ -LoadStackEntry* FS_OpenWad(FileRecord* fr, int32_t offset) { - printf("[OVERLORD] FS Open %s\n", fr->name); - LoadStackEntry* selected = nullptr; - for (uint32_t i = 0; i < MAX_OPEN_FILES; i++) { - if (!sLoadStack[i].fr) { - selected = sLoadStack + i; - selected->fr = fr; - selected->location = fr->location + offset; - return selected; - } - } - lg::warn("[OVERLORD ISO CD] Failed to use FS_OpenWad {}", fr->name); - ExitIOP(); - return nullptr; -} - -/*! - * Close an open file. - * This is an ISO FS API Function - */ -void FS_Close(LoadStackEntry* fd) { - lg::info("[OVERLORD] FS Close {}", fd->fr->name); - if (fd == sReadInfo) { - // the file is currently being read, so lets try to finish out the read, if possible. - int count = 0; - - // the non-blocking sync, so we don't get stuck here on a catastrophic error. - while (sceCdSync(1)) { - DelayThread(1000); // wait 1 ms and allow other stuff to run. - count++; - if (count == 1000) { // waited too long to close this file - sceCdBreak(); // interrupt the read - break; - } - } - sReadInfo = nullptr; - } - - // close the FD - fd->fr = nullptr; -} - -/*! - * Begin reading! Returns FS_READ_OK on success (always) - * This is an ISO FS API Function - */ -uint32_t FS_BeginRead(LoadStackEntry* fd, void* buffer, int32_t len) { - // set the reading state: - // I guess continuous stream buffer reads don't count as continuous? - _continuous = (len == BUFFER_PAGE_SIZE) && (fd->location == (_sector + _sectors)); - _sector = fd->location; - int32_t real_size = len; - if (len < 0) { - // not sure what this is about... - lg::warn("[OVERLORD ISO CD] Negative length warning!"); - real_size = len + 0x7ff; - } - _sectors = real_size >> 11; - _retries = 0; - _buffer = buffer; - GetSystemTime(&_starttime); - - // compute _real_sector - SetRealSector(); - - while (!sceCdRead(_real_sector, _sectors, _buffer, sMode)) { - // error starting the read. this is bad and possibly indicates somebody took the CD out. - // lets wait for the CD to be ready again... - CD_WaitReturn(); - _retries++; - if (_sector >= sArea1) { - // the original file we tried to read is duplicated... - // so lets try reading the other copy of it! - _dupseg = 1 - _dupseg; - _continuous = 0; // mark as noncontinuous read - SetRealSector(); // recompute! - } - } - - // ??? this is strangely set up. - if (len < 0) { - len = len + 0x7ff; - } - - fd->location += (len >> 0xb); - - // set sReadInfo to point to the current read. - sReadInfo = fd; - return CMD_STATUS_IN_PROGRESS; -} - -/*! - * Wait for current read to complete! - * This is an ISO FS API Function - * @return - */ -uint32_t FS_SyncRead() { - // make sure a read is actually in progress - if (!sReadInfo) { - return CMD_STATUS_READ_ERR; - } - - // remember when we start doing a SyncRead. - SysClock now; - GetSystemTime(&now); - - // block and wait for completion - sceCdSync(0); - // remember when we sync. - GetSystemTime(&_endtime); - - // Loop to check if read succeed and start an additional read if not. - while (sceCdGetError()) { - // no, it didn't, lets retry - _retries++; - // toggle dupseg - if (_sector >= sArea1) { - _dupseg = 1 - _dupseg; - _continuous = 0; - SetRealSector(); - } - - // try until a read starts... - while (!sceCdRead(_real_sector, _sectors, _buffer, sMode)) { - // read start failed, possibly CD is removed - CD_WaitReturn(); - // retry! - _retries++; - // toggle dupseg if possible - if (_sector >= sArea1) { - _dupseg = 1 - _dupseg; - _continuous = 0; - SetRealSector(); - } - } - - // read has started - // set dirty cd to indicate we had trouble - gDirtyCd = 1; - // wait for read to finish... - sceCdSync(0); - // if the read/sync fails, the loop will go again. - } - - // Read complete! Mark CD as not dirty and clear active read! - gDirtyCd = 0; - sReadInfo = nullptr; - - // Optionally do some timing checks - // (note that these never run because we don't have DUP files) - // continuous read with no failures from dup zone - // more than half the time spent in FS_SyncRead - // Basically it tries to learn about which segment does worse in "too slow" reads - // by averaging all historical too slow reads. Once the other is winning by a certain amount - // it will swap. It will also swap if there isn't enough samples on one. - if (_retries == 0 && _continuous && _sectors >= sArea1 && - (_endtime.hi - _starttime.hi) / 2 < (_endtime.hi - now.hi)) { - // record the time - _times[_timesix++] = _endtime.hi - _starttime.hi; - - // if we filled the time buffer - if (_timesix == TIME_SIZE) { - // compute total time - s32 total_time = 0; - for (s32 i = 0; i < TIME_SIZE; i++) { - total_time += _times[i]; - } - - // determine read speed - gLastSpeed = 0x69780000 / (total_time >> 4); // todo - work out this constant - - // add to average kps for this seg - if (_tsamps[_dupseg] < 0x40000) { - _tkps[_dupseg] = _tkps[_dupseg] + gLastSpeed; - _tsamps[_dupseg] = _tsamps[_dupseg]; - } - - // average speed of this segment - gDiskSpeed[_dupseg] = _tkps[_dupseg] / _tsamps[_dupseg]; - - _timesix = 0; - - if (_tsamps[0] < 8) { - // not much information about segment 0 - if (_dupseg) { - // and we aren't reading segment 0... - // so let's read segment 0 - _dupseg = 0; - _sector = 0; - } - } else { - // got enough info about segment 0. - if (_tsamps[1] < 8) { - // not enough information about segment 1 - if (!_dupseg) { - // and not reading, so lets read it. - _dupseg = 1; - _sector = 0; - } - } else { - // enough info about both. - if ((_tkps[1] / _tsamps[1] + 0x32) < (_tkps[0] / _tsamps[0])) { - // section 0 wins by at least 0x32, lets use it if we aren't already - if (_dupseg) { - _dupseg = 0; - _sector = 0; - } - } else if ((_tkps[0] / _tsamps[0] + 0x32) < (_tkps[1] / _tsamps[1])) { - if (!_dupseg) { - _dupseg = 1; - _sector = 0; - } - } - } - } - // set our current decision in a global for the EE to read. - gDupSeg = _dupseg; - } - } - return CMD_STATUS_IN_PROGRESS; -} - -/*! - * Load a SoundBank now. Doesn't do any fancy read stuff. - */ -uint32_t FS_LoadSoundBank(char* name, void* buffer) { - char full_name[32]; // may actually be 8, but lets be safe - - // ??? todo this is probably a field of the buffer. - u32 header_size; - if (*(s32*)(((u8*)buffer) + 0x14) == 0x65) { - header_size = 1; - } else { - header_size = 10; - } - - if (strlen(name) > 16) { - printf("[OVERLORD ISO CD] FS_LoadSoundBank has an invalid name!\n"); - } - - // append .sbk - strcpy(full_name, name); - strcat(full_name, ".sbk"); - - FileRecord* fr = FS_Find(full_name); - if (!fr) { - printf("[OVERLORD ISO CD] FS_LoadSoundBank cannot find bank %s, loading empty instead.\n", - full_name); - fr = FS_Find("empty1.sbk"); - } - - // hack to do a read now (the Sound Bank loads bypass all the other fancy loading stuff evidently) - _sector = fr->location; - SetRealSector(); - - // loop until we read header successfully. - // don't set retries or dirty cd - while (!ReadSectorsNow(_real_sector, header_size, buffer)) { - // ReadSectorsNow will only return if the read fails to start. in this case we assume the disc - // was removed: - CD_WaitReturn(); - // we don't increment retries... - if (_sector >= sArea1) { - _dupseg = 1 - _dupseg; - _continuous = 0; - SetRealSector(); - } - } - - // now have the sound library do a load. - // (this time we set dirty cd if it fails, but no retries) - auto load_status = snd_BankLoadByLoc(_real_sector + header_size, 0); - while (!load_status && snd_GetLastLoadError() < 0x100) { - CD_WaitReturn(); - if (_sector >= sArea1) { - _dupseg = 1 - _dupseg; - _continuous = 0; - SetRealSector(); - } - load_status = snd_BankLoadByLoc(_real_sector + header_size, 0); - if (!load_status) { - gDirtyCd = 1; - } - } - gDirtyCd = 0; - - // pirate check sometimes - sound_bank_loads++; - if ((sound_bank_loads & 7) == 0) { - pirated = 1; - // check that one file is past sector 0x80000 (approx 1 GB) - for (u32 i = 0; i < sNumFiles; i++) { - if (sFiles[i].location + (sFiles[i].size >> 11) > 0x80000) { - pirated = 0; - } - } - } - - snd_ResolveBankXREFS(); - PrintBankInfo((SoundBank*)buffer); - _sector = 0; - // ??? todo this is probably a field of the buffer. - *(s32*)(((u8*)buffer) + 0x10) = load_status; - return 0; -} - -/*! - * Load a music file. Load now, doesn't do fancy reading stuff. - */ -uint32_t FS_LoadMusic(char* name, void* buffer) { - char full_name[32]; // may actually be 8, but lets be safe - if (strlen(name) > 16) { - printf("[OVERLORD ISO CD] FS_LoadMusic has an invalid name!\n"); - } - - // append .mus - strcpy(full_name, name); - strcat(full_name, ".mus"); - - FileRecord* fr = FS_Find(full_name); - if (!fr) { - printf("[OVERLORD ISO CD] FS_LoadMusic cannot find bank %s.\n", full_name); - return 6; - } - - _sector = fr->location; - SetRealSector(); - // another "piracy" check to make sure the media is the correct type... - (*cdmmode)(SCECdDVD); - - // now have the sound library do a load. - auto load_status = snd_BankLoadByLoc(_real_sector, 0); - // TODO magic constant 0x100 - while (!load_status && snd_GetLastLoadError() < 0x100) { - CD_WaitReturn(); - if (_sector >= sArea1) { - _dupseg = 1 - _dupseg; - _continuous = 0; - SetRealSector(); - } - load_status = snd_BankLoadByLoc(_real_sector, 0); - if (!load_status) { - gDirtyCd = 1; - } - } - gDirtyCd = 0; - snd_ResolveBankXREFS(); - _sector = 0; - *(s32*)buffer = load_status; - return 0; -} - -/*! - * Make sure the drive is happy. - * NOTE - only call this when the drive should have nothing to do! - */ -void FS_PollDrive() { - if (sceCdDiskReady(1) == SCECdNotReady) { // non-blocking - CD_WaitReturn(); - } -} - -/*! - * Wait for the game CD/DVD to be put back in the playstation. - * Only call this if you think the CD/DVD has been removed, as requires a seek. - */ -void CD_WaitReturn() { - gNoCD = 1; - do { - while (sceCdDiskReady(1) == SCECdNotReady) { - } - } while (!CheckDiskID()); - gNoCD = 0; -} diff --git a/game/overlord/iso_cd.h b/game/overlord/iso_cd.h deleted file mode 100644 index 93545cc501..0000000000 --- a/game/overlord/iso_cd.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -/*! - * @file iso_cd.cpp - * IsoFs API for accessing the CD/DVD drive. - */ - -#ifndef JAK_ISO_CD_H -#define JAK_ISO_CD_H - -#include "iso.h" - -#include "common/common_types.h" - -void iso_cd_init_globals(); -extern IsoFs iso_cd_; - -#endif // JAK_ISO_CD_H diff --git a/game/overlord/isocommon.cpp b/game/overlord/isocommon.cpp deleted file mode 100644 index cfbaa266b7..0000000000 --- a/game/overlord/isocommon.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/*! - * @file isocommon.cpp - * Common ISO utilities. - */ - -#include "isocommon.h" - -#include - -#include "common/common_types.h" -#include "common/util/Assert.h" - -/*! - * Convert file name to "ISO Name" - * ISO names are upper case and 12 bytes long. - * xxxxxxxxyyy0 - * - * x - uppercase letter of file name, or space - * y - uppercase letter of file extension, or space - * 0 - null terminator (\0, not the character zero) - */ -void MakeISOName(char* dst, const char* src) { - int i = 0; - const char* src_ptr = src; - char* dst_ptr = dst; - - // copy name and upper case - while ((i < 8) && (*src_ptr) && (*src_ptr != '.')) { - char c = *src_ptr; - src_ptr++; - if (('`' < c) && (c < '{')) { // lower case - c -= 0x20; - } - *dst_ptr = c; - dst_ptr++; - i++; - } - - // pad out name with spaces - while (i < 8) { - *dst_ptr = ' '; - dst_ptr++; - i++; - } - - // increment past period - if (*src_ptr == '.') - src_ptr++; - - // same for extension - while (i < 11 && (*src_ptr)) { - char c = *src_ptr; - src_ptr++; - if (('`' < c) && (c < '{')) { // lower case - c -= 0x20; - } - *dst_ptr = c; - dst_ptr++; - i++; - } - - while (i < 11) { - *dst_ptr = ' '; - dst_ptr++; - i++; - } - *dst_ptr = 0; -} - -/*! - * Unmakes an ISO name back to the original name. - * Keeps it upper case. - * Not used. - */ -void UnmakeISOName(char* dst, const char* src) { - int i = 0; - const char* src_ptr = src; - char* dst_ptr = dst; - - // copy non-space characters - while ((i < 8) && (*src != ' ')) { - *dst_ptr = *src_ptr; - src_ptr++; - dst_ptr++; - i++; - } - - // skip src to the extension - src_ptr += 8 - i; - - if (*src_ptr != ' ') { - // if there's an extension, add the period - *dst_ptr = '.'; - i = 0; - // copy extension - dst_ptr++; - while (i < 3 && *src_ptr != ' ') { - *dst_ptr = *src_ptr; - src_ptr++; - i++; - } - } - *dst_ptr = 0; -} - -/*! - * Convert an animation name to ISO name. - * The animation name is a bunch of dash separated words. - * The resulting ISO name has the same first two chars as the animation name, and one char from each - * remaining word. Once there are no more words but remaining chars in the ISO name, the ith extra - * char is the i+1 th char of the last word. A word ending in a number (or just a number) is turned - * into the number. The word "resolution" becomes z. The word "accept" becomes y. The word "reject" - * becomes n. Other words become the first char of the word. The result is uppercased and the file - * extension is STR Examples (animation name and disc file name, not ISO name): - * green-sagecage-outro-beat-boss-enough-cells -> GRSOBBEC.STR - * swamp-tetherrock-swamprockexplode-4 -> SWTS4.STR - * minershort-resolution-1-orbs -> MIZ1ORBS.STR - * @param dst - * @param src - */ -void ISONameFromAnimationName(char* dst, const char* src) { - // The Animation Name is a bunch of words separated by dashes - - // copy first two chars of the first word exactly - dst[0] = src[0]; - dst[1] = src[1]; - s32 i = 2; // 2 chars added to dst. - - // skip ahead to the first dash (or \0 if there's no dashes) - const char* src_ptr = src; - while (*src_ptr && *src_ptr != '-') { - src_ptr++; - } - - // the points to the next dash (or \0 if there's none). - const char* next_ptr = src_ptr; - if (*src_ptr) { - // loop over words (next_ptr points to dash before word, i counts chars in dest) - while (src_ptr = next_ptr + 1, i < 8) { - // scan next_ptr forward to next dash - next_ptr = src_ptr; - while (*next_ptr && *next_ptr != '-') { - next_ptr++; - } - - // there's no next word, so break (the current word will be handled there) - if (!*next_ptr) - break; - - // add a char for the current word: - char char_to_add; - if (next_ptr[-1] < '0' || next_ptr[-1] > '9') { - // word doesn't end in a number. - - // some special case words map to special letters (likely to avoid animation name conflicts) - if (next_ptr - src_ptr == 10 && !memcmp(src_ptr, "resolution", 10)) { - // NOTE : jak 2 also allows "res" here but that doesn't work properly. - char_to_add = 'z'; - } else if (next_ptr - src_ptr == 6 && !memcmp(src_ptr, "accept", 6)) { - char_to_add = 'y'; - } else if (next_ptr - src_ptr == 6 && !memcmp(src_ptr, "reject", 6)) { - char_to_add = 'n'; - } else if (next_ptr - src_ptr == 5 && !memcmp(src_ptr, "keira", 5)) { - // NOTE : this was added in jak 2. it's safe to use in jak 1 since she was referred to as - // "assistant" there - char_to_add = 'i'; - } else { - // not a special case, just take the first letter. - char_to_add = *src_ptr; - } - } else { - // the current word ends in a number, just use this number (I think usually the whole word - // is just a number) - char_to_add = next_ptr[-1]; - } - - dst[i++] = char_to_add; - } - - // here we ran out of room in dest, or words in source. - // if there's still room in dest and chars in source, just add them - while (*src_ptr && (i < 8)) { - dst[i] = *src_ptr; - src_ptr++; - i++; - } - } - - // pad with spaces (for ISO Name) - while (i < 8) { - dst[i++] = ' '; - } - - // upper case - for (i = 0; i < 8; i++) { - if (dst[i] > '`' && dst[i] < '{') { - dst[i] -= 0x20; - } - } - - // append file extension - strcpy(dst + 8, "STR"); -} diff --git a/game/overlord/jak1/dma.cpp b/game/overlord/jak1/dma.cpp new file mode 100644 index 0000000000..c20f6846b2 --- /dev/null +++ b/game/overlord/jak1/dma.cpp @@ -0,0 +1,51 @@ +/*! + * @file dma.cpp + * DMA Related functions for Overlord. + * This code is not great. + */ + +#include "dma.h" + +#include +#include + +#include "common/common_types.h" + +#include "game/sce/iop.h" +#include "game/sound/sdshim.h" +#include "game/sound/sndshim.h" + +using namespace iop; + +namespace jak1 { +u32 strobe; // ?? mysterious sound DMA flag. + +void dma_init_globals() { + strobe = 0; +} + +/*! + * SPU DMA interrupt handler. + */ +s32 intr(s32 /*channel*/, void* /*userdata*/) { + strobe = 1; + return 0; +} + +bool DMA_SendToSPUAndSync(void* src_addr, u32 size, u32 dst_addr) { + s32 channel = snd_GetFreeSPUDMA(); + if (channel == -1) + return false; + strobe = 0; + sceSdSetTransIntrHandler(channel, intr, nullptr); + // Skip this, we end up memcpy's from OOB (which trips asan) + // u32 size_aligned = (size + 63) & 0xFFFFFFF0; + u32 size_aligned = size; + u32 transferred = sceSdVoiceTrans(channel, 0, src_addr, dst_addr, size_aligned); + while (!strobe) + ; + sceSdSetTransIntrHandler(channel, nullptr, nullptr); + snd_FreeSPUDMA(channel); + return transferred >= size_aligned; +} +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/dma.h b/game/overlord/jak1/dma.h similarity index 62% rename from game/overlord/dma.h rename to game/overlord/jak1/dma.h index dd390c17c8..da3c72fb92 100644 --- a/game/overlord/dma.h +++ b/game/overlord/jak1/dma.h @@ -6,14 +6,10 @@ * This code is not great. */ -#ifndef JAK_V2_DMA_H -#define JAK_V2_DMA_H - #include "common/common_types.h" -void DMA_Sync(); -void DMA_SendToEE(void* data, u32 size, void* dest); +namespace jak1 { bool DMA_SendToSPUAndSync(void* src_addr, u32 size, u32 dst_addr); void dma_init_globals(); -#endif // JAK_V2_DMA_H +} // namespace jak1 diff --git a/game/overlord/jak1/fake_iso.cpp b/game/overlord/jak1/fake_iso.cpp new file mode 100644 index 0000000000..bbb3b903ff --- /dev/null +++ b/game/overlord/jak1/fake_iso.cpp @@ -0,0 +1,225 @@ +#include "fake_iso.h" + +#include "common/log/log.h" +#include "common/util/Assert.h" +#include "common/util/FileUtil.h" + +#include "game/overlord/common/fake_iso.h" +#include "game/overlord/common/overlord.h" +#include "game/overlord/common/soundcommon.h" +#include "game/overlord/jak1/isocommon.h" +#include "game/sound/sndshim.h" + +namespace jak1 { +IsoFs fake_iso; +LoadStackEntry* FS_Open(FileRecord* fr, int32_t offset); +uint32_t FS_BeginRead(LoadStackEntry* fd, void* buffer, int32_t len); +LoadStackEntry* FS_OpenWad(FileRecord* fr, int32_t offset); +uint32_t FS_LoadSoundBank(char* name, SoundBank* bank); +void FS_PollDrive(); +uint32_t FS_SyncRead(); +uint32_t FS_LoadMusic(char* name, s32* bank_handle); +void FS_Close(LoadStackEntry* fd); +static LoadStackEntry sLoadStack[MAX_OPEN_FILES]; //! List of all files that are "open" +static LoadStackEntry* sReadInfo; // LoadStackEntry for currently reading file + +void fake_iso_init_globals() { + // init API struct + fake_iso.init = fake_iso_FS_Init; + fake_iso.find = FS_Find; + fake_iso.find_in = FS_FindIN; + fake_iso.get_length = FS_GetLength; + fake_iso.open = FS_Open; + fake_iso.open_wad = FS_OpenWad; + fake_iso.close = FS_Close; + fake_iso.begin_read = FS_BeginRead; + fake_iso.sync_read = FS_SyncRead; + fake_iso.poll_drive = FS_PollDrive; + fake_iso.load_sound_bank = FS_LoadSoundBank; + fake_iso.load_music = FS_LoadMusic; + + memset(sLoadStack, 0, sizeof(sLoadStack)); + sReadInfo = nullptr; +} + +/*! + * Open a file by putting it on the load stack. + * Set the offset to 0 or -1 if you do not want to have an offset. + * This is an ISO FS API Function + */ +LoadStackEntry* FS_Open(FileRecord* fr, int32_t offset) { + lg::debug("[OVERLORD] FS Open {}", fr->name); + LoadStackEntry* selected = nullptr; + // find first unused spot on load stack. + for (uint32_t i = 0; i < MAX_OPEN_FILES; i++) { + if (!sLoadStack[i].fr) { + selected = sLoadStack + i; + selected->fr = fr; + selected->location = 0; + + if (offset != -1) { + selected->location += offset; + } + return selected; + } + } + lg::warn("[OVERLORD] Failed to FS Open {}", fr->name); + ExitIOP(); + return nullptr; +} + +/*! + * Open a file by putting it on the load stack. + * Like Open, but allows an offset of -1 to be applied. + * This is an ISO FS API Function + */ +LoadStackEntry* FS_OpenWad(FileRecord* fr, int32_t offset) { + lg::debug("[OVERLORD] FS_OpenWad {}", fr->name); + LoadStackEntry* selected = nullptr; + for (uint32_t i = 0; i < MAX_OPEN_FILES; i++) { + if (!sLoadStack[i].fr) { + selected = sLoadStack + i; + selected->fr = fr; + selected->location = offset; + return selected; + } + } + lg::warn("[OVERLORD] Failed to FS_OpenWad {}", fr->name); + ExitIOP(); + return nullptr; +} + +/*! + * Close an open file. + * This is an ISO FS API Function + */ +void FS_Close(LoadStackEntry* fd) { + lg::debug("[OVERLORD] FS_Close {} @ {}/{}", fd->fr->name, fd->fr->location, fd->location); + + // close the FD + fd->fr = nullptr; + if (fd == sReadInfo) { + sReadInfo = nullptr; + } +} + +/*! + * Begin reading! Returns FS_READ_OK on success (always) + * This is an ISO FS API Function + * + * Idea: do the fopen in FS_Open and keep the file open? It would be faster. + */ +uint32_t FS_BeginRead(LoadStackEntry* fd, void* buffer, int32_t len) { + ASSERT(fd->fr->location < fake_iso_entry_count); + + int32_t real_size = len; + if (len < 0) { + // not sure what this is about... + lg::warn("[OVERLORD ISO CD] Negative length warning!"); + real_size = len + 0x7ff; + } + + u32 sectors = real_size / SECTOR_SIZE; + real_size = sectors * SECTOR_SIZE; + u32 offset_into_file = SECTOR_SIZE * fd->location; + + const char* path = get_file_path(fd->fr); + FILE* fp = file_util::open_file(path, "rb"); + if (!fp) { + lg::error("[OVERLORD] fake iso could not open the file \"{}\"", path); + } + ASSERT(fp); + fseek(fp, 0, SEEK_END); + uint32_t file_len = ftell(fp); + rewind(fp); + + if (offset_into_file < file_len) { + if (offset_into_file) { + fseek(fp, offset_into_file, SEEK_SET); + } + + if (offset_into_file + real_size > file_len) { + real_size = (file_len - offset_into_file); + } + + if (fread(buffer, real_size, 1, fp) != 1) { + ASSERT(false); + } + } + + if (len < 0) { + len = len + 0x7ff; + } + + fd->location += (len / SECTOR_SIZE); + sReadInfo = fd; + + fclose(fp); + + return CMD_STATUS_IN_PROGRESS; +} + +/*! + * Block until read completes. + */ +uint32_t FS_SyncRead() { + // FS_BeginRead is blocking, so this is useless. + if (sReadInfo) { + sReadInfo = nullptr; + return CMD_STATUS_IN_PROGRESS; + } else { + return CMD_STATUS_READ_ERR; + } +} + +/*! + * Poll drive + */ +void FS_PollDrive() {} + +uint32_t FS_LoadMusic(char* name, s32* bank_handle) { + char namebuf[16]; + strcpy(namebuf, name); + namebuf[8] = 0; + strcat(namebuf, ".mus"); + auto file = FS_Find(namebuf); + if (!file) + return CMD_STATUS_FAILED_TO_OPEN; + + *bank_handle = snd_BankLoadEx(get_file_path(file), 0, 0, 0); + snd_ResolveBankXREFS(); + + return 0; +} + +uint32_t FS_LoadSoundBank(char* name, SoundBank* bank) { + char namebuf[16]; + + int offset = 10 * 2048; + if (bank->sound_count == 101) { + offset = 1 * 2048; + } + + strcpy(namebuf, name); + namebuf[8] = 0; + strcat(namebuf, ".sbk"); + + auto file = FS_Find(namebuf); + if (!file) { + file = FS_Find("empty1.sbk"); + if (!file) // Might have no files when running tests. + return 0; + } + + auto fp = file_util::open_file(get_file_path(file), "rb"); + fread(bank, offset, 1, fp); + fclose(fp); + + s32 handle = snd_BankLoadEx(get_file_path(file), offset, 0, 0); + snd_ResolveBankXREFS(); + PrintBankInfo(bank); + bank->bank_handle = handle; + + return 0; +} +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/jak1/fake_iso.h b/game/overlord/jak1/fake_iso.h new file mode 100644 index 0000000000..1cb2468e1b --- /dev/null +++ b/game/overlord/jak1/fake_iso.h @@ -0,0 +1,7 @@ +#pragma once +#include "game/overlord/jak1/isocommon.h" + +namespace jak1 { +void fake_iso_init_globals(); +extern IsoFs fake_iso; +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/iso.cpp b/game/overlord/jak1/iso.cpp similarity index 93% rename from game/overlord/iso.cpp rename to game/overlord/jak1/iso.cpp index 77c34dcf0e..d04df551a4 100644 --- a/game/overlord/iso.cpp +++ b/game/overlord/jak1/iso.cpp @@ -9,10 +9,7 @@ #include #include -#include "dma.h" -#include "fake_iso.h" #include "iso_api.h" -#include "iso_cd.h" #include "iso_queue.h" #include "stream.h" @@ -20,7 +17,12 @@ #include "common/util/Assert.h" #include "game/common/dgo_rpc_types.h" -#include "game/overlord/srpc.h" +#include "game/overlord/common/dma.h" +#include "game/overlord/common/fake_iso.h" +#include "game/overlord/common/iso.h" +#include "game/overlord/jak1/dma.h" +#include "game/overlord/jak1/fake_iso.h" +#include "game/overlord/jak1/srpc.h" #include "game/runtime.h" #include "game/sce/iop.h" #include "game/sound/sdshim.h" @@ -28,6 +30,7 @@ using namespace iop; +namespace jak1 { u32 ISOThread(); u32 DGOThread(); u32 RunDGOStateMachine(IsoMessage* _cmd, IsoBufferHeader* buffer_header); @@ -45,41 +48,11 @@ static s32 GetPlayPos(); static void UpdatePlayPos(); static void VAG_MarkLoopEnd(void* data, u32 size); -constexpr int LOADING_SCREEN_SIZE = 0x800000; -constexpr u32 LOADING_SCREEN_DEST_ADDR = 0x1000000; - -static constexpr s32 LOOP_END = 1; -static constexpr s32 LOOP_REPEAT = 2; -static constexpr s32 LOOP_START = 4; - -// Empty ADPCM block with loop flags -// clang-format off -static u8 VAG_SilentLoop[0x60] = { - 0x0, LOOP_START | LOOP_REPEAT, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, LOOP_REPEAT, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, LOOP_END | LOOP_REPEAT, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -}; -// clang-format on - -IsoFs* isofs; -u32 iso_init_flag; -s32 sync_mbx; -s32 iso_mbx; -s32 dgo_mbx; -s32 iso_thread; -s32 dgo_thread; -s32 str_thread; -s32 play_thread; -VagDirJak2 gVagDir; u32 gPlayPos; -// todo move... -static RPC_Dgo_Cmd sRPCBuff[1]; -DgoCommand scmd; // renamed to sLoadDGO in Jak 2 -// :-) -#define sLoadDGO scmd static VagCommand vag_cmd; VagCommand* gVAGCMD = nullptr; +VagDir gVagDir; s32 gDialogVolume = 0; s32 gFakeVAGClockPaused = 0; s32 gFakeVAGClockRunning = 0; @@ -91,8 +64,20 @@ s32 gPlaying = 0; s32 gSampleRate = 0; bool gLastVagHalf = false; s32 gVoice; +IsoFs* isofs; +u32 iso_init_flag; +s32 sync_mbx; +s32 iso_mbx; +s32 dgo_mbx; +s32 iso_thread; +s32 dgo_thread; +s32 str_thread; +s32 play_thread; +static RPC_Dgo_Cmd sRPCBuff[1]; +DgoCommand sLoadDGO; // renamed from scmd to sLoadDGO in Jak 2 void iso_init_globals() { + gPlayPos = 0; isofs = nullptr; iso_init_flag = 0; sync_mbx = 0; @@ -102,48 +87,22 @@ void iso_init_globals() { dgo_thread = 0; str_thread = 0; play_thread = 0; - memset(&gVagDir, 0, sizeof(gVagDir)); - gPlayPos = 0; memset(sRPCBuff, 0, sizeof(sRPCBuff)); - memset(&scmd, 0, sizeof(DgoCommand)); + memset(&sLoadDGO, 0, sizeof(DgoCommand)); } /*! - * Initialize the ISO Driver. - * Requires a buffer large enough to hold 3 sector (or 4 if you have DUP files) + * Find a file by name. Return nullptr if it fails. */ -static MsgPacket not_on_stack_sync; -void InitDriver(u8* buffer) { - if (!isofs->init(buffer)) { - // succesful init! - iso_init_flag = 0; - } - - // you idiots, you're giving the kernel a pointer to a stack variable! - // (this is fixed in Jak 1 Japan and NTSC Greatest Hits) - // SendMbx(sync_mbx, &msg_packet); - - // whoever fixed that bug felt similarly about it - SendMbx(sync_mbx, ¬_on_stack_sync); +FileRecord* FindISOFile(const char* name) { + return isofs->find(name); } /*! - * Does the messagebox have a message in it? + * Get the length of an ISO File by FileRecord */ -u32 LookMbx(s32 mbx) { - MsgPacket* msg_packet; - return PollMbx((&msg_packet), mbx) != KE_MBOX_NOMSG; -} - -/*! - * Wait for a messagebox to have a message. This is inefficient and polls with a 100 us wait. - * This is stupid because the IOP does have much better syncronization primitives so you don't have - * to do this. - */ -void WaitMbx(s32 mbx) { - while (!LookMbx(mbx)) { - DelayThread(100); - } +u32 GetISOFileLength(FileRecord* f) { + return isofs->get_length(f); } /*! @@ -155,22 +114,16 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) { // isofs = &iso_cd; // ADDED - if (!strcmp(fs_mode, "iso_cd")) { - isofs = &iso_cd_; - } else if (!strcmp(fs_mode, "fakeiso")) { - isofs = &fake_iso; - } else { - printf("[OVERLORD ISO] ISOFS has unknown fs_mode %s\n", fs_mode); - } + isofs = &fake_iso; + (void)fs_mode; // ignore user's request. + // always pick fake_iso because the others are not useful. // END ADDED // mark us as NOT initialized. iso_init_flag = 1; - if (g_game_version == GameVersion::Jak1) { - while (!DMA_SendToSPUAndSync(&VAG_SilentLoop, 0x30, gTrapSRAM)) { - DelayThread(1000); - } + while (!jak1::DMA_SendToSPUAndSync(&VAG_SilentLoop, 0x30, jak1::gTrapSRAM)) { + DelayThread(1000); } // INITIALIZE MESSAGE BOXES @@ -211,7 +164,7 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) { thread_param.initPriority = 100; thread_param.stackSize = 0x1000; thread_param.option = 0; - thread_param.entry = (void*)ISOThread; + thread_param.entry = jak1::ISOThread; strcpy(thread_param.name, "ISOThread"); iso_thread = CreateThread(&thread_param); if (iso_thread <= 0) { @@ -225,7 +178,7 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) { thread_param.initPriority = 98; thread_param.stackSize = 0x800; thread_param.option = 0; - thread_param.entry = (void*)DGOThread; + thread_param.entry = DGOThread; strcpy(thread_param.name, "DGOThread"); dgo_thread = CreateThread(&thread_param); if (dgo_thread <= 0) { @@ -239,7 +192,7 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) { thread_param.initPriority = 97; thread_param.stackSize = 0x800; thread_param.option = 0; - thread_param.entry = (void*)STRThread; + thread_param.entry = jak1::STRThread; strcpy(thread_param.name, "STRThread"); str_thread = CreateThread(&thread_param); if (str_thread <= 0) { @@ -253,7 +206,7 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) { thread_param.initPriority = 97; thread_param.stackSize = 0x800; thread_param.option = 0; - thread_param.entry = (void*)PLAYThread; + thread_param.entry = jak1::PLAYThread; strcpy(thread_param.name, "PLAYThread"); play_thread = CreateThread(&thread_param); if (play_thread <= 0) { @@ -275,13 +228,15 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) { // LOAD VAGDIR file FileRecord* vagdir_file = FindISOFile("VAGDIR.AYB"); if (vagdir_file) { - LoadISOFileToIOP(vagdir_file, &gVagDir, - g_game_version == GameVersion::Jak1 ? sizeof(VagDir) : sizeof(VagDirJak2)); + LoadISOFileToIOP(vagdir_file, &gVagDir, sizeof(gVagDir)); } else { printf("IOP: ======================================================================\n"); printf("IOP : iso InitISOFS : cannot load VAG directory\n"); printf("IOP: ======================================================================\n"); } + + constexpr int LOADING_SCREEN_SIZE = 0x800000; + constexpr u32 LOADING_SCREEN_DEST_ADDR = 0x1000000; FileRecord* loading_screen_file = FindISOFile(loading_screen); if (loading_screen_file) { LoadISOFileToEE(loading_screen_file, LOADING_SCREEN_DEST_ADDR, LOADING_SCREEN_SIZE); @@ -292,33 +247,189 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) { } /*! - * Find a file by name. Return nullptr if it fails. + * Initialize the ISO Driver. + * Requires a buffer large enough to hold 3 sector (or 4 if you have DUP files) */ -FileRecord* FindISOFile(const char* name) { - return isofs->find(name); -} - -/*! - * Get the length of an ISO File by FileRecord - */ -u32 GetISOFileLength(FileRecord* f) { - return isofs->get_length(f); -} - -/*! - * Find VAG file by "name", where name is 8 bytes (chars with spaces at the end, treated as two - * s32's). Returns pointer to name in the VAGDIR file data. - */ -VagDirEntry* FindVAGFile(const char* name) { - VagDirEntry* entry = gVagDir.vag; - for (u32 idx = 0; idx < gVagDir.count; idx++) { - // check if matching name - if (memcmp(entry->name, name, 8) == 0) { - return entry; - } - entry++; +static MsgPacket not_on_stack_sync; +void InitDriver() { + if (!isofs->init()) { + // succesful init! + iso_init_flag = 0; + } + + // you idiots, you're giving the kernel a pointer to a stack variable! + // (this is fixed in Jak 1 Japan and NTSC Greatest Hits) + // SendMbx(sync_mbx, &msg_packet); + + // whoever fixed that bug felt similarly about it + SendMbx(sync_mbx, ¬_on_stack_sync); +} + +void* RPC_DGO(unsigned int fno, void* _cmd, int y); +void LoadDGO(RPC_Dgo_Cmd* cmd); +void LoadNextDGO(RPC_Dgo_Cmd* cmd); +void CancelDGO(RPC_Dgo_Cmd* cmd); + +/*! + * DGO RPC Thread. + */ +u32 DGOThread() { + sceSifQueueData dq; + sceSifServeData serve; + + // setup RPC. + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, DGO_RPC_ID[g_game_version], RPC_DGO, sRPCBuff, nullptr, nullptr, &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + return 0; +} + +/*! + * DGO RPC Handler. + */ +void* RPC_DGO(unsigned int fno, void* _cmd, int y) { + (void)y; + auto* cmd = (RPC_Dgo_Cmd*)_cmd; + // call appropriate handler. + switch (fno) { + case DGO_RPC_LOAD_FNO: + LoadDGO(cmd); + break; + case DGO_RPC_LOAD_NEXT_FNO: + LoadNextDGO(cmd); + break; + case DGO_RPC_CANCEL_FNO: + CancelDGO(cmd); + break; + default: + cmd->result = DGO_RPC_RESULT_ERROR; + } + return cmd; +} + +/*! + * Begin loading a DGO. Returns when the first obj is loaded. + * Then will load the next obj into the second buffer. + * Then the DGO loader will block until LoadNextDGO is called. + * This approach keeps two loads in flight at a time to increase loading throughput. + * One load will be read from DVD / DMA'd to EE + * Another will be linked on the EE. + * The final load is done directly onto the heap, and isn't double buffered + * (otherwise the linking object could allocate on the heap where the final loading object is + * being copied). This avoids having to relocate the data from the temporary load buffer to the + * heap, and is the only way to make sure that the entire heap can be filled. + */ +void LoadDGO(RPC_Dgo_Cmd* cmd) { + // Find the file + FileRecord* fr = isofs->find(cmd->name); + if (!fr) { + cmd->result = DGO_RPC_RESULT_ERROR; + return; + } + + // cancel an in progress command and wait for it to end. + // note - this doesn't handle a nullptr correctly, so if this actually ends up cancelling + // it will crash. + CancelDGO(nullptr); + + // set up the ISO Command + sLoadDGO.cmd_id = LOAD_DGO_CMD_ID; + sLoadDGO.messagebox_to_reply = dgo_mbx; + sLoadDGO.thread_id = 0; + sLoadDGO.buffer1 = (u8*)(u64)(cmd->buffer1); + sLoadDGO.buffer2 = (u8*)(u64)(cmd->buffer2); + sLoadDGO.buffer_heaptop = (u8*)(u64)(cmd->buffer_heap_top); + sLoadDGO.fr = fr; + + // printf("LOAD DGO -- 0x%x\n", cmd->buffer1); + + // send the command to ISO Thread + SendMbx(iso_mbx, &sLoadDGO); + + // wait for the ReturnMessage in the DGO callback state machine. + // this happens when the first file is loaded + WaitMbx(dgo_mbx); + + if (sLoadDGO.status == CMD_STATUS_IN_PROGRESS) { + // we got one, but there's more to load. + // we don't set cmd->buffer1 as it's already the correct buffer in this case - + // when there are >1 objs, we load into buffer1 first. + cmd->result = DGO_RPC_RESULT_MORE; + } else if (sLoadDGO.status == CMD_STATUS_DONE) { + // all done! make sure our reply says we loaded to the top. + cmd->result = DGO_RPC_RESULT_DONE; + cmd->buffer1 = cmd->buffer_heap_top; + sLoadDGO.cmd_id = 0; + } else { + // error. + cmd->result = DGO_RPC_RESULT_ERROR; + sLoadDGO.cmd_id = 0; + } +} + +/*! + * Signal to the IOP it can keep loading and overwrite the oldest obj buffer. + * This will return when there's another loaded obj. + */ +void LoadNextDGO(RPC_Dgo_Cmd* cmd) { + // printf("LOAD NEXT DGO -- 0x%x\n", cmd->buffer1); + + if (sLoadDGO.cmd_id == 0) { + // something went wrong. + cmd->result = DGO_RPC_RESULT_ERROR; + } else { + // update heap location + sLoadDGO.buffer_heaptop = (u8*)(u64)cmd->buffer_heap_top; + if (g_game_version != GameVersion::Jak1) { + sLoadDGO.buffer1 = (u8*)(u64)cmd->buffer1; + sLoadDGO.buffer2 = (u8*)(u64)cmd->buffer2; + } + // allow DGO state machine to advance + SendMbx(sync_mbx, nullptr); + // wait for another load to finish. + WaitMbx(dgo_mbx); + // another load finished, respond with the result. + if (sLoadDGO.status == CMD_STATUS_IN_PROGRESS) { + // more, use the selected buffer. + cmd->result = DGO_RPC_RESULT_MORE; + cmd->buffer1 = (u32)(u64)sLoadDGO.selectedBuffer; + } else if (sLoadDGO.status == CMD_STATUS_DONE) { + // last obj, always loaded to top. + cmd->result = DGO_RPC_RESULT_DONE; + cmd->buffer1 = cmd->buffer_heap_top; + sLoadDGO.cmd_id = 0; + } else { + cmd->result = DGO_RPC_RESULT_ERROR; + sLoadDGO.cmd_id = 0; + } + } +} + +/*! + * Abort an in progress load. + */ +void CancelDGO(RPC_Dgo_Cmd* cmd) { + if (sLoadDGO.cmd_id) { + sLoadDGO.want_abort = 1; + // wake up DGO state machine with abort + SendMbx(sync_mbx, nullptr); + // wait for it to abort. + WaitMbx(dgo_mbx); + // this will cause a crash if we cancel because we try to load 2 dgos at the same time. + // this should succeed if it's an actual cancel because we changed which level we're trying to + // load. + // This is weird in the original game, the IOP doesn't crash on writing to 0 + // or, we have some other bug. + // NOTE : actually got fixed in Jak 2 so who cares + if (cmd) { + cmd->result = DGO_RPC_RESULT_ABORTED; + } + + sLoadDGO.cmd_id = 0; } - return nullptr; } /*! @@ -328,7 +439,7 @@ u32 ISOThread() { // Initialize! InitBuffers(); auto temp_buffer = AllocateBuffer(BUFFER_PAGE_SIZE); - InitDriver(temp_buffer->get_data()); // unblocks InitISOFS's WaitMbx + InitDriver(); // unblocks InitISOFS's WaitMbx FreeBuffer(temp_buffer); VagCommand* in_progress_vag_command = nullptr; @@ -567,7 +678,7 @@ u32 ISOThread() { gFakeVAGClockRunning = true; gFakeVAGClockPaused = 0; } - gVAG_Id = in_progress_vag_command->sound_id; + gVAG_Id = in_progress_vag_command ? in_progress_vag_command->sound_id : 1; } ReturnMessage(cmd); } break; @@ -1340,173 +1451,6 @@ static void UpdatePlayPos() { gPlayPos = pos; } -void* RPC_DGO(unsigned int fno, void* _cmd, int y); -void LoadDGO(RPC_Dgo_Cmd* cmd); -void LoadNextDGO(RPC_Dgo_Cmd* cmd); -void CancelDGO(RPC_Dgo_Cmd* cmd); - -/*! - * DGO RPC Thread. - */ -u32 DGOThread() { - sceSifQueueData dq; - sceSifServeData serve; - - // setup RPC. - CpuDisableIntr(); - sceSifInitRpc(0); - sceSifSetRpcQueue(&dq, GetThreadId()); - sceSifRegisterRpc(&serve, DGO_RPC_ID[g_game_version], RPC_DGO, sRPCBuff, nullptr, nullptr, &dq); - CpuEnableIntr(); - sceSifRpcLoop(&dq); - return 0; -} - -/*! - * DGO RPC Handler. - */ -void* RPC_DGO(unsigned int fno, void* _cmd, int y) { - (void)y; - auto* cmd = (RPC_Dgo_Cmd*)_cmd; - // call appropriate handler. - switch (fno) { - case DGO_RPC_LOAD_FNO: - LoadDGO(cmd); - break; - case DGO_RPC_LOAD_NEXT_FNO: - LoadNextDGO(cmd); - break; - case DGO_RPC_CANCEL_FNO: - CancelDGO(cmd); - break; - default: - cmd->result = DGO_RPC_RESULT_ERROR; - } - return cmd; -} - -/*! - * Begin loading a DGO. Returns when the first obj is loaded. - * Then will load the next obj into the second buffer. - * Then the DGO loader will block until LoadNextDGO is called. - * This approach keeps two loads in flight at a time to increase loading throughput. - * One load will be read from DVD / DMA'd to EE - * Another will be linked on the EE. - * The final load is done directly onto the heap, and isn't double buffered - * (otherwise the linking object could allocate on the heap where the final loading object is - * being copied). This avoids having to relocate the data from the temporary load buffer to the - * heap, and is the only way to make sure that the entire heap can be filled. - */ -void LoadDGO(RPC_Dgo_Cmd* cmd) { - // Find the file - FileRecord* fr = isofs->find(cmd->name); - if (!fr) { - cmd->result = DGO_RPC_RESULT_ERROR; - return; - } - - // cancel an in progress command and wait for it to end. - // note - this doesn't handle a nullptr correctly, so if this actually ends up cancelling - // it will crash. - CancelDGO(nullptr); - - // set up the ISO Command - scmd.cmd_id = LOAD_DGO_CMD_ID; - scmd.messagebox_to_reply = dgo_mbx; - scmd.thread_id = 0; - scmd.buffer1 = (u8*)(u64)(cmd->buffer1); - scmd.buffer2 = (u8*)(u64)(cmd->buffer2); - scmd.buffer_heaptop = (u8*)(u64)(cmd->buffer_heap_top); - scmd.fr = fr; - - // printf("LOAD DGO -- 0x%x\n", cmd->buffer1); - - // send the command to ISO Thread - SendMbx(iso_mbx, &scmd); - - // wait for the ReturnMessage in the DGO callback state machine. - // this happens when the first file is loaded - WaitMbx(dgo_mbx); - - if (scmd.status == CMD_STATUS_IN_PROGRESS) { - // we got one, but there's more to load. - // we don't set cmd->buffer1 as it's already the correct buffer in this case - - // when there are >1 objs, we load into buffer1 first. - cmd->result = DGO_RPC_RESULT_MORE; - } else if (scmd.status == CMD_STATUS_DONE) { - // all done! make sure our reply says we loaded to the top. - cmd->result = DGO_RPC_RESULT_DONE; - cmd->buffer1 = cmd->buffer_heap_top; - scmd.cmd_id = 0; - } else { - // error. - cmd->result = DGO_RPC_RESULT_ERROR; - scmd.cmd_id = 0; - } -} - -/*! - * Signal to the IOP it can keep loading and overwrite the oldest obj buffer. - * This will return when there's another loaded obj. - */ -void LoadNextDGO(RPC_Dgo_Cmd* cmd) { - // printf("LOAD NEXT DGO -- 0x%x\n", cmd->buffer1); - - if (scmd.cmd_id == 0) { - // something went wrong. - cmd->result = DGO_RPC_RESULT_ERROR; - } else { - // update heap location - scmd.buffer_heaptop = (u8*)(u64)cmd->buffer_heap_top; - if (g_game_version != GameVersion::Jak1) { - scmd.buffer1 = (u8*)(u64)cmd->buffer1; - scmd.buffer2 = (u8*)(u64)cmd->buffer2; - } - // allow DGO state machine to advance - SendMbx(sync_mbx, nullptr); - // wait for another load to finish. - WaitMbx(dgo_mbx); - // another load finished, respond with the result. - if (scmd.status == CMD_STATUS_IN_PROGRESS) { - // more, use the selected buffer. - cmd->result = DGO_RPC_RESULT_MORE; - cmd->buffer1 = (u32)(u64)scmd.selectedBuffer; - } else if (scmd.status == CMD_STATUS_DONE) { - // last obj, always loaded to top. - cmd->result = DGO_RPC_RESULT_DONE; - cmd->buffer1 = cmd->buffer_heap_top; - scmd.cmd_id = 0; - } else { - cmd->result = DGO_RPC_RESULT_ERROR; - scmd.cmd_id = 0; - } - } -} - -/*! - * Abort an in progress load. - */ -void CancelDGO(RPC_Dgo_Cmd* cmd) { - if (scmd.cmd_id) { - scmd.want_abort = 1; - // wake up DGO state machine with abort - SendMbx(sync_mbx, nullptr); - // wait for it to abort. - WaitMbx(dgo_mbx); - // this will cause a crash if we cancel because we try to load 2 dgos at the same time. - // this should succeed if it's an actual cancel because we changed which level we're trying to - // load. - // This is weird in the original game, the IOP doesn't crash on writing to 0 - // or, we have some other bug. - // NOTE : actually got fixed in Jak 2 so who cares - if (cmd) { - cmd->result = DGO_RPC_RESULT_ABORTED; - } - - scmd.cmd_id = 0; - } -} - s32 GetVAGStreamPos() { UpdatePlayPos(); if (gFakeVAGClockRunning) { @@ -1521,3 +1465,20 @@ s32 GetVAGStreamPos() { static void VAG_MarkLoopEnd(void* data, u32 size) { ((u8*)data)[size - 15] = 3; } + +/*! + * Find VAG file by "name", where name is 8 bytes (chars with spaces at the end, treated as two + * s32's). Returns pointer to name in the VAGDIR file data. + */ +VagDirEntry* FindVAGFile(const char* name) { + VagDirEntry* entry = gVagDir.vag; + for (u32 idx = 0; idx < gVagDir.count; idx++) { + // check if matching name + if (memcmp(entry->name, name, 8) == 0) { + return entry; + } + entry++; + } + return nullptr; +} +} // namespace jak1 diff --git a/game/overlord/iso.h b/game/overlord/jak1/iso.h similarity index 74% rename from game/overlord/iso.h rename to game/overlord/jak1/iso.h index 66287704b5..0d76eb6c15 100644 --- a/game/overlord/iso.h +++ b/game/overlord/jak1/iso.h @@ -10,33 +10,36 @@ #include "common/common_types.h" +namespace jak1 { extern s32 gFakeVAGClockPaused; extern s32 gFakeVAGClockRunning; extern s32 gFakeVAGClock; extern s32 gRealVAGClock; extern s32 gVoice; +extern IsoFs* isofs; +extern s32 iso_mbx; +extern s32 sync_mbx; +extern DgoCommand sLoadDGO; // renamed from scmd to sLoadDGO in Jak 2 struct VagDirEntry { char name[8]; u32 offset; }; - static constexpr int VAG_COUNT = 868; struct VagDir { u32 count; VagDirEntry vag[VAG_COUNT]; }; - -static constexpr int VAG_COUNT_JAK2 = 2728; -struct VagDirJak2 { - u32 count; - VagDirEntry vag[VAG_COUNT_JAK2]; -}; +extern VagDir gVagDir; void iso_init_globals(); -FileRecord* FindISOFile(const char* name); -u32 GetISOFileLength(FileRecord* f); -u32 InitISOFS(const char* fs_mode, const char* loading_screen); -VagDirEntry* FindVAGFile(const char* name); s32 GetVAGStreamPos(); void SetVAGVol(); +u32 ISOThread(); +u32 InitISOFS(const char* fs_mode, const char* loading_screen); +void InitDriver(u8* buffer); +FileRecord* FindISOFile(const char* name); +u32 GetISOFileLength(FileRecord* f); +VagDirEntry* FindVAGFile(const char* name); + +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/iso_api.cpp b/game/overlord/jak1/iso_api.cpp similarity index 96% rename from game/overlord/iso_api.cpp rename to game/overlord/jak1/iso_api.cpp index bcab1e3950..c9e826547d 100644 --- a/game/overlord/iso_api.cpp +++ b/game/overlord/jak1/iso_api.cpp @@ -1,77 +1,18 @@ #include "iso_api.h" #include "iso_queue.h" -#include "sbank.h" #include "common/log/log.h" #include "common/util/Assert.h" -#include "game/overlord/srpc.h" +#include "game/overlord/common/sbank.h" +#include "game/overlord/common/srpc.h" +#include "game/overlord/jak1/iso.h" #include "game/sce/iop.h" using namespace iop; -/*! - * Load a File to IOP memory (blocking) - */ -s32 LoadISOFileToIOP(FileRecord* file, void* addr, uint32_t length) { - lg::debug("[OVERLORD] LoadISOFileToIOP {}, {}/{} bytes", file->name, length, (s32)file->size); - IsoCommandLoadSingle cmd; - cmd.cmd_id = LOAD_TO_IOP_CMD_ID; - cmd.messagebox_to_reply = 0; - cmd.thread_id = GetThreadId(); - cmd.file_record = file; - cmd.dest_addr = (u8*)addr; - cmd.length = length; - SendMbx(iso_mbx, &cmd); - SleepThread(); - - if (cmd.status) { - cmd.length_to_copy = 0; - } - - return cmd.length_to_copy; -} - -/*! - * Load a File to IOP memory (blocking) - */ -s32 LoadISOFileToEE(FileRecord* file, uint32_t addr, uint32_t length) { - lg::debug("[OVERLORD] LoadISOFileToEE {}, {}/{} bytes", file->name, length, (s32)file->size); - IsoCommandLoadSingle cmd; - cmd.cmd_id = LOAD_TO_EE_CMD_ID; - cmd.messagebox_to_reply = 0; - cmd.thread_id = GetThreadId(); - cmd.file_record = file; - cmd.dest_addr = (u8*)(u64)addr; - cmd.length = length; - SendMbx(iso_mbx, &cmd); - SleepThread(); - - if (cmd.status) { - cmd.length_to_copy = 0; - } - - return cmd.length_to_copy; -} - -s32 LoadISOFileChunkToEE(FileRecord* file, uint32_t dest_addr, uint32_t length, uint32_t offset) { - lg::debug("[OVERLORD] LoadISOFileChunkToEE {} : {} offset {}", file->name, length, offset); - IsoCommandLoadSingle cmd; - cmd.cmd_id = LOAD_TO_EE_OFFSET_CMD_ID; - cmd.messagebox_to_reply = 0; - cmd.thread_id = GetThreadId(); - cmd.file_record = file; - cmd.dest_addr = (u8*)(u64)dest_addr; - cmd.length = length; - cmd.offset = offset; - SendMbx(iso_mbx, &cmd); - SleepThread(); - if (cmd.status) { - cmd.length_to_copy = 0; - } - return cmd.length_to_copy; -} +namespace jak1 { /*! * Send a command to the ISO thread to load a sound bank. This will sleep the calling thread @@ -199,3 +140,67 @@ void UnpauseVAGStream() { cmd->thread_id = 0; SendMbx(iso_mbx, cmd); } + +/*! + * Load a File to IOP memory (blocking) + */ +s32 LoadISOFileToIOP(FileRecord* file, void* addr, uint32_t length) { + lg::debug("[OVERLORD] LoadISOFileToIOP {}, {}/{} bytes", file->name, length, (s32)file->size); + IsoCommandLoadSingle cmd; + cmd.cmd_id = LOAD_TO_IOP_CMD_ID; + cmd.messagebox_to_reply = 0; + cmd.thread_id = GetThreadId(); + cmd.file_record = file; + cmd.dest_addr = (u8*)addr; + cmd.length = length; + SendMbx(iso_mbx, &cmd); + SleepThread(); + + if (cmd.status) { + cmd.length_to_copy = 0; + } + + return cmd.length_to_copy; +} + +/*! + * Load a File to IOP memory (blocking) + */ +s32 LoadISOFileToEE(FileRecord* file, uint32_t addr, uint32_t length) { + lg::debug("[OVERLORD] LoadISOFileToEE {}, {}/{} bytes", file->name, length, (s32)file->size); + IsoCommandLoadSingle cmd; + cmd.cmd_id = LOAD_TO_EE_CMD_ID; + cmd.messagebox_to_reply = 0; + cmd.thread_id = GetThreadId(); + cmd.file_record = file; + cmd.dest_addr = (u8*)(u64)addr; + cmd.length = length; + SendMbx(iso_mbx, &cmd); + SleepThread(); + + if (cmd.status) { + cmd.length_to_copy = 0; + } + + return cmd.length_to_copy; +} + +s32 LoadISOFileChunkToEE(FileRecord* file, uint32_t dest_addr, uint32_t length, uint32_t offset) { + lg::debug("[OVERLORD] LoadISOFileChunkToEE {} : {} offset {}", file->name, length, offset); + IsoCommandLoadSingle cmd; + cmd.cmd_id = LOAD_TO_EE_OFFSET_CMD_ID; + cmd.messagebox_to_reply = 0; + cmd.thread_id = GetThreadId(); + cmd.file_record = file; + cmd.dest_addr = (u8*)(u64)dest_addr; + cmd.length = length; + cmd.offset = offset; + SendMbx(iso_mbx, &cmd); + SleepThread(); + if (cmd.status) { + cmd.length_to_copy = 0; + } + return cmd.length_to_copy; +} + +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/iso_api.h b/game/overlord/jak1/iso_api.h similarity index 87% rename from game/overlord/iso_api.h rename to game/overlord/jak1/iso_api.h index 94985f35a3..a2b5ecbb4d 100644 --- a/game/overlord/iso_api.h +++ b/game/overlord/jak1/iso_api.h @@ -1,13 +1,11 @@ #pragma once -#include "isocommon.h" - +#include "game/overlord/common/isocommon.h" +#include "game/overlord/common/ssound.h" struct SoundBank; -struct VagDirEntry; -s32 LoadISOFileToIOP(FileRecord* file, void* addr, uint32_t length); -s32 LoadISOFileToEE(FileRecord* file, uint32_t ee_addr, uint32_t length); -s32 LoadISOFileChunkToEE(FileRecord* file, uint32_t dest_addr, uint32_t length, uint32_t offset); +namespace jak1 { +struct VagDirEntry; void LoadSoundBank(const char* bank_name, SoundBank* bank); void LoadMusic(const char* music_name, s32* bank); @@ -23,3 +21,8 @@ void SetDialogVolume(s32 volume); void StopVAGStream(VagDirEntry* vag, u32 unk); void PauseVAGStream(); void UnpauseVAGStream(); +s32 LoadISOFileToIOP(FileRecord* file, void* addr, uint32_t length); +s32 LoadISOFileToEE(FileRecord* file, uint32_t ee_addr, uint32_t length); +s32 LoadISOFileChunkToEE(FileRecord* file, uint32_t dest_addr, uint32_t length, uint32_t offset); + +} // namespace jak1 diff --git a/game/overlord/iso_queue.cpp b/game/overlord/jak1/iso_queue.cpp similarity index 99% rename from game/overlord/iso_queue.cpp rename to game/overlord/jak1/iso_queue.cpp index 5a6fcd820e..2479233617 100644 --- a/game/overlord/iso_queue.cpp +++ b/game/overlord/jak1/iso_queue.cpp @@ -8,10 +8,12 @@ #include "common/log/log.h" #include "common/util/Assert.h" +#include "game/overlord/jak1/iso.h" #include "game/sce/iop.h" using namespace iop; +namespace jak1 { constexpr int N_BUFFERS = 4; constexpr int N_STR_BUFFERS = 1; constexpr int N_VAG_CMDS = 64; @@ -367,3 +369,4 @@ void FreeVAGCommand(VagCommand* cmd) { printf("[OVERLORD] Invalid FreeVAGCommand!\n"); } } +} // namespace jak1 diff --git a/game/overlord/iso_queue.h b/game/overlord/jak1/iso_queue.h similarity index 87% rename from game/overlord/iso_queue.h rename to game/overlord/jak1/iso_queue.h index 91072a95ab..5f93783773 100644 --- a/game/overlord/iso_queue.h +++ b/game/overlord/jak1/iso_queue.h @@ -4,6 +4,9 @@ #include "common/common_types.h" +#include "game/overlord/common/isocommon.h" + +namespace jak1 { void iso_queue_init_globals(); void InitBuffers(); IsoBufferHeader* AllocateBuffer(uint32_t size); @@ -18,3 +21,4 @@ IsoBufferHeader* TryAllocateBuffer(uint32_t size); VagCommand* GetVAGCommand(); void FreeVAGCommand(VagCommand* cmd); void ReleaseMessage(IsoMessage* cmd); +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/jak1/isocommon.cpp b/game/overlord/jak1/isocommon.cpp new file mode 100644 index 0000000000..ceeef3c101 --- /dev/null +++ b/game/overlord/jak1/isocommon.cpp @@ -0,0 +1,51 @@ +/*! + * @file isocommon.cpp + * Common ISO utilities. + */ + +#include "isocommon.h" + +#include + +#include "common/common_types.h" +#include "common/util/Assert.h" + +namespace jak1 { + +/*! + * Unmakes an ISO name back to the original name. + * Keeps it upper case. + * Not used. + */ +void UnmakeISOName(char* dst, const char* src) { + int i = 0; + const char* src_ptr = src; + char* dst_ptr = dst; + + // copy non-space characters + while ((i < 8) && (*src != ' ')) { + *dst_ptr = *src_ptr; + src_ptr++; + dst_ptr++; + i++; + } + + // skip src to the extension + src_ptr += 8 - i; + + if (*src_ptr != ' ') { + // if there's an extension, add the period + *dst_ptr = '.'; + i = 0; + // copy extension + dst_ptr++; + while (i < 3 && *src_ptr != ' ') { + *dst_ptr = *src_ptr; + src_ptr++; + i++; + } + } + *dst_ptr = 0; +} + +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/isocommon.h b/game/overlord/jak1/isocommon.h similarity index 63% rename from game/overlord/isocommon.h rename to game/overlord/jak1/isocommon.h index 3f10629957..7ba79ee415 100644 --- a/game/overlord/isocommon.h +++ b/game/overlord/jak1/isocommon.h @@ -5,59 +5,35 @@ * Common ISO utilities. */ -#ifndef JAK_V2_ISOCOMMON_H -#define JAK_V2_ISOCOMMON_H - #include #include "common/common_types.h" #include "common/link_types.h" #include "game/common/overlord_common.h" -#include "game/overlord/ssound.h" +#include "game/overlord/common/isocommon.h" +#include "game/overlord/jak1/ssound.h" + +struct SoundBank; + +namespace jak1 { +struct VagDirEntry; constexpr int PRI_STACK_LENGTH = 4; // number of queued commands per priority constexpr int N_PRIORITIES = 4; // number of priorities -constexpr u32 CMD_STATUS_READ_ERR = 8; // read encountered a problem or was canceled. -constexpr u32 CMD_STATUS_NULL_CB = 7; // status returned if you don't set a callback -constexpr u32 CMD_STATUS_FAILED_TO_OPEN = 6; // status if file couldn't be opened -constexpr u32 CMD_STATUS_FAILED_TO_QUEUE = 2; // status if we couldn't be queued -constexpr u32 CMD_STATUS_IN_PROGRESS = 0xffffffff; // status if command is running and healthy -constexpr u32 CMD_STATUS_DONE = 0; // status if command is done. - constexpr int BUFFER_PAGE_SIZE = 0xc000; // size in bytes of normal read buffer constexpr int STR_BUFFER_DATA_SIZE = 0x6000; // size in bytes of vag read buffer -constexpr int LOAD_TO_EE_CMD_ID = 0x100; // command to load file to ee -constexpr int LOAD_TO_IOP_CMD_ID = 0x101; // command to load to iop -constexpr int LOAD_TO_EE_OFFSET_CMD_ID = 0x102; // command to load file to ee with offset. -constexpr int LOAD_DGO_CMD_ID = 0x200; // command to load DGO -constexpr int LOAD_SOUND_BANK = 0x300; // Command to load a sound bank -constexpr int LOAD_MUSIC = 0x380; // Command to load music -constexpr int QUEUE_VAG_STREAM = 0x400; // Command to load a vag stream -constexpr int PLAY_VAG_STREAM = 0x401; // Command to play a vag stream -constexpr int STOP_VAG_STREAM = 0x402; // Command to stop a vag stream -constexpr int PAUSE_VAG_STREAM = 0x403; // Command to pause a vag stream -constexpr int CONTINUE_VAG_STREAM = 0x404; // Command to continue a vag stream -constexpr int SET_VAG_VOLUME = 0x405; // Command to set the volume of vag playback -constexpr int SET_DIALOG_VOLUME = 0x406; // Command to set the volume of vag playback - -// TODO - hack workaround for now, was originally 350 -constexpr int MAX_ISO_FILES = 999; // maximum files on FS -constexpr int MAX_OPEN_FILES = 16; // maximum number of open files at a time. - -/*! - * Record for file. There is one for each file in the FS, and pointers to each FileRecord act as - * an identifier. - * The location/size can't be counted on to be anything meaningful as it depends on the IsoFs - * implementation being used. - */ -struct FileRecord { - char name[12]; - uint32_t location; - uint32_t size; -}; +constexpr int LOAD_SOUND_BANK = 0x300; // Command to load a sound bank +constexpr int LOAD_MUSIC = 0x380; // Command to load music +constexpr int QUEUE_VAG_STREAM = 0x400; // Command to load a vag stream +constexpr int PLAY_VAG_STREAM = 0x401; // Command to play a vag stream +constexpr int STOP_VAG_STREAM = 0x402; // Command to stop a vag stream +constexpr int PAUSE_VAG_STREAM = 0x403; // Command to pause a vag stream +constexpr int CONTINUE_VAG_STREAM = 0x404; // Command to continue a vag stream +constexpr int SET_VAG_VOLUME = 0x405; // Command to set the volume of vag playback +constexpr int SET_DIALOG_VOLUME = 0x406; // Command to set the volume of vag playback /*! * Record for an open file. @@ -67,6 +43,26 @@ struct LoadStackEntry { uint32_t location; // sectors. }; +/*! + * API to access files. There are debug modes + reading from an ISO filesystem. + */ +struct IsoFs { + int (*init)(); // 0 + FileRecord* (*find)(const char*); // 4 + FileRecord* (*find_in)(const char*); // 8 + uint32_t (*get_length)(FileRecord*); // c + LoadStackEntry* (*open)(FileRecord*, int32_t); // 10 + LoadStackEntry* (*open_wad)(FileRecord*, int32_t); // 14 + void (*close)(LoadStackEntry*); // 18 + uint32_t (*begin_read)(LoadStackEntry*, void*, int32_t); // 1c + uint32_t (*sync_read)(); // 20 + uint32_t (*load_sound_bank)(char*, SoundBank*); // 24 + uint32_t (*load_music)(char*, s32*); + void (*poll_drive)(); +}; + +struct IsoMessage; + /*! * Header for a ISO data buffer. */ @@ -80,9 +76,6 @@ struct IsoBufferHeader { u8* get_data() { return ((u8*)this) + sizeof(IsoBufferHeader); } }; -struct IsoMessage; -struct LoadStackEntry; - //! Callback function for data loads. typedef u32 (*iso_callback_func)(IsoMessage* cmd, IsoBufferHeader* buffer); @@ -115,40 +108,6 @@ struct IsoCommandLoadSingle : public IsoMessage { s32 bytes_done; // 0x40 }; -struct VagDirEntry; -/*! - * Command to do something. - */ -struct VagCommand : public IsoMessage { - FileRecord* file; - VagDirEntry* vag; - u32 buffer_number; - u32 data_left; - u32 started; - u32 paused; - u32 sample_rate; - u32 stop; - s32 end_point; - u32 unk2; - s32 volume; - u32 sound_id; - u32 priority; - u32 positioned; - Vec3w trans; -}; - -struct SoundBank; - -struct SoundBankLoadCommand : public IsoMessage { - char bank_name[16]; - SoundBank* bank; -}; - -struct MusicLoadCommand : public IsoMessage { - char music_name[16]; - s32* music_handle; -}; - /*! * DGO Load State Machine states. */ @@ -185,6 +144,37 @@ struct DgoCommand : public IsoMessage { u32 want_abort; // 0xd4, should we quit? }; +/*! + * Command to do something. + */ +struct VagCommand : public IsoMessage { + FileRecord* file; + VagDirEntry* vag; + u32 buffer_number; + u32 data_left; + u32 started; + u32 paused; + u32 sample_rate; + u32 stop; + s32 end_point; + u32 unk2; + s32 volume; + u32 sound_id; + u32 priority; + u32 positioned; + Vec3w trans; +}; + +struct SoundBankLoadCommand : public IsoMessage { + char bank_name[16]; + SoundBank* bank; +}; + +struct MusicLoadCommand : public IsoMessage { + char music_name[16]; + s32* music_handle; +}; + /*! * Priority Stack entry. */ @@ -196,28 +186,4 @@ struct PriStackEntry { void reset(); }; -/*! - * API to access files. There are debug modes + reading from an ISO filesystem. - */ -struct IsoFs { - int (*init)(u8*); // 0 - FileRecord* (*find)(const char*); // 4 - FileRecord* (*find_in)(const char*); // 8 - uint32_t (*get_length)(FileRecord*); // c - LoadStackEntry* (*open)(FileRecord*, int32_t); // 10 - LoadStackEntry* (*open_wad)(FileRecord*, int32_t); // 14 - void (*close)(LoadStackEntry*); // 18 - uint32_t (*begin_read)(LoadStackEntry*, void*, int32_t); // 1c - uint32_t (*sync_read)(); // 20 - uint32_t (*load_sound_bank)(char*, void*); // 24 - uint32_t (*load_music)(char*, void*); - void (*poll_drive)(); -}; - -extern IsoFs* isofs; -extern s32 iso_mbx; - -void MakeISOName(char* dst, const char* src); -void ISONameFromAnimationName(char* dst, const char* src); - -#endif // JAK_V2_ISOCOMMON_H +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/overlord.cpp b/game/overlord/jak1/overlord.cpp similarity index 87% rename from game/overlord/overlord.cpp rename to game/overlord/jak1/overlord.cpp index 03ec3811e8..67538c8602 100644 --- a/game/overlord/overlord.cpp +++ b/game/overlord/jak1/overlord.cpp @@ -2,18 +2,18 @@ #include -#include "iso.h" #include "ramdisk.h" -#include "sbank.h" #include "srpc.h" #include "ssound.h" #include "common/util/Assert.h" +#include "game/overlord/jak1/iso.h" #include "game/sce/iop.h" using namespace iop; +namespace jak1 { static s32 gargc; static const char* const* gargv; static bool* init_complete; @@ -46,7 +46,7 @@ int start_overlord(int argc, const char* const* argv) { thread_param.initPriority = 98; thread_param.stackSize = 0x800; thread_param.option = 0; - thread_param.entry = (void*)Thread_Server; + thread_param.entry = Thread_Server; strcpy(thread_param.name, "Server"); // added auto thread_server = CreateThread(&thread_param); if (thread_server <= 0) { @@ -57,7 +57,7 @@ int start_overlord(int argc, const char* const* argv) { thread_param.initPriority = 96; thread_param.stackSize = 0x800; thread_param.option = 0; - thread_param.entry = (void*)Thread_Player; + thread_param.entry = Thread_Player; strcpy(thread_param.name, "Player"); // added auto thread_player = CreateThread(&thread_param); if (thread_player <= 0) { @@ -68,7 +68,7 @@ int start_overlord(int argc, const char* const* argv) { thread_param.initPriority = 99; thread_param.stackSize = 0x1000; thread_param.option = 0; - thread_param.entry = (void*)Thread_Loader; + thread_param.entry = Thread_Loader; strcpy(thread_param.name, "Loader"); // added for debug auto thread_loader = CreateThread(&thread_param); if (thread_loader <= 0) { @@ -83,13 +83,14 @@ int start_overlord(int argc, const char* const* argv) { return 0; } -static void call_start() { +static u32 call_start() { start_overlord(gargc, gargv); *init_complete = true; while (true) { SleepThread(); } + return 0; } int start_overlord_wrapper(int argc, const char* const* argv, bool* signal) { @@ -104,7 +105,7 @@ int start_overlord_wrapper(int argc, const char* const* argv, bool* signal) { param.stackSize = 0x800; param.option = 0; strcpy(param.name, "start"); // added for debug - param.entry = (void*)call_start; + param.entry = call_start; auto start_thread = CreateThread(¶m); StartThread(start_thread, 0); @@ -112,10 +113,4 @@ int start_overlord_wrapper(int argc, const char* const* argv, bool* signal) { return 0; } -/*! - * Loop endlessly and never return. - */ -void ExitIOP() { - while (true) { - } -} +} // namespace jak1 diff --git a/game/overlord/overlord.h b/game/overlord/jak1/overlord.h similarity index 59% rename from game/overlord/overlord.h rename to game/overlord/jak1/overlord.h index 5900646494..458170a6b5 100644 --- a/game/overlord/overlord.h +++ b/game/overlord/jak1/overlord.h @@ -1,10 +1,6 @@ #pragma once -#ifndef JAK_V2_OVERLORD_H -#define JAK_V2_OVERLORD_H - +namespace jak1 { int start_overlord(int argc, const char* const* argv); int start_overlord_wrapper(int argc, const char* const* argv, bool* signal); -void ExitIOP(); - -#endif // JAK_V2_OVERLORD_H +} // namespace jak1 diff --git a/game/overlord/ramdisk.cpp b/game/overlord/jak1/ramdisk.cpp similarity index 98% rename from game/overlord/ramdisk.cpp rename to game/overlord/jak1/ramdisk.cpp index 3186e2c5b9..4b86d72b07 100644 --- a/game/overlord/ramdisk.cpp +++ b/game/overlord/jak1/ramdisk.cpp @@ -9,19 +9,19 @@ #include #include -#include "iso.h" -#include "iso_api.h" - #include "common/common_types.h" #include "common/util/Assert.h" #include "game/common/ramdisk_rpc_types.h" +#include "game/overlord/jak1/iso.h" +#include "game/overlord/jak1/iso_api.h" #include "game/runtime.h" #include "game/sce/iop.h" // Note - the RAMDISK code supports having multiple files, but it appears only one file can ever be // used at a time. +namespace jak1 { constexpr int RAMDISK_SIZE = 0xcac00; // Memory size of RAMDISK constexpr int RAMDISK_MAX_FILES = 16; // Maximum number of files to store in RAMDISK. constexpr int RAMDISK_RETURN_BUFFER_SIZE = 0x2000; // Maximum size of an individual RAMDISK read @@ -192,3 +192,4 @@ void* RPC_Ramdisk(unsigned int fno, void* data, int size) { } return nullptr; } +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/ramdisk.h b/game/overlord/jak1/ramdisk.h similarity index 79% rename from game/overlord/ramdisk.h rename to game/overlord/jak1/ramdisk.h index e48c9d508e..05a1cd1831 100644 --- a/game/overlord/ramdisk.h +++ b/game/overlord/jak1/ramdisk.h @@ -6,15 +6,12 @@ * Also called "Server". */ -#ifndef JAK_RAMDISK_H -#define JAK_RAMDISK_H - #include "common/common_types.h" +namespace jak1 { extern u32 gMemFreeAtStart; void ramdisk_init_globals(); void InitRamdisk(); u32 Thread_Server(); - -#endif // JAK_RAMDISK_H +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/srpc.cpp b/game/overlord/jak1/srpc.cpp similarity index 53% rename from game/overlord/srpc.cpp rename to game/overlord/jak1/srpc.cpp index 0906dad2fe..b54c5db9ac 100644 --- a/game/overlord/srpc.cpp +++ b/game/overlord/jak1/srpc.cpp @@ -3,10 +3,8 @@ #include #include -#include "iso.h" #include "iso_api.h" #include "ramdisk.h" -#include "sbank.h" #include "common/log/log.h" #include "common/util/Assert.h" @@ -16,7 +14,12 @@ #include "game/common/loader_rpc_types.h" #include "game/common/player_rpc_types.h" #include "game/graphics/gfx.h" -#include "game/overlord/soundcommon.h" +#include "game/overlord/common/iso.h" +#include "game/overlord/common/sbank.h" +#include "game/overlord/common/soundcommon.h" +#include "game/overlord/common/srpc.h" +#include "game/overlord/common/ssound.h" +#include "game/overlord/jak1/iso.h" #include "game/runtime.h" #include "game/sce/iop.h" #include "game/sound/sndshim.h" @@ -26,33 +29,22 @@ using namespace iop; -MusicTweaks gMusicTweakInfo; +namespace jak1 { constexpr int SRPC_MESSAGE_SIZE = 0x50; static uint8_t gLoaderBuf[SRPC_MESSAGE_SIZE]; static uint8_t gPlayerBuf[SRPC_MESSAGE_SIZE * 128]; -int32_t gSoundEnable = 1; static u32 gInfoEE = 0; // EE address where we should send info on each frame. s16 gFlava; -static s32 gMusic; -s32 gMusicTweak = 0x80; -s32 gMusicPause = 0; u32 gFreeMem = 0; -u32 gFrameNum = 0; -u8 gFPS = 60; - -// added -u32 gMusicFadeHack = 0; static SoundIopInfo info; s32 gVAG_Id = 0; // TODO probably doesn't belong here. // english, french, germain, spanish, italian, japanese, uk. -static const char* languages[] = {"ENG", "FRE", "GER", "SPA", "ITA", "JAP", "UKE"}; -const char* gLanguage = nullptr; +const char* languages[] = {"ENG", "FRE", "GER", "SPA", "ITA", "JAP", "UKE"}; void srpc_init_globals() { - memset((void*)&gMusicTweakInfo, 0, sizeof(gMusicTweakInfo)); memset((void*)gLoaderBuf, 0, sizeof(gLoaderBuf)); memset((void*)gPlayerBuf, 0, sizeof(gPlayerBuf)); gSoundEnable = 1; @@ -61,8 +53,6 @@ void srpc_init_globals() { } void* RPC_Player(unsigned int fno, void* data, int size); -void* RPC_Player2(unsigned int fno, void* data, int size); -PerGameVersion RPC_Player_Func = {RPC_Player, RPC_Player2}; u32 Thread_Player() { sceSifQueueData dq; @@ -72,17 +62,14 @@ u32 Thread_Player() { CpuDisableIntr(); sceSifInitRpc(0); sceSifSetRpcQueue(&dq, GetThreadId()); - sceSifRegisterRpc(&serve, PLAYER_RPC_ID[g_game_version], RPC_Player_Func[g_game_version], - gPlayerBuf, nullptr, nullptr, &dq); + sceSifRegisterRpc(&serve, PLAYER_RPC_ID[g_game_version], RPC_Player, gPlayerBuf, nullptr, nullptr, + &dq); CpuEnableIntr(); sceSifRpcLoop(&dq); return 0; } void* RPC_Loader(unsigned int fno, void* data, int size); -void* RPC_Loader2(unsigned int fno, void* data, int size); - -PerGameVersion RPC_Loader_Func = {RPC_Loader, RPC_Loader2}; u32 Thread_Loader() { sceSifQueueData dq; @@ -92,8 +79,8 @@ u32 Thread_Loader() { CpuDisableIntr(); sceSifInitRpc(0); sceSifSetRpcQueue(&dq, GetThreadId()); - sceSifRegisterRpc(&serve, LOADER_RPC_ID[g_game_version], RPC_Loader_Func[g_game_version], - gLoaderBuf, nullptr, nullptr, &dq); + sceSifRegisterRpc(&serve, LOADER_RPC_ID[g_game_version], RPC_Loader, gLoaderBuf, nullptr, nullptr, + &dq); CpuEnableIntr(); sceSifRpcLoop(&dq); return 0; @@ -362,301 +349,6 @@ void* RPC_Player(unsigned int /*fno*/, void* data, int size) { return nullptr; } -void* RPC_Player2(unsigned int /*fno*/, void* data, int size) { - if (!gSoundEnable) { - return nullptr; - } - - gFreeMem = QueryTotalFreeMemSize(); - if (!PollSema(gSema)) { - if (gMusic) { - if (!gMusicPause && !LookupSound(666)) { - Sound* music = AllocateSound(); - if (music != nullptr) { - gMusicFade = 0; - gMusicFadeDir = 1; - SetMusicVol(); - music->sound_handle = snd_PlaySoundVolPanPMPB(gMusic, 0, 0x400, -1, 0, 0); - music->id = 666; - music->is_music = 1; - } - } - } - - SignalSema(gSema); - } - - SetMusicVol(); - Sound* music = LookupSound(666); - if (music != nullptr) { - snd_SetSoundVolPan(music->sound_handle, 0x7FFFFFFF, 0); - } - - int n_messages = size / SRPC_MESSAGE_SIZE; - SoundRpcCommand* cmd = (SoundRpcCommand*)(data); - if (!gSoundEnable) { - return nullptr; - } - - while (n_messages > 0) { - switch (cmd->j2command) { - case Jak2SoundCommand::play: { - if (!cmd->play.sound_id) { - break; - } - - auto sound = LookupSound(cmd->play.sound_id); - if (sound != nullptr) { - // update - sound->params = cmd->play.parms; - sound->is_music = false; - SFXUserData data{}; - s32 found = snd_GetSoundUserData(0, nullptr, -1, sound->name, &data); - if ((sound->params.mask & 0x40) == 0) { - s16 fo_min = 5; - if (found && data.data[0]) - fo_min = data.data[0]; - sound->params.fo_min = fo_min; - } - if ((sound->params.mask & 0x80) == 0) { - s16 fo_max = 30; - if (found && data.data[1]) - fo_max = data.data[1]; - sound->params.fo_max = fo_max; - } - if ((sound->params.mask & 0x100) == 0) { - s16 fo_curve = 2; - if (found && data.data[2]) - fo_curve = data.data[2]; - sound->params.fo_curve = fo_curve; - } - UpdateVolume(sound); - snd_SetSoundPitchModifier(sound->sound_handle, sound->params.pitch_mod); - if (sound->params.mask & 0x4) { - snd_SetSoundPitchBend(sound->sound_handle, sound->params.bend); - } - if (sound->params.mask & 0x800) { - snd_SetSoundReg(sound->sound_handle, 0, sound->params.reg[0]); - } - if (sound->params.mask & 0x1000) { - snd_SetSoundReg(sound->sound_handle, 1, sound->params.reg[1]); - } - if (sound->params.mask & 0x2000) { - snd_SetSoundReg(sound->sound_handle, 2, sound->params.reg[2]); - } - - } else { - // new sound - sound = AllocateSound(); - if (sound == nullptr) { - // no free sounds - break; - } - strcpy_toupper(sound->name, cmd->play.name); - // TODO update params struct - sound->params = cmd->play.parms; - sound->is_music = false; - sound->bank_entry = nullptr; - - SFXUserData data{}; - s32 found = snd_GetSoundUserData(0, nullptr, -1, sound->name, &data); - if ((sound->params.mask & 0x40) == 0) { - s16 fo_min = 5; - if (found && data.data[0]) - fo_min = data.data[0]; - sound->params.fo_min = fo_min; - } - if ((sound->params.mask & 0x80) == 0) { - s16 fo_max = 30; - if (found && data.data[1]) - fo_max = data.data[1]; - sound->params.fo_max = fo_max; - } - if ((sound->params.mask & 0x100) == 0) { - s16 fo_curve = 2; - if (found && data.data[2]) - fo_curve = data.data[2]; - sound->params.fo_curve = fo_curve; - } - // lg::warn("RPC: PLAY {} v:{}, p:{}", sound->name, GetVolume(sound), GetPan(sound)); - - s32 handle = snd_PlaySoundByNameVolPanPMPB(0, nullptr, sound->name, GetVolume(sound), - GetPan(sound), sound->params.pitch_mod, - sound->params.bend); - sound->sound_handle = handle; - if (handle != 0) { - sound->id = cmd->play.sound_id; - if (sound->params.mask & 0x800) { - snd_SetSoundReg(sound->sound_handle, 0, sound->params.reg[0]); - } - if (sound->params.mask & 0x1000) { - snd_SetSoundReg(sound->sound_handle, 1, sound->params.reg[1]); - } - if (sound->params.mask & 0x2000) { - snd_SetSoundReg(sound->sound_handle, 2, sound->params.reg[2]); - } - } - } - } break; - case Jak2SoundCommand::pause_sound: { - Sound* sound = LookupSound(cmd->sound_id.sound_id); - if (sound != nullptr) { - snd_PauseSound(sound->sound_handle); - } - // TODO vag - } break; - case Jak2SoundCommand::stop_sound: { - Sound* sound = LookupSound(cmd->sound_id.sound_id); - if (sound != nullptr) { - snd_StopSound(sound->sound_handle); - } - // TODO vag - } break; - case Jak2SoundCommand::continue_sound: { - Sound* sound = LookupSound(cmd->sound_id.sound_id); - if (sound != nullptr) { - snd_ContinueSound(sound->sound_handle); - } - // TODO vag - } break; - case Jak2SoundCommand::set_param: { - Sound* sound = LookupSound(cmd->sound_id.sound_id); - u32 mask = cmd->param.parms.mask; - if (sound != nullptr) { - if (mask & 1) { - if (mask & 0x10) { - sound->auto_time = cmd->param.auto_time; - sound->new_volume = cmd->param.parms.volume; - } else { - sound->params.volume = cmd->param.parms.volume; - } - } - if (mask & 0x20) { - sound->params.trans = cmd->param.parms.trans; - } - if (mask & 0x21) { - UpdateVolume(sound); - } - if (mask & 2) { - sound->params.pitch_mod = cmd->param.parms.pitch_mod; - if (mask & 0x10) { - snd_AutoPitch(sound->sound_handle, sound->params.pitch_mod, cmd->param.auto_time, - cmd->param.auto_from); - } else { - snd_SetSoundPitchModifier(sound->sound_handle, cmd->param.parms.pitch_mod); - } - } - if (mask & 4) { - sound->params.bend = cmd->param.parms.bend; - if (mask & 0x10) { - snd_AutoPitchBend(sound->sound_handle, sound->params.bend, cmd->param.auto_time, - cmd->param.auto_from); - } else { - snd_SetSoundPitchBend(sound->sound_handle, cmd->param.parms.bend); - } - } - if (mask & 0x400) { - sound->params.priority = cmd->param.parms.priority; - } - if (mask & 0x8) { - sound->params.group = cmd->param.parms.group; - } - if (mask & 0x40) { - sound->params.fo_min = cmd->param.parms.fo_min; - } - if (mask & 0x80) { - sound->params.fo_max = cmd->param.parms.fo_max; - } - if (mask & 0x100) { - sound->params.fo_curve = cmd->param.parms.fo_curve; - } - if (mask & 0x800) { - sound->params.reg[0] = cmd->param.parms.reg[0]; - snd_SetSoundReg(sound->sound_handle, 0, cmd->param.parms.reg[0]); - } - if (mask & 0x1000) { - sound->params.reg[1] = cmd->param.parms.reg[1]; - snd_SetSoundReg(sound->sound_handle, 1, cmd->param.parms.reg[1]); - } - if (mask & 0x2000) { - sound->params.reg[2] = cmd->param.parms.reg[2]; - snd_SetSoundReg(sound->sound_handle, 2, cmd->param.parms.reg[2]); - } - } - // TODO vag - } break; - case Jak2SoundCommand::set_master_volume: { - u32 group = cmd->master_volume.group.group; - // FIXME array of set volumes - for (int i = 0; i < 32; i++) { - if (((group >> i) & 1) != 0) { - if (i == 1) { - gMusicVol = cmd->master_volume.volume; - } else if (i == 2) { - SetDialogVolume(cmd->master_volume.volume); - } else { - snd_SetMasterVolume(i, cmd->master_volume.volume); - } - } - } - } break; - case Jak2SoundCommand::pause_group: { - snd_PauseAllSoundsInGroup(cmd->group.group); - if (cmd->group.group & 2) { - gMusicPause = 1; - } - if (cmd->group.group & 4) { - // TODO vag - } - } break; - case Jak2SoundCommand::stop_group: { - KillSoundsInGroup(cmd->group.group); - } break; - case Jak2SoundCommand::continue_group: { - snd_ContinueAllSoundsInGroup(cmd->group.group); - if (cmd->group.group & 2) { - gMusicPause = 0; - } - if (cmd->group.group & 4) { - // TODO vag - } - } break; - case Jak2SoundCommand::set_midi_reg: { - if (cmd->midi_reg.reg == 16) { - snd_SetGlobalExcite(cmd->midi_reg.value); - } else { - Sound* sound = LookupSound(666); - if (sound != nullptr) { - snd_SetMIDIRegister(sound->sound_handle, cmd->midi_reg.reg, cmd->midi_reg.value); - } - } - } break; - case Jak2SoundCommand::set_reverb: { - lg::warn("RPC_Player: unimplemented set_reverb"); - // TODO reverb - } break; - case Jak2SoundCommand::set_ear_trans: { - SetEarTrans(&cmd->ear_trans_j2.ear_trans0, &cmd->ear_trans_j2.ear_trans1, - &cmd->ear_trans_j2.cam_trans, cmd->ear_trans_j2.cam_angle); - } break; - case Jak2SoundCommand::shutdown: { - gSoundEnable = 0; - } break; - case Jak2SoundCommand::set_fps: { - gFPS = cmd->fps.fps; - } break; - default: - ASSERT_MSG(false, fmt::format("Unhandled RPC Player command {}", - magic_enum::enum_name(cmd->j2command))); - } - - n_messages--; - cmd++; - } - - return nullptr; -} - void* RPC_Loader(unsigned int /*fno*/, void* data, int size) { int n_messages = size / SRPC_MESSAGE_SIZE; SoundRpcCommand* cmd = (SoundRpcCommand*)(data); @@ -748,104 +440,6 @@ void* RPC_Loader(unsigned int /*fno*/, void* data, int size) { return nullptr; } -static void UnLoadMusic(s32* handle) { - gMusicFadeDir = -1; - while (gMusicFade) - DelayThread(1000); - snd_UnloadBank(*handle); - snd_ResolveBankXREFS(); - *handle = 0; -} - -void* RPC_Loader2(unsigned int /*fno*/, void* data, int size) { - int n_messages = size / SRPC_MESSAGE_SIZE; - SoundRpcCommand* cmd = (SoundRpcCommand*)(data); - if (!gSoundEnable) { - return nullptr; - } - - while (n_messages > 0) { - switch (cmd->j2command) { - case Jak2SoundCommand::load_bank: { - if (LookupBank(cmd->load_bank.bank_name)) { - break; - } - - auto bank = AllocateBankName(cmd->load_bank.bank_name); - if (bank == nullptr) { - break; - } - - strncpy(bank->name, cmd->load_bank.bank_name, 16); - bank->in_use = true; - bank->unk4 = 0; - LoadSoundBank(cmd->load_bank.bank_name, bank); - } break; - case Jak2SoundCommand::load_music: { - while (WaitSema(gSema)) - ; - if (gMusic) { - UnLoadMusic(&gMusic); - } - LoadMusic(cmd->load_bank.bank_name, &gMusic); - SignalSema(gSema); - } break; - case Jak2SoundCommand::unload_bank: { - auto bank = LookupBank(cmd->load_bank.bank_name); - if (!bank) { - break; - } - auto handle = bank->bank_handle; - if (!bank->unk4) { - bank->in_use = false; - } - bank->in_use = false; - snd_UnloadBank(handle); - snd_ResolveBankXREFS(); - } break; - case Jak2SoundCommand::get_irx_version: { - cmd->irx_version.major = 4; - cmd->irx_version.minor = 0; - gInfoEE = cmd->irx_version.ee_addr; - return data; - } break; - case Jak2SoundCommand::set_language: { - gLanguage = languages[cmd->set_language.langauge_id]; - } break; - case Jak2SoundCommand::list_sounds: { - // Not present in real jak2 overlord - PrintActiveSounds(); - } break; - case Jak2SoundCommand::unload_music: { - while (WaitSema(gSema)) - ; - if (gMusic) { - UnLoadMusic(&gMusic); - } - SignalSema(gSema); - } break; - case Jak2SoundCommand::set_stereo_mode: { - s32 mode = cmd->stereo_mode.stereo_mode; - if (mode == 0) { - snd_SetPlayBackMode(1); - } else if (mode == 1) { - snd_SetPlayBackMode(2); - } else if (mode == 2) { - snd_SetPlayBackMode(0); - } - } break; - default: - ASSERT_MSG(false, fmt::format("Unhandled RPC Loader command {}", - magic_enum::enum_name(cmd->j2command))); - } - - n_messages--; - cmd++; - } - - return nullptr; -} - static s32 dmaid = 0; s32 VBlank_Handler(void*) { @@ -914,3 +508,4 @@ s32 VBlank_Handler(void*) { return 1; } +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/jak1/srpc.h b/game/overlord/jak1/srpc.h new file mode 100644 index 0000000000..c0ff1ab822 --- /dev/null +++ b/game/overlord/jak1/srpc.h @@ -0,0 +1,94 @@ +#pragma once + +#include "ssound.h" + +#include "common/common_types.h" + +#include "game/overlord/common/srpc.h" + +namespace jak1 { +void srpc_init_globals(); + +extern s32 gVAG_Id; + +enum class Jak1SoundCommand : u16 { + LOAD_BANK = 0, + LOAD_MUSIC = 1, + UNLOAD_BANK = 2, + PLAY = 3, + PAUSE_SOUND = 4, + STOP_SOUND = 5, + CONTINUE_SOUND = 6, + SET_PARAM = 7, + SET_MASTER_VOLUME = 8, + PAUSE_GROUP = 9, + STOP_GROUP = 10, + CONTINUE_GROUP = 11, + GET_IRX_VERSION = 12, + SET_FALLOFF_CURVE = 13, + SET_SOUND_FALLOFF = 14, + RELOAD_INFO = 15, + SET_LANGUAGE = 16, + SET_FLAVA = 17, + SET_REVERB = 18, + SET_EAR_TRANS = 19, + SHUTDOWN = 20, + LIST_SOUNDS = 21, + UNLOAD_MUSIC = 22, + MIRROR_MODE = 201, +}; + +struct SoundRpcCommand { + u16 rsvd1; + union { + Jak1SoundCommand j1command; + // Jak2SoundCommand j2command; + }; + union { + SoundRpcGetIrxVersion irx_version; + SoundRpcBankCommand load_bank; + SoundRpcSetLanguageCommand set_language; + SoundRpcPlayCommand play; + SoundRpcSoundIdCommand sound_id; + SoundRpcSetFPSCommand fps; + SoundRpcSetEarTrans ear_trans; + SoundRpc2SetEarTrans ear_trans_j2; + SoundRpcSetReverb reverb; + SoundRpcSetFallof fallof; + SoundRpcSetFallofCurve fallof_curve; + SoundRpcGroupCommand group; + SoundRpcSetFlavaCommand flava; + SoundRpcMasterVolCommand master_volume; + SoundRpcSetParamCommand param; + SoundRpcStereoMode stereo_mode; + SoundRpcSetMidiReg midi_reg; + SoundRpcSetMirrror mirror; + u8 max_size[0x4C]; // Temporary + }; +}; + +static_assert(sizeof(SoundRpcCommand) == 0x50); + +struct SoundIopInfo { + u32 frame; + s32 strpos; + u32 std_id; + u32 freemem; + u8 chinfo[48]; + u32 freemem2; + u32 nocd; + u32 dirtycd; + u32 diskspeed[2]; + u32 lastspeed; + s32 dupseg; + u32 times[41]; + u32 times_seq; + u8 pad[10]; // pad up to transfer size +}; + +u32 Thread_Loader(); +u32 Thread_Player(); + +s32 VBlank_Handler(void*); + +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/jak1/ssound.cpp b/game/overlord/jak1/ssound.cpp new file mode 100644 index 0000000000..7bf1f56087 --- /dev/null +++ b/game/overlord/jak1/ssound.cpp @@ -0,0 +1,153 @@ +#include "ssound.h" + +#include +#include + +#include "common/util/Assert.h" + +#include "game/overlord/common/srpc.h" +#include "game/overlord/common/ssound.h" +#include "game/overlord/jak1/iso.h" +#include "game/runtime.h" +#include "game/sound/sndshim.h" + +using namespace iop; + +namespace jak1 { +VolumePair gPanTable[361]; + +s32 gMusicVol = 0x400; + +u32 gStreamSRAM = 0; +u32 gTrapSRAM = 0; + +void CatalogSRAM() {} + +static void* SndMemAlloc(); +static void SndMemFree(void* ptr); +void InitSound_Overlord() { + for (auto& s : gSounds) { + s.id = 0; + } + + if (g_game_version == GameVersion::Jak1) { + SetCurve(1, 0, 0); + SetCurve(2, 4096, 0); + SetCurve(3, 0, 4096); + SetCurve(4, 2048, 0); + SetCurve(5, 2048, 2048); + SetCurve(6, -4096, 0); + SetCurve(7, -2048, 0); + } else { + SetCurve(2, 0, 0); + SetCurve(9, 0, 0); + SetCurve(11, 0, 0); + SetCurve(10, 0, 0); + SetCurve(3, 4096, 0); + SetCurve(4, 0, 4096); + SetCurve(5, 2048, 0); + SetCurve(6, 2048, 2048); + SetCurve(7, -4096, 0); + SetCurve(8, -2048, 0); + } + + snd_StartSoundSystem(); + snd_RegisterIOPMemAllocator(SndMemAlloc, SndMemFree); + snd_LockVoiceAllocator(1); + u32 voice = snd_ExternVoiceAlloc(2, 0x7f); + snd_UnlockVoiceAllocator(); + + // The voice allocator returns a number in the range 0-47 where voices + // 0-23 are on SPU Core 0 and 24-47 are on core 2. + // For some reason we convert it to this format where 0-47 alternate core every step. + voice = voice / 24 + ((voice % 24) * 2); + + // Allocate SPU RAM for our streams. + // (Which we don't need on PC) + gStreamSRAM = snd_SRAMMalloc(0xc030); + gTrapSRAM = gStreamSRAM + 0xC000; + + snd_SetMixerMode(0, 0); + + for (int i = 0; i < 8; i++) { + snd_SetGroupVoiceRange(i, 0x10, 0x2f); + } + + snd_SetGroupVoiceRange(1, 0, 0xf); + snd_SetGroupVoiceRange(2, 0, 0xf); + + snd_SetReverbDepth(SND_CORE_0 | SND_CORE_1, 0, 0); + snd_SetReverbType(SND_CORE_0, SD_REV_MODE_OFF); + snd_SetReverbType(SND_CORE_1, SD_REV_MODE_OFF); + + CatalogSRAM(); + + for (int i = 0; i < 91; i++) { + s16 opposing_front = static_cast(((i * 0x33ff) / 0x5a) + 0xc00); + + s16 rear_right = static_cast(((i * -0x2800) / 0x5a) + 0x3400); + s16 rear_left = static_cast(((i * -0xbff) / 0x5a) + 0x3fff); + + gPanTable[90 - i].left = 0x3FFF; + gPanTable[180 - i].left = opposing_front; + gPanTable[270 - i].left = rear_right; + gPanTable[360 - i].left = rear_left; + + gPanTable[i].right = opposing_front; + gPanTable[90 + i].right = 0x3FFF; + gPanTable[180 + i].right = rear_left; + gPanTable[270 + i].right = rear_right; + } + + snd_SetPanTable((s16*)gPanTable); + snd_SetPlayBackMode(2); + + SemaParam sema; + sema.attr = SA_THPRI; + sema.init_count = 1; + sema.max_count = 1; + sema.option = 0; + + gSema = CreateSema(&sema); + if (gSema < 0) { + while (true) + ; + } +} + +void SetEarTrans(Vec3w* ear_trans0, Vec3w* ear_trans1, Vec3w* cam_trans, s32 cam_angle) { + s32 tick = snd_GetTick(); + u32 delta = tick - sLastTick; + sLastTick = tick; + + gEarTrans[0] = *ear_trans0; + gEarTrans[1] = *ear_trans1; + gCamTrans = *cam_trans; + gCamAngle = cam_angle; + + for (auto& s : gSounds) { + if (s.id != 0 && s.is_music == 0) { + if (s.auto_time != 0) { + UpdateAutoVol(&s, delta); + } + UpdateLocation(&s); + } + } + + SetVAGVol(); +} + +void SetMusicVol() { + s32 volume = (gMusicVol * gMusicFade >> 0x10) * gMusicTweak >> 7; + snd_SetMasterVolume(1, volume); + snd_SetMasterVolume(2, volume); +} + +// Do we even need/want these +// TODO void SetBufferMem() {} +// TODO void ReleaseBufferMem() {} +static void* SndMemAlloc() { + return nullptr; +} +static void SndMemFree(void* /*ptr*/) {} +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/jak1/ssound.h b/game/overlord/jak1/ssound.h new file mode 100644 index 0000000000..e1e583489b --- /dev/null +++ b/game/overlord/jak1/ssound.h @@ -0,0 +1,18 @@ +#pragma once + +#include "game/overlord/common/sbank.h" +#include "game/overlord/common/ssound.h" +#include "game/sce/iop.h" + +namespace jak1 { + +extern VolumePair gPanTable[361]; +extern u32 gStreamSRAM; +extern u32 gTrapSRAM; + +extern s32 gMusicVol; + +void InitSound_Overlord(); +void SetEarTrans(Vec3w* ear_trans1, Vec3w* ear_trans2, Vec3w* cam_trans, s32 cam_angle); +void SetMusicVol(); +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/jak1/stream.cpp b/game/overlord/jak1/stream.cpp new file mode 100644 index 0000000000..11f45b7bef --- /dev/null +++ b/game/overlord/jak1/stream.cpp @@ -0,0 +1,226 @@ +/*! + * @file stream.cpp + * OVERLORD streaming driver. + * Supports loading a file directly to the EE, or loading chunks of a chunked file. + */ + +#include "stream.h" + +#include + +#include "common/util/Assert.h" +#include "common/util/FileUtil.h" + +#include "game/common/play_rpc_types.h" +#include "game/common/str_rpc_types.h" +#include "game/overlord/common/iso.h" +#include "game/overlord/common/isocommon.h" +#include "game/overlord/jak1/iso.h" +#include "game/overlord/jak1/iso_api.h" +#include "game/overlord/jak1/srpc.h" +#include "game/runtime.h" +#include "game/sce/iop.h" + +using namespace iop; + +namespace jak1 { +static RPC_Str_Cmd_Jak1 sSTRBuf; +static RPC_Play_Cmd_Jak1 sPLAYBuf[2]; + +void* RPC_STR(unsigned int fno, void* _cmd, int y); +void* RPC_PLAY(unsigned int fno, void* _cmd, int y); + +static constexpr int PLAY_MSG_SIZE = 0x40; + +static u32 global_vag_count = 0; + +/*! + * We cache the chunk file headers so we can avoid seeking to the chunk header each time we + * need to load another chunk, even if we load chunks out of order. + */ +struct CacheEntry { + // the record for the chunk file described. + FileRecord* fr = nullptr; + // counts down from INT32_MAX - 1 each time we have a cache miss. + s32 countdown = 0; + // the actual cached data. + StrFileHeaderJ1 header; +}; + +// the actual header cache. +constexpr int STR_INDEX_CACHE_SIZE = 4; +CacheEntry sCacheJ1[STR_INDEX_CACHE_SIZE]; + +void stream_init_globals() { + memset(&sSTRBuf, 0, sizeof(RPC_Str_Cmd_Jak1)); + memset(&sPLAYBuf, 0, sizeof(RPC_Play_Cmd_Jak1) * 2); +} + +/*! + * Run the STR RPC handler. + */ +u32 STRThread() { + sceSifQueueData dq; + sceSifServeData serve; + + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, STR_RPC_ID[g_game_version], RPC_STR, &sSTRBuf, nullptr, nullptr, &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + return 0; +} + +u32 PLAYThread() { + sceSifQueueData dq; + sceSifServeData serve; + + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, PLAY_RPC_ID[g_game_version], RPC_PLAY, sPLAYBuf, nullptr, nullptr, &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + return 0; +} + +/*! + * The STR RPC handler. + */ +void* RPC_STR(unsigned int fno, void* _cmd, int y) { + (void)fno; + (void)y; + auto* cmd = (RPC_Str_Cmd_Jak1*)_cmd; + if (cmd->chunk_id < 0) { + // it's _not_ a stream file. So we just treat it like a normal load. + + // find the file with the given name + auto file_record = isofs->find(cmd->name); + if (file_record == nullptr) { + // file not found! + printf("[OVERLORD STR] Failed to find file %s for loading.\n", cmd->name); + cmd->result = STR_RPC_RESULT_ERROR; + } else { + // load directly to the EE + cmd->length = LoadISOFileToEE(file_record, cmd->ee_addr, cmd->length); + if (cmd->length) { + // successful load! + cmd->result = STR_RPC_RESULT_DONE; + } else { + // there was an error loading. + cmd->result = STR_RPC_RESULT_ERROR; + } + } + } else { + // it's a chunked file. These are only animations - these have a separate naming scheme. + char animation_iso_name[128]; + file_util::ISONameFromAnimationName(animation_iso_name, cmd->name); + auto file_record = isofs->find_in(animation_iso_name); + + if (!file_record) { + // didn't find the file + printf("[OVERLORD STR] Failed to find animation %s\n", cmd->name); + cmd->result = STR_RPC_RESULT_ERROR; + } else { + // found it! See if we've cached this animation's header. + int cache_entry = 0; + int oldest = INT32_MAX; + int oldest_idx = -1; + while (cache_entry < STR_INDEX_CACHE_SIZE && sCacheJ1[cache_entry].fr != file_record) { + sCacheJ1[cache_entry].countdown--; + if (sCacheJ1[cache_entry].countdown < oldest) { + oldest_idx = cache_entry; + oldest = sCacheJ1[cache_entry].countdown; + } + cache_entry++; + } + + if (cache_entry == STR_INDEX_CACHE_SIZE) { + // cache miss, we need to load the header to the header cache on the IOP + cache_entry = oldest_idx; + sCacheJ1[oldest_idx].fr = file_record; + sCacheJ1[oldest_idx].countdown = INT32_MAX - 1; + if (!LoadISOFileToIOP(file_record, &sCacheJ1[oldest_idx].header, sizeof(StrFileHeaderJ1))) { + printf("[OVERLORD STR] Failed to load chunk file header for animation %s\n", cmd->name); + cmd->result = 1; + return cmd; + } + } + + // load data, using the cached header to find the location of the chunk. + if (!LoadISOFileChunkToEE(file_record, cmd->ee_addr, + sCacheJ1[cache_entry].header.sizes[cmd->chunk_id], + sCacheJ1[cache_entry].header.sectors[cmd->chunk_id])) { + printf("[OVERLORD STR] Failed to load chunk %d for animation %s\n", cmd->chunk_id, + cmd->name); + cmd->result = 1; + } else { + // successful load! + cmd->length = sCacheJ1[cache_entry].header.sizes[cmd->chunk_id]; + cmd->result = 0; + } + } + } + + return cmd; +} + +void* RPC_PLAY([[maybe_unused]] unsigned int fno, void* _cmd, int size) { + s32 n_messages = size / PLAY_MSG_SIZE; + char namebuf[16]; + + auto* cmd = (RPC_Play_Cmd_Jak1*)(_cmd); + while (n_messages > 0) { + if (cmd->name[0] == '$') { + char* name_part = &cmd->name[1]; + size_t name_len = strlen(name_part); + + if (name_len < 9) { + memset(namebuf, ' ', 8); + memcpy(namebuf, name_part, name_len); + } else { + memcpy(namebuf, name_part, 8); + } + + // ASCII toupper + for (int i = 0; i < 8; i++) { + if (namebuf[i] >= 0x61 && namebuf[i] < 0x7b) { + namebuf[i] -= 0x20; + } + } + } else { + file_util::ISONameFromAnimationName(namebuf, cmd->name); + } + + auto vag = FindVAGFile(namebuf); + memcpy(namebuf, "VAGWAD ", 8); + strcpy(&namebuf[8], gLanguage); + + FileRecord* file = nullptr; + + global_vag_count = (global_vag_count + 1) & 0x3f; + if (!cmd->result && global_vag_count == 0) { + namebuf[0] -= 3; + file = isofs->find_in(namebuf); + namebuf[0] += 3; + } + + file = isofs->find_in(namebuf); + + if (cmd->result == 0) { + PlayVAGStream(file, vag, cmd->address, 0x400, 1, nullptr); + } else if (cmd->result == 1) { + StopVAGStream(vag, 1); + } else { + QueueVAGStream(file, vag, 0, 1); + } + + n_messages--; + cmd++; + } + + return _cmd; +} + +} // namespace jak1 diff --git a/game/overlord/stream.h b/game/overlord/jak1/stream.h similarity index 59% rename from game/overlord/stream.h rename to game/overlord/jak1/stream.h index 70bb710f2b..5d49f4bce4 100644 --- a/game/overlord/stream.h +++ b/game/overlord/jak1/stream.h @@ -1,11 +1,9 @@ #pragma once -#ifndef JAK_V2_STREAM_H -#define JAK_V2_STREAM_H - #include "common/common_types.h" + +namespace jak1 { u32 STRThread(); u32 PLAYThread(); void stream_init_globals(); - -#endif // JAK_V2_STREAM_H +} // namespace jak1 \ No newline at end of file diff --git a/game/overlord/jak2/dma.cpp b/game/overlord/jak2/dma.cpp new file mode 100644 index 0000000000..683e4360eb --- /dev/null +++ b/game/overlord/jak2/dma.cpp @@ -0,0 +1,232 @@ +#include "dma.h" + +#include "game/overlord/jak2/vag.h" +#include "game/sound/sdshim.h" +#include "game/sound/sndshim.h" + +namespace jak2 { + +// This file has SPU DMA functions. Unlike Jak 1, they run SPU DMA in the background, and it doesn't +// work correctly if we assume instant DMA. We end up running the DMA finished interrupt handler +// in the loop of ISO thread - this makes sure that DMA appears to finish pretty quickly, and before +// any more loading stuff happens (so loads will never "wait" for the fake simulated dma). + +s32 SpuDmaStatus = 0; //! set to 1 when SPU DMA is in progress +VagCmd* DmaVagCmd; //! VagCmd currently doing SPU DMA +VagCmd* DmaStereoVagCmd; //! VagCmd for the stereo sibling SPU DMA +int pending_dma = 0; //! PC-port addition to indicate that "dma is running" + +constexpr int kDmaDelay = 10; + +void dma_init_globals() { + SpuDmaStatus = 0; + DmaVagCmd = nullptr; + DmaStereoVagCmd = nullptr; + pending_dma = 0; +} + +/*! + * Interrupt handler for DMA completion. + */ +int SpuDmaIntr(int, void*) { + if (SpuDmaStatus != 1) { + return 0; + } + + if (!DmaVagCmd) { + goto cleanup; + } + + if (!DmaStereoVagCmd) { + // not stereo mode, just set status bits + if ((DmaVagCmd->num_processed_chunks & 1U) == 0) { + DmaVagCmd->sb_even_buffer_dma_complete = 1; + } else { + DmaVagCmd->sb_odd_buffer_dma_complete = 1; + } + } else { + // in stereo mode, we need to do two DMA transfers. The first one starts the second stereo one. + if (DmaStereoVagCmd->xfer_size != 0) { + // pick the appropriate double buffer + s16 chan; + u8* iop_ptr; + int spu_addr; + if ((DmaStereoVagCmd->num_processed_chunks & 1U) == 0) { + chan = DmaVagCmd->dma_chan; + iop_ptr = DmaStereoVagCmd->dma_iop_mem_ptr; + spu_addr = DmaStereoVagCmd->spu_stream_dma_mem_addr; + } else { + chan = DmaVagCmd->dma_chan; + iop_ptr = DmaStereoVagCmd->dma_iop_mem_ptr; + spu_addr = DmaStereoVagCmd->spu_stream_dma_mem_addr + 0x2000; + } + + // clear the pending transfer, so we don't try to start it again + int old_xfer = DmaStereoVagCmd->xfer_size; + DmaStereoVagCmd->xfer_size = 0; + DmaStereoVagCmd->dma_iop_mem_ptr = nullptr; + + // start the transfer! + pending_dma = kDmaDelay; + sceSdVoiceTrans((int)chan, 0, iop_ptr, spu_addr, old_xfer); + // and return. This will get called again on completion + return 0; + } + + // if we made it here, both transfers are done, so just toggle the buffers. + if ((DmaVagCmd->num_processed_chunks & 1U) == 0) { + DmaVagCmd->sb_even_buffer_dma_complete = 1; + DmaStereoVagCmd->sb_even_buffer_dma_complete = 1; + } else { + DmaVagCmd->sb_odd_buffer_dma_complete = 1; + DmaStereoVagCmd->sb_odd_buffer_dma_complete = 1; + } + } + + // if we just finished the first upload, start playing! I'm not entirely sure if this is playing + // sound yet, or if we're just looping and waiting for the second upload to actually start. + // (we don't set the appropriate volumes here, so this is probably not the real playback) + if (DmaVagCmd->num_processed_chunks == 1) { + int pitch = CalculateVAGPitch(DmaVagCmd->pitch1, DmaVagCmd->unk_256_pitch2); + if (!DmaStereoVagCmd) { + DmaVagCmd->spu_addr_to_start_playing = 0; + sceSdSetAddr(((s16)DmaVagCmd->voice) | 0x2040, DmaVagCmd->spu_stream_dma_mem_addr + 0x30); + sceSdSetParam((u16)DmaVagCmd->voice | 0x300, 0xf); + sceSdSetParam((u16)DmaVagCmd->voice | 0x400, 0x1fc0); + sceSdSetParam((u16)DmaVagCmd->voice | 0x200, pitch); + + // start playback! + sceSdkey_on_jak2_voice(DmaVagCmd->voice); + } else { + // same for stereo, but we start both voices. + DmaVagCmd->spu_addr_to_start_playing = 0; + DmaStereoVagCmd->spu_addr_to_start_playing = 0; + + sceSdSetAddr((u16)DmaVagCmd->voice | 0x2040, DmaVagCmd->spu_stream_dma_mem_addr + 0x30); + sceSdSetAddr((u16)DmaStereoVagCmd->voice | 0x2040, + DmaStereoVagCmd->spu_stream_dma_mem_addr + 0x30); + sceSdSetParam((u16)DmaVagCmd->voice | 0x300, 0xf); + sceSdSetParam((u16)DmaStereoVagCmd->voice | 0x300, 0xf); + sceSdSetParam((u16)DmaVagCmd->voice | 0x400, 0x1fc0); + sceSdSetParam((u16)DmaStereoVagCmd->voice | 0x400, 0x1fc0); + sceSdSetParam((u16)DmaVagCmd->voice | 0x200, pitch); + sceSdSetParam((u16)DmaStereoVagCmd->voice | 0x200, pitch); + + sceSdkey_on_jak2_voice(DmaVagCmd->voice); + sceSdkey_on_jak2_voice(DmaStereoVagCmd->voice); + } + } else if (DmaVagCmd->num_processed_chunks == 2) { + // on the second chunk's DMA finish, start playing by unpausing. + + // set playing flag + DmaVagCmd->sb_playing = 1; + if (DmaStereoVagCmd) { + DmaStereoVagCmd->sb_playing = 1; + } + + // if we paused since the first, kill the voice. + if (DmaVagCmd->sb_paused) { + if (!DmaStereoVagCmd) { + sceSdSetParam((u16)DmaVagCmd->voice | 0x200, 0); + } else { + sceSdSetParam((u16)DmaStereoVagCmd->voice | 0x200, 0); + sceSdSetParam((u16)DmaVagCmd->voice | 0x200, 0); + } + sceSdkey_off_jak2_voice(DmaVagCmd->voice); + goto hack; + } + + // mark as paused manually and unpause to start playback. + DmaVagCmd->sb_paused = 1; + UnPauseVAG(DmaVagCmd, 0); + hack:; + } + + // now that we're done, mark it as not in use and remove from DmaVagCmd. + DmaVagCmd->safe_to_change_dma_fields = 1; + if (DmaStereoVagCmd) { + DmaStereoVagCmd->safe_to_change_dma_fields = 1; + } + DmaVagCmd = nullptr; + DmaStereoVagCmd = nullptr; + +cleanup: + // sceSdSetTransIntrHandler(param_1, nullptr, nullptr); + // if (-1 < param_1) { + // snd_FreeSPUDMA(param_1); + // } + SpuDmaStatus = 0; + return 0; +} + +/*! + * Call any pending DMA transfer complete interrupt handlers. + */ +void spu_dma_hack() { + if (pending_dma) { + pending_dma--; + if (!pending_dma) { + SpuDmaIntr(0, nullptr); + } + } +} + +/*! + * Despite the name, this does not sync and just starts dma. + */ +bool DMA_SendToSPUAndSync(uint8_t* iop_mem, + int size_one_side, + int spu_addr, + VagCmd* cmd, + int /*disable_intr*/) { + int chan; + int ret; + if ((SpuDmaStatus == 0) && (chan = snd_GetFreeSPUDMA(), chan != -1)) { + DmaVagCmd = cmd; + if (cmd) { + auto* sibling = cmd->stereo_sibling; + // mark as in-use by dma. + cmd->safe_to_change_dma_fields = 0; + DmaStereoVagCmd = sibling; + if (sibling) { + sibling->dma_iop_mem_ptr = iop_mem + size_one_side; + sibling->xfer_size = size_one_side; + sibling->num_processed_chunks = cmd->num_processed_chunks; + cmd->dma_chan = chan; + } + } + SpuDmaStatus = 1; + + // note: I've bypassed the way the dma interrupts work for jak 2. + // here, the interrupt handler set is removed, and we instead set a pending_dma flag. + // the actual interrupt will be run from iso.cpp, in the isothread loop. + // sceSdSetTransIntrHandler(chan, SpuDmaIntr, 0); + pending_dma = kDmaDelay; // added + int sz = sceSdVoiceTrans((int)(short)chan, 0, iop_mem, spu_addr, size_one_side); + // if (disable_intr == 1) { + // CpuResumeIntr(local_28[0]); + //} + ret = int(size_one_side + 0x3fU & 0xffffffc0) <= sz; + } else { + ret = false; + // if (disable_intr == 1) { + // CpuResumeIntr(local_28[0]); + ret = false; + //} + } + return ret; +} + +void DmaCancelThisVagCmd(VagCmd* param_1) { + if (DmaVagCmd == param_1) { + sceSdSetTransIntrHandler(DmaVagCmd->dma_chan, nullptr, nullptr); + if (-1 < DmaVagCmd->dma_chan) { + snd_FreeSPUDMA(DmaVagCmd->dma_chan); + } + DmaVagCmd = nullptr; + DmaStereoVagCmd = nullptr; + SpuDmaStatus = 0; + } +} + +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/dma.h b/game/overlord/jak2/dma.h new file mode 100644 index 0000000000..43bc84c7e5 --- /dev/null +++ b/game/overlord/jak2/dma.h @@ -0,0 +1,13 @@ +#pragma once + +#include "common/common_types.h" + +namespace jak2 { +struct VagCmd; +void dma_init_globals(); +bool DMA_SendToSPUAndSync(uint8_t* iop_mem, + int size_one_side, + int spu_addr, + VagCmd* cmd, + int disable_intr); +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/iso.cpp b/game/overlord/jak2/iso.cpp new file mode 100644 index 0000000000..a69ff313cd --- /dev/null +++ b/game/overlord/jak2/iso.cpp @@ -0,0 +1,1215 @@ +#include "iso.h" + +#include +#include + +#include "common/util/Assert.h" + +#include "game/common/dgo_rpc_types.h" +#include "game/overlord/common/dma.h" +#include "game/overlord/common/iso.h" +#include "game/overlord/common/srpc.h" +#include "game/overlord/jak2/iso_api.h" +#include "game/overlord/jak2/iso_cd.h" +#include "game/overlord/jak2/iso_queue.h" +#include "game/overlord/jak2/spustreams.h" +#include "game/overlord/jak2/srpc.h" +#include "game/overlord/jak2/ssound.h" +#include "game/overlord/jak2/stream.h" +#include "game/overlord/jak2/streamlist.h" +#include "game/overlord/jak2/vag.h" +#include "game/runtime.h" +#include "game/sce/iop.h" + +using namespace iop; + +namespace jak2 { +void spu_dma_hack(); +u32 DGOThread(); +FileRecord* FindISOFile(const char* name); +int LoadISOFileToIOP(FileRecord* fr, uint8_t* dest, int length); +int RunDGOStateMachine(CmdHeader* param_1, Buffer* param_2); +void CancelDGO(RPC_Dgo_Cmd* cmd); +int CopyDataToIOP(CmdHeader* param_1, Buffer* param_2); +int CopyDataToEE(CmdHeader* param_1, Buffer* param_2); + +IsoFs* isofs; + +int iso_init_flag = 0; +int iso_mbx = 0; +int dgo_mbx = 0; +int sync_mbx = 0; +int iso_thread = 0; +int dgo_thread = 0; +int str_thread = 0; +int play_thread = 0; + +int ext_pause = 0; +int ext_resume = 0; + +CmdDgo sLoadDgo; // renamed from scmd to sLoadDGO in Jak 2 +static RPC_Dgo_Cmd sRPCBuff[1]; +VagDir gVagDir; + +/// The main buffer used for reading data and doing blzo decompression. +LargeBuffer* SpLargeBuffer = nullptr; + +void iso_init_globals() { + isofs = nullptr; + iso_init_flag = 0; + iso_mbx = 0; + dgo_mbx = 0; + sync_mbx = 0; + iso_thread = 0; + dgo_thread = 0; + str_thread = 0; + play_thread = 0; + ext_pause = 0; + ext_resume = 0; + memset(&sLoadDgo, 0, sizeof(sLoadDgo)); + memset(&gVagDir, 0, sizeof(gVagDir)); + memset(sRPCBuff, 0, sizeof(RPC_Dgo_Cmd)); + SpLargeBuffer = nullptr; +} + +// The "ISO Thread" is responsible managing "messages" - both starting reads for messages that need +// data, and calling callbacks on messages that have pending data. + +/*! + * Set up messageboxes/threads for the ISO thread. + */ +u32 InitISOFS() { + isofs = &iso_cd; + iso_init_flag = 1; + + SpLargeBuffer = (LargeBuffer*)ScratchPadMemory; + ScratchPadMemory += sizeof(LargeBuffer); + + MbxParam mbx_param; + mbx_param.attr = 0; + mbx_param.option = 0; + iso_mbx = CreateMbx(&mbx_param); + if (iso_mbx < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: iso InitISOFS: Cannot create ISO mbx\n"); + printf("IOP: ======================================================================\n"); + return 1; + } + + mbx_param.attr = 0; + mbx_param.option = 0; + dgo_mbx = CreateMbx(&mbx_param); + if (dgo_mbx < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: iso InitISOFS: Cannot create DGO mbx\n"); + printf("IOP: ======================================================================\n"); + return 1; + } + mbx_param.attr = 0; + mbx_param.option = 0; + sync_mbx = CreateMbx(&mbx_param); + if (sync_mbx < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: iso InitISOFS: Cannot create sync mbx\n"); + printf("IOP: ======================================================================\n"); + return 1; + } + + ThreadParam thread_param; + thread_param.entry = ISOThread; + thread_param.initPriority = 0x6e; + thread_param.attr = TH_C; + thread_param.stackSize = 0x1000; + thread_param.option = 0; + iso_thread = CreateThread(&thread_param); + if (iso_thread < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: iso InitISOFS: Cannot create ISO thread\n"); + printf("IOP: ======================================================================\n"); + return 1; + } + thread_param.entry = DGOThread; + thread_param.attr = TH_C; + thread_param.initPriority = 0x6f; + thread_param.stackSize = 0x800; + thread_param.option = 0; + dgo_thread = CreateThread(&thread_param); + if (dgo_thread < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: iso InitISOFS: Cannot create DGO thread\n"); + printf("IOP: ======================================================================\n"); + return 1; + } + thread_param.entry = STRThread; + thread_param.attr = TH_C; + thread_param.initPriority = 0x72; + thread_param.stackSize = 0x800; + thread_param.option = 0; + str_thread = CreateThread(&thread_param); + if (str_thread < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: iso InitISOFS: Cannot create STR thread\n"); + printf("IOP: ======================================================================\n"); + return 1; + } + thread_param.entry = PLAYThread; + thread_param.attr = 0x2000000; + thread_param.initPriority = 0x3c; + thread_param.stackSize = 0x800; + thread_param.option = 0; + play_thread = CreateThread(&thread_param); + if (play_thread < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: iso InitISOFS: Cannot create PLAY thread\n"); + printf("IOP: ======================================================================\n"); + return 1; + } + StartThread(iso_thread, 0); + StartThread(dgo_thread, 0); + StartThread(str_thread, 0); + StartThread(play_thread, 0); + // wait for ISO Thread to initialize + WaitMbx(sync_mbx); + + FileRecord* vagdir_file = FindISOFile("VAGDIR.AYB"); + if (vagdir_file) { + LoadISOFileToIOP(vagdir_file, (u8*)&gVagDir, sizeof(gVagDir)); + } else { + printf("IOP: ======================================================================\n"); + printf("IOP : iso InitISOFS : cannot load VAG directory\n"); + printf("IOP: ======================================================================\n"); + } + + // loading screen thing. + /* + iVar2 = FindISOFile(param_2); + if (iVar2 == 0) { + return iso_init_flag; + } + LoadISOFileToEE(iVar2, 0x1000000, 0x800000); + */ + return iso_init_flag; +} + +void IsoQueueVagStream(VagCmd* cmd, int param_2) { + int iVar1; + VagCmd* new_cmd; + LoadStackEntry* pLVar5; + VagCmd* pVVar7; + VagCmd* new_stereo_cmd; + + // HACK + if (!cmd->vag_dir_entry) { + printf("IsoQueueVagStream: no entry for %s\n", cmd->name); + return; + } + + if (param_2 == 1) { + // CpuSuspendIntr(local_20); + } + new_stereo_cmd = nullptr; + + // allocate/find a vag cmd to hold this stream command. We don't own the incoming command. + if ((cmd->id == 0) || (((cmd->vag_dir_entry->flag & 1U) != 0 && + (iVar1 = HowManyBelowThisPriority(cmd->priority, 0), iVar1 < 2)))) + goto LAB_000049dc; + new_cmd = FindThisVagStream(cmd->name, cmd->id); + if (!new_cmd) { + new_cmd = SmartAllocVagCmd(cmd); + if (!new_cmd) + goto LAB_000049dc; + + if ((*(u32*)&new_cmd->status_bytes[BYTE4] & 0xffff00) != 0) { + IsoStopVagStream(new_cmd, 0); + } + + // copy data from the other command to us. + new_cmd->header.unk_0 = cmd->header.unk_0; + new_cmd->header.unk_4 = cmd->header.unk_4; + new_cmd->header.cmd_kind = cmd->header.cmd_kind; + new_cmd->header.status = cmd->header.status; + + new_cmd->header.mbx_to_reply = cmd->header.mbx_to_reply; + new_cmd->header.thread_id = cmd->header.thread_id; + new_cmd->header.unk_24 = cmd->header.unk_24; + new_cmd->header.callback_buffer = cmd->header.callback_buffer; + + new_cmd->header.callback = cmd->header.callback; + new_cmd->header.lse = cmd->header.lse; + + new_cmd->file_record = cmd->file_record; + new_cmd->vag_dir_entry = cmd->vag_dir_entry; + strncpy(new_cmd->name, cmd->name, 0x30); + new_cmd->unk_196 = cmd->unk_196; + new_cmd->num_processed_chunks = cmd->num_processed_chunks; + new_cmd->xfer_size = cmd->xfer_size; + new_cmd->unk_248 = cmd->unk_248; + new_cmd->unk_260 = cmd->unk_260; + new_cmd->unk_264 = cmd->unk_264; + new_cmd->unk_268 = cmd->unk_268; + new_cmd->vol_multiplier = cmd->vol_multiplier; + new_cmd->unk_256_pitch2 = cmd->unk_256_pitch2; + new_cmd->id = cmd->id; + + new_cmd->plugin_id = cmd->plugin_id; + new_cmd->unk_136 = cmd->unk_136; + new_cmd->unk_176 = cmd->unk_176; + new_cmd->unk_288 = cmd->unk_288; + new_cmd->unk_292 = cmd->unk_292; + new_cmd->unk_296 = cmd->unk_296; + new_cmd->vec3.x = cmd->vec3.x; + new_cmd->vec3.y = cmd->vec3.y; + new_cmd->vec3.z = cmd->vec3.z; + InitVAGCmd(new_cmd, 1); + new_cmd->sb_scanned = true; + + // check for stereo + if ((new_cmd->vag_dir_entry->flag & 1U) != 0) { + // try allocating it + new_stereo_cmd = SmartAllocVagCmd(cmd); + if (!new_stereo_cmd) { + // no room for stereo, give up + new_cmd->sb_scanned = false; + ReleaseMessage(&new_cmd->header, 0); + RemoveVagCmd(new_cmd, 0); + FreeVagCmd(new_cmd, 0); + new_cmd = nullptr; + } else { + // set up stereo command. + if ((*(u32*)&new_stereo_cmd->status_bytes[BYTE4] & 0xffff00) != 0) { + IsoStopVagStream(new_stereo_cmd, 0); + } + new_stereo_cmd->status_bytes[BYTE11] = true; + new_cmd->stereo_sibling = new_stereo_cmd; + new_stereo_cmd->stereo_sibling = new_cmd; + strncpy(new_stereo_cmd->name, "Stereo", 0x30); + new_stereo_cmd->id = ~new_cmd->id; + new_stereo_cmd->sb_scanned = true; + new_stereo_cmd->vag_dir_entry = new_cmd->vag_dir_entry; + } + } + if (new_cmd == nullptr) + goto LAB_000049dc; + + // queue the command. + iVar1 = QueueMessage(&new_cmd->header, 3, "QueueVAGStream", 0); + if (iVar1 == 0) { + // queue failed, give up. + new_cmd->sb_scanned = false; + RemoveVagCmd(new_cmd, 0); + FreeVagCmd(new_cmd, 0); + if ((new_cmd->vag_dir_entry->flag & 1U) != 0) { + new_stereo_cmd->sb_scanned = false; + RemoveVagCmd(new_stereo_cmd, 0); + FreeVagCmd(new_stereo_cmd, 0); + } + ReleaseMessage(&new_cmd->header, 0); + } else { + // queue succeeded! open the file + if (new_cmd->vag_dir_entry == nullptr) { + (new_cmd->header).lse = nullptr; + } else { + pLVar5 = (isofs->open_wad)(new_cmd->file_record, new_cmd->vag_dir_entry->offset); + (new_cmd->header).lse = pLVar5; + } + if (cmd->unk_288 != 0) { + new_cmd->status_bytes[BYTE10] = true; + } + if (cmd->unk_292 != 0) { + new_cmd->unk_232 = true; + } + new_cmd->sb_paused = true; + + // set up name/priority + SetNewVagCmdPri(new_cmd, cmd->priority, 0); + if (new_stereo_cmd != nullptr) { + new_stereo_cmd->sb_scanned = true; + new_stereo_cmd->sb_paused = true; + SetNewVagCmdPri(new_stereo_cmd, 10, 0); + } + SetVagStreamName(new_cmd, 0x30, 0); + if (new_stereo_cmd != nullptr) { + SetVagStreamName(new_stereo_cmd, 0x30, 0); + } + + // set up buffer + (new_cmd->header).status = -1; + (new_cmd->header).callback = ProcessVAGData; + } + if (new_cmd == nullptr) + goto LAB_000049dc; + } + pLVar5 = (new_cmd->header).lse; + pVVar7 = new_cmd->stereo_sibling; + new_cmd->unk_188 = 0; + new_cmd->unk_180 = 0; + new_cmd->unk_184 = 0; + new_cmd->unk_192 = 0; + + if (pLVar5 == nullptr) { + new_cmd->status_bytes[BYTE6] = true; + } else { + new_cmd->status_bytes[BYTE5] = true; + if (pVVar7 != nullptr) { + pVVar7->status_bytes[BYTE5] = true; + } + } +LAB_000049dc: + if (param_2 == 1) { + // CpuResumeIntr(local_20[0]); + } +} + +void IsoPlayVagStream(VagCmd* param_1, int param_2) { + VagCmd* iVar1; + LoadStackEntry* pLVar1; + VagCmd* pVVar1; + VagCmd* pRVar2; + + if (param_2 == 1) { + // CpuSuspendIntr(local_20); + } + pRVar2 = param_1->stereo_sibling; + iVar1 = FindThisVagStream(param_1->name, param_1->id); + if (iVar1 != nullptr) { + if (iVar1->status_bytes[BYTE4] == false) { + iVar1->vol_multiplier = param_1->vol_multiplier; + if (iVar1->sb_paused != false) { + if (ext_pause != 0) { + ext_resume = 1; + } + if (iVar1->sb_playing == false) { + iVar1->sb_paused = false; + if (pRVar2 != nullptr) { + pRVar2->sb_paused = false; + } + } else { + UnPauseVAG(iVar1, 0); + } + if ((u32)param_1->priority < 3) { + SetNewVagCmdPri(param_1, 7, 0); + } + } + iVar1->status_bytes[BYTE4] = true; + if (pRVar2 != nullptr) { + pRVar2->status_bytes[BYTE4] = true; + } + } else { + iVar1 = nullptr; + } + if (iVar1 != nullptr) { + pLVar1 = (iVar1->header).lse; + pVVar1 = iVar1->stereo_sibling; + iVar1->unk_188 = 0; + iVar1->unk_180 = 0; + iVar1->unk_184 = 0; + iVar1->unk_192 = 0; + + if (pLVar1 == nullptr) { + iVar1->status_bytes[BYTE6] = true; + } else { + iVar1->status_bytes[BYTE5] = true; + if (pVVar1 != nullptr) { + pVVar1->status_bytes[BYTE5] = true; + } + } + } + } + if (param_2 == 1) { + // CpuResumeIntr(local_20[0]); + } +} + +u32 _not_on_stack_sync = 0; +u32 IsoThreadCounter = 0; + +u32 ISOThread() { + bool bVar1; + CmdLoadSingleIop* inasdf; + Buffer* pBVar3; + int iVar4; + LoadStackEntry* pLVar5; + Page* pages; + VagCmd* pRVar7; + Buffer* pBVar8; + Buffer* pBVar9; + VagCmd* pRVar10; + int iVar11; + FileRecord* pFVar12; + VagStrListNode* pLVar14; + CmdLoadSingleIop* local_30; + + InitBuffers(); + InitVagCmds(); + InitSpuStreamsThread(); + + pBVar3 = AllocateBuffer(1, nullptr, 1); + iVar4 = (isofs->init)(/*pBVar3->unk_12*/); + if (iVar4 == 0) { + iso_init_flag = 0; + } + SendMbx(sync_mbx, &_not_on_stack_sync); + FreeBuffer(pBVar3, 1); + + do { + spu_dma_hack(); + + IsoThreadCounter = IsoThreadCounter + 1; + // iVar4 = PollMbx(&local_30, iso_mbx); + iVar4 = PollMbx((MsgPacket**)(&local_30), iso_mbx); + inasdf = local_30; + auto* in_dgo = (CmdDgo*)local_30; + auto* in_sbk = (CmdLoadSoundBank*)local_30; + auto* in_music = (CmdLoadMusic*)local_30; + auto* in_vag = (VagCmd*)local_30; + + if (iVar4 == 0) { + iVar4 = (local_30->header).cmd_kind; + (local_30->header).callback_buffer = (Buffer*)nullptr; + (local_30->header).unk_24 = 1; + (local_30->header).callback = NullCallback; + (local_30->header).lse = (LoadStackEntry*)nullptr; + if (iVar4 - 0x100U < 3) { + iVar4 = QueueMessage(&local_30->header, 2, "LoadSingle", 1); + if (iVar4 != 0) { + if ((inasdf->header).cmd_kind == 0x102) { + pFVar12 = inasdf->file_record; + iVar4 = inasdf->offset; + } else { + iVar4 = -1; + pFVar12 = inasdf->file_record; + } + pLVar5 = (isofs->open)(pFVar12, iVar4, OpenMode::KNOWN_NOT_BLZO); + (inasdf->header).lse = pLVar5; + if ((inasdf->header).lse == (LoadStackEntry*)nullptr) { + (inasdf->header).status = 6; + UnqueueMessage(&inasdf->header, 1); + LAB_00005120: + ReturnMessage(&inasdf->header); + } else { + inasdf->unk_64 = 0; + inasdf->ptr = inasdf->dest_addr; + iVar4 = (isofs->get_length)(inasdf->file_record); + inasdf->length_to_copy = iVar4; + if (iVar4 == 0) { + inasdf->length_to_copy = inasdf->length; + } else if (inasdf->length < iVar4) { + inasdf->length_to_copy = inasdf->length; + } + iVar4 = (inasdf->header).cmd_kind; + if (iVar4 == 0x101) { + (inasdf->header).callback = CopyDataToIOP; + } else { + if (iVar4 < 0x102) { + if (iVar4 != 0x100) { + (inasdf->header).status = -1; + goto LAB_00005144; + } + } else if (iVar4 != 0x102) + goto LAB_00004e50; + (inasdf->header).callback = CopyDataToEE; + } + LAB_00004e50: + (inasdf->header).status = -1; + } + } + } else if (iVar4 == 0x200) { + iVar4 = QueueMessage(&local_30->header, 0, "LoadDGO", 1); + if (iVar4 != 0) { + pLVar5 = (LoadStackEntry*)(isofs->open)(in_dgo->fr, -1, OpenMode::MODE1); + (in_dgo->header).lse = pLVar5; + if (pLVar5 != (LoadStackEntry*)nullptr) { + in_dgo->dgo_state = DgoState::Init; + (in_dgo->header).callback = RunDGOStateMachine; + goto LAB_00004e50; + } + UnqueueMessage(&in_dgo->header, 1); + SendMbx(iso_mbx, &sLoadDgo); + } + } else { + if (iVar4 == 0x300) { + gSoundInUse = gSoundInUse + 1; + if (gSoundEnable != 0) { + pages = (Page*)AllocPages(SpMemoryBuffers, 1); + if (pages == (Page*)nullptr) { + LAB_00004f28: + SendMbx(iso_mbx, inasdf); + } else { + SetBufferMem(pages->buffer, SpMemoryBuffers->page_size); + // iVar4 = inasdf->maybe_offset; + // pcVar6 = (code*)isofs->load_sound_bank; + iVar4 = isofs->load_sound_bank(in_sbk->bank_name, in_sbk->bank); + LAB_00004f6c: + // iVar4 = (*pcVar6)(&inasdf->file_record, iVar4); + (inasdf->header).status = iVar4; + ReleaseBufferMem(); + FreePagesList(SpMemoryBuffers, pages); + } + } + } else { + if (iVar4 != 0x380) { + if (iVar4 == 0x403) { + if (ext_pause == 0) { + SetVagStreamsNoStart(1, 1); + iVar4 = AnyVagRunning(); + if (iVar4 != 0) { + PauseVagStreams(); + } + ext_resume = (u32)(iVar4 != 0); + ext_pause = 1; + } + } else if (iVar4 == 0x404) { + if (ext_pause != 0) { + if (ext_resume != 0) { + UnPauseVagStreams(); // 0? + } + ext_pause = 0; + ext_resume = 0; + } + SetVagStreamsNoStart(0, 1); + } else if (iVar4 == 0x405) { + pRVar7 = FindVagStreamId(in_vag->id); + if (pRVar7 != nullptr) { + pRVar7->vol_multiplier = in_vag->vol_multiplier; + SetVAGVol(pRVar7, 1); + } + } else if (iVar4 == 0x406) { + pRVar7 = FindVagStreamId(in_vag->id); + if (pRVar7 != nullptr) { + pRVar7->unk_256_pitch2 = in_vag->unk_256_pitch2; + SetVAGVol(pRVar7, 1); + } + } else if (iVar4 == 0x407) { + MasterVolume[2] = in_vag->vol_multiplier; + SetAllVagsVol(-1); + } else { + if ((local_30->header).cmd_kind == 0x666) { + ReturnMessage(&local_30->header); + ASSERT_NOT_REACHED(); + } + (local_30->header).status = 4; + } + goto LAB_00005120; + } + gSoundInUse = gSoundInUse + 1; + if (gSoundEnable != 0) { + pages = (Page*)AllocPages(SpMemoryBuffers, 1); + if (pages == (Page*)nullptr) + goto LAB_00004f28; + SetBufferMem(pages->buffer, SpMemoryBuffers->page_size); + iVar4 = inasdf->offset; + // pcVar6 = (code*)isofs->load_music; + iVar4 = isofs->load_music(in_music->name, in_music->handle); + goto LAB_00004f6c; + } + } + gSoundInUse = gSoundInUse + -1; + ReturnMessage(&inasdf->header); + } + } else if (iVar4 == -0x1a9) { + return 0; + } + + LAB_00005144: + pBVar3 = (Buffer*)nullptr; + pRVar7 = (VagCmd*)GetMessage(); + + if (pRVar7 == nullptr) { + LAB_00005208:; + // (isofs->poll_drive)(); + } else { + u32 uVar13 = 1; + if ((pRVar7->header).callback == ProcessVAGData) { + if (pRVar7->xfer_size != 0) { + LAB_000051ac: + uVar13 = 2; + goto LAB_000051b0; + } + // no idea what happens here.. i think this is a bug and the callback_buffer == 0 should + // flip. + if (((pRVar7->header).callback_buffer == (Buffer*)nullptr) && + (uVar13 = 2, /*DAT_00000008 == 0*/ true)) + goto LAB_000051b0; + if (pRVar7->xfer_size != 0) + goto LAB_000051ac; + } else { + LAB_000051b0: + pBVar3 = AllocateBuffer(uVar13, pRVar7, 1); + } + if (pBVar3 == (Buffer*)nullptr) { + LAB_000051fc: + pRVar7 = nullptr; + } else { + iVar4 = (isofs->page_begin_read)((pRVar7->header).lse, pBVar3); + (pRVar7->header).status = iVar4; + if (iVar4 != -1) { + FreeBuffer(pBVar3, 1); + pBVar3 = (Buffer*)nullptr; + goto LAB_000051fc; + } + } + if (pRVar7 == nullptr) + goto LAB_00005208; + } + ProcessMessageData(); + if (pBVar3 != (Buffer*)nullptr) { + iVar4 = (isofs->sync_read)(/*pBVar3*/); + if (iVar4 == 8) { + FreeBuffer(pBVar3, 1); + pBVar3 = (Buffer*)nullptr; + } else { + (pRVar7->header).status = iVar4; + pBVar3->decomp_buffer = (uint8_t*)pBVar3->unk_12; + pBVar8 = (pRVar7->header).callback_buffer; + if (pBVar8 == (Buffer*)nullptr) { + (pRVar7->header).callback_buffer = pBVar3; + } else { + pBVar9 = pBVar8->next; + while (pBVar9 != (Buffer*)nullptr) { + pBVar8 = pBVar8->next; + pBVar9 = pBVar8->next; + } + pBVar8->next = pBVar3; + } + pBVar3 = (Buffer*)nullptr; + } + } + WaitSema(RequestedStreamsList.sema); + if (RequestedStreamsList.unk2_init0 == 1) { + QueueNewStreamsFromList(&RequestedStreamsList); + iVar4 = 0; + pLVar14 = (VagStrListNode*)NewStreamsList.next; + do { + if (pLVar14->id != 0) { + QueueVAGStream(pLVar14); + } + pLVar14 = (VagStrListNode*)pLVar14->list.next; + iVar4 = iVar4 + 1; + } while (iVar4 < 4); + } + pRVar7 = VagCmds; + iVar4 = 0; + // pcVar15 = VagCmds[0].name; + auto* cmd_iter = VagCmds; + do { + if ((((cmd_iter->byte11 == false) && (cmd_iter->sb_scanned == false)) && + (cmd_iter->id != 0)) || + ((StopPluginStreams == 1 && (cmd_iter->unk_136) != 0))) { + // CpuSuspendIntr(&local_2c); + bVar1 = false; + if (cmd_iter->id == 0) { + if (cmd_iter->name[0] != false) { + while (pRVar10 = FindVagStreamName(pRVar7->name), pRVar10 != nullptr) { + TerminateVAG(pRVar10, 0); + bVar1 = true; + } + } + } else { + pRVar10 = FindThisVagStream(cmd_iter->name, cmd_iter->id); + if (pRVar10 != nullptr) { + TerminateVAG(pRVar10, 0); + bVar1 = true; + } + } + if ((bVar1) && (iVar11 = AnyVagRunning(), iVar11 == 0)) { + ext_pause = 0; + ext_resume = 0; + } + // CpuResumeIntr(local_2c); + } + // pcVar15 = pcVar15 + 0x144; + cmd_iter++; + iVar4 = iVar4 + 1; + pRVar7 = pRVar7 + 1; + } while (iVar4 < 4); + SignalSema(RequestedStreamsList.sema); + RequestedStreamsList.unk2_init0 = 0; + if (pBVar3 == (Buffer*)nullptr) { + bool should_sleep = true; + if (PeekMbx(iso_mbx)) { + should_sleep = false; + } + auto* msg = GetMessage(); + if (msg && msg->callback != ProcessVAGData) { + should_sleep = false; + } + + if (should_sleep) { + DelayThread(1000); + } + } + } while (true); +} + +int RunDGOStateMachine(CmdHeader* param_1_in, Buffer* param_2) { + auto* param_1 = (CmdDgo*)param_1_in; + uint8_t* puVar1; + size_t bytes_to_read; + size_t sVar2; + int iVar3; + int iVar4; + size_t sVar5; + size_t bytes_left; + uint8_t* unprocessed_data; + int return_value; + + return_value = -1; + bytes_left = param_2->decompressed_size; + unprocessed_data = param_2->decomp_buffer; + do { + if (bytes_left == 0) + goto LAB_000059b4; + switch (param_1->dgo_state) { + case DgoState::Init: + param_1->bytes_processed = 0; + param_1->dgo_state = DgoState::Read_Header; + param_1->finished_first_object = 0; + param_1->want_abort = 0; + break; + case DgoState::Read_Header: + bytes_to_read = 0x40 - param_1->bytes_processed; + if ((int)bytes_left < (int)bytes_to_read) { + bytes_to_read = bytes_left; + } + for (; bytes_to_read != 0; bytes_to_read = bytes_to_read - sVar5) { + sVar2 = (param_2->page->ptr - unprocessed_data) + 1; + sVar5 = bytes_to_read; + if ((int)sVar2 < (int)bytes_to_read) { + sVar5 = sVar2; + } + bytes_left = bytes_left - sVar5; + memcpy((param_1->dgo_header).name + param_1->bytes_processed + -4, unprocessed_data, + sVar5); + param_2->decomp_buffer = param_2->decomp_buffer + sVar5; + param_2->decompressed_size = param_2->decompressed_size - sVar5; + unprocessed_data = (uint8_t*)CheckForIsoPageBoundaryCrossing(param_2); + param_1->bytes_processed = param_1->bytes_processed + sVar5; + } + if (param_1->bytes_processed == 0x40) { + iVar4 = (param_1->dgo_header).object_count; + param_1->bytes_processed = 0; + param_1->objects_loaded = 0; + if (iVar4 == 1) { + LAB_00005990: + puVar1 = param_1->buffer_heaptop; + param_1->buffer_toggle = 0; + } else { + puVar1 = param_1->buffer1; + param_1->buffer_toggle = 1; + } + param_1->dgo_state = DgoState::Read_Obj_Header; + param_1->ee_dest_buffer = puVar1; + } + break; + case DgoState::Finish_Obj: + if (param_1->finished_first_object == 0) { + LAB_00005870: + if (param_1->buffer1 == param_1->buffer2) + goto LAB_000058c4; + iVar4 = param_1->buffer_toggle; + (param_1->header).status = -1; + if (iVar4 == 1) { + puVar1 = param_1->buffer1; + } else { + puVar1 = param_1->buffer2; + } + param_1->selected_buffer = puVar1; + ReturnMessage(¶m_1->header); + if (param_1->buffer1 == param_1->buffer2) + goto LAB_000058c4; + } else { + if (param_1->buffer1 != param_1->buffer2) { + if (LookMbx(sync_mbx)) { + if (param_1->want_abort != 0) + goto LAB_00005988; + goto LAB_00005870; + } + goto LAB_000059b4; + } + LAB_000058c4: + if (param_1->objects_loaded + 1 < (param_1->dgo_header).object_count) { + if (!LookMbx(sync_mbx)) + goto LAB_000059b4; + if (param_1->want_abort != 0) + goto LAB_00005988; + } + } + param_1->finished_first_object = 1; + if (param_1->buffer_toggle == 1) { + param_1->buffer_toggle = 2; + param_1->ee_dest_buffer = param_1->buffer2; + } else { + param_1->buffer_toggle = 1; + param_1->ee_dest_buffer = param_1->buffer1; + } + if (param_1->objects_loaded + 1 == (param_1->dgo_header).object_count) { + param_1->dgo_state = DgoState::Read_Last_Obj; + } else { + param_1->dgo_state = DgoState::Read_Obj_Header; + } + break; + case DgoState::Read_Last_Obj: + if (!LookMbx(sync_mbx)) + goto LAB_000059b4; + if (param_1->want_abort == 0) + goto LAB_00005990; + LAB_00005988: + param_1->dgo_state = DgoState::Finish_Dgo; + break; + case DgoState::Read_Obj_Header: + bytes_to_read = 0x40 - param_1->bytes_processed; + if ((int)bytes_left < (int)bytes_to_read) { + bytes_to_read = bytes_left; + } + for (; bytes_to_read != 0; bytes_to_read = bytes_to_read - sVar5) { + sVar2 = (param_2->page->ptr - unprocessed_data) + 1; + sVar5 = bytes_to_read; + if ((int)sVar2 < (int)bytes_to_read) { + sVar5 = sVar2; + } + bytes_left = bytes_left - sVar5; + memcpy((param_1->obj_header).name + param_1->bytes_processed + -4, unprocessed_data, + sVar5); + param_2->decomp_buffer = param_2->decomp_buffer + sVar5; + param_2->decompressed_size = param_2->decompressed_size - sVar5; + unprocessed_data = (uint8_t*)CheckForIsoPageBoundaryCrossing(param_2); + param_1->bytes_processed = param_1->bytes_processed + sVar5; + } + if (param_1->bytes_processed == 0x40) { + DMA_SendToEE(¶m_1->obj_header, 0x40, param_1->ee_dest_buffer); + param_1->dgo_state = DgoState::Read_Obj_data; + iVar4 = (param_1->obj_header).size; + param_1->bytes_processed = 0; + param_1->ee_dest_buffer = param_1->ee_dest_buffer + 0x40; + (param_1->obj_header).size = iVar4 + 0xfU & 0xfffffff0; + } + break; + case DgoState::Read_Obj_data: + bytes_to_read = (param_1->obj_header).size - param_1->bytes_processed; + if ((int)bytes_left < (int)bytes_to_read) { + bytes_to_read = bytes_left; + } + for (; bytes_to_read != 0; bytes_to_read = bytes_to_read - sVar5) { + sVar2 = (param_2->page->ptr - unprocessed_data) + 1; + sVar5 = bytes_to_read; + if ((int)sVar2 < (int)bytes_to_read) { + sVar5 = sVar2; + } + bytes_left = bytes_left - sVar5; + DMA_SendToEE(unprocessed_data, sVar5, param_1->ee_dest_buffer); + param_2->decomp_buffer = param_2->decomp_buffer + sVar5; + param_2->decompressed_size = param_2->decompressed_size - sVar5; + unprocessed_data = (uint8_t*)CheckForIsoPageBoundaryCrossing(param_2); + param_1->ee_dest_buffer = param_1->ee_dest_buffer + sVar5; + param_1->bytes_processed = param_1->bytes_processed + sVar5; + } + if (param_1->bytes_processed == (param_1->obj_header).size) { + iVar3 = (param_1->dgo_header).object_count; + iVar4 = param_1->objects_loaded + 1; + param_1->objects_loaded = iVar4; + if (iVar4 < iVar3) { + DgoState nstate = DgoState::Finish_Obj_NoDoubleBuffer; + if (param_1->buffer1 != param_1->buffer2) { + nstate = DgoState::Finish_Obj; + } + param_1->dgo_state = nstate; + param_1->bytes_processed = 0; + } else { + param_1->dgo_state = DgoState::Finish_Dgo; + return_value = 0; + } + } + break; + case DgoState::Finish_Dgo: + return_value = 0; + LAB_000059b4: + if ((return_value == 0) || (bytes_left == 0)) { + param_2->decomp_buffer = (uint8_t*)nullptr; + param_2->decompressed_size = 0; + } else { + param_2->decomp_buffer = unprocessed_data; + param_2->decompressed_size = bytes_left; + } + return return_value; + case DgoState::Finish_Obj_NoDoubleBuffer: + iVar4 = param_1->buffer_toggle; + (param_1->header).status = -1; + if (iVar4 == 1) { + puVar1 = param_1->buffer1; + } else { + puVar1 = param_1->buffer2; + } + param_1->selected_buffer = puVar1; + ReturnMessage(¶m_1->header); + param_1->dgo_state = DgoState::Finish_Obj; + } + } while (true); +} + +void LoadDGO(RPC_Dgo_Cmd* param_1) { + FileRecord* iVar1; + iVar1 = (isofs->find)(param_1->name); + if (iVar1 == 0) { + printf("overlord couldn't find dgo: %s\n", param_1->name); + param_1->result = 1; + } else { + CancelDGO(0); + sLoadDgo.header.cmd_kind = 0x200; + sLoadDgo.header.thread_id = 0; + sLoadDgo.header.mbx_to_reply = dgo_mbx; + sLoadDgo.buffer1 = (uint8_t*)(u64)param_1->buffer1; + sLoadDgo.buffer2 = (uint8_t*)(u64)param_1->buffer2; + sLoadDgo.buffer_heaptop = (uint8_t*)(u64)param_1->buffer_heap_top; + sLoadDgo.fr = iVar1; + SendMbx(iso_mbx, &sLoadDgo); + + // wait for the ReturnMessage in the DGO callback state machine. + // this happens when the first file is loaded + WaitMbx(dgo_mbx); + + if (sLoadDgo.header.status == -1) { + param_1->result = 2; + } else { + if (sLoadDgo.header.status == 0) { + param_1->result = 0; + param_1->buffer1 = param_1->buffer_heap_top; + } else { + param_1->result = 1; + } + sLoadDgo.header.cmd_kind = 0; + } + } +} + +int CopyData(CmdLoadSingleIop* param_1, Buffer* param_2, int param_3) { + size_t sVar1; + Page* pPVar2; + uint8_t* src; + size_t n; + + pPVar2 = param_2->page; + if (param_2->decompressed_size != 0) { + n = param_1->length_to_copy - param_1->unk_64; + if (pPVar2 != (Page*)nullptr) { + while (0 < (int)n) { + n = param_1->length_to_copy - param_1->unk_64; + if (param_2->decompressed_size < (int)n) { + n = param_2->decompressed_size; + } + src = param_2->decomp_buffer; + sVar1 = (pPVar2->ptr - src) + 1; + if ((int)sVar1 < (int)n) { + n = sVar1; + } + if (param_3 == 0) { + DMA_SendToEE(src, n, param_1->ptr); + } else if (param_3 == 1) { + memcpy(param_1->ptr, src, n); + } + param_1->ptr = param_1->ptr + n; + param_1->unk_64 = param_1->unk_64 + n; + param_2->decomp_buffer = param_2->decomp_buffer + n; + param_2->decompressed_size = param_2->decompressed_size - n; + CheckForIsoPageBoundaryCrossing(param_2); + pPVar2 = param_2->page; + if ((u32)param_1->length_to_copy <= (u32)param_1->unk_64) { + if (pPVar2 != (Page*)nullptr) { + pPVar2->state = PageState::SIX; + pPVar2 = (Page*)StepTopPage(param_2->plist, pPVar2); + param_2->page = pPVar2; + param_2->free_pages = param_2->free_pages + -1; + } + break; + } + if (pPVar2 == (Page*)nullptr) + break; + } + } + if ((u32)param_1->length_to_copy <= (u32)param_1->unk_64) { + return 0; + } + } + return -1; +} + +/*! + * Find a file by name. Return nullptr if it fails. + */ +FileRecord* FindISOFile(const char* name) { + return isofs->find(name); +} + +// FindVAGFile in common + +u32 GetISOFileLength(FileRecord* fr) { + return isofs->get_length(fr); +} + +int NullCallback(CmdHeader* cmd, Buffer* buff) { + (void)cmd; + buff->decompressed_size = 0; + return CMD_STATUS_NULL_CB; +} + +void IsoStopVagStream(VagCmd* param_1, int param_2) { + bool bVar1; + VagCmd* pRVar2; + int iVar3; + + if (param_2 == 1) { + // CpuSuspendIntr(local_18); + } + bVar1 = false; + if (param_1->id == 0) { + if (param_1->name[0] != false) { + while (pRVar2 = FindVagStreamName(param_1->name), pRVar2 != nullptr) { + printf("terminate from IsoStop 1"); + + TerminateVAG(pRVar2, 0); + bVar1 = true; + } + } + } else { + pRVar2 = FindThisVagStream(param_1->name, param_1->id); + if (pRVar2 != nullptr) { + printf("terminate from IsoStop 2"); + TerminateVAG(pRVar2, 0); + bVar1 = true; + } + } + if ((bVar1) && (iVar3 = AnyVagRunning(), iVar3 == 0)) { + ext_pause = 0; + ext_resume = 0; + } + if (param_2 == 1) { + // CpuResumeIntr(local_18[0]); + } +} + +int CopyDataToIOP(CmdHeader* param_1, Buffer* param_2) { + return CopyData((CmdLoadSingleIop*)param_1, param_2, 1); +} + +int CopyDataToEE(CmdHeader* param_1, Buffer* param_2) { + return CopyData((CmdLoadSingleIop*)param_1, param_2, 0); +} + +void* RPC_DGO(unsigned int fno, void* _cmd, int y); +void LoadNextDGO(RPC_Dgo_Cmd* cmd); + +u32 DGOThread() { + sceSifQueueData dq; + sceSifServeData serve; + + // setup RPC. + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, DGO_RPC_ID[g_game_version], RPC_DGO, sRPCBuff, nullptr, nullptr, &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + return 0; +} + +void* RPC_DGO(unsigned int param_1, void* param_2, int) { + if (param_1 == 0) { + LoadDGO((RPC_Dgo_Cmd*)param_2); + } else if (param_1 == 1) { + LoadNextDGO((RPC_Dgo_Cmd*)param_2); + } else if (param_1 == 2) { + CancelDGO((RPC_Dgo_Cmd*)param_2); + } else { + ((RPC_Dgo_Cmd*)param_2)->result = 1; + } + return param_2; +} + +void LoadNextDGO(RPC_Dgo_Cmd* param_1) { + if (sLoadDgo.header.cmd_kind == 0) { + param_1->result = 1; + } else { + sLoadDgo.buffer_heaptop = (uint8_t*)(u64)param_1->buffer_heap_top; + sLoadDgo.buffer1 = (uint8_t*)(u64)param_1->buffer1; + sLoadDgo.buffer2 = (uint8_t*)(u64)param_1->buffer2; + SendMbx(sync_mbx, nullptr /*&a*/); // no idea why they put an address here.. + WaitMbx(dgo_mbx); + + if (sLoadDgo.header.status == -1) { + param_1->result = 2; + param_1->buffer1 = (u32)(u64)sLoadDgo.selected_buffer; + } else { + if (sLoadDgo.header.status == 0) { + param_1->result = 0; + param_1->buffer1 = param_1->buffer_heap_top; + } else { + param_1->result = 1; + } + sLoadDgo.header.cmd_kind = 0; + } + } +} + +void CancelDGO(RPC_Dgo_Cmd* param_1) { + if (sLoadDgo.header.cmd_kind != 0) { + sLoadDgo.want_abort = 1; + SendMbx(sync_mbx, nullptr); // was some stack addr... + WaitMbx(dgo_mbx); + + if (param_1 != (RPC_Dgo_Cmd*)nullptr) { + param_1->result = 3; + } + sLoadDgo.header.cmd_kind = 0; + } +} + +void InitDriver() { + int iVar1; + + iVar1 = (isofs->init)(); + if (iVar1 == 0) { + iso_init_flag = 0; + } + SendMbx(sync_mbx, &_not_on_stack_sync); +} + +void SetVagClock(VagCmd* param_1, int param_2) { + LoadStackEntry* pLVar1; + + if (param_2 == 1) { + // CpuSuspendIntr(local_18); + } + pLVar1 = (param_1->header).lse; + param_1->unk_188 = 0; + param_1->unk_180 = 0; + param_1->unk_184 = 0; + param_1->unk_192 = 0; + if (pLVar1 == (LoadStackEntry*)nullptr) { + param_1->byte6 = true; + } else { + param_1->byte5 = true; + if (param_1->stereo_sibling != (VagCmd*)nullptr) { + param_1->stereo_sibling->byte5 = true; + } + } + if (param_2 == 1) { + // CpuResumeIntr(local_18[0]); + } +} + +/*! + * Find VAG file by "name", where name is 8 bytes (chars with spaces at the end, treated as two + * s32's). Returns pointer to name in the VAGDIR file data. + */ +VagDirEntry* FindVAGFile(const char* name) { + VagDirEntry* entry = gVagDir.vag; + for (u32 idx = 0; idx < gVagDir.count; idx++) { + // check if matching name + if (memcmp(entry->name, name, 8) == 0) { + return entry; + } + entry++; + } + return nullptr; +} + +} // namespace jak2 diff --git a/game/overlord/jak2/iso.h b/game/overlord/jak2/iso.h new file mode 100644 index 0000000000..43a6cfeb86 --- /dev/null +++ b/game/overlord/jak2/iso.h @@ -0,0 +1,177 @@ +#pragma once + +#include "common/common_types.h" + +#include "game/overlord/common/isocommon.h" +#include "game/overlord/jak2/pages.h" + +namespace jak2 { +void iso_init_globals(); +u32 ISOThread(); +extern u32 IsoThreadCounter; + +struct LoadStackEntry { + FileRecord* fr; + int cd_offset; // location in cd (sector). In OpenGOAL, it's just relative to the start of the + // file. + int uses_blzo; + int read_bytes; + u32 size_after_decompression; +}; + +enum class OpenMode { MODE0, MODE1, KNOWN_NOT_BLZO }; + +struct Buffer { + u8* decomp_buffer; + int decompressed_size; + Buffer* next; + u8* unk_12; + int data_buffer_idx; + int use_mode; + PageList* plist; + int num_pages; + int unk_32; + int free_pages; + Page* page; + int unk_44; +}; + +struct IsoFs { + int (*init)(); // 0 + FileRecord* (*find)(const char*); // 4 + FileRecord* (*find_in)(const char*); // 8 + uint32_t (*get_length)(FileRecord*); // c + LoadStackEntry* (*open)(FileRecord*, int, OpenMode); // 10 + LoadStackEntry* (*open_wad)(FileRecord*, int32_t); // 14 + void (*close)(LoadStackEntry*); // 18 + int (*page_begin_read)(LoadStackEntry*, Buffer*); // 1c + uint32_t (*sync_read)(); // 20 + uint32_t (*load_sound_bank)(char*, SoundBank*); // 24 + uint32_t (*load_music)(char*, s32*); + // void (*poll_drive)(); +}; + +struct LargeBuffer { + PageList* page_list; + Page* allocated_pages; + Page* page_before_midway_page; + Page* mid_way_page; + Page* unk_page_end2; + Page* current_page; + int unk3; + int first_done_flag; + // ?? + int done_flag_2; + int maybe_post_first_done; + int unk4; + // ?? + int chunk_cnt_1; + int chunk_cnt_2; + u8* some_buffer; + u8* current_buffer_base_ptr; + u32 blzo_chunk_size; + int blzo_buffer_size_bytes; + u32 incoming_block_size; + u8* ptr; // pointer to data to be processed by DecompressBlock + u8* end_ptr; // end of data to be processed by DecompressBlock + int init0_2; +}; + +extern IsoFs* isofs; +extern LargeBuffer* SpLargeBuffer; + +struct CmdHeader { + int unk_0; + int unk_4; + int cmd_kind; + int status; + int mbx_to_reply; + int thread_id; + int unk_24; // 24 (init to 1) + Buffer* callback_buffer; // 28 + int (*callback)(CmdHeader*, Buffer*); // 32 + LoadStackEntry* lse; // 36 +}; + +struct CmdLoadSingleIop { + CmdHeader header; + FileRecord* file_record; + u8* dest_addr; + int length; + int length_to_copy; + int offset; + u8* ptr; + int unk_64; +}; + +/*! + * DGO Load State Machine states. + */ +enum class DgoState { + Init = 0, + Read_Header = 1, + Finish_Obj = 2, + Read_Last_Obj = 3, + Read_Obj_Header = 4, + Read_Obj_data = 5, + Finish_Dgo = 6, + Finish_Obj_NoDoubleBuffer = 7, // jak 2 only +}; + +struct CmdDgo { + CmdHeader header; + FileRecord* fr; // 0x28, DGO file that's open + u8* buffer1; // 0x2c, first EE buffer + u8* buffer2; // 0x30, second EE buffer + u8* buffer_heaptop; // 0x34, top of the heap + + DgoHeader dgo_header; // 0x38, current DGO's header + ObjectHeader obj_header; // 0x78, current obj's header + + u8* ee_dest_buffer; // 0xb8, where we are currently loading to on ee + u32 bytes_processed; // 0xbc, how many bytes processed in the current state + u32 objects_loaded; // 0xc0, completed object count + DgoState dgo_state; // 0xc4, state machine state + u32 finished_first_object; // 0xc8, have we finished loading the first object? + u32 buffer_toggle; // 0xcc, which buffer to load into (top, buffer1, buffer2) + u8* selected_buffer; // 0xd0, most recently completed load destination + u32 want_abort; // 0xd4, should we quit? +}; + +struct CmdLoadSoundBank { + CmdHeader header; + char bank_name[16]; + SoundBank* bank; +}; + +struct CmdLoadMusic { + CmdHeader header; + char name[16]; + s32* handle; +}; + +struct VagDirEntry { + char name[8]; + u32 offset; + u32 flag; +}; + +struct VagCmd; + +int NullCallback(CmdHeader* cmd, Buffer* buff); +u32 InitISOFS(); +void IsoStopVagStream(VagCmd* param_1, int param_2); +void ProcessMessageData(); +void IsoPlayVagStream(VagCmd* param_1, int param_2); +VagDirEntry* FindVAGFile(const char* name); +void IsoQueueVagStream(VagCmd* cmd, int param_2); + +static constexpr int VAG_COUNT = 2728; +struct VagDir { + u32 count; + VagDirEntry vag[VAG_COUNT]; +}; +extern VagDir gVagDir; +extern s32 iso_mbx; + +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/iso_api.cpp b/game/overlord/jak2/iso_api.cpp new file mode 100644 index 0000000000..c9b963a241 --- /dev/null +++ b/game/overlord/jak2/iso_api.cpp @@ -0,0 +1,254 @@ +#include "iso_api.h" + +#include + +#include "common/util/FileUtil.h" + +#include "game/overlord/common/srpc.h" +#include "game/overlord/jak2/iso_queue.h" +#include "game/overlord/jak2/streamlist.h" +#include "game/overlord/jak2/vag.h" +#include "game/sce/iop.h" +#include "game/sound/sndshim.h" + +using namespace iop; + +namespace jak2 { +void EEVagAndVagwad(char* name, VagCmd* cmd) { + char name_buff[16]; + + int name_len; + if (*name != '$') { + name_len = strlen(name); + if (8 < name_len) { + file_util::ISONameFromAnimationName(name_buff, name); + goto LAB_0000cc60; + } + } + + name_len = strlen(name); + if (*name == '$') { + name = name + 1; + } + if ((int)name_len < 9) { + memset(name_buff, 0x20, 8); + memcpy(name_buff, name, name_len); + } else { + memcpy(name_buff, name, 8); + } + { + int iVar3 = 0; + char* pbVar4 = name_buff; + do { + *pbVar4 = ::toupper(*pbVar4); + iVar3 = iVar3 + 1; + pbVar4 = (name_buff + iVar3); + } while (iVar3 < 8); + } + +LAB_0000cc60: + cmd->vag_dir_entry = FindVAGFile(name_buff); + memcpy(name_buff, "VAGWAD ", 8); + strncpy(name_buff + 8, gLanguage, 4); + cmd->file_record = (isofs->find_in)(name_buff); +} + +void QueueVAGStream(VagStrListNode* param_1) { + char bVar1; + int iVar2; + char* pcVar3; + char* pbVar4; + VagCmd cmd; + char local_20[12]; + + cmd.header.cmd_kind = 0x400; + cmd.header.mbx_to_reply = 0; + cmd.header.thread_id = 0; + if (param_1->unk_72 == 0) { + EEVagAndVagwad(param_1->name, &cmd); + cmd.vol_multiplier = 0x400; + } else { + pcVar3 = param_1->name; + strcpy(local_20, " "); + pbVar4 = local_20; + do { + bVar1 = *pcVar3; + pcVar3 = pcVar3 + 1; + *pbVar4 = bVar1; + pbVar4 = pbVar4 + 1; + if (*pcVar3 == 0x2e) + break; + } while (*pcVar3 != 0); + iVar2 = 0; + pbVar4 = local_20; + do { + if (*pbVar4 - 0x61 < 0x1a) { + *pbVar4 = *pbVar4 - 0x20; + } + iVar2 = iVar2 + 1; + pbVar4 = (local_20 + iVar2); + } while (iVar2 < 0xc); + cmd.vag_dir_entry = FindVAGFile(local_20); + strcpy(local_20, "VAGWAD "); + strncpy(local_20 + 8, gLanguage, 3); + cmd.file_record = (isofs->find_in)(local_20); + cmd.vol_multiplier = param_1->vol_multiplier; + cmd.unk_176 = param_1->unk_100; + } + strncpy(cmd.name, param_1->name, 0x30); + cmd.unk_136 = param_1->unk_72; + cmd.id = param_1->id; + cmd.plugin_id = param_1->unk_68; + cmd.priority = param_1->prio; + cmd.unk_288 = param_1->unk_76; + cmd.unk_292 = param_1->unk_80; + if (cmd.unk_288 != 0) { + cmd.byte10 = '\x01'; + } + if (cmd.unk_292 != 0) { + cmd.unk_232 = '\x01'; + } + cmd.unk_296 = 0; + IsoQueueVagStream(&cmd, 1); +} + +int LoadISOFileToIOP(FileRecord* fr, uint8_t* addr, int len) { + int iVar1; + CmdLoadSingleIop cmd; + + cmd.header.cmd_kind = 0x101; + cmd.header.mbx_to_reply = 0; + cmd.header.thread_id = GetThreadId(); + cmd.file_record = fr; + cmd.dest_addr = addr; + cmd.length = len; + SendMbx(iso_mbx, &cmd); + SleepThread(); + iVar1 = 0; + if (cmd.header.status == 0) { + iVar1 = cmd.length_to_copy; + } + return iVar1; +} + +int LoadISOFileToEE(FileRecord* param_1, uint32_t param_2, int param_3) { + int iVar1; + CmdLoadSingleIop auStack88; + + auStack88.header.cmd_kind = 0x100; + auStack88.header.mbx_to_reply = 0; + auStack88.header.thread_id = GetThreadId(); + auStack88.file_record = param_1; + auStack88.dest_addr = (u8*)(u64)param_2; + auStack88.length = param_3; + SendMbx(iso_mbx, &auStack88); + SleepThread(); + iVar1 = 0; + if (auStack88.header.status == 0) { + iVar1 = auStack88.length_to_copy; + } + return iVar1; +} + +int LoadISOFileChunkToEE(FileRecord* param_1, uint32_t param_2, int param_3, int param_4) { + int iVar1; + CmdLoadSingleIop auStack96; + + auStack96.header.cmd_kind = 0x102; + auStack96.header.mbx_to_reply = 0; + auStack96.header.thread_id = GetThreadId(); + auStack96.file_record = param_1; + auStack96.dest_addr = (u8*)(u64)param_2; + auStack96.length = param_3; + auStack96.offset = param_4; + SendMbx(iso_mbx, &auStack96); + SleepThread(); + iVar1 = 0; + if (auStack96.header.status == 0) { + iVar1 = auStack96.length_to_copy; + } + return iVar1; +} + +void PauseVAGStreams() { + VagCmd* inasdf; + + inasdf = GetVAGCommand(); + (inasdf->header).cmd_kind = 0x403; + (inasdf->header).mbx_to_reply = 0; + (inasdf->header).thread_id = 0; + SendMbx(iso_mbx, inasdf); +} + +void UnpauseVAGStreams() { + auto* inasdf = GetVAGCommand(); + (inasdf->header).cmd_kind = 0x404; + (inasdf->header).mbx_to_reply = 0; + (inasdf->header).thread_id = 0; + SendMbx(iso_mbx, inasdf); +} + +void SetVAGStreamPitch(int param_1, int param_2) { + auto* inasdf = GetVAGCommand(); + (inasdf->header).cmd_kind = 0x406; + (inasdf->header).mbx_to_reply = 0; + (inasdf->header).thread_id = 0; + inasdf->id = param_1; + inasdf->unk_256_pitch2 = param_2; + SendMbx(iso_mbx, inasdf); +} + +void SetDialogVolume(int param_1) { + auto* inasdf = GetVAGCommand(); + (inasdf->header).cmd_kind = 0x407; + (inasdf->header).mbx_to_reply = 0; + (inasdf->header).thread_id = 0; + inasdf->vol_multiplier = param_1; + SendMbx(iso_mbx, inasdf); +} + +void LoadSoundBank(char* param_1, SoundBank* param_2) { + CmdLoadSoundBank auStack80; + auStack80.header.cmd_kind = 0x300; + auStack80.header.mbx_to_reply = 0; + auStack80.header.thread_id = GetThreadId(); + strncpy(auStack80.bank_name, param_1, 0x10); + auStack80.bank = param_2; + SendMbx(iso_mbx, &auStack80); + SleepThread(); +} + +void LoadMusic(char* param_1, s32* param_2) { + CmdLoadMusic auStack88; + + auStack88.header.cmd_kind = 0x380; + auStack88.header.mbx_to_reply = 0; + auStack88.header.thread_id = GetThreadId(); + strncpy(auStack88.name, param_1, 0x10); + auStack88.handle = param_2; + SendMbx(iso_mbx, &auStack88); + SleepThread(); + + for (u32 i = 0; i < gMusicTweakInfo.TweakCount; i++) { + if (!strcmp(gMusicTweakInfo.MusicTweak[i].MusicName, param_1)) { + gMusicTweak = gMusicTweakInfo.MusicTweak[i].VolumeAdjust; + return; + } + } + + gMusicTweak = 0x80; +} + +void UnLoadMusic(s32* param_1) { + gMusicFadeDir = -1; + if (gMusicFade != 0) { + do { + DelayThread(1000); + } while (gMusicFade != 0); + } + snd_UnloadBank(*param_1); + snd_ResolveBankXREFS(); + *param_1 = 0; +} + +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/iso_api.h b/game/overlord/jak2/iso_api.h new file mode 100644 index 0000000000..362db5ff52 --- /dev/null +++ b/game/overlord/jak2/iso_api.h @@ -0,0 +1,18 @@ +#pragma once + +#include "common/common_types.h" + +struct SoundBank; +struct FileRecord; +namespace jak2 { +struct VagStrListNode; +void SetVAGStreamPitch(int param_1, int param_2); +void SetDialogVolume(int param_1); +void LoadSoundBank(char* param_1, SoundBank* param_2); +void UnLoadMusic(s32* param_1); +void LoadMusic(char* param_1, s32* param_2); +void QueueVAGStream(VagStrListNode* param_1); +int LoadISOFileToEE(FileRecord* param_1, uint32_t param_2, int param_3); +int LoadISOFileToIOP(FileRecord* fr, uint8_t* addr, int len); +int LoadISOFileChunkToEE(FileRecord* param_1, uint32_t param_2, int param_3, int param_4); +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/iso_cd.cpp b/game/overlord/jak2/iso_cd.cpp new file mode 100644 index 0000000000..7840d3afbc --- /dev/null +++ b/game/overlord/jak2/iso_cd.cpp @@ -0,0 +1,758 @@ +#include "iso_cd.h" + +#include +#include + +#include "common/log/log.h" +#include "common/util/Assert.h" +#include "common/util/FileUtil.h" + +#include "game/common/overlord_common.h" +#include "game/overlord/common/fake_iso.h" +#include "game/overlord/common/isocommon.h" +#include "game/overlord/common/sbank.h" +#include "game/overlord/jak2/iso_queue.h" +#include "game/sce/iop.h" +#include "game/sound/sndshim.h" + +using namespace iop; + +namespace jak2 { + +/// Page being written by CD reads +Page* ReadPagesCurrentPage = nullptr; + +/// Semaphore that blocks on a CD read +s32 DvdSema = -1; + +s32 BlzoSema = -1; + +/// Callback function installed before using the iso_cd.cpp system +void (*PreviousCallBack)(int) = nullptr; + +/// Flag to indicate that we should stop reading. +s32 ReadPagesCancelRead = 0; + +/// The number of pages to read for the current read. +s32 ReadPagesNumToRead = 0; + +/// The actual buffer in IOP memory to write to for the current read. +void* ReadPagesCurrentBuffer = nullptr; + +/// The sector of the read in progress +s32 ReadPagesCurrentSector = 0; + +/// How many sectors should be done per page (and call to sceCdRead) +s32 ReadPagesSectorsPerPage = 0; + +PageList* ReadPagesPagePool = nullptr; + +s32 SubBufferToRead = 0; +// -1 is set after some stuff. +// 5 or 6 needed for IsoCdPagesCallback to fire +// 5 for non-blzo read +// 6 for blzo read +// 9 is backed up by insta-reads (it happens during CD_WaitReturn) +// 8 for insta-reads itself + +/// Flag that can be set to 1 once reading pages is done. +s32* ReadPagesDoneFlag = nullptr; + +/// LoadStackEntry for currently reading file +static LoadStackEntry* sReadInfo; + +s32 StopPluginStreams = 0; + +s32 SubBuffersFlags = 0; + +void* sMode = nullptr; + +static LoadStackEntry sLoadStack[MAX_OPEN_FILES]; //! List of all files that are "open" + +IsoFs iso_cd; + +int FS_Init(); +LoadStackEntry* FS_Open(FileRecord* file_record, int offset, OpenMode mode); +LoadStackEntry* FS_OpenWad(FileRecord* fr, int offset); +void FS_Close(LoadStackEntry* lse); +int FS_PageBeginRead(LoadStackEntry* lse, Buffer* buffer); +uint32_t FS_LoadSoundBank(char* name, SoundBank* buffer); +uint32_t FS_LoadMusic(char* name, s32* buffer); +u32 FS_SyncRead(); + +void iso_cd_init_globals() { + ReadPagesCurrentPage = nullptr; + DvdSema = -1; + BlzoSema = -1; + PreviousCallBack = nullptr; + ReadPagesCancelRead = 0; + SubBufferToRead = 0; + ReadPagesNumToRead = 0; + ReadPagesCurrentBuffer = nullptr; + ReadPagesCurrentSector = 0; + ReadPagesSectorsPerPage = 0; + ReadPagesDoneFlag = nullptr; + ReadPagesPagePool = nullptr; + SpLargeBuffer = nullptr; + SubBuffersFlags = 0; + StopPluginStreams = 0; + memset(sLoadStack, 0, sizeof(sLoadStack)); + sReadInfo = nullptr; + + iso_cd.init = FS_Init; + iso_cd.find = FS_Find; + iso_cd.find_in = FS_FindIN; + iso_cd.get_length = FS_GetLength; + iso_cd.open = FS_Open; + iso_cd.open_wad = FS_OpenWad; + iso_cd.close = FS_Close; + iso_cd.page_begin_read = FS_PageBeginRead; + iso_cd.load_sound_bank = FS_LoadSoundBank; + iso_cd.load_music = FS_LoadMusic; + iso_cd.sync_read = FS_SyncRead; +} + +/////////////////////////// +// Sony Fake CD Functions +/////////////////////////// + +struct FakeCd { + int offset_into_file = 0; + FILE* fp = nullptr; + void (*callback)(int) = nullptr; + FileRecord* last_fr = nullptr; +} gFakeCd; + +auto sceCdCallback(void (*callback)(int)) { + auto ret = gFakeCd.callback; + gFakeCd.callback = callback; + return ret; +} + +int sceCdRead(int lsn, int num_sectors, void* dest, void* mode) { + (void)mode; + // printf("sceCdRead %d, %d -> %p\n", lsn, num_sectors, dest); + ASSERT(gFakeCd.fp); + if (fseek(gFakeCd.fp, lsn * SECTOR_SIZE, SEEK_SET)) { + ASSERT_MSG(false, "Failed to fseek"); + } + if (fread(dest, num_sectors * SECTOR_SIZE, 1, gFakeCd.fp) < 0) { + printf("dest is %p, num_sectors %d, lsn %d\n", dest, num_sectors, lsn); + printf("err: %s\n", strerror(errno)); + ASSERT_MSG(false, "Failed to fread"); + } + ASSERT(gFakeCd.callback); + + return 1; +} + +void do_cd_callback() { + if (gFakeCd.callback) { + gFakeCd.callback(1); + } +} + +//////////////////////// +// Overlord Functions +//////////////////////// + +/*! + * Handle a completed read. Called by Sony CD system. + */ +void IsoCdPagesCallback(int done) { + if (!ReadPagesCurrentPage) { + // somehow there is nothing left to read. I guess the read is no longer desired. + printf("-- ReadPagesCurrentPage was mysteriously null in IsoCdPagesCallback\n"); + + // allow stuff waiting on the dvd semaphore + SignalSema(DvdSema); // was iSignalSema + + // restore old CD callback + sceCdCallback(PreviousCallBack); + } else if (done == 1) { + if (ReadPagesCancelRead == 0) { + // read is still in progress. + + // ??? + if ((SubBufferToRead != 5) && (SubBufferToRead != 6)) { + // not a FS_BeginPagedRead read, so don't use this callback. seems bad if this is reached. + return; + } + + // ??? + if (ReadPagesCurrentPage->state == PageState::ALLOCATED_EMPTY) { + ReadPagesCurrentPage->state = PageState::ALLOCATED_FILLED; + } + + // advance to the next page. + ReadPagesCurrentPage = ReadPagesCurrentPage->next; + ReadPagesNumToRead = ReadPagesNumToRead + -1; + + // kick off next read if we can. + if (ReadPagesCurrentPage && ReadPagesNumToRead > 0) { + ReadPagesCurrentBuffer = ReadPagesCurrentPage->buffer; + ReadPagesCurrentSector = ReadPagesCurrentSector + ReadPagesSectorsPerPage; + + // read! + int cd_ret = sceCdRead(ReadPagesCurrentSector, ReadPagesSectorsPerPage, + ReadPagesCurrentBuffer, sMode); + if (cd_ret != 0) { + return; + } + + // no need for CdReturnThread - just checks for removed CD. + // iWakeupThread(CdReturnThread); + return; + } + + // otherwise, we cannot read. Hopefully we read everything the user requested + // added this check here + if (ReadPagesNumToRead) { + printf("---- IsoCdPagesCallback wants to keep reading, but ran out of pages!\n"); + ASSERT_NOT_REACHED(); + } + + ReadPagesPagePool = 0; + ReadPagesCurrentPage = nullptr; + ReadPagesCurrentSector = 0; + if (ReadPagesDoneFlag == nullptr) { + ReadPagesDoneFlag = nullptr; + } else { + *ReadPagesDoneFlag = 1; + } + } else { // we were cancelled. + ReadPagesPagePool = 0; + ReadPagesCurrentPage = nullptr; + ReadPagesCurrentSector = 0; + ReadPagesDoneFlag = nullptr; + ReadPagesCancelRead = 0; + } + + // read is done. + SubBufferToRead = -1; + sceCdCallback(PreviousCallBack); + SignalSema(DvdSema); // was iSignalSema. + } +} + +// ReadDirectory : skipped +// DecodeDUP : skipped +// LoadMusicTweaks : can use common +// LoadDiscID : skipped + +/*! + * Initialize the iso_cd filesystem. + */ +int FS_Init() { + // added: initialize fake_iso. This will allow us to call fake_iso functions in the implementation + // of jak 2 CD reading code. + // this will also take care of loading music tweaks + fake_iso_FS_Init(); + + // removed checks related to checking DVD/CD type. + + SemaParam sema_param; + sema_param.attr = 0; + sema_param.init_count = 1; + sema_param.max_count = 1; + sema_param.option = 0; + DvdSema = CreateSema(&sema_param); + if (DvdSema < 0) { + printf("IOP: ======================================================================\n"); + printf("IOP: iso_cd FS_Init: Can\'t create DVD semaphore\n"); + printf("IOP: ======================================================================\n"); + ASSERT_NOT_REACHED(); + } + + // removed creation of CD Return thread. + // this only checks for the CD being removed and put back in. + + sema_param.attr = 1; + sema_param.init_count = 1; + sema_param.max_count = 1; + sema_param.option = 0; + BlzoSema = CreateSema(&sema_param); + if (BlzoSema < 0) { + printf("IOP: ======================================================================\n"); + printf("IOP: iso_cd FS_Init: Can\'t create BLZO semaphore\n"); + printf("IOP: ======================================================================\n"); + ASSERT_NOT_REACHED(); + } + + // init the LargeBuffer. + SubBufferToRead = -1; + SubBuffersFlags = 0; + SpLargeBuffer->chunk_cnt_1 = 8; + SpLargeBuffer->chunk_cnt_2 = 8; + SpLargeBuffer->blzo_buffer_size_bytes = 0x40000; + SpLargeBuffer->current_buffer_base_ptr = nullptr; + SpLargeBuffer->page_list = SpMemoryBuffers; + SpLargeBuffer->blzo_chunk_size = 0x8000; + SpLargeBuffer->incoming_block_size = 0; + SpLargeBuffer->ptr = nullptr; + SpLargeBuffer->init0_2 = 0; + SpLargeBuffer->end_ptr = (SpLargeBuffer->current_buffer_base_ptr + 0x40000); // ? + + return 0; +} + +LoadStackEntry* FS_Open(FileRecord* file_record, int offset, OpenMode mode) { + // CpuSuspendIntr(); + // first, find a LoadStackEntry* + LoadStackEntry* load_stack_entry = nullptr; + for (auto& entry : sLoadStack) { + if (!entry.fr) { + load_stack_entry = &entry; + load_stack_entry->fr = file_record; + break; + } + } + // CpuResumeIntr(local_28[0]); + + if (!load_stack_entry) { + printf("IOP: ======================================================================\n"); + printf("IOP: iso_cd FS_Open: stack full\n"); + printf("IOP: ======================================================================\n"); + ASSERT_NOT_REACHED(); + } + + u32 first_four_bytes_of_file = 0; + u32 next_four_bytes_of_file = 0; + + switch (mode) { + case OpenMode::MODE0: + case OpenMode::MODE1: + // we'd read 1 sector now to check the header. this would populate first_four_bytes_of_file. + // in OpenGOAL we don't use BLZO, so just put + first_four_bytes_of_file = 0; + break; + case OpenMode::KNOWN_NOT_BLZO: + // like it was in the original + first_four_bytes_of_file = 0; + break; + default: + ASSERT_NOT_REACHED(); + } + + if (first_four_bytes_of_file == 0x426c5a6f) { // blzo magic. + load_stack_entry->uses_blzo = 1; + if (PollSema(BlzoSema) != 0) { + load_stack_entry->size_after_decompression = 0; + file_record->size = 0; + printf("======================================================================\n"); + // printf("IOP: iso_cd FS_Open: blzo file %s cant get blzo semaphore\n", file_record); + printf("======================================================================\n"); + ASSERT_NOT_REACHED(); + } + // remember the size + load_stack_entry->size_after_decompression = next_four_bytes_of_file; + // also modify the file record!! + file_record->size = next_four_bytes_of_file; + + // allocate a list of pages to hold the data. + Page* blzo_pages = + AllocPagesBytes(SpLargeBuffer->page_list, SpLargeBuffer->blzo_buffer_size_bytes); + SpLargeBuffer->allocated_pages = blzo_pages; + + auto page_size = SpLargeBuffer->page_list->page_size; + + // make sure we have enough pages. + if ((u32)blzo_pages->free_pages < + ((SpLargeBuffer->blzo_buffer_size_bytes + page_size) - 1) / page_size) { + printf("IOP: ======================================================================\n"); + page_size = SpLargeBuffer->page_list->page_size; + printf("IOP: iso_cd FS_Open: need %d pages got %d\n", + ((SpLargeBuffer->blzo_buffer_size_bytes + page_size) - 1) / page_size, + SpLargeBuffer->allocated_pages->free_pages); + printf("IOP: ======================================================================\n"); + + if (0 < SpLargeBuffer->allocated_pages->free_pages) { + FreePagesList(SpLargeBuffer->page_list, SpLargeBuffer->allocated_pages); + } + StopPluginStreams = 1; + SignalSema(BlzoSema); + load_stack_entry->size_after_decompression = 0; + load_stack_entry->fr = nullptr; + return nullptr; + } + auto* page_iter = SpLargeBuffer->allocated_pages; + SpLargeBuffer->current_page = blzo_pages; + SpLargeBuffer->mid_way_page = page_iter->end_page_first_only; + SpLargeBuffer->unk_page_end2 = page_iter->end_page_first_only; + + // seek page-iter to the midway page. + int midway_page_idx = page_iter->free_pages / 2; + int i = 0; + if (0 < midway_page_idx) { + do { + page_iter = page_iter->next; + i = i + 1; + } while (i < midway_page_idx); + } + SpLargeBuffer->mid_way_page = page_iter; + + blzo_pages = page_iter->prev; + SpLargeBuffer->first_done_flag = 0; + SpLargeBuffer->done_flag_2 = 0; + SpLargeBuffer->unk3 = 0; + SpLargeBuffer->maybe_post_first_done = 0; + SpLargeBuffer->unk4 = 0; + SpLargeBuffer->ptr = 0; + SpLargeBuffer->page_before_midway_page = blzo_pages; + SpLargeBuffer->some_buffer = nullptr; + SpLargeBuffer->current_buffer_base_ptr = SpLargeBuffer->allocated_pages->buffer; + } else { + load_stack_entry->uses_blzo = 0; + // load_stack_entry->size_after_decompression = file_record->size; + load_stack_entry->size_after_decompression = FS_GetLength(file_record); + } + load_stack_entry->read_bytes = 0; + // load_stack_entry->cd_offset = file_record->location; + load_stack_entry->cd_offset = 0; + if (offset != -1) { + load_stack_entry->cd_offset += offset; + } + return load_stack_entry; +} + +int DecompressBlock(u8* /*input*/, u8* output) { + int size_out = -1; + int decomp_return_code = -1; + + // Note: in here SpLargeBuffer's ptr points to the start of the new data + // and Page's ptr points to the end. + + // see if we should use decompress or not. + // in some cases, compressing the data makes it bigger. + // in this case, the data on DVD contains a CHUNK_SIZE block of uncompressed data + // and the _incoming_block_size is set to the larger-than-CHUNK_SIZE size of a compressed block. + if (SpLargeBuffer->blzo_chunk_size < SpLargeBuffer->incoming_block_size) { + // the case where compressing doesn't help. Copy data from the current page to output. + FromPagesCopy(SpLargeBuffer->current_page, SpLargeBuffer->ptr, output, + SpLargeBuffer->blzo_chunk_size); + // output size is exactly max size + size_out = SpLargeBuffer->blzo_chunk_size; + // no error possible in this case. + decomp_return_code = 0; + // adjust to the actual size of data processed. + SpLargeBuffer->incoming_block_size = size_out; + } else { + // otherwise actually decompress. + // this reads incoming_block_size data, writes decompressed to output, and stores the number + // of bytes output in size_out. + ASSERT_NOT_REACHED(); + // decomp_return_code = lzo1x_decompress(input, SpLargeBuffer->incoming_block_size, output, + // &size_out, 0); + } + + // align to 4 bytes so our next read is still 4 byte aligned. + auto aligned_incoming_size = SpLargeBuffer->incoming_block_size + 3U & 0xfffffffc; + SpLargeBuffer->incoming_block_size = aligned_incoming_size; + + // seek the pointer in SpLargeBuffer simply by adding the size for now... + // this might run on the page... + auto* end_of_incoming = SpLargeBuffer->ptr + aligned_incoming_size; + SpLargeBuffer->ptr = end_of_incoming; + + // now check to see if we need to advance the page + Page* page = SpLargeBuffer->current_page; + auto* page_ptr = page->ptr; + + if (page_ptr < end_of_incoming) { // did our pointer seek go past the end of this page? + // if so, seek the page! + page = page->next; + if (page) { + SpLargeBuffer->current_page = page; + // carry over... not sure what the -1 is. + SpLargeBuffer->ptr = end_of_incoming - page_ptr + page->buffer - 1; + } + } + + // check to see if there is additional data read, after this block. + if (SpLargeBuffer->ptr < SpLargeBuffer->end_ptr) { + // there is! + // we can determine the next block's size! + + // read it + memcpy(&SpLargeBuffer->incoming_block_size, SpLargeBuffer->ptr, 4); + end_of_incoming = SpLargeBuffer->ptr + 4; + SpLargeBuffer->ptr = end_of_incoming; + page_ptr = SpLargeBuffer->current_page->ptr; + + // check for crossing page boundary by reading this... + if (page_ptr < end_of_incoming) { + page = SpLargeBuffer->current_page->next; + if (page) { + SpLargeBuffer->current_page = page; + SpLargeBuffer->ptr = end_of_incoming - page_ptr + page->buffer - 1; + } + } + + // check for insane value + if (70000 < SpLargeBuffer->incoming_block_size) { + printf("IOP: ======================================================================\n"); + printf("IOP: iso_cd DecompressBlock: next compressed block length too big page %d\n", + SpLargeBuffer->current_page->maybe_page_id); + printf("IOP: ======================================================================\n"); + ASSERT_NOT_REACHED(); + } + } else { + // no data read. I guess we set incoming block size to 0, for now. + SpLargeBuffer->incoming_block_size = 0; + } + if (decomp_return_code != 0) { + ASSERT_NOT_REACHED(); + } + return size_out; +} + +int FS_PageBeginRead(LoadStackEntry* lse, Buffer* buffer) { + // bool bVar1; + // undefined4 uVar3; + // int iVar4; + // int *piVar5; + // int iVar6; + // Page *pPVar7; + // uint8_t *puVar8; + // int iVar9; + // uint uVar10; + // uint uVar11; + // PageList *plist; + // Page *pages; + // undefined4 local_40; + // undefined4 local_3c; + // undefined4 local_38; + // int local_34; + // undefined4 local_30 [2]; + + // _buffer = buffer->decomp_buffer; + int sector = lse->cd_offset; + // _sectors = 0; + sReadInfo = lse; + // _sector = uVar10; + // _real_sector = uVar10; + if (lse->uses_blzo == 1) { + ASSERT_NOT_REACHED_MSG("no blzo for u"); + } else { + if ((lse->size_after_decompression != 0) && + (lse->size_after_decompression <= (u32)lse->read_bytes)) { + // _sectors = 0; + // read past the end already. + // not entirely sure why this is "in progress"... + return CMD_STATUS_IN_PROGRESS; + } + + // these pages will hold the data. + auto* plist = buffer->plist; + auto* pages = buffer->page; + + // wait for drive + if (PollSema(DvdSema) == KE_SEMA_ZERO) { + WaitSema(DvdSema); + } + + // wait for pending read to finish, I guess... + if (-1 < SubBufferToRead) { + while (-1 < SubBufferToRead) { + DelayThread(100); + } + } + + // set SubBufferToRead to 5, to indicate a non-blzo FS read. + // iVar4 = CpuSuspendIntr(local_30); + SubBufferToRead = 5; + /* + if (iVar4 != -0x66) { + CpuResumeIntr(local_30[0]); + } + */ + int page_size = plist->page_size; + if (page_size < 0) { // usual page size mystery. + page_size = page_size + 0x7ff; + } + + // init globals for the callback + ReadPagesCurrentBuffer = (void*)pages->buffer; + ReadPagesSectorsPerPage = page_size >> 0xb; + ReadPagesCancelRead = 0; + ReadPagesPagePool = plist; + ReadPagesCurrentPage = pages; + ReadPagesCurrentSector = sector; + int local_34 = 0; // super sketchy... + ReadPagesDoneFlag = &local_34; + int npages = pages->free_pages; + ReadPagesNumToRead = npages; + + // mark all as allocated and empty. + pages->state = PageState::ALLOCATED_EMPTY; + auto* next = pages->next; + while ((next && (npages = npages + -1, 0 < npages))) { + pages = pages->next; + next = pages->next; + pages->state = PageState::ALLOCATED_EMPTY; + } + + // start a read! + if (gFakeCd.last_fr != lse->fr) { + const char* path = get_file_path(lse->fr); + FILE* fp = file_util::open_file(path, "rb"); + if (!fp) { + lg::error("[OVERLORD] fake iso could not open the file \"{}\"", path); + } else { + // printf("PAGE READING %s\n", path); + } + ASSERT(fp); + + if (gFakeCd.fp) { + fclose(gFakeCd.fp); + } + gFakeCd.fp = fp; + gFakeCd.last_fr = lse->fr; + } + + while (true) { + PreviousCallBack = nullptr; + PreviousCallBack = sceCdCallback(IsoCdPagesCallback); + int ret = + sceCdRead(ReadPagesCurrentSector, ReadPagesSectorsPerPage, ReadPagesCurrentBuffer, sMode); + if (ret) + break; + sceCdCallback(PreviousCallBack); + // FS_PollDrive(); + } + + // wait for read to finish + while (-1 < SubBufferToRead) { + // DelayThread(1000); + do_cd_callback(); // added, to make progress. TODO remove sleep avoe. + } + + // update stats. + int bytes_read = buffer->page->free_pages * buffer->plist->page_size; + lse->read_bytes = lse->read_bytes + bytes_read; + buffer->decompressed_size = bytes_read; + lse->cd_offset += bytes_read >> 0xb; + } + + // not sure why we use "in progress" here, maybe the meaning changed. + return CMD_STATUS_IN_PROGRESS; +} + +uint32_t FS_LoadSoundBank(char* name, SoundBank* buffer) { + SoundBank* bank = (SoundBank*)buffer; + FileRecord* file = nullptr; + char namebuf[16]; + char isoname[16]; + u32 handle; + + strncpy(namebuf, name, 12); + namebuf[8] = 0; + strcat(namebuf, ".sbk"); + + MakeISOName(isoname, namebuf); + file = FS_FindIN(isoname); + if (!file) { + return CMD_STATUS_FAILED_TO_OPEN; + } + + handle = snd_BankLoadEx(get_file_path(file), 0, bank->spu_loc, bank->spu_size); + snd_ResolveBankXREFS(); + bank->bank_handle = handle; + + return CMD_STATUS_DONE; +} + +uint32_t FS_LoadMusic(char* name, s32* bank_handle) { + FileRecord* file = nullptr; + char namebuf[16]; + char isoname[16]; + u32 handle; + + strncpy(namebuf, name, 12); + namebuf[8] = 0; + strcat(namebuf, ".mus"); + + MakeISOName(isoname, namebuf); + + file = FS_FindIN(isoname); + if (!file) { + return CMD_STATUS_FAILED_TO_OPEN; + } + + handle = snd_BankLoadEx(get_file_path(file), 0, 0xcfcc0, 0x61a80); + snd_ResolveBankXREFS(); + *bank_handle = handle; + + return CMD_STATUS_DONE; +} + +// CD_WaitReturn: don't need it +// FS_Find: common +// FS_FindIN: common +// FS_GetLength: common + +LoadStackEntry* FS_OpenWad(FileRecord* fr, int offset) { + // CpuSuspendIntr(); + LoadStackEntry* selected = nullptr; + for (uint32_t i = 0; i < MAX_OPEN_FILES; i++) { + if (!sLoadStack[i].fr) { + selected = sLoadStack + i; + selected->fr = fr; + break; + } + } + // CpuResumeIntr(local_20[0]); + if (!selected) { + printf("======================================================================\n"); + printf("IOP: iso_cd FS_OpenWad: stack full\n"); + printf("======================================================================\n"); + ASSERT_NOT_REACHED(); + } + + selected->uses_blzo = 0; + selected->size_after_decompression = 0; + selected->read_bytes = 0; + // selected->cd_offset = fr->location + offset; + selected->cd_offset = offset; + return selected; +} + +void FS_Close(LoadStackEntry* lse) { + if (lse->uses_blzo == 1) { + SpLargeBuffer->ptr = nullptr; + SpLargeBuffer->current_buffer_base_ptr = nullptr; + SpLargeBuffer->allocated_pages = FreePagesList(SpMemoryBuffers, SpLargeBuffer->allocated_pages); + SignalSema(BlzoSema); + if (StopPluginStreams == 1) { + StopPluginStreams = 0; + } + } + if (lse == sReadInfo) { + sReadInfo = (LoadStackEntry*)0x0; + ReadPagesCancelRead = 1; + } + lse->fr = nullptr; +} + +u32 FS_SyncRead() { + if (sReadInfo) { + sReadInfo = nullptr; + return CMD_STATUS_IN_PROGRESS; + } else { + return CMD_STATUS_READ_ERR; + } +} + +// FS_StoreSoundBankInIOP: stub +// FS_LoadSoundBankFromIOP: stub +// FS_LoadSoundBankFromEE: stub + +// FS_PollDrive: not needed. + +// CdReturn: not needed thread + +// DoCdReadPages: inlined + +// CheckPagesReady: inline/not used + +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/iso_cd.h b/game/overlord/jak2/iso_cd.h new file mode 100644 index 0000000000..c411cb95a2 --- /dev/null +++ b/game/overlord/jak2/iso_cd.h @@ -0,0 +1,15 @@ +#pragma once + +#include "common/common_types.h" + +#include "game/overlord/common/isocommon.h" +#include "game/overlord/jak2/iso.h" +#include "game/overlord/jak2/pages.h" + +namespace jak2 { +void iso_cd_init_globals(); + +extern IsoFs iso_cd; +extern s32 StopPluginStreams; + +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/iso_queue.cpp b/game/overlord/jak2/iso_queue.cpp new file mode 100644 index 0000000000..a04cdf50bd --- /dev/null +++ b/game/overlord/jak2/iso_queue.cpp @@ -0,0 +1,698 @@ +#include "iso_queue.h" + +#include + +#include "common/log/log.h" +#include "common/util/Assert.h" + +#include "game/overlord/common/iso.h" +#include "game/overlord/jak2/dma.h" +#include "game/overlord/jak2/iso.h" +#include "game/overlord/jak2/spustreams.h" +#include "game/overlord/jak2/vag.h" +#include "game/sce/iop.h" +#include "game/sound/sndshim.h" + +using namespace iop; + +namespace jak2 { + +/// The data structure containing all memory pages. +PageList* SpMemoryBuffers = nullptr; +u8* ScratchPadMemory = nullptr; +constexpr int N_BUFFERS = 3 + 11; // ?? +static Buffer sBuffer[N_BUFFERS]; +static Buffer* sFreeBuffer = nullptr; +static Buffer* sFreeStrBuffer = nullptr; +u32 BuffersAlloc = 0; +u32 StrBuffersAlloc = 0; +u32 AllocdBuffersCount = 0; +u32 NextBuffer = 0; +u32 AllocdStrBuffersCount = 0; +u32 NextStrBuffer = 0; +int sSema = 0; +int vag_cmd_cnt = 0; +VagCmd vag_cmds[16]; +u32 vag_cmd_used = 0; +u32 max_vag_cmd_cnt = 0; + +PriStackEntry gPriStack[N_PRIORITIES]; +std::string gPriEntryNames[N_PRIORITIES][PRI_STACK_LENGTH]; // my addition for debug + +void ReturnMessage(CmdHeader* param_1); +void FreeVAGCommand(VagCmd* param_1); + +void iso_queue_init_globals() { + memset(sBuffer, 0, sizeof(sBuffer)); + memset(gPriStack, 0, sizeof(gPriStack)); + memset(vag_cmds, 0, sizeof(vag_cmds)); + + ScratchPadMemory = nullptr; + SpMemoryBuffers = nullptr; + sFreeBuffer = nullptr; + sFreeStrBuffer = nullptr; + BuffersAlloc = 0; + StrBuffersAlloc = 0; + AllocdBuffersCount = 0; + NextBuffer = 0; + sSema = 0; + vag_cmd_cnt = 0; + vag_cmd_used = 0; + max_vag_cmd_cnt = 0; +} + +void InitBuffers() { + SpMemoryBuffers = (PageList*)ScratchPadMemory; + ScratchPadMemory += sizeof(PageList); + InitPagedMemory(SpMemoryBuffers, 0x12, 0x8000); + Buffer* next_buffer = sBuffer; + for (int i = 0; i < 3; i++) { + next_buffer++; + sBuffer[i].next = next_buffer; + sBuffer[i].decomp_buffer = nullptr; + sBuffer[i].decompressed_size = 0; + sBuffer[i].unk_12 = 0; + sBuffer[i].data_buffer_idx = -1; + sBuffer[i].use_mode = 1; + sBuffer[i].plist = SpMemoryBuffers; + sBuffer[i].num_pages = 1; + sBuffer[i].unk_32 = 0; + sBuffer[i].free_pages = 0; + sBuffer[i].page = nullptr; + sBuffer[i].unk_44 = 0; + }; + sBuffer[2].next = nullptr; + + next_buffer = sBuffer + 4; + sFreeBuffer = sBuffer; + BuffersAlloc = 0; + for (int i = 0; i < 8; i++) { + sBuffer[i + 3].next = next_buffer; + next_buffer++; + sBuffer[i + 3].decomp_buffer = nullptr; + sBuffer[i + 3].decompressed_size = 0; + sBuffer[i + 3].unk_12 = 0; + sBuffer[i + 3].data_buffer_idx = -1; + sBuffer[i + 3].use_mode = 2; + sBuffer[i + 3].plist = SpMemoryBuffers; + sBuffer[i + 3].num_pages = 1; + sBuffer[i + 3].unk_32 = 2; + sBuffer[i + 3].free_pages = 0; + sBuffer[i + 3].page = nullptr; + sBuffer[i + 3].unk_44 = 0; + }; + sBuffer[10].next = nullptr; + sFreeStrBuffer = sBuffer + 3; + StreamSRAM[0] = 0x5040; + StrBuffersAlloc = 0; + TrapSRAM[0] = 0x9040; + snd_SRAMMarkUsed(0x5040, 0x4040); + StreamSRAM[1] = 0x9080; + TrapSRAM[1] = 0xd080; + snd_SRAMMarkUsed(0x9080, 0x4040); + StreamSRAM[2] = 0xd0c0; + TrapSRAM[2] = 0x110c0; + snd_SRAMMarkUsed(0xd0c0, 0x4040); + StreamSRAM[3] = 0x11100; + TrapSRAM[3] = 0x15100; + snd_SRAMMarkUsed(0x11100, 0x4040); + + for (int i = 0; i < 4; i++) { + if (DMA_SendToSPUAndSync(VAG_SilentLoop, 0x30, TrapSRAM[i], 0, 1)) { + ASSERT_NOT_REACHED(); + break; + } + DelayThread(1000); + } + + SemaParam param; + param.attr = 1; + param.init_count = 1; + param.max_count = 1; + param.option = 0; + sSema = CreateSema(¶m); + if (sSema < 0) { + printf("IOP: ======================================================================\n"); + printf("IOP: iso_queue InitBuffers: Can\'t create semaphore\n"); + printf("IOP: ======================================================================\n"); + ASSERT_NOT_REACHED(); + } +} + +u32 AllocDataBuffer(u32* param_1, u32 param_2) { + bool bVar1; + u32 uVar2; + u32 uVar3; + int iVar4; + u32 uVar5; + + uVar5 = 0xffffffff; + bVar1 = false; + uVar3 = uVar5; + if (param_1 == &BuffersAlloc) { + if (AllocdBuffersCount < param_2) { + if ((BuffersAlloc & 1 << (NextBuffer & 0x1f)) == 0) { + bVar1 = true; + } else { + iVar4 = 0; + if (0 < (int)param_2) { + do { + NextBuffer = NextBuffer + 1; + if (param_2 <= NextBuffer) { + NextBuffer = 0; + } + iVar4 = iVar4 + 1; + if ((BuffersAlloc & 1 << (NextBuffer & 0x1f)) == 0) { + bVar1 = true; + iVar4 = param_2 + 1; + } + } while (iVar4 < (int)param_2); + } + } + uVar5 = NextBuffer; + if (bVar1) { + BuffersAlloc = BuffersAlloc | 1 << (NextBuffer & 0x1f); + AllocdBuffersCount = AllocdBuffersCount + 1; + NextBuffer = NextBuffer + 1; + uVar3 = uVar5; + if (param_2 <= NextBuffer) { + NextBuffer = 0; + } + } + } + } else { + uVar3 = 0xffffffff; + if ((param_1 == &StrBuffersAlloc) && (uVar3 = uVar5, AllocdStrBuffersCount < param_2)) { + if ((StrBuffersAlloc & 1 << (NextStrBuffer & 0x1f)) == 0) { + bVar1 = true; + } else { + iVar4 = 0; + if (0 < (int)param_2) { + do { + NextStrBuffer = NextStrBuffer + 1; + if (param_2 <= NextStrBuffer) { + NextStrBuffer = 0; + } + iVar4 = iVar4 + 1; + if ((StrBuffersAlloc & 1 << (NextStrBuffer & 0x1f)) == 0) { + bVar1 = true; + iVar4 = param_2 + 1; + } + } while (iVar4 < (int)param_2); + } + } + uVar2 = NextStrBuffer; + if (bVar1) { + StrBuffersAlloc = StrBuffersAlloc | 1 << (NextStrBuffer & 0x1f); + AllocdStrBuffersCount = AllocdStrBuffersCount + 1; + NextStrBuffer = NextStrBuffer + 1; + uVar3 = uVar2; + if (param_2 <= NextStrBuffer) { + NextStrBuffer = 0; + } + } + } + } + return uVar3; +} + +Buffer* AllocateBuffer(int param_1, VagCmd* param_2, int /*param_3*/) { + PageList** ppPVar1; + int* piVar2; + int iVar3; + int iVar4; + int iVar5; + Buffer* pBVar6; + Buffer* pBVar7; + Page* pPVar8; + + // if (param_3 == 1) { + // CpuSuspendIntr(local_28); + //} + pBVar6 = (Buffer*)0x0; + pPVar8 = (Page*)0x0; + if (param_1 == 1) { + if ((sFreeBuffer != (Buffer*)0x0) && + (iVar3 = AllocDataBuffer(&BuffersAlloc, 3), pBVar7 = sFreeBuffer, -1 < iVar3)) { + ppPVar1 = &sFreeBuffer->plist; + piVar2 = &sFreeBuffer->num_pages; + sFreeBuffer->data_buffer_idx = iVar3; + sFreeBuffer->use_mode = 1; + sFreeBuffer = sFreeBuffer->next; + pPVar8 = (Page*)AllocPages(*ppPVar1, *piVar2); + if (pPVar8 != (Page*)0x0) { + pBVar7->page = pPVar8; + pBVar7->free_pages = pPVar8->free_pages; + pBVar7->decomp_buffer = (uint8_t*)pPVar8->buffer; + } + goto LAB_00006a0c; + } + LAB_00006a28: + pBVar7 = pBVar6; + if (pPVar8 != (Page*)0x0) + goto LAB_00006a44; + } else { + if (((param_1 != 2) || (sFreeStrBuffer == (Buffer*)0x0)) || + (iVar3 = AllocDataBuffer(&StrBuffersAlloc, 8), pBVar7 = sFreeStrBuffer, iVar3 < 0)) + goto LAB_00006a28; + sFreeStrBuffer->data_buffer_idx = iVar3; + sFreeStrBuffer->use_mode = 2; + pBVar6 = (param_2->header).callback_buffer; + pPVar8 = (Page*)0x0; + if (param_2->xfer_size == 0) { + iVar5 = sFreeStrBuffer->num_pages; + } else { + iVar4 = sFreeStrBuffer->plist->page_size; + iVar3 = param_2->xfer_size + iVar4 + -1; + if (iVar4 == 0) { + ASSERT_NOT_REACHED(); + // trap(0x1c00); + } + if (pBVar6 == (Buffer*)0x0) { + iVar5 = 0; + } else { + iVar5 = -pBVar6->page->free_pages; + } + iVar5 = iVar3 / iVar4 + iVar5; + if (iVar5 < 0) { + iVar5 = 0; + } + } + pBVar6 = sFreeStrBuffer->next; + if (iVar5 != 0) { + if ((param_2->status_bytes[BYTE10] == '\0') || (param_2->unk_232 == '\0')) { + if (param_2->status_bytes[BYTE4] == '\0') { + iVar3 = sFreeStrBuffer->num_pages; + } else { + iVar3 = sFreeStrBuffer->unk_32; + } + if (iVar5 < iVar3) { + iVar3 = iVar5; + } + } else { + iVar3 = iVar5; + if (3 < iVar5) { + iVar3 = 3; + } + } + ppPVar1 = &sFreeStrBuffer->plist; + sFreeStrBuffer = sFreeStrBuffer->next; + pPVar8 = (Page*)AllocPages(*ppPVar1, iVar3); + pBVar6 = sFreeStrBuffer; + } + sFreeStrBuffer = pBVar6; + if (pPVar8 != (Page*)0x0) { + pBVar7->page = pPVar8; + pBVar7->free_pages = pPVar8->free_pages; + pBVar7->decomp_buffer = (uint8_t*)pPVar8->buffer; + } + LAB_00006a0c: + if (pPVar8 != (Page*)0x0) { + pBVar7->decompressed_size = 0; + pBVar7->next = (Buffer*)0x0; + pBVar7->unk_12 = pPVar8->buffer; + pBVar6 = pBVar7; + goto LAB_00006a28; + } + } + if (pBVar7) { + FreeBuffer(pBVar7, 0); + pBVar7 = (Buffer*)0x0; + } +LAB_00006a44: + // if (param_3 == 1) { + // CpuResumeIntr(local_28[0]); + //} + return pBVar7; +} + +void FreeBuffer(Buffer* param_1, int /*param_2*/) { + Buffer* pBVar1; + Page* pPVar2; + int iVar3; + u32 uVar4; + // if (param_2 == 1) { + // CpuSuspendIntr(local_18); + //} + iVar3 = param_1->use_mode; + if (iVar3 == 1) { + if ((BuffersAlloc & 1 << (param_1->data_buffer_idx & 0x1fU)) != 0) { + pPVar2 = FreePagesList(param_1->plist, param_1->page); + pBVar1 = sFreeBuffer; + uVar4 = param_1->data_buffer_idx; + param_1->page = pPVar2; + param_1->data_buffer_idx = -1; + param_1->decompressed_size = 0; + param_1->unk_12 = 0; + sFreeBuffer = param_1; + param_1->use_mode = 0; + param_1->next = pBVar1; + BuffersAlloc = BuffersAlloc & ~(1 << (uVar4 & 0x1f)); + AllocdBuffersCount = AllocdBuffersCount + -1; + } + } else if (((1 < iVar3) && (iVar3 == 2)) && + ((StrBuffersAlloc & 1 << (param_1->data_buffer_idx & 0x1fU)) != 0)) { + pPVar2 = FreePagesList(param_1->plist, param_1->page); + param_1->page = pPVar2; + param_1->decompressed_size = 0; + param_1->unk_12 = 0; + pBVar1 = param_1; + param_1->next = sFreeStrBuffer; + sFreeStrBuffer = pBVar1; + StrBuffersAlloc = StrBuffersAlloc & ~(1 << (param_1->data_buffer_idx & 0x1fU)); + AllocdStrBuffersCount = AllocdStrBuffersCount + -1; + param_1->data_buffer_idx = -1; + param_1->use_mode = 0; + } + // if (param_2 == 1) { + // CpuResumeIntr(local_18[0]); + //} +} + +void ReleaseMessage(CmdHeader* param_1, int param_2) { + Buffer* pBVar1; + int iVar2; + PriStackEntry* pPVar3; + int iVar4; + int iVar5; + PriStackEntry* pPVar6; + + pBVar1 = param_1->callback_buffer; + while (pBVar1 != (Buffer*)0x0) { + pBVar1 = param_1->callback_buffer; + param_1->callback_buffer = pBVar1->next; + FreeBuffer(pBVar1, param_2); + pBVar1 = param_1->callback_buffer; + } + if (param_1->lse != (LoadStackEntry*)0x0) { + // (*(code*)isofs->close)(); + isofs->close(param_1->lse); + } + // if (param_2 == 1) { + // CpuSuspendIntr(local_18); + //} + iVar5 = 0; + pPVar6 = gPriStack; +LAB_00006d0c: + iVar4 = 0; + pPVar3 = pPVar6; + if (pPVar6->count < 1) + goto LAB_00006da0; + do { + if (pPVar3->entries[0] == param_1) + break; + iVar4 = iVar4 + 1; + pPVar3 = (PriStackEntry*)(pPVar3->entries + 1); + } while (iVar4 < pPVar6->count); + iVar2 = pPVar6->count + -1; + if (pPVar6->count <= iVar4) + goto LAB_00006da0; + pPVar6->count = iVar2; + if (iVar4 < iVar2) { + do { + iVar5 = iVar4 + 1; + pPVar6->entries[iVar4] = pPVar6->entries[iVar4 + 1]; + iVar4 = iVar5; + } while (iVar5 < pPVar6->count); + } + if (param_2 != 1) { + return; + } + goto LAB_00006dbc; +LAB_00006da0: + iVar5 = iVar5 + 1; + pPVar6 = pPVar6 + 1; + if (3 < iVar5) { + if (param_2 == 1) { + LAB_00006dbc:; + // CpuResumeIntr(local_18[0]); + } + return; + } + goto LAB_00006d0c; +} + +void DisplayQueue() { + for (int pri = 0; pri < N_PRIORITIES; pri++) { + for (int cmd = 0; cmd < (int)gPriStack[pri].count; cmd++) { + lg::debug(" PRI {} elt {} {} @ #x{:X}", pri, cmd, gPriEntryNames[pri][cmd], + (u64)gPriStack[pri].entries[cmd]); + } + } +} + +int QueueMessage(CmdHeader* param_1, int param_2, const char* param_3, int param_4) { + int uVar1; + // undefined4 local_20[2]; + + if (param_4 == 1) { + // CpuSuspendIntr(local_20); + } + if (gPriStack[param_2].count == 8) { + param_1->status = 2; + // CpuResumeIntr(local_20[0]); + ReturnMessage(param_1); + uVar1 = 0; + } else { + gPriStack[param_2].entries[gPriStack[param_2].count] = param_1; + gPriEntryNames[param_2][gPriStack[param_2].count] = param_3; + + gPriStack[param_2].count = gPriStack[param_2].count + 1; + if (param_4 == 1) { + // CpuResumeIntr(local_20[0]); + } + uVar1 = 1; + } + return uVar1; +} + +void UnqueueMessage(CmdHeader* param_1, int param_2) { + int iVar1; + PriStackEntry* pPVar2; + int iVar3; + PriStackEntry* pPVar4; + int iVar5; + + if (param_2 == 1) { + // CpuSuspendIntr(local_18); + } + iVar5 = 0; + pPVar4 = gPriStack; +LAB_00007088: + iVar3 = 0; + pPVar2 = pPVar4; + if (pPVar4->count < 1) + goto LAB_0000711c; + do { + if (pPVar2->entries[0] == param_1) + break; + iVar3 = iVar3 + 1; + pPVar2 = (PriStackEntry*)(pPVar2->entries + 1); + } while (iVar3 < pPVar4->count); + iVar1 = pPVar4->count + -1; + if (pPVar4->count <= iVar3) + goto LAB_0000711c; + pPVar4->count = iVar1; + if (iVar3 < iVar1) { + do { + iVar5 = iVar3 + 1; + pPVar4->entries[iVar3] = pPVar4->entries[iVar3 + 1]; + iVar3 = iVar5; + } while (iVar5 < pPVar4->count); + } + if (param_2 != 1) { + return; + } + goto LAB_00007138; +LAB_0000711c: + iVar5 = iVar5 + 1; + pPVar4 = pPVar4 + 1; + if (3 < iVar5) { + if (param_2 == 1) { + LAB_00007138:; + // CpuResumeIntr(local_18[0]); + } + return; + } + goto LAB_00007088; +} + +CmdHeader* GetMessage() { + CmdHeader* pCVar1; + int iVar2; + CmdHeader** ppCVar3; + PriStackEntry* iVar4; + int iVar5; + + iVar5 = 3; + iVar4 = gPriStack + 3; + do { + iVar2 = iVar4->count + -1; + if (-1 < iVar2) { + ppCVar3 = iVar4->entries + iVar4->count + -1; + do { + pCVar1 = *ppCVar3; + if ((((pCVar1->lse != (LoadStackEntry*)0x0) && (pCVar1->status == -1)) && + (pCVar1->unk_24 != 0)) && + ((pCVar1->callback_buffer == (Buffer*)0x0 || + (pCVar1->callback_buffer->next == (Buffer*)0x0)))) { + return pCVar1; + } + iVar2 = iVar2 + -1; + ppCVar3 = ppCVar3 + -1; + } while (-1 < iVar2); + } + iVar5 = iVar5 + -1; + iVar4 = iVar4 + -1; + if (iVar5 < 0) { + return (CmdHeader*)0x0; + } + } while (true); +} + +void ProcessMessageData() { + int iVar1; + CmdHeader* pCVar2; + Buffer* pBVar3; + int iVar4; + CmdHeader** ppCVar5; + PriStackEntry* iVar6; + int iVar7; + + iVar7 = 2; + iVar6 = gPriStack + 2; + do { + iVar4 = iVar6->count + -1; + if (-1 < iVar4) { + ppCVar5 = iVar6->entries + iVar6->count + -1; + do { + pCVar2 = *ppCVar5; + if ((pCVar2 != (CmdHeader*)0x0) && (pCVar2->unk_24 != 0)) { + iVar1 = pCVar2->status; + if (iVar1 == -1) { + pBVar3 = pCVar2->callback_buffer; + if (pBVar3 != (Buffer*)0x0) { + if (pCVar2->callback != ProcessVAGData) { + iVar1 = (pCVar2->callback)(pCVar2, pBVar3); + pCVar2->status = iVar1; + if (pBVar3->decompressed_size == 0) { + pCVar2->callback_buffer = pBVar3->next; + FreeBuffer(pBVar3, 1); + } + } + iVar1 = pCVar2->status; + } + if (iVar1 == -1) + goto LAB_00007308; + } + + ReleaseMessage(pCVar2, 1); + ReturnMessage(pCVar2); + iVar6 = iVar6 + 1; + iVar7 = iVar7 + 1; + break; + } + LAB_00007308: + iVar4 = iVar4 + -1; + ppCVar5 = ppCVar5 + -1; + } while (-1 < iVar4); + } + iVar7 = iVar7 + -1; + iVar6 = iVar6 + -1; + if (iVar7 < 0) { + return; + } + } while (true); +} + +void ReturnMessage(CmdHeader* param_1) { + if (param_1->mbx_to_reply == 0) { + if (param_1->thread_id == 0) { + FreeVAGCommand((VagCmd*)param_1); + } else { + WakeupThread(param_1->thread_id); + } + } else { + SendMbx(param_1->mbx_to_reply, param_1); + } +} + +VagCmd* GetVAGCommand() { + int iVar1; + u32 uVar2; + VagCmd* pRVar3; + + do { + while (vag_cmd_cnt == 0x1f) { + DelayThread(100); + } + do { + iVar1 = WaitSema(sSema); + uVar2 = 0; + pRVar3 = vag_cmds; + } while (iVar1 != 0); + do { + if (((int)vag_cmd_used >> (uVar2 & 0x1f) & 1U) == 0) { + vag_cmd_used = vag_cmd_used | 1 << (uVar2 & 0x1f); + vag_cmd_cnt = vag_cmd_cnt + 1; + if ((int)max_vag_cmd_cnt < vag_cmd_cnt) { + max_vag_cmd_cnt = vag_cmd_cnt; + } + SignalSema(sSema); + return pRVar3; + } + uVar2 = uVar2 + 1; + pRVar3 = pRVar3 + 1; + } while ((int)uVar2 < 0x1f); + SignalSema(sSema); + } while (true); +} + +void FreeVAGCommand(VagCmd* param_1) { + int iVar1; + u32 uVar2; + + // uVar2 = (param_1 + -0x17e50) * 0x781948b1 >> 2; + // kinda sus + uVar2 = (param_1 - vag_cmds) / sizeof(VagCmd); + if ((uVar2 < 0x1f) && (((int)vag_cmd_used >> (uVar2 & 0x1f) & 1U) != 0)) { + do { + iVar1 = WaitSema(sSema); + } while (iVar1 != 0); + vag_cmd_used = vag_cmd_used & ~(1 << (uVar2 & 0x1f)); + vag_cmd_cnt = vag_cmd_cnt + -1; + SignalSema(sSema); + } +} + +uint8_t* CheckForIsoPageBoundaryCrossing(Buffer* param_1) { + Page* new_page; + uint8_t* iVar1; + uint8_t* our_ptr; + uint8_t* page_end; + + our_ptr = param_1->decomp_buffer; + page_end = (uint8_t*)param_1->page->ptr; + if (page_end <= our_ptr) { + new_page = StepTopPage(param_1->plist, param_1->page); + param_1->page = new_page; + if (new_page != (Page*)0x0) { + iVar1 = new_page->buffer; + param_1->unk_12 = iVar1; + param_1->decomp_buffer = page_end + (iVar1 - (our_ptr + -1)); + } + } + return param_1->decomp_buffer; +} + +void FreeDataBuffer(u32* param_1, u32 param_2) { + if (param_1 == &BuffersAlloc) { + BuffersAlloc = BuffersAlloc & ~(1 << (param_2 & 0x1f)); + AllocdBuffersCount = AllocdBuffersCount + -1; + } else if (param_1 == &StrBuffersAlloc) { + AllocdStrBuffersCount = AllocdStrBuffersCount + -1; + StrBuffersAlloc = StrBuffersAlloc & ~(1 << (param_2 & 0x1f)); + } +} + +} // namespace jak2 diff --git a/game/overlord/jak2/iso_queue.h b/game/overlord/jak2/iso_queue.h new file mode 100644 index 0000000000..8c92b09aae --- /dev/null +++ b/game/overlord/jak2/iso_queue.h @@ -0,0 +1,35 @@ +#pragma once +#include + +#include "common/common_types.h" + +#include "game/overlord/jak2/iso.h" +#include "game/overlord/jak2/pages.h" +namespace jak2 { +extern uint8_t* ScratchPadMemory; +void iso_queue_init_globals(); +extern PageList* SpMemoryBuffers; +void ReleaseMessage(CmdHeader* param_1, int param_2); +int QueueMessage(CmdHeader* param_1, int param_2, const char* param_3, int param_4); +void DisplayQueue(); +uint8_t* CheckForIsoPageBoundaryCrossing(Buffer* param_1); +void InitBuffers(); +void FreeBuffer(Buffer* param_1, int param_2); +Buffer* AllocateBuffer(int param_1, VagCmd* param_2, int param_3); +void UnqueueMessage(CmdHeader* param_1, int param_2); +void ReturnMessage(CmdHeader* param_1); +CmdHeader* GetMessage(); +VagCmd* GetVAGCommand(); + +constexpr int N_PRIORITIES = 4; // number of queued commands per priority +constexpr int PRI_STACK_LENGTH = 8; // number of queued commands per priority + +struct PriStackEntry { + CmdHeader* entries[PRI_STACK_LENGTH]; + int count; +}; + +extern std::string gPriEntryNames[N_PRIORITIES][PRI_STACK_LENGTH]; // my addition for debug +extern PriStackEntry gPriStack[N_PRIORITIES]; + +} // namespace jak2 diff --git a/game/overlord/jak2/list.cpp b/game/overlord/jak2/list.cpp new file mode 100644 index 0000000000..4d3979a033 --- /dev/null +++ b/game/overlord/jak2/list.cpp @@ -0,0 +1,127 @@ +#include "list.h" + +#include + +#include "common/util/Assert.h" + +#include "game/sce/iop.h" + +using namespace iop; +namespace jak2 { + +bool InitList(List* head, u32 elt_count, int elt_size) { + ListNode* buf_ptr; + int iVar1; + ListNode** ppLVar2; + u32 elt_idx; + SemaParam local_20; + + head->elt_count = elt_count; + buf_ptr = (ListNode*)AllocSysMemory(0, elt_count * elt_size, 0); + head->buffer = (u8*)buf_ptr; + if (!buf_ptr) { + printf("IOP: ======================================================================\n"); + printf("IOP: list InitList: no memory for list %s\n", head->name); + printf("IOP: ======================================================================\n"); + ASSERT_NOT_REACHED(); + } + elt_idx = 0; + head->next = buf_ptr; + // suspicious pointer math ahead. + if (elt_count != 0) { + ppLVar2 = &buf_ptr->prev; + do { + ppLVar2[1] = (ListNode*)0x0; + if (elt_idx < elt_count - 1) { + buf_ptr->next = (ListNode*)((u8*)&buf_ptr->next + elt_size); + } else { + buf_ptr->next = (ListNode*)0x0; + } + if (elt_idx == 0) { + *ppLVar2 = (ListNode*)0x0; + } else { + *ppLVar2 = (ListNode*)((u8*)buf_ptr - elt_size); + } + ppLVar2 = (ListNode**)((u8*)ppLVar2 + elt_size); + elt_idx = elt_idx + 1; + buf_ptr = (ListNode*)((u8*)&buf_ptr->next + elt_size); + } while (elt_idx < elt_count); + } + head->maybe_any_in_use = 0; + head->unk2_init0 = 0; + local_20.attr = 1; + local_20.init_count = 1; + local_20.max_count = 1; + local_20.option = 0; + iVar1 = CreateSema(&local_20); + head->sema = iVar1; + if (iVar1 < 0) { + printf("IOP: ======================================================================\n"); + printf("IOP: list InitList: can\'t create semaphore for list %s\n", head->name); + printf("IOP: ======================================================================\n"); + ASSERT_NOT_REACHED(); + } + return head->buffer != (void*)0x0; +} + +ListNode* AddToCircularList(List* param_1) { + int iVar1; + ListNode* pLVar2; + + iVar1 = param_1->elt_count; + pLVar2 = param_1->next; + while (iVar1 != 0) { + iVar1 = iVar1 + -1; + if (pLVar2->in_use != 1) + goto LAB_00011c14; + pLVar2 = pLVar2->next; + } + if (pLVar2->in_use == 1) { + pLVar2 = param_1->next->next; + param_1->next = pLVar2; + pLVar2 = pLVar2->prev; + } +LAB_00011c14: + param_1->maybe_any_in_use = 1; + pLVar2->in_use = 1; + return pLVar2; +} + +void MakeCircularList(List* lst) { + ListNode* pLVar1; + ListNode* pLVar2; + int iVar3; + ListNode* pLVar4; + + pLVar4 = lst->next; + iVar3 = lst->elt_count; + pLVar1 = pLVar4->next; + pLVar2 = pLVar4; + while (true) { + if (pLVar1 == (ListNode*)0x0) { + if (iVar3 != 0) { + pLVar2->next = pLVar4; + pLVar4->prev = pLVar2; + } + return; + } + if (iVar3 == 0) + break; + pLVar2 = pLVar2->next; + pLVar1 = pLVar2->next; + iVar3 = iVar3 + -1; + } +} + +void BreakCircularList(List* param_1) { + ListNode* pLVar1; + ListNode* pLVar2; + + pLVar2 = param_1->next; + pLVar1 = pLVar2->prev; + if (pLVar1) { + pLVar1->next = nullptr; + pLVar2->prev = nullptr; + } +} +} // namespace jak2 diff --git a/game/overlord/jak2/list.h b/game/overlord/jak2/list.h new file mode 100644 index 0000000000..fc917574b6 --- /dev/null +++ b/game/overlord/jak2/list.h @@ -0,0 +1,26 @@ +#pragma once + +#include "common/common_types.h" +namespace jak2 { + +struct ListNode; + +struct List { + char name[8]; + int sema; // 12 + int maybe_any_in_use; // 16 + int elt_count; // 20 + int unk2_init0; // 24 + + ListNode* next; + u8* buffer; +}; + +struct ListNode { + ListNode* next; + ListNode* prev; + int in_use; +}; + +bool InitList(List* head, u32 elt_count, int elt_size); +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/notes.md b/game/overlord/jak2/notes.md new file mode 100644 index 0000000000..786e526fea --- /dev/null +++ b/game/overlord/jak2/notes.md @@ -0,0 +1,348 @@ +### overlord.c +start + done, removed ramdisk stuff. + +ExitIOP + done (just loops forever) + + +### iso_cd.c +was ported. calling cd callbacks is a little sus. + +## ramdisk.c +ramdisk is believed unused, we will try without it for now + +InitRamdisk +Thread_Server +RPC_Ramdisk +gcc2_compiled. +__gnu_compiled_c +gNumFiles +gMemUsed +gMemSize +gRPCBuf +gMem +gReturnBuffer + + +### fakeiso.c +We make this up. Snd/Music loading is a tiny bit different but Ziemas has patched this. +Should move these to common once we figure out how to deal with FileRecord changes. + +### deviso.c +Empty file + +### isocommon.c +All can be common. Additionally, some of these are implemented in FileUtils already, and are used in the decompiler. + +ISONameFromAnimationName + technically is game specific, but we've already patched it +MakeISOName +UnmakeISOName + +### isodesc.c +Empty file! + +### dma.c +Changed a bit for jak 2. there's now DmaVagCmd, which is used for dmaing stuff to the SPU. TODO +The EE stuff has also changed and has a semaphore. However, we will ignore this and use the same instant dma as jak 1. +Downstream stuff that looks at the semaphore will need to be patched. + +SpuDmaIntr + TODO + +DMA_SendToEE + moved to common, instant dma, removed semaphore stuff + +DMA_SendToSPUAndSync + TODO. different +DmaCancelThisVagCmd + TODO. different +EeDmaIntr + Not ported yet, just calls iSignalSema on the ee dma semaphore. Don't think we need this. + +### iso.c +Note that jak 2 drops the chained buffer system from jak 1 and uses the "pages" system instead. + +InitISOFS +IsoQueueVagStream +IsoPlayVagStream +ISOThread +RunDGOStateMachine +LoadDGO +CopyData +FindISOFile +FindVAGFile +GetISOFileLength +NullCallback +IsoStopVagStream +CopyDataToIOP +CopyDataToEE +DGOThread +RPC_DGO +LoadNextDGO +CancelDGO +InitDriver +SetVagClock +gcc2_compiled. +__gnu_compiled_c +iso_thread +dgo_mbx +dgo_thread +str_thread +play_thread +sync_mbx +iso_init_flag +_not_on_stack_sync +sLoadDgo +sRPCBuf + +### iso_queue.c +InitBuffers +AllocDataBuffer +AllocateBuffer +FreeBuffer +ReleaseMessage +AllocIsoPages +FreeIsoPages +QueueMessage +UnqueueMessage +GetMessage +ProcessMessageData +ReturnMessage +GetVAGCommand +FreeVAGCommand +CheckForIsoPageBoundaryCrossing +FreeDataBuffer +gcc2_compiled. +__gnu_compiled_c +AllocdBuffersCount +NextBuffer +AllocdStrBuffersCount +NextStrBuffer +VAG_SilentLoop +sFreeBuffer +sFreeStrBuffer +sSema +vag_cmd_used +vag_cmd_cnt +max_vag_cmd_cnt +vag_cmds + +### stream.c +RPC_STR +RPC_PLAY +STRThread +PLAYThread +gcc2_compiled. +__gnu_compiled_c +sCache + +### srpc.c +RPC_Player +RPC_Loader +VBlank_Handler +Thread_Player +Thread_Loader +SetVagStreamName +SetVagName +gcc2_compiled. +__gnu_compiled_c +gInfoEE +gMusic +languages.8 +dmaid +info +gPlayerBuf +gLoaderBuf + +### vag.c +InitVagCmds +SmartAllocVagCmd +TerminateVAG +PauseVAG +UnPauseVAG +RestartVag +SetVAGVol +SetVagStreamsNoStart +InitVAGCmd +SetVagStreamsNotScanned +RemoveVagCmd +FindFreeVagCmd +FindNotQueuedVagCmd +FindWhosPlaying +FindVagStreamId +FindVagStreamPluginId +FindVagStreamName +FindThisVagStream +AnyVagRunning +FreeVagCmd +SetNewVagCmdPri +HowManyBelowThisPriority +StopVAG +VAG_MarkLoopEnd +VAG_MarkLoopStart +CalculateVAGPitch +PauseVagStreams +UnPauseVagStreams +SetAllVagsVol +CalculateVAGVolumes +gcc2_compiled. +__gnu_compiled_c +sbank.c +InitBanks +AllocateBankName +LookupBank +gcc2_compiled. +__gnu_compiled_c +gBanks +gCommonBank +gGunBank +gBoardBank +gLevelBanks + +### ssound.c +InitSound +AllocateSound +CalculateFalloffVolume +CalculateAngle +SetEarTrans +SndMemAlloc +LookupSound +CleanSounds +UpdateVolume +GetVolume +GetPan +KillSoundsInGroup +SetCurve +SetMusicVol +SetBufferMem +ReleaseBufferMem +SndMemFree +gcc2_compiled. +__gnu_compiled_c +sqrt_table +atan_table +gSounds +gEarTrans +gCamTrans +gCamAngle +last_tick.26 +common_bank +common_bank_mem +other_bank +other_bank_mem +mmd_bank +mmd_bank_mem +buffer_mem + +### /usr/home/agavin/src/jak2/libs/common/soundcommon.c +ReadBankSoundNames +strcpy_toupper +gcc2_compiled. +__gnu_compiled_c + +### iso_api.c +EEVagAndVagwad +QueueVAGStream +LoadISOFileToIOP +LoadISOFileToEE +LoadISOFileChunkToEE +PauseVAGStreams +UnpauseVAGStreams +SetVAGStreamPitch +SetDialogVolume +LoadSoundBank +LoadMusic +UnLoadMusic +PluginVagAndVagWad +gcc2_compiled. +__gnu_compiled_c + +### /usr/home/agavin/src/jak2/libs/common/minilzo.c +lzo1x_decompress +__lzo_init2 +gcc2_compiled. +__gnu_compiled_c +__lzo_init_done +plugin.c +Init989Plugins +QueueVagStream989 +NullPlugin989 +PlayQueuedVagStream989 +StopVagStream989 +SetVagStreamVolume989 +StopEmAll989 +SetStreamLfo989 +gcc2_compiled. +__gnu_compiled_c +PluginId + +### streamlfo.c +SineLfo +InitSineLfo +InitRandLfo +InitStreamLfoHandler +RandomLfo +RemoveLfoStreamFromList +CheckLfoList +UpdateLfoVars +RandomLfoSetPitchVars +RandomLfoWaitForPitch +SineLfoSetPitchVars +SineLfoWaitForPitch +StreamLfo +InitStreamLfoList +AddToCircularLfoStreamList +FindLfoStreamInList +gcc2_compiled. +__gnu_compiled_c +sine +_seed + +### streamlist.c +InsertVagStreamInList +QueueNewStreamsFromList +CheckPlayList +StreamListThread +InitVagStreamList +FindVagStreamInList +GetVagStreamInList +RemoveVagStreamFromList +EmptyVagStreamList +MergeVagStreamLists +gcc2_compiled. +__gnu_compiled_c + +### spustreams.c +ProcessVAGData +GetVAGStreamPos +CheckVAGStreamProgress +CheckVagStreamsProgress +StopVagStream +UpdateIsoBuffer +InitSpuStreamsThread +WakeSpuStreamsUp +GetSpuRamAddress +bswap +ProcessStreamData +gcc2_compiled. +__gnu_compiled_c +StreamsThread + +### pages.c +InitPagedMemory +AllocPagesBytes +AllocPages +FreePagesList +StepTopPage +FromPagesCopy +gcc2_compiled. +__gnu_compiled_c + +### list.c +InitList +AddToCircularList +MakeCircularList +BreakCircularList +gcc2_compiled. \ No newline at end of file diff --git a/game/overlord/jak2/overlord.cpp b/game/overlord/jak2/overlord.cpp new file mode 100644 index 0000000000..40545ef7ba --- /dev/null +++ b/game/overlord/jak2/overlord.cpp @@ -0,0 +1,122 @@ +#include "overlord.h" + +#include +#include + +#include "game/overlord/common/sbank.h" +#include "game/overlord/jak1/ramdisk.h" +#include "game/overlord/jak2/iso.h" +#include "game/overlord/jak2/iso_queue.h" +#include "game/overlord/jak2/srpc.h" +#include "game/overlord/jak2/ssound.h" +#include "game/sce/iop.h" + +namespace jak2 { +using namespace iop; + +u8* ScratchPadMemoryBase; + +namespace { +// believed unused global +s32 SndPlayThread; +} // namespace + +/*! + * Entry point for the overlord. This runs InitISOFS, registers the vblank handler, and starts up + * the threads. It returns and assumes that the IOP kernel runs the threads. + */ +int start_overlord(int, const char* const*) { + sceSifInit(); + sceSifInitRpc(0); + printf("IOP: =========Startup===(%x)====\n", 0); + // removed memory prints. + + ScratchPadMemory = (u8*)AllocScratchPad(0); + ScratchPadMemoryBase = ScratchPadMemory; + // removed allocation check code. + + InitBanks(); + InitSound_overlord(); + jak1::InitRamdisk(); // ramdisk believed unused. + RegisterVblankHandler(0, 0x20, VBlank_Handler, 0); + + // ramdisk believed unused. + ThreadParam param; + param.entry = jak1::Thread_Server; + param.attr = TH_C; + param.initPriority = 0x7a; + param.stackSize = 0x800; + param.option = 0; + strcpy(param.name, "Server"); // added + auto thread_server = CreateThread(¶m); + if (thread_server <= 0) { + return 1; + } + + param.entry = Thread_Player; + param.attr = TH_C; + param.initPriority = 100; + param.stackSize = 0x800; + param.option = 0; + strcpy(param.name, "Player"); // added + auto thread_player = CreateThread(¶m); + if (thread_player <= 0) { + return 1; + } + + param.entry = Thread_Loader; + param.attr = 0x73; + param.initPriority = TH_C; + param.stackSize = 0x1000; + param.option = 0; + SndPlayThread = thread_player; + auto thread_loader = CreateThread(¶m); + if (thread_loader <= 0) { + return 1; + } + + InitISOFS(/*argv[1], argv[2]*/); + StartThread(thread_server, 0); + StartThread(thread_player, 0); + StartThread(thread_loader, 0); + printf("IOP: =========After inits=============\n"); + // removed memory printing code + + return 0; +} + +static s32 gargc; +static const char* const* gargv; +static bool* init_complete; + +static u32 call_start() { + start_overlord(gargc, gargv); + *init_complete = true; + + while (true) { + SleepThread(); + } + return 0; +} + +int start_overlord_wrapper(int argc, const char* const* argv, bool* signal) { + ThreadParam param = {}; + + gargc = argc; + gargv = argv; + init_complete = signal; + + param.attr = TH_C; + param.initPriority = 0; + param.stackSize = 0x800; + param.option = 0; + strcpy(param.name, "start"); // added for debug + param.entry = call_start; + + auto start_thread = CreateThread(¶m); + StartThread(start_thread, 0); + + return 0; +} + +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/overlord.h b/game/overlord/jak2/overlord.h new file mode 100644 index 0000000000..adc1e1eaf1 --- /dev/null +++ b/game/overlord/jak2/overlord.h @@ -0,0 +1,7 @@ +#pragma once + +namespace jak2 { + +int start_overlord_wrapper(int argc, const char* const* argv, bool* signal); + +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/pages.cpp b/game/overlord/jak2/pages.cpp new file mode 100644 index 0000000000..1e33d5f2d2 --- /dev/null +++ b/game/overlord/jak2/pages.cpp @@ -0,0 +1,204 @@ +#include "pages.h" + +#include +#include + +#include "common/util/Assert.h" + +#include "game/overlord/jak2/iso_queue.h" +#include "game/sce/iop.h" + +using namespace iop; +namespace jak2 { + +void InitPagedMemory(PageList* pool, int page_count, int page_size) { + // this is such a hack... + // we assume that we're allocated on the scratchpad, and can jump bump the pointer again. + pool->pages = (Page*)(pool + 1); + pool->page_count = page_count; + pool->page_size = page_size; + ScratchPadMemory = ScratchPadMemory + page_count * sizeof(Page); + int fixed_page_size = page_size; + if (page_size < 0) { + fixed_page_size = page_size + 0x7ff; + } + pool->sector_per_page = fixed_page_size >> 0xb; + pool->free_pages = page_count; + pool->page_memory = nullptr; + uintptr_t addr = (uintptr_t)AllocSysMemory(0, page_count * page_size + 0x100, nullptr); + addr += 0x3f; + addr &= ~uintptr_t(63); + u8* mem = (u8*)addr; + if (mem == 0) { + printf("======================================================================\n"); + printf("IOP: pages InitPagedMemory: no memory for pages\n"); + printf("======================================================================\n"); + ASSERT_NOT_REACHED(); + } + Page* page = pool->pages; + pool->page_memory = mem; + if (0 < page_count) { + for (int i = 0; i < page_count; i++) { + page->state = PageState::FREE; + page->buffer = mem; + page->maybe_page_id = i; + page->free_pages = 0; + page->ptr = mem + page_size - 1; + page->next = nullptr; + page->prev = nullptr; + page->end_page_first_only = nullptr; + page++; + mem += page_size; + } + } +} + +/*! + * Allocate a list of pages that contain at least size_bytes in total. + */ +Page* AllocPagesBytes(PageList* page_list, u32 size_bytes) { + u32 num_pages = (size_bytes + page_list->page_size - 1) / page_list->page_size; + return AllocPages(page_list, num_pages); +} + +/*! + * Allocate a list of pages. + */ +Page* AllocPages(PageList* page_list, u32 num_pages) { + if (page_list->page_count < num_pages) { + printf("======================================================================\n"); + printf("IOP: pages AllocPages: %d pages requested %d maximum pages\n", num_pages, + page_list->page_count); + printf("======================================================================\n"); + ASSERT_NOT_REACHED(); + } + if (page_list->free_pages < num_pages) { + printf("======================================================================\n"); + printf("IOP: pages AllocPages: need %d only %d free pages\n", num_pages, page_list->free_pages); + printf("======================================================================\n"); + num_pages = page_list->free_pages; + ASSERT_NOT_REACHED(); // added. + } + + Page* first_page = nullptr; + if (num_pages == 0) { + first_page = nullptr; + } else { + Page* prev_page = nullptr; + int page_idx_in_page_list = 0; + u32 added_pages = 0; + Page* iter = page_list->pages; + do { + if (iter->state == PageState::FREE) { + added_pages++; + page_list->free_pages = page_list->free_pages + -1; + iter->state = PageState::ALLOCATED_EMPTY; + iter->pages_after_this = num_pages - added_pages; + if (!first_page) { + iter->prev = nullptr; + first_page = iter; + } else { + prev_page->next = iter; + iter->prev = prev_page; + } + iter->end_page_first_only = nullptr; + prev_page = iter; + } + page_idx_in_page_list++; + iter++; + } while ((page_idx_in_page_list < MAX_PAGES_IN_POOL) && (added_pages < num_pages)); + prev_page->next = nullptr; + first_page->end_page_first_only = prev_page; + first_page->free_pages = added_pages; + } + return first_page; +} + +/*! + * Return the linked list of pages to the page list. + */ +Page* FreePagesList(PageList* page_list, Page* pages) { + if (pages) { + if (pages->prev) { + printf("======================================================================\n"); + printf("IOP: pages FreePages: First page %d is not top of list\n", pages->maybe_page_id); + printf("======================================================================\n"); + ASSERT_NOT_REACHED(); + } + Page* next; + do { + next = pages->next; + pages->prev = nullptr; + pages->next = nullptr; + pages->end_page_first_only = nullptr; + pages->state = PageState::FREE; + page_list->free_pages = page_list->free_pages + 1; + pages = next; + } while (next); + } + return nullptr; +} + +/*! + * Free the "top" page (the first one) + */ +Page* StepTopPage(PageList* param_1, Page* top_page) { + Page* result = nullptr; + + if (top_page) { + // if we're first, shouldn't have a prev. + if (top_page->prev) { + printf("======================================================================\n"); + printf("IOP: pages StepTopPage: Page %d is not top of list\n", top_page->maybe_page_id); + printf("======================================================================\n"); + ASSERT_NOT_REACHED(); + } + + // new top page + result = top_page->next; + if (result) { + // set up new top page. + result->free_pages = top_page->free_pages + -1; + result->prev = nullptr; + result->end_page_first_only = top_page->end_page_first_only; + } + + // return to pool + top_page->next = nullptr; + top_page->state = PageState::FREE; + param_1->free_pages = param_1->free_pages + 1; + } + return result; +} + +/*! + * Copy bytes from pages + */ +void FromPagesCopy(const Page* page, const u8* page_ptr, u8* dest, int bytes_to_copy) { + Page* next_page; + + const auto* page_data_end = page->ptr; + do { + auto n_this_time = (page_data_end - page_ptr) + 1; + do { + while (true) { + if (!bytes_to_copy) { + return; + } + if (n_this_time <= bytes_to_copy) + break; + memcpy(dest, page_ptr, bytes_to_copy); + bytes_to_copy = 0; + } + memcpy(dest, page_ptr, n_this_time); + dest = dest + n_this_time; + next_page = page->next; + bytes_to_copy = bytes_to_copy - n_this_time; + } while (!next_page); + page_ptr = (uint8_t*)next_page->buffer; + page_data_end = next_page->ptr; + page = next_page; + } while (true); +} + +} // namespace jak2 diff --git a/game/overlord/jak2/pages.h b/game/overlord/jak2/pages.h new file mode 100644 index 0000000000..2fee0d2563 --- /dev/null +++ b/game/overlord/jak2/pages.h @@ -0,0 +1,50 @@ +#pragma once + +#include "common/common_types.h" + +namespace jak2 { +enum class PageState { FREE = 0, ALLOCATED_EMPTY = 3, ALLOCATED_FILLED = 4, SIX = 6 }; + +/*! + * A linked list of pages associated with a single read. + * Each "page" points to a buffer of memory. + */ +struct Page { + // FREE = belongs to the pool, ALLOCATED_EMPTY = in a chain, but no data + PageState state; + + int maybe_page_id; + + // how many pages in the chain after this one + int pages_after_this; + + // how many pages are ALLOCATED_EMPTY in the chain? + int free_pages; + + // the memory for the page + u8* buffer; + + u8* ptr; + + Page* prev; + Page* next; + Page* end_page_first_only; +}; + +struct PageList { + u32 page_count; + u32 page_size; + u32 sector_per_page; // round down + u32 free_pages; + u8* page_memory; + Page* pages; +}; + +constexpr int MAX_PAGES_IN_POOL = 0x12; +void InitPagedMemory(PageList* pool, int page_count, int page_size); +Page* AllocPagesBytes(PageList* page_list, u32 size_bytes); +Page* AllocPages(PageList* page_list, u32 num_pages); +Page* FreePagesList(PageList* page_list, Page* pages); +void FromPagesCopy(const Page* page, const u8* page_ptr, u8* dest, int bytes_to_copy); +Page* StepTopPage(PageList* param_1, Page* top_page); +} // namespace jak2 diff --git a/game/overlord/jak2/spustreams.cpp b/game/overlord/jak2/spustreams.cpp new file mode 100644 index 0000000000..c955e8decf --- /dev/null +++ b/game/overlord/jak2/spustreams.cpp @@ -0,0 +1,1065 @@ +#include "spustreams.h" + +#include "common/common_types.h" +#include "common/util/Assert.h" + +#include "game/overlord/jak2/dma.h" +#include "game/overlord/jak2/iso.h" +#include "game/overlord/jak2/iso_queue.h" +#include "game/overlord/jak2/streamlist.h" +#include "game/overlord/jak2/vag.h" +#include "game/sce/iop.h" +#include "game/sound/sdshim.h" + +using namespace iop; + +namespace jak2 { + +s32 StreamsThread = 0; +void spusstreams_init_globals() { + StreamsThread = 0; +} + +int ProcessVAGData(CmdHeader* param_1_in, Buffer* param_2) { + VagCmd* param_1 = (VagCmd*)param_1_in; + int iVar1; + int iVar2; + u32 uVar3; + int iVar4; + u32 uVar5; + int* piVar6; + VagCmd* pRVar7; + // undefined4 local_18[2]; + + if (param_1->status_bytes[BYTE6] != '\0') { + // printf("ProcessVAG didn't want the data: byte 6 is set\n"); + return -1; + } + if (param_1->status_bytes[BYTE11] != '\0') { + // printf("ProcessVAG didn't want the data: byte 11 is set\n"); + return -1; + } + if (param_1->unk_260 != 0) { + // printf("ProcessVAG didn't want the data: unk_260 is set, indicating INVALID data.\n"); + param_2->decompressed_size = 0; + return -1; + } + if (!param_1->safe_to_change_dma_fields) { + return -1; + } + // CpuSuspendIntr(local_18); + CheckForIsoPageBoundaryCrossing(param_2); + // added this check + if (!param_2->page) { + // printf("ProcessVAG didn't want the data: the buffer has no page (added check)\n"); + return -1; + } + + iVar2 = (int)param_2->page->state; + if ((iVar2 != 6) && (iVar2 != 4)) { + // printf("ProcessVAG didn't want the data: the buffer isn't full.\n"); + goto LAB_0000fecc; + } + + param_2->page->state = PageState::SIX; + pRVar7 = param_1->stereo_sibling; + iVar2 = 0x2000; + if (pRVar7 != 0x0) { + iVar2 = 0x4000; + } + uVar3 = param_1->num_processed_chunks; + if (uVar3 == 0) { + piVar6 = (int*)param_2->decomp_buffer; + if ((*piVar6 != 0x70474156) && (*piVar6 != 0x56414770)) { + param_1->unk_260 = 1; + param_2->decompressed_size = 0; + goto LAB_0000fecc; + } + param_1->unk_248 = piVar6[4]; + iVar2 = piVar6[3]; + param_1->unk_204 = 0; + param_1->xfer_size = iVar2; + if (*piVar6 == 0x70474156) { + uVar3 = param_1->unk_248; + uVar5 = param_1->xfer_size; + param_1->unk_248 = + uVar3 >> 0x18 | ((int)uVar3 >> 8 & 0xff00U) | (uVar3 & 0xff00) << 8 | uVar3 << 0x18; + param_1->xfer_size = + uVar5 >> 0x18 | ((int)uVar5 >> 8 & 0xff00U) | (uVar5 & 0xff00) << 8 | uVar5 << 0x18; + } + if (pRVar7 != 0x0) { + pRVar7->unk_248 = piVar6[4]; + iVar2 = piVar6[3]; + pRVar7->unk_204 = 0; + pRVar7->xfer_size = iVar2; + } + iVar4 = param_1->xfer_size; + iVar2 = iVar4 + 0x30; + param_1->unk_264 = 0x4000; + param_1->xfer_size = iVar2; + param_1->pitch1 = (u32)(param_1->unk_248 << 0xc) / 48000; + if ((iVar2 < 0x2001) && (0x3fff < (u32)param_1->unk_264)) { + iVar1 = 0x10; + if (0x1f < iVar2) { + iVar1 = iVar4 + 0x20; + } + param_1->unk_264 = iVar1; + if (pRVar7 != 0x0) { + pRVar7->unk_248 = param_1->unk_248; + iVar2 = param_1->xfer_size; + pRVar7->unk_204 = 0; + pRVar7->xfer_size = iVar2; + pRVar7->unk_264 = param_1->unk_264; + pRVar7->pitch1 = param_1->pitch1; + pRVar7->xfer_size = param_1->xfer_size; + pRVar7->unk_264 = param_1->unk_264; + } + } + iVar2 = DMA_SendToSPUAndSync(param_2->decomp_buffer, 0x2000, param_1->spu_stream_dma_mem_addr, + param_1, 0); + if (iVar2 == 0) + goto LAB_0000fecc; + param_1->unk_196 = 0; + param_1->unk_200 = 0; + if (pRVar7) { // added + pRVar7->unk_200 = 0; + } + LAB_0000fbdc: + iVar2 = 0x2000; + if (pRVar7 != 0x0) { + iVar2 = 0x4000; + } + param_2->decomp_buffer = param_2->decomp_buffer + iVar2; + iVar4 = param_1->xfer_size - iVar2; + if (iVar2 < param_1->xfer_size) + goto LAB_0000fe98; + param_1->xfer_size = 0; + LAB_0000feb4: + param_2->decompressed_size = 0; + } else { + if (uVar3 == 1) { + iVar4 = param_1->xfer_size; + if ((iVar2 < iVar4) || ((u32)param_1->unk_264 < 0x4000)) { + VAG_MarkLoopEnd((int8_t*)param_2->decomp_buffer, 0x2000); + VAG_MarkLoopStart((int8_t*)param_2->decomp_buffer); + if (pRVar7 != 0x0) { + VAG_MarkLoopEnd((int8_t*)param_2->decomp_buffer, 0x4000); + VAG_MarkLoopStart((int8_t*)(param_2->decomp_buffer + 0x2000)); + } + } else { + iVar2 = 0x2010; + if (0x1f < iVar4) { + if (pRVar7 == 0x0) { + iVar2 = iVar4 + 0x1ff0; + } else { + iVar2 = iVar4 / 2 + 0x1ff0; + } + } + param_1->unk_264 = iVar2; + if (pRVar7 != 0x0) { + pRVar7->unk_264 = param_1->unk_264; + } + } + iVar2 = DMA_SendToSPUAndSync(param_2->decomp_buffer, 0x2000, + param_1->spu_stream_dma_mem_addr + 0x2000, param_1, 0); + if (iVar2 == 0) + goto LAB_0000fecc; + (param_1->header).unk_24 = 0; + goto LAB_0000fbdc; + } + if ((uVar3 & 1) != 0) { + iVar4 = param_1->xfer_size; + if ((iVar2 < iVar4) || ((u32)param_1->unk_264 < 0x4000)) { + VAG_MarkLoopEnd((int8_t*)param_2->decomp_buffer, 0x2000); + VAG_MarkLoopStart((int8_t*)param_2->decomp_buffer); + if (pRVar7 != 0x0) { + VAG_MarkLoopEnd((int8_t*)param_2->decomp_buffer, 0x4000); + VAG_MarkLoopStart((int8_t*)(param_2->decomp_buffer + 0x2000)); + } + } else { + iVar2 = 0x2010; + if (0x1f < iVar4) { + if (pRVar7 == 0x0) { + iVar2 = iVar4 + 0x1ff0; + } else { + iVar2 = iVar4 / 2 + 0x1ff0; + } + } + param_1->unk_264 = iVar2; + if (pRVar7 != 0x0) { + pRVar7->unk_264 = param_1->unk_264; + } + } + iVar2 = DMA_SendToSPUAndSync(param_2->decomp_buffer, 0x2000, + param_1->spu_stream_dma_mem_addr + 0x2000, param_1, 0); + if (iVar2 == 0) + goto LAB_0000fecc; + (param_1->header).unk_24 = 0; + goto LAB_0000fbdc; + } + iVar4 = param_1->xfer_size; + if ((iVar2 < iVar4) || ((u32)param_1->unk_264 < 0x4000)) { + VAG_MarkLoopEnd((int8_t*)param_2->decomp_buffer, 0x2000); + VAG_MarkLoopStart((int8_t*)param_2->decomp_buffer); + if (pRVar7 != 0x0) { + VAG_MarkLoopEnd((int8_t*)param_2->decomp_buffer, 0x4000); + VAG_MarkLoopStart((int8_t*)(param_2->decomp_buffer + 0x2000)); + } + } else { + iVar2 = 0x10; + if (0x1f < iVar4) { + if (pRVar7 == 0x0) { + iVar2 = iVar4 + -0x10; + } else { + iVar2 = iVar4 / 2 + -0x10; + } + } + param_1->unk_264 = iVar2; + if (pRVar7 != 0x0) { + pRVar7->unk_264 = param_1->unk_264; + } + } + iVar2 = DMA_SendToSPUAndSync(param_2->decomp_buffer, 0x2000, param_1->spu_stream_dma_mem_addr, + param_1, 0); + if (iVar2 == 0) + goto LAB_0000fecc; + (param_1->header).unk_24 = 0; + iVar2 = 0x2000; + if (pRVar7 != 0x0) { + iVar2 = 0x4000; + } + param_2->decomp_buffer = param_2->decomp_buffer + iVar2; + iVar4 = param_1->xfer_size - iVar2; + if (param_1->xfer_size <= iVar2) { + param_1->xfer_size = 0; + goto LAB_0000feb4; + } + LAB_0000fe98: + param_1->xfer_size = iVar4; + param_2->decompressed_size = param_2->decompressed_size - iVar2; + } + + param_1->num_processed_chunks++; + +LAB_0000fecc: + // CpuResumeIntr(local_18[0]); + return -1; +} + +int GetVAGStreamPos(VagCmd* param_1) { + bool bVar1; + u32 uVar2; + u32 uVar3; + u32 uVar4; + u32 uVar5; + int iVar6; + VagCmd* pRVar7; + u32 uVar8; + u32 uVar9; + u32 uVar10; + + pRVar7 = param_1->stereo_sibling; + if (param_1->id == 0) { + param_1->unk_200 = 0; + if (pRVar7 == 0x0) { + return 0; + } + pRVar7->unk_200 = 0; + return 0; + } + if (param_1->byte6 != '\0') { + param_1->unk_200 = param_1->unk_192; + if (pRVar7 == 0x0) { + return 0; + } + pRVar7->unk_200 = pRVar7->unk_192; + return 0; + } + if (((param_1->byte4 == '\0') || (param_1->sb_playing == '\0')) || (param_1->sb_paused != '\0')) { + param_1->unk_200 = param_1->unk_180; + if (pRVar7 == 0x0) { + return 0; + } + pRVar7->unk_200 = pRVar7->unk_180; + return 0; + } + if (param_1->byte11 != '\0') { + param_1->unk_200 = param_1->unk_180; + return 0; + } + // CpuSuspendIntr(local_30); + uVar9 = param_1->spu_stream_dma_mem_addr; + uVar8 = (param_1->voice & 0xffffU) | 0x2240; + do { + uVar10 = 0; + do { + uVar2 = sceSdGetAddr(uVar8); + uVar3 = sceSdGetAddr(uVar8); + uVar4 = sceSdGetAddr(uVar8); + if ((uVar2 == uVar3) || + ((uVar3 != uVar4 && (bVar1 = uVar2 == uVar4, uVar4 = uVar10, bVar1)))) { + uVar4 = uVar2; + } + uVar10 = uVar4; + } while (uVar4 == 0); + } while ((uVar4 < uVar9) || (uVar9 + 0x4040 <= uVar4)); + uVar4 = uVar4 - param_1->spu_stream_dma_mem_addr; + if (pRVar7 == 0x0) { + uVar8 = 0; + } else { + uVar10 = pRVar7->spu_stream_dma_mem_addr; + uVar9 = (pRVar7->voice & 0xffffU) | 0x2240; + do { + uVar2 = 0; + do { + uVar3 = sceSdGetAddr(uVar9); + uVar5 = sceSdGetAddr(uVar9); + uVar8 = sceSdGetAddr(uVar9); + if ((uVar3 == uVar5) || + ((uVar5 != uVar8 && (bVar1 = uVar3 == uVar8, uVar8 = uVar2, bVar1)))) { + uVar8 = uVar3; + } + uVar2 = uVar8; + } while (uVar8 == 0); + } while ((uVar8 < uVar10) || (uVar10 + 0x4040 <= uVar8)); + uVar8 = uVar8 - pRVar7->spu_stream_dma_mem_addr; + } + // CpuResumeIntr(local_30[0]); + if (pRVar7 != 0x0) { + if ((((uVar4 < 0x4000) && (uVar8 < 0x4000)) && (param_1->byte20 == '\0')) && + (pRVar7->byte20 == '\0')) { + iVar6 = (int)((uVar4 - uVar8) * 0x40000) >> 0x12; + if (iVar6 < 0) { + iVar6 = -iVar6; + } + if (4 < iVar6) { + PauseVAG(param_1, 1); + uVar4 = param_1->spu_addr_to_start_playing - param_1->spu_stream_dma_mem_addr; + uVar8 = pRVar7->spu_addr_to_start_playing - pRVar7->spu_stream_dma_mem_addr; + UnPauseVAG(param_1, 1); + } + } + if (pRVar7 == 0x0) + goto LAB_00010860; + // CpuSuspendIntr(local_30); + if ((0x4000 < uVar4) && (param_1->byte20 == '\0')) { + param_1->byte20 = '\x01'; + param_1->byte21 = '\0'; + param_1->byte22 = '\0'; + pRVar7->byte20 = '\x01'; + pRVar7->byte21 = '\0'; + pRVar7->byte22 = '\0'; + } + if (uVar8 < 0x4001) { + if (uVar4 < 0x2000) { + if (param_1->byte21 == '\0') { + iVar6 = param_1->unk_204; + param_1->byte21 = '\x01'; + param_1->byte22 = '\0'; + LAB_00010234: + param_1->byte20 = '\0'; + param_1->unk_204 = iVar6 + 1; + } + } else if (param_1->byte22 == '\0') { + iVar6 = param_1->unk_204; + param_1->byte22 = '\x01'; + param_1->byte21 = '\0'; + goto LAB_00010234; + } + if (uVar8 < 0x2000) { + if (pRVar7->byte21 == '\0') { + iVar6 = pRVar7->unk_204; + pRVar7->byte21 = '\x01'; + pRVar7->byte22 = '\0'; + LAB_00010288: + pRVar7->byte20 = '\0'; + pRVar7->unk_204 = iVar6 + 1; + } + } else if (pRVar7->byte22 == '\0') { + iVar6 = pRVar7->unk_204; + pRVar7->byte22 = '\x01'; + pRVar7->byte21 = '\0'; + goto LAB_00010288; + } + } else if (pRVar7->byte20 == '\0') { + param_1->byte20 = '\x01'; + param_1->byte21 = '\0'; + param_1->byte22 = '\0'; + pRVar7->byte20 = '\x01'; + pRVar7->byte21 = '\0'; + pRVar7->byte22 = '\0'; + } + // CpuResumeIntr(local_30[0]); + switch (param_1->unk_236) { + case 0: + if ((((param_1->sb_odd_buffer_dma_complete == '\0') || (param_1->byte21 == '\0')) || + (pRVar7->sb_odd_buffer_dma_complete == '\0')) || + (pRVar7->byte21 == '\0')) + goto switchD_000102c4_caseD_1; + param_1->sb_odd_buffer_dma_complete = '\0'; + pRVar7->sb_odd_buffer_dma_complete = '\0'; + param_1->unk_236 = 2; + pRVar7->unk_236 = 2; + case 2: + if ((param_1->sb_even_buffer_dma_complete == '\0') || + (pRVar7->sb_even_buffer_dma_complete == '\0')) { + if ((param_1->byte20 == '\0') && (pRVar7->byte20 == '\0')) + goto switchD_000102c4_caseD_1; + uVar4 = 0x2000; + uVar8 = 0x2000; + param_1->byte17 = '\x01'; + param_1->byte16 = '\0'; + pRVar7->byte17 = '\x01'; + iVar6 = 4; + LAB_00010744: + pRVar7->byte16 = '\0'; + } else { + if ((param_1->byte20 == '\0') && (pRVar7->byte20 == '\0')) { + // CpuSuspendIntr(local_30); + sceSdSetAddr(*(u16*)¶m_1->voice | 0x2140, + param_1->spu_stream_dma_mem_addr + 0x2000); + sceSdSetAddr(*(u16*)&pRVar7->voice | 0x2140, pRVar7->spu_stream_dma_mem_addr + 0x2000); + param_1->byte15 = '\x01'; + param_1->byte14 = '\0'; + param_1->byte13 = '\0'; + pRVar7->byte15 = '\x01'; + pRVar7->byte14 = '\0'; + pRVar7->byte13 = '\0'; + iVar6 = 3; + LAB_000106d4: + param_1->unk_236 = iVar6; + pRVar7->unk_236 = iVar6; + // CpuResumeIntr(local_30[0]); + goto switchD_000102c4_caseD_1; + } + uVar4 = 0x2000; + uVar8 = 0x2000; + RestartVag(param_1, 1, 1); + iVar6 = 9; + } + break; + default: + goto switchD_000102c4_caseD_1; + case 3: + if ((param_1->byte20 != '\0') || (pRVar7->byte20 != '\0')) { + uVar4 = 0x2000; + uVar8 = 0x2000; + RestartVag(param_1, 1, 1); + iVar6 = 9; + break; + } + if ((param_1->byte22 == '\0') || (pRVar7->byte22 == '\0')) + goto switchD_000102c4_caseD_1; + // CpuSuspendIntr(local_30); + sceSdSetAddr(*(u16*)¶m_1->voice | 0x2140, param_1->spu_trap_mem_addr); + sceSdSetAddr(*(u16*)&pRVar7->voice | 0x2140, pRVar7->spu_trap_mem_addr); + param_1->byte13 = '\x01'; + param_1->byte14 = '\0'; + param_1->byte15 = '\0'; + pRVar7->byte13 = '\x01'; + pRVar7->byte14 = '\0'; + pRVar7->byte15 = '\0'; + param_1->sb_even_buffer_dma_complete = '\0'; + pRVar7->sb_even_buffer_dma_complete = '\0'; + iVar6 = 5; + goto LAB_000106d4; + case 4: + uVar4 = param_1->unk_196; + uVar8 = pRVar7->unk_196; + if ((param_1->sb_even_buffer_dma_complete == '\0') || + (pRVar7->sb_even_buffer_dma_complete == '\0')) + goto switchD_000102c4_caseD_1; + RestartVag(param_1, 1, 1); + iVar6 = 9; + break; + case 5: + if ((param_1->sb_odd_buffer_dma_complete == '\0') || + (pRVar7->sb_odd_buffer_dma_complete == '\0')) { + if (param_1->byte20 == '\0') + goto switchD_000102c4_caseD_1; + uVar4 = 0x4000; + uVar8 = 0x4000; + param_1->byte16 = '\x01'; + param_1->byte17 = '\0'; + pRVar7->byte16 = '\x01'; + iVar6 = 7; + pRVar7->byte17 = '\0'; + } else { + if ((param_1->byte20 == '\0') && (pRVar7->byte20 == '\0')) { + // CpuSuspendIntr(local_30); + sceSdSetAddr(*(u16*)¶m_1->voice | 0x2140, param_1->spu_stream_dma_mem_addr); + sceSdSetAddr(*(u16*)&pRVar7->voice | 0x2140, pRVar7->spu_stream_dma_mem_addr); + param_1->byte14 = '\x01'; + param_1->byte15 = '\0'; + param_1->byte13 = '\0'; + pRVar7->byte14 = '\x01'; + pRVar7->byte15 = '\0'; + pRVar7->byte13 = '\0'; + iVar6 = 6; + goto LAB_000106d4; + } + uVar4 = 0x4000; + uVar8 = 0x4000; + RestartVag(param_1, 0, 1); + iVar6 = 8; + } + break; + case 6: + if ((param_1->byte20 == '\0') && (pRVar7->byte20 == '\0')) { + if ((param_1->byte21 == '\0') || (pRVar7->byte21 == '\0')) + goto switchD_000102c4_caseD_1; + // CpuSuspendIntr(local_30); + sceSdSetAddr(*(u16*)¶m_1->voice | 0x2140, param_1->spu_trap_mem_addr); + sceSdSetAddr(*(u16*)&pRVar7->voice | 0x2140, pRVar7->spu_trap_mem_addr); + param_1->byte13 = '\x01'; + param_1->byte14 = '\0'; + param_1->byte15 = '\0'; + pRVar7->byte13 = '\x01'; + pRVar7->byte14 = '\0'; + pRVar7->byte15 = '\0'; + param_1->sb_odd_buffer_dma_complete = '\0'; + pRVar7->sb_odd_buffer_dma_complete = '\0'; + iVar6 = 2; + goto LAB_000106d4; + } + uVar4 = 0x4000; + uVar8 = 0x4000; + RestartVag(param_1, 0, 1); + iVar6 = 8; + break; + case 7: + uVar8 = param_1->unk_196; + uVar4 = uVar8; + if ((param_1->sb_odd_buffer_dma_complete == '\0') || + (pRVar7->sb_odd_buffer_dma_complete == '\0')) + goto switchD_000102c4_caseD_1; + RestartVag(param_1, 0, 1); + iVar6 = 8; + break; + case 8: + if ((param_1->byte21 == '\0') || (iVar6 = 6, pRVar7->byte21 == '\0')) { + uVar8 = param_1->unk_196; + uVar4 = uVar8; + goto switchD_000102c4_caseD_1; + } + param_1->byte16 = '\0'; + goto LAB_00010744; + case 9: + if ((param_1->byte22 == '\0') || (iVar6 = 3, pRVar7->byte22 == '\0')) { + uVar8 = pRVar7->unk_196; + uVar4 = param_1->unk_196; + goto switchD_000102c4_caseD_1; + } + param_1->byte17 = '\0'; + pRVar7->byte17 = '\0'; + } + param_1->unk_236 = iVar6; + pRVar7->unk_236 = iVar6; + switchD_000102c4_caseD_1: + if (param_1->unk_204 == 0) { + param_1->unk_188 = uVar4; + pRVar7->unk_188 = uVar4; + } else { + param_1->unk_188 = uVar4 + (param_1->unk_204 + -1) * 0x2000; + pRVar7->unk_188 = uVar8 + (pRVar7->unk_204 + -1) * 0x2000; + if (0x2000 < uVar4) { + param_1->unk_188 = param_1->unk_188 + -0x2000; + } + if (0x2000 < uVar8) { + pRVar7->unk_188 = pRVar7->unk_188 + -0x2000; + } + } + uVar9 = param_1->unk_248; + if (uVar9 == 0) { + uVar10 = 0; + } else { + uVar10 = (u32)(param_1->unk_188 * 0x1c0) / uVar9; + if (uVar9 == 0) { + // trap(0x1c00); + ASSERT_NOT_REACHED(); + } + } + param_1->unk_180 = uVar10 << 2; + param_1->unk_200 = uVar10 << 2; + param_1->unk_196 = uVar4; + uVar9 = pRVar7->unk_248; + if (uVar9 == 0) { + uVar10 = 0; + } else { + uVar10 = (u32)(pRVar7->unk_188 * 0x1c0) / uVar9; + if (uVar9 == 0) { + // trap(0x1c00); + ASSERT_NOT_REACHED(); + } + } + pRVar7->unk_180 = uVar10 << 2; + pRVar7->unk_200 = uVar10 << 2; + pRVar7->unk_196 = uVar8; + return 0; + } +LAB_00010860: + if (uVar4 < 0x4001) { + if (uVar4 < 0x2000) { + if (param_1->byte21 == '\0') { + iVar6 = param_1->unk_204; + param_1->byte21 = '\x01'; + param_1->byte22 = '\0'; + LAB_000108cc: + param_1->byte20 = '\0'; + param_1->unk_204 = iVar6 + 1; + } + } else if (param_1->byte22 == '\0') { + iVar6 = param_1->unk_204; + param_1->byte22 = '\x01'; + param_1->byte21 = '\0'; + goto LAB_000108cc; + } + } else if (param_1->byte20 == '\0') { + param_1->byte20 = '\x01'; + param_1->byte21 = '\0'; + param_1->byte22 = '\0'; + } + switch (param_1->unk_236) { + case 0: + if ((param_1->sb_odd_buffer_dma_complete == '\0') || (param_1->byte21 == '\0')) + goto switchD_000108fc_caseD_1; + param_1->sb_odd_buffer_dma_complete = '\0'; + param_1->unk_236 = 2; + case 2: + if (param_1->sb_even_buffer_dma_complete == '\0') { + if (param_1->byte20 != '\0') { + uVar4 = 0x2000; + param_1->byte17 = '\x01'; + iVar6 = 4; + LAB_00010b7c: + param_1->byte16 = '\0'; + param_1->unk_236 = iVar6; + } + } else if (param_1->byte20 == '\0') { + // CpuSuspendIntr(local_30); + sceSdSetAddr(*(u16*)¶m_1->voice | 0x2140, param_1->spu_stream_dma_mem_addr + 0x2000); + param_1->byte15 = '\x01'; + param_1->byte14 = '\0'; + param_1->byte13 = '\0'; + iVar6 = 3; + LAB_00010b30: + param_1->unk_236 = iVar6; + // CpuResumeIntr(local_30[0]); + } else { + uVar4 = 0x2000; + LAB_00010a1c: + RestartVag(param_1, 1, 1); + param_1->unk_236 = 9; + } + default: + goto switchD_000108fc_caseD_1; + case 3: + if (param_1->byte20 != '\0') { + uVar4 = 0x2000; + goto LAB_00010a1c; + } + if (param_1->byte22 == '\0') + goto switchD_000108fc_caseD_1; + // CpuSuspendIntr(local_30); + sceSdSetAddr(*(u16*)¶m_1->voice | 0x2140, param_1->spu_trap_mem_addr); + param_1->byte13 = '\x01'; + param_1->byte14 = '\0'; + param_1->byte15 = '\0'; + param_1->sb_even_buffer_dma_complete = '\0'; + iVar6 = 5; + goto LAB_00010b30; + case 4: + uVar4 = param_1->unk_196; + if (param_1->sb_even_buffer_dma_complete == '\0') + goto switchD_000108fc_caseD_1; + goto LAB_00010a1c; + case 5: + if (param_1->sb_odd_buffer_dma_complete == '\0') { + if (param_1->byte20 == '\0') + goto switchD_000108fc_caseD_1; + uVar4 = 0x4000; + param_1->byte16 = '\x01'; + iVar6 = 7; + param_1->byte17 = '\0'; + goto LAB_00010acc; + } + if (param_1->byte20 == '\0') { + // CpuSuspendIntr(local_30); + sceSdSetAddr(*(u16*)¶m_1->voice | 0x2140, param_1->spu_stream_dma_mem_addr); + param_1->byte14 = '\x01'; + param_1->byte15 = '\0'; + param_1->byte13 = '\0'; + iVar6 = 6; + goto LAB_00010b30; + } + uVar4 = 0x4000; + break; + case 6: + if (param_1->byte20 == '\0') { + if (param_1->byte21 == '\0') + goto switchD_000108fc_caseD_1; + // CpuSuspendIntr(local_30); + sceSdSetAddr(*(u16*)¶m_1->voice | 0x2140, param_1->spu_trap_mem_addr); + param_1->byte13 = '\x01'; + param_1->byte14 = '\0'; + param_1->byte15 = '\0'; + param_1->sb_odd_buffer_dma_complete = '\0'; + iVar6 = 2; + goto LAB_00010b30; + } + uVar4 = 0x4000; + break; + case 7: + uVar4 = param_1->unk_196; + if (param_1->sb_odd_buffer_dma_complete == '\0') + goto switchD_000108fc_caseD_1; + break; + case 8: + iVar6 = 6; + if (param_1->byte21 == '\0') { + LAB_00010b88: + uVar4 = param_1->unk_196; + goto switchD_000108fc_caseD_1; + } + goto LAB_00010b7c; + case 9: + iVar6 = 3; + if (param_1->byte22 == '\0') + goto LAB_00010b88; + param_1->byte17 = '\0'; + LAB_00010acc: + param_1->unk_236 = iVar6; + goto switchD_000108fc_caseD_1; + } + RestartVag(param_1, 0, 1); + param_1->unk_236 = 8; +switchD_000108fc_caseD_1: + if (param_1->unk_204 == 0) { + param_1->unk_188 = uVar4; + } else { + iVar6 = uVar4 + (param_1->unk_204 + -1) * 0x2000; + param_1->unk_188 = iVar6; + if (0x2000 < uVar4) { + param_1->unk_188 = iVar6 + -0x2000; + } + } + uVar8 = param_1->unk_248; + if (uVar8 == 0) { + uVar9 = 0; + } else { + uVar9 = (u32)(param_1->unk_188 * 0x1c0) / uVar8; + if (uVar8 == 0) { + // trap(0x1c00); + ASSERT_NOT_REACHED(); + } + } + param_1->unk_180 = uVar9 << 2; + param_1->unk_200 = uVar9 << 2; + param_1->unk_196 = uVar4; + return 0; +} + +int CheckVAGStreamProgress(VagCmd* param_1) { + int uVar1; + u32 uVar2; + u32 uVar3; + VagCmd* pRVar4; + // undefined4 local_18 [2]; + + if (param_1->byte11 != '\0') { + return 1; + } + if (param_1->unk_260 != 0) { + return 0; + } + if (param_1->sb_playing == '\0') { + return 1; + } + if (param_1->sb_paused != '\0') { + return 1; + } + uVar2 = param_1->unk_264; + pRVar4 = param_1->stereo_sibling; + uVar3 = param_1->unk_196; + if (uVar2 < 0x4000) { + if ((0x2000 < uVar3) || (0x2000 < uVar2)) { + if ((uVar3 < 0x2000) || (uVar2 < 0x2000)) + goto LAB_00010d58; + uVar2 = param_1->unk_264; + } + uVar1 = 0; + if ((uVar3 & 0xfffffff0) < uVar2) { + // CpuSuspendIntr(local_18); + if ((param_1->unk_268 == 0) && (uVar3 < (u32)param_1->unk_264)) { + sceSdSetAddr(*(u16*)¶m_1->voice | 0x2140, + param_1->spu_stream_dma_mem_addr + param_1->unk_264); + param_1->unk_268 = 1; + if (pRVar4 != 0x0) { + sceSdSetAddr(*(u16*)&pRVar4->voice | 0x2140, + pRVar4->spu_stream_dma_mem_addr + param_1->unk_264); + pRVar4->unk_268 = 1; + } + } + (param_1->header).unk_24 = 0; + // CpuResumeIntr(local_18[0]); + uVar1 = 1; + } + } else { + LAB_00010d58: + uVar1 = 1; + if ((((param_1->sb_playing != '\0') && (uVar1 = 1, (param_1->header).unk_24 == 0)) && + param_1->safe_to_change_dma_fields) && + (uVar1 = 1, param_1->unk_268 == 0)) { + if (uVar3 < 0x2000) { + uVar1 = 1; + if ((param_1->num_processed_chunks & 1U) != 0) { + (param_1->header).unk_24 = 1; + } + } else { + uVar1 = 1; + if ((param_1->num_processed_chunks & 1U) == 0) { + (param_1->header).unk_24 = 1; + } + } + } + } + return uVar1; +} + +u32 CheckVagStreamsProgress() { + int iVar1; + VagCmd* pRVar2; + // int8_t* piVar3; + Buffer* pBVar4; + VagCmd* cmd; + int iVar5; + CmdHeader** ppCVar6; + VagStrListNode VStack200; + LfoListNode LStack96; + // undefined4 local_30 [2]; + + do { + if (gPriStack[3].count < 8) { + iVar5 = gPriStack[3].count + -1; + if (-1 < iVar5) { + ppCVar6 = gPriStack[3].entries + gPriStack[3].count + -1; + do { + pRVar2 = (VagCmd*)*ppCVar6; + if (pRVar2 != 0x0) { + if ((pRVar2->header).status == -1) { + if ((((pRVar2->header).unk_24 != 0) && + (pBVar4 = (pRVar2->header).callback_buffer, pBVar4 != (Buffer*)0x0)) && + ((pRVar2->header).callback == ProcessVAGData)) { + iVar1 = ProcessVAGData(&pRVar2->header, pBVar4); + (pRVar2->header).status = iVar1; + if ((pBVar4->decompressed_size == 0) && pRVar2->safe_to_change_dma_fields == 1) { + (pRVar2->header).callback_buffer = pBVar4->next; + FreeBuffer(pBVar4, 1); + } + if ((pRVar2->header).status == -1) + goto LAB_00010f30; + if (pRVar2->safe_to_change_dma_fields) { + ReleaseMessage((CmdHeader*)pRVar2, 1); + } + } + if ((pRVar2->header).status == -1) + goto LAB_00010f30; + } + ReleaseMessage((CmdHeader*)pRVar2, 1); + } + LAB_00010f30: + iVar5 = iVar5 + -1; + ppCVar6 = ppCVar6 + -1; + } while (-1 < iVar5); + } + } + pRVar2 = VagCmds; + iVar5 = 0; + // piVar3 = &VagCmds[0].byte9; + auto* cmd_iter = VagCmds; + do { + if (((cmd_iter->sb_playing != '\0') || + ((cmd_iter->byte4 != '\0' && (cmd_iter->byte6 != '\0')))) || + ((cmd_iter->header.unk_24 == 1 && (cmd_iter->id != 0)))) { + iVar1 = CheckVAGStreamProgress(pRVar2); + if (iVar1 == 0) { + if (cmd_iter->byte11 == '\0') { + // CpuSuspendIntr(local_30); + cmd = cmd_iter->stereo_sibling; + // piVar3[-8] = '\0'; + cmd_iter->sb_playing = 0; + if (cmd != 0x0) { + cmd->sb_playing = '\0'; + } + if (cmd_iter->unk_136 == 0) { + PauseVAG(pRVar2, 0); + // *piVar3 = '\x01'; + cmd_iter->byte9 = 1; + if (cmd != 0x0) { + PauseVAG(cmd, 0); + // *piVar3 = '\x01'; + cmd_iter->byte9 = 1; + } + } else { + PauseVAG(pRVar2, 0); + strncpy(VStack200.name, pRVar2->name, 0x30); + VStack200.id = cmd_iter->id; + RemoveVagStreamFromList(&VStack200, &PluginStreamsList); + RemoveVagStreamFromList(&VStack200, &EEPlayList); + LStack96.id = cmd_iter->id; + LStack96.plugin_id = cmd_iter->plugin_id; + RemoveLfoStreamFromList(&LStack96, &LfoList); + } + // CpuResumeIntr(local_30[0]); + } + } else { + GetVAGStreamPos(pRVar2); + } + } + pRVar2 = pRVar2 + 1; + // piVar3 = piVar3 + 0x144; + cmd_iter++; + iVar5 = iVar5 + 1; + } while (iVar5 < 4); + if (ActiveVagStreams < 1) { + SleepThread(); + } else { + DelayThread(1000); + } + } while (true); + return 0; +} + +void StopVagStream(VagCmd* param_1, int param_2) { + VagCmd* cmd; + VagStrListNode VStack184; + LfoListNode LStack80; + // undefined4 local_20 [2]; + + if (param_2 == 1) { + // CpuSuspendIntr(local_20); + } + cmd = param_1->stereo_sibling; + param_1->sb_playing = '\0'; + if (cmd != 0x0) { + cmd->sb_playing = '\0'; + } + if (param_1->unk_136 == 0) { + PauseVAG(param_1, 0); + param_1->byte9 = '\x01'; + if (cmd != 0x0) { + PauseVAG(cmd, 0); + param_1->byte9 = '\x01'; + } + } else { + PauseVAG(param_1, 0); + strncpy(VStack184.name, param_1->name, 0x30); + VStack184.id = param_1->id; + RemoveVagStreamFromList(&VStack184, &PluginStreamsList); + RemoveVagStreamFromList(&VStack184, &EEPlayList); + LStack80.id = param_1->id; + LStack80.plugin_id = param_1->plugin_id; + RemoveLfoStreamFromList(&LStack80, &LfoList); + } + if (param_2 == 1) { + // CpuResumeIntr(local_20[0]); + } +} + +void InitSpuStreamsThread() { + ThreadParam local_20; + + local_20.attr = 0x2000000; + local_20.entry = CheckVagStreamsProgress; + local_20.initPriority = 0x32; + local_20.stackSize = 0x800; + local_20.option = 0; + StreamsThread = CreateThread(&local_20); + if (StreamsThread < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: spustreams InitSpuStreamsThread: Cannot create streams thread\n"); + printf("IOP: ======================================================================\n"); + ASSERT_NOT_REACHED(); + } + StartThread(StreamsThread, 0); +} + +void WakeSpuStreamsUp() { + iWakeupThread(StreamsThread); +} + +u32 GetSpuRamAddress(VagCmd* param_1) { + bool bVar1; + u32 uVar2; + u32 uVar3; + u32 uVar4; + u32 uVar5; + u32 uVar6; + u32 uVar7; + + uVar7 = param_1->spu_stream_dma_mem_addr; + uVar6 = (param_1->voice & 0xffffU) | 0x2240; + do { + uVar5 = 0; + do { + uVar2 = sceSdGetAddr(uVar6); + uVar3 = sceSdGetAddr(uVar6); + uVar4 = sceSdGetAddr(uVar6); + // printf("got nax: %d\n", uVar3); + if ((uVar2 == uVar3) || + ((uVar3 != uVar4 && (bVar1 = uVar2 == uVar4, uVar4 = uVar5, bVar1)))) { + uVar4 = uVar2; + } + uVar5 = uVar4; + } while (uVar4 == 0); + } while ((uVar4 < uVar7) || (uVar7 + 0x4040 <= uVar4)); + return uVar4; +} + +u32 bswap(u32 param_1) { + return param_1 >> 0x18 | ((int)param_1 >> 8 & 0xff00U) | (param_1 & 0xff00) << 8 | + param_1 << 0x18; +} + +void ProcessStreamData(void) { + int iVar1; + VagCmd* pRVar2; + Buffer* pBVar3; + int iVar4; + CmdHeader** ppCVar5; + + iVar4 = gPriStack[3].count + -1; + if ((gPriStack[3].count < 8) && (-1 < iVar4)) { + ppCVar5 = gPriStack[3].entries + gPriStack[3].count + -1; + do { + pRVar2 = (VagCmd*)*ppCVar5; + if (pRVar2 != 0x0) { + if ((pRVar2->header).status == -1) { + if ((((pRVar2->header).unk_24 != 0) && + (pBVar3 = (pRVar2->header).callback_buffer, pBVar3 != (Buffer*)0x0)) && + ((pRVar2->header).callback == ProcessVAGData)) { + iVar1 = ProcessVAGData(&pRVar2->header, pBVar3); + (pRVar2->header).status = iVar1; + if ((pBVar3->decompressed_size == 0) && pRVar2->safe_to_change_dma_fields) { + (pRVar2->header).callback_buffer = pBVar3->next; + FreeBuffer(pBVar3, 1); + } + if ((pRVar2->header).status == -1) + goto LAB_0001151c; + if (pRVar2->safe_to_change_dma_fields) { + ReleaseMessage((CmdHeader*)pRVar2, 1); + } + } + if ((pRVar2->header).status == -1) + goto LAB_0001151c; + } + ReleaseMessage((CmdHeader*)pRVar2, 1); + } + LAB_0001151c: + iVar4 = iVar4 + -1; + ppCVar5 = ppCVar5 + -1; + } while (-1 < iVar4); + } +} + +} // namespace jak2 diff --git a/game/overlord/jak2/spustreams.h b/game/overlord/jak2/spustreams.h new file mode 100644 index 0000000000..69e4b51253 --- /dev/null +++ b/game/overlord/jak2/spustreams.h @@ -0,0 +1,11 @@ +#pragma once +#include "game/overlord/jak2/iso.h" + +namespace jak2 { +void spusstreams_init_globals(); +void WakeSpuStreamsUp(); +void InitSpuStreamsThread(); +int ProcessVAGData(CmdHeader* param_1_in, Buffer* param_2); +void StopVagStream(VagCmd* param_1, int param_2); +u32 GetSpuRamAddress(VagCmd* param_1); +} // namespace jak2 diff --git a/game/overlord/jak2/srpc.cpp b/game/overlord/jak2/srpc.cpp new file mode 100644 index 0000000000..db4cf093ab --- /dev/null +++ b/game/overlord/jak2/srpc.cpp @@ -0,0 +1,614 @@ +#include "srpc.h" + +#include "common/log/log.h" +#include "common/util/Assert.h" + +#include "game/common/loader_rpc_types.h" +#include "game/common/player_rpc_types.h" +#include "game/overlord/common/soundcommon.h" +#include "game/overlord/common/srpc.h" +#include "game/overlord/common/ssound.h" +#include "game/overlord/jak2/iso_api.h" +#include "game/overlord/jak2/spustreams.h" +#include "game/overlord/jak2/ssound.h" +#include "game/overlord/jak2/vag.h" +#include "game/runtime.h" +#include "game/sce/iop.h" +#include "game/sound/sndshim.h" + +using namespace iop; +namespace jak2 { + +// korean inserted +static const char* languages[] = {"ENG", "FRE", "GER", "SPA", "ITA", "JAP", "KOR", "UKE"}; +static u32 gInfoEE = 0; +static u32 IopTicks = 0; +static SoundIopInfo info; +static uint8_t gPlayerBuf[0x50 * 128]; +static uint8_t gLoaderBuf[0x50]; + +void srpc_init_globals() {} + +void* RPC_Player(unsigned int /*fno*/, void* data, int size) { + if (!gSoundEnable) { + return nullptr; + } + + // gFreeMem = QueryTotalFreeMemSize(); + if (!PollSema(gSema)) { + if (gMusic) { + if (!gMusicPause && !LookupSound(666)) { + Sound* music = AllocateSound(); + if (music != nullptr) { + gMusicFade = 0; + gMusicFadeDir = 1; + SetMusicVol(); + music->sound_handle = snd_PlaySoundVolPanPMPB(gMusic, 0, 0x400, -1, 0, 0); + music->id = 666; + music->is_music = 1; + } + } + } + SignalSema(gSema); + } + + SetMusicVol(); + Sound* music = LookupSound(666); + if (music != nullptr) { + snd_SetSoundVolPan(music->sound_handle, 0x7FFFFFFF, 0); + } + + constexpr int kMsgSize = 0x50; + static_assert(sizeof(SoundRpcCommand) == kMsgSize); + int n_messages = size / kMsgSize; + SoundRpcCommand* cmd = (SoundRpcCommand*)(data); + if (!gSoundEnable) { + return nullptr; + } + + while (n_messages > 0) { + switch (cmd->j2command) { + case Jak2SoundCommand::play: { + if (!cmd->play.sound_id) { + break; + } + + auto sound = LookupSound(cmd->play.sound_id); + if (sound != nullptr) { + // update + sound->params = cmd->play.parms; + sound->is_music = false; + SFXUserData data{}; + s32 found = snd_GetSoundUserData(0, nullptr, -1, sound->name, &data); + if ((sound->params.mask & 0x40) == 0) { + s16 fo_min = 5; + if (found && data.data[0]) + fo_min = data.data[0]; + sound->params.fo_min = fo_min; + } + if ((sound->params.mask & 0x80) == 0) { + s16 fo_max = 30; + if (found && data.data[1]) + fo_max = data.data[1]; + sound->params.fo_max = fo_max; + } + if ((sound->params.mask & 0x100) == 0) { + s16 fo_curve = 2; + if (found && data.data[2]) + fo_curve = data.data[2]; + sound->params.fo_curve = fo_curve; + } + UpdateVolume(sound); + snd_SetSoundPitchModifier(sound->sound_handle, sound->params.pitch_mod); + if (sound->params.mask & 0x4) { + snd_SetSoundPitchBend(sound->sound_handle, sound->params.bend); + } + if (sound->params.mask & 0x800) { + snd_SetSoundReg(sound->sound_handle, 0, sound->params.reg[0]); + } + if (sound->params.mask & 0x1000) { + snd_SetSoundReg(sound->sound_handle, 1, sound->params.reg[1]); + } + if (sound->params.mask & 0x2000) { + snd_SetSoundReg(sound->sound_handle, 2, sound->params.reg[2]); + } + + } else { + // new sound + sound = AllocateSound(); + if (sound == nullptr) { + // no free sounds + break; + } + strcpy_toupper(sound->name, cmd->play.name); + // TODO update params struct + sound->params = cmd->play.parms; + sound->is_music = false; + sound->bank_entry = nullptr; + + SFXUserData data{}; + s32 found = snd_GetSoundUserData(0, nullptr, -1, sound->name, &data); + if ((sound->params.mask & 0x40) == 0) { + s16 fo_min = 5; + if (found && data.data[0]) + fo_min = data.data[0]; + sound->params.fo_min = fo_min; + } + if ((sound->params.mask & 0x80) == 0) { + s16 fo_max = 30; + if (found && data.data[1]) + fo_max = data.data[1]; + sound->params.fo_max = fo_max; + } + if ((sound->params.mask & 0x100) == 0) { + s16 fo_curve = 2; + if (found && data.data[2]) + fo_curve = data.data[2]; + sound->params.fo_curve = fo_curve; + } + // lg::warn("RPC: PLAY {} v:{}, p:{}", sound->name, GetVolume(sound), GetPan(sound)); + + s32 handle = snd_PlaySoundByNameVolPanPMPB(0, nullptr, sound->name, GetVolume(sound), + GetPan(sound), sound->params.pitch_mod, + sound->params.bend); + sound->sound_handle = handle; + if (handle != 0) { + sound->id = cmd->play.sound_id; + if (sound->params.mask & 0x800) { + snd_SetSoundReg(sound->sound_handle, 0, sound->params.reg[0]); + } + if (sound->params.mask & 0x1000) { + snd_SetSoundReg(sound->sound_handle, 1, sound->params.reg[1]); + } + if (sound->params.mask & 0x2000) { + snd_SetSoundReg(sound->sound_handle, 2, sound->params.reg[2]); + } + } + } + } break; + case Jak2SoundCommand::pause_sound: { + Sound* sound = LookupSound(cmd->sound_id.sound_id); + if (sound != nullptr) { + snd_PauseSound(sound->sound_handle); + } else { + auto* vs = FindVagStreamId(cmd->sound_id.sound_id); + if (vs) { + PauseVAG(vs, 1); + } + } + // TODO vag + } break; + case Jak2SoundCommand::stop_sound: { + Sound* sound = LookupSound(cmd->sound_id.sound_id); + if (sound != nullptr) { + snd_StopSound(sound->sound_handle); + } else { + auto* vs = FindVagStreamId(cmd->sound_id.sound_id); + if (vs) { + StopVagStream(vs, 1); + } + } + // TODO vag + } break; + case Jak2SoundCommand::continue_sound: { + Sound* sound = LookupSound(cmd->sound_id.sound_id); + if (sound != nullptr) { + snd_ContinueSound(sound->sound_handle); + } else { + auto* vs = FindVagStreamId(cmd->sound_id.sound_id); + if (vs) { + UnPauseVAG(vs, 1); + } + } + // TODO vag + } break; + case Jak2SoundCommand::set_param: { + Sound* sound = LookupSound(cmd->sound_id.sound_id); + u32 mask = cmd->param.parms.mask; + if (sound != nullptr) { + if (mask & 1) { + if (mask & 0x10) { + sound->auto_time = cmd->param.auto_time; + sound->new_volume = cmd->param.parms.volume; + } else { + sound->params.volume = cmd->param.parms.volume; + } + } + if (mask & 0x20) { + sound->params.trans = cmd->param.parms.trans; + } + if (mask & 0x21) { + UpdateVolume(sound); + } + if (mask & 2) { + sound->params.pitch_mod = cmd->param.parms.pitch_mod; + if (mask & 0x10) { + snd_AutoPitch(sound->sound_handle, sound->params.pitch_mod, cmd->param.auto_time, + cmd->param.auto_from); + } else { + snd_SetSoundPitchModifier(sound->sound_handle, cmd->param.parms.pitch_mod); + } + } + if (mask & 4) { + sound->params.bend = cmd->param.parms.bend; + if (mask & 0x10) { + snd_AutoPitchBend(sound->sound_handle, sound->params.bend, cmd->param.auto_time, + cmd->param.auto_from); + } else { + snd_SetSoundPitchBend(sound->sound_handle, cmd->param.parms.bend); + } + } + if (mask & 0x400) { + sound->params.priority = cmd->param.parms.priority; + } + if (mask & 0x8) { + sound->params.group = cmd->param.parms.group; + } + if (mask & 0x40) { + sound->params.fo_min = cmd->param.parms.fo_min; + } + if (mask & 0x80) { + sound->params.fo_max = cmd->param.parms.fo_max; + } + if (mask & 0x100) { + sound->params.fo_curve = cmd->param.parms.fo_curve; + } + if (mask & 0x800) { + sound->params.reg[0] = cmd->param.parms.reg[0]; + snd_SetSoundReg(sound->sound_handle, 0, cmd->param.parms.reg[0]); + } + if (mask & 0x1000) { + sound->params.reg[1] = cmd->param.parms.reg[1]; + snd_SetSoundReg(sound->sound_handle, 1, cmd->param.parms.reg[1]); + } + if (mask & 0x2000) { + sound->params.reg[2] = cmd->param.parms.reg[2]; + snd_SetSoundReg(sound->sound_handle, 2, cmd->param.parms.reg[2]); + } + } else { + auto* vs = FindVagStreamId(cmd->param.sound_id); + if (vs) { + if (mask & 0x2) { + SetVAGStreamPitch(cmd->param.sound_id, cmd->param.parms.pitch_mod); + } + } + } + // TODO vag + } break; + case Jak2SoundCommand::set_master_volume: { + u32 group = cmd->master_volume.group.group; + // FIXME array of set volumes + for (int i = 0; i < 32; i++) { + if (((group >> i) & 1) != 0) { + if (i == 1) { + // gMusicVol = cmd->master_volume.volume; + MasterVolume[1] = cmd->master_volume.volume; + } else if (i == 2) { + MasterVolume[2] = cmd->master_volume.volume; + SetDialogVolume(cmd->master_volume.volume); + } else { + MasterVolume[i] = cmd->master_volume.volume; + snd_SetMasterVolume(i, cmd->master_volume.volume); + SetAllVagsVol(i); + } + } + } + } break; + case Jak2SoundCommand::pause_group: { + snd_PauseAllSoundsInGroup(cmd->group.group); + if (cmd->group.group & 2) { + gMusicPause = 1; + } + if (cmd->group.group & 4) { + PauseVagStreams(); + } + } break; + case Jak2SoundCommand::stop_group: { + KillSoundsInGroup(cmd->group.group); + if (cmd->group.group & 4) { + VagCmd local_178; + local_178.header.cmd_kind = 0x402; + local_178.header.mbx_to_reply = 0; + local_178.header.thread_id = 0; + local_178.vag_dir_entry = nullptr; + local_178.name[0] = '\0'; + local_178.unk_136 = 0; + local_178.id = 0; + local_178.priority = 0; + StopVagStream(&local_178, 1); + } + } break; + case Jak2SoundCommand::continue_group: { + snd_ContinueAllSoundsInGroup(cmd->group.group); + if (cmd->group.group & 2) { + gMusicPause = 0; + } + if (cmd->group.group & 4) { + UnPauseVagStreams(); + } + } break; + case Jak2SoundCommand::set_midi_reg: { + if (cmd->midi_reg.reg == 16) { + snd_SetGlobalExcite(cmd->midi_reg.value); + } else { + Sound* sound = LookupSound(666); + if (sound != nullptr) { + snd_SetMIDIRegister(sound->sound_handle, cmd->midi_reg.reg, cmd->midi_reg.value); + } + } + } break; + case Jak2SoundCommand::set_reverb: { + lg::warn("RPC_Player: unimplemented set_reverb"); + // TODO reverb + } break; + case Jak2SoundCommand::set_ear_trans: { + SetEarTrans(&cmd->ear_trans_j2.ear_trans0, &cmd->ear_trans_j2.ear_trans1, + &cmd->ear_trans_j2.cam_trans, cmd->ear_trans_j2.cam_angle); + } break; + case Jak2SoundCommand::shutdown: { + gSoundEnable = 0; + } break; + case Jak2SoundCommand::set_fps: { + gFPS = cmd->fps.fps; + } break; + default: + ASSERT_MSG(false, fmt::format("Unhandled RPC Player command {}", int(cmd->j2command))); + } + + n_messages--; + cmd++; + } + + return nullptr; +} + +void* RPC_Loader(unsigned int /*fno*/, void* data, int size) { + constexpr int kMsgSize = 0x50; + static_assert(sizeof(SoundRpcCommand) == kMsgSize); + int n_messages = size / kMsgSize; + SoundRpcCommand* cmd = (SoundRpcCommand*)(data); + if (!gSoundEnable) { + return nullptr; + } + + while (n_messages > 0) { + switch (cmd->j2command) { + case Jak2SoundCommand::load_bank: { + if (LookupBank(cmd->load_bank.bank_name)) { + break; + } + + auto bank = AllocateBankName(cmd->load_bank.bank_name); + if (bank == nullptr) { + break; + } + + strncpy(bank->name, cmd->load_bank.bank_name, 16); + bank->in_use = true; + bank->unk4 = 0; + LoadSoundBank(cmd->load_bank.bank_name, bank); + } break; + case Jak2SoundCommand::load_music: { + while (WaitSema(gSema)) + ; + if (gMusic) { + UnLoadMusic(&gMusic); + } + LoadMusic(cmd->load_bank.bank_name, &gMusic); + SignalSema(gSema); + } break; + case Jak2SoundCommand::unload_bank: { + auto bank = LookupBank(cmd->load_bank.bank_name); + if (!bank) { + break; + } + auto handle = bank->bank_handle; + if (!bank->unk4) { + bank->in_use = false; + } + bank->in_use = false; + snd_UnloadBank(handle); + snd_ResolveBankXREFS(); + } break; + case Jak2SoundCommand::get_irx_version: { + cmd->irx_version.major = 4; + cmd->irx_version.minor = 0; + gInfoEE = cmd->irx_version.ee_addr; + return data; + } break; + case Jak2SoundCommand::set_language: { + gLanguage = languages[cmd->set_language.langauge_id]; + } break; + case Jak2SoundCommand::list_sounds: { + // Not present in real jak2 overlord + PrintActiveSounds(); + } break; + case Jak2SoundCommand::unload_music: { + while (WaitSema(gSema)) + ; + if (gMusic) { + UnLoadMusic(&gMusic); + } + SignalSema(gSema); + } break; + case Jak2SoundCommand::set_stereo_mode: { + s32 mode = cmd->stereo_mode.stereo_mode; + if (mode == 0) { + snd_SetPlayBackMode(1); + } else if (mode == 1) { + snd_SetPlayBackMode(2); + } else if (mode == 2) { + snd_SetPlayBackMode(0); + } + } break; + default: + ASSERT_MSG(false, fmt::format("Unhandled RPC Loader command {}", int(cmd->j2command))); + } + + n_messages--; + cmd++; + } + + return nullptr; +} + +int VBlank_Handler(void*) { + bool bVar1; + int iVar2; + int iVar3; + uint8_t uVar4; + + IopTicks = IopTicks + 1; + if (gSoundEnable == 0) { + return 1; + } + iWakeupThread(StreamThread); + if (gMusicFadeDir < 0) { + gMusicFade = gMusicFade + -0x200; + if (-1 < gMusicFade) + goto LAB_00008d9c; + gMusicFade = 0; + } else { + if ((gMusicFadeDir < 1) || (gMusicFade = gMusicFade + 0x400, gMusicFade < 0x10001)) + goto LAB_00008d9c; + gMusicFade = 0x10000; + } + gMusicFadeDir = 0; +LAB_00008d9c: + if (gInfoEE != 0) { + gFrameNum = gFrameNum + 1; + // instant dma + // if (dmaid != 0) { + // iVar2 = sceSifDmaStat(); + // if (-1 < iVar2) { + // return 1; + // } + // dmaid = 0; + // } + + for (int i = 0; i < 4; i++) { + u32 status_bits = 0; + u32 pos; + for (int j = 0; j < 24; j++) { + if (VagCmds[i].status_bytes[j]) { + status_bits |= (1 << j); + } + } + if (VagCmds[i].unk_232) { + status_bits |= (1 << 24); + } + + if (VagCmds[i].byte6 && VagCmds[i].sb_paused == 0) { + VagCmds[i].unk_192 += CalculateVAGPitch(0x400, VagCmds[i].unk_256_pitch2) / gFPS; + } + + if (VagCmds[i].sb_playing == 0 && VagCmds[i].byte5) { + pos = 0; + } else { + pos = VagCmds[i].unk_200; + } + + info.stream_status[i] = status_bits; + info.stream_position[i] = pos; + // printf("positions: %d\n", pos); + info.stream_id[i] = VagCmds[i].id; + } + + info.iop_ticks = IsoThreadCounter; + info.frame = gFrameNum; + info.freemem = 100 /*gFreeMem*/; + info.freemem2 = QueryTotalFreeMemSize(); + info.nocd = 0 /*gNoCD*/; + info.dirtycd = 0 /*gDirtyCD*/; + info.diskspeed[0] = 0 /*gDiskSpeed*/; + info.diskspeed[1] = 0 /*DAT_00013488*/; + info.lastspeed = 0 /*gLastSpeed*/; + info.dupseg = 0 /*gDupSeg*/; + iVar2 = 1; + do { + iVar3 = snd_GetVoiceStatus(iVar2); + uVar4 = '\0'; + if (iVar3 == 1) { + uVar4 = 0xff; + } + info.chinfo[iVar2] = uVar4; + bVar1 = iVar2 < 0x30; + iVar2 = iVar2 + 1; + } while (bVar1); + LookupSound(0x29a); // lol idk + + /* + local_38 = &info; + local_30 = 0x250; + local_2c = 0; + local_34 = gInfoEE; + dmaid = sceSifSetDma(&local_38,1); + */ + + sceSifDmaData dma; + dma.data = &info; + dma.addr = (void*)(uintptr_t)gInfoEE; + dma.size = 0x250; + dma.mode = 0; + /*dmaid =*/sceSifSetDma(&dma, 1); + } + return 1; +} + +u32 Thread_Player() { + sceSifQueueData dq; + sceSifServeData serve; + + // set up RPC + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, PLAYER_RPC_ID[g_game_version], RPC_Player, gPlayerBuf, nullptr, nullptr, + &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + return 0; +} + +u32 Thread_Loader() { + sceSifQueueData dq; + sceSifServeData serve; + + // set up RPC + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, LOADER_RPC_ID[g_game_version], RPC_Loader, gLoaderBuf, nullptr, nullptr, + &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + return 0; +} + +void SetVagStreamName(VagCmd* param_1, int param_2, int param_3) { + // undefined4 local_18 [2]; + + if (param_3 == 1) { + // CpuSuspendIntr(local_18); + } + if (param_2 == 0) { + info.stream_name[param_1->idx_in_cmd_arr].dat[0] = '\0'; + } else { + strncpy(info.stream_name[param_1->idx_in_cmd_arr].dat, param_1->name, 0x30); + } + if (param_3 == 1) { + // CpuResumeIntr(local_18[0]); + } +} + +void SetVagName(int param_1, char* param_2, int param_3) { + // CpuSuspendIntr(local_18); + if (param_3 == 0) { + info.stream_name[param_1].dat[0] = '\0'; + } else { + strncpy(info.stream_name[param_1].dat, param_2, 0x30); + } + // CpuResumeIntr(local_18[0]); +} + +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/srpc.h b/game/overlord/jak2/srpc.h new file mode 100644 index 0000000000..fa03388871 --- /dev/null +++ b/game/overlord/jak2/srpc.h @@ -0,0 +1,153 @@ +#pragma once + +#include "common/common_types.h" + +#include "game/overlord/common/srpc.h" + +namespace jak2 { + +enum class Jak2SoundCommand : u16 { + iop_store = 0, + iop_free = 1, + load_bank = 2, + load_bank_from_iop = 3, + load_bank_from_ee = 4, + load_music = 5, + unload_bank = 6, + play = 7, + pause_sound = 8, + stop_sound = 9, + continue_sound = 10, + set_param = 11, + set_master_volume = 12, + pause_group = 13, + stop_group = 14, + continue_group = 15, + get_irx_version = 16, + set_falloff_curve = 17, + set_sound_falloff = 18, + reload_info = 19, + set_language = 20, + set_flava = 21, + set_midi_reg = 22, + set_reverb = 23, + set_ear_trans = 24, + shutdown = 25, + list_sounds = 26, + unload_music = 27, + set_fps = 28, + boot_load = 29, + game_load = 30, + num_tests = 31, + num_testruns = 32, + num_sectors = 33, + num_streamsectors = 34, + num_streambanks = 35, + track_pitch = 36, + linvel_nom = 37, + linvel_stm = 38, + seek_nom = 39, + seek_stm = 40, + read_seq_nom = 41, + read_seq_stm = 42, + read_spr_nom = 43, + read_spr_stm = 44, + read_spr_strn_nom = 45, + rand_stm_abort = 46, + rand_nom_abort = 47, + iop_mem = 48, + cancel_dgo = 49, + set_stereo_mode = 50, +}; + +struct SoundRpcCommand { + u16 rsvd1; + Jak2SoundCommand j2command; + union { + SoundRpcGetIrxVersion irx_version; + SoundRpcBankCommand load_bank; + SoundRpcSetLanguageCommand set_language; + SoundRpcPlayCommand play; + SoundRpcSoundIdCommand sound_id; + SoundRpcSetFPSCommand fps; + SoundRpcSetEarTrans ear_trans; + SoundRpc2SetEarTrans ear_trans_j2; + SoundRpcSetReverb reverb; + SoundRpcSetFallof fallof; + SoundRpcSetFallofCurve fallof_curve; + SoundRpcGroupCommand group; + SoundRpcSetFlavaCommand flava; + SoundRpcMasterVolCommand master_volume; + SoundRpcSetParamCommand param; + SoundRpcStereoMode stereo_mode; + SoundRpcSetMidiReg midi_reg; + SoundRpcSetMirrror mirror; + u8 max_size[0x4C]; // Temporary + }; +}; + +/* + * + ((frame uint32 :offset-assert 0) + (strpos int32 :offset-assert 4) + (str-id uint32 :offset-assert 8) + (str-id-sign int32 :offset 8) + (freemem uint32 :offset-assert 12) + (chinfo uint8 48 :offset-assert 16) + (freemem2 uint32 :offset-assert 64) + (nocd uint32 :offset-assert 68) + (dirtycd uint32 :offset-assert 72) + (diskspeed uint32 2 :offset-assert 76) + (lastspeed uint32 :offset-assert 84) + (dupseg int32 :offset-assert 88) + (times int32 41 :offset-assert 92) + (times-seq uint32 :offset-assert 256) + (iop-ticks uint32 :offset-assert 260) + (stream-position uint32 4 :offset 272) + (stream-status stream-status 4 :offset-assert 288) + (stream-name sound-stream-name 4 :inline :offset-assert 304) + (stream-id sound-id 4 :offset-assert 496) + (stream-id-int32 int32 4 :offset 496) ;; ughhhh... + (music-register uint8 17 :offset-assert 512) + (music-excite int8 :offset 528) + (ramdisk-name uint8 48 :offset-assert 529) + */ +struct StreamName { + char dat[48]; +}; +struct SoundIopInfo { + u32 frame; + s32 strpos; + u32 std_id; + u32 freemem; + u8 chinfo[48]; + u32 freemem2; + u32 nocd; + u32 dirtycd; + u32 diskspeed[2]; + u32 lastspeed; + s32 dupseg; + u32 times[41]; + u32 times_seq; + u32 iop_ticks; + u32 p; + u32 q; + s32 stream_position[4]; + s32 stream_status[4]; + StreamName stream_name[4]; + s32 stream_id[4]; + u8 music_register[17]; + char ramdisk_name[48]; + char pad[3]; + char more_padding[12]; +}; +static_assert(sizeof(SoundIopInfo) == 0x250); + +struct VagCmd; +void SetVagStreamName(VagCmd* param_1, int param_2, int param_3); +void srpc_init_globals(); +int VBlank_Handler(void*); +u32 Thread_Player(); +u32 Thread_Loader(); + +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/ssound.cpp b/game/overlord/jak2/ssound.cpp new file mode 100644 index 0000000000..8ca1dda7df --- /dev/null +++ b/game/overlord/jak2/ssound.cpp @@ -0,0 +1,175 @@ +#include "ssound.h" + +#include "common/util/Assert.h" + +#include "game/overlord/common/srpc.h" +#include "game/overlord/common/ssound.h" +#include "game/overlord/jak2/spustreams.h" +#include "game/overlord/jak2/streamlist.h" +#include "game/overlord/jak2/vag.h" +#include "game/sce/iop.h" +#include "game/sound/sndshim.h" + +using namespace iop; + +namespace jak2 { +VolumePair gPanTable[361]; + +s32 StreamThread = 0; +void ssound_init_globals() { + StreamThread = 0; +} + +void SetBufferMem(void*, int) {} +void ReleaseBufferMem() {} + +void InitSound_overlord() { + for (auto& s : gSounds) { + s.id = 0; + } + + SetCurve(2, 0, 0); + SetCurve(9, 0, 0); + SetCurve(11, 0, 0); + SetCurve(10, 0, 0); + SetCurve(3, 4096, 0); + SetCurve(4, 0, 4096); + SetCurve(5, 2048, 0); + SetCurve(6, 2048, 2048); + SetCurve(7, -4096, 0); + SetCurve(8, -2048, 0); + + // need this one for PC sound to start up + snd_StartSoundSystem(); + + // there's a bunch of stuff that we don't use. + StreamVoice[0] = 0; + StreamVoice[1] = 1; + StreamVoice[2] = 2; + StreamVoice[3] = 3; // TODO idk what im doing. + + for (int i = 0; i < 91; i++) { + s16 opposing_front = static_cast(((i * 0x33ff) / 0x5a) + 0xc00); + + s16 rear_right = static_cast(((i * -0x2800) / 0x5a) + 0x3400); + s16 rear_left = static_cast(((i * -0xbff) / 0x5a) + 0x3fff); + + gPanTable[90 - i].left = 0x3FFF; + gPanTable[180 - i].left = opposing_front; + gPanTable[270 - i].left = rear_right; + gPanTable[360 - i].left = rear_left; + + gPanTable[i].right = opposing_front; + gPanTable[90 + i].right = 0x3FFF; + gPanTable[180 + i].right = rear_left; + gPanTable[270 + i].right = rear_right; + } + + snd_SetPanTable((s16*)gPanTable); + snd_SetPlayBackMode(2); + + SemaParam local_58; + local_58.attr = 1; + local_58.init_count = 1; + local_58.max_count = 1; + local_58.option = 0; + gSema = CreateSema(&local_58); + if (gSema < 0) { + printf("IOP: ======================================================================\n"); + printf("IOP: ssound InitSound: can\'t create semaphore\n"); + printf("IOP: ======================================================================\n"); + ASSERT_NOT_REACHED(); + } + // Init989Plugins(); TODO + // InitStreamLfoHandler(); TODO + InitVagStreamList(&PluginStreamsList, 4, "plugin"); + InitVagStreamList(&EEStreamsList, 4, "ee"); + InitVagStreamList(&EEPlayList, 8, "play"); + InitVagStreamList(&RequestedStreamsList, 8, "streams"); + InitVagStreamList(&NewStreamsList, 4, "new"); + + ThreadParam local_30; + local_30.attr = 0x2000000; + local_30.entry = StreamListThread; + local_30.initPriority = 0x78; + local_30.stackSize = 0x1000; + local_30.option = 0; + StreamThread = CreateThread(&local_30); + if (StreamThread < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: ssound InitSound: can\'t create streamlist thread\n"); + printf("IOP: ======================================================================\n"); + ASSERT_NOT_REACHED(); + } + StartThread(StreamThread, 0); +} + +void SetMusicVol() { + int vol = (MasterVolume[1] * gMusicFade >> 0x10) * gMusicTweak >> 7; + snd_SetMasterVolume(1, vol); + snd_SetMasterVolume(2, vol); +} + +void SetEarTrans(Vec3w* ear_trans0, Vec3w* ear_trans1, Vec3w* cam_trans, s32 cam_angle) { + // some assuming that this is the same in jak2... + s32 tick = snd_GetTick(); + u32 delta = tick - sLastTick; + sLastTick = tick; + + gEarTrans[0] = *ear_trans0; + gEarTrans[1] = *ear_trans1; + gCamTrans = *cam_trans; + gCamAngle = cam_angle; + + for (auto& s : gSounds) { + if (s.id != 0 && s.is_music == 0) { + if (s.auto_time != 0) { + UpdateAutoVol(&s, delta); + } + UpdateLocation(&s); + } + } + + // SetVAGVol(); + + int iVar2 = 0; + auto* cmd = VagCmds; + // piVar6 = &VagCmds[0].vol_multiplier; + do { + if (cmd->unk_136 == 0x0) { + LAB_0000c388: + SetVAGVol(cmd, 1); + } else if ((cmd->sb_scanned == '\0') || (cmd->byte8 != '\0')) { + if (cmd->byte20 == '\0') { + if ((u32)cmd->vol_multiplier < 0x11) { + cmd->vol_multiplier = 0; + } else { + cmd->vol_multiplier = cmd->vol_multiplier - 0x10; + } + SetVAGVol(cmd, 1); + if (cmd->vol_multiplier != 0) + goto LAB_0000c398; + } + LAB_0000c378: + StopVagStream(cmd, 1); + } else { + if (snd_SoundIsStillPlaying(cmd->id) != 0) + goto LAB_0000c388; + if (cmd->byte20 != '\0') + goto LAB_0000c378; + // CpuSuspendIntr(local_30); + cmd->byte8 = '\x01'; + + // CpuResumeIntr(local_30[0]); + } + LAB_0000c398: + cmd = cmd + 1; + // piVar6 = piVar6 + 0x51; + iVar2 = iVar2 + 1; + if (3 < iVar2) { + return; + } + } while (true); +} + +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/ssound.h b/game/overlord/jak2/ssound.h new file mode 100644 index 0000000000..bc8a99b5eb --- /dev/null +++ b/game/overlord/jak2/ssound.h @@ -0,0 +1,13 @@ +#pragma once +#include "game/overlord/common/ssound.h" + +namespace jak2 { +void ssound_init_globals(); +void SetBufferMem(void*, int); +void ReleaseBufferMem(); +void SetMusicVol(); +void SetEarTrans(Vec3w* ear_trans0, Vec3w* ear_trans1, Vec3w* cam_trans, s32 cam_angle); +void InitSound_overlord(); +extern s32 StreamThread; +extern VolumePair gPanTable[361]; +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/stream.cpp b/game/overlord/jak2/stream.cpp new file mode 100644 index 0000000000..63ad1b91a6 --- /dev/null +++ b/game/overlord/jak2/stream.cpp @@ -0,0 +1,359 @@ +#include "stream.h" + +#include + +#include "common/util/FileUtil.h" + +#include "game/common/play_rpc_types.h" +#include "game/common/str_rpc_types.h" +#include "game/overlord/common/iso.h" +#include "game/overlord/common/iso_api.h" +#include "game/overlord/common/isocommon.h" +#include "game/overlord/jak2/iso.h" +#include "game/overlord/jak2/iso_api.h" +#include "game/overlord/jak2/streamlist.h" +#include "game/overlord/jak2/vag.h" +#include "game/runtime.h" +#include "game/sce/iop.h" + +using namespace iop; + +namespace jak2 { +static RPC_Str_Cmd_Jak2 sSTRBuf; +static RPC_Play_Cmd_Jak2 sPLAYBuf[2]; // called sRPCBuf2 + +struct CacheEntry { + FileRecord* fr = nullptr; + s32 countdown = 0; + StrFileHeaderJ2 header; +}; + +constexpr int STR_INDEX_CACHE_SIZE = 4; +CacheEntry sCache[STR_INDEX_CACHE_SIZE]; + +void stream_init_globals() { + memset(&sSTRBuf, 0, sizeof(RPC_Str_Cmd_Jak2)); + memset(&sPLAYBuf, 0, sizeof(RPC_Play_Cmd_Jak2) * 2); +} + +/*! + * The STR RPC handler. + */ +void* RPC_STR(unsigned int /*fno*/, void* _cmd, int /*y*/) { + auto* cmd = (RPC_Str_Cmd_Jak2*)_cmd; + if (cmd->section < 0) { + // it's _not_ a stream file. So we just treat it like a normal load. + + // find the file with the given name + auto file_record = isofs->find(cmd->basename); + if (file_record == nullptr) { + // file not found! + printf("[OVERLORD STR] Failed to find file %s for loading.\n", cmd->basename); + cmd->result = STR_RPC_RESULT_ERROR; + } else { + // load directly to the EE + cmd->maxlen = LoadISOFileToEE(file_record, cmd->address, cmd->maxlen); + if (cmd->maxlen) { + // successful load! + cmd->result = STR_RPC_RESULT_DONE; + } else { + // there was an error loading. + cmd->result = STR_RPC_RESULT_ERROR; + } + } + } else { + // it's a chunked file. These are only animations - these have a separate naming scheme. + char animation_iso_name[128]; + file_util::ISONameFromAnimationName(animation_iso_name, cmd->basename); + auto file_record = isofs->find_in(animation_iso_name); + + if (!file_record) { + // didn't find the file + printf("[OVERLORD STR] Failed to find animation %s (%s)\n", cmd->basename, + animation_iso_name); + cmd->result = STR_RPC_RESULT_ERROR; + } else { + // found it! See if we've cached this animation's header. + int cache_entry = 0; + int oldest = INT32_MAX; + int oldest_idx = -1; + while (cache_entry < STR_INDEX_CACHE_SIZE && sCache[cache_entry].fr != file_record) { + sCache[cache_entry].countdown--; + if (sCache[cache_entry].countdown < oldest) { + oldest_idx = cache_entry; + oldest = sCache[cache_entry].countdown; + } + cache_entry++; + } + + if (cache_entry == STR_INDEX_CACHE_SIZE) { + // cache miss, we need to load the header to the header cache on the IOP + cache_entry = oldest_idx; + sCache[oldest_idx].fr = file_record; + sCache[oldest_idx].countdown = INT32_MAX - 1; + if (!LoadISOFileToIOP(file_record, (u8*)&sCache[oldest_idx].header, + sizeof(StrFileHeaderJ2))) { + printf("[OVERLORD STR] Failed to load chunk file header for animation %s\n", + cmd->basename); + cmd->result = 1; + return cmd; + } + } + + // load data, using the cached header to find the location of the chunk. + if (!LoadISOFileChunkToEE(file_record, cmd->address, + sCache[cache_entry].header.sizes[cmd->section], + sCache[cache_entry].header.sectors[cmd->section])) { + printf("[OVERLORD STR] Failed to load chunk %d for animation %s\n", cmd->section, + cmd->basename); + cmd->result = 1; + } else { + // successful load! + cmd->maxlen = sCache[cache_entry].header.sizes[cmd->section]; + cmd->result = 0; + } + } + } + + // don't remember why we changed this... + return cmd; + // return nullptr; +} + +void* RPC_PLAY([[maybe_unused]] unsigned int fno, void* _cmd, int size) { + // uint16_t uVar1; + VagCmd* pRVar2; + VagStrListNode* iVar3; + VagStrListNode* iVar4; + // RPC_Play_Cmd_Jak2* pRVar3; + // char* __src; + int iVar5; + // int iVar6; + // uint uVar7; + // RPC_Play_Cmd_Jak2* pRVar8; + // int iVar10; + VagStrListNode list_node; + // int local_30; + // int local_2c; + + // if (size < 0) { + // size = size + 0xff; + // } + // local_30 = size >> 8; + // local_2c = 0; + + int n_messages = size / sizeof(RPC_Play_Cmd_Jak2); + auto* cmd_iter = (RPC_Play_Cmd_Jak2*)_cmd; + + for (int i = 0; i < n_messages; i++) { + // printf("RPC_PLAY message %d\n", i); + auto cmd_result = cmd_iter->result; + + if (cmd_result == 1) { + for (int s = 0; s < 4; s++) { + if (cmd_iter->names[s].chars[0]) { + strncpy(list_node.name, cmd_iter->names[s].chars, 0x30); + list_node.id = cmd_iter->id[s]; + WaitSema(EEStreamsList.sema); + RemoveVagStreamFromList(&list_node, &EEStreamsList); + SignalSema(EEStreamsList.sema); + WaitSema(EEPlayList.sema); + RemoveVagStreamFromList(&list_node, &EEPlayList); + SignalSema(EEPlayList.sema); + } + } + + } else { + iVar5 = 9; + if (cmd_result == 2) { + // uVar7 = 0; + // iVar6 = 0x20; + WaitSema(EEStreamsList.sema); + EmptyVagStreamList(&EEStreamsList); + + for (int s = 0; s < 4; s++) { + if (cmd_iter->names[s].chars[0] && cmd_iter->id[s]) { + // printf("got queue command %d: %s %d\n", s, cmd_iter->names[s].chars, + // cmd_iter->id[s]); + strncpy(list_node.name, cmd_iter->names[s].chars, 0x30); + list_node.id = cmd_iter->id[s]; + list_node.unk_76 = cmd_iter->address & 1 << (s & 0x1f) & 0xf; + list_node.unk_72 = 0; + list_node.unk_80 = cmd_iter->address & 0x10 << (s & 0x1f) & 0xf0; + list_node.prio = iVar5; + pRVar2 = FindThisVagStream(list_node.name, list_node.id); + if (pRVar2 != 0x0) { + pRVar2->unk_288 = list_node.unk_76; + pRVar2->unk_292 = list_node.unk_80; + if (pRVar2->unk_288 != 0) { + pRVar2->byte10 = '\x01'; + } + if (pRVar2->unk_292 != 0) { + pRVar2->unk_232 = '\x01'; + } + } + InsertVagStreamInList(&list_node, &EEStreamsList); + } + if (iVar5 == 8) { + iVar5 = 2; + } else if (0 < iVar5) { + iVar5 = iVar5 + -1; + } + } + + /* + pRVar3 = cmd_iter; + pRVar8 = cmd_iter; + do { + if ((pRVar8->names[0].data[0] != '\0') && (pRVar3->id[0] != 0)) { + strncpy(list_node.name, (char*)((int)cmd_iter->id + iVar6 + -0x10), 0x30); + list_node.id = pRVar3->id[0]; + list_node.unk_76 = cmd_iter->address & 1 << (uVar7 & 0x1f) & 0xf; + list_node.unk_72 = 0; + list_node.unk_80 = cmd_iter->address & 0x10 << (uVar7 & 0x1f) & 0xf0; + list_node.prio = iVar5; + pRVar2 = FindThisVagStream(list_node.name, list_node.id); + if (pRVar2 != (RealVagCmd*)0x0) { + pRVar2->unk_288 = list_node.unk_76; + pRVar2->unk_292 = list_node.unk_80; + if (pRVar2->unk_288 != 0) { + pRVar2->byte10 = '\x01'; + } + if (pRVar2->unk_292 != 0) { + pRVar2->unk_232 = '\x01'; + } + } + InsertVagStreamInList(&list_node, (List*)EEStreamsList); + } + if (iVar5 == 8) { + iVar5 = 2; + } else if (0 < iVar5) { + iVar5 = iVar5 + -1; + } + iVar6 = iVar6 + 0x30; + pRVar3 = (RPC_Play_Cmd*)&pRVar3->address; + uVar7 = uVar7 + 1; + pRVar8 = (RPC_Play_Cmd*)(pRVar8->names[0].data + 0x10); + } while ((int)uVar7 < 4); + */ + + SignalSema(EEStreamsList.sema); + } else if (cmd_result == 0) { + iVar5 = 9; + + for (int s = 0; s < 4; s++) { + if (cmd_iter->names[s].chars[0] && cmd_iter->id[s]) { + // __src = (char*)((int)cmd_iter->id + iVar10 + -0x10); + strncpy(list_node.name, cmd_iter->names[s].chars, 0x30); + list_node.id = cmd_iter->id[s]; + list_node.unk_68 = 0; + list_node.unk_72 = 0; + list_node.prio = iVar5; + pRVar2 = FindThisVagStream(cmd_iter->names[s].chars, cmd_iter->id[s]); + if ((pRVar2 == 0x0) || (pRVar2->byte4 == '\0')) { + printf(" didn't exist, looks like it needs to be added!\n"); + WaitSema(EEPlayList.sema); + iVar3 = (VagStrListNode*)FindVagStreamInList(&list_node, &EEPlayList); + if (iVar3 == (VagStrListNode*)0x0) { + printf("node also doesn't exist, adding it!\n"); + iVar4 = (VagStrListNode*)InsertVagStreamInList(&list_node, &EEPlayList); + + iVar4->id = list_node.id; + iVar4->prio = list_node.prio; + iVar4->unk_72 = list_node.unk_72; + iVar4->unk_76 = 0; + iVar4->unk_80 = 0; + iVar4->unk_92 = 0; + iVar4->unk_68 = list_node.unk_68; + strncpy(iVar4->name, list_node.name, 0x30); + } + SignalSema(EEPlayList.sema); + } + } + + if (iVar5 == 8) { + iVar5 = 2; + } else if (0 < iVar5) { + iVar5 = iVar5 + -1; + } + } + + /* + iVar6 = 0; + iVar10 = 0x20; + pRVar3 = cmd_iter; + pRVar8 = cmd_iter; + do { + if ((pRVar8->names[0].data[0] != '\0') && (pRVar3->id[0] != 0)) { + __src = (char*)((int)cmd_iter->id + iVar10 + -0x10); + strncpy(list_node.name, __src, 0x30); + list_node.id = pRVar3->id[0]; + list_node.unk_68 = 0; + list_node.unk_72 = 0; + list_node.prio = iVar5; + pRVar2 = FindThisVagStream(__src, pRVar3->id[0]); + if ((pRVar2 == (RealVagCmd*)0x0) || (pRVar2->byte4 == '\0')) { + WaitSema(EEPlayList._12_4_); + iVar3 = (VagStrListNode*)FindVagStreamInList(&list_node, (List*)EEPlayList); + if (iVar3 == (VagStrListNode*)0x0) { + iVar4 = (VagStrListNode*)InsertVagStreamInList(&list_node, (List*)EEPlayList); + strncpy(iVar4->name, list_node.name, 0x30); + iVar4->id = list_node.id; + iVar4->prio = list_node.prio; + iVar4->unk_72 = list_node.unk_72; + iVar4->unk_76 = 0; + iVar4->unk_80 = 0; + iVar4->unk_92 = 0; + iVar4->unk_68 = list_node.unk_68; + } + SignalSema(EEPlayList._12_4_); + } + } + if (iVar5 == 8) { + iVar5 = 2; + } else if (0 < iVar5) { + iVar5 = iVar5 + -1; + } + iVar10 = iVar10 + 0x30; + pRVar3 = (RPC_Play_Cmd*)&pRVar3->address; + iVar6 = iVar6 + 1; + pRVar8 = (RPC_Play_Cmd*)(pRVar8->names[0].data + 0x10); + } while (iVar6 < 4); + */ + } + } + cmd_iter = cmd_iter + 1; + } + return _cmd; +} + +/*! + * Run the STR RPC handler. + */ +u32 STRThread() { + sceSifQueueData dq; + sceSifServeData serve; + + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, STR_RPC_ID[g_game_version], RPC_STR, &sSTRBuf, nullptr, nullptr, &dq); + + CpuEnableIntr(); + sceSifRpcLoop(&dq); + return 0; +} +sceSifServeData* gserve = nullptr; +u32 PLAYThread() { + sceSifQueueData dq; + sceSifServeData serve; + gserve = &serve; + CpuDisableIntr(); + sceSifInitRpc(0); + sceSifSetRpcQueue(&dq, GetThreadId()); + sceSifRegisterRpc(&serve, PLAY_RPC_ID[g_game_version], RPC_PLAY, sPLAYBuf, nullptr, nullptr, &dq); + CpuEnableIntr(); + sceSifRpcLoop(&dq); + return 0; +} +} // namespace jak2 diff --git a/game/overlord/jak2/stream.h b/game/overlord/jak2/stream.h new file mode 100644 index 0000000000..5c4cec2814 --- /dev/null +++ b/game/overlord/jak2/stream.h @@ -0,0 +1,9 @@ +#pragma once + +#include "common/common_types.h" + +namespace jak2 { +void stream_init_globals(); +u32 STRThread(); +u32 PLAYThread(); +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/jak2/streamlfo.cpp b/game/overlord/jak2/streamlfo.cpp new file mode 100644 index 0000000000..a4231776a0 --- /dev/null +++ b/game/overlord/jak2/streamlfo.cpp @@ -0,0 +1,3 @@ + +#include "streamlfo.h" +namespace jak2 {} \ No newline at end of file diff --git a/game/overlord/jak2/streamlfo.h b/game/overlord/jak2/streamlfo.h new file mode 100644 index 0000000000..acbcaf9bb8 --- /dev/null +++ b/game/overlord/jak2/streamlfo.h @@ -0,0 +1,3 @@ +#pragma once + +namespace jak2 {} \ No newline at end of file diff --git a/game/overlord/jak2/streamlist.cpp b/game/overlord/jak2/streamlist.cpp new file mode 100644 index 0000000000..29aaef0699 --- /dev/null +++ b/game/overlord/jak2/streamlist.cpp @@ -0,0 +1,633 @@ +#include "streamlist.h" + +#include +#include + +#include "game/overlord/jak2/vag.h" +#include "game/sce/iop.h" + +using namespace iop; + +namespace jak2 { + +List PluginStreamsList; +List LfoList; +List EEPlayList; +List RequestedStreamsList; +List NewStreamsList; +List EEStreamsList; + +void init_globals_streamlist() { + memset(&PluginStreamsList, 0, sizeof(PluginStreamsList)); + memset(&LfoList, 0, sizeof(LfoList)); + memset(&EEPlayList, 0, sizeof(EEPlayList)); + memset(&RequestedStreamsList, 0, sizeof(RequestedStreamsList)); + memset(&NewStreamsList, 0, sizeof(NewStreamsList)); + memset(&EEStreamsList, 0, sizeof(EEStreamsList)); +} + +// TODO +void CheckLfoList(void*) {} +void RemoveLfoStreamFromList(void*, void*) {} + +VagStrListNode* InsertVagStreamInList(VagStrListNode* param_1, List* param_2) { + int iVar1; + u32 uVar2; + u32 uVar3; + VagStrListNode* pLVar3; + VagStrListNode* pVVar4; + VagStrListNode* pVVar5; + VagStrListNode* pVVar6; + + uVar2 = 0; + uVar3 = param_2->elt_count; + pLVar3 = (VagStrListNode*)param_2->next; + pVVar5 = (VagStrListNode*)0x0; + if (uVar3 != 0) { + do { + if (pLVar3->id == 0) { + uVar2 = uVar3; + pVVar5 = pLVar3; + } + pLVar3 = (VagStrListNode*)(pLVar3->list).next; + uVar2 = uVar2 + 1; + } while (uVar2 < uVar3); + pLVar3 = (VagStrListNode*)param_2->next; + } + pVVar6 = (VagStrListNode*)0x0; + if (pVVar5 == (VagStrListNode*)0x0) { + printf("IOP: ======================================================================\n"); + printf("IOP: streamlist InsertVagStreamInList: no free spot in list %s\n", param_2->name); + printf("IOP: ======================================================================\n"); + } else { + uVar2 = 0; + if (uVar3 != 0) { + do { + pVVar4 = pLVar3; + uVar2 = uVar2 + 1; + if (pVVar4->prio < param_1->prio) { + param_2->maybe_any_in_use = 1; + (pVVar5->list).in_use = 1; + strncpy(pVVar5->name, param_1->name, 0x30); + pVVar5->id = param_1->id; + pVVar5->unk_68 = param_1->unk_68; + pVVar5->unk_76 = param_1->unk_76; + pVVar5->unk_80 = param_1->unk_80; + pVVar5->prio = param_1->prio; + iVar1 = param_1->unk_72; + pVVar5->unk_92 = 0; + pVVar5->unk_72 = iVar1; + pVVar5->vol_multiplier = param_1->vol_multiplier; + pVVar5->unk_100 = param_1->unk_100; + if (pVVar6 == (VagStrListNode*)0x0) { + if (pVVar5 == pVVar4) { + return pVVar5; + } + ((pVVar5->list).next)->prev = (pVVar5->list).prev; + ((pVVar5->list).prev)->next = (pVVar5->list).next; + (pVVar4->list).prev = &pVVar5->list; + (pVVar5->list).next = &pVVar4->list; + (pVVar5->list).prev = (ListNode*)0x0; + param_2->next = &pVVar5->list; + return pVVar5; + } + if (pVVar5 == pVVar4) { + return pVVar5; + } + ((pVVar5->list).prev)->next = (pVVar5->list).next; + ((pVVar5->list).next)->prev = (pVVar5->list).prev; + (pVVar5->list).next = (pVVar6->list).next; + (pVVar6->list).next = &pVVar5->list; + (pVVar4->list).prev = &pVVar5->list; + (pVVar5->list).prev = &pVVar6->list; + return pVVar5; + } + pLVar3 = (VagStrListNode*)(pVVar4->list).next; + pVVar6 = pVVar4; + } while (uVar2 < uVar3); + } + } + return pVVar5; +} + +void QueueNewStreamsFromList(List* list) { + int iVar1; + u32 uVar2; + VagCmd* pRVar3; + // undefined4 *puVar4; + VagStrListNode* pVVar5; + VagStrListNode* pvVar6; + u32 uVar6; + u32 uVar7; + + SetVagStreamsNotScanned(); + iVar1 = NewStreamsList.elt_count; + uVar6 = 0; + uVar7 = 0; + if (NewStreamsList.elt_count != 0) { + // puVar4 = (undefined4 *)((int)NewStreamsList.buffer + 8); + pvVar6 = (VagStrListNode*)NewStreamsList.buffer; + do { + strncpy(pvVar6->name, "free", 0x30); + // puVar4[0xe] = 0; + pvVar6->id = 0; + // puVar4[0x10] = 0; + pvVar6->unk_72 = 0; + // puVar4[0x13] = 0; + pvVar6->prio = 0; + // puVar4[0x11] = 0; + pvVar6->unk_76 = 0; + // puVar4[0x12] = 0; + pvVar6->unk_80 = 0; + // puVar4[0x14] = 0; + pvVar6->unk_88 = 0; + // puVar4[0x15] = 0; + pvVar6->unk_92 = 0; + // puVar4[0x16] = 0; + pvVar6->vol_multiplier = 0; + // puVar4[0x17] = 0; + pvVar6->unk_100 = 0; + // *puVar4 = 0; + pvVar6->list.in_use = 0; + // puVar4 = puVar4 + 0x1a; + uVar6 = uVar6 + 1; + pvVar6 = pvVar6 + 1; + } while (uVar6 < (u32)iVar1); + } + uVar6 = 0; + NewStreamsList.maybe_any_in_use = 0; + do { + do { + pVVar5 = (VagStrListNode*)0x0; + if (uVar7 < (u32)list->elt_count) { + pVVar5 = (VagStrListNode*)list->next; + for (uVar2 = uVar7; uVar2 != 0; uVar2 = uVar2 - 1) { + pVVar5 = (VagStrListNode*)(pVVar5->list).next; + } + } + uVar7 = uVar7 + 1; + if (pVVar5 == (VagStrListNode*)0x0) { + uVar6 = 4; + goto LAB_0000ef9c; + } + } while (pVVar5->id == 0); + pRVar3 = FindThisVagStream(pVVar5->name, pVVar5->id); + if (pRVar3 == 0x0) { + pRVar3 = FindThisVagStream(pVVar5->name, pVVar5->id); + if (pRVar3 != 0x0) + goto LAB_0000ef9c; + InsertVagStreamInList(pVVar5, &NewStreamsList); + uVar6 = uVar6 + 1; + } else { + pRVar3->sb_scanned = '\x01'; + if (pRVar3->stereo_sibling != 0x0) { + pRVar3->stereo_sibling->sb_scanned = '\x01'; + } + if (pVVar5->prio == pRVar3->priority) { + LAB_0000ef9c: + uVar6 = uVar6 + 1; + } else { + SetNewVagCmdPri(pRVar3, pVVar5->prio, 1); + uVar6 = uVar6 + 1; + } + } + if (3 < uVar6) { + return; + } + } while (true); +} + +void CheckPlayList(List* param_1) { + VagCmd* pRVar1; + int iVar2; + VagStrListNode* pLVar3; + VagStrListNode* pVVar3; + VagStrListNode* pVVar4; + u32 uVar5; + u32 uVar6; + VagStrListNode* pLVar7; + int iVar7; + + iVar7 = param_1->elt_count; + pLVar7 = (VagStrListNode*)param_1->next; +joined_r0x0000f00c: + do { + while (true) { + if (iVar7 == 0) { + return; + } + iVar7 = iVar7 + -1; + if (pLVar7->id != 0) + break; + pLVar7 = (VagStrListNode*)(pLVar7->list).next; + } + pRVar1 = FindThisVagStream(pLVar7->name, pLVar7->id); + } while (pRVar1 == 0x0); + uVar5 = 0; + if (pRVar1->byte4 == '\0') + goto code_r0x0000f058; + uVar6 = param_1->elt_count; + pVVar3 = (VagStrListNode*)param_1->next; + pVVar4 = (VagStrListNode*)0x0; + if (uVar6 != 0) { + do { + if ((pVVar3->id == pLVar7->id) && + (iVar2 = strncmp(pVVar3->name, pLVar7->name, 0x30), iVar2 == 0)) { + pVVar4 = pVVar3; + uVar5 = uVar6; + } + pVVar3 = (VagStrListNode*)(pVVar3->list).next; + uVar5 = uVar5 + 1; + } while (uVar5 < uVar6); + } + goto LAB_0000f144; +code_r0x0000f058: + if (((pRVar1->sb_playing != '\0') || (pRVar1->byte6 != '\0')) && (pRVar1->byte23 == '\0')) { + IsoPlayVagStream(pRVar1, 1); + uVar5 = 0; + uVar6 = param_1->elt_count; + pLVar3 = (VagStrListNode*)param_1->next; + pVVar4 = (VagStrListNode*)0x0; + if (uVar6 != 0) { + do { + if ((pLVar3->id == pLVar7->id) && + (iVar2 = strncmp(pLVar3->name, pLVar7->name, 0x30), iVar2 == 0)) { + pVVar4 = pLVar3; + uVar5 = uVar6; + } + pLVar3 = (VagStrListNode*)(pLVar3->list).next; + uVar5 = uVar5 + 1; + } while (uVar5 < uVar6); + } + LAB_0000f144: + if (pVVar4 != (VagStrListNode*)0x0) { + (pVVar4->list).in_use = 0; + strncpy(pVVar4->name, "free", 0x30); + pVVar4->id = 0; + pVVar4->unk_72 = 0; + pVVar4->prio = 0; + pVVar4->unk_76 = 0; + pVVar4->unk_80 = 0; + pVVar4->unk_88 = 0; + pVVar4->unk_92 = 0; + pVVar4->vol_multiplier = 0; + pVVar4->unk_100 = 0; + param_1->maybe_any_in_use = 1; + } + } + goto joined_r0x0000f00c; +} + +u32 StreamListThread() { + int iVar1; + int iVar2; + VagStrListNode* pVVar3; + // undefined4* puVar4; + VagStrListNode* pVVar5; + VagStrListNode* pLVar6; + VagStrListNode* pvVar6; + u32 uVar7; + u32 uVar8; + VagStrListNode* pLVar10; + u32 uVar9; + + do { + do { + SleepThread(); + } while (RequestedStreamsList.unk2_init0 != 0); + uVar8 = 0; + WaitSema(RequestedStreamsList.sema); + iVar1 = RequestedStreamsList.elt_count; + if (RequestedStreamsList.elt_count != 0) { + // puVar4 = (undefined4*)((int)RequestedStreamsList.buffer + 8); + pvVar6 = (VagStrListNode*)RequestedStreamsList.buffer; + do { + strncpy(pvVar6->name, "free", 0x30); + // puVar4[0xe] = 0; + pvVar6->id = 0; + // puVar4[0x10] = 0; + pvVar6->unk_72 = 0; + // puVar4[0x13] = 0; + pvVar6->prio = 0; + // puVar4[0x11] = 0; + pvVar6->unk_76 = 0; + // puVar4[0x12] = 0; + pvVar6->unk_80 = 0; + // puVar4[0x14] = 0; + pvVar6->unk_88 = 0; + // puVar4[0x15] = 0; + pvVar6->unk_92 = 0; + // puVar4[0x16] = 0; + pvVar6->vol_multiplier = 0; + // puVar4[0x17] = 0; + pvVar6->unk_100 = 0; + // *puVar4 = 0; + pvVar6->list.in_use = 0; + // puVar4 = puVar4 + 0x1a; + uVar8 = uVar8 + 1; + pvVar6++; + // pvVar6 = (void*)((int)pvVar6 + 0x68); + } while (uVar8 < (u32)iVar1); + } + uVar8 = 0; + RequestedStreamsList.maybe_any_in_use = 0; + uVar9 = 0; + WaitSema(PluginStreamsList.sema); + LAB_0000f2c4: + do { + iVar1 = RequestedStreamsList.elt_count; + pVVar3 = (VagStrListNode*)0x0; + uVar7 = uVar8; + pVVar5 = (VagStrListNode*)PluginStreamsList.next; + if (uVar8 < (u32)PluginStreamsList.elt_count) { + for (; pVVar3 = pVVar5, uVar7 != 0; uVar7 = uVar7 - 1) { + pVVar5 = (VagStrListNode*)(pVVar3->list).next; + } + } + uVar8 = uVar8 + 1; + if (pVVar3 != (VagStrListNode*)0x0) { + if (pVVar3->id == 0) + goto LAB_0000f2c4; + uVar7 = 0; + pLVar10 = (VagStrListNode*)0x0; + pVVar5 = (VagStrListNode*)RequestedStreamsList.next; + if (RequestedStreamsList.elt_count != 0) { + do { + if ((pVVar5->id == pVVar3->id) && + (iVar2 = strncmp(pVVar5->name, pVVar3->name, 0x30), iVar2 == 0)) { + uVar7 = iVar1; + pLVar10 = pVVar5; + } + pVVar5 = (VagStrListNode*)(pVVar5->list).next; + uVar7 = uVar7 + 1; + } while (uVar7 < (u32)iVar1); + } + if (pLVar10 == (VagStrListNode*)0x0) { + InsertVagStreamInList(pVVar3, &RequestedStreamsList); + } + } + uVar9 = uVar9 + 1; + } while (uVar9 < 4); + uVar8 = 0; + SignalSema(PluginStreamsList.sema); + uVar9 = 0; + WaitSema(EEStreamsList.sema); + LAB_0000f3c0: + do { + iVar1 = RequestedStreamsList.elt_count; + pVVar3 = (VagStrListNode*)0x0; + uVar7 = uVar8; + pVVar5 = (VagStrListNode*)EEStreamsList.next; + if (uVar8 < (u32)EEStreamsList.elt_count) { + for (; pVVar3 = pVVar5, uVar7 != 0; uVar7 = uVar7 - 1) { + pVVar5 = (VagStrListNode*)(pVVar3->list).next; + } + } + uVar8 = uVar8 + 1; + if (pVVar3 != (VagStrListNode*)0x0) { + if (pVVar3->id == 0) + goto LAB_0000f3c0; + uVar7 = 0; + pVVar5 = (VagStrListNode*)0x0; + pLVar6 = (VagStrListNode*)RequestedStreamsList.next; + if (RequestedStreamsList.elt_count != 0) { + do { + if ((pLVar6->id == pVVar3->id) && + (iVar2 = strncmp(pLVar6->name, pVVar3->name, 0x30), iVar2 == 0)) { + uVar7 = iVar1; + pVVar5 = pLVar6; + } + pLVar6 = (VagStrListNode*)(pLVar6->list).next; + uVar7 = uVar7 + 1; + } while (uVar7 < (u32)iVar1); + } + if (pVVar5 == (VagStrListNode*)0x0) { + InsertVagStreamInList(pVVar3, &RequestedStreamsList); + } + } + uVar9 = uVar9 + 1; + } while (uVar9 < 4); + SignalSema(EEStreamsList.sema); + RequestedStreamsList.unk2_init0 = 1; + SignalSema(RequestedStreamsList.sema); + WaitSema(EEPlayList.sema); + CheckPlayList(&EEPlayList); + SignalSema(EEPlayList.sema); + WaitSema(LfoList.sema); + CheckLfoList(&LfoList); + SignalSema(LfoList.sema); + } while (true); + return 0; +} + +bool InitVagStreamList(List* param_1, u32 param_2, const char* param_3) { + // uint8_t* piVar1; + u32 uVar1; + VagStrListNode* pLVar3; + + strncpy(param_1->name, param_3, 8); + InitList(param_1, param_2, sizeof(VagStrListNode)); + pLVar3 = (VagStrListNode*)param_1->next; + uVar1 = 0; + if (param_2 != 0) { + // piVar1 = (uint8_t*)&pLVar3->unk_100; + do { + // *(undefined4*)(piVar1 + -0x5c) = 0; + pLVar3->list.in_use = 0; + strncpy(pLVar3->name, "free", 0x30); + // *(undefined4*)(piVar1 + -0x24) = 0; + pLVar3->id = 0; + // *(undefined4*)(piVar1 + -0x1c) = 0; + pLVar3->unk_72 = 0; + // *(undefined4*)(piVar1 + -0x10) = 0; + pLVar3->prio = 0; + // *(undefined4*)(piVar1 + -0x18) = 0; + pLVar3->unk_76 = 0; + // *(undefined4*)(piVar1 + -0x14) = 0; + pLVar3->unk_80 = 0; + // *(undefined4*)(piVar1 + -0xc) = 0; + pLVar3->unk_88 = 0; + // *(undefined4*)(piVar1 + -8) = 0; + pLVar3->unk_92 = 0; + // *(undefined4*)(piVar1 + -4) = 0; + pLVar3->vol_multiplier = 0; + // *(undefined4*)piVar1 = 0; + pLVar3->unk_100 = 0; + // piVar1 = piVar1 + 0x68; + uVar1 = uVar1 + 1; + pLVar3 = pLVar3 + 1; + } while (uVar1 < param_2); + } + return param_1->buffer != (void*)0x0; +} + +VagStrListNode* FindVagStreamInList(VagStrListNode* param_1, List* param_2) { + int iVar1; + VagStrListNode* pLVar2; + u32 uVar2; + u32 uVar3; + VagStrListNode* pVVar4; + + uVar2 = 0; + uVar3 = param_2->elt_count; + pLVar2 = (VagStrListNode*)param_2->next; + pVVar4 = (VagStrListNode*)0x0; + if (uVar3 != 0) { + do { + if ((pLVar2->id == param_1->id) && + (iVar1 = strncmp(pLVar2->name, param_1->name, 0x30), iVar1 == 0)) { + uVar2 = uVar3; + pVVar4 = pLVar2; + } + pLVar2 = (VagStrListNode*)(pLVar2->list).next; + uVar2 = uVar2 + 1; + } while (uVar2 < uVar3); + } + return pVVar4; +} + +ListNode* GetVagStreamInList(u32 param_1, List* param_2) { + ListNode* pLVar1; + + pLVar1 = (ListNode*)0x0; + if ((param_1 < (u32)param_2->elt_count) && (pLVar1 = param_2->next, param_1 != 0)) { + do { + pLVar1 = pLVar1->next; + param_1 = param_1 - 1; + } while (param_1 != 0); + } + return pLVar1; +} + +void RemoveVagStreamFromList(VagStrListNode* param_1, List* param_2) { + int iVar1; + VagStrListNode* pLVar2; + VagStrListNode* pVVar2; + u32 uVar3; + u32 uVar4; + + uVar3 = 0; + uVar4 = param_2->elt_count; + pLVar2 = (VagStrListNode*)param_2->next; + pVVar2 = (VagStrListNode*)0x0; + if (uVar4 != 0) { + do { + if ((pLVar2->id == param_1->id) && + (iVar1 = strncmp(pLVar2->name, param_1->name, 0x30), iVar1 == 0)) { + pVVar2 = pLVar2; + uVar3 = uVar4; + } + pLVar2 = (VagStrListNode*)(pLVar2->list).next; + uVar3 = uVar3 + 1; + } while (uVar3 < uVar4); + } + if (pVVar2 != (VagStrListNode*)0x0) { + (pVVar2->list).in_use = 0; + strncpy(pVVar2->name, "free", 0x30); + pVVar2->id = 0; + pVVar2->unk_72 = 0; + pVVar2->prio = 0; + pVVar2->unk_76 = 0; + pVVar2->unk_80 = 0; + pVVar2->unk_88 = 0; + pVVar2->unk_92 = 0; + pVVar2->vol_multiplier = 0; + pVVar2->unk_100 = 0; + param_2->maybe_any_in_use = 1; + } +} + +void EmptyVagStreamList(List* param_1) { + // undefined4 *puVar1; + VagStrListNode* pvVar2; + u32 uVar3; + u32 uVar4; + + uVar4 = param_1->elt_count; + pvVar2 = (VagStrListNode*)param_1->buffer; + uVar3 = 0; + if (uVar4 != 0) { + // puVar1 = (undefined4 *)((int)pvVar2 + 8); + do { + strncpy(pvVar2->name, "free", 0x30); + // puVar1[0xe] = 0; + // puVar1[0x10] = 0; + // puVar1[0x13] = 0; + // puVar1[0x11] = 0; + // puVar1[0x12] = 0; + // puVar1[0x14] = 0; + // puVar1[0x15] = 0; + // puVar1[0x16] = 0; + // puVar1[0x17] = 0; + // *puVar1 = 0; + // puVar1 = puVar1 + 0x1a; + + pvVar2->id = 0; + pvVar2->unk_72 = 0; + pvVar2->prio = 0; + pvVar2->unk_76 = 0; + pvVar2->unk_80 = 0; + pvVar2->unk_88 = 0; + pvVar2->unk_92 = 0; + pvVar2->vol_multiplier = 0; + pvVar2->unk_100 = 0; + + uVar3 = uVar3 + 1; + pvVar2++; + } while (uVar3 < uVar4); + } + param_1->maybe_any_in_use = 1; +} + +void MergeVagStreamLists(List* param_1, List* param_2) { + u32 uVar1; + int iVar2; + VagStrListNode* pVVar3; + VagStrListNode* pLVar4; + u32 uVar4; + VagStrListNode* pVVar5; + u32 uVar6; + u32 uVar7; + + uVar6 = 0; + uVar7 = 0; + do { + do { + pVVar3 = (VagStrListNode*)0x0; + if (uVar6 < (u32)param_1->elt_count) { + pVVar3 = (VagStrListNode*)param_1->next; + for (uVar1 = uVar6; uVar1 != 0; uVar1 = uVar1 - 1) { + pVVar3 = (VagStrListNode*)(pVVar3->list).next; + } + } + uVar6 = uVar6 + 1; + if (pVVar3 == (VagStrListNode*)0x0) + goto LAB_0000f930; + } while (pVVar3->id == 0); + uVar4 = param_2->elt_count; + uVar1 = 0; + pLVar4 = (VagStrListNode*)param_2->next; + pVVar5 = (VagStrListNode*)0x0; + if (uVar4 != 0) { + do { + if ((pLVar4->id == pVVar3->id) && + (iVar2 = strncmp(pLVar4->name, pVVar3->name, 0x30), iVar2 == 0)) { + uVar1 = uVar4; + pVVar5 = pLVar4; + } + pLVar4 = (VagStrListNode*)(pLVar4->list).next; + uVar1 = uVar1 + 1; + } while (uVar1 < uVar4); + } + if (pVVar5 == (VagStrListNode*)0x0) { + InsertVagStreamInList(pVVar3, param_2); + } + LAB_0000f930: + uVar7 = uVar7 + 1; + if (3 < uVar7) { + return; + } + } while (true); +} + +} // namespace jak2 diff --git a/game/overlord/jak2/streamlist.h b/game/overlord/jak2/streamlist.h new file mode 100644 index 0000000000..8de1118c90 --- /dev/null +++ b/game/overlord/jak2/streamlist.h @@ -0,0 +1,51 @@ +#pragma once + +#include "game/overlord/jak2/list.h" + +namespace jak2 { + +struct VagStrListNode { + ListNode list; + char name[48]; + int unk_60; + int id; + int unk_68; + int unk_72; + int unk_76; + int unk_80; + int prio; + int unk_88; + int unk_92; + int vol_multiplier; + int unk_100; +}; + +struct LfoListNode { + ListNode list; + int unk_12; + int unk_16; + int unk_20; + int unk_24; + int unk_28; + int unk_32; + int id; + int plugin_id; +}; + +extern List PluginStreamsList; +extern List LfoList; +extern List EEPlayList; +extern List RequestedStreamsList; +extern List NewStreamsList; +extern List EEStreamsList; + +void init_globals_streamlist(); +void RemoveVagStreamFromList(VagStrListNode* param_1, List* param_2); +void EmptyVagStreamList(List* param_1); +VagStrListNode* InsertVagStreamInList(VagStrListNode* param_1, List* param_2); +VagStrListNode* FindVagStreamInList(VagStrListNode* param_1, List* param_2); +void QueueNewStreamsFromList(List* list); +bool InitVagStreamList(List* param_1, u32 param_2, const char* param_3); +u32 StreamListThread(); +void RemoveLfoStreamFromList(void*, void*); +} // namespace jak2 diff --git a/game/overlord/jak2/vag.cpp b/game/overlord/jak2/vag.cpp new file mode 100644 index 0000000000..d0b3cc739a --- /dev/null +++ b/game/overlord/jak2/vag.cpp @@ -0,0 +1,1082 @@ +#include "vag.h" + +#include + +#include "common/log/log.h" +#include "common/util/Assert.h" + +#include "game/overlord/jak2/iso_queue.h" +#include "game/overlord/jak2/spustreams.h" +#include "game/overlord/jak2/srpc.h" +#include "game/overlord/jak2/ssound.h" +#include "game/overlord/jak2/streamlist.h" +#include "game/sound/sdshim.h" + +namespace jak2 { +VagCmd VagCmds[N_VAG_CMDS]; +int StreamSRAM[N_VAG_CMDS]; +int TrapSRAM[N_VAG_CMDS]; +int StreamVoice[N_VAG_CMDS]; + +// sizes seem sketchy +// maybe pri 0 is a special 'free' priority. +VagCmdPriListEntry VagCmdsPriList[11]; +int VagCmdsPriCounter[11]; +int ActiveVagStreams; + +void CalculateVAGVolumes(VagCmd* cmd, int* l_out, int* r_out); + +enum VolumeCategory { + DIALOGUE = 2, // VAG streams. Copied "dialogue" name from jak 1. +}; +int MasterVolume[17]; + +void vag_init_globals() { + memset(VagCmds, 0, sizeof(VagCmds)); + memset(StreamSRAM, 0, sizeof(StreamSRAM)); + memset(TrapSRAM, 0, sizeof(TrapSRAM)); + memset(StreamVoice, 0, sizeof(StreamVoice)); + memset(VagCmdsPriList, 0, sizeof(VagCmdsPriList)); + memset(VagCmdsPriCounter, 0, sizeof(VagCmdsPriCounter)); + + for (auto& x : MasterVolume) { + x = 0x400; // check!!! + } + ActiveVagStreams = 0; +} + +void InitVagCmds() { + int cmd_idx = 0; + for (auto& cmd : VagCmds) { + for (auto& x : cmd.status_bytes) { + x = 0; + } + // puVar5 is offset 292 + cmd.unk_236 = 0; // puVar5[-0xe] = 0; + cmd.unk_140 = 0; // puVar5[-0x26] = 0; + cmd.sb_paused = 1; // *(undefined*)((int)puVar5 + -0x52) = 1; + cmd.unk_196 = 0; // puVar5[-0x18] = 0; + cmd.unk_200 = 0; // puVar5[-0x17] = 0; + cmd.unk_204 = 0; // puVar5[-0x16] = 0; + cmd.unk_180 = 0; // puVar5[-0x1c] = 0; + cmd.unk_184 = 0; // puVar5[-0x1b] = 0; + cmd.unk_188 = 0; // puVar5[-0x1a] = 0; + cmd.unk_192 = 0; // puVar5[-0x19] = 0; + cmd.status_bytes[VagCmdByte::BYTE5] = 0; // *(undefined*)((int)puVar5 + -0x4f) = 0; + cmd.status_bytes[VagCmdByte::BYTE6] = 0; // *(undefined*)((int)puVar5 + -0x4e) = 0; + cmd.num_processed_chunks = 0; // puVar5[-0xd] = 0; + cmd.safe_to_change_dma_fields = 1; // puVar5[-0x3a] = 1; + cmd.xfer_size = 0; // puVar5[-0xc] = 0; + cmd.unk_248 = 0; // puVar5[-0xb] = 0; + cmd.unk_260 = 0; // puVar5[-8] = 0; + cmd.unk_264 = 0x4000; // puVar5[-7] = 0x4000; + cmd.unk_268 = 0; // puVar5[-6] = 0; + cmd.header.callback_buffer = nullptr; // puVar5[-0x42] = 0; + cmd.header.unk_24 = 1; // puVar5[-0x43] = 1; + cmd.header.callback = NullCallback; // puVar5[-0x41] = NullCallback; + cmd.header.lse = nullptr; // puVar5[-0x40] = 0; + cmd.stereo_sibling = nullptr; // puVar5[-0x3d] = 0; + cmd.dma_iop_mem_ptr = nullptr; // puVar5[-0x3c] = 0; + cmd.dma_chan = -1; // puVar5[-0x3b] = 0xffffffff; + cmd.unk_256_pitch2 = 0; // puVar5[-9] = 0; + cmd.unk_296 = 0; // puVar5[1] = 0; + cmd.vec3.x = 0; // puVar5[2] = 0; + cmd.vec3.y = 0; // puVar5[3] = 0; + cmd.vec3.z = 0; // puVar5[4] = 0; + cmd.fo_min = 5; // puVar5[5] = 5; + cmd.fo_max = 0x1e; // puVar5[6] = 0x1e; + cmd.fo_curve = 1; // puVar5[7] = 1; + // puVar5[-0x2b] = *(undefined4*)(StreamSRAM + cmd_idx * 4); + cmd.spu_stream_dma_mem_addr = StreamSRAM[cmd_idx]; + // puVar5[-0x2a] = *(undefined4*)(TrapSRAM + cmd_idx * 4); + cmd.spu_trap_mem_addr = TrapSRAM[cmd_idx]; + // pRVar7 = pRVar7 + 1; + // puVar5[-0x28] = iVar6; + cmd.idx_in_cmd_arr = cmd_idx; + // iVar6 = iVar6 + 1; + cmd.file_record = nullptr; // puVar5[-0x3f] = 0; + cmd.vag_dir_entry = nullptr; // puVar5[-0x3e] = 0; + cmd.sb_playing = 0; // *(undefined*)((int)puVar5 + -0x53) = 0; + cmd.vol_multiplier = 0; // puVar5[-5] = 0; + cmd.unk_256_pitch2 = 0; // puVar5[-9] = 0; + cmd.id = 0; // puVar5[-4] = 0; + cmd.plugin_id = 0; // puVar5[-3] = 0; + cmd.unk_136 = 0; // puVar5[-0x27] = 0; + cmd.unk_176 = 0; // puVar5[-0x1d] = 0; + cmd.priority = 0; // puVar5[-2] = 0; + cmd.unk_288 = 0; // puVar5[-1] = 0; + cmd.unk_292 = 0; // *puVar5 = 0; + cmd.voice = StreamVoice[cmd_idx]; + // puVar5[-0x29] = uVar2; + // puVar5 = puVar5 + 0x51; + cmd_idx++; + } + + for (auto& entry : VagCmdsPriList) { + for (auto& c : entry.cmds) { + c = nullptr; + } + } + + for (auto& c : VagCmdsPriCounter) { + c = 0; + } + VagCmdsPriCounter[0] = 4; +} + +/*! + * Get a VagCmd from VagCmds for the given VagCmd. + */ +VagCmd* SmartAllocVagCmd(VagCmd* cmd) { + VagCmd* selected = nullptr; + + // first, just try looking for any free commands in the list. + for (auto& c : VagCmds) { + if (c.id == 0) { + // free! + selected = &c; + break; + } + } + + // next, try FindNotQueuedVagCmd + if (!selected) { + selected = FindNotQueuedVagCmd(); + } + + // next, try some existing ones. + if (!selected) { + int our_priority = cmd->priority; + + // if we have a nonzero priority, try taking over a lower priority command + if (our_priority) { + int check_priority = 0; + do { + // loop over other commands at this priority + int cmd_at_pri_idx = 0; + do { + auto* potential_cmd = VagCmdsPriList[check_priority].cmds[cmd_at_pri_idx]; + if (potential_cmd) { + // this part is a bit strange... as we iterate through lower priority commands, we + // immediately take the first one with byte11 set to 0. But if this isn't 0, we keep + // looking. This means that we won't take the lowest priority free command if they have + // nonzero BYTE11's. (this would make sense if BYTE11 was some exclusive "please don't + // interrupt me" bit) + selected = potential_cmd; + if (selected->status_bytes[VagCmdByte::BYTE11] == 0) { + // exit immediately + cmd_at_pri_idx = 4; + check_priority = cmd->priority; + } + } + cmd_at_pri_idx++; + } while (cmd_at_pri_idx < 4); + check_priority++; + } while (check_priority < our_priority); + } + } + + if (!selected) { + // failed. + return nullptr; + } + + ActiveVagStreams = ActiveVagStreams + 1; + if (ActiveVagStreams < 2) { + WakeSpuStreamsUp(); + } + return selected; +} + +void TerminateVAG(VagCmd* cmd, int param_2) { + int* piVar1; + int iVar2; + u32 uVar3; + VagCmd* pRVar4; + VagCmd* pRVar5; + VagStrListNode vag_node; + LfoListNode lfo_node; + // undefined4 auStack32 [2]; + + if (param_2 == 1) { + // CpuSuspendIntr(auStack32); + } + pRVar4 = cmd->stereo_sibling; + strncpy(vag_node.name, cmd->name, 0x30); + vag_node.id = cmd->id; + cmd->sb_scanned = '\0'; + if (cmd->status_bytes[BYTE5] != '\0') { + pRVar5 = cmd->stereo_sibling; + PauseVAG(cmd, 0); + if (cmd->status_bytes[BYTE5] != '\0') { + uVar3 = 1 << (cmd->voice >> 1 & 0x1fU); + if (pRVar5 != 0x0) { + uVar3 = uVar3 | 1 << (pRVar5->voice >> 1 & 0x1fU); + } + // sceSdSetSwitch(*(u16*)&cmd->voice & 1 | 0x1600, uVar3); + sceSdkey_off_jak2_voice(cmd->voice); + if (cmd->stereo_sibling) { + sceSdkey_off_jak2_voice(cmd->stereo_sibling->voice); + } + } + // iVar2 = 0x18; + // piVar1 = &(cmd->header).unk_24; + // do { + // *(undefined *)(piVar1 + 0x34) = 0; + // iVar2 = iVar2 + -1; + // piVar1 = (int *)((int)piVar1 + -1); + // } while (-1 < iVar2); + for (auto& x : cmd->status_bytes) { + x = 0; + } + cmd->vol_multiplier = 0; + cmd->unk_256_pitch2 = 0; + cmd->id = 0; + cmd->plugin_id = 0; + (cmd->header).unk_24 = 0; + cmd->unk_136 = 0; + cmd->unk_140 = 0; + cmd->pitch1 = 0; + (cmd->header).callback = NullCallback; + cmd->unk_180 = 0; + cmd->unk_184 = 0; + cmd->unk_188 = 0; + cmd->unk_192 = 0; + } + ReleaseMessage(&cmd->header, 0); + VagCmdsPriList[cmd->priority].cmds[cmd->idx_in_cmd_arr] = 0x0; + if (VagCmdsPriCounter[cmd->priority] < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: vag RemoveVagCmd: VagCmdsPriCounter[%d] is zero\n", cmd->priority); + printf("IOP: ======================================================================\n"); + } else { + VagCmdsPriCounter[cmd->priority] = VagCmdsPriCounter[cmd->priority] + -1; + } + // iVar2 = 0x18; + // piVar1 = &(cmd->header).unk_24; + VagCmdsPriCounter[0] = VagCmdsPriCounter[0] + 1; + for (auto& x : cmd->status_bytes) { + x = 0; + } + // do { + // *(undefined*)(piVar1 + 0x34) = 0; + // iVar2 = iVar2 + -1; + // piVar1 = (int*)((int)piVar1 + -1); + // } while (-1 < iVar2); + cmd->sb_playing = '\0'; + cmd->sb_paused = '\x01'; + cmd->sb_scanned = '\0'; + cmd->unk_180 = 0; + cmd->unk_184 = 0; + cmd->unk_188 = 0; + cmd->unk_192 = 0; + SetVagStreamName(cmd, 0, 0); + cmd->name[0] = '\0'; + iVar2 = ActiveVagStreams; + cmd->safe_to_change_dma_fields = 1; + cmd->unk_264 = 0x4000; + (cmd->header).callback = NullCallback; + cmd->unk_140 = 0; + cmd->pitch1 = 0; + cmd->file_record = nullptr; + cmd->vag_dir_entry = nullptr; + cmd->unk_196 = 0; + cmd->unk_200 = 0; + cmd->unk_204 = 0; + cmd->num_processed_chunks = 0; + cmd->xfer_size = 0; + cmd->unk_248 = 0; + cmd->unk_260 = 0; + cmd->unk_268 = 0; + cmd->vol_multiplier = 0; + cmd->unk_256_pitch2 = 0; + cmd->id = 0; + cmd->plugin_id = 0; + cmd->unk_136 = 0; + cmd->priority = 0; + cmd->unk_288 = 0; + cmd->unk_292 = 0; + cmd->unk_296 = 0; + (cmd->header).callback_buffer = (Buffer*)0x0; + (cmd->header).unk_24 = 0; + (cmd->header).lse = (LoadStackEntry*)0x0; + cmd->dma_iop_mem_ptr = (uint8_t*)0x0; + cmd->dma_chan = -1; + cmd->unk_236 = 0; + if (0 < iVar2) { + ActiveVagStreams = iVar2 + -1; + } + if (pRVar4 != 0x0) { + pRVar4->sb_scanned = '\0'; + VagCmdsPriList[pRVar4->priority].cmds[pRVar4->idx_in_cmd_arr] = 0x0; + if (VagCmdsPriCounter[pRVar4->priority] < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: vag RemoveVagCmd: VagCmdsPriCounter[%d] is zero\n", pRVar4->priority); + printf("IOP: ======================================================================\n"); + } else { + VagCmdsPriCounter[pRVar4->priority] = VagCmdsPriCounter[pRVar4->priority] + -1; + } + iVar2 = 0x18; + piVar1 = &(pRVar4->header).unk_24; + VagCmdsPriCounter[0] = VagCmdsPriCounter[0] + 1; + for (auto& x : cmd->status_bytes) { + x = 0; + } + // do { + // *(undefined*)(piVar1 + 0x34) = 0; + // iVar2 = iVar2 + -1; + // piVar1 = (int*)((int)piVar1 + -1); + // } while (-1 < iVar2); + pRVar4->sb_playing = '\0'; + pRVar4->sb_paused = '\x01'; + pRVar4->sb_scanned = '\0'; + pRVar4->unk_180 = 0; + pRVar4->unk_184 = 0; + pRVar4->unk_188 = 0; + pRVar4->unk_192 = 0; + SetVagStreamName(pRVar4, 0, 0); + pRVar4->name[0] = '\0'; + iVar2 = ActiveVagStreams; + pRVar4->safe_to_change_dma_fields = 1; + pRVar4->unk_264 = 0x4000; + (pRVar4->header).callback = NullCallback; + pRVar4->unk_140 = 0; + pRVar4->pitch1 = 0; + pRVar4->file_record = nullptr; + pRVar4->vag_dir_entry = nullptr; + pRVar4->unk_196 = 0; + pRVar4->unk_200 = 0; + pRVar4->unk_204 = 0; + pRVar4->num_processed_chunks = 0; + pRVar4->xfer_size = 0; + pRVar4->unk_248 = 0; + pRVar4->unk_260 = 0; + pRVar4->unk_268 = 0; + pRVar4->vol_multiplier = 0; + pRVar4->unk_256_pitch2 = 0; + pRVar4->id = 0; + pRVar4->plugin_id = 0; + pRVar4->unk_136 = 0; + pRVar4->priority = 0; + pRVar4->unk_288 = 0; + pRVar4->unk_292 = 0; + pRVar4->unk_296 = 0; + (pRVar4->header).callback_buffer = (Buffer*)0x0; + (pRVar4->header).unk_24 = 0; + (pRVar4->header).lse = (LoadStackEntry*)0x0; + pRVar4->dma_iop_mem_ptr = (uint8_t*)0x0; + pRVar4->dma_chan = -1; + pRVar4->unk_236 = 0; + if (0 < iVar2) { + ActiveVagStreams = iVar2 + -1; + } + } + if (cmd->unk_136) { + RemoveVagStreamFromList(&vag_node, &PluginStreamsList); + lfo_node.id = cmd->id; + lfo_node.plugin_id = cmd->plugin_id; + RemoveLfoStreamFromList(&lfo_node, &LfoList); + } + printf("termina removing %s (2)\n", vag_node.name); + + RemoveVagStreamFromList(&vag_node, &EEPlayList); + if (param_2 == 1) { + // CpuResumeIntr(auStack32[0]); + } + // return; +} + +void PauseVAG(VagCmd* cmd, int /*param_2*/) { + if (!cmd->sb_paused) { + // if (param_2 == 1) { + // CpuSuspendIntr(local_20); + // } + if (cmd->status_bytes[BYTE11] == '\0') { + auto* stereo_cmd = cmd->stereo_sibling; + if (!stereo_cmd) { + if (cmd->sb_playing != '\0') { + sceSdSetParam((u16)cmd->voice | SD_VP_VOLL, 0); + sceSdSetParam(((u16)cmd->voice) | SD_VP_VOLR, 0); + } + sceSdSetParam(((u16)cmd->voice) | SD_VP_PITCH, 0); + // TODO: ignored, whatever this is + // sceSdSetSwitch((((s16)cmd->voice) & 1) | 0x1600, 1 << (cmd->voice >> 1 & 0x1fU)); + sceSdkey_off_jak2_voice(cmd->voice); + if (cmd->status_bytes[BYTE5] == '\0') { + cmd->spu_addr_to_start_playing = 0; + } else { + cmd->spu_addr_to_start_playing = GetSpuRamAddress(cmd); + } + cmd->sb_paused = 1; + } else { + if (cmd->sb_playing != '\0') { + sceSdSetParam(((u16)cmd->voice) | SD_VP_VOLL, 0); + sceSdSetParam(((u16)cmd->voice) | SD_VP_VOLR, 0); + sceSdSetParam(((u16)stereo_cmd->voice) | SD_VP_VOLL, 0); + sceSdSetParam(((u16)stereo_cmd->voice) | SD_VP_VOLR, 0); + } + sceSdSetParam(((u16)stereo_cmd->voice) | SD_VP_PITCH, 0); + sceSdSetParam(((u16)cmd->voice) | SD_VP_PITCH, 0); + // sceSdSetSwitch(((u16)cmd->voice & 1) | 0x1600, + // 1 << (cmd->voice >> 1 & 0x1fU) | 1 << (stereo_cmd->voice >> 1 & 0x1fU)); + sceSdkey_off_jak2_voice(cmd->voice); + sceSdkey_off_jak2_voice(stereo_cmd->voice); + + if (cmd->status_bytes[BYTE5] == '\0') { + cmd->spu_addr_to_start_playing = 0; + stereo_cmd->spu_addr_to_start_playing = 0; + } else { + int ram_addr = GetSpuRamAddress(cmd); + cmd->spu_addr_to_start_playing = ram_addr & 0xfffffff8; + stereo_cmd->spu_addr_to_start_playing = + ((ram_addr & 0xfffffff8) - cmd->spu_stream_dma_mem_addr) + + stereo_cmd->spu_stream_dma_mem_addr; + } + cmd->sb_paused = 1; + stereo_cmd->sb_paused = 1; + } + } + // if (param_2 == 1) { + // CpuResumeIntr(local_20[0]); + //} + } +} + +void UnPauseVAG(VagCmd* param_1, int /*param_2*/) { + if (param_1->sb_paused) { + // if (param_2 == 1) { + // CpuSuspendIntr(&local_30); + //} + if (param_1->status_bytes[BYTE11] == '\0') { + auto* stereo_cmd = param_1->stereo_sibling; + int pitch_reuslt = CalculateVAGPitch(param_1->pitch1, param_1->unk_256_pitch2); + int vol_l, vol_r; + CalculateVAGVolumes(param_1, &vol_l, &vol_r); + if (!stereo_cmd) { + if (param_1->sb_playing != '\0') { + sceSdSetParam(((u16)param_1->voice) | 0x200, pitch_reuslt); + if (param_1->spu_addr_to_start_playing != 0) { + sceSdSetAddr(((u16)param_1->voice) | 0x2040, param_1->spu_addr_to_start_playing); + } + // sceSdSetSwitch(((u16)param_1->voice & 1) | 0x1500, 1 << (voice >> 1 & 0x1fU)); + sceSdkey_on_jak2_voice(param_1->voice); + sceSdSetParam(((u16)param_1->voice), vol_l); + sceSdSetParam(((u16)param_1->voice) | 0x100, vol_r); + } + param_1->sb_paused = 0; + } else { + if (param_1->sb_playing != '\0') { + sceSdSetParam(((u16)param_1->voice) | 0x200, pitch_reuslt); + sceSdSetParam(((u16)stereo_cmd->voice) | 0x200, pitch_reuslt); + if (param_1->spu_addr_to_start_playing != 0) { + sceSdSetAddr(((u16)param_1->voice) | 0x2040, param_1->spu_addr_to_start_playing); + sceSdSetAddr(((u16)stereo_cmd->voice) | 0x2040, stereo_cmd->spu_addr_to_start_playing); + } + sceSdkey_on_jak2_voice(param_1->voice); + sceSdkey_on_jak2_voice(stereo_cmd->voice); + + // sceSdSetSwitch(((u16)param_1->voice & 1) | 0x1500, + // 1 << (voice >> 1 & 0x1fU) | 1 << (stereo_voice >> 1 & 0x1fU)); + sceSdSetParam(((u16)param_1->voice), vol_l); + sceSdSetParam(((u16)stereo_cmd->voice), 0); + sceSdSetParam(((u16)param_1->voice) | 0x100, 0); + sceSdSetParam(((u16)stereo_cmd->voice) | 0x100, vol_r); + } + param_1->sb_paused = 0; + stereo_cmd->sb_paused = 0; + } + } + // if (param_2 == 1) { + // CpuResumeIntr(local_30); + //} + } +} + +void RestartVag(VagCmd* param_1, int param_2, int /*param_3*/) { + // u16 uVar1; + // int iVar2; + // RealVagCmd *stereo_sibling; + // u32 uVar4; + // int iVar5; + // undefined4 local_30; + // undefined2 local_2c [2]; + // undefined2 local_28 [4]; + + // if (param_3 == 1) { + // CpuSuspendIntr(&local_30); + //} + int vol_l, vol_r; + CalculateVAGVolumes(param_1, &vol_l, &vol_r); + if (param_1->status_bytes[BYTE11] == '\0') { + int voice = 1 << (param_1->voice >> 1 & 0x1fU); + auto* stereo_sibling = param_1->stereo_sibling; + int sram_offset = param_2 ? 0x2000 : 0; + if (stereo_sibling) { + voice = voice | 1 << (stereo_sibling->voice >> 1 & 0x1fU); + } + // sceSdSetSwitch(((u16)param_1->voice & 1) | 0x1600, voice); + sceSdkey_off_jak2_voice(param_1->voice); + if (stereo_sibling) { + sceSdkey_off_jak2_voice(stereo_sibling->voice); + } + sceSdSetParam(((u16)param_1->voice), 0); + sceSdSetParam(((u16)param_1->voice) | 0x100, 0); + + int other_voice; + int sram_addr; + if (!stereo_sibling) { + other_voice = *(u16*)¶m_1->voice; + sram_addr = param_1->spu_stream_dma_mem_addr; + } else { + sceSdSetParam(((u16)stereo_sibling->voice), 0); + sceSdSetParam(((u16)stereo_sibling->voice) | 0x100, 0); + sceSdSetAddr(((u16)param_1->voice) | 0x2040, param_1->spu_stream_dma_mem_addr + sram_offset); + other_voice = ((u16)stereo_sibling->voice); + sram_addr = stereo_sibling->spu_stream_dma_mem_addr; + } + sceSdSetAddr(other_voice | 0x2040, sram_addr + sram_offset); + // sceSdSetSwitch(((u16)param_1->voice & 1) | 0x1500, voice); + sceSdkey_on_jak2_voice(param_1->voice); + if (stereo_sibling) { + sceSdkey_on_jak2_voice(stereo_sibling->voice); + } + + if (!stereo_sibling) { + sceSdSetParam(((u16)param_1->voice), vol_l); + other_voice = ((u16)param_1->voice); + } else { + sceSdSetParam(((u16)param_1->voice), vol_l); + sceSdSetParam(((u16)stereo_sibling->voice), 0); + sceSdSetParam(((u16)param_1->voice) | 0x100, 0); + other_voice = ((u16)stereo_sibling->voice); + } + sceSdSetParam(other_voice | 0x100, vol_r); + } + // if (param_3 == 1) { + // CpuResumeIntr(local_30); + //} +} + +struct sceSdBatch { + u32 entry; + u32 value; + u32 func; +}; + +void sceSdProcBatch(sceSdBatch* b, int, int n) { + for (int i = 0; i < n; i++) { + sceSdSetParam(b[i].entry, b[i].value); + } +} + +void SetVAGVol(VagCmd* cmd, int param_2) { + u32 uVar1; + u32 uVar3; + int iVar4; + int iVar5; + VagCmd* stereo_cmd; + sceSdBatch batch[6]; + u32 local_28; + u32 local_24; + // undefined4 local_20 [2]; + + if (cmd == 0x0) { + return; + } + if (cmd->byte4 == '\0') { + return; + } + if (cmd->sb_paused != '\0') { + return; + } + if (cmd->byte11 != '\0') { + return; + } + auto pvVar2 = cmd->unk_136; + stereo_cmd = cmd->stereo_sibling; + if (pvVar2 == 0) { + if (cmd->unk_296 == 0) { + local_28 = (u32)(cmd->vol_multiplier * MasterVolume[2]) >> 6; + local_24 = local_28; + if (0x3fff < local_28) { + local_28 = 0x3fff; + local_24 = local_28; + } + goto LAB_0000a258; + } + iVar4 = CalculateFallofVolume(&cmd->vec3, (u32)(cmd->vol_multiplier * MasterVolume[2]) >> 10, + cmd->fo_curve, cmd->fo_min, cmd->fo_max); + iVar5 = CalculateAngle(&cmd->vec3); + uVar3 = 0x276 - iVar5; + uVar1 = (uVar3 >> 3) / 0x2d; + local_28 = ((s16*)gPanTable)[uVar1 * -0x2d0 + uVar3 * 2] * iVar4; + local_24 = ((s16*)gPanTable)[uVar1 * -0x2d0 + uVar3 * 2 + 1] * iVar4; + } else { + ASSERT_NOT_REACHED(); + // uVar3 = cmd->unk_176 + 0x5a; + // uVar1 = (uVar3 >> 3) / 0x2d; + // local_24 = (((u32)(cmd->vol_multiplier * MasterVolume[*(char *)((int)pvVar2 + 0x17)]) >> + // 10) * + // (int)*(short *)((int)pvVar2 + 0x10) >> 10) * 0x3fff >> 10; + // local_28 = (int)gPanTable[uVar1 * -0x2d0 + uVar3 * 2] * local_24; + // local_24 = (int)gPanTable[uVar1 * -0x2d0 + uVar3 * 2 + 1] * local_24; + } + local_28 = local_28 >> 10; + local_24 = local_24 >> 10; + if (0x3fff < local_28) { + local_28 = 0x3fff; + } + if (0x3fff < local_24) { + local_24 = 0x3fff; + } +LAB_0000a258: + if (stereo_cmd == (VagCmd*)0x0) { + batch[0].entry = *(uint16_t*)&cmd->voice; + iVar4 = 2; + batch[1].entry = *(u16*)&cmd->voice | 0x100; + batch[2].entry = *(u16*)&cmd->voice | 0x200; + iVar5 = cmd->unk_256_pitch2; + uVar1 = cmd->pitch1; + // printf("cmd's pitch is %d, %d\n", cmd->pitch1, cmd->unk_256_pitch2); + batch[1].value = local_24; + } else { + batch[0].entry = *(uint16_t*)&cmd->voice; + batch[1].entry = *(uint16_t*)&stereo_cmd->voice; + batch[1].value = 0; + batch[2].value = 0; + batch[2].entry = *(u16*)&cmd->voice | 0x100; + batch[3].func = 1; + batch[3].entry = *(u16*)&stereo_cmd->voice | 0x100; + batch[4].func = 1; + batch[4].entry = *(u16*)&cmd->voice | 0x200; + iVar4 = cmd->unk_256_pitch2; + batch[4].value = cmd->pitch1; + if (iVar4 != 0) { + if (iVar4 < 1) { + batch[4].value = (u32)(batch[4].value * 0x5f4) / (0x5f4U - iVar4); + if (0x5f4U - iVar4 == 0) { + ASSERT_NOT_REACHED(); + // trap(0x1c00); + } + } else { + batch[4].value = (u32)(batch[4].value * (iVar4 + 0x5f4)) / 0x5f4; + } + } + iVar4 = 5; + batch[5].func = 1; + batch[5].entry = *(u16*)&stereo_cmd->voice | 0x200; + iVar5 = cmd->unk_256_pitch2; + uVar1 = cmd->pitch1; + batch[3].value = local_24; + } + if (iVar5 != 0) { + if (iVar5 < 1) { + uVar1 = (uVar1 * 0x5f4) / (0x5f4U - iVar5); + if (0x5f4U - iVar5 == 0) { + ASSERT_NOT_REACHED(); + // trap(0x1c00); + } + } else { + uVar1 = (uVar1 * (iVar5 + 0x5f4)) / 0x5f4; + } + } + batch[2].func = 1; + batch[1].func = 1; + batch[0].value = local_28; + batch[0].func = 1; + batch[iVar4].value = uVar1; + if (param_2 == 1) { + // CpuSuspendIntr(local_20); + sceSdProcBatch(batch, 0, iVar4 + 1); + // CpuResumeIntr(local_20[0]); + } else { + sceSdProcBatch(batch, 0, iVar4 + 1); + } +} + +void SetVagStreamsNoStart(int param_1, int /*param_2*/) { + // if (param_2 == 1) { + // CpuSuspendIntr(local_18); + //} + // pRVar2 = VagCmds; + for (auto& cmd : VagCmds) { + cmd.status_bytes[VagCmdByte::BYTE23_NOSTART] = param_1; + } + // if (param_2 == 1) { + // CpuResumeIntr(local_18[0]); + //} +} + +void InitVAGCmd(VagCmd* param_1, int param_2) { + for (auto& x : param_1->status_bytes) { + x = 0; + } + param_1->unk_236 = 0; + param_1->unk_140 = 0; + param_1->sb_paused = param_2 ? 1 : 0; + param_1->unk_264 = 0x4000; + (param_1->header).callback = NullCallback; + param_1->dma_chan = -1; + param_1->fo_min = 5; + param_1->unk_196 = 0; + param_1->unk_200 = 0; + param_1->unk_204 = 0; + param_1->unk_180 = 0; + param_1->unk_184 = 0; + param_1->unk_188 = 0; + param_1->unk_192 = 0; + param_1->status_bytes[VagCmdByte::BYTE5] = '\0'; + param_1->status_bytes[VagCmdByte::BYTE5] = '\0'; + param_1->num_processed_chunks = 0; + param_1->safe_to_change_dma_fields = 1; + param_1->xfer_size = 0; + param_1->unk_248 = 0; + param_1->unk_260 = 0; + param_1->unk_268 = 0; + (param_1->header).callback_buffer = nullptr; + (param_1->header).unk_24 = 1; + (param_1->header).lse = nullptr; + param_1->stereo_sibling = nullptr; + param_1->dma_iop_mem_ptr = nullptr; + param_1->unk_256_pitch2 = 0; + param_1->unk_296 = 0; + param_1->vec3.x = 0; + param_1->vec3.y = 0; + param_1->vec3.z = 0; + param_1->fo_max = 0x1e; + param_1->fo_curve = 1; +} + +void SetVagStreamsNotScanned() { + for (auto& cmd : VagCmds) { + cmd.sb_scanned = 0; + } +} + +void RemoveVagCmd(VagCmd* cmd, int /*param_2*/) { + // if (param_2 == 1) { + // CpuSuspendIntr(local_18); + //} + VagCmdsPriList[cmd->priority].cmds[cmd->idx_in_cmd_arr] = nullptr; + if (VagCmdsPriCounter[cmd->priority] < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: vag RemoveVagCmd: VagCmdsPriCounter[%d] is zero\n", cmd->priority); + printf("IOP: ======================================================================\n"); + } else { + VagCmdsPriCounter[cmd->priority]--; + } + VagCmdsPriCounter[0]++; + // if (param_2 == 1) { + // CpuResumeIntr(local_18[0]); + //} +} + +VagCmd* FindFreeVagCmd() { + for (auto& cmd : VagCmds) { + if (cmd.id == 0) { + return &cmd; + } + } + return nullptr; +} + +VagCmd* FindNotQueuedVagCmd() { + for (auto& cmd : VagCmds) { + if (!cmd.sb_scanned && !cmd.status_bytes[BYTE11] && !cmd.status_bytes[BYTE4]) { + return &cmd; + } + } + return nullptr; +} + +VagCmd* FindWhosPlaying() { + for (auto& cmd : VagCmds) { + if (!cmd.sb_paused && cmd.sb_playing) { + return &cmd; + } + } + return nullptr; +} + +VagCmd* FindVagStreamId(int id) { + if (id) { + for (auto& cmd : VagCmds) { + if (cmd.id == id) { + return &cmd; + } + } + } + return nullptr; +} + +VagCmd* FindVagStreamPluginId(int plugin_id) { + if (plugin_id) { + for (auto& cmd : VagCmds) { + if (cmd.plugin_id == plugin_id) { + return &cmd; + } + } + } + return nullptr; +} + +VagCmd* FindVagStreamName(const char* name) { + for (auto& cmd : VagCmds) { + if (strcmp(cmd.name, name) == 0) { + return &cmd; + } + } + return nullptr; +} + +/*! + * Check the global VagCmds array for an existing command with this name or ID. + */ +VagCmd* FindThisVagStream(const char* name, int id) { + for (auto& cmd : VagCmds) { + if (strcmp(cmd.name, name) == 0 && cmd.id == id) { + return &cmd; + } + } + return nullptr; +} + +int AnyVagRunning() { + int cnt = 0; + for (auto& cmd : VagCmds) { + if (cmd.status_bytes[BYTE4]) { + cnt++; + } + } + return cnt; +} + +void FreeVagCmd(VagCmd* cmd, int /*param_2*/) { + // if (param_2 == 1) { + // CpuSuspendIntr(local_18); + //} + for (auto& x : cmd->status_bytes) { + x = 0; + } + cmd->sb_playing = '\0'; + cmd->sb_paused = 1; + cmd->sb_scanned = '\0'; + cmd->unk_180 = 0; + cmd->unk_184 = 0; + cmd->unk_188 = 0; + cmd->unk_192 = 0; + SetVagStreamName(cmd, 0, 0); + cmd->name[0] = '\0'; + cmd->unk_264 = 0x4000; + (cmd->header).callback = NullCallback; + cmd->unk_140 = 0; + cmd->pitch1 = 0; + cmd->file_record = nullptr; + cmd->vag_dir_entry = nullptr; + cmd->unk_196 = 0; + cmd->unk_200 = 0; + cmd->unk_204 = 0; + cmd->num_processed_chunks = 0; + cmd->safe_to_change_dma_fields = 1; + cmd->xfer_size = 0; + cmd->unk_248 = 0; + cmd->unk_260 = 0; + cmd->unk_268 = 0; + cmd->vol_multiplier = 0; + cmd->unk_256_pitch2 = 0; + cmd->id = 0; + cmd->plugin_id = 0; + cmd->unk_136 = 0; + cmd->priority = 0; + cmd->unk_288 = 0; + cmd->unk_292 = 0; + cmd->unk_296 = 0; + (cmd->header).callback_buffer = nullptr; + (cmd->header).unk_24 = 0; + (cmd->header).lse = nullptr; + cmd->dma_iop_mem_ptr = (uint8_t*)0x0; + cmd->dma_chan = -1; + cmd->unk_236 = 0; + if (0 < ActiveVagStreams) { + ActiveVagStreams--; + } + // if (param_2 == 1) { + // CpuResumeIntr(local_18[0]); + //} +} + +void SetNewVagCmdPri(VagCmd* cmd, int new_pri, int /*param_3*/) { + // if (param_3 == 1) { + // CpuSuspendIntr(local_20); + //} + if (cmd) { + VagCmdsPriList[cmd->priority].cmds[cmd->idx_in_cmd_arr] = nullptr; + if (VagCmdsPriCounter[cmd->priority] < 1) { + printf("IOP: ======================================================================\n"); + printf("IOP: vag SetNewVagCmdPri: VagCmdsPriCounter[%d] is zero\n", cmd->priority); + printf("IOP: ======================================================================\n"); + } else { + VagCmdsPriCounter[cmd->priority]--; + } + VagCmdsPriList[new_pri].cmds[cmd->idx_in_cmd_arr] = cmd; + VagCmdsPriCounter[new_pri]++; + cmd->priority = new_pri; + } + // if (param_3 == 1) { + // CpuResumeIntr(local_20[0]); + //} +} + +int HowManyBelowThisPriority(int pri, int /*disable_intr*/) { + int cnt = 0; + for (int p = 0; p < pri; p++) { + cnt += VagCmdsPriCounter[p]; + } + return cnt; +} + +void StopVAG(VagCmd* cmd, int /*param_2*/) { + // int *piVar1; + // int iVar2; + // u32 uVar3; + // RealVagCmd *sibling; + // undefined4 local_20 [2]; + + // if (param_2 == 1) { + // CpuSuspendIntr(local_20); + //} + auto& sibling = cmd->stereo_sibling; + PauseVAG(cmd, 0); + if (cmd->status_bytes[BYTE5] != '\0') { + int val = 1 << (cmd->voice >> 1 & 0x1fU); + if (sibling) { + val = val | 1 << (sibling->voice >> 1 & 0x1fU); + } + // sceSdSetSwitch(u16(cmd->voice) & 1 | 0x1600, val); + sceSdkey_off_jak2_voice(cmd->voice); + if (sibling) { + sceSdkey_off_jak2_voice(sibling->voice); + } + } + for (auto& x : cmd->status_bytes) { + x = 0; + } + (cmd->header).callback = NullCallback; + cmd->vol_multiplier = 0; + cmd->unk_256_pitch2 = 0; + cmd->id = 0; + cmd->plugin_id = 0; + (cmd->header).unk_24 = 0; + cmd->unk_136 = 0; + cmd->unk_140 = 0; + cmd->pitch1 = 0; + cmd->unk_180 = 0; + cmd->unk_184 = 0; + cmd->unk_188 = 0; + cmd->unk_192 = 0; + // if (param_2 == 1) { + // CpuResumeIntr(local_20[0]); + //} +} + +void VAG_MarkLoopEnd(int8_t* data, int offset) { + data[offset + -0xf] = '\x03'; +} + +void VAG_MarkLoopStart(int8_t* param_1) { + param_1[1] = 6; + param_1[0x11] = 2; +} + +int CalculateVAGPitch(int param_1, int param_2) { + if (param_2 != 0) { + if (param_2 < 1) { + param_1 = (param_1 * 0x5f4) / (0x5f4U - param_2); + if (0x5f4U - param_2 == 0) { + ASSERT_NOT_REACHED(); + } + } else { + param_1 = (param_1 * (param_2 + 0x5f4)) / 0x5f4; + } + } + return param_1; +} + +void PauseVagStreams() { + for (auto& cmd : VagCmds) { + if (cmd.status_bytes[BYTE4] && !cmd.sb_paused) { + PauseVAG(&cmd, 1); + } + } +} + +void UnPauseVagStreams() { + for (auto& cmd : VagCmds) { + if (cmd.status_bytes[BYTE4] && cmd.sb_paused) { + UnPauseVAG(&cmd, 1); + } + } +} + +void SetAllVagsVol(int param_1) + +{ + int iVar1; + VagCmd* cmd; + + cmd = VagCmds; + if (param_1 < 0) { + iVar1 = 0; + do { + SetVAGVol(cmd, 1); + iVar1 = iVar1 + 1; + cmd = cmd + 1; + } while (iVar1 < 4); + } else { + iVar1 = 0; + do { + if (cmd->unk_136) { + ASSERT_NOT_REACHED(); + // if (*(char *)((int)cmd->unk_136 + 0x17) == param_1) { + // SetVAGVol(cmd,1); + // } + cmd = cmd + 1; + } + iVar1 = iVar1 + 1; + } while (iVar1 < 4); + } + return; +} + +void CalculateVAGVolumes(VagCmd* cmd, int* l_out, int* r_out) { + // int iVar1; + // int iVar2; + // u32 uVar3; + + if (cmd->unk_296 == 0) { + u32 vol = (u32)(cmd->vol_multiplier * MasterVolume[VolumeCategory::DIALOGUE]) >> 6; + if (0x3fff < vol) { + vol = 0x3fff; + } + *l_out = vol; + *r_out = vol; + } else { + int fo_vol = + CalculateFallofVolume(&cmd->vec3, (u32)(cmd->vol_multiplier * MasterVolume[2]) >> 10, + cmd->fo_curve, cmd->fo_min, cmd->fo_max); + int angle = CalculateAngle(&cmd->vec3); + int uVar4 = 0x276 - angle; + int uVar3 = (uVar4 >> 3) / 0x2d; + auto* pan = (s16*)gPanTable; + *l_out = (u32)(pan[uVar3 * -0x2d0 + uVar4 * 2] * fo_vol) >> 10; + *r_out = (u32)(pan[uVar3 * -0x2d0 + uVar4 * 2 + 1] * fo_vol) >> 10; + if (0x3fff < *l_out) { + *l_out = 0x3fff; + } + if (0x3fff < *r_out) { + *r_out = 0x3fff; + } + } +} + +} // namespace jak2 diff --git a/game/overlord/jak2/vag.h b/game/overlord/jak2/vag.h new file mode 100644 index 0000000000..2ac502271c --- /dev/null +++ b/game/overlord/jak2/vag.h @@ -0,0 +1,145 @@ +#pragma once + +#include "common/common_types.h" + +#include "game/overlord/common/iso.h" +#include "game/overlord/common/ssound.h" +#include "game/overlord/jak2/iso.h" +#include "game/overlord/jak2/list.h" + +namespace jak2 { + +enum VagCmdByte { + // BYTE1 = 1, // init to 0 (playing?) + // PAUSED = 2, // init to 1 (paused?) + BYTE4 = 4, // streaming? + BYTE5 = 5, // init to 0 (maybe something to do with setting sdsetswitch stuff. + BYTE6 = 6, // init to 0 + // 8 + // 9 + BYTE10 = 10, // 10 + BYTE11 = 11, // try not to interrupt this one with SmartAllocVagCmd. + // 12 + // 13 + // 14 + // 15 + BYTE23_NOSTART = 23, // start?? +}; + +struct VagCmd { + CmdHeader header; // 0 to ?? + FileRecord* file_record; // 40 + VagDirEntry* vag_dir_entry; // 44 + VagCmd* stereo_sibling; // 48 + u8* dma_iop_mem_ptr; // 52 + int dma_chan; // 56 - which spu dma channel to use. Not needed for PC. + int safe_to_change_dma_fields; // 60 - set to 0 when DMA is processing data from this command. + int spu_addr_to_start_playing; // 64 - address to use when starting stream. + char name[48]; // 68 + int spu_stream_dma_mem_addr; // 120 - address we should DMA to (or just DMA'd to) + int spu_trap_mem_addr; // 124 + int voice; // 128 + int idx_in_cmd_arr; // 132 (index in VagCmds) + int unk_136; // 136 + int unk_140; // 140 + int unk_176; // 176 + int unk_180; // 180 + int unk_184; // 184 + int unk_188; // 188 + int unk_192; // 192 pitch ramping stuff maybe + int unk_196; // 196 + int unk_200; // 200 pos + int unk_204; // 204 + union { + u8 status_bytes[24]; // 208 + struct { + u8 byte0; + u8 sb_playing; + u8 sb_paused; + u8 byte3; + u8 byte4; + u8 byte5; + u8 byte6; + u8 sb_scanned; + u8 byte8; + u8 byte9; + u8 byte10; + u8 byte11; + u8 byte12; + u8 byte13; + u8 byte14; + u8 byte15; + u8 byte16; + u8 byte17; + u8 sb_odd_buffer_dma_complete; + u8 sb_even_buffer_dma_complete; // set when even buffer's spu dma finishes + u8 byte20; + u8 byte21; + u8 byte22; + u8 byte23; + }; + }; + u8 unk_232; // 232 wtf is this + int unk_236; // 236 + int num_processed_chunks; // 240 (where "processed" means that they were added to dma command) + int xfer_size; // 244 + int unk_248; // 248 + int pitch1; // 252 + int unk_256_pitch2; // 256 + int unk_260; // 260 + int unk_264; // 264 (init to 0x4000) + int unk_268; // 268 + int vol_multiplier; // 272 + int id; // 276 + int plugin_id; // 280 + int priority; // 284 + int unk_288; // 288 + int unk_292; // 292 + int unk_296; // 296 + Vec3w vec3; // 300 + int fo_min; // 312 (init to 5) + int fo_max; // 316 (init to 316) + int fo_curve; // 320 (init to 1) +}; + +struct VagCmdPriListEntry { + VagCmd* cmds[4]; +}; + +constexpr int N_VAG_CMDS = 4; +extern VagCmd VagCmds[N_VAG_CMDS]; +extern int StreamSRAM[N_VAG_CMDS]; +extern int TrapSRAM[N_VAG_CMDS]; +extern int StreamVoice[N_VAG_CMDS]; + +extern int ActiveVagStreams; +extern int MasterVolume[17]; + +void vag_init_globals(); + +VagCmd* FindThisVagStream(const char* name, int id); +VagCmd* FindNotQueuedVagCmd(); +int CalculateVAGPitch(int param_1, int param_2); +void UnPauseVAG(VagCmd* param_1, int param_2); +int HowManyBelowThisPriority(int pri, int disable_intr); +VagCmd* SmartAllocVagCmd(VagCmd* cmd); +void InitVAGCmd(VagCmd* param_1, int param_2); +void RemoveVagCmd(VagCmd* cmd, int param_2); +void FreeVagCmd(VagCmd* cmd, int param_2); +void SetNewVagCmdPri(VagCmd* cmd, int new_pri, int param_3); +VagCmd* FindVagStreamName(const char* name); +void TerminateVAG(VagCmd* cmd, int param_2); +void PauseVAG(VagCmd* cmd, int param_2); +int AnyVagRunning(); +void InitVagCmds(); +void VAG_MarkLoopEnd(int8_t* data, int offset); +void VAG_MarkLoopStart(int8_t* param_1); +void RestartVag(VagCmd* param_1, int param_2, int param_3); +void SetVagStreamsNoStart(int param_1, int param_2); +void PauseVagStreams(); +void UnPauseVagStreams(); +VagCmd* FindVagStreamId(int id); +void SetVAGVol(VagCmd* cmd, int param_2); +void SetAllVagsVol(int vol); +void SetVagStreamsNotScanned(); +} // namespace jak2 \ No newline at end of file diff --git a/game/overlord/srpc.h b/game/overlord/srpc.h deleted file mode 100644 index f5b2ff38c9..0000000000 --- a/game/overlord/srpc.h +++ /dev/null @@ -1,258 +0,0 @@ -#pragma once - -#include "ssound.h" - -#include "common/common_types.h" - -void srpc_init_globals(); - -extern const char* gLanguage; -extern s32 gVAG_Id; - -constexpr int MUSIC_TWEAK_COUNT = 32; - -struct MusicTweaks { - u32 TweakCount; - - struct { - char MusicName[12]; - s32 VolumeAdjust; - } MusicTweak[MUSIC_TWEAK_COUNT]; -}; - -enum class Jak1SoundCommand : u16 { - LOAD_BANK = 0, - LOAD_MUSIC = 1, - UNLOAD_BANK = 2, - PLAY = 3, - PAUSE_SOUND = 4, - STOP_SOUND = 5, - CONTINUE_SOUND = 6, - SET_PARAM = 7, - SET_MASTER_VOLUME = 8, - PAUSE_GROUP = 9, - STOP_GROUP = 10, - CONTINUE_GROUP = 11, - GET_IRX_VERSION = 12, - SET_FALLOFF_CURVE = 13, - SET_SOUND_FALLOFF = 14, - RELOAD_INFO = 15, - SET_LANGUAGE = 16, - SET_FLAVA = 17, - SET_REVERB = 18, - SET_EAR_TRANS = 19, - SHUTDOWN = 20, - LIST_SOUNDS = 21, - UNLOAD_MUSIC = 22, - MIRROR_MODE = 201, -}; - -enum class Jak2SoundCommand : u16 { - iop_store = 0, - iop_free = 1, - load_bank = 2, - load_bank_from_iop = 3, - load_bank_from_ee = 4, - load_music = 5, - unload_bank = 6, - play = 7, - pause_sound = 8, - stop_sound = 9, - continue_sound = 10, - set_param = 11, - set_master_volume = 12, - pause_group = 13, - stop_group = 14, - continue_group = 15, - get_irx_version = 16, - set_falloff_curve = 17, - set_sound_falloff = 18, - reload_info = 19, - set_language = 20, - set_flava = 21, - set_midi_reg = 22, - set_reverb = 23, - set_ear_trans = 24, - shutdown = 25, - list_sounds = 26, - unload_music = 27, - set_fps = 28, - boot_load = 29, - game_load = 30, - num_tests = 31, - num_testruns = 32, - num_sectors = 33, - num_streamsectors = 34, - num_streambanks = 35, - track_pitch = 36, - linvel_nom = 37, - linvel_stm = 38, - seek_nom = 39, - seek_stm = 40, - read_seq_nom = 41, - read_seq_stm = 42, - read_spr_nom = 43, - read_spr_stm = 44, - read_spr_strn_nom = 45, - rand_stm_abort = 46, - rand_nom_abort = 47, - iop_mem = 48, - cancel_dgo = 49, - set_stereo_mode = 50, -}; - -struct SoundRpcGetIrxVersion { - u32 major; - u32 minor; - u32 ee_addr; -}; - -struct SoundRpcBankCommand { - u8 pad[12]; - char bank_name[16]; -}; - -struct SoundRpcSetLanguageCommand { - u32 langauge_id; // game_common_types.h, Language -}; - -struct SoundRpcPlayCommand { - u32 sound_id; - u32 pad[2]; - char name[16]; - SoundParams parms; -}; - -struct SoundRpcSetParamCommand { - u32 sound_id; - SoundParams parms; - s32 auto_time; - s32 auto_from; -}; - -struct SoundRpcSoundIdCommand { - u32 sound_id; -}; - -struct SoundRpcSetFlavaCommand { - u8 flava; -}; - -struct SoundRpcSetReverb { - u8 core; - s32 reverb; - u32 left; - u32 right; -}; - -struct SoundRpcSetEarTrans { - Vec3w ear_trans; - Vec3w cam_trans; - s32 cam_angle; -}; - -struct SoundRpc2SetEarTrans { - Vec3w ear_trans1; - Vec3w ear_trans0; - Vec3w cam_trans; - s32 cam_angle; -}; - -struct SoundRpcSetFPSCommand { - u8 fps; -}; - -struct SoundRpcSetFallof { - u8 pad[12]; - char name[16]; - s32 curve; - s32 min; - s32 max; -}; - -struct SoundRpcSetFallofCurve { - s32 curve; - s32 falloff; - s32 ease; -}; - -struct SoundRpcGroupCommand { - u8 group; -}; - -struct SoundRpcMasterVolCommand { - SoundRpcGroupCommand group; - s32 volume; -}; - -struct SoundRpcStereoMode { - s32 stereo_mode; -}; - -struct SoundRpcSetMidiReg { - s32 reg; - s32 value; -}; - -struct SoundRpcSetMirrror { - u8 value; -}; - -struct SoundRpcCommand { - u16 rsvd1; - union { - Jak1SoundCommand j1command; - Jak2SoundCommand j2command; - }; - union { - SoundRpcGetIrxVersion irx_version; - SoundRpcBankCommand load_bank; - SoundRpcSetLanguageCommand set_language; - SoundRpcPlayCommand play; - SoundRpcSoundIdCommand sound_id; - SoundRpcSetFPSCommand fps; - SoundRpcSetEarTrans ear_trans; - SoundRpc2SetEarTrans ear_trans_j2; - SoundRpcSetReverb reverb; - SoundRpcSetFallof fallof; - SoundRpcSetFallofCurve fallof_curve; - SoundRpcGroupCommand group; - SoundRpcSetFlavaCommand flava; - SoundRpcMasterVolCommand master_volume; - SoundRpcSetParamCommand param; - SoundRpcStereoMode stereo_mode; - SoundRpcSetMidiReg midi_reg; - SoundRpcSetMirrror mirror; - u8 max_size[0x4C]; // Temporary - }; -}; - -static_assert(sizeof(SoundRpcCommand) == 0x50); - -struct SoundIopInfo { - u32 frame; - s32 strpos; - u32 std_id; - u32 freemem; - u8 chinfo[48]; - u32 freemem2; - u32 nocd; - u32 dirtycd; - u32 diskspeed[2]; - u32 lastspeed; - s32 dupseg; - u32 times[41]; - u32 times_seq; - u8 pad[10]; // pad up to transfer size -}; - -extern MusicTweaks gMusicTweakInfo; -extern s32 gMusicTweak; - -u32 Thread_Loader(); -u32 Thread_Player(); - -s32 VBlank_Handler(void*); - -// added for PC port -extern u32 gMusicFadeHack; diff --git a/game/overlord/stream.cpp b/game/overlord/stream.cpp deleted file mode 100644 index e2922629c6..0000000000 --- a/game/overlord/stream.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/*! - * @file stream.cpp - * OVERLORD streaming driver. - * Supports loading a file directly to the EE, or loading chunks of a chunked file. - */ - -#include "stream.h" - -#include - -#include "common/util/Assert.h" - -#include "game/common/play_rpc_types.h" -#include "game/common/str_rpc_types.h" -#include "game/overlord/iso.h" -#include "game/overlord/iso_api.h" -#include "game/overlord/isocommon.h" -#include "game/overlord/srpc.h" -#include "game/runtime.h" -#include "game/sce/iop.h" - -using namespace iop; - -static RPC_Str_Cmd_Jak1 sSTRBufJak1; -static RPC_Str_Cmd_Jak2 sSTRBufJak2; -static RPC_Play_Cmd_Jak1 sPLAYBufJak1[2]; -static RPC_Play_Cmd_Jak2 sPLAYBufJak2[2]; - -void* RPC_STR_jak1(unsigned int fno, void* _cmd, int y); -void* RPC_STR_jak2(unsigned int fno, void* _cmd, int y); -void* RPC_PLAY_jak1(unsigned int fno, void* _cmd, int y); -void* RPC_PLAY_jak2(unsigned int fno, void* _cmd, int y); - -static constexpr int PLAY_MSG_SIZE = 0x40; - -static u32 global_vag_count = 0; - -/*! - * We cache the chunk file headers so we can avoid seeking to the chunk header each time we - * need to load another chunk, even if we load chunks out of order. - */ -struct CacheEntryJ1 { - // the record for the chunk file described. - FileRecord* fr = nullptr; - // counts down from INT32_MAX - 1 each time we have a cache miss. - s32 countdown = 0; - // the actual cached data. - StrFileHeaderJ1 header; -}; - -struct CacheEntryJ2 { - FileRecord* fr = nullptr; - s32 countdown = 0; - StrFileHeaderJ2 header; -}; - -// the actual header cache. -constexpr int STR_INDEX_CACHE_SIZE = 4; -CacheEntryJ1 sCacheJ1[STR_INDEX_CACHE_SIZE]; -CacheEntryJ2 sCacheJ2[STR_INDEX_CACHE_SIZE]; - -void stream_init_globals() { - memset(&sSTRBufJak1, 0, sizeof(RPC_Str_Cmd_Jak1)); - memset(&sSTRBufJak2, 0, sizeof(RPC_Str_Cmd_Jak2)); - memset(&sPLAYBufJak1, 0, sizeof(RPC_Play_Cmd_Jak1) * 2); - memset(&sPLAYBufJak2, 0, sizeof(RPC_Play_Cmd_Jak2) * 2); -} - -/*! - * Run the STR RPC handler. - */ -u32 STRThread() { - sceSifQueueData dq; - sceSifServeData serve; - - CpuDisableIntr(); - sceSifInitRpc(0); - sceSifSetRpcQueue(&dq, GetThreadId()); - if (g_game_version == GameVersion::Jak1) { - sceSifRegisterRpc(&serve, STR_RPC_ID[g_game_version], RPC_STR_jak1, &sSTRBufJak1, nullptr, - nullptr, &dq); - } else if (g_game_version == GameVersion::Jak2) { - sceSifRegisterRpc(&serve, STR_RPC_ID[g_game_version], RPC_STR_jak2, &sSTRBufJak2, nullptr, - nullptr, &dq); - } else { - ASSERT_MSG(false, "unsupported game version in STRThread initialization!"); - } - - CpuEnableIntr(); - sceSifRpcLoop(&dq); - return 0; -} - -u32 PLAYThread() { - sceSifQueueData dq; - sceSifServeData serve; - - CpuDisableIntr(); - sceSifInitRpc(0); - sceSifSetRpcQueue(&dq, GetThreadId()); - if (g_game_version == GameVersion::Jak1) { - sceSifRegisterRpc(&serve, PLAY_RPC_ID[g_game_version], RPC_PLAY_jak1, sPLAYBufJak1, nullptr, - nullptr, &dq); - - } else if (g_game_version == GameVersion::Jak2) { - sceSifRegisterRpc(&serve, PLAY_RPC_ID[g_game_version], RPC_PLAY_jak2, sPLAYBufJak2, nullptr, - nullptr, &dq); - - } else { - ASSERT_MSG(false, "unsupported game version in PLAYThread initialization!"); - } - CpuEnableIntr(); - sceSifRpcLoop(&dq); - return 0; -} - -/*! - * The STR RPC handler. - */ -void* RPC_STR_jak1(unsigned int fno, void* _cmd, int y) { - (void)fno; - (void)y; - auto* cmd = (RPC_Str_Cmd_Jak1*)_cmd; - if (cmd->chunk_id < 0) { - // it's _not_ a stream file. So we just treat it like a normal load. - - // find the file with the given name - auto file_record = isofs->find(cmd->name); - if (file_record == nullptr) { - // file not found! - printf("[OVERLORD STR] Failed to find file %s for loading.\n", cmd->name); - cmd->result = STR_RPC_RESULT_ERROR; - } else { - // load directly to the EE - cmd->length = LoadISOFileToEE(file_record, cmd->ee_addr, cmd->length); - if (cmd->length) { - // successful load! - cmd->result = STR_RPC_RESULT_DONE; - } else { - // there was an error loading. - cmd->result = STR_RPC_RESULT_ERROR; - } - } - } else { - // it's a chunked file. These are only animations - these have a separate naming scheme. - char animation_iso_name[128]; - ISONameFromAnimationName(animation_iso_name, cmd->name); - auto file_record = isofs->find_in(animation_iso_name); - - if (!file_record) { - // didn't find the file - printf("[OVERLORD STR] Failed to find animation %s\n", cmd->name); - cmd->result = STR_RPC_RESULT_ERROR; - } else { - // found it! See if we've cached this animation's header. - int cache_entry = 0; - int oldest = INT32_MAX; - int oldest_idx = -1; - while (cache_entry < STR_INDEX_CACHE_SIZE && sCacheJ1[cache_entry].fr != file_record) { - sCacheJ1[cache_entry].countdown--; - if (sCacheJ1[cache_entry].countdown < oldest) { - oldest_idx = cache_entry; - oldest = sCacheJ1[cache_entry].countdown; - } - cache_entry++; - } - - if (cache_entry == STR_INDEX_CACHE_SIZE) { - // cache miss, we need to load the header to the header cache on the IOP - cache_entry = oldest_idx; - sCacheJ1[oldest_idx].fr = file_record; - sCacheJ1[oldest_idx].countdown = INT32_MAX - 1; - if (!LoadISOFileToIOP(file_record, &sCacheJ1[oldest_idx].header, sizeof(StrFileHeaderJ1))) { - printf("[OVERLORD STR] Failed to load chunk file header for animation %s\n", cmd->name); - cmd->result = 1; - return cmd; - } - } - - // load data, using the cached header to find the location of the chunk. - if (!LoadISOFileChunkToEE(file_record, cmd->ee_addr, - sCacheJ1[cache_entry].header.sizes[cmd->chunk_id], - sCacheJ1[cache_entry].header.sectors[cmd->chunk_id])) { - printf("[OVERLORD STR] Failed to load chunk %d for animation %s\n", cmd->chunk_id, - cmd->name); - cmd->result = 1; - } else { - // successful load! - cmd->length = sCacheJ1[cache_entry].header.sizes[cmd->chunk_id]; - cmd->result = 0; - } - } - } - - return cmd; -} - -/*! - * The STR RPC handler. - */ -void* RPC_STR_jak2(unsigned int fno, void* _cmd, int y) { - (void)fno; - (void)y; - auto* cmd = (RPC_Str_Cmd_Jak2*)_cmd; - if (cmd->section < 0) { - // it's _not_ a stream file. So we just treat it like a normal load. - - // find the file with the given name - auto file_record = isofs->find(cmd->basename); - if (file_record == nullptr) { - // file not found! - printf("[OVERLORD STR] Failed to find file %s for loading.\n", cmd->basename); - cmd->result = STR_RPC_RESULT_ERROR; - } else { - // load directly to the EE - cmd->maxlen = LoadISOFileToEE(file_record, cmd->address, cmd->maxlen); - if (cmd->maxlen) { - // successful load! - cmd->result = STR_RPC_RESULT_DONE; - } else { - // there was an error loading. - cmd->result = STR_RPC_RESULT_ERROR; - } - } - } else { - // it's a chunked file. These are only animations - these have a separate naming scheme. - char animation_iso_name[128]; - ISONameFromAnimationName(animation_iso_name, cmd->basename); - auto file_record = isofs->find_in(animation_iso_name); - - if (!file_record) { - // didn't find the file - printf("[OVERLORD STR] Failed to find animation %s (%s)\n", cmd->basename, - animation_iso_name); - cmd->result = STR_RPC_RESULT_ERROR; - } else { - // found it! See if we've cached this animation's header. - int cache_entry = 0; - int oldest = INT32_MAX; - int oldest_idx = -1; - while (cache_entry < STR_INDEX_CACHE_SIZE && sCacheJ2[cache_entry].fr != file_record) { - sCacheJ2[cache_entry].countdown--; - if (sCacheJ2[cache_entry].countdown < oldest) { - oldest_idx = cache_entry; - oldest = sCacheJ2[cache_entry].countdown; - } - cache_entry++; - } - - if (cache_entry == STR_INDEX_CACHE_SIZE) { - // cache miss, we need to load the header to the header cache on the IOP - cache_entry = oldest_idx; - sCacheJ2[oldest_idx].fr = file_record; - sCacheJ2[oldest_idx].countdown = INT32_MAX - 1; - if (!LoadISOFileToIOP(file_record, &sCacheJ2[oldest_idx].header, sizeof(StrFileHeaderJ2))) { - printf("[OVERLORD STR] Failed to load chunk file header for animation %s\n", - cmd->basename); - cmd->result = 1; - return cmd; - } - } - - // load data, using the cached header to find the location of the chunk. - if (!LoadISOFileChunkToEE(file_record, cmd->address, - sCacheJ2[cache_entry].header.sizes[cmd->section], - sCacheJ2[cache_entry].header.sectors[cmd->section])) { - printf("[OVERLORD STR] Failed to load chunk %d for animation %s\n", cmd->section, - cmd->basename); - cmd->result = 1; - } else { - // successful load! - cmd->maxlen = sCacheJ2[cache_entry].header.sizes[cmd->section]; - cmd->result = 0; - } - } - } - - return cmd; -} - -void* RPC_PLAY_jak1([[maybe_unused]] unsigned int fno, void* _cmd, int size) { - s32 n_messages = size / PLAY_MSG_SIZE; - char namebuf[16]; - - auto* cmd = (RPC_Play_Cmd_Jak1*)(_cmd); - while (n_messages > 0) { - if (cmd->name[0] == '$') { - char* name_part = &cmd->name[1]; - size_t name_len = strlen(name_part); - - if (name_len < 9) { - memset(namebuf, ' ', 8); - memcpy(namebuf, name_part, name_len); - } else { - memcpy(namebuf, name_part, 8); - } - - // ASCII toupper - for (int i = 0; i < 8; i++) { - if (namebuf[i] >= 0x61 && namebuf[i] < 0x7b) { - namebuf[i] -= 0x20; - } - } - } else { - ISONameFromAnimationName(namebuf, cmd->name); - } - - auto vag = FindVAGFile(namebuf); - memcpy(namebuf, "VAGWAD ", 8); - strcpy(&namebuf[8], gLanguage); - - FileRecord* file = nullptr; - - global_vag_count = (global_vag_count + 1) & 0x3f; - if (!cmd->result && global_vag_count == 0) { - namebuf[0] -= 3; - file = isofs->find_in(namebuf); - namebuf[0] += 3; - } - - file = isofs->find_in(namebuf); - - if (cmd->result == 0) { - PlayVAGStream(file, vag, cmd->address, 0x400, 1, nullptr); - } else if (cmd->result == 1) { - StopVAGStream(vag, 1); - } else { - QueueVAGStream(file, vag, 0, 1); - } - - n_messages--; - cmd++; - } - - return _cmd; -} - -/*! - * This is just copied from Jak 1, and is totally wrong for jak 2. - * It does nothing. - */ -void* RPC_PLAY_jak2([[maybe_unused]] unsigned int fno, void* _cmd, int size) { - s32 n_messages = size / PLAY_MSG_SIZE; - char namebuf[16]; - - auto* cmd = (RPC_Play_Cmd_Jak2*)(_cmd); - while (n_messages > 0) { - if (cmd->names[0].chars[0] == '$') { - char* name_part = &cmd->names[0].chars[1]; - size_t name_len = strlen(name_part); - - if (name_len < 9) { - memset(namebuf, ' ', 8); - memcpy(namebuf, name_part, name_len); - } else { - memcpy(namebuf, name_part, 8); - } - - // ASCII toupper - for (int i = 0; i < 8; i++) { - if (namebuf[i] >= 0x61 && namebuf[i] < 0x7b) { - namebuf[i] -= 0x20; - } - } - } else { - ISONameFromAnimationName(namebuf, cmd->names[0].chars); - } - - n_messages--; - cmd++; - } - - return _cmd; -} diff --git a/game/runtime.cpp b/game/runtime.cpp index c97a99485b..2c43e94bfd 100644 --- a/game/runtime.cpp +++ b/game/runtime.cpp @@ -24,6 +24,7 @@ #include "runtime.h" #include "common/cross_os_debug/xdbg.h" +#include "common/global_profiler/GlobalProfiler.h" #include "common/goal_constants.h" #include "common/log/log.h" #include "common/util/FileUtil.h" @@ -47,17 +48,30 @@ #include "game/kernel/jak2/kboot.h" #include "game/kernel/jak2/klisten.h" #include "game/kernel/jak2/kscheme.h" -#include "game/overlord/dma.h" -#include "game/overlord/fake_iso.h" -#include "game/overlord/iso.h" -#include "game/overlord/iso_cd.h" -#include "game/overlord/iso_queue.h" -#include "game/overlord/overlord.h" -#include "game/overlord/ramdisk.h" -#include "game/overlord/sbank.h" -#include "game/overlord/srpc.h" -#include "game/overlord/ssound.h" -#include "game/overlord/stream.h" +#include "game/overlord/common/fake_iso.h" +#include "game/overlord/common/iso.h" +#include "game/overlord/common/sbank.h" +#include "game/overlord/common/srpc.h" +#include "game/overlord/common/ssound.h" +#include "game/overlord/jak1/dma.h" +#include "game/overlord/jak1/fake_iso.h" +#include "game/overlord/jak1/iso.h" +#include "game/overlord/jak1/iso_queue.h" +#include "game/overlord/jak1/overlord.h" +#include "game/overlord/jak1/ramdisk.h" +#include "game/overlord/jak1/srpc.h" +#include "game/overlord/jak1/ssound.h" +#include "game/overlord/jak1/stream.h" +#include "game/overlord/jak2/dma.h" +#include "game/overlord/jak2/iso_cd.h" +#include "game/overlord/jak2/iso_queue.h" +#include "game/overlord/jak2/overlord.h" +#include "game/overlord/jak2/spustreams.h" +#include "game/overlord/jak2/srpc.h" +#include "game/overlord/jak2/ssound.h" +#include "game/overlord/jak2/stream.h" +#include "game/overlord/jak2/streamlist.h" +#include "game/overlord/jak2/vag.h" #include "game/system/Deci2Server.h" #include "game/system/iop_thread.h" #include "game/system/vm/dmac.h" @@ -183,6 +197,10 @@ void ee_runner(SystemThreadInterface& iface) { jak1::klisten_init_globals(); jak2::klisten_init_globals(); + jak2::vag_init_globals(); + + jak2::init_globals_streamlist(); + kmemcard_init_globals(); kprint_init_globals_common(); @@ -211,7 +229,9 @@ void ee_runner(SystemThreadInterface& iface) { /*! * SystemThread function for running the IOP (separate I/O Processor) */ -void iop_runner(SystemThreadInterface& iface) { +void iop_runner(SystemThreadInterface& iface, GameVersion version) { + prof().root_event(); + prof().begin_event("iop-init"); IOP iop; lg::debug("[IOP] Restart!"); iop.reset_allocator(); @@ -219,26 +239,41 @@ void iop_runner(SystemThreadInterface& iface) { iop::LIBRARY_register(&iop); Gfx::register_vsync_callback([&iop]() { iop.kernel.signal_vblank(); }); - // todo! - dma_init_globals(); - iso_init_globals(); - fake_iso_init_globals(); - // iso_api - iso_cd_init_globals(); - iso_queue_init_globals(); - // isocommon - // overlord - ramdisk_init_globals(); - sbank_init_globals(); - // soundcommon - srpc_init_globals(); - // ssound - stream_init_globals(); + jak1::dma_init_globals(); + jak2::dma_init_globals(); + iso_init_globals(); + jak1::iso_init_globals(); + jak2::iso_init_globals(); + + fake_iso_init_globals(); + jak1::fake_iso_init_globals(); + jak2::iso_cd_init_globals(); + + jak1::iso_queue_init_globals(); + jak2::iso_queue_init_globals(); + + jak2::spusstreams_init_globals(); + jak1::ramdisk_init_globals(); + sbank_init_globals(); + + // soundcommon + jak1::srpc_init_globals(); + jak2::srpc_init_globals(); + srpc_init_globals(); + ssound_init_globals(); + jak2::ssound_init_globals(); + + jak1::stream_init_globals(); + jak2::stream_init_globals(); + prof().end_event(); iface.initialization_complete(); lg::debug("[IOP] Wait for OVERLORD to start..."); - iop.wait_for_overlord_start_cmd(); + { + auto p = scoped_prof("iop-wait-for-ee"); + iop.wait_for_overlord_start_cmd(); + } if (iop.status == IOP_OVERLORD_INIT) { lg::debug("[IOP] Run!"); } else { @@ -251,9 +286,26 @@ void iop_runner(SystemThreadInterface& iface) { // init bool complete = false; - start_overlord_wrapper(iop.overlord_argc, iop.overlord_argv, &complete); // todo! - while (complete == false) { - iop.wait_run_iop(iop.kernel.dispatch()); + { + auto p = scoped_prof("overlord-start"); + switch (version) { + case GameVersion::Jak1: + jak1::start_overlord_wrapper(iop.overlord_argc, iop.overlord_argv, &complete); + break; + case GameVersion::Jak2: + jak2::start_overlord_wrapper(iop.overlord_argc, iop.overlord_argv, &complete); + break; + default: + ASSERT_NOT_REACHED(); + } + } + + { + auto p = scoped_prof("overlord-wait-for-init"); + while (complete == false) { + prof().root_event(); + iop.kernel.dispatch(); + } } // unblock the EE, the overlord is set up! @@ -261,9 +313,14 @@ void iop_runner(SystemThreadInterface& iface) { // IOP Kernel loop while (!iface.get_want_exit() && !iop.want_exit) { + prof().root_event(); // The IOP scheduler informs us of how many microseconds are left until it has something to do. // So we can wait for that long or until something else needs it to wake up. - iop.wait_run_iop(iop.kernel.dispatch()); + auto wait_duration = iop.kernel.dispatch(); + if (wait_duration && + *wait_duration - std::chrono::steady_clock::now() > std::chrono::microseconds(100)) { + iop.wait_run_iop(*wait_duration); + } } Gfx::clear_vsync_callback(); @@ -275,8 +332,6 @@ void iop_runner(SystemThreadInterface& iface) { */ void null_runner(SystemThreadInterface& iface) { iface.initialization_complete(); - - return; } /*! @@ -303,8 +358,6 @@ void dmac_runner(SystemThreadInterface& iface) { } VM::unsubscribe_component(); - - return; } /*! @@ -312,6 +365,7 @@ void dmac_runner(SystemThreadInterface& iface) { * GOAL kernel arguments are currently ignored. */ RuntimeExitStatus exec_runtime(GameLaunchOptions game_options, int argc, const char** argv) { + prof().root_event(); g_argc = argc; g_argv = argv; g_main_thread_id = std::this_thread::get_id(); @@ -323,19 +377,26 @@ RuntimeExitStatus exec_runtime(GameLaunchOptions game_options, int argc, const c // set up discord stuff gStartTime = time(nullptr); - init_discord_rpc(); + { + auto p = scoped_prof("init-discord"); + init_discord_rpc(); + } // initialize graphics first - the EE code will upload textures during boot and we // want the graphics system to catch them. if (enable_display) { + auto p = scoped_prof("init-gfx"); Gfx::Init(g_game_version); } // step 1: sce library prep - iop::LIBRARY_INIT(); - ee::LIBRARY_INIT_sceCd(); - ee::LIBRARY_INIT_sceDeci2(); - ee::LIBRARY_INIT_sceSif(); + { + auto p = scoped_prof("init-library"); + iop::LIBRARY_INIT(); + ee::LIBRARY_INIT_sceCd(); + ee::LIBRARY_INIT_sceDeci2(); + ee::LIBRARY_INIT_sceSif(); + } // step 2: system prep VM::vm_prepare(); // our fake ps2 VM needs to be prepared @@ -346,10 +407,20 @@ RuntimeExitStatus exec_runtime(GameLaunchOptions game_options, int argc, const c auto& vm_dmac_thread = tm.create_thread("VM-DMAC"); // step 3: start the EE! - iop_thread.start(iop_runner); - deci_thread.start(deci2_runner); - ee_thread.start(ee_runner); + { + auto p = scoped_prof("iop-start"); + iop_thread.start([=](SystemThreadInterface& sti) { iop_runner(sti, g_game_version); }); + } + { + auto p = scoped_prof("deci-start"); + deci_thread.start(deci2_runner); + } + { + auto p = scoped_prof("ee-start"); + ee_thread.start(ee_runner); + } if (VM::use) { + auto p = scoped_prof("dmac-start"); vm_dmac_thread.start(dmac_runner); } diff --git a/game/sce/iop.cpp b/game/sce/iop.cpp index fb44fbcf37..fff38a8f14 100644 --- a/game/sce/iop.cpp +++ b/game/sce/iop.cpp @@ -82,6 +82,16 @@ void* AllocSysMemory(int type, unsigned long size, void* addr) { return iop->iop_alloc(size); } +/*! + * Allocate the 1 kB scratchpad memory. On PS2, this would give you a pointer to the actual + * scratchpad of the IOP, but this is just normal memory. + */ +void* AllocScratchPad(int mode) { + ASSERT(mode == 0); + constexpr int kScratchpadSize = 1024 * 16; + return iop->iop_alloc(kScratchpadSize); +} + /*! * Create a new thread */ @@ -140,12 +150,6 @@ void sceSifRpcLoop(sceSifQueueData* pd) { iop->kernel.rpc_loop(pd); } -int sceCdRead(uint32_t logical_sector, uint32_t sectors, void* buf, sceCdRMode* mode) { - (void)mode; - iop->kernel.read_disc_sectors(logical_sector, sectors, buf); - return 1; -} - int sceCdSync(int mode) { (void)mode; return 0; @@ -193,6 +197,10 @@ s32 PollMbx(MsgPacket** recvmsg, int mbxid) { return iop->kernel.PollMbx((void**)recvmsg, mbxid); } +s32 PeekMbx(s32 mbx) { + return iop->kernel.PeekMbx(mbx); +} + static int now = 0; void GetSystemTime(SysClock* time) { @@ -226,6 +234,11 @@ s32 WakeupThread(s32 thid) { return 0; } +s32 iWakeupThread(s32 thid) { + iop->kernel.iWakeupThread(thid); + return 0; +} + s32 RegisterVblankHandler(int edge, int priority, int (*handler)(void*), void* /*userdata*/) { (void)edge; (void)priority; diff --git a/game/sce/iop.h b/game/sce/iop.h index 708920c9b1..1aaa9183c8 100644 --- a/game/sce/iop.h +++ b/game/sce/iop.h @@ -20,7 +20,7 @@ #define SCECdComplete 0x02 #define SCECdNotReady 0x06 #define KE_OK 0 -#define KE_SEMA_ZERO -419 +#define KE_SEMA_ZERO (-419) #define KE_SEMA_OVF -420 #define KE_MBOX_NOMSG -424 #define KE_WAIT_DELETE -425 @@ -76,7 +76,7 @@ struct MbxParam { struct ThreadParam { u32 attr; u32 option; - void* entry; + u32 (*entry)(); int stackSize; int initPriority; @@ -94,6 +94,7 @@ struct SemaParam { // void PS2_RegisterIOP(IOP *iop); int QueryTotalFreeMemSize(); void* AllocSysMemory(int type, unsigned long size, void* addr); +void* AllocScratchPad(int mode); int GetThreadId(); void CpuDisableIntr(); @@ -104,6 +105,7 @@ s32 CreateThread(ThreadParam* param); s32 ExitThread(); s32 StartThread(s32 thid, u32 arg); s32 WakeupThread(s32 thid); +s32 iWakeupThread(s32 thid); void sceSifInitRpc(int mode); void sceSifInitRpc(unsigned int mode); @@ -117,7 +119,6 @@ void sceSifRegisterRpc(sceSifServeData* serve, sceSifQueueData* qd); void sceSifRpcLoop(sceSifQueueData* pd); -int sceCdRead(uint32_t logical_sector, uint32_t sectors, void* buf, sceCdRMode* mode); int sceCdSync(int mode); int sceCdGetError(); int sceCdGetDiskType(); @@ -129,6 +130,7 @@ u32 sceSifSetDma(sceSifDmaData* sdd, int len); s32 SendMbx(int mbxid, void* sendmsg); s32 PollMbx(MsgPacket** recvmsg, int mbxid); +s32 PeekMbx(s32 mbx); s32 CreateMbx(MbxParam* param); void GetSystemTime(SysClock* time); diff --git a/game/sound/989snd/sfxblock2.cpp b/game/sound/989snd/sfxblock2.cpp index 3dc0dc3c4b..7619b7624b 100644 --- a/game/sound/989snd/sfxblock2.cpp +++ b/game/sound/989snd/sfxblock2.cpp @@ -57,11 +57,11 @@ SFXBlock2::SFXBlock2(locator& loc, u32 id, BankTag* tag) } } - auto idx = 0; - for (auto& s : m_sounds) { - lg::warn("sound {} : {}", idx, s.name); - idx++; - } + // auto idx = 0; + // for (auto& s : m_sounds) { + // lg::warn("sound {} : {}", idx, s.name); + // idx++; + //} } std::optional> SFXBlock2::make_handler(voice_manager& vm, diff --git a/game/sound/common/voice.cpp b/game/sound/common/voice.cpp index 162baf66a1..6d57072047 100644 --- a/game/sound/common/voice.cpp +++ b/game/sound/common/voice.cpp @@ -97,9 +97,8 @@ void voice::key_on() { m_DecodeBuf.Reset(); m_CustomLoop = false; // Console.WriteLn("SPU[%d]:VOICE[%d] Key On, SSA %08x", m_SPU.m_Id, m_Id, m_SSA); - // fmt::print("Key On {} {} {} {:x}\n",(void*)m_sample, m_Volume.left.Get(), m_Volume.right.Get(), - // m_ADSR.m_Reg.bits); } + void voice::key_off() { m_ADSR.Release(); // fmt::print("Key Off\n"); diff --git a/game/sound/common/voice.h b/game/sound/common/voice.h index 790e35bc56..c7e3242133 100644 --- a/game/sound/common/voice.h +++ b/game/sound/common/voice.h @@ -23,6 +23,7 @@ class voice { s16_output run(); void key_on(); + void key_off(); bool dead() { diff --git a/game/sound/sdshim.cpp b/game/sound/sdshim.cpp index d8958741c5..ac50296a64 100644 --- a/game/sound/sdshim.cpp +++ b/game/sound/sdshim.cpp @@ -3,13 +3,14 @@ #include #include "common/common_types.h" +#include "common/util/Assert.h" #include "game/sound/common/voice.h" #include "third-party/fmt/core.h" -std::shared_ptr voice; -u8 spu_memory[0xc060]; +std::shared_ptr voices[4]; +u8 spu_memory[0x15160 * 10]; static sceSdTransIntrHandler trans_handler[2] = {nullptr, nullptr}; static void* userdata[2] = {nullptr, nullptr}; @@ -19,7 +20,13 @@ u32 sceSdGetSwitch(u32 entry) { return 0; } +snd::voice* voice_from_entry(u32 entry) { + u32 it = entry & 3; + return voices[it].get(); +} + u32 sceSdGetAddr(u32 entry) { + auto* voice = voice_from_entry(entry); if (!voice) { return 0; } @@ -28,15 +35,33 @@ u32 sceSdGetAddr(u32 entry) { // u32 reg = entry & ~0x3f; // Only ever used for getting NAX - return voice->get_nax() << 1; } -void sceSdSetSwitch(u32 entry, u32 value) { +void sceSdSetSwitch(u32 entry, u32 /*value*/) { // we can ignore this, only used for vmix + u32 reg = entry & ~0x3f; + switch (reg) { + case 0x1500: + voice_from_entry(entry)->key_on(); + voice_from_entry(entry + 1)->key_on(); + break; + case 0x1600: + voice_from_entry(entry)->key_off(); + break; + } +} + +void sceSdkey_on_jak2_voice(int id) { + voice_from_entry(id)->key_on(); +} + +void sceSdkey_off_jak2_voice(int id) { + voice_from_entry(id)->key_off(); } void sceSdSetAddr(u32 entry, u32 value) { + auto* voice = voice_from_entry(entry); if (!voice) { return; } @@ -51,10 +76,15 @@ void sceSdSetAddr(u32 entry, u32 value) { case SD_VA_LSAX: { voice->set_lsa(value >> 1); } break; + default: + printf("unknown 0x%x\n", reg); + ASSERT_NOT_REACHED(); + break; } } void sceSdSetParam(u32 entry, u32 value) { + auto* voice = voice_from_entry(entry); if (!voice) { return; } diff --git a/game/sound/sdshim.h b/game/sound/sdshim.h index 3f1b5d32f8..21e6a761ca 100644 --- a/game/sound/sdshim.h +++ b/game/sound/sdshim.h @@ -16,8 +16,8 @@ #define SD_VP_ADSR2 (0x04 << 8) #define SD_VA_NAX ((0x22 << 8) + (0x01 << 6)) -extern std::shared_ptr voice; -extern u8 spu_memory[0xc060]; +extern std::shared_ptr voices[4]; +extern u8 spu_memory[0x15160 * 10]; using sceSdTransIntrHandler = int (*)(int, void*); @@ -28,3 +28,5 @@ void sceSdSetAddr(u32 entry, u32 value); void sceSdSetParam(u32 entry, u32 value); void sceSdSetTransIntrHandler(s32 channel, sceSdTransIntrHandler, void* data); u32 sceSdVoiceTrans(s32 channel, s32 mode, void* iop_addr, u32 spu_addr, u32 size); +void sceSdkey_on_jak2_voice(int id); +void sceSdkey_off_jak2_voice(int id); diff --git a/game/sound/sndshim.cpp b/game/sound/sndshim.cpp index 75eb6bbf8a..e06026c9e9 100644 --- a/game/sound/sndshim.cpp +++ b/game/sound/sndshim.cpp @@ -11,9 +11,11 @@ std::unique_ptr player; void snd_StartSoundSystem() { player = std::make_unique(); - voice = std::make_shared(snd::voice::AllocationType::permanent); - voice->set_sample((u16*)spu_memory); - player->submit_voice(voice); + for (auto& voice : voices) { + voice = std::make_shared(snd::voice::AllocationType::permanent); + voice->set_sample((u16*)spu_memory); + player->submit_voice(voice); + } } void snd_StopSoundSystem() { @@ -60,6 +62,10 @@ u32 snd_SRAMMalloc(u32 size) { return 0; } +void snd_SRAMMarkUsed(u32 addr, u32 size) { + // hope this doesn't matter... +} + void snd_SetMixerMode(s32 channel_mode, s32 reverb_mode) {} void snd_SetGroupVoiceRange(s32 group, s32 min, s32 max) {} @@ -212,14 +218,14 @@ s32 snd_GetVoiceStatus(s32 voice) { } void snd_keyOnVoiceRaw(u32 core, u32 voice_id) { - if (voice) { - voice->key_on(); + if (voices[0]) { + voices[0]->key_on(); } } void snd_keyOffVoiceRaw(u32 core, u32 voice_id) { - if (voice) { - voice->key_off(); + if (voices[0]) { + voices[0]->key_off(); } } diff --git a/game/sound/sndshim.h b/game/sound/sndshim.h index cd5a815e8c..1b80630285 100644 --- a/game/sound/sndshim.h +++ b/game/sound/sndshim.h @@ -1,5 +1,4 @@ -#ifndef SNDSHIM_H_ -#define SNDSHIM_H_ + #pragma once #include "common/common_types.h" @@ -22,6 +21,7 @@ int snd_LockVoiceAllocator(bool block); void snd_UnlockVoiceAllocator(); s32 snd_ExternVoiceAlloc(s32 vol_group, s32 priority); u32 snd_SRAMMalloc(u32 size); +void snd_SRAMMarkUsed(u32 addr, u32 size); void snd_SetMixerMode(s32 channel_mode, s32 reverb_mode); void snd_SetGroupVoiceRange(s32 group, s32 min, s32 max); void snd_SetReverbDepth(s32 core, s32 left, s32 right); @@ -72,5 +72,3 @@ s32 snd_GetSoundUserData(s32 block_handle, char* sound_name, SFXUserData* dst); void snd_SetSoundReg(s32 sound_handle, s32 which, u8 val); - -#endif // SNDSHIM_H_ diff --git a/game/system/IOP_Kernel.cpp b/game/system/IOP_Kernel.cpp index c4fa84d207..171956af25 100644 --- a/game/system/IOP_Kernel.cpp +++ b/game/system/IOP_Kernel.cpp @@ -96,6 +96,12 @@ void IOP_Kernel::WakeupThread(s32 id) { threads.at(id).state = IopThread::State::Ready; } +void IOP_Kernel::iWakeupThread(s32 id) { + ASSERT(id > 0); + std::scoped_lock lock(wakeup_mtx); + wakeup_queue.push(id); +} + s32 IOP_Kernel::WaitSema(s32 id) { auto& sema = semas.at(id); if (sema.count > 0) { @@ -194,7 +200,8 @@ void IOP_Kernel::updateDelay() { } } -time_stamp IOP_Kernel::nextWakeup() { +std::optional IOP_Kernel::nextWakeup() { + bool found_ready = false; time_stamp lowest = time_point_cast(steady_clock::now()) + microseconds(1000); for (auto& t : threads) { @@ -203,9 +210,17 @@ time_stamp IOP_Kernel::nextWakeup() { lowest = t.resumeTime; } } + + if (t.state == IopThread::State::Ready) { + found_ready = true; + } } - return lowest; + if (found_ready) { + return {}; + } else { + return lowest; + } } /*! @@ -242,13 +257,7 @@ void IOP_Kernel::processWakeups() { /*! * Run the next IOP thread. */ -time_stamp IOP_Kernel::dispatch() { - // Check vblank interrupt - if (vblank_handler != nullptr && vblank_recieved) { - vblank_handler(nullptr); - vblank_recieved = false; - } - +std::optional IOP_Kernel::dispatch() { // Update thread states updateDelay(); processWakeups(); @@ -256,9 +265,15 @@ time_stamp IOP_Kernel::dispatch() { // Run until all threads are idle IopThread* next = schedNext(); while (next != nullptr) { + // Check vblank interrupt + if (vblank_handler != nullptr && vblank_recieved) { + vblank_handler(nullptr); + vblank_recieved = false; + } // printf("[IOP Kernel] Dispatch %s (%d)\n", next->name.c_str(), next->thID); runThread(next); updateDelay(); + processWakeups(); next = schedNext(); // printf("[IOP Kernel] back to kernel!\n"); } @@ -333,10 +348,7 @@ void IOP_Kernel::sif_rpc(s32 rpcChannel, rec->cmd.started = false; rec->cmd.finished = false; - { - std::scoped_lock lock(wakeup_mtx); - wakeup_queue.push(rec->thread_to_wake); - } + iWakeupThread(rec->thread_to_wake); sif_mtx.unlock(); } @@ -383,22 +395,3 @@ void IOP_Kernel::rpc_loop(iop::sceSifQueueData* qd) { SleepThread(); } } - -void IOP_Kernel::read_disc_sectors(u32 sector, u32 sectors, void* buffer) { - if (!iso_disc_file) { - iso_disc_file = file_util::open_file("./disc.iso", "rb"); - } - - ASSERT(iso_disc_file); - if (fseek(iso_disc_file, sector * 0x800, SEEK_SET)) { - ASSERT(false); - } - auto rv = fread(buffer, sectors * 0x800, 1, iso_disc_file); - ASSERT(rv == 1); -} - -IOP_Kernel::~IOP_Kernel() { - if (iso_disc_file) { - fclose(iso_disc_file); - } -} diff --git a/game/system/IOP_Kernel.h b/game/system/IOP_Kernel.h index 7d9db68645..b8a5b51389 100644 --- a/game/system/IOP_Kernel.h +++ b/game/system/IOP_Kernel.h @@ -1,12 +1,10 @@ #pragma once -#ifndef JAK_IOP_KERNEL_H -#define JAK_IOP_KERNEL_H - #include #include #include #include +#include #include #include #include @@ -104,15 +102,14 @@ class IOP_Kernel { kernel_thread = co_active(); } - ~IOP_Kernel(); - s32 CreateThread(std::string n, void (*f)(), u32 priority); s32 ExitThread(); void StartThread(s32 id); void DelayThread(u32 usec); void SleepThread(); void WakeupThread(s32 id); - time_stamp dispatch(); + void iWakeupThread(s32 id); + std::optional dispatch(); void set_rpc_queue(iop::sceSifQueueData* qd, u32 thread); void rpc_loop(iop::sceSifQueueData* qd); void shutdown(); @@ -154,6 +151,8 @@ class IOP_Kernel { return gotSomething ? KE_OK : KE_MBOX_NOMSG; } + s32 PeekMbx(s32 mbx) { return !mbxs[mbx].empty(); } + /*! * Push something into a mbx */ @@ -180,7 +179,6 @@ class IOP_Kernel { void signal_vblank() { vblank_recieved = true; }; - void read_disc_sectors(u32 sector, u32 sectors, void* buffer); bool sif_busy(u32 id); void sif_rpc(s32 rpcChannel, @@ -198,7 +196,7 @@ class IOP_Kernel { void processWakeups(); IopThread* schedNext(); - time_stamp nextWakeup(); + std::optional nextWakeup(); s32 (*vblank_handler)(void*); std::atomic_bool vblank_recieved = false; @@ -212,8 +210,5 @@ class IOP_Kernel { std::vector semas; std::queue wakeup_queue; bool mainThreadSleep = false; - FILE* iso_disc_file = nullptr; std::mutex sif_mtx, wakeup_mtx; }; - -#endif // JAK_IOP_KERNEL_H diff --git a/goal_src/jak1/engine/dma/dma.gc b/goal_src/jak1/engine/dma/dma.gc index 6a122eb69a..2b396da20e 100644 --- a/goal_src/jak1/engine/dma/dma.gc +++ b/goal_src/jak1/engine/dma/dma.gc @@ -155,6 +155,11 @@ (defun dma-send-to-spr ((sadr uint) (madr uint) (qwc uint) (sync symbol)) "Transfer data to spr" (local-vars (s5-0 dma-bank-spr)) + + (#when PC_PORT + (return 0) + ) + (set! s5-0 SPR_TO_BANK) (dma-sync (the-as pointer s5-0) 0 0) (flush-cache 0) @@ -173,6 +178,10 @@ (defun dma-send-to-spr-no-flush ((sadr uint) (madr uint) (qwc uint) (sync symbol)) "Transfer to spr. Doesn't flush the cache first, so be careful." (local-vars (s5-0 dma-bank-spr)) + (#when PC_PORT + (return 0) + ) + (set! s5-0 SPR_TO_BANK) (dma-sync (the-as pointer s5-0) 0 0) (.sync.l) @@ -189,6 +198,10 @@ (defun dma-send-from-spr ((madr uint) (sadr uint) (qwc uint) (sync symbol)) "Transfer from spr." (local-vars (s5-0 dma-bank-spr)) + (#when PC_PORT + (return 0) + ) + (set! s5-0 SPR_FROM_BANK) (dma-sync (the-as pointer s5-0) 0 0) (flush-cache 0) @@ -206,6 +219,10 @@ (defun dma-send-from-spr-no-flush ((madr uint) (sadr uint) (qwc uint) (sync symbol)) "Transfer from spr, don't flush the cache." (local-vars (s5-0 dma-bank-spr)) + (#when PC_PORT + (return 0) + ) + (set! s5-0 SPR_FROM_BANK) (dma-sync (the-as pointer s5-0) 0 0) (.sync.l) diff --git a/goal_src/jak1/engine/gfx/hw/display-h.gc b/goal_src/jak1/engine/gfx/hw/display-h.gc index 680d02d2ba..daf9cd6b51 100644 --- a/goal_src/jak1/engine/gfx/hw/display-h.gc +++ b/goal_src/jak1/engine/gfx/hw/display-h.gc @@ -59,6 +59,9 @@ "Begin DMA transfer to the GIF/GS to send a draw env packet. The length of the transfer is taken from the nloop field of the tag." ;; this is a workaround for OpenGOAL not supporting 128-bitfield access yet. + (#when PC_PORT + (return #f) + ) (let ((packet64 (the-as (pointer gif-tag64) packet))) (dma-send GIF_DMA_BANK (the-as uint packet) diff --git a/goal_src/jak1/kernel/gcommon.gc b/goal_src/jak1/kernel/gcommon.gc index 30d43c898d..78a17ff6e0 100644 --- a/goal_src/jak1/kernel/gcommon.gc +++ b/goal_src/jak1/kernel/gcommon.gc @@ -22,7 +22,7 @@ ;; redirects access to EE memory mapped registers through get-vm-ptr to valid addresses that ;; are monitored in the runtime for debugging. -(defglobalconstant USE_VM #t) +(defglobalconstant USE_VM #f) ;; enables the with-profiler statements, which send profiling data from ;; GOAL code to the frame profiler in C++. diff --git a/goal_src/jak2/engine/ambient/ambient.gc b/goal_src/jak2/engine/ambient/ambient.gc index 815c53d084..d42952674f 100644 --- a/goal_src/jak2/engine/ambient/ambient.gc +++ b/goal_src/jak2/engine/ambient/ambient.gc @@ -359,8 +359,6 @@ (if (and (or (zero? (-> self voice-id)) (= (get-status *gui-control* (-> self voice-id)) (gui-status ready))) (or (zero? (-> self message-id)) (= (get-status *gui-control* (-> self message-id)) (gui-status active))) ) - ;; TODO - remove duplicate once gui-control is fixed - (go-virtual active) (go-virtual active) ) (suspend) diff --git a/goal_src/jak2/engine/load/loader.gc b/goal_src/jak2/engine/load/loader.gc index 08c2469d88..fb8d983358 100644 --- a/goal_src/jak2/engine/load/loader.gc +++ b/goal_src/jak2/engine/load/loader.gc @@ -789,7 +789,7 @@ ;; to point to hacked versions if STREAM_PLAY_HACK is true, otherwise it just maps to the original ;; version. -(defglobalconstant STREAM_PLAY_HACK #t) +(defglobalconstant STREAM_PLAY_HACK #f) (#cond (STREAM_PLAY_HACK (define *hack-pos-buffer-id* (new 'static 'array int 4)) ;; 4 channels? diff --git a/goal_src/jak2/game.gp b/goal_src/jak2/game.gp index 4ac8598bf9..3698b3e4e8 100644 --- a/goal_src/jak2/game.gp +++ b/goal_src/jak2/game.gp @@ -295,7 +295,7 @@ ;; MUSIC ;;;;;;;;;;;;;;;;;;;;; -(copy-vag-files "ENG") +(copy-vag-files "ENG" "FRE" "GER" "ITA" "JAP" "KOR" "SPA") (copy-sbk-files "ASHTAN1" "ASHTAN2" "ATOLL1" "ATOLL2" "ATOLL3" "ATOLL4" diff --git a/goal_src/jak2/levels/atoll/sig0-course.gc b/goal_src/jak2/levels/atoll/sig0-course.gc index 8814c71745..497559e80a 100644 --- a/goal_src/jak2/levels/atoll/sig0-course.gc +++ b/goal_src/jak2/levels/atoll/sig0-course.gc @@ -2582,8 +2582,7 @@ :on-update (lambda ((arg0 sig-atoll)) (with-pp (cond - ;; TODO remove when VAG streams work - (#f ;; ((not (speech-playing? arg0 27)) + ((not (speech-playing? arg0 27)) (if (>= (- (-> pp clock frame-counter) (-> arg0 waypoint-time0)) (seconds 0.5)) (play-speech arg0 27) ) diff --git a/goal_src/jak2/levels/castle/boss/castle-baron.gc b/goal_src/jak2/levels/castle/boss/castle-baron.gc index ae5485f053..9451ab33da 100644 --- a/goal_src/jak2/levels/castle/boss/castle-baron.gc +++ b/goal_src/jak2/levels/castle/boss/castle-baron.gc @@ -3313,10 +3313,9 @@ For example for an elevator pre-compute the distance between the first and last (ja-eval) (suspend) ) - ;; TODO uncomment when VAG streams work - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self id)))) + (suspend) + ) (set! (-> self movie-handle) (ppointer->handle (process-spawn scene-player :init scene-player-init diff --git a/goal_src/jak2/levels/common/ai/bot.gc b/goal_src/jak2/levels/common/ai/bot.gc index 031bfefb34..5c0ad9fc0f 100644 --- a/goal_src/jak2/levels/common/ai/bot.gc +++ b/goal_src/jak2/levels/common/ai/bot.gc @@ -1323,8 +1323,6 @@ If the player is too far, play a warning speech." (defmethod channel-active? bot ((obj bot) (channel uint)) "Is the given [[gui-channel]] active?" - ;; TODO remove early return when VAG streams work - (return #f) (if (zero? channel) (set! channel (-> obj channel)) ) diff --git a/goal_src/jak2/levels/dig/dig-obs.gc b/goal_src/jak2/levels/dig/dig-obs.gc index d7d0dd8f1c..fd04aa5f7b 100644 --- a/goal_src/jak2/levels/dig/dig-obs.gc +++ b/goal_src/jak2/levels/dig/dig-obs.gc @@ -575,10 +575,9 @@ (suspend) (set! v1-12 (and *target* (not (focus-test? *target* in-air)) (process-grab? *target* #f))) ) - ;; TODO uncomment when VAG streams work - ;; (while (!= (get-status *gui-control* s5-0) (gui-status ready)) - ;; (suspend) - ;; ) + (while (!= (get-status *gui-control* s5-0) (gui-status ready)) + (suspend) + ) (set! (-> self state-time) (-> self clock frame-counter)) (until (>= (- (-> self clock frame-counter) (-> self state-time)) (seconds 0.2)) (suspend) diff --git a/goal_src/jak2/levels/gungame/gungame-obs.gc b/goal_src/jak2/levels/gungame/gungame-obs.gc index eeffa5a8ba..6b772b14a7 100644 --- a/goal_src/jak2/levels/gungame/gungame-obs.gc +++ b/goal_src/jak2/levels/gungame/gungame-obs.gc @@ -221,7 +221,7 @@ This commonly includes things such as: ) (defmethod render-text training-manager ((obj training-manager) (arg0 text-id)) - (when #t ;; TODO - disabled until sound is working (= (get-status *gui-control* (-> obj gui-id)) (gui-status active)) + (when (= (get-status *gui-control* (-> obj gui-id)) (gui-status active)) (let ((s5-1 (new 'stack 'font-context *font-default-matrix* 32 290 0.0 (font-color default) (font-flags shadow kerning)) ) @@ -276,10 +276,9 @@ This commonly includes things such as: (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "sigc003" -99.0 0) ) - ;; TODO - disable until sound is ready - ;; (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) + (suspend) + ) (until (cpad-pressed? 0 r1) (render-text self (text-id gungame-tutorial-fire-button)) (suspend) @@ -296,10 +295,9 @@ This commonly includes things such as: (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "sigc007" -99.0 0) ) - ;; TODO - disable until sound is ready - ;; (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) + (suspend) + ) (when *target* (while (focus-test? *target* gun) (render-text self (text-id gungame-tutorial-put-red-away)) @@ -312,10 +310,9 @@ This commonly includes things such as: (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "sigc009" -99.0 0) ) - ;; TODO - disable until sound is ready - ;; (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) + (suspend) + ) (while (or (not *target*) (not (logtest? (focus-status gun) (-> *target* focus-status)))) (render-text self (text-id gungame-tutorial-take-red-out)) (suspend) @@ -326,10 +323,9 @@ This commonly includes things such as: (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "sigc011" -99.0 0) ) - ;; TODO - disable until sound is ready - ;; (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) + (suspend) + ) (when (nonzero? (training-manager-method-26 self)) (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "sigc012" -99.0 0) @@ -347,10 +343,9 @@ This commonly includes things such as: (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "sigc014" -99.0 0) ) - ;; TODO - disable until sound is ready - ;; (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) + (suspend) + ) (task-node-close! (game-task-node city-red-gun-training-introduction)) (go-virtual red-training) (none) @@ -1004,10 +999,9 @@ This commonly includes things such as: (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "sigc017" -99.0 0) ) - ;; TODO - disable until sound is ready - ;; (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) + (suspend) + ) (let ((gp-2 (-> *game-info* gun-type))) (until (!= gp-2 (-> *game-info* gun-type)) (render-text self (text-id gungame-tutorial-switch-to-yellow)) @@ -1020,10 +1014,9 @@ This commonly includes things such as: (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "sigc075" -99.0 0) ) - ;; TODO - disable until sound is ready - ;; (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) + (suspend) + ) (set! (-> self combo-done?) #f) (until #f (let ((gp-3 *yellow-training-path-combo-info*)) @@ -1048,10 +1041,9 @@ This commonly includes things such as: (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "sigc080" -99.0 0) ) - ;; TODO - disable until sound is ready - ;; (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) + (suspend) + ) #t (goto cfg-61) ) @@ -1059,10 +1051,9 @@ This commonly includes things such as: (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "sigc077" -99.0 0) ) - ;; TODO - disable until sound is ready - ;; (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) + (suspend) + ) ) ) ) @@ -1074,10 +1065,9 @@ This commonly includes things such as: (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "sigc022" -99.0 0) ) - ;; TODO - disable until sound is ready - ;; (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) + (suspend) + ) (task-node-close! (game-task-node city-yellow-gun-training-introduction)) (go yellow-training) (none) @@ -1834,10 +1824,9 @@ This commonly includes things such as: (none) ) :code (behavior () - ;; TODO - disable until sound is ready - ;; (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (-> self last-sound-id))) + (suspend) + ) (when (> (-> self egg-count) 0) (let* ((gp-0 (handle->process (-> self voicebox))) (v1-8 (if (type? gp-0 process-drawable) diff --git a/goal_src/jak2/levels/mars_tomb/left/chase/tomb-boulder.gc b/goal_src/jak2/levels/mars_tomb/left/chase/tomb-boulder.gc index 7e48bff7d8..31dfa7faca 100644 --- a/goal_src/jak2/levels/mars_tomb/left/chase/tomb-boulder.gc +++ b/goal_src/jak2/levels/mars_tomb/left/chase/tomb-boulder.gc @@ -759,11 +759,10 @@ (add-process *gui-control* self (gui-channel art-load-next) (gui-action queue) (-> self anim name) -1.0 0) ) ) - ;; TODO remove when VAG streams work - #|(while (!= (get-status *gui-control* (the-as sound-id (-> self gui-id))) (gui-status ready)) + (while (!= (get-status *gui-control* (the-as sound-id (-> self gui-id))) (gui-status ready)) (set-blackout-frames (seconds 0.1)) (suspend) - )|# + ) (let ((v1-7 (lookup-gui-connection *gui-control* self diff --git a/goal_src/jak2/levels/stadium/jetboard/skatea-obs.gc b/goal_src/jak2/levels/stadium/jetboard/skatea-obs.gc index fa1c988c72..1268aba67c 100644 --- a/goal_src/jak2/levels/stadium/jetboard/skatea-obs.gc +++ b/goal_src/jak2/levels/stadium/jetboard/skatea-obs.gc @@ -62,7 +62,7 @@ (defmethod render-text hoverboard-training-manager ((obj hoverboard-training-manager) (arg0 text-id)) - (when #t ;; TODO - no streaming audio yet (= (get-status *gui-control* (the-as sound-id (-> obj gui-id))) (gui-status active)) + (when (= (get-status *gui-control* (the-as sound-id (-> obj gui-id))) (gui-status active)) (let ((s5-1 (new 'stack 'font-context @@ -329,10 +329,9 @@ (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "kei002" -99.0 0) ) - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (send-event (handle->process (-> self voicebox)) 'speak-effect #f) (send-event *target* 'get-notify self) (set! (-> self trick-type) (board-tricks none)) @@ -355,10 +354,9 @@ :virtual #t :event hoverboard-training-manager-event-handler :code (behavior () - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (send-event (handle->process (-> self voicebox)) 'speak-effect #f) (let ((gp-0 (-> self clock frame-counter))) (until (>= (- (-> self clock frame-counter) gp-0) (seconds 1)) @@ -369,10 +367,9 @@ (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "kei006" -99.0 0) ) - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (send-event (handle->process (-> self voicebox)) 'speak-effect #f) (send-event *target* 'get-notify self) (set! (-> self trick-type) (board-tricks none)) @@ -399,10 +396,9 @@ (none) ) :code (behavior () - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (send-event (handle->process (-> self voicebox)) 'speak-effect #f) (let ((gp-0 (-> self clock frame-counter))) (until (>= (- (-> self clock frame-counter) gp-0) (seconds 1)) @@ -476,10 +472,9 @@ (none) ) :code (behavior () - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (let ((gp-0 (-> self clock frame-counter))) (until (>= (- (-> self clock frame-counter) gp-0) (seconds 1)) (suspend) @@ -542,10 +537,9 @@ :virtual #t :event hoverboard-training-manager-event-handler :code (behavior () - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (send-event (handle->process (-> self voicebox)) 'speak-effect #f) (let ((gp-0 (-> self clock frame-counter))) (until (>= (- (-> self clock frame-counter) gp-0) (seconds 1)) @@ -559,10 +553,9 @@ (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "kei011" -99.0 0) ) - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (send-event (handle->process (-> self voicebox)) 'speak-effect #f) (send-event *target* 'get-notify self) (set! (-> self trick-type) (board-tricks none)) @@ -585,10 +578,9 @@ :virtual #t :event hoverboard-training-manager-event-handler :code (behavior () - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (send-event (handle->process (-> self voicebox)) 'speak-effect #f) (let ((gp-0 (-> self clock frame-counter))) (until (>= (- (-> self clock frame-counter) gp-0) (seconds 1)) @@ -599,10 +591,9 @@ (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "kei016" -99.0 0) ) - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (send-event (handle->process (-> self voicebox)) 'speak-effect #f) (send-event *target* 'get-notify self) (set! (-> self trick-type) (board-tricks none)) @@ -625,10 +616,9 @@ :virtual #t :event hoverboard-training-manager-event-handler :code (behavior () - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (send-event (handle->process (-> self voicebox)) 'speak-effect #f) (let ((gp-0 (-> self clock frame-counter))) (until (>= (- (-> self clock frame-counter) gp-0) (seconds 1)) @@ -639,10 +629,9 @@ (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "kei017" -99.0 0) ) - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (send-event (handle->process (-> self voicebox)) 'speak-effect #f) (send-event *target* 'get-notify self) (set! (-> self trick-type) (board-tricks none)) @@ -673,10 +662,9 @@ :virtual #t :event hoverboard-training-manager-event-handler :code (behavior () - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (send-event (handle->process (-> self voicebox)) 'speak-effect #f) (send-event (handle->process (-> self voicebox)) 'speak-effect #t) (set! (-> self last-sound-id) @@ -685,10 +673,9 @@ (set! (-> self last-sound-id) (add-process *gui-control* self (gui-channel sig) (gui-action play) "kei019" -99.0 0) ) - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id (-> self last-sound-id)))) + (suspend) + ) (send-event (handle->process (-> self voicebox)) 'speak-effect #f) (when (!= (-> self voicebox) #f) (send-event (handle->process (-> self voicebox)) 'die) @@ -1098,10 +1085,9 @@ ) ) ) - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id s5-0))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id s5-0))) + (suspend) + ) (let* ((s5-1 (handle->process gp-3)) (v1-97 (if (type? s5-1 process-drawable) (the-as process-drawable s5-1) @@ -1301,10 +1287,9 @@ ) ) ) - ;; TODO - no streaming audio - ;; (while (nonzero? (get-status *gui-control* (the-as sound-id s5-0))) - ;; (suspend) - ;; ) + (while (nonzero? (get-status *gui-control* (the-as sound-id s5-0))) + (suspend) + ) (let* ((s5-1 (handle->process gp-2)) (v1-44 (if (type? s5-1 process-drawable) (the-as process-drawable s5-1) diff --git a/goal_src/jak2/levels/temple/mountain-obs.gc b/goal_src/jak2/levels/temple/mountain-obs.gc index ea13d9ae8d..cc4b5a4fa0 100644 --- a/goal_src/jak2/levels/temple/mountain-obs.gc +++ b/goal_src/jak2/levels/temple/mountain-obs.gc @@ -2277,7 +2277,7 @@ This commonly includes things such as: (+! gp-0 1) ) ) - ;; TODO - disabled to let the rocks fall down + ;; TODO - disabled to let the rocks fall down, not yet solved by overlord branch ;; (let ((gp-1 ;; (add-process *gui-control* self (gui-channel art-load-next) (gui-action queue) (-> self anim name) -1.0 0) ;; ) diff --git a/goal_src/jak2/levels/underport/underb-master.gc b/goal_src/jak2/levels/underport/underb-master.gc index 4a9a43b7d9..11802e951f 100644 --- a/goal_src/jak2/levels/underport/underb-master.gc +++ b/goal_src/jak2/levels/underport/underb-master.gc @@ -901,8 +901,7 @@ ) :trans (behavior () (when (and (zero? (-> self state-time)) - ;; TODO remove when gui-control works - ;; (= (get-status *gui-control* (the-as sound-id (-> self spooled-sound-id))) (gui-status ready)) + (= (get-status *gui-control* (the-as sound-id (-> self spooled-sound-id))) (gui-status ready)) ) (set! (-> self state-time) (-> self clock frame-counter)) (set! (-> self last-reminder-time) (-> self clock frame-counter)) @@ -1008,8 +1007,7 @@ ) :trans (behavior () (when (and (zero? (-> self state-time)) - ;; TODO this always returns false? - ;; (= (get-status *gui-control* (the-as sound-id (-> self spooled-sound-id))) (gui-status ready)) + (= (get-status *gui-control* (the-as sound-id (-> self spooled-sound-id))) (gui-status ready)) ) (set! (-> self state-time) (-> self clock frame-counter)) (set! (-> self last-reminder-time) (-> self clock frame-counter)) diff --git a/test/common/formatter/test_formatter.cpp b/test/common/formatter/test_formatter.cpp index 0c69bb56ea..0239c9005f 100644 --- a/test/common/formatter/test_formatter.cpp +++ b/test/common/formatter/test_formatter.cpp @@ -39,7 +39,7 @@ bool run_tests(fs::path file_path) { const auto contents = str_util::split(file_util::read_text_file(file_path)); std::vector tests; TestDefinition curr_test; - int i = 0; + size_t i = 0; while (i < contents.size()) { const auto& line = contents.at(i); if (line == "===") {