From 2af0d744cc3486274d046a71cfdcf4c42ce94690 Mon Sep 17 00:00:00 2001 From: Henrique Gemignani Passos Lima Date: Sat, 22 Oct 2022 00:40:29 +0300 Subject: [PATCH] Add CScriptMidi Former-commit-id: 1b5ee3bee85ea2642aed12edea2d7fbbeb8bd1a8 --- asm/MetroidPrime/ScriptObjects/CScriptMidi.s | 12 +-- configure.py | 2 +- include/Kyoto/Audio/CMidiManager.hpp | 15 ++++ include/Kyoto/Basics/CCast.hpp | 12 +++ include/MetroidPrime/CGameArea.hpp | 1 + include/MetroidPrime/CInGameTweakManager.hpp | 4 + .../ScriptObjects/CScriptMidi.hpp | 29 +++++++ include/dolphin/os/OSFastCast.h | 1 + .../ScriptObjects/CScriptCameraWaypoint.cpp | 2 +- .../ScriptObjects/CScriptMidi.cpp | 79 +++++++++++++++++++ 10 files changed, 149 insertions(+), 8 deletions(-) create mode 100644 include/Kyoto/Audio/CMidiManager.hpp create mode 100644 include/MetroidPrime/ScriptObjects/CScriptMidi.hpp create mode 100644 src/MetroidPrime/ScriptObjects/CScriptMidi.cpp diff --git a/asm/MetroidPrime/ScriptObjects/CScriptMidi.s b/asm/MetroidPrime/ScriptObjects/CScriptMidi.s index 54ab3472..a15dabce 100644 --- a/asm/MetroidPrime/ScriptObjects/CScriptMidi.s +++ b/asm/MetroidPrime/ScriptObjects/CScriptMidi.s @@ -3,8 +3,8 @@ .section .data .balign 8 -.global lbl_803E7048 -lbl_803E7048: +.global __vt__11CScriptMidi +__vt__11CScriptMidi: # ROM: 0x3E4048 .4byte 0 .4byte 0 @@ -202,9 +202,9 @@ __dt__11CScriptMidiFv: /* 8020BBDC 00208B3C 93 C1 00 08 */ stw r30, 8(r1) /* 8020BBE0 00208B40 7C 7E 1B 79 */ or. r30, r3, r3 /* 8020BBE4 00208B44 41 82 00 48 */ beq lbl_8020BC2C -/* 8020BBE8 00208B48 3C 80 80 3E */ lis r4, lbl_803E7048@ha +/* 8020BBE8 00208B48 3C 80 80 3E */ lis r4, __vt__11CScriptMidi@ha /* 8020BBEC 00208B4C C0 22 B1 B0 */ lfs f1, lbl_805ACED0@sda21(r2) -/* 8020BBF0 00208B50 38 04 70 48 */ addi r0, r4, lbl_803E7048@l +/* 8020BBF0 00208B50 38 04 70 48 */ addi r0, r4, __vt__11CScriptMidi@l /* 8020BBF4 00208B54 90 1E 00 00 */ stw r0, 0(r30) /* 8020BBF8 00208B58 4B FF FD 45 */ bl StopInternal__11CScriptMidiFf /* 8020BBFC 00208B5C 34 1E 00 34 */ addic. r0, r30, 0x34 @@ -324,9 +324,9 @@ Accept__11CScriptMidiFR8IVisitor: /* 8020BD84 00208CE4 7C 87 23 78 */ mr r7, r4 /* 8020BD88 00208CE8 38 81 00 08 */ addi r4, r1, 8 /* 8020BD8C 00208CEC 4B E4 55 99 */ bl "__ct__7CEntityF9TUniqueIdRC11CEntityInfobRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>" -/* 8020BD90 00208CF0 3C 60 80 3E */ lis r3, lbl_803E7048@ha +/* 8020BD90 00208CF0 3C 60 80 3E */ lis r3, __vt__11CScriptMidi@ha /* 8020BD94 00208CF4 3C 80 43 53 */ lis r4, 0x43534E47@ha -/* 8020BD98 00208CF8 38 03 70 48 */ addi r0, r3, lbl_803E7048@l +/* 8020BD98 00208CF8 38 03 70 48 */ addi r0, r3, __vt__11CScriptMidi@l /* 8020BD9C 00208CFC 38 61 00 0C */ addi r3, r1, 0xc /* 8020BDA0 00208D00 90 1D 00 00 */ stw r0, 0(r29) /* 8020BDA4 00208D04 38 04 4E 47 */ addi r0, r4, 0x43534E47@l diff --git a/configure.py b/configure.py index 4f97c69e..558959b2 100755 --- a/configure.py +++ b/configure.py @@ -312,7 +312,7 @@ LIBS = [ "MetroidPrime/CVisorFlare", "MetroidPrime/Enemies/CFlaahgraPlants", "MetroidPrime/CWorldTransManager", - "MetroidPrime/ScriptObjects/CScriptMidi", + ["MetroidPrime/ScriptObjects/CScriptMidi", False], "MetroidPrime/ScriptObjects/CScriptStreamedAudio", "MetroidPrime/CRagDoll", "MetroidPrime/Player/CGameOptions", diff --git a/include/Kyoto/Audio/CMidiManager.hpp b/include/Kyoto/Audio/CMidiManager.hpp new file mode 100644 index 00000000..4168ffcc --- /dev/null +++ b/include/Kyoto/Audio/CMidiManager.hpp @@ -0,0 +1,15 @@ +#ifndef _CMIDIMANAGER +#define _CMIDIMANAGER + +#include "Kyoto/Audio/CSfxHandle.hpp" + +class CMidiManager { +public: + class CMidiWrapper {}; + class CMidiData {}; + + static CSfxHandle Play(const CMidiData&, unsigned short fadeTime, bool stopExisting, short volume); + static void Stop(const CSfxHandle&, unsigned short); +}; + +#endif // _CMIDIMANAGER diff --git a/include/Kyoto/Basics/CCast.hpp b/include/Kyoto/Basics/CCast.hpp index 354f8a76..62854cbf 100644 --- a/include/Kyoto/Basics/CCast.hpp +++ b/include/Kyoto/Basics/CCast.hpp @@ -36,10 +36,22 @@ inline short FtoS(register float in) { } return *ptr; } + +inline ushort FtoUS(register float in) { + ushort a; + register ushort* ptr = &a; + + asm { + psq_st in, 0(ptr), 1, OS_FASTCAST_U16 + } + return *ptr; +} + #else inline uchar ToUint8(float in) { return static_cast< uchar >(in); } inline float ToReal32(uchar in) { return static_cast< float >(in); } inline short FtoS(float in) { return static_cast< short >(in); } +inline ushort FtoUS(float in) { return static_cast< ushort >(in); } #endif inline int ToInt32(float in) { return static_cast< int >(in); } diff --git a/include/MetroidPrime/CGameArea.hpp b/include/MetroidPrime/CGameArea.hpp index 49c0bd4a..3729e2b3 100644 --- a/include/MetroidPrime/CGameArea.hpp +++ b/include/MetroidPrime/CGameArea.hpp @@ -99,6 +99,7 @@ public: EOcclusionState x10dc_occlusionState; }; + CAssetId GetAreaAssetId() const { return x84_mrea; } const CAreaFog* GetAreaFog() const { return x12c_postConstructed->x10c4_areaFog.get(); } CAreaFog* AreaFog() { return x12c_postConstructed->x10c4_areaFog.get(); } EOcclusionState GetOcclusionState() const { return x12c_postConstructed->x10dc_occlusionState; } diff --git a/include/MetroidPrime/CInGameTweakManager.hpp b/include/MetroidPrime/CInGameTweakManager.hpp index b62e959c..125092b7 100644 --- a/include/MetroidPrime/CInGameTweakManager.hpp +++ b/include/MetroidPrime/CInGameTweakManager.hpp @@ -58,8 +58,12 @@ class CInGameTweakManager { public: CInGameTweakManager(); + bool HasTweakValue(const rstl::string& name) const; + const CTweakValue* GetTweakValue(const rstl::string& name) const; bool ReadFromMemoryCard(const rstl::string&); + static rstl::string GetIdentifierForMidiEvent(CAssetId world, CAssetId area, const rstl::string& midiObj); + private: rstl::vector< CTweakValue > x0_values; }; diff --git a/include/MetroidPrime/ScriptObjects/CScriptMidi.hpp b/include/MetroidPrime/ScriptObjects/CScriptMidi.hpp new file mode 100644 index 00000000..58770074 --- /dev/null +++ b/include/MetroidPrime/ScriptObjects/CScriptMidi.hpp @@ -0,0 +1,29 @@ +#ifndef _CSCRIPTMIDI +#define _CSCRIPTMIDI + +#include "MetroidPrime/CEntity.hpp" + +#include "Kyoto/Audio/CMidiManager.hpp" + +class CScriptMidi : public CEntity { +public: + CScriptMidi(TUniqueId id, const CEntityInfo& info, const rstl::string& name, bool active, + CAssetId csng, float, float, int); + ~CScriptMidi() override; + + void Stop(CStateManager& mgr, float fadeTime); + void Play(CStateManager& mgr, float fadeTime); + void Accept(IVisitor& visitor) override; + void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CStateManager& stateMgr) override; + +private: + TToken< CMidiManager::CMidiData > x34_song; + CSfxHandle x3c_handle; + float x40_fadeInTime; + float x44_fadeOutTime; + ushort x48_volume; + + void StopInternal(float fadeTime); +}; + +#endif // _CSCRIPTMIDI diff --git a/include/dolphin/os/OSFastCast.h b/include/dolphin/os/OSFastCast.h index 5b3f8d41..1be2a9a4 100644 --- a/include/dolphin/os/OSFastCast.h +++ b/include/dolphin/os/OSFastCast.h @@ -6,6 +6,7 @@ extern "C" { #endif #define OS_FASTCAST_U8 2 +#define OS_FASTCAST_U16 3 #define OS_FASTCAST_S16 5 #ifdef __cplusplus diff --git a/src/MetroidPrime/ScriptObjects/CScriptCameraWaypoint.cpp b/src/MetroidPrime/ScriptObjects/CScriptCameraWaypoint.cpp index 2f962281..f480dfe9 100644 --- a/src/MetroidPrime/ScriptObjects/CScriptCameraWaypoint.cpp +++ b/src/MetroidPrime/ScriptObjects/CScriptCameraWaypoint.cpp @@ -30,7 +30,7 @@ TUniqueId CScriptCameraWaypoint::GetRandomNextWaypointId(const CStateManager& mg rstl::vector< TUniqueId > candidateIds; rstl::vector< SConnection >::const_iterator conn = x20_conns.begin(); - + for (; conn != x20_conns.end(); ++conn) { if (conn->x0_state == kSS_Arrived && conn->x4_msg == kSM_Next) { TUniqueId uid = mgr.GetIdForScript(conn->x8_objId); diff --git a/src/MetroidPrime/ScriptObjects/CScriptMidi.cpp b/src/MetroidPrime/ScriptObjects/CScriptMidi.cpp new file mode 100644 index 00000000..ff8196fd --- /dev/null +++ b/src/MetroidPrime/ScriptObjects/CScriptMidi.cpp @@ -0,0 +1,79 @@ +#include "MetroidPrime/ScriptObjects/CScriptMidi.hpp" + +#include "MetroidPrime/CGameArea.hpp" +#include "MetroidPrime/CInGameTweakManager.hpp" +#include "MetroidPrime/CWorld.hpp" + +CScriptMidi::CScriptMidi(TUniqueId id, const CEntityInfo& info, const rstl::string& name, + bool active, CAssetId csng, float fadeIn, float fadeOut, int volume) +: CEntity(id, info, active, name) +, x34_song(gpSimplePool->GetObj(SObjectTag('CSNG', csng))) +, x3c_handle() +, x40_fadeInTime(fadeIn) +, x44_fadeOutTime(fadeOut) +, x48_volume(volume) {} + +void CScriptMidi::Accept(IVisitor& visitor) { visitor.Visit(*this); } + +void CScriptMidi::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, + CStateManager& stateMgr) { + CEntity::AcceptScriptMsg(msg, objId, stateMgr); + switch (msg) { + case kSM_Play: + if (GetActive()) { + Play(stateMgr, x40_fadeInTime); + } + break; + case kSM_Stop: + if (GetActive()) { + Stop(stateMgr, x44_fadeOutTime); + } + break; + case kSM_Deactivate: + StopInternal(0.f); + break; + default: + break; + } +} + +CScriptMidi::~CScriptMidi() { StopInternal(0.f); } + +void CScriptMidi::Play(CStateManager& mgr, float fadeTime) { + short volume = x48_volume; + + const CWorld* wld = mgr.GetWorld(); + const CGameArea& area = wld->GetAreaAlways(GetAreaIdAlways()); + rstl::string twkName = CInGameTweakManager::GetIdentifierForMidiEvent( + wld->GetWorldAssetId(), area.GetAreaAssetId(), x10_name); + + if (gpTweakManager->HasTweakValue(twkName)) { + const CTweakValue::Audio& audio = gpTweakManager->GetTweakValue(twkName)->GetAudio(); + x34_song = gpSimplePool->GetObj(SObjectTag('CSNG', audio.GetResId())); + fadeTime = audio.GetFadeIn(); + volume = static_cast< short >(audio.GetVolume() * 127.f); + } + + x3c_handle = CMidiManager::Play(**x34_song, CCast::FtoUS(fadeTime * 1000.f), false, volume); +} + +void CScriptMidi::Stop(CStateManager& mgr, float fadeTime) { + const CWorld* wld = mgr.GetWorld(); + const CGameArea& area = wld->GetAreaAlways(GetAreaIdAlways()); + const rstl::string twkName = CInGameTweakManager::GetIdentifierForMidiEvent( + wld->GetWorldAssetId(), area.GetAreaAssetId(), x10_name); + + if (gpTweakManager->HasTweakValue(twkName)) { + const CTweakValue::Audio& audio = gpTweakManager->GetTweakValue(twkName)->GetAudio(); + fadeTime = audio.GetFadeOut(); + } + + StopInternal(fadeTime); +} + +void CScriptMidi::StopInternal(float fadeTime) { + if (x3c_handle != CSfxHandle::NullHandle()) { + CMidiManager::Stop(x3c_handle, CCast::FtoUS(fadeTime * 1000.f)); + } + x3c_handle.Clear(); +}