mirror of
https://github.com/open-goal/jak-project
synced 2026-08-30 17:30:03 -04:00
jak2: overlord rework (#2544)
Fixes #2545 Fixes #2546 Fixes #2547 Fixes #2548 Fixes #2549 Fixes #2550 Fixes #2551 Fixes #2552 Fixes #2553 Fixes #2554 Fixes #2555 Fixes #2556 Fixes #2557 Fixes #2558 Fixes #2559 Fixes #2560 Fixes #2561 Fixes #2562 Fixes #2563 Fixes #2564 Fixes #2565 Fixes #2567 Fixes #2566 Fixes #2568 Fixes #2569 Fixes #2570 Fixes #2522 Fixes #2571 --------- Co-authored-by: water <awaterford111445@gmail.com> Co-authored-by: Hat Kid <6624576+Hat-Kid@users.noreply.github.com> Co-authored-by: ManDude <7569514+ManDude@users.noreply.github.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -532,7 +532,7 @@ std::string decompile_sparticle_launcher_by_id(const std::vector<LinkedWord>& wo
|
||||
|
||||
std::string decompile_sparticle_flags(const std::vector<LinkedWord>& 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);
|
||||
|
||||
|
||||
+36
-14
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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<bool()> 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");
|
||||
|
||||
@@ -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<u8> 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;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
/*!
|
||||
|
||||
+3
-3
@@ -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<std::string> 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 =
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
void DMA_SendToEE(void* data, u32 size, void* dest);
|
||||
void DMA_Sync();
|
||||
@@ -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 <cstring>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "iso.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "iso_api.h"
|
||||
|
||||
#include "common/log/log.h"
|
||||
|
||||
#include "game/overlord/common/iso.h"
|
||||
#include "game/sce/iop.h"
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "game/overlord/common/isocommon.h"
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "overlord.h"
|
||||
|
||||
/*!
|
||||
* Loop endlessly and never return.
|
||||
*/
|
||||
void ExitIOP() {
|
||||
while (true) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void ExitIOP();
|
||||
@@ -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
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "srpc.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
// 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));
|
||||
}
|
||||
@@ -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();
|
||||
@@ -1,37 +1,21 @@
|
||||
#include "ssound.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#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<s16>(((i * 0x33ff) / 0x5a) + 0xc00);
|
||||
|
||||
s16 rear_right = static_cast<s16>(((i * -0x2800) / 0x5a) + 0x3400);
|
||||
s16 rear_left = static_cast<s16>(((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*/) {}
|
||||
@@ -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);
|
||||
@@ -1,113 +0,0 @@
|
||||
/*!
|
||||
* @file dma.cpp
|
||||
* DMA Related functions for Overlord.
|
||||
* This code is not great.
|
||||
*/
|
||||
|
||||
#include "dma.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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 <cstring>
|
||||
|
||||
#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
|
||||
@@ -1,990 +0,0 @@
|
||||
/*!
|
||||
* @file iso_cd.cpp
|
||||
* IsoFs API for accessing the CD/DVD drive.
|
||||
*/
|
||||
|
||||
#include "iso_cd.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -1,203 +0,0 @@
|
||||
/*!
|
||||
* @file isocommon.cpp
|
||||
* Common ISO utilities.
|
||||
*/
|
||||
|
||||
#include "isocommon.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#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");
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*!
|
||||
* @file dma.cpp
|
||||
* DMA Related functions for Overlord.
|
||||
* This code is not great.
|
||||
*/
|
||||
|
||||
#include "dma.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -9,10 +9,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,51 @@
|
||||
/*!
|
||||
* @file isocommon.cpp
|
||||
* Common ISO utilities.
|
||||
*/
|
||||
|
||||
#include "isocommon.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
@@ -5,59 +5,35 @@
|
||||
* Common ISO utilities.
|
||||
*/
|
||||
|
||||
#ifndef JAK_V2_ISOCOMMON_H
|
||||
#define JAK_V2_ISOCOMMON_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#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
|
||||
@@ -2,18 +2,18 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
@@ -9,19 +9,19 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
@@ -3,10 +3,8 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#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<void* (*)(unsigned int, void*, int)> 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<void* (*)(unsigned int, void*, int)> 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
|
||||
@@ -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
|
||||
@@ -0,0 +1,153 @@
|
||||
#include "ssound.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#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<s16>(((i * 0x33ff) / 0x5a) + 0xc00);
|
||||
|
||||
s16 rear_right = static_cast<s16>(((i * -0x2800) / 0x5a) + 0x3400);
|
||||
s16 rear_left = static_cast<s16>(((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
|
||||
@@ -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
|
||||
@@ -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 <cstring>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -0,0 +1,254 @@
|
||||
#include "iso_api.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
@@ -0,0 +1,758 @@
|
||||
#include "iso_cd.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
@@ -0,0 +1,698 @@
|
||||
#include "iso_queue.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,127 @@
|
||||
#include "list.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -0,0 +1,122 @@
|
||||
#include "overlord.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace jak2 {
|
||||
|
||||
int start_overlord_wrapper(int argc, const char* const* argv, bool* signal);
|
||||
|
||||
} // namespace jak2
|
||||
@@ -0,0 +1,204 @@
|
||||
#include "pages.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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<s16>(((i * 0x33ff) / 0x5a) + 0xc00);
|
||||
|
||||
s16 rear_right = static_cast<s16>(((i * -0x2800) / 0x5a) + 0x3400);
|
||||
s16 rear_left = static_cast<s16>(((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
|
||||
@@ -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
|
||||
@@ -0,0 +1,359 @@
|
||||
#include "stream.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace jak2 {
|
||||
void stream_init_globals();
|
||||
u32 STRThread();
|
||||
u32 PLAYThread();
|
||||
} // namespace jak2
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
#include "streamlfo.h"
|
||||
namespace jak2 {}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
namespace jak2 {}
|
||||
@@ -0,0 +1,633 @@
|
||||
#include "streamlist.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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;
|
||||
@@ -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 <cstring>
|
||||
|
||||
#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;
|
||||
}
|
||||
+115
-44
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+19
-6
@@ -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;
|
||||
|
||||
+5
-3
@@ -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);
|
||||
|
||||
@@ -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<std::unique_ptr<sound_handler>> SFXBlock2::make_handler(voice_manager& vm,
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -23,6 +23,7 @@ class voice {
|
||||
s16_output run();
|
||||
|
||||
void key_on();
|
||||
|
||||
void key_off();
|
||||
|
||||
bool dead() {
|
||||
|
||||
+34
-4
@@ -3,13 +3,14 @@
|
||||
#include <cstring>
|
||||
|
||||
#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<snd::voice> voice;
|
||||
u8 spu_memory[0xc060];
|
||||
std::shared_ptr<snd::voice> 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;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user