From a27674311676111f08f29ecc9f5cdc48c1aad71d Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sat, 7 Jan 2023 11:41:26 -0800 Subject: [PATCH] Match and link CRumbleGenerator, nearly match CRumbleVoice Former-commit-id: bd48696bf3e296d3ee44530ca04a30fd62236b30 --- asm/Kyoto/Input/CRumbleGenerator.s | 12 ++-- asm/MetroidPrime/CStateManager.s | 4 +- configure.py | 2 +- include/Kyoto/Input/CRumbleGenerator.hpp | 4 +- include/Kyoto/Input/CRumbleVoice.hpp | 5 +- src/Kyoto/Input/CRumbleGenerator.cpp | 81 ++++++++++++++++++++++++ src/Kyoto/Input/CRumbleVoice.cpp | 31 +++++---- 7 files changed, 114 insertions(+), 25 deletions(-) create mode 100644 src/Kyoto/Input/CRumbleGenerator.cpp diff --git a/asm/Kyoto/Input/CRumbleGenerator.s b/asm/Kyoto/Input/CRumbleGenerator.s index f6c318c8..b160b8a1 100644 --- a/asm/Kyoto/Input/CRumbleGenerator.s +++ b/asm/Kyoto/Input/CRumbleGenerator.s @@ -2,8 +2,8 @@ .section .text, "ax" -.global SetDisabled__14CRumbleManagerFb -SetDisabled__14CRumbleManagerFb: +.global SetDisabled__16CRumbleGeneratorFb +SetDisabled__16CRumbleGeneratorFb: /* 80369D00 00366C60 94 21 FF F0 */ stwu r1, -0x10(r1) /* 80369D04 00366C64 7C 08 02 A6 */ mflr r0 /* 80369D08 00366C68 90 01 00 14 */ stw r0, 0x14(r1) @@ -52,8 +52,8 @@ lbl_80369D84: /* 80369DA0 00366D00 2C 1C 00 04 */ cmpwi r28, 4 /* 80369DA4 00366D04 3B DE 00 04 */ addi r30, r30, 4 /* 80369DA8 00366D08 41 80 FF DC */ blt lbl_80369D84 -/* 80369DAC 00366D0C 3C 60 80 3E */ lis r3, lbl_803D8548@ha -/* 80369DB0 00366D10 38 63 85 48 */ addi r3, r3, lbl_803D8548@l +/* 80369DAC 00366D0C 3C 60 80 3E */ lis r3, kStopAll__16CRumbleGenerator@ha +/* 80369DB0 00366D10 38 63 85 48 */ addi r3, r3, kStopAll__16CRumbleGenerator@l /* 80369DB4 00366D14 48 01 CD 71 */ bl PADControlAllMotors /* 80369DB8 00366D18 E3 E1 00 28 */ psq_l f31, 40(r1), 0, qr0 /* 80369DBC 00366D1C 80 01 00 34 */ lwz r0, 0x34(r1) @@ -388,8 +388,8 @@ lbl_805AEB1C: .section .rodata .balign 8 -.global lbl_803D8548 -lbl_803D8548: +.global kStopAll__16CRumbleGenerator +kStopAll__16CRumbleGenerator: # ROM: 0x3D5548 .4byte 0x00000002 .4byte 0x00000002 diff --git a/asm/MetroidPrime/CStateManager.s b/asm/MetroidPrime/CStateManager.s index ce8cf298..84b7c281 100644 --- a/asm/MetroidPrime/CStateManager.s +++ b/asm/MetroidPrime/CStateManager.s @@ -590,7 +590,7 @@ lbl_80043FAC: /* 80043FB4 00040F14 54 00 CF FF */ rlwinm. r0, r0, 0x19, 0x1f, 0x1f /* 80043FB8 00040F18 41 82 00 34 */ beq lbl_80043FEC /* 80043FBC 00040F1C 38 80 00 00 */ li r4, 0 -/* 80043FC0 00040F20 48 32 5D 41 */ bl SetDisabled__14CRumbleManagerFb +/* 80043FC0 00040F20 48 32 5D 41 */ bl SetDisabled__16CRumbleGeneratorFb /* 80043FC4 00040F24 48 00 00 28 */ b lbl_80043FEC lbl_80043FC8: /* 80043FC8 00040F28 80 7E 08 8C */ lwz r3, 0x88c(r30) @@ -598,7 +598,7 @@ lbl_80043FC8: /* 80043FD0 00040F30 54 00 CF FF */ rlwinm. r0, r0, 0x19, 0x1f, 0x1f /* 80043FD4 00040F34 40 82 00 0C */ bne lbl_80043FE0 /* 80043FD8 00040F38 38 80 00 01 */ li r4, 1 -/* 80043FDC 00040F3C 48 32 5D 25 */ bl SetDisabled__14CRumbleManagerFb +/* 80043FDC 00040F3C 48 32 5D 25 */ bl SetDisabled__16CRumbleGeneratorFb lbl_80043FE0: /* 80043FE0 00040F40 80 7E 08 50 */ lwz r3, 0x850(r30) /* 80043FE4 00040F44 38 80 00 01 */ li r4, 1 diff --git a/configure.py b/configure.py index c826347e..9f3a8cbc 100755 --- a/configure.py +++ b/configure.py @@ -690,7 +690,7 @@ LIBS = [ "Kyoto/Animation/CPoseAsTransformsVariableSize", ["Kyoto/Input/CRumbleVoice", False], ["Kyoto/Input/RumbleAdsr", True], - "Kyoto/Input/CRumbleGenerator", + ["Kyoto/Input/CRumbleGenerator", True], "Kyoto/Audio/SDSPStream", ["Kyoto/Audio/g721", True], "Kyoto/Audio/CStaticAudioPlayer", diff --git a/include/Kyoto/Input/CRumbleGenerator.hpp b/include/Kyoto/Input/CRumbleGenerator.hpp index 8cfb5d87..11fe9e7e 100644 --- a/include/Kyoto/Input/CRumbleGenerator.hpp +++ b/include/Kyoto/Input/CRumbleGenerator.hpp @@ -8,6 +8,7 @@ class CRumbleGenerator { private: + static const EMotorState kStopAll[4]; CRumbleVoice x0_voices[4]; float xc0_periodTime[4]; float xd0_onTime[4]; @@ -18,7 +19,7 @@ public: CRumbleGenerator(); ~CRumbleGenerator(); - s16 Rumble(const SAdsrData& adsr, float, ERumblePriority prio, EIOPort port); + short Rumble(const SAdsrData& adsr, float, ERumblePriority prio, EIOPort port); void Stop(short id, EIOPort port) { if (id == -1) return; @@ -28,6 +29,7 @@ public: void Deactivate(short, bool); void Update(float); void HardStopAll(); + void SetDisabled(const bool disabled); }; #endif // _CRUMBLEGENERATOR diff --git a/include/Kyoto/Input/CRumbleVoice.hpp b/include/Kyoto/Input/CRumbleVoice.hpp index 424f8d00..3a13bea3 100644 --- a/include/Kyoto/Input/CRumbleVoice.hpp +++ b/include/Kyoto/Input/CRumbleVoice.hpp @@ -88,10 +88,13 @@ public: void HardReset(); bool UpdateChannel(SAdsrDelta& delta, const SAdsrData& data, float dt); bool Update(float dt); - uint GetFreeChannel() const; + ushort GetFreeChannel() const; float GetIntensity() const; bool OwnsSustained(short id) const; short CreateRumbleHandle(ushort idx); + ushort GetChannelId(short handle) const { return handle & 0xf; } + ushort GetOwnerId(short handle) const { return ((handle >> 8) & 0xFF); } + ERumblePriority GetPriority(uint idx) { return x10_deltas[idx].x1c_priority; } }; #endif // _CRUMBLEVOICE diff --git a/src/Kyoto/Input/CRumbleGenerator.cpp b/src/Kyoto/Input/CRumbleGenerator.cpp new file mode 100644 index 00000000..83c4aace --- /dev/null +++ b/src/Kyoto/Input/CRumbleGenerator.cpp @@ -0,0 +1,81 @@ +#include "Kyoto/Input/CRumbleGenerator.hpp" + +const EMotorState CRumbleGenerator::kStopAll[4] = { + kMS_StopHard, + kMS_StopHard, + kMS_StopHard, + kMS_StopHard, +}; + +CRumbleGenerator::CRumbleGenerator() : xf0_24_disabled(false) { HardStopAll(); } + +CRumbleGenerator::~CRumbleGenerator() { HardStopAll(); } + +short CRumbleGenerator::Rumble(const SAdsrData& adsr, float gain, ERumblePriority prio, + EIOPort port) { + ushort freeChan = x0_voices[port].GetFreeChannel(); + if (prio >= x0_voices[port].GetPriority(freeChan)) { + xc0_periodTime[port] = 0.f; + xd0_onTime[port] = 0.f; + return x0_voices[port].Activate(adsr, freeChan, gain, prio); + } + return -1; +} + +void CRumbleGenerator::Update(float dt) { + if (!xf0_24_disabled) { + bool updated = false; + for (int i = 0; i < 4; ++i) { + const float intensity = x0_voices[i].GetIntensity(); + if (!x0_voices[i].Update(dt) || intensity <= 0.f) { + xc0_periodTime[i] = 0.f; + xd0_onTime[i] = 0.f; + if (xe0_commandArray[i] != kMS_Stop) { + xe0_commandArray[i] = kMS_Stop; + updated = true; + } + } else { + xc0_periodTime[i] += dt; + if (xc0_periodTime[i] >= 1.f / (30.f * intensity)) { + xc0_periodTime[i] = 0.f; + if (xe0_commandArray[i] != kMS_Rumble) { + xe0_commandArray[i] = kMS_Rumble; + updated = true; + } + } else { + xd0_onTime[i] += dt; + if (xd0_onTime[i] >= (1.f / 30.f)) { + xd0_onTime[i] = 0.f; + if (xe0_commandArray[i] != kMS_Stop) { + xe0_commandArray[i] = kMS_Stop; + updated = true; + } + } + } + } + } + if (updated) { + PADControlAllMotors(reinterpret_cast< const u32* >(xe0_commandArray)); + } + } +} + +void CRumbleGenerator::HardStopAll() { + + for (int i = 0; i < 4; ++i) { + xc0_periodTime[i] = 0.f; + xd0_onTime[i] = 0.f; + xe0_commandArray[i] = kMS_Stop; + x0_voices[i].HardReset(); + } + + PADControlAllMotors(reinterpret_cast< const u32* >(kStopAll)); +} + +void CRumbleGenerator::SetDisabled(const bool disabled) { + if (disabled) { + HardStopAll(); + } + + xf0_24_disabled = disabled; +} diff --git a/src/Kyoto/Input/CRumbleVoice.cpp b/src/Kyoto/Input/CRumbleVoice.cpp index c821a8d8..183a1541 100644 --- a/src/Kyoto/Input/CRumbleVoice.cpp +++ b/src/Kyoto/Input/CRumbleVoice.cpp @@ -22,14 +22,13 @@ short CRumbleVoice::Activate(const SAdsrData& data, ushort idx, float gain, ERum } void CRumbleVoice::Deactivate(short id, bool b1) { - if (id == -1) - return; - if (OwnsSustained(id)) { - return; - } else if (x2c_usedChannels & (1 << (id & 0xf))) { - x10_deltas[(id & 0xf)].x20_phase = SAdsrDelta::kP_Release; + if (id == -1 || !OwnsSustained(id)) { return; } + + if (x2c_usedChannels & (1 << GetChannelId(id))) { + x10_deltas[GetChannelId(id)].x20_phase = SAdsrDelta::kP_Release; + } } void CRumbleVoice::HardReset() { @@ -130,14 +129,15 @@ bool CRumbleVoice::Update(float dt) { return false; } -uint CRumbleVoice::GetFreeChannel() const { +ushort CRumbleVoice::GetFreeChannel() const { for (ushort i = 0; i < 4; ++i) { if ((x2c_usedChannels & (1 << i)) == 0) { - return i; + return (ushort)i; } } return 0; } + float CRumbleVoice::GetIntensity() const { float ret = x10_deltas[0].x0_curIntensity; if (ret < x10_deltas[1].x0_curIntensity) { @@ -158,17 +158,20 @@ float CRumbleVoice::GetIntensity() const { return ret; } + bool CRumbleVoice::OwnsSustained(short handle) const { - ushort idx = (((ushort)handle >> 8) & 0xff); - if (idx < 4) - return x20_handleIds[idx] == (idx & 0xf); - return false; + const ushort i = GetChannelId(handle); + const uint owner = GetOwnerId(handle); + return i < 4 ? x20_handleIds[i] == owner : false; } +/* TODO: Fake matched, find real solution */ short CRumbleVoice::CreateRumbleHandle(ushort idx) { ++x2e_lastId; if (x2e_lastId == 0) x2e_lastId = 1; - x20_handleIds[idx] = x2e_lastId; - return ((x2e_lastId << 8) | idx) & 0xFFFF; + u16 x = idx; + u16* h = &x20_handleIds[x]; + *h = x2e_lastId; + return ((x2e_lastId << 8) | x) & 0xFFFF; }