JASOscillator (#675)

* JASOscillator work

* JASOscillator matching

* JASOscillator code cleanup

* JASOscillator minor tweak

* Fixed build

* Update src/JSystem/JAudio/JASOscillator.cpp

Co-authored-by: LagoLunatic <LagoLunatic@users.noreply.github.com>

---------

Co-authored-by: LagoLunatic <LagoLunatic@users.noreply.github.com>
This commit is contained in:
Daniel Hajjar
2024-08-22 08:29:36 +02:00
committed by GitHub
parent ce9dde8595
commit fb2a2e978e
6 changed files with 284 additions and 54 deletions
+1 -1
View File
@@ -745,7 +745,7 @@ config.libs = [
Object(Matching, "JSystem/JAudio/JASChAllocQueue.cpp"),
Object(NonMatching, "JSystem/JAudio/JASChannel.cpp"),
Object(NonMatching, "JSystem/JAudio/JASChannelMgr.cpp"),
Object(NonMatching, "JSystem/JAudio/JASOscillator.cpp"),
Object(Matching, "JSystem/JAudio/JASOscillator.cpp"),
Object(Matching, "JSystem/JAudio/JASDriverTables.cpp"),
Object(Matching, "JSystem/JAudio/dspproc.c", extra_cflags="-lang c++ -O4 -func_align 32"),
Object(Matching, "JSystem/JAudio/dsptask.c", extra_cflags="-lang c++ -O4 -func_align 32"),
+25 -12
View File
@@ -9,8 +9,8 @@ namespace JASystem {
struct Osc_ {
/* 0x00 */ u8 field_0x0;
/* 0x04 */ f32 field_0x4;
/* 0x08 */ void* table;
/* 0x0C */ void* rel_table;
/* 0x08 */ s16* table;
/* 0x0C */ s16* rel_table;
/* 0x10 */ f32 field_0x10;
/* 0x14 */ f32 field_0x14;
};
@@ -22,18 +22,31 @@ namespace JASystem {
f32 getOffset();
bool forceStop();
bool release();
void calc(s16*);
f32 calc(s16*);
/* 0x00 */ const Osc_* field_0x0;
/* 0x04 */ u8 field_0x4;
const Osc_* getOsc() const { return mOsc; }
void setOsc(const Osc_* osc) { mOsc = osc; }
BOOL isOsc() { return mOsc != NULL ? TRUE : FALSE; }
void releaseDirect(u16 param_0) { mDirectRelease = param_0; }
void bankOscToOfs() {}
void getEffectorKind() const {}
void getOscMode() const {}
static s16 oscTableForceStop[6];
static const f32 relTableSampleCell[17];
static const f32 relTableSqRoot[17];
static const f32 relTableSquare[17];
/* 0x00 */ const Osc_* mOsc;
/* 0x04 */ u8 mState;
/* 0x05 */ u8 field_0x5;
/* 0x06 */ short field_0x6;
/* 0x08 */ f32 field_0x8;
/* 0x0C */ f32 field_0xc;
/* 0x10 */ f32 field_0x10;
/* 0x14 */ f32 field_0x14;
/* 0x18 */ u16 field_0x18;
/* 0x1C */ f32 field_0x1c;
/* 0x06 */ u16 field_0x6;
/* 0x08 */ f32 mReleaseRate;
/* 0x0C */ f32 mPhase;
/* 0x10 */ f32 mTargetPhase;
/* 0x14 */ f32 mPhaseChangeRate;
/* 0x18 */ u16 mDirectRelease;
/* 0x1C */ f32 mInitialReleaseRate;
};
}
+10 -9
View File
@@ -47,7 +47,7 @@ void JASystem::TChannel::init() {
}
for (u32 i = 0; i < 4; i++) {
JUT_ASSERT(155, osc[i]);
osc[i]->field_0x0 = NULL;
osc[i]->setOsc(NULL);
osc[i]->init();
}
mPauseFlag = 0;
@@ -67,7 +67,7 @@ void JASystem::TChannel::setOscillator(u32 oscnum, TOscillator* param_2) {
/* 8028B620-8028B6A8 .text setOscInit__Q28JASystem8TChannelFUlPCQ38JASystem11TOscillator4Osc_ */
void JASystem::TChannel::setOscInit(u32 oscnum, const TOscillator::Osc_* param_2) {
JUT_ASSERT(183, oscnum < (4));
osc[oscnum]->field_0x0 = param_2;
osc[oscnum]->setOsc(param_2);
osc[oscnum]->initStart();
}
@@ -75,27 +75,28 @@ void JASystem::TChannel::setOscInit(u32 oscnum, const TOscillator::Osc_* param_2
bool JASystem::TChannel::forceStopOsc(u32 numosc) {
/* Nonmatching */
JUT_ASSERT(195, numosc < (4));
return osc[numosc]->field_0x0 != NULL ? osc[numosc]->forceStop() : false;
return osc[numosc]->isOsc() ? osc[numosc]->forceStop() : false;
}
/* 8028B73C-8028B7D0 .text releaseOsc__Q28JASystem8TChannelFUl */
bool JASystem::TChannel::releaseOsc(u32 numosc) {
/* Nonmatching */
JUT_ASSERT(209, numosc < (4));
return osc[numosc]->field_0x0 ? osc[numosc]->release() : false;
return osc[numosc]->isOsc() ? osc[numosc]->release() : false;
}
/* 8028B7D0-8028B850 .text directReleaseOsc__Q28JASystem8TChannelFUlUs */
void JASystem::TChannel::directReleaseOsc(u32 oscnum, u16 param_2) {
JUT_ASSERT(224, oscnum < (4));
osc[oscnum]->field_0x18 = param_2;
osc[oscnum]->releaseDirect(param_2);
}
/* 8028B850-8028B8E4 .text bankOscToOfs__Q28JASystem8TChannelFUl */
f32 JASystem::TChannel::bankOscToOfs(u32 oscnum) {
/* Nonmatching */
JUT_ASSERT(234, oscnum < (4));
return osc[oscnum]->field_0x0 ? osc[oscnum]->getOffset() : 1.0f;
// Probably uses inline JASystem::TOscillator::bankOscToOfs
return osc[oscnum]->isOsc() ? osc[oscnum]->getOffset() : 1.0f;
}
/* 8028B8E4-8028BA98 .text effectOsc__Q28JASystem8TChannelFUlf */
@@ -107,14 +108,14 @@ void JASystem::TChannel::effectOsc(u32 oscnum, f32 param_2) {
int JASystem::TChannel::getOscState(u32 oscnum) const {
/* Nonmatching */
JUT_ASSERT(274, oscnum < (4));
return osc[oscnum]->field_0x4;
return osc[oscnum]->mState;
}
/* 8028BB14-8028BB98 .text isOsc__Q28JASystem8TChannelFUl */
BOOL JASystem::TChannel::isOsc(u32 oscnum) {
/* Nonmatching */
JUT_ASSERT(284, oscnum < (4));
return osc[oscnum]->field_0x0 != 0;
return osc[oscnum]->isOsc();
}
/* 8028BB98-8028BC78 .text copyOsc__Q28JASystem8TChannelFUlPQ38JASystem11TOscillator4Osc_ */
@@ -122,7 +123,7 @@ void JASystem::TChannel::copyOsc(u32 oscnum, TOscillator::Osc_* param_2) {
/* Nonmatching */
JUT_ASSERT(295, oscnum < (4));
if (isOsc(oscnum)) {
*param_2 = *osc[oscnum]->field_0x0;
*param_2 = *osc[oscnum]->getOsc();
} else {
OSReport("osc[%d] is NULL\n", oscnum);
}
+240 -24
View File
@@ -4,59 +4,275 @@
//
#include "JSystem/JAudio/JASOscillator.h"
#include "JSystem/JAudio/JASDriverIF.h"
#include "JSystem/JAudio/JASRate.h"
#include "dolphin/os/OS.h"
#include "dolphin/types.h"
#include "math.h"
s16 JASystem::TOscillator::oscTableForceStop[] = {
0, 15, 0,
15, 0, 0
};
const f32 JASystem::TOscillator::relTableSampleCell[] = {
1.0f, 0.970489f, 0.781274f, 0.546281f, 0.399792f, 0.289315f,
0.212104f, 0.157476f, 0.112613f, 0.0817896f, 0.0579852f, 0.0436415f,
0.0308237f, 0.0237129f, 0.0152593f, 0.00915555f,
};
// relTableSqRoot[i] = pow(1 - i/16, 2)
const f32 JASystem::TOscillator::relTableSqRoot[] = {
1.0f, 0.878906f, 0.765625f, 0.660156f,
0.5625f, 0.472656f, 0.390625f, 0.316406f,
0.25f, 0.191406f, 0.140625f, 0.0976562f,
0.0625f, 0.0351562f, 0.015625f, 0.00390625,
};
// relTableSquare[i] = sqrt(1 - i/16)
const f32 JASystem::TOscillator::relTableSquare[] = {
1.0f, 0.968246f, 0.935414f, 0.901388f,
0.866025f, 0.829156f, 0.790569f, 0.75f,
0.707107f, 0.661438f, 0.612372f, 0.559017f,
0.5f, 0.433013f, 0.353553f, 0.25f,
};
/* 8028DE94-8028DECC .text init__Q28JASystem11TOscillatorFv */
void JASystem::TOscillator::init() {
field_0x0 = NULL;
field_0x4 = 1;
mOsc = NULL;
mState = 1;
field_0x5 = 0;
field_0x6 = 0;
field_0x8 = 0.0f;
field_0xc = 0.0f;
field_0x10 = 0.0f;
field_0x14 = 0.0f;
field_0x18 = 0;
field_0x1c = 0.0f;
mReleaseRate = 0.0f;
mPhase = 0.0f;
mTargetPhase = 0.0f;
mPhaseChangeRate = 0.0f;
mDirectRelease = 0;
mInitialReleaseRate = 0.0f;
}
/* 8028DECC-8028DF2C .text initStart__Q28JASystem11TOscillatorFv */
void JASystem::TOscillator::initStart() {
field_0x4 = 2;
field_0x18 = 0;
if (!field_0x0 || !field_0x0->table) {
field_0xc = 0.0f;
mState = 2;
mDirectRelease = 0;
if (mOsc == NULL || !mOsc->table) {
mPhase = 0.0f;
return;
}
field_0x6 = 0;
field_0x8 = 0.0f;
field_0x10 = 0.0f;
field_0x18 = 0;
field_0x8 -= field_0x0->field_0x4;
mReleaseRate = 0.0f;
mTargetPhase = 0.0f;
mDirectRelease = 0;
mReleaseRate -= mOsc->field_0x4;
}
/* 8028DF2C-8028E070 .text getOffset__Q28JASystem11TOscillatorFv */
f32 JASystem::TOscillator::getOffset() {
/* Nonmatching */
if (mOsc == NULL) {
OSReport("----- Oscillator is NULL\n");
mPhase = 1.0f;
return 1.0f;
}
switch (mState) {
case 0:
return 1.0f;
case 3:
return mOsc->field_0x14 + (mPhase * mOsc->field_0x10);
case 1:
mState = 2;
OSReport("----- Error Initialize\n");
/* Fallthrough */
default:
s16* var_r4;
if (mState == 4) {
var_r4 = mOsc->rel_table;
} else if (mState == 5) {
var_r4 = oscTableForceStop;
} else {
var_r4 = mOsc->table;
}
if (var_r4 == NULL && mState != 6) {
mPhase = 1.0f;
return 1.0f;
}
if (mState == 5) {
mReleaseRate -= 1.0f;
} else {
mReleaseRate -= mOsc->field_0x4;
}
return calc(var_r4);
}
}
/* 8028E070-8028E0AC .text forceStop__Q28JASystem11TOscillatorFv */
bool JASystem::TOscillator::forceStop() {
if (field_0x4 == 5) {
if (mState == 5) {
return false;
}
field_0x6 = 0;
field_0x8 = 0.0f;
field_0x10 = field_0xc;
field_0x4 = 5;
mReleaseRate = 0.0f;
mTargetPhase = mPhase;
mState = 5;
return true;
}
/* 8028E0AC-8028E238 .text release__Q28JASystem11TOscillatorFv */
bool JASystem::TOscillator::release() {
/* Nonmatching */
if (mState == 5) {
return false;
}
if (mOsc->table != mOsc->rel_table) {
field_0x6 = 0;
mReleaseRate = 0.0f;
mTargetPhase = mPhase;
}
if (mOsc->rel_table == NULL && mDirectRelease == 0) {
mDirectRelease = 0x10;
}
if (mDirectRelease != 0) {
mState = 6;
field_0x5 = (mDirectRelease >> 14) & 3;
f32 temp_f31 = mDirectRelease & 0x3FFF;
temp_f31 *= ((Kernel::getDacRate() / 80.0f) / 600.0f);
temp_f31 /= Driver::getUpdateInterval();
mReleaseRate = temp_f31;
if (mReleaseRate < 1.0f) {
mReleaseRate = 1.0f;
}
mInitialReleaseRate = mReleaseRate;
mTargetPhase = 0.0f;
if (field_0x5 == 0) {
mPhaseChangeRate = (mTargetPhase - mPhase) / mReleaseRate;
} else {
mPhaseChangeRate = mTargetPhase - mPhase;
}
} else {
mState = 4;
}
return true;
}
/* 8028E238-8028E5EC .text calc__Q28JASystem11TOscillatorFPs */
void JASystem::TOscillator::calc(s16*) {
/* Nonmatching */
f32 JASystem::TOscillator::calc(s16* i_table) {
while (mReleaseRate <= 0.0f) {
int idx = field_0x6 * 3;
mPhase = mTargetPhase;
if (mState == 6) {
mState = 0;
break;
}
s16 envMode = i_table[idx];
s16 envTime = i_table[idx + 1];
s16 envValue = i_table[idx + 2];
if (envMode == 13) {
field_0x6 = envValue;
continue;
}
if (envMode == 15) {
mState = 0;
break;
}
if (envMode == 14) {
mState = 3;
return mOsc->field_0x14 + mPhase * mOsc->field_0x10;
}
field_0x5 = envMode;
if (envTime == 0) {
mTargetPhase = envValue / 32768.0f;
field_0x6 += 1;
continue;
}
mReleaseRate = envTime * ((Kernel::getDacRate() / 80.0f) / 600.0f) / Driver::getUpdateInterval();
mInitialReleaseRate = mReleaseRate;
mTargetPhase = envValue / 32768.0f;
if (field_0x5 == 0) {
mPhaseChangeRate = (mTargetPhase - mPhase) / mReleaseRate;
} else {
mPhaseChangeRate = mTargetPhase - mPhase;
}
field_0x6 += 1;
}
if (mOsc->field_0x10 == 0.0f) {
return mOsc->field_0x14;
}
f32 temp_f31 = 0.0f;
f32 newPhase;
if (mInitialReleaseRate == 0.0) { // Developer probably forgot the f suffix
newPhase = mTargetPhase;
mPhase = mTargetPhase;
} else {
if (field_0x5 == 0 || (temp_f31 = mPhaseChangeRate) == 0.0f) {
newPhase = mTargetPhase - (mPhaseChangeRate * mReleaseRate);
mPhase = newPhase;
} else if (field_0x5 == 3 || field_0x5 == 1 || field_0x5 == 2) {
const f32* table = NULL;
switch (field_0x5) {
case 3:
table = relTableSampleCell;
break;
case 1:
table = relTableSquare;
break;
case 2:
table = relTableSqRoot;
break;
}
f32 fIdx;
if (temp_f31 < 0.0f) {
fIdx = 16.0f * (1.0f - (mReleaseRate / mInitialReleaseRate));
} else {
fIdx = 16.0f * (mReleaseRate / mInitialReleaseRate);
}
u32 idx = fIdx;
f32 prop = fIdx - (f32)idx;
if (idx >= 16) {
idx = 15;
prop = 1.0f;
}
f32 valAbs = std::fabsf(temp_f31 * (prop * (table[idx + 1] - table[idx]) + table[idx]));
if (mPhaseChangeRate < 0.0f) {
newPhase = mTargetPhase + valAbs;
} else {
newPhase = mTargetPhase - (mPhaseChangeRate - valAbs);
}
mPhase = newPhase;
} else {
newPhase = mTargetPhase - (temp_f31 * mReleaseRate);
mPhase = newPhase;
}
}
return newPhase * mOsc->field_0x10 + mOsc->field_0x14;
}
+3 -3
View File
@@ -65,15 +65,15 @@ const JASystem::TOscillator::Osc_ JASystem::Player::sAdsrDef = {
};
const JASystem::TOscillator::Osc_ JASystem::Player::sEnvelopeDef = {
0, 1.0f, NULL, &sRelTable, 1.0f, 0.0f
0, 1.0f, NULL, sRelTable, 1.0f, 0.0f
};
const JASystem::TOscillator::Osc_ JASystem::Player::sVibratoDef = {
1, 0.5f, &sVibTable, &sVibTable, 0.0f, 1.0f
1, 0.5f, sVibTable, sVibTable, 0.0f, 1.0f
};
const JASystem::TOscillator::Osc_ JASystem::Player::sTremoroDef = {
0, 0.5f, &sTreTable, &sTreTable, 0.0f, 1.0f
0, 0.5f, sTreTable, sTreTable, 0.0f, 1.0f
};
s16 JASystem::Player::CUTOFF_TO_IIR_TABLE[] = {
+5 -5
View File
@@ -325,7 +325,7 @@ void JASystem::TTrack::overwriteOsc(TChannel* param_1) {
}
param_1->copyOsc(r28, &field_0x2cc[i]);
} else if (var1 & 4) {
void* var4 = field_0x2cc[i].rel_table;
s16* var4 = field_0x2cc[i].rel_table;
if (!param_1->isOsc(r28)) {
JUT_WARN(603, "%s", "cannot copy osc");
continue;
@@ -390,7 +390,7 @@ void JASystem::TTrack::oscSetupFull(u8 param_1, u32 param_2, u32 param_3) {
if (param_2 == 0) {
field_0x2cc[var1].table = NULL;
}
field_0x2cc[var1].table = mSeqCtrl.mRawFilePtr + param_2;
field_0x2cc[var1].table = (s16*)(mSeqCtrl.mRawFilePtr + param_2);
}
if (!var5) {
return;
@@ -398,7 +398,7 @@ void JASystem::TTrack::oscSetupFull(u8 param_1, u32 param_2, u32 param_3) {
if (param_3 == 0) {
field_0x2cc[var1].rel_table = Player::sRelTable;
}
field_0x2cc[var1].rel_table = mSeqCtrl.mRawFilePtr + param_2;
field_0x2cc[var1].rel_table = (s16*)(mSeqCtrl.mRawFilePtr + param_2);
}
/* 802817E4-80281850 .text oscSetupSimpleEnv__Q28JASystem6TTrackFUcUl */
@@ -406,10 +406,10 @@ void JASystem::TTrack::oscSetupSimpleEnv(u8 param_1, u32 param_2) {
switch (param_1) {
case 0:
field_0x2cc[0] = Player::sEnvelopeDef;
field_0x2cc[0].table = mSeqCtrl.mRawFilePtr + param_2;
field_0x2cc[0].table = (s16*)(mSeqCtrl.mRawFilePtr + param_2);
break;
case 1:
field_0x2cc[0].rel_table = mSeqCtrl.mRawFilePtr + param_2;
field_0x2cc[0].rel_table = (s16*)(mSeqCtrl.mRawFilePtr + param_2);
break;
}
}