diff --git a/config/RSPE01_01/symbols.txt b/config/RSPE01_01/symbols.txt index 6a6f969a..6f7b5359 100644 --- a/config/RSPE01_01/symbols.txt +++ b/config/RSPE01_01/symbols.txt @@ -17891,7 +17891,7 @@ __EarlyCoefTable = .data:0x803AE8A0; // type:object size:0x60 scope:local __FilterSizeTable = .data:0x803AE900; // type:object size:0xE0 scope:local __EarlySizeTable = .data:0x803AE9E0; // type:object size:0x60 scope:local __EarlyCoefTable = .data:0x803AEA40; // type:object size:0x60 scope:local -__FilterSizeTable = .data:0x803AEAA0; // type:object size:0x100 scope:local +__FilterSizeTable = .data:0x803AEAA0; // type:object size:0xFC scope:local __SinTableFixedPoint = .data:0x803AEBA0; // type:object size:0x200 scope:local align:8 __SrcTab12khz = .data:0x803AEDA0; // type:object size:0x800 scope:local align:8 @472 = .data:0x803AF5A0; // type:object size:0x37 scope:local align:4 data:string @@ -23329,32 +23329,26 @@ gap_12_804C1277_sdata2 = .sdata2:0x804C1277; // type:object size:0x1 scope:globa @83 = .sdata2:0x804C129C; // type:object size:0x4 scope:local align:4 data:float @176 = .sdata2:0x804C12A0; // type:object size:0x4 scope:local align:4 data:float @177 = .sdata2:0x804C12A4; // type:object size:0x4 scope:local align:4 data:float -lbl_804C12A8 = .sdata2:0x804C12A8; // type:object size:0x4 align:4 data:float -lbl_804C12AC = .sdata2:0x804C12AC; // type:object size:0x4 align:4 data:float -lbl_804C12B0 = .sdata2:0x804C12B0; // type:object size:0x4 align:4 data:float -lbl_804C12B4 = .sdata2:0x804C12B4; // type:object size:0x4 align:4 data:float -lbl_804C12B8 = .sdata2:0x804C12B8; // type:object size:0x4 align:4 data:float -gap_12_804C12BC_sdata2 = .sdata2:0x804C12BC; // type:object size:0x4 scope:global -lbl_804C12C0 = .sdata2:0x804C12C0; // type:object size:0x8 align:8 data:double -lbl_804C12C8 = .sdata2:0x804C12C8; // type:object size:0x4 align:4 data:float -gap_12_804C12CC_sdata2 = .sdata2:0x804C12CC; // type:object size:0x4 scope:global -lbl_804C12D0 = .sdata2:0x804C12D0; // type:object size:0x8 align:8 data:double -lbl_804C12D8 = .sdata2:0x804C12D8; // type:object size:0x4 align:4 data:float -gap_12_804C12DC_sdata2 = .sdata2:0x804C12DC; // type:object size:0x4 scope:global -lbl_804C12E0 = .sdata2:0x804C12E0; // type:object size:0x8 align:8 data:double -lbl_804C12E8 = .sdata2:0x804C12E8; // type:object size:0x4 align:4 data:float -lbl_804C12EC = .sdata2:0x804C12EC; // type:object size:0x4 align:4 data:float -lbl_804C12F0 = .sdata2:0x804C12F0; // type:object size:0x4 align:4 data:float -lbl_804C12F4 = .sdata2:0x804C12F4; // type:object size:0x4 align:4 data:float -lbl_804C12F8 = .sdata2:0x804C12F8; // type:object size:0x4 align:4 data:float -gap_12_804C12FC_sdata2 = .sdata2:0x804C12FC; // type:object size:0x4 scope:global -lbl_804C1300 = .sdata2:0x804C1300; // type:object size:0x8 align:8 data:double -lbl_804C1308 = .sdata2:0x804C1308; // type:object size:0x4 align:4 data:float -gap_12_804C130C_sdata2 = .sdata2:0x804C130C; // type:object size:0x4 scope:global -lbl_804C1310 = .sdata2:0x804C1310; // type:object size:0x8 align:8 data:double -lbl_804C1318 = .sdata2:0x804C1318; // type:object size:0x4 align:4 data:float -gap_12_804C131C_sdata2 = .sdata2:0x804C131C; // type:object size:0x4 scope:global -lbl_804C1320 = .sdata2:0x804C1320; // type:object size:0x8 align:8 data:double +@1049 = .sdata2:0x804C12A8; // type:object size:0x4 scope:local align:4 data:float +@1094 = .sdata2:0x804C12AC; // type:object size:0x4 scope:local align:4 data:float +@1250 = .sdata2:0x804C12B0; // type:object size:0x4 scope:local align:4 data:float +@1251 = .sdata2:0x804C12B4; // type:object size:0x4 scope:local align:4 data:float +@1252 = .sdata2:0x804C12B8; // type:object size:0x4 scope:local align:4 data:float +@1256 = .sdata2:0x804C12C0; // type:object size:0x8 scope:local align:8 data:double +@1442 = .sdata2:0x804C12C8; // type:object size:0x4 scope:local align:4 data:float +@1443 = .sdata2:0x804C12D0; // type:object size:0x8 scope:local align:8 data:double +@1444 = .sdata2:0x804C12D8; // type:object size:0x4 scope:local align:4 data:float +@1447 = .sdata2:0x804C12E0; // type:object size:0x8 scope:local align:8 data:double +@1099 = .sdata2:0x804C12E8; // type:object size:0x4 scope:local align:4 data:float +@1145 = .sdata2:0x804C12EC; // type:object size:0x4 scope:local align:4 data:float +@1303 = .sdata2:0x804C12F0; // type:object size:0x4 scope:local align:4 data:float +@1304 = .sdata2:0x804C12F4; // type:object size:0x4 scope:local align:4 data:float +@1305 = .sdata2:0x804C12F8; // type:object size:0x4 scope:local align:4 data:float +@1309 = .sdata2:0x804C1300; // type:object size:0x8 scope:local align:8 data:double +@1496 = .sdata2:0x804C1308; // type:object size:0x4 scope:local align:4 data:float +@1397 = .sdata2:0x804C1310; // type:object size:0x8 scope:local align:8 data:double +@1504 = .sdata2:0x804C1318; // type:object size:0x4 scope:local align:4 data:float +@1507 = .sdata2:0x804C1320; // type:object size:0x8 scope:local align:8 data:double @770 = .sdata2:0x804C1328; // type:object size:0x4 scope:local align:4 data:float @771 = .sdata2:0x804C132C; // type:object size:0x4 scope:local align:4 data:float @774 = .sdata2:0x804C1330; // type:object size:0x8 scope:local align:8 data:double @@ -23362,17 +23356,17 @@ lbl_804C1320 = .sdata2:0x804C1320; // type:object size:0x8 align:8 data:double @83 = .sdata2:0x804C133C; // type:object size:0x4 scope:local align:4 data:float @84 = .sdata2:0x804C1340; // type:object size:0x4 scope:local align:4 data:float @87 = .sdata2:0x804C1348; // type:object size:0x8 scope:local align:8 data:double -lbl_804C1350 = .sdata2:0x804C1350; // type:object size:0x4 align:4 data:float -lbl_804C1354 = .sdata2:0x804C1354; // type:object size:0x4 align:4 data:float -lbl_804C1358 = .sdata2:0x804C1358; // type:object size:0x8 align:8 data:double -lbl_804C1360 = .sdata2:0x804C1360; // type:object size:0x4 align:4 data:float -lbl_804C1364 = .sdata2:0x804C1364; // type:object size:0x4 align:4 data:float -lbl_804C1368 = .sdata2:0x804C1368; // type:object size:0x4 align:4 data:float -lbl_804C136C = .sdata2:0x804C136C; // type:object size:0x4 align:4 data:float -lbl_804C1370 = .sdata2:0x804C1370; // type:object size:0x4 align:4 data:float -lbl_804C1374 = .sdata2:0x804C1374; // type:object size:0x4 align:4 data:float -lbl_804C1378 = .sdata2:0x804C1378; // type:object size:0x4 align:4 data:float -lbl_804C137C = .sdata2:0x804C137C; // type:object size:0x4 align:4 data:float +@640 = .sdata2:0x804C1350; // type:object size:0x4 align:4 data:float +@637 = .sdata2:0x804C1354; // type:object size:0x4 align:4 data:float +@857 = .sdata2:0x804C1358; // type:object size:0x8 align:8 data:double +@635 = .sdata2:0x804C1360; // type:object size:0x4 align:4 data:float +@636 = .sdata2:0x804C1364; // type:object size:0x4 align:4 data:float +@638 = .sdata2:0x804C1368; // type:object size:0x4 align:4 data:float +@639 = .sdata2:0x804C136C; // type:object size:0x4 align:4 data:float +@643 = .sdata2:0x804C1370; // type:object size:0x4 align:4 data:float +@644 = .sdata2:0x804C1374; // type:object size:0x4 align:4 data:float +@642 = .sdata2:0x804C1378; // type:object size:0x4 align:4 data:float +@641 = .sdata2:0x804C137C; // type:object size:0x4 align:4 data:float lbl_804C1380 = .sdata2:0x804C1380; // type:object size:0x8 lbl_804C1388 = .sdata2:0x804C1388; // type:object size:0x8 bta_sys_cfg = .sdata2:0x804C1390; // type:object size:0x8 scope:global diff --git a/configure.py b/configure.py index 25ef57e8..a0a4167c 100755 --- a/configure.py +++ b/configure.py @@ -1006,8 +1006,8 @@ def MatchingFor(*versions): Object(Matching, "revolution/AX/AXProf.c"), Object(Matching, "revolution/AXFX/AXFXReverbHi.c"), Object(Matching, "revolution/AXFX/AXFXReverbHiDpl2.c"), - Object(NonMatching, "revolution/AXFX/AXFXReverbHiExp.c"), - Object(NonMatching, "revolution/AXFX/AXFXReverbHiExpDpl2.c"), + Object(Matching, "revolution/AXFX/AXFXReverbHiExp.c"), + Object(Matching, "revolution/AXFX/AXFXReverbHiExpDpl2.c"), Object(Matching, "revolution/AXFX/AXFXDelay.c"), Object(Matching, "revolution/AXFX/AXFXChorus.c"), Object(NonMatching, "revolution/AXFX/AXFXChorusExp.c"), diff --git a/include/revolution/AXFX/AXFXCommon.h b/include/revolution/AXFX/AXFXCommon.h index 71013cf8..b398f0e5 100644 --- a/include/revolution/AXFX/AXFXCommon.h +++ b/include/revolution/AXFX/AXFXCommon.h @@ -11,6 +11,13 @@ typedef struct AXFX_BUS { s32* surround; // at 0x8 } AXFX_BUS; +typedef struct AXFX_BUS_DPL2 { + s32* left; // at 0x0 + s32* right; // at 0x4 + s32* left_surround; // at 0x8 + s32* right_surround; // at 0xC +} AXFX_BUS_DPL2; + typedef struct AXFX_BUFFERUPDATE { s32* left; // at 0x0 s32* right; // at 0x4 diff --git a/include/revolution/AXFX/AXFXReverbHiExp.h b/include/revolution/AXFX/AXFXReverbHiExp.h index f4081a3b..932130c0 100644 --- a/include/revolution/AXFX/AXFXReverbHiExp.h +++ b/include/revolution/AXFX/AXFXReverbHiExp.h @@ -57,7 +57,7 @@ typedef struct AXFX_REVERBHI_EXP { f32 sendGain; // at 0x144 } AXFX_REVERBHI_EXP; -u32 AXFXReverbHiExpGetMemSize(const AXFX_REVERBHI_EXP* fx); +u32 AXFXReverbHiExpGetMemSize(AXFX_REVERBHI_EXP* fx); BOOL AXFXReverbHiExpInit(AXFX_REVERBHI_EXP* fx); void AXFXReverbHiExpShutdown(AXFX_REVERBHI_EXP* fx); BOOL AXFXReverbHiExpSettings(AXFX_REVERBHI_EXP* fx); diff --git a/include/revolution/AXFX/AXFXReverbHiExpDpl2.h b/include/revolution/AXFX/AXFXReverbHiExpDpl2.h index 04b34d35..d5d0fa03 100644 --- a/include/revolution/AXFX/AXFXReverbHiExpDpl2.h +++ b/include/revolution/AXFX/AXFXReverbHiExpDpl2.h @@ -7,7 +7,9 @@ extern "C" { // Forward declarations typedef struct AXFX_BUS AXFX_BUS; +typedef struct AXFX_BUS_DPL2 AXFX_BUS_DPL2; typedef struct AXFX_BUFFERUPDATE AXFX_BUFFERUPDATE; +typedef struct AXFX_BUFFERUPDATE_DPL2 AXFX_BUFFERUPDATE_DPL2; typedef struct AXFX_REVERBHI_EXP_DPL2 { f32* earlyLine[4]; // at 0x0 @@ -37,27 +39,27 @@ typedef struct AXFX_REVERBHI_EXP_DPL2 { u32 lastAllpassLength[4]; // at 0x104 u32 lastAllpassMaxLength[4]; // at 0x114 - f32 allpassCoef; // at 0x124 - f32 lastLpfOut[4]; // at 0x128 - f32 lpfCoef; // at 0x138 - u32 active; // at 0x13C - u32 earlyMode; // at 0x140 - f32 preDelayTimeMax; // at 0x144 - f32 preDelayTime; // at 0x148 - u32 fusedMode; // at 0x14C - f32 fusedTime; // at 0x150 - f32 coloration; // at 0x154 - f32 damping; // at 0x158 - f32 crosstalk; // at 0x15C - f32 earlyGain; // at 0x160 - f32 fusedGain; // at 0x164 - AXFX_BUS* busIn; // at 0x168 - AXFX_BUS* busOut; // at 0x16C - f32 outGain; // at 0x170 - f32 sendGain; // at 0x174 + f32 allpassCoef; // at 0x124 + f32 lastLpfOut[4]; // at 0x128 + f32 lpfCoef; // at 0x138 + u32 active; // at 0x13C + u32 earlyMode; // at 0x140 + f32 preDelayTimeMax; // at 0x144 + f32 preDelayTime; // at 0x148 + u32 fusedMode; // at 0x14C + f32 fusedTime; // at 0x150 + f32 coloration; // at 0x154 + f32 damping; // at 0x158 + f32 crosstalk; // at 0x15C + f32 earlyGain; // at 0x160 + f32 fusedGain; // at 0x164 + AXFX_BUS_DPL2* busIn; // at 0x168 + AXFX_BUS_DPL2* busOut; // at 0x16C + f32 outGain; // at 0x170 + f32 sendGain; // at 0x174 } AXFX_REVERBHI_EXP_DPL2; -u32 AXFXReverbHiExpGetMemSizeDpl2(const AXFX_REVERBHI_EXP_DPL2* fx); +u32 AXFXReverbHiExpGetMemSizeDpl2(AXFX_REVERBHI_EXP_DPL2* fx); BOOL AXFXReverbHiExpInitDpl2(AXFX_REVERBHI_EXP_DPL2* fx); void AXFXReverbHiExpShutdownDpl2(AXFX_REVERBHI_EXP_DPL2* fx); BOOL AXFXReverbHiExpSettingsDpl2(AXFX_REVERBHI_EXP_DPL2* fx); diff --git a/src/revolution/AXFX/AXFXChorusExp.c b/src/revolution/AXFX/AXFXChorusExp.c new file mode 100644 index 00000000..cd15d504 --- /dev/null +++ b/src/revolution/AXFX/AXFXChorusExp.c @@ -0,0 +1,389 @@ +#include +#include +#include + +void dummy(u32 zero, ...); + +static BOOL __InitParams(AXFX_CHORUS_EXP* fx); +static BOOL __AllocDelay(AXFX_CHORUS_EXP* fx); +static BOOL __InitDelay(AXFX_CHORUS_EXP* fx); +static void __FreeDelay(AXFX_CHORUS_EXP* fx); +static void __CalcLFO(u32 param_1[], AXFX_CHORUS_EXP_LFO* fx); + +u32 AXFXChorusExpGetMemSize(const AXFX_CHORUS_EXP* fx) { + return 0x9600; +} + +BOOL AXFXChorusExpInit(AXFX_CHORUS_EXP* fx) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + fx->active |= 1; + (fx->delay).size = 0xc80; + + if (!__AllocDelay(fx)) { + AXFXChorusExpShutdown(fx); + OSRestoreInterrupts(enabled); + return FALSE; + } + + if (!__InitDelay(fx)) { + AXFXChorusExpShutdown(fx); + OSRestoreInterrupts(enabled); + return FALSE; + } + + if (!__InitParams(fx)) { + AXFXChorusExpShutdown(fx); + OSRestoreInterrupts(enabled); + return FALSE; + } + + fx->active &= ~1; + OSRestoreInterrupts(enabled); + + return TRUE; +} + +BOOL AXFXChorusExpSettings(AXFX_CHORUS_EXP* fx) { + BOOL enabled; + BOOL success; + + enabled = OSDisableInterrupts(); + fx->active |= TRUE; + AXFXChorusExpShutdown(fx); + + success = AXFXChorusExpInit(fx); + + if (success == FALSE) { + AXFXChorusExpShutdown(fx); + OSRestoreInterrupts(enabled); + return FALSE; + } + + fx->active |= 2; + fx->active &= ~1; + OSRestoreInterrupts(enabled); + + return success; +} + +void AXFXChorusExpShutdown(AXFX_CHORUS_EXP* fx) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + + __FreeDelay(fx); + + OSRestoreInterrupts(enabled); +} + +// Non-matching +void AXFXChorusExpCallback(AXFX_BUFFERUPDATE* bufferUpdate, + AXFX_CHORUS_EXP* fx) { + + int iVar1; + f32 fVar2; + u32 uVar3; + s32 c; + f32* pfVar4; + u32 uVar4; + u32 uVar5; + u32 outPos; + s32 size; + AXFX_CHORUS_EXP* pAVar6; + s32** ppsVar7; + AXFX_BUS* busOut; + s32 currentPos; + s32** ppsVar8; + AXFX_BUS* busIn; + AXFX_CHORUS_EXP* pAVar9; + s32** ppsVar10; + u32 uVar11; + s32* piVar12; + f32* pfVar13; + u32 samp; + u32* ptr; + u32 i; + int ch; + f32 dVar16; + f32 dVar14; + s32* input[3]; + s32* inBusData[3]; + s32* outBusData[3]; + u32 lfo[96]; + + if (fx->active != 0) { + fx->active &= ~2; + return; + } + + busIn = fx->busIn; + input[0] = bufferUpdate->left; + input[1] = bufferUpdate->right; + input[2] = bufferUpdate->surround; + if (busIn != NULL) { + inBusData[0] = busIn->left; + inBusData[1] = busIn->right; + inBusData[2] = busIn->surround; + } + busOut = fx->busOut; + if (busOut != NULL) { + outBusData[0] = busOut->left; + outBusData[1] = busOut->right; + outBusData[2] = busOut->surround; + } + __CalcLFO(lfo, &fx->lfo); + ptr = lfo; + for (samp = 0; samp < 96; samp++) { + size = (fx->delay).sizeFP; + currentPos = (fx->delay).outPos + *ptr; + if (currentPos >= size) { + currentPos = currentPos - size; + } else { + if (currentPos < 0) { + currentPos = currentPos + size; + } + } + outPos = (fx->delay).lastPos; + c = currentPos - outPos; + if (c < 0) { + c = c + size; + } + + uVar11 = outPos / 65536; + outPos = fx->histIndex; + for (i = (u32)c / 65536; i != 0; i--) { + fx->history[0][outPos] = (fx->delay).line[0][uVar11]; + fx->history[1][outPos] = (fx->delay).line[1][uVar11]; + fx->history[2][outPos] = (fx->delay).line[2][uVar11]; + + uVar11++; + + outPos += 1; + outPos = outPos & 3; + + if (uVar11 >= (fx->delay).size) { + uVar11 = 0; + } + } + (fx->delay).lastPos = currentPos & 0xffff0000; + pfVar4 = __AXFXGetSrcCoef((c & 0xffffU) >> 9); + ppsVar7 = inBusData; + ppsVar8 = input; + ppsVar10 = outBusData; + pAVar6 = fx; + pAVar9 = fx; + for (ch = 3; ch != 0; ch--) { + i = outPos + 1 & 3; + pfVar13 = pAVar6->history[0] + outPos; + uVar5 = i + 1 & 3; + uVar11 = uVar5 + 1 & 3; + outPos = uVar11 + 1 & 3; + dVar14 = (f32)(*pfVar4 * *pfVar13 + 0.0 + + pfVar4[1] * pAVar6->history[0][i] + + pfVar4[2] * pAVar6->history[0][uVar5] + + pfVar4[3] * pAVar6->history[0][uVar11]); + + if (fx->busIn != NULL) { + u32 sum = **ppsVar8 + **ppsVar7; + + (*ppsVar7)++; + + dVar16 = (double)(sum); + } else { + dVar16 = (double)(**ppsVar8); + } + uVar3 = (fx->delay).inPos; + pfVar13 = (pAVar9->delay).line[0]; + piVar12 = *ppsVar8; + *ppsVar8 = (s32*)(piVar12 + 1); + + iVar1 = (dVar14 * fx->outGain); + *piVar12 = iVar1; + if (fx->busOut != NULL) { + fVar2 = fx->sendGain; + piVar12 = *ppsVar10; + *ppsVar10 = piVar12 + 1; + iVar1 = (int)((f32)dVar14 * fVar2); + *piVar12 = iVar1; + } + pAVar6 = (AXFX_CHORUS_EXP*)&(pAVar6->delay).outPos; + ppsVar7++; + ppsVar8++; + ppsVar10++; + pAVar9 = (AXFX_CHORUS_EXP*)((pAVar9->delay).line + 1); + } + i = (fx->delay).size; + uVar5 = (fx->delay).inPos + 1; + fx->histIndex = outPos; + (fx->delay).inPos = uVar5; + if (i >= uVar5) { + (fx->delay).inPos = 0; + } + outPos = (fx->delay).outPos + 0x10000; + (fx->delay).outPos = outPos; + if ((fx->delay).sizeFP >= outPos) { + (fx->delay).outPos = 0; + } + ptr = ptr + 1; + } + + return; +} + +static BOOL __AllocDelay(AXFX_CHORUS_EXP* fx) { + f32** line = fx->delay.line; + u32 i; + + for (i = 0; i < 3; i++, line++) { + *line = __AXFXAlloc(fx->delay.size * sizeof(f32)); + if (*line == NULL) { + return FALSE; + } + } + + return TRUE; +} + +static BOOL __InitDelay(AXFX_CHORUS_EXP* fx) { + f32** line = fx->delay.line; + u32 i; + u32 uVar2; + + for (i = 0; i < 3; i++, line++) { + if (*line == NULL) { + return FALSE; + } + + memset(*line, 0, (fx->delay).size * sizeof(f32)); + } + + (fx->delay).inPos = 0; + uVar2 = (u32)(fx->delayTime * 32.0f); + uVar2 = ((fx->delay).size - uVar2) * 0x10000; + (fx->delay).sizeFP = (fx->delay).size << 0x10; + (fx->delay).outPos = uVar2; + (fx->delay).lastPos = uVar2; + + return TRUE; +} + +static void __FreeDelay(AXFX_CHORUS_EXP* fx) { + u32 i; + + fx->active |= TRUE; + for (i = 0; i < 3; i++) { + if (fx->delay.line[i] != NULL) { + __AXFXFree(fx->delay.line[i]); + } + fx->delay.line[i] = NULL; + } +} + +static BOOL __InitParams(AXFX_CHORUS_EXP* fx) { + s32 j; + s32 i; + s32* table; + + s32 phaseAdd; + s32 tempSamp; + f32 gradFactor; + f32 depthSamp; + f32 tempVal; + f32 stepSamp; + + if ((fx->delayTime < 0.1f) || (fx->delayTime > 50.0f)) { + return FALSE; + } + if ((fx->depth < 0.0f) || (fx->depth > 1.0f)) { + return FALSE; + } + if ((fx->rate < 0.1f) || (fx->rate > 2.0f)) { + return FALSE; + } + if ((fx->feedback < 0.0f) || (fx->feedback >= 1.0f)) { + return FALSE; + } + if ((fx->outGain < 0.0f) || (fx->outGain > 1.0f)) { + return FALSE; + } + if ((fx->sendGain < 0.0f) || (fx->sendGain > 1.0f)) { + return FALSE; + } + table = __AXFXGetLfoSinTable(); + fx->lfo.table = table; + + depthSamp = 32.0f * fx->delayTime * fx->depth; + if (depthSamp >= 32.0f * fx->delayTime) { + depthSamp -= 1.0f; + if (depthSamp < 0.0f) { + depthSamp = 0.0f; + } + } + + fx->lfo.lastNum = -1; + fx->lfo.phase = 0; + fx->lfo.sign = 0; + + tempSamp = (s32)(65536.0f * depthSamp); + fx->lfo.depthSamp = tempSamp; + + fx->lfo.grad = fx->lfo.lastValue = 0; + + phaseAdd = (s32)(65536.0f * (((tempVal = 256.0f) * fx->rate) / 32000.0f)); + fx->lfo.phaseAdd = phaseAdd; + + stepSamp = (1.25f / 320) * (32000 / fx->rate); + gradFactor = depthSamp / stepSamp; + + tempSamp = (s32)(65536.0f * stepSamp); + fx->lfo.stepSamp = tempSamp; + + fx->lfo.gradFactor = (s32)(65536.0f * gradFactor); + + for (i = 0; i < 3; i++) { + for (j = 0; j < 4; j++) { + fx->history[i][j] = 0.0f; + } + } + + fx->histIndex = 0; + + return TRUE; +} + +void __CalcLFO(u32* out, AXFX_CHORUS_EXP_LFO* lfo) { + u32 samp; + u32 lastNum; + s32 tableVal; + s64 value; + u64 diff; + s32 wtf; + + for (samp = 0x60; samp != 0; samp--) { + lastNum = lfo->phase & 0xFFFF0000; + if (lastNum != lfo->lastNum) { + lfo->lastNum = lastNum; + lastNum = lastNum >> 16; + tableVal = lfo->table[lastNum]; + diff = lfo->table[(lastNum + (wtf = 1)) & 0x7F] - tableVal; + lfo->grad = (s32)((((s64)diff) * (lfo->gradFactor)) >> 24); + value = (((s64)tableVal) * lfo->depthSamp) >> 24; + } else { + value = (s64)(lfo->lastValue + lfo->grad); + } + + lfo->lastValue = (s32)value; + if (lfo->sign >= 1) { + value = -value; + } + + lfo->phase += lfo->phaseAdd; + if ((lfo->phase & 0xFF800000) != 0) { + lfo->phase &= 0x7FFFFF; + lfo->sign ^= wtf; + } + *(out++) = (u32)value; + } +} diff --git a/src/revolution/AXFX/AXFXReverbHiExp.c b/src/revolution/AXFX/AXFXReverbHiExp.c new file mode 100644 index 00000000..9322d4e3 --- /dev/null +++ b/src/revolution/AXFX/AXFXReverbHiExp.c @@ -0,0 +1,471 @@ +#include +#include +#include + +#include + +static BOOL __AllocDelayLine(AXFX_REVERBHI_EXP* fx); +static void __BzeroDelayLines(AXFX_REVERBHI_EXP* fx); +static void __FreeDelayLine(AXFX_REVERBHI_EXP* fx); +static BOOL __InitParams(AXFX_REVERBHI_EXP* fx); + +static u32 __EarlySizeTable[8][3] = {{157, 479, 829}, {317, 809, 1117}, + {479, 941, 1487}, {641, 1259, 1949}, + {797, 1667, 2579}, {967, 1901, 2903}, + {1123, 2179, 3413}, {1279, 2477, 3889}}; + +static f32 __EarlyCoefTable[8][3] = {{0.4f, -1.0f, 0.3f}, {0.5f, -0.95f, 0.3f}, + {0.6f, -0.9f, 0.3f}, {0.75f, -0.85f, 0.3f}, + {-0.9f, 0.8f, 0.3f}, {-1.0f, 0.7f, 0.3f}, + {-1.0f, 0.7f, 0.3f}, {-1.0f, 0.7f, 0.3f}}; + +static u32 __FilterSizeTable[7][8] = {{1789, 1999, 2333, 433, 149, 47, 73, 67}, + {149, 293, 449, 251, 103, 47, 73, 67}, + {947, 1361, 1531, 433, 137, 47, 73, 67}, + {1279, 1531, 1973, 509, 149, 47, 73, 67}, + {1531, 1847, 2297, 563, 179, 47, 73, 67}, + {1823, 2357, 2693, 571, 137, 47, 73, 67}, + {1823, 2357, 2693, 571, 179, 47, 73, 67}}; + +u32 AXFXReverbHiExpGetMemSize(AXFX_REVERBHI_EXP* fx) { + u32 sum = 0; + u32 i = 0; + + sum += __EarlySizeTable[7][2]; + sum += (int)(fx->preDelayTimeMax * 32000); + + for (i = 0; i < 5; i++) { + sum += __FilterSizeTable[6][i]; + } + + sum *= 3; + + for (i = 5; i < 8; i++) { + sum += __FilterSizeTable[6][i]; + } + + sum *= 4; + + return sum; +} + +BOOL AXFXReverbHiExpInit(AXFX_REVERBHI_EXP* fx) { + u32 ch, i; + BOOL result = TRUE; + BOOL mask = OSDisableInterrupts(); + + fx->active = 1; + + if (fx->preDelayTimeMax < 0.0f) { + AXFXReverbHiExpShutdown(fx); + OSRestoreInterrupts(mask); + return FALSE; + } + + fx->earlyMaxLength = __EarlySizeTable[8 - 1][2]; + fx->preDelayMaxLength = (u32)(fx->preDelayTimeMax * 32000); + + for (i = 0; i < 3; i++) { + fx->combMaxLength[i] = __FilterSizeTable[6][i]; + } + + for (i = 0; i < 2; i++) { + fx->allpassMaxLength[i] = __FilterSizeTable[6][3 + i]; + } + + for (ch = 0; ch < 3; ch++) { + fx->lastAllpassMaxLength[ch] = __FilterSizeTable[6][5 + ch]; + } + + result = __AllocDelayLine(fx); + if (result == FALSE) { + AXFXReverbHiExpShutdown(fx); + OSRestoreInterrupts(mask); + return FALSE; + } + + __BzeroDelayLines(fx); + result = __InitParams(fx); + if (result == FALSE) { + AXFXReverbHiExpShutdown(fx); + OSRestoreInterrupts(mask); + return FALSE; + } + + fx->active &= ~1; + OSRestoreInterrupts(mask); + return TRUE; +} + +BOOL AXFXReverbHiExpSettings(AXFX_REVERBHI_EXP* fx) { + u32 uVar1; + u32 uVar2; + int iVar3; + + uVar1 = OSDisableInterrupts(); + fx->active = fx->active | 1; + AXFXReverbHiExpShutdown(fx); + + if (!AXFXReverbHiExpInit(fx)) { + AXFXReverbHiExpShutdown(fx); + OSRestoreInterrupts(uVar1); + return FALSE; + } else { + fx->active |= 2; + fx->active &= ~1; + OSRestoreInterrupts(uVar1); + return TRUE; + } + + return iVar3 != 0; +} + +void AXFXReverbHiExpShutdown(AXFX_REVERBHI_EXP* fx) { + BOOL mask = OSDisableInterrupts(); + fx->active |= 1; + __FreeDelayLine(fx); + OSRestoreInterrupts(mask); +} + +void AXFXReverbHiExpCallback(AXFX_BUFFERUPDATE* bufferUpdate, + AXFX_REVERBHI_EXP* fx) { + u32 ch, i; + u32 samp; + s32* input[3]; + f32 data; + f32 output[3]; + f32* earlyLine; + f32 earlyOut; + f32* preDelayLine; + f32 preDelayOut; + f32 filterOut; + f32* combLine; + f32 combOutOne; + f32* allpass; + f32 outTmp; + f32 allpassIn; + f32 allpassCoef; + f32 lpfOut; + f32 lpfCoef1; + f32 lpfCoef2; + f32 fusedOut[3]; + f32 fusedGain; + f32 crosstalkGain; + f32 crosstalkL; + f32 crosstalkR; + f32 crosstalkS; + s32* inBusData[3]; + s32* outBusData[3]; + + if (fx->active != 0) { + fx->active &= ~2; + return; + } + + input[0] = bufferUpdate->left; + input[1] = bufferUpdate->right; + input[2] = bufferUpdate->surround; + + if (fx->busIn != NULL) { + inBusData[0] = fx->busIn->left; + inBusData[1] = fx->busIn->right; + inBusData[2] = fx->busIn->surround; + } + + if (fx->busOut != NULL) { + outBusData[0] = fx->busOut->left; + outBusData[1] = fx->busOut->right; + outBusData[2] = fx->busOut->surround; + } + + lpfCoef1 = 1.0f - fx->lpfCoef; + lpfCoef2 = fx->lpfCoef; + allpassCoef = fx->allpassCoef; + fusedGain = fx->fusedGain * 0.6f; + crosstalkGain = fx->crosstalk * 0.5f; + + for (samp = 0; samp < 96; samp++) { + for (ch = 0; ch < 3; ch++) { + if (fx->busIn != NULL) { + data = (f32)(*(input[ch]) + *(inBusData[ch]++)); + } else { + data = (f32)(*input[ch]); + } + + earlyLine = fx->earlyLine[ch]; + earlyOut = earlyLine[fx->earlyPos[0]] * fx->earlyCoef[0] + + earlyLine[fx->earlyPos[1]] * fx->earlyCoef[1] + + earlyLine[fx->earlyPos[2]] * fx->earlyCoef[2]; + + if (fx->preDelayLength != 0) { + preDelayLine = fx->preDelayLine[ch]; + preDelayOut = preDelayLine[fx->preDelayPos]; + preDelayLine[fx->preDelayPos] = data; + } else { + preDelayOut = data; + } + + filterOut = 0.0f; + for (i = 0; i < 3; i++) { + combLine = fx->combLine[ch][i]; + combOutOne = combLine[fx->combPos[i]]; + combLine[fx->combPos[i]] = + preDelayOut + (combOutOne * fx->combCoef[i]); + filterOut += combOutOne; + } + + for (i = 0; i < 2; i++) { + allpass = fx->allpassLine[ch][i]; + outTmp = allpass[fx->allpassPos[i]]; + allpassIn = filterOut + outTmp * allpassCoef; + allpass[fx->allpassPos[i]] = allpassIn; + filterOut = outTmp - allpassIn * allpassCoef; + } + + lpfOut = lpfCoef1 * filterOut + lpfCoef2 * fx->lastLpfOut[ch]; + fx->lastLpfOut[ch] = lpfOut; + allpass = fx->lastAllpassLine[ch]; + outTmp = allpass[fx->lastAllpassPos[ch]]; + allpassIn = lpfOut + outTmp * allpassCoef; + allpass[fx->lastAllpassPos[ch]] = allpassIn; + fusedOut[ch] = outTmp - allpassIn * allpassCoef; + if (++fx->lastAllpassPos[ch] >= fx->lastAllpassLength[ch]) { + fx->lastAllpassPos[ch] = 0; + } + + fusedOut[ch] *= fusedGain; + fusedOut[ch] += earlyOut; + } + + crosstalkL = fusedOut[1] + fusedOut[2]; + crosstalkR = fusedOut[0] + fusedOut[2]; + crosstalkS = fusedOut[0] + fusedOut[1]; + + output[0] = fusedOut[0] + crosstalkL * crosstalkGain; + output[1] = fusedOut[1] + crosstalkR * crosstalkGain; + output[2] = fusedOut[2] + crosstalkS * crosstalkGain; + + *(input[0]++) = (s32)(output[0] * fx->outGain); + *(input[1]++) = (s32)(output[1] * fx->outGain); + *(input[2]++) = (s32)(output[2] * fx->outGain); + + if (fx->busOut != NULL) { + *(outBusData[0]++) = (s32)(output[0] * fx->sendGain); + *(outBusData[1]++) = (s32)(output[1] * fx->sendGain); + *(outBusData[2]++) = (s32)(output[2] * fx->sendGain); + } + + for (i = 0; i < 3; i++) { + if (++fx->earlyPos[i] >= fx->earlyLength) { + fx->earlyPos[i] = 0; + } + } + + if (fx->preDelayLength != 0) { + if (++fx->preDelayPos >= fx->preDelayLength) { + fx->preDelayPos = 0; + } + } + + for (i = 0; i < 3; i++) { + if (++fx->combPos[i] >= fx->combLength[i]) { + fx->combPos[i] = 0; + } + } + + for (i = 0; i < 2; i++) { + if (++fx->allpassPos[i] >= fx->allpassLength[i]) { + fx->allpassPos[i] = 0; + } + } + } +} + +static BOOL __AllocDelayLine(AXFX_REVERBHI_EXP* fx) { + u32 ch, i; + + for (ch = 0; ch < 3; ch++) { + fx->earlyLine[ch] = (f32*)__AXFXAlloc(sizeof(f32) * fx->earlyMaxLength); + if (fx->earlyLine[ch] == NULL) + return FALSE; + + if (fx->preDelayMaxLength != 0) { + fx->preDelayLine[ch] = + (f32*)__AXFXAlloc(sizeof(f32) * fx->preDelayMaxLength); + if (fx->preDelayLine[ch] == NULL) + return FALSE; + } else { + fx->preDelayLine[ch] = NULL; + } + + for (i = 0; i < 3; i++) { + fx->combLine[ch][i] = + (f32*)__AXFXAlloc(sizeof(f32) * fx->combMaxLength[i]); + if (fx->combLine[ch][i] == NULL) + return FALSE; + } + + for (i = 0; i < 2; i++) { + fx->allpassLine[ch][i] = + (f32*)__AXFXAlloc(sizeof(f32) * fx->allpassMaxLength[i]); + if (fx->allpassLine[ch][i] == NULL) + return FALSE; + } + + fx->lastAllpassLine[ch] = + (f32*)__AXFXAlloc(sizeof(f32) * fx->lastAllpassMaxLength[ch]); + if (fx->lastAllpassLine[ch] == NULL) + return FALSE; + } + + return TRUE; +} + +static void __BzeroDelayLines(AXFX_REVERBHI_EXP* fx) { + u32 ch, i; + + for (ch = 0; ch < 3; ch++) { + if (fx->earlyLine[ch] != NULL) { + memset(fx->earlyLine[ch], 0, sizeof(f32) * fx->earlyMaxLength); + } + + if (fx->preDelayLine[ch] != NULL) { + memset(fx->preDelayLine[ch], 0, + sizeof(f32) * fx->preDelayMaxLength); + } + + for (i = 0; i < 3; i++) { + if (fx->combLine[ch][i] != NULL) { + memset(fx->combLine[ch][i], 0, + sizeof(f32) * fx->combMaxLength[i]); + } + } + + for (i = 0; i < 2; i++) { + if (fx->allpassLine[ch][i] != NULL) { + memset(fx->allpassLine[ch][i], 0, + sizeof(f32) * fx->allpassMaxLength[i]); + } + } + + if (fx->lastAllpassLine[ch] != NULL) { + memset(fx->lastAllpassLine[ch], 0, + sizeof(f32) * fx->lastAllpassMaxLength[ch]); + } + } +} + +static void __FreeDelayLine(AXFX_REVERBHI_EXP* fx) { + u32 ch, i; + + for (ch = 0; ch < 3; ch++) { + if (fx->earlyLine[ch] != NULL) { + __AXFXFree(fx->earlyLine[ch]); + fx->earlyLine[ch] = NULL; + } + + if (fx->preDelayLine[ch] != NULL) { + __AXFXFree(fx->preDelayLine[ch]); + fx->preDelayLine[ch] = NULL; + } + + for (i = 0; i < 3; i++) { + if (fx->combLine[ch][i] != NULL) { + __AXFXFree(fx->combLine[ch][i]); + fx->combLine[ch][i] = NULL; + } + } + + for (i = 0; i < 2; i++) { + if (fx->allpassLine[ch][i] != NULL) { + __AXFXFree(fx->allpassLine[ch][i]); + fx->allpassLine[ch][i] = NULL; + } + } + + if (fx->lastAllpassLine[ch] != NULL) { + __AXFXFree(fx->lastAllpassLine[ch]); + fx->lastAllpassLine[ch] = NULL; + } + } +} + +DECOMP_FORCELITERAL(AXFXReverbHiExp_c, -3.0f, 10.0); + +static BOOL __InitParams(AXFX_REVERBHI_EXP* reverb) { + u32 ch, i; + + if (reverb->earlyMode >= 8) + return FALSE; + + if (reverb->preDelayTime < 0.0f || + reverb->preDelayTime > reverb->preDelayTimeMax) + return FALSE; + + if (reverb->fusedMode >= 6) + return FALSE; + + if (reverb->fusedTime < 0.0f) + return FALSE; + + if (reverb->coloration < 0.0f || reverb->coloration > 1.0f) + return FALSE; + + if (reverb->damping < 0.0f || reverb->damping > 1.0f) + return FALSE; + + if (reverb->crosstalk < 0.0f || reverb->crosstalk > 1.0f) + return FALSE; + + if (reverb->earlyGain < 0.0f || reverb->earlyGain > 1.0f) + return FALSE; + + if (reverb->fusedGain < 0.0f || reverb->fusedGain > 1.0f) + return FALSE; + + if (reverb->outGain < 0.0f || reverb->outGain > 1.0f) + return FALSE; + + if (reverb->sendGain < 0.0f || reverb->sendGain > 1.0f) + return FALSE; + + reverb->earlyLength = __EarlySizeTable[reverb->earlyMode][2]; + for (i = 0; i < 3; i++) { + reverb->earlyPos[i] = + reverb->earlyLength - __EarlySizeTable[reverb->earlyMode][i]; + reverb->earlyCoef[i] = + __EarlyCoefTable[reverb->earlyMode][i] * reverb->earlyGain * 0.6f; + } + + reverb->preDelayPos = 0; + reverb->preDelayLength = (u32)(reverb->preDelayTime * (f32)32000); + + for (i = 0; i < 3; i++) { + reverb->combPos[i] = 0; + reverb->combLength[i] = __FilterSizeTable[reverb->fusedMode][i]; + reverb->combCoef[i] = pow(10.0f, (-3.0f * (f32)(reverb->combLength[i]) / + (f32)(reverb->fusedTime * 32000))); + } + + for (i = 0; i < 2; i++) { + reverb->allpassPos[i] = 0; + reverb->allpassLength[i] = __FilterSizeTable[reverb->fusedMode][3 + i]; + } + + for (ch = 0; ch < 3; ch++) { + reverb->lastAllpassPos[ch] = 0; + reverb->lastAllpassLength[ch] = + __FilterSizeTable[reverb->fusedMode][5 + ch]; + } + + reverb->allpassCoef = reverb->coloration; + reverb->lpfCoef = 1.0f - reverb->damping; + if (reverb->lpfCoef > 0.95f) + reverb->lpfCoef = 0.95f; + + for (ch = 0; ch < 3; ch++) { + reverb->lastLpfOut[ch] = 0.0f; + } + + return TRUE; +} diff --git a/src/revolution/AXFX/AXFXReverbHiExpDpl2.c b/src/revolution/AXFX/AXFXReverbHiExpDpl2.c new file mode 100644 index 00000000..717144b4 --- /dev/null +++ b/src/revolution/AXFX/AXFXReverbHiExpDpl2.c @@ -0,0 +1,485 @@ +#include +#include +#include + +#include + +static BOOL __AllocDelayLine(AXFX_REVERBHI_EXP_DPL2* fx); +static void __BzeroDelayLines(AXFX_REVERBHI_EXP_DPL2* fx); +static void __FreeDelayLine(AXFX_REVERBHI_EXP_DPL2* fx); +static BOOL __InitParams(AXFX_REVERBHI_EXP_DPL2* reverb); + +static u32 __EarlySizeTable[8][3] = {{157, 479, 829}, {317, 809, 1117}, + {479, 941, 1487}, {641, 1259, 1949}, + {797, 1667, 2579}, {967, 1901, 2903}, + {1123, 2179, 3413}, {1279, 2477, 3889}}; + +static f32 __EarlyCoefTable[8][3] = {{0.4f, -1.0f, 0.3f}, {0.5f, -0.95f, 0.3f}, + {0.6f, -0.9f, 0.3f}, {0.75f, -0.85f, 0.3f}, + {-0.9f, 0.8f, 0.3f}, {-1.0f, 0.7f, 0.3f}, + {-1.0f, 0.7f, 0.3f}, {-1.0f, 0.7f, 0.3f}}; + +static u32 __FilterSizeTable[7][9] = { + {1789, 1999, 2333, 433, 149, 47, 73, 67, 71}, + {149, 293, 449, 251, 103, 47, 73, 67, 71}, + {947, 1361, 1531, 433, 137, 47, 73, 67, 71}, + {1279, 1531, 1973, 509, 149, 47, 73, 67, 71}, + {1531, 1847, 2297, 563, 179, 47, 73, 67, 71}, + {1823, 2357, 2693, 571, 137, 47, 73, 67, 71}, + {1823, 2357, 2693, 571, 179, 47, 73, 67, 71}}; + +u32 AXFXReverbHiExpGetMemSizeDpl2(AXFX_REVERBHI_EXP_DPL2* fx) { + u32 sum = 0; + u32 i = 0; + + sum += __EarlySizeTable[7][2]; + sum += (int)(fx->preDelayTimeMax * 32000); + + for (i = 0; i < 5; i++) { + sum += __FilterSizeTable[6][i]; + } + + sum *= 4; + + for (i = 5; i < 9; i++) { + sum += __FilterSizeTable[6][i]; + } + + sum *= 4; + + return sum; +} + +BOOL AXFXReverbHiExpInitDpl2(AXFX_REVERBHI_EXP_DPL2* fx) { + u32 ch, i; + BOOL result = TRUE; + BOOL mask = OSDisableInterrupts(); + + if (AXGetMode() != 2) { + OSRestoreInterrupts(mask); + return FALSE; + } + + fx->active = 1; + + if (fx->preDelayTimeMax < 0.0f) { + AXFXReverbHiExpShutdownDpl2(fx); + OSRestoreInterrupts(mask); + return FALSE; + } + + fx->earlyMaxLength = __EarlySizeTable[8 - 1][2]; + fx->preDelayMaxLength = (u32)(fx->preDelayTimeMax * 32000); + + for (i = 0; i < 3; i++) { + fx->combMaxLength[i] = __FilterSizeTable[6][i]; + } + + for (i = 0; i < 2; i++) { + fx->allpassMaxLength[i] = __FilterSizeTable[6][3 + i]; + } + + for (ch = 0; ch < 4; ch++) { + fx->lastAllpassMaxLength[ch] = __FilterSizeTable[6][5 + ch]; + } + + result = __AllocDelayLine(fx); + if (result == FALSE) { + AXFXReverbHiExpShutdownDpl2(fx); + OSRestoreInterrupts(mask); + return FALSE; + } + + __BzeroDelayLines(fx); + result = __InitParams(fx); + if (result == FALSE) { + AXFXReverbHiExpShutdownDpl2(fx); + OSRestoreInterrupts(mask); + return FALSE; + } + + fx->active &= ~1; + OSRestoreInterrupts(mask); + return TRUE; +} + +BOOL AXFXReverbHiExpSettingsDpl2(AXFX_REVERBHI_EXP_DPL2* fx) { + u32 uVar1; + u32 uVar2; + int iVar3; + + uVar1 = OSDisableInterrupts(); + fx->active = fx->active | 1; + AXFXReverbHiExpShutdownDpl2(fx); + + if (!AXFXReverbHiExpInitDpl2(fx)) { + AXFXReverbHiExpShutdownDpl2(fx); + OSRestoreInterrupts(uVar1); + return FALSE; + } else { + fx->active |= 2; + fx->active &= ~1; + OSRestoreInterrupts(uVar1); + return TRUE; + } + + return iVar3 != 0; +} + +void AXFXReverbHiExpShutdownDpl2(AXFX_REVERBHI_EXP_DPL2* fx) { + BOOL mask = OSDisableInterrupts(); + fx->active |= 1; + __FreeDelayLine(fx); + OSRestoreInterrupts(mask); +} + +void AXFXReverbHiExpCallbackDpl2(AXFX_BUFFERUPDATE_DPL2* bufferUpdate, + AXFX_REVERBHI_EXP_DPL2* fx) { + u32 ch, i; + u32 samp; + s32* input[4]; + f32 data; + f32 output[4]; + f32* earlyLine; + f32 earlyOut; + f32* preDelayLine; + f32 preDelayOut; + f32 filterOut; + f32* combLine; + f32 combOutOne; + f32* allpass; + f32 outTmp; + f32 allpassIn; + f32 allpassCoef; + f32 lpfOut; + f32 lpfCoef1; + f32 lpfCoef2; + f32 fusedOut[4]; + f32 fusedGain; + f32 crosstalkGain; + f32 crosstalkL; + f32 crosstalkR; + f32 crosstalkRS; + f32 crosstalkLS; + s32* inBusData[4]; + s32* outBusData[4]; + + if (fx->active != 0) { + fx->active &= ~2; + return; + } + + input[0] = bufferUpdate->left; + input[1] = bufferUpdate->right; + input[2] = bufferUpdate->left_surround; + input[3] = bufferUpdate->right_surround; + + if (fx->busIn != NULL) { + inBusData[0] = fx->busIn->left; + inBusData[1] = fx->busIn->right; + inBusData[2] = fx->busIn->left_surround; + inBusData[3] = fx->busIn->right_surround; + } + + if (fx->busOut != NULL) { + outBusData[0] = fx->busOut->left; + outBusData[1] = fx->busOut->right; + outBusData[2] = fx->busOut->left_surround; + outBusData[3] = fx->busOut->right_surround; + } + + lpfCoef1 = 1.0f - fx->lpfCoef; + lpfCoef2 = fx->lpfCoef; + allpassCoef = fx->allpassCoef; + fusedGain = fx->fusedGain * 0.6f; + crosstalkGain = fx->crosstalk * 0.333333f; + + for (samp = 0; samp < 96; samp++) { + for (ch = 0; ch < 4; ch++) { + if (fx->busIn != NULL) { + data = (f32)(*(input[ch]) + *(inBusData[ch]++)); + } else { + data = (f32)(*input[ch]); + } + + earlyLine = fx->earlyLine[ch]; + earlyOut = earlyLine[fx->earlyPos[0]] * fx->earlyCoef[0] + + earlyLine[fx->earlyPos[1]] * fx->earlyCoef[1] + + earlyLine[fx->earlyPos[2]] * fx->earlyCoef[2]; + + if (fx->preDelayLength != 0) { + preDelayLine = fx->preDelayLine[ch]; + preDelayOut = preDelayLine[fx->preDelayPos]; + preDelayLine[fx->preDelayPos] = data; + } else { + preDelayOut = data; + } + + filterOut = 0.0f; + for (i = 0; i < 3; i++) { + combLine = fx->combLine[ch][i]; + combOutOne = combLine[fx->combPos[i]]; + combLine[fx->combPos[i]] = + preDelayOut + (combOutOne * fx->combCoef[i]); + filterOut += combOutOne; + } + + for (i = 0; i < 2; i++) { + allpass = fx->allpassLine[ch][i]; + outTmp = allpass[fx->allpassPos[i]]; + allpassIn = filterOut + outTmp * allpassCoef; + allpass[fx->allpassPos[i]] = allpassIn; + filterOut = outTmp - allpassIn * allpassCoef; + } + + lpfOut = lpfCoef1 * filterOut + lpfCoef2 * fx->lastLpfOut[ch]; + fx->lastLpfOut[ch] = lpfOut; + allpass = fx->lastAllpassLine[ch]; + outTmp = allpass[fx->lastAllpassPos[ch]]; + allpassIn = lpfOut + outTmp * allpassCoef; + allpass[fx->lastAllpassPos[ch]] = allpassIn; + fusedOut[ch] = outTmp - allpassIn * allpassCoef; + if (++fx->lastAllpassPos[ch] >= fx->lastAllpassLength[ch]) { + fx->lastAllpassPos[ch] = 0; + } + + fusedOut[ch] *= fusedGain; + fusedOut[ch] += earlyOut; + } + + crosstalkL = fusedOut[1] + fusedOut[2] + fusedOut[3]; + crosstalkR = fusedOut[0] + fusedOut[2] + fusedOut[3]; + crosstalkLS = fusedOut[0] + fusedOut[1] + fusedOut[3]; + crosstalkRS = fusedOut[0] + fusedOut[1] + fusedOut[2]; + + output[0] = fusedOut[0] + crosstalkL * crosstalkGain; + output[1] = fusedOut[1] + crosstalkR * crosstalkGain; + output[2] = fusedOut[2] + crosstalkLS * crosstalkGain; + output[3] = fusedOut[3] + crosstalkRS * crosstalkGain; + + *(input[0]++) = (s32)(output[0] * fx->outGain); + *(input[1]++) = (s32)(output[1] * fx->outGain); + *(input[2]++) = (s32)(output[2] * fx->outGain); + *(input[3]++) = (s32)(output[3] * fx->outGain); + + if (fx->busOut != NULL) { + *(outBusData[0]++) = (s32)(output[0] * fx->sendGain); + *(outBusData[1]++) = (s32)(output[1] * fx->sendGain); + *(outBusData[2]++) = (s32)(output[2] * fx->sendGain); + *(outBusData[3]++) = (s32)(output[3] * fx->sendGain); + } + + for (i = 0; i < 3; i++) { + if (++fx->earlyPos[i] >= fx->earlyLength) { + fx->earlyPos[i] = 0; + } + } + + if (fx->preDelayLength != 0) { + if (++fx->preDelayPos >= fx->preDelayLength) { + fx->preDelayPos = 0; + } + } + + for (i = 0; i < 3; i++) { + if (++fx->combPos[i] >= fx->combLength[i]) { + fx->combPos[i] = 0; + } + } + + for (i = 0; i < 2; i++) { + if (++fx->allpassPos[i] >= fx->allpassLength[i]) { + fx->allpassPos[i] = 0; + } + } + } +} + +static BOOL __AllocDelayLine(AXFX_REVERBHI_EXP_DPL2* fx) { + u32 ch, i; + + for (ch = 0; ch < 4; ch++) { + fx->earlyLine[ch] = (f32*)__AXFXAlloc(sizeof(f32) * fx->earlyMaxLength); + if (fx->earlyLine[ch] == NULL) + return FALSE; + + if (fx->preDelayMaxLength != 0) { + fx->preDelayLine[ch] = + (f32*)__AXFXAlloc(sizeof(f32) * fx->preDelayMaxLength); + if (fx->preDelayLine[ch] == NULL) + return FALSE; + } else { + fx->preDelayLine[ch] = NULL; + } + + for (i = 0; i < 3; i++) { + fx->combLine[ch][i] = + (f32*)__AXFXAlloc(sizeof(f32) * fx->combMaxLength[i]); + if (fx->combLine[ch][i] == NULL) + return FALSE; + } + + for (i = 0; i < 2; i++) { + fx->allpassLine[ch][i] = + (f32*)__AXFXAlloc(sizeof(f32) * fx->allpassMaxLength[i]); + if (fx->allpassLine[ch][i] == NULL) + return FALSE; + } + + fx->lastAllpassLine[ch] = + (f32*)__AXFXAlloc(sizeof(f32) * fx->lastAllpassMaxLength[ch]); + if (fx->lastAllpassLine[ch] == NULL) + return FALSE; + } + + return TRUE; +} + +static void __BzeroDelayLines(AXFX_REVERBHI_EXP_DPL2* fx) { + u32 ch, i; + + for (ch = 0; ch < 4; ch++) { + if (fx->earlyLine[ch] != NULL) { + memset(fx->earlyLine[ch], 0, sizeof(f32) * fx->earlyMaxLength); + } + + if (fx->preDelayLine[ch] != NULL) { + memset(fx->preDelayLine[ch], 0, + sizeof(f32) * fx->preDelayMaxLength); + } + + for (i = 0; i < 3; i++) { + if (fx->combLine[ch][i] != NULL) { + memset(fx->combLine[ch][i], 0, + sizeof(f32) * fx->combMaxLength[i]); + } + } + + for (i = 0; i < 2; i++) { + if (fx->allpassLine[ch][i] != NULL) { + memset(fx->allpassLine[ch][i], 0, + sizeof(f32) * fx->allpassMaxLength[i]); + } + } + + if (fx->lastAllpassLine[ch] != NULL) { + memset(fx->lastAllpassLine[ch], 0, + sizeof(f32) * fx->lastAllpassMaxLength[ch]); + } + } +} + +static void __FreeDelayLine(AXFX_REVERBHI_EXP_DPL2* fx) { + u32 ch, i; + + for (ch = 0; ch < 4; ch++) { + if (fx->earlyLine[ch] != NULL) { + __AXFXFree(fx->earlyLine[ch]); + fx->earlyLine[ch] = NULL; + } + + if (fx->preDelayLine[ch] != NULL) { + __AXFXFree(fx->preDelayLine[ch]); + fx->preDelayLine[ch] = NULL; + } + + for (i = 0; i < 3; i++) { + if (fx->combLine[ch][i] != NULL) { + __AXFXFree(fx->combLine[ch][i]); + fx->combLine[ch][i] = NULL; + } + } + + for (i = 0; i < 2; i++) { + if (fx->allpassLine[ch][i] != NULL) { + __AXFXFree(fx->allpassLine[ch][i]); + fx->allpassLine[ch][i] = NULL; + } + } + + if (fx->lastAllpassLine[ch] != NULL) { + __AXFXFree(fx->lastAllpassLine[ch]); + fx->lastAllpassLine[ch] = NULL; + } + } +} + +DECOMP_FORCELITERAL(AXFXReverbHiExpDpl2_c, -3.0f, 10.0); + +static BOOL __InitParams(AXFX_REVERBHI_EXP_DPL2* reverb) { + u32 ch, i; + + if (reverb->earlyMode >= 8) + return FALSE; + + if (reverb->preDelayTime < 0.0f || + reverb->preDelayTime > reverb->preDelayTimeMax) + return FALSE; + + if (reverb->fusedMode >= 6) + return FALSE; + + if (reverb->fusedTime < 0.0f) + return FALSE; + + if (reverb->coloration < 0.0f || reverb->coloration > 1.0f) + return FALSE; + + if (reverb->damping < 0.0f || reverb->damping > 1.0f) + return FALSE; + + if (reverb->crosstalk < 0.0f || reverb->crosstalk > 1.0f) + return FALSE; + + if (reverb->earlyGain < 0.0f || reverb->earlyGain > 1.0f) + return FALSE; + + if (reverb->fusedGain < 0.0f || reverb->fusedGain > 1.0f) + return FALSE; + + if (reverb->outGain < 0.0f || reverb->outGain > 1.0f) + return FALSE; + + if (reverb->sendGain < 0.0f || reverb->sendGain > 1.0f) + return FALSE; + + reverb->earlyLength = __EarlySizeTable[reverb->earlyMode][2]; + for (i = 0; i < 3; i++) { + reverb->earlyPos[i] = + reverb->earlyLength - __EarlySizeTable[reverb->earlyMode][i]; + reverb->earlyCoef[i] = + __EarlyCoefTable[reverb->earlyMode][i] * reverb->earlyGain * 0.6f; + } + + reverb->preDelayPos = 0; + reverb->preDelayLength = (u32)(reverb->preDelayTime * (f32)32000); + + for (i = 0; i < 3; i++) { + reverb->combPos[i] = 0; + reverb->combLength[i] = __FilterSizeTable[reverb->fusedMode][i]; + reverb->combCoef[i] = pow(10.0f, (-3.0f * (f32)(reverb->combLength[i]) / + (f32)(reverb->fusedTime * 32000))); + } + + for (i = 0; i < 2; i++) { + reverb->allpassPos[i] = 0; + reverb->allpassLength[i] = __FilterSizeTable[reverb->fusedMode][3 + i]; + } + + for (ch = 0; ch < 4; ch++) { + reverb->lastAllpassPos[ch] = 0; + reverb->lastAllpassLength[ch] = + __FilterSizeTable[reverb->fusedMode][5 + ch]; + } + + reverb->allpassCoef = reverb->coloration; + reverb->lpfCoef = 1.0f - reverb->damping; + if (reverb->lpfCoef > 0.95f) + reverb->lpfCoef = 0.95f; + + for (ch = 0; ch < 4; ch++) { + reverb->lastLpfOut[ch] = 0.0f; + } + + return TRUE; +}