From 9b5566fa05a347427d2d81144f06d3d0fe54f23d Mon Sep 17 00:00:00 2001 From: kiwi515 <49212064+kiwi515@users.noreply.github.com> Date: Fri, 23 Jan 2026 20:39:50 -0500 Subject: [PATCH 1/2] RPSndSpeakerMgr, RPSndUtility, RPSndObject OK --- config/RSPE01_01/splits.txt | 2 +- config/RSPE01_01/symbols.txt | 100 +++---- configure.py | 6 +- include/Pack/RPAudio.h | 10 + include/Pack/RPAudio/RPSndAudioMgr.h | 36 +++ include/Pack/RPAudio/RPSndMoveParam.h | 151 ++++++++++ include/Pack/RPAudio/RPSndObject.h | 210 ++++++++++++++ include/Pack/RPAudio/RPSndSpeakerMgr.h | 201 +++++++++++++ include/Pack/RPAudio/RPSndUtility.h | 50 ++++ include/egg/audio.h | 1 + include/egg/audio/eggAudio3DActor.h | 2 +- include/egg/audio/eggAudioActor.h | 21 ++ include/egg/audio/eggAudioExpMgr.h | 4 - include/egg/audio/eggAudioMgr.h | 4 +- include/nw4r/snd/snd_SeqSoundHandle.h | 7 +- include/nw4r/snd/snd_SoundHandle.h | 15 +- src/Pack/RPAudio/RPSndMoveParam.cpp | 149 ++++++++++ src/Pack/RPAudio/RPSndObject.cpp | 37 +++ src/Pack/RPAudio/RPSndSpeakerMgr.cpp | 377 +++++++++++++++++++++++++ src/Pack/RPAudio/RPSndUtility.cpp | 48 ++++ 20 files changed, 1366 insertions(+), 65 deletions(-) create mode 100644 include/Pack/RPAudio.h create mode 100644 include/Pack/RPAudio/RPSndAudioMgr.h create mode 100644 include/Pack/RPAudio/RPSndMoveParam.h create mode 100644 include/Pack/RPAudio/RPSndObject.h create mode 100644 include/Pack/RPAudio/RPSndSpeakerMgr.h create mode 100644 include/Pack/RPAudio/RPSndUtility.h create mode 100644 include/egg/audio/eggAudioActor.h create mode 100644 src/Pack/RPAudio/RPSndMoveParam.cpp create mode 100644 src/Pack/RPAudio/RPSndObject.cpp create mode 100644 src/Pack/RPAudio/RPSndSpeakerMgr.cpp create mode 100644 src/Pack/RPAudio/RPSndUtility.cpp diff --git a/config/RSPE01_01/splits.txt b/config/RSPE01_01/splits.txt index 25186a4f..5ce4bdd9 100644 --- a/config/RSPE01_01/splits.txt +++ b/config/RSPE01_01/splits.txt @@ -3235,10 +3235,10 @@ Pack/RPAudio/RPSndSpeakerMgr.cpp: Pack/RPAudio/RPSndObject.cpp: .text start:0x801B8EF8 end:0x801B8F78 .bss start:0x804A4670 end:0x804A4680 - .sbss start:0x804BF658 end:0x804BF660 Pack/RPAudio/RPSndUtility.cpp: .text start:0x801B8F78 end:0x801B9070 + .sbss start:0x804BF658 end:0x804BF660 .sdata2 start:0x804C1970 end:0x804C1980 Pack/RPAudio/RPSndMoveParam.cpp: diff --git a/config/RSPE01_01/symbols.txt b/config/RSPE01_01/symbols.txt index 14a7b700..62928a93 100644 --- a/config/RSPE01_01/symbols.txt +++ b/config/RSPE01_01/symbols.txt @@ -8159,31 +8159,31 @@ fn_801B8364 = .text:0x801B8364; // type:function size:0x8 fn_801B836C = .text:0x801B836C; // type:function size:0x8 fn_801B8374 = .text:0x801B8374; // type:function size:0x8 fn_801B837C = .text:0x801B837C; // type:function size:0x8 -fn_801B8384 = .text:0x801B8384; // type:function size:0x2C -fn_801B83B0 = .text:0x801B83B0; // type:function size:0x80 -fn_801B8430 = .text:0x801B8430; // type:function size:0xF8 -fn_801B8528 = .text:0x801B8528; // type:function size:0x34 -fn_801B855C = .text:0x801B855C; // type:function size:0x30 -fn_801B858C = .text:0x801B858C; // type:function size:0xD0 -fn_801B865C = .text:0x801B865C; // type:function size:0xD4 -fn_801B8730 = .text:0x801B8730; // type:function size:0x58 -fn_801B8788 = .text:0x801B8788; // type:function size:0xE4 -fn_801B886C = .text:0x801B886C; // type:function size:0x190 -fn_801B89FC = .text:0x801B89FC; // type:function size:0xEC -fn_801B8AE8 = .text:0x801B8AE8; // type:function size:0x30 -fn_801B8B18 = .text:0x801B8B18; // type:function size:0x80 -fn_801B8B98 = .text:0x801B8B98; // type:function size:0x208 -fn_801B8DA0 = .text:0x801B8DA0; // type:function size:0xF8 -fn_801B8E98 = .text:0x801B8E98; // type:function size:0x60 -fn_801B8EF8 = .text:0x801B8EF8; // type:function size:0x80 -fn_801B8F78 = .text:0x801B8F78; // type:function size:0xF8 -fn_801B9070 = .text:0x801B9070; // type:function size:0x94 -fn_801B9104 = .text:0x801B9104; // type:function size:0x168 -fn_801B926C = .text:0x801B926C; // type:function size:0x3C -fn_801B92A8 = .text:0x801B92A8; // type:function size:0x78 -fn_801B9320 = .text:0x801B9320; // type:function size:0x4C -fn_801B936C = .text:0x801B936C; // type:function size:0x2C -fn_801B9398 = .text:0x801B9398; // type:function size:0x8 +isDisconnectAllFinished__15RPSndSpeakerMgrFv = .text:0x801B8384; // type:function size:0x2C +disconnectAll__15RPSndSpeakerMgrFv = .text:0x801B83B0; // type:function size:0x80 +connectAll__15RPSndSpeakerMgrFv = .text:0x801B8430; // type:function size:0xF8 +setSpeakerShutdownCallback__15RPSndSpeakerMgrFll = .text:0x801B8528; // type:function size:0x34 +setSpeakerSetupCallback__15RPSndSpeakerMgrFll = .text:0x801B855C; // type:function size:0x30 +setSpeakerOffCallback__15RPSndSpeakerMgrFll = .text:0x801B858C; // type:function size:0xD0 +setSpeakerOnCallback__15RPSndSpeakerMgrFll = .text:0x801B865C; // type:function size:0xD4 +__dt__15RPSndSpeakerMgrFv = .text:0x801B8730; // type:function size:0x58 +__ct__15RPSndSpeakerMgrFPQ23EGG4Heap = .text:0x801B8788; // type:function size:0xE4 +setRemoteSend__15RPSndSpeakerMgrFPQ34nw4r3snd11SoundHandleUlfff = .text:0x801B886C; // type:function size:0x190 +setEnableSw__15RPSndSpeakerMgrFlb = .text:0x801B89FC; // type:function size:0xEC +updateMasterVolume__15RPSndSpeakerMgrFv = .text:0x801B8AE8; // type:function size:0x30 +exit__15RPSndSpeakerMgrFv = .text:0x801B8B18; // type:function size:0x80 +calc__15RPSndSpeakerMgrFv = .text:0x801B8B98; // type:function size:0x208 +reset__15RPSndSpeakerMgrFv = .text:0x801B8DA0; // type:function size:0xF8 +CreateInstance__15RPSndSpeakerMgrFPQ23EGG4Heap = .text:0x801B8E98; // type:function size:0x60 +stopAllActorSound__11RPSndObjMgrFi = .text:0x801B8EF8; // type:function size:0x80 +setHandleDpdPan__12RPSndUtilityFRQ34nw4r3snd11SoundHandleRCQ34nw4r4math4VEC2f = .text:0x801B8F78; // type:function size:0xF8 +update__17RPSndMoveParamMgrFv = .text:0x801B9070; // type:function size:0x94 +update__14RPSndMoveParamFv = .text:0x801B9104; // type:function size:0x168 +__ct__14RPSndMoveParamFQ214RPSndMoveParam13ParamCategoryRQ34nw4r3snd11SoundHandle = .text:0x801B926C; // type:function size:0x3C +update__17RPSndMoveValueF32Fv = .text:0x801B92A8; // type:function size:0x78 +moveValue__17RPSndMoveValueF32FfUl = .text:0x801B9320; // type:function size:0x4C +__ct__17RPSndMoveValueF32Fv = .text:0x801B936C; // type:function size:0x2C +@8@update__14RPSndMoveParamFv = .text:0x801B9398; // type:function size:0x8 fn_801B93A0 = .text:0x801B93A0; // type:function size:0x18 fn_801B93B8 = .text:0x801B93B8; // type:function size:0x54 fn_801B940C = .text:0x801B940C; // type:function size:0x90 @@ -9860,7 +9860,7 @@ fn_80214AC8 = .text:0x80214AC8; // type:function size:0x9C fn_80214B64 = .text:0x80214B64; // type:function size:0x200 fn_80214D64 = .text:0x80214D64; // type:function size:0x78 fn_80214DDC = .text:0x80214DDC; // type:function size:0x58 -fn_80214E34 = .text:0x80214E34; // type:function size:0xC +__ct__Q34nw4r3snd11SoundHandleFv = .text:0x80214E34; // type:function size:0xC fn_80214E40 = .text:0x80214E40; // type:function size:0x104 fn_80214F44 = .text:0x80214F44; // type:function size:0x78 fn_80214FBC = .text:0x80214FBC; // type:function size:0x44 @@ -10056,12 +10056,12 @@ fn_8021DAC4 = .text:0x8021DAC4; // type:function size:0xB4 fn_8021DB78 = .text:0x8021DB78; // type:function size:0x8 fn_8021DB80 = .text:0x8021DB80; // type:function size:0x464 fn_8021DFE4 = .text:0x8021DFE4; // type:function size:0x10C -fn_8021E0F0 = .text:0x8021E0F0; // type:function size:0xB0 -fn_8021E1A0 = .text:0x8021E1A0; // type:function size:0xAC +__dt__15TRPSndObject<4>Fv = .text:0x8021E0F0; // type:function size:0xB0 +__dt__36TRPSndAudioActorBaseWithHandles<4,4>Fv = .text:0x8021E1A0; // type:function size:0xAC fn_8021E24C = .text:0x8021E24C; // type:function size:0x58 -fn_8021E2A4 = .text:0x8021E2A4; // type:function size:0x8 -fn_8021E2AC = .text:0x8021E2AC; // type:function size:0x8 -fn_8021E2B4 = .text:0x8021E2B4; // type:function size:0x8 +getOuterPitch__21TRPSndAudioHandles<8>Fv = .text:0x8021E2A4; // type:function size:0x8 +getOuterVolume__21TRPSndAudioHandles<8>Fv = .text:0x8021E2AC; // type:function size:0x8 +get3DPosition__36TRPSndAudioActorBaseWithHandles<4,4>Fi = .text:0x8021E2B4; // type:function size:0x8 fn_8021E2BC = .text:0x8021E2BC; // type:function size:0xE8 fn_8021E3A4 = .text:0x8021E3A4; // type:function size:0x110 fn_8021E4B4 = .text:0x8021E4B4; // type:function size:0x11C @@ -14253,11 +14253,11 @@ fn_8032781C = .text:0x8032781C; // type:function size:0x3C fn_80327858 = .text:0x80327858; // type:function size:0x298 fn_80327AF0 = .text:0x80327AF0; // type:function size:0xA0 fn_80327B90 = .text:0x80327B90; // type:function size:0x4C -fn_80327BDC = .text:0x80327BDC; // type:function size:0x70 -fn_80327C4C = .text:0x80327C4C; // type:function size:0x4C -fn_80327C98 = .text:0x80327C98; // type:function size:0x64 -fn_80327CFC = .text:0x80327CFC; // type:function size:0x6C -fn_80327D68 = .text:0x80327D68; // type:function size:0x9C +__ct__15TRPSndObject<4>FRQ34nw4r3snd18SoundArchivePlayerRQ34nw4r3snd14Sound3DManagerUl = .text:0x80327BDC; // type:function size:0x70 +__ct__36TRPSndAudioActorBaseWithHandles<4,4>Fi = .text:0x80327C4C; // type:function size:0x4C +__ct__21TRPSndAudioHandles<8>Fv = .text:0x80327C98; // type:function size:0x64 +__ct__19RPSndAudioActorBaseFi = .text:0x80327CFC; // type:function size:0x6C +__ct__21TRPSndAudio3DActor<4>FRQ34nw4r3snd18SoundArchivePlayer = .text:0x80327D68; // type:function size:0x9C fn_80327E04 = .text:0x80327E04; // type:function size:0xC fn_80327E10 = .text:0x80327E10; // type:function size:0x8 fn_80327E18 = .text:0x80327E18; // type:function size:0x8 @@ -18722,8 +18722,8 @@ lbl_803BAA20 = .data:0x803BAA20; // type:object size:0xD data:string lbl_803BAA30 = .data:0x803BAA30; // type:object size:0x10 data:string lbl_803BAA40 = .data:0x803BAA40; // type:object size:0xC data:string lbl_803BAA50 = .data:0x803BAA50; // type:object size:0x10 data:string -lbl_803BAA60 = .data:0x803BAA60; // type:object size:0x10 -lbl_803BAA70 = .data:0x803BAA70; // type:object size:0x18 +__vt__15RPSndSpeakerMgr = .data:0x803BAA60; // type:object size:0xC +__vt__14RPSndMoveParam = .data:0x803BAA70; // type:object size:0x18 lbl_803BAA88 = .data:0x803BAA88; // type:object size:0x10 lbl_803BAA98 = .data:0x803BAA98; // type:object size:0x88 sStaticSoundArchive__14RPSndStaticMgr = .data:0x803BAB20; // type:object size:0x6BA0 align:32 noreloc @@ -18892,7 +18892,7 @@ lbl_803C3718 = .data:0x803C3718; // type:object size:0x18 lbl_803C3730 = .data:0x803C3730; // type:object size:0x80 lbl_803C37B0 = .data:0x803C37B0; // type:object size:0x68 lbl_803C3818 = .data:0x803C3818; // type:object size:0x10 -lbl_803C3828 = .data:0x803C3828; // type:object size:0x28 +__vt__19RPSndAudioActorBase = .data:0x803C3828; // type:object size:0x28 lbl_803C3850 = .data:0x803C3850; // type:object size:0x10 lbl_803C3860 = .data:0x803C3860; // type:object size:0x10 lbl_803C3870 = .data:0x803C3870; // type:object size:0xC @@ -18914,7 +18914,7 @@ lbl_803C3CD8 = .data:0x803C3CD8; // type:object size:0x30 lbl_803C3D08 = .data:0x803C3D08; // type:object size:0x30 lbl_803C3D38 = .data:0x803C3D38; // type:object size:0xDC lbl_803C3E14 = .data:0x803C3E14; // type:object size:0xDC -lbl_803C3EF0 = .data:0x803C3EF0; // type:object size:0xD0 +__vt__15TRPSndObject<4> = .data:0x803C3EF0; // type:object size:0xD0 lbl_803C3FC0 = .data:0x803C3FC0; // type:object size:0x38 lbl_803C3FF8 = .data:0x803C3FF8; // type:object size:0x10 lbl_803C4008 = .data:0x803C4008; // type:object size:0x10 @@ -19888,8 +19888,8 @@ lbl_804A45BC = .bss:0x804A45BC; // type:object size:0x4C align:4 data:float lbl_804A4608 = .bss:0x804A4608; // type:object size:0x30 align:4 data:float lbl_804A4638 = .bss:0x804A4638; // type:object size:0x28 data:byte lbl_804A4660 = .bss:0x804A4660; // type:object size:0x10 data:4byte -lbl_804A4670 = .bss:0x804A4670; // type:object size:0x10 -lbl_804A4680 = .bss:0x804A4680; // type:object size:0x10 +sActorList__19RPSndAudioActorBase = .bss:0x804A4670; // type:object size:0xC +sMoveParamList__17RPSndMoveParamMgr = .bss:0x804A4680; // type:object size:0x10 lbl_804A4690 = .bss:0x804A4690; // type:object size:0xC align:4 data:float lbl_804A469C = .bss:0x804A469C; // type:object size:0xC align:4 data:float lbl_804A46A8 = .bss:0x804A46A8; // type:object size:0xC align:4 data:float @@ -21939,10 +21939,10 @@ lbl_804BF628 = .sbss:0x804BF628; // type:object size:0x8 data:byte lbl_804BF630 = .sbss:0x804BF630; // type:object size:0x8 data:4byte lbl_804BF638 = .sbss:0x804BF638; // type:object size:0x8 data:4byte lbl_804BF640 = .sbss:0x804BF640; // type:object size:0x4 data:4byte -lbl_804BF644 = .sbss:0x804BF644; // type:object size:0x4 data:4byte +spInstance__13RPSndAudioMgr = .sbss:0x804BF644; // type:object size:0x4 data:4byte lbl_804BF648 = .sbss:0x804BF648; // type:object size:0x8 data:4byte -lbl_804BF650 = .sbss:0x804BF650; // type:object size:0x8 data:4byte -lbl_804BF658 = .sbss:0x804BF658; // type:object size:0x8 data:4byte +spInstance__15RPSndSpeakerMgr = .sbss:0x804BF650; // type:object size:0x4 data:4byte +spSoundArchivePlayer__12RPSndUtility = .sbss:0x804BF658; // type:object size:0x4 data:4byte lbl_804BF660 = .sbss:0x804BF660; // type:object size:0x8 align:4 data:float lbl_804BF668 = .sbss:0x804BF668; // type:object size:0x8 data:4byte lbl_804BF670 = .sbss:0x804BF670; // type:object size:0x4 data:4byte @@ -23726,11 +23726,11 @@ lbl_804C1954 = .sdata2:0x804C1954; // type:object size:0x4 align:4 data:float lbl_804C1958 = .sdata2:0x804C1958; // type:object size:0x4 align:4 data:float gap_12_804C195C_sdata2 = .sdata2:0x804C195C; // type:object size:0x4 scope:global lbl_804C1960 = .sdata2:0x804C1960; // type:object size:0x8 align:8 data:double -lbl_804C1968 = .sdata2:0x804C1968; // type:object size:0x8 align:4 data:float -lbl_804C1970 = .sdata2:0x804C1970; // type:object size:0x4 align:4 data:float -lbl_804C1974 = .sdata2:0x804C1974; // type:object size:0x4 align:4 data:float -lbl_804C1978 = .sdata2:0x804C1978; // type:object size:0x4 align:4 data:float -lbl_804C197C = .sdata2:0x804C197C; // type:object size:0x4 align:4 data:float +@11215 = .sdata2:0x804C1968; // type:object size:0x4 scope:local align:4 data:float +@10669 = .sdata2:0x804C1970; // type:object size:0x4 scope:local align:4 data:float +@10670 = .sdata2:0x804C1974; // type:object size:0x4 scope:local align:4 data:float +@10671 = .sdata2:0x804C1978; // type:object size:0x4 scope:local align:4 data:float +@10672 = .sdata2:0x804C197C; // type:object size:0x4 scope:local align:4 data:float lbl_804C1980 = .sdata2:0x804C1980; // type:object size:0x8 align:8 data:double lbl_804C1988 = .sdata2:0x804C1988; // type:object size:0x8 align:4 data:float lbl_804C1990 = .sdata2:0x804C1990; // type:object size:0x4 align:4 data:float diff --git a/configure.py b/configure.py index 5ddf83cf..040774d7 100755 --- a/configure.py +++ b/configure.py @@ -1216,9 +1216,9 @@ def MatchingFor(*versions): "progress_category": "audio", # str | List[str] "objects": [ Object(NonMatching, "Pack/RPAudio/RPSndAudioMgr.cpp"), - Object(NonMatching, "Pack/RPAudio/RPSndSpeakerMgr.cpp"), - Object(NonMatching, "Pack/RPAudio/RPSndObject.cpp"), - Object(NonMatching, "Pack/RPAudio/RPSndUtility.cpp"), + Object(Matching, "Pack/RPAudio/RPSndSpeakerMgr.cpp"), + Object(Matching, "Pack/RPAudio/RPSndObject.cpp"), + Object(Matching, "Pack/RPAudio/RPSndUtility.cpp"), Object(NonMatching, "Pack/RPAudio/RPSndMoveParam.cpp"), Object(NonMatching, "Pack/RPAudio/RPSndHomeMenuArcMgr.cpp"), Object(NonMatching, "Pack/RPAudio/RPSndStaticMgr.cpp"), diff --git a/include/Pack/RPAudio.h b/include/Pack/RPAudio.h new file mode 100644 index 00000000..2042e42c --- /dev/null +++ b/include/Pack/RPAudio.h @@ -0,0 +1,10 @@ +#ifndef RP_PUBLIC_AUDIO_H +#define RP_PUBLIC_AUDIO_H + +#include +#include +#include +#include +#include + +#endif diff --git a/include/Pack/RPAudio/RPSndAudioMgr.h b/include/Pack/RPAudio/RPSndAudioMgr.h new file mode 100644 index 00000000..5cedeb68 --- /dev/null +++ b/include/Pack/RPAudio/RPSndAudioMgr.h @@ -0,0 +1,36 @@ +#ifndef RP_AUDIO_SND_AUDIO_MGR_H +#define RP_AUDIO_SND_AUDIO_MGR_H +#include + +#include + +#include +#include + +#include + +//! @addtogroup rp_audio +//! @{ + +/** + * @brief RP sound manager (BGM, SFX, etc.) + */ +class RPSndAudioMgr : public EGG::ExpAudioMgr { + RP_SINGLETON_DECL_EX(RPSndAudioMgr); + +public: + u32 getUserParam(const nw4r::snd::SoundArchivePlayer& rPlayer, + u32 id) const; + + u32 getPlayerNum() const { + return mPlayerNum; + } + +private: + char unk8A0[0x968 - 0x8A0]; + u32 mPlayerNum; // at 0x968 +}; + +//! @} + +#endif diff --git a/include/Pack/RPAudio/RPSndMoveParam.h b/include/Pack/RPAudio/RPSndMoveParam.h new file mode 100644 index 00000000..b5522b52 --- /dev/null +++ b/include/Pack/RPAudio/RPSndMoveParam.h @@ -0,0 +1,151 @@ +#ifndef RP_AUDIO_SND_MOVE_PARAM_H +#define RP_AUDIO_SND_MOVE_PARAM_H +#include + +#include +#include + +//! @addtogroup rp_audio +//! @{ + +/****************************************************************************** + * + * RPSndMoveValueF32 + * + ******************************************************************************/ + +/** + * @brief Configurable value interpolation + */ +class RPSndMoveValueF32 { +public: + /** + * @brief Move value callback + * + * @param value Current move value + * @param pUserData Callback user argument + */ + typedef void (*Callback)(f32 value, void* pUserData); + +public: + /** + * @brief Constructor + */ + RPSndMoveValueF32(); + + /** + * @brief Begins interpolation of this value + * + * @param target Interpolation target + * @param frame Interpolation duration + */ + void moveValue(f32 target, u32 frame); + + /** + * @brief Updates the interpolation state + * + * @return Whether interpolation is ongoing + */ + virtual bool update(); // at 0x8 + +protected: + //! Interpolation callback + Callback mpCallback; // at 0x4 + //! Callback user argument + void* mpUserData; // at 0x8 + + //! Remaining frame count + u32 mFrame; // at 0xC + //! Move target value + f32 mTarget; // at 0x10 + //! Current move value + f32 mValue; // at 0x14 + //! Frame delta value + f32 mDelta; // at 0x18 +}; + +/****************************************************************************** + * + * RPSndMoveParamLink + * + ******************************************************************************/ + +/** + * @brief Move parameter linked-list item + */ +class RPSndMoveParamLink { +public: + //! Linked-list node + NW4R_UT_LIST_LINK_DECL(); // at 0x0 +}; + +/****************************************************************************** + * + * RPSndMoveParam + * + ******************************************************************************/ + +/** + * @brief Sound parameter interpolation + */ +class RPSndMoveParam : public RPSndMoveParamLink, public RPSndMoveValueF32 { +public: + /** + * @brief Move parameter type + */ + enum ParamCategory { + ParamCategory_SoundPitch, //!< Controls pitch of the attached sound + ParamCategory_SoundLpf, //!< Controls LPF freq. of the attached sound + ParamCategory_TrackVolume, //!< Controls volume of the selected track(s) + ParamCategory_TrackPitch, //!< Controls pitch of the selected track(s) + }; + +public: + /** + * @brief Constructor + * + * @param category Sound parameter category + * @param rHandle Sound handle + */ + RPSndMoveParam(ParamCategory category, nw4r::snd::SoundHandle& rHandle); + + /** + * @brief Updates the interpolation state + * + * @return Whether interpolation is ongoing + */ + virtual bool update(); // at 0x8 + +private: + //! Sound handle + nw4r::snd::SoundHandle& mrHandle; // at 0x28 + //! Sound parameter category + ParamCategory mCategory; // at 0x2C + //! Sequence sound track flags + u32 mTrackFlags; // at 0x30 +}; + +/****************************************************************************** + * + * RPSndMoveParamMgr + * + ******************************************************************************/ + +/** + * @brief Move parameter manager + */ +class RPSndMoveParamMgr { +public: + /** + * @brief Updates the state of all move parameters + */ + void update(); + +private: + //! List of all active move parameters + static nw4r::ut::List sMoveParamList; +}; + +//! @} + +#endif diff --git a/include/Pack/RPAudio/RPSndObject.h b/include/Pack/RPAudio/RPSndObject.h new file mode 100644 index 00000000..41d8da20 --- /dev/null +++ b/include/Pack/RPAudio/RPSndObject.h @@ -0,0 +1,210 @@ +#ifndef RP_AUDIO_SND_OBJECT_H +#define RP_AUDIO_SND_OBJECT_H +#include + +#include +#include + +#include +#include + +#include +#include + +//! @addtogroup rp_audio +//! @{ + +/****************************************************************************** + * + * RPSndAudioActorBase + * + ******************************************************************************/ + +/** + * @brief Base class for managed audio actors + */ +class RPSndAudioActorBase : public EGG::Disposer { + friend class RPSndObjMgr; + +public: + RPSndAudioActorBase(UNKWORD arg0) : mIsSilenced(false), WORD_0x14(arg0) { + nw4r::ut::List_Append(&sActorList, this); + } + + virtual ~RPSndAudioActorBase() { // at 0x8 + nw4r::ut::List_Remove(&sActorList, this); + } + + virtual void stopSound(u32 id, int frames) = 0; // at 0xC + virtual void stopSound(unsigned int id, int frames) = 0; // at 0x10 + virtual void stopSound(const char* pName, int frames) = 0; // at 0x14 + virtual void stopAllSound(int frames) = 0; // at 0x18 + + virtual void setActorVolume(f32 volume, int frames) = 0; // at 0x1C + virtual void update() = 0; // at 0x20 + + static nw4r::ut::List& getActorList() { + return sActorList; + } + +protected: + RPSndMoveValueF32 mVolume; // at 0x8 + bool mIsSilenced; // at 0x10 + UNKWORD WORD_0x14; // at 0x14 + char unk18[0x20 - 0x18]; + +private: + static nw4r::ut::List sActorList; +}; + +/****************************************************************************** + * + * TRPSndAudioHandles + * + ******************************************************************************/ +template class TRPSndAudioHandles { +public: + TRPSndAudioHandles() { + mHandleCount = N; + unkC = N; + } + + ~TRPSndAudioHandles() { + mHandleCount = 0; + unkC = 0; + } + + virtual f32 getOuterVolume() { + return 1.0f; + } // at 0x8 + + virtual f32 getOuterPitch() { + return 1.0f; + } // at 0xC + +protected: + s32 mHandleCount; + s32 unkC; + nw4r::snd::SoundHandle mSoundHandles[N]; +}; + +/****************************************************************************** + * + * TRPSndAudioActorBaseWithHandles + * + ******************************************************************************/ +template +class TRPSndAudioActorBaseWithHandles : public RPSndAudioActorBase, + public TRPSndAudioHandles { +public: + TRPSndAudioActorBaseWithHandles(UNKWORD arg0) : RPSndAudioActorBase(arg0) {} + + virtual const nw4r::math::VEC3* get3DPosition(int /* idx */) { // at 0x10 + return NULL; + } +}; + +/****************************************************************************** + * + * TRPSndAudio3DActor + * + ******************************************************************************/ +template +class TRPSndAudio3DActor : public EGG::AudioSoundActorBaseWithCamera { +public: + TRPSndAudio3DActor(nw4r::snd::SoundArchivePlayer& rPlayer) { + for (int i = 0; i < N; i++) { +#line 375 + RP_ASSERT(smCommon3DManager[i]); + + mSound3DActors[i] = + new nw4r::snd::Sound3DActor(rPlayer, *smCommon3DManager[i]); + } + } + +protected: + nw4r::snd::Sound3DActor* mSound3DActors[N]; +}; + +/****************************************************************************** + * + * TRPSndObject + * + ******************************************************************************/ +template +class TRPSndObject : public TRPSndAudio3DActor, + public TRPSndAudioActorBaseWithHandles { +public: + enum RemoteFlag { + FLAG_REMOTE_1 = 1 << 0, + FLAG_REMOTE_2 = 1 << 1, + FLAG_REMOTE_3 = 1 << 2, + FLAG_REMOTE_4 = 1 << 3, + + FLAG_REMOTE_ALL = + FLAG_REMOTE_1 | FLAG_REMOTE_2 | FLAG_REMOTE_3 | FLAG_REMOTE_4 + }; + +public: + TRPSndObject(nw4r::snd::SoundArchivePlayer& rPlayer, + nw4r::snd::Sound3DManager& /* rManager */, + u32 remoteFlag = FLAG_REMOTE_ALL) + : TRPSndAudio3DActor(rPlayer), + TRPSndAudioActorBaseWithHandles(0), + BOOL_0x7C(false), + mRemoteFlag(remoteFlag) {} + + virtual const nw4r::math::VEC3* get3DPosition(int idx); // at 0x10 + virtual void set3DPosition(const nw4r::math::VEC3& rPos); // at 0x14 + + virtual void calc(); // at 0x18 + virtual void update(); // at 0x1C + + virtual nw4r::snd::SoundHandle* startSoundWithRemotePlayer(u32, u32, + s32); // at 0x20 + virtual nw4r::snd::SoundHandle* + startSoundWithRemotePlayer(unsigned int, u32, s32); // at 0x24 + virtual nw4r::snd::SoundHandle* startSoundWithRemotePlayer(const char*, u32, + s32); // at 0x28 + + virtual nw4r::snd::SoundHandle* startSound(u32 id, + u32 handle = 0); // at 0x20 + virtual nw4r::snd::SoundHandle* startSound(unsigned int id, + u32 handle = 0); // at 0x24 + + virtual void stopSound(u32 id, int frames); // at 0xC + virtual void stopSound(unsigned int id, int frames); // at 0x10 + virtual void stopSound(const char* pName, int frames); // at 0x14 + virtual void stopAllSound(int frames); // at 0x18 + + virtual void setActorVolume(f32 volume, int frames); // at 0x1C + + // TODO.... more virtual functions.... + +private: + bool BOOL_0x7C; + u32 mRemoteFlag; +}; + +/****************************************************************************** + * + * RPSndObjMgr + * + ******************************************************************************/ + +/** + * @brief Sound object/actor manager + */ +class RPSndObjMgr { +public: + /** + * @brief Fades out all active sounds in the specified number of frames + * + * @param frames Fade out time + */ + static void stopAllActorSound(int frames); +}; + +//! @} + +#endif diff --git a/include/Pack/RPAudio/RPSndSpeakerMgr.h b/include/Pack/RPAudio/RPSndSpeakerMgr.h new file mode 100644 index 00000000..55301b44 --- /dev/null +++ b/include/Pack/RPAudio/RPSndSpeakerMgr.h @@ -0,0 +1,201 @@ +#ifndef RP_AUDIO_SND_SPEAKER_MGR_H +#define RP_AUDIO_SND_SPEAKER_MGR_H +#include + +#include + +#include + +#include + +//! @addtogroup rp_audio +//! @{ + +/** + * @brief Remote speaker manager + */ +class RPSndSpeakerMgr : public EGG::Disposer { + RP_SINGLETON_DECL_EX(RPSndSpeakerMgr); + +public: + /** + * @brief Resets the state of each remote speaker + */ + void reset(); + + /** + * @brief Updates the state of each remote speaker + */ + void calc(); + + /** + * @brief Finalizes the state of each remote speaker + */ + void exit(); + + /** + * @brief Fetches the latest WPAD master volume + */ + void updateMasterVolume(); + + /** + * @brief Toggles enabling output of the specified remote speaker + * + * @param chan Remote speaker channel + * @param enable Whether to enable the speaker output + * @return Previous enable status + */ + bool setEnableSw(s32 chan, bool enable); + + /** + * @brief Configures the main and remote output volumes of the specified + * sound handle + * + * @param pHandle Sound handle + * @param channelFlag Remote channel output line flags + * @param mainOut Main output volume + * @param remoteOut Remote output volume + * @param muteOut Main output volume when the remote speaker is muted + */ + void setRemoteSend(nw4r::snd::SoundHandle* pHandle, u32 channelFlag, + f32 mainOut, f32 remoteOut, f32 muteOut); + + /** + * @brief Callback for new remote connections + * + * @param chan Remote channel + * @param result WPAD library result + */ + static void setSpeakerOnCallback(s32 chan, s32 result); + + /** + * @brief Callback for remote disconnections + * + * @param chan Remote channel + * @param result WPAD library result + */ + static void setSpeakerOffCallback(s32 chan, s32 result); + + /** + * @brief Callback for initializing remote speaker connections + * + * @param chan Remote channel + * @param result WPAD library result + */ + static void setSpeakerSetupCallback(s32 chan, s32 result); + + /** + * @brief Callback for finalizing remote speaker connections + * + * @param chan Remote channel + * @param result WPAD library result + */ + static void setSpeakerShutdownCallback(s32 chan, s32 result); + + /** + * @brief Attempts to connect to all remote speakers + */ + void connectAll(); + + /** + * @brief Attempts to disconnect from all remote speakers + */ + void disconnectAll(); + + /** + * @brief Tests whether the manager has no connections and is in an idle + * state + */ + bool isDisconnectAllFinished(); + +private: + /** + * @brief Speaker connection task + */ + struct ConnectTask { + //! Whether to turn the speakers on + bool on; // at 0x0 + //! Whether this command has finished + bool finish; // at 0x1 + //! Time-out threshold + u16 timeOut; // at 0x2 + //! Remote channel index + s32 chan; // at 0x4 + }; + + //! Task queue size + static const int QUEUE_SIZE = 20; + //! Task time-out threshold + static const int TIMEOUT = 180; + +private: + /** + * @brief Converts player-indexed bitflags to remote channel output flags + * + * @param playerFlag Player flags + * @return Remote channel output line flags + */ + u32 changeBitPlayerToChannel(u32 playerFlag); + + /** + * @brief Requests a change in the specified remote speaker's state + * + * @param chan Remote speaker channel + * @param on Whether to turn the speaker on + */ + static void setSpeakerSw(s32 chan, bool on); + + /** + * @brief Processes the specified remote speaker connection + * + * @param chan Remote speaker channel + * @param on Whether to turn the speaker on + */ + void taskSpeakerSw(s32 chan, bool on); + + /** + * @brief Tests whether the specified connection task has completed + * + * @param chan Remote speaker channel + */ + static bool isTaskFinished(s32 chan); + +private: + s32 unk14; + u8 unk18; + + //! Whether a connect task is currently ongoing + bool mIsBusy; // at 0x19 + //! Whether all speakers have been disconnected + bool mIsDisconnected; // at 0x1A + + //! Master speaker volume + u8 mMasterVolume; // at 0x1B + + u32 unk1C[WPAD_MAX_CONTROLLERS]; + u32 unk2C[WPAD_MAX_CONTROLLERS]; + u32 unk3C[WPAD_MAX_CONTROLLERS]; + u32 unk4C[WPAD_MAX_CONTROLLERS]; + + //! Whether each speaker has been initialized + bool mIsSpeakerSetUp[WPAD_MAX_CONTROLLERS]; // at 0x5C + //! Whether each speaker is currently turned on + bool mIsSpeakerOn[WPAD_MAX_CONTROLLERS]; // at 0x60 + //! Whether each speaker has audio output enabled + bool mIsEnabledOutput[WPAD_MAX_CONTROLLERS]; // at 0x64 + + u8 unk68[WPAD_MAX_CONTROLLERS]; + + //! Speaker connection task queue + ConnectTask mTaskQueue[QUEUE_SIZE]; // at 0x6C + //! Number of finished tasks + u32 mTaskFinishCount; // at 0x10C + //! Number of requested tasks + u32 mTaskRequestCount; // at 0x110 + + u32 unk114; // at 0x114 +}; + +//! @} + +#endif diff --git a/include/Pack/RPAudio/RPSndUtility.h b/include/Pack/RPAudio/RPSndUtility.h new file mode 100644 index 00000000..085f3c6d --- /dev/null +++ b/include/Pack/RPAudio/RPSndUtility.h @@ -0,0 +1,50 @@ +#ifndef RP_AUDIO_SND_UTILITY_H +#define RP_AUDIO_SND_UTILITY_H +#include + +#include +#include + +//! @addtogroup rp_audio +//! @{ + +/** + * @brief Sound utilities + */ +class RPSndUtility { +public: + /** + * @brief Sets the panning of the sound handle to match the DPD position + * + * @param rHandle Sound handle + * @param rDpdPos DPD position + * @param scale Panning scale + * @return Success + */ + static bool setHandleDpdPan(nw4r::snd::SoundHandle& rHandle, + const nw4r::math::VEC2& rDpdPos, f32 scale); + + /** + * @brief Gets the active sound archive player + */ + static nw4r::snd::SoundArchivePlayer* getPlayer() { + return spSoundArchivePlayer; + } + + /** + * @brief Sets the active sound archive player + * + * @param pPlayer Sound archive player + */ + static void setPlayer(nw4r::snd::SoundArchivePlayer* pPlayer) { + spSoundArchivePlayer = pPlayer; + } + +private: + //! Active sound archive player + static nw4r::snd::SoundArchivePlayer* spSoundArchivePlayer; +}; + +//! @} + +#endif diff --git a/include/egg/audio.h b/include/egg/audio.h index 8147db50..782a86fc 100644 --- a/include/egg/audio.h +++ b/include/egg/audio.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/include/egg/audio/eggAudio3DActor.h b/include/egg/audio/eggAudio3DActor.h index 8cf1384e..faee73dd 100644 --- a/include/egg/audio/eggAudio3DActor.h +++ b/include/egg/audio/eggAudio3DActor.h @@ -15,7 +15,7 @@ class AudioSound3DActor { smCommon3DManager = pManager; } -private: +protected: static nw4r::snd::SoundArchivePlayer* smCommonPlayer; static nw4r::snd::Sound3DManager* smCommon3DManager; }; diff --git a/include/egg/audio/eggAudioActor.h b/include/egg/audio/eggAudioActor.h new file mode 100644 index 00000000..161a36b4 --- /dev/null +++ b/include/egg/audio/eggAudioActor.h @@ -0,0 +1,21 @@ +#ifndef EGG_AUDIO_ACTOR_H +#define EGG_AUDIO_ACTOR_H +#include + +#include + +namespace EGG { + +template class AudioSoundActorBaseWithCamera { +public: + static void setCommonManager(nw4r::snd::Sound3DManager* pManager, int idx) { + smCommon3DManager[idx] = pManager; + } + +protected: + static nw4r::snd::Sound3DManager* smCommon3DManager[N]; +}; + +} // namespace EGG + +#endif diff --git a/include/egg/audio/eggAudioExpMgr.h b/include/egg/audio/eggAudioExpMgr.h index 86aa94ce..64463050 100644 --- a/include/egg/audio/eggAudioExpMgr.h +++ b/include/egg/audio/eggAudioExpMgr.h @@ -5,7 +5,6 @@ #include #include #include - #include #include @@ -92,9 +91,6 @@ class ExpAudioMgr : public SimpleAudioMgr, return SoundHeapMgr::loadState(id); } // at 0x8 - -private: - ; }; } // namespace EGG diff --git a/include/egg/audio/eggAudioMgr.h b/include/egg/audio/eggAudioMgr.h index 6c9a5466..8a5c9eb8 100644 --- a/include/egg/audio/eggAudioMgr.h +++ b/include/egg/audio/eggAudioMgr.h @@ -45,8 +45,8 @@ class IAudioMgr { }; public: - virtual void initialize(Arg* pArg) {} // at 0x8 - virtual void calc() = 0; // at 0xC + virtual void initialize(Arg* /* pArg */) {} // at 0x8 + virtual void calc() = 0; // at 0xC protected: bool mIsInitialized; // at 0x4 diff --git a/include/nw4r/snd/snd_SeqSoundHandle.h b/include/nw4r/snd/snd_SeqSoundHandle.h index e22b00d8..f284296c 100644 --- a/include/nw4r/snd/snd_SeqSoundHandle.h +++ b/include/nw4r/snd/snd_SeqSoundHandle.h @@ -3,7 +3,6 @@ #include #include - #include namespace nw4r { @@ -37,6 +36,12 @@ class SeqSoundHandle : private ut::NonCopyable { } } + void SetTrackPitch(u32 trackFlags, f32 pitch) { + if (IsAttachedSound()) { + mSound->SetTrackPitch(trackFlags, pitch); + } + } + void WriteVariable(int idx, s16 value) { if (IsAttachedSound()) { mSound->WriteVariable(idx, value); diff --git a/include/nw4r/snd/snd_SoundHandle.h b/include/nw4r/snd/snd_SoundHandle.h index f616781b..c06e3b56 100644 --- a/include/nw4r/snd/snd_SoundHandle.h +++ b/include/nw4r/snd/snd_SoundHandle.h @@ -3,7 +3,6 @@ #include #include - #include namespace nw4r { @@ -67,14 +66,24 @@ class SoundHandle : private ut::NonCopyable { mSound->SetVolume(volume, frames); } } + void SetPitch(f32 pitch) { + if (IsAttachedSound()) { + mSound->SetPitch(pitch); + } + } void SetPan(f32 pan) { if (IsAttachedSound()) { mSound->SetPan(pan); } } - void SetPitch(f32 pitch) { + void SetSurroundPan(f32 pan) { if (IsAttachedSound()) { - mSound->SetPitch(pitch); + mSound->SetSurroundPan(pan); + } + } + void SetLpfFreq(f32 freq) { + if (IsAttachedSound()) { + mSound->SetLpfFreq(freq); } } diff --git a/src/Pack/RPAudio/RPSndMoveParam.cpp b/src/Pack/RPAudio/RPSndMoveParam.cpp new file mode 100644 index 00000000..6115ed18 --- /dev/null +++ b/src/Pack/RPAudio/RPSndMoveParam.cpp @@ -0,0 +1,149 @@ +#include + +#include +#include + +/****************************************************************************** + * + * RPSndMoveValueF32 + * + ******************************************************************************/ + +/** + * @brief Constructor + */ +RPSndMoveValueF32::RPSndMoveValueF32() + : mFrame(0), mTarget(1.0f), mValue(1.0f), mDelta(1.0f) { + + mpCallback = NULL; +} + +/** + * @brief Begins interpolation of this value + * + * @param target Interpolation target + * @param frame Interpolation duration + */ +void RPSndMoveValueF32::moveValue(f32 target, u32 frame) { + mTarget = target; + mFrame = frame; + + if (frame == 0) { + mValue = target; + } else { + mDelta = (mValue - target) / frame; + } +} + +/** + * @brief Updates the interpolation state + * + * @return Whether interpolation is ongoing + */ +bool RPSndMoveValueF32::update() { + if (mFrame > 0) { + if (--mFrame > 0) { + mValue -= mDelta; + } else { + mValue = mTarget; + } + + if (mpCallback != NULL) { + mpCallback(mValue, mpUserData); + } + + return true; + } + + return false; +} + +/****************************************************************************** + * + * RPSndMoveParam + * + ******************************************************************************/ + +/** + * @brief Constructor + * + * @param category Sound parameter category + * @param rHandle Sound handle + */ +RPSndMoveParam::RPSndMoveParam(ParamCategory category, + nw4r::snd::SoundHandle& rHandle) + : mCategory(category), mrHandle(rHandle) {} + +/** + * @brief Updates the interpolation state + * + * @return Whether interpolation is ongoing + */ +bool RPSndMoveParam::update() { + if (mrHandle.IsAttachedSound()) { + nw4r::snd::SeqSoundHandle seqHandle(&mrHandle); + bool ongoing = RPSndMoveValueF32::update(); + + switch (mCategory) { + case ParamCategory_SoundPitch: { + mrHandle.SetPitch(mValue); + break; + } + + case ParamCategory_SoundLpf: { + mrHandle.SetLpfFreq(mValue); + break; + } + + case ParamCategory_TrackVolume: { + seqHandle.SetTrackVolume(mTrackFlags, mValue); + break; + } + + case ParamCategory_TrackPitch: { + seqHandle.SetTrackPitch(mTrackFlags, mValue); + break; + } + + default: { + break; + } + } + + return ongoing; + } + + return false; +} + +/****************************************************************************** + * + * RPSndMoveParamMgr + * + ******************************************************************************/ + +/** + * @brief List of all active move parameters + */ +nw4r::ut::List RPSndMoveParamMgr::sMoveParamList; + +/** + * @brief Updates the state of all move parameters + */ +void RPSndMoveParamMgr::update() { + RPSndMoveParamLink* pIt = static_cast( + nw4r::ut::List_GetFirst(&sMoveParamList)); + + RPSndMoveParamLink* pNext = NULL; + + for (; pIt != NULL; pIt = pNext) { + bool ongoing = static_cast(pIt)->update(); + + pNext = static_cast( + nw4r::ut::List_GetNext(&sMoveParamList, pIt)); + + if (!ongoing) { + nw4r::ut::List_Remove(&sMoveParamList, pIt); + } + } +} diff --git a/src/Pack/RPAudio/RPSndObject.cpp b/src/Pack/RPAudio/RPSndObject.cpp new file mode 100644 index 00000000..55910eab --- /dev/null +++ b/src/Pack/RPAudio/RPSndObject.cpp @@ -0,0 +1,37 @@ +#include + +#include + +/****************************************************************************** + * + * RPSndAudioActorBase + * + ******************************************************************************/ + +/** + * @brief List of all active actors + */ +nw4r::ut::List RPSndAudioActorBase::sActorList; + +/****************************************************************************** + * + * RPSndObjMgr + * + ******************************************************************************/ + +/** + * @brief Fades out all active sounds in the specified number of frames + * + * @param frames Fade out time + */ +void RPSndObjMgr::stopAllActorSound(int frames) { + RPSndAudioActorBase* pIt = static_cast( + nw4r::ut::List_GetFirst(&RPSndAudioActorBase::sActorList)); + + for (; pIt != NULL; + pIt = static_cast( + nw4r::ut::List_GetNext(&RPSndAudioActorBase::sActorList, pIt))) { + + pIt->stopAllSound(frames); + } +} diff --git a/src/Pack/RPAudio/RPSndSpeakerMgr.cpp b/src/Pack/RPAudio/RPSndSpeakerMgr.cpp new file mode 100644 index 00000000..11dc8c45 --- /dev/null +++ b/src/Pack/RPAudio/RPSndSpeakerMgr.cpp @@ -0,0 +1,377 @@ +#include + +#include +#include + +RP_SINGLETON_IMPL_EX(RPSndSpeakerMgr); + +/** + * @brief Resets the state of each remote speaker + */ +void RPSndSpeakerMgr::reset() { + connectAll(); +} + +/** + * @brief Updates the state of each remote speaker + */ +void RPSndSpeakerMgr::calc() { + s32 chan; + + for (chan = 0; chan < WPAD_MAX_CONTROLLERS; chan++) { + bool enableNow = + nw4r::snd::SoundSystem::GetRemoteSpeaker(chan).IsEnabledOutput(); + + if (enableNow != mIsEnabledOutput[chan] && + mIsEnabledOutput[chan] == true) { + + if (unk3C[chan] < unk1C[chan]) { + unk3C[chan] = unk1C[chan]; + } + + unk1C[chan] = 0; + } + + mIsEnabledOutput[chan] = enableNow; + } + + if (!mIsBusy) { + if (mTaskFinishCount != mTaskRequestCount) { + taskSpeakerSw(mTaskQueue[mTaskFinishCount].chan, + mTaskQueue[mTaskFinishCount].on); + } + } else { + chan = mTaskQueue[mTaskFinishCount].chan; + mTaskQueue[mTaskFinishCount].timeOut--; + + if (isTaskFinished(chan) || mTaskQueue[mTaskFinishCount].timeOut == 0) { + mIsBusy = false; + + if (++mTaskFinishCount >= QUEUE_SIZE) { + mTaskFinishCount = 0; + } + } + } +} + +/** + * @brief Finalizes the state of each remote speaker + */ +void RPSndSpeakerMgr::exit() { + disconnectAll(); +} + +/** + * @brief Fetches the latest WPAD master volume + */ +void RPSndSpeakerMgr::updateMasterVolume() { + mMasterVolume = WPADGetSpeakerVolume(); +} + +/** + * @brief Toggles enabling output of the specified remote speaker + * + * @param chan Remote speaker channel + * @param enable Whether to enable the speaker output + * @return Previous enable status + */ +bool RPSndSpeakerMgr::setEnableSw(s32 chan, bool enable) { + if (!mIsSpeakerSetUp[chan]) { + return false; + } + + bool enablePrev = + nw4r::snd::SoundSystem::GetRemoteSpeaker(chan).IsEnabledOutput(); + + if (enable == true && unk2C[chan] != 0) { + return false; + } + + if (chan < WPAD_MAX_CONTROLLERS && enablePrev != enable) { + nw4r::snd::SoundSystem::GetRemoteSpeaker(chan).EnableOutput(enable); + + if (!enable) { + if (unk3C[chan] < unk1C[chan]) { + unk3C[chan] = unk1C[chan]; + } + + unk1C[chan] = 0; + unk2C[chan] = 0; + unk4C[chan] = 0; + } + + return enable; + } + + return enablePrev; +} + +/** + * @brief Configures the main and remote output volumes of the specified + * sound handle + * + * @param pHandle Sound handle + * @param channelFlag Remote channel output line flags + * @param mainOut Main output volume + * @param remoteOut Remote output volume + * @param muteOut Main output volume when the remote speaker is muted + */ +void RPSndSpeakerMgr::setRemoteSend(nw4r::snd::SoundHandle* pHandle, + u32 channelFlag, f32 mainOut, f32 remoteOut, + f32 muteOut) { + if (pHandle == NULL) { + return; + } + + if (unk14 == 1 || mMasterVolume == 0) { + remoteOut = 0.0f; + mainOut = muteOut; + } + + u32 remoteOutFlag = + channelFlag == 0 ? 0 : changeBitPlayerToChannel(channelFlag); + + u32 outputFlag = 0; + u32 mainOutFlag = 0; + + if (remoteOut > 0.0f) { + for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) { + if (!(remoteOutFlag & (1 << i)) || !mIsSpeakerSetUp[i]) { + continue; + } + + outputFlag |= 1 << i; + setEnableSw(i, true); + pHandle->SetRemoteOutVolume(i, remoteOut); + } + } + + if (mainOut != 0.0f) { + pHandle->SetMainOutVolume(mainOut); + mainOutFlag = nw4r::snd::OUTPUT_LINE_MAIN; + } + + pHandle->SetOutputLine(mainOutFlag | (outputFlag << 1)); +} + +/** + * @brief Constructor + * + * @param pHeap Parent heap + */ +RPSndSpeakerMgr::RPSndSpeakerMgr(EGG::Heap* pHeap) : mpParentHeap(pHeap) { + for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) { + unk1C[i] = 0; + unk3C[i] = 0; + unk2C[i] = 0; + mIsSpeakerSetUp[i] = false; + unk4C[i] = 0; + mIsEnabledOutput[i] = false; + unk68[i] = 0; + } + + unk18 = 0; + mTaskRequestCount = 0; + mTaskFinishCount = 0; + mIsBusy = false; + unk114 = 0; + mMasterVolume = WPAD_MAX_SPEAKER_VOLUME; + unk14 = 0; + mIsDisconnected = false; +} + +/** + * @brief Destructor + */ +RPSndSpeakerMgr::~RPSndSpeakerMgr() {} + +/** + * @brief Callback for new remote connections + * + * @param chan Remote channel + * @param result WPAD library result + */ +void RPSndSpeakerMgr::setSpeakerOnCallback(s32 chan, s32 result) { + if (RP_GET_INSTANCE(RPSndSpeakerMgr)->mIsDisconnected) { + RP_GET_INSTANCE(RPSndSpeakerMgr)->mIsSpeakerOn[chan] = true; + } else if (result == WPAD_ERR_OK) { + setSpeakerSw(chan, true); + } +} + +/** + * @brief Callback for remote disconnections + * + * @param chan Remote channel + * @param result WPAD library result + */ +void RPSndSpeakerMgr::setSpeakerOffCallback(s32 chan, s32 result) { + if (RP_GET_INSTANCE(RPSndSpeakerMgr)->mIsDisconnected) { + RP_GET_INSTANCE(RPSndSpeakerMgr)->mIsSpeakerOn[chan] = false; + } else if (result == WPAD_ERR_NO_CONTROLLER) { + setSpeakerSw(chan, false); + } +} + +/** + * @brief Callback for initializing remote speaker connections + * + * @param chan Remote channel + * @param result WPAD library result + */ +void RPSndSpeakerMgr::setSpeakerSetupCallback(s32 chan, s32 result) { + if (result == WPAD_ERR_OK) { + RP_GET_INSTANCE(RPSndSpeakerMgr)->mIsSpeakerSetUp[chan] = true; + } + + RP_GET_INSTANCE(RPSndSpeakerMgr)->mTaskQueue[chan].finish = true; +} + +/** + * @brief Callback for finalizing remote speaker connections + * + * @param chan Remote channel + * @param result WPAD library result + */ +void RPSndSpeakerMgr::setSpeakerShutdownCallback(s32 chan, s32 result) { + if (result == WPAD_ERR_OK || result == WPAD_ERR_NO_CONTROLLER) { + RP_GET_INSTANCE(RPSndSpeakerMgr)->mIsSpeakerSetUp[chan] = false; + } + + RP_GET_INSTANCE(RPSndSpeakerMgr)->mTaskQueue[chan].finish = true; +} + +/** + * @brief Attempts to connect to all remote speakers + */ +void RPSndSpeakerMgr::connectAll() { + for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) { + s32 dev; + if (WPADProbe(i, &dev) == WPAD_ERR_NO_CONTROLLER) { + continue; + } + + bool success = nw4r::snd::SoundSystem::GetRemoteSpeaker(i).Setup( + setSpeakerSetupCallback); + + if (!success) { + setSpeakerSw(i, true); + } + } + + mIsDisconnected = false; +} +/** + * @brief Attempts to disconnect from all remote speakers + */ +void RPSndSpeakerMgr::disconnectAll() { + for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) { + nw4r::snd::SoundSystem::GetRemoteSpeaker(i).Shutdown(NULL); + + mIsSpeakerSetUp[i] = false; + mIsSpeakerOn[i] = true; + } + + mIsDisconnected = true; +} + +/** + * @brief Tests whether the manager has no connections and is in an idle + * state + */ +bool RPSndSpeakerMgr::isDisconnectAllFinished() { + if (mIsDisconnected == false) { + return false; + } + + return mTaskRequestCount == mTaskFinishCount; +} + +/** + * @brief Converts player-indexed bitflags to remote channel output flags + * + * @param playerFlag Player flags + * @return Remote channel output line flags + */ +u32 RPSndSpeakerMgr::changeBitPlayerToChannel(u32 playerFlag) { + u32 channelFlag = 0; + + for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) { + if (!(playerFlag & (1 << i))) { + continue; + } + + if (i >= RP_GET_INSTANCE(RPSndAudioMgr)->getPlayerNum()) { + continue; + } + + s32 chan = EGG_GET_INSTANCE(EGG::CoreControllerMgr) + ->getNthController(i) + ->getChannelID(); + + channelFlag |= 1 << chan; + } + + return channelFlag; +} + +/** + * @brief Requests a change in the specified remote speaker's state + * + * @param chan Remote speaker channel + * @param on Whether to turn the speaker on + */ +void RPSndSpeakerMgr::setSpeakerSw(s32 chan, bool on) { + BOOL enabled = OSDisableInterrupts(); + + // clang-format off + RP_GET_INSTANCE(RPSndSpeakerMgr) + ->mTaskQueue[RP_GET_INSTANCE(RPSndSpeakerMgr)->mTaskRequestCount].chan = chan; + + RP_GET_INSTANCE(RPSndSpeakerMgr) + ->mTaskQueue[RP_GET_INSTANCE(RPSndSpeakerMgr)->mTaskRequestCount].on = on; + + RP_GET_INSTANCE(RPSndSpeakerMgr) + ->mTaskQueue[RP_GET_INSTANCE(RPSndSpeakerMgr)->mTaskRequestCount].finish = false; + + RP_GET_INSTANCE(RPSndSpeakerMgr) + ->mTaskQueue[RP_GET_INSTANCE(RPSndSpeakerMgr)->mTaskRequestCount].timeOut = TIMEOUT; + // clang-format on + + if (++RP_GET_INSTANCE(RPSndSpeakerMgr)->mTaskRequestCount >= QUEUE_SIZE) { + RP_GET_INSTANCE(RPSndSpeakerMgr)->mTaskRequestCount = 0; + } + + OSRestoreInterrupts(enabled); +} + +/** + * @brief Processes the specified remote speaker connection + * + * @param chan Remote speaker channel + * @param on Whether to turn the speaker on + */ +void RPSndSpeakerMgr::taskSpeakerSw(s32 chan, bool on) { + mIsBusy = true; + + if (on) { + bool success = nw4r::snd::SoundSystem::GetRemoteSpeaker(chan).Setup( + setSpeakerSetupCallback); + + if (!success) { + setSpeakerSw(chan, true); + } + } else { + nw4r::snd::SoundSystem::GetRemoteSpeaker(chan).Shutdown( + setSpeakerShutdownCallback); + } +} + +/** + * @brief Tests whether the specified connection task has completed + * + * @param chan Remote speaker channel + */ +bool RPSndSpeakerMgr::isTaskFinished(s32 chan) { + return RP_GET_INSTANCE(RPSndSpeakerMgr)->mTaskQueue[chan].finish == true; +} diff --git a/src/Pack/RPAudio/RPSndUtility.cpp b/src/Pack/RPAudio/RPSndUtility.cpp new file mode 100644 index 00000000..b356735b --- /dev/null +++ b/src/Pack/RPAudio/RPSndUtility.cpp @@ -0,0 +1,48 @@ +#include + +#include +#include +#include + +/** + * @brief Active sound archive player + */ +nw4r::snd::SoundArchivePlayer* RPSndUtility::spSoundArchivePlayer = NULL; + +/** + * @brief Sets the panning of the sound handle to match the DPD position + * + * @param rHandle Sound handle + * @param rDpdPos DPD position + * @param scale Panning scale + * @return Success + */ +bool RPSndUtility::setHandleDpdPan(nw4r::snd::SoundHandle& rHandle, + const nw4r::math::VEC2& rDpdPos, f32 scale) { + + if (rHandle.IsAttachedSound()) { + f32 pan = rDpdPos.x * scale; + + if (pan > 1.0f) { + pan = 1.0f; + } else if (pan < -1.0f) { + pan = -1.0f; + } + + rHandle.SetPan(pan); + + if (scale > 1.0f && pan > 0.8f) { + f32 surroundPan = scale - 0.8f; + + if (surroundPan > 0.5f) { + surroundPan = 0.5f; + } + + rHandle.SetSurroundPan(surroundPan); + } + + return true; + } + + return false; +} From cef5100cc339f5a5febe5f5fb84ffe936bf40c08 Mon Sep 17 00:00:00 2001 From: kiwi515 <49212064+kiwi515@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:31:15 -0500 Subject: [PATCH 2/2] RPSndHomeMenuArcMgr OK --- config/RSPE01_01/symbols.txt | 14 +++---- configure.py | 2 +- include/Pack/RPAudio.h | 1 + include/Pack/RPAudio/RPSndAudioMgr.h | 1 - include/Pack/RPAudio/RPSndHomeMenuArcMgr.h | 47 ++++++++++++++++++++++ src/Pack/RPAudio/RPSndHomeMenuArcMgr.cpp | 36 +++++++++++++++++ 6 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 include/Pack/RPAudio/RPSndHomeMenuArcMgr.h create mode 100644 src/Pack/RPAudio/RPSndHomeMenuArcMgr.cpp diff --git a/config/RSPE01_01/symbols.txt b/config/RSPE01_01/symbols.txt index 62928a93..bc071ac8 100644 --- a/config/RSPE01_01/symbols.txt +++ b/config/RSPE01_01/symbols.txt @@ -8184,12 +8184,12 @@ update__17RPSndMoveValueF32Fv = .text:0x801B92A8; // type:function size:0x78 moveValue__17RPSndMoveValueF32FfUl = .text:0x801B9320; // type:function size:0x4C __ct__17RPSndMoveValueF32Fv = .text:0x801B936C; // type:function size:0x2C @8@update__14RPSndMoveParamFv = .text:0x801B9398; // type:function size:0x8 -fn_801B93A0 = .text:0x801B93A0; // type:function size:0x18 -fn_801B93B8 = .text:0x801B93B8; // type:function size:0x54 -fn_801B940C = .text:0x801B940C; // type:function size:0x90 -fn_801B949C = .text:0x801B949C; // type:function size:0x9C -fn_801B9538 = .text:0x801B9538; // type:function size:0x8 -fn_801B9540 = .text:0x801B9540; // type:function size:0x8 +calc__19RPSndHomeMenuArcMgrFv = .text:0x801B93A0; // type:function size:0x18 +setupArchive__19RPSndHomeMenuArcMgrFPCv = .text:0x801B93B8; // type:function size:0x54 +__dt__19RPSndHomeMenuArcMgrFv = .text:0x801B940C; // type:function size:0x90 +__ct__19RPSndHomeMenuArcMgrFv = .text:0x801B949C; // type:function size:0x9C +@240@calc__19RPSndHomeMenuArcMgrFv = .text:0x801B9538; // type:function size:0x8 +@240@__dt__19RPSndHomeMenuArcMgrFv = .text:0x801B9540; // type:function size:0x8 fn_801B9548 = .text:0x801B9548; // type:function size:0x148 fn_801B9690 = .text:0x801B9690; // type:function size:0x16C fn_801B97FC = .text:0x801B97FC; // type:function size:0x54 @@ -18725,7 +18725,7 @@ lbl_803BAA50 = .data:0x803BAA50; // type:object size:0x10 data:string __vt__15RPSndSpeakerMgr = .data:0x803BAA60; // type:object size:0xC __vt__14RPSndMoveParam = .data:0x803BAA70; // type:object size:0x18 lbl_803BAA88 = .data:0x803BAA88; // type:object size:0x10 -lbl_803BAA98 = .data:0x803BAA98; // type:object size:0x88 +__vt__19RPSndHomeMenuArcMgr = .data:0x803BAA98; // type:object size:0x88 sStaticSoundArchive__14RPSndStaticMgr = .data:0x803BAB20; // type:object size:0x6BA0 align:32 noreloc lbl_803C16C0 = .data:0x803C16C0; // type:object size:0x60 lbl_803C1720 = .data:0x803C1720; // type:object size:0x28 diff --git a/configure.py b/configure.py index 040774d7..29ce1bf0 100755 --- a/configure.py +++ b/configure.py @@ -1220,7 +1220,7 @@ def MatchingFor(*versions): Object(Matching, "Pack/RPAudio/RPSndObject.cpp"), Object(Matching, "Pack/RPAudio/RPSndUtility.cpp"), Object(NonMatching, "Pack/RPAudio/RPSndMoveParam.cpp"), - Object(NonMatching, "Pack/RPAudio/RPSndHomeMenuArcMgr.cpp"), + Object(Matching, "Pack/RPAudio/RPSndHomeMenuArcMgr.cpp"), Object(NonMatching, "Pack/RPAudio/RPSndStaticMgr.cpp"), ], }, diff --git a/include/Pack/RPAudio.h b/include/Pack/RPAudio.h index 2042e42c..fcac58f4 100644 --- a/include/Pack/RPAudio.h +++ b/include/Pack/RPAudio.h @@ -2,6 +2,7 @@ #define RP_PUBLIC_AUDIO_H #include +#include #include #include #include diff --git a/include/Pack/RPAudio/RPSndAudioMgr.h b/include/Pack/RPAudio/RPSndAudioMgr.h index 5cedeb68..4864de72 100644 --- a/include/Pack/RPAudio/RPSndAudioMgr.h +++ b/include/Pack/RPAudio/RPSndAudioMgr.h @@ -5,7 +5,6 @@ #include #include -#include #include diff --git a/include/Pack/RPAudio/RPSndHomeMenuArcMgr.h b/include/Pack/RPAudio/RPSndHomeMenuArcMgr.h new file mode 100644 index 00000000..c1620125 --- /dev/null +++ b/include/Pack/RPAudio/RPSndHomeMenuArcMgr.h @@ -0,0 +1,47 @@ +#ifndef RP_AUDIO_SND_HOME_MENU_ARC_MGR_H +#define RP_AUDIO_SND_HOME_MENU_ARC_MGR_H +#include + +#include + +//! @addtogroup rp_audio +//! @{ + +/** + * @brief Home menu sound archive manager + */ +class RPSndHomeMenuArcMgr : public EGG::SoundHeapMgr, public EGG::ArcPlayer { +public: + /** + * @brief Constructor + */ + RPSndHomeMenuArcMgr(); + + /** + * @brief Destructor + */ + virtual ~RPSndHomeMenuArcMgr(); // at 0x8 + + /** + * @brief Updates the state of the sound player + */ + virtual void calc(); // at 0x34 + + /** + * @brief Mounts the provided sound archive + * + * @param pBinary Binary sound archive + * @return Success + */ + bool setupArchive(const void* pBinary); + +private: + //! Active sound handle + nw4r::snd::SoundHandle mSoundHandle; // at 0x6A4 + //! Whether the sound archive has been setup + bool mIsInitialized; // at 0x6A8 +}; + +//! @} + +#endif diff --git a/src/Pack/RPAudio/RPSndHomeMenuArcMgr.cpp b/src/Pack/RPAudio/RPSndHomeMenuArcMgr.cpp new file mode 100644 index 00000000..1f1d88a1 --- /dev/null +++ b/src/Pack/RPAudio/RPSndHomeMenuArcMgr.cpp @@ -0,0 +1,36 @@ +#include + +/** + * @brief Constructor + */ +RPSndHomeMenuArcMgr::RPSndHomeMenuArcMgr() + : EGG::ArcPlayer(&getSoundHeap()), mSoundHandle(), mIsInitialized(false) {} + +/** + * @brief Destructor + */ +RPSndHomeMenuArcMgr::~RPSndHomeMenuArcMgr() {} + +/** + * @brief Mounts the provided sound archive + * + * @param pBinary Binary sound archive + * @return Success + */ +bool RPSndHomeMenuArcMgr::setupArchive(const void* pBinary) { + bool success = setupMemoryArchive(pBinary, &getSoundHeap()) != NULL; + + mIsInitialized = true; + return success; +} + +/** + * @brief Updates the state of the sound player + */ +void RPSndHomeMenuArcMgr::calc() { + if (!mIsInitialized) { + return; + } + + EGG::ArcPlayer::calc(); +}