From 8894f73305da296dd7d67036eae97865b5f29876 Mon Sep 17 00:00:00 2001 From: robojumper Date: Thu, 29 May 2025 15:10:23 +0200 Subject: [PATCH] snd_AnimSound OK --- config/SOUE01/symbols.txt | 12 +- configure.py | 2 +- include/nw4r/math/math_arithmetic.h | 6 +- include/nw4r/snd/snd_AnimSound.h | 137 +++++ include/nw4r/snd/snd_AnimSoundReader.h | 62 ++- include/nw4r/snd/snd_BasicSound.h | 1 + include/nw4r/snd/snd_RemoteSpeakerManager.h | 5 +- include/nw4r/snd/snd_SeqSoundHandle.h | 6 + include/nw4r/snd/snd_SoundHandle.h | 6 + include/nw4r/snd/snd_SoundStartable.h | 25 +- .../MSL/MSL_C/MSL_Common/Include/cmath | 20 +- .../MSL/MSL_C/MSL_Common/Include/cmath.h | 9 +- .../MSL/MSL_C/MSL_Common/Include/math.h | 2 +- src/REL/d/a/e/d_a_e_sm.cpp | 2 + src/nw4r/snd/snd_AnimSound.cpp | 481 +++++++++++++++++- src/nw4r/snd/snd_AnimSoundReader.cpp | 4 +- 16 files changed, 733 insertions(+), 47 deletions(-) diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index 8779a92f..0dfcce5d 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -49635,12 +49635,12 @@ norm_epsilon__Q34nw4r3g3d26@unnamed@g3d_calcview_cpp@ = .sdata2:0x8057EDF0; // t @11135 = .sdata2:0x8057EEE4; // type:object size:0x4 scope:local align:4 data:float @11136 = .sdata2:0x8057EEE8; // type:object size:0x4 scope:local align:4 data:float @11190 = .sdata2:0x8057EEF0; // type:object size:0x4 scope:local align:4 data:float -lbl_8057EEF8 = .sdata2:0x8057EEF8; // type:object size:0x4 align:4 data:float -lbl_8057EEFC = .sdata2:0x8057EEFC; // type:object size:0x4 align:4 data:float -lbl_8057EF00 = .sdata2:0x8057EF00; // type:object size:0x8 align:8 data:double -lbl_8057EF08 = .sdata2:0x8057EF08; // type:object size:0x8 align:8 data:double -lbl_8057EF10 = .sdata2:0x8057EF10; // type:object size:0x4 align:4 data:float -lbl_8057EF14 = .sdata2:0x8057EF14; // type:object size:0x4 align:4 data:float +@4352 = .sdata2:0x8057EEF8; // type:object size:0x4 scope:local align:4 data:float +@4353 = .sdata2:0x8057EEFC; // type:object size:0x4 scope:local align:4 data:float +@4474 = .sdata2:0x8057EF00; // type:object size:0x8 scope:local align:8 data:double +@4600 = .sdata2:0x8057EF08; // type:object size:0x8 scope:local align:8 data:double +@5006 = .sdata2:0x8057EF10; // type:object size:0x4 scope:local align:4 data:float +@5007 = .sdata2:0x8057EF14; // type:object size:0x4 scope:local align:4 data:float @2457 = .sdata2:0x8057EF18; // type:object size:0x4 scope:local align:4 data:float @2458 = .sdata2:0x8057EF1C; // type:object size:0x4 scope:local align:4 data:float @2523 = .sdata2:0x8057EF20; // type:object size:0x8 scope:local align:8 data:double diff --git a/configure.py b/configure.py index 7b6c3265..9d62279b 100644 --- a/configure.py +++ b/configure.py @@ -1012,7 +1012,7 @@ config.libs = [ nw4rLib( "snd", [ - Object(NonMatching, "nw4r/snd/snd_AnimSound.cpp"), + Object(Matching, "nw4r/snd/snd_AnimSound.cpp"), Object(Matching, "nw4r/snd/snd_AnimSoundReader.cpp"), Object(Matching, "nw4r/snd/snd_AxManager.cpp"), Object(Matching, "nw4r/snd/snd_AxVoice.cpp"), diff --git a/include/nw4r/math/math_arithmetic.h b/include/nw4r/math/math_arithmetic.h index 8bd573cb..2892128b 100644 --- a/include/nw4r/math/math_arithmetic.h +++ b/include/nw4r/math/math_arithmetic.h @@ -5,6 +5,8 @@ #include "nw4r/types_nw4r.h" // IWYU pragma: export #include "rvl/OS.h" // IWYU pragma: export +#include + #define NW4R_MATH_QNAN (-(0.0f / 0.0f)) #define NW4R_MATH_FLT_MAX 3.402823466e+38f @@ -30,7 +32,7 @@ inline f32 FAbs(register f32 x) { } inline f32 FCeil(f32 x) { - return ceilf(x); + return std::ceilf(x); } inline f32 FExp(f32 x) { @@ -38,7 +40,7 @@ inline f32 FExp(f32 x) { } inline f32 FFloor(f32 x) { - return floorf(x); + return std::floorf(x); } inline f32 FInv(register f32 x) { diff --git a/include/nw4r/snd/snd_AnimSound.h b/include/nw4r/snd/snd_AnimSound.h index 2b25ea5b..7f60bbec 100644 --- a/include/nw4r/snd/snd_AnimSound.h +++ b/include/nw4r/snd/snd_AnimSound.h @@ -1 +1,138 @@ /* Only implemented to the extent necessary to match data sections. */ + +#include "nw4r/snd/snd_AnimSoundReader.h" +#include "nw4r/snd/snd_BasicSound.h" +#include "nw4r/snd/snd_SoundHandle.h" +#include "nw4r/snd/snd_SoundStartable.h" + +// Class and non-inline function names from InazumaWii, everything else made up + +namespace nw4r { +namespace snd { +namespace detail { + +class AnimEventPlayer { +public: + AnimEventPlayer(); + ~AnimEventPlayer(); + + SoundHandle *GetHandle() { + return &mHandle; + } + + bool IsAttachedSound() const { + return mHandle.IsAttachedSound(); + } + + bool IsCurrentEvent(const AnimEvent *event) const { + return event == mpEvent; + } + + int GetPriority() const { + if (!IsAttachedSound()) { + return 0; + } + return mHandle.detail_GetAttachedSound()->GetPriority(); + } + + bool IsRunning() const { + return mIsRunning; + } + + void SetRunning(bool running) { + mIsRunning = running; + } + + void UpdateFrame() { + if (!mHandle.IsAttachedSound()) { + mpEvent = 0; + } + } + + void Stop() { + if (IsAttachedSound()) { + mHandle.detail_GetAttachedSound()->Stop(0); + } + mpEvent = 0; + } + + void StopEvent(const AnimEvent *event) { + if (mpEvent == event) { + Stop(); + } + } + + void SetVolume(f32 volume) { + if (IsAttachedSound()) { + mHandle.detail_GetAttachedSound()->SetVolume(volume, 0); + } + } + + void SetPitch(f32 pitch) { + if (IsAttachedSound()) { + mHandle.detail_GetAttachedSound()->SetPitch(pitch); + } + } + + bool StartSound(const AnimEvent *event, SoundStartable *startable, bool b); + bool HoldSound(const AnimEvent *event, SoundStartable *startable, bool b); + void SetVolumePitch(const AnimEvent *event, bool b); + void SetVariable(const AnimEvent *event, u32 varNo, f32 f); + +private: + SoundHandle mHandle; // at 0x00 + const AnimEvent *mpEvent; // at 0x04 + bool mIsRunning; // at 0x08 +}; + +class AnimSoundImpl { +public: + enum PlayDirection { + FORWARD, + BACKWARD, + }; + + AnimSoundImpl(SoundStartable &startable, AnimEventPlayer *player, int); + ~AnimSoundImpl(); + + bool Setup(const void *data); + void Shutdown(); + void ResetFrame(f32, int); + void UpdateFrame(f32 frame, PlayDirection dir); + void UpdateForward(f32 frame); + void UpdateBackward(f32 frame); + void UpdateTrigger(const AnimEventRef *, s32, PlayDirection); + void UpdateForwardRange(const AnimEventRef *, s32); + void UpdateBackwardRange(const AnimEventRef *, s32); + + void StartEvent(const AnimEvent *, bool); + void HoldEvent(const AnimEvent *, bool); + // StartEvent is not inlined, but there seems to be + // a corresponding StopEvent function that got inlined + void StopEvent(const AnimEvent *); + + // Made up inlines + bool ShouldPlayEvent(const AnimEventRef *ref) const; + void UpdateEvents(s32 duration, PlayDirection direction); + + typedef void (*Callback)(int, s32, const char *, UNKWORD, UNKWORD); + +private: + /* 0x00 */ SoundStartable &mStartable; + /* 0x04 */ AnimSoundFileReader mReader; + /* 0x0C */ f32 field_0x0C; + /* 0x10 */ AnimEventPlayer *mpSounds; + /* 0x14 */ int mNumSounds; + /* 0x18 */ bool mIsActive; + /* 0x19 */ u8 field_0x19; + /* 0x1A */ u8 field_0x1A; + /* 0x1C */ UNKWORD field_0x1C; + /* 0x20 */ Callback mCallback; + /* 0x24 */ UNKWORD field_0x24; + /* 0x28 */ f32 field_0x28; + /* 0x2C */ f32 mVariableValue; +}; + +} // namespace detail +} // namespace snd +} // namespace nw4r diff --git a/include/nw4r/snd/snd_AnimSoundReader.h b/include/nw4r/snd/snd_AnimSoundReader.h index 4ab47f21..909ffecd 100644 --- a/include/nw4r/snd/snd_AnimSoundReader.h +++ b/include/nw4r/snd/snd_AnimSoundReader.h @@ -5,11 +5,54 @@ namespace nw4r { namespace snd { namespace detail { -struct AnimEvent {}; +struct AnimEvent { + u32 flags_0x00; // at 0x00 + u32 soundId; // at 0x04 + detail::Util::DataRef soundLabelRef; // at 0x08 + u8 volume; // at 0x10 + u8 field_0x11; // at 0x11 + u8 varNo; // at 0x12 + f32 pitch; // at 0x14 + UNKWORD field_0x18; // at 0x18 + UNKWORD field_0x1C; // at 0x1C + + bool ShouldPreventStart() const { + return flags_0x00 & 1; + } + + const char *GetSoundLabel() const { + return Util::GetDataRefAddress0(soundLabelRef, this); + } + + bool GetVarNo(u32 *var) const { + if (ShouldSetVariable()) { + *var = varNo; + return true; + } + return false; + } + + bool ShouldSetVariable() const { + return flags_0x00 & 2; + } + + bool MatchesDirection(int playDirection) const { + bool ret = 0; + u32 config = field_0x11; + if ((config == 0 || (playDirection == 0 && config == 1) || (playDirection == 1 && config == 2))) { + ret = true; + } + return ret; + } +}; struct AnimEventRef { - u8 _0x00[0xC]; - Util::DataRef event; // at 0x08 + int field_0x00; // at 0x08 + int field_0x04; // at 0x04 + u8 flags_0x08; // at 0x08 + s8 field_0x09; // at 0x09 + u8 field_0x0A; // at 0x0A + Util::DataRef event; // at 0x0C }; struct AnimSoundFile { @@ -27,7 +70,7 @@ struct AnimSoundFile { struct Block { ut::BinaryBlockHeader blockHeader; // at 0x00 - UNKWORD _0x08; // at 0x08 + u32 duration; // at 0x08 Util::DataRef eventTable; // at 0x0C }; }; @@ -43,6 +86,17 @@ public: const AnimEventRef *GetEventRef(u32 id) const; const AnimEvent *GetEvent(const AnimEventRef *ref) const; + bool IsValid() const { + return mpHeader != NULL; + } + + u32 GetAnimDuration() const { + if (!IsValid()) { + return 0; + } + return mpBlock->duration; + } + private: const AnimSoundFile::Header *mpHeader; // at 0x00 const AnimSoundFile::Block *mpBlock; // at 0x04 diff --git a/include/nw4r/snd/snd_BasicSound.h b/include/nw4r/snd/snd_BasicSound.h index b36f3cc9..8fc57508 100644 --- a/include/nw4r/snd/snd_BasicSound.h +++ b/include/nw4r/snd/snd_BasicSound.h @@ -260,6 +260,7 @@ namespace nw4r { namespace snd { namespace detail PlayerHeap *GetPlayerHeap() { return mPlayerHeap; } SoundPlayer *GetSoundPlayer() { return mSoundPlayer; } int GetVoiceOutCount() const; + int GetPriority() const { return mPriority; } void SetPlayerPriority(int priority); void SetInitialVolume(f32 volume); diff --git a/include/nw4r/snd/snd_RemoteSpeakerManager.h b/include/nw4r/snd/snd_RemoteSpeakerManager.h index 79ebd56d..2793637c 100644 --- a/include/nw4r/snd/snd_RemoteSpeakerManager.h +++ b/include/nw4r/snd/snd_RemoteSpeakerManager.h @@ -21,8 +21,9 @@ public: private: static const int SPEAKER_ALARM_HZ = 150; - static const int SPEAKER_ALARM_PERIOD_NSEC = static_cast(1.0f / SPEAKER_ALARM_HZ * 1000 * 1000 * 1000); - + // commented out since it causes compiler warnings + // static const int SPEAKER_ALARM_PERIOD_NSEC = static_cast(1.0f / SPEAKER_ALARM_HZ * 1000 * 1000 * 1000); + static const int SPEAKER_ALARM_PERIOD_NSEC = 6666667; private: RemoteSpeakerManager(); diff --git a/include/nw4r/snd/snd_SeqSoundHandle.h b/include/nw4r/snd/snd_SeqSoundHandle.h index b5e775b2..709701ed 100644 --- a/include/nw4r/snd/snd_SeqSoundHandle.h +++ b/include/nw4r/snd/snd_SeqSoundHandle.h @@ -7,6 +7,7 @@ #include "common.h" // nullptr +#include "nw4r/snd/snd_SeqSound.h" #include "nw4r/ut/ut_NonCopyable.h" // ut::NonCopyable /******************************************************************************* @@ -33,6 +34,11 @@ namespace nw4r { namespace snd void DetachSound(); + void WriteVariable(int varNo, s16 value) { + if (IsAttachedSound()) + mSound->WriteVariable(varNo, value); + } + // members private: /* base ut::NonCopyable */ // size 0x00, offset 0x00 diff --git a/include/nw4r/snd/snd_SoundHandle.h b/include/nw4r/snd/snd_SoundHandle.h index 19040155..e400a441 100644 --- a/include/nw4r/snd/snd_SoundHandle.h +++ b/include/nw4r/snd/snd_SoundHandle.h @@ -31,8 +31,14 @@ namespace nw4r { namespace snd void detail_AttachSound(detail::BasicSound *sound); bool IsAttachedSound() const { return mSound != nullptr; } detail::BasicSound *detail_GetAttachedSound() { return mSound; } + const detail::BasicSound *detail_GetAttachedSound() const { return mSound; } void DetachSound(); + void Stop() { + if (IsAttachedSound()) + mSound->Stop(0); + } + u32 GetId() const { if (IsAttachedSound()) diff --git a/include/nw4r/snd/snd_SoundStartable.h b/include/nw4r/snd/snd_SoundStartable.h index 5f0a70df..e92a2d02 100644 --- a/include/nw4r/snd/snd_SoundStartable.h +++ b/include/nw4r/snd/snd_SoundStartable.h @@ -144,35 +144,40 @@ namespace nw4r { namespace snd const StartInfo *pStartInfo ); - // TODO: Fix after removal of above functions bool StartSound(SoundHandle *pHandle, u32 id) { - return detail_StartSound(pHandle, id, NULL, NULL, NULL) == START_SUCCESS; + return detail_StartSound(pHandle, id, NULL) == START_SUCCESS; + } + bool StartSound(SoundHandle *pHandle, const char *label) { + return detail_StartSound(pHandle, label, NULL) == START_SUCCESS; } bool StartSound(SoundHandle *pHandle, unsigned int id) { - return detail_StartSound(pHandle, id, NULL, NULL, NULL) == START_SUCCESS; + return detail_StartSound(pHandle, id, NULL) == START_SUCCESS; } bool StartSound(SoundHandle *pHandle, int id) { - return detail_StartSound(pHandle, id, NULL, NULL, NULL) == START_SUCCESS; + return detail_StartSound(pHandle, id, NULL) == START_SUCCESS; } bool HoldSound(SoundHandle *pHandle, u32 id) { - return detail_HoldSound(pHandle, id, NULL, NULL, NULL) == START_SUCCESS; + return detail_HoldSound(pHandle, id, NULL) == START_SUCCESS; + } + bool HoldSound(SoundHandle *pHandle, const char *label) { + return detail_HoldSound(pHandle, label, NULL) == START_SUCCESS; } bool HoldSound(SoundHandle *pHandle, unsigned int id) { - return detail_HoldSound(pHandle, id, NULL, NULL, NULL) == START_SUCCESS; + return detail_HoldSound(pHandle, id, NULL) == START_SUCCESS; } bool HoldSound(SoundHandle *pHandle, int id) { - return detail_HoldSound(pHandle, id, NULL, NULL, NULL) == START_SUCCESS; + return detail_HoldSound(pHandle, id, NULL) == START_SUCCESS; } bool PrepareSound(SoundHandle *pHandle, u32 id) { - return detail_PrepareSound(pHandle, id, NULL, NULL, NULL) == START_SUCCESS; + return detail_PrepareSound(pHandle, id, NULL) == START_SUCCESS; } bool PrepareSound(SoundHandle *pHandle, unsigned int id) { - return detail_PrepareSound(pHandle, id, NULL, NULL, NULL) == START_SUCCESS; + return detail_PrepareSound(pHandle, id, NULL) == START_SUCCESS; } bool PrepareSound(SoundHandle *pHandle, int id) { - return detail_PrepareSound(pHandle, id, NULL, NULL, NULL) == START_SUCCESS; + return detail_PrepareSound(pHandle, id, NULL) == START_SUCCESS; } // members diff --git a/src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/cmath b/src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/cmath index 57ceb903..d6685a2a 100644 --- a/src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/cmath +++ b/src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/cmath @@ -15,13 +15,13 @@ using ::atan; using ::atan2; using ::atan2f; using ::ceil; -using ::ceilf; +// using ::ceilf; using ::copysign; using ::cos; // using ::cosf; -using ::fabsf; +// using ::fabsf; using ::floor; -using ::floorf; +// using ::floorf; using ::fmod; using ::fmodf; using ::frexp; @@ -35,18 +35,26 @@ using ::scalbn; using ::sin; using ::sinf; using ::sqrt; -using ::sqrtf; +// using ::sqrtf; using ::tan; using ::tanf; -inline float sqrt(float x) { - return ::sqrtf(x); +inline float ceilf(float x) { + return ::ceil(x); +} + +inline float floorf(float x) { + return ::floor(x); } inline float cosf(float x) { return cos(x); } +inline float sqrtf(float x) { + return ::sqrtf(x); +} + // TODO: Very fake! // inline double fabs_wrapper(double x) { // return __fabs(x); diff --git a/src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/cmath.h b/src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/cmath.h index 38e4772b..4ab23c36 100644 --- a/src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/cmath.h +++ b/src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/cmath.h @@ -3,21 +3,14 @@ namespace std { -/* float fabs(float num) { - return ::fabsf(num); -} */ inline float fabsf(float num) { return ::fabsf(num); } -inline float sqrt(float x) { - return ::sqrtf(x); -} - inline float abs(float x) { return ::fabsf(x); } } // namespace std -#endif \ No newline at end of file +#endif diff --git a/src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/math.h b/src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/math.h index 0d311c0e..58b6b4e7 100644 --- a/src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/math.h +++ b/src/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/math.h @@ -29,7 +29,7 @@ double cos(double); float cosf(float); double exp(double); double ceil(double); -float ceilf(float); +// float ceilf(float); double frexp(double, int *); double ldexp(double, int); double modf(double, double *); diff --git a/src/REL/d/a/e/d_a_e_sm.cpp b/src/REL/d/a/e/d_a_e_sm.cpp index dae7f886..6b6e4131 100644 --- a/src/REL/d/a/e/d_a_e_sm.cpp +++ b/src/REL/d/a/e/d_a_e_sm.cpp @@ -41,6 +41,8 @@ #include "toBeSorted/small_sound_mgr.h" #include "toBeSorted/time_area_mgr.h" +#include + SPECIAL_ACTOR_PROFILE(E_SM, dAcEsm_c, fProfile::E_SM, 0xEB, 0, 4098); static dCcD_SrcSph sSphSrc = { diff --git a/src/nw4r/snd/snd_AnimSound.cpp b/src/nw4r/snd/snd_AnimSound.cpp index de514c8b..5f98612d 100644 --- a/src/nw4r/snd/snd_AnimSound.cpp +++ b/src/nw4r/snd/snd_AnimSound.cpp @@ -1,10 +1,481 @@ /* Only implemented to the extent necessary to match data sections. */ +#include "nw4r/snd/snd_AnimSound.h" + #include "common.h" // nullptr -#include +#include "nw4r/snd/snd_BasicSound.h" +#include "nw4r/snd/snd_SeqSound.h" +#include "nw4r/snd/snd_SeqSoundHandle.h" +#include "nw4r/snd/snd_SoundHandle.h" +#include "nw4r/snd/snd_SoundStartable.h" -#include "nw4r/snd/snd_Util.h" +#include -DECOMP_FORCE(nw4r::snd::detail::Util::GetDataRefAddress0( - *static_cast const *>(nullptr), - nullptr)); +namespace nw4r { +namespace snd { +namespace detail { + +AnimSoundImpl::AnimSoundImpl(SoundStartable &startable, AnimEventPlayer *player, int numSounds) + : mStartable(startable), + mpSounds(player), + mNumSounds(numSounds), + field_0x0C(0.0f), + mIsActive(false), + field_0x19(0), + field_0x1A(0), + field_0x1C(0), + mCallback(NULL), + field_0x28(1.0f) {} + +AnimSoundImpl::~AnimSoundImpl() { + Shutdown(); +} + +bool AnimSoundImpl::Setup(const void *data) { + Shutdown(); + if (!mReader.Setup(data)) { + return false; + } + + field_0x19 = 1; + mIsActive = true; + field_0x0C = 0.0f; + field_0x1C = 0; + return true; +} + +void AnimSoundImpl::Shutdown() { + if (mIsActive) { + for (int i = 0; i < mNumSounds; i++) { + if (mpSounds[i].GetHandle()->IsAttachedSound() && mpSounds[i].IsRunning()) { + mpSounds[i].GetHandle()->Stop(); + } + } + + mReader.Shutdown(); + mIsActive = false; + } +} + +void AnimSoundImpl::ResetFrame(f32 f, int i) { + field_0x0C = f; + field_0x1C = i; + field_0x1A = 1; + field_0x19 = 0; +} + +void AnimSoundImpl::UpdateFrame(f32 frame, PlayDirection dir) { + for (int i = 0; i < mNumSounds; i++) { + mpSounds[i].UpdateFrame(); + } + + if (field_0x19) { + if (dir == FORWARD) { + ResetFrame(0.0f, 0); + } else { + u32 duration = mReader.GetAnimDuration(); + ResetFrame(duration - 1.0f, 0); + } + field_0x19 = false; + } + + mVariableValue = (frame - field_0x0C) / field_0x28; + if (dir == FORWARD) { + UpdateForward(frame); + } else { + UpdateBackward(frame); + } + field_0x0C = frame; + field_0x1A = false; +} + +bool AnimSoundImpl::ShouldPlayEvent(const AnimEventRef *ref) const { + if (!(ref->flags_0x08 & 1) && (ref->flags_0x08 & 4 || ref->flags_0x08 & 2)) { + return true; + } + int i1 = ut::Max((int)ref->field_0x09, 0); + int i2 = ut::Abs(field_0x1C); + if (ref->field_0x0A == 0) { + if (i2 < i1) { + return false; + } + } else { + if (i2 < i1) { + return false; + } + if ((i2 - i1) % ref->field_0x0A != 0) { + return false; + } + } + + return true; +} + +void AnimSoundImpl::UpdateEvents(s32 duration, PlayDirection direction) { + for (u32 eventIdx = 0; eventIdx < mReader.GetEventCount(); eventIdx++) { + const AnimEventRef *ref = mReader.GetEventRef(eventIdx); + if (ref == NULL) { + continue; + } + if (ShouldPlayEvent(ref)) { + // HACK/Fakematch: Force a reload + if ((((AnimEventRef *)ref)->flags_0x08) & 1) { + UpdateTrigger(ref, duration, direction); + } else { + if (direction == FORWARD) { + UpdateForwardRange(ref, duration); + } else { + UpdateBackwardRange(ref, duration); + } + } + } + } +} + +void AnimSoundImpl::UpdateForward(f32 frame) { + s32 duration = std::floorf(field_0x0C); + s32 iFrame = std::floorf(frame); + + if (field_0x1A && field_0x0C == duration) { + duration -= 1; + } + + if (duration == iFrame) { + return; + } + + s32 loopFrame = duration + 1; + while (true) { + if (loopFrame == mReader.GetAnimDuration()) { + loopFrame -= mReader.GetAnimDuration(); + field_0x1C++; + } + + UpdateEvents(loopFrame, FORWARD); + + if (loopFrame == iFrame) { + break; + } + loopFrame++; + } +} + +void AnimSoundImpl::UpdateBackward(f32 frame) { + s32 duration = std::ceilf(field_0x0C); + s32 iFrame = std::ceilf(frame); + + if (duration >= mReader.GetAnimDuration()) { + duration -= mReader.GetAnimDuration(); + } + + if (iFrame >= mReader.GetAnimDuration()) { + iFrame -= mReader.GetAnimDuration(); + } + + if (field_0x1A && field_0x0C == duration) { + duration += 1; + } + + if (duration == iFrame) { + return; + } + + s32 loopFrame = duration - 1; + while (true) { + if (loopFrame == -1) { + loopFrame += mReader.GetAnimDuration(); + field_0x1C--; + } + + UpdateEvents(loopFrame, BACKWARD); + + if (loopFrame == iFrame) { + break; + } + loopFrame--; + } +} + +void AnimSoundImpl::UpdateTrigger(const AnimEventRef *ref, s32 frame, PlayDirection direction) { + const AnimEvent *event = mReader.GetEvent(ref); + if (event == NULL) { + return; + } + + if (ref->flags_0x08 & 4) { + return; + } + + if (!event->MatchesDirection(direction)) { + return; + } + + if ((ref->flags_0x08 & 2)) { + if (ref->field_0x00 == frame) { + StopEvent(event); + if (mCallback != NULL) { + (mCallback)(0, frame, event->GetSoundLabel(), event->field_0x1C, field_0x24); + } + StartEvent(event, true); + } + } else { + if (ref->field_0x00 == frame) { + StopEvent(event); + if (mCallback != NULL) { + (mCallback)(0, frame, event->GetSoundLabel(), event->field_0x1C, field_0x24); + } + StartEvent(event, true); + } + + s32 u; + if (direction == FORWARD) { + u = ref->field_0x04; + } else { + u = ut::Max(ref->field_0x00 * 2 - ref->field_0x04, 0); + } + + if (u == frame) { + if (mCallback != NULL) { + (mCallback)(1, frame, event->GetSoundLabel(), event->field_0x1C, field_0x24); + } + StopEvent(event); + } + } +} + +void AnimSoundImpl::UpdateForwardRange(const AnimEventRef *ref, s32 frame) { + const AnimEvent *event = mReader.GetEvent(ref); + if (event == NULL) { + return; + } + + if (ref->flags_0x08 & 4 && ref->flags_0x08 & 2) { + HoldEvent(event, true); + return; + } + + if (ref->flags_0x08 & 4) { + if (ref->field_0x04 == frame && mCallback != NULL) { + (mCallback)(3, frame, event->GetSoundLabel(), event->field_0x1C, field_0x24); + } + if (field_0x1C < ref->field_0x09) { + HoldEvent(event, true); + } else if (field_0x1C == ref->field_0x09) { + if (frame < ref->field_0x04) { + HoldEvent(event, true); + } else { + StopEvent(event); + } + } + } else if ((ref->flags_0x08 & 2)) { + if (ref->field_0x00 == frame && mCallback != NULL) { + (mCallback)(2, frame, event->GetSoundLabel(), event->field_0x1C, field_0x24); + } + if (field_0x1C > ref->field_0x09) { + HoldEvent(event, true); + } else if (field_0x1C == ref->field_0x09 && ref->field_0x00 <= frame) { + HoldEvent(event, true); + } + } else { + if (ref->field_0x00 == frame && mCallback != NULL) { + (mCallback)(2, frame, event->GetSoundLabel(), event->field_0x1C, field_0x24); + } + if (ref->field_0x04 == frame && mCallback != NULL) { + (mCallback)(3, frame, event->GetSoundLabel(), event->field_0x1C, field_0x24); + } + if (ref->field_0x00 <= frame && frame < ref->field_0x04) { + HoldEvent(event, true); + } else { + StopEvent(event); + } + } +} + +void AnimSoundImpl::UpdateBackwardRange(const AnimEventRef *ref, s32 frame) { + const AnimEvent *event = mReader.GetEvent(ref); + if (event == NULL) { + return; + } + + if (ref->flags_0x08 & 4 && ref->flags_0x08 & 2) { + HoldEvent(event, true); + return; + } + + if (ref->flags_0x08 & 4) { + if (ref->field_0x04 == frame && mCallback != NULL) { + (mCallback)(2, frame, event->GetSoundLabel(), event->field_0x1C, field_0x24); + } + if (field_0x1C < ref->field_0x09) { + HoldEvent(event, true); + } else if (field_0x1C == ref->field_0x09 && frame <= ref->field_0x04) { + HoldEvent(event, true); + } + } else if ((ref->flags_0x08 & 2)) { + if (ref->field_0x00 == frame && mCallback != NULL) { + (mCallback)(3, frame, event->GetSoundLabel(), event->field_0x1C, field_0x24); + } + if (field_0x1C > ref->field_0x09) { + HoldEvent(event, true); + } else if (field_0x1C == ref->field_0x09) { + if (ref->field_0x00 < frame) { + HoldEvent(event, true); + } else { + StopEvent(event); + } + } + } else { + if (ref->field_0x00 == frame && mCallback != NULL) { + (mCallback)(3, frame, event->GetSoundLabel(), event->field_0x1C, field_0x24); + } + if (ref->field_0x04 == frame && mCallback != NULL) { + (mCallback)(2, frame, event->GetSoundLabel(), event->field_0x1C, field_0x24); + } + if (ref->field_0x00 < frame && frame <= ref->field_0x04) { + HoldEvent(event, true); + } else { + StopEvent(event); + } + } +} + +void AnimSoundImpl::StartEvent(const AnimEvent *event, bool b) { + int leastPriority = 0x80; + int leastPriorityIdx = -1; + int i = 0; + for (; i < mNumSounds; i++) { + if (!mpSounds[i].IsAttachedSound()) { + break; + } + int priority = mpSounds[i].GetPriority(); + if (leastPriority > priority) { + leastPriorityIdx = i; + leastPriority = priority; + } + } + + if (i == mNumSounds) { + mpSounds[leastPriorityIdx].Stop(); + i = leastPriorityIdx; + } + + mpSounds[i].StartSound(event, &mStartable, b); + + u32 varNo = 0; + if (event->GetVarNo(&varNo)) { + mpSounds[i].SetVariable(event, varNo, mVariableValue); + } +} + +void AnimSoundImpl::HoldEvent(const AnimEvent *event, bool b) { + int leastPriority = 0x80; + int leastPriorityIdx = -1; + int i = 0; + for (; i < mNumSounds; i++) { + if (mpSounds[i].IsCurrentEvent(event)) { + return; + } + if (!mpSounds[i].IsAttachedSound()) { + leastPriorityIdx = i; + leastPriority = -1; + } else { + int priority = mpSounds[i].GetPriority(); + if (leastPriority > priority) { + leastPriorityIdx = i; + leastPriority = priority; + } + } + } + + if (i == mNumSounds) { + mpSounds[leastPriorityIdx].Stop(); + i = leastPriorityIdx; + } + + mpSounds[i].HoldSound(event, &mStartable, b); + + u32 varNo = 0; + if (event->GetVarNo(&varNo)) { + mpSounds[i].SetVariable(event, varNo, mVariableValue); + } +} + +void AnimSoundImpl::StopEvent(const AnimEvent *event) { + for (int i = 0; i < mNumSounds; i++) { + mpSounds[i].StopEvent(event); + } +} + +bool AnimEventPlayer::StartSound(const AnimEvent *event, SoundStartable *startable, bool b) { + if (event->soundId == 0xFFFFFFFF) { + if (!startable->StartSound(GetHandle(), event->GetSoundLabel())) { + return false; + } + } else { + if (!startable->StartSound(GetHandle(), event->soundId)) { + return false; + } + } + + SetVolumePitch(event, b); + + return true; +} + +bool AnimEventPlayer::HoldSound(const AnimEvent *event, SoundStartable *startable, bool b) { + if (event->soundId == 0xFFFFFFFF) { + if (!startable->HoldSound(GetHandle(), event->GetSoundLabel())) { + return false; + } + } else { + if (!startable->HoldSound(GetHandle(), event->soundId)) { + return false; + } + } + + GetHandle()->detail_GetAttachedSound()->SetAutoStopCounter(0); + SetVolumePitch(event, b); + + return true; +} + +void AnimEventPlayer::SetVolumePitch(const AnimEvent *event, bool b) { + if (event->volume < 128) { + SetVolume(event->volume / 128.0f); + } + if (event->pitch != 1.0f) { + SetPitch(event->pitch); + } + + mpEvent = event; + if (b) { + b = !event->ShouldPreventStart(); + } + mIsRunning = b; +} + +void AnimEventPlayer::SetVariable(const AnimEvent *event, u32 varNo, f32 f) { + if (varNo < 16) { + if (GetHandle()->IsAttachedSound()) { + SeqSoundHandle handle(GetHandle()); + int iVal = f * 100.0f; + handle.WriteVariable(varNo, ut::Clamp(iVal, -0x8000, 0x7FFF)); + handle.DetachSound(); + } + } else if (varNo < 32) { + int iVal = f * 100.0f; + SeqSound::WriteGlobalVariable(varNo - 16, ut::Clamp(iVal, -0x8000, 0x7FFF)); + } +} + +AnimEventPlayer::AnimEventPlayer() : mpEvent(0), mIsRunning(false) {} + +AnimEventPlayer::~AnimEventPlayer() { + if (mHandle.IsAttachedSound() && IsRunning()) { + mHandle.Stop(); + } +} + +} // namespace detail +} // namespace snd +} // namespace nw4r diff --git a/src/nw4r/snd/snd_AnimSoundReader.cpp b/src/nw4r/snd/snd_AnimSoundReader.cpp index 555e5e94..a003139d 100644 --- a/src/nw4r/snd/snd_AnimSoundReader.cpp +++ b/src/nw4r/snd/snd_AnimSoundReader.cpp @@ -58,7 +58,7 @@ const AnimSoundFile::EventTable *AnimSoundFileReader::GetEventTable() const { if (mpBlock == NULL) { return NULL; } - return Util::GetDataRefAddress0(mpBlock->eventTable, &mpBlock->_0x08); + return Util::GetDataRefAddress0(mpBlock->eventTable, &mpBlock->duration); } const AnimEvent *AnimSoundFileReader::GetEvent(const AnimEventRef *ref) const { @@ -66,7 +66,7 @@ const AnimEvent *AnimSoundFileReader::GetEvent(const AnimEventRef *ref) const { return NULL; } const AnimSoundFile::EventTable *event = GetEventTable(); // unused - return Util::GetDataRefAddress0(ref->event, &mpBlock->_0x08); + return Util::GetDataRefAddress0(ref->event, &mpBlock->duration); } } // namespace detail