mirror of
https://github.com/open-goal/jak-project.git
synced 2026-11-07 09:26:09 -10:00
Compare commits
37
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
637b043293 | ||
|
|
46db6a36da | ||
|
|
619f39d3b7 | ||
|
|
2071c98b55 | ||
|
|
7a8aa71204 | ||
|
|
a80cff9a4c | ||
|
|
4cccaf2645 | ||
|
|
9d680a0aba | ||
|
|
b0713641e7 | ||
|
|
aa68b80da2 | ||
|
|
6901e80e7f | ||
|
|
12118e57cb | ||
|
|
349919f788 | ||
|
|
a01d78c7d4 | ||
|
|
708c15788b | ||
|
|
6cfb89a78a | ||
|
|
99da5da441 | ||
|
|
c7af284c6b | ||
|
|
3e568cb95d | ||
|
|
4b9c1dde70 | ||
|
|
35daebcce7 | ||
|
|
897e9c588b | ||
|
|
f17427bc26 | ||
|
|
168afa0e2e | ||
|
|
9b6f16f561 | ||
|
|
1808596679 | ||
|
|
94b984326f | ||
|
|
2795d3aa67 | ||
|
|
be6a6dead4 | ||
|
|
974f5931de | ||
|
|
e119a66788 | ||
|
|
37069e2f8e | ||
|
|
dfa6622544 | ||
|
|
a3af37989b | ||
|
|
a01182315b | ||
|
|
e38fe70ac4 | ||
|
|
956645bdb9 |
No files matched your search
@@ -63,7 +63,7 @@ jobs:
|
||||
python ./scripts/docs/append-file-docs.py
|
||||
|
||||
- name: Upload Docs Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: opengoal-docs
|
||||
if-no-files-found: error
|
||||
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
strip ./build/lsp/lsp
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.uploadArtifacts }}
|
||||
with:
|
||||
name: opengoal-linux-${{ inputs.cachePrefix }}
|
||||
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
run: ./test.sh
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: opengoal-macos-${{ inputs.cachePrefix }}
|
||||
if-no-files-found: error
|
||||
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
strip ./build/lsp/lsp
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.uploadArtifacts }}
|
||||
with:
|
||||
name: opengoal-macos-${{ inputs.cachePrefix }}
|
||||
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
- name: Prepare Artifact Folder
|
||||
run: mkdir -p ./ci-artifacts/final
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
name: Download all Artifacts
|
||||
with:
|
||||
path: ./ci-artifacts/
|
||||
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
run: ./build/bin/goalc-test.exe --gtest_color=yes --gtest_brief=0 --gtest_filter="-*MANUAL_TEST*"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.uploadArtifacts }}
|
||||
with:
|
||||
name: opengoal-windows-${{ inputs.cachePrefix }}
|
||||
|
||||
@@ -218,6 +218,19 @@
|
||||
"--config-override \"{\\\"decompile_code\\\": false, \\\"levels_extract\\\": true, \\\"allowed_objects\\\": []}\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "decompiler.exe (bin\\decompiler.exe)",
|
||||
"name": "Decompiler - Jak 3",
|
||||
"args": [
|
||||
"${workspaceRoot}/decompiler/config/jak3/jak3_config.jsonc",
|
||||
"${workspaceRoot}/iso_data",
|
||||
"${workspaceRoot}/decompiler_out",
|
||||
"--version",
|
||||
"ntsc_v1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
|
||||
Vendored
+1
-1
@@ -5,7 +5,7 @@
|
||||
"comments": true,
|
||||
"strings": true
|
||||
},
|
||||
"editor.wordBasedSuggestions": true,
|
||||
"editor.wordBasedSuggestions": "matchingDocuments",
|
||||
"editor.snippetSuggestions": "top"
|
||||
},
|
||||
"python.formatting.provider": "black",
|
||||
|
||||
@@ -42,6 +42,7 @@ void ShrubDraw::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&num_triangles);
|
||||
ser.from_ptr(&first_index_index);
|
||||
ser.from_ptr(&num_indices);
|
||||
ser.from_ptr(&proto_idx);
|
||||
}
|
||||
|
||||
void InstancedStripDraw::serialize(Serializer& ser) {
|
||||
@@ -416,6 +417,9 @@ void ShrubTree::serialize(Serializer& ser) {
|
||||
for (auto& draw : static_draws) {
|
||||
draw.serialize(ser);
|
||||
}
|
||||
|
||||
ser.from_ptr(&has_per_proto_visibility_toggle);
|
||||
ser.from_string_vector(&proto_names);
|
||||
}
|
||||
|
||||
void BVH::serialize(Serializer& ser) {
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace tfrag3 {
|
||||
// - if changing any large things (vertices, vis, bvh, colors, textures) update get_memory_usage
|
||||
// - if adding a new category to the memory usage, update extract_level to print it.
|
||||
|
||||
constexpr int TFRAG3_VERSION = 38;
|
||||
constexpr int TFRAG3_VERSION = 39;
|
||||
|
||||
enum MemoryUsageCategory {
|
||||
TEXTURE,
|
||||
@@ -219,6 +219,8 @@ struct ShrubDraw {
|
||||
|
||||
// for debug counting.
|
||||
u32 num_triangles = 0;
|
||||
|
||||
u16 proto_idx = 0;
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
@@ -430,6 +432,10 @@ struct ShrubTree {
|
||||
std::vector<ShrubGpuVertex> vertices; // mesh vertices
|
||||
} unpacked;
|
||||
|
||||
// jak 2 and later can toggle on and off visibility per proto by name
|
||||
bool has_per_proto_visibility_toggle = false;
|
||||
std::vector<std::string> proto_names;
|
||||
|
||||
void serialize(Serializer& ser);
|
||||
void memory_usage(MemoryUsageTracker* tracker) const;
|
||||
void unpack();
|
||||
|
||||
@@ -21,8 +21,8 @@ struct FormFormattingConfig {
|
||||
bool combine_first_two_lines =
|
||||
false; // NOTE - basically hang, but will probably stick around after hang is gone, may be
|
||||
// redundant (inline_until_index!)
|
||||
std::function<std::optional<int>(const std::vector<std::string>& curr_lines)> inline_until_index =
|
||||
[](std::vector<std::string> curr_lines) { return std::nullopt; };
|
||||
std::function<std::optional<int>(const std::vector<std::string>& /*curr_lines*/)>
|
||||
inline_until_index = [](std::vector<std::string> /*curr_lines*/) { return std::nullopt; };
|
||||
bool has_constant_pairs = false;
|
||||
bool prevent_inlining = false; // TODO - duplicate of below
|
||||
std::function<bool(FormFormattingConfig, int num_refs)> should_prevent_inlining =
|
||||
|
||||
@@ -1888,7 +1888,7 @@ Object Interpreter::eval_format(const Object& form,
|
||||
fmt::format_args(args2.data(), static_cast<unsigned>(args2.size())));
|
||||
|
||||
if (truthy(dest)) {
|
||||
lg::print(formatted.c_str());
|
||||
lg::print("{}", formatted.c_str());
|
||||
}
|
||||
|
||||
return StringObject::make_new(formatted);
|
||||
|
||||
+1
-1
@@ -106,7 +106,7 @@ void log_print(const char* message) {
|
||||
}
|
||||
|
||||
if (gLogger.stdout_log_level < lg::level::off_unless_die) {
|
||||
fmt::print(message);
|
||||
fmt::print("{}", message);
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ bool GameSubtitleDB::write_subtitle_db_to_files(const GameVersion game_version)
|
||||
file_util::write_text_file(dump_path, lines_file.dump(2));
|
||||
}
|
||||
} catch (std::exception& ex) {
|
||||
lg::error(ex.what());
|
||||
lg::error("{}", ex.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -16,12 +16,12 @@ void private_assert_failed(const char* expr,
|
||||
if (!msg || msg[0] == '\0') {
|
||||
std::string log = fmt::format("Assertion failed: '{}'\n\tSource: {}:{}\n\tFunction: {}\n", expr,
|
||||
file, line, function);
|
||||
lg::die(log);
|
||||
lg::die("{}", log);
|
||||
} else {
|
||||
std::string log =
|
||||
fmt::format("Assertion failed: '{}'\n\tMessage: {}\n\tSource: {}:{}\n\tFunction: {}\n",
|
||||
expr, msg, file, line, function);
|
||||
lg::die(log);
|
||||
lg::die("{}", log);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
@@ -12,30 +12,33 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/Assert.h"
|
||||
|
||||
#include "third-party/span.hpp"
|
||||
|
||||
class BinaryReader {
|
||||
public:
|
||||
explicit BinaryReader(const std::vector<uint8_t>& _buffer) : m_buffer(_buffer) {}
|
||||
explicit BinaryReader(nonstd::span<const uint8_t> _span) : m_span(_span) {}
|
||||
|
||||
template <typename T>
|
||||
T read() {
|
||||
ASSERT(m_seek + sizeof(T) <= m_buffer.size());
|
||||
ASSERT(m_seek + sizeof(T) <= m_span.size());
|
||||
T obj;
|
||||
memcpy(&obj, m_buffer.data() + m_seek, sizeof(T));
|
||||
memcpy(&obj, m_span.data() + m_seek, sizeof(T));
|
||||
m_seek += sizeof(T);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void ffwd(int amount) {
|
||||
m_seek += amount;
|
||||
ASSERT(m_seek <= m_buffer.size());
|
||||
ASSERT(m_seek <= m_span.size());
|
||||
}
|
||||
|
||||
uint32_t bytes_left() const { return m_buffer.size() - m_seek; }
|
||||
uint8_t* here() { return m_buffer.data() + m_seek; }
|
||||
uint32_t bytes_left() const { return m_span.size() - m_seek; }
|
||||
const uint8_t* here() { return m_span.data() + m_seek; }
|
||||
BinaryReader at(u32 pos) { return BinaryReader(m_span.subspan(pos)); }
|
||||
uint32_t get_seek() const { return m_seek; }
|
||||
void set_seek(u32 seek) { m_seek = seek; }
|
||||
|
||||
private:
|
||||
std::vector<u8> m_buffer;
|
||||
nonstd::span<const u8> m_span;
|
||||
uint32_t m_seek = 0;
|
||||
};
|
||||
@@ -21,7 +21,7 @@ void assert_string_empty_after(const char* str, int size) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_object_file_name(const std::string& original_name, u8* data, int size) {
|
||||
std::string get_object_file_name(const std::string& original_name, const u8* data, int size) {
|
||||
const std::string art_group_text_strings[] = {
|
||||
fmt::format("/src/next/data/art-group{}/", versions::jak1::ART_FILE_VERSION),
|
||||
fmt::format("/src/jak2/final/art-group{}/", versions::jak2::ART_FILE_VERSION),
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
#include "common/versions/versions.h"
|
||||
|
||||
void assert_string_empty_after(const char* str, int size);
|
||||
std::string get_object_file_name(const std::string& original_name, u8* data, int size);
|
||||
std::string get_object_file_name(const std::string& original_name, const u8* data, int size);
|
||||
@@ -20,16 +20,30 @@
|
||||
// this makes collision 2x slower and bigger, so only use if really needed
|
||||
"double_sided_collide": false,
|
||||
|
||||
// available res-lump tag data types:
|
||||
// int32, float, meters, vector, vector4m (meters)
|
||||
// available res-lump tag types:
|
||||
// value types: int32, uint32, enum-int32, enum-uint32, float, meters (1 meter = 4096.0 units), degrees (65536.0 = 360°)
|
||||
// vector types: vector (normal floats), vector4m (meters), vector3m (meters with w set to 1.0), vector-vol (normal floats with w in meters), movie-pos (meters with w in degrees)
|
||||
// special types: eco-info, water-height
|
||||
//
|
||||
// examples:
|
||||
//
|
||||
// adds a float tag 'spring-height' with value of 200 meters (1 meter = 4096.0 units):
|
||||
// "spring-height": ["meters", 200.0]
|
||||
//
|
||||
// adds a vector tag 'movie-pos':
|
||||
// "movie-pos": ["vector", [4096000.0, -176128.0, 1353973.76, 1.0]]
|
||||
// adds a degrees tag 'rotoffset':
|
||||
// "rotoffset": ["degrees", -45.0]
|
||||
//
|
||||
// adds a movie-pos tag:
|
||||
// "movie-pos": ["movie-pos", [100.22, -25.3, 99.5, 180.0]]
|
||||
//
|
||||
// adds an enum tag 'options':
|
||||
// "options": ["enum-int32", "(fact-options large)"]
|
||||
//
|
||||
// adds a water-height tag:
|
||||
// "water-height": ["water-height", 25.0, 0.5, 2.0, "(water-flags wt08 wt03 wt01)"]
|
||||
//
|
||||
// adds an eco-info tag:
|
||||
// "eco-info": ["eco-info", "(pickup-type health)", 2]
|
||||
|
||||
// The base actor id for your custom level. If you have multiple levels this should be unique!
|
||||
"base_id": 100,
|
||||
@@ -65,7 +79,7 @@
|
||||
"lump": {
|
||||
"name": "test-ambient",
|
||||
"type": "'hint",
|
||||
"text-id": ["int32", 557], // text id for the "POWER CELL" text
|
||||
"text-id": ["enum-uint32", "(text-id fuel-cell)"], // text id for the "POWER CELL" text
|
||||
"play-mode": "'notice"
|
||||
}
|
||||
}
|
||||
@@ -75,7 +89,7 @@
|
||||
{
|
||||
"trans": [-21.6238, 20.0496, 17.1191], // translation
|
||||
"etype": "fuel-cell", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-21.6238, 19.3496, 17.1191, 10], // bounding sphere
|
||||
"lump": {
|
||||
@@ -86,20 +100,20 @@
|
||||
{
|
||||
"trans": [-15.2818, 15.2461, 17.1360], // translation
|
||||
"etype": "crate", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-crate",
|
||||
"crate-type": "'steel",
|
||||
"eco-info": ["int32", 5, 10]
|
||||
"eco-info": ["eco-info", "(pickup-type money)", 10]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"trans": [-5.4630, 17.4553, 1.6169], // translation
|
||||
"etype": "eco-yellow", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere
|
||||
"lump": {
|
||||
@@ -109,7 +123,7 @@
|
||||
// {
|
||||
// "trans": [-7.41, 3.5, 28.42], // translation
|
||||
// "etype": "plat", // actor type
|
||||
// "game_task": 0, // associated game task (for powercells, etc)
|
||||
// "game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
// "quat": [0, 0, 0, 1], // quaternion
|
||||
// "bsphere": [-7.41, 3.5, 28.42, 10], // bounding sphere
|
||||
// "lump": {
|
||||
|
||||
@@ -20,24 +20,37 @@
|
||||
// this makes collision 2x slower and bigger, so only use if really needed
|
||||
"double_sided_collide": false,
|
||||
|
||||
// available res-lump tag data types:
|
||||
// int32, float, meters, vector, vector4m (meters)
|
||||
// available res-lump tag types:
|
||||
// value types: int32, uint32, enum-int32, enum-uint32, float, meters (1 meter = 4096.0 units), degrees (65536.0 = 360°)
|
||||
// vector types: vector (normal floats), vector4m (meters), vector3m (meters with w set to 1.0), vector-vol (normal floats with w in meters), movie-pos (meters with w in degrees)
|
||||
// special types: eco-info, water-height
|
||||
//
|
||||
// examples:
|
||||
//
|
||||
// adds a float tag 'spring-height' with value of 200 meters (1 meter = 4096.0 units):
|
||||
// "spring-height": ["meters", 200.0]
|
||||
//
|
||||
// adds a vector tag 'movie-pos':
|
||||
// "movie-pos": ["vector", [4096000.0, -176128.0, 1353973.76, 1.0]]
|
||||
// adds a degrees tag 'rotoffset':
|
||||
// "rotoffset": ["degrees", -45.0]
|
||||
//
|
||||
// adds a movie-pos tag:
|
||||
// "movie-pos": ["movie-pos", [100.22, -25.3, 99.5, 180.0]]
|
||||
//
|
||||
// adds an enum tag 'options':
|
||||
// "options": ["enum-int32", "(fact-options large)"]
|
||||
//
|
||||
// adds a water-height tag:
|
||||
// "water-height": ["water-height", 25.0, 0.5, 2.0, "(water-flags can-swim can-wade)"]
|
||||
//
|
||||
// adds an eco-info tag:
|
||||
// "eco-info": ["eco-info", "(pickup-type health)", 2]
|
||||
|
||||
// The base actor id for your custom level. If you have multiple levels, this should be unique!
|
||||
"base_id": 100,
|
||||
|
||||
// All art groups you want to use in your custom level. Will add their models and corresponding textures to the FR3 file.
|
||||
// Removed so that the release builds don't have to double-decompile the game
|
||||
//"art_groups": ["prsn-torture-ag"],
|
||||
"art_groups": [],
|
||||
// "art_groups": ["prsn-torture-ag"],
|
||||
|
||||
// Any textures you want to include in your custom level.
|
||||
// This is mainly useful for textures which are not in the common level files and have no art group associated with them.
|
||||
@@ -55,14 +68,14 @@
|
||||
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-crate",
|
||||
"eco-info": ["int32", 18, 2]
|
||||
"eco-info": ["eco-info", "(pickup-type health)", 2]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"trans": [-5.4630, 17.4553, 1.6169], // translation
|
||||
"etype": "eco-yellow", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"kill_mask": 0,
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere
|
||||
@@ -74,7 +87,7 @@
|
||||
{
|
||||
"trans": [-7.41, 13.5, 28.42], // translation
|
||||
"etype": "prsn-torture", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-7.41, 13.5, 28.42, 10], // bounding sphere
|
||||
"lump": {
|
||||
|
||||
@@ -3141,11 +3141,11 @@ goos::Object DefskelgroupElement::to_form_internal(const Env& env) const {
|
||||
}
|
||||
if (m_static_info.shadow_joint_index != 0) {
|
||||
forms.push_back(pretty_print::to_symbol(
|
||||
fmt::format(":shadow-joint-index {}", m_static_info.origin_joint_index)));
|
||||
fmt::format(":shadow-joint-index {}", m_static_info.shadow_joint_index)));
|
||||
}
|
||||
if (m_static_info.light_index != 0) {
|
||||
forms.push_back(pretty_print::to_symbol(
|
||||
fmt::format(":light-index {}", m_static_info.origin_joint_index)));
|
||||
forms.push_back(
|
||||
pretty_print::to_symbol(fmt::format(":light-index {}", m_static_info.light_index)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,13 +222,14 @@ class ObjectFileDB {
|
||||
void ir2_setup_labels(const Config& config, ObjectFileData& data);
|
||||
void ir2_run_mips2c(const Config& config, ObjectFileData& data);
|
||||
struct PerObjectAllTypeInfo {
|
||||
std::string object_name;
|
||||
std::unordered_set<std::string> already_seen_symbols;
|
||||
|
||||
// type-name : { method id : state name }
|
||||
std::unordered_map<std::string, std::unordered_map<int, std::string>> state_methods;
|
||||
// symbol-name : type-name
|
||||
std::unordered_map<std::string, std::string> symbol_types;
|
||||
// state-name : type-name
|
||||
std::unordered_map<std::string, std::string> non_virtual_state_guesses;
|
||||
|
||||
struct TypeInfo {
|
||||
bool from_inspect_method = false; // does this come from an inspect method?
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "common/util/Timer.h"
|
||||
#include "common/util/string_util.h"
|
||||
|
||||
#include "decompiler/IR2/Form.h"
|
||||
#include "decompiler/analysis/analyze_inspect_method.h"
|
||||
@@ -319,7 +320,7 @@ void ObjectFileDB::ir2_top_level_pass(const Config& config) {
|
||||
void ObjectFileDB::ir2_analyze_all_types(const fs::path& output_file,
|
||||
const std::optional<std::string>& previous_game_types,
|
||||
const std::unordered_set<std::string>& bad_types) {
|
||||
std::vector<PerObjectAllTypeInfo> per_object;
|
||||
std::unordered_map<std::string, PerObjectAllTypeInfo> per_object;
|
||||
|
||||
DecompilerTypeSystem previous_game_ts(GameVersion::Jak2); // version here doesn't matter.
|
||||
if (previous_game_types) {
|
||||
@@ -328,16 +329,66 @@ void ObjectFileDB::ir2_analyze_all_types(const fs::path& output_file,
|
||||
|
||||
TypeInspectorCache ti_cache;
|
||||
|
||||
// Do a first pass to initialize all types and symbols
|
||||
for_each_obj([&](ObjectFileData& data) {
|
||||
if (data.obj_version == 3 || (data.obj_version == 5 && data.linked_data.has_any_functions())) {
|
||||
auto& object_result = per_object.emplace_back();
|
||||
object_result.object_name = data.to_unique_name();
|
||||
|
||||
per_object[data.to_unique_name()] = PerObjectAllTypeInfo();
|
||||
// Go through the top-level segment first to identify the type names associated with each
|
||||
// symbol def
|
||||
for_each_function_in_seg_in_obj(TOP_LEVEL_SEGMENT, data, [&](Function& f) {
|
||||
inspect_top_level_for_metadata(f, data.linked_data, dts, previous_game_ts, object_result);
|
||||
inspect_top_level_for_metadata(f, data.linked_data, dts, previous_game_ts,
|
||||
per_object.at(data.to_unique_name()));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Guess at non-virtual state type's:
|
||||
//
|
||||
// Collect all type names, since the DTS doesn't know the actual type tree (all-types is empty!)
|
||||
// we can't filter by what is actually a process type (with existing code).
|
||||
std::unordered_map<std::string, std::vector<std::string>> all_type_names;
|
||||
for (auto& [obj_name, obj_info] : per_object) {
|
||||
for (const auto& type_name : obj_info.type_names_in_order) {
|
||||
if (all_type_names.find(obj_name) == all_type_names.end()) {
|
||||
all_type_names[obj_name] = {};
|
||||
}
|
||||
all_type_names[obj_name].push_back(type_name);
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> state_to_type_map;
|
||||
for (auto& [obj_name, obj_info] : per_object) {
|
||||
for (const auto& [sym_name, sym_type] : obj_info.symbol_types) {
|
||||
if (sym_type == "state") {
|
||||
int longest_match_length = 0;
|
||||
std::string longest_match = "";
|
||||
std::string longest_match_object_name = "";
|
||||
// Make a best effort guess by finding the longest prefix match
|
||||
for (const auto& [obj_name, type_names] : all_type_names) {
|
||||
for (const auto& type_name : type_names) {
|
||||
if (str_util::starts_with(sym_name, type_name) &&
|
||||
type_name.length() > longest_match_length) {
|
||||
longest_match_length = type_name.length();
|
||||
longest_match = type_name;
|
||||
longest_match_object_name = obj_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (longest_match != "") {
|
||||
if (per_object.find(longest_match_object_name) != per_object.end()) {
|
||||
per_object.at(longest_match_object_name).non_virtual_state_guesses[sym_name] =
|
||||
longest_match;
|
||||
obj_info.already_seen_symbols.insert(sym_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then another to actually setup the definitions
|
||||
for_each_obj([&](ObjectFileData& data) {
|
||||
if (data.obj_version == 3 || (data.obj_version == 5 && data.linked_data.has_any_functions())) {
|
||||
auto& object_result = per_object.at(data.to_unique_name());
|
||||
|
||||
// Handle the top level last, which is fine as all symbol_defs are always written after
|
||||
// typedefs
|
||||
@@ -368,12 +419,14 @@ void ObjectFileDB::ir2_analyze_all_types(const fs::path& output_file,
|
||||
}
|
||||
});
|
||||
|
||||
// Output result
|
||||
|
||||
std::string result;
|
||||
result += ";; All Types\n\n";
|
||||
|
||||
for (auto& obj : per_object) {
|
||||
for (auto& [obj_name, obj] : per_object) {
|
||||
result += fmt::format(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
|
||||
result += fmt::format(";; {:30s} ;;\n", obj.object_name);
|
||||
result += fmt::format(";; {:30s} ;;\n", obj_name);
|
||||
result += fmt::format(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n");
|
||||
for (const auto& type_name : obj.type_names_in_order) {
|
||||
auto& info = obj.type_info.at(type_name);
|
||||
@@ -749,7 +802,7 @@ void ObjectFileDB::ir2_insert_lets(int seg, ObjectFileData& data) {
|
||||
"Error while inserting lets: {}. Make sure that the return type is not "
|
||||
"none if something is actually returned.",
|
||||
e.what());
|
||||
lg::warn(err);
|
||||
lg::warn("{}", err);
|
||||
func.warnings.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1427,10 +1427,15 @@ std::string inspect_inspect_method(Function& inspect_method,
|
||||
object_file_meta);
|
||||
}
|
||||
|
||||
std::string old_method_string(const MethodInfo& info) {
|
||||
std::string old_method_string(const MethodInfo& info, const bool omit_comment = false) {
|
||||
if (info.type.arg_count() > 0) {
|
||||
if (info.type.base_type() == "function" || info.type.base_type() == "state") {
|
||||
std::string result = fmt::format(" ;; ({} (", info.name);
|
||||
std::string result;
|
||||
if (omit_comment) {
|
||||
result = fmt::format(" ({} (", info.name);
|
||||
} else {
|
||||
result = fmt::format(" ;; ({} (", info.name);
|
||||
}
|
||||
bool add = false;
|
||||
for (int i = 0; i < (int)info.type.arg_count() - 1; i++) {
|
||||
result += info.type.get_arg(i).print();
|
||||
@@ -1450,6 +1455,9 @@ std::string old_method_string(const MethodInfo& info) {
|
||||
}
|
||||
}
|
||||
|
||||
if (omit_comment) {
|
||||
return fmt::format(" ({} {}) weird method", info.name, info.type.print());
|
||||
}
|
||||
return fmt::format(" ;; ({} {}) weird method", info.name, info.type.print());
|
||||
}
|
||||
|
||||
@@ -1637,81 +1645,75 @@ std::string TypeInspectorResult::print_as_deftype(
|
||||
result.append("\n ");
|
||||
}
|
||||
|
||||
std::string state_methods_list;
|
||||
std::unordered_map<int, std::string> method_states = {};
|
||||
if (object_file_meta.state_methods.count(type_name) != 0) {
|
||||
method_states = object_file_meta.state_methods.at(type_name);
|
||||
for (const auto& [method_id, state_name] : method_states) {
|
||||
MethodInfo info;
|
||||
state_methods_list += fmt::format(" {} ;; {}", state_name, method_id);
|
||||
if (old_game_type && old_game_type->get_my_method(method_id, &info)) {
|
||||
state_methods_list += ", old:" + old_method_string(info, true);
|
||||
}
|
||||
state_methods_list += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::string methods_list;
|
||||
if (type_method_count > 9) {
|
||||
std::string methods_list;
|
||||
std::string state_methods_list;
|
||||
|
||||
MethodInfo old_new_method;
|
||||
if (old_game_type && old_game_type->get_my_new_method(&old_new_method)) {
|
||||
methods_list.append(" ");
|
||||
methods_list.append(old_method_string(old_new_method));
|
||||
methods_list.push_back('\n');
|
||||
}
|
||||
bool done_with_state_methods = false;
|
||||
for (int i = parent_method_count; i < type_method_count; i++) {
|
||||
bool print_as_state_method = false;
|
||||
if (method_states.count(i) != 0) {
|
||||
if (!done_with_state_methods) {
|
||||
print_as_state_method = true;
|
||||
state_methods_list.append(fmt::format(" {}", method_states.at(i)));
|
||||
} else {
|
||||
methods_list.append(
|
||||
fmt::format(" ({} () _type_ :state) ;; {}", method_states.at(i), i));
|
||||
}
|
||||
} else {
|
||||
done_with_state_methods = true;
|
||||
methods_list.append(fmt::format(" ({}-method-{} () none) ;; {}", type_name, i, i));
|
||||
// If it's a state-method (virtual state) skip it
|
||||
if (method_states.find(i) != method_states.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
methods_list.append(fmt::format(" ({}-method-{} () none) ;; {}", type_name, i, i));
|
||||
if (old_game_type) {
|
||||
MethodInfo info;
|
||||
if (old_game_type->get_my_method(i, &info)) {
|
||||
if (print_as_state_method) {
|
||||
state_methods_list += old_method_string(info);
|
||||
} else {
|
||||
methods_list += old_method_string(info);
|
||||
}
|
||||
methods_list += old_method_string(info);
|
||||
}
|
||||
}
|
||||
if (print_as_state_method) {
|
||||
state_methods_list.push_back('\n');
|
||||
} else {
|
||||
methods_list.push_back('\n');
|
||||
}
|
||||
}
|
||||
if (!state_methods_list.empty()) {
|
||||
result.append("(:state-methods\n");
|
||||
result.append(state_methods_list);
|
||||
result.append(" )\n ");
|
||||
}
|
||||
if (!methods_list.empty()) {
|
||||
result.append("(:methods");
|
||||
result.append(methods_list);
|
||||
result.append(" )\n ");
|
||||
methods_list.push_back('\n');
|
||||
}
|
||||
}
|
||||
|
||||
// Print out (normal) states if we have em
|
||||
// - Could probably assume the process name comes first and associate it with the right type
|
||||
// but that may or may not be risky so, edit the types yourself...
|
||||
if (method_states.size() > 0) {
|
||||
result.append("(:states\n ");
|
||||
for (const auto& [id, name] : method_states) {
|
||||
result.append(name);
|
||||
// Append old symbol def if we have it
|
||||
auto it = previous_game_ts.symbol_types.find(name);
|
||||
// non-virtual states
|
||||
std::string non_virtual_states_list;
|
||||
for (const auto& [state_name, guessed_type_name] : object_file_meta.non_virtual_state_guesses) {
|
||||
if (type_name == guessed_type_name) {
|
||||
std::string line;
|
||||
line += fmt::format(" {}", state_name);
|
||||
auto it = previous_game_ts.symbol_types.find(state_name);
|
||||
if (it != previous_game_ts.symbol_types.end()) {
|
||||
result.append(fmt::format(" ;; {}", it->second.print()));
|
||||
line += fmt::format(" ;; associated process guessed by decompiler, old: {}",
|
||||
it->second.print());
|
||||
}
|
||||
// Add symbol name to `already_seen_symbols`
|
||||
object_file_meta.already_seen_symbols.insert(name);
|
||||
result.append("\n ");
|
||||
non_virtual_states_list.append(line + "\n");
|
||||
}
|
||||
result.append(")\n ");
|
||||
}
|
||||
// methods and virtual states
|
||||
if (!methods_list.empty()) {
|
||||
result.append("(:methods\n");
|
||||
result.append(methods_list);
|
||||
result.append(" )\n ");
|
||||
}
|
||||
if (!state_methods_list.empty()) {
|
||||
result.append("(:state-methods\n");
|
||||
result.append(state_methods_list);
|
||||
result.append(" )\n ");
|
||||
}
|
||||
// non-virtual states
|
||||
if (!non_virtual_states_list.empty()) {
|
||||
result.append("(:states\n");
|
||||
result.append(non_virtual_states_list);
|
||||
result.append(" )\n ");
|
||||
}
|
||||
|
||||
result.append(")\n");
|
||||
@@ -1800,7 +1802,8 @@ void inspect_top_level_for_metadata(Function& top_level,
|
||||
const auto& aop = top_level.ir2.atomic_ops->ops.at(i);
|
||||
const std::string as_str = aop.get()->to_string(top_level.ir2.env);
|
||||
|
||||
// Keep track of the last seen label so we can easily reference it if a later operation uses it
|
||||
// Keep track of the last seen label so we can easily reference it if a later operation uses
|
||||
// it
|
||||
auto label_match = get_regex_match(as_str, std::regex("\\(set!\\s[^\\s]*\\s(L.*)\\)"));
|
||||
if (!label_match.empty()) {
|
||||
last_seen_label = label_match;
|
||||
@@ -1858,7 +1861,8 @@ void inspect_top_level_for_metadata(Function& top_level,
|
||||
}
|
||||
|
||||
// lwu t9, 16(v1) ;; [ 21] (set! t9-0 (l.wu (+ v1-10 16)))
|
||||
// ;; [v1: <the etype type> ] -> [t9: (function symbol type int type)
|
||||
// ;; [v1: <the etype type> ] -> [t9: (function symbol type int
|
||||
// type)
|
||||
const auto& aop_1 = top_level.ir2.atomic_ops->ops.at(i + 1);
|
||||
if (!is_set_reg_to_load(aop_1.get(), Register(Reg::GPR, Reg::T9), 16)) {
|
||||
continue;
|
||||
@@ -1935,8 +1939,9 @@ std::string inspect_top_level_symbol_defines(Function& top_level,
|
||||
if (as_store && as_store->addr().kind() == SimpleExpression::Kind::IDENTITY &&
|
||||
as_store->addr().get_arg(0).is_sym_val()) {
|
||||
auto& sym_name = as_store->addr().get_arg(0).get_str();
|
||||
if (object_file_meta.already_seen_symbols.find(sym_name) ==
|
||||
object_file_meta.already_seen_symbols.end()) {
|
||||
const auto sym_already_seen = object_file_meta.already_seen_symbols.find(sym_name) !=
|
||||
object_file_meta.already_seen_symbols.end();
|
||||
if (!sym_already_seen) {
|
||||
object_file_meta.already_seen_symbols.insert(sym_name);
|
||||
if (dts.ts.partially_defined_type_exists(sym_name)) {
|
||||
continue;
|
||||
|
||||
@@ -172,7 +172,7 @@ bool convert_to_expressions(
|
||||
"statement.",
|
||||
f.name());
|
||||
f.warnings.warning(warn);
|
||||
lg::warn(warn);
|
||||
lg::warn("{}", warn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ bool rewrite_inline_asm_instructions(Form* top_level_form,
|
||||
} catch (std::exception& e) {
|
||||
std::string warning =
|
||||
fmt::format("ASM instruction re-writing failed in {}: {}", f.name(), e.what());
|
||||
lg::warn(warning);
|
||||
lg::warn("{}", warning);
|
||||
f.warnings.error(";; {}", warning);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -23608,7 +23608,7 @@
|
||||
(define-extern nav-enemy-turn-to-face-point (function vector float none :behavior nav-enemy))
|
||||
(define-extern nav-enemy-execute-jump (function none :behavior nav-enemy))
|
||||
(define-extern nav-enemy-jump-land-anim (function none :behavior nav-enemy)) ;; TODO
|
||||
(define-extern nav-enemy-rnd-float-range (function float float float :behavior nav-enemy))
|
||||
(define-extern nav-enemy-rnd-float-range (function float float float))
|
||||
(define-extern nav-enemy-common-post (function none :behavior nav-enemy)) ;; TODO not confirmed
|
||||
(define-extern nav-enemy-execute-custom-jump (function int float float none :behavior nav-enemy))
|
||||
(define-extern nav-enemy-initialize-custom-jump (function vector symbol float float float none :behavior nav-enemy))
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
// these can be displayed in game, but makes the .fr3 files slightly larger
|
||||
"extract_collision": true,
|
||||
// save game textures as .png files.
|
||||
"save_texture_pngs": true,
|
||||
"save_texture_pngs": false,
|
||||
|
||||
////////////////////////////
|
||||
// PATCHING OPTIONS
|
||||
|
||||
@@ -7381,6 +7381,14 @@
|
||||
(progress-cheats-board-tricks #x1260)
|
||||
(progress-cheats-weather-bad #x1261)
|
||||
(progress-cheats-weather-good #x1262)
|
||||
(progress-cheats-hijack-lines #x1263)
|
||||
(progress-cheats-locked #x1264)
|
||||
(progress-cheats-turbo-board-unlock #x1265)
|
||||
(progress-cheats-health-bars-unlock #x1266)
|
||||
(progress-cheats-vehicle-health-bars-unlock #x1267)
|
||||
(progress-cheats-statistics-unlock #x1268)
|
||||
(progress-cheats-suck-in-all-unlock #x1269)
|
||||
(progress-cheats-fast-travel-unlock #x126a)
|
||||
(progress-camera-options #x1280)
|
||||
(progress-camera-options-first-horz #x1281)
|
||||
(progress-camera-options-first-vert #x1282)
|
||||
@@ -7415,6 +7423,47 @@
|
||||
(progress-shadows #x12a0)
|
||||
(progress-shadows-normal #x12a1)
|
||||
(progress-shadows-extended #x12a2)
|
||||
(progress-error-no-resolutions #x12a3)
|
||||
(progress-territory-auto #x12a4)
|
||||
(progress-kill-stats #x12a5)
|
||||
(progress-other-stats #x12a6)
|
||||
(progress-ks-total-killed #x12a7)
|
||||
(progress-ks-killed-by-jak #x12a8)
|
||||
(progress-ks-killed-by-darkjak #x12a9)
|
||||
(progress-ks-killed-by-daxter #x12aa)
|
||||
(progress-ks-killed-by-others #x12ab)
|
||||
(progress-ks-source-gun-yellow #x12ac)
|
||||
(progress-ks-source-gun-red #x12ad)
|
||||
(progress-ks-source-gun-blue #x12ae)
|
||||
(progress-ks-source-gun-dark #x12af)
|
||||
(progress-ks-source-board #x12b0)
|
||||
(progress-ks-source-board-trick #x12b1)
|
||||
(progress-ks-source-mech #x12b2)
|
||||
(progress-ks-source-mech-bonk #x12b3)
|
||||
(progress-ks-source-turret #x12b4)
|
||||
(progress-ks-source-punch #x12b5)
|
||||
(progress-ks-source-flop #x12b6)
|
||||
(progress-ks-source-uppercut #x12b7)
|
||||
(progress-ks-source-spin #x12b8)
|
||||
(progress-ks-source-roll #x12b9)
|
||||
(progress-ks-source-darkjak-punch #x12ba)
|
||||
(progress-ks-source-darkjak-flop #x12bb)
|
||||
(progress-ks-source-darkjak-uppercut #x12bc)
|
||||
(progress-ks-source-darkjak-spin #x12bd)
|
||||
(progress-ks-source-darkjak-roll #x12be)
|
||||
(progress-ks-source-darkjak-bomb0 #x12bf)
|
||||
(progress-ks-source-darkjak-bomb1 #x12c0)
|
||||
(progress-ks-source-indax-punch #x12c1)
|
||||
(progress-ks-source-indax-spin #x12c2)
|
||||
(progress-ks-source-guard #x12c3)
|
||||
(progress-ks-source-sig #x12c4)
|
||||
(progress-ks-source-ashelin #x12c5)
|
||||
(progress-ks-source-jinx #x12c6)
|
||||
(progress-ks-source-grim #x12c7)
|
||||
(progress-ks-source-mog #x12c8)
|
||||
(progress-ks-source-metalhead #x12c9)
|
||||
(progress-ks-source-other-bot #x12ca)
|
||||
(progress-ks-source-other-enemy #x12cb)
|
||||
(progress-input-options-auto-hide-cursor #x1300)
|
||||
(progress-menu-reassign-binds #x1301)
|
||||
(progress-reassign-binds-controller #x1302)
|
||||
@@ -7437,6 +7486,7 @@
|
||||
(progress-highscores-local-time #x1313)
|
||||
(progress-fps-disclaimer-warning #x1314)
|
||||
(progress-fps-disclaimer #x1315)
|
||||
(progress-highscores-local-score #x1316)
|
||||
(trick-board-none #x1320)
|
||||
(trick-board-spin #x1321)
|
||||
(trick-board-boost #x1322)
|
||||
@@ -15775,6 +15825,24 @@
|
||||
(test 22) ;; hi 64
|
||||
)
|
||||
|
||||
|
||||
;; +++game-h:knocked-type
|
||||
(defenum knocked-type
|
||||
:type uint8
|
||||
(knocked-type-0 0)
|
||||
(knocked-type-1 1)
|
||||
(knocked-type-2 2)
|
||||
(knocked-type-3 3)
|
||||
(knocked-type-4 4) ;; what the heck is this! (its on gator, and cant trigger it for the life of me)
|
||||
(knocked-type-5 5)
|
||||
(knocked-type-6 6)
|
||||
(knocked-type-7 7)
|
||||
(knocked-type-8 8)
|
||||
(knocked-type-9 9)
|
||||
(knocked-type-10 10)
|
||||
)
|
||||
;; ---game-h:knocked-type
|
||||
|
||||
(declare-type touching-shapes-entry structure)
|
||||
|
||||
(deftype attack-info (structure)
|
||||
@@ -15800,7 +15868,7 @@
|
||||
(penetrate-using penetrate :offset-assert 136)
|
||||
(damage float :offset-assert 144)
|
||||
(shield-damage float :offset-assert 148)
|
||||
(knock uint8 :offset-assert 152)
|
||||
(knock knocked-type :offset-assert 152)
|
||||
(test symbol :offset-assert 156)
|
||||
)
|
||||
:method-count-assert 12
|
||||
@@ -24877,7 +24945,7 @@
|
||||
(define-extern shadow-add-single-tris function)
|
||||
(define-extern shadow-add-double-tris function)
|
||||
(define-extern shadow-add-double-edges function)
|
||||
(define-extern debug-draw-settings (function matrix none))
|
||||
(define-extern debug-draw-settings (function shadow-settings symbol))
|
||||
(define-extern shadow-execute (function shadow-dma-packet pointer pointer))
|
||||
(define-extern shadow-vu0-upload (function none))
|
||||
(define-extern shadow-execute-all (function dma-buffer none))
|
||||
@@ -27728,7 +27796,7 @@
|
||||
(define-extern dist-info-valid? (function collide-los-dist-info symbol)) ;;
|
||||
(define-extern dist-info-append (function collide-los-dist-info vector none)) ;;
|
||||
(define-extern dist-info-print (function collide-los-dist-info string object)) ;;
|
||||
(define-extern los-cw-ccw (function (inline-array collide-cache-tri) vector vector float collide-los-result vector float symbol)) ;;
|
||||
(define-extern los-cw-ccw (function (inline-array collide-cache-tri) vector vector float collide-los-result vector float symbol :behavior camera-slave)) ;;
|
||||
(define-extern cam-los-spline-collide (function vector vector pat-surface float)) ;;
|
||||
(define-extern cam-los-setup-lateral (function collide-los-result vector vector symbol :behavior camera-slave)) ;;
|
||||
(define-extern cam-los-collide (function vector vector collide-los-result pat-surface symbol :behavior camera-slave)) ;;
|
||||
@@ -32801,42 +32869,42 @@
|
||||
(defenum enemy-flag
|
||||
:type int64
|
||||
:bitfield #t
|
||||
(lock-focus 0)
|
||||
(death-start 1)
|
||||
(enable-on-active 2)
|
||||
(checking-water 3)
|
||||
(check-water 4)
|
||||
(spawn-gem 5)
|
||||
(chase-startup 6)
|
||||
(attackable-backup 7)
|
||||
(look-at-focus 8)
|
||||
(use-notice-distance 9)
|
||||
(enable-on-notice 10)
|
||||
(look-at-move-dest 11)
|
||||
(notice 12)
|
||||
(auto-reset-penetrate 13)
|
||||
(jump-check-blocked 14)
|
||||
(drawn-mirrored 15)
|
||||
(multi-focus 16)
|
||||
(alert 17)
|
||||
(victory 18)
|
||||
(dangerous-backup 19)
|
||||
(actor-pause-backup 20)
|
||||
(trackable 21)
|
||||
(called-dying 22)
|
||||
(check-water-backup 23)
|
||||
(no-initial-move-to-ground 24)
|
||||
(cam-attack-mode 25)
|
||||
(trackable-backup 26)
|
||||
(enable-on-hostile 27)
|
||||
(directed-ready 28)
|
||||
(use-trigger 29)
|
||||
(directed 30)
|
||||
(dislike-combo 31)
|
||||
(recover-applied-velocity 32)
|
||||
(vulnerable-backup 33)
|
||||
(vulnerable 34)
|
||||
(recover 35)
|
||||
(look-at-focus 0)
|
||||
(look-at-move-dest 1)
|
||||
(vulnerable 2)
|
||||
(vulnerable-backup 3)
|
||||
(dangerous-backup 4)
|
||||
(notice 5)
|
||||
(alert 6)
|
||||
(auto-reset-penetrate 7)
|
||||
(victory 8)
|
||||
(cam-attack-mode 9)
|
||||
(use-notice-distance 10)
|
||||
(attackable-backup 11)
|
||||
(actor-pause-backup 12)
|
||||
(enable-on-notice 13)
|
||||
(enable-on-active 14)
|
||||
(enable-on-hostile 15)
|
||||
(dislike-combo 16)
|
||||
(directed 17)
|
||||
(directed-ready 18)
|
||||
(chase-startup 19)
|
||||
(lock-focus 20)
|
||||
(multi-focus 21)
|
||||
(use-trigger 22)
|
||||
(trackable 23)
|
||||
(trackable-backup 24)
|
||||
(spawn-gem 25)
|
||||
(check-water 26)
|
||||
(check-water-backup 27)
|
||||
(checking-water 28)
|
||||
(recover 29)
|
||||
(recover-applied-velocity 30)
|
||||
(drawn-mirrored 31)
|
||||
(called-dying 32)
|
||||
(no-initial-move-to-ground 33)
|
||||
(jump-check-blocked 34)
|
||||
(death-start 35)
|
||||
(enemy-flag36 36)
|
||||
(enemy-flag37 37)
|
||||
(enemy-flag38 38)
|
||||
@@ -32975,8 +33043,21 @@
|
||||
:flag-assert #x900000018
|
||||
)
|
||||
|
||||
(defenum enemy-jump-flags
|
||||
:bitfield #t
|
||||
:type uint8
|
||||
(enjflag-0)
|
||||
(enjflag-1)
|
||||
(enjflag-2)
|
||||
(enjflag-3)
|
||||
(enjflag-4)
|
||||
(enjflag-5)
|
||||
(enjflag-6)
|
||||
(enjflag-7)
|
||||
)
|
||||
|
||||
(deftype enemy-jump-info (structure)
|
||||
((flags uint8 :offset-assert 0)
|
||||
((flags enemy-jump-flags :offset-assert 0)
|
||||
(anim-speed float :offset-assert 4)
|
||||
(hang-time time-frame :offset-assert 8)
|
||||
(start-pos vector :inline :offset-assert 16)
|
||||
@@ -33000,27 +33081,13 @@
|
||||
:flag-assert #x90000002c
|
||||
)
|
||||
|
||||
;; +++enemy-h:knocked-type
|
||||
(defenum knocked-type
|
||||
:type uint8
|
||||
(knocked-type-0 0)
|
||||
(knocked-type-1 1)
|
||||
(knocked-type-2 2)
|
||||
(knocked-type-3 3)
|
||||
(knocked-type-4 4) ;; what the heck is this! (its on gator, and cant trigger it for the life of me)
|
||||
(knocked-type-5 5)
|
||||
(knocked-type-6 6)
|
||||
(knocked-type-7 7)
|
||||
)
|
||||
;; ---enemy-h:knocked-type
|
||||
|
||||
(deftype enemy-attack-info (structure)
|
||||
((attack-id uint32 :offset-assert 0)
|
||||
(knocked-type knocked-type :offset-assert 4)
|
||||
(blue-juggle-count uint8 :offset-assert 5)
|
||||
(attacker-handle handle :offset-assert 8)
|
||||
(attack-time time-frame :offset-assert 16)
|
||||
(penetrate-using uint64 :offset-assert 24)
|
||||
(penetrate-using penetrate :offset-assert 24)
|
||||
(attacker-pos vector :inline :offset-assert 32)
|
||||
(attack-direction vector :inline :offset-assert 48)
|
||||
)
|
||||
@@ -33114,7 +33181,7 @@
|
||||
"TODO"
|
||||
(_type_ process-focusable) symbol) ;; 53
|
||||
(enemy-method-54 (_type_) enemy-flag) ;; 54
|
||||
(track-target!
|
||||
(common-post
|
||||
"Does a lot of various things relating to interacting with the target
|
||||
- tracks when the enemy was last drawn
|
||||
- looks at the target and handles attacking
|
||||
@@ -33139,8 +33206,8 @@
|
||||
(enemy-method-61 (_type_ int) int :behavior enemy) ;; 61
|
||||
(enemy-method-62 (_type_) none) ;; 62
|
||||
(enemy-method-63 (_type_ process-focusable enemy-aware) symbol) ;; 63
|
||||
(enemy-method-64 (_type_) none) ;; 64
|
||||
(enemy-method-65 (_type_) none) ;; 65
|
||||
(go-dormant (_type_) object) ;; 64
|
||||
(go-dormant-aware (_type_) object) ;; 65
|
||||
(go-ambush (_type_) object) ;; 66
|
||||
(go-stare (_type_) object) ;; 67
|
||||
(go-stare2 (_type_) object) ;; 68
|
||||
@@ -33159,8 +33226,8 @@
|
||||
(_type_ process int symbol event-message-block) object) ;; 74
|
||||
(enemy-method-75 (_type_ process event-message-block) object) ;; 75
|
||||
(enemy-method-76 (_type_ process event-message-block) symbol) ;; 76
|
||||
(enemy-method-77 (_type_ (pointer float)) symbol) ;; 77
|
||||
(enemy-method-78 (_type_ (pointer float)) symbol) ;; 78
|
||||
(enemy-method-77 (_type_ enemy-knocked-info) symbol) ;; 77
|
||||
(enemy-method-78 (_type_ enemy-knocked-info) symbol) ;; 78
|
||||
(enemy-method-79 (_type_ int enemy-knocked-info) symbol) ;; 79
|
||||
(enemy-method-80 (_type_ enemy-knocked-info) symbol) ;; 80
|
||||
(enemy-method-81 (_type_) symbol) ;; 81
|
||||
@@ -33174,10 +33241,7 @@
|
||||
(enemy-method-89 (_type_ enemy-jump-info) symbol) ;; 89
|
||||
(enemy-method-90 (_type_ int enemy-jump-info) symbol) ;; 90
|
||||
(enemy-method-91 (_type_ int enemy-jump-info) none) ;; 91
|
||||
(enemy-method-92
|
||||
"TODO - nav-poly is a guess
|
||||
@abstract"
|
||||
(_type_ int nav-poly) none) ;; 92
|
||||
(enemy-method-92 "@abstract" (_type_ int enemy-jump-info) none) ;; 92
|
||||
(enemy-method-93 (_type_) none) ;; 93
|
||||
(enemy-method-94 (_type_ vector float) symbol) ;; 94
|
||||
(enemy-method-95 (_type_ vector float) symbol) ;; 95
|
||||
@@ -33197,11 +33261,11 @@
|
||||
(enemy-method-103 (_type_) collide-spec) ;; 103
|
||||
(enemy-method-104 (_type_ process touching-shapes-entry uint) symbol :behavior process) ;; 104
|
||||
(enemy-method-105 (_type_ process) enemy-flag) ;; 105
|
||||
(enemy-method-106 (_type_ process object int attack-info) none :behavior enemy) ;; 106
|
||||
(set-incoming-attack-info (_type_ process object penetrate attack-info) none :behavior enemy) ;; 106
|
||||
(get-enemy-target
|
||||
"@returns the [[process-focusable]] that the enemy is currently focusing on, or [[#f]] otherwise"
|
||||
(_type_) process-focusable) ;; 107
|
||||
(enemy-method-108 (_type_ enemy event-message-block) int) ;; 108
|
||||
(enemy-method-108 (_type_ process-drawable event-message-block) int) ;; 108
|
||||
(look-at-target!
|
||||
"Logic for looking at the target that is locked on, sets some flags and adjusts the neck to look at the target if available
|
||||
@param flag Reacts to [[enemy-flag::death-start]] and [[enemy-flag::enable-on-active]], see implementation for details"
|
||||
@@ -33224,33 +33288,32 @@
|
||||
"Common method called to initialize the enemy, typically sets up default field values and calls ancillary helper methods"
|
||||
(_type_) none) ;; 115
|
||||
(go-idle (_type_) none) ;; 116
|
||||
(get-rand-float
|
||||
(rnd-float
|
||||
"@returns the result of calling [[rand-vu]]"
|
||||
(_type_) float) ;; 117
|
||||
(get-rand-float-range
|
||||
(rnd-float-range
|
||||
"@param low The lower bound of the range (inclusive)
|
||||
@param high The upper bound of the range (exclusive)
|
||||
@returns A random float in the specified range"
|
||||
(_type_ float float) float) ;; 118
|
||||
(get-rand-int
|
||||
(rnd-int-count
|
||||
"@param high The upper bound of the range (exclusive)
|
||||
@returns a random integer in the range 0 to `high`
|
||||
@see [[rand-vu]]"
|
||||
(_type_ int) int) ;; 119
|
||||
(enemy-method-120 "TODO" (_type_ int int) int) ;; 120
|
||||
(get-rand-int-range
|
||||
(rnd-bit "TODO" (_type_ int int) int) ;; 120
|
||||
(rnd-int-range
|
||||
"@param low The lower bound of the range (inclusive)
|
||||
@param high The upper bound of the range (exclusive)
|
||||
@returns A random integer in the specified range"
|
||||
(_type_ int int) int) ;; 121
|
||||
(rng-hit?
|
||||
"TODO - not the best name
|
||||
@param chance The value to compare ([[>=]]) with the result from [[rand-vu]].
|
||||
(rnd-percent?
|
||||
"@param chance The value to compare ([[>=]]) with the result from [[rand-vu]].
|
||||
@returns If `chance` is greater than the random draw"
|
||||
(_type_ float) symbol) ;; 122
|
||||
(enemy-method-123 "TODO" (_type_ float) symbol) ;; 123
|
||||
(rnd-go-idle? "TODO" (_type_ float) symbol) ;; 123
|
||||
(enemy-method-124 "TODO" (_type_) collide-spec) ;; 124
|
||||
(enemy-method-125 (_type_ collide-query collide-spec float float float) pat-surface) ;; 125
|
||||
(ground-pat-set! (_type_ collide-query collide-spec float float float) pat-surface) ;; 125
|
||||
(enemy-above-ground?
|
||||
"@returns if the enemy is above the ground or not
|
||||
@see [[above-ground?]]"
|
||||
@@ -33259,12 +33322,12 @@
|
||||
(enemy-method-128 (_type_ vector move-above-ground-params) none) ;; 128
|
||||
(enemy-method-129 (_type_) none) ;; 129
|
||||
(enemy-method-130 (_type_ float) symbol) ;; 130
|
||||
(enemy-method-131 (_type_ int) uint) ;; 131
|
||||
(dispose!
|
||||
(penetrate-using->knocked (_type_ penetrate) knocked-type) ;; 131
|
||||
(dying
|
||||
"Cleans-up the enemy and any associated resources. Potentially spawns skull gems"
|
||||
(_type_) none) ;; 132
|
||||
(enemy-method-133 (_type_) symbol) ;; 133
|
||||
(enemy-method-134 (_type_ process attack-info) process-focusable) ;; 134
|
||||
(get-attacker (_type_ process attack-info) process-focusable) ;; 134
|
||||
(enemy-method-135 (_type_ int) sound-id) ;; 135
|
||||
(enemy-method-136 (_type_) enemy-flag) ;; 136
|
||||
)
|
||||
@@ -34814,7 +34877,7 @@
|
||||
(unknown-byte-n1k2n3 int8 :offset 636)
|
||||
(unknown-byte-m2j342 int8 :offset 637)
|
||||
(unknown-byte-1ji2n3 int8 :offset 638)
|
||||
(unknown-byte-n123n int8 :offset 639)
|
||||
(unknown-byte-n123n uint8 :offset 639)
|
||||
(state-timeout2 uint64 :offset-assert 640)
|
||||
(next-warn-time time-frame :offset-assert 648)
|
||||
(dest vector :inline :offset-assert 656)
|
||||
@@ -38515,7 +38578,7 @@
|
||||
charge
|
||||
)
|
||||
(:methods
|
||||
(rhino-method-182 (_type_ process event-message-block) symbol) ;; 182
|
||||
(hit-stomach? (_type_ process event-message-block) symbol) ;; 182
|
||||
)
|
||||
)
|
||||
|
||||
@@ -39415,7 +39478,7 @@
|
||||
(hit-by-enemy-count uint16 :offset-assert 698)
|
||||
(hit-by-player-count uint16 :offset-assert 700)
|
||||
(notice-enemy-dist float :offset-assert 704)
|
||||
(channel uint8 :offset-assert 708)
|
||||
(channel gui-channel :offset-assert 708)
|
||||
(focus-mode int8 :offset-assert 709)
|
||||
(nav-mesh-index int8 :offset-assert 710)
|
||||
(delay-too-far-check int8 :offset-assert 711)
|
||||
@@ -39478,13 +39541,13 @@
|
||||
(play-speech (_type_ int) none) ;; 206
|
||||
(play-death-sound "Play one of our death sounds." (_type_ string) none) ;; 207
|
||||
(bot-method-208 (_type_) symbol) ;; 208
|
||||
(channel-active? "Is the given [[gui-channel]] active?" (_type_ uint) symbol) ;; 209
|
||||
(channel-active? "Is the given [[gui-channel]] active?" (_type_ gui-channel) symbol) ;; 209
|
||||
(init! "Set defaults for various fields." (_type_) none) ;; 210
|
||||
(clear-speech-flags! "Clear the `playing` flag for all of our speeches." (_type_) none) ;; 211
|
||||
(reset-warn-time! (_type_) none) ;; 212
|
||||
(go-to-waypoint! "Start moving to the given [[bot-waypoint]]." (_type_ int symbol) object) ;; 213
|
||||
(bot-method-214 (_type_) symbol) ;; 214
|
||||
(skip-waypoint (_type_) none) ;; 215
|
||||
(skip-waypoint (_type_) object) ;; 215
|
||||
(bot-method-216 (_type_) none) ;; 216
|
||||
(speech-ended? "Is the given speech active?" (_type_ int) symbol) ;; 217
|
||||
(speech-playing? "Is the given speech playing?" (_type_ int) symbol) ;; 218
|
||||
@@ -43427,7 +43490,7 @@
|
||||
(define-extern set-countdown-to-roar (function none :behavior metalkor))
|
||||
(define-extern metalkor-go-next-stage (function none :behavior metalkor))
|
||||
(define-extern metalkor-setup-hit-anim (function attack-info process-drawable art-element art-element float none :behavior metalkor))
|
||||
(define-extern metalkor-get-gem-tracker (function process-focusable none :behavior metalkor))
|
||||
(define-extern metalkor-get-gem-tracker (function process-focusable gem-tracker :behavior metalkor))
|
||||
(define-extern metalkor-handler (function process int symbol event-message-block object :behavior metalkor))
|
||||
(define-extern metalkor-start-egg (function symbol :behavior metalkor))
|
||||
(define-extern metalkor-check-egg (function symbol :behavior metalkor))
|
||||
@@ -50579,13 +50642,15 @@
|
||||
(
|
||||
(ai-hook (function vehicle-guard none) :offset-assert 880)
|
||||
(turret turret-control :inline :offset-assert 888)
|
||||
(target-flags turret-flag :offset-assert 968)
|
||||
(target-flags traffic-target-flag :offset-assert 968)
|
||||
(target-in-sight-time time-frame :offset-assert 976)
|
||||
(minimap connection-minimap :offset-assert 984)
|
||||
(vehicle-guard-pad-k1jn23k1 uint32 :offset-assert 988)
|
||||
(traffic-target-status traffic-target-status :offset-assert 992)
|
||||
(pursuit-target handle :offset-assert 1000)
|
||||
(vehicle-guard-pad-1kjh2nb3k1 uint32 16 :offset-assert 1008)
|
||||
(vehicle-guard-pad-0jkfdjslf uint32 4 :offset-assert 1008)
|
||||
(vehicle-guard-vector0341413 vector :inline :offset-assert 1024)
|
||||
(vehicle-guard-pad-1kjh2nb3k1 uint32 8 :offset-assert 1040)
|
||||
(lod2 symbol :offset-assert 1072)
|
||||
)
|
||||
:method-count-assert 159
|
||||
@@ -50616,7 +50681,7 @@
|
||||
(define-extern vehicle-draw-beam (function sparticle-launcher vector vector object symbol none))
|
||||
(define-extern vehicle-draw-laser-spot (function vector vector symbol none))
|
||||
(define-extern vehicle-draw-laser (function vector vector none))
|
||||
(define-extern vehicle-guard-choose-branch (function vehicle-controller vehicle nav-branch))
|
||||
(define-extern vehicle-guard-choose-branch (function vehicle-controller vehicle-guard nav-branch))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; transport ;;
|
||||
@@ -52949,7 +53014,9 @@
|
||||
(deftype mechblock (process-drawable)
|
||||
((root collide-shape-moving :override)
|
||||
(origin vector :inline :offset-assert 208)
|
||||
(drop-point vector :inline :offset 256)
|
||||
(unknown-quat quaternion :inline :offset-assert 224)
|
||||
(unknown-vector vector :inline :offset-assert 240)
|
||||
(drop-point vector :inline :offset-assert 256)
|
||||
(allow-drag? symbol :offset-assert 272)
|
||||
(reset-on-land? symbol :offset-assert 276)
|
||||
(hit-something? symbol :offset-assert 280)
|
||||
@@ -53473,4 +53540,4 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define-extern *default-envmap-shader* adgif-shader)
|
||||
(define-extern *generic-envmap-texture* texture)
|
||||
(define-extern *generic-envmap-texture* texture)
|
||||
@@ -654,7 +654,7 @@
|
||||
"collectables": [[69, "(function part-tracker vector)"]],
|
||||
"mech-states": [[50, "(function none :behavior target)"]],
|
||||
"target-mech": [
|
||||
[7, "(function none :behavior target)"],
|
||||
[7, "(function none :behavior manipy)"],
|
||||
[8, "(function none :behavior mech)"],
|
||||
[9, "(function none :behavior manipy)"],
|
||||
[18, "(function surface object surface int none :behavior target)"],
|
||||
@@ -1227,8 +1227,8 @@
|
||||
"castle-baron": [[7, "(function collectable none)"]],
|
||||
"metalkor-extras": [[65, "(function vector :behavior metalkor-shot)"]],
|
||||
"metalkor-setup": [
|
||||
[1, "(function gem-tracker none)"],
|
||||
[2, "(function gem-tracker none)"]
|
||||
[1, "(function gem-tracker symbol)"],
|
||||
[2, "(function gem-tracker symbol)"]
|
||||
],
|
||||
"meet-brutter": [
|
||||
[0, "(function none :behavior task-manager)"],
|
||||
|
||||
@@ -4309,7 +4309,8 @@
|
||||
"(method 74 enemy)": [
|
||||
[50, "s3", "process-drawable"],
|
||||
[94, "v1", "attack-info"],
|
||||
[[111, 205], "s2", "attack-info"],
|
||||
[[111, 137], "s2", "attack-info"],
|
||||
[204, "s2", "attack-info"],
|
||||
[554, "a0", "vector"]
|
||||
],
|
||||
"(method 56 enemy)": [[[0, 6], "v1", "attack-info"]],
|
||||
@@ -4537,7 +4538,7 @@
|
||||
],
|
||||
"(method 23 joint-exploder)": [[26, "v1", "process-drawable"]],
|
||||
"(method 28 joint-exploder)": [[[0, 250], "s5", "joint-exploder-list"]],
|
||||
"joint-exploder-joint-callback": [[3, "s4", "joint-exploder"]],
|
||||
"joint-exploder-joint-callback": [[[3, 25], "s4", "joint-exploder"]],
|
||||
"(event idle fort-trap-door)": [[4, "v1", "attack-info"]],
|
||||
"(code idle hide-light)": [[10, "v1", "art-joint-anim"]],
|
||||
"(event impact turret-shot)": [[11, "s4", "process-drawable"]],
|
||||
@@ -4968,10 +4969,6 @@
|
||||
],
|
||||
"(enter target-mech-carry-hit-ground)": [[3, "v0", "sound-rpc-set-param"]],
|
||||
"(event target-mech-grab)": [[24, "a0", "process"]],
|
||||
"(anon-function 7 target-mech)": [
|
||||
[32, "a0", "joint-mod-ik"],
|
||||
[26, "a0", "(array joint-mod-ik)"]
|
||||
],
|
||||
"(enter target-mech-hit-ground)": [[3, "v0", "sound-rpc-set-param"]],
|
||||
"(exit target-mech-carry-drag)": [
|
||||
[11, "v0", "sound-rpc-set-param"],
|
||||
@@ -7064,7 +7061,7 @@
|
||||
],
|
||||
"(method 9 city-level-info)": [[387, "v1", "nav-segment"]],
|
||||
"(method 67 traffic-engine)": [
|
||||
[[137, 183], "s0", "crimson-guard"],
|
||||
[[137, 185], "s0", "crimson-guard"],
|
||||
[[44, 86], "a3", "vehicle"]
|
||||
],
|
||||
"set-eye-draw-flag": [[20, "s5", "eye-control"]],
|
||||
@@ -10155,5 +10152,8 @@
|
||||
"race-birth-func-texture-position-word": [
|
||||
[10, "v1", "(array int32)"],
|
||||
[1, "v1", "(array int32)"]
|
||||
]
|
||||
],
|
||||
"(method 206 hal)": [[32, "a2", "bot"]],
|
||||
"(method 209 hal)": [[32, "v1", "bot"]],
|
||||
"(method 220 hal)": [[29, "v1", "bot"]]
|
||||
}
|
||||
@@ -4228,7 +4228,9 @@
|
||||
"vars": {
|
||||
"v1-3": "shadow-settings",
|
||||
"a3-0": "shadow-geo",
|
||||
"t0-0": "dist"
|
||||
"t0-0": "dist",
|
||||
"a3-2": ["shadow-pack1", "shadow-dma-packet"],
|
||||
"t2-11": ["shadow-pack2", "shadow-dma-packet"]
|
||||
}
|
||||
},
|
||||
"progress-selected": {
|
||||
@@ -4637,5 +4639,27 @@
|
||||
"vars": {
|
||||
"t1-3": ["imp-sound", "sound-name"]
|
||||
}
|
||||
},
|
||||
"(method 9 menu-secret-option)": {
|
||||
"vars": {
|
||||
"s5-1": "hero?",
|
||||
"s3-0": "min-item",
|
||||
"s2-0": "max-item",
|
||||
"s5-2": "scroll-sound?",
|
||||
"v1-74": "item",
|
||||
"a0-54": "flag",
|
||||
"a1-9": "on-off?"
|
||||
}
|
||||
},
|
||||
"(method 10 menu-unlocked-menu-option)": {
|
||||
"vars": {
|
||||
"s5-0": "secrets",
|
||||
"f30-0": "alpha"
|
||||
}
|
||||
},
|
||||
"joint-exploder-joint-callback": {
|
||||
"vars": {
|
||||
"s4-0": ["exploder", "joint-exploder"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,7 +169,7 @@
|
||||
(_data uint8 :score -50 :dynamic :offset 16)
|
||||
)
|
||||
(:methods
|
||||
(new (symbol type int) _type_ 0))
|
||||
(new (symbol type int) _type_))
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
@@ -296,9 +296,9 @@
|
||||
(self process-tree :offset-assert 32)
|
||||
)
|
||||
(:methods
|
||||
(new (symbol type string) _type_ 0)
|
||||
(activate (_type_ process-tree basic pointer) process-tree 9)
|
||||
(deactivate (_type_) none 10)
|
||||
(new (symbol type string) _type_)
|
||||
(activate (_type_ process-tree basic pointer) process-tree)
|
||||
(deactivate (_type_) none)
|
||||
(init-from-entity!
|
||||
"Typically the method that does the initial setup on the process, potentially using the [[entity-actor]] provided as part of that.
|
||||
This commonly includes things such as:
|
||||
@@ -306,9 +306,9 @@
|
||||
- collision information
|
||||
- loading the skeleton group / bones
|
||||
- sounds"
|
||||
(_type_ entity-actor) none 11)
|
||||
(run-logic? (_type_) symbol 12)
|
||||
(process-tree-method-13 () none 13)
|
||||
(_type_ entity-actor) none)
|
||||
(run-logic? (_type_) symbol)
|
||||
(process-tree-method-13 () none)
|
||||
)
|
||||
:size-assert #x24
|
||||
:method-count-assert 14
|
||||
@@ -361,13 +361,13 @@
|
||||
:size-assert #x5c
|
||||
:flag-assert #xf0000005c
|
||||
(:methods
|
||||
(new (symbol type int) _type_ 0)
|
||||
(update-rates! (_type_ float) float 9)
|
||||
(advance-by! (_type_ float) clock 10)
|
||||
(tick! (_type_) clock 11)
|
||||
(save! (_type_ (pointer uint64)) int 12)
|
||||
(load! (_type_ (pointer uint64)) int 13)
|
||||
(reset! (_type_) none 14)
|
||||
(new (symbol type int) _type_)
|
||||
(update-rates! (_type_ float) float)
|
||||
(advance-by! (_type_ float) clock)
|
||||
(tick! (_type_) clock)
|
||||
(save! (_type_ (pointer uint64)) int)
|
||||
(load! (_type_ (pointer uint64)) int)
|
||||
(reset! (_type_) none)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -387,9 +387,9 @@
|
||||
:size-assert #x28
|
||||
:flag-assert #xc00000028
|
||||
(:methods
|
||||
(stack-size-set! (_type_ int) none 9)
|
||||
(thread-suspend (_type_) none 10)
|
||||
(thread-resume (_type_) none 11)
|
||||
(stack-size-set! (_type_ int) none)
|
||||
(thread-suspend (_type_) none)
|
||||
(thread-resume (_type_) none)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -408,7 +408,7 @@
|
||||
:size-assert #x80
|
||||
:flag-assert #xc00000080
|
||||
(:methods
|
||||
(new (symbol type process symbol int pointer) _type_ 0)
|
||||
(new (symbol type process symbol int pointer) _type_)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -421,9 +421,9 @@
|
||||
:flag-assert #x1000000024
|
||||
;; Failed to read fields.
|
||||
(:methods
|
||||
(new (symbol type int int string) _type_ 0)
|
||||
(get-process (_type_ type int) process 14)
|
||||
(return-process (_type_ process) none 15)
|
||||
(new (symbol type int int string) _type_)
|
||||
(get-process (_type_ type int) process)
|
||||
(return-process (_type_ process) none)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -459,19 +459,19 @@
|
||||
:flag-assert #x1c00000068
|
||||
;; Failed to read fields.
|
||||
(:methods
|
||||
(new (symbol type string int int) _type_ 0)
|
||||
(init (_type_ symbol int) none 16)
|
||||
(compact (dead-pool-heap int) none 17)
|
||||
(shrink-heap (dead-pool-heap process) dead-pool-heap 18)
|
||||
(churn (dead-pool-heap int) none 19)
|
||||
(memory-used (_type_) int 20)
|
||||
(memory-total (_type_) int 21)
|
||||
(memory-free (dead-pool-heap) int 22)
|
||||
(compact-time (dead-pool-heap) uint 23)
|
||||
(gap-size (dead-pool-heap dead-pool-heap-rec) int 24)
|
||||
(gap-location (dead-pool-heap dead-pool-heap-rec) pointer 25)
|
||||
(find-gap (dead-pool-heap dead-pool-heap-rec) dead-pool-heap-rec 26)
|
||||
(find-gap-by-size (dead-pool-heap int) dead-pool-heap-rec 27)
|
||||
(new (symbol type string int int) _type_)
|
||||
(init (_type_ symbol int) none)
|
||||
(compact (dead-pool-heap int) none)
|
||||
(shrink-heap (dead-pool-heap process) dead-pool-heap)
|
||||
(churn (dead-pool-heap int) none)
|
||||
(memory-used (_type_) int)
|
||||
(memory-total (_type_) int)
|
||||
(memory-free (dead-pool-heap) int)
|
||||
(compact-time (dead-pool-heap) uint)
|
||||
(gap-size (dead-pool-heap dead-pool-heap-rec) int)
|
||||
(gap-location (dead-pool-heap dead-pool-heap-rec) pointer)
|
||||
(find-gap (dead-pool-heap dead-pool-heap-rec) dead-pool-heap-rec)
|
||||
(find-gap-by-size (dead-pool-heap int) dead-pool-heap-rec)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -499,7 +499,7 @@
|
||||
:size-assert #xb0
|
||||
:flag-assert #x9000000b0
|
||||
(:methods
|
||||
(new (symbol type symbol function (pointer uint64)) object 0)
|
||||
(new (symbol type symbol function (pointer uint64)) object)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -535,7 +535,7 @@
|
||||
(function none)
|
||||
function
|
||||
(function none)
|
||||
(function process int symbol event-message-block object)) _type_ 0)
|
||||
(function process int symbol event-message-block object)) _type_)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x24
|
||||
@@ -566,7 +566,7 @@
|
||||
:size-assert #x10
|
||||
:flag-assert #xa00000010
|
||||
(:methods
|
||||
(send-all! (_type_) none 9)
|
||||
(send-all! (_type_) none)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -594,7 +594,7 @@
|
||||
(stack uint8 :dynamic :offset-assert 128 :score -1)
|
||||
)
|
||||
(:methods
|
||||
(new (symbol type string int) _type_ 0)
|
||||
(new (symbol type string int) _type_)
|
||||
)
|
||||
(:states
|
||||
dead-state
|
||||
@@ -604,17 +604,6 @@
|
||||
:no-runtime-type ;; already defined by kscheme. Don't do it again.
|
||||
)
|
||||
|
||||
(deftype sql-result (basic)
|
||||
((len int32 :offset-assert 4)
|
||||
(allocated-length uint32 :offset-assert 8)
|
||||
(error symbol :offset-assert 12)
|
||||
(data string :dynamic :offset-assert 16) ;; are these actually symbols, or are they strings (in the GOAL code they are treated as strings atleast)
|
||||
)
|
||||
(:methods (new (symbol type uint) _type_ 0))
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
)
|
||||
|
||||
(define-extern *sql-result* sql-result)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -693,4 +682,4 @@
|
||||
(define-extern *mid-pool* process-tree)
|
||||
(define-extern *pusher-pool* process-tree)
|
||||
(define-extern *bg-pool* process-tree)
|
||||
(define-extern *default-pool* process-tree) ;; process-tree
|
||||
(define-extern *default-pool* process-tree) ;; process-tree
|
||||
@@ -80,7 +80,7 @@
|
||||
////////////////////////////
|
||||
// CONFIG FILES
|
||||
////////////////////////////
|
||||
|
||||
|
||||
"type_casts_file": "decompiler/config/jak3/ntsc_v1/type_casts.jsonc",
|
||||
"anonymous_function_types_file": "decompiler/config/jak3/ntsc_v1/anonymous_function_types.jsonc",
|
||||
"var_names_file": "decompiler/config/jak3/ntsc_v1/var_names.jsonc",
|
||||
|
||||
@@ -133,20 +133,23 @@ void TextureDB::replace_textures(const fs::path& path) {
|
||||
fs::path base_path(path);
|
||||
for (auto& tex : textures) {
|
||||
fs::path full_path = base_path / tpage_names.at(tex.second.page) / (tex.second.name + ".png");
|
||||
if (fs::exists(full_path)) {
|
||||
lg::info("Replacing {}", full_path.string().c_str());
|
||||
int w, h;
|
||||
auto data = stbi_load(full_path.string().c_str(), &w, &h, 0, 4); // rgba channels
|
||||
if (!data) {
|
||||
lg::warn("failed to load PNG file: {}", full_path.string().c_str());
|
||||
if (!fs::exists(full_path)) {
|
||||
full_path = base_path / "_all" / (tex.second.name + ".png");
|
||||
if (!fs::exists(full_path))
|
||||
continue;
|
||||
}
|
||||
tex.second.rgba_bytes.resize(w * h);
|
||||
memcpy(tex.second.rgba_bytes.data(), data, w * h * 4);
|
||||
tex.second.w = w;
|
||||
tex.second.h = h;
|
||||
stbi_image_free(data);
|
||||
}
|
||||
lg::info("Replacing {}", tpage_names.at(tex.second.page) + "/" + (tex.second.name));
|
||||
int w, h;
|
||||
auto data = stbi_load(full_path.string().c_str(), &w, &h, 0, 4); // rgba channels
|
||||
if (!data) {
|
||||
lg::warn("failed to load PNG file: {}", full_path.string().c_str());
|
||||
continue;
|
||||
}
|
||||
tex.second.rgba_bytes.resize(w * h);
|
||||
memcpy(tex.second.rgba_bytes.data(), data, w * h * 4);
|
||||
tex.second.w = w;
|
||||
tex.second.h = h;
|
||||
stbi_image_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "extract_collide_frags.h"
|
||||
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
|
||||
namespace decompiler {
|
||||
@@ -230,6 +231,7 @@ void set_vertices_for_tri(tfrag3::CollisionMesh::Vertex* out, const math::Vector
|
||||
|
||||
void extract_collide_frags(const level_tools::DrawableTreeCollideFragment* tree,
|
||||
const std::vector<const level_tools::DrawableTreeInstanceTie*>& ties,
|
||||
const Config& config,
|
||||
const std::string& debug_name,
|
||||
tfrag3::Level& out,
|
||||
bool dump_level) {
|
||||
@@ -260,8 +262,8 @@ void extract_collide_frags(const level_tools::DrawableTreeCollideFragment* tree,
|
||||
|
||||
if (dump_level) {
|
||||
auto debug_out = debug_dump_to_obj(all_frags);
|
||||
auto file_path =
|
||||
file_util::get_file_path({"debug_out", fmt::format("collide-{}.obj", debug_name)});
|
||||
auto file_path = file_util::get_file_path(
|
||||
{fmt::format("debug_out/{}", config.game_name), fmt::format("collide-{}.obj", debug_name)});
|
||||
file_util::create_dir_if_needed_for_file(file_path);
|
||||
file_util::write_text_file(file_path, debug_out);
|
||||
}
|
||||
@@ -408,10 +410,40 @@ void handle_collide_fragment(const TypedRef& collide_fragment,
|
||||
}
|
||||
}
|
||||
|
||||
std::string debug_dump_to_obj(const std::vector<tfrag3::CollisionMesh::Vertex>& verts_in) {
|
||||
std::vector<math::Vector4f> verts;
|
||||
std::vector<math::Vector<u32, 3>> faces;
|
||||
|
||||
for (auto& v : verts_in) {
|
||||
verts.emplace_back(v.x / 4096.0, v.y / 4096.0, v.z / 4096.0, 1.0);
|
||||
|
||||
u32 v_len = verts.size();
|
||||
if (v_len % 3 == 0) {
|
||||
// add face from last 3 vertices
|
||||
faces.emplace_back(v_len - 2, v_len - 1, v_len);
|
||||
}
|
||||
}
|
||||
|
||||
std::string result;
|
||||
for (auto& vert : verts) {
|
||||
result += fmt::format("v {} {} {}\n", vert.x(), vert.y(), vert.z());
|
||||
}
|
||||
|
||||
for (auto& face : faces) {
|
||||
result += fmt::format("f {}/{} {}/{} {}/{}\n", face.x(), face.x(), face.y(), face.y(), face.z(),
|
||||
face.z());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void extract_collide_frags(const level_tools::CollideHash& chash,
|
||||
const std::vector<const level_tools::DrawableTreeInstanceTie*>& ties,
|
||||
const Config& config,
|
||||
const std::string& debug_name,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
tfrag3::Level& out) {
|
||||
tfrag3::Level& out,
|
||||
bool dump_level) {
|
||||
// We need to find all collide-hash-fragments, but we can't just scan through the entire file.
|
||||
// for collide-hash-fragments, we need to figure out which TIEs they belong to, to apply the
|
||||
// instance transformation matrix.
|
||||
@@ -474,5 +506,15 @@ void extract_collide_frags(const level_tools::CollideHash& chash,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dump_level) {
|
||||
// out.collision.vertices every 3 vertices make a face, so it duplicates vertices in many cases
|
||||
// for now debug_dump_to_obj isn't smart and doesn't hash these to save space or anything
|
||||
auto debug_out = debug_dump_to_obj(out.collision.vertices);
|
||||
auto file_path = file_util::get_file_path(
|
||||
{fmt::format("debug_out/{}", config.game_name), fmt::format("collide-{}.obj", debug_name)});
|
||||
file_util::create_dir_if_needed_for_file(file_path);
|
||||
file_util::write_text_file(file_path, debug_out);
|
||||
}
|
||||
}
|
||||
} // namespace decompiler
|
||||
@@ -8,13 +8,17 @@ namespace decompiler {
|
||||
|
||||
void extract_collide_frags(const level_tools::DrawableTreeCollideFragment* tree,
|
||||
const std::vector<const level_tools::DrawableTreeInstanceTie*>& ties,
|
||||
const Config& config,
|
||||
const std::string& debug_name,
|
||||
tfrag3::Level& out,
|
||||
bool dump_level);
|
||||
|
||||
void extract_collide_frags(const level_tools::CollideHash& chash,
|
||||
const std::vector<const level_tools::DrawableTreeInstanceTie*>& ties,
|
||||
const Config& config,
|
||||
const std::string& debug_name,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
tfrag3::Level& out);
|
||||
tfrag3::Level& out,
|
||||
bool dump_level);
|
||||
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
@@ -159,9 +159,10 @@ std::vector<level_tools::TextureRemap> extract_tex_remap(const ObjectFileDB& db,
|
||||
level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db,
|
||||
const TextureDB& tex_db,
|
||||
const std::string& dgo_name,
|
||||
const DecompileHacks& hacks,
|
||||
const Config& config,
|
||||
bool extract_collision,
|
||||
tfrag3::Level& level_data) {
|
||||
auto hacks = config.hacks;
|
||||
auto bsp_rec = get_bsp_file(db.obj_files_by_dgo.at(dgo_name), dgo_name);
|
||||
if (!bsp_rec) {
|
||||
lg::warn("Skipping extract for {} because the BSP file was not found", dgo_name);
|
||||
@@ -236,8 +237,8 @@ level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db,
|
||||
ASSERT(as_collide_frags);
|
||||
ASSERT(!got_collide);
|
||||
got_collide = true;
|
||||
extract_collide_frags(as_collide_frags, all_ties, fmt::format("{}-{}-collide", dgo_name, i++),
|
||||
level_data, false);
|
||||
extract_collide_frags(as_collide_frags, all_ties, config,
|
||||
fmt::format("{}-{}-collide", dgo_name, i++), level_data, false);
|
||||
} else {
|
||||
lg::print(" unsupported tree {}\n", draw_tree->my_type());
|
||||
}
|
||||
@@ -245,7 +246,8 @@ level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db,
|
||||
|
||||
if (bsp_header.collide_hash.num_items) {
|
||||
ASSERT(!got_collide);
|
||||
extract_collide_frags(bsp_header.collide_hash, all_ties, db.dts, level_data);
|
||||
extract_collide_frags(bsp_header.collide_hash, all_ties, config,
|
||||
fmt::format("{}-{}-collide", dgo_name, i++), db.dts, level_data, false);
|
||||
}
|
||||
level_data.level_name = level_name;
|
||||
|
||||
@@ -348,7 +350,7 @@ void extract_from_level(const ObjectFileDB& db,
|
||||
|
||||
// the bsp header file data
|
||||
auto bsp_header =
|
||||
extract_bsp_from_level(db, tex_db, dgo_name, config.hacks, extract_collision, level_data);
|
||||
extract_bsp_from_level(db, tex_db, dgo_name, config, extract_collision, level_data);
|
||||
extract_art_groups_from_level(db, tex_db, bsp_header.texture_remap_table, dgo_name, level_data,
|
||||
art_group_data);
|
||||
|
||||
|
||||
@@ -424,7 +424,8 @@ void make_draws(tfrag3::Level& lev,
|
||||
std::vector<std::vector<u32>> indices_regrouped_by_draw;
|
||||
std::unordered_map<u32, std::vector<u32>> static_draws_by_tex;
|
||||
size_t global_vert_counter = 0;
|
||||
for (auto& proto : protos) {
|
||||
for (u32 proto_idx = 0; proto_idx < protos.size(); proto_idx++) {
|
||||
auto& proto = protos[proto_idx];
|
||||
// packed_vert_indices[frag][draw] = {start, end}
|
||||
std::vector<std::vector<std::pair<int, int>>> packed_vert_indices;
|
||||
|
||||
@@ -509,7 +510,9 @@ void make_draws(tfrag3::Level& lev,
|
||||
std::vector<u32>* verts_to_add_to = nullptr;
|
||||
if (existing_draws_in_tex != static_draws_by_tex.end()) {
|
||||
for (auto idx : existing_draws_in_tex->second) {
|
||||
if (tree_out.static_draws.at(idx).mode == mode) {
|
||||
auto& candidate_draw_out = tree_out.static_draws.at(idx);
|
||||
if (candidate_draw_out.mode == mode && (!tree_out.has_per_proto_visibility_toggle ||
|
||||
candidate_draw_out.proto_idx == proto_idx)) {
|
||||
draw_to_add_to = &tree_out.static_draws[idx];
|
||||
verts_to_add_to = &indices_regrouped_by_draw[idx];
|
||||
}
|
||||
@@ -523,6 +526,9 @@ void make_draws(tfrag3::Level& lev,
|
||||
draw_to_add_to = &tree_out.static_draws.back();
|
||||
draw_to_add_to->mode = mode;
|
||||
draw_to_add_to->tree_tex_id = idx_in_lev_data;
|
||||
if (tree_out.has_per_proto_visibility_toggle) {
|
||||
draw_to_add_to->proto_idx = proto_idx;
|
||||
}
|
||||
verts_to_add_to = &indices_regrouped_by_draw.emplace_back();
|
||||
}
|
||||
|
||||
@@ -573,10 +579,16 @@ void extract_shrub(const shrub_types::DrawableTreeInstanceShrub* tree,
|
||||
bool dump_level,
|
||||
GameVersion version) {
|
||||
auto& tree_out = out.shrub_trees.emplace_back();
|
||||
|
||||
if (version > GameVersion::Jak1) {
|
||||
tree_out.has_per_proto_visibility_toggle = true;
|
||||
}
|
||||
|
||||
auto& protos = tree->info.prototype_inline_array_shrub;
|
||||
std::vector<ShrubProtoInfo> proto_info;
|
||||
for (auto& proto : protos.data) {
|
||||
proto_info.push_back(extract_proto(proto, tex_db, map, version));
|
||||
tree_out.proto_names.push_back(proto.name);
|
||||
}
|
||||
|
||||
for (auto& arr : tree->discovered_arrays) {
|
||||
|
||||
@@ -115,6 +115,29 @@ void DecompilerTypeSystem::parse_type_defs(const std::vector<std::string>& file_
|
||||
});
|
||||
}
|
||||
|
||||
void DecompilerTypeSystem::parse_enum_defs(const std::vector<std::string>& file_path) {
|
||||
auto read = m_reader.read_from_file(file_path);
|
||||
auto& data = cdr(read);
|
||||
|
||||
for_each_in_list(data, [&](goos::Object& o) {
|
||||
try {
|
||||
if (car(o).as_symbol() == "defenum") {
|
||||
auto symbol_metadata = DefinitionMetadata();
|
||||
parse_defenum(cdr(o), &ts, &symbol_metadata);
|
||||
symbol_metadata.definition_info = m_reader.db.get_short_info_for(o);
|
||||
auto* rest = &cdr(o);
|
||||
const auto& enum_name = car(*rest).as_symbol();
|
||||
symbol_metadata_map[enum_name.name_ptr] = symbol_metadata;
|
||||
// so far, enums are never runtime types so there's no symbol for them.
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
auto info = m_reader.db.get_info_for(o);
|
||||
lg::error("{} when parsing decompiler type file:{}", e.what(), info);
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TypeSpec DecompilerTypeSystem::parse_type_spec(const std::string& str) const {
|
||||
auto read = m_reader.read_from_string(str);
|
||||
auto data = cdr(read);
|
||||
|
||||
@@ -56,6 +56,7 @@ class DecompilerTypeSystem {
|
||||
const TypeSpec& type_spec,
|
||||
const DefinitionMetadata& symbol_metadata);
|
||||
void parse_type_defs(const std::vector<std::string>& file_path);
|
||||
void parse_enum_defs(const std::vector<std::string>& file_path);
|
||||
TypeSpec parse_type_spec(const std::string& str) const;
|
||||
void add_type_flags(const std::string& name, u64 flags);
|
||||
void add_type_parent(const std::string& child, const std::string& parent);
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,4 +1,243 @@
|
||||
{
|
||||
"cutscenes": {},
|
||||
"other": {}
|
||||
"other": {
|
||||
"erol002": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 100,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
},
|
||||
{
|
||||
"frame_end": 162,
|
||||
"frame_start": 101,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
},
|
||||
{
|
||||
"frame_end": 277,
|
||||
"frame_start": 163,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
},
|
||||
{
|
||||
"frame_end": 348,
|
||||
"frame_start": 278,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
},
|
||||
{
|
||||
"frame_end": 425,
|
||||
"frame_start": 349,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
},
|
||||
{
|
||||
"frame_end": 588,
|
||||
"frame_start": 426,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
},
|
||||
{
|
||||
"frame_end": 815,
|
||||
"frame_start": 589,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
}
|
||||
]
|
||||
},
|
||||
"jakfall": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 93,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "jak"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mtn-plat-buried-rocks-a": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 168,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mtn-step-plat-rocks-a": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 88,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mtn-step-plat-rocks-b": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 92,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mtn-step-plat-rocks-c": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 80,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sam001": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 120,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "youngsamos"
|
||||
},
|
||||
{
|
||||
"frame_end": 273,
|
||||
"frame_start": 121,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "youngsamos"
|
||||
},
|
||||
{
|
||||
"frame_end": 423,
|
||||
"frame_start": 274,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "youngsamos"
|
||||
},
|
||||
{
|
||||
"frame_end": 479,
|
||||
"frame_start": 424,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "youngsamos"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sigc001": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 140,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "sig"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sigc073": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 52,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "sig"
|
||||
},
|
||||
{
|
||||
"frame_end": 151,
|
||||
"frame_start": 53,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "sig"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tombplta": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 129,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tombpltb": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 350,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"wtrdrain": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 163,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"wtrfill": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 165,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ys002": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 55,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "youngsamos"
|
||||
},
|
||||
{
|
||||
"frame_end": 93,
|
||||
"frame_start": 56,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "samos"
|
||||
},
|
||||
{
|
||||
"frame_end": 153,
|
||||
"frame_start": 94,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "samos"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,7 +92,7 @@
|
||||
"1251": "Enemy Health Bars",
|
||||
"1252": "Vehicle Health Bars",
|
||||
"1253": "Vehicle Invulnerability",
|
||||
"1254": "Statistics Page",
|
||||
"1254": "Statistics",
|
||||
"1255": "Automatically Grab Collectables",
|
||||
"1256": "Music Player",
|
||||
"1257": "No Textures Mode",
|
||||
@@ -107,6 +107,14 @@
|
||||
"1260": "JET-Board Trick Display",
|
||||
"1261": "Bad Weather",
|
||||
"1262": "Nice Weather",
|
||||
"1263": "Vehicle Hijack Voice Lines",
|
||||
"1264": "Locked",
|
||||
"1265": "Hit all 3 valves and find Mar's Statue in \"~S\" in under ~D seconds",
|
||||
"1266": "Reduce Haven City's population count by ~D",
|
||||
"1267": "Reduce Haven City's vehicle count by ~D",
|
||||
"1268": "Hunt every species of Metal Head",
|
||||
"1269": "Use the JET-Board to break open containers",
|
||||
"126a": "Transport the Rift Rider while leaving Samos and Young Samos unscathed",
|
||||
"1280": "Camera Options",
|
||||
"1281": "Left/Right (1st Person)",
|
||||
"1282": "Up/Down (1st Person)",
|
||||
@@ -142,6 +150,40 @@
|
||||
"12a0": "Object Shadows",
|
||||
"12a1": "Normal",
|
||||
"12a2": "Extended",
|
||||
"12a3": "No valid resolutions found.",
|
||||
"12a4": "Automatic",
|
||||
"12a5": "Bestiary",
|
||||
"12a6": "Other Statistics",
|
||||
"12a7": "Total Killed",
|
||||
"12a8": "Killed by Jak",
|
||||
"12a9": "Killed by Dark Jak",
|
||||
"12aa": "Killed by Daxter",
|
||||
"12ab": "Killed by Others",
|
||||
"12ac": "Blaster",
|
||||
"12ad": "Scatter Gun",
|
||||
"12ae": "Vulcan Fury",
|
||||
"12af": "Peacemaker",
|
||||
"12b0": "JET-Board",
|
||||
"12b1": "JET-Board Trick",
|
||||
"12b2": "Titan Suit Punch",
|
||||
"12b3": "Titan Suit Body",
|
||||
"12b4": "Gunpod",
|
||||
"12b5": "Punch",
|
||||
"12b6": "Flop",
|
||||
"12b7": "Uppercut",
|
||||
"12b8": "Spin",
|
||||
"12b9": "Roll",
|
||||
"12bf": "Dark Bomb",
|
||||
"12c0": "Dark Blast",
|
||||
"12c3": "Krimzon Guard",
|
||||
"12c4": "Sig",
|
||||
"12c5": "Ashelin",
|
||||
"12c6": "Jinx",
|
||||
"12c7": "Grim",
|
||||
"12c8": "Mog",
|
||||
"12c9": "Metal Heads",
|
||||
"12ca": "Other Friends",
|
||||
"12cb": "Other Enemies",
|
||||
"1300": "Auto Hide Cursor",
|
||||
"1301": "Reassign Binds",
|
||||
"1302": "Controller Binds",
|
||||
@@ -164,6 +206,7 @@
|
||||
"1313": "Local Time",
|
||||
"1314": "Warning!",
|
||||
"1315": "This setting is highly experimental. When not played at 60 frames per second, visual and gameplay issues may arise as a result.",
|
||||
"1316": "Local Score",
|
||||
"1320": "None",
|
||||
"1321": "Spin",
|
||||
"1322": "Boost",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"1a3": "Veuillez ne pas retirer ou insérer de périphériques, éteindre votre système ou arreter le jeu",
|
||||
"1b5": "Lorsque cette icône est à l'écran, ne retirez pas ou n'insérez aucun périphérique, n'éteignez pas votre système et n'arretez pas le jeu",
|
||||
"1a3": "Sauvegarde en cours. Veuillez à ne retirer ou n'insérer aucun périphérique, ni éteindre votre système ou arrêter le jeu.",
|
||||
"1b5": "Lorsque cette icône est à l'écran, ne retirez ou n'insérez aucun périphérique, ni éteindre votre système ou arrêter le jeu.",
|
||||
"1100": "Pas dans une mission",
|
||||
"1101": "Jouer une mission bonus",
|
||||
"1102": "Pulvérisator (Entrainement)",
|
||||
@@ -10,84 +10,84 @@
|
||||
"1106": "Le jeu d'Onin",
|
||||
"1107": "Chasse-taupe",
|
||||
"1200": "Mode d'affichage",
|
||||
"1201": "Fenetré",
|
||||
"1201": "Fenêtré",
|
||||
"1202": "Plein écran",
|
||||
"1203": "Sans bordures",
|
||||
"1204": "Auto",
|
||||
"1203": "Sans bordure",
|
||||
"1204": "Adapté à la fenêtre",
|
||||
"1205": "Personnalisé",
|
||||
"1206": "4x3",
|
||||
"1207": "16x9",
|
||||
"1207": "16x9 (4x3 zoomé en vertical)",
|
||||
"1208": "Choisissez le rapport entre la largeur/hauteur",
|
||||
"1209": "Appuyer sur <PAD_X> pour confirmer et quitter.",
|
||||
"120a": "Appuyer <PAD_CIRCLE> pour confirmer et quitter.",
|
||||
"1209": "Appuyer sur <PAD_X> pour confirmer.",
|
||||
"120a": "Appuyer <PAD_CIRCLE> pour confirmer.",
|
||||
"120b": "Le ratio ne doit pas être inférieur à 4x3!",
|
||||
"120c": "Lecteur de musique",
|
||||
"120c": "Musiques",
|
||||
"120d": "Synchronisation Verticale",
|
||||
"120e": "Langue du texte",
|
||||
"120f": "Secrets OpenGoal",
|
||||
"1210": "Largeur",
|
||||
"1211": "Hauteur",
|
||||
"1212": "??????????",
|
||||
"1213": "Lecture en cours...",
|
||||
"1214": "No Track",
|
||||
"1215": "Défaut",
|
||||
"1216": "Morph Gun",
|
||||
"1217": "Jet Board",
|
||||
"1218": "Titan Suit",
|
||||
"1219": "Dark Jak",
|
||||
"121a": "Vehicule",
|
||||
"1212": "Non débloqué",
|
||||
"1213": "Lecture en cours :",
|
||||
"1214": "Pas de musique",
|
||||
"1215": "Normal",
|
||||
"1216": "Avec une arme",
|
||||
"1217": "Sur le Jet Board",
|
||||
"1218": "Dans la Titanocombi",
|
||||
"1219": "En Dark Jak",
|
||||
"121a": "Dans un Véhicule",
|
||||
"121b": "Danger",
|
||||
"121c": "Sans",
|
||||
"121c": "Non",
|
||||
"121d": "Faible",
|
||||
"121e": "Moyen",
|
||||
"121f": "Élevé",
|
||||
"1220": "Exploration d'Abriville",
|
||||
"1220": "Abriville",
|
||||
"1221": "Course-poursuite",
|
||||
"1222": "Chasse-taupes (Alt)",
|
||||
"1223": "Le tombeau de Mar",
|
||||
"1222": "Inutilisé (Jak 3)",
|
||||
"1223": "Araignée géante",
|
||||
"1224": "Le défi d'Onin",
|
||||
"1225": "Métal Kor",
|
||||
"1225": "Praxis / Métal Kor",
|
||||
"1226": "Combat contre Krew",
|
||||
"1227": "Combat contre le Baron",
|
||||
"1228": "Bouncing Boulders",
|
||||
"1229": "Eco explosive",
|
||||
"1227": "Praxis au tombeau",
|
||||
"1228": "Éboulement",
|
||||
"1229": "Bombes plasmites",
|
||||
"122a": "Tank de la forteresse",
|
||||
"122b": "Station de pompage",
|
||||
"122c": "Protéger Sig",
|
||||
"122d": "Mine à ciel ouvert",
|
||||
"122e": "Forêt d'Abriville",
|
||||
"122f": "Dragons de la foret",
|
||||
"122e": "Abriforêt",
|
||||
"122f": "Abriforêt 2 / Crédits",
|
||||
"1230": "La forteresse",
|
||||
"1231": "Fuite",
|
||||
"1232": "Temple de la montagne",
|
||||
"1233": "Chasse-taupe",
|
||||
"1234": "Palais du baron Praxis",
|
||||
"1231": "La forteresse 2",
|
||||
"1232": "Temple montagne",
|
||||
"1233": "Rhinocéros",
|
||||
"1234": "Palais",
|
||||
"1235": "Usine d'armes",
|
||||
"1236": "Course d'arène",
|
||||
"1236": "Les courses",
|
||||
"1237": "Ville morte",
|
||||
"1238": "Taille de la fenetre",
|
||||
"1239": "Sélectionnez la taille de la fenetre",
|
||||
"1238": "Taille de la fenêtre",
|
||||
"1239": "Sélectionnez une taille",
|
||||
"123a": "Résolution du jeu",
|
||||
"123b": "Sélectionnez la résolution du jeu",
|
||||
"123c": "Niveau des détails (arrière-plan)",
|
||||
"123d": "Niveau des détails (premier plan)",
|
||||
"123c": "Niveau des textures",
|
||||
"123d": "Distance d'affichage des unités",
|
||||
"123f": "Nom de l'orateur",
|
||||
"1240": "Jamais",
|
||||
"1241": "Hors écran",
|
||||
"1242": "Toujours",
|
||||
"1243": "Game Territory",
|
||||
"1244": "America (SCEA)",
|
||||
"1243": "Territoire de jeu",
|
||||
"1244": "Amérique (SCEA)",
|
||||
"1245": "Europe (SCEE)",
|
||||
"1246": "Japan (SCEI)",
|
||||
"1247": "Korea (SCEK)",
|
||||
"1248": "MSAA",
|
||||
"1246": "Japon (SCEI)",
|
||||
"1247": "Corée (SCEK)",
|
||||
"1248": "Anti-Aliasing",
|
||||
"1249": "~DX",
|
||||
"124a": "Options de la LED du contrôleur",
|
||||
"124b": "Afficher l'état du joueur",
|
||||
"124c": "Afficher le niveau de santé",
|
||||
"124d": "Désactiver la sauvegarde automatique",
|
||||
"124e": "Sauvegarde automatique désactivée",
|
||||
"124f": "Etes-vous sûr de vouloir désactiver la sauvegarde automatique?",
|
||||
"124f": "Êtes-vous sûr de vouloir désactiver la sauvegarde automatique ?",
|
||||
"1250": "Turbo Jet Board dans Abriville",
|
||||
"1251": "Barres de santé des ennemis",
|
||||
"1252": "Barres de santé des véhicules",
|
||||
@@ -104,24 +104,24 @@
|
||||
"125d": "Suivi des orbes",
|
||||
"125e": "Heure réelle de la journée",
|
||||
"125f": "Ruines d'Abriville",
|
||||
"1260": "Afficher les figures de Jet Board",
|
||||
"1260": "Afficher les figures du Jet Board",
|
||||
"1261": "Mauvais temps",
|
||||
"1262": "Beau temps",
|
||||
"1280": "Options de caméra",
|
||||
"1281": "Gauche/Droite (1ere Personne)",
|
||||
"1282": "Haut/Bas (1ere Personne)",
|
||||
"1283": "Gauche/Droite (3eme Personne)",
|
||||
"1284": "Haut/Bas (3eme Personne)",
|
||||
"1281": "Horizontal (1ère Personne)",
|
||||
"1282": "Vertical (1ère Personne)",
|
||||
"1283": "Horizontal (3ème Personne)",
|
||||
"1284": "Vertical (3ème Personne)",
|
||||
"1285": "Réinitialiser les paramètres par défaut",
|
||||
"1286": "Normale",
|
||||
"1287": "Inversée",
|
||||
"1288": "Élimination des particules",
|
||||
"1289": "Discord Rich-Presence",
|
||||
"128a": "Défaut",
|
||||
"1289": "Rich Presence sur Discord",
|
||||
"128a": "Par défaut",
|
||||
"128b": "Bas",
|
||||
"128c": "Haut",
|
||||
"128d": "Crédits",
|
||||
"128e": "Fréquence d'images",
|
||||
"128e": "Fréquence d'images (FPS)",
|
||||
"128f": "Autres",
|
||||
"1290": "Mode speedrun",
|
||||
"1291": "Options d'entrée",
|
||||
@@ -129,7 +129,7 @@
|
||||
"1293": "Options de la manette",
|
||||
"1294": "Sélectionnez la manette",
|
||||
"1295": "Zone morte",
|
||||
"1296": "Ignorer si la fenetre est en arrière-plan",
|
||||
"1296": "Pause en arrière-plan",
|
||||
"1297": "Utiliser la LED pour la santé",
|
||||
"1298": "Utiliser la LED pour d'autres états",
|
||||
"1299": "Activer le clavier",
|
||||
@@ -139,9 +139,9 @@
|
||||
"129d": "Sensibilité horizontale",
|
||||
"129e": "Sensibilité verticale",
|
||||
"129f": "Déplacements du personnage",
|
||||
"12a0": "Object Shadows",
|
||||
"12a0": "Ombres des objets",
|
||||
"12a1": "Normal",
|
||||
"12a2": "Extended",
|
||||
"12a2": "Élevées",
|
||||
"1300": "Masquer automatiquement le curseur",
|
||||
"1301": "Configuration des touches",
|
||||
"1302": "Affectation des boutons de la manette",
|
||||
@@ -164,8 +164,8 @@
|
||||
"1313": "Heure locale",
|
||||
"1314": "Attention !",
|
||||
"1315": "Ce paramètre est expérimental. Si le jeu n'est pas joué à 60 images par seconde, des problèmes visuels et de gameplay peuvent survenir.",
|
||||
"1320": "None",
|
||||
"1321": "Spin",
|
||||
"1320": "Rien",
|
||||
"1321": "Tourbillon",
|
||||
"1322": "Boost",
|
||||
"1323": "Flip",
|
||||
"1324": "Rail Grind",
|
||||
@@ -183,11 +183,11 @@
|
||||
"1330": "Dark Bomb",
|
||||
"1331": "Dark Blast",
|
||||
"1332": "Dark Giant",
|
||||
"1333": "PS2 Options",
|
||||
"1333": "Options PS2",
|
||||
"1334": "Actor Culling",
|
||||
"1335": "Force Environment Mapping",
|
||||
"1336": "Fast Progress Menu",
|
||||
"1336": "Menu de pause rapide",
|
||||
"1337": "PS2 LOD Distance",
|
||||
"1338": "Off",
|
||||
"1339": "Display"
|
||||
"1339": "Écran"
|
||||
}
|
||||
@@ -559,6 +559,7 @@
|
||||
030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
|
||||
030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows,
|
||||
030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
|
||||
030000009b2800006100000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
|
||||
030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows,
|
||||
030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows,
|
||||
030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
@@ -1408,6 +1409,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00002f01000011010000,PDP Wired PS3 Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
|
||||
03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
|
||||
@@ -45,6 +45,13 @@ void Shrub::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProf
|
||||
memcpy(&m_pc_port_data, pc_port_data.data, sizeof(TfragPcPortData));
|
||||
m_pc_port_data.level_name[11] = '\0';
|
||||
|
||||
if (render_state->version == GameVersion::Jak2) {
|
||||
// jak 2 proto visibility
|
||||
auto proto_mask_data = dma.read_and_advance();
|
||||
m_proto_vis_data = proto_mask_data.data;
|
||||
m_proto_vis_data_size = proto_mask_data.size_bytes;
|
||||
}
|
||||
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
@@ -91,6 +98,13 @@ void Shrub::update_load(const LevelData* loader_data) {
|
||||
m_trees[l_tree].vertex_buffer = loader_data->shrub_vertex_data[l_tree];
|
||||
m_trees[l_tree].vert_count = verts;
|
||||
m_trees[l_tree].draws = &tree.static_draws;
|
||||
m_trees[l_tree].proto_vis_mask.clear();
|
||||
m_trees[l_tree].proto_vis_mask.resize(tree.proto_names.size(), true);
|
||||
m_trees[l_tree].proto_name_to_idx.clear();
|
||||
size_t i = 0;
|
||||
for (auto& name : tree.proto_names) {
|
||||
m_trees[l_tree].proto_name_to_idx[name].push_back(i++);
|
||||
}
|
||||
m_trees[l_tree].colors = &tree.time_of_day_colors;
|
||||
m_trees[l_tree].index_data = tree.indices.data();
|
||||
m_trees[l_tree].tod_cache = swizzle_time_of_day(tree.time_of_day_colors);
|
||||
@@ -216,6 +230,45 @@ void Shrub::render_all_trees(const TfragRenderSettings& settings,
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
void update_vis_mask(std::vector<bool>& vis_mask,
|
||||
const u8* data,
|
||||
u32 data_size,
|
||||
const std::unordered_map<std::string, std::vector<u32>>& name_to_idx) {
|
||||
char name_buffer[256]; // ??
|
||||
|
||||
for (u32 i = 0; i < vis_mask.size(); i++) {
|
||||
vis_mask[i] = true;
|
||||
}
|
||||
|
||||
const u8* end = data + data_size;
|
||||
while (true) {
|
||||
int name_idx = 0;
|
||||
while (*data) {
|
||||
name_buffer[name_idx++] = *data;
|
||||
data++;
|
||||
}
|
||||
if (name_idx) {
|
||||
ASSERT(name_idx < 254);
|
||||
name_buffer[name_idx] = '\0';
|
||||
const auto& it = name_to_idx.find(name_buffer);
|
||||
if (it != name_to_idx.end()) {
|
||||
for (auto x : name_to_idx.at(name_buffer)) {
|
||||
vis_mask[x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (*data == 0) {
|
||||
if (data >= end) {
|
||||
return;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Shrub::render_tree(int idx,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
@@ -259,6 +312,10 @@ void Shrub::render_tree(int idx,
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
glPrimitiveRestartIndex(UINT32_MAX);
|
||||
if (m_proto_vis_data) {
|
||||
update_vis_mask(tree.proto_vis_mask, m_proto_vis_data, m_proto_vis_data_size,
|
||||
tree.proto_name_to_idx);
|
||||
}
|
||||
tree.perf.tod_time.add(setup_timer.getSeconds());
|
||||
|
||||
int last_texture = -1;
|
||||
@@ -282,6 +339,9 @@ void Shrub::render_tree(int idx,
|
||||
|
||||
for (size_t draw_idx = 0; draw_idx < tree.draws->size(); draw_idx++) {
|
||||
const auto& draw = tree.draws->operator[](draw_idx);
|
||||
if (!tree.proto_vis_mask.at(draw.proto_idx)) {
|
||||
continue;
|
||||
}
|
||||
const auto& multidraw_indices = m_cache.multidraw_offset_per_stripdraw[draw_idx];
|
||||
const auto& singledraw_indices = m_cache.draw_idx_temp[draw_idx];
|
||||
|
||||
|
||||
@@ -42,6 +42,8 @@ class Shrub : public BucketRenderer {
|
||||
const std::vector<tfrag3::TimeOfDayColor>* colors = nullptr;
|
||||
const u32* index_data = nullptr;
|
||||
SwizzledTimeOfDay tod_cache;
|
||||
std::vector<bool> proto_vis_mask;
|
||||
std::unordered_map<std::string, std::vector<u32>> proto_name_to_idx;
|
||||
|
||||
struct {
|
||||
u32 draws = 0;
|
||||
@@ -78,4 +80,6 @@ class Shrub : public BucketRenderer {
|
||||
std::vector<void*> multidraw_index_offset_buffer;
|
||||
} m_cache;
|
||||
TfragPcPortData m_pc_port_data;
|
||||
const u8* m_proto_vis_data = nullptr;
|
||||
int m_proto_vis_data_size = 0;
|
||||
};
|
||||
@@ -365,7 +365,7 @@ void Loader::update_blocking(TexturePool& tex_pool) {
|
||||
}
|
||||
|
||||
const std::string* Loader::get_most_unloadable_level() {
|
||||
for (const auto& [name, lev] : m_loaded_tfrag3_levels) {
|
||||
for (auto& [name, lev] : m_loaded_tfrag3_levels) {
|
||||
if (lev->frames_since_last_used > 180 &&
|
||||
std::find(m_desired_levels.begin(), m_desired_levels.end(), name) ==
|
||||
m_desired_levels.end()) {
|
||||
@@ -511,7 +511,7 @@ void Loader::update(TexturePool& texture_pool) {
|
||||
}
|
||||
|
||||
if (unload_timer.getMs() > 5.f) {
|
||||
fmt::print("Unload took {:.2f}\n", unload_timer.getMs());
|
||||
fmt::print("Unload took {:.2f}ms\n", unload_timer.getMs());
|
||||
}
|
||||
|
||||
if (!m_garbage_buffers.empty()) {
|
||||
|
||||
@@ -512,13 +512,13 @@ void pc_get_active_display_size(u32 w_ptr, u32 h_ptr) {
|
||||
return;
|
||||
}
|
||||
if (w_ptr) {
|
||||
auto w_out = Ptr<u32>(w_ptr).c();
|
||||
auto w_out = Ptr<s64>(w_ptr).c();
|
||||
if (w_out) {
|
||||
*w_out = Display::GetMainDisplay()->get_display_manager()->get_screen_width();
|
||||
}
|
||||
}
|
||||
if (h_ptr) {
|
||||
auto h_out = Ptr<u32>(h_ptr).c();
|
||||
auto h_out = Ptr<s64>(h_ptr).c();
|
||||
if (h_out) {
|
||||
*h_out = Display::GetMainDisplay()->get_display_manager()->get_screen_height();
|
||||
}
|
||||
@@ -537,13 +537,13 @@ void pc_get_window_size(u32 w_ptr, u32 h_ptr) {
|
||||
return;
|
||||
}
|
||||
if (w_ptr) {
|
||||
auto w = Ptr<u32>(w_ptr).c();
|
||||
auto w = Ptr<s64>(w_ptr).c();
|
||||
if (w) {
|
||||
*w = Display::GetMainDisplay()->get_display_manager()->get_window_width();
|
||||
}
|
||||
}
|
||||
if (h_ptr) {
|
||||
auto h = Ptr<u32>(h_ptr).c();
|
||||
auto h = Ptr<s64>(h_ptr).c();
|
||||
if (h) {
|
||||
*h = Display::GetMainDisplay()->get_display_manager()->get_window_height();
|
||||
}
|
||||
@@ -590,11 +590,11 @@ s64 pc_get_num_resolutions() {
|
||||
void pc_get_resolution(u32 id, u32 w_ptr, u32 h_ptr) {
|
||||
if (Display::GetMainDisplay()) {
|
||||
auto res = Display::GetMainDisplay()->get_display_manager()->get_resolution(id);
|
||||
auto w = Ptr<u32>(w_ptr).c();
|
||||
auto w = Ptr<s64>(w_ptr).c();
|
||||
if (w) {
|
||||
*w = res.width;
|
||||
}
|
||||
auto h = Ptr<u32>(h_ptr).c();
|
||||
auto h = Ptr<s64>(h_ptr).c();
|
||||
if (h) {
|
||||
*h = res.height;
|
||||
}
|
||||
@@ -664,7 +664,14 @@ u64 pc_get_controller_count() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pc_get_controller(u32 controller_id, u32 port) {
|
||||
u64 pc_get_controller_index(u32 port) {
|
||||
if (Display::GetMainDisplay()) {
|
||||
return Display::GetMainDisplay()->get_input_manager()->get_controller_index(port);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pc_set_controller(u32 controller_id, u32 port) {
|
||||
if (Display::GetMainDisplay()) {
|
||||
Display::GetMainDisplay()->get_input_manager()->set_controller_for_port(controller_id, port);
|
||||
}
|
||||
@@ -913,7 +920,8 @@ void init_common_pc_port_functions(
|
||||
make_func_symbol_func("pc-get-controller-name", (void*)pc_get_controller_name);
|
||||
make_func_symbol_func("pc-get-current-bind", (void*)pc_get_current_bind);
|
||||
make_func_symbol_func("pc-get-controller-count", (void*)pc_get_controller_count);
|
||||
make_func_symbol_func("pc-set-controller!", (void*)pc_get_controller);
|
||||
make_func_symbol_func("pc-get-controller-index", (void*)pc_get_controller_index);
|
||||
make_func_symbol_func("pc-set-controller!", (void*)pc_set_controller);
|
||||
make_func_symbol_func("pc-set-keyboard-enabled!", (void*)pc_set_keyboard_enabled);
|
||||
make_func_symbol_func("pc-set-mouse-options!", (void*)pc_set_mouse_options);
|
||||
make_func_symbol_func("pc-set-mouse-camera-sens!", (void*)pc_set_mouse_camera_sens);
|
||||
|
||||
@@ -70,7 +70,7 @@ void load_and_link_dgo_from_c_fast(const char* name,
|
||||
// open the DGO file:
|
||||
auto file_path = file_util::get_jak_project_dir() / "out" / game_version_names[g_game_version] /
|
||||
"iso" / name_on_cd;
|
||||
auto fp = fopen(file_path.string().c_str(), "rb");
|
||||
auto fp = file_util::open_file(file_path, "rb");
|
||||
if (!fp) {
|
||||
lg::die("Failed to open DGO: {}, path {}\n", name, file_path.string());
|
||||
}
|
||||
|
||||
@@ -730,22 +730,23 @@ std::unordered_map<std::string, std::vector<std::pair<std::string, float>>>
|
||||
external_highscores_cache = {};
|
||||
|
||||
// clang-format off
|
||||
// TODO - eventually don't depend on SRC
|
||||
const std::unordered_map<std::string, std::string> external_speedrun_lookup_urls = {
|
||||
{"any", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/category/wdmze42q?embed=players&max=200"},
|
||||
{"anyhoverless", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/category/xd1rxxrk?embed=players&max=200"},
|
||||
{"allmissions", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/category/mkeon9d6?embed=players&max=200"},
|
||||
{"100", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/category/7dg8q424?embed=players&max=200"},
|
||||
{"anyorbs", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/category/wkpj7vkr?embed=players&max=200"},
|
||||
{"anyhero", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/category/vdo0jodp?embed=players&max=200"}};
|
||||
{"any", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/category/n2y6y4ed?embed=players&max=200"},
|
||||
{"anyhoverless", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/category/7kjyn5gk?embed=players&max=200"},
|
||||
{"allmissions", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/category/xk96myxk?embed=players&max=200"},
|
||||
{"100", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/category/z27exp5k?embed=players&max=200"},
|
||||
{"anyorbs", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/category/zdn3vm72?embed=players&max=200"},
|
||||
{"anyhero", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/category/q25pv0wd?embed=players&max=200"}};
|
||||
const std::unordered_map<std::string, std::string> external_race_lookup_urls = {
|
||||
{"class3", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/rw6vp697/xd1738d8?embed=players&max=200"},
|
||||
{"class2", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/n9305r90/xd1738d8?embed=players&max=200"},
|
||||
{"class1", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/z98jv1wl/xd1738d8?embed=players&max=200"},
|
||||
{"class3rev", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/rdn5j6dm/xd1738d8?embed=players&max=200"},
|
||||
{"class2rev", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/ldye77w3/xd1738d8?embed=players&max=200"},
|
||||
{"class1rev", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/gdrqkk9z/xd1738d8?embed=players&max=200"},
|
||||
{"erol", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/nwl7kg9v/xd1738d8?embed=players&max=200"},
|
||||
{"port", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/ywe8z4wl/xd1738d8?embed=players&max=200"}};
|
||||
{"class3", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/y9m7qmx9/jdr0mg0d?embed=players&max=200"},
|
||||
{"class2", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/5wk5zmpw/jdr0mg0d?embed=players&max=200"},
|
||||
{"class1", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/5922g639/jdr0mg0d?embed=players&max=200"},
|
||||
{"class3rev", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/29v4e8l9/jdr0mg0d?embed=players&max=200"},
|
||||
{"class2rev", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/xd4475rd/jdr0mg0d?embed=players&max=200"},
|
||||
{"class1rev", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/xd0mre4w/jdr0mg0d?embed=players&max=200"},
|
||||
{"erol", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/rw68p7gd/jdr0mg0d?embed=players&max=200"},
|
||||
{"port", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/n93v5xzd/jdr0mg0d?embed=players&max=200"}};
|
||||
const std::unordered_map<std::string, std::string> external_highscores_lookup_urls = {
|
||||
{"scatter", "https://api.jakspeedruns.workers.dev/v1/highscores/2"},
|
||||
{"blaster", "https://api.jakspeedruns.workers.dev/v1/highscores/3"},
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ int main(int argc, char** argv) {
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
if (show_version) {
|
||||
lg::print(build_revision());
|
||||
lg::print("{}", build_revision());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,10 +19,12 @@ SoundBank* gBanks[N_BANKS] = {&gCommonBank, &gGunBank, &gBoardBank,
|
||||
&gLevelBanks[0], &gLevelBanks[1], &gLevelBanks[2]};
|
||||
|
||||
void sbank_init_globals() {
|
||||
memset((void*)&gCommonBank, 0, sizeof(gCommonBank));
|
||||
memset((void*)&gGunBank, 0, sizeof(gGunBank));
|
||||
memset((void*)&gBoardBank, 0, sizeof(gBoardBank));
|
||||
memset((void*)&gLevelBanks, 0, sizeof(gLevelBanks));
|
||||
gCommonBank = {};
|
||||
gGunBank = {};
|
||||
gBoardBank = {};
|
||||
for (auto& b : gLevelBanks) {
|
||||
b = {};
|
||||
}
|
||||
}
|
||||
|
||||
void InitBanks() {
|
||||
@@ -30,34 +32,41 @@ void InitBanks() {
|
||||
bank->bank_handle = 0;
|
||||
bank->sound_count = 0;
|
||||
|
||||
bank->in_use = false;
|
||||
bank->unk4 = 0;
|
||||
// paper over version differences
|
||||
// in_use doesn't exist in jak1, but setting it to true
|
||||
// for all banks results in the same behaviour
|
||||
if (g_game_version == GameVersion::Jak1) {
|
||||
bank->in_use = true;
|
||||
} else {
|
||||
bank->in_use = false;
|
||||
}
|
||||
|
||||
strcpy(bank->name, "<unused>");
|
||||
bank->unk4 = 0;
|
||||
strcpy(bank->name.data(), "<unused>");
|
||||
}
|
||||
|
||||
if (g_game_version == GameVersion::Jak2) {
|
||||
strncpy(gBanks[0]->name, "common", 16);
|
||||
strncpy(gBanks[0]->name.data(), "common", 16);
|
||||
gBanks[0]->spu_loc = 0x20000;
|
||||
gBanks[0]->spu_size = 0xAFCC0;
|
||||
|
||||
strncpy(gBanks[1]->name, "gun", 16);
|
||||
strncpy(gBanks[1]->name.data(), "gun", 16);
|
||||
gBanks[1]->spu_loc = 0x131740;
|
||||
gBanks[1]->spu_size = 0;
|
||||
|
||||
strncpy(gBanks[2]->name, "board", 16);
|
||||
strncpy(gBanks[2]->name.data(), "board", 16);
|
||||
gBanks[2]->spu_loc = 0x131740;
|
||||
gBanks[2]->spu_size = 0;
|
||||
|
||||
strncpy(gBanks[3]->name, "level0", 16);
|
||||
strncpy(gBanks[3]->name.data(), "level0", 16);
|
||||
gBanks[3]->spu_loc = 0x131740;
|
||||
gBanks[3]->spu_size = 0x42800;
|
||||
|
||||
strncpy(gBanks[4]->name, "level1", 16);
|
||||
strncpy(gBanks[4]->name.data(), "level1", 16);
|
||||
gBanks[4]->spu_loc = 0x173f40;
|
||||
gBanks[4]->spu_size = 0x42800;
|
||||
|
||||
strncpy(gBanks[5]->name, "level2", 16);
|
||||
strncpy(gBanks[5]->name.data(), "level2", 16);
|
||||
gBanks[5]->spu_loc = 0x1B6740;
|
||||
gBanks[5]->spu_size = 0x42800;
|
||||
}
|
||||
@@ -111,7 +120,7 @@ s32 LookupSoundIndex(const char* name, SoundBank** bank_out) {
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)bank->sound_count; i++) {
|
||||
if (memcmp(bank->sound[i].name, name, 16) == 0) {
|
||||
if (memcmp(bank->sound[i].name.data(), name, 16) == 0) {
|
||||
*bank_out = bank;
|
||||
return i;
|
||||
}
|
||||
@@ -129,16 +138,9 @@ SoundBank* LookupBank(const char* name) {
|
||||
return nullptr; // not found.
|
||||
}
|
||||
auto bank = gBanks[idx];
|
||||
// they had some weird stuff here that took advantage of the fact that this region was
|
||||
// 16-byte aligned, so it probably wasn't a memcmp, but this is easier.
|
||||
if (g_game_version == GameVersion::Jak1) {
|
||||
if ((memcmp(bank->name, name, 16) == 0)) {
|
||||
return bank;
|
||||
}
|
||||
} else {
|
||||
if ((memcmp(bank->name, name, 16) == 0) && bank->in_use) {
|
||||
return bank;
|
||||
}
|
||||
|
||||
if ((memcmp(bank->name.data(), name, 16) == 0) && bank->in_use) {
|
||||
return bank;
|
||||
}
|
||||
idx--;
|
||||
}
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "game/sound/sndshim.h"
|
||||
|
||||
struct SoundRecord {
|
||||
char name[16];
|
||||
std::array<char, 16> name;
|
||||
u32 fallof_params;
|
||||
};
|
||||
|
||||
struct SoundBank {
|
||||
char name[16];
|
||||
u32 bank_handle;
|
||||
std::array<char, 16> name;
|
||||
snd::BankHandle bank_handle;
|
||||
u32 sound_count;
|
||||
|
||||
union {
|
||||
SoundRecord sound[1];
|
||||
// name list, only for jak1
|
||||
std::vector<SoundRecord> sound;
|
||||
|
||||
// Needs to fit the biggest bank (common.sbk)
|
||||
u8 buffer[10 * 2048];
|
||||
|
||||
// Jak 2 additions go here
|
||||
struct {
|
||||
u32 spu_loc;
|
||||
u32 spu_size;
|
||||
u32 unk4;
|
||||
bool in_use;
|
||||
};
|
||||
};
|
||||
// jak2 additions
|
||||
u32 spu_loc;
|
||||
u32 spu_size;
|
||||
u32 unk4;
|
||||
bool in_use;
|
||||
};
|
||||
|
||||
void sbank_init_globals();
|
||||
|
||||
@@ -33,10 +33,10 @@ void PrintBankInfo(SoundBank* bank) {
|
||||
// we dont need this and it spams the console too much
|
||||
return;
|
||||
|
||||
printf("Bank %s\n\n", bank->name);
|
||||
printf("Bank %s\n\n", bank->name.data());
|
||||
for (u32 i = 0; i < bank->sound_count; i++) {
|
||||
// Some characters use the full 16 characters (bonelurker-grunt) and dont have a null terminator
|
||||
std::string name = std::string(bank->sound[i].name, 16);
|
||||
std::string name = std::string(bank->sound[i].name.data(), 16);
|
||||
printf("%d : %16s : min %d max %d curve %d\n", i, name.c_str(),
|
||||
bank->sound[i].fallof_params & 0x3fff, (bank->sound[i].fallof_params >> 14) & 0x3fff,
|
||||
bank->sound[i].fallof_params >> 28);
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "game/sound/sndshim.h"
|
||||
|
||||
// added
|
||||
u32 gMusicFadeHack = 0;
|
||||
MusicTweaks gMusicTweakInfo;
|
||||
s32 gMusicTweak = 0x80;
|
||||
int32_t gSoundEnable = 1;
|
||||
s32 gMusic = 0;
|
||||
snd::BankHandle gMusic = nullptr;
|
||||
s32 gMusicPause = 0;
|
||||
s32 gSoundInUse = 0;
|
||||
u8 gFPS = 60;
|
||||
|
||||
@@ -117,10 +117,10 @@ struct SoundRpcSetMirrror {
|
||||
extern s32 gMusicTweak;
|
||||
extern MusicTweaks gMusicTweakInfo;
|
||||
extern int32_t gSoundEnable;
|
||||
extern s32 gMusic;
|
||||
extern snd::BankHandle gMusic;
|
||||
extern s32 gMusicPause;
|
||||
extern s32 gSoundInUse;
|
||||
extern u8 gFPS;
|
||||
extern const char* gLanguage;
|
||||
extern u32 gFrameNum;
|
||||
void srpc_init_globals();
|
||||
void srpc_init_globals();
|
||||
+71
-112
@@ -11,7 +11,7 @@ Sound gSounds[64];
|
||||
Vec3w gEarTrans[2];
|
||||
Vec3w gCamTrans;
|
||||
s32 gMusicFadeDir = 0;
|
||||
Curve gCurve[16];
|
||||
Curve gCurves[16];
|
||||
s32 gCamAngle;
|
||||
u8 gMirrorMode = 0;
|
||||
u32 sLastTick = 0;
|
||||
@@ -134,10 +134,12 @@ s32 CalculateAngle(Vec3w* trans) {
|
||||
} else {
|
||||
angle = angle + 90;
|
||||
}
|
||||
} else if (diffZ >= 0) {
|
||||
angle = angle + 270;
|
||||
} else {
|
||||
angle = 270 - angle;
|
||||
if (diffZ >= 0) {
|
||||
angle = angle + 270;
|
||||
} else {
|
||||
angle = 270 - angle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +156,7 @@ s32 GetPan(Sound* sound) {
|
||||
return CalculateAngle(&sound->params.trans);
|
||||
}
|
||||
|
||||
s32 CalculateFallofVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 fo_max) {
|
||||
s32 CalculateFalloffVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 fo_max) {
|
||||
s32 xdiff = 0;
|
||||
s32 ydiff = 0;
|
||||
s32 zdiff = 0;
|
||||
@@ -170,30 +172,22 @@ s32 CalculateFallofVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32
|
||||
} else {
|
||||
if (fo_curve == 1) {
|
||||
return volume;
|
||||
}
|
||||
|
||||
if (fo_curve < 9) {
|
||||
xdiff = gEarTrans[0].x - pos->x;
|
||||
ydiff = gEarTrans[0].y - pos->y;
|
||||
zdiff = gEarTrans[0].z - pos->z;
|
||||
}
|
||||
|
||||
if (fo_curve == 9) {
|
||||
} else if (fo_curve == 9) {
|
||||
xdiff = gEarTrans[1].x - pos->x;
|
||||
ydiff = gEarTrans[1].y - pos->y;
|
||||
zdiff = gEarTrans[1].z - pos->z;
|
||||
}
|
||||
|
||||
if (fo_curve == 10) {
|
||||
} else if (fo_curve == 10) {
|
||||
xdiff = 0;
|
||||
ydiff = gEarTrans[0].y - pos->y;
|
||||
zdiff = 0;
|
||||
}
|
||||
|
||||
if (fo_curve == 11) {
|
||||
} else if (fo_curve == 11) {
|
||||
xdiff = gEarTrans[1].x - pos->x;
|
||||
ydiff = gEarTrans[1].y - pos->y;
|
||||
zdiff = gEarTrans[1].z - pos->z;
|
||||
} else {
|
||||
xdiff = gEarTrans[0].x - pos->x;
|
||||
ydiff = gEarTrans[0].y - pos->y;
|
||||
zdiff = gEarTrans[0].z - pos->z;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,72 +204,63 @@ s32 CalculateFallofVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32
|
||||
s32 min = fo_min << 8;
|
||||
s32 max = fo_max << 8;
|
||||
|
||||
if (max < xdiff || max < ydiff || max < zdiff) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (max > 0x7FFF) {
|
||||
max >>= 1;
|
||||
min >>= 1;
|
||||
xdiff >>= 1;
|
||||
ydiff >>= 1;
|
||||
zdiff >>= 1;
|
||||
}
|
||||
|
||||
u32 distance = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff;
|
||||
if (distance != 0) {
|
||||
s32 steps = 0;
|
||||
while ((distance & 0xc0000000) == 0) {
|
||||
distance <<= 2;
|
||||
steps++;
|
||||
s32 new_vol = 0;
|
||||
if (xdiff <= max && ydiff <= max && zdiff <= max) {
|
||||
while (max > 0x7fff) {
|
||||
max >>= 1;
|
||||
min >>= 1;
|
||||
xdiff >>= 1;
|
||||
ydiff >>= 1;
|
||||
zdiff >>= 1;
|
||||
}
|
||||
s32 dist_squared = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff;
|
||||
s32 dist_steps = 0;
|
||||
if (dist_squared != 0) {
|
||||
while ((dist_squared & 0xc0000000) == 0) {
|
||||
dist_steps = dist_steps + 1;
|
||||
dist_squared <<= 2;
|
||||
}
|
||||
dist_steps = sqrt_table[dist_squared >> 24] >> (dist_steps & 0x1f);
|
||||
}
|
||||
new_vol = volume;
|
||||
if (min < dist_steps) {
|
||||
s32 voldiff = dist_steps - min;
|
||||
if (dist_steps < max) {
|
||||
dist_steps = max - min;
|
||||
while (0xffff < voldiff) {
|
||||
dist_steps >>= 1;
|
||||
voldiff >>= 1;
|
||||
}
|
||||
voldiff = (voldiff << 0x10) / dist_steps;
|
||||
if (voldiff != 0x10000) {
|
||||
new_vol = voldiff * voldiff >> 0x10;
|
||||
new_vol = gCurves[fo_curve].unk4 * 0x10000 + gCurves[fo_curve].unk3 * voldiff +
|
||||
gCurves[fo_curve].unk2 * new_vol +
|
||||
gCurves[fo_curve].unk1 * ((new_vol * voldiff) >> 0x10) >>
|
||||
0xc;
|
||||
if (new_vol < 0) {
|
||||
new_vol = 0;
|
||||
} else {
|
||||
if (0x10000 < new_vol) {
|
||||
new_vol = 0x10000;
|
||||
}
|
||||
}
|
||||
new_vol = (new_vol * volume) >> 0x10;
|
||||
}
|
||||
} else {
|
||||
new_vol = 0;
|
||||
}
|
||||
}
|
||||
|
||||
distance = sqrt_table[distance >> 24] >> steps;
|
||||
} else {
|
||||
distance = 0;
|
||||
}
|
||||
|
||||
if (distance <= (u32)min) {
|
||||
return volume;
|
||||
if (fo_curve == 11 && new_vol < 0x180) {
|
||||
new_vol = 0x180;
|
||||
}
|
||||
|
||||
if (distance >= (u32)max) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 start = distance - min;
|
||||
s32 end = max - min;
|
||||
|
||||
while (start > 0xFFFF) {
|
||||
start >>= 1;
|
||||
end >>= 1;
|
||||
}
|
||||
|
||||
s32 v13 = (start << 16) / end;
|
||||
if (v13 == 0x10000) {
|
||||
return volume;
|
||||
}
|
||||
|
||||
s32 factor = ((gCurve[fo_curve].unk4 << 16) + gCurve[fo_curve].unk3 * v13 +
|
||||
gCurve[fo_curve].unk2 * ((v13 * v13) >> 16) +
|
||||
gCurve[fo_curve].unk1 * (((((v13 * v13) >> 16) * v13) >> 16) >> 16)) >>
|
||||
12;
|
||||
|
||||
if (factor > 0x10000) {
|
||||
factor = 0x10000;
|
||||
}
|
||||
|
||||
s32 ret = (factor * volume) >> 16;
|
||||
if (fo_curve == 11 && ret < 0x180) {
|
||||
ret = 0x180;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return new_vol;
|
||||
}
|
||||
|
||||
s32 GetVolume(Sound* sound) {
|
||||
return CalculateFallofVolume(&sound->params.trans, sound->params.volume, sound->params.fo_curve,
|
||||
sound->params.fo_min, sound->params.fo_max);
|
||||
return CalculateFalloffVolume(&sound->params.trans, sound->params.volume, sound->params.fo_curve,
|
||||
sound->params.fo_min, sound->params.fo_max);
|
||||
}
|
||||
|
||||
void UpdateVolume(Sound* sound) {
|
||||
@@ -322,32 +307,6 @@ void KillSoundsInGroup(u8 group) {
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateLocation(Sound* sound) {
|
||||
if (sound->id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_game_version == GameVersion::Jak1) {
|
||||
if ((sound->bank_entry->fallof_params >> 28) == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
s32 id = snd_SoundIsStillPlaying(sound->sound_handle);
|
||||
if (id == 0) {
|
||||
sound->id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
s32 volume = GetVolume(sound);
|
||||
if (volume == 0) {
|
||||
snd_StopSound(sound->sound_handle);
|
||||
} else {
|
||||
s32 pan = GetPan(sound);
|
||||
snd_SetSoundVolPan(id, volume, pan);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAutoVol(Sound* sound, s32 ticks) {
|
||||
if (ticks < sound->auto_time) {
|
||||
s32 nvol = sound->new_volume;
|
||||
@@ -395,12 +354,12 @@ void PrintActiveSounds() {
|
||||
for (auto& s : gSounds) {
|
||||
if (s.id != 0 && s.is_music == 0) {
|
||||
if (s.bank_entry != nullptr) {
|
||||
u32 len = strlen(s.bank_entry->name);
|
||||
u32 len = strlen(s.bank_entry->name.data());
|
||||
if (len > 16) {
|
||||
len = 16;
|
||||
}
|
||||
sprintf(string, " : Vol %d", GetVolume(&s));
|
||||
memcpy(string, s.bank_entry->name, len);
|
||||
memcpy(string, s.bank_entry->name.data(), len);
|
||||
printf("%s\n", string);
|
||||
} else { // added for printing jak2 sounds
|
||||
u32 len = strlen(s.name);
|
||||
@@ -417,8 +376,8 @@ void PrintActiveSounds() {
|
||||
}
|
||||
|
||||
void SetCurve(s32 curve, s32 falloff, s32 ease) {
|
||||
gCurve[curve].unk1 = ease * 2;
|
||||
gCurve[curve].unk2 = falloff - 3 * ease;
|
||||
gCurve[curve].unk3 = ease - falloff - 0x1000;
|
||||
gCurve[curve].unk4 = 0x1000;
|
||||
gCurves[curve].unk1 = ease * 2;
|
||||
gCurves[curve].unk2 = falloff - 3 * ease;
|
||||
gCurves[curve].unk3 = ease - falloff - 0x1000;
|
||||
gCurves[curve].unk4 = 0x1000;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ struct Curve {
|
||||
|
||||
extern Sound gSounds[64];
|
||||
extern Vec3w gEarTrans[2];
|
||||
extern Curve gCurve[16];
|
||||
extern Curve gCurves[16];
|
||||
extern Vec3w gCamTrans;
|
||||
extern u8 gMirrorMode;
|
||||
extern s32 gCamAngle;
|
||||
@@ -64,11 +64,10 @@ Sound* LookupSound(s32 id);
|
||||
Sound* AllocateSound();
|
||||
s32 GetVolume(Sound* sound);
|
||||
void UpdateVolume(Sound* sound);
|
||||
s32 CalculateFallofVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 fo_max);
|
||||
s32 CalculateFalloffVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 fo_max);
|
||||
s32 GetPan(Sound* sound);
|
||||
s32 CalculateAngle(Vec3w* trans);
|
||||
void KillSoundsInGroup(u8 group);
|
||||
void UpdateLocation(Sound* sound);
|
||||
void UpdateAutoVol(Sound* sound, s32 ticks);
|
||||
void PrintActiveSounds();
|
||||
void SetCurve(s32 curve, s32 fallof, s32 ease);
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/Assert.h"
|
||||
#include "common/util/BinaryReader.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
|
||||
#include "game/overlord/common/fake_iso.h"
|
||||
@@ -18,7 +19,7 @@ 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);
|
||||
uint32_t FS_LoadMusic(char* name, snd::BankHandle* 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
|
||||
@@ -200,7 +201,7 @@ uint32_t FS_SyncRead() {
|
||||
*/
|
||||
void FS_PollDrive() {}
|
||||
|
||||
uint32_t FS_LoadMusic(char* name, s32* bank_handle) {
|
||||
uint32_t FS_LoadMusic(char* name, snd::BankHandle* bank_handle) {
|
||||
char namebuf[16];
|
||||
strcpy(namebuf, name);
|
||||
namebuf[8] = 0;
|
||||
@@ -215,9 +216,27 @@ uint32_t FS_LoadMusic(char* name, s32* bank_handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// original overlord uses good old fread into a struct instance
|
||||
// lets use BinaryReader instead
|
||||
static void parseSoundBank(BinaryReader data, SoundBank& bank) {
|
||||
bank.name = data.read<std::array<char, 16>>();
|
||||
|
||||
data.read<u32>();
|
||||
bank.bank_handle = nullptr;
|
||||
|
||||
bank.sound_count = data.read<u32>();
|
||||
bank.sound.resize(bank.sound_count);
|
||||
|
||||
for (auto& snd : bank.sound) {
|
||||
snd.name = data.read<std::array<char, 16>>();
|
||||
snd.fallof_params = data.read<u32>();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t FS_LoadSoundBank(char* name, SoundBank* bank) {
|
||||
char namebuf[16];
|
||||
|
||||
// sector size of sound name list
|
||||
int offset = 10 * 2048;
|
||||
if (bank->sound_count == 101) {
|
||||
offset = 1 * 2048;
|
||||
@@ -234,11 +253,14 @@ uint32_t FS_LoadSoundBank(char* name, SoundBank* bank) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto fp = file_util::open_file(get_file_path(file), "rb");
|
||||
fread(bank, offset, 1, fp);
|
||||
fclose(fp);
|
||||
// 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);
|
||||
auto data = file_util::read_binary_file(fs::path(get_file_path(file)));
|
||||
parseSoundBank(BinaryReader(data), *bank);
|
||||
|
||||
snd::BankHandle handle = snd_BankLoadEx(get_file_path(file), offset, 0, 0);
|
||||
snd_ResolveBankXREFS();
|
||||
PrintBankInfo(bank);
|
||||
bank->bank_handle = handle;
|
||||
|
||||
@@ -1368,7 +1368,7 @@ static void PauseVAG(VagCommand* vag) {
|
||||
|
||||
static void CalculateVAGVolumes(s32 volume, s32 positioned, Vec3w* trans, s32* left, s32* right) {
|
||||
if (positioned) {
|
||||
volume = CalculateFallofVolume(trans, (volume * gDialogVolume) >> 10, 1, 10, 50);
|
||||
volume = CalculateFalloffVolume(trans, (volume * gDialogVolume) >> 10, 1, 10, 50);
|
||||
auto* pan = &gPanTable[(630 - CalculateAngle(trans)) % 360];
|
||||
*left = (pan->left * volume) >> 10;
|
||||
*right = (pan->right * volume) >> 10;
|
||||
|
||||
@@ -31,7 +31,7 @@ void LoadSoundBank(const char* bank_name, SoundBank* bank) {
|
||||
SleepThread(); // wait for finish.
|
||||
}
|
||||
|
||||
void LoadMusic(const char* music_name, s32* bank) {
|
||||
void LoadMusic(const char* music_name, snd::BankHandle* bank) {
|
||||
ASSERT(strlen(music_name) < 16);
|
||||
MusicLoadCommand cmd;
|
||||
cmd.cmd_id = LOAD_MUSIC;
|
||||
@@ -203,4 +203,4 @@ s32 LoadISOFileChunkToEE(FileRecord* file, uint32_t dest_addr, uint32_t length,
|
||||
return cmd.length_to_copy;
|
||||
}
|
||||
|
||||
} // namespace jak1
|
||||
} // namespace jak1
|
||||
@@ -7,7 +7,7 @@ struct SoundBank;
|
||||
namespace jak1 {
|
||||
struct VagDirEntry;
|
||||
void LoadSoundBank(const char* bank_name, SoundBank* bank);
|
||||
void LoadMusic(const char* music_name, s32* bank);
|
||||
void LoadMusic(const char* music_name, snd::BankHandle* bank);
|
||||
|
||||
void QueueVAGStream(FileRecord* file, VagDirEntry* vag, u32 sound_id, u32 unk);
|
||||
void PlayVAGStream(FileRecord* file,
|
||||
|
||||
@@ -58,7 +58,7 @@ struct IsoFs {
|
||||
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*);
|
||||
uint32_t (*load_music)(char*, snd::BankHandle*);
|
||||
void (*poll_drive)();
|
||||
};
|
||||
|
||||
@@ -173,7 +173,7 @@ struct SoundBankLoadCommand : public IsoMessage {
|
||||
|
||||
struct MusicLoadCommand : public IsoMessage {
|
||||
char music_name[16];
|
||||
s32* music_handle;
|
||||
snd::BankHandle* music_handle;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
||||
@@ -374,7 +374,7 @@ void* RPC_Loader(unsigned int /*fno*/, void* data, int size) {
|
||||
case Jak1SoundCommand::UNLOAD_BANK: {
|
||||
SoundBank* bank = LookupBank(cmd->load_bank.bank_name);
|
||||
if (bank != nullptr) {
|
||||
s32 id = bank->bank_handle;
|
||||
snd::BankHandle id = bank->bank_handle;
|
||||
bank->bank_handle = 0;
|
||||
snd_UnloadBank(id);
|
||||
snd_ResolveBankXREFS();
|
||||
@@ -403,7 +403,7 @@ void* RPC_Loader(unsigned int /*fno*/, void* data, int size) {
|
||||
}
|
||||
snd_UnloadBank(gMusic);
|
||||
snd_ResolveBankXREFS();
|
||||
gMusic = 0;
|
||||
gMusic = nullptr;
|
||||
}
|
||||
LoadMusic(cmd->load_bank.bank_name, &gMusic);
|
||||
SignalSema(gSema);
|
||||
@@ -508,4 +508,4 @@ s32 VBlank_Handler(void*) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
} // namespace jak1
|
||||
} // namespace jak1
|
||||
@@ -54,13 +54,13 @@ void InitSound_Overlord() {
|
||||
snd_StartSoundSystem();
|
||||
snd_RegisterIOPMemAllocator(SndMemAlloc, SndMemFree);
|
||||
snd_LockVoiceAllocator(1);
|
||||
u32 voice = snd_ExternVoiceAlloc(2, 0x7f);
|
||||
s32 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);
|
||||
gVoice = voice / 24 + ((voice % 24) * 2);
|
||||
|
||||
// Allocate SPU RAM for our streams.
|
||||
// (Which we don't need on PC)
|
||||
@@ -115,6 +115,30 @@ void InitSound_Overlord() {
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateLocation(Sound* sound) {
|
||||
if (sound->id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((sound->bank_entry->fallof_params >> 28) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
s32 id = snd_SoundIsStillPlaying(sound->sound_handle);
|
||||
if (id == 0) {
|
||||
sound->id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
s32 volume = GetVolume(sound);
|
||||
if (volume == 0) {
|
||||
snd_StopSound(sound->sound_handle);
|
||||
} else {
|
||||
s32 pan = GetPan(sound);
|
||||
snd_SetSoundVolPan(id, volume, pan);
|
||||
}
|
||||
}
|
||||
|
||||
void SetEarTrans(Vec3w* ear_trans0, Vec3w* ear_trans1, Vec3w* cam_trans, s32 cam_angle) {
|
||||
s32 tick = snd_GetTick();
|
||||
u32 delta = tick - sLastTick;
|
||||
@@ -150,4 +174,4 @@ static void* SndMemAlloc() {
|
||||
return nullptr;
|
||||
}
|
||||
static void SndMemFree(void* /*ptr*/) {}
|
||||
} // namespace jak1
|
||||
} // namespace jak1
|
||||
@@ -13,6 +13,7 @@ extern u32 gTrapSRAM;
|
||||
extern s32 gMusicVol;
|
||||
|
||||
void InitSound_Overlord();
|
||||
void UpdateLocation(Sound* sound);
|
||||
void SetEarTrans(Vec3w* ear_trans1, Vec3w* ear_trans2, Vec3w* cam_trans, s32 cam_angle);
|
||||
void SetMusicVol();
|
||||
} // namespace jak1
|
||||
} // namespace jak1
|
||||
+22
-22
@@ -1,5 +1,6 @@
|
||||
#include "dma.h"
|
||||
|
||||
#include "game/overlord/jak2/ssound.h"
|
||||
#include "game/overlord/jak2/vag.h"
|
||||
#include "game/sound/sdshim.h"
|
||||
#include "game/sound/sndshim.h"
|
||||
@@ -90,30 +91,29 @@ int SpuDmaIntr(int, void*) {
|
||||
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);
|
||||
sceSdSetAddr(SD_VA_SSA | DmaVagCmd->voice, DmaVagCmd->spu_stream_dma_mem_addr + 0x30);
|
||||
sceSdSetParam(SD_VP_ADSR1 | DmaVagCmd->voice, 0xf);
|
||||
sceSdSetParam(SD_VP_ADSR2 | DmaVagCmd->voice, 0x1fc0);
|
||||
sceSdSetParam(SD_VP_PITCH | DmaVagCmd->voice, pitch);
|
||||
|
||||
// start playback!
|
||||
sceSdkey_on_jak2_voice(DmaVagCmd->voice);
|
||||
sceSdSetSwitch(SD_S_KON | (DmaVagCmd->voice & 1), VOICE_BIT(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,
|
||||
sceSdSetAddr(SD_VA_SSA | DmaVagCmd->voice, DmaVagCmd->spu_stream_dma_mem_addr + 0x30);
|
||||
sceSdSetAddr(SD_VA_SSA | DmaStereoVagCmd->voice,
|
||||
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);
|
||||
sceSdSetParam(SD_VP_ADSR1 | DmaVagCmd->voice, 0xf);
|
||||
sceSdSetParam(SD_VP_ADSR1 | DmaStereoVagCmd->voice, 0xf);
|
||||
sceSdSetParam(SD_VP_ADSR2 | DmaVagCmd->voice, 0x1fc0);
|
||||
sceSdSetParam(SD_VP_ADSR2 | DmaStereoVagCmd->voice, 0x1fc0);
|
||||
sceSdSetParam(SD_VP_PITCH | DmaVagCmd->voice, pitch);
|
||||
sceSdSetParam(SD_VP_PITCH | DmaStereoVagCmd->voice, pitch);
|
||||
|
||||
sceSdkey_on_jak2_voice(DmaVagCmd->voice);
|
||||
sceSdkey_on_jak2_voice(DmaStereoVagCmd->voice);
|
||||
sceSdSetSwitch(SD_S_KON | (DmaVagCmd->voice & 1),
|
||||
VOICE_BIT(DmaVagCmd->voice) | VOICE_BIT(DmaStereoVagCmd->voice));
|
||||
}
|
||||
} else if (DmaVagCmd->num_processed_chunks == 2) {
|
||||
// on the second chunk's DMA finish, start playing by unpausing.
|
||||
@@ -127,13 +127,13 @@ int SpuDmaIntr(int, void*) {
|
||||
// if we paused since the first, kill the voice.
|
||||
if (DmaVagCmd->sb_paused) {
|
||||
if (!DmaStereoVagCmd) {
|
||||
sceSdSetParam((u16)DmaVagCmd->voice | 0x200, 0);
|
||||
sceSdSetParam(SD_VP_PITCH | DmaVagCmd->voice, 0);
|
||||
} else {
|
||||
sceSdSetParam((u16)DmaStereoVagCmd->voice | 0x200, 0);
|
||||
sceSdSetParam((u16)DmaVagCmd->voice | 0x200, 0);
|
||||
sceSdkey_off_jak2_voice(DmaStereoVagCmd->voice);
|
||||
sceSdSetParam(SD_VP_PITCH | DmaStereoVagCmd->voice, 0);
|
||||
sceSdSetParam(SD_VP_PITCH | DmaVagCmd->voice, 0);
|
||||
sceSdSetSwitch(SD_S_KOFF | (DmaVagCmd->voice & 1), VOICE_BIT(DmaStereoVagCmd->voice));
|
||||
}
|
||||
sceSdkey_off_jak2_voice(DmaVagCmd->voice);
|
||||
sceSdSetSwitch(SD_S_KOFF | (DmaVagCmd->voice & 1), VOICE_BIT(DmaVagCmd->voice));
|
||||
goto hack;
|
||||
}
|
||||
|
||||
@@ -231,4 +231,4 @@ void DmaCancelThisVagCmd(VagCmd* param_1) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace jak2
|
||||
} // namespace jak2
|
||||
@@ -241,7 +241,7 @@ void IsoQueueVagStream(VagCmd* cmd, int param_2) {
|
||||
new_cmd->id = cmd->id;
|
||||
|
||||
new_cmd->plugin_id = cmd->plugin_id;
|
||||
new_cmd->unk_136 = cmd->unk_136;
|
||||
new_cmd->sound_handler = cmd->sound_handler;
|
||||
new_cmd->unk_176 = cmd->unk_176;
|
||||
new_cmd->unk_288 = cmd->unk_288;
|
||||
new_cmd->unk_292 = cmd->unk_292;
|
||||
@@ -689,7 +689,7 @@ u32 ISOThread() {
|
||||
do {
|
||||
if ((((cmd_iter->byte11 == false) && (cmd_iter->sb_scanned == false)) &&
|
||||
(cmd_iter->id != 0)) ||
|
||||
((StopPluginStreams == 1 && (cmd_iter->unk_136) != 0))) {
|
||||
((StopPluginStreams == 1 && (cmd_iter->sound_handler) != 0))) {
|
||||
// CpuSuspendIntr(&local_2c);
|
||||
bVar1 = false;
|
||||
if (cmd_iter->id == 0) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "game/overlord/common/isocommon.h"
|
||||
#include "game/overlord/jak2/pages.h"
|
||||
#include "game/sce/iop.h"
|
||||
#include "game/sound/sndshim.h"
|
||||
|
||||
namespace jak2 {
|
||||
void iso_init_globals();
|
||||
@@ -48,7 +49,7 @@ struct IsoFs {
|
||||
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*);
|
||||
uint32_t (*load_music)(char*, snd::BankHandle*);
|
||||
// void (*poll_drive)();
|
||||
};
|
||||
|
||||
@@ -147,7 +148,7 @@ struct CmdLoadSoundBank {
|
||||
struct CmdLoadMusic {
|
||||
CmdHeader header;
|
||||
char name[16];
|
||||
s32* handle;
|
||||
snd::BankHandle* handle;
|
||||
};
|
||||
|
||||
struct VagDirEntry {
|
||||
|
||||
@@ -64,7 +64,7 @@ void QueueVAGStream(VagStrListNode* param_1) {
|
||||
cmd.header.cmd_kind = 0x400;
|
||||
cmd.header.mbx_to_reply = 0;
|
||||
cmd.header.thread_id = 0;
|
||||
if (param_1->unk_72 == 0) {
|
||||
if (param_1->sound_handler == 0) {
|
||||
EEVagAndVagwad(param_1->name, &cmd);
|
||||
cmd.vol_multiplier = 0x400;
|
||||
} else {
|
||||
@@ -96,7 +96,7 @@ void QueueVAGStream(VagStrListNode* param_1) {
|
||||
cmd.unk_176 = param_1->unk_100;
|
||||
}
|
||||
strncpy(cmd.name, param_1->name, 0x30);
|
||||
cmd.unk_136 = param_1->unk_72;
|
||||
cmd.sound_handler = param_1->sound_handler;
|
||||
cmd.id = param_1->id;
|
||||
cmd.plugin_id = param_1->unk_68;
|
||||
cmd.priority = param_1->prio;
|
||||
@@ -218,7 +218,7 @@ void LoadSoundBank(char* param_1, SoundBank* param_2) {
|
||||
SleepThread();
|
||||
}
|
||||
|
||||
void LoadMusic(char* param_1, s32* param_2) {
|
||||
void LoadMusic(char* param_1, snd::BankHandle* param_2) {
|
||||
CmdLoadMusic auStack88;
|
||||
|
||||
auStack88.header.cmd_kind = 0x380;
|
||||
@@ -239,7 +239,7 @@ void LoadMusic(char* param_1, s32* param_2) {
|
||||
gMusicTweak = 0x80;
|
||||
}
|
||||
|
||||
void UnLoadMusic(s32* param_1) {
|
||||
void UnLoadMusic(snd::BankHandle* param_1) {
|
||||
gMusicFadeDir = -1;
|
||||
if (gMusicFade != 0) {
|
||||
do {
|
||||
@@ -251,4 +251,4 @@ void UnLoadMusic(s32* param_1) {
|
||||
*param_1 = 0;
|
||||
}
|
||||
|
||||
} // namespace jak2
|
||||
} // namespace jak2
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "game/sound/sndshim.h"
|
||||
|
||||
struct SoundBank;
|
||||
struct FileRecord;
|
||||
namespace jak2 {
|
||||
@@ -9,10 +11,10 @@ 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 UnLoadMusic(snd::BankHandle* param_1);
|
||||
void LoadMusic(char* param_1, snd::BankHandle* 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
|
||||
} // namespace jak2
|
||||
@@ -77,7 +77,7 @@ 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);
|
||||
uint32_t FS_LoadMusic(char* name, snd::BankHandle* buffer);
|
||||
u32 FS_SyncRead();
|
||||
|
||||
void iso_cd_init_globals() {
|
||||
@@ -661,7 +661,7 @@ uint32_t FS_LoadSoundBank(char* name, SoundBank* buffer) {
|
||||
FileRecord* file = nullptr;
|
||||
char namebuf[16];
|
||||
char isoname[16];
|
||||
u32 handle;
|
||||
snd::BankHandle handle;
|
||||
|
||||
strncpy(namebuf, name, 12);
|
||||
namebuf[8] = 0;
|
||||
@@ -680,11 +680,11 @@ uint32_t FS_LoadSoundBank(char* name, SoundBank* buffer) {
|
||||
return CMD_STATUS_DONE;
|
||||
}
|
||||
|
||||
uint32_t FS_LoadMusic(char* name, s32* bank_handle) {
|
||||
uint32_t FS_LoadMusic(char* name, snd::BankHandle* bank_handle) {
|
||||
FileRecord* file = nullptr;
|
||||
char namebuf[16];
|
||||
char isoname[16];
|
||||
u32 handle;
|
||||
snd::BankHandle handle;
|
||||
|
||||
strncpy(namebuf, name, 12);
|
||||
namebuf[8] = 0;
|
||||
|
||||
@@ -842,7 +842,7 @@ void StopVagStream(VagCmd* param_1, int param_2) {
|
||||
if (cmd != 0x0) {
|
||||
cmd->sb_playing = '\0';
|
||||
}
|
||||
if (param_1->unk_136 == 0) {
|
||||
if (param_1->sound_handler == 0) {
|
||||
PauseVAG(param_1, 0);
|
||||
param_1->byte9 = '\x01';
|
||||
if (cmd != 0x0) {
|
||||
@@ -892,7 +892,7 @@ u32 GetSpuRamAddress(VagCmd* param_1) {
|
||||
// if the overlord thread isn't keeping up.
|
||||
// as far as I can tell, it's totally fine to discard these checks because our sceSdGetAddr
|
||||
// works perfectly.
|
||||
return sceSdGetAddr((param_1->voice & 0xffffU) | 0x2240);
|
||||
return sceSdGetAddr(SD_VA_NAX | param_1->voice);
|
||||
}
|
||||
|
||||
u32 bswap(u32 param_1) {
|
||||
|
||||
@@ -312,7 +312,7 @@ void* RPC_Player(unsigned int /*fno*/, void* data, int size) {
|
||||
local_178.header.thread_id = 0;
|
||||
local_178.vag_dir_entry = nullptr;
|
||||
local_178.name[0] = '\0';
|
||||
local_178.unk_136 = 0;
|
||||
local_178.sound_handler = 0;
|
||||
local_178.id = 0;
|
||||
local_178.priority = 0;
|
||||
StopVagStream(&local_178, 1);
|
||||
@@ -383,7 +383,7 @@ void* RPC_Loader(unsigned int /*fno*/, void* data, int size) {
|
||||
break;
|
||||
}
|
||||
|
||||
strncpy(bank->name, cmd->load_bank.bank_name, 16);
|
||||
strncpy(bank->name.data(), cmd->load_bank.bank_name, 16);
|
||||
bank->in_use = true;
|
||||
bank->unk4 = 0;
|
||||
LoadSoundBank(cmd->load_bank.bank_name, bank);
|
||||
@@ -611,4 +611,4 @@ void SetVagName(int param_1, char* param_2, int param_3) {
|
||||
// CpuResumeIntr(local_18[0]);
|
||||
}
|
||||
|
||||
} // namespace jak2
|
||||
} // namespace jak2
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "game/overlord/jak2/streamlist.h"
|
||||
#include "game/overlord/jak2/vag.h"
|
||||
#include "game/sce/iop.h"
|
||||
#include "game/sound/sdshim.h"
|
||||
#include "game/sound/sndshim.h"
|
||||
|
||||
using namespace iop;
|
||||
@@ -42,17 +43,16 @@ void InitSound_overlord() {
|
||||
// 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.
|
||||
StreamVoice[0] = SD_VOICE(0, 0);
|
||||
StreamVoice[1] = SD_VOICE(0, 1);
|
||||
StreamVoice[2] = SD_VOICE(0, 2);
|
||||
StreamVoice[3] = SD_VOICE(0, 3);
|
||||
|
||||
for (int i = 0; i < 91; i++) {
|
||||
s16 opposing_front = static_cast<s16>(((i * 0x33ff) / 0x5a) + 0xc00);
|
||||
s16 opposing_front = static_cast<s16>(((i * 0x33ff) / 90) + 0xc00);
|
||||
|
||||
s16 rear_right = static_cast<s16>(((i * -0x2800) / 0x5a) + 0x3400);
|
||||
s16 rear_left = static_cast<s16>(((i * -0xbff) / 0x5a) + 0x3fff);
|
||||
s16 rear_right = static_cast<s16>(((i * -0x2800) / 90) + 0x3400);
|
||||
s16 rear_left = static_cast<s16>(((i * -0xbff) / 90) + 0x3fff);
|
||||
|
||||
gPanTable[90 - i].left = 0x3FFF;
|
||||
gPanTable[180 - i].left = opposing_front;
|
||||
@@ -110,6 +110,32 @@ void SetMusicVol() {
|
||||
snd_SetMasterVolume(2, vol);
|
||||
}
|
||||
|
||||
void UpdateLocation(Sound* sound) {
|
||||
if (sound->id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
s32 id = snd_SoundIsStillPlaying(sound->sound_handle);
|
||||
if (id == 0) {
|
||||
sound->id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
s32 volume = GetVolume(sound);
|
||||
if (volume == 0) {
|
||||
snd_StopSound(sound->sound_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sound->params.fo_curve == 1 || sound->params.fo_curve == 10) {
|
||||
snd_SetSoundVolPan(id, volume, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
s32 pan = GetPan(sound);
|
||||
snd_SetSoundVolPan(id, volume, pan);
|
||||
}
|
||||
|
||||
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();
|
||||
@@ -136,7 +162,7 @@ void SetEarTrans(Vec3w* ear_trans0, Vec3w* ear_trans1, Vec3w* cam_trans, s32 cam
|
||||
auto* cmd = VagCmds;
|
||||
// piVar6 = &VagCmds[0].vol_multiplier;
|
||||
do {
|
||||
if (cmd->unk_136 == 0x0) {
|
||||
if (cmd->sound_handler == 0x0) {
|
||||
LAB_0000c388:
|
||||
SetVAGVol(cmd, 1);
|
||||
} else if ((cmd->sb_scanned == '\0') || (cmd->byte8 != '\0')) {
|
||||
@@ -172,4 +198,4 @@ void SetEarTrans(Vec3w* ear_trans0, Vec3w* ear_trans1, Vec3w* cam_trans, s32 cam
|
||||
} while (true);
|
||||
}
|
||||
|
||||
} // namespace jak2
|
||||
} // namespace jak2
|
||||
@@ -2,12 +2,15 @@
|
||||
#include "game/overlord/common/ssound.h"
|
||||
|
||||
namespace jak2 {
|
||||
#define VOICE_BIT(voice) (1 << ((voice) >> 1))
|
||||
#define CORE_BIT(voice) ((voice)&1)
|
||||
void ssound_init_globals();
|
||||
void SetBufferMem(void*, int);
|
||||
void ReleaseBufferMem();
|
||||
void SetMusicVol();
|
||||
void UpdateLocation(Sound* sound);
|
||||
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
|
||||
} // namespace jak2
|
||||
@@ -178,7 +178,7 @@ void* RPC_PLAY([[maybe_unused]] unsigned int fno, void* _cmd, int size) {
|
||||
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.sound_handler = 0;
|
||||
list_node.unk_80 = cmd_iter->address & 0x10 << (s & 0x1f) & 0xf0;
|
||||
list_node.prio = iVar5;
|
||||
pRVar2 = FindThisVagStream(list_node.name, list_node.id);
|
||||
@@ -247,7 +247,7 @@ void* RPC_PLAY([[maybe_unused]] unsigned int fno, void* _cmd, int size) {
|
||||
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.sound_handler = 0;
|
||||
list_node.prio = iVar5;
|
||||
pRVar2 = FindThisVagStream(cmd_iter->names[s].chars, cmd_iter->id[s]);
|
||||
if ((pRVar2 == 0x0) || (pRVar2->byte4 == '\0')) {
|
||||
@@ -260,7 +260,7 @@ void* RPC_PLAY([[maybe_unused]] unsigned int fno, void* _cmd, int size) {
|
||||
|
||||
iVar4->id = list_node.id;
|
||||
iVar4->prio = list_node.prio;
|
||||
iVar4->unk_72 = list_node.unk_72;
|
||||
iVar4->sound_handler = list_node.sound_handler;
|
||||
iVar4->unk_76 = 0;
|
||||
iVar4->unk_80 = 0;
|
||||
iVar4->unk_92 = 0;
|
||||
|
||||
@@ -74,9 +74,9 @@ VagStrListNode* InsertVagStreamInList(VagStrListNode* param_1, List* param_2) {
|
||||
pVVar5->unk_76 = param_1->unk_76;
|
||||
pVVar5->unk_80 = param_1->unk_80;
|
||||
pVVar5->prio = param_1->prio;
|
||||
iVar1 = param_1->unk_72;
|
||||
iVar1 = param_1->sound_handler;
|
||||
pVVar5->unk_92 = 0;
|
||||
pVVar5->unk_72 = iVar1;
|
||||
pVVar5->sound_handler = iVar1;
|
||||
pVVar5->vol_multiplier = param_1->vol_multiplier;
|
||||
pVVar5->unk_100 = param_1->unk_100;
|
||||
if (pVVar6 == (VagStrListNode*)0x0) {
|
||||
@@ -132,7 +132,7 @@ void QueueNewStreamsFromList(List* list) {
|
||||
// puVar4[0xe] = 0;
|
||||
pvVar6->id = 0;
|
||||
// puVar4[0x10] = 0;
|
||||
pvVar6->unk_72 = 0;
|
||||
pvVar6->sound_handler = 0;
|
||||
// puVar4[0x13] = 0;
|
||||
pvVar6->prio = 0;
|
||||
// puVar4[0x11] = 0;
|
||||
@@ -264,7 +264,7 @@ code_r0x0000f058:
|
||||
(pVVar4->list).in_use = 0;
|
||||
strncpy(pVVar4->name, "free", 0x30);
|
||||
pVVar4->id = 0;
|
||||
pVVar4->unk_72 = 0;
|
||||
pVVar4->sound_handler = 0;
|
||||
pVVar4->prio = 0;
|
||||
pVVar4->unk_76 = 0;
|
||||
pVVar4->unk_80 = 0;
|
||||
@@ -306,7 +306,7 @@ u32 StreamListThread() {
|
||||
// puVar4[0xe] = 0;
|
||||
pvVar6->id = 0;
|
||||
// puVar4[0x10] = 0;
|
||||
pvVar6->unk_72 = 0;
|
||||
pvVar6->sound_handler = 0;
|
||||
// puVar4[0x13] = 0;
|
||||
pvVar6->prio = 0;
|
||||
// puVar4[0x11] = 0;
|
||||
@@ -438,7 +438,7 @@ bool InitVagStreamList(List* param_1, u32 param_2, const char* param_3) {
|
||||
// *(undefined4*)(piVar1 + -0x24) = 0;
|
||||
pLVar3->id = 0;
|
||||
// *(undefined4*)(piVar1 + -0x1c) = 0;
|
||||
pLVar3->unk_72 = 0;
|
||||
pLVar3->sound_handler = 0;
|
||||
// *(undefined4*)(piVar1 + -0x10) = 0;
|
||||
pLVar3->prio = 0;
|
||||
// *(undefined4*)(piVar1 + -0x18) = 0;
|
||||
@@ -525,7 +525,7 @@ void RemoveVagStreamFromList(VagStrListNode* param_1, List* param_2) {
|
||||
(pVVar2->list).in_use = 0;
|
||||
strncpy(pVVar2->name, "free", 0x30);
|
||||
pVVar2->id = 0;
|
||||
pVVar2->unk_72 = 0;
|
||||
pVVar2->sound_handler = 0;
|
||||
pVVar2->prio = 0;
|
||||
pVVar2->unk_76 = 0;
|
||||
pVVar2->unk_80 = 0;
|
||||
@@ -563,7 +563,7 @@ void EmptyVagStreamList(List* param_1) {
|
||||
// puVar1 = puVar1 + 0x1a;
|
||||
|
||||
pvVar2->id = 0;
|
||||
pvVar2->unk_72 = 0;
|
||||
pvVar2->sound_handler = 0;
|
||||
pvVar2->prio = 0;
|
||||
pvVar2->unk_76 = 0;
|
||||
pvVar2->unk_80 = 0;
|
||||
|
||||
@@ -10,7 +10,7 @@ struct VagStrListNode {
|
||||
int unk_60;
|
||||
int id;
|
||||
int unk_68;
|
||||
int unk_72;
|
||||
int sound_handler; // 989snd handler that owns this stream
|
||||
int unk_76;
|
||||
int unk_80;
|
||||
int prio;
|
||||
|
||||
+146
-422
@@ -24,7 +24,8 @@ VagCmdPriListEntry VagCmdsPriList[11];
|
||||
int VagCmdsPriCounter[11];
|
||||
int ActiveVagStreams;
|
||||
|
||||
void CalculateVAGVolumes(VagCmd* cmd, int* l_out, int* r_out);
|
||||
void CalculateVAGVolumes(VagCmd* cmd, u32* l_out, u32* r_out);
|
||||
void StopVAG(VagCmd* cmd, int /*param_2*/);
|
||||
|
||||
enum VolumeCategory {
|
||||
DIALOGUE = 2, // VAG streams. Copied "dialogue" name from jak 1.
|
||||
@@ -101,7 +102,7 @@ void InitVagCmds() {
|
||||
cmd.unk_256_pitch2 = 0; // puVar5[-9] = 0;
|
||||
cmd.id = 0; // puVar5[-4] = 0;
|
||||
cmd.plugin_id = 0; // puVar5[-3] = 0;
|
||||
cmd.unk_136 = 0; // puVar5[-0x27] = 0;
|
||||
cmd.sound_handler = 0; // puVar5[-0x27] = 0;
|
||||
cmd.unk_176 = 0; // puVar5[-0x1d] = 0;
|
||||
cmd.priority = 0; // puVar5[-2] = 0;
|
||||
cmd.unk_288 = 0; // puVar5[-1] = 0;
|
||||
@@ -189,189 +190,34 @@ VagCmd* SmartAllocVagCmd(VagCmd* cmd) {
|
||||
}
|
||||
|
||||
void TerminateVAG(VagCmd* cmd, int param_2) {
|
||||
[[maybe_unused]] int* piVar1;
|
||||
int iVar2;
|
||||
u32 uVar3;
|
||||
VagCmd* pRVar4;
|
||||
VagCmd* pRVar5;
|
||||
VagStrListNode vag_node;
|
||||
LfoListNode lfo_node;
|
||||
// undefined4 auStack32 [2];
|
||||
|
||||
if (param_2 == 1) {
|
||||
// CpuSuspendIntr(auStack32);
|
||||
}
|
||||
pRVar4 = cmd->stereo_sibling;
|
||||
// if (param_2 == 1) {
|
||||
// CpuSuspendIntr(auStack32);
|
||||
//}
|
||||
|
||||
auto* sibling = cmd->stereo_sibling;
|
||||
strncpy(vag_node.name, cmd->name, 0x30);
|
||||
vag_node.id = cmd->id;
|
||||
cmd->sb_scanned = '\0';
|
||||
|
||||
if (cmd->status_bytes[BYTE5] != '\0') {
|
||||
pRVar5 = cmd->stereo_sibling;
|
||||
PauseVAG(cmd, 0);
|
||||
if (cmd->status_bytes[BYTE5] != '\0') {
|
||||
uVar3 = 1 << (cmd->voice >> 1 & 0x1fU);
|
||||
if (pRVar5 != 0x0) {
|
||||
uVar3 = uVar3 | 1 << (pRVar5->voice >> 1 & 0x1fU);
|
||||
}
|
||||
// sceSdSetSwitch(*(u16*)&cmd->voice & 1 | 0x1600, uVar3);
|
||||
sceSdkey_off_jak2_voice(cmd->voice);
|
||||
if (cmd->stereo_sibling) {
|
||||
sceSdkey_off_jak2_voice(cmd->stereo_sibling->voice);
|
||||
}
|
||||
}
|
||||
// iVar2 = 0x18;
|
||||
// piVar1 = &(cmd->header).unk_24;
|
||||
// do {
|
||||
// *(undefined *)(piVar1 + 0x34) = 0;
|
||||
// iVar2 = iVar2 + -1;
|
||||
// piVar1 = (int *)((int)piVar1 + -1);
|
||||
// } while (-1 < iVar2);
|
||||
for (auto& x : cmd->status_bytes) {
|
||||
x = 0;
|
||||
}
|
||||
cmd->vol_multiplier = 0;
|
||||
cmd->unk_256_pitch2 = 0;
|
||||
cmd->id = 0;
|
||||
cmd->plugin_id = 0;
|
||||
(cmd->header).ready_for_data = 0;
|
||||
cmd->unk_136 = 0;
|
||||
cmd->unk_140 = 0;
|
||||
cmd->pitch1 = 0;
|
||||
(cmd->header).callback = NullCallback;
|
||||
cmd->unk_180 = 0;
|
||||
cmd->unk_184 = 0;
|
||||
cmd->unk_188 = 0;
|
||||
cmd->unk_192 = 0;
|
||||
StopVAG(cmd, 0);
|
||||
}
|
||||
|
||||
ReleaseMessage(&cmd->header, 0);
|
||||
VagCmdsPriList[cmd->priority].cmds[cmd->idx_in_cmd_arr] = 0x0;
|
||||
if (VagCmdsPriCounter[cmd->priority] < 1) {
|
||||
printf("IOP: ======================================================================\n");
|
||||
printf("IOP: vag RemoveVagCmd: VagCmdsPriCounter[%d] is zero\n", cmd->priority);
|
||||
printf("IOP: ======================================================================\n");
|
||||
} else {
|
||||
VagCmdsPriCounter[cmd->priority] = VagCmdsPriCounter[cmd->priority] + -1;
|
||||
RemoveVagCmd(cmd, 0);
|
||||
FreeVagCmd(cmd, 0);
|
||||
|
||||
if (sibling != nullptr) {
|
||||
sibling->sb_scanned = '\0';
|
||||
RemoveVagCmd(sibling, 0);
|
||||
FreeVagCmd(sibling, 0);
|
||||
}
|
||||
// iVar2 = 0x18;
|
||||
// piVar1 = &(cmd->header).unk_24;
|
||||
VagCmdsPriCounter[0] = VagCmdsPriCounter[0] + 1;
|
||||
for (auto& x : cmd->status_bytes) {
|
||||
x = 0;
|
||||
}
|
||||
// do {
|
||||
// *(undefined*)(piVar1 + 0x34) = 0;
|
||||
// iVar2 = iVar2 + -1;
|
||||
// piVar1 = (int*)((int)piVar1 + -1);
|
||||
// } while (-1 < iVar2);
|
||||
cmd->sb_playing = '\0';
|
||||
cmd->sb_paused = '\x01';
|
||||
cmd->sb_scanned = '\0';
|
||||
cmd->unk_180 = 0;
|
||||
cmd->unk_184 = 0;
|
||||
cmd->unk_188 = 0;
|
||||
cmd->unk_192 = 0;
|
||||
SetVagStreamName(cmd, 0, 0);
|
||||
cmd->name[0] = '\0';
|
||||
iVar2 = ActiveVagStreams;
|
||||
cmd->safe_to_change_dma_fields = 1;
|
||||
cmd->unk_264 = 0x4000;
|
||||
(cmd->header).callback = NullCallback;
|
||||
cmd->unk_140 = 0;
|
||||
cmd->pitch1 = 0;
|
||||
cmd->file_record = nullptr;
|
||||
cmd->vag_dir_entry = nullptr;
|
||||
cmd->unk_196 = 0;
|
||||
cmd->unk_200 = 0;
|
||||
cmd->unk_204 = 0;
|
||||
cmd->num_processed_chunks = 0;
|
||||
cmd->xfer_size = 0;
|
||||
cmd->sample_rate = 0;
|
||||
cmd->unk_260 = 0;
|
||||
cmd->unk_268 = 0;
|
||||
cmd->vol_multiplier = 0;
|
||||
cmd->unk_256_pitch2 = 0;
|
||||
cmd->id = 0;
|
||||
cmd->plugin_id = 0;
|
||||
cmd->unk_136 = 0;
|
||||
cmd->priority = 0;
|
||||
cmd->unk_288 = 0;
|
||||
cmd->unk_292 = 0;
|
||||
cmd->unk_296 = 0;
|
||||
(cmd->header).callback_buffer = (Buffer*)0x0;
|
||||
(cmd->header).ready_for_data = 0;
|
||||
(cmd->header).lse = (LoadStackEntry*)0x0;
|
||||
cmd->dma_iop_mem_ptr = (uint8_t*)0x0;
|
||||
cmd->dma_chan = -1;
|
||||
cmd->unk_236 = 0;
|
||||
if (0 < iVar2) {
|
||||
ActiveVagStreams = iVar2 + -1;
|
||||
}
|
||||
if (pRVar4 != 0x0) {
|
||||
pRVar4->sb_scanned = '\0';
|
||||
VagCmdsPriList[pRVar4->priority].cmds[pRVar4->idx_in_cmd_arr] = 0x0;
|
||||
if (VagCmdsPriCounter[pRVar4->priority] < 1) {
|
||||
printf("IOP: ======================================================================\n");
|
||||
printf("IOP: vag RemoveVagCmd: VagCmdsPriCounter[%d] is zero\n", pRVar4->priority);
|
||||
printf("IOP: ======================================================================\n");
|
||||
} else {
|
||||
VagCmdsPriCounter[pRVar4->priority] = VagCmdsPriCounter[pRVar4->priority] + -1;
|
||||
}
|
||||
iVar2 = 0x18;
|
||||
piVar1 = &(pRVar4->header).ready_for_data;
|
||||
VagCmdsPriCounter[0] = VagCmdsPriCounter[0] + 1;
|
||||
for (auto& x : cmd->status_bytes) {
|
||||
x = 0;
|
||||
}
|
||||
// do {
|
||||
// *(undefined*)(piVar1 + 0x34) = 0;
|
||||
// iVar2 = iVar2 + -1;
|
||||
// piVar1 = (int*)((int)piVar1 + -1);
|
||||
// } while (-1 < iVar2);
|
||||
pRVar4->sb_playing = '\0';
|
||||
pRVar4->sb_paused = '\x01';
|
||||
pRVar4->sb_scanned = '\0';
|
||||
pRVar4->unk_180 = 0;
|
||||
pRVar4->unk_184 = 0;
|
||||
pRVar4->unk_188 = 0;
|
||||
pRVar4->unk_192 = 0;
|
||||
SetVagStreamName(pRVar4, 0, 0);
|
||||
pRVar4->name[0] = '\0';
|
||||
iVar2 = ActiveVagStreams;
|
||||
pRVar4->safe_to_change_dma_fields = 1;
|
||||
pRVar4->unk_264 = 0x4000;
|
||||
(pRVar4->header).callback = NullCallback;
|
||||
pRVar4->unk_140 = 0;
|
||||
pRVar4->pitch1 = 0;
|
||||
pRVar4->file_record = nullptr;
|
||||
pRVar4->vag_dir_entry = nullptr;
|
||||
pRVar4->unk_196 = 0;
|
||||
pRVar4->unk_200 = 0;
|
||||
pRVar4->unk_204 = 0;
|
||||
pRVar4->num_processed_chunks = 0;
|
||||
pRVar4->xfer_size = 0;
|
||||
pRVar4->sample_rate = 0;
|
||||
pRVar4->unk_260 = 0;
|
||||
pRVar4->unk_268 = 0;
|
||||
pRVar4->vol_multiplier = 0;
|
||||
pRVar4->unk_256_pitch2 = 0;
|
||||
pRVar4->id = 0;
|
||||
pRVar4->plugin_id = 0;
|
||||
pRVar4->unk_136 = 0;
|
||||
pRVar4->priority = 0;
|
||||
pRVar4->unk_288 = 0;
|
||||
pRVar4->unk_292 = 0;
|
||||
pRVar4->unk_296 = 0;
|
||||
(pRVar4->header).callback_buffer = (Buffer*)0x0;
|
||||
(pRVar4->header).ready_for_data = 0;
|
||||
(pRVar4->header).lse = (LoadStackEntry*)0x0;
|
||||
pRVar4->dma_iop_mem_ptr = (uint8_t*)0x0;
|
||||
pRVar4->dma_chan = -1;
|
||||
pRVar4->unk_236 = 0;
|
||||
if (0 < iVar2) {
|
||||
ActiveVagStreams = iVar2 + -1;
|
||||
}
|
||||
}
|
||||
if (cmd->unk_136) {
|
||||
|
||||
if (cmd->sound_handler) {
|
||||
RemoveVagStreamFromList(&vag_node, &PluginStreamsList);
|
||||
lfo_node.id = cmd->id;
|
||||
lfo_node.plugin_id = cmd->plugin_id;
|
||||
@@ -380,10 +226,9 @@ void TerminateVAG(VagCmd* cmd, int param_2) {
|
||||
// printf("termina removing %s (2)\n", vag_node.name);
|
||||
|
||||
RemoveVagStreamFromList(&vag_node, &EEPlayList);
|
||||
if (param_2 == 1) {
|
||||
// CpuResumeIntr(auStack32[0]);
|
||||
}
|
||||
// return;
|
||||
// if (param_2 == 1) {
|
||||
// CpuResumeIntr(auStack32[0]);
|
||||
//}
|
||||
}
|
||||
|
||||
void PauseVAG(VagCmd* cmd, int /*param_2*/) {
|
||||
@@ -395,13 +240,11 @@ void PauseVAG(VagCmd* cmd, int /*param_2*/) {
|
||||
auto* stereo_cmd = cmd->stereo_sibling;
|
||||
if (!stereo_cmd) {
|
||||
if (cmd->sb_playing != '\0') {
|
||||
sceSdSetParam((u16)cmd->voice | SD_VP_VOLL, 0);
|
||||
sceSdSetParam(((u16)cmd->voice) | SD_VP_VOLR, 0);
|
||||
sceSdSetParam(SD_VP_VOLL | cmd->voice, 0);
|
||||
sceSdSetParam(SD_VP_VOLR | cmd->voice, 0);
|
||||
}
|
||||
sceSdSetParam(((u16)cmd->voice) | SD_VP_PITCH, 0);
|
||||
// TODO: ignored, whatever this is
|
||||
// sceSdSetSwitch((((s16)cmd->voice) & 1) | 0x1600, 1 << (cmd->voice >> 1 & 0x1fU));
|
||||
sceSdkey_off_jak2_voice(cmd->voice);
|
||||
sceSdSetParam(SD_VP_PITCH | cmd->voice, 0);
|
||||
sceSdSetSwitch(SD_S_KOFF | CORE_BIT(cmd->voice), VOICE_BIT(cmd->voice));
|
||||
if (cmd->status_bytes[BYTE5] == '\0') {
|
||||
cmd->spu_addr_to_start_playing = 0;
|
||||
} else {
|
||||
@@ -410,23 +253,21 @@ void PauseVAG(VagCmd* cmd, int /*param_2*/) {
|
||||
cmd->sb_paused = 1;
|
||||
} else {
|
||||
if (cmd->sb_playing != '\0') {
|
||||
sceSdSetParam(((u16)cmd->voice) | SD_VP_VOLL, 0);
|
||||
sceSdSetParam(((u16)cmd->voice) | SD_VP_VOLR, 0);
|
||||
sceSdSetParam(((u16)stereo_cmd->voice) | SD_VP_VOLL, 0);
|
||||
sceSdSetParam(((u16)stereo_cmd->voice) | SD_VP_VOLR, 0);
|
||||
sceSdSetParam(SD_VP_VOLL | cmd->voice, 0);
|
||||
sceSdSetParam(SD_VP_VOLR | cmd->voice, 0);
|
||||
sceSdSetParam(SD_VP_VOLL | stereo_cmd->voice, 0);
|
||||
sceSdSetParam(SD_VP_VOLR | stereo_cmd->voice, 0);
|
||||
}
|
||||
sceSdSetParam(((u16)stereo_cmd->voice) | SD_VP_PITCH, 0);
|
||||
sceSdSetParam(((u16)cmd->voice) | SD_VP_PITCH, 0);
|
||||
// sceSdSetSwitch(((u16)cmd->voice & 1) | 0x1600,
|
||||
// 1 << (cmd->voice >> 1 & 0x1fU) | 1 << (stereo_cmd->voice >> 1 & 0x1fU));
|
||||
sceSdkey_off_jak2_voice(cmd->voice);
|
||||
sceSdkey_off_jak2_voice(stereo_cmd->voice);
|
||||
sceSdSetParam(SD_VP_PITCH | stereo_cmd->voice, 0);
|
||||
sceSdSetParam(SD_VP_PITCH | cmd->voice, 0);
|
||||
sceSdSetSwitch(SD_S_KOFF | CORE_BIT(cmd->voice),
|
||||
VOICE_BIT(cmd->voice) | VOICE_BIT(stereo_cmd->voice));
|
||||
|
||||
if (cmd->status_bytes[BYTE5] == '\0') {
|
||||
cmd->spu_addr_to_start_playing = 0;
|
||||
stereo_cmd->spu_addr_to_start_playing = 0;
|
||||
} else {
|
||||
int ram_addr = GetSpuRamAddress(cmd);
|
||||
u32 ram_addr = GetSpuRamAddress(cmd);
|
||||
cmd->spu_addr_to_start_playing = ram_addr & 0xfffffff8;
|
||||
stereo_cmd->spu_addr_to_start_playing =
|
||||
((ram_addr & 0xfffffff8) - cmd->spu_stream_dma_mem_addr) +
|
||||
@@ -449,38 +290,35 @@ void UnPauseVAG(VagCmd* param_1, int /*param_2*/) {
|
||||
//}
|
||||
if (param_1->status_bytes[BYTE11] == '\0') {
|
||||
auto* stereo_cmd = param_1->stereo_sibling;
|
||||
int pitch_reuslt = CalculateVAGPitch(param_1->pitch1, param_1->unk_256_pitch2);
|
||||
int vol_l, vol_r;
|
||||
int pitch = CalculateVAGPitch(param_1->pitch1, param_1->unk_256_pitch2);
|
||||
u32 vol_l, vol_r;
|
||||
CalculateVAGVolumes(param_1, &vol_l, &vol_r);
|
||||
if (!stereo_cmd) {
|
||||
if (param_1->sb_playing != '\0') {
|
||||
sceSdSetParam(((u16)param_1->voice) | 0x200, pitch_reuslt);
|
||||
sceSdSetParam(SD_VP_PITCH | param_1->voice, pitch);
|
||||
if (param_1->spu_addr_to_start_playing != 0) {
|
||||
sceSdSetAddr(((u16)param_1->voice) | 0x2040, param_1->spu_addr_to_start_playing);
|
||||
sceSdSetAddr(SD_VA_SSA | param_1->voice, param_1->spu_addr_to_start_playing);
|
||||
}
|
||||
// sceSdSetSwitch(((u16)param_1->voice & 1) | 0x1500, 1 << (voice >> 1 & 0x1fU));
|
||||
sceSdkey_on_jak2_voice(param_1->voice);
|
||||
sceSdSetParam(((u16)param_1->voice), vol_l);
|
||||
sceSdSetParam(((u16)param_1->voice) | 0x100, vol_r);
|
||||
sceSdSetSwitch(SD_S_KON | CORE_BIT(param_1->voice), VOICE_BIT(param_1->voice));
|
||||
sceSdSetParam(SD_VP_VOLL | param_1->voice, vol_l);
|
||||
sceSdSetParam(SD_VP_VOLR | param_1->voice, vol_r);
|
||||
}
|
||||
param_1->sb_paused = 0;
|
||||
} else {
|
||||
if (param_1->sb_playing != '\0') {
|
||||
sceSdSetParam(((u16)param_1->voice) | 0x200, pitch_reuslt);
|
||||
sceSdSetParam(((u16)stereo_cmd->voice) | 0x200, pitch_reuslt);
|
||||
sceSdSetParam(SD_VP_PITCH | param_1->voice, pitch);
|
||||
sceSdSetParam(SD_VP_PITCH | stereo_cmd->voice, pitch);
|
||||
if (param_1->spu_addr_to_start_playing != 0) {
|
||||
sceSdSetAddr(((u16)param_1->voice) | 0x2040, param_1->spu_addr_to_start_playing);
|
||||
sceSdSetAddr(((u16)stereo_cmd->voice) | 0x2040, stereo_cmd->spu_addr_to_start_playing);
|
||||
sceSdSetAddr(SD_VA_SSA | param_1->voice, param_1->spu_addr_to_start_playing);
|
||||
sceSdSetAddr(SD_VA_SSA | stereo_cmd->voice, stereo_cmd->spu_addr_to_start_playing);
|
||||
}
|
||||
sceSdkey_on_jak2_voice(param_1->voice);
|
||||
sceSdkey_on_jak2_voice(stereo_cmd->voice);
|
||||
|
||||
// sceSdSetSwitch(((u16)param_1->voice & 1) | 0x1500,
|
||||
// 1 << (voice >> 1 & 0x1fU) | 1 << (stereo_voice >> 1 & 0x1fU));
|
||||
sceSdSetParam(((u16)param_1->voice), vol_l);
|
||||
sceSdSetParam(((u16)stereo_cmd->voice), 0);
|
||||
sceSdSetParam(((u16)param_1->voice) | 0x100, 0);
|
||||
sceSdSetParam(((u16)stereo_cmd->voice) | 0x100, vol_r);
|
||||
sceSdSetSwitch(SD_S_KON | CORE_BIT(param_1->voice),
|
||||
VOICE_BIT(param_1->voice) | VOICE_BIT(stereo_cmd->voice));
|
||||
sceSdSetParam(SD_VP_VOLL | param_1->voice, vol_l);
|
||||
sceSdSetParam(SD_VP_VOLL | stereo_cmd->voice, 0);
|
||||
sceSdSetParam(SD_VP_VOLR | param_1->voice, 0);
|
||||
sceSdSetParam(SD_VP_VOLR | stereo_cmd->voice, vol_r);
|
||||
}
|
||||
param_1->sb_paused = 0;
|
||||
stereo_cmd->sb_paused = 0;
|
||||
@@ -505,82 +343,54 @@ void RestartVag(VagCmd* param_1, int param_2, int /*param_3*/) {
|
||||
// if (param_3 == 1) {
|
||||
// CpuSuspendIntr(&local_30);
|
||||
//}
|
||||
int vol_l, vol_r;
|
||||
u32 vol_l, vol_r;
|
||||
CalculateVAGVolumes(param_1, &vol_l, &vol_r);
|
||||
if (param_1->status_bytes[BYTE11] == '\0') {
|
||||
int voice = 1 << (param_1->voice >> 1 & 0x1fU);
|
||||
auto* stereo_sibling = param_1->stereo_sibling;
|
||||
int sram_offset = param_2 ? 0x2000 : 0;
|
||||
if (stereo_sibling) {
|
||||
voice = voice | 1 << (stereo_sibling->voice >> 1 & 0x1fU);
|
||||
}
|
||||
// sceSdSetSwitch(((u16)param_1->voice & 1) | 0x1600, voice);
|
||||
sceSdkey_off_jak2_voice(param_1->voice);
|
||||
if (stereo_sibling) {
|
||||
sceSdkey_off_jak2_voice(stereo_sibling->voice);
|
||||
}
|
||||
sceSdSetParam(((u16)param_1->voice), 0);
|
||||
sceSdSetParam(((u16)param_1->voice) | 0x100, 0);
|
||||
|
||||
int other_voice;
|
||||
int sram_addr;
|
||||
if (!stereo_sibling) {
|
||||
other_voice = *(u16*)¶m_1->voice;
|
||||
sram_addr = param_1->spu_stream_dma_mem_addr;
|
||||
} else {
|
||||
sceSdSetParam(((u16)stereo_sibling->voice), 0);
|
||||
sceSdSetParam(((u16)stereo_sibling->voice) | 0x100, 0);
|
||||
sceSdSetAddr(((u16)param_1->voice) | 0x2040, param_1->spu_stream_dma_mem_addr + sram_offset);
|
||||
other_voice = ((u16)stereo_sibling->voice);
|
||||
sram_addr = stereo_sibling->spu_stream_dma_mem_addr;
|
||||
}
|
||||
sceSdSetAddr(other_voice | 0x2040, sram_addr + sram_offset);
|
||||
// sceSdSetSwitch(((u16)param_1->voice & 1) | 0x1500, voice);
|
||||
sceSdkey_on_jak2_voice(param_1->voice);
|
||||
int voices = VOICE_BIT(param_1->voice);
|
||||
if (stereo_sibling) {
|
||||
sceSdkey_on_jak2_voice(stereo_sibling->voice);
|
||||
voices |= VOICE_BIT(stereo_sibling->voice);
|
||||
}
|
||||
|
||||
sceSdSetSwitch(SD_S_KOFF | CORE_BIT(param_1->voice), voices);
|
||||
|
||||
sceSdSetParam(SD_VP_VOLL | param_1->voice, 0);
|
||||
sceSdSetParam(SD_VP_VOLR | param_1->voice, 0);
|
||||
if (stereo_sibling) {
|
||||
sceSdSetParam(SD_VP_VOLL | stereo_sibling->voice, 0);
|
||||
sceSdSetParam(SD_VP_VOLR | stereo_sibling->voice, 0);
|
||||
}
|
||||
|
||||
sceSdSetAddr(SD_VA_SSA | param_1->voice, param_1->spu_stream_dma_mem_addr + sram_offset);
|
||||
if (stereo_sibling) {
|
||||
sceSdSetAddr(SD_VA_SSA | stereo_sibling->voice,
|
||||
stereo_sibling->spu_stream_dma_mem_addr + sram_offset);
|
||||
}
|
||||
|
||||
sceSdSetSwitch(SD_S_KON | CORE_BIT(param_1->voice), voices);
|
||||
|
||||
if (!stereo_sibling) {
|
||||
sceSdSetParam(((u16)param_1->voice), vol_l);
|
||||
other_voice = ((u16)param_1->voice);
|
||||
sceSdSetParam(SD_VP_VOLL | param_1->voice, vol_l);
|
||||
sceSdSetParam(SD_VP_VOLR | param_1->voice, vol_r);
|
||||
} else {
|
||||
sceSdSetParam(((u16)param_1->voice), vol_l);
|
||||
sceSdSetParam(((u16)stereo_sibling->voice), 0);
|
||||
sceSdSetParam(((u16)param_1->voice) | 0x100, 0);
|
||||
other_voice = ((u16)stereo_sibling->voice);
|
||||
sceSdSetParam(SD_VP_VOLL | param_1->voice, vol_l);
|
||||
sceSdSetParam(SD_VP_VOLL | stereo_sibling->voice, 0);
|
||||
sceSdSetParam(SD_VP_VOLR | param_1->voice, 0);
|
||||
sceSdSetParam(SD_VP_VOLR | stereo_sibling->voice, vol_r);
|
||||
}
|
||||
sceSdSetParam(other_voice | 0x100, vol_r);
|
||||
}
|
||||
// if (param_3 == 1) {
|
||||
// CpuResumeIntr(local_30);
|
||||
//}
|
||||
}
|
||||
|
||||
struct sceSdBatch {
|
||||
u32 entry;
|
||||
u32 value;
|
||||
u32 func;
|
||||
};
|
||||
|
||||
void sceSdProcBatch(sceSdBatch* b, int, int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
sceSdSetParam(b[i].entry, b[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
void SetVAGVol(VagCmd* cmd, int param_2) {
|
||||
u32 uVar1;
|
||||
u32 uVar3;
|
||||
int iVar4;
|
||||
int iVar5;
|
||||
VagCmd* stereo_cmd;
|
||||
sceSdBatch batch[6];
|
||||
u32 local_28;
|
||||
u32 local_24;
|
||||
// undefined4 local_20 [2];
|
||||
u32 lvol, rvol;
|
||||
|
||||
if (cmd == 0x0) {
|
||||
if (cmd == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (cmd->byte4 == '\0') {
|
||||
@@ -592,105 +402,43 @@ void SetVAGVol(VagCmd* cmd, int param_2) {
|
||||
if (cmd->byte11 != '\0') {
|
||||
return;
|
||||
}
|
||||
auto pvVar2 = cmd->unk_136;
|
||||
stereo_cmd = cmd->stereo_sibling;
|
||||
if (pvVar2 == 0) {
|
||||
if (cmd->unk_296 == 0) {
|
||||
local_28 = (u32)(cmd->vol_multiplier * MasterVolume[2]) >> 6;
|
||||
local_24 = local_28;
|
||||
if (0x3fff < local_28) {
|
||||
local_28 = 0x3fff;
|
||||
local_24 = local_28;
|
||||
}
|
||||
goto LAB_0000a258;
|
||||
}
|
||||
iVar4 = CalculateFallofVolume(&cmd->vec3, (u32)(cmd->vol_multiplier * MasterVolume[2]) >> 10,
|
||||
cmd->fo_curve, cmd->fo_min, cmd->fo_max);
|
||||
iVar5 = CalculateAngle(&cmd->vec3);
|
||||
uVar3 = 0x276 - iVar5;
|
||||
uVar1 = (uVar3 >> 3) / 0x2d;
|
||||
local_28 = ((s16*)gPanTable)[uVar1 * -0x2d0 + uVar3 * 2] * iVar4;
|
||||
local_24 = ((s16*)gPanTable)[uVar1 * -0x2d0 + uVar3 * 2 + 1] * iVar4;
|
||||
|
||||
if (!cmd->sound_handler) {
|
||||
CalculateVAGVolumes(cmd, &lvol, &rvol);
|
||||
} else {
|
||||
ASSERT_NOT_REACHED();
|
||||
// uVar3 = cmd->unk_176 + 0x5a;
|
||||
// uVar1 = (uVar3 >> 3) / 0x2d;
|
||||
// local_24 = (((u32)(cmd->vol_multiplier * MasterVolume[*(char *)((int)pvVar2 + 0x17)]) >>
|
||||
// 10) *
|
||||
// (int)*(short *)((int)pvVar2 + 0x10) >> 10) * 0x3fff >> 10;
|
||||
// local_28 = (int)gPanTable[uVar1 * -0x2d0 + uVar3 * 2] * local_24;
|
||||
// local_24 = (int)gPanTable[uVar1 * -0x2d0 + uVar3 * 2 + 1] * local_24;
|
||||
// TODO vag 989snd plugin
|
||||
// SoundHandler* hnd = cmd->sound_handler;
|
||||
// u32 vol =
|
||||
// 0x3fff *
|
||||
// ((((cmd->vol_multiplier * MasterVolume[hnd->VolGroup]) >> 10) * hnd->Current_Vol) >> 10)
|
||||
// >> 10;
|
||||
// lvol = (vol * gPanTable[(cmd->unk_176 + 90) % 360].left) >> 10;
|
||||
// lvol = (vol * gPanTable[(cmd->unk_176 + 90) % 360].right) >> 10;
|
||||
// if (lvol >= 0x4000) {
|
||||
// lvol = 0x3fff;
|
||||
//}
|
||||
// if (rvol >= 0x4000) {
|
||||
// rvol = 0x3fff;
|
||||
//}
|
||||
}
|
||||
local_28 = local_28 >> 10;
|
||||
local_24 = local_24 >> 10;
|
||||
if (0x3fff < local_28) {
|
||||
local_28 = 0x3fff;
|
||||
}
|
||||
if (0x3fff < local_24) {
|
||||
local_24 = 0x3fff;
|
||||
}
|
||||
LAB_0000a258:
|
||||
if (stereo_cmd == (VagCmd*)0x0) {
|
||||
batch[0].entry = *(uint16_t*)&cmd->voice;
|
||||
iVar4 = 2;
|
||||
batch[1].entry = *(u16*)&cmd->voice | 0x100;
|
||||
batch[2].entry = *(u16*)&cmd->voice | 0x200;
|
||||
iVar5 = cmd->unk_256_pitch2;
|
||||
uVar1 = cmd->pitch1;
|
||||
// printf("cmd's pitch is %d, %d\n", cmd->pitch1, cmd->unk_256_pitch2);
|
||||
batch[1].value = local_24;
|
||||
|
||||
// Originally used ProcBatch, buts this is easier to read.
|
||||
stereo_cmd = cmd->stereo_sibling;
|
||||
if (stereo_cmd) {
|
||||
sceSdSetParam(SD_VP_VOLL | cmd->voice, lvol);
|
||||
sceSdSetParam(SD_VP_VOLR | cmd->voice, 0);
|
||||
|
||||
sceSdSetParam(SD_VP_VOLL | stereo_cmd->voice, 0);
|
||||
sceSdSetParam(SD_VP_VOLR | stereo_cmd->voice, rvol);
|
||||
|
||||
sceSdSetParam(SD_VP_PITCH | cmd->voice, CalculateVAGPitch(cmd->pitch1, cmd->unk_256_pitch2));
|
||||
sceSdSetParam(SD_VP_PITCH | stereo_cmd->voice,
|
||||
CalculateVAGPitch(cmd->pitch1, cmd->unk_256_pitch2));
|
||||
} else {
|
||||
batch[0].entry = *(uint16_t*)&cmd->voice;
|
||||
batch[1].entry = *(uint16_t*)&stereo_cmd->voice;
|
||||
batch[1].value = 0;
|
||||
batch[2].value = 0;
|
||||
batch[2].entry = *(u16*)&cmd->voice | 0x100;
|
||||
batch[3].func = 1;
|
||||
batch[3].entry = *(u16*)&stereo_cmd->voice | 0x100;
|
||||
batch[4].func = 1;
|
||||
batch[4].entry = *(u16*)&cmd->voice | 0x200;
|
||||
iVar4 = cmd->unk_256_pitch2;
|
||||
batch[4].value = cmd->pitch1;
|
||||
if (iVar4 != 0) {
|
||||
if (iVar4 < 1) {
|
||||
batch[4].value = (u32)(batch[4].value * 0x5f4) / (0x5f4U - iVar4);
|
||||
if (0x5f4U - iVar4 == 0) {
|
||||
ASSERT_NOT_REACHED();
|
||||
// trap(0x1c00);
|
||||
}
|
||||
} else {
|
||||
batch[4].value = (u32)(batch[4].value * (iVar4 + 0x5f4)) / 0x5f4;
|
||||
}
|
||||
}
|
||||
iVar4 = 5;
|
||||
batch[5].func = 1;
|
||||
batch[5].entry = *(u16*)&stereo_cmd->voice | 0x200;
|
||||
iVar5 = cmd->unk_256_pitch2;
|
||||
uVar1 = cmd->pitch1;
|
||||
batch[3].value = local_24;
|
||||
}
|
||||
if (iVar5 != 0) {
|
||||
if (iVar5 < 1) {
|
||||
uVar1 = (uVar1 * 0x5f4) / (0x5f4U - iVar5);
|
||||
if (0x5f4U - iVar5 == 0) {
|
||||
ASSERT_NOT_REACHED();
|
||||
// trap(0x1c00);
|
||||
}
|
||||
} else {
|
||||
uVar1 = (uVar1 * (iVar5 + 0x5f4)) / 0x5f4;
|
||||
}
|
||||
}
|
||||
batch[2].func = 1;
|
||||
batch[1].func = 1;
|
||||
batch[0].value = local_28;
|
||||
batch[0].func = 1;
|
||||
batch[iVar4].value = uVar1;
|
||||
if (param_2 == 1) {
|
||||
// CpuSuspendIntr(local_20);
|
||||
sceSdProcBatch(batch, 0, iVar4 + 1);
|
||||
// CpuResumeIntr(local_20[0]);
|
||||
} else {
|
||||
sceSdProcBatch(batch, 0, iVar4 + 1);
|
||||
sceSdSetParam(SD_VP_VOLL | cmd->voice, lvol);
|
||||
sceSdSetParam(SD_VP_VOLR | cmd->voice, rvol);
|
||||
sceSdSetParam(SD_VP_PITCH | cmd->voice, CalculateVAGPitch(cmd->pitch1, cmd->unk_256_pitch2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -866,6 +614,7 @@ void FreeVagCmd(VagCmd* cmd, int /*param_2*/) {
|
||||
cmd->unk_188 = 0;
|
||||
cmd->unk_192 = 0;
|
||||
SetVagStreamName(cmd, 0, 0);
|
||||
|
||||
cmd->name[0] = '\0';
|
||||
cmd->unk_264 = 0x4000;
|
||||
(cmd->header).callback = NullCallback;
|
||||
@@ -886,7 +635,7 @@ void FreeVagCmd(VagCmd* cmd, int /*param_2*/) {
|
||||
cmd->unk_256_pitch2 = 0;
|
||||
cmd->id = 0;
|
||||
cmd->plugin_id = 0;
|
||||
cmd->unk_136 = 0;
|
||||
cmd->sound_handler = 0;
|
||||
cmd->priority = 0;
|
||||
cmd->unk_288 = 0;
|
||||
cmd->unk_292 = 0;
|
||||
@@ -948,15 +697,11 @@ void StopVAG(VagCmd* cmd, int /*param_2*/) {
|
||||
auto& sibling = cmd->stereo_sibling;
|
||||
PauseVAG(cmd, 0);
|
||||
if (cmd->status_bytes[BYTE5] != '\0') {
|
||||
int val = 1 << (cmd->voice >> 1 & 0x1fU);
|
||||
int val = VOICE_BIT(cmd->voice);
|
||||
if (sibling) {
|
||||
val = val | 1 << (sibling->voice >> 1 & 0x1fU);
|
||||
}
|
||||
// sceSdSetSwitch(u16(cmd->voice) & 1 | 0x1600, val);
|
||||
sceSdkey_off_jak2_voice(cmd->voice);
|
||||
if (sibling) {
|
||||
sceSdkey_off_jak2_voice(sibling->voice);
|
||||
val = val | VOICE_BIT(sibling->voice);
|
||||
}
|
||||
sceSdSetSwitch(SD_S_KOFF | CORE_BIT(cmd->voice), val);
|
||||
}
|
||||
for (auto& x : cmd->status_bytes) {
|
||||
x = 0;
|
||||
@@ -967,7 +712,7 @@ void StopVAG(VagCmd* cmd, int /*param_2*/) {
|
||||
cmd->id = 0;
|
||||
cmd->plugin_id = 0;
|
||||
(cmd->header).ready_for_data = 0;
|
||||
cmd->unk_136 = 0;
|
||||
cmd->sound_handler = 0;
|
||||
cmd->unk_140 = 0;
|
||||
cmd->pitch1 = 0;
|
||||
cmd->unk_180 = 0;
|
||||
@@ -989,16 +734,14 @@ void VAG_MarkLoopStart(int8_t* param_1) {
|
||||
}
|
||||
|
||||
int CalculateVAGPitch(int param_1, int param_2) {
|
||||
if (param_2 != 0) {
|
||||
if (param_2 < 1) {
|
||||
param_1 = (param_1 * 0x5f4) / (0x5f4U - param_2);
|
||||
if (0x5f4U - param_2 == 0) {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
if (param_2) {
|
||||
if (param_2 <= 0) {
|
||||
return 0x5f4 * param_1 / (0x5f4 - param_2);
|
||||
} else {
|
||||
param_1 = (param_1 * (param_2 + 0x5f4)) / 0x5f4;
|
||||
return param_1 * (param_2 + 0x5f4) / 0x5f4;
|
||||
}
|
||||
}
|
||||
|
||||
return param_1;
|
||||
}
|
||||
|
||||
@@ -1018,61 +761,42 @@ void UnPauseVagStreams() {
|
||||
}
|
||||
}
|
||||
|
||||
void SetAllVagsVol(int param_1)
|
||||
|
||||
{
|
||||
int iVar1;
|
||||
VagCmd* cmd;
|
||||
|
||||
cmd = VagCmds;
|
||||
if (param_1 < 0) {
|
||||
iVar1 = 0;
|
||||
do {
|
||||
SetVAGVol(cmd, 1);
|
||||
iVar1 = iVar1 + 1;
|
||||
cmd = cmd + 1;
|
||||
} while (iVar1 < 4);
|
||||
} else {
|
||||
iVar1 = 0;
|
||||
do {
|
||||
if (cmd->unk_136) {
|
||||
void SetAllVagsVol(int param_1) {
|
||||
if (param_1 >= 0) {
|
||||
for (auto& VagCmd : VagCmds) {
|
||||
if (VagCmd.sound_handler /* && VagCmd.sound_handler->VolGroup == param_1 */) {
|
||||
ASSERT_NOT_REACHED();
|
||||
// if (*(char *)((int)cmd->unk_136 + 0x17) == param_1) {
|
||||
// SetVAGVol(cmd,1);
|
||||
// }
|
||||
cmd = cmd + 1;
|
||||
SetVAGVol(&VagCmd, 1);
|
||||
}
|
||||
iVar1 = iVar1 + 1;
|
||||
} while (iVar1 < 4);
|
||||
}
|
||||
} else {
|
||||
for (auto& VagCmd : VagCmds) {
|
||||
SetVAGVol(&VagCmd, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CalculateVAGVolumes(VagCmd* cmd, int* l_out, int* r_out) {
|
||||
// int iVar1;
|
||||
// int iVar2;
|
||||
// u32 uVar3;
|
||||
|
||||
void CalculateVAGVolumes(VagCmd* cmd, u32* l_out, u32* r_out) {
|
||||
if (cmd->unk_296 == 0) {
|
||||
u32 vol = (u32)(cmd->vol_multiplier * MasterVolume[VolumeCategory::DIALOGUE]) >> 6;
|
||||
if (0x3fff < vol) {
|
||||
if (vol >= 0x4000) {
|
||||
vol = 0x3fff;
|
||||
}
|
||||
*l_out = vol;
|
||||
*r_out = vol;
|
||||
} else {
|
||||
int fo_vol =
|
||||
CalculateFallofVolume(&cmd->vec3, (u32)(cmd->vol_multiplier * MasterVolume[2]) >> 10,
|
||||
cmd->fo_curve, cmd->fo_min, cmd->fo_max);
|
||||
int angle = CalculateAngle(&cmd->vec3);
|
||||
int uVar4 = 0x276 - angle;
|
||||
int uVar3 = (uVar4 >> 3) / 0x2d;
|
||||
auto* pan = (s16*)gPanTable;
|
||||
*l_out = (u32)(pan[uVar3 * -0x2d0 + uVar4 * 2] * fo_vol) >> 10;
|
||||
*r_out = (u32)(pan[uVar3 * -0x2d0 + uVar4 * 2 + 1] * fo_vol) >> 10;
|
||||
if (0x3fff < *l_out) {
|
||||
CalculateFalloffVolume(&cmd->vec3, (u32)(cmd->vol_multiplier * MasterVolume[2]) >> 10,
|
||||
cmd->fo_curve, cmd->fo_min, cmd->fo_max);
|
||||
|
||||
auto* pan = &gPanTable[(630 - CalculateAngle(&cmd->vec3)) % 360];
|
||||
*l_out = (pan->left * fo_vol) >> 10;
|
||||
*r_out = (pan->right * fo_vol) >> 10;
|
||||
|
||||
if (*l_out >= 0x4000) {
|
||||
*l_out = 0x3fff;
|
||||
}
|
||||
if (0x3fff < *r_out) {
|
||||
if (*r_out >= 0x4000) {
|
||||
*r_out = 0x3fff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ struct VagCmd {
|
||||
int spu_trap_mem_addr; // 124
|
||||
int voice; // 128
|
||||
int idx_in_cmd_arr; // 132 (index in VagCmds)
|
||||
int unk_136; // 136
|
||||
int sound_handler; // 136 (989snd sound that played this stream)
|
||||
int unk_140; // 140
|
||||
int unk_176; // 176
|
||||
int unk_180; // 180
|
||||
@@ -95,7 +95,7 @@ struct VagCmd {
|
||||
int priority; // 284
|
||||
int unk_288; // 288
|
||||
int unk_292; // 292
|
||||
int unk_296; // 296
|
||||
int unk_296; // 296 (audio has world positioning)
|
||||
Vec3w vec3; // 300
|
||||
int fo_min; // 312 (init to 5)
|
||||
int fo_max; // 316 (init to 316)
|
||||
@@ -142,4 +142,4 @@ VagCmd* FindVagStreamId(int id);
|
||||
void SetVAGVol(VagCmd* cmd, int param_2);
|
||||
void SetAllVagsVol(int vol);
|
||||
void SetVagStreamsNotScanned();
|
||||
} // namespace jak2
|
||||
} // namespace jak2
|
||||
+1
-1
@@ -235,7 +235,7 @@ void ee_runner(SystemThreadInterface& iface) {
|
||||
void ee_worker_runner(SystemThreadInterface& iface) {
|
||||
iface.initialization_complete();
|
||||
while (!iface.get_want_exit()) {
|
||||
const auto queues_weres_empty = g_background_worker.process_queues();
|
||||
const auto queues_weres_empty = !g_background_worker.process_queues();
|
||||
if (queues_weres_empty) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
@@ -12,19 +12,13 @@ namespace snd {
|
||||
u64 SoundFlavaHack = 0;
|
||||
u8 GlobalExcite = 0;
|
||||
|
||||
ame_handler::ame_handler(MultiMIDIBlockHeader* block,
|
||||
voice_manager& vm,
|
||||
MIDISound& sound,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
locator& loc,
|
||||
SoundBank& bank)
|
||||
: m_sound(sound),
|
||||
m_bank(bank),
|
||||
m_header(block),
|
||||
m_locator(loc),
|
||||
m_vm(vm),
|
||||
m_repeats(sound.Repeats) {
|
||||
AmeHandler::AmeHandler(MultiMidi* block,
|
||||
VoiceManager& vm,
|
||||
MusicBank::MIDISound& sound,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SoundBank& bank)
|
||||
: m_sound(sound), m_bank(bank), m_header(block), m_vm(vm), m_repeats(sound.Repeats) {
|
||||
if (vol == VOLUME_DONT_CHANGE) {
|
||||
vol = 1024;
|
||||
}
|
||||
@@ -41,12 +35,12 @@ ame_handler::ame_handler(MultiMIDIBlockHeader* block,
|
||||
m_pan = pan;
|
||||
}
|
||||
|
||||
start_segment(0);
|
||||
StartSegment(0);
|
||||
};
|
||||
|
||||
bool ame_handler::tick() {
|
||||
bool AmeHandler::Tick() {
|
||||
for (auto it = m_midis.begin(); it != m_midis.end();) {
|
||||
bool done = it->second->tick();
|
||||
bool done = it->second->Tick();
|
||||
if (done) {
|
||||
it = m_midis.erase(it);
|
||||
} else {
|
||||
@@ -57,48 +51,47 @@ bool ame_handler::tick() {
|
||||
return m_midis.empty();
|
||||
};
|
||||
|
||||
void ame_handler::start_segment(u32 id) {
|
||||
void AmeHandler::StartSegment(u32 id) {
|
||||
if (m_midis.find(id) == m_midis.end()) {
|
||||
auto midiblock = (MIDIBlockHeader*)(m_header->BlockPtr[id] + (uintptr_t)m_header);
|
||||
auto sound_handler = (MIDISoundHandler*)((uintptr_t)midiblock + sizeof(MIDIBlockHeader));
|
||||
auto& midi = m_header->midi[id];
|
||||
|
||||
// Skip adding if not midi type
|
||||
u32 type = (sound_handler->OwnerID >> 24) & 0xf;
|
||||
u32 type = (midi.SoundHandle >> 24) & 0xf;
|
||||
if (type == 1 || type == 3) {
|
||||
m_midis.emplace(id, std::make_unique<midi_handler>(midiblock, m_vm, m_sound, m_vol, m_pan,
|
||||
m_locator, m_bank, this));
|
||||
m_midis.emplace(id, std::make_unique<MidiHandler>(static_cast<Midi*>(&midi), m_vm, m_sound,
|
||||
m_vol, m_pan, m_bank, this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ame_handler::stop() {
|
||||
void AmeHandler::Stop() {
|
||||
for (auto it = m_midis.begin(); it != m_midis.end();) {
|
||||
it->second->stop();
|
||||
it->second->Stop();
|
||||
it = m_midis.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void ame_handler::stop_segment(u32 id) {
|
||||
void AmeHandler::StopSegment(u32 id) {
|
||||
auto m = m_midis.find(id);
|
||||
if (m == m_midis.end())
|
||||
return;
|
||||
|
||||
m->second->stop();
|
||||
m->second->Stop();
|
||||
}
|
||||
|
||||
void ame_handler::pause() {
|
||||
void AmeHandler::Pause() {
|
||||
for (auto& m : m_midis) {
|
||||
m.second->pause();
|
||||
m.second->Pause();
|
||||
}
|
||||
}
|
||||
|
||||
void ame_handler::unpause() {
|
||||
void AmeHandler::Unpause() {
|
||||
for (auto& m : m_midis) {
|
||||
m.second->unpause();
|
||||
m.second->Unpause();
|
||||
}
|
||||
}
|
||||
|
||||
void ame_handler::set_vol_pan(s32 vol, s32 pan) {
|
||||
void AmeHandler::SetVolPan(s32 vol, s32 pan) {
|
||||
if (vol >= 0) {
|
||||
if (vol != VOLUME_DONT_CHANGE) {
|
||||
m_vol = (m_sound.Vol * vol) >> 10;
|
||||
@@ -118,13 +111,13 @@ void ame_handler::set_vol_pan(s32 vol, s32 pan) {
|
||||
}
|
||||
|
||||
for (auto& m : m_midis) {
|
||||
m.second->set_vol_pan(vol, pan);
|
||||
m.second->SetVolPan(vol, pan);
|
||||
}
|
||||
}
|
||||
|
||||
void ame_handler::set_pmod(s32 mod) {
|
||||
void AmeHandler::SetPMod(s32 mod) {
|
||||
for (auto& m : m_midis) {
|
||||
m.second->set_pmod(mod);
|
||||
m.second->SetPMod(mod);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +134,7 @@ void ame_handler::set_pmod(s32 mod) {
|
||||
; \
|
||||
stream += (x);
|
||||
|
||||
std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
|
||||
std::pair<bool, u8*> AmeHandler::RunAME(MidiHandler& midi, u8* stream) {
|
||||
int skip = 0;
|
||||
bool done = false;
|
||||
bool cont = true;
|
||||
@@ -186,7 +179,7 @@ std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
|
||||
} break;
|
||||
case 0x3: {
|
||||
AME_BEGIN(op)
|
||||
stop_segment(stream[0]);
|
||||
StopSegment(stream[0]);
|
||||
AME_END(1)
|
||||
} break;
|
||||
case 0x4: {
|
||||
@@ -225,7 +218,7 @@ std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
|
||||
} break;
|
||||
case 0xc: {
|
||||
AME_BEGIN(op)
|
||||
auto [sub_cont, ptr] = run_ame(midi, m_macro[stream[0]]);
|
||||
auto [sub_cont, ptr] = RunAME(midi, m_macro[stream[0]]);
|
||||
if (!sub_cont) {
|
||||
cont = false;
|
||||
done = true;
|
||||
@@ -236,12 +229,12 @@ std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
|
||||
AME_BEGIN(op)
|
||||
cont = false;
|
||||
done = true;
|
||||
start_segment(m_register[stream[0]] - 1);
|
||||
StartSegment(m_register[stream[0]] - 1);
|
||||
AME_END(1)
|
||||
} break;
|
||||
case 0xe: {
|
||||
AME_BEGIN(op)
|
||||
start_segment(m_register[stream[0]] - 1);
|
||||
StartSegment(m_register[stream[0]] - 1);
|
||||
AME_END(1)
|
||||
} break;
|
||||
case 0xf: {
|
||||
@@ -285,9 +278,9 @@ std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
|
||||
// note : added hack here! :-)
|
||||
if (!SoundFlavaHack &&
|
||||
(comp < m_groups[group].excite_min[i] || comp > m_groups[group].excite_max[i])) {
|
||||
midi.mute_channel(m_groups[group].channel[i]);
|
||||
midi.MuteChannel(m_groups[group].channel[i]);
|
||||
} else {
|
||||
midi.unmute_channel(m_groups[group].channel[i]);
|
||||
midi.UnmuteChannel(m_groups[group].channel[i]);
|
||||
}
|
||||
}
|
||||
AME_END(1)
|
||||
@@ -296,12 +289,12 @@ std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
|
||||
AME_BEGIN(op)
|
||||
done = true;
|
||||
cont = false;
|
||||
start_segment(stream[0]);
|
||||
StartSegment(stream[0]);
|
||||
AME_END(1)
|
||||
} break;
|
||||
case 0x12: {
|
||||
AME_BEGIN(op)
|
||||
start_segment(stream[0]);
|
||||
StartSegment(stream[0]);
|
||||
AME_END(1)
|
||||
} break;
|
||||
case 0x13: {
|
||||
@@ -334,7 +327,7 @@ std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
|
||||
AME_END(2)
|
||||
} break;
|
||||
default: {
|
||||
throw ame_error(fmt::format("Unhandled AME event {:02x}", (u8)op));
|
||||
throw AMEError(fmt::format("Unhandled AME event {:02x}", (u8)op));
|
||||
} break;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "loader.h"
|
||||
#include "midi_handler.h"
|
||||
#include "musicbank.h"
|
||||
#include "sound_handler.h"
|
||||
#include "vagvoice.h"
|
||||
|
||||
@@ -17,34 +18,33 @@ extern u64 SoundFlavaHack;
|
||||
|
||||
extern u8 GlobalExcite;
|
||||
|
||||
class midi_handler;
|
||||
class ame_handler : public sound_handler {
|
||||
friend class midi_handler;
|
||||
class MidiHandler;
|
||||
class AmeHandler : public SoundHandler {
|
||||
friend class MidiHandler;
|
||||
|
||||
public:
|
||||
ame_handler(MultiMIDIBlockHeader* block,
|
||||
voice_manager& vm,
|
||||
MIDISound& sound,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
locator& loc,
|
||||
SoundBank& bank);
|
||||
bool tick() override;
|
||||
SoundBank& bank() override { return m_bank; };
|
||||
AmeHandler(MultiMidi* block,
|
||||
VoiceManager& vm,
|
||||
MusicBank::MIDISound& sound,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SoundBank& bank);
|
||||
bool Tick() override;
|
||||
SoundBank& Bank() override { return m_bank; };
|
||||
|
||||
void pause() override;
|
||||
void unpause() override;
|
||||
void stop() override;
|
||||
u8 group() override { return m_sound.VolGroup; };
|
||||
void set_vol_pan(s32 vol, s32 pan) override;
|
||||
void Pause() override;
|
||||
void Unpause() override;
|
||||
void Stop() override;
|
||||
u8 Group() override { return m_sound.VolGroup; };
|
||||
void SetVolPan(s32 vol, s32 pan) override;
|
||||
|
||||
void set_register(u8 reg, u8 value) override { m_register[reg] = value; }
|
||||
void set_pmod(s32 mod) override;
|
||||
void SetRegister(u8 reg, u8 value) override { m_register[reg] = value; }
|
||||
void SetPMod(s32 mod) override;
|
||||
|
||||
private:
|
||||
struct ame_error : public std::exception {
|
||||
ame_error(std::string text) : msg(std::move(text)) {}
|
||||
ame_error() : msg("Unknown AME error") {}
|
||||
struct AMEError : public std::exception {
|
||||
AMEError(std::string text) : msg(std::move(text)) {}
|
||||
AMEError() : msg("Unknown AME error") {}
|
||||
std::string msg;
|
||||
const char* what() const noexcept override { return msg.c_str(); }
|
||||
};
|
||||
@@ -58,21 +58,20 @@ class ame_handler : public sound_handler {
|
||||
/* 24 */ s8 excite_max[16];
|
||||
};
|
||||
|
||||
void start_segment(u32 id);
|
||||
void stop_segment(u32 id);
|
||||
std::pair<bool, u8*> run_ame(midi_handler&, u8* stream);
|
||||
void StartSegment(u32 id);
|
||||
void StopSegment(u32 id);
|
||||
std::pair<bool, u8*> RunAME(MidiHandler&, u8* stream);
|
||||
|
||||
MIDISound& m_sound;
|
||||
MusicBank::MIDISound& m_sound;
|
||||
SoundBank& m_bank;
|
||||
|
||||
MultiMIDIBlockHeader* m_header{nullptr};
|
||||
locator& m_locator;
|
||||
voice_manager& m_vm;
|
||||
MultiMidi* m_header{nullptr};
|
||||
VoiceManager& m_vm;
|
||||
s32 m_vol{0};
|
||||
s32 m_pan{0};
|
||||
s8 m_repeats{0};
|
||||
|
||||
std::unordered_map<u32, std::unique_ptr<midi_handler>> m_midis;
|
||||
std::unordered_map<u32, std::unique_ptr<MidiHandler>> m_midis;
|
||||
|
||||
std::array<GroupDescription, 16> m_groups{};
|
||||
std::array<u8, 16> m_register{};
|
||||
|
||||
@@ -10,15 +10,111 @@
|
||||
namespace snd {
|
||||
std::array<s8, 32> g_block_reg{};
|
||||
|
||||
bool blocksound_handler::tick() {
|
||||
m_voices.remove_if([](std::weak_ptr<blocksound_voice>& p) { return p.expired(); });
|
||||
BlockSoundHandler::BlockSoundHandler(SoundBank& bank,
|
||||
SFXBlock::SFX& sfx,
|
||||
VoiceManager& vm,
|
||||
s32 sfx_vol,
|
||||
s32 sfx_pan,
|
||||
SndPlayParams& params)
|
||||
: m_group(sfx.VolGroup), m_sfx(sfx), m_vm(vm), m_bank(bank) {
|
||||
s32 vol, pan, pitch_mod, pitch_bend;
|
||||
if (sfx_vol == -1) {
|
||||
sfx_vol = sfx.Vol;
|
||||
}
|
||||
if (sfx_pan == -1) {
|
||||
sfx_pan = sfx.Pan;
|
||||
}
|
||||
|
||||
if (params.vol.has_value()) {
|
||||
vol = params.vol.value();
|
||||
} else {
|
||||
vol = 1024;
|
||||
}
|
||||
|
||||
if (params.pan.has_value()) {
|
||||
pan = params.pan.value();
|
||||
} else {
|
||||
pan = -1;
|
||||
}
|
||||
|
||||
if (params.pitch_mod.has_value()) {
|
||||
pitch_mod = params.pitch_mod.value();
|
||||
} else {
|
||||
pitch_mod = 0;
|
||||
}
|
||||
|
||||
if (params.pitch_bend.has_value()) {
|
||||
pitch_bend = params.pitch_bend.value();
|
||||
} else {
|
||||
pitch_bend = 0;
|
||||
}
|
||||
|
||||
if (vol == VOLUME_DONT_CHANGE) {
|
||||
vol = 1024;
|
||||
}
|
||||
s32 play_vol = (sfx_vol * vol) >> 10;
|
||||
if (play_vol >= 128) {
|
||||
play_vol = 127;
|
||||
}
|
||||
|
||||
if (pan == PAN_RESET || pan == PAN_DONT_CHANGE) {
|
||||
pan = sfx_pan;
|
||||
}
|
||||
|
||||
m_orig_volume = sfx_vol;
|
||||
m_orig_pan = sfx_pan;
|
||||
|
||||
m_cur_volume = play_vol;
|
||||
m_cur_pan = pan;
|
||||
m_cur_pb = pitch_bend;
|
||||
m_cur_pm = pitch_mod;
|
||||
|
||||
m_app_volume = vol;
|
||||
m_app_pan = pan;
|
||||
m_app_pb = pitch_bend;
|
||||
m_app_pm = pitch_mod;
|
||||
|
||||
m_lfo_volume = 0;
|
||||
m_lfo_pan = 0;
|
||||
m_lfo_pb = 0;
|
||||
m_lfo_pm = 0;
|
||||
|
||||
if (params.registers.has_value()) {
|
||||
m_registers = params.registers.value();
|
||||
}
|
||||
|
||||
// Figure this stuff out properly someday
|
||||
// if (m_sfx.d.Flags & 2) {
|
||||
// fmt::print("solo flag\n");
|
||||
// m_done = true;
|
||||
// return;
|
||||
// }
|
||||
|
||||
m_next_grain = 0;
|
||||
m_countdown = m_sfx.Grains[0].Delay;
|
||||
while (m_countdown <= 0 && !m_done) {
|
||||
DoGrain();
|
||||
}
|
||||
}
|
||||
|
||||
BlockSoundHandler::~BlockSoundHandler() {
|
||||
for (auto& p : m_voices) {
|
||||
auto v = p.lock();
|
||||
if (v != nullptr) {
|
||||
v->Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BlockSoundHandler::Tick() {
|
||||
m_voices.remove_if([](std::weak_ptr<BlockSoundVoice>& p) { return p.expired(); });
|
||||
|
||||
for (auto& lfo : m_lfo) {
|
||||
lfo.tick();
|
||||
lfo.Tick();
|
||||
}
|
||||
|
||||
for (auto it = m_children.begin(); it != m_children.end();) {
|
||||
bool done = it->get()->tick();
|
||||
bool done = it->get()->Tick();
|
||||
if (done) {
|
||||
it = m_children.erase(it);
|
||||
} else {
|
||||
@@ -39,17 +135,17 @@ bool blocksound_handler::tick() {
|
||||
|
||||
m_countdown--;
|
||||
while (m_countdown <= 0 && !m_done) {
|
||||
do_grain();
|
||||
DoGrain();
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
void blocksound_handler::pause() {
|
||||
void BlockSoundHandler::Pause() {
|
||||
m_paused = true;
|
||||
|
||||
for (auto& c : m_children) {
|
||||
c->pause();
|
||||
c->Pause();
|
||||
}
|
||||
|
||||
for (auto& p : m_voices) {
|
||||
@@ -58,15 +154,15 @@ void blocksound_handler::pause() {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_vm.pause(voice);
|
||||
m_vm.Pause(voice);
|
||||
}
|
||||
}
|
||||
|
||||
void blocksound_handler::unpause() {
|
||||
void BlockSoundHandler::Unpause() {
|
||||
m_paused = false;
|
||||
|
||||
for (auto& c : m_children) {
|
||||
c->unpause();
|
||||
c->Unpause();
|
||||
}
|
||||
|
||||
for (auto& p : m_voices) {
|
||||
@@ -75,15 +171,15 @@ void blocksound_handler::unpause() {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_vm.unpause(voice);
|
||||
m_vm.Unpause(voice);
|
||||
}
|
||||
}
|
||||
|
||||
void blocksound_handler::stop() {
|
||||
void BlockSoundHandler::Stop() {
|
||||
m_done = true;
|
||||
|
||||
for (auto& c : m_children) {
|
||||
c->stop();
|
||||
c->Stop();
|
||||
}
|
||||
|
||||
for (auto& p : m_voices) {
|
||||
@@ -92,11 +188,11 @@ void blocksound_handler::stop() {
|
||||
continue;
|
||||
}
|
||||
|
||||
voice->key_off();
|
||||
voice->KeyOff();
|
||||
}
|
||||
}
|
||||
|
||||
void blocksound_handler::set_vol_pan(s32 vol, s32 pan) {
|
||||
void BlockSoundHandler::SetVolPan(s32 vol, s32 pan) {
|
||||
if (vol >= 0) {
|
||||
if (vol != VOLUME_DONT_CHANGE) {
|
||||
m_app_volume = vol;
|
||||
@@ -106,7 +202,7 @@ void blocksound_handler::set_vol_pan(s32 vol, s32 pan) {
|
||||
}
|
||||
|
||||
if (pan == PAN_RESET) {
|
||||
m_app_pan = m_sfx.d.Pan;
|
||||
m_app_pan = m_sfx.Pan;
|
||||
} else if (pan != PAN_DONT_CHANGE) {
|
||||
m_app_pan = pan;
|
||||
}
|
||||
@@ -127,7 +223,7 @@ void blocksound_handler::set_vol_pan(s32 vol, s32 pan) {
|
||||
m_cur_pan = new_pan;
|
||||
|
||||
for (auto& c : m_children) {
|
||||
c->set_vol_pan(m_app_volume * m_orig_volume / 127, pan);
|
||||
c->SetVolPan(m_app_volume * m_orig_volume / 127, pan);
|
||||
}
|
||||
|
||||
for (auto& p : m_voices) {
|
||||
@@ -136,16 +232,16 @@ void blocksound_handler::set_vol_pan(s32 vol, s32 pan) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto volume = m_vm.make_volume(127, 0, m_cur_volume, m_cur_pan, voice->g_vol, voice->g_pan);
|
||||
auto left = m_vm.adjust_vol_to_group(volume.left, m_group);
|
||||
auto right = m_vm.adjust_vol_to_group(volume.right, m_group);
|
||||
auto volume = m_vm.MakeVolume(127, 0, m_cur_volume, m_cur_pan, voice->g_vol, voice->g_pan);
|
||||
auto left = m_vm.AdjustVolToGroup(volume.left, m_group);
|
||||
auto right = m_vm.AdjustVolToGroup(volume.right, m_group);
|
||||
|
||||
voice->set_volume(left >> 1, right >> 1);
|
||||
voice->SetVolume(left >> 1, right >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void blocksound_handler::update_pitch() {
|
||||
void BlockSoundHandler::UpdatePitch() {
|
||||
m_cur_pm = m_app_pm + m_lfo_pm;
|
||||
m_cur_pb = std::clamp<s32>(m_app_pb + m_lfo_pb, INT16_MIN, INT16_MAX);
|
||||
|
||||
@@ -155,34 +251,34 @@ void blocksound_handler::update_pitch() {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto note = pitchbend(voice->tone, m_cur_pb, m_cur_pm, m_note, m_fine);
|
||||
auto note = PitchBend(voice->tone, m_cur_pb, m_cur_pm, m_note, m_fine);
|
||||
auto pitch =
|
||||
PS1Note2Pitch(voice->tone.CenterNote, voice->tone.CenterFine, note.first, note.second);
|
||||
|
||||
voice->set_pitch(pitch);
|
||||
voice->SetPitch(pitch);
|
||||
}
|
||||
}
|
||||
|
||||
void blocksound_handler::set_pmod(s32 mod) {
|
||||
void BlockSoundHandler::SetPMod(s32 mod) {
|
||||
for (auto& c : m_children) {
|
||||
c->set_pmod(mod);
|
||||
c->SetPMod(mod);
|
||||
}
|
||||
m_app_pm = mod;
|
||||
update_pitch();
|
||||
UpdatePitch();
|
||||
}
|
||||
|
||||
void blocksound_handler::set_pbend(s32 bend) {
|
||||
void BlockSoundHandler::SetPBend(s32 bend) {
|
||||
for (auto& c : m_children) {
|
||||
c->set_pbend(bend);
|
||||
c->SetPBend(bend);
|
||||
}
|
||||
m_app_pb = bend;
|
||||
update_pitch();
|
||||
UpdatePitch();
|
||||
}
|
||||
|
||||
void blocksound_handler::do_grain() {
|
||||
auto& grain = m_sfx.grains[m_next_grain];
|
||||
void BlockSoundHandler::DoGrain() {
|
||||
auto& grain = m_sfx.Grains[m_next_grain];
|
||||
|
||||
s32 ret = grain->execute(*this);
|
||||
s32 ret = grain(*this);
|
||||
|
||||
if (m_skip_grains) {
|
||||
m_grains_to_play--;
|
||||
@@ -193,12 +289,12 @@ void blocksound_handler::do_grain() {
|
||||
}
|
||||
|
||||
m_next_grain++;
|
||||
if (m_next_grain >= m_sfx.grains.size()) {
|
||||
if (m_next_grain >= m_sfx.Grains.size()) {
|
||||
m_done = true;
|
||||
return;
|
||||
}
|
||||
|
||||
m_countdown = m_sfx.grains[m_next_grain]->delay() + ret;
|
||||
m_countdown = m_sfx.Grains[m_next_grain].Delay + ret;
|
||||
}
|
||||
|
||||
} // namespace snd
|
||||
@@ -5,132 +5,44 @@
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "game/sound/989snd/lfo.h"
|
||||
#include "sfxblock2.h"
|
||||
#include "game/sound/989snd/sfxblock.h"
|
||||
|
||||
namespace snd {
|
||||
|
||||
extern std::array<s8, 32> g_block_reg;
|
||||
|
||||
class blocksound_voice : public vag_voice {
|
||||
class BlockSoundVoice : public VagVoice {
|
||||
public:
|
||||
blocksound_voice(Tone& t) : vag_voice(t) {}
|
||||
BlockSoundVoice(Tone& t) : VagVoice(t) {}
|
||||
s32 g_vol;
|
||||
s32 g_pan;
|
||||
};
|
||||
|
||||
class blocksound_handler : public sound_handler {
|
||||
class BlockSoundHandler : public SoundHandler {
|
||||
public:
|
||||
blocksound_handler(SoundBank& bank,
|
||||
SFX2& sfx,
|
||||
voice_manager& vm,
|
||||
s32 sfx_vol,
|
||||
s32 sfx_pan,
|
||||
SndPlayParams& params)
|
||||
: m_group(sfx.d.VolGroup), m_sfx(sfx), m_vm(vm), m_bank(bank) {
|
||||
s32 vol, pan, pitch_mod, pitch_bend;
|
||||
if (sfx_vol == -1) {
|
||||
sfx_vol = sfx.d.Vol;
|
||||
}
|
||||
if (sfx_pan == -1) {
|
||||
sfx_pan = sfx.d.Pan;
|
||||
}
|
||||
BlockSoundHandler(SoundBank& bank,
|
||||
SFXBlock::SFX& sfx,
|
||||
VoiceManager& vm,
|
||||
s32 sfx_vol,
|
||||
s32 sfx_pan,
|
||||
SndPlayParams& params);
|
||||
|
||||
if (params.vol.has_value()) {
|
||||
vol = params.vol.value();
|
||||
} else {
|
||||
vol = 1024;
|
||||
}
|
||||
~BlockSoundHandler() override;
|
||||
bool Tick() override;
|
||||
SoundBank& Bank() override { return m_bank; };
|
||||
|
||||
if (params.pan.has_value()) {
|
||||
pan = params.pan.value();
|
||||
} else {
|
||||
pan = -1;
|
||||
}
|
||||
void Pause() override;
|
||||
void Unpause() override;
|
||||
void Stop() override;
|
||||
u8 Group() override { return m_group; };
|
||||
void SetVolPan(s32 vol, s32 pan) override;
|
||||
void SetPMod(s32 mod) override;
|
||||
void SetRegister(u8 reg, u8 value) override { m_registers.at(reg) = value; };
|
||||
void SetPBend(s32 bend) override;
|
||||
|
||||
if (params.pitch_mod.has_value()) {
|
||||
pitch_mod = params.pitch_mod.value();
|
||||
} else {
|
||||
pitch_mod = 0;
|
||||
}
|
||||
void DoGrain();
|
||||
|
||||
if (params.pitch_bend.has_value()) {
|
||||
pitch_bend = params.pitch_bend.value();
|
||||
} else {
|
||||
pitch_bend = 0;
|
||||
}
|
||||
|
||||
if (vol == VOLUME_DONT_CHANGE) {
|
||||
vol = 1024;
|
||||
}
|
||||
s32 play_vol = (sfx_vol * vol) >> 10;
|
||||
if (play_vol >= 128) {
|
||||
play_vol = 127;
|
||||
}
|
||||
|
||||
if (pan == PAN_RESET || pan == PAN_DONT_CHANGE) {
|
||||
pan = sfx_pan;
|
||||
}
|
||||
|
||||
m_orig_volume = sfx_vol;
|
||||
m_orig_pan = sfx_pan;
|
||||
|
||||
m_cur_volume = play_vol;
|
||||
m_cur_pan = pan;
|
||||
m_cur_pb = pitch_bend;
|
||||
m_cur_pm = pitch_mod;
|
||||
|
||||
m_app_volume = vol;
|
||||
m_app_pan = pan;
|
||||
m_app_pb = pitch_bend;
|
||||
m_app_pm = pitch_mod;
|
||||
|
||||
m_lfo_volume = 0;
|
||||
m_lfo_pan = 0;
|
||||
m_lfo_pb = 0;
|
||||
m_lfo_pm = 0;
|
||||
|
||||
if (params.registers.has_value()) {
|
||||
m_registers = params.registers.value();
|
||||
}
|
||||
|
||||
// Figure this stuff out properly someday
|
||||
// if (m_sfx.d.Flags & 2) {
|
||||
// fmt::print("solo flag\n");
|
||||
// m_done = true;
|
||||
// return;
|
||||
// }
|
||||
|
||||
m_next_grain = 0;
|
||||
m_countdown = m_sfx.grains[0]->delay();
|
||||
while (m_countdown <= 0 && !m_done) {
|
||||
do_grain();
|
||||
}
|
||||
}
|
||||
|
||||
~blocksound_handler() override {
|
||||
for (auto& p : m_voices) {
|
||||
auto v = p.lock();
|
||||
if (v != nullptr) {
|
||||
v->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool tick() override;
|
||||
SoundBank& bank() override { return m_bank; };
|
||||
|
||||
void pause() override;
|
||||
void unpause() override;
|
||||
void stop() override;
|
||||
u8 group() override { return m_group; };
|
||||
void set_vol_pan(s32 vol, s32 pan) override;
|
||||
void set_pmod(s32 mod) override;
|
||||
void set_register(u8 reg, u8 value) override { m_registers.at(reg) = value; };
|
||||
void set_pbend(s32 bend) override;
|
||||
|
||||
void do_grain();
|
||||
|
||||
void update_pitch();
|
||||
void UpdatePitch();
|
||||
|
||||
bool m_paused{false};
|
||||
|
||||
@@ -141,12 +53,12 @@ class blocksound_handler : public sound_handler {
|
||||
u32 m_grains_to_skip{0};
|
||||
bool m_skip_grains{false};
|
||||
|
||||
SFX2& m_sfx;
|
||||
voice_manager& m_vm;
|
||||
SFXBlock::SFX& m_sfx;
|
||||
VoiceManager& m_vm;
|
||||
|
||||
std::list<std::weak_ptr<blocksound_voice>> m_voices;
|
||||
std::list<std::weak_ptr<BlockSoundVoice>> m_voices;
|
||||
|
||||
std::list<std::unique_ptr<sound_handler>> m_children;
|
||||
std::list<std::unique_ptr<SoundHandler>> m_children;
|
||||
|
||||
s32 m_orig_volume{0};
|
||||
s32 m_orig_pan{0};
|
||||
@@ -172,8 +84,6 @@ class blocksound_handler : public sound_handler {
|
||||
std::array<s8, 4> m_registers{};
|
||||
std::array<LFOTracker, 4> m_lfo{{*this, *this, *this, *this}};
|
||||
|
||||
// TODO LFO
|
||||
|
||||
s32 m_countdown{0};
|
||||
u32 m_next_grain{0};
|
||||
};
|
||||
|
||||
@@ -9,24 +9,24 @@
|
||||
|
||||
namespace snd {
|
||||
|
||||
class id_allocator {
|
||||
class IdAllocator {
|
||||
public:
|
||||
u32 get_id() {
|
||||
u32 GetId() {
|
||||
u32 id = 0;
|
||||
if (m_free_ids.empty()) {
|
||||
id = next_id++;
|
||||
if (mFreeIds.empty()) {
|
||||
id = mNextId++;
|
||||
} else {
|
||||
id = m_free_ids.front();
|
||||
m_free_ids.pop();
|
||||
id = mFreeIds.front();
|
||||
mFreeIds.pop();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void free_id(u32 id) { m_free_ids.push(id); }
|
||||
void FreeId(u32 id) { mFreeIds.push(id); }
|
||||
|
||||
private:
|
||||
u32 next_id{1};
|
||||
std::queue<u32> m_free_ids;
|
||||
u32 mNextId{1};
|
||||
std::queue<u32> mFreeIds;
|
||||
};
|
||||
|
||||
} // namespace snd
|
||||
+33
-33
@@ -7,79 +7,79 @@
|
||||
namespace snd {
|
||||
#include "lfo_sine.c.inc"
|
||||
|
||||
void LFOTracker::init() {
|
||||
if (m_type == lfo_type::RAND) {
|
||||
void LFOTracker::Init() {
|
||||
if (m_type == LFOType::RAND) {
|
||||
m_state_hold1 = -(rand() & 0x7fff) * (rand() & 1);
|
||||
m_state_hold2 = 1;
|
||||
}
|
||||
|
||||
calc_depth();
|
||||
tick();
|
||||
CalcDepth();
|
||||
Tick();
|
||||
}
|
||||
|
||||
void LFOTracker::calc_depth() {
|
||||
if (m_target == lfo_target::VOLUME) {
|
||||
m_range = (m_handler.m_sfx.d.Vol * m_depth) >> 10;
|
||||
void LFOTracker::CalcDepth() {
|
||||
if (m_target == LFOTarget::VOLUME) {
|
||||
m_range = (m_handler.m_sfx.Vol * m_depth) >> 10;
|
||||
}
|
||||
if (m_target == lfo_target::PAN) {
|
||||
if (m_target == LFOTarget::PAN) {
|
||||
m_range = (180 * m_depth) >> 10;
|
||||
}
|
||||
if (m_target == lfo_target::PMOD) {
|
||||
if (m_target == LFOTarget::PMOD) {
|
||||
m_range = (6096 * m_depth) >> 10;
|
||||
}
|
||||
if (m_target == lfo_target::PBEND) {
|
||||
if (m_target == LFOTarget::PBEND) {
|
||||
m_range = (0x7fff * m_depth) >> 10;
|
||||
}
|
||||
|
||||
m_last_lfo = 0;
|
||||
}
|
||||
|
||||
void LFOTracker::tick() {
|
||||
void LFOTracker::Tick() {
|
||||
m_tick++;
|
||||
|
||||
if (m_target == lfo_target::NONE || (m_tick & 1) == 0) {
|
||||
if (m_target == LFOTarget::NONE || (m_tick & 1) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_target) {
|
||||
case lfo_target::VOLUME: {
|
||||
s32 vol = (m_range * (get_lfo(2) - 0x7fff)) >> 16;
|
||||
case LFOTarget::VOLUME: {
|
||||
s32 vol = (m_range * (GetLFO(2) - 0x7fff)) >> 16;
|
||||
if (m_handler.m_lfo_volume != vol) {
|
||||
m_handler.m_lfo_volume = vol;
|
||||
m_handler.set_vol_pan(VOLUME_DONT_CHANGE, PAN_DONT_CHANGE);
|
||||
m_handler.SetVolPan(VOLUME_DONT_CHANGE, PAN_DONT_CHANGE);
|
||||
}
|
||||
} break;
|
||||
case lfo_target::PAN: {
|
||||
s32 pan = (m_range * get_lfo(2)) >> 15;
|
||||
case LFOTarget::PAN: {
|
||||
s32 pan = (m_range * GetLFO(2)) >> 15;
|
||||
if (m_handler.m_lfo_pan != pan) {
|
||||
m_handler.m_lfo_pan = pan;
|
||||
m_handler.set_vol_pan(VOLUME_DONT_CHANGE, PAN_DONT_CHANGE);
|
||||
m_handler.SetVolPan(VOLUME_DONT_CHANGE, PAN_DONT_CHANGE);
|
||||
}
|
||||
} break;
|
||||
case lfo_target::PMOD: {
|
||||
s32 pm = (get_lfo(2) * m_range) >> 15;
|
||||
case LFOTarget::PMOD: {
|
||||
s32 pm = (GetLFO(2) * m_range) >> 15;
|
||||
if (m_handler.m_lfo_pm != pm) {
|
||||
m_handler.m_lfo_pm = pm;
|
||||
m_handler.update_pitch();
|
||||
m_handler.UpdatePitch();
|
||||
}
|
||||
} break;
|
||||
case lfo_target::PBEND: {
|
||||
s32 pb = (get_lfo(2) * m_range) >> 15;
|
||||
case LFOTarget::PBEND: {
|
||||
s32 pb = (GetLFO(2) * m_range) >> 15;
|
||||
if (m_handler.m_lfo_pb != pb) {
|
||||
m_handler.m_lfo_pb = pb;
|
||||
m_handler.update_pitch();
|
||||
m_handler.UpdatePitch();
|
||||
}
|
||||
} break;
|
||||
case lfo_target::UNK1: {
|
||||
case LFOTarget::UNK1: {
|
||||
} break;
|
||||
case lfo_target::UNK2: {
|
||||
case LFOTarget::UNK2: {
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s32 LFOTracker::get_lfo(s32 step_mult) {
|
||||
s32 LFOTracker::GetLFO(s32 step_mult) {
|
||||
s32 step = m_next_step >> 16;
|
||||
m_next_step += step_mult * m_step_size;
|
||||
if (m_next_step > 0x7ffffff) {
|
||||
@@ -89,20 +89,20 @@ s32 LFOTracker::get_lfo(s32 step_mult) {
|
||||
s32 ret = 0;
|
||||
|
||||
switch (m_type) {
|
||||
case lfo_type::OFF:
|
||||
case LFOType::OFF:
|
||||
ret = 0;
|
||||
break;
|
||||
case lfo_type::SINE:
|
||||
case LFOType::SINE:
|
||||
ret = gLFO_sine.at(step);
|
||||
break;
|
||||
case lfo_type::SQUARE:
|
||||
case LFOType::SQUARE:
|
||||
if (step >= m_state_hold1) {
|
||||
ret = -32767;
|
||||
} else {
|
||||
ret = 32767;
|
||||
}
|
||||
break;
|
||||
case lfo_type::TRIANGLE:
|
||||
case LFOType::TRIANGLE:
|
||||
if (step < 512) {
|
||||
ret = 0x7fff * step / 512;
|
||||
} else if (step >= 1536) {
|
||||
@@ -111,14 +111,14 @@ s32 LFOTracker::get_lfo(s32 step_mult) {
|
||||
ret = 0x7fff - 65534 * (step - 512) / 1024;
|
||||
}
|
||||
break;
|
||||
case lfo_type::SAW:
|
||||
case LFOType::SAW:
|
||||
if (step >= 1024) {
|
||||
ret = 0x7fff * (step - 1024) / 1024 - 0x7fff;
|
||||
} else {
|
||||
ret = 0x7fff * step / 1023;
|
||||
}
|
||||
break;
|
||||
case lfo_type::RAND:
|
||||
case LFOType::RAND:
|
||||
if (step >= 1024 && m_state_hold2 == 1) {
|
||||
m_state_hold2 = 0;
|
||||
m_state_hold1 = 2 * ((rand() & 0x7fff) - 0x3fff);
|
||||
|
||||
+11
-11
@@ -5,16 +5,16 @@
|
||||
|
||||
namespace snd {
|
||||
|
||||
enum class lfo_type { OFF, SINE, SQUARE, TRIANGLE, SAW, RAND };
|
||||
enum class lfo_target { NONE, VOLUME, PAN, PMOD, PBEND, UNK1, UNK2 };
|
||||
enum class LFOType { OFF, SINE, SQUARE, TRIANGLE, SAW, RAND };
|
||||
enum class LFOTarget { NONE, VOLUME, PAN, PMOD, PBEND, UNK1, UNK2 };
|
||||
|
||||
class blocksound_handler;
|
||||
class BlockSoundHandler;
|
||||
|
||||
class LFOTracker {
|
||||
public:
|
||||
LFOTracker(blocksound_handler& handler) : m_handler(handler) {}
|
||||
lfo_type m_type{lfo_type::OFF};
|
||||
lfo_target m_target{0};
|
||||
LFOTracker(BlockSoundHandler& handler) : m_handler(handler) {}
|
||||
LFOType m_type{LFOType::OFF};
|
||||
LFOTarget m_target{0};
|
||||
u8 m_target_extra{0};
|
||||
u8 m_setup_flags{0};
|
||||
u8 m_running_flags{0};
|
||||
@@ -30,12 +30,12 @@ class LFOTracker {
|
||||
|
||||
u32 m_tick{0};
|
||||
|
||||
void init();
|
||||
void calc_depth();
|
||||
void tick();
|
||||
s32 get_lfo(s32 step_mult);
|
||||
void Init();
|
||||
void CalcDepth();
|
||||
void Tick();
|
||||
s32 GetLFO(s32 step_mult);
|
||||
|
||||
blocksound_handler& m_handler;
|
||||
BlockSoundHandler& m_handler;
|
||||
};
|
||||
|
||||
} // namespace snd
|
||||
|
||||
+437
-118
@@ -5,121 +5,462 @@
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
|
||||
#include "midi_handler.h"
|
||||
#include "sfxblock.h"
|
||||
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/BinaryReader.h"
|
||||
|
||||
#include "sfxblock2.h"
|
||||
#include "game/sound/989snd/musicbank.h"
|
||||
|
||||
#include "third-party/fmt/core.h"
|
||||
|
||||
namespace snd {
|
||||
|
||||
enum chunk : u32 { bank, samples, midi };
|
||||
|
||||
#define FOURCC(a, b, c, d) ((u32)(((d) << 24) | ((c) << 16) | ((b) << 8) | (a)))
|
||||
|
||||
u32 loader::read_bank(std::fstream& in) {
|
||||
size_t origin = in.tellg();
|
||||
FileAttributes<3> attr;
|
||||
in.read((char*)(&attr), sizeof(attr));
|
||||
|
||||
if (attr.type != 1 && attr.type != 3) {
|
||||
lg::error("Error: File type {} not supported.", attr.type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* if there's midi data the pointer to the allocated memory is stored
|
||||
* just before the sound bank data...
|
||||
if (attr.num_chunks > 2) {
|
||||
attr.where[chunk::bank].size += 4;
|
||||
}
|
||||
*/
|
||||
|
||||
// auto pos = in.tellg();
|
||||
auto bank_buf = std::make_unique<u8[]>(attr.where[chunk::bank].size);
|
||||
in.seekg(origin + attr.where[chunk::bank].offset, std::fstream::beg);
|
||||
in.read((char*)bank_buf.get(), attr.where[chunk::bank].size);
|
||||
auto bank_tag = (BankTag*)bank_buf.get();
|
||||
|
||||
u32 bank_id = m_id_allocator.get_id();
|
||||
std::unique_ptr<SoundBank> bank;
|
||||
|
||||
if (bank_tag->DataID == FOURCC('S', 'B', 'v', '2')) {
|
||||
bank = std::make_unique<MusicBank>(*this, bank_id, bank_tag);
|
||||
} else if (bank_tag->DataID == FOURCC('S', 'B', 'l', 'k')) {
|
||||
if (bank_tag->Version < 2) {
|
||||
bank = std::make_unique<SFXBlock>(*this, bank_id, bank_tag);
|
||||
} else {
|
||||
bank = std::make_unique<SFXBlock2>(*this, bank_id, bank_tag);
|
||||
}
|
||||
} else {
|
||||
m_id_allocator.free_id(bank_id);
|
||||
throw std::runtime_error("Unknown bank ID, bad file?");
|
||||
}
|
||||
|
||||
m_soundbanks.emplace(bank_id, std::move(bank));
|
||||
|
||||
if (attr.num_chunks >= 2) {
|
||||
in.seekg(origin + attr.where[chunk::samples].offset, std::fstream::beg);
|
||||
auto samples = std::make_unique<u8[]>(attr.where[chunk::samples].size);
|
||||
in.read((char*)samples.get(), attr.where[chunk::samples].size);
|
||||
load_samples(bank_id, std::move(samples));
|
||||
}
|
||||
|
||||
if (attr.num_chunks >= 3) {
|
||||
in.seekg(origin + attr.where[chunk::midi].offset, std::fstream::beg);
|
||||
load_midi(in);
|
||||
}
|
||||
|
||||
return bank_id;
|
||||
inline static constexpr u32 fourcc(std::string_view p) {
|
||||
return p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
|
||||
}
|
||||
|
||||
void loader::load_midi(std::fstream& in) {
|
||||
FileAttributes<1> attr;
|
||||
u32 cur = in.tellg();
|
||||
void FileAttributes::Read(BinaryReader& data) {
|
||||
type = data.read<u32>();
|
||||
num_chunks = data.read<u32>();
|
||||
|
||||
in.read((char*)&attr, sizeof(attr));
|
||||
in.seekg(cur + attr.where[0].offset, std::fstream::beg);
|
||||
|
||||
auto midi = std::make_unique<u8[]>(attr.where[0].size);
|
||||
in.read((char*)midi.get(), attr.where[0].size);
|
||||
|
||||
auto h = (MIDIBlock*)midi.get();
|
||||
lg::info("Loaded midi {:.4}", (char*)&h->ID);
|
||||
|
||||
m_midi.emplace(h->ID, (MIDIBlock*)midi.get());
|
||||
m_midi_chunks.emplace_back(std::move(midi));
|
||||
where.resize(num_chunks);
|
||||
for (int i = 0; i < num_chunks; i++) {
|
||||
where[i].offset = data.read<u32>();
|
||||
where[i].size = data.read<u32>();
|
||||
}
|
||||
}
|
||||
|
||||
SoundBank* loader::get_bank_by_handle(u32 id) {
|
||||
if (m_soundbanks.find(id) == m_soundbanks.end()) {
|
||||
static Tone ReadTone(BinaryReader& data, u8* samples) {
|
||||
Tone tone{};
|
||||
|
||||
tone.Priority = data.read<s8>();
|
||||
tone.Vol = data.read<s8>();
|
||||
tone.CenterNote = data.read<s8>();
|
||||
tone.CenterFine = data.read<s8>();
|
||||
tone.Pan = data.read<s16>();
|
||||
tone.MapLow = data.read<s8>();
|
||||
tone.MapHigh = data.read<s8>();
|
||||
tone.PBLow = data.read<s8>();
|
||||
tone.PBHigh = data.read<s8>();
|
||||
tone.ADSR1 = data.read<u16>();
|
||||
tone.ADSR2 = data.read<u16>();
|
||||
tone.Flags = data.read<u16>();
|
||||
u32 SampleOffset = data.read<u32>();
|
||||
tone.Sample = &samples[SampleOffset];
|
||||
|
||||
data.read<u32>(); // reserved1
|
||||
|
||||
return tone;
|
||||
};
|
||||
|
||||
static Midi ReadMidi(BinaryReader& data) {
|
||||
Midi mid;
|
||||
u8* base = const_cast<u8*>(data.here());
|
||||
|
||||
mid.DataID = data.read<u32>();
|
||||
mid.Version = data.read<s16>();
|
||||
mid.Flags = data.read<s8>();
|
||||
data.read<s8>();
|
||||
mid.ID = data.read<u32>();
|
||||
data.read<u32>();
|
||||
mid.BankID = data.read<u32>();
|
||||
data.read<u32>();
|
||||
u32 DataStart = data.read<u32>();
|
||||
mid.DataStart = base + DataStart;
|
||||
data.read<u32>();
|
||||
mid.Tempo = data.read<u32>();
|
||||
mid.PPQ = data.read<s32>();
|
||||
|
||||
return mid;
|
||||
}
|
||||
|
||||
static MultiMidi ReadMultiMidi(BinaryReader& data) {
|
||||
MultiMidi mmid;
|
||||
|
||||
mmid.DataID = data.read<u32>();
|
||||
mmid.Version = data.read<s16>();
|
||||
mmid.Flags = data.read<s8>();
|
||||
s8 NumSegments = data.read<s8>();
|
||||
mmid.midi.resize(NumSegments);
|
||||
mmid.ID = data.read<u32>();
|
||||
data.read<u32>();
|
||||
|
||||
for (auto& midi : mmid.midi) {
|
||||
u32 offset = data.read<u32>();
|
||||
auto mr = data.at(offset);
|
||||
midi.Midi::operator=(ReadMidi(mr));
|
||||
midi.SoundHandle = mr.read<u32>();
|
||||
}
|
||||
|
||||
return mmid;
|
||||
}
|
||||
|
||||
static Grain ReadGrainV1(BinaryReader& data, u8* samples) {
|
||||
Grain grain{};
|
||||
|
||||
u32 pos = data.get_seek();
|
||||
|
||||
grain.Type = static_cast<GrainType>(data.read<u32>());
|
||||
grain.Delay = data.read<s32>();
|
||||
|
||||
switch (grain.Type) {
|
||||
case GrainType::TONE:
|
||||
case GrainType::TONE2: {
|
||||
grain.data = ReadTone(data, samples);
|
||||
} break;
|
||||
case GrainType::LFO_SETTINGS: {
|
||||
grain.data = data.read<LFOParams>();
|
||||
} break;
|
||||
case GrainType::BRANCH:
|
||||
case GrainType::STARTCHILDSOUND:
|
||||
case GrainType::STOPCHILDSOUND:
|
||||
grain.data = data.read<PlaySoundParams>();
|
||||
break;
|
||||
case GrainType::PLUGIN_MESSAGE:
|
||||
grain.data = data.read<PluginParams>();
|
||||
break;
|
||||
case GrainType::RAND_DELAY:
|
||||
grain.data = data.read<RandDelayParams>();
|
||||
break;
|
||||
default:
|
||||
grain.data = data.read<ControlParams>();
|
||||
break;
|
||||
}
|
||||
|
||||
data.set_seek(pos);
|
||||
data.ffwd(0x28);
|
||||
|
||||
return grain;
|
||||
};
|
||||
|
||||
static Grain ReadGrainV2(BinaryReader& data, BinaryReader grainData, u8* samples) {
|
||||
union OpcodeData {
|
||||
struct {
|
||||
s8 arg[3];
|
||||
u8 type;
|
||||
};
|
||||
|
||||
u32 Opcode;
|
||||
} op;
|
||||
|
||||
Grain grain{};
|
||||
|
||||
op = data.read<OpcodeData>();
|
||||
grain.Type = static_cast<GrainType>(op.type);
|
||||
grain.Delay = data.read<s32>();
|
||||
|
||||
u32 value = op.Opcode & 0xFFFFFF;
|
||||
|
||||
switch (grain.Type) {
|
||||
case GrainType::TONE:
|
||||
case GrainType::TONE2: {
|
||||
grainData.set_seek(value);
|
||||
grain.data = ReadTone(grainData, samples);
|
||||
} break;
|
||||
case GrainType::LFO_SETTINGS: {
|
||||
grainData.set_seek(value);
|
||||
grain.data = grainData.read<LFOParams>();
|
||||
} break;
|
||||
case GrainType::BRANCH:
|
||||
case GrainType::STARTCHILDSOUND:
|
||||
case GrainType::STOPCHILDSOUND:
|
||||
grainData.set_seek(value);
|
||||
grain.data = grainData.read<PlaySoundParams>();
|
||||
break;
|
||||
case GrainType::PLUGIN_MESSAGE:
|
||||
grainData.set_seek(value);
|
||||
grain.data = grainData.read<PluginParams>();
|
||||
break;
|
||||
case GrainType::RAND_DELAY:
|
||||
RandDelayParams rp;
|
||||
rp.Amount = (s32)value + 1;
|
||||
grain.data = rp;
|
||||
break;
|
||||
default:
|
||||
ControlParams p;
|
||||
p.param[0] = op.arg[0];
|
||||
p.param[1] = op.arg[1];
|
||||
p.param[2] = op.arg[2];
|
||||
grain.data = p;
|
||||
break;
|
||||
}
|
||||
|
||||
return grain;
|
||||
};
|
||||
|
||||
SFXBlock* SFXBlock::ReadBlock(nonstd::span<u8> bank_data, nonstd::span<u8> samples) {
|
||||
BinaryReader data(bank_data);
|
||||
// auto block = std::make_unique<SFXBlock>();
|
||||
auto block = new SFXBlock();
|
||||
block->DataID = data.read<u32>();
|
||||
if (block->DataID != fourcc("SBlk")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_soundbanks[id].get();
|
||||
}
|
||||
block->SampleData = std::make_unique<u8[]>(samples.size());
|
||||
std::copy(samples.begin(), samples.end(), block->SampleData.get());
|
||||
|
||||
MusicBank* loader::get_bank_by_id(u32 id) {
|
||||
for (auto& b : m_soundbanks) {
|
||||
if (b.second->type == BankType::Music) {
|
||||
auto* bank = static_cast<MusicBank*>(b.second.get());
|
||||
if (bank->bank_name == id) {
|
||||
return bank;
|
||||
block->Version = data.read<u32>();
|
||||
block->Flags.flags = data.read<u32>();
|
||||
block->BankID = data.read<u32>();
|
||||
block->BankNum = data.read<s8>();
|
||||
|
||||
// discard padding
|
||||
data.read<s8>();
|
||||
data.read<s16>();
|
||||
data.read<s16>();
|
||||
|
||||
s16 NumSounds = data.read<s16>();
|
||||
block->Sounds.resize(NumSounds);
|
||||
s16 NumGrains = data.read<s16>();
|
||||
s16 NumVAGs = data.read<s16>();
|
||||
|
||||
u32 FirstSound = data.read<u32>();
|
||||
u32 FirstGrain = data.read<u32>();
|
||||
|
||||
u32 VagsInSR = data.read<u32>();
|
||||
u32 VagDataSize = data.read<u32>();
|
||||
u32 SRAMAllocSize = data.read<u32>();
|
||||
u32 NextBlock = data.read<u32>();
|
||||
u32 GrainData = 0;
|
||||
if (block->Version >= 2) {
|
||||
GrainData = data.read<u32>();
|
||||
}
|
||||
u32 BlockNames = data.read<u32>();
|
||||
u32 SFXUD = data.read<u32>();
|
||||
|
||||
data.set_seek(FirstSound);
|
||||
for (auto& sfx : block->Sounds) {
|
||||
sfx.Vol = data.read<s8>();
|
||||
sfx.VolGroup = data.read<s8>();
|
||||
sfx.Pan = data.read<s16>();
|
||||
|
||||
s8 NumGrains = data.read<s8>();
|
||||
sfx.Grains.resize(NumGrains);
|
||||
|
||||
sfx.InstanceLimit = data.read<s8>();
|
||||
sfx.Flags.flags = data.read<u16>();
|
||||
|
||||
u32 FirstSFXGrain = data.read<u32>();
|
||||
if (NumGrains) {
|
||||
auto grains = data.at(FirstGrain + FirstSFXGrain);
|
||||
for (auto& grain : sfx.Grains) {
|
||||
if (block->Version < 2) {
|
||||
grain = ReadGrainV1(grains, block->SampleData.get());
|
||||
} else {
|
||||
grain = ReadGrainV2(grains, data.at(GrainData), block->SampleData.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (block->Flags.hasNames()) {
|
||||
struct SFXBlockNames { // 0x98
|
||||
/* 0x00 */ u32 BlockName[2];
|
||||
/* 0x08 */ u32 SFXNameTableOffset;
|
||||
/* 0x0c */ u32 VAGNameTableOffset;
|
||||
/* 0x10 */ u32 VAGImportsTableOffset;
|
||||
/* 0x14 */ u32 VAGExportsTableOffset;
|
||||
/* 0x18 */ s16 SFXHashOffsets[32];
|
||||
/* 0x58 */ s16 VAGHashOffsets[32];
|
||||
};
|
||||
|
||||
struct SFXName { // 0x14
|
||||
/* 0x00 */ u32 Name[4];
|
||||
/* 0x10 */ s16 Index;
|
||||
/* 0x12 */ s16 reserved;
|
||||
};
|
||||
|
||||
data.set_seek(BlockNames);
|
||||
auto names = data.read<SFXBlockNames>();
|
||||
|
||||
char buf[17];
|
||||
buf[16] = 0;
|
||||
strncpy(buf, (char*)names.BlockName, 8);
|
||||
block->Name = buf;
|
||||
|
||||
data.set_seek(BlockNames + names.SFXNameTableOffset);
|
||||
|
||||
auto name_table = (SFXName*)(data.here());
|
||||
for (auto SFXHashOffset : names.SFXHashOffsets) {
|
||||
auto name = &name_table[SFXHashOffset];
|
||||
while (name->Name[0] != 0) {
|
||||
strncpy(buf, (char*)name->Name, 16);
|
||||
|
||||
std::string str(buf);
|
||||
if (block->Names.find(str) == block->Names.end()) {
|
||||
block->Names[str] = name->Index;
|
||||
}
|
||||
|
||||
name++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (block->Flags.hasUserdata()) {
|
||||
data.set_seek(SFXUD);
|
||||
for (auto& sfx : block->Sounds) {
|
||||
sfx.UserData.data[0] = data.read<u32>();
|
||||
sfx.UserData.data[1] = data.read<u32>();
|
||||
sfx.UserData.data[2] = data.read<u32>();
|
||||
sfx.UserData.data[3] = data.read<u32>();
|
||||
}
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
MusicBank* MusicBank::ReadBank(nonstd::span<u8> bank_data,
|
||||
nonstd::span<u8> samples,
|
||||
nonstd::span<u8> midi_data) {
|
||||
BinaryReader data(bank_data);
|
||||
// auto bank = std::make_unique<MusicBank>();
|
||||
auto bank = new MusicBank();
|
||||
|
||||
bank->DataID = data.read<u32>();
|
||||
if (bank->DataID != fourcc("SBv2")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bank->SampleData = std::make_unique<u8[]>(samples.size_bytes());
|
||||
std::copy(samples.begin(), samples.end(), bank->SampleData.get());
|
||||
|
||||
bank->SeqData = std::make_unique<u8[]>(midi_data.size_bytes());
|
||||
std::copy(midi_data.begin(), midi_data.end(), bank->SeqData.get());
|
||||
|
||||
bank->Version = data.read<u32>();
|
||||
bank->Flags.flags = data.read<u32>();
|
||||
bank->BankID = data.read<u32>();
|
||||
bank->BankNum = data.read<s8>();
|
||||
|
||||
// discard padding
|
||||
data.read<s8>();
|
||||
data.read<s16>();
|
||||
|
||||
s16 NumSounds = data.read<s16>();
|
||||
bank->Sounds.resize(NumSounds);
|
||||
s16 NumProgs = data.read<s16>();
|
||||
bank->Progs.resize(NumProgs);
|
||||
s16 NumTones = data.read<s16>();
|
||||
s16 NumVAGs = data.read<s16>();
|
||||
|
||||
u32 FirstSound = data.read<u32>();
|
||||
u32 FirstProg = data.read<u32>();
|
||||
u32 FirstTone = data.read<u32>();
|
||||
|
||||
// vagsinsr
|
||||
data.read<u32>();
|
||||
// vagdatasize
|
||||
data.read<u32>();
|
||||
|
||||
data.set_seek(FirstSound);
|
||||
for (auto& sound : bank->Sounds) {
|
||||
sound.Type = data.read<s32>();
|
||||
data.read<u32>(); // bankptr
|
||||
data.read<u32>(); // ogbankptr
|
||||
sound.MIDIID = data.read<s32>();
|
||||
sound.Vol = data.read<s16>();
|
||||
sound.Repeats = data.read<s8>();
|
||||
sound.VolGroup = data.read<s8>();
|
||||
sound.Pan = data.read<s16>();
|
||||
sound.Index = data.read<s8>();
|
||||
sound.Flags = data.read<u8>();
|
||||
data.read<u32>(); // midiblockptr
|
||||
|
||||
sound.Bank = bank;
|
||||
sound.OrigBank = bank;
|
||||
}
|
||||
|
||||
data.set_seek(FirstProg);
|
||||
for (auto& prog : bank->Progs) {
|
||||
s8 NumTones = data.read<s8>();
|
||||
prog.Vol = data.read<s8>();
|
||||
prog.Pan = data.read<s16>();
|
||||
u32 FirstTone = data.read<u32>();
|
||||
prog.Tones.resize(NumTones);
|
||||
|
||||
auto tones = data.at(FirstTone);
|
||||
for (auto& tone : prog.Tones) {
|
||||
tone = ReadTone(tones, bank->SampleData.get());
|
||||
}
|
||||
}
|
||||
|
||||
auto seq_buf = nonstd::span<u8>(bank->SeqData.get(), midi_data.size_bytes());
|
||||
BinaryReader seq_data(seq_buf);
|
||||
FileAttributes fa;
|
||||
fa.Read(seq_data);
|
||||
|
||||
BinaryReader midi(seq_buf.subspan(fa.where[0].offset));
|
||||
u32 id = midi.read<u32>();
|
||||
midi.set_seek(0);
|
||||
if (id == fourcc("MID ")) {
|
||||
bank->MidiData = ReadMidi(midi);
|
||||
} else if (id == fourcc("MMID")) {
|
||||
bank->MidiData = ReadMultiMidi(midi);
|
||||
} else {
|
||||
lg::error("Invalid midi\n");
|
||||
}
|
||||
|
||||
return bank;
|
||||
}
|
||||
|
||||
BankHandle Loader::BankLoad(nonstd::span<u8> bank) {
|
||||
BinaryReader reader(bank);
|
||||
FileAttributes fa;
|
||||
fa.Read(reader);
|
||||
|
||||
if (fa.type != 1 && fa.type != 3) {
|
||||
fmt::print("bad file type\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
reader.set_seek(fa.where[0].offset);
|
||||
u32 fourcc = reader.read<u32>();
|
||||
nonstd::span<u8> bank_data(nonstd::span<u8>(bank).subspan(fa.where[0].offset, fa.where[0].size));
|
||||
nonstd::span<u8> sample_data(
|
||||
nonstd::span<u8>(bank).subspan(fa.where[1].offset, fa.where[1].size));
|
||||
|
||||
if (fourcc == snd::fourcc("SBv2")) {
|
||||
if (fa.num_chunks != 3) {
|
||||
fmt::print("SBv2 without midi data not supported\n");
|
||||
return 0;
|
||||
}
|
||||
nonstd::span<u8> midi_data(
|
||||
nonstd::span<u8>(bank).subspan(fa.where[2].offset, fa.where[2].size));
|
||||
|
||||
auto bank = MusicBank::ReadBank(bank_data, sample_data, midi_data);
|
||||
mBanks.emplace_back(bank);
|
||||
|
||||
return bank;
|
||||
} else if (fourcc == snd::fourcc("SBlk")) {
|
||||
auto block = SFXBlock::ReadBlock(bank_data, sample_data);
|
||||
mBanks.emplace_back(block);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SoundBank* loader::get_bank_by_name(const char* name) {
|
||||
for (auto& b : m_soundbanks) {
|
||||
auto bankname = b.second->get_name();
|
||||
SoundBank* Loader::GetBankByHandle(BankHandle handle) {
|
||||
auto bank = std::find_if(mBanks.begin(), mBanks.end(),
|
||||
[handle](auto& bank) { return bank.get() == handle; });
|
||||
if (bank == mBanks.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return bank->get();
|
||||
}
|
||||
|
||||
SoundBank* Loader::GetBankByName(const char* name) {
|
||||
for (auto& b : mBanks) {
|
||||
auto bankname = b->GetName();
|
||||
if (bankname.has_value()) {
|
||||
if (bankname->compare(name) == 0) {
|
||||
return b.second.get();
|
||||
return b.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,45 +468,23 @@ SoundBank* loader::get_bank_by_name(const char* name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SoundBank* loader::get_bank_with_sound(const char* name) {
|
||||
for (auto& b : m_soundbanks) {
|
||||
auto sound = b.second->get_sound_by_name(name);
|
||||
SoundBank* Loader::GetBankWithSound(const char* name) {
|
||||
for (auto& b : mBanks) {
|
||||
auto sound = b->GetSoundByName(name);
|
||||
if (sound.has_value()) {
|
||||
return b.second.get();
|
||||
return b.get();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MIDIBlock* loader::get_midi(u32 id) {
|
||||
return m_midi.at(id);
|
||||
}
|
||||
|
||||
u8* loader::get_bank_samples(u32 id) {
|
||||
return m_soundbanks.at(id).get()->sampleBuf.get();
|
||||
}
|
||||
|
||||
void loader::load_samples(u32 bank_id, std::unique_ptr<u8[]> samples) {
|
||||
auto& bank = m_soundbanks.at(bank_id);
|
||||
bank->sampleBuf = std::move(samples);
|
||||
}
|
||||
|
||||
void loader::unload_bank(u32 id) {
|
||||
fmt::print("Deleting bank {}\n", id);
|
||||
for (auto it = m_midi_chunks.begin(); it != m_midi_chunks.end();) {
|
||||
bool del = false;
|
||||
// FIXME delete midi
|
||||
|
||||
if (del) {
|
||||
it = m_midi_chunks.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
void Loader::UnloadBank(BankHandle handle) {
|
||||
auto bank = std::find_if(mBanks.begin(), mBanks.end(),
|
||||
[handle](auto& bank) { return bank.get() == handle; });
|
||||
if (bank != mBanks.end()) {
|
||||
mBanks.erase(bank);
|
||||
}
|
||||
|
||||
m_soundbanks.erase(id);
|
||||
m_id_allocator.free_id(id);
|
||||
}
|
||||
|
||||
} // namespace snd
|
||||
+21
-38
@@ -5,58 +5,41 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "handle_allocator.h"
|
||||
#include "musicbank.h"
|
||||
#include "sfxblock.h"
|
||||
#include "sound_handler.h"
|
||||
#include "soundbank.h"
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/BinaryReader.h"
|
||||
|
||||
#include "../common/synth.h"
|
||||
#include "third-party/span.hpp"
|
||||
|
||||
namespace snd {
|
||||
|
||||
#define FOURCC(a, b, c, d) ((u32)(((d) << 24) | ((c) << 16) | ((b) << 8) | (a)))
|
||||
struct LocAndSize {
|
||||
/* 0 */ u32 offset;
|
||||
/* 4 */ u32 size;
|
||||
};
|
||||
using BankHandle = SoundBank*;
|
||||
|
||||
template <size_t chunks>
|
||||
struct FileAttributes {
|
||||
/* 0 */ u32 type;
|
||||
/* 4 */ u32 num_chunks;
|
||||
/* 8 */ LocAndSize where[chunks];
|
||||
};
|
||||
|
||||
class loader : public locator {
|
||||
class FileAttributes {
|
||||
public:
|
||||
SoundBank* get_bank_by_handle(u32 id) override;
|
||||
MusicBank* get_bank_by_id(u32 id) override;
|
||||
MIDIBlock* get_midi(u32 id) override;
|
||||
u8* get_bank_samples(u32 id) override;
|
||||
struct LocAndSize {
|
||||
u32 offset;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
SoundBank* get_bank_by_name(const char* name);
|
||||
SoundBank* get_bank_with_sound(const char* name);
|
||||
u32 type;
|
||||
u32 num_chunks;
|
||||
std::vector<LocAndSize> where;
|
||||
void Read(BinaryReader& data);
|
||||
};
|
||||
|
||||
void unload_bank(u32 id);
|
||||
class Loader {
|
||||
public:
|
||||
SoundBank* GetBankByHandle(BankHandle id);
|
||||
SoundBank* GetBankByName(const char* name);
|
||||
SoundBank* GetBankWithSound(const char* name);
|
||||
|
||||
u32 read_bank(std::fstream& in);
|
||||
void load_midi(std::fstream& in);
|
||||
void UnloadBank(BankHandle id);
|
||||
|
||||
bool read_midi();
|
||||
BankHandle BankLoad(nonstd::span<u8> bank);
|
||||
|
||||
private:
|
||||
void load_samples(u32 bank, std::unique_ptr<u8[]> samples);
|
||||
|
||||
id_allocator m_id_allocator;
|
||||
std::unordered_map<u32, std::unique_ptr<SoundBank>> m_soundbanks;
|
||||
|
||||
std::vector<std::unique_ptr<u8[]>> m_midi_chunks;
|
||||
|
||||
std::unordered_map<u32, MIDIBlock*> m_midi;
|
||||
|
||||
u32 m_next_id{0};
|
||||
std::vector<std::unique_ptr<SoundBank>> mBanks;
|
||||
};
|
||||
} // namespace snd
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace snd {
|
||||
|
||||
class MusicBank;
|
||||
class SoundBank;
|
||||
struct MIDIBlock;
|
||||
|
||||
class locator {
|
||||
public:
|
||||
virtual ~locator() = default;
|
||||
virtual SoundBank* get_bank_by_handle(u32 id) = 0;
|
||||
virtual MusicBank* get_bank_by_id(u32 id) = 0;
|
||||
virtual u8* get_bank_samples(u32 id) = 0;
|
||||
virtual MIDIBlock* get_midi(u32 id) = 0;
|
||||
};
|
||||
} // namespace snd
|
||||
@@ -22,19 +22,13 @@ namespace snd {
|
||||
**
|
||||
*/
|
||||
|
||||
midi_handler::midi_handler(MIDIBlockHeader* block,
|
||||
voice_manager& vm,
|
||||
MIDISound& sound,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
locator& loc,
|
||||
SoundBank& bank)
|
||||
: m_sound(sound),
|
||||
m_locator(loc),
|
||||
m_repeats(sound.Repeats),
|
||||
m_bank(bank),
|
||||
m_header(block),
|
||||
m_vm(vm) {
|
||||
MidiHandler::MidiHandler(Midi* block,
|
||||
VoiceManager& vm,
|
||||
MusicBank::MIDISound& sound,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SoundBank& bank)
|
||||
: m_sound(sound), m_repeats(sound.Repeats), m_bank(bank), m_header(block), m_vm(vm) {
|
||||
if (vol == VOLUME_DONT_CHANGE) {
|
||||
vol = 1024;
|
||||
}
|
||||
@@ -50,31 +44,29 @@ midi_handler::midi_handler(MIDIBlockHeader* block,
|
||||
m_pan = pan;
|
||||
}
|
||||
|
||||
init_midi();
|
||||
InitMidi();
|
||||
}
|
||||
|
||||
midi_handler::midi_handler(MIDIBlockHeader* block,
|
||||
voice_manager& vm,
|
||||
MIDISound& sound,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
locator& loc,
|
||||
SoundBank& bank,
|
||||
std::optional<ame_handler*> parent)
|
||||
MidiHandler::MidiHandler(Midi* block,
|
||||
VoiceManager& vm,
|
||||
MusicBank::MIDISound& sound,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SoundBank& bank,
|
||||
std::optional<AmeHandler*> parent)
|
||||
: m_parent(parent),
|
||||
m_sound(sound),
|
||||
m_locator(loc),
|
||||
m_vol(vol),
|
||||
m_pan(pan),
|
||||
m_repeats(sound.Repeats),
|
||||
m_bank(bank),
|
||||
m_header(block),
|
||||
m_vm(vm) {
|
||||
init_midi();
|
||||
InitMidi();
|
||||
}
|
||||
|
||||
void midi_handler::init_midi() {
|
||||
m_seq_data_start = (u8*)((uintptr_t)m_header + (uintptr_t)m_header->DataStart);
|
||||
void MidiHandler::InitMidi() {
|
||||
m_seq_data_start = m_header->DataStart;
|
||||
m_seq_ptr = m_seq_data_start;
|
||||
m_tempo = m_header->Tempo;
|
||||
m_ppq = m_header->PPQ;
|
||||
@@ -82,7 +74,7 @@ void midi_handler::init_midi() {
|
||||
m_chanpan.fill(0);
|
||||
}
|
||||
|
||||
std::pair<size_t, u32> midi_handler::read_vlq(u8* value) {
|
||||
std::pair<size_t, u32> MidiHandler::ReadVLQ(u8* value) {
|
||||
size_t len = 1;
|
||||
u32 out = *value & 0x7f;
|
||||
// fmt::print("starting with {:x}\n", *value);
|
||||
@@ -98,7 +90,7 @@ std::pair<size_t, u32> midi_handler::read_vlq(u8* value) {
|
||||
return {len, out};
|
||||
}
|
||||
|
||||
void midi_handler::pause() {
|
||||
void MidiHandler::Pause() {
|
||||
m_paused = true;
|
||||
|
||||
for (auto& p : m_voices) {
|
||||
@@ -107,11 +99,11 @@ void midi_handler::pause() {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_vm.pause(voice);
|
||||
m_vm.Pause(voice);
|
||||
}
|
||||
}
|
||||
|
||||
void midi_handler::unpause() {
|
||||
void MidiHandler::Unpause() {
|
||||
m_paused = false;
|
||||
|
||||
for (auto& p : m_voices) {
|
||||
@@ -120,11 +112,11 @@ void midi_handler::unpause() {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_vm.unpause(voice);
|
||||
m_vm.Unpause(voice);
|
||||
}
|
||||
}
|
||||
|
||||
void midi_handler::stop() {
|
||||
void MidiHandler::Stop() {
|
||||
m_track_complete = true;
|
||||
|
||||
for (auto& p : m_voices) {
|
||||
@@ -133,11 +125,11 @@ void midi_handler::stop() {
|
||||
continue;
|
||||
}
|
||||
|
||||
voice->key_off();
|
||||
voice->KeyOff();
|
||||
}
|
||||
}
|
||||
|
||||
void midi_handler::set_vol_pan(s32 vol, s32 pan) {
|
||||
void MidiHandler::SetVolPan(s32 vol, s32 pan) {
|
||||
if (vol != VOLUME_DONT_CHANGE) {
|
||||
if (vol >= 0) {
|
||||
m_vol = (m_sound.Vol * vol) >> 10;
|
||||
@@ -170,16 +162,16 @@ void midi_handler::set_vol_pan(s32 vol, s32 pan) {
|
||||
}
|
||||
|
||||
voice->basevol =
|
||||
m_vm.make_volume_b(m_vol, voice->velocity * m_chanvol[voice->channel] / 127, pan,
|
||||
voice->prog.Vol, voice->prog.Pan, voice->tone.Vol, voice->tone.Pan);
|
||||
m_vm.MakeVolumeB(m_vol, voice->velocity * m_chanvol[voice->channel] / 127, pan,
|
||||
voice->prog.Vol, voice->prog.Pan, voice->tone.Vol, voice->tone.Pan);
|
||||
|
||||
auto left = m_vm.adjust_vol_to_group(voice->basevol.left, voice->group);
|
||||
auto right = m_vm.adjust_vol_to_group(voice->basevol.right, voice->group);
|
||||
voice->set_volume(left >> 1, right >> 1);
|
||||
auto left = m_vm.AdjustVolToGroup(voice->basevol.left, voice->group);
|
||||
auto right = m_vm.AdjustVolToGroup(voice->basevol.right, voice->group);
|
||||
voice->SetVolume(left >> 1, right >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
void midi_handler::set_pmod(s32 mod) {
|
||||
void MidiHandler::SetPMod(s32 mod) {
|
||||
m_cur_pm = mod;
|
||||
|
||||
for (auto& v : m_voices) {
|
||||
@@ -189,31 +181,31 @@ void midi_handler::set_pmod(s32 mod) {
|
||||
}
|
||||
|
||||
voice->current_pm = m_cur_pm;
|
||||
auto note = pitchbend(voice->tone, voice->current_pb, voice->current_pm, voice->start_note,
|
||||
auto note = PitchBend(voice->tone, voice->current_pb, voice->current_pm, voice->start_note,
|
||||
voice->start_fine);
|
||||
auto pitch =
|
||||
PS1Note2Pitch(voice->tone.CenterNote, voice->tone.CenterFine, note.first, note.second);
|
||||
voice->set_pitch(pitch);
|
||||
voice->SetPitch(pitch);
|
||||
}
|
||||
}
|
||||
|
||||
void midi_handler::mute_channel(u8 channel) {
|
||||
void MidiHandler::MuteChannel(u8 channel) {
|
||||
// fmt::print("{:x} ame muting channel {}\n", (u64)this, channel);
|
||||
m_mute_state[channel] = true;
|
||||
}
|
||||
|
||||
void midi_handler::unmute_channel(u8 channel) {
|
||||
void MidiHandler::UnmuteChannel(u8 channel) {
|
||||
// fmt::print("{:x} ame unmuting channel {}\n", (u64)this, channel);
|
||||
m_mute_state[channel] = false;
|
||||
}
|
||||
|
||||
void midi_handler::note_on() {
|
||||
void MidiHandler::NoteOn() {
|
||||
u8 channel = m_status & 0xf;
|
||||
u8 note = m_seq_ptr[0];
|
||||
u8 velocity = m_seq_ptr[1];
|
||||
|
||||
if (velocity == 0) {
|
||||
note_off();
|
||||
NoteOff();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -226,19 +218,21 @@ void midi_handler::note_on() {
|
||||
// velocity);
|
||||
|
||||
// Key on all the applicable tones for the program
|
||||
auto bank = dynamic_cast<MusicBank*>(m_locator.get_bank_by_id(m_header->BankID));
|
||||
auto& program = bank->m_programs[m_programs[channel]];
|
||||
// FIXME bank from midi
|
||||
// auto bank = dynamic_cast<MusicBank*>(m_locator.get_bank_by_id(m_header->BankID));
|
||||
auto bank = static_cast<MusicBank*>(&m_bank);
|
||||
auto& program = bank->Progs[m_programs[channel]];
|
||||
|
||||
for (auto& t : program.tones) {
|
||||
for (auto& t : program.Tones) {
|
||||
if (note >= t.MapLow && note <= t.MapHigh) {
|
||||
s16 pan = m_chanpan[channel] + m_pan;
|
||||
if (pan >= 360) {
|
||||
pan -= 360;
|
||||
}
|
||||
|
||||
auto voice = std::make_shared<midi_voice>(t, program.d);
|
||||
voice->basevol = m_vm.make_volume_b(m_vol, (velocity * m_chanvol[channel]) / 0x7f, pan,
|
||||
program.d.Vol, program.d.Pan, t.Vol, t.Pan);
|
||||
auto voice = std::make_shared<midi_voice>(t, program);
|
||||
voice->basevol = m_vm.MakeVolumeB(m_vol, (velocity * m_chanvol[channel]) / 0x7f, pan,
|
||||
program.Vol, program.Pan, t.Vol, t.Pan);
|
||||
|
||||
voice->note = note;
|
||||
voice->channel = channel;
|
||||
@@ -251,7 +245,7 @@ void midi_handler::note_on() {
|
||||
voice->current_pb = m_cur_pm;
|
||||
|
||||
voice->group = m_sound.VolGroup;
|
||||
m_vm.start_tone(voice, m_bank.bank_id);
|
||||
m_vm.StartTone(voice);
|
||||
m_voices.emplace_front(voice);
|
||||
}
|
||||
}
|
||||
@@ -259,7 +253,7 @@ void midi_handler::note_on() {
|
||||
m_seq_ptr += 2;
|
||||
}
|
||||
|
||||
void midi_handler::note_off() {
|
||||
void MidiHandler::NoteOff() {
|
||||
u8 channel = m_status & 0xf;
|
||||
u8 note = m_seq_ptr[0];
|
||||
// Yep, no velocity for note-offs
|
||||
@@ -275,14 +269,14 @@ void midi_handler::note_off() {
|
||||
}
|
||||
|
||||
if (voice->channel == channel && voice->note == note) {
|
||||
voice->key_off();
|
||||
voice->KeyOff();
|
||||
}
|
||||
}
|
||||
|
||||
m_seq_ptr += 2;
|
||||
}
|
||||
|
||||
void midi_handler::program_change() {
|
||||
void MidiHandler::ProgramChange() {
|
||||
u8 channel = m_status & 0xf;
|
||||
u8 program = m_seq_ptr[0];
|
||||
|
||||
@@ -293,7 +287,7 @@ void midi_handler::program_change() {
|
||||
m_seq_ptr += 1;
|
||||
}
|
||||
|
||||
void midi_handler::channel_pressure() {
|
||||
void MidiHandler::ChannelPressure() {
|
||||
u8 channel = m_status & 0xf;
|
||||
u8 note = m_seq_ptr[0];
|
||||
// fmt::print("{}: channel pressure {:02x} {:02x}\n", m_time, m_status, m_seq_ptr[0]);
|
||||
@@ -305,14 +299,14 @@ void midi_handler::channel_pressure() {
|
||||
}
|
||||
|
||||
if (voice->channel == channel && voice->note == note) {
|
||||
voice->key_off();
|
||||
voice->KeyOff();
|
||||
}
|
||||
}
|
||||
|
||||
m_seq_ptr += 1;
|
||||
}
|
||||
|
||||
void midi_handler::channel_pitch() {
|
||||
void MidiHandler::ChannelPitch() {
|
||||
u8 channel = m_status & 0xF;
|
||||
s32 pitch = 0xFFFF * ((m_seq_ptr[0] & 0x7f) | ((m_seq_ptr[1] & 0x7f) << 7)) / 0x3FFF;
|
||||
// lg::debug("{}: pitch ch{:01x} {:04x}", m_time, channel, pitch);
|
||||
@@ -326,18 +320,18 @@ void midi_handler::channel_pitch() {
|
||||
|
||||
if (voice->channel == channel) {
|
||||
voice->current_pb = m_pitch_bend[channel];
|
||||
auto note = pitchbend(voice->tone, voice->current_pb, voice->current_pm, voice->start_note,
|
||||
auto note = PitchBend(voice->tone, voice->current_pb, voice->current_pm, voice->start_note,
|
||||
voice->start_fine);
|
||||
auto pitch =
|
||||
PS1Note2Pitch(voice->tone.CenterNote, voice->tone.CenterFine, note.first, note.second);
|
||||
voice->set_pitch(pitch);
|
||||
voice->SetPitch(pitch);
|
||||
}
|
||||
}
|
||||
|
||||
m_seq_ptr += 2;
|
||||
}
|
||||
|
||||
void midi_handler::meta_event() {
|
||||
void MidiHandler::MetaEvent() {
|
||||
// fmt::print("{}: meta event {:02x}\n", m_time, *m_seq_ptr);
|
||||
size_t len = m_seq_ptr[1];
|
||||
|
||||
@@ -373,7 +367,7 @@ static s16 midiTo360Pan(u8 pan) {
|
||||
}
|
||||
}
|
||||
|
||||
void midi_handler::controller_change() {
|
||||
void MidiHandler::ControllerChange() {
|
||||
u8 channel = m_status & 0xf;
|
||||
u8 controller = m_seq_ptr[0];
|
||||
u8 value = m_seq_ptr[1];
|
||||
@@ -388,21 +382,21 @@ void midi_handler::controller_change() {
|
||||
} break;
|
||||
// case 0x40: {} break; // TODO damper
|
||||
default:
|
||||
throw midi_error(fmt::format("invalid midi controller change {}", controller));
|
||||
throw MidiError(fmt::format("invalid midi controller change {}", controller));
|
||||
break;
|
||||
}
|
||||
|
||||
m_seq_ptr += 2;
|
||||
}
|
||||
|
||||
void midi_handler::system_event() {
|
||||
void MidiHandler::SystemEvent() {
|
||||
// fmt::print("{}: system event {:02x}\n", m_time, *m_seq_ptr);
|
||||
|
||||
switch (*m_seq_ptr) {
|
||||
case 0x75:
|
||||
m_seq_ptr++;
|
||||
if (m_parent.has_value()) {
|
||||
auto [cont, ptr] = m_parent.value()->run_ame(*this, m_seq_ptr);
|
||||
auto [cont, ptr] = m_parent.value()->RunAME(*this, m_seq_ptr);
|
||||
m_seq_ptr = ptr;
|
||||
|
||||
if (!cont) {
|
||||
@@ -410,23 +404,23 @@ void midi_handler::system_event() {
|
||||
m_track_complete = true;
|
||||
}
|
||||
} else {
|
||||
throw midi_error("MIDI tried to run AME without an AME handler");
|
||||
throw MidiError("MIDI tried to run AME without an AME handler");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw midi_error(fmt::format("Unknown system message {:02x}", *m_seq_ptr));
|
||||
throw MidiError(fmt::format("Unknown system message {:02x}", *m_seq_ptr));
|
||||
}
|
||||
}
|
||||
|
||||
bool midi_handler::tick() {
|
||||
bool MidiHandler::Tick() {
|
||||
if (m_paused) {
|
||||
return m_track_complete;
|
||||
}
|
||||
|
||||
try {
|
||||
m_voices.remove_if([](auto& v) { return v.expired(); });
|
||||
step();
|
||||
} catch (midi_error& e) {
|
||||
Step();
|
||||
} catch (MidiError& e) {
|
||||
m_track_complete = true;
|
||||
lg::error("MIDI Error: {}", e.what());
|
||||
fmt::print("Sequence following: ");
|
||||
@@ -439,8 +433,8 @@ bool midi_handler::tick() {
|
||||
return m_track_complete;
|
||||
}
|
||||
|
||||
void midi_handler::new_delta() {
|
||||
auto [len, delta] = read_vlq(m_seq_ptr);
|
||||
void MidiHandler::NewDelta() {
|
||||
auto [len, delta] = ReadVLQ(m_seq_ptr);
|
||||
|
||||
m_seq_ptr += len;
|
||||
m_time += delta;
|
||||
@@ -457,9 +451,9 @@ void midi_handler::new_delta() {
|
||||
}
|
||||
}
|
||||
|
||||
void midi_handler::step() {
|
||||
void MidiHandler::Step() {
|
||||
if (m_get_delta) {
|
||||
new_delta();
|
||||
NewDelta();
|
||||
m_get_delta = false;
|
||||
} else {
|
||||
m_tick_countdown--;
|
||||
@@ -474,40 +468,40 @@ void midi_handler::step() {
|
||||
|
||||
switch (m_status >> 4) {
|
||||
case 0x8:
|
||||
note_off();
|
||||
NoteOff();
|
||||
break;
|
||||
case 0x9:
|
||||
note_on();
|
||||
NoteOn();
|
||||
break;
|
||||
case 0xB:
|
||||
controller_change();
|
||||
ControllerChange();
|
||||
break;
|
||||
case 0xD:
|
||||
channel_pressure();
|
||||
ChannelPressure();
|
||||
break;
|
||||
case 0xC:
|
||||
program_change();
|
||||
ProgramChange();
|
||||
break;
|
||||
case 0xE:
|
||||
channel_pitch();
|
||||
ChannelPitch();
|
||||
break;
|
||||
case 0xF:
|
||||
// normal meta-event
|
||||
if (m_status == 0xFF) {
|
||||
meta_event();
|
||||
MetaEvent();
|
||||
break;
|
||||
}
|
||||
if (m_status == 0xF0) {
|
||||
system_event();
|
||||
SystemEvent();
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
throw midi_error(fmt::format("invalid status {}", m_status));
|
||||
throw MidiError(fmt::format("invalid status {}", m_status));
|
||||
return;
|
||||
}
|
||||
|
||||
new_delta();
|
||||
NewDelta();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "ame_handler.h"
|
||||
#include "loader.h"
|
||||
#include "musicbank.h"
|
||||
#include "sound_handler.h"
|
||||
#include "vagvoice.h"
|
||||
|
||||
@@ -17,87 +17,72 @@
|
||||
|
||||
namespace snd {
|
||||
|
||||
struct ProgData {
|
||||
/* 0 */ s8 NumTones;
|
||||
/* 1 */ s8 Vol;
|
||||
/* 2 */ s16 Pan;
|
||||
/* 4 */ /*Tone**/ u32 FirstTone;
|
||||
};
|
||||
|
||||
struct Prog {
|
||||
ProgData d;
|
||||
std::vector<Tone> tones;
|
||||
};
|
||||
|
||||
class midi_voice : public vag_voice {
|
||||
class midi_voice : public VagVoice {
|
||||
public:
|
||||
midi_voice(Tone& t, ProgData& prog) : vag_voice(t), prog(prog) {}
|
||||
midi_voice(Tone& t, MusicBank::Prog& _prog) : VagVoice(t), prog(_prog) {}
|
||||
u8 note{0};
|
||||
u8 channel{0};
|
||||
u8 velocity{0};
|
||||
ProgData& prog;
|
||||
MusicBank::Prog& prog;
|
||||
};
|
||||
|
||||
class ame_handler;
|
||||
class midi_handler : public sound_handler {
|
||||
class AmeHandler;
|
||||
class MidiHandler : public SoundHandler {
|
||||
public:
|
||||
midi_handler(MIDIBlockHeader* block,
|
||||
voice_manager& vm,
|
||||
MIDISound& sound,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
locator& loc,
|
||||
SoundBank& bank);
|
||||
MidiHandler(Midi* block,
|
||||
VoiceManager& vm,
|
||||
MusicBank::MIDISound& sound,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SoundBank& bank);
|
||||
|
||||
midi_handler(MIDIBlockHeader* block,
|
||||
voice_manager& vm,
|
||||
MIDISound& sound,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
locator& loc,
|
||||
SoundBank& bank,
|
||||
std::optional<ame_handler*> parent);
|
||||
MidiHandler(Midi* block,
|
||||
VoiceManager& vm,
|
||||
MusicBank::MIDISound& sound,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SoundBank& bank,
|
||||
std::optional<AmeHandler*> parent);
|
||||
|
||||
~midi_handler() override {
|
||||
~MidiHandler() override {
|
||||
for (auto& p : m_voices) {
|
||||
auto v = p.lock();
|
||||
if (v != nullptr) {
|
||||
v->stop();
|
||||
v->Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
void init_midi();
|
||||
void start();
|
||||
bool tick() override;
|
||||
void mute_channel(u8 channel);
|
||||
void unmute_channel(u8 channel);
|
||||
SoundBank& bank() override { return m_bank; };
|
||||
void InitMidi();
|
||||
void Start();
|
||||
bool Tick() override;
|
||||
void MuteChannel(u8 channel);
|
||||
void UnmuteChannel(u8 channel);
|
||||
SoundBank& Bank() override { return m_bank; };
|
||||
|
||||
void pause() override;
|
||||
void stop() override;
|
||||
void unpause() override;
|
||||
u8 group() override { return m_sound.VolGroup; }
|
||||
void set_vol_pan(s32 vol, s32 pan) override;
|
||||
void Pause() override;
|
||||
void Stop() override;
|
||||
void Unpause() override;
|
||||
u8 Group() override { return m_sound.VolGroup; }
|
||||
void SetVolPan(s32 vol, s32 pan) override;
|
||||
|
||||
bool complete() { return m_track_complete; };
|
||||
void set_pmod(s32 mod) override;
|
||||
bool Complete() { return m_track_complete; };
|
||||
void SetPMod(s32 mod) override;
|
||||
|
||||
private:
|
||||
static constexpr int tickrate = 240;
|
||||
static constexpr int mics_per_tick = 1000000 / tickrate;
|
||||
struct midi_error : public std::exception {
|
||||
midi_error(std::string text) : msg(std::move(text)) {}
|
||||
midi_error() : msg("Unknown MIDI error") {}
|
||||
struct MidiError : public std::exception {
|
||||
MidiError(std::string text) : msg(std::move(text)) {}
|
||||
MidiError() : msg("Unknown MIDI error") {}
|
||||
std::string msg;
|
||||
const char* what() const noexcept override { return msg.c_str(); }
|
||||
};
|
||||
|
||||
std::optional<ame_handler*> m_parent;
|
||||
std::optional<AmeHandler*> m_parent;
|
||||
|
||||
std::list<std::weak_ptr<midi_voice>> m_voices;
|
||||
|
||||
MIDISound& m_sound;
|
||||
locator& m_locator;
|
||||
MusicBank::MIDISound& m_sound;
|
||||
s32 m_vol{0x7f};
|
||||
s32 m_pan{0};
|
||||
s32 m_cur_pm{0};
|
||||
@@ -106,7 +91,7 @@ class midi_handler : public sound_handler {
|
||||
|
||||
bool m_paused{false};
|
||||
|
||||
MIDIBlockHeader* m_header{nullptr};
|
||||
Midi* m_header{nullptr};
|
||||
|
||||
std::array<bool, 16> m_mute_state{};
|
||||
std::array<s8, 16> m_chanvol{};
|
||||
@@ -130,20 +115,20 @@ class midi_handler : public sound_handler {
|
||||
|
||||
std::array<u8, 16> m_programs{};
|
||||
|
||||
voice_manager& m_vm;
|
||||
VoiceManager& m_vm;
|
||||
|
||||
void step();
|
||||
void new_delta();
|
||||
void Step();
|
||||
void NewDelta();
|
||||
|
||||
void note_on();
|
||||
void note_off();
|
||||
void controller_change();
|
||||
void channel_pressure();
|
||||
void program_change();
|
||||
void meta_event();
|
||||
void system_event();
|
||||
void channel_pitch();
|
||||
void NoteOn();
|
||||
void NoteOff();
|
||||
void ControllerChange();
|
||||
void ChannelPressure();
|
||||
void ProgramChange();
|
||||
void MetaEvent();
|
||||
void SystemEvent();
|
||||
void ChannelPitch();
|
||||
|
||||
static std::pair<size_t, u32> read_vlq(u8* value);
|
||||
static std::pair<size_t, u32> ReadVLQ(u8* value);
|
||||
};
|
||||
} // namespace snd
|
||||
@@ -3,50 +3,34 @@
|
||||
#include "ame_handler.h"
|
||||
#include "midi_handler.h"
|
||||
|
||||
#include "../common/synth.h"
|
||||
#include "common/log/log.h"
|
||||
|
||||
namespace snd {
|
||||
|
||||
MusicBank::MusicBank(locator& loc, u32 id, BankTag* tag)
|
||||
: SoundBank(id, BankType::Music), m_locator(loc) {
|
||||
auto data = (SoundBankData*)tag;
|
||||
std::optional<std::unique_ptr<SoundHandler>> MusicBank::MakeHandler(VoiceManager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
s32 pm,
|
||||
s32 pb) {
|
||||
auto& sound = Sounds[sound_id];
|
||||
|
||||
auto sound = (MIDISound*)((uintptr_t)data + data->FirstSound);
|
||||
for (int i = 0; i < data->NumSounds; i++) {
|
||||
m_sounds.emplace_back(sound[i]);
|
||||
}
|
||||
// FIXME: global midi list
|
||||
// search only local bank for now
|
||||
// (always the case in jak games anyway)
|
||||
|
||||
auto progdata = (ProgData*)((uintptr_t)data + data->FirstProg);
|
||||
for (int i = 0; i < data->NumProgs; i++) {
|
||||
Prog prog;
|
||||
prog.d = progdata[i];
|
||||
m_programs.emplace_back(std::move(prog));
|
||||
}
|
||||
|
||||
for (auto& prog : m_programs) {
|
||||
auto tonedata = (Tone*)((uintptr_t)data + prog.d.FirstTone);
|
||||
for (int i = 0; i < prog.d.NumTones; i++) {
|
||||
prog.tones.emplace_back(tonedata[i]);
|
||||
if (sound.Type == 4) {
|
||||
auto& midi = std::get<Midi>(MidiData);
|
||||
if (sound.MIDIID == midi.ID) {
|
||||
return std::make_unique<MidiHandler>(&midi, vm, sound, vol, pan, *this);
|
||||
}
|
||||
}
|
||||
|
||||
bank_name = data->BankID;
|
||||
}
|
||||
|
||||
std::optional<std::unique_ptr<sound_handler>> MusicBank::make_handler(voice_manager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
s32 pm,
|
||||
s32 pb) {
|
||||
auto& sound = m_sounds[sound_id];
|
||||
|
||||
if (sound.Type == 4) { // midi
|
||||
auto midi = static_cast<MIDIBlockHeader*>(m_locator.get_midi(sound.MIDIID));
|
||||
return std::make_unique<midi_handler>(midi, vm, sound, vol, pan, m_locator, *this);
|
||||
} else if (sound.Type == 5) { // ame
|
||||
auto midi = static_cast<MultiMIDIBlockHeader*>(m_locator.get_midi(sound.MIDIID));
|
||||
return std::make_unique<ame_handler>(midi, vm, sound, vol, pan, m_locator, *this);
|
||||
return std::nullopt;
|
||||
} else if (sound.Type == 5) {
|
||||
auto& midi = std::get<MultiMidi>(MidiData);
|
||||
if (sound.MIDIID == midi.ID) {
|
||||
return std::make_unique<AmeHandler>(&midi, vm, sound, vol, pan, *this);
|
||||
}
|
||||
return std::nullopt;
|
||||
} else {
|
||||
lg::error("Invalid music sound type");
|
||||
return std::nullopt;
|
||||
@@ -54,11 +38,11 @@ std::optional<std::unique_ptr<sound_handler>> MusicBank::make_handler(voice_mana
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::unique_ptr<sound_handler>> MusicBank::make_handler(voice_manager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SndPlayParams& params) {
|
||||
std::optional<std::unique_ptr<SoundHandler>> MusicBank::MakeHandler(VoiceManager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SndPlayParams& params) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,88 +1,83 @@
|
||||
#pragma once
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "soundbank.h"
|
||||
|
||||
#include "third-party/span.hpp"
|
||||
|
||||
namespace snd {
|
||||
struct SoundBankData : BankTag {
|
||||
/* 10 */ s8 BankNum;
|
||||
/* 11 */ s8 pad1;
|
||||
/* 12 */ s16 pad2;
|
||||
/* 14 */ s16 NumSounds;
|
||||
/* 16 */ s16 NumProgs;
|
||||
/* 18 */ s16 NumTones;
|
||||
/* 1a */ s16 NumVAGs;
|
||||
/* 1c */ /*Sound**/ u32 FirstSound;
|
||||
/* 20 */ /*Prog**/ u32 FirstProg;
|
||||
/* 24 */ /*Tone**/ u32 FirstTone;
|
||||
/* 28 */ /*void**/ u32 VagsInSR;
|
||||
/* 2c */ u32 VagDataSize;
|
||||
/* 30 */ /*SoundBank**/ u32 NextBank;
|
||||
|
||||
struct Midi {
|
||||
u32 DataID;
|
||||
s16 Version;
|
||||
s8 Flags;
|
||||
u32 ID;
|
||||
u32 BankID;
|
||||
u8* DataStart;
|
||||
u32 Tempo;
|
||||
s32 PPQ;
|
||||
};
|
||||
|
||||
struct MIDIBlock {
|
||||
/* 0 */ u32 DataID;
|
||||
/* 4 */ s16 Version;
|
||||
/* 6 */ s8 Flags;
|
||||
/* 7 */ s8 NumMIDIBlocks;
|
||||
/* 8 */ u32 ID;
|
||||
struct MidiSegment : Midi {
|
||||
// For MultiMidi data where the sound handler struct is baked into the
|
||||
// file, we need to know the handler type to determine if we should
|
||||
// play the segment. For unknown reasons the files contain segments
|
||||
// that have invalid/unknown handler types that should not be played as midi.
|
||||
u32 SoundHandle;
|
||||
};
|
||||
|
||||
struct MIDIBlockHeader : MIDIBlock {
|
||||
/* c */ /*void**/ u32 NextMIDIBlock;
|
||||
/* 10 */ u32 BankID;
|
||||
/* 14 */ /*SoundBank**/ u32 BankPtr;
|
||||
/* 18 */ /*s8**/ u32 DataStart;
|
||||
/* 1c */ /*s8**/ u32 MultiMIDIParent;
|
||||
/* 20 */ u32 Tempo;
|
||||
/* 24 */ u32 PPQ;
|
||||
struct MultiMidi {
|
||||
u32 DataID;
|
||||
u32 Version;
|
||||
s8 Flags;
|
||||
u32 ID;
|
||||
|
||||
std::vector<MidiSegment> midi;
|
||||
};
|
||||
|
||||
struct MultiMIDIBlockHeader : MIDIBlock {
|
||||
/* c */ /*void**/ u32 NextMIDIBlock;
|
||||
/* 10 */ /*s8**/ u32 BlockPtr[0];
|
||||
};
|
||||
|
||||
struct MIDISound {
|
||||
/* 0 */ s32 Type;
|
||||
/* 4 */ /*SoundBank**/ u32 Bank;
|
||||
/* 8 */ /*void**/ u32 OrigBank;
|
||||
/* c */ u32 MIDIID;
|
||||
/* 10 */ s16 Vol;
|
||||
/* 12 */ s8 Repeats;
|
||||
/* 13 */ s8 VolGroup;
|
||||
/* 14 */ s16 Pan;
|
||||
/* 16 */ s8 Index;
|
||||
/* 17 */ s8 Flags;
|
||||
/* 18 */ /*void**/ u32 MIDIBlock;
|
||||
};
|
||||
|
||||
// Annoyingly enough we need some data out of this struct
|
||||
struct MIDISoundHandler {
|
||||
u32 OwnerID;
|
||||
};
|
||||
|
||||
struct Prog;
|
||||
class MusicBank : public SoundBank {
|
||||
public:
|
||||
MusicBank(locator& loc, u32 id, BankTag* tag);
|
||||
std::optional<std::unique_ptr<sound_handler>> make_handler(voice_manager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
s32 pm,
|
||||
s32 pb) override;
|
||||
struct MIDISound { // 0x1c
|
||||
s32 Type;
|
||||
SoundBank* Bank;
|
||||
void* OrigBank;
|
||||
u32 MIDIID;
|
||||
s16 Vol;
|
||||
s8 Repeats;
|
||||
s8 VolGroup;
|
||||
s16 Pan;
|
||||
s8 Index;
|
||||
u8 Flags;
|
||||
};
|
||||
|
||||
std::optional<std::unique_ptr<sound_handler>> make_handler(voice_manager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SndPlayParams& params) override;
|
||||
struct Prog {
|
||||
s8 Vol;
|
||||
s16 Pan;
|
||||
std::vector<Tone> Tones;
|
||||
};
|
||||
|
||||
std::vector<Prog> m_programs;
|
||||
std::vector<MIDISound> m_sounds;
|
||||
std::vector<MIDISound> Sounds;
|
||||
std::vector<Prog> Progs;
|
||||
std::unique_ptr<u8[]> SampleData;
|
||||
std::unique_ptr<u8[]> SeqData;
|
||||
std::variant<Midi, MultiMidi> MidiData;
|
||||
|
||||
private:
|
||||
locator& m_locator;
|
||||
static MusicBank* ReadBank(nonstd::span<u8> bank_data,
|
||||
nonstd::span<u8> samples,
|
||||
nonstd::span<u8> midi_data);
|
||||
|
||||
std::optional<std::unique_ptr<SoundHandler>> MakeHandler(VoiceManager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
s32 pm,
|
||||
s32 pb) override;
|
||||
|
||||
std::optional<std::unique_ptr<SoundHandler>> MakeHandler(VoiceManager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SndPlayParams& params) override;
|
||||
};
|
||||
} // namespace snd
|
||||
+132
-129
@@ -4,9 +4,12 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "sfxblock.h"
|
||||
|
||||
#include "third-party/fmt/core.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <combaseapi.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
@@ -16,15 +19,15 @@ namespace snd {
|
||||
|
||||
u8 g_global_excite = 0;
|
||||
|
||||
player::player() : m_vmanager(m_synth, m_loader) {
|
||||
init_cubeb();
|
||||
Player::Player() : mVmanager(mSynth) {
|
||||
InitCubeb();
|
||||
}
|
||||
|
||||
player::~player() {
|
||||
destroy_cubeb();
|
||||
Player::~Player() {
|
||||
DestroyCubeb();
|
||||
}
|
||||
|
||||
void player::init_cubeb() {
|
||||
void Player::InitCubeb() {
|
||||
#ifdef _WIN32
|
||||
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
m_coinitialized = SUCCEEDED(hr);
|
||||
@@ -35,7 +38,7 @@ void player::init_cubeb() {
|
||||
}
|
||||
#endif
|
||||
|
||||
cubeb_init(&m_ctx, "OpenGOAL", nullptr);
|
||||
cubeb_init(&mCtx, "OpenGOAL", nullptr);
|
||||
|
||||
cubeb_stream_params outparam = {};
|
||||
outparam.channels = 2;
|
||||
@@ -46,30 +49,30 @@ void player::init_cubeb() {
|
||||
|
||||
s32 err = 0;
|
||||
u32 latency = 0;
|
||||
err = cubeb_get_min_latency(m_ctx, &outparam, &latency);
|
||||
err = cubeb_get_min_latency(mCtx, &outparam, &latency);
|
||||
if (err != CUBEB_OK) {
|
||||
lg::error("Cubeb init failed");
|
||||
return;
|
||||
}
|
||||
|
||||
err = cubeb_stream_init(m_ctx, &m_stream, "OpenGOAL", nullptr, nullptr, nullptr, &outparam,
|
||||
latency, &sound_callback, &state_callback, this);
|
||||
err = cubeb_stream_init(mCtx, &mStream, "OpenGOAL", nullptr, nullptr, nullptr, &outparam, latency,
|
||||
&sound_callback, &state_callback, this);
|
||||
if (err != CUBEB_OK) {
|
||||
lg::error("Cubeb init failed");
|
||||
return;
|
||||
}
|
||||
|
||||
err = cubeb_stream_start(m_stream);
|
||||
err = cubeb_stream_start(mStream);
|
||||
if (err != CUBEB_OK) {
|
||||
lg::error("Cubeb init failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void player::destroy_cubeb() {
|
||||
cubeb_stream_stop(m_stream);
|
||||
cubeb_stream_destroy(m_stream);
|
||||
cubeb_destroy(m_ctx);
|
||||
void Player::DestroyCubeb() {
|
||||
cubeb_stream_stop(mStream);
|
||||
cubeb_stream_destroy(mStream);
|
||||
cubeb_destroy(mCtx);
|
||||
#ifdef _WIN32
|
||||
if (m_coinitialized) {
|
||||
CoUninitialize();
|
||||
@@ -78,34 +81,35 @@ void player::destroy_cubeb() {
|
||||
#endif
|
||||
}
|
||||
|
||||
long player::sound_callback([[maybe_unused]] cubeb_stream* stream,
|
||||
long Player::sound_callback([[maybe_unused]] cubeb_stream* stream,
|
||||
void* user,
|
||||
[[maybe_unused]] const void* input,
|
||||
void* output_buffer,
|
||||
long nframes) {
|
||||
((player*)user)->tick((s16_output*)output_buffer, nframes);
|
||||
((Player*)user)->Tick((s16Output*)output_buffer, nframes);
|
||||
return nframes;
|
||||
}
|
||||
|
||||
void player::state_callback([[maybe_unused]] cubeb_stream* stream,
|
||||
void Player::state_callback([[maybe_unused]] cubeb_stream* stream,
|
||||
[[maybe_unused]] void* user,
|
||||
[[maybe_unused]] cubeb_state state) {}
|
||||
|
||||
void player::tick(s16_output* stream, int samples) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
m_tick++;
|
||||
void Player::Tick(s16Output* stream, int samples) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
static int htick = 200;
|
||||
static int stick = 48000;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
// The handlers expect to tick at 240hz
|
||||
// 48000/240 = 200
|
||||
if (htick == 200) {
|
||||
for (auto it = m_handlers.begin(); it != m_handlers.end();) {
|
||||
bool done = it->second->tick();
|
||||
mTick++;
|
||||
|
||||
for (auto it = mHandlers.begin(); it != mHandlers.end();) {
|
||||
bool done = it->second->Tick();
|
||||
if (done) {
|
||||
// fmt::print("erasing handler\n");
|
||||
m_handle_allocator.free_id(it->first);
|
||||
it = m_handlers.erase(it);
|
||||
mHandleAllocator.FreeId(it->first);
|
||||
it = mHandlers.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
@@ -121,45 +125,45 @@ void player::tick(s16_output* stream, int samples) {
|
||||
|
||||
stick++;
|
||||
htick++;
|
||||
*stream++ = m_synth.tick();
|
||||
*stream++ = mSynth.Tick();
|
||||
}
|
||||
}
|
||||
|
||||
u32 player::play_sound(u32 bank_id, u32 sound_id, s32 vol, s32 pan, s32 pm, s32 pb) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
auto bank = m_loader.get_bank_by_handle(bank_id);
|
||||
u32 Player::PlaySound(BankHandle bank_id, u32 sound_id, s32 vol, s32 pan, s32 pm, s32 pb) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
auto bank = mLoader.GetBankByHandle(bank_id);
|
||||
if (bank == nullptr) {
|
||||
lg::error("play_sound: Bank {} does not exist", bank_id);
|
||||
lg::error("play_sound: Bank {} does not exist", static_cast<void*>(bank_id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto handler = bank->make_handler(m_vmanager, sound_id, vol, pan, pm, pb);
|
||||
auto handler = bank->MakeHandler(mVmanager, sound_id, vol, pan, pm, pb);
|
||||
if (!handler.has_value()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 handle = m_handle_allocator.get_id();
|
||||
m_handlers.emplace(handle, std::move(handler.value()));
|
||||
u32 handle = mHandleAllocator.GetId();
|
||||
mHandlers.emplace(handle, std::move(handler.value()));
|
||||
// fmt::print("play_sound {}:{} - {}\n", bank_id, sound_id, handle);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
u32 player::play_sound_by_name(u32 bank_id,
|
||||
char* bank_name,
|
||||
char* sound_name,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
s32 pm,
|
||||
s32 pb) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
u32 Player::PlaySoundByName(BankHandle bank_id,
|
||||
char* bank_name,
|
||||
char* sound_name,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
s32 pm,
|
||||
s32 pb) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
SoundBank* bank = nullptr;
|
||||
if (bank_id == 0 && bank_name != nullptr) {
|
||||
bank = m_loader.get_bank_by_name(bank_name);
|
||||
bank = mLoader.GetBankByName(bank_name);
|
||||
} else if (bank_id != 0) {
|
||||
bank = m_loader.get_bank_by_handle(bank_id);
|
||||
bank = mLoader.GetBankByHandle(bank_id);
|
||||
} else {
|
||||
bank = m_loader.get_bank_with_sound(sound_name);
|
||||
bank = mLoader.GetBankWithSound(sound_name);
|
||||
}
|
||||
|
||||
if (bank == nullptr) {
|
||||
@@ -167,9 +171,9 @@ u32 player::play_sound_by_name(u32 bank_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto sound = bank->get_sound_by_name(sound_name);
|
||||
auto sound = bank->GetSoundByName(sound_name);
|
||||
if (sound.has_value()) {
|
||||
return play_sound(bank->bank_id, sound.value(), vol, pan, pm, pb);
|
||||
return PlaySound(bank, sound.value(), vol, pan, pm, pb);
|
||||
}
|
||||
|
||||
// lg::error("play_sound_by_name: failed to find sound {}", sound_name);
|
||||
@@ -177,41 +181,41 @@ u32 player::play_sound_by_name(u32 bank_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void player::stop_sound(u32 sound_id) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
auto handler = m_handlers.find(sound_id);
|
||||
if (handler == m_handlers.end())
|
||||
void Player::StopSound(u32 sound_id) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
auto handler = mHandlers.find(sound_id);
|
||||
if (handler == mHandlers.end())
|
||||
return;
|
||||
|
||||
handler->second->stop();
|
||||
handler->second->Stop();
|
||||
|
||||
// m_handle_allocator.free_id(sound_id);
|
||||
// m_handlers.erase(sound_id);
|
||||
}
|
||||
|
||||
void player::set_sound_reg(u32 sound_id, u8 reg, u8 value) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
if (m_handlers.find(sound_id) == m_handlers.end()) {
|
||||
void Player::SetSoundReg(u32 sound_id, u8 reg, u8 value) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
if (mHandlers.find(sound_id) == mHandlers.end()) {
|
||||
// fmt::print("set_midi_reg: Handler {} does not exist\n", sound_id);
|
||||
return;
|
||||
}
|
||||
|
||||
auto* handler = m_handlers.at(sound_id).get();
|
||||
handler->set_register(reg, value);
|
||||
auto* handler = mHandlers.at(sound_id).get();
|
||||
handler->SetRegister(reg, value);
|
||||
}
|
||||
|
||||
bool player::sound_still_active(u32 sound_id) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
auto handler = m_handlers.find(sound_id);
|
||||
if (handler == m_handlers.end())
|
||||
bool Player::SoundStillActive(u32 sound_id) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
auto handler = mHandlers.find(sound_id);
|
||||
if (handler == mHandlers.end())
|
||||
return false;
|
||||
|
||||
// fmt::print("sound_still_active {}\n", sound_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
void player::set_master_volume(u32 group, s32 volume) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
void Player::SetMasterVolume(u32 group, s32 volume) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
if (volume > 0x400)
|
||||
volume = 0x400;
|
||||
|
||||
@@ -221,125 +225,124 @@ void player::set_master_volume(u32 group, s32 volume) {
|
||||
if (group == 15)
|
||||
return;
|
||||
|
||||
m_vmanager.set_master_vol(group, volume);
|
||||
mVmanager.SetMasterVol(group, volume);
|
||||
|
||||
// Master volume
|
||||
if (group == 16) {
|
||||
m_synth.set_master_vol(0x3ffff * volume / 0x400);
|
||||
mSynth.SetMasterVol(0x3ffff * volume / 0x400);
|
||||
}
|
||||
}
|
||||
|
||||
u32 player::load_bank(fs::path& filepath, size_t offset) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
std::fstream in(filepath, std::fstream::binary | std::fstream::in);
|
||||
in.seekg(offset, std::fstream::beg);
|
||||
|
||||
return m_loader.read_bank(in);
|
||||
BankHandle Player::LoadBank(nonstd::span<u8> bank) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
return mLoader.BankLoad(bank);
|
||||
}
|
||||
|
||||
void player::unload_bank(u32 bank_handle) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
auto* bank = m_loader.get_bank_by_handle(bank_handle);
|
||||
void Player::UnloadBank(BankHandle bank_handle) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
auto* bank = mLoader.GetBankByHandle(bank_handle);
|
||||
if (bank == nullptr)
|
||||
return;
|
||||
|
||||
for (auto it = m_handlers.begin(); it != m_handlers.end();) {
|
||||
if (it->second->bank().bank_id == bank_handle) {
|
||||
m_handle_allocator.free_id(it->first);
|
||||
it = m_handlers.erase(it);
|
||||
for (auto it = mHandlers.begin(); it != mHandlers.end();) {
|
||||
if (&it->second->Bank() == bank_handle) {
|
||||
mHandleAllocator.FreeId(it->first);
|
||||
it = mHandlers.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
m_loader.unload_bank(bank_handle);
|
||||
mLoader.UnloadBank(bank_handle);
|
||||
}
|
||||
|
||||
void player::set_pan_table(vol_pair* pantable) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
m_vmanager.set_pan_table(pantable);
|
||||
void Player::SetPanTable(VolPair* pantable) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
mVmanager.SetPanTable(pantable);
|
||||
}
|
||||
|
||||
void player::set_playback_mode(s32 mode) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
m_vmanager.set_playback_mode(mode);
|
||||
void Player::SetPlaybackMode(s32 mode) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
mVmanager.SetPlaybackMode(mode);
|
||||
}
|
||||
|
||||
void player::pause_sound(s32 sound_id) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
auto handler = m_handlers.find(sound_id);
|
||||
if (handler == m_handlers.end())
|
||||
void Player::PauseSound(s32 sound_id) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
auto handler = mHandlers.find(sound_id);
|
||||
if (handler == mHandlers.end())
|
||||
return;
|
||||
|
||||
handler->second->pause();
|
||||
handler->second->Pause();
|
||||
}
|
||||
|
||||
void player::continue_sound(s32 sound_id) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
auto handler = m_handlers.find(sound_id);
|
||||
if (handler == m_handlers.end())
|
||||
void Player::ContinueSound(s32 sound_id) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
auto handler = mHandlers.find(sound_id);
|
||||
if (handler == mHandlers.end())
|
||||
return;
|
||||
|
||||
handler->second->unpause();
|
||||
handler->second->Unpause();
|
||||
}
|
||||
|
||||
void player::pause_all_sounds_in_group(u8 group) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
void Player::PauseAllSoundsInGroup(u8 group) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
|
||||
for (auto& h : m_handlers) {
|
||||
if ((1 << h.second->group()) & group) {
|
||||
h.second->pause();
|
||||
for (auto& h : mHandlers) {
|
||||
if ((1 << h.second->Group()) & group) {
|
||||
h.second->Pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void player::continue_all_sounds_in_group(u8 group) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
void Player::ContinueAllSoundsInGroup(u8 group) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
|
||||
for (auto& h : m_handlers) {
|
||||
if ((1 << h.second->group()) & group) {
|
||||
h.second->unpause();
|
||||
for (auto& h : mHandlers) {
|
||||
if ((1 << h.second->Group()) & group) {
|
||||
h.second->Unpause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void player::set_sound_vol_pan(s32 sound_id, s32 vol, s32 pan) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
auto handler = m_handlers.find(sound_id);
|
||||
if (handler == m_handlers.end())
|
||||
void Player::SetSoundVolPan(s32 sound_id, s32 vol, s32 pan) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
auto handler = mHandlers.find(sound_id);
|
||||
if (handler == mHandlers.end())
|
||||
return;
|
||||
|
||||
handler->second->set_vol_pan(vol, pan);
|
||||
handler->second->SetVolPan(vol, pan);
|
||||
}
|
||||
|
||||
void player::set_sound_pmod(s32 sound_handle, s32 mod) {
|
||||
auto handler = m_handlers.find(sound_handle);
|
||||
if (handler == m_handlers.end())
|
||||
void Player::SetSoundPmod(s32 sound_handle, s32 mod) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
auto handler = mHandlers.find(sound_handle);
|
||||
if (handler == mHandlers.end())
|
||||
return;
|
||||
|
||||
handler->second->set_pmod(mod);
|
||||
handler->second->SetPMod(mod);
|
||||
}
|
||||
|
||||
void player::stop_all_sounds() {
|
||||
for (auto it = m_handlers.begin(); it != m_handlers.end();) {
|
||||
m_handle_allocator.free_id(it->first);
|
||||
it = m_handlers.erase(it);
|
||||
void Player::StopAllSounds() {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
for (auto it = mHandlers.begin(); it != mHandlers.end();) {
|
||||
mHandleAllocator.FreeId(it->first);
|
||||
it = mHandlers.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
s32 player::get_sound_user_data(s32 block_handle,
|
||||
char* block_name,
|
||||
s32 sound_id,
|
||||
char* sound_name,
|
||||
SFXUserData* dst) {
|
||||
std::scoped_lock lock(m_ticklock);
|
||||
s32 Player::GetSoundUserData(BankHandle block_handle,
|
||||
char* block_name,
|
||||
s32 sound_id,
|
||||
char* sound_name,
|
||||
SFXUserData* dst) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
SoundBank* bank = nullptr;
|
||||
if (block_handle == 0 && block_name != nullptr) {
|
||||
bank = m_loader.get_bank_by_name(block_name);
|
||||
} else if (block_handle != 0) {
|
||||
bank = m_loader.get_bank_by_handle(block_handle);
|
||||
if (block_handle == nullptr && block_name != nullptr) {
|
||||
bank = mLoader.GetBankByName(block_name);
|
||||
} else if (block_handle != nullptr) {
|
||||
bank = mLoader.GetBankByHandle(block_handle);
|
||||
} else {
|
||||
bank = m_loader.get_bank_with_sound(sound_name);
|
||||
bank = mLoader.GetBankWithSound(sound_name);
|
||||
}
|
||||
|
||||
if (bank == nullptr) {
|
||||
@@ -347,7 +350,7 @@ s32 player::get_sound_user_data(s32 block_handle,
|
||||
}
|
||||
|
||||
if (sound_id == -1) {
|
||||
auto sound = bank->get_sound_by_name(sound_name);
|
||||
auto sound = bank->GetSoundByName(sound_name);
|
||||
if (sound.has_value()) {
|
||||
sound_id = sound.value();
|
||||
} else {
|
||||
@@ -355,7 +358,7 @@ s32 player::get_sound_user_data(s32 block_handle,
|
||||
}
|
||||
}
|
||||
|
||||
auto ud = bank->get_sound_user_data(sound_id);
|
||||
auto ud = bank->GetSoundUserData(sound_id);
|
||||
if (ud.has_value()) {
|
||||
dst->data[0] = ud.value()->data[0];
|
||||
dst->data[1] = ud.value()->data[1];
|
||||
|
||||
+49
-50
@@ -10,82 +10,81 @@
|
||||
#include "ame_handler.h"
|
||||
#include "handle_allocator.h"
|
||||
#include "loader.h"
|
||||
#include "midi_handler.h"
|
||||
#include "sound_handler.h"
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
|
||||
#include "../common/synth.h"
|
||||
#include "game/sound/989snd/vagvoice.h"
|
||||
|
||||
#include "third-party/cubeb/cubeb/include/cubeb/cubeb.h"
|
||||
#include "third-party/span.hpp"
|
||||
|
||||
namespace snd {
|
||||
|
||||
class player {
|
||||
class Player {
|
||||
public:
|
||||
player();
|
||||
~player();
|
||||
player(const player&) = delete;
|
||||
player operator=(const player&) = delete;
|
||||
Player();
|
||||
~Player();
|
||||
Player(const Player&) = delete;
|
||||
Player operator=(const Player&) = delete;
|
||||
|
||||
// player(player&& other) noexcept = default;
|
||||
// player& operator=(player&& other) noexcept = default;
|
||||
|
||||
u32 load_bank(fs::path& path, size_t offset);
|
||||
BankHandle LoadBank(nonstd::span<u8> bank);
|
||||
|
||||
u32 play_sound(u32 bank, u32 sound, s32 vol, s32 pan, s32 pm, s32 pb);
|
||||
u32 play_sound_by_name(u32 bank,
|
||||
char* bank_name,
|
||||
char* sound_name,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
s32 pm,
|
||||
s32 pb);
|
||||
void set_sound_reg(u32 sound_id, u8 reg, u8 value);
|
||||
void set_global_excite(u8 value) { GlobalExcite = value; };
|
||||
bool sound_still_active(u32 sound_id);
|
||||
void set_master_volume(u32 group, s32 volume);
|
||||
void unload_bank(u32 bank_handle);
|
||||
void stop_sound(u32 sound_handle);
|
||||
void set_pan_table(vol_pair* pantable);
|
||||
void set_playback_mode(s32 mode);
|
||||
void pause_sound(s32 sound_handle);
|
||||
void continue_sound(s32 sound_handle);
|
||||
void pause_all_sounds_in_group(u8 group);
|
||||
void continue_all_sounds_in_group(u8 group);
|
||||
void set_sound_vol_pan(s32 sound_handle, s32 vol, s32 pan);
|
||||
void submit_voice(std::shared_ptr<voice>& voice) { m_synth.add_voice(voice); };
|
||||
void set_sound_pmod(s32 sound_handle, s32 mod);
|
||||
void init_cubeb();
|
||||
void destroy_cubeb();
|
||||
s32 get_tick() { return m_tick; };
|
||||
void stop_all_sounds();
|
||||
s32 get_sound_user_data(s32 block_handle,
|
||||
char* block_name,
|
||||
s32 sound_id,
|
||||
char* sound_name,
|
||||
SFXUserData* dst);
|
||||
u32 PlaySound(BankHandle bank, u32 sound, s32 vol, s32 pan, s32 pm, s32 pb);
|
||||
u32 PlaySoundByName(BankHandle bank,
|
||||
char* bank_name,
|
||||
char* sound_name,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
s32 pm,
|
||||
s32 pb);
|
||||
void SetSoundReg(u32 sound_id, u8 reg, u8 value);
|
||||
void SetGlobalExcite(u8 value) { GlobalExcite = value; };
|
||||
bool SoundStillActive(u32 sound_id);
|
||||
void SetMasterVolume(u32 group, s32 volume);
|
||||
void UnloadBank(BankHandle bank_handle);
|
||||
void StopSound(u32 sound_handle);
|
||||
void SetPanTable(VolPair* pantable);
|
||||
void SetPlaybackMode(s32 mode);
|
||||
void PauseSound(s32 sound_handle);
|
||||
void ContinueSound(s32 sound_handle);
|
||||
void PauseAllSoundsInGroup(u8 group);
|
||||
void ContinueAllSoundsInGroup(u8 group);
|
||||
void SetSoundVolPan(s32 sound_handle, s32 vol, s32 pan);
|
||||
void SubmitVoice(std::shared_ptr<Voice>& voice) { mSynth.AddVoice(voice); };
|
||||
void SetSoundPmod(s32 sound_handle, s32 mod);
|
||||
void InitCubeb();
|
||||
void DestroyCubeb();
|
||||
s32 GetTick() { return mTick; };
|
||||
void StopAllSounds();
|
||||
s32 GetSoundUserData(BankHandle block_handle,
|
||||
char* block_name,
|
||||
s32 sound_id,
|
||||
char* sound_name,
|
||||
SFXUserData* dst);
|
||||
|
||||
private:
|
||||
std::recursive_mutex m_ticklock; // TODO does not need to recursive with some light restructuring
|
||||
id_allocator m_handle_allocator;
|
||||
std::unordered_map<u32, std::unique_ptr<sound_handler>> m_handlers;
|
||||
std::recursive_mutex mTickLock; // TODO does not need to recursive with some light restructuring
|
||||
IdAllocator mHandleAllocator;
|
||||
std::unordered_map<u32, std::unique_ptr<SoundHandler>> mHandlers;
|
||||
|
||||
void tick(s16_output* stream, int samples);
|
||||
void Tick(s16Output* stream, int samples);
|
||||
|
||||
#ifdef _WIN32
|
||||
bool m_coinitialized = false;
|
||||
#endif
|
||||
|
||||
loader m_loader;
|
||||
synth m_synth;
|
||||
voice_manager m_vmanager;
|
||||
s32 m_tick{0};
|
||||
Loader mLoader;
|
||||
Synth mSynth;
|
||||
VoiceManager mVmanager;
|
||||
s32 mTick{0};
|
||||
|
||||
cubeb* m_ctx{nullptr};
|
||||
cubeb_stream* m_stream{nullptr};
|
||||
cubeb* mCtx{nullptr};
|
||||
cubeb_stream* mStream{nullptr};
|
||||
|
||||
static long sound_callback(cubeb_stream* stream,
|
||||
void* user,
|
||||
|
||||
Loaded 100 of 582 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user