summaryrefslogtreecommitdiff
path: root/libs/JSystem/src/JAudio2/JASTrack.cpp
diff options
context:
space:
mode:
authorLuke Street <luke@street.dev>2026-03-01 15:35:36 -0700
committerGitHub <noreply@github.com>2026-03-01 14:35:36 -0800
commit9649319ec4926457ef85e6094f8207474c977c2d (patch)
tree1c5cd4c7cc4c1aee03f28921213da47f2775444d /libs/JSystem/src/JAudio2/JASTrack.cpp
parent6e149819e13b1f70ecbf8a4c66b030c17ffed2bb (diff)
Reorganize library code into `libs/` (#3119)
* Reorganize files into libs/{dolphin,JSystem,PowerPC_EABI_Support,revolution,TRK_MINNOW_DOLPHIN} * Update configure.py and project.py for new libs structure * Refactor `#include <dolphin/x.h>` -> `<x.h>` * Remove `__REVOLUTION_SDK__` forwards from dolphin * Fix dolphin/ references in revolution * Wrap `#include <dolphin.h>` in `!__REVOLUTION_SDK__` * Always build TRK against dolphin headers * Resolve revolution SDK header resolution issues
Diffstat (limited to 'libs/JSystem/src/JAudio2/JASTrack.cpp')
-rw-r--r--libs/JSystem/src/JAudio2/JASTrack.cpp878
1 files changed, 878 insertions, 0 deletions
diff --git a/libs/JSystem/src/JAudio2/JASTrack.cpp b/libs/JSystem/src/JAudio2/JASTrack.cpp
new file mode 100644
index 0000000000..eec0ebd644
--- /dev/null
+++ b/libs/JSystem/src/JAudio2/JASTrack.cpp
@@ -0,0 +1,878 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JAudio2/JASTrack.h"
+#include "JSystem/JAudio2/JASCriticalSection.h"
+#include "JSystem/JAudio2/JASDriverIF.h"
+#include "JSystem/JAudio2/JASBank.h"
+#include "JSystem/JAudio2/JASAiCtrl.h"
+#include "JSystem/JAudio2/JASDSPInterface.h"
+
+JASTrack::JASTrack() : mDefaultChannelMgr(this), mChannelMgrCount(1), mStatus(0) {
+ mChannelMgrs[0] = &mDefaultChannelMgr;
+ for (int i = 1; i < 4; i++) {
+ mChannelMgrs[i] = NULL;
+ }
+ init();
+}
+
+JASDefaultBankTable JASTrack::sDefaultBankTable;
+
+JASTrack::TList JASTrack::sTrackList;
+
+// NONMATCHING JASPoolAllocObject_MultiThreaded<_> locations
+JASTrack::~JASTrack() {
+ JUT_ASSERT(70, mStatus != STATUS_RUN);
+ for (int i = 1; i < 4; i++) {
+ delete mChannelMgrs[i];
+ }
+}
+
+// NONMATCHING JASPoolAllocObject_MultiThreaded<_> locations
+void JASTrack::setChannelMgrCount(u32 count) {
+ JUT_ASSERT(79, mStatus != STATUS_RUN);
+ JUT_ASSERT(80, count >= 1 && count <= CHANNEL_MGR_MAX);
+ mChannelMgrCount = 1;
+ for (int i = 1; i < count; i++) {
+ if (mChannelMgrs[i] == NULL) {
+ mChannelMgrs[i] = new TChannelMgr(this);
+ if (mChannelMgrs[i] == NULL) {
+ JUT_WARN(87, "%s", "Not enough JASTrackChannelMgr\n");
+ return;
+ }
+ }
+ mChannelMgrCount++;
+ }
+ for (u32 i = mChannelMgrCount; i < 4; i++) {
+ if (mChannelMgrs[i] != NULL) {
+ delete mChannelMgrs[i];
+ mChannelMgrs[i] = NULL;
+ }
+ }
+}
+
+JASOscillator::Point const JASTrack::sAdsTable[4] = {
+ {0, 0, 0x7fff},
+ {0, 0, 0x7fff},
+ {0, 0, 0},
+ {0xe, 0, 0},
+};
+
+JASOscillator::Data const JASTrack::sEnvOsc = {0, 1.0f, NULL, NULL, 1.0f, 0.0f};
+
+JASOscillator::Data const JASTrack::sPitchEnvOsc = {1, 1.0f, NULL, NULL, 1.0f, 0.0f};
+
+// NONMATCHING JASPoolAllocObject_MultiThreaded<_> locations
+void JASTrack::init() {
+ JUT_ASSERT(104, mStatus == STATUS_FREE || mStatus == STATUS_STOPPED);
+ mSeqCtrl.init();
+ mTrackPort.init();
+ initTimed();
+ mRegisterParam.init();
+ mOscParam[0] = sEnvOsc;
+ mOscParam[1] = sPitchEnvOsc;
+ for (int i = 0; i < 4; i++) {
+ mOscPoint[i] = sAdsTable[i];
+ }
+ mParent = NULL;
+ for (int i = 0; i < 16; i++) {
+ mChildren[i] = NULL;
+ }
+ mChannelMgrs[0]->init();
+ mChannelMgrCount = 1;
+ for (int i = 1; i < 4; i++) {
+ if (mChannelMgrs[i] != NULL) {
+ delete mChannelMgrs[i];
+ mChannelMgrs[i] = NULL;
+ }
+ }
+ mBankTable = &sDefaultBankTable;
+ field_0x1d8 = 1.0f;
+ field_0x1dc = 1.0f;
+ mVibDepth = 0.0f;
+ mVibPitch = 1.0f;
+ mTremDepth = 0.0f;
+ mTremPitch = 1.0f;
+ mVibDelay = 0;
+ mTremDelay = 0;
+ mPanPower = 1.0f;
+ mDirectRelease = 0;
+ mSkipSample = 0;
+ mTempo = 120;
+ mTimebase = 0x30;
+ mTempoRate = 1.0f;
+ updateTempo();
+ mTranspose = 0;
+ field_0x22b = 60;
+ mBankNumber = 0;
+ mProgNumber = 0xf0;
+ mBendSense = 0xc;
+ mNoteOnPrio = 0x40;
+ mReleasePrio = 0;
+ mGateRate = 100;
+ mMixConfig[0] = 0x150;
+ mMixConfig[1] = 0x210;
+ mMixConfig[2] = 0x352;
+ mMixConfig[3] = 0x412;
+ mMixConfig[4] = 0;
+ mMixConfig[5] = 0;
+ for (int i = 0; i < 8; i++) {
+ mFIR[i] = 0;
+ }
+ mFIR[0] = 0x7fff;
+ for (int i = 0; i < 8; i++) {
+ mIIR[i] = 0;
+ }
+ mIIR[0] = 0x7fff;
+ mFilterMode = 0;
+ mFlags.pause = false;
+ mFlags.mute = false;
+ mFlags.flag2 = true;
+ mFlags.flag5 = true;
+ mFlags.autoDelete = false;
+ mFlags.flag4 = false;
+ mFlags.flag6 = false;
+ mStatus = STATUS_FREE;
+}
+
+void JASTrack::initTimed() {
+ mMoveParam.params.volume.mValue = 1.0f;
+ mMoveParam.params.pitch.mValue = 0.0f;
+ mMoveParam.params.pan.mValue = 0.5f;
+ mMoveParam.params.fxmix.mValue = 0.0f;
+ mMoveParam.params.dolby.mValue = 0.0f;
+ mMoveParam.params.distFilter.mValue = 0.0f;
+ for (int i = 0; i < 6; i++) {
+ mMoveParam.array[i].mCount = 0;
+ mMoveParam.array[i].mTarget = mMoveParam.array[i].mValue;
+ }
+}
+
+void JASTrack::inherit(JASTrack const& i_parent) {
+ mFlags.flag2 = i_parent.mFlags.flag2;
+ mBankNumber = i_parent.mBankNumber;
+ mProgNumber = i_parent.mProgNumber;
+ mNoteOnPrio = i_parent.mNoteOnPrio;
+ mReleasePrio = i_parent.mReleasePrio;
+ mSkipSample = i_parent.mSkipSample;
+ for (int i = 0; i < 8; i++) {
+ mFIR[i] = i_parent.mFIR[i];
+ }
+ for (int i = 0; i < 8; i++) {
+ mIIR[i] = i_parent.mIIR[i];
+ }
+ mFilterMode = i_parent.mFilterMode;
+ for (int i = 0; i < 6; i++) {
+ mMixConfig[i] = i_parent.mMixConfig[i];
+ }
+}
+
+void JASTrack::assignExtBuffer(u32 index, JASSoundParams* i_soundParams) {
+ JUT_ASSERT(249, index < mChannelMgrCount);
+ mChannelMgrs[index]->mSoundParams = i_soundParams;
+}
+
+void JASTrack::setSeqData(void* param_0, u32 param_1) {
+ JUT_ASSERT(257, mStatus == STATUS_FREE);
+ mSeqCtrl.start(param_0, param_1);
+}
+
+void JASTrack::startSeq() {
+ JUT_ASSERT(265, mParent == 0);
+ JUT_ASSERT(266, mStatus == STATUS_FREE);
+ JASCriticalSection critical_section;
+ sTrackList.append(this);
+ mStatus = STATUS_RUN;
+}
+
+void JASTrack::stopSeq() {
+ JASCriticalSection critical_section;
+ mFlags.flag6 = 1;
+}
+
+void JASTrack::start() {
+ JUT_ASSERT(289, mParent != NULL);
+ JUT_ASSERT(290, mStatus == STATUS_FREE);
+ mStatus = STATUS_RUN;
+}
+
+void JASTrack::close() {
+ for (int i = 0; i < 16; i++) {
+ JASTrack* child = mChildren[i];
+ if (child != NULL) {
+ child->close();
+ if (child->mFlags.autoDelete) {
+ delete child;
+ mChildren[i] = NULL;
+ }
+ }
+ }
+ for (u32 i = 0; i < mChannelMgrCount; i++) {
+ if (mChannelMgrs[i] != NULL) {
+ mChannelMgrs[i]->releaseAll();
+ }
+ }
+ mParent = NULL;
+ mStatus = STATUS_STOPPED;
+}
+
+bool JASTrack::connectChild(u32 track_no, JASTrack* i_child) {
+ JUT_ASSERT(326, track_no < MAX_CHILDREN);
+ if (mChildren[track_no] != NULL) {
+ return false;
+ }
+ i_child->mParent = this;
+ mChildren[track_no] = i_child;
+ return true;
+}
+
+void JASTrack::closeChild(u32 track_no) {
+ JUT_ASSERT(340, track_no < MAX_CHILDREN);
+ JASTrack* child = mChildren[track_no];
+ if (child != NULL) {
+ getRootTrack()->updateSeq(false, 1.0f);
+ child->close();
+ if (child->mFlags.autoDelete) {
+ delete child;
+ mChildren[track_no] = NULL;
+ }
+ }
+}
+
+// NONMATCHING JASPoolAllocObject_MultiThreaded<_> locations
+JASTrack* JASTrack::openChild(u32 trk_no) {
+ JUT_ASSERT(358, trk_no < MAX_CHILDREN);
+ JASTrack* child = mChildren[trk_no];
+ if (child != NULL) {
+ switch (child->mStatus) {
+ case STATUS_FREE:
+ break;
+ case STATUS_RUN:
+ getRootTrack()->updateSeq(false, 1.0f);
+ child->close();
+ // no break
+ case STATUS_STOPPED:
+ bool auto_delete = child->mFlags.autoDelete;
+ child->init();
+ child->mFlags.autoDelete = auto_delete;
+ mChildren[trk_no] = NULL;
+ connectChild(trk_no, child);
+ break;
+ }
+ } else {
+ child = new JASTrack();
+ if (child == NULL) {
+ JUT_WARN(388, "%s", "Not enough JASTrack\n");
+ return NULL;
+ }
+ child->mFlags.autoDelete = true;
+ connectChild(trk_no, child);
+ }
+ child->setChannelMgrCount(mChannelMgrCount);
+ child->inherit(*this);
+ return child;
+}
+
+void JASTrack::connectBus(int line, int param_1) {
+ JUT_ASSERT(404, line < JASChannel::BUSOUT_CPUCH);
+ mMixConfig[line] = param_1;
+}
+
+f32 JASTrack::getVolume() const { return mMoveParam.params.volume.mValue; }
+f32 JASTrack::getPitch() const { return mMoveParam.params.pitch.mValue; }
+f32 JASTrack::getPan() const { return mMoveParam.params.pan.mValue; }
+f32 JASTrack::getFxmix() const { return mMoveParam.params.fxmix.mValue; }
+f32 JASTrack::getDolby() const { return mMoveParam.params.dolby.mValue; }
+
+void JASTrack::setLatestKey(u8 param_0) {
+ field_0x22b = param_0;
+ field_0x22b += getTransposeTotal();
+}
+
+JASChannel* JASTrack::channelStart(JASTrack::TChannelMgr* i_channelMgr, u32 param_1, u32 param_2,
+ u32 i_updateTimer) {
+ JASBank* bank = NULL;
+ if (mBankTable != NULL) {
+ bank = mBankTable->getBank(mBankNumber);
+ }
+ JASChannel* channel = JASBank::noteOn(bank, mProgNumber, param_1, param_2,
+ mNoteOnPrio | mReleasePrio << 8,
+ channelUpdateCallback, i_channelMgr);
+ if (channel == NULL) {
+ return NULL;
+ }
+ channel->setUpdateTimer(i_updateTimer);
+ channel->setSkipSamples(mSkipSample);
+ channel->setVibrateDelay(mVibDelay);
+ channel->setTremoloDelay(mTremDelay);
+ channel->setParams(i_channelMgr->mParams);
+ for (u32 i = 0; i < 6; i++) {
+ channel->setMixConfig(i, mMixConfig[i]);
+ }
+ overwriteOsc(channel);
+ if (mDirectRelease != 0) {
+ channel->setDirectRelease(mDirectRelease);
+ }
+ return channel;
+}
+
+int JASTrack::noteOn(u32 noteid, u32 param_1, u32 param_2) {
+ JUT_ASSERT(486, noteid != 0 && noteid < TChannelMgr::CHANNEL_MAX);
+ if (isMute()) {
+ return 0;
+ }
+ int ret = 1;
+ param_1 += getTransposeTotal();
+ for (u32 i = 0; i < mChannelMgrCount; i++) {
+ if (mChannelMgrs[i] != NULL) {
+ mChannelMgrs[i]->noteOff(noteid, 0);
+ JASChannel* channel = channelStart(mChannelMgrs[i], param_1, param_2, 0);
+ if (channel == NULL) {
+ ret = 0;
+ }
+ mChannelMgrs[i]->mChannels[noteid] = channel;
+ }
+ }
+ return ret;
+}
+
+int JASTrack::gateOn(u32 param_0, u32 i_velocity, f32 i_time, u32 i_flags) {
+ bool result = true;
+ param_0 += getTransposeTotal();
+ if (mGateRate != 100) {
+ i_time *= mGateRate / 100.0f;
+ }
+ u32 uvar2 = seqTimeToDspTime(i_time);
+ u32 update_timer = (i_flags & 6) ? 0 : uvar2;
+ int uvar7 = i_flags & 1 ? field_0x22b : param_0;
+ for (u32 i = 0; i < mChannelMgrCount; i++) {
+ TChannelMgr* channel_mgr = mChannelMgrs[i];
+ if (channel_mgr != NULL) {
+ if (!mFlags.flag4) {
+ channel_mgr->noteOff(0, 0);
+ if (!isMute()) {
+ channel_mgr->mChannels[0] =
+ channelStart(channel_mgr, uvar7, i_velocity, update_timer);
+ }
+ } else {
+ JASChannel* channel = channel_mgr->mChannels[0];
+ if (channel != NULL) {
+ channel->setKey(uvar7 - channel->field_0xdc.field_0x4.field_0x01);
+ channel->setVelocity(i_velocity);
+ channel->setUpdateTimer(update_timer);
+ }
+ }
+ if (i_flags & 1) {
+ JASChannel* channel = channel_mgr->mChannels[0];
+ if (channel != NULL) {
+ channel->setKeySweepTarget(param_0 - uvar7, uvar2);
+ }
+ }
+ }
+ }
+ mFlags.flag4 = (i_flags & 2) ? true : false;
+ field_0x22b = param_0;
+ return result;
+}
+
+int JASTrack::noteOff(u32 noteid, u16 param_1) {
+ JUT_ASSERT(563, noteid < TChannelMgr::CHANNEL_MAX);
+ int ret = 1;
+ for (u32 i = 0; i < mChannelMgrCount; i++) {
+ if (mChannelMgrs[i] != NULL) {
+ if (!mChannelMgrs[i]->noteOff(noteid, param_1)) {
+ ret = 0;
+ }
+ }
+ }
+ return ret;
+}
+
+bool JASTrack::checkNoteStop(u32 noteid) const {
+ JUT_ASSERT(581, noteid < TChannelMgr::CHANNEL_MAX);
+ for (u32 i = 0; i < mChannelMgrCount; i++) {
+ if (mChannelMgrs[i] != NULL) {
+ JASChannel* channel = mChannelMgrs[i]->mChannels[noteid];
+ if (channel != NULL) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void JASTrack::overwriteOsc(JASChannel* i_channel) {
+ for (u32 i = 0; i < 2; i++) {
+ if (mOscParam[i].mTable != NULL) {
+ JUT_ASSERT(599, mOscParam[i].rel_table == 0);
+ i_channel->setOscInit(i, &mOscParam[i]);
+ }
+ }
+}
+
+void JASTrack::updateTimedParam() {
+ for (int i = 0; i < 6; i++) {
+ MoveParam_* param = &mMoveParam.array[i];
+ if (param->mCount != 0) {
+ param->mValue += (param->mTarget - param->mValue) / param->mCount;
+ param->mCount--;
+ }
+ }
+}
+
+void JASTrack::updateTrack(f32 param_0) {
+ updateTempo();
+ for (u32 i = 0; i < mChannelMgrCount; i++) {
+ TChannelMgr* channel_mgr = mChannelMgrs[i];
+ if (channel_mgr != NULL) {
+ f32 volume = mMoveParam.params.volume.mValue;
+ volume = volume * volume;
+ f32 pitch = 1.0f;
+ f32 fvar6 = mMoveParam.params.pitch.mValue * mBendSense * (1.0f / 3.0f);
+ f32 pan = (mMoveParam.params.pan.mValue - 0.5f) * mPanPower;
+ f32 fxmix = mMoveParam.params.fxmix.mValue;
+ f32 dolby = mMoveParam.params.dolby.mValue;
+ if (channel_mgr->mSoundParams != NULL) {
+ volume *= channel_mgr->mSoundParams->mVolume;
+ pitch *= channel_mgr->mSoundParams->mPitch;
+ pan += channel_mgr->mSoundParams->mPan - 0.5f;
+ fxmix += channel_mgr->mSoundParams->mFxMix;
+ dolby += channel_mgr->mSoundParams->mDolby;
+ }
+ pan *= param_0;
+ if (mParent == NULL) {
+ channel_mgr->mParams.mVolume = volume;
+ channel_mgr->mParams.mPitch = pitch;
+ channel_mgr->mParams.mPan = pan;
+ channel_mgr->mParams.mFxMix = fxmix;
+ channel_mgr->mParams.mDolby = dolby;
+ channel_mgr->mParams.field_0x8 = fvar6;
+ } else {
+ TChannelMgr* parent_channel_mgr = mParent->mChannelMgrs[i];
+ if (parent_channel_mgr == NULL) {
+ parent_channel_mgr = mParent->mChannelMgrs[0];
+ }
+ channel_mgr->mParams.mVolume = parent_channel_mgr->mParams.mVolume * volume;
+ channel_mgr->mParams.mPitch = parent_channel_mgr->mParams.mPitch * pitch;
+ channel_mgr->mParams.mPan = (parent_channel_mgr->mParams.mPan - 0.5f) + pan;
+ channel_mgr->mParams.mFxMix = parent_channel_mgr->mParams.mFxMix + fxmix;
+ channel_mgr->mParams.mDolby = parent_channel_mgr->mParams.mDolby + dolby;
+ channel_mgr->mParams.field_0x8 = parent_channel_mgr->mParams.field_0x8 + fvar6;
+ }
+ channel_mgr->mParams.mPan += 0.5f;
+ }
+ }
+}
+
+void JASTrack::updateTempo() {
+ if (mParent == NULL) {
+ field_0x1dc = mTempoRate * (mTimebase * mTempo * (4.0f / 3.0f) / JASDriver::getDacRate());
+ } else {
+ mTempo = mParent->mTempo;
+ mTimebase = mParent->mTimebase;
+ field_0x1dc = mParent->field_0x1dc;
+ }
+}
+
+void JASTrack::updateSeq(bool param_0, f32 param_1) {
+ if (!param_0) {
+ param_0 = mFlags.flag5;
+ }
+ mFlags.flag5 = false;
+ if (param_0) {
+ updateTrack(param_1);
+ }
+ f32 fvar1 = param_1 * mPanPower;
+ for (int i = 0; i < 16; i++) {
+ JASTrack* child = mChildren[i];
+ if (child != NULL && child->mStatus == STATUS_RUN) {
+ child->updateSeq(param_0, fvar1);
+ }
+ }
+}
+
+u32 JASTrack::seqTimeToDspTime(f32 i_seqTime) {
+ if (mFlags.flag2) {
+ i_seqTime = i_seqTime / field_0x1dc;
+ } else {
+ i_seqTime = i_seqTime * (120.0f / mTimebase);
+ i_seqTime *= JASDriver::getSubFrames() / 10.0f;
+ }
+ return i_seqTime;
+}
+
+void JASTrack::setParam(u32 target, f32 i_target, u32 i_count) {
+ JUT_ASSERT(739, target < TIMED_PARAMS);
+ MoveParam_* param = &mMoveParam.array[target];
+ param->mTarget = i_target;
+ if (i_count == 0) {
+ param->mValue = param->mTarget;
+ }
+ param->mCount = i_count;
+}
+
+void JASTrack::noteOffAll(u16 param_0) {
+ for (u8 i = 0; i < 8; i++) {
+ noteOff(i, param_0);
+ }
+ for (int i = 0; i < 16; i++) {
+ JASTrack* child = mChildren[i];
+ if (child != NULL && child->mStatus == STATUS_RUN) {
+ child->noteOffAll(param_0);
+ }
+ }
+}
+
+void JASTrack::mute(bool i_mute) {
+ mFlags.mute = i_mute;
+ if (i_mute) {
+ noteOffAll(10);
+ }
+}
+
+void JASTrack::setOscScale(u32 osc_no, f32 i_scale) {
+ JUT_ASSERT(792, osc_no < OSC_NUM);
+ mOscParam[osc_no].mScale = i_scale;
+}
+
+void JASTrack::setOscTable(u32 osc_no, JASOscillator::Point const* i_table) {
+ JUT_ASSERT(799, osc_no < OSC_NUM)
+ mOscParam[osc_no].mTable = i_table;
+ if (osc_no != 0) {
+ mOscParam[osc_no].rel_table = NULL;
+ }
+}
+
+void JASTrack::setOscAdsr(s16 param_0, s16 param_1, s16 param_2, s16 param_3, u16 i_directRelease) {
+ mOscParam[0] = sEnvOsc;
+ mOscParam[0].mTable = mOscPoint;
+ mOscPoint[0]._2 = param_0;
+ mOscPoint[1]._2 = param_1;
+ mOscPoint[2]._2 = param_2;
+ mOscPoint[2]._4 = param_3;
+ mDirectRelease = i_directRelease;
+}
+
+const u32 JASDsp::FILTER_MODE_IIR = 0x00000020;
+
+void JASTrack::setFIR(s16 const* i_FIR) {
+ for (int i = 0; i < 8; i++) {
+ mFIR[i] = i_FIR[i];
+ }
+ mFilterMode &= JASDsp::FILTER_MODE_IIR;
+ mFilterMode |= 8;
+}
+
+void JASTrack::setIIR(s16 const* i_IIR) {
+ for (int i = 0; i < 8; i++) {
+ mIIR[i] = i_IIR[i];
+ }
+ mFilterMode |= JASDsp::FILTER_MODE_IIR;
+}
+
+u16 JASTrack::readPortSelf(u32 param_0) {
+ return mTrackPort.readImport(param_0);
+}
+
+void JASTrack::writePortSelf(u32 param_0, u16 param_1) {
+ mTrackPort.writeExport(param_0, param_1);
+}
+
+void JASTrack::writePort(u32 param_0, u16 param_1) {
+ JASSeqCtrl::IntrType intr;
+ mTrackPort.writeImport(param_0, param_1);
+ if (param_0 == 0 || param_0 == 1) {
+ if (param_0 == 0) {
+ intr = JASSeqCtrl::INTRTYPE_VALUE_2;
+ } else {
+ intr = JASSeqCtrl::INTRTYPE_VALUE_3;
+ }
+ mSeqCtrl.interrupt(intr);
+ }
+}
+
+u16 JASTrack::readPort(u32 param_0) {
+ return mTrackPort.readExport(param_0);
+}
+
+void JASTrack::setChannelPauseFlag(bool i_pause) {
+ for (u32 i = 0; i < mChannelMgrCount; i++) {
+ TChannelMgr* mgr = mChannelMgrs[i];
+ if (mgr != NULL) {
+ mgr->setPauseFlag(i_pause);
+ }
+ }
+ for (int i = 0; i < 16; i++) {
+ JASTrack* child = mChildren[i];
+ if (child != NULL) {
+ child->setChannelPauseFlag(i_pause);
+ }
+ }
+}
+
+void JASTrack::pause(bool i_pause) {
+ if (mFlags.pause != i_pause) {
+ mFlags.pause = i_pause;
+ setChannelPauseFlag(i_pause);
+ mSeqCtrl.interrupt(i_pause ? JASSeqCtrl::INTRTYPE_VALUE_0 : JASSeqCtrl::INTRTYPE_VALUE_1);
+ }
+}
+
+int JASTrack::getTransposeTotal() const {
+ if (mParent != NULL) {
+ return mTranspose + mParent->getTransposeTotal();
+ } else {
+ return mTranspose;
+ }
+}
+
+bool JASTrack::isMute() const {
+ if (mParent != NULL) {
+ return mFlags.mute || mParent->isMute();
+ } else {
+ return mFlags.mute;
+ }
+}
+
+void JASTrack::setTempo(u16 i_tempo) {
+ JUT_ASSERT(961, mParent == 0);
+ mTempo = i_tempo;
+ mFlags.flag5 = true;
+ updateTempo();
+}
+
+void JASTrack::setTempoRate(f32 i_tempoRate) {
+ JUT_ASSERT(969, mParent == 0);
+ mTempoRate = i_tempoRate;
+ mFlags.flag5 = true;
+ updateTempo();
+}
+
+void JASTrack::setTimebase(u16 i_timebase) {
+ JUT_ASSERT(977, mParent == 0);
+ mTimebase = i_timebase;
+ mFlags.flag5 = true;
+ updateTempo();
+}
+
+void JASTrack::updateChannel(JASChannel* param_0, JASDsp::TChannel* param_1) {
+ param_0->setVibrate(mVibDepth, mVibPitch);
+ param_0->setTremolo(mTremDepth, mTremPitch);
+ if (mFilterMode & 0x20) {
+ param_1->setIIRFilterParam(mIIR);
+ }
+ if (mFilterMode & 0x1f) {
+ param_1->setFIR8FilterParam(mFIR);
+ }
+ param_1->setFilterMode(mFilterMode);
+ param_1->setDistFilter(mMoveParam.params.distFilter.mValue * 32767.0f);
+}
+
+
+void JASTrack::channelUpdateCallback(u32 param_0, JASChannel* param_1,
+ JASDsp::TChannel* param_2, void* param_3) {
+ TChannelMgr* channel_mgr = static_cast<TChannelMgr*>(param_3);
+ JASTrack* track = channel_mgr->mTrack;
+ switch (param_0) {
+ case 0:
+ case 1:
+ param_1->setParams(channel_mgr->mParams);
+ track->updateChannel(param_1, param_2);
+ break;
+ case 3:
+ param_1->release(0);
+ param_1->free();
+ channel_mgr->mChannels[0] = NULL;
+ break;
+ case 2:
+ for (int i = 0; i < 8; i++) {
+ if (param_1 == channel_mgr->mChannels[i]) {
+ channel_mgr->mChannels[i] = NULL;
+ break;
+ }
+ }
+ break;
+ }
+}
+
+int JASTrack::getChannelCount() const {
+ JASCriticalSection cs;
+ int count = 0;
+ for (int i = 0; i < mChannelMgrCount; i++) {
+ if (mChannelMgrs[i]) {
+ for (int j = 0; j < 8; j++) {
+ if (mChannelMgrs[i]->mChannels[j]) {
+ count++;
+ }
+ }
+ }
+ }
+ return count;
+}
+
+JASTrack* JASTrack::getRootTrack() {
+ JASTrack* track = this;
+ while (track->mParent != NULL) {
+ track = track->mParent;
+ }
+ return track;
+}
+
+int JASTrack::tickProc() {
+ if (mFlags.pause) {
+ return 0;
+ }
+ int ret = mSeqCtrl.tickProc(this);
+ updateTimedParam();
+ mFlags.flag5 = true;
+ if (ret < 0) {
+ return -1;
+ }
+ for (int i = 0; i < 16; i++) {
+ JASTrack* child = mChildren[i];
+ if (child != NULL && child->mStatus == STATUS_RUN) {
+ JUT_ASSERT(1090, this == child->mParent);
+ ret = child->tickProc();
+ if (ret < 0) {
+ getRootTrack()->updateSeq(false, 1.0f);
+ child->close();
+ if (child->mFlags.autoDelete) {
+ delete child;
+ mChildren[i] = NULL;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int JASTrack::seqMain() {
+ JUT_ASSERT(1108, mStatus == STATUS_RUN);
+ if (mFlags.flag6) {
+ updateSeq(true, 1.0f);
+ close();
+ return -1;
+ } else {
+ while (field_0x1d8 >= 1.0f) {
+ field_0x1d8 -= 1.0f;
+ int ret = tickProc();
+ if (ret < 0) {
+ updateSeq(false, 1.0f);
+ close();
+ return -1;
+ }
+ }
+ field_0x1d8 += field_0x1dc;
+ updateSeq(false, 1.0f);
+ return 0;
+ }
+}
+
+s32 JASTrack::TList::cbSeqMain(void* i_this) {
+ JASTrack::TList* list = static_cast<JASTrack::TList*>(i_this);
+ list->seqMain();
+ return 0;
+}
+
+void JASTrack::TList::append(JASTrack* i_track) {
+ if (!mCallbackRegistered) {
+ if (!JASDriver::registerSubFrameCallback(cbSeqMain, this)) {
+ JUT_WARN(1157, "%s", "Failed: registerSubFrameCallback");
+ return;
+ }
+ mCallbackRegistered = true;
+ }
+ Push_back(i_track);
+}
+
+void JASTrack::TList::seqMain() {
+#if DEBUG
+ iterator it, it2;
+ for (it = begin(); it != end(); it = it2) {
+ it2 = it;
+ ++it2;
+ int seqMainRes = it->seqMain();
+ if (seqMainRes < 0) {
+ Remove(&*it);
+ if (it->mFlags.autoDelete) {
+ delete &*it;
+ }
+ }
+ }
+#else
+ iterator it;
+ for (it = begin(); it != end();) {
+ // Fakematch: Debug shows that it2 should be declared outside the loop and then this line
+ // should use operator=, but that results in a missing load instruction for retail, so we
+ // use the copy constructor instead of the assignment operator, which fixes it for some
+ // reason. Might be related to the fakematch in the assignment operator?
+ iterator it2 = it;
+ ++it2;
+ int seqMainRes = it->seqMain();
+ if (seqMainRes < 0) {
+ Remove(&*it);
+ if (it->mFlags.autoDelete) {
+ delete &*it;
+ }
+ }
+ it = it2;
+ }
+#endif
+}
+
+JASTrack::TChannelMgr::TChannelMgr(JASTrack* i_track) : mSoundParams(NULL), mTrack(i_track) {
+ for (int i = 0; i < 8; i++) {
+ mChannels[i] = NULL;
+ }
+ for (int i = 0; i < 8; i++) {
+ field_0x38[i] = 0;
+ }
+}
+
+
+void JASTrack::TChannelMgr::init() {
+ mSoundParams = NULL;
+ mParams.init();
+ for (int i = 0; i < 8; i++) {
+ mChannels[i] = NULL;
+ }
+ for (int i = 0; i < 8; i++) {
+ field_0x38[i] = 0;
+ }
+}
+
+
+void JASTrack::TChannelMgr::releaseAll() {
+ for (int i = 0; i < 8; i++) {
+ JASChannel* channel = mChannels[i];
+ if (channel != NULL) {
+ channel->release(0);
+ channel->free();
+ mChannels[i] = NULL;
+ }
+ }
+}
+
+bool JASTrack::TChannelMgr::noteOff(u32 noteid, u16 param_1) {
+ JUT_ASSERT(1224, noteid < CHANNEL_MAX);
+ JASChannel* channel = mChannels[noteid];
+ if (channel == NULL) {
+ return false;
+ }
+ if (param_1 == 0) {
+ channel->release(0);
+ } else {
+ channel->release(param_1);
+ }
+ channel->free();
+ mChannels[noteid] = NULL;
+ return true;
+}
+
+void JASTrack::TChannelMgr::setPauseFlag(bool i_pause) {
+ for (int i = 0; i < 8; i++) {
+ JASChannel* channel = mChannels[i];
+ if (channel != NULL) {
+ channel->setPauseFlag(i_pause);
+ }
+ }
+}