summaryrefslogtreecommitdiff
path: root/src/nw4r
diff options
context:
space:
mode:
authorrobojumper <robojumper@gmail.com>2025-05-29 15:10:23 +0200
committerrobojumper <robojumper@gmail.com>2025-05-29 15:10:29 +0200
commit8894f73305da296dd7d67036eae97865b5f29876 (patch)
tree5f68ae9cf202fa8921ddacad5a35d0802531ddd2 /src/nw4r
parent79b20186423b791b8bacb4dfbfc4ea764bbd8051 (diff)
snd_AnimSound OK
Diffstat (limited to 'src/nw4r')
-rw-r--r--src/nw4r/snd/snd_AnimSound.cpp481
-rw-r--r--src/nw4r/snd/snd_AnimSoundReader.cpp4
2 files changed, 478 insertions, 7 deletions
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 <decomp.h>
+#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 <cmath>
+
+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) {}
-#include "nw4r/snd/snd_Util.h"
+AnimEventPlayer::~AnimEventPlayer() {
+ if (mHandle.IsAttachedSound() && IsRunning()) {
+ mHandle.Stop();
+ }
+}
-DECOMP_FORCE(nw4r::snd::detail::Util::GetDataRefAddress0(
- *static_cast<nw4r::snd::detail::Util::DataRef<char> const *>(nullptr),
- nullptr));
+} // 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