From 46c688ea10601edd56945b506e42d15318deb01f Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Sat, 21 Jun 2025 04:26:24 -0400 Subject: [PATCH] jaudio_NES: building from pik1 --- .../PowerPC_EABI_Support/MetroTRK/trktypes.h | 2 +- .../Msl/MSL_C/PPC_EABI/cmath_gcn.h | 33 + include/jaudio_NES/aictrl.h | 56 +- include/jaudio_NES/aramcall.h | 27 +- include/jaudio_NES/audiostruct.h | 218 +- include/jaudio_NES/bankdrv.h | 27 + include/jaudio_NES/bankread.h | 25 +- include/jaudio_NES/bx.h | 254 ++ include/jaudio_NES/centcalc.h | 16 + include/jaudio_NES/cmdstack.h | 31 +- include/jaudio_NES/connect.h | 18 +- include/jaudio_NES/cpubuf.h | 17 +- include/jaudio_NES/driverinterface.h | 38 + include/jaudio_NES/dsp_cardunlock.h | 16 + include/jaudio_NES/dspdriver.h | 21 +- include/jaudio_NES/dspinterface.h | 134 +- include/jaudio_NES/dspproc.h | 7 +- include/jaudio_NES/dummyrom.h | 2 +- include/jaudio_NES/fat.h | 18 + include/jaudio_NES/fxinterface.h | 20 + include/jaudio_NES/heapctrl.h | 43 +- include/jaudio_NES/ipldec.h | 27 +- include/jaudio_NES/ja_calc.h | 13 +- include/jaudio_NES/jammain.h | 16 - include/jaudio_NES/jammain_2.h | 358 ++ include/jaudio_NES/jamosc.h | 24 + include/jaudio_NES/memory.h | 4 +- include/jaudio_NES/noteon.h | 15 + include/jaudio_NES/oneshot.h | 53 + include/jaudio_NES/playercall.h | 8 + include/jaudio_NES/rate.h | 14 +- include/jaudio_NES/seqsetup.h | 24 +- include/jaudio_NES/tables.h | 9 + include/jaudio_NES/waveread.h | 18 + src/actor/ac_birth_control.c | 2 +- src/static/jaudio_NES/game/game64_dummy.c_inc | 14 +- src/static/jaudio_NES/game/verysimple.c | 2 +- src/static/jaudio_NES/internal/aramcall.c | 178 + src/static/jaudio_NES/internal/bankdrv.c | 327 ++ src/static/jaudio_NES/internal/bankread.c | 246 +- src/static/jaudio_NES/internal/centcalc.c | 44 + src/static/jaudio_NES/internal/cmdstack.c | 211 ++ src/static/jaudio_NES/internal/connect.c | 308 ++ .../jaudio_NES/internal/driverinterface.c | 1123 ++++++ .../jaudio_NES/internal/dsp_cardunlock.c | 331 ++ src/static/jaudio_NES/internal/dspdriver.c | 365 ++ src/static/jaudio_NES/internal/dspinterface.c | 479 +++ src/static/jaudio_NES/internal/dummyrom.c | 6 +- src/static/jaudio_NES/internal/fat.c | 415 +++ src/static/jaudio_NES/internal/fxinterface.c | 62 + src/static/jaudio_NES/internal/heapctrl.c | 568 +++ src/static/jaudio_NES/internal/ipldec.c | 113 + src/static/jaudio_NES/internal/ja_calc.c | 71 + src/static/jaudio_NES/internal/jammain_2.c | 3229 +++++++++++++++++ src/static/jaudio_NES/internal/jamosc.c | 195 + src/static/jaudio_NES/internal/memory.c | 604 +++ src/static/jaudio_NES/internal/midplay.c | 47 + src/static/jaudio_NES/internal/noteon.c | 201 + src/static/jaudio_NES/internal/oneshot.c | 1043 ++++++ src/static/jaudio_NES/internal/rate.c | 7 + src/static/jaudio_NES/internal/seqsetup.c | 648 ++++ src/static/jaudio_NES/internal/tables.c | 20 + src/static/jaudio_NES/internal/waveread.c | 261 ++ src/static/libforest/emu64/emu64.c | 1 + 64 files changed, 12460 insertions(+), 267 deletions(-) create mode 100644 include/PowerPC_EABI_Support/Msl/MSL_C/PPC_EABI/cmath_gcn.h create mode 100644 include/jaudio_NES/bankdrv.h create mode 100644 include/jaudio_NES/bx.h create mode 100644 include/jaudio_NES/centcalc.h create mode 100644 include/jaudio_NES/driverinterface.h create mode 100644 include/jaudio_NES/dsp_cardunlock.h create mode 100644 include/jaudio_NES/fat.h create mode 100644 include/jaudio_NES/fxinterface.h delete mode 100644 include/jaudio_NES/jammain.h create mode 100644 include/jaudio_NES/jammain_2.h create mode 100644 include/jaudio_NES/jamosc.h create mode 100644 include/jaudio_NES/noteon.h create mode 100644 include/jaudio_NES/oneshot.h create mode 100644 include/jaudio_NES/tables.h create mode 100644 include/jaudio_NES/waveread.h create mode 100644 src/static/jaudio_NES/internal/aramcall.c create mode 100644 src/static/jaudio_NES/internal/bankdrv.c create mode 100644 src/static/jaudio_NES/internal/centcalc.c create mode 100644 src/static/jaudio_NES/internal/cmdstack.c create mode 100644 src/static/jaudio_NES/internal/connect.c create mode 100644 src/static/jaudio_NES/internal/driverinterface.c create mode 100644 src/static/jaudio_NES/internal/dsp_cardunlock.c create mode 100644 src/static/jaudio_NES/internal/dspdriver.c create mode 100644 src/static/jaudio_NES/internal/dspinterface.c create mode 100644 src/static/jaudio_NES/internal/fat.c create mode 100644 src/static/jaudio_NES/internal/fxinterface.c create mode 100644 src/static/jaudio_NES/internal/heapctrl.c create mode 100644 src/static/jaudio_NES/internal/ipldec.c create mode 100644 src/static/jaudio_NES/internal/ja_calc.c create mode 100644 src/static/jaudio_NES/internal/jammain_2.c create mode 100644 src/static/jaudio_NES/internal/jamosc.c create mode 100644 src/static/jaudio_NES/internal/memory.c create mode 100644 src/static/jaudio_NES/internal/midplay.c create mode 100644 src/static/jaudio_NES/internal/noteon.c create mode 100644 src/static/jaudio_NES/internal/oneshot.c create mode 100644 src/static/jaudio_NES/internal/rate.c create mode 100644 src/static/jaudio_NES/internal/seqsetup.c create mode 100644 src/static/jaudio_NES/internal/tables.c create mode 100644 src/static/jaudio_NES/internal/waveread.c diff --git a/include/PowerPC_EABI_Support/MetroTRK/trktypes.h b/include/PowerPC_EABI_Support/MetroTRK/trktypes.h index d7f07106..bafea98f 100644 --- a/include/PowerPC_EABI_Support/MetroTRK/trktypes.h +++ b/include/PowerPC_EABI_Support/MetroTRK/trktypes.h @@ -2,7 +2,7 @@ #define _METROTRK_TRKTYPES_H #include "types.h" -#include "Dolphin/OS/OSInterrupt.h" +#include "dolphin/os/OSInterrupt.h" #include "PowerPC_EABI_Support/MetroTRK/trkenum.h" #ifdef __cplusplus diff --git a/include/PowerPC_EABI_Support/Msl/MSL_C/PPC_EABI/cmath_gcn.h b/include/PowerPC_EABI_Support/Msl/MSL_C/PPC_EABI/cmath_gcn.h new file mode 100644 index 00000000..8e0133ef --- /dev/null +++ b/include/PowerPC_EABI_Support/Msl/MSL_C/PPC_EABI/cmath_gcn.h @@ -0,0 +1,33 @@ +#include "MSL_C/w_math.h" +// #include "MSL_C/MSL_Common/float.h" + +#define HALF_PI 1.5707964f + +#ifdef __cplusplus +namespace std { +#endif + + float sqrtf(float); + float sinf(float); + +#ifdef __cplusplus +} +#endif + +// TODO: this should be obtained from the other math header +// inline float sqrtf(float x) { +// static const double _half = .5; +// static const double _three = 3.0; +// volatile float y; + +// if (x > 0.0f) { +// double guess = __frsqrte((double)x); // returns an approximation to +// guess = _half * guess * (_three - guess * guess * x); // now have 12 sig bits +// guess = _half * guess * (_three - guess * guess * x); // now have 24 sig bits +// guess = _half * guess * (_three - guess * guess * x); // now have 32 sig bits +// y = (float)(x * guess); +// return y; +// } + +// return x; +// } diff --git a/include/jaudio_NES/aictrl.h b/include/jaudio_NES/aictrl.h index 77631ce8..9edc156f 100644 --- a/include/jaudio_NES/aictrl.h +++ b/include/jaudio_NES/aictrl.h @@ -1,36 +1,52 @@ -#ifndef AICTRL_H -#define AICTRL_H +#ifndef _JAUDIO_AICTRL_H +#define _JAUDIO_AICTRL_H #include "types.h" #ifdef __cplusplus extern "C" { -#endif +#endif // ifdef __cplusplus -extern u32 UNIVERSAL_DACCOUNTER; -extern u32 JAC_VFRAME_COUNTER; +/////////// JAUDIO AI CONTROL DEFINITIONS /////////// +// Callbacks. +typedef s16* (*MixCallback)(s32); +typedef void (*DACCallback)(s16*, s32); +// Enums. +/** + * @brief TODO + */ typedef enum _MixMode { - MixMode_Mono, - MixMode_MonoWide, - MixMode_Extra, - MixMode_Interleave, - - MixMode_Num + MixMode_Mono = 0, + MixMode_MonoWide = 1, + MixMode_Extra = 2, + MixMode_Interleave = 3, + MixMode_Num, // 4 } MixMode; -typedef s16* (*MixCallback)(s32); +// Global counters. +extern u32 UNIVERSAL_DACCOUNTER; +extern u32 JAC_VFRAME_COUNTER; +extern u32 JAC_SYSTEM_OUTPUT_MODE; -extern void Jac_HeapSetup(void* pHeap, s32 size); -extern void* OSAlloc2(u32 size); -extern void Jac_Init(void); +///////////////////////////////////////////////////// + +//////////// JAUDIO AI CONTROL FUNCTIONS //////////// +void Jac_HeapSetup(void* heap, s32 size); +void* OSAlloc2(u32 size); +void Jac_Init(); +void Jac_VframeWork(); +void Jac_UpdateDAC(); +void Jac_SetOutputMode(int mode); +int Jac_GetOutputMode(); +void Jac_SetMixerLevel(f32, f32); +void Jac_RegisterMixcallback(MixCallback mixcallback, u8 mixmode); extern MixCallback Jac_GetMixcallback(u8* mixmode); -extern void Jac_RegisterMixcallback(MixCallback mixcallback, u8 mixmode); -extern void Jac_VframeWork(void); -extern void Jac_UpdateDAC(void); + +///////////////////////////////////////////////////// #ifdef __cplusplus -} -#endif +}; +#endif // ifdef __cplusplus #endif diff --git a/include/jaudio_NES/aramcall.h b/include/jaudio_NES/aramcall.h index e4f14bdc..67fd20e4 100644 --- a/include/jaudio_NES/aramcall.h +++ b/include/jaudio_NES/aramcall.h @@ -1,11 +1,22 @@ -#ifndef ARAMCALL_H -#define ARAMCALL_H -#include "types.h" -#include "jaudio_NES/heapctrl.h" +#ifndef _JAUDIO_ARAMCALL_H +#define _JAUDIO_ARAMCALL_H -void Jac_WaveDirectorySet(char*); -void Jac_RegisterARAMCallback(u32 (*callback)(char*, u32, u32, u32*, JAHEAP*)); -void Init_AramMotherHeap(); -JAHEAP* Get_AramMotherHeap(); +#include "types.h" + +typedef struct jaheap_ jaheap_; + +typedef u32 (*ARAMCallback)(char* filename, u32 src, u32 length, u32* status, jaheap_* heap); + +void Jac_RegisterARAMCallback(ARAMCallback callback); +u32 LoadAram(char* filepath, u32* status, u32 dst); +u32 LoadAramSingle(char* filepath, u32 src, u32 length, u32* status, u32 dst); +void Jac_WaveDirectorySet(char* directory); +jaheap_* Get_AramMotherHeap(void); +void Show_AramMotherHeap(void); +void Collect_AramMotherHeap(void); +void Init_AramMotherHeap(void); +u32 LoadAram_Default(char* filename, u32 src, u32 length, u32* status, jaheap_* heap); +u32 LoadAram_All(char* filename, u32* status, jaheap_* heap); +u32 LoadAram_One(char* filename, u32 src, u32 length, u32* status, jaheap_* heap); #endif diff --git a/include/jaudio_NES/audiostruct.h b/include/jaudio_NES/audiostruct.h index afcecd3e..ae17aac1 100644 --- a/include/jaudio_NES/audiostruct.h +++ b/include/jaudio_NES/audiostruct.h @@ -5,6 +5,7 @@ #include "jaudio_NES/audiocommon.h" #include "PR/abi.h" #include "libultra/libultra.h" +#include "jaudio_NES/bx.h" #ifdef __cplusplus extern "C" { @@ -922,41 +923,198 @@ typedef struct AudioGlobals { /* 0x92AC */ s32 _92AC; } AudioGlobals; -typedef union SOUNDID_ { - struct { - u8 wave_id; - u8 inst_id; - u8 _02; - u8 _03; - }; +// typedef union SOUNDID_ { +// struct { +// u8 wave_id; +// u8 inst_id; +// u8 _02; +// u8 _03; +// }; - u32 uint32; -} SOUNDID; +// u32 uint32; +// } SOUNDID; -typedef s32 (*PlayerCallBack)(void*); +// typedef s32 (*PlayerCallBack)(void*); -typedef struct PLAYER_CALL_ { - PlayerCallBack callback; - void* arg; - u32 DSP_mode; -} PLAYER_CALL; +// typedef struct PLAYER_CALL_ { +// PlayerCallBack callback; +// void* arg; +// u32 DSP_mode; +// } PLAYER_CALL; -typedef struct Bank_ { - u32 magic; // 'BANK' - u8* part0[128]; - u8* part1[100]; - u8* part2[12]; - // more? -} Bank; +// typedef struct Bank_ { +// u32 magic; // 'BANK' +// u8* part0[128]; +// u8* part1[100]; +// u8* part2[12]; +// // more? +// } Bank; -typedef struct InstBank_ { - u32 magic; // 'IBNK' - u32 _04; - u32 vid; - u8 pad[32 - 3 * sizeof(u32)]; - Bank bank; - // more -} InstBank; +// typedef struct InstBank_ { +// u32 magic; // 'IBNK' +// u32 _04; +// u32 vid; +// u8 pad[32 - 3 * sizeof(u32)]; +// Bank bank; +// // more +// } InstBank; + +typedef union SOUNDID_ SOUNDID; +typedef struct PLAYER_CALL_ PLAYER_CALL; +typedef struct Bank_ Bank; +typedef struct Ibnk_ InstBank; + +// C++ JAudio1 +typedef enum JCSTATUS { + JCSTAT_Unk0 = 0, + JCSTAT_Unk1 = 1, + JCSTAT_Unk2 = 2, + JCSTAT_Unk6 = 6, +} JCSTATUS; + +typedef struct dspch_ dspch_; // TODO: Figure out why there is another struct named `DSPChannel_` in syncstream.c. +typedef struct Jac_MessageQueue Jac_MessageQueue; +typedef struct JCMgr JCMgr; +typedef struct jc_ jc_; +typedef struct jcs_ jcs_; +typedef struct Wave_ Wave_; + +typedef BOOL (*DSPChannelCallback)(dspch_*, u32); + +/** + * @brief TODO. + */ +struct dspch_ { + u8 buffer_idx; // _00 + u8 _01; // _01 + u8 _02; // _02 + u8 _03; // _03 + u16 _04; // _04 + u16 _06; // _06 + jc_* _08; // _08 + DSPChannelCallback _0C; // _0C + + // DSPchannel_* _0C; // TODO: SMS says this exists, Pikmin 1 disagrees. +}; + +typedef struct PanMatrix_ { + f32 values[3]; +} PanMatrix_; + +/** + * @brief TODO + * + * @note Size: 0x74. + */ +struct jcs_ { + u32 chanCount; // _00, Number of channels in this system + u32 chanAllocCount; // _04, Total channel allocation counter + jc_* freeChannels; // _08, Linked list of free channels + jc_* activeChannels; // _0C, Linked list of active channels + jc_* releasingChannels; // _10, Linked list of releasing channels + jc_* waitingChannels; // _14, Linked list of channels waiting for DSP + f32 volume; // _18, Master volume (default 1.0) + f32 pitch; // _1C, Master pitch/cent adjustment (default 1.0) + f32 pan; // _20, Master pan position (default 0.5) + f32 fxmix; // _24, Effects mix level (default 0.0) + f32 dolby; // _28, Dolby surround level (default 0.0) + + s16 firCoefficients[8]; // _2C, FIR filter coefficients (8 taps) + s16 iirCoefficients[4]; // _3C, IIR filter coefficients + + char _44[8]; // _44 + s16 distFilter; // _4C, Distance filter parameter (default 0) + u16 busConnect[6]; // _4E, Bus routing configuration for 6 outputs + u8 masterLevels[6]; // _5A + u8 maxDelay; // _60, Maximum delay setting (default 0) + u8 filterMode; // _61, Filter enable flags (bit 5=IIR, bits 0-4=FIR taps) + u8 panCalcTypes[3]; // _62, Pan calculation types (default [26,1,1]) + u32 channelPriority; // _68 + u16 releaseTime; // _6C, Release/fade time in samples (default 600) + int voiceStealingMode; // _70, Voice stealing enabled (0=off, 1=on) +}; + +// needed to match UpdateEffecterParam +typedef union MixConfig { + u16 whole; + struct { + u8 upper; + u8 lower0 : 4; + u8 lower1 : 4; + } parts; +} MixConfig; + +typedef BOOL (*JCUpdateCallback)(jc_*, JCSTATUS); + +/** + * @brief TODO. + */ +struct jc_ { + u8 velocity; // _00 + u8 note; // _01 + u8 pauseFlag; // _02 + u8 toFlush; // _03 + jcs_* mMgr; // _04 + void** chanListHead; // _08 + u8 logicalChanType; // _0C, 0 = Wave, 1 = ??, 2 = Oscillator + Wave_* waveData; // _10 + u32 _14; // _14 + u32 _18; // _18 + u32 _1C; // _1C + dspch_* dspChannel; // _20 + void* mNext; // _24 + JCUpdateCallback updateCallback; // _28 + JCUpdateCallback pitchSweepUpdater; // _2C + s32 playId; // _30 + s32 savedPlayId; // _34 + struct Osc_* mOscillators[4]; // _38 + struct Oscbuf_ mOscBuffers[2]; // _48 + f32 _78; // _78 + char _7C[8]; // _7C + f32 _84; // _84 + char _88[4]; // _88 + f32 _8C; // _8C + f32 _90; // _90 + f32 _94; // _94 + u16 _98; // _98 + u16 _9A; // _9A + void* _9C; // _9C + char _A0[8]; // _A0 + f32 basePitch; // _A8 + f32 baseVolume; // _AC + f32 currentPitch; // _B0 + f32 currentVolume; // _B4 + u8 panCalcTypes[3]; // _B8 + PanMatrix_ panMatrices[4]; // _BC, 0 = Power distribution, 1 = Pan, 2 = Effects send (fxmix), 3 = Dolby surround + f32 pitchModifier; // _EC + f32 volumeModifier; // _F0 + f32 targetPitch; // _F4 + u16 finalPitch; // _F8 + u16 pitchSweepSteps; // _FA + jcs_* lastManager; // _FC + f32 managerPitch; // _100 + f32 managerVolume; // _104 + MixConfig busRouting[6]; // _108 + u16 mixerLevels[6]; // _114 + u32 channelPriority; // _120 + u16 releaseTime; // _124 + u16 channelId; // _126 + int soundId; // _128 + u8 polyphonyCounter; // _12C + char _12D[3]; // _12D + int _130; // _130 + int _134; // _134 + int _138; // _138 + int _13C; // _13C +}; + +typedef struct Wavelookuptable_ { + // TODO +} Wavelookuptable; + +typedef struct fxconfig { + // TODO: members +} fxconfig_; #ifdef __cplusplus } diff --git a/include/jaudio_NES/bankdrv.h b/include/jaudio_NES/bankdrv.h new file mode 100644 index 00000000..d618ee75 --- /dev/null +++ b/include/jaudio_NES/bankdrv.h @@ -0,0 +1,27 @@ +#ifndef _JAUDIO_BANKDRV_H +#define _JAUDIO_BANKDRV_H + +#include "types.h" + +typedef struct Bank_ Bank_; +typedef struct Inst_ Inst_; +typedef struct Perc_ Perc_; +typedef struct Voice_ Voice_; +typedef struct Sense_ Sense_; +typedef struct Rand_ Rand_; +typedef struct Osc_ Osc_; +typedef struct Oscbuf_ Oscbuf_; +typedef struct Vmap_ Vmap_; + +Inst_* Bank_InstChange(Bank_*, u32); +Voice_* Bank_VoiceChange(Bank_*, u32); +Perc_* Bank_PercChange(Bank_*, u32); +int Bank_GetInstKeymap(Inst_*, u8); +int Bank_GetInstVmap(Inst_*, u8, u8); +Vmap_* Bank_GetPercVmap(Perc_*, u8, u8); +int Bank_GetVoiceMap(Voice_*, u16); +f32 Bank_SenseToOfs(Sense_*, u8); +f32 Bank_RandToOfs(Rand_* rand); +f32 Bank_OscToOfs(Osc_*, Oscbuf_*); + +#endif diff --git a/include/jaudio_NES/bankread.h b/include/jaudio_NES/bankread.h index b052e1a0..6a213c35 100644 --- a/include/jaudio_NES/bankread.h +++ b/include/jaudio_NES/bankread.h @@ -1,19 +1,14 @@ -#ifndef BANKREAD_H -#define BANKREAD_H +#ifndef _JAUDIO_BANKREAD_H +#define _JAUDIO_BANKREAD_H #include "types.h" -#include "audiostruct.h" -#ifdef __cplusplus -extern "C" { +typedef struct Bank_ Bank_; + +Bank_* Bank_Test(u8*); +BOOL Bank_Regist(void*, u32); +BOOL Bank_Regist_Direct(void*, u32, u32); +void Bank_Init(); +Bank_* Bank_Get(u32); + #endif - -BOOL Bank_Regist(void* bank, u32 pid); -void Bank_Init(void); -Bank* Bank_Get(u32 pid); - -#ifdef __cplusplus -} -#endif - -#endif /* BANKREAD_H */ diff --git a/include/jaudio_NES/bx.h b/include/jaudio_NES/bx.h new file mode 100644 index 00000000..5d1b3a63 --- /dev/null +++ b/include/jaudio_NES/bx.h @@ -0,0 +1,254 @@ +#ifndef _JAUDIO_BX_H +#define _JAUDIO_BX_H + +// This is an invented header containing several structs related to the file structure of pikibank.bx + +#include "types.h" +#include "jaudio_NES/heapctrl.h" + +#define BANK_INST_COUNT (0xF0) +#define BANK_TEST_INST_COUNT (0x80) +#define BANK_TEST_VOICE_OFFSET (BANK_TEST_INST_COUNT) +#define BANK_TEST_VOICE_COUNT (0x64) +#define BANK_TEST_PERC_OFFSET (BANK_TEST_INST_COUNT + BANK_TEST_VOICE_COUNT) +#define BANK_TEST_PERC_COUNT (0x0C) + +typedef struct Bank_ Bank_; +typedef struct Ibnk_ Ibnk_; +typedef struct Inst_ Inst_; +typedef struct Perc_ Perc_; +typedef struct Voice_ Voice_; +typedef struct Sense_ Sense_; +typedef struct Rand_ Rand_; +typedef struct Osc_ Osc_; +typedef struct Oscbuf_ Oscbuf_; + +typedef struct Vmap_ Vmap_; +typedef struct InstKeymap_ InstKeymap_; +typedef struct PercKeymap_ PercKeymap_; + +// these type names are confirmed: +typedef struct WaveArchiveBank_ WaveArchiveBank_; +typedef struct CtrlGroup_ CtrlGroup_; +typedef struct Ctrl_ Ctrl_; +typedef struct WaveArchive_ WaveArchive_; +typedef struct Wave_ Wave_; + +// these type names are fabricated, feel free to rename if found: +typedef struct Wsys_ Wsys_; +typedef struct SCNE_ SCNE_; +typedef struct WaveID_ WaveID_; + +////////////////////////////////////////////////////////// +////////////////////// BANK STRUCTS ////////////////////// + +struct Bank_ { + int mMagic; // _00 | 'BANK' + union { // _04 | Can point to INST, VOICE, PERC. + // There's no way this was actually an anonymous union, as this only became a feature + // of the C programming language in C11. However, it does make the code nicer to read. + Inst_* mInstruments[BANK_INST_COUNT]; + Voice_* mVoices[BANK_INST_COUNT]; + Perc_* mPercs[BANK_INST_COUNT]; + }; +}; + +struct Ibnk_ { + int magic; // _00 | 'IBNK' + u32 _04; // _04 + u32 _08; // _08 + int _0C; // _0C + struct WaveArchiveBank_* waveArcBank; // _10 + u8 _14[0x20 - 0x14]; // _14 + Bank_ bank; // _20 +}; + +/** + * @brief This is an invented type of an unknown name. + * + * @note Size: 0x10. + */ +struct Vmap_ { + u8 mBaseVelocity; // _00 + s16 mWsysID; // _04 + s16 mWaveID; // _06 + f32 mVolume; // _08 + f32 mPitch; // _0C +}; + +/** + * @brief This is an invented type of an unknown name. + * + * @note Size: 0x10. + */ +struct InstKeymap_ { + u8 mBaseKey; // _00 + u32 mVelocityCount; // _04 + Vmap_* mVelocities[2]; // _08 +}; + +/** + * @brief This is an invented type of an unknown name. + * + * @note Size: 0x18. + */ +struct PercKeymap_ { + f32 mPitch; // _00 + f32 mVolume; // _04 + void* _08; // _08, pointer type unknown, but gets hit by PTconvert in Bank_Test + void* _0C; // _0C, pointer type unknown, but gets hit by PTconvert in Bank_Test + int mVelocityCount; // _10 + Vmap_* mVelocities[2]; // _14 +}; + +struct Sense_ { + u8 id; // _00 + u8 type; // _01 + u8 threshold; // _02 + f32 min; // _04 + f32 max; // _08 +}; + +struct Osc_ { + u8 mode; // _00 + f32 rate; // _04 + s16* attackVecOffset; // _08 + s16* releaseVecOffset; // _0C + f32 width; // _10 + f32 vertex; // _14 +}; + +/** + * @note Size: 0x18. + */ +struct Oscbuf_ { + u8 state; // _00 + u8 curveType; // _01 + u16 tableIndex; // _02 + f32 timeCounter; // _04 + f32 value; // _08 + f32 targetValue; // _0C + f32 deltaRate; // _10 + u16 releaseParam; // _14 +}; + +/** + * @note Size: 0x40. + */ +struct Inst_ { + int mMagic; // _00 | 'INST' + u32 mFlag; // _04 + f32 mFreqMultiplier; // _08 + f32 mGainMultiplier; // _0C + Osc_* mOscillators[2]; // _10 + Rand_* mEffects[2]; // _18 + Sense_* mSensors[2]; // _20 + int mKeyRegionCount; // _28 + InstKeymap_* mKeyRegions[5]; // _2C +}; + +struct Voice_ { + u8 _00[0x8]; // _00, unknown + int size; // _08, count of whatever's at 0xC + void* _0C[1]; // _0C, unsure of length of array or type +}; + +struct Perc_ { + int mMagic; // _00 | 'PER2' (or 'PERC'?) + u8 _04[0x84]; // _04, unknown + PercKeymap_* mKeyRegions[128]; // _88 + s8 _288[128]; // _288 + u16 _308[128]; // _308 +}; + +struct Rand_ { + u8 id; // _00 + f32 value; // _04 + f32 range; // _08 + u8 _0C[0x10 - 0x0C]; // _0C +}; + +struct Pmap_ { + Rand_* _00; // _00 + int _04; // _04 +}; + +////////////////////////////////////////////////////////// +////////////////////// WAVE STRUCTS ////////////////////// + +// Name fabricated, but makes sense in line with Ibnk_ +struct Wsys_ { + int magic; // _00, 'WSYS' + int size; // _04 + int globalID; // _08 + int _0C; // _0C, unused? + WaveArchiveBank_* waveArcBank; // _10 + CtrlGroup_* ctrlGroup; // _14 +}; + +struct WaveArchiveBank_ { + int magic; // _00, 'WINF' + int count; // _04, same count as CtrlGroup_ + WaveArchive_* waveGroups[1]; // _08, array size variable +}; + +struct CtrlGroup_ { + int magic; // _00, 'WBCT' + u32 _04; // _04, unknown + int count; // _08, same count as WaveArchiveBank_ + SCNE_* scenes[1]; // _0C, array size variable +}; + +// Name fabricated based on magic ID. +struct SCNE_ { + int magic; // _00, 'SCNE' + u32 _04; // _04 + u32 _08; // _08 + Ctrl_* cdf; // _0C + Ctrl_* cex; // _10 + Ctrl_* cst; // _14 + int _18[1]; // _18, variable size? +}; + +struct Ctrl_ { + int magic; // _00, 'C-DF', 'C-EX' or 'C-ST' + int count; // _04 + WaveID_* waveIDs[1]; // _08, array size variable +}; + +// Name fabricated from Xayr's tools. +struct WaveID_ { + u32 id; // _00, split into sound id and ws id + jaheap_ heap; // _04 + u32 loadStatus; // _30 + Wave_* data; // _34 +}; + +struct WaveArchive_ { + char filePath[0x40]; // _00, might be smaller, unsure + jaheap_ heap; // _40 + u32 fileLoadStatus; // _6C + int waveCount; // _70 + Wave_* waves[1]; // _74, array size variable +}; + +/** + * @brief File data, size unknown + */ +struct Wave_ { + u8 _00; // _00 + u8 compBlockIdx; // _01 + u8 key; // _02 + f32 _04; // _04 + int srcAddress; // _08 + int length; // _0C + s32 isLooping; // _10 + s32 loopAddress; // _14 + s32 loopStartPosition; // _18 + s32 _1C; // _1C + s16 loopYN1; // _20 + s16 loopYN2; // _22 + u32* fileLoadStatus; // _24, set to dolphin/dvd.h 'DVD_RESULT_*' defines +}; + +#endif diff --git a/include/jaudio_NES/centcalc.h b/include/jaudio_NES/centcalc.h new file mode 100644 index 00000000..c3708394 --- /dev/null +++ b/include/jaudio_NES/centcalc.h @@ -0,0 +1,16 @@ +#ifndef _JAUDIO_CENTCALC_H +#define _JAUDIO_CENTCALC_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif // ifdef __cplusplus + +f32 Jam_PitchToCent(f32, f32); + +#ifdef __cplusplus +}; +#endif // ifdef __cplusplus + +#endif diff --git a/include/jaudio_NES/cmdstack.h b/include/jaudio_NES/cmdstack.h index 7e378757..e9177ccf 100644 --- a/include/jaudio_NES/cmdstack.h +++ b/include/jaudio_NES/cmdstack.h @@ -1,15 +1,36 @@ -#ifndef CMDSTACK_H -#define CMDSTACK_H +#ifndef _JAUDIO_CMDSTACK_H +#define _JAUDIO_CMDSTACK_H + #include "types.h" +typedef struct JPorthead_ { + u32 _00; // _00 + u32 _04; // _04 +} JPorthead_; + #ifdef __cplusplus extern "C" { -#endif +#endif // ifdef __cplusplus +void Add_PortcmdOnce(u32*); +void Add_PortcmdStay(void); // UNUSED but we know it's extern "C" +int Set_Portcmd(int*, int, int); +BOOL Add_Portcmd(JPorthead_*, u32*); +void Cancel_Portcmd(void); // UNUSED but we know it's extern "C" +void Cancel_PortcmdStay(void); // UNUSED but we know it's extern "C" +int Jac_Portcmd_Proc_Once(JPorthead_*); +int Jac_Portcmd_Proc_Stay(JPorthead_*); +void Jac_Porthead_Init(JPorthead_*); void Jac_Portcmd_Init(void); +void JP_Pitch1Shot(void); // UNUSED but we know it's extern "C" +void JP_Start1Shot(void); // UNUSED but we know it's extern "C" +void JP_Stop1Shot(void); // UNUSED but we know it's extern "C" #ifdef __cplusplus } -#endif +#endif // ifdef __cplusplus -#endif \ No newline at end of file +static int Get_Portcmd(JPorthead_* port); +static s32 Portcmd_Main(void* a); + +#endif diff --git a/include/jaudio_NES/connect.h b/include/jaudio_NES/connect.h index 3113b4ad..3c9dd00c 100644 --- a/include/jaudio_NES/connect.h +++ b/include/jaudio_NES/connect.h @@ -3,7 +3,21 @@ #include "types.h" -void Jac_ConnectTableInit(void); -void Jac_BnkConnectTableSet(u32 vid, u32 pid); +typedef struct WaveArchive_ WaveArchive_; +typedef struct WaveArchiveBank_ WaveArchiveBank_; +typedef struct Ctrl_ Ctrl_; +typedef struct CtrlGroup_ CtrlGroup_; + +void Jac_SceneClose(WaveArchiveBank_*, CtrlGroup_*, u32, BOOL); +BOOL Jac_SceneSet(WaveArchiveBank_*, CtrlGroup_*, u32, BOOL); +struct WaveID_* GetSoundHandle(CtrlGroup_*, u32); +u16 Jac_WsVirtualToPhysical(u16); +u16 Jac_BnkVirtualToPhysical(u16); +u16 Jac_BnkPhysicalToVirtual(u16); +u16 Jac_WsPhysicalToVirtual(u16); +void Jac_WsConnectTableSet(u32, u32); +void Jac_BnkConnectTableSet(u32, u32); +void Jac_ConnectTableInit(); +struct WaveID_* __GetSoundHandle(CtrlGroup_*, u32, u32); #endif diff --git a/include/jaudio_NES/cpubuf.h b/include/jaudio_NES/cpubuf.h index a834d4b0..ff997c0d 100644 --- a/include/jaudio_NES/cpubuf.h +++ b/include/jaudio_NES/cpubuf.h @@ -1,12 +1,15 @@ -#ifndef CPUBUF_H -#define CPUBUF_H +#ifndef _JAUDIO_CPUBUF_H +#define _JAUDIO_CPUBUF_H #include "types.h" -#include "jaudio_NES/rate.h" -#include "jaudio_NES/audiocommon.h" +#include "jaudio_NES/dspbuf.h" -extern s16* CpubufProcess(DSPBUF_EVENTS event); -extern void CpuFrameEnd(void); -extern s16* MixCpu(s32 nSamples); +/////////// JAUDIO CPU BUFFER DEFINITIONS /////////// +// Global functions (all C++, so no extern C wrap). +s16* CpubufProcess(DSPBUF_EVENTS event); +void CpuFrameEnd(); +s16* MixCpu(s32 n_samples); + +///////////////////////////////////////////////////// #endif diff --git a/include/jaudio_NES/driverinterface.h b/include/jaudio_NES/driverinterface.h new file mode 100644 index 00000000..fdb89271 --- /dev/null +++ b/include/jaudio_NES/driverinterface.h @@ -0,0 +1,38 @@ +#ifndef _JAUDIO_DRIVERINTERFACE_H +#define _JAUDIO_DRIVERINTERFACE_H + +#include "types.h" +#include "jaudio_NES/audiostruct.h" + +/////////// JAUDIO DRIVER INTERFACE DEFINITIONS /////////// +// Global functions (all C++, so no extern C wrap). +void Channel_SetMixerLevel(f32); +jcs_* Get_GlobalHandle(); +int List_CountChannel(jc_**); +int List_CutChannel(jc_*); +jc_* List_GetChannel(jc_**); +void List_AddChannelTail(jc_**, jc_*); +void List_AddChannel(jc_**, jc_*); +int FixAllocChannel(jcs_*, u32); +int FixReleaseChannel(jc_*); +int FixReleaseChannelAll(jcs_*); +int FixMoveChannelAll(jcs_*, jcs_*); +void InitJcs(jcs_*); +void Channel_Init(jc_*); +void InitGlobalChannel(); +void UpdateJcToDSP(jc_*); +void UpdateEffecterParam(jc_*); +void DoEffectOsc(jc_*, u8, f32); +BOOL StopLogicalChannel(jc_*); +BOOL CheckLogicalChannel(jc_*); +BOOL PlayLogicalChannel(jc_*); +BOOL ResetInitialVolume(jc_*); +BOOL Add_WaitDSPChannel(jc_*); +BOOL Del_WaitDSPChannel(jc_*); +void __Entry_WaitChannel(u8); +void EntryCheck_WaitDSPChannel(); +BOOL ForceStopLogicalChannel(jc_*); + +/////////////////////////////////////////////////////////// + +#endif diff --git a/include/jaudio_NES/dsp_cardunlock.h b/include/jaudio_NES/dsp_cardunlock.h new file mode 100644 index 00000000..9df5d408 --- /dev/null +++ b/include/jaudio_NES/dsp_cardunlock.h @@ -0,0 +1,16 @@ +#ifndef _JAUDIO_DSP_CARDUNLOCK_H +#define _JAUDIO_DSP_CARDUNLOCK_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif // ifdef __cplusplus + +int __CARDUnlock(int chan, u8 flashID[12]); + +#ifdef __cplusplus +}; +#endif // ifdef __cplusplus + +#endif diff --git a/include/jaudio_NES/dspdriver.h b/include/jaudio_NES/dspdriver.h index 0e3fbba6..eb5fd300 100644 --- a/include/jaudio_NES/dspdriver.h +++ b/include/jaudio_NES/dspdriver.h @@ -1,8 +1,23 @@ -#ifndef DSPDRIVER_H -#define DSPDRIVER_H +#ifndef _JAUDIO_DSPDRIVER_H +#define _JAUDIO_DSPDRIVER_H #include "types.h" +#include "jaudio_NES/audiostruct.h" -extern void UpdateDSPchannelAll(void); +/////////// JAUDIO DSP DRIVER DEFINITIONS /////////// +// Global functions (all C++, so no extern C wrap). + +dspch_* GetDSPchannelHandle(u32 idx); +void InitDSPchannel(); +dspch_* AllocDSPchannel(u32, u32); +int DeAllocDSPchannel(dspch_*, u32); +dspch_* GetLowerDSPchannel(); +dspch_* GetLowerActiveDSPchannel(); +BOOL ForceStopDSPchannel(dspch_*); +BOOL BreakLowerDSPchannel(u8); +BOOL BreakLowerActiveDSPchannel(u8); +void UpdateDSPchannelAll(); + +///////////////////////////////////////////////////// #endif diff --git a/include/jaudio_NES/dspinterface.h b/include/jaudio_NES/dspinterface.h index d1f35aea..0b7b59f9 100644 --- a/include/jaudio_NES/dspinterface.h +++ b/include/jaudio_NES/dspinterface.h @@ -1,9 +1,135 @@ -#ifndef DSPINTERFACE_H -#define DSPINTERFACE_H +#ifndef _JAUDIO_DSPINTERFACE_H +#define _JAUDIO_DSPINTERFACE_H #include "types.h" +#include "jaudio_NES/audiostruct.h" -extern void DSP_InitBuffer(void); -extern void DSP_InvalChannelAll(void); +typedef struct DSPMixerChannel DSPMixerChannel; +typedef struct DSPchannel_ DSPchannel_; +typedef struct FXDestination FXDestination; +typedef struct FXBuffer FXBuffer; + +// A lot of u16s in these DSP structs act like BOOL, so lets codify it. +typedef u16 DSPBOOL; +#define DSP_TRUE ((DSPBOOL)1) +#define DSP_FALSE ((DSPBOOL)0) + +/////////// JAUDIO DSP INTERFACE DEFINITIONS /////////// +// Global functions (all C++, so no extern C wrap). + +DSPchannel_* GetDspHandle(u8 idx); +FXBuffer* GetFxHandle(u8 idx); +void DSP_SetPitch(u8 idx, u16 pitch); +void DSP_SetMixerInitDelayMax(u8 idx, u8 initDelayMax); +void DSP_SetMixerInitVolume(u8 idx, u8 mixer, s16 volume, u8 param_4); +void DSP_SetMixerVolume(u8 idx, u8 mixer, s16 volume, u8 param_4); +void DSP_SetOscInfo(u8 idx, u32 samplesSourceType); +void DSP_SetPauseFlag(u8 idx, u8 pauseFlag); +void DSP_SetWaveInfo(u8 idx, Wave_* wave, u32 baseAddress); +void DSP_SetBusConnect(u8 idx, u8 mixer, u8 busConnect); +void DSP_PlayStop(u8 idx); +void DSP_AllocInit(u8 idx); +void DSP_PlayStart(u8 idx); +void DSP_SetDistFilter(u8 idx, s16 distFilter); +void DSP_SetFilterTable(s16* dst, s16* src, u32 len); +void DSP_SetIIRFilterParam(u8 idx, s16* param_2); +void DSP_SetFIR8FilterParam(u8 idx, s16* param_2); +void DSP_SetFilterMode(u8 idx, u16 filterMode); +void DSP_InitFilter(u8 idx); +void DSP_FlushBuffer(); +void DSP_FlushChannel(u8 idx); +void DSP_InvalChannelAll(); +void DSP_ClearBuffer(); +void DSP_SetupBuffer(); +void DSP_InitBuffer(); + +/////////////////////////////////////////////////////////////////////////////// +// Based on `ZeldaAudioRenderer::VPB` from Dolphin Emulator. Thank you all! + +/** + * @brief TODO. + */ +struct DSPMixerChannel { + u16 id; // _00 + u16 targetVolume; // _02 + u16 currentVolume; // _04 + u16 level; // _06 +}; + +/** + * @brief TODO. + */ +struct DSPchannel_ { + DSPBOOL enabled; // _00 - DSP_AllocInit, DSP_PlayStop, DSP_PlayStart + DSPBOOL done; // _02 - DSP_AllocInit + u16 resamplingRatio; // _04 - DSP_SetPitch + u16 _06; // _06 + DSPBOOL resetVpb; // _08 - DSP_PlayStart + DSPBOOL endReached; // _0A + DSPBOOL useConstantSample; // _0C - DSP_SetPauseFlag + u16 samplesToKeepCount; // _0E - DSP_SetMixerInitDelayMax + DSPMixerChannel mixChannels[6]; // _10 - DSP_SetMixerInitVolume, DSP_SetMixerVolume, DSP_SetBusConnect + u8 _40[0x50 - 0x40]; // _40 + u16 dolbyVoicePosition; // _50 + s16 dolbyReverbFactor; // _52 + s16 dolbyVolumeCurrent; // _54 + s16 dolbyVolumeTarget; // _56 + DSPBOOL useDolbyVolume; // _58 + u16 _5A; // _5A + u16 _5C; // _5C + u16 _5E; // _5E + u16 currentPosFrac; // _60 - DSP_PlayStart + u16 _62; // _62 + u16 afcRemainingDecodedSamples; // _64 - DSP_SetOscInfo, DSP_SetWaveInfo + s16 constantSample; // _66 - DSP_PlayStart + u32 currentPosition; // _68 - DSP_PlayStart + u16 samplesBeforeLoop; // _6C + u16 _6E; // _6E + u32 currentAramAddr; // _70 + u32 remainingLength; // _74 + s16 resampleBuffer[4]; // _78 - DSP_PlayStart + u16 variableFirHistory[20]; // _80 - DSP_PlayStart + s16 biquadHistory[4]; // _A8 - DSP_PlayStart + u16 afcRemainingSamples[16]; // _B0 - DSP_SetWaveInfo + s16 lowPassHistory[2]; // _D0 + u8 _D4[0x100 - 0xD4]; // _D4 + u16 samplesSourceType; // _100 - DSP_SetOscInfo, DSP_SetWaveInfo + DSPBOOL isLooping; // _102 - DSP_SetWaveInfo + s16 loopYN1; // _104 - DSP_SetWaveInfo + s16 loopYN2; // _106 - DSP_SetWaveInfo + s16 filterMode; // _108 - DSP_SetFilterMode + DSPBOOL endRequested; // _10A - DSP_AllocInit, DSP_SetMixerVolume + u32 _10C; // _10C - DSP_PlayStart + u32 loopAddress; // _110 - DSP_SetWaveInfo + u32 loopStartPosition; // _114 - DSP_SetWaveInfo + u32 baseAddress; // _118 - DSP_SetOscInfo, DSP_SetWaveInfo + u32 _11C; // _11C - DSP_SetWaveInfo + s16 variableFirCoeffs[20]; // _120 - DSP_InitFilter, DSP_SetFIR8FilterParam + s16 biquadFilterCoeffs[4]; // _148 - DSP_InitFilter, DSP_SetIIRFilterParam + s16 lowPassCoeff; // _150 - DSP_InitFilter, DSP_SetDistFilter + u8 padding[0x180 - 0x152]; // _152 +}; + +/////////////////////////////////////////////////////////////////////////////// +// Based on `DSP::HLE::ReverbPB` from Dolphin Emulator. Thank you all! + +/** + * @brief TODO. Does this name make sense? Dolphin calls this "Destination" + */ +struct FXDestination { + u16 bufferId; // _00 - See DSPMixerChannel::id + s16 volume; // _02 - 1.15 format. +}; + +/** + * @brief TODO. + */ +struct FXBuffer { + DSPBOOL enabled; // _00 + u16 circularBufferSize; // _02 + s16* circularBufferBase; // _04 + FXDestination dest[2]; // _08 + s16 filterCoeffs[8]; // _10 +}; #endif diff --git a/include/jaudio_NES/dspproc.h b/include/jaudio_NES/dspproc.h index 8ab52eb0..ec69d29f 100644 --- a/include/jaudio_NES/dspproc.h +++ b/include/jaudio_NES/dspproc.h @@ -3,8 +3,13 @@ #include "types.h" -extern u32 DSPReleaseHalt(void); +extern s32 DSPSendCommands(u32* commands, u32 count); +extern u32 DSPReleaseHalt(); +extern void DSPWaitFinish(); +extern void DsetupTable(u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4); extern void DsyncFrame(u32 subframes, u32 dspbuf_start, u32 dspbuf_end); extern void DwaitFrame(); +extern void DiplSec(u32 arg0); +extern void DagbSec(u32 arg0); #endif diff --git a/include/jaudio_NES/dummyrom.h b/include/jaudio_NES/dummyrom.h index c4084e9e..d84cc62b 100644 --- a/include/jaudio_NES/dummyrom.h +++ b/include/jaudio_NES/dummyrom.h @@ -17,7 +17,7 @@ extern u32 GetNeosRom_PreLoaded(void); extern u32 SetPreCopy_NeosRom(u8* load_addr, u32 load_size, BOOL cut_flag); extern BOOL ARAMStartDMAmesg(u32 dir, u32 dramAddr, u32 aramAddr, u32 size, s32 unused, OSMesgQueue* mq); extern void Jac_SetAudioARAMSize(u32 size); -extern void ARAllocFull(u32* outSize); +extern void* ARAllocFull(u32* outSize); extern void Jac_InitARAM(u32 loadAudiorom); #endif diff --git a/include/jaudio_NES/fat.h b/include/jaudio_NES/fat.h new file mode 100644 index 00000000..e3da7246 --- /dev/null +++ b/include/jaudio_NES/fat.h @@ -0,0 +1,18 @@ +#ifndef _JAUDIO_FAT_H +#define _JAUDIO_FAT_H + +#include "types.h" + +void Jac_FatMemory_Init(u32); +void FAT_InitSystem(u8*, u32); +int FAT_AllocateMemory(u32); +int FAT_FreeMemory(u16); +u8* FAT_GetPointer(u16, u32); +u8 FAT_ReadByte(u16, u32); +u16 FAT_ReadWord(u16, u32); // UNUSED, but these were probably global +void FAT_ReadWordD(u16, u32); // UNUSED, but these were probably global +u32 FAT_ReadLong(u16, u32); // UNUSED, but these were probably global +void FAT_ReadLongD(u16, u32); // UNUSED, but these were probably global +int FAT_StoreBlock(u8*, u16, u32, u32); + +#endif diff --git a/include/jaudio_NES/fxinterface.h b/include/jaudio_NES/fxinterface.h new file mode 100644 index 00000000..223b308a --- /dev/null +++ b/include/jaudio_NES/fxinterface.h @@ -0,0 +1,20 @@ +#ifndef _JAUDIO_FXINTERFACE_H +#define _JAUDIO_FXINTERFACE_H + +#include "jaudio_NES/dspinterface.h" + +typedef struct FxlineConfig_ FxlineConfig; + +struct FxlineConfig_ { + u8 enabled; // _00 + u16 sendIdx0; // _02 + s16 volume0; // _04 + u16 sendIdx1; // _06 + s16 volume1; // _08 + s32 circularBufferSize; // _0C + s16 filterCoeffs[8]; // _10 +}; + +BOOL DFX_SetFxLine(u8 idx, s16* circularBufferBase, FxlineConfig* fxlineConfig); + +#endif diff --git a/include/jaudio_NES/heapctrl.h b/include/jaudio_NES/heapctrl.h index a7de7d85..57db913f 100644 --- a/include/jaudio_NES/heapctrl.h +++ b/include/jaudio_NES/heapctrl.h @@ -1,13 +1,40 @@ -#ifndef HEAPCTRL_H -#define HEAPCTRL_H +#ifndef _JAUDIO_HEAPCTRL_H +#define _JAUDIO_HEAPCTRL_H + #include "types.h" -typedef struct jaheap_ { - void* _00; - void* _04; - void* _08; -} JAHEAP; +typedef struct jaheap_ jaheap_; +typedef struct jaheap_ jaheap; -JAHEAP* Jac_AllocHeap(jaheap_*, jaheap_*, unsigned long); +struct jaheap_ { + u8 isRootHeap; // _00, is this a 'mother' heap? + u8 memoryType; // _01, 0 = ARAM, 1 = DRAM + u16 childCount; // _02 + u32 heapId; // _04 + u32 startAddress; // _08 + u32 usedSize; // _0C + u32 size; // _10 + jaheap_* firstChild; // _14 + jaheap_* parent; // _18 + jaheap_* nextSibling; // _1C + jaheap_* groupOwner; // _20 + jaheap_* firstGroupedHeap; // _24 + jaheap_* nextGroupedHeap; // _28 +}; + +void Jac_GetUnlockHeap(jaheap_*); +void Jac_CheckAlloc(jaheap_*); +void Jac_InitHeap(jaheap_*); +void Jac_SelfInitHeap(jaheap_*, u32, u32, u32); +BOOL Jac_SelfAllocHeap(jaheap_*, jaheap_*, u32, u32); +BOOL Jac_SetGroupHeap(jaheap_*, jaheap_*); +void Jac_CutdownHeap(jaheap_*); +void Jac_InitMotherHeap(jaheap_*, u32, u32, u8); +BOOL Jac_AllocHeap(jaheap_*, jaheap_*, u32); +BOOL Jac_DeleteHeap(jaheap_*); +void Jac_GarbageCollection_St(jaheap_*); +void Jac_CheckFreeHeap_Total(jaheap_*); +void Jac_CheckFreeHeap_Linear(jaheap_*); +void Jac_ShowHeap(jaheap_*, u32); #endif diff --git a/include/jaudio_NES/ipldec.h b/include/jaudio_NES/ipldec.h index c86fc8c1..e20a0cd0 100644 --- a/include/jaudio_NES/ipldec.h +++ b/include/jaudio_NES/ipldec.h @@ -1,8 +1,29 @@ -#ifndef IPLDEC_H -#define IPLDEC_H +#ifndef _JAUDIO_IPLDEC_H +#define _JAUDIO_IPLDEC_H #include "types.h" +#include "dolphin/dsp.h" -extern BOOL DspExtraTaskCheck(void); +/////////// JAUDIO IPL DEC DEFINITIONS /////////// +// Global functions (all C++, so no extern C wrap). +BOOL DspExtraTaskCheck(); +void Jac_DSPcardDecodeAsync(void*, void*, DSPCallback); + +// IPL Decode specific structs. + +#define DSPTARGET_IPL 0 +#define DSPTARGET_AGB 1 + +/** + * @brief TODO. + */ +typedef struct DSPTask { + u8 target; // _00, ipl (gc) or agb (gameboy player) + u32 cmd; // _04 + void* task; // _08 + DSPCallback callback; // _0C +} DSPTask; + +////////////////////////////////////////////////// #endif diff --git a/include/jaudio_NES/ja_calc.h b/include/jaudio_NES/ja_calc.h index a361ad8c..2c9ee004 100644 --- a/include/jaudio_NES/ja_calc.h +++ b/include/jaudio_NES/ja_calc.h @@ -1,8 +1,15 @@ -#ifndef JA_CALC_H -#define JA_CALC_H +#ifndef _JAUDIO_JA_CALC_H +#define _JAUDIO_JA_CALC_H #include "types.h" -extern void Jac_InitSinTable(void); +/////////// JAUDIO MATH DEFINITIONS /////////// +// Global functions (all C++, so no extern C wrap). +f32 sqrtf2(f32); +f32 atanf2(f32, f32); +void Jac_InitSinTable(); +f32 sinf3(f32); + +/////////////////////////////////////////////// #endif diff --git a/include/jaudio_NES/jammain.h b/include/jaudio_NES/jammain.h deleted file mode 100644 index 14fe49b5..00000000 --- a/include/jaudio_NES/jammain.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef JAMMAIN_H -#define JAMMAIN_H - -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - - void Jam_InitRegistTrack(void); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/include/jaudio_NES/jammain_2.h b/include/jaudio_NES/jammain_2.h new file mode 100644 index 00000000..bb1c941e --- /dev/null +++ b/include/jaudio_NES/jammain_2.h @@ -0,0 +1,358 @@ +#ifndef _JAUDIO_JAMMAIN_2_H +#define _JAUDIO_JAMMAIN_2_H + +#include "types.h" + +#include "jaudio_NES/audiostruct.h" + +#ifdef __cplusplus +extern "C" { +#endif // ifdef __cplusplus + +//! NOTE from intns: +//! There's something iffy going on with the value 0xC0. +//! It appears in seqsetup with flags regarding opening tracks, +//! It appears to do with command id(s) for some reason +//! It's everywhere, but why? Why, J(esus)System? + +typedef struct seqp_ seqp_; +typedef struct TrackPort_ TrackPort_; +typedef struct MoveParam_ MoveParam_; +typedef struct AInnerParam_ AInnerParam_; +typedef union TimedParam_ TimedParam_; +typedef struct OuterParam_ OuterParam_; +typedef struct RegisterParam_ RegisterParam_; +typedef union URegisterParam_ URegisterParam_; + +typedef u32 (*CmdFunction)(); // TODO: Confirm return type +typedef u16 (*TrackCallback)(seqp_*, u16); // TODO: Confirm return type + +typedef enum { + OuterParamFlag_None = 0, + OuterParamFlag_Volume = 1 << 0, + OuterParamFlag_Pitch = 1 << 1, + OuterParamFlag_Fxmix = 1 << 2, + OuterParamFlag_Pan = 1 << 3, + OuterParamFlag_Dolby = 1 << 4, + OuterParamFlag_DistFilt = 1 << 5, + OuterParamFlag_Tempo = 1 << 6, + OuterParamFlag_FIR8Filter = 1 << 7, // Probably related to FIR filter + + OuterParamFlag_IIR0 = 1 << 12, // IIR0 filter + OuterParamFlag_IIR1 = 1 << 13, // IIR1 filter + OuterParamFlag_IIR2 = 1 << 14, // IIR2 filter + OuterParamFlag_IIR3 = 1 << 15, // IIR3 filter + OuterParamFlag_IIRFilter = (OuterParamFlag_IIR0 | OuterParamFlag_IIR1 | OuterParamFlag_IIR2 | OuterParamFlag_IIR3), + + SEQTRACK_FLAG_MASTER_LEVEL = 1 << 17 // TODO: suspicious, unknown use +} OuterParamFlag; + +typedef enum { + CMD_NONE_0 = 0, // 0 + CMD_OPEN_TRACK, // 1 + CMD_OPEN_TRACK_BROS, // 2 + CMD_CALL, // 3 + CMD_CALL_F, // 4 + CMD_RETURN, // 5 + CMD_RETURN_F, // 6 + CMD_JUMP, // 7 + CMD_JUMP_F, // 8 + CMD_LOOP_START, // 9 + CMD_LOOP_END, // 10 + CMD_READ_PORT, // 11 + CMD_WRITE_PORT, // 12 + CMD_CHECK_PORT_IMPORT, // 13 + CMD_CHECK_PORT_EXPORT, // 14 + CMD_WAIT_REGISTER, // 15 + CMD_CONNECT_NAME, // 16 + CMD_PARENT_WRITE_PORT, // 17 + CMD_CHILD_WRITE_PORT, // 18 + CMD_NONE_1, // 19 + CMD_SET_LAST_NOTE, // 20 + CMD_TIME_RELATE, // 21 + CMD_SIMPLE_OSC, // 22 + CMD_SIMPLE_ENV, // 23 + CMD_SIMPLE_ADSR, // 24 + CMD_TRANSPOSE, // 25 + CMD_CLOSE_TRACK, // 26 + CMD_OUTPUT_SWITCH, // 27 + CMD_UPDATE_SYNC, // 28 + CMD_BUS_CONNECT, // 29 + CMD_PAUSE_STATUS, // 30 + CMD_SET_INTERRUPT, // 31 + CMD_DISABLE_INTERRUPT, // 32 + CMD_CLEAR_I, // 33 + CMD_SET_I, // 34 + CMD_RETURN_I, // 35 + CMD_INTERRUPT_TIMER, // 36 + CMD_CONNECT_OPEN, // 37 + CMD_CONNECT_CLOSE, // 38 + CMD_SYNC_CPU, // 39 + CMD_FLUSH_ALL, // 40 + CMD_FLUSH_RELEASE, // 41 + CMD_WAIT_3, // 42 + CMD_PAN_POWER_SET, // 43 + CMD_IIR_SET, // 44 + CMD_FIR_SET, // 45 + CMD_EXT_SET, // 46 + CMD_PAN_SWITCH_SET, // 47 + CMD_OSC_ROUTE, // 48 + CMD_IIR_CUTOFF, // 49 + CMD_OSC_FULL, // 50 + CMD_NONE_2, // 51 + CMD_NONE_3, // 52 + CMD_NONE_4, // 53 + CMD_NONE_5, // 54 + CMD_NONE_6, // 55 + CMD_NONE_7, // 56 + CMD_NONE_8, // 57 + CMD_CHECK_WAVE, // 58 + CMD_PRINTF, // 59 + CMD_NOP, // 60 + CMD_TEMPO, // 61 + CMD_TIME_BASE, // 62 + CMD_FINISH, // 63 + CMD_COUNT // 64 +} CommandID; + +/** + * @brief This is an invented type of an unknown name. + * + * @note Size: 4 + */ +struct TrackPort_ { + u8 importFlag; // _00 + u8 exportFlag; // _01 + u16 value; // _02 +}; + +/** + * @brief Name borrowed from `JASTrack.h` from Pikmin 2. + * + * @note Size: 16 + */ +struct MoveParam_ { + f32 currentValue; // _00 + f32 targetValue; // _04 + f32 duration; // _08 + f32 stepSize; // _0C +}; + +/** + * @brief Name borrowed from `JASTrack.h` from Pikmin 2. + * + * @note Size: 0x120 + */ +struct AInnerParam_ { + MoveParam_ volume; // _00 + MoveParam_ pitch; // _10 + MoveParam_ fxmix; // _20 + MoveParam_ pan; // _30 + MoveParam_ dolby; // _40 + MoveParam_ distFilter; // _50 + MoveParam_ osc0Width; // _60 + MoveParam_ osc0Rate; // _70 + MoveParam_ osc0Vertex; // _80 + MoveParam_ osc1Width; // _90 + MoveParam_ osc1Rate; // _A0 + MoveParam_ osc1Vertex; // _B0 + MoveParam_ IIRs[4]; // _C0 + MoveParam_ _100; // _100 + MoveParam_ _110; // _110 +}; + +union TimedParam_ { + AInnerParam_ inner; // Get individual params by member name + MoveParam_ move[18]; // Get individual params by index +}; + +/** + * @brief Name borrowed from `JASTrack.h` from Pikmin 2. + * + * @note Size: 0x40. + */ +struct OuterParam_ { + BOOL isAssigned; // _00 + u32 refCount; // _04 + u16 flags; // _08 + u16 updateFlags; // _0A + f32 volume; // _0C + f32 fxMix; // _10 + f32 dolby; // _14 + f32 pitch; // _18 + f32 pan; // _1C + f32 tempo; // _20 + s16 firCoefficients[8]; // _24 + u8 _34[0x40 - 0x34]; // _34 +}; + +/** + * @brief Name borrowed from `JASRegisterParam.h` from Pikmin 2. + * + * @note Size: 0x40. + */ +struct RegisterParam_ { + u8 _00[0x06 - 0x00]; // _00, 00 - 02 + u16 value; // _06, 03 + u8 _08[0x0C - 0x08]; // _08, 04 - 05 + u16 bankNumber; // _0C, 06 + u16 pitchScale; // _0E, 07 + u16 arguments[5]; // _10, 08 - 12, Exact length confirmed: `Cmd_PanPowSet`. + u16 basePriority; // _1A, 13 + u8 _1C[0x20 - 0x1C]; // _1C, 14 + u32 _20[4]; // _20, 15 - 22, Exact length semi-confirmed; Pikmin 2 also says 4. + u8 _30[0x40 - 0x30]; // _1C, 23 - 31 +}; + +/** + * @brief Invented struct necessitated by behavior in `seqsetup.c`. + * + * @note Size: 0x40. + */ +union URegisterParam_ { + RegisterParam_ param; + u16 reg[32]; +}; + +/** + * @brief This struct is analogous to `JASTrack` of later JAudio. + * + * @note Size: 0x434 (Confirmed by `Jaf_HandleToSeq`). + */ +struct seqp_ { + u8* baseData; // _000 + u32 programCounter; // _004 + u32 callStackDepth; // _008 + u32 callStack[2]; // _00C, Exact length unknown, but it is an array. + u8 _10[0x02c - 0x014]; // _008 + u16 loopCounters[2]; // _02C, Exact length unknown, but it is an array. + u8 _30[0x03c - 0x030]; // _030 + u8 trackState; // _03C, Confirmed unsigned by switch cases + u8 dataSourceMode; // _03D + u8 fileHandle; // _03E + u8 flags; // _03F + seqp_* parent; // _040 + seqp_* children[16]; // _044 + u32 connectionId; // _084 + u32 trackId; // _088 + s32 waitTimer; // _08C + u32 _90; // _090 + u8 _94[8]; // _094 + jc_* channels[8]; // _09C + u16 activeSoundIds[8]; // _0BC + u8 _CC; // _0CC + u8 _CD; // _0CD + u8 _CE[0x0d0 - 0x0ce]; // _0CE + u32 _D0; // _0D0 + u8 _D4; // _0D4 + u8 _D5; // _0D5 + u8 _D6; // _0D6, boolean-like + u8 _D7[0x0d8 - 0x0d7]; // _0D7 + jcs_ parentController; // _0D8 + TimedParam_ timedParam; // _14C + URegisterParam_ regParam; // _26C + OuterParam_* outerParams; // _2AC + OuterParam_* childOuterParams[16]; // _2B0 + TrackPort_ trackPort[16]; // _2F0 + f32 tempoAccumulator; // _330 + f32 tempoFactor; // _334 + u16 timeBase; // _338 + u16 tempo; // _33A + u8 timeRelationMode; // _33C + u8 _33D; // _33D + Osc_ oscillators[2]; // _340 + u8 oscillatorRouting[2]; // _370 + s16 adsTable[12]; // _372 + s16 relTable[6]; // _38A + s8 transpose; // _396 + u8 finalTranspose; // _397 + s32 tickCounter; // _398 + u8 isPaused; // _39C, boolean-like + u8 pauseStatus; // _39D + u8 isMuted; // _39E, boolean-like + u8 _39F[0x3a0 - 0x39f]; // _39F + u16 childMuteMask; // _3A0 + u8 _3A2[0x3a4 - 0x3a2]; // _3A2 + u8 interruptActive; // _3A4 + u8 interruptPending; // _3A5 + u8 interruptEnable; // _3A6 + u8 timerCount; // _3A7 + u32 interruptAddresses[8]; // _3A8 + u32 savedProgramCounter; // _3C8 + u32 _3CC; // _3CC, to do with timers (CMD_IntTimer) + u32 timer; // _3D0, to do with timers (CMD_IntTimer) + u32 maxTime; // _3D4, to do with timers (CMD_IntTimer) + u32 updateFlags; // _3D8, see `SEQTRACK_FLAG_*` defines + u8 panCalcTypes[3]; // _3DC + u8 parentPanCalcTypes[3]; // _3DF + u8 isRegistered; // _3E2 + u8 doChangeTempo; // _3E3, boolean-like + u8 _3E4; // _3E4 + u8 _3E5[0x3e8 - 0x3e5]; // _3E5 + Oscbuf_ oscillatorParams[2]; // _3E8 + u8 _418[0x434 - 0x418]; // _400 +}; + +extern s16 CUTOFF_TO_IIR_TABLE[128][4]; + +void* Jam_OfsToAddr(seqp_*, u32); +void Jam_WriteRegDirect(seqp_*, u8, u16); +void Jam_WriteRegParam(seqp_*, u8); +u16 Jam_ReadRegDirect(seqp_*, u8); +u32 Jam_ReadReg32(seqp_* track, u8 index); +void Jam_WriteRegXY(seqp_* track, u32 param_2); +void Jam_WritePortApp(void); +void Jam_ReadPortApp(void); +void Jam_CheckExportApp(void); +void Jam_CheckImportApp(void); +void Jam_WritePortIndirect(void); +void Jam_ReadPortIndirect(void); +void Jam_CheckPortIndirect(void); +BOOL Jam_WritePortAppDirect(seqp_*, u32, u16); +BOOL Jam_ReadPortAppDirect(seqp_*, u32, u16*); +BOOL Jam_CheckPortAppDirect(seqp_*, u32, u16); +void Jam_WritePort(void); +void Jam_ReadPort(void); +void Jam_WritePortChild(void); +void Jam_WritePortBros(void); +void Jam_InitRegistTrack(void); +void Jam_UnRegistTrack(seqp_*); +seqp_* Jam_GetTrackHandle(u32); +void Jam_InitExtBuffer(OuterParam_*); +BOOL Jam_AssignExtBuffer(seqp_*, OuterParam_*); +BOOL Jam_AssignExtBufferP(seqp_*, u8, OuterParam_*); +void Jam_SetExtFirFilterD(OuterParam_*, s16*); +void Jam_SetExtParamD(f32, OuterParam_*, u8); +void Jam_OnExtSwitchD(OuterParam_*, u16); +void Jam_OffExtSwitchD(OuterParam_*, u16); +void Jam_SetExtSwitchDirectD(void); +void Jam_SetExtFirFilter(void); +void Jam_SetExtParam(f32, seqp_*, u8); +void Jam_OnExtSwitch(seqp_*, u16); +void Jam_OffExtSwitch(seqp_*, u16); +void Jam_SetExtSwitchDirect(void); +void Jam_SetExtFirFilterP(void); +void Jam_SetExtParamP(f32, seqp_*, u8, u8); +void Jam_OnExtSwitchP(seqp_*, u8, u16); +void Jam_OffExtSwitchP(seqp_*, u8, u16); +void Jam_SetExtSwitchDirectP(void); +void Jam_CheckRunningCounter(void); +BOOL Jam_RegisterTrackCallback(TrackCallback); +void Jam_SetTrackExtPanPower(void); +void Jam_UpdateTrackAll(seqp_*); +void Jam_UpdateTrack(seqp_*, u32); +void Jam_UpdateTempo(seqp_*); +void Jam_MuteTrack(seqp_*, u8); +void Jam_MuteChildTracks(void); +void Jam_PauseTrack(seqp_*, u8); +void Jam_UnPauseTrack(seqp_*, u8); +void Jam_SetInterrupt(seqp_*, u16); +BOOL Jam_TryInterrupt(seqp_*); +s32 Jam_SeqmainNote(seqp_*, u8); +void SeqUpdate(seqp_*, u32); + +#ifdef __cplusplus +}; +#endif // ifdef __cplusplus + +#endif diff --git a/include/jaudio_NES/jamosc.h b/include/jaudio_NES/jamosc.h new file mode 100644 index 00000000..0774a939 --- /dev/null +++ b/include/jaudio_NES/jamosc.h @@ -0,0 +1,24 @@ +#ifndef _JAUDIO_JAMOSC_H +#define _JAUDIO_JAMOSC_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif // ifdef __cplusplus + +typedef struct seqp_ seqp_; + +void Osc_Update_Param(seqp_* track, u8 id, f32 val); +void Osc_Setup_Simple(seqp_* track, u8); +void Osc_Clear_Overwrite(seqp_* track); +void Osc_Init_Env(seqp_* track); +void Osc_Setup_SimpleEnv(seqp_* track, u8, u32); +void Osc_Setup_ADSR(seqp_* track, s16*); +void Osc_Setup_Full(seqp_* track, u8, u32, u32); + +#ifdef __cplusplus +}; +#endif // ifdef __cplusplus + +#endif diff --git a/include/jaudio_NES/memory.h b/include/jaudio_NES/memory.h index a580346a..e9b461b1 100644 --- a/include/jaudio_NES/memory.h +++ b/include/jaudio_NES/memory.h @@ -1,5 +1,5 @@ -#ifndef JAUDIO_MEMORY_H -#define JAUDIO_MEMORY_H +#ifndef _JAUDIO_MEMORY_H +#define _JAUDIO_MEMORY_H #include "types.h" #include "jaudio_NES/audiostruct.h" diff --git a/include/jaudio_NES/noteon.h b/include/jaudio_NES/noteon.h new file mode 100644 index 00000000..f843ae01 --- /dev/null +++ b/include/jaudio_NES/noteon.h @@ -0,0 +1,15 @@ +#ifndef _JAUDIO_NOTEON_H +#define _JAUDIO_NOTEON_H + +#include "types.h" + +typedef struct seqp_ seqp_; + +s32 NoteON(seqp_*, s32, s32, s32, s32); +s32 NoteOFF_R(seqp_*, u8, u16); +s32 NoteOFF(seqp_*, u8); +s32 GateON(seqp_*, s32, s32, s32, s32); +void ProgramChange(s32); +BOOL CheckNoteStop(seqp_*, s32); + +#endif diff --git a/include/jaudio_NES/oneshot.h b/include/jaudio_NES/oneshot.h new file mode 100644 index 00000000..e770edd2 --- /dev/null +++ b/include/jaudio_NES/oneshot.h @@ -0,0 +1,53 @@ +#ifndef _JAUDIO_ONESHOT_H +#define _JAUDIO_ONESHOT_H + +#include "types.h" + +typedef struct jc_ jc_; +typedef struct Inst_ Inst_; +typedef struct Perc_ Perc_; +typedef struct Pmap_ Pmap_; +typedef struct Osc_ Osc_; +typedef struct jcs_ jcs_; +typedef struct Vmap_ Vmap_; + +typedef struct CtrlWave_ { + int _00; // _00 + int _04; // _04 + int _08; // _08 + u32 _0C; // _0C + u8 _10[0x34 - 0x10]; // _10, unknown + u32 _34; // _34, unknown +} CtrlWave_; +typedef union SOUNDID_ SOUNDID_; + +/** + * @brief This is a "boxed" integer type to be passed by value. + * + * @note Size: 4. Why wasn't this just an enum... This compiler is not smart enough to optimize this. + */ +union SOUNDID_ { + u32 value; // _00 + u8 bytes[4]; +}; + +void Effecter_Overwrite_1ShotD(jc_*, Osc_*, u32); +Perc_* PercRead(u32, u32); +Inst_* InstRead(u32, u32); +Vmap_* VmapRead(Inst_*, u8, u8); +void Init_1shot(jcs_*, u32); +void Stop_1Shot(jc_*); +void Stop_1Shot_R(jc_*, u16); +void AllStop_1Shot(jcs_*); +void SetPitchTarget_1Shot(jc_*, f32, u32); +void SetKeyTarget_1Shot(jc_*, u8, u32); +void Gate_1Shot(jc_*, u8, u8, s32); +void UpdatePause_1Shot(jc_*, u8 a1); +void UpdatePanPower_1Shot(jc_*, f32, f32, f32, f32); +void FlushRelease_1Shot(jcs_*); +u32 One_CheckInstWave(SOUNDID_); // Return type unsure +jc_* Play_1shot(jcs_*, SOUNDID_, u32); +jc_* Play_1shot_Perc(jcs_*, SOUNDID_, u32); +jc_* Play_1shot_Osc(jcs_*, SOUNDID_, u32); + +#endif diff --git a/include/jaudio_NES/playercall.h b/include/jaudio_NES/playercall.h index 9b9a5cab..00c800e6 100644 --- a/include/jaudio_NES/playercall.h +++ b/include/jaudio_NES/playercall.h @@ -8,6 +8,14 @@ extern "C" { #endif +typedef s32 (*PlayerCallBack)(void*); + +typedef struct PLAYER_CALL_ { + PlayerCallBack callback; // _00 + void* arg; // _04 + u32 DSP_mode; // _08 +} PLAYER_CALL; + extern void ResetPlayerCallback(); extern s32 Jac_RegisterDspPlayerCallback(PlayerCallBack callback, void* arg); extern s32 Jac_RegisterPlayerCallback(PlayerCallBack callback, void* arg); diff --git a/include/jaudio_NES/rate.h b/include/jaudio_NES/rate.h index ef121740..7c0bf1a7 100644 --- a/include/jaudio_NES/rate.h +++ b/include/jaudio_NES/rate.h @@ -1,19 +1,15 @@ -#ifndef RATE_H -#define RATE_H +#ifndef _JAUDIO_RATE_H +#define _JAUDIO_RATE_H #include "types.h" -#ifdef __cplusplus -extern "C" { -#endif - +/////////// JAUDIO GLOBAL RATE SETTINGS /////////// extern u32 JAC_AI_SETTING; +extern f32 JAC_DAC_RATE; extern u32 JAC_SUBFRAMES; extern u32 JAC_FRAMESAMPLES; extern u32 DAC_SIZE; -#ifdef __cplusplus -} -#endif +/////////////////////////////////////////////////// #endif diff --git a/include/jaudio_NES/seqsetup.h b/include/jaudio_NES/seqsetup.h index 58299e9e..adee7e7d 100644 --- a/include/jaudio_NES/seqsetup.h +++ b/include/jaudio_NES/seqsetup.h @@ -1,19 +1,27 @@ -#ifndef SEQSETUP_H -#define SEQSETUP_H +#ifndef _JAUDIO_SEQSETUP_H +#define _JAUDIO_SEQSETUP_H + #include "types.h" #ifdef __cplusplus extern "C" { -#endif +#endif // ifdef __cplusplus -typedef struct seqp seqp; // TODO +typedef struct seqp_ seqp_; void Jaq_Reset(void); -s32 Jaq_SetSeqData(seqp* seqp, u8* param_2, u32 param_3, int param_4); -s32 Jaq_StartSeq(u8); +void Jaq_GetRemainFreeTracks(void); +seqp_* Jaq_HandleToSeq(u32 handle); +BOOL Jaq_StopSeq(s32 index); +s32 Jaq_SetSeqData(seqp_*, u8*, u32, u32); +s32 Jaq_SetSeqData_Limit(seqp_*, u8*, u32, u32, u8); +BOOL Jaq_SetBankNumber(seqp_* track, u8 bankNum); +BOOL Jaq_StartSeq(u32); +s32 Jaq_OpenTrack(seqp_*, u32, u32); +u32 Jaq_CloseTrack(seqp_*); #ifdef __cplusplus -} -#endif +}; +#endif // ifdef __cplusplus #endif diff --git a/include/jaudio_NES/tables.h b/include/jaudio_NES/tables.h new file mode 100644 index 00000000..e4dde7a4 --- /dev/null +++ b/include/jaudio_NES/tables.h @@ -0,0 +1,9 @@ +#ifndef _JAUDIO_TABLES_H +#define _JAUDIO_TABLES_H + +#include "types.h" + +#define C5BASE_PITCHTABLE_LENGTH (128) +extern f32 C5BASE_PITCHTABLE[C5BASE_PITCHTABLE_LENGTH]; + +#endif diff --git a/include/jaudio_NES/waveread.h b/include/jaudio_NES/waveread.h new file mode 100644 index 00000000..0781de8c --- /dev/null +++ b/include/jaudio_NES/waveread.h @@ -0,0 +1,18 @@ +#ifndef _JAUDIO_WAVEREAD_H +#define _JAUDIO_WAVEREAD_H + +#include "types.h" + +typedef struct CtrlGroup_ CtrlGroup_; + +CtrlGroup_* Wave_Test(u8*); +void GetSound_Test(u32); +BOOL Wavegroup_Regist(void*, u32); +void Wavegroup_Init(); +CtrlGroup_* WaveidToWavegroup(u32, u32); +BOOL WaveScene_Set(u32, u32); +BOOL WaveScene_Load(u32, u32); +void WaveScene_Close(u32, u32); +void WaveScene_Erase(u32, u32); + +#endif diff --git a/src/actor/ac_birth_control.c b/src/actor/ac_birth_control.c index 156ccd42..fc94d433 100644 --- a/src/actor/ac_birth_control.c +++ b/src/actor/ac_birth_control.c @@ -256,7 +256,7 @@ static int aBC_chk_near_boat_block(BIRTH_CONTROL_ACTOR* birth_control, GAME_PLAY } static void aBC_set_boat(BIRTH_CONTROL_ACTOR* birth_control, GAME_PLAY* play) { - if (mEv_CheckNotTitleDemo() && aBC_chk_near_boat_block(birth_control, play) == TRUE) { + if (mEv_IsNotTitleDemo() && aBC_chk_near_boat_block(birth_control, play) == TRUE) { mActor_name_t* boat_ut_p = mFI_UtNum2UtFG(5 * UT_X_NUM + 5, 6 * UT_Z_NUM + 10); // Set boat at F-5, unit 5-10 (x-z) if (boat_ut_p != NULL) { diff --git a/src/static/jaudio_NES/game/game64_dummy.c_inc b/src/static/jaudio_NES/game/game64_dummy.c_inc index ffb4bd6a..f1f93745 100644 --- a/src/static/jaudio_NES/game/game64_dummy.c_inc +++ b/src/static/jaudio_NES/game/game64_dummy.c_inc @@ -168,25 +168,25 @@ u8 NIN_WAVE[] ATTRIBUTE_ALIGN(32) = { void __OK(u32 a) { (void)a; int r31 = Jaq_SetSeqData(0, NIN_SEQ, 0x60, 0); - int unused1 = Jaq_StartSeq(r31); + int unused1 = Jaq_StartSeq((u8)r31); } u32 bootsound_ptr; u32 bootsound_size; -u32 dummy_callback(char* a, u32 b, u32 c, u32* d, JAHEAP* e) { +u32 dummy_callback(char* a, u32 b, u32 c, u32* d, jaheap_* e) { (void)a; (void)b; (void)c; - JAHEAP* heap2; - JAHEAP* heap; + BOOL allocd; + jaheap_* heap; Init_AramMotherHeap(); heap = Get_AramMotherHeap(); - heap2 = Jac_AllocHeap(e, heap, bootsound_size); - if ((s32)heap2 == 0) { + allocd = Jac_AllocHeap(e, heap, bootsound_size); + if (allocd == 0) { return 0; } - u32 p = (u32)e->_08; + u32 p = (u32)e->startAddress; int unused = DVDT_DRAMtoARAM(0, bootsound_ptr, p, bootsound_size, d, 0); return p; } diff --git a/src/static/jaudio_NES/game/verysimple.c b/src/static/jaudio_NES/game/verysimple.c index f293e0a6..aade8e30 100644 --- a/src/static/jaudio_NES/game/verysimple.c +++ b/src/static/jaudio_NES/game/verysimple.c @@ -4,7 +4,7 @@ #include "jaudio_NES/cmdstack.h" #include "jaudio_NES/seqsetup.h" #include "jaudio_NES/connect.h" -#include "jaudio_NES/jammain.h" +#include "jaudio_NES/jammain_2.h" extern void Jac_Start(void* heap, u32 heap_size, u32 aram_size) { StartAudioThread(heap, heap_size, aram_size, 7); diff --git a/src/static/jaudio_NES/internal/aramcall.c b/src/static/jaudio_NES/internal/aramcall.c new file mode 100644 index 00000000..e7f03b0b --- /dev/null +++ b/src/static/jaudio_NES/internal/aramcall.c @@ -0,0 +1,178 @@ +#include "jaudio_NES/aramcall.h" + +#include "jaudio_NES/heapctrl.h" +#include "jaudio_NES/dummyrom.h" +#include "jaudio_NES/dvdthread.h" + +#include "string.h" + +jaheap_ aram_mother; + +ARAMCallback ARCALL = &LoadAram_Default; +static char extdir[64] = "/Banks/"; + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +void Jac_RegisterARAMCallback(ARAMCallback callback) +{ + ARCALL = callback; +} + +/* + * --INFO-- + * Address: 8000D8A0 + * Size: 000064 + */ +u32 LoadAram(char* filepath, u32* status, u32 dst) +{ + // GUH MUH BRUH + volatile char** filepathGuh = (volatile char**)&filepath; + volatile u32* dstGuh = &dst; + char* filepathMruh = (char*)*filepathGuh; + u32 dstMruh = *dstGuh; + + if (DVDT_LoadtoARAM(0, filepathMruh, dstMruh, 0, 0, status, NULL) == -1) { + return 0; + } + return dst; +} + +/* + * --INFO-- + * Address: 8000D920 + * Size: 000068 + */ +u32 LoadAramSingle(char* filepath, u32 src, u32 length, u32* status, u32 dst) +{ + // GUH MUH BRUH (this function is very stupidly written, why does this match?) + u32 pad[1]; + volatile char** filepathGuh = (volatile char**)&filepath; + volatile u32* srcGuh = &src; + volatile u32* lengthGuh = &length; + char* filepathMruh = (char*)*filepathGuh; + u32 lengthMuh = *lengthGuh; + u32 srcMuh = *srcGuh; + // u32 dstMuh = *dstGuh; + + // Why is normal dst passed into this function when everything else isn't??? + if (DVDT_LoadtoARAM(0, filepathMruh, dst, srcMuh, lengthMuh, status, NULL) == -1) { + return 0; + } + return dst; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000030 + */ +void Jac_WaveDirectorySet(char* directory) +{ + strcpy(extdir, directory); +} + +/* + * --INFO-- + * Address: ........ + * Size: 00000C + */ +jaheap_* Get_AramMotherHeap(void) +{ + return &aram_mother; +} + +/* + * --INFO-- + * Address: 8000D9A0 + * Size: 00002C + */ +void Show_AramMotherHeap(void) +{ + Jac_ShowHeap(&aram_mother, 0); +} + +/* + * --INFO-- + * Address: 8000D9E0 + * Size: 00002C + */ +void Collect_AramMotherHeap(void) +{ + Jac_GarbageCollection_St(&aram_mother); + Show_AramMotherHeap(); +} + +/* + * --INFO-- + * Address: 8000DA20 + * Size: 00006C + */ +void Init_AramMotherHeap(void) +{ + void* alloc; + u32 outSize; + + static BOOL inited = FALSE; + if (!inited) { + inited = TRUE; + + void* alloc = ARAllocFull(&outSize); + Jac_InitMotherHeap(&aram_mother, (u32)alloc, outSize, 0); + } +} + +// Used only by `LoadAram_Default`. +static BOOL first = TRUE; + +/* + * --INFO-- + * Address: 8000DAA0 + * Size: 0000F8 + */ +u32 LoadAram_Default(char* filename, u32 src, u32 length, u32* status, jaheap_* heap) +{ + char filepath[140]; + + if (first) { + Init_AramMotherHeap(); + first = FALSE; + } + + strcpy(filepath, extdir); + strcat(filepath, filename); + + if (src == 0 && length == 0) { + if (!Jac_AllocHeap(heap, &aram_mother, DVDT_CheckFile(filepath))) { + return 0; + } + return LoadAram(filepath, status, heap->startAddress); + } else { + if (!Jac_AllocHeap(heap, &aram_mother, length)) { + return 0; + } + return LoadAramSingle(filepath, src, length, status, heap->startAddress); + } +} + +/* + * --INFO-- + * Address: 8000DBA0 + * Size: 000038 + */ +u32 LoadAram_All(char* filename, u32* status, jaheap_* heap) +{ + return ARCALL(filename, 0, 0, status, heap); +} + +/* + * --INFO-- + * Address: 8000DBE0 + * Size: 000028 + */ +u32 LoadAram_One(char* filename, u32 src, u32 length, u32* status, jaheap_* heap) +{ + return ARCALL(filename, src, length, status, heap); +} diff --git a/src/static/jaudio_NES/internal/bankdrv.c b/src/static/jaudio_NES/internal/bankdrv.c new file mode 100644 index 00000000..1ff7313a --- /dev/null +++ b/src/static/jaudio_NES/internal/bankdrv.c @@ -0,0 +1,327 @@ +#include "jaudio_NES/bankdrv.h" + +#include "jaudio_NES/random.h" +#include "jaudio_NES/rate.h" +#include "jaudio_NES/bx.h" +#include "jaudio_NES/ja_calc.h" + +static u32 FORCE_RELEASE_TABLE[3] = { 5, 15, 0 }; + +/* + * --INFO-- + * Address: 8000CFC0 + * Size: 000030 + */ +Inst_* Bank_InstChange(Bank_* bank, volatile u32 VOLATILE_index) +{ + u32 index; + + index = VOLATILE_index; + if (!bank) { + return NULL; + } + return bank->mInstruments[index]; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000030 + */ +Voice_* Bank_VoiceChange(Bank_* bank, volatile u32 VOLATILE_index) +{ + u32 index; + + index = VOLATILE_index; + if (!bank) { + return NULL; + } + return bank->mVoices[index]; +} + +/* + * --INFO-- + * Address: 8000D000 + * Size: 000030 + */ +Perc_* Bank_PercChange(Bank_* bank, volatile u32 VOLATILE_index) +{ + u32 index; + + index = VOLATILE_index; + if (!bank) { + return NULL; + } + return bank->mPercs[index]; +} + +/* + * --INFO-- + * Address: 8000D040 + * Size: 00005C + */ +int Bank_GetInstKeymap(Inst_* inst, u8 param_2) +{ + if (!inst) { + return 0; + } + + for (u32 i = 0; i < inst->mKeyRegionCount; i++) { + if (param_2 <= inst->mKeyRegions[i]->mBaseKey) { + return i; // Return the index of the keymap + } + } + + return -1; +} + +/* + * --INFO-- + * Address: 8000D0A0 + * Size: 000090 + */ +int Bank_GetInstVmap(Inst_* inst, u8 param_2, u8 param_3) +{ + + if (!inst) { + return 0; + } + + int instIndex = Bank_GetInstKeymap(inst, param_2); + if (instIndex != -1) { + u8* REF_p3 = ¶m_3; + InstKeymap_* key = inst->mKeyRegions[instIndex]; + for (u32 i = 0; i < key->mVelocityCount; i++) { + Vmap_* vmap = key->mVelocities[i]; + if (param_3 <= vmap->mBaseVelocity) { + return (int)vmap; + } + } + + return 0; + } + + return instIndex; +} + +/* + * --INFO-- + * Address: 8000D140 + * Size: 000068 + */ +Vmap_* Bank_GetPercVmap(Perc_* perc, u8 keyIdx, u8 vel) +{ + if (!perc) { + return 0; + } + + PercKeymap_* keymap = perc->mKeyRegions[keyIdx]; + if (!keymap) { + return 0; + } + for (u32 i = 0; i < keymap->mVelocityCount; i++) { + Vmap_* vmap = keymap->mVelocities[i]; + if (vel <= vmap->mBaseVelocity) { + return vmap; + } + } + return 0; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000010 + */ +int Bank_GetVoiceMap(Voice_* voice, u16 id) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000D1C0 + * Size: 000104 + */ +f32 Bank_SenseToOfs(Sense_* sensor, u8 p2) +{ + if (!sensor) { + return 1.0f; + } + + if (sensor->threshold == 127 || sensor->threshold == 0) { + return sensor->min + (f32)p2 * (sensor->max - sensor->min) / 127.0f; + } + + if (p2 < sensor->threshold) { + return sensor->min + (1.0f - sensor->min) * ((f32)p2 / (f32)sensor->threshold); + } + + int a = p2 - sensor->threshold; + int b = 127 - sensor->threshold; + + return 1.0f + (sensor->max - 1.0f) * ((f32)a / (f32)b); +} + +/* + * --INFO-- + * Address: 8000D2E0 + * Size: 000048 + */ +f32 Bank_RandToOfs(Rand_* rand) +{ + f32 value; + + if (!rand) { + return 1.0f; + } + value = GetRandom_sf32(); + value *= rand->range; + value += rand->value; + return value; +} + +/* + * --INFO-- + * Address: 8000D340 + * Size: 0003F8 + */ +f32 Bank_OscToOfs(Osc_* osc, Oscbuf_* buf) +{ + f32 sub; + int offset; + s16 val0, val1, val2; + f32 calc; + s16* table; + + if (osc == NULL) { + buf->value = 1.0f; + return 1.0f; + } + + if (buf->state == 4) { + if (osc->attackVecOffset != osc->releaseVecOffset) { + buf->tableIndex = 0; + buf->timeCounter = 0.0f; + buf->targetValue = buf->value; + } + if (osc->releaseVecOffset == 0 && buf->releaseParam == 0) { + buf->releaseParam = 0x10; + } + + if (buf->releaseParam) { + buf->state = 8; + buf->curveType = buf->releaseParam >> 14 & 3; + f32 x = buf->releaseParam & 0x3fff; + x *= (JAC_DAC_RATE / 80.0f) / 600.0f; + buf->timeCounter = x; + if (buf->timeCounter < 1.0f) { + buf->timeCounter = 1.0f; + } + buf->targetValue = 0.0f; + buf->deltaRate = (buf->targetValue - buf->value) / buf->timeCounter; + } else { + buf->state = 5; + } + } + if (buf->state == 6) { + buf->tableIndex = 0; + buf->timeCounter = 0.0f; + buf->targetValue = buf->value; + buf->state = 7; + } + + if (buf->state == 5) { + table = osc->releaseVecOffset; + } else if (buf->state == 7) { + table = (s16*)FORCE_RELEASE_TABLE; + } else { + table = osc->attackVecOffset; + } + + if (table == NULL && buf->state != 8) { + buf->value = 1.0f; + return 1.0f; + } + if (buf->state == 0) { + return 1.0f; + } + if (buf->state == 3) { + return buf->value * osc->width + osc->vertex; + } + + if (buf->state == 1) { + buf->state = 2; + buf->tableIndex = 0; + buf->timeCounter = 0.0f; + buf->targetValue = 0.0f; + buf->releaseParam = 0; + sub = osc->rate; + } else { + sub = osc->rate; + } + if (buf->state == 7) { + sub = 1.0f; + } + buf->timeCounter -= sub; + + while (buf->timeCounter <= 0.0f) { + offset = (buf->tableIndex * 3); + buf->value = buf->targetValue; + if (buf->state == 8) { + buf->state = 0; + break; + } + val0 = table[offset + 0]; + val1 = table[offset + 1]; + val2 = table[offset + 2]; + + if (val0 == 0xd) { + buf->tableIndex = val2; + continue; + } else if (val0 == 0xf) { + buf->state = 0; + break; + } else if (val0 == 0xe) { + buf->state = 3; + return buf->value * osc->width + osc->vertex; + } + buf->curveType = val0; + + if (val1 == 0) { + buf->targetValue = val2 / 32768.0f; + buf->tableIndex++; + } else { + f32 x = (u16)val1; + x *= (JAC_DAC_RATE / 80.0f) / 600.0f; + buf->timeCounter = x; + buf->targetValue = val2 / 32768.0f; + buf->deltaRate = (buf->targetValue - buf->value) / buf->timeCounter; + buf->tableIndex++; + } + } + + calc = -(buf->deltaRate * buf->timeCounter - buf->targetValue); + buf->value = calc; + + switch (buf->curveType) { + case 0: + break; + case 1: + if (calc > 0.0f) { + calc = calc * calc; + } else { + calc = -calc * calc; + } + break; + + case 2: + if (calc > 0.0f) { + calc = sqrtf2(calc); + } else { + calc = -sqrtf2(-calc); + } + break; + } + return calc * osc->width + osc->vertex; +} diff --git a/src/static/jaudio_NES/internal/bankread.c b/src/static/jaudio_NES/internal/bankread.c index 939592ab..586eb015 100644 --- a/src/static/jaudio_NES/internal/bankread.c +++ b/src/static/jaudio_NES/internal/bankread.c @@ -1,138 +1,166 @@ -#include "jaudio_NES/audiostruct.h" +#include "jaudio_NES/bankread.h" #include "jaudio_NES/connect.h" +#include "jaudio_NES/bx.h" -static void PTconvert(void** s, u32 ramaddr) { - u32 ofs = (u32)*s; +#define BANKP_SIZE (0x100) +static Bank_* bankp[BANKP_SIZE]; - if (ofs >= ramaddr || ofs == 0) { - return; - } - - *s = (void*)(ofs + ramaddr); +/* + * --INFO-- + * Address: 8000BE00 + * Size: 000024 + */ +static void PTconvert(void** pointer, u32 base_address) +{ + if (*pointer >= (void*)base_address || *pointer == NULL) { + return; + } + *pointer = *(char**)pointer + base_address; } -// @nonmatching - regswaps (need to make structs for these) -static Bank* Bank_Test(u8* data) { - InstBank* ibnk = (InstBank*)data; - u32 ramaddr = (u32)data; - Bank* bank = &ibnk->bank; - u32 i; - u32 j; - void** unk_pp; - u32 k; - void* unk; - void** inst_p; - void* inst; +/* + * --INFO-- + * Address: 8000BE40 + * Size: 000270 + */ +Bank_* Bank_Test(u8* ibnk_address) +{ + u32 i, k, j; + u32 base_addr = (u32)ibnk_address; + Bank_* startBank = (Bank_*)(ibnk_address + 0x20); + if (startBank->mMagic != 'BANK') { + return NULL; + } - if (bank->magic != 'BANK') { - return NULL; - } + for (i = 0; i < BANK_TEST_INST_COUNT; ++i) { + PTconvert((void**)&startBank->mInstruments[i], base_addr); - for (i = 0; i < ARRAY_COUNT(bank->part0); i++) { - inst_p = (void**)&bank->part0[i]; - PTconvert(inst_p, ramaddr); + Inst_* inst = (Inst_*)startBank->mInstruments[i]; + if (!inst) { + continue; + } - inst = *inst_p; - if (inst != NULL) { - for (j = 0; j < 2; j++) { - unk_pp = (void**)((u32)inst + j * 4 + 0x10); - PTconvert((void**)(unk_pp), ramaddr); - PTconvert((void**)((u32)inst + j * 4 + 0x18), ramaddr); - PTconvert((void**)((u32)inst + j * 4 + 0x20), ramaddr); - - if (*unk_pp != NULL) { - PTconvert((void**)((u32)*unk_pp + 0x08), ramaddr); - PTconvert((void**)((u32)*unk_pp + 0x0C), ramaddr); - } - } + // each instrument has two oscillators, effects, and sensors + for (j = 0; j < 2; j++) { + PTconvert((void**)&inst->mOscillators[j], base_addr); + PTconvert((void**)&inst->mEffects[j], base_addr); + PTconvert((void**)&inst->mSensors[j], base_addr); - for (j = 0; j < *((u32*)inst + 0x28); j++) { - unk_pp = (void**)((u32)inst + j * 4 + 0x2C); - - PTconvert(unk_pp, ramaddr); - for (k = 0; k < *(u32*)((u32)*unk_pp + 4); k++) { - PTconvert((void**)((u32)*unk_pp + k * 4 + 8), ramaddr); - } - } - } - } + if (inst->mOscillators[j]) { + PTconvert((void**)&inst->mOscillators[j]->attackVecOffset, base_addr); + PTconvert((void**)&inst->mOscillators[j]->releaseVecOffset, base_addr); + } + } - for (i = 0; i < ARRAY_COUNT(bank->part1); i++) { - inst_p = (void**)&bank->part1[i]; + // each instrument also has a certain number of key regions + for (j = 0; j < inst->mKeyRegionCount; j++) { + PTconvert((void**)&inst->mKeyRegions[j], base_addr); - PTconvert(inst_p, ramaddr); - inst = *inst_p; + for (k = 0; k < inst->mKeyRegions[j]->mVelocityCount; k++) { + PTconvert((void**)&inst->mKeyRegions[j]->mVelocities[k], base_addr); + } + } + } - if (inst != NULL) { - for (j = 0; j < *((u32*)inst + 0x08); j++) { - void** unk = (void**)((u32)inst + j * 4 + 0x0C); - - PTconvert(unk, ramaddr); - } - } - } + // treat the next block of 100 as voices (for some reason) + for (i = 0; i < BANK_TEST_VOICE_COUNT; i++) { + PTconvert((void**)&(startBank->mInstruments + BANK_TEST_VOICE_OFFSET)[i], base_addr); - for (i = 0; i < ARRAY_COUNT(bank->part2); i++) { - inst_p = (void**)&bank->part2[i]; - inst; + Voice_* voice = (Voice_*)(startBank->mInstruments + BANK_TEST_VOICE_OFFSET)[i]; + if (!voice) { + continue; + } - PTconvert(inst_p, ramaddr); + for (j = 0; j < voice->size; j++) { + PTconvert(&voice->_0C[j], base_addr); + } + } - inst = *inst_p; - if (inst != NULL) { - for (j = 0; j < 128; j++) { - unk_pp = (void**)((u32)inst + j * 4 + 0x88); + // treat the next block of 12 as percussion (for some reason) + for (i = 0; i < BANK_TEST_PERC_COUNT; i++) { + PTconvert((void**)&(startBank->mInstruments + BANK_TEST_PERC_OFFSET)[i], base_addr); - PTconvert(unk_pp, ramaddr); + Perc_* perc = (Perc_*)(startBank->mInstruments + BANK_TEST_PERC_OFFSET)[i]; + if (!perc) { + continue; + } - unk = *unk_pp; - if (unk != NULL) { - PTconvert((void**)((u32)unk + 0x08), ramaddr); - PTconvert((void**)((u32)unk + 0x0C), ramaddr); + for (j = 0; j < 128; j++) { + PTconvert((void**)&perc->mKeyRegions[j], base_addr); - for (k = 0; k < *(u32*)((u32)unk + 0x10); k++) { - PTconvert((void**)((u32)unk + k * 4 + 0x14), ramaddr); - } - } - } - } - } + PercKeymap_* key = perc->mKeyRegions[j]; + if (!key) { + continue; + } - return bank; + PTconvert(&key->_08, base_addr); + PTconvert(&key->_0C, base_addr); + + for (k = 0; k < key->mVelocityCount; k++) { + PTconvert((void**)&key->mVelocities[k], base_addr); + } + } + } + + return startBank; } -static Bank* bankp[256]; - -static BOOL __Bank_Regist_Inner(u8* bank, u32 pid, u32 vid) { - Jac_BnkConnectTableSet(vid, pid); - bankp[pid] = Bank_Test(bank); - - if (bankp[pid] != NULL) { - return TRUE; - } - - return FALSE; +/* + * --INFO-- + * Address: 8000C0C0 + * Size: 000068 + */ +static BOOL __Bank_Regist_Inner(u8* ibnk, u32 param_2, u32 param_3) +{ + Jac_BnkConnectTableSet(param_3, param_2); + bankp[param_2] = Bank_Test(ibnk); + if (!bankp[param_2]) + return FALSE; + return TRUE; } -BOOL Bank_Regist(void* bank, u32 pid) { - InstBank* ibnk = (InstBank*)bank; - - return __Bank_Regist_Inner((u8*)bank, pid, ibnk->vid); +/* + * --INFO-- + * Address: 8000C140 + * Size: 000024 + */ +BOOL Bank_Regist(void* ibnk, u32 param_2) +{ + return __Bank_Regist_Inner((u8*)ibnk, param_2, ((Ibnk_*)ibnk)->_08); } -void Bank_Init(void) { - int i; - - for (i = 0; i < ARRAY_COUNT(bankp); i++) { - bankp[i] = NULL; - } +/* + * --INFO-- + * Address: ........ + * Size: 000020 + */ +BOOL Bank_Regist_Direct(void* ibnk, u32 param_2, u32 param_3) +{ + return __Bank_Regist_Inner((u8*)ibnk, param_2, param_3); } -Bank* Bank_Get(u32 pid) { - if (pid >= ARRAY_COUNT(bankp)) { - return NULL; - } - - return bankp[pid]; +/* + * --INFO-- + * Address: 8000C180 + * Size: 00002C + */ +void Bank_Init() +{ + for (int i = 0; i < BANKP_SIZE; ++i) { + bankp[i] = NULL; + } +} + +/* + * --INFO-- + * Address: 8000C1C0 + * Size: 000028 + */ +Bank_* Bank_Get(u32 index) +{ + if (index >= BANKP_SIZE) { + return NULL; + } + return bankp[index]; } diff --git a/src/static/jaudio_NES/internal/centcalc.c b/src/static/jaudio_NES/internal/centcalc.c new file mode 100644 index 00000000..542c951c --- /dev/null +++ b/src/static/jaudio_NES/internal/centcalc.c @@ -0,0 +1,44 @@ +#include "jaudio_NES/centcalc.h" + +#include "jaudio_NES/tables.h" + +// Calculated via powf(2.0f, x / 12.0f) +#define KEY_CURVE_RESOLUTION (64) +static f32 KEY_TABLE[KEY_CURVE_RESOLUTION] = { + 1.0000000, 1.0009100, 1.0018210, 1.0027330, 1.0036449, 1.0045590, 1.0054730, 1.0063879, 1.0073040, 1.0082200, 1.0091380, + 1.0100560, 1.0109750, 1.0118960, 1.0128160, 1.0137380, 1.0146610, 1.0155840, 1.0165080, 1.0174330, 1.0183589, 1.0192860, + 1.0202140, 1.0211420, 1.0220710, 1.0230020, 1.0239330, 1.0248640, 1.0257970, 1.0267310, 1.0276650, 1.0286000, 1.0295360, + 1.0304730, 1.0314110, 1.0323499, 1.0332890, 1.0342300, 1.0351710, 1.0361130, 1.0370560, 1.0380000, 1.0389440, 1.0398900, + 1.0408360, 1.0417830, 1.0427310, 1.0436800, 1.0446300, 1.0455810, 1.0465320, 1.0474850, 1.0484380, 1.0493920, 1.0503470, + 1.0513030, 1.0522600, 1.0532170, 1.0541760, 1.0551350, 1.0560950, 1.0570560, 1.0580180, 1.0589809, +}; + +/* + * --INFO-- + * Address: 80014BC0 + * Size: 0000CC + */ +f32 Jam_PitchToCent(f32 basePitch, f32 scaleFactor) +{ + + f32 scaledPitch; + f32 fractionalPart; + s16 tableIndex; + + scaledPitch = 4.0f * basePitch * scaleFactor; + tableIndex = scaledPitch; + fractionalPart = scaledPitch - tableIndex; + + // Handle negative input rounding + if (scaledPitch < 0.0f && fractionalPart != 0.0f) { + fractionalPart += 1.0f; + tableIndex -= 1; + } + + if (fractionalPart >= 1.0f) { + fractionalPart -= 1.0f; + tableIndex += 1; + } + + return C5BASE_PITCHTABLE[tableIndex + 60] * (KEY_TABLE)[(u16)(fractionalPart * KEY_CURVE_RESOLUTION)]; +} diff --git a/src/static/jaudio_NES/internal/cmdstack.c b/src/static/jaudio_NES/internal/cmdstack.c new file mode 100644 index 00000000..28780de3 --- /dev/null +++ b/src/static/jaudio_NES/internal/cmdstack.c @@ -0,0 +1,211 @@ +#include "jaudio_NES/cmdstack.h" +#include "jaudio_NES/playercall.h" +#include "dolphin/os.h" + +JPorthead_ cmd_once; +JPorthead_ cmd_stay; + +/* + * --INFO-- + * Address: 8000E300 + * Size: 000028 + */ +void Add_PortcmdOnce(u32* a1) +{ + Add_Portcmd(&cmd_once, a1); +} + +/* + * --INFO-- + * Address: ........ + * Size: 000028 + */ +void Add_PortcmdStay(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000E340 + * Size: 000018 + */ +int Set_Portcmd(int* a1, int a2, int a3) +{ + // Is this a struct? I have no idea + a1[5] = a2; + a1[6] = a3; + a1[3] = 0; + return 1; +} + +/* + * --INFO-- + * Address: 8000E360 + * Size: 000078 + */ +BOOL Add_Portcmd(JPorthead_* port, u32* a2) +{ + BOOL interrupt = OSDisableInterrupts(); + + if (a2[3]) { + OSRestoreInterrupts(interrupt); + return FALSE; + } + + if (port->_04) { + ((int*)port->_04)[4] = (int)a2; + } else { + port->_00 = (int)a2; + } + + port->_04 = (int)a2; + a2[4] = 0; + a2[3] = (int)port; + OSRestoreInterrupts(interrupt); + return TRUE; +} + +/* + * --INFO-- + * Address: 8000E3E0 + * Size: 000040 + */ +static int Get_Portcmd(JPorthead_* port) +{ + u32 a = port->_00; + if (a) { + port->_00 = ((int*)port->_00)[4]; + if (port->_00 == 0) { + port->_04 = 0; + } + ((int*)a)[3] = 0; + } else { + a = 0; + } + + return a; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000080 + */ +void Cancel_Portcmd(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000028 + */ +void Cancel_PortcmdStay(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000E420 + * Size: 000050 + */ +int Jac_Portcmd_Proc_Once(JPorthead_* port) +{ + u32 p; + while (1) { + p = Get_Portcmd(port); + if (!p) { + break; + } + // Ckit ahh moment unless someone figures out what type Get_Portcmd actually returns + ((int (*)(int)) * (int*)(p + 0x14))(((int*)p)[6]); + } + return 0; +} + +/* + * --INFO-- + * Address: 8000E480 + * Size: 00004C + */ +int Jac_Portcmd_Proc_Stay(JPorthead_* port) +{ + u32 p = port->_00; + while (1) { + if (!p) { + break; + } + ((int (*)(int)) * (int*)(p + 0x14))(((int*)p)[6]); + + p = ((u32*)p)[4]; + } + return 0; +} + +/* + * --INFO-- + * Address: 8000E4E0 + * Size: 000030 + */ +static s32 Portcmd_Main(void* a) +{ + Jac_Portcmd_Proc_Once(&cmd_once); + Jac_Portcmd_Proc_Stay(&cmd_stay); + return 0; +} + +/* + * --INFO-- + * Address: 8000E520 + * Size: 000010 + */ +void Jac_Porthead_Init(JPorthead_* port) +{ + port->_00 = 0; + port->_04 = 0; +} + +/* + * --INFO-- + * Address: 8000E540 + * Size: 00003C + */ +void Jac_Portcmd_Init(void) +{ + Jac_Porthead_Init(&cmd_once); + Jac_Porthead_Init(&cmd_stay); + Jac_RegisterPlayerCallback(Portcmd_Main, 0); +} + +/* + * --INFO-- + * Address: ........ + * Size: 00001C + */ +void JP_Pitch1Shot(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00006C + */ +void JP_Start1Shot(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00004C + */ +void JP_Stop1Shot(void) +{ + // UNUSED FUNCTION +} diff --git a/src/static/jaudio_NES/internal/connect.c b/src/static/jaudio_NES/internal/connect.c new file mode 100644 index 00000000..1dd4e364 --- /dev/null +++ b/src/static/jaudio_NES/internal/connect.c @@ -0,0 +1,308 @@ +#include "jaudio_NES/connect.h" +#include "jaudio_NES/heapctrl.h" +#include "jaudio_NES/bx.h" +#include "jaudio_NES/aramcall.h" + +static s16 WS_V2P_TABLE[0x100]; +static s16 BNK_V2P_TABLE[0x100]; + +/* + * --INFO-- + * Address: 8000C860 + * Size: 0000A0 + */ +static int UpdateWave(WaveArchive_* arc, Ctrl_* ctrl, u32 base) +{ + u32 i = 0; + for (; i < ctrl->count; i++) { + WaveID_* wave = ctrl->waveIDs[i]; + wave->data = arc->waves[i + base]; + if (arc->heap.startAddress) { + Jac_SelfAllocHeap(&wave->heap, &arc->heap, wave->data->length + 0x1f & 0xffffffe0, + arc->heap.startAddress + wave->data->srcAddress); + } + } + return i + base; +} + +/* + * --INFO-- + * Address: 8000C900 + * Size: 000174 + */ +static BOOL UpdateWave_Extern(WaveArchiveBank_* bank, CtrlGroup_* group, Ctrl_* ctrl) +{ + WaveID_* wave; + for (u32 i = 0; i < ctrl->count; i++) { + wave = ctrl->waveIDs[i]; + u32 a = wave->id >> 16; + u32 b = wave->id & 0xffff; + if (wave->heap.startAddress) { + continue; + } + Ctrl_* cdf = group->scenes[a]->cdf; + u32 index = 0; + u32* ptr = &a; + u32* ptr2 = &index; + while (index < cdf->count) { + if ((cdf->waveIDs[index]->id & 0xffff) == b) { + break; + } + index++; + } + + if (index != cdf->count) { + WaveID_** wave2 = &cdf->waveIDs[index]; + if ((*wave2)->heap.startAddress) { + wave->data = (*wave2)->data; + Jac_SelfInitHeap(&wave->heap, (*wave2)->heap.startAddress, 0, (*wave2)->heap.memoryType); + Jac_SetGroupHeap(&wave->heap, &(*wave2)->heap); + } else { + WaveArchive_* wave3 = bank->waveGroups[a]; + wave->data = wave3->waves[index]; + wave->loadStatus = 0; + wave->data->fileLoadStatus = &wave->loadStatus; + LoadAram_One(wave3->filePath, wave->data->srcAddress, wave->data->length, &wave->loadStatus, &wave->heap); + Jac_SetGroupHeap(&wave->heap, &wave3->heap); + } + } + } + return TRUE; +} + +/* + * --INFO-- + * Address: 8000CA80 + * Size: 00009C + */ +void Jac_SceneClose(WaveArchiveBank_* bank, CtrlGroup_* group, u32 id, BOOL set) +{ + WaveArchive_* arc; + SCNE_* scene; + + scene = group->scenes[id]; + arc = bank->waveGroups[id]; + Jac_DeleteHeap(&arc->heap); + arc->fileLoadStatus = 0; + + if (set && scene->_08) { + for (u32 i = 0; i < scene->_08; i++) { + Jac_SceneClose(bank, group, scene->_18[i], TRUE); + } + } +} + +/* + * --INFO-- + * Address: 8000CB20 + * Size: 00015C + */ +BOOL Jac_SceneSet(WaveArchiveBank_* bank, CtrlGroup_* group, u32 id, BOOL set) +{ + WaveArchiveBank_** bankp = &bank; + u32* idp = &id; + WaveArchive_* arc; + int stat = 0; + SCNE_* scene; + Ctrl_* cdf; + u32 i; + + arc = bank->waveGroups[id]; + !arc; + + if (arc->heap.startAddress && arc->fileLoadStatus) { + for (i = 0; i < arc->waveCount; i++) { + arc->waves[i]->fileLoadStatus = &arc->fileLoadStatus; + } + } else { + arc->fileLoadStatus = 0; + for (i = 0; i < arc->waveCount; i++) { + arc->waves[i]->fileLoadStatus = &arc->fileLoadStatus; + } + + if (LoadAram_All(arc->filePath, &arc->fileLoadStatus, &arc->heap) == 0) { + return FALSE; + } + } + + scene = group->scenes[id]; + cdf = scene->cdf; + if (cdf) { + stat = UpdateWave(arc, cdf, 0); + } + if (scene->cex) { + if (scene->_04 == 0) { + UpdateWave(arc, scene->cex, stat); + } else { + UpdateWave_Extern(bank, group, scene->cex); + } + } + + if (set) { + group->_04 = id; + } + return TRUE; +} + +/* + * --INFO-- + * Address: 8000CC80 + * Size: 000044 + */ +static WaveID_* SearchWave(Ctrl_* ctrl, u32 flag) +{ + for (u32 i = 0; i < ctrl->count; i++) { + WaveID_* wave = ctrl->waveIDs[i]; + if ((u16)wave->id == flag) { + return wave; + } + } + return NULL; +} + +/* + * --INFO-- + * Address: 8000CCE0 + * Size: 00010C + */ +WaveID_* __GetSoundHandle(CtrlGroup_* group, u32 id, u32 id2) +{ + u16 wId = id; + SCNE_* scene = group->scenes[id2]; + Ctrl_* ctrl; + + ctrl = scene->cdf; + if (ctrl) { + WaveID_* wave = SearchWave(ctrl, wId); + if (wave && wave->data && (int)wave->data != 0xffffffff) { + return wave; + } + } + + ctrl = scene->cex; + if (ctrl) { + WaveID_* wave = SearchWave(ctrl, wId); + if (wave && wave->data && (int)wave->data != 0xffffffff) { + return wave; + } + } + + for (u32 i = 0; i < scene->_08; i++) { + WaveID_* wave = __GetSoundHandle(group, id, scene->_18[i]); + if (wave && wave->data && (int)wave->data != 0xffffffff) { + return wave; + } + } + return NULL; +} + +/* + * --INFO-- + * Address: 8000CE00 + * Size: 000074 + */ +WaveID_* GetSoundHandle(CtrlGroup_* group, u32 flag) +{ + u32* flagptr = &flag; + WaveID_* wave = __GetSoundHandle(group, flag, group->_04); + if (wave == NULL) { + return NULL; + } + if (wave->data == NULL) { + return NULL; + } + + u32* ptr = wave->data->fileLoadStatus; + if (ptr == NULL) { + return NULL; + } + + if (*ptr == 0) { + return NULL; + } + + return wave; +} + +/* + * --INFO-- + * Address: 8000CE80 + * Size: 000018 + */ +u16 Jac_WsVirtualToPhysical(u16 vID) +{ + return WS_V2P_TABLE[vID]; +} + +/* + * --INFO-- + * Address: 8000CEA0 + * Size: 000018 + */ +u16 Jac_BnkVirtualToPhysical(u16 vID) +{ + return BNK_V2P_TABLE[vID]; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000040 + */ +u16 Jac_BnkPhysicalToVirtual(u16 bnk) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000040 + */ +u16 Jac_WsPhysicalToVirtual(u16 ws) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000CEC0 + * Size: 000050 + */ +void Jac_WsConnectTableSet(u32 id, u32 val) +{ + u32* id2 = &id; + u32* bnk = &val; + + if (id != 0xffff && id < 0x100 && WS_V2P_TABLE[id] == -1) { + WS_V2P_TABLE[id] = *bnk; + } +} + +/* + * --INFO-- + * Address: 8000CF20 + * Size: 000050 + */ +void Jac_BnkConnectTableSet(u32 id, u32 val) +{ + u32* id2 = &id; + u32* bnk = &val; + + if (id != 0xffff && id < 0x100 && BNK_V2P_TABLE[id] == -1) { + BNK_V2P_TABLE[id] = *bnk; + } +} + +/* + * --INFO-- + * Address: 8000CF80 + * Size: 00003C + */ +void Jac_ConnectTableInit() +{ + for (int i = 0; i < 0x100; i++) { + WS_V2P_TABLE[i] = -1; + BNK_V2P_TABLE[i] = -1; + } +} diff --git a/src/static/jaudio_NES/internal/driverinterface.c b/src/static/jaudio_NES/internal/driverinterface.c new file mode 100644 index 00000000..d33ecb08 --- /dev/null +++ b/src/static/jaudio_NES/internal/driverinterface.c @@ -0,0 +1,1123 @@ +#include "jaudio_NES/driverinterface.h" + +#include "jaudio_NES/dspinterface.h" +#include "jaudio_NES/audiostruct.h" +#include "jaudio_NES/dspdriver.h" +#include "jaudio_NES/ja_calc.h" +#include "jaudio_NES/bankdrv.h" +#include "jaudio_NES/aictrl.h" + +#define CHANNEL_SIZE (0x100) + +static jcs_ GLOBAL_CHANNEL; +static jc_ CHANNEL[CHANNEL_SIZE] ATTRIBUTE_ALIGN(32); + +static u16 MAX_MIXERLEVEL = 12000; +u32 JAC_SYSTEM_OUTPUT_MODE = 1; + +static u32 cur_waits; +static u32 cur_top; +static u32 cur_tail; +static jc_* waitp[0x20] ATTRIBUTE_ALIGN(32); +static int waittime[0x20]; + +static u8 calc_sw_table[] + = { 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 2, 0, 1, 0, 0, 2, 1, 0, 2, 2, 1, 0, 0, 1, 0, 1, 1, 0, 2, 1, 1, 0, 1, 1, + 1, 1, 1, 2, 1, 2, 0, 1, 2, 1, 1, 2, 2, 1, 0, 0, 2, 0, 1, 2, 0, 2, 2, 1, 0, 2, 1, 1, 2, 1, 2, 2, 2, 0, 2, 2, 1, 2, 2, 2 }; + +// forward declarations +static void Cancel_WaitDSPChannel(jc_* jc); + +/* + * --INFO-- + * Address: 80009400 + * Size: 000024 + */ +void Channel_SetMixerLevel(f32 mix) +{ + MAX_MIXERLEVEL = mix * 16384.0f; +} + +/* + * --INFO-- + * Address: 80009440 + * Size: 00000C + */ +jcs_* Get_GlobalHandle() +{ + return &GLOBAL_CHANNEL; +} + +/* + * --INFO-- + * Address: 80009460 + * Size: 000020 + */ +int List_CountChannel(jc_** jc) +{ + jc_* chan = *jc; + int num = 0; + + while (TRUE) { + if (chan == NULL) { + break; + } + chan = (jc_*)chan->mNext; + num++; + } + + return num; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000044 + */ +void Check_GlobalActiveChannel() +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00002C + */ +void Check_GlobalRelease(jc_** jc) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00006C + */ +void List_GlobalChannel() +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 80009480 + * Size: 000070 + */ +int List_CutChannel(jc_* jc) +{ + jc_* chan = (jc_*)*jc->chanListHead; + int num = 0; + + if (chan == jc) { + *jc->chanListHead = jc->mNext; + jc->chanListHead = NULL; + return 0; + } + + while (TRUE) { + num++; + if (chan == NULL) { + return -1; + } + + if (chan->mNext == jc) { + break; + } + + chan = (jc_*)chan->mNext; + } + + chan->mNext = jc->mNext; + jc->chanListHead = NULL; + + return num; +} + +/* + * --INFO-- + * Address: 80009500 + * Size: 000030 + */ +jc_* List_GetChannel(jc_** jc) +{ + jc_* chan = *jc; + + if (chan == NULL) { + return NULL; + } + + *jc = (jc_*)chan->mNext; + chan->chanListHead = NULL; + return chan; +} + +/* + * --INFO-- + * Address: 80009540 + * Size: 000048 + */ +void List_AddChannelTail(jc_** jc, jc_* in) +{ + jc_* chan = *jc; + in->chanListHead = (void**)jc; + + if (chan == NULL) { + *jc = in; + in->mNext = NULL; + return; + } + + jc_* next; + while (TRUE) { + next = (jc_*)chan->mNext; + if (next == NULL) { + chan->mNext = in; + in->mNext = NULL; + return; + } + chan = next; + } +} + +/* + * --INFO-- + * Address: 800095A0 + * Size: 000014 + */ +void List_AddChannel(jc_** jc, jc_* in) +{ + jc_* chan = *jc; + in->chanListHead = (void**)jc; + *jc = in; + in->mNext = chan; +} + +/* + * --INFO-- + * Address: 800095C0 + * Size: 00009C + */ +int FixAllocChannel(jcs_* sys, u32 size) +{ + jcs_** REF_sys = &sys; + u32* REF_size = &size; + int num = 0; + while (num < size) { + jc_* chan = List_GetChannel(&GLOBAL_CHANNEL.freeChannels); + if (chan == NULL) { + break; + } + + List_AddChannel(&sys->freeChannels, chan); + chan->mMgr = sys; + Channel_Init(chan); + num++; + } + + sys->chanCount += num; + GLOBAL_CHANNEL.chanCount -= num; + return num; +} + +/* + * --INFO-- + * Address: 80009660 + * Size: 000060 + */ +int FixReleaseChannel(jc_* chan) +{ + List_AddChannel(&GLOBAL_CHANNEL.freeChannels, chan); + chan->mMgr->chanCount--; + GLOBAL_CHANNEL.chanCount++; + chan->mMgr = &GLOBAL_CHANNEL; + return 0; +} + +/* + * --INFO-- + * Address: 800096C0 + * Size: 0000F0 + */ +int FixReleaseChannelAll(jcs_* sys) +{ + jc_* chan; + + while (TRUE) { + chan = List_GetChannel(&sys->freeChannels); + if (chan == NULL) { + break; + } + List_AddChannel(&GLOBAL_CHANNEL.freeChannels, chan); + chan->mMgr = &GLOBAL_CHANNEL; + } + + while (TRUE) { + chan = List_GetChannel(&sys->activeChannels); + if (chan == NULL) { + break; + } + List_AddChannel(&GLOBAL_CHANNEL.activeChannels, chan); + chan->mMgr = &GLOBAL_CHANNEL; + } + + while (TRUE) { + chan = List_GetChannel(&sys->releasingChannels); + if (chan == NULL) { + break; + } + List_AddChannel(&GLOBAL_CHANNEL.releasingChannels, chan); + chan->mMgr = &GLOBAL_CHANNEL; + } + + while (TRUE) { + chan = List_GetChannel(&sys->waitingChannels); + if (chan == NULL) { + break; + } + Cancel_WaitDSPChannel(chan); + List_AddChannel(&GLOBAL_CHANNEL.freeChannels, chan); + chan->mMgr = &GLOBAL_CHANNEL; + } + + GLOBAL_CHANNEL.chanCount += sys->chanCount; + sys->chanCount = 0; + return 0; +} + +/* + * --INFO-- + * Address: 800097C0 + * Size: 0000EC + */ +int FixMoveChannelAll(jcs_* sys, jcs_* sys2) +{ + jc_* chan; + + while (TRUE) { + chan = List_GetChannel(&sys->freeChannels); + if (chan == NULL) { + break; + } + List_AddChannel(&sys2->freeChannels, chan); + chan->mMgr = sys2; + } + + while (TRUE) { + chan = List_GetChannel(&sys->activeChannels); + if (chan == NULL) { + break; + } + List_AddChannel(&sys2->activeChannels, chan); + chan->mMgr = sys2; + } + + while (TRUE) { + chan = List_GetChannel(&sys->releasingChannels); + if (chan == NULL) { + break; + } + List_AddChannel(&sys2->releasingChannels, chan); + chan->mMgr = sys2; + } + + while (TRUE) { + chan = List_GetChannel(&sys->waitingChannels); + if (chan == NULL) { + break; + } + List_AddChannel(&sys2->waitingChannels, chan); + chan->mMgr = sys2; + } + + sys2->chanCount += sys->chanCount; + sys->chanCount = 0; + sys2->chanAllocCount += sys->chanAllocCount; + sys->chanAllocCount = 0; + return 0; +} + +/* + * --INFO-- + * Address: 800098C0 + * Size: 000070 + */ +static f32 PanCalc(const PanMatrix_* mtx1, const PanMatrix_* mtx2, u8 a) +{ + f32 calc = 0.0f; + + u8* vals = calc_sw_table + (a * 3); + + for (int i = 0; i < 3; i++) { + switch (vals[i]) { + case 0: + break; + case 1: + calc += mtx1->values[i]; + break; + case 2: + calc += (mtx1->values[i] * mtx2->values[i]); + break; + } + } + return calc; +} + +/* + * --INFO-- + * Address: 80009940 + * Size: 000104 + */ +void InitJcs(jcs_* sys) +{ + sys->freeChannels = NULL; + sys->activeChannels = NULL; + sys->releasingChannels = NULL; + sys->waitingChannels = NULL; + sys->chanAllocCount = 0; + sys->chanCount = 0; + sys->voiceStealingMode = 1; + sys->volume = 1.0f; + sys->pitch = 1.0f; + sys->pan = 0.5f; + sys->fxmix = 0.0f; + sys->dolby = 0.0f; + + int i; + + for (i = 0; i < 8; i++) { + sys->firCoefficients[i] = 0; + } + + sys->firCoefficients[0] = 0x7fff; + sys->distFilter = 0; + + for (i = 0; i < 4; i++) { + sys->iirCoefficients[i] = 0; + sys->masterLevels[i] = 0; + } + + sys->maxDelay = 0; + sys->iirCoefficients[0] = 0x7fff; + sys->filterMode = 0; + sys->busConnect[0] = 0x150; + sys->busConnect[1] = 0x210; + sys->busConnect[2] = 0x352; + sys->busConnect[3] = 0x412; + sys->busConnect[4] = 0; + sys->busConnect[5] = 0; + sys->channelPriority = 0x20103; + sys->releaseTime = 600; + sys->panCalcTypes[0] = 26; + sys->panCalcTypes[1] = 1; + sys->panCalcTypes[2] = 1; +} + +/* + * --INFO-- + * Address: 80009A60 + * Size: 000138 + */ +void Channel_Init(jc_* jc) +{ + jc->updateCallback = NULL; + jc->pitchSweepUpdater = NULL; + jc->playId = 0; + jc->savedPlayId = 0; + jc->waveData = NULL; + jc->logicalChanType = 0; + jc->_14 = 0; + jc->_18 = 0; + jc->_1C = 0; + + if (jc->mMgr == NULL) { + jc->busRouting[0].whole = 0x150; + jc->busRouting[1].whole = 0x210; + jc->busRouting[2].whole = 0x352; + jc->busRouting[3].whole = 0x412; + jc->busRouting[4].whole = 0; + jc->busRouting[5].whole = 0; + jc->channelPriority = 0x10101; + jc->releaseTime = 0x258; + jc->panCalcTypes[0] = 0x1A; + jc->panCalcTypes[1] = 1; + jc->panCalcTypes[2] = 1; + } else { + for (int i = 0; i < 6; i++) { + jc->busRouting[i].whole = jc->mMgr->busConnect[i]; + } + + jc->channelPriority = jc->mMgr->channelPriority; + jc->releaseTime = jc->mMgr->releaseTime; + + for (int i = 0; i < 3; i++) { + jc->panCalcTypes[i] = jc->mMgr->panCalcTypes[i]; + } + } + + for (int i = 0; i < 4; i++) { + jc->mOscillators[i] = NULL; + } + + jc->pauseFlag = 0; + jc->channelId++; + if ((int)jc->channelId == 0) { + jc->channelId = 1; + } +} + +/* + * --INFO-- + * Address: 80009BA0 + * Size: 000030 + */ +static void Channel_FirstInit(jc_* jc) +{ + jc->dspChannel = NULL; + jc->mNext = NULL; + jc->mMgr = NULL; + Channel_Init(jc); +} + +/* + * --INFO-- + * Address: 80009BE0 + * Size: 00007C + */ +void InitGlobalChannel() +{ + jcs_* global_channel; + int i; + + global_channel = &GLOBAL_CHANNEL; + InitJcs(global_channel); + + for (i = 0; i < CHANNEL_SIZE; i++) { + Channel_FirstInit(&CHANNEL[i]); + List_AddChannel(&global_channel->freeChannels, &CHANNEL[i]); + CHANNEL[i].mMgr = global_channel; + } + + global_channel->chanCount = CHANNEL_SIZE; +} + +/* + * --INFO-- + * Address: 80009C60 + * Size: 0000D8 + */ +static void __UpdateJcToDSPInit(jc_* jc) +{ + int buf = jc->dspChannel->buffer_idx; + DSP_SetMixerInitDelayMax(buf, jc->mMgr->maxDelay); + + for (u32 i = 0; i < 6; i++) { + DSP_SetMixerInitVolume(buf, i, jc->mixerLevels[i], jc->mMgr->masterLevels[i]); + } + + DSP_SetPitch(buf, jc->finalPitch); + + if (jc->mMgr->filterMode & 0x20) { + DSP_SetIIRFilterParam(buf, jc->mMgr->iirCoefficients); + } + + if (jc->mMgr->filterMode & 0x1f) { + DSP_SetFIR8FilterParam(buf, jc->mMgr->firCoefficients); + } + + DSP_SetFilterMode(buf, jc->mMgr->filterMode); + DSP_SetPauseFlag(buf, jc->pauseFlag); +} + +/* + * --INFO-- + * Address: 80009D40 + * Size: 0000D8 + */ +static void __UpdateJcToDSP(jc_* jc) +{ + u8 uVar1; + + uVar1 = jc->dspChannel->buffer_idx; + for (u32 i = 0; i < 6; ++i) { + DSP_SetMixerVolume(uVar1, i, jc->mixerLevels[i], jc->mMgr->masterLevels[i]); + } + + DSP_SetPitch(uVar1, jc->finalPitch); + + if ((jc->mMgr->filterMode & 0x20) != 0) { + DSP_SetIIRFilterParam(uVar1, jc->mMgr->iirCoefficients); + } + + if ((jc->mMgr->filterMode & 0x1f) != 0) { + DSP_SetFIR8FilterParam(uVar1, jc->mMgr->firCoefficients); + } + + DSP_SetFilterMode(uVar1, jc->mMgr->filterMode); + DSP_SetDistFilter(uVar1, jc->mMgr->distFilter); + DSP_SetPauseFlag(uVar1, jc->pauseFlag); +} + +/* + * --INFO-- + * Address: 80009E20 + * Size: 000038 + */ +void UpdateJcToDSP(jc_* jc) +{ + __UpdateJcToDSP(jc); + DSP_FlushChannel(jc->dspChannel->buffer_idx); +} + +/* + * --INFO-- + * Address: 80009E60 + * Size: 000348 + */ +void UpdateEffecterParam(jc_* jc) +{ + f32 pan; + f32 volume; + f32 fxmix; + f32 dolby = 0.0f; + f32 angle; + + f32 tmp; + if (jc->lastManager == jc->mMgr) { + jc->managerPitch = jc->mMgr->pitch; + jc->managerVolume = jc->mMgr->volume; + jc->panMatrices[1].values[2] = jc->mMgr->pan; + jc->panMatrices[2].values[2] = jc->mMgr->fxmix; + jc->panMatrices[3].values[2] = jc->mMgr->dolby; + + for (u32 i = 0; i < 3; i++) { + jc->panCalcTypes[i] = jc->mMgr->panCalcTypes[i]; + } + } + + switch (JAC_SYSTEM_OUTPUT_MODE) { + case 0: + pan = 0.5f; + dolby = 0.0f; + fxmix = PanCalc(&jc->panMatrices[2], &jc->panMatrices[0], jc->panCalcTypes[1]); + break; + + case 1: + if (jc->panCalcTypes[0] == 0) { + pan = 0.5f; + } else { + pan = PanCalc(&jc->panMatrices[1], &jc->panMatrices[0], jc->panCalcTypes[0]); + } + fxmix = PanCalc(&jc->panMatrices[2], &jc->panMatrices[0], jc->panCalcTypes[1]); + dolby = PanCalc(&jc->panMatrices[3], &jc->panMatrices[0], jc->panCalcTypes[2]); + break; + } + + volume = jc->currentVolume * jc->volumeModifier * jc->managerVolume; + + if (pan < 0.0f) { + pan = 0.0f; + } else if (pan > 1.0f) { + pan = 1.0f; + } + + if (fxmix < 0.0f) { + fxmix = 0.0f; + } else if (fxmix > 1.0f) { + fxmix = 1.0f; + } + + if (dolby < 0.0f) { + dolby = 0.0f; + } else if (dolby > 1.0f) { + dolby = 1.0f; + } + + jc->finalPitch = jc->currentPitch * jc->pitchModifier * jc->managerPitch * 4096.0f; + + for (u32 i = 0; i < 6; i++) { + f32 tmp = volume; + MixConfig config = jc->busRouting[i]; + + if (config.parts.upper == 0) { + jc->mixerLevels[i] = 0; + continue; + } + + f32 angle; + if (config.parts.lower0) { + switch (config.parts.lower0) { + case 1: + angle = pan; + break; + case 2: + angle = fxmix; + break; + case 3: + angle = dolby; + break; + case 5: + angle = 1.0f - pan; + break; + case 6: + angle = 1.0f - fxmix; + break; + case 7: + angle = 1.0f - dolby; + break; + } + tmp *= sinf3(angle); + } + + if (config.parts.lower1) { + switch (config.parts.lower1) { + case 1: + angle = pan; + break; + case 2: + angle = fxmix; + break; + case 3: + angle = dolby; + break; + case 5: + angle = 1.0f - pan; + break; + case 6: + angle = 1.0f - fxmix; + break; + case 7: + angle = 1.0f - dolby; + break; + } + tmp *= sinf3(angle); + } + + if (tmp < 0.0f) { + tmp = 0.0f; + } else if (tmp > 1.0f) { + tmp = 1.0f; + } + jc->mixerLevels[i] = tmp * (f32)MAX_MIXERLEVEL; + } +} + +/* + * --INFO-- + * Address: 8000A1C0 + * Size: 000068 + */ +void DoEffectOsc(jc_* jc, u8 id, f32 val) +{ + switch (id) { + case 1: + jc->pitchModifier *= val; + break; + case 0: + jc->volumeModifier *= val; + break; + case 2: + jc->panMatrices[1].values[1] = val; + break; + case 3: + jc->panMatrices[2].values[1] = val; + break; + case 4: + jc->panMatrices[3].values[1] = val; + break; + } +} + +/* + * --INFO-- + * Address: 8000A240 + * Size: 000084 + */ +static void KillBrokenLogicalChannels(dspch_* ch) +{ + size_t i; + jc_* chan; + + for (i = 0; i < CHANNEL_SIZE; i++) { + chan = &CHANNEL[i]; + if (chan->dspChannel == ch) { + StopLogicalChannel(chan); + if (List_CutChannel(chan) != -1) { + List_AddChannel(&chan->mMgr->freeChannels, chan); + } + } + } +} + +/* + * --INFO-- + * Address: 8000A2E0 + * Size: 000384 + */ +static int CommonCallbackLogicalChannel(dspch_* ch, u32 a) +{ + u32 b = 0; + jc_* jc = ch->_08; + u32 i; + dspch_** REF_ch = &ch; + jc_** REF_jc = &jc; + if (jc == NULL) { + ch->_0C = NULL; + ch->_03 = 0; + KillBrokenLogicalChannels(ch); + return FALSE; + } + + if (jc->dspChannel != ch) { + if (jc->dspChannel && jc->dspChannel->_08 == jc) { + KillBrokenLogicalChannels(ch); + } else { + StopLogicalChannel(jc); + if (List_CutChannel(jc) != -1) { + List_AddChannel(&jc->mMgr->freeChannels, jc); + } + } + ch->_08 = 0; + ch->_03 = 0; + ch->_0C = nullptr; + return FALSE; + } + + if (a == 2) { + if (jc->updateCallback) { + jc->updateCallback(jc, JCSTAT_Unk1); + } else { + StopLogicalChannel(jc); + if (List_CutChannel(jc) != -1) { + List_AddChannel(&jc->mMgr->freeChannels, jc); + } + } + return FALSE; + } + + if (jc->waveData && !*jc->waveData->fileLoadStatus) { + ForceStopDSPchannel(jc->dspChannel); + return -1; + } + + if (a == 4) { + u8 prio = jc->channelPriority >> 16; + if (jc->dspChannel && prio < jc->dspChannel->_03) { + jc->dspChannel->_03 = prio; + } + return FALSE; + } + + if (a == 3) { + jc->mOscBuffers[0].state = 6; + if (List_CutChannel(jc) == -1) { + return TRUE; + } + List_AddChannel(&jc->mMgr->waitingChannels, jc); + a = 0; + } + + if (a == 0) { + jc->pitchModifier = 1.0f; + jc->volumeModifier = 1.0f; + jc->panMatrices[1].values[1] = 0.5f; + jc->panMatrices[2].values[1] = 0.0f; + jc->panMatrices[3].values[1] = 0.0f; + + for (i = 0; i < 4; i++) { + u32* REF_i = &i; + if (jc->mOscillators[i]) { + DoEffectOsc(jc, jc->mOscillators[i]->mode, Bank_OscToOfs(jc->mOscillators[i], &jc->mOscBuffers[i])); + if (jc->mOscBuffers[i].state == 0) { + if (jc->updateCallback == NULL) { + if (StopLogicalChannel(jc) == FALSE) { + DSP_PlayStop(ch->buffer_idx); + DSP_FlushChannel(ch->buffer_idx); + } + if (List_CutChannel(jc) != -1) { + List_AddChannel(&jc->mMgr->freeChannels, jc); + } + return FALSE; + } else { + jc->updateCallback(jc, JCSTAT_Unk2); + return FALSE; + } + } + b++; + } + } + + if (b) { + UpdateEffecterParam(jc); + jc->toFlush = 1; + } + + if (jc->pitchSweepUpdater && (u32)jc->pitchSweepUpdater(jc, JCSTAT_Unk0) == TRUE) { + jc->toFlush++; + } + + if (jc->updateCallback == NULL) { + return TRUE; + } + + if (jc->savedPlayId > 0) { + jc->savedPlayId--; + } + } + + if (jc->savedPlayId == 0) { + jc->updateCallback(jc, JCSTAT_Unk0); + jc->savedPlayId = jc->playId; + } + + if (jc->toFlush) { + UpdateJcToDSP(jc); + jc->toFlush = 0; + } + + return TRUE; +} + +/* + * --INFO-- + * Address: 8000A680 + * Size: 000078 + */ +BOOL StopLogicalChannel(jc_* jc) +{ + dspch_* ch = jc->dspChannel; + if (ch == NULL) { + return FALSE; + } + + ch->_0C = NULL; + jc->dspChannel->_06 = 0; + DSP_PlayStop(jc->dspChannel->buffer_idx); + DSP_FlushChannel(jc->dspChannel->buffer_idx); + DeAllocDSPchannel(jc->dspChannel, (u32)jc); + jc->dspChannel = NULL; + return TRUE; +} + +/* + * --INFO-- + * Address: 8000A700 + * Size: 000028 + */ +BOOL CheckLogicalChannel(jc_* jc) +{ + if (jc->waveData == NULL && jc->logicalChanType == 0) { + return FALSE; + } + return TRUE; +} + +/* + * --INFO-- + * Address: 8000A740 + * Size: 000180 + */ +BOOL PlayLogicalChannel(jc_* jc) +{ + if (jc->dspChannel == NULL) { + return FALSE; + } + if (CheckLogicalChannel(jc) == FALSE) { + return FALSE; + } + + jc->dspChannel->_0C = CommonCallbackLogicalChannel; + jc->dspChannel->_06 = 1; + + switch (jc->logicalChanType) { + case 0: + DSP_SetWaveInfo(jc->dspChannel->buffer_idx, jc->waveData, jc->_14); + break; + case 1: + break; + case 2: + DSP_SetOscInfo(jc->dspChannel->buffer_idx, jc->_14); + break; + } + + for (u32 i = 0; i < 6; i++) { + MixConfig bus = jc->busRouting[i]; + if (JAC_SYSTEM_OUTPUT_MODE == 0) { + switch (bus.parts.upper) { + case 8: + bus.parts.upper = 11; + break; + case 9: + bus.parts.upper = 2; + break; + } + } + DSP_SetBusConnect(jc->dspChannel->buffer_idx, i, bus.parts.upper); + } + + jc->lastManager = jc->mMgr; + UpdateEffecterParam(jc); + __UpdateJcToDSPInit(jc); + jc->dspChannel->_03 = jc->channelPriority; + jc->dspChannel->_04 = jc->releaseTime; + DSP_PlayStart(jc->dspChannel->buffer_idx); + DSP_FlushChannel(jc->dspChannel->buffer_idx); + return TRUE; +} + +/* + * --INFO-- + * Address: 8000A8C0 + * Size: 000074 + */ +BOOL ResetInitialVolume(jc_* jc) +{ + if (jc->dspChannel == NULL) { + return FALSE; + } + + if (CheckLogicalChannel(jc) == FALSE) { + return FALSE; + } + + UpdateEffecterParam(jc); + __UpdateJcToDSPInit(jc); + DSP_FlushChannel(jc->dspChannel->buffer_idx); + return TRUE; +} + +/* + * --INFO-- + * Address: 8000A940 + * Size: 0000B0 + */ +BOOL Add_WaitDSPChannel(jc_* jc) +{ + if (cur_waits == 32) { + return FALSE; + } + + if (BreakLowerDSPchannel(jc->channelPriority) == FALSE) { + return FALSE; + } + + waittime[cur_tail] = 0; + waitp[cur_tail] = jc; + cur_tail++; + cur_waits++; + + if (cur_tail == 32) { + cur_tail = 0; + } + return TRUE; +} + +/* + * --INFO-- + * Address: 8000AA00 + * Size: 000064 + */ +BOOL Del_WaitDSPChannel(jc_* jc) +{ + for (u32 i = 0; i < cur_waits; i++) { + u32 a = (cur_top + i) & 0x1F; + if (waitp[a] == jc) { + waitp[a] = NULL; + return TRUE; + } + } + return FALSE; +} + +/* + * --INFO-- + * Address: 8000AA80 + * Size: 0000FC + */ +void __Entry_WaitChannel(u8 a) +{ + jc_* jc; + dspch_* ch; + + while (cur_waits != 0) { + jc = waitp[cur_top]; + if (jc) { + ch = AllocDSPchannel(0, (u32)jc); + if (ch == NULL) { + break; + } + jc->dspChannel = ch; + PlayLogicalChannel(jc); + if (List_CutChannel(jc) != -1) { + List_AddChannelTail(&jc->mMgr->activeChannels, jc); + } + cur_top++; + if (cur_top == 0x20) { + cur_top = 0; + } + cur_waits--; + if (a == 1) { + break; + } + } else { + cur_top++; + if (cur_top == 0x20) { + cur_top = 0; + } + cur_waits--; + } + } +} + +/* + * --INFO-- + * Address: 8000AB80 + * Size: 0000C4 + */ +void EntryCheck_WaitDSPChannel() +{ + __Entry_WaitChannel(0); + + for (u32 i = 0; i < cur_waits; i++) { + jc_* jc = waitp[(cur_top + i) & 0x1f]; + if (jc) { + waittime[(cur_top + i) & 0x1f]++; + if (jc->playId > 0) { + jc->playId--; + } + if (jc->playId == 0) { + jc->updateCallback(jc, JCSTAT_Unk6); + waitp[(cur_top + i) & 0x1f] = NULL; + } + } + } +} + +/* + * --INFO-- + * Address: 8000AC60 + * Size: 00004C + */ +static void Cancel_WaitDSPChannel(jc_* jc) +{ + for (u32 i = 0; i < cur_waits; i++) { + if (waitp[(cur_top + i) & 0x1F] == jc) { + waitp[(cur_top + i) & 0x1F] = NULL; + } + } +} + +/* + * --INFO-- + * Address: 8000ACC0 + * Size: 000038 + */ +BOOL ForceStopLogicalChannel(jc_* jc) +{ + if (jc->dspChannel == NULL) { + return FALSE; + } + + ForceStopDSPchannel(jc->dspChannel); + return TRUE; +} diff --git a/src/static/jaudio_NES/internal/dsp_cardunlock.c b/src/static/jaudio_NES/internal/dsp_cardunlock.c new file mode 100644 index 00000000..9b0cb629 --- /dev/null +++ b/src/static/jaudio_NES/internal/dsp_cardunlock.c @@ -0,0 +1,331 @@ +#include "jaudio_NES/dsp_cardunlock.h" + +#include "dolphin/os.h" +#include "dolphin/card.h" +#include "MSL_C/rand.h" +#include "jaudio_NES/ipldec.h" +#include "_mem.h" +#include "card/__card.h" + +#define DATA_SCRAMBLE_R(data) (~(data ^ (data >> 7) ^ (data >> 15) ^ (data >> 23))) +#define DATA_SCRAMBLE_L(data) (~(data ^ (data << 7) ^ (data << 15) ^ (data << 23))) + +/* + * --INFO-- + * Address: 80008BE0 + * Size: 000038 + */ +static u32 exnor_1st(u32 data, u32 rshift) +{ + for (u32 i = 0; i < rshift; ++i) { + data = (data >> 1) | (DATA_SCRAMBLE_R(data) << 30) & 0x40000000; + } + return data; +} + +/* + * --INFO-- + * Address: 80008C20 + * Size: 000038 + */ +static u32 exnor(u32 data, u32 lshift) +{ + for (u32 i = 0; i < lshift; ++i) { + data = (data << 1) | (DATA_SCRAMBLE_L(data) >> 30) & 0x00000002; + } + return data; +} + +/* + * --INFO-- + * Address: 80008C60 + * Size: 00007C + */ +static u32 bitrev(u32 data) +{ + u32 wk; + u32 i; + u32 k = 0; + u32 j = 1; + + wk = 0; + for (i = 0; i < 32; ++i) { + if (i > 0x0f) { + if (i == 31) { + wk |= (data & 1 << 31) >> 31; + } else { + wk |= (data & 1 << i) >> j; + j += 2; + } + } else { + wk |= (data & 1 << i) << (31 - i - k); + k += 1; + } + } + return wk; +} + +/* + * --INFO-- + * Address: 80008CE0 + * Size: 00017C + */ +static s32 ReadArrayUnlock(s32 chan, u32 data, void* rbuf, s32 length, BOOL mode) +{ + ASSERTLINE(216, 0 <= chan && chan < 2); + CARDControl* card = &__CARDBlock[chan]; + + if (!EXISelect(chan, 0, 4)) + return CARD_RESULT_NOCARD; + + data &= 0xFFFFF000; + u8 cmd[5]; + memset(cmd, 0, sizeof(cmd)); + cmd[0] = 0x52; + if (mode == FALSE) { + cmd[1] = data >> 29 & 0x03; + cmd[2] = data >> 21 & 0xff; + cmd[3] = data >> 19 & 0x03; + cmd[4] = data >> 12 & 0x7f; + } else { + cmd[1] = data >> 24 & 0xff; + cmd[2] = data >> 16 & 0xff; + } + + BOOL err = FALSE; + err |= !EXIImmEx(chan, cmd, sizeof(cmd), EXI_WRITE); + err |= !EXIImmEx(chan, (void*)(((CARDID*)card->workArea)+1), card->latency, EXI_WRITE); + err |= !EXIImmEx(chan, rbuf, length, EXI_READ); + err |= !EXIDeselect(chan); + return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY; +} + +/* + * --INFO-- + * Address: 80008E60 + * Size: 000044 + */ +static u32 GetInitVal() +{ + srand(OSGetTick()); + u32 val = 0x7fec8000; + val |= rand(); + val &= 0xFFFFF000; + return val; +} + +/* + * --INFO-- + * Address: 80008EC0 + * Size: 00008C + */ +static u32 DummyLen() +{ + u32 lshift = 1; + u32 i = 0; + + srand(OSGetTick()); + int result = (rand() & 0x1f) + 1; + for (; result < 4 && i < 10; i++) { + result = OSGetTick() << lshift; + if (++lshift > 0x10) + lshift = 1; + srand(result); + result = (rand() & 0x1f) + 1; + } + return result < 4 ? 4 : result; +} + +static void InitCallback(void* dspTask); +static void DoneCallback(void* dspTask); + +struct CARDDecodeParameters { + u8* inputAddr; // _00 + u32 inputLength; // _04 + u32 aramAddr; // _08 + u8* outputAddr; // _0C +}; + +/* + * --INFO-- + * Address: 80008F60 + * Size: 0002B0 + */ +int __CARDUnlock(int chan, u8 flashID[12]) +{ + u32 Ans1, Ans2; + u8 rbuf[64]; + + // The nonsense + CARDControl* card = &__CARDBlock[chan]; + DSPTaskInfo* task = &card->task; + CARDDecodeParameters* param = (CARDDecodeParameters*)card->workArea; + u8* input = (u8*)param + sizeof(CARDDecodeParameters); + input = (u8*)OSRoundUp32B(input); + u8* output = input + 32; + + u32 data; + s32 dummy; + s32 rlen; + + data = GetInitVal(); + dummy = DummyLen(); + rlen = dummy; + if (ReadArrayUnlock(chan, data, rbuf, rlen, FALSE) < CARD_RESULT_READY) + return CARD_RESULT_NOCARD; + + // TODO: Pikmin uses `card->formatStep`, but every other + // decomp uses `card->scramble`. What's up with that? + + u32 shift; + u32 wk; + + shift = dummy * 8 + 1; + wk = exnor_1st(data, shift); + card->formatStep = wk | (DATA_SCRAMBLE_R(wk) << 31 & 0x80000000); + card->formatStep = bitrev(card->formatStep); + + data = 0; + dummy = DummyLen(); + rlen = dummy + 20; + if (ReadArrayUnlock(chan, data, rbuf, rlen, TRUE) < CARD_RESULT_READY) + return CARD_RESULT_NOCARD; + + u32 para1A = *(u32*)(rbuf + 0); + u32 para1B = *(u32*)(rbuf + 4); + Ans1 = *(u32*)(rbuf + 8); + u32 para2A = *(u32*)(rbuf + 12); + u32 para2B = *(u32*)(rbuf + 16); + para1A ^= card->formatStep; + + shift = 32; + wk = exnor(card->formatStep, shift); + card->formatStep = wk | (DATA_SCRAMBLE_L(wk) >> 31 & 0x00000001); + para1B ^= card->formatStep; + + shift = 32; + wk = exnor(card->formatStep, shift); + card->formatStep = wk | (DATA_SCRAMBLE_L(wk) >> 31 & 0x00000001); + Ans1 ^= card->formatStep; + + shift = 32; + wk = exnor(card->formatStep, shift); + card->formatStep = wk | (DATA_SCRAMBLE_L(wk) >> 31 & 0x00000001); + para2A ^= card->formatStep; + + shift = 32; + wk = exnor(card->formatStep, shift); + card->formatStep = wk | (DATA_SCRAMBLE_L(wk) >> 31 & 0x00000001); + para2B ^= card->formatStep; + + shift = dummy * 8; + wk = exnor(card->formatStep, shift); + card->formatStep = wk | (DATA_SCRAMBLE_L(wk) >> 31 & 0x00000001); + + shift = 32 + 1; + wk = exnor(card->formatStep, shift); + card->formatStep = wk | (DATA_SCRAMBLE_L(wk) >> 31 & 0x00000001); + + *(u32*)(input + 0) = para2A; + *(u32*)(input + 4) = para2B; + + param->inputAddr = input; + param->inputLength = 8; + param->outputAddr = output; + param->aramAddr = 0; + + DCFlushRange(input, 8); + DCInvalidateRange(output, 4); + DCFlushRange(param, sizeof(CARDDecodeParameters)); + + Jac_DSPcardDecodeAsync(task, param, DoneCallback); + + *(u32*)(flashID + 0) = para1A; + *(u32*)(flashID + 4) = para1B; + *(u32*)(flashID + 8) = Ans1; + + return CARD_RESULT_READY; +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000C4 + */ +static void InitCallback(void* dspTask) +{ +} + +/* + * --INFO-- + * Address: 80009220 + * Size: 0001E0 + */ +static void DoneCallback(void* dspTask) +{ + DSPTaskInfo* task = (DSPTaskInfo*)dspTask; + + u8 rbuf[64]; + u32 Ans2; + u8 status; + + s32 chan; + CARDControl* card; + for (chan = 0; chan < 2; ++chan) { + card = &__CARDBlock[chan]; + if (&card->task == task) { + break; + } + } + ASSERTLINE(548, 0 <= chan && chan < 2); + + // The nonsense + CARDDecodeParameters* param = (CARDDecodeParameters*)card->workArea; + u8* input = (u8*)param + sizeof(CARDDecodeParameters); + input = (u8*)OSRoundUp32B(input); + u8* output = input + 32; + Ans2 = *(u32*)output; + + // TODO: Pikmin uses `card->formatStep`, but every other + // decomp uses `card->scramble`. What's up with that? + + s32 dummy; + s32 rlen; + u32 data; + + dummy = DummyLen(); + rlen = dummy; + data = (Ans2 ^ card->formatStep) & 0xffff0000; + if (ReadArrayUnlock(chan, data, rbuf, rlen, TRUE) < CARD_RESULT_READY) { + EXIUnlock(chan); + __CARDMountCallback(chan, CARD_RESULT_NOCARD); + return; + } + + u32 shift; + u32 wk, wk1; + + shift = (rlen + 4 + card->latency) * 8 + 1; + wk = exnor(card->formatStep, shift); + card->formatStep = wk | ((DATA_SCRAMBLE_L(wk) >> 31) & 0x00000001); + + dummy = DummyLen(); + rlen = dummy; + data = ((Ans2 << 16) ^ card->formatStep) & 0xffff0000; + if (ReadArrayUnlock(chan, data, rbuf, rlen, TRUE) < CARD_RESULT_READY) { + EXIUnlock(chan); + __CARDMountCallback(chan, CARD_RESULT_NOCARD); + return; + } + s32 result = __CARDReadStatus(chan, &status); + if (!EXIProbe(chan)) { + EXIUnlock(chan); + __CARDMountCallback(chan, CARD_RESULT_NOCARD); + return; + } + if (result == CARD_RESULT_READY && !(status & 0x40)) { + EXIUnlock(chan); + result = CARD_RESULT_IOERROR; + } + __CARDMountCallback(chan, result); +} diff --git a/src/static/jaudio_NES/internal/dspdriver.c b/src/static/jaudio_NES/internal/dspdriver.c new file mode 100644 index 00000000..2acc343c --- /dev/null +++ b/src/static/jaudio_NES/internal/dspdriver.c @@ -0,0 +1,365 @@ +#include "jaudio_NES/dspdriver.h" + +#include "jaudio_NES/dspinterface.h" +#include "jaudio_NES/audiothread.h" +#include "jaudio_NES/driverinterface.h" +#include "jaudio_NES/rate.h" +#include + +#define DSPCH_LENGTH (64) +static dspch_ DSPCH[DSPCH_LENGTH] ATTRIBUTE_ALIGN(32); + +static int old_time; +static u32 history[10] = { 0xF4240 }; + +/* + * --INFO-- + * Address: ........ + * Size: 000014 + */ +dspch_* GetDSPchannelHandle(u32 idx) +{ + return &DSPCH[idx]; + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000AD00 + * Size: 000060 + */ +void InitDSPchannel() +{ + dspch_* chan; + int i; + + for (i = 0; i < DSPCH_LENGTH; ++i) { + chan = &DSPCH[i]; + + chan->buffer_idx = i; + chan->_01 = 0; + chan->_08 = 0; + chan->_06 = 0; + chan->_0C = NULL; + chan->_03 = 0; + chan->_04 = 0; + } +} + +/* + * --INFO-- + * Address: 8000AD60 + * Size: 000114 + */ +dspch_* AllocDSPchannel(u32 param_1, u32 param_2) +{ + + s32 i; + u32* p2 = ¶m_2; + s32* ip = &i; + if (param_1 == 0) { + + for (i = 0; i < DSPCH_LENGTH; ++i) { + if (DSPCH[i]._01 == 0) { + DSPCH[i]._01 = TRUE; + DSPCH[i]._08 = (jc_*)param_2; + DSPCH[i]._03 = 1; + DSP_AllocInit(i); + return &DSPCH[i]; + } + } + return NULL; + } + + for (i = 1; i < DSPCH_LENGTH; i += 2) { + + if (DSPCH[i]._01 || DSPCH[i - 1]._01) + continue; + + DSPCH[i]._01 = 3; + DSPCH[i - 1]._01 = 2; + DSPCH[i]._08 = (jc_*)param_2; + DSPCH[i - 1]._08 = (jc_*)param_2; + DSP_AllocInit(i); + DSP_AllocInit(i - 1); + return &DSPCH[i - 1]; + } + return NULL; +} + +/* + * --INFO-- + * Address: 8000AE80 + * Size: 0000DC + */ +int DeAllocDSPchannel(dspch_* chan, u32 id) +{ + if (chan == NULL) { + return -1; + } + if (chan->_08 != (jc_*)id) { + return -2; + } + + switch (chan->_01) { + case 1: + case 4: + chan->_01 = 0; + break; + case 2: + chan->_01 = 0; + DeAllocDSPchannel(&DSPCH[chan->buffer_idx + 1], id); + break; + case 3: + chan->_01 = 0; + DeAllocDSPchannel(&DSPCH[chan->buffer_idx - 1], id); + break; + } + chan->_03 = 0; + chan->_0C = nullptr; + chan->_08 = 0; + return 0; +} + +/* + * --INFO-- + * Address: 8000AF60 + * Size: 000104 + */ +dspch_* GetLowerDSPchannel() +{ + u8 max = 255; + u32 id = 0; + u32 x = 0; + u32 i = 0; + u8* REF_max = &max; + u32* REF_id = &id; + u32* REF_x = &x; + u32* REF_i = &i; + + for (i; i < DSPCH_LENGTH; i++) { + if (DSPCH[i]._01 != 4) { + if (DSPCH[i]._01 == 0) { + DSPCH[i]._03 = 0; + id = i; + break; + } + + if (DSPCH[i]._0C) { + GetDspHandle(DSPCH[i].buffer_idx); + if (DSPCH[i]._03 <= max) { + DSPchannel_* buf = GetDspHandle(DSPCH[i].buffer_idx); + if (max != DSPCH[i]._03 || (x && (buf->_10C >= x || buf->_10C == 0))) { + x = buf->_10C; + id = i; + max = DSPCH[i]._03; + } + } + } + } + } + + return &DSPCH[id]; +} + +/* + * --INFO-- + * Address: 8000B080 + * Size: 0000D8 + */ +dspch_* GetLowerActiveDSPchannel() +{ + u8 a = 0xFF; + u32 index = 0; + u32 c = 0; + u32 i; + DSPchannel_* buf; + + u8* REF_a = &a; + u32* REF_index = &index; + u32* REF_c = &c; + + for (i = 0; i < DSPCH_LENGTH; ++i) { + if (DSPCH[i]._01 == 4 || DSPCH[i]._01 == 0) + continue; + + if (DSPCH[i]._03 > a) + continue; + + buf = GetDspHandle(DSPCH[i].buffer_idx); + if (a == DSPCH[i]._03) { + + if (c == 0) + continue; + if (buf->_10C < c && buf->_10C != 0) + continue; + } + c = buf->_10C; + index = i; + a = DSPCH[i]._03; + } + + return &DSPCH[index]; +} + +/* + * --INFO-- + * Address: 8000B160 + * Size: 00007C + */ +BOOL ForceStopDSPchannel(dspch_* chan) +{ + dspch_** REF_chan; + + DSPchannel_* buf; + + REF_chan = &chan; + if (chan->_01 == 4) + return FALSE; + buf = GetDspHandle(chan->buffer_idx); + if (!buf->enabled) + return FALSE; + buf->endRequested = DSP_TRUE; + chan->_01 = 4; + DSP_FlushChannel(chan->buffer_idx); + return TRUE; +} + +/* + * --INFO-- + * Address: 8000B1E0 + * Size: 0000AC + */ +BOOL BreakLowerDSPchannel(u8 param_1) +{ + u8* REF_param_1; + + dspch_* chan; + DSPchannel_* buf; + + chan = GetLowerDSPchannel(); + REF_param_1 = ¶m_1; + if (chan->_03 > param_1) + return FALSE; + if (chan->_03 == param_1) { + buf = GetDspHandle(chan->buffer_idx); // UNUSED?? + } + if (chan->_01) { + if (chan->_0C) { + chan->_06 = chan->_0C(chan, 3); + ForceStopDSPchannel(chan); + chan->_01 = 4; + } + ForceStopDSPchannel(chan); + } else { + return FALSE; + } + return TRUE; +} + +/* + * --INFO-- + * Address: 8000B2A0 + * Size: 0000AC + */ +BOOL BreakLowerActiveDSPchannel(u8 id) +{ + u8* id_ptr = &id; + dspch_* chan = GetLowerActiveDSPchannel(); + + if (chan->_03 > id) { + return FALSE; + } + + if (chan->_03 == id) { + GetDspHandle(chan->buffer_idx); + } + + if (chan->_01) { + if (chan->_0C) { + chan->_06 = chan->_0C(chan, 3); + ForceStopDSPchannel(chan); + chan->_01 = 4; + } + ForceStopDSPchannel(chan); + } else { + return FALSE; + } + + return TRUE; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +void UpdateDSPchannel(dspch_* chan) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000B360 + * Size: 0001F4 + */ +void UpdateDSPchannelAll() +{ + int tick = OSGetTick(); + u32 old = tick - old_time; + old_time = tick; + int id = JAC_SUBFRAMES - DspSyncCountCheck(); + history[id] = old; + + if (id != 0 && (f32)history[0] / (f32)old < 1.1f) { + BreakLowerActiveDSPchannel(0x7e); + } + + for (u32 i = 0; i < DSPCH_LENGTH; i++) { + dspch_* chan = &DSPCH[i]; + dspch_** chanptr = &chan; + + if (chan->_01 == FALSE) { + continue; + } + DSPchannel_* buf = GetDspHandle(chan->buffer_idx); + if (buf->done) { + if (chan->_0C) { + chan->_06 = chan->_0C(chan, 2); + } + buf->done = FALSE; + buf->enabled = FALSE; + DSP_FlushChannel(chan->buffer_idx); + if (chan->_01 == FALSE) { + continue; + } + } + + if (!buf->endRequested) { + buf->_10C++; + if (buf->_10C == chan->_04 && chan->_0C) { + chan->_06 = chan->_0C(chan, 4); + } + } + + if (chan->_0C) { + u16* ptr = &chan->_06; + u16 a = *ptr; + if (a) { + *ptr = a - 1; + } + if (*ptr == 0) { + *ptr = chan->_0C(chan, 0); + if (*ptr == 0) { + buf->done = FALSE; + buf->enabled = FALSE; + __Entry_WaitChannel(1); + DSP_FlushChannel(chan->buffer_idx); + } + } + } + } + EntryCheck_WaitDSPChannel(); + PPCSync(); +} diff --git a/src/static/jaudio_NES/internal/dspinterface.c b/src/static/jaudio_NES/internal/dspinterface.c new file mode 100644 index 00000000..39734b61 --- /dev/null +++ b/src/static/jaudio_NES/internal/dspinterface.c @@ -0,0 +1,479 @@ +#include "jaudio_NES/dspinterface.h" + +#include "dolphin/os.h" +#include "jaudio_NES/sample.h" +#include "jaudio_NES/dspproc.h" +#include "jaudio_NES/dspdriver.h" +#include "jaudio_NES/driverinterface.h" +#include "jaudio_NES/fxinterface.h" + +#include "limits.h" + +#define CH_BUF_LENGTH (64) +#define FX_BUF_LENGTH (4) + +static DSPchannel_ CH_BUF[CH_BUF_LENGTH]; +static FXBuffer FX_BUF[FX_BUF_LENGTH]; + +/* + * --INFO-- + * Address: 8000B560 + * Size: 000018 + */ +DSPchannel_* GetDspHandle(u8 idx) +{ + return &CH_BUF[idx]; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000034 + */ +DSPchannel_* GetDspHandleNc(u8) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000B580 + * Size: 000014 + */ +FXBuffer* GetFxHandle(u8 idx) +{ + return &FX_BUF[idx]; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000030 + */ +FXBuffer* GetFxHandleNc(u8 idx) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000B5A0 + * Size: 00002C + */ +void DSP_SetPitch(u8 idx, u16 pitch) +{ + DSPchannel_* buf = &CH_BUF[idx]; + if (pitch >= SHRT_MAX) + pitch = SHRT_MAX; + buf->resamplingRatio = pitch; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000050 + */ +void DSP_SetPitch_Indirect(u8 idx, f32, f32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000B5E0 + * Size: 000020 + */ +void DSP_SetMixerInitDelayMax(u8 idx, u8 initDelayMax) +{ + DSPchannel_* buf = &CH_BUF[idx]; + buf->samplesToKeepCount = initDelayMax; +} + +/* + * --INFO-- + * Address: 8000B600 + * Size: 00004C + */ +void DSP_SetMixerInitVolume(u8 idx, u8 mixer, s16 volume, u8 level) +{ + u8* REF_idx; + u8* REF_mixer; + + DSPchannel_* buf; + DSPMixerChannel* mixChan; + + REF_idx = &idx; + REF_mixer = &mixer; + + buf = &CH_BUF[idx]; + mixChan = &buf->mixChannels[mixer]; + + mixChan->currentVolume = volume; + mixChan->targetVolume = volume; + mixChan->level = (level << 8) | (level); +} + +/* + * --INFO-- + * Address: 8000B660 + * Size: 000044 + */ +void DSP_SetMixerVolume(u8 idx, u8 mixer, s16 volume, u8 param_4) +{ + DSPchannel_* buf = &CH_BUF[idx]; + DSPMixerChannel* mixChan = &buf->mixChannels[mixer]; + if (buf->endRequested) + return; + mixChan->targetVolume = volume; + mixChan->level = (param_4 << 8) | (mixChan->level & 0xff); +} + +/* + * --INFO-- + * Address: 8000B6C0 + * Size: 00002C + */ +void DSP_SetOscInfo(u8 idx, u32 samplesSourceType) +{ + DSPchannel_* buf = &CH_BUF[idx]; + buf->baseAddress = 0; + buf->afcRemainingDecodedSamples = 16; + buf->samplesSourceType = samplesSourceType; +} + +/* + * --INFO-- + * Address: 8000B700 + * Size: 000020 + */ +void DSP_SetPauseFlag(u8 idx, u8 pauseFlag) +{ + DSPchannel_* buf = &CH_BUF[idx]; + buf->useConstantSample = pauseFlag; +} + +/* + * --INFO-- + * Address: 8000B720 + * Size: 0000B0 + */ +void DSP_SetWaveInfo(u8 idx, Wave_* wave, u32 baseAddress) +{ + static u8 COMP_BLOCKSAMPLES[] = { + 0x10, 0x10, 0x01, 0x01, 0x01, 0x10, 0x10, 0x01, + }; + static u8 COMP_BLOCKBYTES[] = { + 0x09, 0x05, 0x08, 0x10, 0x01, 0x01, 0x01, 0x01, + }; + + DSPchannel_* buf = &CH_BUF[idx]; + + buf->baseAddress = baseAddress; + buf->afcRemainingDecodedSamples = COMP_BLOCKSAMPLES[wave->compBlockIdx]; + buf->samplesSourceType = COMP_BLOCKBYTES[wave->compBlockIdx]; + if (buf->samplesSourceType < 4) + return; + buf->_11C = wave->_1C; + buf->isLooping = wave->isLooping; + if (buf->isLooping) { + buf->loopAddress = wave->loopAddress; + buf->loopStartPosition = wave->loopStartPosition; + buf->loopYN1 = wave->loopYN1; + buf->loopYN2 = wave->loopYN2; + } else { + buf->loopStartPosition = buf->_11C; + } + for (int i = 0; i < 16; ++i) { + buf->afcRemainingSamples[i] = 0; + } +} + +/* + * --INFO-- + * Address: 8000B7E0 + * Size: 000038 + */ +void DSP_SetBusConnect(u8 idx, u8 mixer, u8 busConnect) +{ + static u16 connect_table[] = { + 0x0000, 0x0D00, 0x0D60, 0x0DC0, 0x0E20, 0x0E80, 0x0EE0, 0x0CA0, 0x0F40, 0x0FA0, 0x0B00, 0x09A0, + }; + + DSPchannel_* buf = &CH_BUF[idx]; + DSPMixerChannel* mixChan = &buf->mixChannels[mixer]; + mixChan->id = connect_table[busConnect]; +} + +/* + * --INFO-- + * Address: 8000B820 + * Size: 000020 + */ +void DSP_PlayStop(u8 idx) +{ + DSPchannel_* buf = &CH_BUF[idx]; + buf->enabled = DSP_FALSE; +} + +/* + * --INFO-- + * Address: 8000B840 + * Size: 000060 + */ +void DSP_AllocInit(u8 idx) +{ + DSPchannel_* buf = &CH_BUF[idx]; + buf->useConstantSample = DSP_FALSE; + buf->done = DSP_FALSE; + buf->endRequested = DSP_FALSE; + buf->enabled = DSP_FALSE; + DSP_InitFilter(idx); + DSP_FlushChannel(idx); +} + +/* + * --INFO-- + * Address: 8000B8A0 + * Size: 00007C + */ +void DSP_PlayStart(u8 idx) +{ + u32 i; + + DSPchannel_* buf = &CH_BUF[idx]; + buf->_10C = 0; + buf->currentPosition = 0; + buf->currentPosFrac = 0; + buf->resetVpb = DSP_TRUE; + buf->constantSample = 0; + for (i = 0; i < 4; ++i) { + buf->resampleBuffer[i] = 0; + buf->biquadHistory[i] = 0; + } + for (i = 0; i < 20; ++i) { + buf->variableFirHistory[i] = 0; + } + buf->enabled = DSP_TRUE; +} + +/* + * --INFO-- + * Address: 8000B920 + * Size: 00001C + */ +void DSP_SetDistFilter(u8 idx, s16 distFilter) +{ + DSPchannel_* buf = &CH_BUF[idx]; + buf->lowPassCoeff = distFilter; +} + +/* + * --INFO-- + * Address: 8000B940 + * Size: 000024 + */ +void DSP_SetFilterTable(s16* dst, s16* src, u32 len) +{ + for (int i = 0; i < len; ++i) { + *dst++ = *src++; + } +} + +/* + * --INFO-- + * Address: 8000B980 + * Size: 00003C + */ +void DSP_SetIIRFilterParam(u8 idx, s16* param_2) +{ + DSPchannel_* buf = &CH_BUF[idx]; + DSP_SetFilterTable(buf->biquadFilterCoeffs, param_2, 4); +} + +/* + * --INFO-- + * Address: 8000B9C0 + * Size: 00003C + */ +void DSP_SetFIR8FilterParam(u8 idx, s16* param_2) +{ + DSPchannel_* buf = &CH_BUF[idx]; + DSP_SetFilterTable(buf->variableFirCoeffs, param_2, 8); +} + +/* + * --INFO-- + * Address: 8000BA00 + * Size: 000054 + */ +void DSP_SetFilterMode(u8 idx, u16 filterMode) +{ + DSPchannel_* buf = &CH_BUF[idx]; + + u8 enableBiquadFilter = filterMode & 0b100000; + u8 variableFirFilterSize = filterMode & 0b011111; + if (enableBiquadFilter) { + if (variableFirFilterSize > 20) { + variableFirFilterSize = 20; + } + } else { + if (variableFirFilterSize > 24) { + variableFirFilterSize = 24; + } + } + buf->filterMode = enableBiquadFilter + variableFirFilterSize; +} + +/* + * --INFO-- + * Address: 8000BA60 + * Size: 000070 + */ +void DSP_InitFilter(u8 idx) +{ + int i; + DSPchannel_* buf = &CH_BUF[idx]; + + for (i = 0; i < 8; ++i) { + buf->variableFirCoeffs[i] = 0; + } + buf->variableFirCoeffs[0] = SHRT_MAX; + + for (i = 0; i < 4; ++i) { + buf->biquadFilterCoeffs[i] = 0; + } + buf->biquadFilterCoeffs[0] = SHRT_MAX; + + buf->lowPassCoeff = 0; +} + +/* + * --INFO-- + * Address: 8000BAE0 + * Size: 00003C + */ +void DSP_FlushBuffer() +{ + DCFlushRange(CH_BUF, sizeof(CH_BUF)); + DCFlushRange(FX_BUF, sizeof(FX_BUF)); +} + +/* + * --INFO-- + * Address: 8000BB20 + * Size: 000038 + */ +void DSP_FlushChannel(u8 idx) +{ + DCFlushRangeNoSync(&CH_BUF[idx], sizeof(DSPchannel_)); +} + +/* + * --INFO-- + * Address: ........ + * Size: 000038 + */ +void DSP_CacheChannel(u8 idx) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00002C + */ +void DSP_FlushChannelAll() +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00002C + */ +void DSP_CacheChannelAll() +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000BB60 + * Size: 00002C + */ +void DSP_InvalChannelAll() +{ + DCInvalidateRange(CH_BUF, sizeof(CH_BUF)); +} + +/* + * --INFO-- + * Address: 8000BBA0 + * Size: 000050 + */ +void DSP_ClearBuffer() +{ + for (int i = 0; i < CH_BUF_LENGTH; ++i) { + Jac_bzero(&CH_BUF[i], sizeof(DSPchannel_)); + } +} + +static u32 DSPADPCM_FILTER[] ATTRIBUTE_ALIGN(32) = { + 0x00000000, 0x08000000, 0x00000800, 0x04000400, 0x1000f800, 0x0e00fa00, 0x0c00fc00, 0x1200f600, + 0x1068f738, 0x12c0f704, 0x1400f400, 0x0800f800, 0x0400fc00, 0xfc000400, 0xfc000000, 0xf8000000, +}; + +static u32 DSPRES_FILTER[] ATTRIBUTE_ALIGN(32) = { + 0x0c3966ad, 0x0d46ffdf, 0x0b396696, 0x0e5fffd8, 0x0a446669, 0x0f83ffd0, 0x095a6626, 0x10b4ffc8, 0x087d65cd, 0x11f0ffbf, 0x07ab655e, + 0x1338ffb6, 0x06e464d9, 0x148cffac, 0x0628643f, 0x15ebffa1, 0x0577638f, 0x1756ff96, 0x04d162cb, 0x18cbff8a, 0x043561f3, 0x1a4cff7e, + 0x03a46106, 0x1bd7ff71, 0x031c6007, 0x1d6cff64, 0x029f5ef5, 0x1f0bff56, 0x022a5dd0, 0x20b3ff48, 0x01be5c9a, 0x2264ff3a, 0x015b5b53, + 0x241eff2c, 0x010159fc, 0x25e0ff1e, 0x00ae5896, 0x27a9ff10, 0x00635720, 0x297aff02, 0x001f559d, 0x2b50fef4, 0xffe2540d, 0x2d2cfee8, + 0xffac5270, 0x2f0dfedb, 0xff7c50c7, 0x30f3fed0, 0xff534f14, 0x32dcfec6, 0xff2e4d57, 0x34c8febd, 0xff0f4b91, 0x36b6feb6, 0xfef549c2, + 0x38a5feb0, 0xfedf47ed, 0x3a95feac, 0xfece4611, 0x3c85feab, 0xfec04430, 0x3e74feac, 0xfeb6424a, 0x4060feaf, 0xfeaf4060, 0x424afeb6, + 0xfeac3e74, 0x4430fec0, 0xfeab3c85, 0x4611fece, 0xfeac3a95, 0x47edfedf, 0xfeb038a5, 0x49c2fef5, 0xfeb636b6, 0x4b91ff0f, 0xfebd34c8, + 0x4d57ff2e, 0xfec632dc, 0x4f14ff53, 0xfed030f3, 0x50c7ff7c, 0xfedb2f0d, 0x5270ffac, 0xfee82d2c, 0x540dffe2, 0xfef42b50, 0x559d001f, + 0xff02297a, 0x57200063, 0xff1027a9, 0x589600ae, 0xff1e25e0, 0x59fc0101, 0xff2c241e, 0x5b53015b, 0xff3a2264, 0x5c9a01be, 0xff4820b3, + 0x5dd0022a, 0xff561f0b, 0x5ef5029f, 0xff641d6c, 0x6007031c, 0xff711bd7, 0x610603a4, 0xff7e1a4c, 0x61f30435, 0xff8a18cb, 0x62cb04d1, + 0xff961756, 0x638f0577, 0xffa115eb, 0x643f0628, 0xffac148c, 0x64d906e4, 0xffb61338, 0x655e07ab, 0xffbf11f0, 0x65cd087d, 0xffc810b4, + 0x6626095a, 0xffd00f83, 0x66690a44, 0xffd80e5f, 0x66960b39, 0xffdf0d46, 0x66ad0c39, 0x00000c8b, 0x18f82527, 0x30fb3c56, 0x471c5133, + 0x5a8262f1, 0x6a6d70e2, 0x76417a7c, 0x7d897f61, 0x7fff7f61, 0x7d897a7c, 0x764170e2, 0x6a6d62f1, 0x5a825133, 0x471c3c56, 0x30fb2527, + 0x18f80c8b, 0x0000f375, 0xe708dad9, 0xcf05c3aa, 0xb8e4aecd, 0xa57e9d0f, 0x95938f1e, 0x89bf8584, 0x8277809f, 0x8001809f, 0x82778584, + 0x89bf8f1e, 0x95939d0f, 0xa57eaecd, 0xb8e4c3aa, 0xcf05dad9, 0xe708f375, 0x000007ff, 0x0fff17ff, 0x1fff27ff, 0x2fff37ff, 0x3fff47ff, + 0x4fff57ff, 0x5fff67ff, 0x6fff77ff, 0x7fff7800, 0x70006800, 0x60005800, 0x50004800, 0x40003800, 0x30002800, 0x20001800, 0x10000800, + 0x0000f801, 0xf001e801, 0xe001d801, 0xd001c801, 0xc001b801, 0xb001a801, 0xa0019801, 0x90018801, 0x80018800, 0x90009800, 0xa000a800, + 0xb000b800, 0xc000c800, 0xd000d800, 0xe000e800, 0xf000f800, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x1fff3fff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x1fffc001, +}; + +/* + * --INFO-- + * Address: 8000BC00 + * Size: 000044 + */ +void DSP_SetupBuffer() +{ + DsetupTable((u32)CH_BUF_LENGTH, (u32)CH_BUF, (u32)DSPRES_FILTER, (u32)DSPADPCM_FILTER, (u32)FX_BUF); +} + +/* + * --INFO-- + * Address: 8000BC60 + * Size: 000058 + */ +void DSP_InitBuffer() +{ + for (int i = 0; i < 4; ++i) + DFX_SetFxLine(i, NULL, NULL); + DSP_ClearBuffer(); + DSP_SetupBuffer(); + InitDSPchannel(); + InitGlobalChannel(); + DSP_FlushBuffer(); +} diff --git a/src/static/jaudio_NES/internal/dummyrom.c b/src/static/jaudio_NES/internal/dummyrom.c index a6c979b5..9a16c9d9 100644 --- a/src/static/jaudio_NES/internal/dummyrom.c +++ b/src/static/jaudio_NES/internal/dummyrom.c @@ -57,11 +57,11 @@ extern void Jac_SetAudioARAMSize(u32 size) { SELECTED_ARAM_SIZE = size; } -extern void ARAllocFull(u32* outSize) { +extern void* ARAllocFull(u32* outSize) { u32 freeSize = aram_hp.length - ((int)aram_hp.current - (int)aram_hp.base); - - Nas_HeapAlloc(&aram_hp, freeSize - 32); + void* alloc = Nas_HeapAlloc(&aram_hp, freeSize - 32); *outSize = freeSize - 32; + return alloc; } extern void Jac_InitARAM(u32 loadAudiorom) { diff --git a/src/static/jaudio_NES/internal/fat.c b/src/static/jaudio_NES/internal/fat.c new file mode 100644 index 00000000..6822bd12 --- /dev/null +++ b/src/static/jaudio_NES/internal/fat.c @@ -0,0 +1,415 @@ +#include "jaudio_NES/fat.h" +#include "jaudio_NES/aictrl.h" +#include "jaudio_NES/sample.h" + +static int ACTIVE_FATS; +static int USEFAT_TAIL; +static u8* fatheapptr; + +typedef struct FATEntry FATEntry; + +struct FATEntry { + u16 ownerHandle; // _00 + u16 blockSize; // _02 + u8* addr; // _04 +}; + +#define FAT_SIZE (256) + +static struct FAT_info2 { + u16 startBlock; // _00 + u16 blockCount; // _02 +} FH_TO_FAT[FAT_SIZE]; + +static FATEntry FAT[FAT_SIZE]; + +// havent figured this out yet +static struct FATEntry fattmp[FAT_SIZE]; + +/* + * --INFO-- + * Address: 8000DDE0 + * Size: 000044 + */ +void Jac_FatMemory_Init(u32 size) +{ + fatheapptr = (u8*)OSAlloc2(size); + + if (fatheapptr) { + FAT_InitSystem(fatheapptr, size); + } +} + +/* + * --INFO-- + * Address: 8000DE40 + * Size: 0000BC + */ +void FAT_InitSystem(u8* heap, u32 size) +{ + u32 i; + + int fats = 0; + for (i = 0; i < FAT_SIZE; i++) { + if (size < 0x1000) { + break; + } + + size -= 0x1000; + FAT[i].addr = heap; + fats++; + heap += 0x1000; + + FAT[i].blockSize = 0x1000; + FAT[i].ownerHandle = 0xffff; + } + + ACTIVE_FATS = fats; + USEFAT_TAIL = 0; + + for (i = ACTIVE_FATS; i < FAT_SIZE; i++) { + FAT[i].ownerHandle = 0xffff; + FAT[i].blockSize = 0; + } + + for (i = 0; i < FAT_SIZE; i++) { + FH_TO_FAT[i].startBlock = -1; + FH_TO_FAT[i].blockCount = 0; + } +} + +/* + * --INFO-- + * Address: 8000DF00 + * Size: 0000D4 + */ +int FAT_AllocateMemory(u32 size) +{ + u32 a = 0; + + for (int i = 0; i < FAT_SIZE; i++) { + if (FH_TO_FAT[i].blockCount == 0) { + break; + } + a++; + } + + if (a == FAT_SIZE) { + return 0xffff; + } + u16 res = a; + + if (size == 0) { + return 0xffff; + } + + int b = size + 0xfff >> 0xc; + if (ACTIVE_FATS - USEFAT_TAIL < b) { + return 0xffff; + } + + for (u32 i = USEFAT_TAIL; i < USEFAT_TAIL + b; i++) { + FAT[i].ownerHandle = res; + } + + FH_TO_FAT[res].startBlock = USEFAT_TAIL; + FH_TO_FAT[res].blockCount = b; + + USEFAT_TAIL += b; + return res; +} + +/* + * --INFO-- + * Address: 8000DFE0 + * Size: 000190 + */ +int FAT_FreeMemory(u16 size) +{ + u16 temp; + u32 i; + u32 start; + u16 size2; + u32 count; + u16 tail; + + count = FH_TO_FAT[size].blockCount; + start = FH_TO_FAT[size].startBlock; + FH_TO_FAT[size].blockCount = 0; + size2 = start + count; + tail = USEFAT_TAIL - size2; + + if (tail == 0) { + USEFAT_TAIL -= count; + for (i = 0; i < count; i++) { + FAT[USEFAT_TAIL + i].ownerHandle = 0xffff; + } + return 0; + } + + for (i = 0; i < count; i++) { + fattmp[i] = FAT[start + i]; + + fattmp[i].ownerHandle = 0xffff; + } + + temp = 0xffff; + for (i = 0; i < tail; i++) { + FAT[start + i] = FAT[size2 + i]; + if (FAT[size2 + i].ownerHandle != temp) { + FH_TO_FAT[FAT[size2 + i].ownerHandle].startBlock = start + i; + temp = FAT[size2 + i].ownerHandle; + } + } + + USEFAT_TAIL -= count; + for (i = 0; i < count; i++) { + FAT[USEFAT_TAIL + i] = fattmp[i]; + } + return 0; + /* + .loc_0x0: + stwu r1, -0x20(r1) + lis r4, 0x8031 + subi r4, r4, 0x2118 + rlwinm r0,r3,2,14,29 + stmw r30, 0x18(r1) + add r3, r4, r0 + li r11, 0 + lhzx r0, r4, r0 + lhz r5, 0x2(r3) + sth r11, 0x2(r3) + add r3, r0, r5 + rlwinm r3,r3,0,16,31 + lwz r6, 0x2BF4(r13) + sub r7, r6, r3 + rlwinm. r30,r7,0,16,31 + bne- .loc_0x84 + sub r0, r6, r5 + lis r3, 0x1 + stw r0, 0x2BF4(r13) + subi r6, r3, 0x1 + li r8, 0 + lwz r7, 0x2BF4(r13) + mtctr r5 + cmplwi r5, 0 + ble- .loc_0x7C + + .loc_0x64: + add r0, r7, r8 + addi r8, r8, 0x1 + rlwinm r0,r0,3,0,28 + add r3, r4, r0 + sth r6, 0x400(r3) + bdnz+ .loc_0x64 + + .loc_0x7C: + li r3, 0 + b .loc_0x184 + + .loc_0x84: + lis r7, 0x1 + addi r6, r11, 0 + subi r7, r7, 0x1 + mtctr r5 + cmplwi r5, 0 + ble- .loc_0xCC + + .loc_0x9C: + add r8, r0, r11 + add r10, r4, r6 + rlwinm r8,r8,3,0,28 + addi r11, r11, 0x1 + add r8, r4, r8 + addi r6, r6, 0x8 + lwz r9, 0x400(r8) + lwz r8, 0x404(r8) + stw r9, 0xC00(r10) + stw r8, 0xC04(r10) + sth r7, 0xC00(r10) + bdnz+ .loc_0x9C + + .loc_0xCC: + lis r6, 0x1 + li r12, 0 + subi r31, r6, 0x1 + mtctr r30 + cmplwi r30, 0 + ble- .loc_0x130 + + .loc_0xE4: + add r6, r3, r12 + add r11, r0, r12 + rlwinm r7,r6,3,0,28 + rlwinm r6,r11,3,0,28 + add r10, r4, r7 + add r9, r4, r6 + lwz r8, 0x400(r10) + rlwinm r6,r31,0,16,31 + lwz r7, 0x404(r10) + stw r8, 0x400(r9) + stw r7, 0x404(r9) + lhz r7, 0x400(r10) + cmplw r6, r7 + beq- .loc_0x128 + rlwinm r6,r7,2,0,29 + mr r31, r7 + sthx r11, r4, r6 + + .loc_0x128: + addi r12, r12, 0x1 + bdnz+ .loc_0xE4 + + .loc_0x130: + lwz r0, 0x2BF4(r13) + li r9, 0 + li r3, 0 + sub r0, r0, r5 + stw r0, 0x2BF4(r13) + lwz r8, 0x2BF4(r13) + mtctr r5 + cmplwi r5, 0 + ble- .loc_0x180 + + .loc_0x154: + add r7, r4, r3 + add r0, r8, r9 + rlwinm r6,r0,3,0,28 + lwz r5, 0xC00(r7) + lwz r0, 0xC04(r7) + add r6, r4, r6 + addi r9, r9, 0x1 + addi r3, r3, 0x8 + stw r5, 0x400(r6) + stw r0, 0x404(r6) + bdnz+ .loc_0x154 + + .loc_0x180: + li r3, 0 + + .loc_0x184: + lmw r30, 0x18(r1) + addi r1, r1, 0x20 + blr + */ +} + +/* + * --INFO-- + * Address: 8000E180 + * Size: 000048 + */ +u8* FAT_GetPointer(u16 a, u32 b) +{ + u32 c = b >> 12; + if (FH_TO_FAT[a].blockCount <= c) { + return 0; + } + + b &= 0xFFF; + return FAT[c + FH_TO_FAT[a].startBlock].addr + b; +} + +/* + * --INFO-- + * Address: 8000E1E0 + * Size: 000034 + */ +u8 FAT_ReadByte(u16 a, u32 b) +{ + u8* ptr = FAT_GetPointer(a, b); + if (ptr == NULL) { + return 0; + } + return *ptr; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000034 + */ +u16 FAT_ReadWord(u16 a, u32 b) +{ + // Guessing based on name/size + + u16* ptr = (u16*)FAT_GetPointer(a, b); + if (ptr == NULL) { + return 0; + } + return *ptr; + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000050 + */ +void FAT_ReadWordD(u16 a, u32 b) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000024 + */ +u32 FAT_ReadLong(u16 a, u32 b) +{ + // UNUSED FUNCTION + + // Guessing based on name/size + return *(u32*)FAT_GetPointer(a, b); +} + +/* + * --INFO-- + * Address: ........ + * Size: 000080 + */ +void FAT_ReadLongD(u16 a1, u32 a2) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000E220 + * Size: 0000E0 + */ +int FAT_StoreBlock(u8* ptr, u16 a, u32 b, u32 c) +{ + u8* ptr2 = FAT_GetPointer(a, b); + + int size = b; + b &= 0xFFF; + size -= b; + // this whole thing is wrong + while (c != 0) { + b++; + *ptr2++ = *ptr++; + c--; + + if (b == 0x1000) { + size += 0x1000; + + ptr2 = FAT_GetPointer(a, size); + break; + } + } + + for (; 0x1000 <= c;) { + Jac_bcopy(ptr, ptr2, 0x1000); + size += 0x1000; + c -= 0x1000; + ptr += 0x1000; + ptr2 = FAT_GetPointer(a, size); + } + + if (c != 0) { + Jac_bcopy(ptr, ptr2, c); + } + return 0; +} diff --git a/src/static/jaudio_NES/internal/fxinterface.c b/src/static/jaudio_NES/internal/fxinterface.c new file mode 100644 index 00000000..b09bae01 --- /dev/null +++ b/src/static/jaudio_NES/internal/fxinterface.c @@ -0,0 +1,62 @@ +#include "jaudio_NES/fxinterface.h" + +#include "dolphin/os.h" +#include "jaudio_NES/sample.h" + +static u16 SEND_TABLE[] = { + 0x0D00, 0x0D60, 0x0DC0, 0x0E20, 0x0E80, 0x0EE0, 0x0CA0, 0x0F40, 0x0FA0, 0x0B00, 0x09A0, 0x0000, +}; + +/* + * --INFO-- + * Address: 8000BCC0 + * Size: 000138 + */ +BOOL DFX_SetFxLine(u8 idx, s16* circularBufferBase, FxlineConfig* config) +{ + s16** REF_circularBufferBase; + + FXBuffer* buf; + BOOL restoreInterrupts; + + restoreInterrupts = OSDisableInterrupts(); + buf = GetFxHandle(idx); + + buf->enabled = DSP_FALSE; + if (config) { + buf->dest[0].volume = config->volume0; + buf->dest[0].bufferId = SEND_TABLE[config->sendIdx0]; + buf->dest[1].volume = config->volume1; + buf->dest[1].bufferId = SEND_TABLE[config->sendIdx1]; + buf->circularBufferSize = config->circularBufferSize; + DSP_SetFilterTable(buf->filterCoeffs, config->filterCoeffs, 8); + } + REF_circularBufferBase = &circularBufferBase; + if (circularBufferBase && config) { + int size = config->circularBufferSize * 0xa0; // TODO: What is 160 bytes large? + + buf->circularBufferBase = circularBufferBase; + Jac_bzero(circularBufferBase, size); + DCFlushRange(circularBufferBase, size); + } else if (!config || circularBufferBase) { + buf->circularBufferBase = circularBufferBase; + } + if (buf->circularBufferBase) { + buf->enabled = config->enabled; + } else { + buf->enabled = DSP_FALSE; + } + DCFlushRange(buf, sizeof(FXBuffer)); + OSRestoreInterrupts(restoreInterrupts); + return TRUE; +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000E0 + */ +void DFX_ChangeFxLineParam(u8, u8, u32) +{ + // UNUSED FUNCTION +} diff --git a/src/static/jaudio_NES/internal/heapctrl.c b/src/static/jaudio_NES/internal/heapctrl.c new file mode 100644 index 00000000..c00a21a4 --- /dev/null +++ b/src/static/jaudio_NES/internal/heapctrl.c @@ -0,0 +1,568 @@ +#include "jaudio_NES/heapctrl.h" + +#include "jaudio_NES/dummyrom.h" + +#include "dolphin/os/OSMessage.h" +#include "dolphin/ar.h" +#include "dolphin/os/OSCache.h" + +#define DMABUFFER_SIZE (0x10000) +static u8 dmabuffer[DMABUFFER_SIZE] ATTRIBUTE_ALIGN(32); + +static u32 global_id = 0; + +/* + * --INFO-- + * Address: 8000E9C0 + * Size: 000034 + */ +static void ARAMFinish(u32 msg) +{ + // STACK_PAD_VAR(1); + u32* REF_param_1; + + REF_param_1 = &msg; + ARQRequest* request = (ARQRequest*)msg; + OSSendMessage((OSMessageQueue*)request->owner, (OSMessage)1, OS_MESSAGE_BLOCK); +} + +/* + * --INFO-- + * Address: 8000EA00 + * Size: 0000E8 + */ +static void ARAM_TO_ARAM_DMA(u32 src, u32 dst, u32 totalSize) +{ + ARQRequest request; + OSMessageQueue msgQueue; + OSMessage msg; + u32 burstSize; + + OSInitMessageQueue(&msgQueue, &msg, 1); + while (totalSize != 0) { + burstSize = totalSize >= DMABUFFER_SIZE ? DMABUFFER_SIZE : totalSize; + + ARQPostRequest(&request, (u32)&msgQueue, ARQ_TYPE_ARAM_TO_MRAM, ARQ_PRIORITY_LOW, src, (u32)dmabuffer, burstSize, &ARAMFinish); + OSReceiveMessage(&msgQueue, NULL, OS_MESSAGE_BLOCK); + ARQPostRequest(&request, (u32)&msgQueue, ARQ_TYPE_MRAM_TO_ARAM, ARQ_PRIORITY_LOW, (u32)dmabuffer, dst, burstSize, &ARAMFinish); + OSReceiveMessage(&msgQueue, NULL, OS_MESSAGE_BLOCK); + + totalSize -= burstSize; + src += burstSize; + dst += burstSize; + } +} + +/* + * --INFO-- + * Address: 8000EB00 + * Size: 0000FC + */ +static void DRAM_TO_DRAM_DMA(u32 src, u32 dst, u32 totalSize) +{ + ARQRequest request; + OSMessageQueue msgQueue; + OSMessage msg; + u32 dma_buffer_top; + u32 burstSize; + + dma_buffer_top = (u32)JAC_ARAM_DMA_BUFFER_TOP; + OSInitMessageQueue(&msgQueue, &msg, 1); + DCFlushRange((void*)src, totalSize); + DCInvalidateRange((void*)dst, totalSize); + while (totalSize != 0) { + burstSize = totalSize >= DMABUFFER_SIZE ? DMABUFFER_SIZE : totalSize; + + ARQPostRequest(&request, (u32)&msgQueue, ARQ_TYPE_MRAM_TO_ARAM, ARQ_PRIORITY_LOW, src, dma_buffer_top, burstSize, &ARAMFinish); + OSReceiveMessage(&msgQueue, NULL, OS_MESSAGE_BLOCK); + ARQPostRequest(&request, (u32)&msgQueue, ARQ_TYPE_ARAM_TO_MRAM, ARQ_PRIORITY_LOW, dma_buffer_top, dst, burstSize, &ARAMFinish); + OSReceiveMessage(&msgQueue, NULL, OS_MESSAGE_BLOCK); + + totalSize -= burstSize; + src += burstSize; + dst += burstSize; + } +} + +/* + * --INFO-- + * Address: ........ + * Size: 00002C + */ +void Jac_GetUnlockHeap(jaheap_*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00001C + */ +void Jac_CheckAlloc(jaheap_*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000EC00 + * Size: 000044 + */ +void Jac_InitHeap(jaheap_* heap) +{ + heap->startAddress = 0; + heap->usedSize = 0; + heap->size = 0; + heap->heapId = global_id++; + heap->isRootHeap = 0; + heap->childCount = 0; + heap->firstChild = 0; + heap->parent = NULL; + heap->nextSibling = 0; + heap->groupOwner = 0; + heap->firstGroupedHeap = 0; + heap->nextGroupedHeap = 0; +} + +/* + * --INFO-- + * Address: 8000EC60 + * Size: 000038 + */ +void Jac_SelfInitHeap(jaheap_* heap, u32 startAddr, u32 size, u32 memType) +{ + heap->startAddress = startAddr; + heap->size = size; + heap->usedSize = 0; + heap->isRootHeap = 0; + heap->memoryType = memType; + heap->childCount = 0; + heap->firstChild = NULL; + heap->parent = NULL; + heap->nextSibling = 0; + heap->groupOwner = 0; + heap->firstGroupedHeap = 0; + heap->nextGroupedHeap = 0; +} + +/* + * --INFO-- + * Address: 8000ECA0 + * Size: 000100 + */ +BOOL Jac_SelfAllocHeap(jaheap_* parent, jaheap_* heap, u32 size, u32 startAddr) +{ + if (parent->startAddress && parent->startAddress != -1) { + return FALSE; + } + + parent->startAddress = startAddr; + parent->size = size; + parent->usedSize = 0; + parent->isRootHeap = 0; + parent->memoryType = heap->memoryType; + parent->childCount = 0; + parent->firstChild = nullptr; + parent->parent = heap; + + jaheap_* temp = heap->firstChild; + if (temp == NULL) { + heap->firstChild = parent; + parent->nextSibling = nullptr; + heap->usedSize = parent->startAddress - heap->startAddress + parent->size; + } else { + jaheap_* temp2 = heap->firstChild; + if (parent->startAddress < heap->firstChild->startAddress) { + parent->nextSibling = heap->firstChild; + heap->firstChild = parent; + } else { + while (TRUE) { + if (!(temp = temp2->nextSibling)) { + parent->nextSibling = NULL; + temp2->nextSibling = parent; + heap->usedSize = parent->startAddress - heap->startAddress + parent->size; + break; + } + if (parent->startAddress < temp->startAddress) { + parent->nextSibling = temp; + temp2->nextSibling = parent; + break; + } + temp2 = temp; + } + } + } + + heap->childCount++; + return TRUE; +} + +/* + * --INFO-- + * Address: 8000EDA0 + * Size: 000038 + */ +BOOL Jac_SetGroupHeap(jaheap_* heapA, jaheap_* heapB) +{ + if (heapA->groupOwner || heapA->nextGroupedHeap) { + return FALSE; + } + + heapA->groupOwner = heapB; + heapA->nextGroupedHeap = heapB->firstGroupedHeap; + heapB->firstGroupedHeap = heapA; + return TRUE; +} + +/* + * --INFO-- + * Address: ........ + * Size: 00000C + */ +void Jac_CutdownHeap(jaheap_*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000EDE0 + * Size: 00005C + */ +void Jac_InitMotherHeap(jaheap_* heap, u32 startAddr, u32 size, u8 memType) +{ + heap->startAddress = startAddr + 0x1f & 0xffffffe0; + heap->usedSize = 0; + heap->size = size - (startAddr & 0x1f); + heap->heapId = global_id++; + heap->isRootHeap = 1; + heap->memoryType = memType; + heap->childCount = 0; + heap->firstChild = NULL; + heap->parent = NULL; + heap->nextSibling = NULL; + heap->groupOwner = NULL; + heap->firstGroupedHeap = NULL; + heap->nextGroupedHeap = NULL; +} + +/* + * --INFO-- + * Address: 8000EE40 + * Size: 0001B4 + */ +BOOL Jac_AllocHeap(jaheap_* heap, jaheap_* parent, u32 size) +{ + u32 y; + jaheap_* temp; + jaheap_* temp2; + jaheap_* temp3; + jaheap_* result; + u32 t; + u32 max; + u32 x; + + u32 fixedSize = OSRoundUp32B(size); + + if (parent->startAddress == 0) { + return FALSE; + } + + if (heap->startAddress && heap->startAddress != -1) { + return FALSE; + } + + if (parent->size - parent->usedSize < fixedSize) { + temp = parent->firstChild; + y = parent->startAddress; + result = NULL; + max = 0xfffffff; + while (TRUE) { + if (temp == NULL) { + break; + } + x = temp->startAddress - y; + if (x >= fixedSize) { + x -= fixedSize; + + if (x < max) { + result = temp; + t = y; + max = x; + } + } + + y = temp->startAddress + temp->size; + temp = temp->nextSibling; + } + + if (result == 0) { + return FALSE; + } + + if (result == parent->firstChild) { + heap->nextSibling = parent->firstChild; + parent->firstChild = heap; + } else { + temp3 = parent->firstChild; + while (TRUE) { + if (temp3->nextSibling == result) { + heap->nextSibling = temp3->nextSibling; + temp3->nextSibling = heap; + break; + } + temp3 = temp3->nextSibling; + } + } + + heap->startAddress = t; + heap->size = fixedSize; + heap->usedSize = 0; + heap->isRootHeap = 0; + heap->memoryType = parent->memoryType; + heap->childCount = 0; + heap->firstChild = NULL; + heap->parent = parent; + parent->childCount++; + return TRUE; + } + + heap->startAddress = parent->startAddress + parent->usedSize; + heap->size = fixedSize; + heap->usedSize = 0; + heap->isRootHeap = 0; + heap->memoryType = parent->memoryType; + heap->childCount = 0; + heap->firstChild = NULL; + heap->parent = parent; + + temp2 = parent->firstChild; + !temp2; + if (temp2 == NULL) { + parent->firstChild = heap; + heap->nextSibling = NULL; + } else { + while (TRUE) { + if (temp2->nextSibling == NULL) { + temp2->nextSibling = heap; + break; + } + temp2 = temp2->nextSibling; + } + } + + heap->nextSibling = NULL; + parent->usedSize += fixedSize; + parent->childCount++; + return TRUE; +} + +/* + * --INFO-- + * Address: 8000F000 + * Size: 0001B0 + */ +BOOL Jac_DeleteHeap(jaheap_* heap) +{ + // STACK_PAD_VAR(4); + jaheap_** pt = &heap; + + if (heap->startAddress == 0) { + return FALSE; + } + + jaheap_* heap2 = heap->firstChild; + while (heap2) { + jaheap_* next = heap2->nextSibling; + Jac_DeleteHeap(heap2); + heap2 = next; + } + + heap->firstChild = NULL; + + heap2 = heap->firstGroupedHeap; + while (heap2) { + jaheap_* next = heap2->nextGroupedHeap; + Jac_DeleteHeap(heap2); + heap2 = next; + } + + heap->firstGroupedHeap = NULL; + + if (heap->parent) { + heap2 = heap->parent->firstChild; + if (heap2 == heap) { + heap->parent->firstChild = heap->nextSibling; + if (heap->nextSibling == NULL) { + heap->parent->usedSize = NULL; + } + } else { + while (TRUE) { + if (heap2 == NULL) { + heap->startAddress = 0; + return FALSE; + } + + if (heap2->nextSibling == heap) { + heap2->nextSibling = heap->nextSibling; + if (heap->nextSibling == NULL) { + heap->parent->usedSize = heap2->startAddress + heap2->size - heap->parent->startAddress; + } + break; + } + + heap2 = heap2->nextSibling; + } + } + + heap->parent->childCount--; + } + + if (heap->groupOwner) { + heap2 = heap->groupOwner->firstGroupedHeap; + + if (heap2 == heap) { + heap->groupOwner->firstGroupedHeap = heap->nextGroupedHeap; + } else { + while (TRUE) { + if (heap2 == NULL) { + return FALSE; + } + + if (heap2->nextGroupedHeap == heap) { + heap2->nextGroupedHeap = heap->nextGroupedHeap; + break; + } + + heap2 = heap2->nextGroupedHeap; + } + } + + heap->groupOwner = NULL; + heap->nextGroupedHeap = NULL; + } + + heap->startAddress = 0; + return TRUE; +} + +/* + * --INFO-- + * Address: 8000F1C0 + * Size: 000064 + */ +static void Jac_Move_Children(jaheap_* heap, s32 flag) +{ + if (flag == 0) { + return; + } + + for (jaheap_* c = heap->firstChild;; c = c->nextSibling) { + if (c == NULL) { + break; + } + + c->startAddress += flag; + if (c->firstChild) { + Jac_Move_Children(c, flag); + } + } +} + +/* + * --INFO-- + * Address: 8000F240 + * Size: 0000C8 + */ +void Jac_GarbageCollection_St(jaheap_* heap) +{ + jaheap_* heap_00; + u32 src; + u32 dst; + + dst = heap->startAddress; + heap_00 = heap->firstChild; + + if (heap_00 == NULL) { + heap->usedSize = 0; + return; + } + + do { + src = heap_00->startAddress; + if (dst != src) { + switch (heap->memoryType) { + case 0: + ARAM_TO_ARAM_DMA(src, dst, heap_00->size); + break; + case 1: + DRAM_TO_DRAM_DMA(src, dst, heap_00->size); + break; + } + Jac_Move_Children(heap_00, dst - heap_00->startAddress); + heap_00->startAddress = dst; + } + dst = heap_00->startAddress + heap_00->size; + } while (heap_00 = heap_00->nextSibling); + + heap->usedSize = dst - heap->startAddress; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000058 + */ +void Jac_CheckFreeHeap_Total(jaheap_*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00005C + */ +void Jac_CheckFreeHeap_Linear(jaheap_*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000F320 + * Size: 0000C4 + */ +void Jac_ShowHeap(jaheap_* heap, u32 flag) +{ + jaheap_** REF_heap = &heap; + jaheap_* c; + jaheap_** REF_c; + + // STACK_PAD_VAR(3); + char unused[] = " "; + (void*)unused[0]; + + c = heap->firstChild; + REF_c = &c; + // STACK_PAD_VAR(15); + if (c) { + do { + if (c->firstChild) { + Jac_ShowHeap(c, flag + 1); + } + c = c->nextSibling; + } while (c); + } + + jaheap_* c2; + if (c2 = heap->firstGroupedHeap) { + do { + if (c2->firstGroupedHeap) { + Jac_ShowHeap(c2, flag + 1); + } + c2 = c2->nextGroupedHeap; + } while (c2); + } +} diff --git a/src/static/jaudio_NES/internal/ipldec.c b/src/static/jaudio_NES/internal/ipldec.c new file mode 100644 index 00000000..808ae216 --- /dev/null +++ b/src/static/jaudio_NES/internal/ipldec.c @@ -0,0 +1,113 @@ +#include "jaudio_NES/ipldec.h" +#include "jaudio_NES/audiostruct.h" +#include "jaudio_NES/dspproc.h" + +DSPTask EX_DSPTASK[4]; + +static u8 TASK_READPTR; +static u8 TASK_WRITEPTR; +static u8 TASK_REMAIN; + +/* + * --INFO-- + * Address: 80008A00 + * Size: 000070 + */ +static DSPTask* WriteTask(u8 target, u32 cmd, void* task, DSPCallback callback) +{ + if (TASK_REMAIN == 4) { + return NULL; + } + + DSPTask* dspTask = &EX_DSPTASK[TASK_WRITEPTR]; + dspTask->target = target; + dspTask->cmd = cmd; + dspTask->task = task; + dspTask->callback = callback; + + TASK_WRITEPTR++; + if (TASK_WRITEPTR == 4) { + TASK_WRITEPTR = 0; + } + + TASK_REMAIN++; + return EX_DSPTASK; +} + +/* + * --INFO-- + * Address: 80008A80 + * Size: 0000C0 + */ +static void DoTask() +{ + + while (TASK_REMAIN != 0) { + DSPTask* dspTask = &EX_DSPTASK[TASK_READPTR]; + void* task = dspTask->task; + u32 cmd = dspTask->cmd; + DSPCallback cb = dspTask->callback; + switch (dspTask->target) { + case DSPTARGET_IPL: + DiplSec(cmd); + break; + case DSPTARGET_AGB: + DagbSec(cmd); + break; + } + + if (cb) { + cb(task); + } + + TASK_READPTR++; + if (TASK_READPTR == 4) { + TASK_READPTR = 0; + } + + TASK_REMAIN--; + } +} + +/* + * --INFO-- + * Address: 80008B40 + * Size: 000024 + */ +BOOL DspExtraTaskCheck() +{ + DoTask(); + return TRUE; +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000A8 + */ +void Jac_IPLDspSec(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 80008B80 + * Size: 00004C + */ +void Jac_DSPcardDecodeAsync(void* task, void* cmd, DSPCallback callback) +{ + while (WriteTask(DSPTARGET_IPL, (u32)cmd, task, callback) == NULL) { + ; + } +} + +/* + * --INFO-- + * Address: ........ + * Size: 00004C + */ +void Jac_DSPagbDecodeAsync(void*, void*, void (*)(void*)) +{ + // UNUSED FUNCTION +} diff --git a/src/static/jaudio_NES/internal/ja_calc.c b/src/static/jaudio_NES/internal/ja_calc.c new file mode 100644 index 00000000..4e9cd8e8 --- /dev/null +++ b/src/static/jaudio_NES/internal/ja_calc.c @@ -0,0 +1,71 @@ +#include "jaudio_NES/ja_calc.h" + +#include "PowerPC_EABI_Support/msl/MSL_C/PPC_EABI/cmath_gcn.h" +// #include "std/Math.h" +// #include "dolphin/math.h" +// #include "stl/math.h" + +#define SINTABLE_LENGTH (257) +static f32 SINTABLE[SINTABLE_LENGTH]; + +/* + * --INFO-- + * Address: 8000DC20 + * Size: 000020 + */ +f32 sqrtf2(f32 x) +{ + return std::sqrtf(x); +} + +/* + * --INFO-- + * Address: ........ + * Size: 000020 + */ +void cosf2(f32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000DCC0 + * Size: 000024 + */ +f32 atanf2(f32 x, f32 y) +{ + return atan2(x, y); +} + +/* + * --INFO-- + * Address: ........ + * Size: 000020 + */ +void sinf2(f32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000DD00 + * Size: 000088 + */ +void Jac_InitSinTable() +{ + for (u32 i = 0; i < SINTABLE_LENGTH; i++) { + SINTABLE[i] = std::sinf(i * HALF_PI / 256.0f); + } +} + +/* + * --INFO-- + * Address: 8000DDA0 + * Size: 000034 + */ +f32 sinf3(f32 x) +{ + return SINTABLE[(int)(256.0f * x)]; +} diff --git a/src/static/jaudio_NES/internal/jammain_2.c b/src/static/jaudio_NES/internal/jammain_2.c new file mode 100644 index 00000000..b666c880 --- /dev/null +++ b/src/static/jaudio_NES/internal/jammain_2.c @@ -0,0 +1,3229 @@ +#include "jaudio_NES/jammain_2.h" + +#include "jaudio_NES/oneshot.h" +#include "jaudio_NES/jamosc.h" +#include "jaudio_NES/seqsetup.h" +#include "jaudio_NES/fat.h" +#include "jaudio_NES/noteon.h" +#include "jaudio_NES/rate.h" +#include "jaudio_NES/random.h" +#include "jaudio_NES/centcalc.h" +#include "jaudio_NES/bankdrv.h" +#include "jaudio_NES/driverinterface.h" + +#include "dolphin/os/OSError.h" + +// TODO IN THIS FILE: What do the return values for the `Cmd_` functions signify? +// 0 is probably success / "no error". Return values 1 and 2 have been observed. +// This just breaking: Cmd_LoopE returns 0x80. + +#define TRACK_LIST_SIZE (32) + +typedef struct TrackListPair TrackListPair; +typedef struct ArgListPair ArgListPair; + +/** + * @brief This is an invented pair-like struct, needed for `TRACK_LIST`. + * + * @note Size: 8. + */ +struct TrackListPair { + seqp_* track; // _00 + u32 id; // _04 +}; + +/** + * @brief This is an invented pair-like struct, needed for `Arglist`. + * + * @note Size: 4. + */ +struct ArgListPair { + u16 argCount; + u16 argTypes; // This is a bitfield array of eight 2-bit values +}; + +static TrackCallback JAM_CALLBACK_FUNC = NULL; + +static size_t T_LISTS; +static TrackListPair TRACK_LIST[TRACK_LIST_SIZE]; + +static seqp_* SEQ_P; +static u8 SEQ_CMD; +static u32 SEQ_ARG[8]; + +// predeclare this so Jam_UpdateTrackAll can use this stupid function. +extern "C" static void OSf32tos8(f32* in, s8* out); + +/* + * --INFO-- + * Address: 8000F400 + * Size: 000054 + */ +void* Jam_OfsToAddr(seqp_* track, u32 ofs) +{ + // TODO: What do 0, 1, and 2 mean? + switch (track->dataSourceMode) { + case 0: + return track->baseData + ofs; + case 1: + case 2: + return FAT_GetPointer(track->fileHandle, ofs); + } + return 0; +} + +/* + * --INFO-- + * Address: 8000F460 + * Size: 000054 + */ +static u8 __ByteReadOfs(seqp_* track, u32 ofs) +{ + // TODO: What do 0, 1, and 2 mean? + switch (track->dataSourceMode) { + case 0: + return track->baseData[ofs]; + case 1: + case 2: + return FAT_ReadByte(track->fileHandle, ofs); + } + return 0; +} + +/* + * --INFO-- + * Address: 8000F4C0 + * Size: 000050 + */ +static u16 __WordReadOfs(seqp_* track, u32 ofs) +{ + u16 result; + result = __ByteReadOfs(track, ofs + 0) << 8; + result |= __ByteReadOfs(track, ofs + 1) << 0; + return result; +} + +/* + * --INFO-- + * Address: 8000F520 + * Size: 000068 + */ +static u32 __24ReadOfs(seqp_* track, u32 ofs) +{ + u32 result; + result = __ByteReadOfs(track, ofs + 0) << 16; + result |= __ByteReadOfs(track, ofs + 1) << 8; + result |= __ByteReadOfs(track, ofs + 2) << 0; + return result; +} + +/* + * --INFO-- + * Address: 8000F5A0 + * Size: 000050 + */ +static u32 __LongReadOfs(seqp_* track, u32 ofs) +{ + u32 result; + result = __WordReadOfs(track, ofs + 0) << 16; + result |= __WordReadOfs(track, ofs + 2) << 0; + return result; +} + +/* + * --INFO-- + * Address: 8000F600 + * Size: 000070 + */ +static u8 __ByteRead(seqp_* track) +{ + // TODO: What do 0, 1, and 2 mean? + switch (track->dataSourceMode) { + case 0: + return track->baseData[track->programCounter++]; + case 1: + case 2: + return FAT_ReadByte(track->fileHandle, track->programCounter++); + } + return 0; +} + +/* + * --INFO-- + * Address: 8000F680 + * Size: 000048 + */ +static u16 __WordRead(seqp_* track) +{ + u16 result; + result = __ByteRead(track) << 8; + result |= __ByteRead(track) << 0; + return result; +} + +/* + * --INFO-- + * Address: 8000F6E0 + * Size: 00005C + */ +static u32 __24Read(seqp_* track) +{ + u32 result; + result = __ByteRead(track) << 16; + result |= __ByteRead(track) << 8; + result |= __ByteRead(track) << 0; + return result; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000048 + */ +static u32 __32Read(seqp_* track) +{ + // Despite being unused, it's obvious this function is similar to `__LongReadOfs`. + u32 result; + result = __WordRead(track) << 16; + result |= __WordRead(track) << 0; + return result; +} + +/* + * --INFO-- + * Address: 8000F740 + * Size: 0000D0 + */ +static BOOL __ConditionCheck(seqp_* track, u8 param_2) +{ + BOOL result; + u16 uVar1; + + uVar1 = Jam_ReadRegDirect(track, 3); + result = FALSE; + + switch (param_2 & 0x0f) { + case 0: + result = TRUE; + break; + case 1: + if (uVar1 == 0) { + result = TRUE; + } + break; + case 2: + if (uVar1 != 0) { + result = TRUE; + } + break; + case 3: + if (uVar1 == 1) { + result = TRUE; + } + break; + case 4: + if (uVar1 >= 0x8000) { + result = TRUE; + } + break; + case 5: + if (uVar1 < 0x8000) { + result = TRUE; + } + break; + } + return result; +} + +/* + * --INFO-- + * Address: 8000F820 + * Size: 000090 + * Note: Equivalent to `JASTrack::seqTimeToDspTime` in later JAudio + */ +int Jam_SEQtimeToDSPtime(seqp_* track, s32 param_2, u8 param_3) +{ + f32 dspTime; + + dspTime = (f32)param_2 * (f32)param_3 / 100.0f; + + if (track->timeRelationMode == 1) { + dspTime = dspTime / track->tempoFactor; + } else { + dspTime = dspTime * 120.0f / track->timeBase; + } + + return dspTime; +} + +/* + * --INFO-- + * Address: 8000F8C0 + * Size: 000020 + */ +u16 Extend8to16(u8 value) +{ + if (value & 0x80) { + return value + 0xFF00; + } + return value; +} + +/* + * --INFO-- + * Address: 8000F8E0 + * Size: 0001A8 + */ +void Jam_WriteTimeParam(seqp_* track, u8 controlByte) +{ + + s32 duration; + u8 paramIndex; + s16 targetValue; + MoveParam_* param; + + duration = 0; + paramIndex = __ByteRead(track); + + // Extract target value based on controlByte[3:2] + switch (controlByte & 0x0C) { + case 0x00: // Use register value + targetValue = track->regParam.reg[__ByteRead(track)]; + break; + case 0x04: // 8-bit immediate value + targetValue = __ByteRead(track); + break; + case 0x08: // 8-bit value shifted to high byte + targetValue = __ByteRead(track) << 8; + break; + case 0x0C: // 16-bit immediate value + targetValue = __WordRead(track); + break; + } + + // Determine time over which to interpolate the parameter + switch (controlByte & 0x03) { + case 0: // Immediate (no interpolation) + duration = -1; + break; + case 1: // Time from register + duration = track->regParam.reg[__ByteRead(track)]; + break; + case 2: // 8-bit immediate duration + duration = __ByteRead(track); + break; + case 3: // 16-bit immediate duration + duration = __WordRead(track); + break; + } + + param = &track->timedParam.move[paramIndex]; + param->targetValue = targetValue / 32768.0f; + + if (duration >= 0) { + param->duration = duration; + } + + if (param->duration <= 0.0f) { + param->currentValue = param->targetValue; + param->stepSize = 0.0f; + param->duration = 1.0f; + } else { + param->stepSize = (param->targetValue - param->currentValue) / param->duration; + } +} + +/* + * --INFO-- + * Address: 8000FAA0 + * Size: 0000AC + */ +void Jam_WriteRegDirect(seqp_* track, u8 index, u16 value) +{ + + u16 uVar1; + + switch (index) { + case 0: + case 1: + case 2: + value = value & 0xff; + uVar1 = Extend8to16(value); + break; + case 32: + case 33: + return; + case 34: + Jam_WriteRegDirect(track, 0, value >> 8); + uVar1 = value; + value = value & 0xff; + index = 1; + break; + default: + uVar1 = value; + break; + } + + track->regParam.reg[index] = value; + track->regParam.param.value = uVar1; +} + +/* + * --INFO-- + * Address: 8000FB60 + * Size: 000098 + */ +static u32 LoadTbl(seqp_* track, u32 ofs, u32 idx, u32 param_4) +{ + u32 result; + + switch (param_4) { + case 4: + result = __ByteReadOfs(track, ofs + idx); + break; + case 5: + idx = idx * 2; + result = __WordReadOfs(track, ofs + idx); + break; + case 6: + idx = idx * 2 + idx; // Roundabout way to multiply by 3. + result = __24ReadOfs(track, ofs + idx); + break; + case 7: + idx = idx * 4; + case 8: + result = __LongReadOfs(track, ofs + idx); + break; + } + return result; +} + +/* + * --INFO-- + * Address: 8000FC00 + * Size: 000484 + */ +void Jam_WriteRegParam(seqp_* track, u8 param_2) +{ + + s16 r30_newRegValue; // r30 + u8 r29_regIdx; // r29 + u16 r28; // r28 + u32 unaff_r27; // r27 + u32 r26; // r26 + u32 r25; // r25 + u32 unaff_r24; // r24 + s16 r23_oldRegValue; // r23 + + r26 = param_2 & 0xc; + r25 = param_2 & 3; + if ((param_2 & 0x0F) == 0x0B) { + r26 = 0; + r25 = 0xb; + } + if ((param_2 & 0x0F) == 0x0A) { + param_2 = __ByteRead(track); + r26 = param_2 & 0x0C; + r25 = 0xa; + unaff_r24 = (u8)(param_2 >> 4) + 4; + } + if ((param_2 & 0x0F) == 0x09) { + param_2 = __ByteRead(track); + r26 = param_2 & 0x0c; + r25 = param_2 & 0xf0; + if (r26 == 8) { + r26 = 0x10; + } + } + r29_regIdx = __ByteRead(track); + if (r25 == 0x0A) { + unaff_r27 = Jam_ReadReg32(track, __ByteRead(track)); + } + switch (r26) { + case 0: + r30_newRegValue = Jam_ReadRegDirect(track, __ByteRead(track)); + break; + case 4: + r30_newRegValue = __ByteRead(track); + break; + case 8: + r30_newRegValue = __ByteRead(track) << 8; + break; + case 12: + r30_newRegValue = __WordRead(track); + break; + case 16: + r30_newRegValue = -1; + } + + r23_oldRegValue = Jam_ReadRegDirect(track, r29_regIdx); + switch (r25) { + case 0x00: + break; + case 0x01: + if (r26 == 4) { + r30_newRegValue = Extend8to16(r30_newRegValue); + } + r30_newRegValue = r23_oldRegValue + r30_newRegValue; + break; + case 0x02: + unaff_r27 = r23_oldRegValue * r30_newRegValue; + Jam_WriteRegXY(track, unaff_r27); + return; + case 0x03: + track->regParam.param.value = r23_oldRegValue - r30_newRegValue; + return; + case 0x0B: + r30_newRegValue = r23_oldRegValue - r30_newRegValue; + break; + case 0x10: + if (r26 == 4) { + r30_newRegValue = Extend8to16(r30_newRegValue); + } + if (r30_newRegValue < 0) { + r30_newRegValue = (u16)r23_oldRegValue >> -r30_newRegValue; + } else { + r30_newRegValue = (u16)r23_oldRegValue << r30_newRegValue; + } + break; + case 0x20: + if (r26 == 4) { + r30_newRegValue = Extend8to16(r30_newRegValue); + } + if (r30_newRegValue < 0) { + r30_newRegValue = r23_oldRegValue >> -r30_newRegValue; + } else { + r30_newRegValue = r23_oldRegValue << r30_newRegValue; + } + break; + case 0x30: + r30_newRegValue = r23_oldRegValue & r30_newRegValue; + break; + case 0x40: + r30_newRegValue = r23_oldRegValue | r30_newRegValue; + break; + case 0x50: + r30_newRegValue = r23_oldRegValue ^ r30_newRegValue; + break; + case 0x60: + r30_newRegValue = -r23_oldRegValue; + break; + case 0x90: + unaff_r27 = GetRandom_s32(); + r30_newRegValue = unaff_r27 % (u16)r30_newRegValue; + break; + case 0xA: + unaff_r27 = LoadTbl(track, unaff_r27, r30_newRegValue, unaff_r24); + r30_newRegValue = (u16)unaff_r27; + break; + } + + switch (r29_regIdx) { + case 0: + case 1: + case 2: + r30_newRegValue = r30_newRegValue & 0xff; + r28 = Extend8to16(r30_newRegValue); + break; + case 0x21: + r29_regIdx = 6; + r30_newRegValue = track->regParam.param.bankNumber & 0xff00 | r30_newRegValue & 0x00ff; + break; + case 0x20: + r29_regIdx = 6; + r30_newRegValue = track->regParam.param.bankNumber & 0x00ff | r30_newRegValue << 8; + break; + case 0x2E: + r29_regIdx = 0xd; + r30_newRegValue = track->regParam.param.basePriority & 0xff00 | r30_newRegValue & 0x00ff; + break; + case 0x2F: + r29_regIdx = 0xd; + r30_newRegValue = track->regParam.param.basePriority & 0x00ff | r30_newRegValue << 8; + break; + case 0x22: + Jam_WriteRegDirect(track, 0, r30_newRegValue >> 8); + r30_newRegValue = r30_newRegValue & 0xff; + r28 = r30_newRegValue; + r29_regIdx = 1; + break; + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + track->regParam.param._20[r29_regIdx - 0x28] = unaff_r27; + return; + default: + r28 = r30_newRegValue; + break; + } + + track->regParam.reg[r29_regIdx] = r30_newRegValue; + track->regParam.param.value = r28; + + if (r29_regIdx == 6) { + Osc_Clear_Overwrite(track); + } + if (r29_regIdx == 7) { + track->updateFlags |= OuterParamFlag_Pitch; + } + if (r29_regIdx == 0xd) { + track->parentController.channelPriority = track->regParam.param.basePriority | 0x10000; + track->parentController.releaseTime = 0; + } +} + +/* + * --INFO-- + * Address: 800100A0 + * Size: 00016C + */ +u16 Jam_ReadRegDirect(seqp_* track, u8 regIdx) +{ + s16 result; + u16 regDirectLo; + u16 regDirectHi; + int i; + + switch (regIdx) { + case 0x20: + case 0x21: + result = track->regParam.param.bankNumber; + break; + case 0x22: + regDirectLo = Jam_ReadRegDirect(track, 1); + regDirectHi = Jam_ReadRegDirect(track, 0); + result = regDirectHi << 8 | regDirectLo; + break; + case 0x2C: + result = 0; + for (i = 15; i >= 0; --i) { + result = result << 1; // For some reason, `<<=` prevents `srawi`. + if (track->children[i] && track->children[i]->trackState) { + result |= 1; + } + } + break; + case 0x2D: + result = 0; + for (i = 7; i >= 0; --i) { + result = result << 1; // For some reason, `<<=` prevents `srawi`. + result |= (u8)CheckNoteStop(track, i); + } + break; + case 0x30: + if (track->callStackDepth == 0) { + result = 0; + } else { + result = track->loopCounters[track->callStackDepth - 1]; + } + break; + default: + result = track->regParam.reg[regIdx]; + break; + } + switch (regIdx) { + case 0x00: + case 0x01: + case 0x02: + case 0x21: + result = result & 0xff; + break; + case 0x20: + result = result >> 8; + break; + } + return result; +} + +/* + * --INFO-- + * Address: 80010220 + * Size: 000048 + */ +u32 Jam_ReadRegXY(seqp_* track) +{ + return (Jam_ReadRegDirect(track, 4) << 16) | Jam_ReadRegDirect(track, 5); +} + +/* + * --INFO-- + * Address: 80010280 + * Size: 00005C + */ +u32 Jam_ReadReg32(seqp_* track, u8 index) +{ + switch (index) { + case 40: + case 41: + case 42: + case 43: + return track->regParam.param._20[index - 40]; + case 35: + return Jam_ReadRegXY(track); + } + return Jam_ReadRegDirect(track, index); +} + +/* + * --INFO-- + * Address: 800102E0 + * Size: 000048 + */ +void Jam_WriteRegXY(seqp_* track, u32 param_2) +{ + Jam_WriteRegDirect(track, 4, (u16)(param_2 >> 16)); + Jam_WriteRegDirect(track, 5, (u16)(param_2)); +} + +/* + * --INFO-- + * Address: 80010340 + * Size: 00003C + * Note: Equivalent to `JASTrack::exchangeRegisterValue` in later JAudio. + */ +u32 __ExchangeRegisterValue(seqp_* track, u8 param_2) +{ + if (param_2 < 64) { + return Jam_ReadReg32(track, param_2); + } + return track->trackPort[param_2 - 64].value; +} + +/* + * --INFO-- + * Address: ........ + * Size: 00004C + */ +void Jam_WritePortApp(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00004C + */ +void Jam_ReadPortApp(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000048 + */ +void Jam_CheckExportApp(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000048 + */ +void Jam_CheckImportApp(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000A0 + */ +void Jam_WritePortIndirect(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000058 + */ +void Jam_ReadPortIndirect(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000A4 + */ +void Jam_CheckPortIndirect(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 80010380 + * Size: 000078 + */ +BOOL Jam_WritePortAppDirect(seqp_* track, u32 param_2, u16 param_3) +{ + if (!track) { + return FALSE; + } + track->trackPort[param_2].value = param_3; + track->trackPort[param_2].importFlag = 1; + if (param_2 == 0) { + Jam_SetInterrupt(track, 3); + } + if (param_2 == 1) { + Jam_SetInterrupt(track, 4); + } + return TRUE; +} + +/* + * --INFO-- + * Address: 80010400 + * Size: 000030 + */ +BOOL Jam_ReadPortAppDirect(seqp_* track, u32 param_2, u16* param_3) +{ + if (!track) { + return FALSE; + } + *param_3 = track->trackPort[param_2].value; + track->trackPort[param_2].exportFlag = 0; + return TRUE; +} + +/* + * --INFO-- + * Address: 80010440 + * Size: 00006C + */ +BOOL Jam_CheckPortAppDirect(seqp_* track, u32 param_2, u16 param_3) +{ + // Again with the cast to u8... what is it? + switch ((u8)param_3) { + case FALSE: + if (track->trackPort[param_2].exportFlag == FALSE) { + return FALSE; + } + return TRUE; + case TRUE: + if (track->trackPort[param_2].importFlag == TRUE) { + return FALSE; + } + return TRUE; + } + return FALSE; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000018 + */ +void Jam_WritePort(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000018 + */ +void Jam_ReadPort(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000034 + */ +void Jam_WritePortChild(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000038 + */ +void Jam_WritePortBros(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 800104C0 + * Size: 000030 + */ +void Jam_InitRegistTrack(void) +{ + int i; + + T_LISTS = 0; + for (i = 0; i < TRACK_LIST_SIZE; ++i) { + TRACK_LIST[i].track = NULL; + } +} + +/* + * --INFO-- + * Address: 80010500 + * Size: 0000A8 + */ +void Jam_RegistTrack(seqp_* track, u32 param_2) +{ + u32* REF_param_2; + size_t i; + + for (i = 0; i < T_LISTS; ++i) { + if (param_2 == TRACK_LIST[i].id) { + return; + } + } + if (T_LISTS == TRACK_LIST_SIZE) { + for (i = 0; i < TRACK_LIST_SIZE; ++i) { + if (!TRACK_LIST[i].track) { + break; + } + } + if (i == TRACK_LIST_SIZE) { + return; + } + } else { + i = T_LISTS; + ++T_LISTS; + } + REF_param_2 = ¶m_2; + TRACK_LIST[i].id = param_2; + TRACK_LIST[i].track = track; + track->isRegistered = 1; +} + +/* + * --INFO-- + * Address: 800105C0 + * Size: 00008C + */ +void Jam_UnRegistTrack(seqp_* track) +{ + size_t i; + + if (!track->isRegistered) { + return; + } + for (i = 0; i < T_LISTS; ++i) { + if (track == TRACK_LIST[i].track) { + TRACK_LIST[i].track = NULL; + } + } + track->isRegistered = FALSE; + for (; T_LISTS != 0; --T_LISTS) { + if (TRACK_LIST[T_LISTS - 1].track) { + break; + } + } +} + +/* + * --INFO-- + * Address: 80010660 + * Size: 000050 + */ +seqp_* Jam_GetTrackHandle(u32 param_1) +{ + size_t i; + + for (i = 0; i < T_LISTS; ++i) { + if (param_1 == TRACK_LIST[i].id && TRACK_LIST[i].track) { + return TRACK_LIST[i].track; + } + } + return NULL; +} + +/* + * --INFO-- + * Address: 800106C0 + * Size: 000018 + */ +void Jam_InitExtBuffer(OuterParam_* ext) +{ + ext->flags = 0; + ext->updateFlags = 0; + ext->isAssigned = FALSE; + ext->refCount = 0; +} + +/* + * --INFO-- + * Address: 800106E0 + * Size: 000038 + */ +BOOL Jam_AssignExtBuffer(seqp_* track, OuterParam_* ext) +{ + if (!track) { + return FALSE; + } + if (!ext) { + return FALSE; + } + track->outerParams = ext; + ++ext->refCount; + return TRUE; +} + +/* + * --INFO-- + * Address: 80010720 + * Size: 000060 + */ +BOOL Jam_AssignExtBufferP(seqp_* track, u8 index, OuterParam_* ext) +{ + if (!track) { + return FALSE; + } + if (!ext) { + return FALSE; + } + track->childOuterParams[index] = ext; + ext->isAssigned = TRUE; + Jam_AssignExtBuffer(track->children[index], ext); + return TRUE; +} + +/* + * --INFO-- + * Address: 80010780 + * Size: 000044 + */ +void Jam_SetExtFirFilterD(OuterParam_* ext, s16* param_2) +{ + int i; + + if (!ext) { + return; + } + ext->updateFlags |= OuterParamFlag_FIR8Filter; + ext->flags |= OuterParamFlag_FIR8Filter; + for (i = 0; i < 8; ++i) { + ext->firCoefficients[i] = param_2[i]; + } +} + +/* + * --INFO-- + * Address: 800107E0 + * Size: 0000A4 + */ +void Jam_SetExtParamD(f32 value, OuterParam_* ext, u8 updateFlags) +{ + f32* member; + + if (!ext) { + return; + } + + switch (updateFlags) { + case OuterParamFlag_Volume: + member = &ext->volume; + break; + case OuterParamFlag_Pitch: + member = &ext->pitch; + break; + case OuterParamFlag_Fxmix: + member = &ext->fxMix; + break; + case OuterParamFlag_Dolby: + member = &ext->dolby; + break; + case OuterParamFlag_Pan: + member = &ext->pan; + break; + case OuterParamFlag_Tempo: + member = &ext->tempo; + break; + default: + return; + } + + *member = value; + ext->updateFlags |= updateFlags; +} + +/* + * --INFO-- + * Address: 800108A0 + * Size: 000024 + */ +void Jam_OnExtSwitchD(OuterParam_* ext, u16 param_2) +{ + if (!ext) { + return; + } + ext->flags |= param_2; + ext->updateFlags |= param_2; +} + +/* + * --INFO-- + * Address: 800108E0 + * Size: 000028 + */ +void Jam_OffExtSwitchD(OuterParam_* ext, u16 param_2) +{ + if (!ext) { + return; + } + ext->flags ^= ext->flags & param_2; + ext->updateFlags |= param_2; +} + +/* + * --INFO-- + * Address: ........ + * Size: 00001C + */ +void Jam_SetExtSwitchDirectD(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00002C + */ +void Jam_SetExtFirFilter(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 80010920 + * Size: 00002C + */ +void Jam_SetExtParam(f32 param_1, seqp_* track, u8 param_3) +{ + if (!track) { + return; + } + Jam_SetExtParamD(param_1, track->outerParams, param_3); +} + +/* + * --INFO-- + * Address: 80010960 + * Size: 00002C + */ +void Jam_OnExtSwitch(seqp_* track, u16 param_2) +{ + if (!track) { + return; + } + Jam_OnExtSwitchD(track->outerParams, param_2); +} + +/* + * --INFO-- + * Address: 800109A0 + * Size: 00002C + */ +void Jam_OffExtSwitch(seqp_* track, u16 param_2) +{ + if (!track) { + return; + } + Jam_OffExtSwitchD(track->outerParams, param_2); +} + +/* + * --INFO-- + * Address: ........ + * Size: 00002C + */ +void Jam_SetExtSwitchDirect(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00003C + */ +void Jam_SetExtFirFilterP(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 800109E0 + * Size: 000038 + */ +void Jam_SetExtParamP(f32 param_1, seqp_* track, u8 index, u8 param_4) +{ + if (!track) { + return; + } + Jam_SetExtParamD(param_1, track->childOuterParams[index], param_4); +} + +/* + * --INFO-- + * Address: 80010A20 + * Size: 00003C + */ +void Jam_OnExtSwitchP(seqp_* track, u8 index, u16 param_3) +{ + if (!track) { + return; + } + Jam_OnExtSwitchD(track->childOuterParams[index], param_3); +} + +/* + * --INFO-- + * Address: ........ + * Size: 00003C + */ +void Jam_OffExtSwitchP(seqp_* track, u8 index, u16 param_3) +{ + if (!track) { + return; + } + Jam_OffExtSwitchD(track->childOuterParams[index], param_3); +} + +/* + * --INFO-- + * Address: ........ + * Size: 00003C + */ +void Jam_SetExtSwitchDirectP(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00002C + */ +void Jam_CheckRunningCounter(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 80010A60 + * Size: 00000C + */ +BOOL Jam_RegisterTrackCallback(TrackCallback callback) +{ + JAM_CALLBACK_FUNC = callback; + return TRUE; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000038 + */ +void Jam_SetTrackExtPanPower(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 80010A80 + * Size: 00004C + */ +static f32 __PanCalc(f32 param_1, f32 param_2, f32 param_3, u8 param_4) +{ + f32 result; + + switch (param_4) { + case 0: + return param_1; + case 1: + return param_2; + case 2: + result = param_1 * (1.0f - param_3) + (param_2 * param_3); + } + return result; +} + +/* + * --INFO-- + * Address: 80010AE0 + * Size: 000320 + */ +void Jam_UpdateTrackAll(seqp_* track) +{ + f32 pitchCents; + f32 volumeValue; + f32 panValue; + f32 fxMixValue; + f32 dolbyValue; + f32 distance; + f32 parentDistance; + + f32 panScaled; + s8 pan8bit; + u8 panDelayLeft; + + size_t i; + + distance = track->regParam.param.arguments[3] / 32767.0f; + if (track->flags != 4) { + track->parentController.channelPriority = track->regParam.param.basePriority | 0x10000; + track->parentController.releaseTime = 0; + + panDelayLeft = 0; + panScaled = track->timedParam.inner._110.currentValue * 128.0f; + + OSf32tos8(&panScaled, &pan8bit); + if (pan8bit < 0) { + panDelayLeft = -pan8bit; + pan8bit = 0; + } + + track->parentController.maxDelay = 0x10; + track->parentController.masterLevels[0] = panDelayLeft; + track->parentController.masterLevels[1] = pan8bit; + + // Read base volume; if muted, force to zero + volumeValue = track->timedParam.inner.volume.currentValue; + if (track->isMuted > 0) { + volumeValue = 0.0f; + } + + // Convert pitch to cents, read pan/fxmix/dolby from timed parameters + pitchCents = Jam_PitchToCent(track->timedParam.inner.pitch.currentValue, track->regParam.param.pitchScale); + panValue = track->timedParam.inner.pan.currentValue; + fxMixValue = track->timedParam.inner.fxmix.currentValue; + dolbyValue = track->timedParam.inner.dolby.currentValue; + + if (track->outerParams) { + if (track->outerParams->flags & OuterParamFlag_Volume) { + volumeValue = volumeValue * track->outerParams->volume; + } + + if (track->outerParams->flags & OuterParamFlag_Pitch) { + pitchCents = pitchCents * track->outerParams->pitch; + } + + if (track->outerParams->flags & OuterParamFlag_Fxmix) { + fxMixValue = __PanCalc(fxMixValue, track->outerParams->fxMix, distance, track->panCalcTypes[1]); + } + + if (track->outerParams->flags & OuterParamFlag_Dolby) { + dolbyValue = __PanCalc(dolbyValue, track->outerParams->dolby, distance, track->panCalcTypes[2]); + } + + if (track->outerParams->flags & OuterParamFlag_Pan) { + panValue = __PanCalc(panValue, track->outerParams->pan, distance, track->panCalcTypes[0]); + } + } + + // If there is no parent or this track overrides its parent (trackFlags & 1), + // write the final values directly into the channel state + if (!track->parent || (track->flags & 1)) { + track->parentController.volume = volumeValue; + track->parentController.pitch = pitchCents; + track->parentController.pan = panValue; + track->parentController.fxmix = fxMixValue; + track->parentController.dolby = dolbyValue; + } else { + // Otherwise, combine with parent’s values using a second attenuation factor + parentDistance = track->regParam.param.arguments[4] / 32767.0f; + + track->parentController.volume = track->parent->parentController.volume * volumeValue; + track->parentController.pitch = track->parent->parentController.pitch * pitchCents; + track->parentController.pan + = __PanCalc(panValue, track->parent->parentController.pan, parentDistance, track->parentPanCalcTypes[0]); + track->parentController.fxmix + = __PanCalc(fxMixValue, track->parent->parentController.fxmix, parentDistance, track->parentPanCalcTypes[1]); + track->parentController.dolby + = __PanCalc(dolbyValue, track->parent->parentController.dolby, parentDistance, track->parentPanCalcTypes[2]); + + // If outerParams specify a custom FIR filter, copy those coefficients + if (track->outerParams && (track->outerParams->flags & OuterParamFlag_FIR8Filter)) { + for (i = 0; i < 8; ++i) { + track->parentController.firCoefficients[i] = track->outerParams->firCoefficients[i]; + } + + track->parentController.filterMode = 8; + } + + // Read inner IIR coefficients (normalized floats) and convert to 16-bit + for (i = 0; i < 4; ++i) { + track->parentController.iirCoefficients[i] = track->timedParam.inner.IIRs[i].currentValue * 32767.0f; + } + + track->parentController.filterMode |= 0x20; + track->parentController.distFilter = track->timedParam.inner.distFilter.currentValue * 32767.0f; + } + } +} + +#define OS_FASTCAST_S8 (4) + +/* + * --INFO-- + * Address: 80010E00 + * Size: 00000C + */ +static void OSf32tos8(register f32* in, register s8* out) +{ +#ifdef __MWERKS__ + asm { + lfs f1, 0 (in) + psq_st f1, 0 (out), 0x1, OS_FASTCAST_S8 + } +#endif +} + +/* + * --INFO-- + * Address: 80010E20 + * Size: 0004A8 + */ +void Jam_UpdateTrack(seqp_* track, u32 updateFlags) +{ + // A bizarre way the devs attempted to re-use some repeated AND operations in this function, + // which the compiler can already see and optimize in its own way, causes regalloc inflation. + u32 updateVolumeFlag; + u32 updatePitchFlag; + u32 updatePanFlag; + u32 updateFxMixFlag; + u32 updateDolbyFlag; + + f32 computedVolume; // f31 + f32 unaff_f30; // f30 + f32 unaff_f29; // f29 + f32 unaff_f28; // f28 + f32 unaff_f27; // f27 + f32 regionAttenuation; + f32 offset; + f32 dVar15_3; + + size_t i; + + // Used for `OSf32tos8` + f32 masterLevelF32; + s8 masterRight; + u8 masterLeft; + + regionAttenuation = track->regParam.param.arguments[3] / 32767.0f; + + if (track->flags != 0x04) { + + // Update master pan delay levels if requested + if (updateFlags & SEQTRACK_FLAG_MASTER_LEVEL) { + masterLeft = 0; + masterLevelF32 = track->timedParam.inner._110.currentValue * 128.0f; + OSf32tos8(&masterLevelF32, &masterRight); + if (masterRight < 0) { + masterLeft = -masterRight; + masterRight = 0; + } + track->parentController.masterLevels[0] = masterLeft; + track->parentController.masterLevels[1] = masterRight; + } + + // Tempo update (only if top-level track) + if (updateFlags & OuterParamFlag_Tempo && !track->parent) { + Jam_UpdateTempo(track); + } + + updateVolumeFlag = updateFlags & OuterParamFlag_Volume; + if (updateVolumeFlag) { + computedVolume = track->timedParam.inner.volume.currentValue; + if (track->isMuted != 0) { + computedVolume = 0.0f; + } + + if (track->outerParams && (track->outerParams->flags & OuterParamFlag_Volume)) { + computedVolume *= track->outerParams->volume; + } + + if (track->isPaused && (track->pauseStatus & 1)) { + computedVolume *= track->timedParam.inner._100.currentValue; + } + } + + updatePitchFlag = updateFlags & OuterParamFlag_Pitch; + if (updatePitchFlag) { + unaff_f30 = Jam_PitchToCent((track->timedParam).inner.pitch.currentValue, track->regParam.param.pitchScale); + if (track->outerParams && ((track->outerParams->flags & OuterParamFlag_Pitch) != 0)) { + unaff_f30 = (unaff_f30 * track->outerParams->pitch); + } + } + + updatePanFlag = updateFlags & OuterParamFlag_Pan; + if (updatePanFlag) { + unaff_f29 = (track->timedParam).inner.pan.currentValue; + if (track->outerParams && ((track->outerParams->flags & OuterParamFlag_Pan) != 0)) { + unaff_f29 = __PanCalc(unaff_f29, track->outerParams->pan, regionAttenuation, track->panCalcTypes[0]); + } + } + + updateFxMixFlag = updateFlags & OuterParamFlag_Fxmix; + if (updateFxMixFlag) { + unaff_f28 = (track->timedParam).inner.fxmix.currentValue; + if (track->outerParams && ((track->outerParams->flags & OuterParamFlag_Fxmix) != 0)) { + unaff_f28 = __PanCalc(unaff_f28, track->outerParams->fxMix, regionAttenuation, track->panCalcTypes[1]); + } + } + + updateDolbyFlag = updateFlags & OuterParamFlag_Dolby; + if (updateDolbyFlag) { + unaff_f27 = (track->timedParam).inner.dolby.currentValue; + if (track->outerParams && ((track->outerParams->flags & OuterParamFlag_Dolby) != 0)) { + unaff_f27 = __PanCalc(unaff_f27, track->outerParams->dolby, regionAttenuation, track->panCalcTypes[2]); + } + } + + // IIR flag is set + if (updateFlags & OuterParamFlag_IIRFilter) { + for (i = 0; i < 4; ++i) { + track->parentController.iirCoefficients[i] = track->timedParam.inner.IIRs[i].currentValue * 32767.0f; + } + + track->parentController.filterMode |= 0x20; + } + + if (track->outerParams) { + if (updateFlags & OuterParamFlag_FIR8Filter && (track->outerParams->flags & OuterParamFlag_FIR8Filter)) { + for (i = 0; i < 8; ++i) { + track->parentController.firCoefficients[i] = track->outerParams->firCoefficients[i]; + } + + track->parentController.filterMode = (track->parentController.filterMode & 0x20) + 8; + } + } + + if (updateFlags & OuterParamFlag_DistFilt) { + track->parentController.distFilter = track->timedParam.inner.distFilter.currentValue * 32767.0f; + } + + for (i = 0; i < 2; ++i) { + if (track->oscillatorRouting[i] == 0x0E) { + offset = Bank_OscToOfs(&track->oscillators[i], &track->oscillatorParams[i]); + switch (track->oscillators[i].mode) { + case 1: + unaff_f30 = unaff_f30 * offset; + break; + case 0: + computedVolume = computedVolume * offset; + break; + case 2: + unaff_f29 = unaff_f29 * offset; + break; + case 3: + unaff_f28 = unaff_f28 * offset; + break; + case 4: + unaff_f27 = unaff_f27 * offset; + break; + } + } + } + if (!track->parent || ((track->flags & 1) != 0)) { + if (updateVolumeFlag) { + track->parentController.volume = computedVolume; + } + if (updatePitchFlag) { + track->parentController.pitch = unaff_f30; + } + if (updatePanFlag) { + track->parentController.pan = unaff_f29; + } + if (updateFxMixFlag) { + track->parentController.fxmix = unaff_f28; + } + if (updateDolbyFlag != 0) { + track->parentController.dolby = unaff_f27; + } + } else { + dVar15_3 = track->regParam.param.arguments[4] / 32767.0f; + if (updateVolumeFlag) { + track->parentController.volume = track->parent->parentController.volume * computedVolume; + } + if (updatePitchFlag) { + track->parentController.pitch = track->parent->parentController.pitch * unaff_f30; + } + if (updatePanFlag) { + track->parentController.pan + = __PanCalc(unaff_f29, track->parent->parentController.pan, dVar15_3, track->parentPanCalcTypes[0]); + } + if (updateFxMixFlag) { + track->parentController.fxmix + = __PanCalc(unaff_f28, track->parent->parentController.fxmix, dVar15_3, track->parentPanCalcTypes[1]); + } + if (updateDolbyFlag) { + track->parentController.dolby + = __PanCalc(unaff_f27, track->parent->parentController.dolby, dVar15_3, track->parentPanCalcTypes[2]); + } + } + } +} + +/* + * --INFO-- + * Address: 800112E0 + * Size: 000104 + */ +void Jam_UpdateTempo(seqp_* track) +{ + size_t i; + + size_t* REF_i; + + if (!track->parent) { + track->tempoFactor = (float)track->timeBase * (float)track->tempo / (JAC_DAC_RATE * 60.0f / 80.0f); + if ((track->outerParams->flags & OuterParamFlag_Tempo) != 0) { + track->tempoFactor = track->tempoFactor * track->outerParams->tempo; + } + } else { + track->tempoFactor = track->parent->tempoFactor; + track->timeBase = track->parent->timeBase; + } + for (i = 0; i < 16; ++i) { + REF_i = &i; + if (track->children[i] && track->children[i]->trackState) { + Jam_UpdateTempo(track->children[i]); + } + } +} + +/* + * --INFO-- + * Address: 80011400 + * Size: 0000CC + */ +void Jam_MuteTrack(seqp_* track, u8 param_2) +{ + u32 i; + u16 mask; + + if (track->parent) { + track->isMuted = track->parent->isMuted | param_2; + mask = 1 << (track->trackId & 0xf); + if (!param_2) { + track->parent->childMuteMask &= ~mask; + } else { + track->parent->childMuteMask |= mask; + } + } else { + track->isMuted = param_2; + } + track->updateFlags |= OuterParamFlag_Volume; + if (track->isMuted && (track->pauseStatus & 0x20)) { + for (i = 0; i < 8; ++i) { + NoteOFF_R(track, (u8)i, 10); + }; + } +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000B4 + */ +void Jam_MuteChildTracks(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 800114E0 + * Size: 00013C + */ +void Jam_PauseTrack(seqp_* track, u8 param_2) +{ + size_t i; + jc_* pjVar1; + + size_t* REF_i; + + track->isPaused = TRUE; + if (track->pauseStatus & 0x01) { + track->updateFlags |= OuterParamFlag_Volume; + } + if (track->pauseStatus & 0x04) { + for (i = 0; i < 8; ++i) { + REF_i = &i; + NoteOFF_R(track, i, 10); + } + } + if (track->pauseStatus & 0x08) { + for (i = 0; i < 8; ++i) { + pjVar1 = track->channels[i]; + if (pjVar1 && track->activeSoundIds[i] == pjVar1->channelId) { + UpdatePause_1Shot(pjVar1, 1); + } + } + } + Jam_SetInterrupt(track, 0); + if (param_2 == TRUE) { + for (i = 0; i < 16; ++i) { + if (track->children[i] && track->children[i]->trackState) { + Jam_PauseTrack(track->children[i], 1); + } + } + } +} + +/* + * --INFO-- + * Address: 80011620 + * Size: 0000EC + */ +void Jam_UnPauseTrack(seqp_* track, u8 param_2) +{ + size_t i; + jc_* pjVar1; + + size_t* REF_i; + + track->isPaused = FALSE; + track->updateFlags |= OuterParamFlag_Volume; + for (i = 0; i < 8; ++i) { + REF_i = &i; + pjVar1 = track->channels[i]; + if (pjVar1 && track->activeSoundIds[i] == pjVar1->channelId) { + UpdatePause_1Shot(pjVar1, 0); + } + } + Jam_SetInterrupt(track, 1); + if (param_2 == TRUE) { + for (i = 0; i < 16; ++i) { + if (track->children[i] && track->children[i]->trackState) { + Jam_UnPauseTrack(track->children[i], 1); + } + } + } +} + +/* + * --INFO-- + * Address: 80011720 + * Size: 000028 + * Note: Equivalent to `JASIntrMgr::request` in later JAudio. + */ +void Jam_SetInterrupt(seqp_* track, u16 interrupt) +{ + if (track->interruptEnable & (1 << interrupt)) { + track->interruptPending |= (1 << interrupt); + } +} + +/* + * --INFO-- + * Address: 80011760 + * Size: 000090 + */ +BOOL Jam_TryInterrupt(seqp_* track) +{ + int i; + u32 mask; + + if (track->interruptActive) { + return FALSE; + } + for (i = 0; i < 8; ++i) { + mask = 1 << i; + if ((track->interruptEnable & mask) && (track->interruptPending & mask)) { + track->savedProgramCounter = track->programCounter; + track->programCounter = track->interruptAddresses[i]; + track->interruptActive = mask; + track->_3CC = track->waitTimer; + track->waitTimer = 0; + track->interruptPending ^= mask; + return TRUE; + } + } + return FALSE; +} + +/* + * --INFO-- + * Address: 80011800 + * Size: 000038 + */ +static u32 Cmd_OpenTrack() +{ + Jaq_OpenTrack(SEQ_P, SEQ_ARG[0], SEQ_ARG[1]); + return 0; +} + +/* + * --INFO-- + * Address: 80011840 + * Size: 000050 + */ +static u32 Cmd_OpenTrackBros() +{ + if (SEQ_P->parent) { + Jaq_OpenTrack(SEQ_P->parent, SEQ_ARG[0], SEQ_ARG[1]); + } else { + return 0x40; + } + return 0; +} + +/* + * --INFO-- + * Address: 800118A0 + * Size: 00003C + */ +static u32 Cmd_Call() +{ + SEQ_P->callStack[SEQ_P->callStackDepth++] = SEQ_P->programCounter; + SEQ_P->programCounter = SEQ_ARG[0]; + return 0; +} + +/* + * --INFO-- + * Address: 800118E0 + * Size: 000100 + */ +static u32 Cmd_CallF() +{ + u8 bVar1; + u32 uVar2; + u32 uVar3; + u8 uVar4; + + bVar1 = __ByteRead(SEQ_P); + if (bVar1 & 0x80) { + uVar4 = __ByteRead(SEQ_P); + uVar2 = Jam_ReadRegDirect(SEQ_P, uVar4); + if (bVar1 & 0x40) { + if (bVar1 & 0x20) { + uVar4 = __ByteRead(SEQ_P); + uVar3 = Jam_ReadRegDirect(SEQ_P, uVar4); + } else { + uVar3 = __24Read(SEQ_P); + } + uVar2 = __24ReadOfs(SEQ_P, uVar3 + uVar2 * 3); + } + } else { + uVar2 = __24Read(SEQ_P); + } + if ((u8)__ConditionCheck(SEQ_P, bVar1 & 0x0f) == TRUE) { + if (SEQ_CMD == (0xC0 + CMD_CALL_F)) { + SEQ_P->callStack[SEQ_P->callStackDepth++] = SEQ_P->programCounter; + } + SEQ_P->programCounter = uVar2; + } + return 0; +} + +/* + * --INFO-- + * Address: 800119E0 + * Size: 000028 + */ +static u32 Cmd_Ret() +{ + SEQ_P->programCounter = SEQ_P->callStack[--SEQ_P->callStackDepth]; + return 0; +} + +/* + * --INFO-- + * Address: 80011A20 + * Size: 000060 + */ +static u32 Cmd_RetF() +{ + // But why cast it...? And why check if it explicitly equals TRUE...? + if ((u8)__ConditionCheck(SEQ_P, SEQ_ARG[0] & 0x0f) == TRUE) { + SEQ_P->programCounter = SEQ_P->callStack[--SEQ_P->callStackDepth]; + } + return 0; +} + +/* + * --INFO-- + * Address: 80011A80 + * Size: 00001C + */ +static u32 Cmd_Jmp() +{ + SEQ_P->programCounter = SEQ_ARG[1]; + return 0; +} + +/* + * --INFO-- + * Address: 80011AA0 + * Size: 000020 + */ +static u32 Cmd_JmpF() +{ + Cmd_CallF(); +} + +/* + * --INFO-- + * Address: 80011AC0 + * Size: 000048 + */ +static u32 Cmd_LoopS() +{ + SEQ_P->callStack[SEQ_P->callStackDepth] = SEQ_P->programCounter; + SEQ_P->loopCounters[SEQ_P->callStackDepth++] = SEQ_ARG[0]; + return 0; +} + +/* + * --INFO-- + * Address: 80011B20 + * Size: 000078 + */ +static u32 Cmd_LoopE() +{ + u16 uVar1; + + if (SEQ_P->callStackDepth == 0) { + return 0x80; + } + + uVar1 = SEQ_P->loopCounters[SEQ_P->callStackDepth - 1]; + if (uVar1 != 0) { + uVar1 -= 1; + } + if (uVar1 == 0) { + SEQ_P->callStackDepth -= 1; + return 0; + } + + SEQ_P->loopCounters[SEQ_P->callStackDepth - 1] = uVar1; + SEQ_P->programCounter = SEQ_P->callStack[SEQ_P->callStackDepth - 1]; + return 0; +} + +/* + * --INFO-- + * Address: 80011BA0 + * Size: 000054 + */ +static u32 Cmd_ReadPort() +{ + u16 temp; + + temp = SEQ_P->trackPort[SEQ_ARG[0]].value; + SEQ_P->trackPort[SEQ_ARG[0]].importFlag = 0; + Jam_WriteRegDirect(SEQ_P, SEQ_ARG[1], temp); + return 0; +} + +/* + * --INFO-- + * Address: 80011C00 + * Size: 000040 + */ +static u32 Cmd_WritePort() +{ + SEQ_P->trackPort[SEQ_ARG[0]].value = SEQ_ARG[1]; + SEQ_P->trackPort[SEQ_ARG[0]].exportFlag = 1; + return 0; +} + +/* + * --INFO-- + * Address: 80011C40 + * Size: 000044 + */ +static u32 Cmd_CheckPortImport() +{ + Jam_WriteRegDirect(SEQ_P, 3, SEQ_P->trackPort[SEQ_ARG[0]].importFlag); + return 0; +} + +/* + * --INFO-- + * Address: 80011CA0 + * Size: 000044 + */ +static u32 Cmd_CheckPortExport() +{ + Jam_WriteRegDirect(SEQ_P, 3, SEQ_P->trackPort[SEQ_ARG[0]].exportFlag); + return 0; +} + +/* + * --INFO-- + * Address: 80011D00 + * Size: 00002C + */ +static u32 Cmd_WaitReg() +{ + SEQ_P->waitTimer = SEQ_ARG[0]; + return SEQ_ARG[0] ? 1 : 0; +} + +/* + * --INFO-- + * Address: 80011D40 + * Size: 000028 + */ +static u32 Cmd_ConnectName() +{ + SEQ_P->connectionId = SEQ_ARG[0] << 16 | SEQ_ARG[1]; + return 0; +} + +/* + * --INFO-- + * Address: 80011D80 + * Size: 000040 + */ +static u32 Cmd_ParentWritePort() +{ + Jam_WritePortAppDirect(SEQ_P->parent, SEQ_ARG[0] & 0x0f, SEQ_ARG[1]); + return 0; +} + +/* + * --INFO-- + * Address: 80011DC0 + * Size: 000048 + */ +static u32 Cmd_ChildWritePort() +{ + Jam_WritePortAppDirect(SEQ_P->children[(SEQ_ARG[0] >> 4)], SEQ_ARG[0] & 0x0f, SEQ_ARG[1]); + return 0; +} + +/* + * --INFO-- + * Address: 80011E20 + * Size: 000030 + */ +static u32 Cmd_SetLastNote() +{ + SEQ_P->_D5 = SEQ_ARG[0]; + SEQ_P->_D5 += SEQ_P->finalTranspose; + return 0; +} + +/* + * --INFO-- + * Address: 80011E60 + * Size: 00001C + */ +static u32 Cmd_TimeRelate() +{ + SEQ_P->timeRelationMode = SEQ_ARG[0]; + return 0; +} + +/* + * --INFO-- + * Address: 80011E80 + * Size: 000034 + */ +static u32 Cmd_SimpleOsc() +{ + Osc_Setup_Simple(SEQ_P, SEQ_ARG[0]); + return 0; +} + +/* + * --INFO-- + * Address: 80011EC0 + * Size: 000038 + */ +static u32 Cmd_SimpleEnv() +{ + Osc_Setup_SimpleEnv(SEQ_P, SEQ_ARG[0], SEQ_ARG[1]); + return 0; +} + +/* + * --INFO-- + * Address: 80011F00 + * Size: 000064 + */ +static u32 Cmd_SimpleADSR() +{ + int i; + s16 local_10[5]; + + for (i = 0; i < 5; ++i) { + local_10[i] = SEQ_ARG[i]; + } + Osc_Setup_ADSR(SEQ_P, local_10); + return 0; +} + +/* + * --INFO-- + * Address: 80011F80 + * Size: 000048 + */ +static u32 Cmd_Transpose() +{ + SEQ_P->transpose = SEQ_ARG[0]; + if (SEQ_P->parent) { + SEQ_P->finalTranspose = SEQ_P->parent->transpose + SEQ_P->transpose; + } else { + SEQ_P->finalTranspose = SEQ_P->transpose; + } + return 0; +} + +/* + * --INFO-- + * Address: 80011FE0 + * Size: 000068 + */ +static u32 Cmd_CloseTrack() +{ + u8 index = SEQ_ARG[0]; + if (index >= (u32)ARRAY_COUNT(SEQ_P->children)) { + return 0x80; + } + Jaq_CloseTrack(SEQ_P->children[index]); + SEQ_P->children[index] = NULL; + return 0; +} + +/* + * --INFO-- + * Address: 80012060 + * Size: 000038 + */ +static u32 Cmd_OutSwitch() +{ + if (SEQ_P->outerParams) { + SEQ_P->outerParams->flags = SEQ_ARG[0]; + SEQ_P->outerParams->updateFlags = -1; + } + + return 0; +} + +/* + * --INFO-- + * Address: 800120A0 + * Size: 000034 + */ +static u32 Cmd_UpdateSync() +{ + Jam_UpdateTrack(SEQ_P, SEQ_ARG[0]); + return 0; +} + +/* + * --INFO-- + * Address: 800120E0 + * Size: 00002C + */ +static u32 Cmd_BusConnect() +{ + if (SEQ_ARG[0] < 6) { + SEQ_P->parentController.busConnect[SEQ_ARG[0]] = SEQ_ARG[1]; + } + return 0; +} + +/* + * --INFO-- + * Address: 80012120 + * Size: 00001C + */ +static u32 Cmd_PauseStatus() +{ + SEQ_P->pauseStatus = SEQ_ARG[0]; + return 0; +} + +/* + * --INFO-- + * Address: 80012140 + * Size: 000044 + */ +static u32 Cmd_SetInterrupt() +{ + SEQ_P->interruptEnable |= (1 << SEQ_ARG[0]); + SEQ_P->interruptAddresses[SEQ_ARG[0]] = SEQ_ARG[1]; + return 0; +} + +/* + * --INFO-- + * Address: 800121A0 + * Size: 000030 + */ +static u32 Cmd_DisInterrupt() +{ + u8 arg; + arg = SEQ_ARG[0]; + arg = 1 << arg; + SEQ_P->interruptEnable &= ~arg; + return 0; +} + +/* + * --INFO-- + * Address: 800121E0 + * Size: 000014 + */ +static u32 Cmd_ClrI() +{ + SEQ_P->interruptActive = 0; + return 0; +} + +/* + * --INFO-- + * Address: 80012200 + * Size: 000014 + */ +static u32 Cmd_SetI() +{ + SEQ_P->interruptActive = 1; + return 0; +} + +/* + * --INFO-- + * Address: 80012220 + * Size: 00002C + */ +static u32 Cmd_RetI() +{ + SEQ_P->waitTimer = SEQ_P->_3CC; + SEQ_P->interruptActive = 0; + SEQ_P->programCounter = SEQ_P->savedProgramCounter; + return 2; +} + +/* + * --INFO-- + * Address: 80012260 + * Size: 000034 + */ +static u32 Cmd_IntTimer() +{ + SEQ_P->timerCount = SEQ_ARG[0]; + SEQ_P->timer = SEQ_ARG[1]; + SEQ_P->maxTime = SEQ_ARG[1]; + return 0; +} + +/* + * --INFO-- + * Address: 800122A0 + * Size: 00002C + */ +static u32 Cmd_ConnectOpen() +{ + Jam_RegistTrack(SEQ_P, SEQ_P->connectionId); + return 0; +} + +/* + * --INFO-- + * Address: 800122E0 + * Size: 000028 + */ +static u32 Cmd_ConnectClose() +{ + Jam_UnRegistTrack(SEQ_P); + return 0; +} + +/* + * --INFO-- + * Address: 80012320 + * Size: 000060 + */ +static u32 Cmd_SyncCPU() +{ + u16 seq_arg; + u16 param_3; + + seq_arg = SEQ_ARG[0]; + if (JAM_CALLBACK_FUNC) { + param_3 = JAM_CALLBACK_FUNC(SEQ_P, seq_arg); + } else { + param_3 = 0xffff; + } + Jam_WriteRegDirect(SEQ_P, 3, param_3); + return 0; +} + +/* + * --INFO-- + * Address: 80012380 + * Size: 000038 + */ +static u32 Cmd_FlushAll() +{ + AllStop_1Shot(&SEQ_P->parentController); + FlushRelease_1Shot(&SEQ_P->parentController); + return 0; +} + +/* + * --INFO-- + * Address: 800123C0 + * Size: 00002C + */ +static u32 Cmd_FlushRelease() +{ + FlushRelease_1Shot(&SEQ_P->parentController); + return 0; +} + +/* + * --INFO-- + * Address: 80012400 + * Size: 00002C + */ +static u32 Cmd_Wait3() +{ + SEQ_P->waitTimer = SEQ_ARG[0]; + return SEQ_ARG[0] ? 1 : 0; +} + +/* + * --INFO-- + * Address: 80012440 + * Size: 000044 + */ +static u32 Cmd_TimeBase() +{ + SEQ_P->timeBase = SEQ_ARG[0]; + if (!SEQ_P->parent) { + Jam_UpdateTempo(SEQ_P); + } + return 0; +} + +/* + * --INFO-- + * Address: 800124A0 + * Size: 000050 + */ +static u32 Cmd_Tempo() +{ + SEQ_P->tempo = SEQ_ARG[0]; + if (!SEQ_P->parent) { + Jam_UpdateTempo(SEQ_P); + } else { + SEQ_P->doChangeTempo = TRUE; + } + return 0; +} + +/* + * --INFO-- + * Address: 80012500 + * Size: 0000CC + */ +static u32 Cmd_Finish() +{ + size_t i; + u32 updateFlags; + MoveParam_* temp; + + updateFlags = 0; + for (i = 0; i < 18; ++i) { + temp = &SEQ_P->timedParam.move[i]; + if (temp->duration > 0.0f) { + temp->currentValue += temp->stepSize; + temp->duration -= 1.0f; + if (i <= 5 || i >= 11) { + updateFlags |= 1 << i; + } else { + Osc_Update_Param(SEQ_P, i, temp->currentValue); + } + } + } + SeqUpdate(SEQ_P, updateFlags); + + return 3; +} + +/* + * --INFO-- + * Address: 800125E0 + * Size: 000008 + */ +static u32 Cmd_Nop() +{ + return 0; +} + +/* + * --INFO-- + * Address: 80012600 + * Size: 0000AC + */ +static u32 Cmd_PanPowSet() +{ + size_t i; + + for (i = 0; i < 3; ++i) { + SEQ_P->regParam.param.arguments[i] = SEQ_ARG[i]; + } + for (i = 3; i < 5; ++i) { + SEQ_P->regParam.param.arguments[i] = SEQ_ARG[i] * 327.67f; + } + + return 0; +} + +/* + * --INFO-- + * Address: 800126C0 + * Size: 000094 + */ +static u32 Cmd_IIRSet() +{ + + size_t i; + MoveParam_* iir; + + for (i = 0; i < 4; ++i) { + iir = &SEQ_P->timedParam.move[i + 12]; // IIRs 0 - 4 are at 12-15 + iir->targetValue = (s16)SEQ_ARG[i] / 32768.0f; + iir->currentValue = iir->targetValue; + iir->stepSize = 0.0f; + iir->duration = 1.0f; + } + + return 0; +} + +/* + * --INFO-- + * Address: 80012760 + * Size: 000044 + */ +static u32 Cmd_FIRSet() +{ + Jam_SetExtFirFilterD(SEQ_P->outerParams, (s16*)Jam_OfsToAddr(SEQ_P, SEQ_ARG[0])); + return 0; +} + +/* + * --INFO-- + * Address: 800127C0 + * Size: 000050 + */ +static u32 Cmd_EXTSet() +{ + OuterParam_* ext; + + ext = (OuterParam_*)Jam_OfsToAddr(SEQ_P, SEQ_ARG[0]); + Jam_InitExtBuffer(ext); + Jam_AssignExtBuffer(SEQ_P, ext); + return 0; +} + +/* + * --INFO-- + * Address: 80012820 + * Size: 0000C4 + */ +static u32 Cmd_PanSwSet() +{ + size_t i; + + // Ah yes, let's just construct this on the stack real quick. + u8 calcTypes[] = { 0, 0, 0, 1, 1, 2, 2 }; + u8 parentCalcTypes[] = { 0, 1, 2, 0, 2, 0, 2 }; + + for (i = 0; i < 3; ++i) { + SEQ_P->panCalcTypes[i] = calcTypes[SEQ_ARG[i] >> 5]; + SEQ_P->parentPanCalcTypes[i] = parentCalcTypes[SEQ_ARG[i] >> 5]; + SEQ_P->parentController.panCalcTypes[i] = SEQ_ARG[i] & 0x1f; + SEQ_P->updateFlags |= OuterParamFlag_Pan; + } + + return 0; +} + +/* + * --INFO-- + * Address: 80012900 + * Size: 000040 + */ +static u32 Cmd_OscRoute() +{ + u8 oscRoute; + u8 uVar2; + + oscRoute = SEQ_ARG[0] & 0xf; + uVar2 = SEQ_ARG[0] >> 4 & 0xf; + + SEQ_P->oscillatorRouting[uVar2] = oscRoute; + if (oscRoute == 14) { + SEQ_P->oscillatorParams[uVar2].state = 1; + } + + return 0; +} + +/* + * --INFO-- + * Address: 80012940 + * Size: 0000A0 + */ +static u32 Cmd_IIRCutOff() +{ + u8 index; + size_t i; + MoveParam_* iir; + + index = SEQ_ARG[0]; + for (i = 0; i < 4; ++i) { + iir = &SEQ_P->timedParam.move[i + 12]; // IIRs 0 - 4 are at 12-15 + iir->targetValue = CUTOFF_TO_IIR_TABLE[index][i] / 32767.0f; + iir->currentValue = iir->targetValue; + iir->stepSize = 0.0f; + iir->duration = 1.0f; + } + + return 0; +} + +/* + * --INFO-- + * Address: 800129E0 + * Size: 000040 + */ +static u32 Cmd_OscFull() +{ + Osc_Setup_Full(SEQ_P, SEQ_ARG[0], SEQ_ARG[1], SEQ_ARG[2]); + return 0; +} + +/* + * --INFO-- + * Address: 80012A20 + * Size: 000068 + */ +static u32 Cmd_CheckWave() +{ + SOUNDID_ soundID; + u32 uVar2; + + soundID.value = SEQ_ARG[0] | (Jam_ReadRegDirect(SEQ_P, 6) << 16); + uVar2 = One_CheckInstWave(soundID); + Jam_WriteRegDirect(SEQ_P, 3, (u8)uVar2); + return 0; +} + +/* + * --INFO-- + * Address: 80012AA0 + * Size: 000204 + */ +static u32 Cmd_Printf() +{ + char fmtStr[0x80]; + u8 fmtFlags[4]; + u32 fmtParms[4]; + size_t fmtCount; + size_t i; + + fmtCount = 0; + for (i = 0; i < (u32)ARRAY_COUNT(fmtStr); ++i) { + fmtStr[i] = __ByteRead(SEQ_P); + if (fmtStr[i] == '\0') { + // Handle end of string + break; + } + if (fmtStr[i] == '\\') { + // Handle escape sequences (just the one) + fmtStr[i] = __ByteRead(SEQ_P); + + if (fmtStr[i] == '\0') { + // Unexpected end of string! + break; + } + switch (fmtStr[i]) { + case 'n': + // Convert newlines to... carriage returns? + fmtStr[i] = '\r'; + break; + } + continue; + } + if (fmtStr[i] == '%') { + // Handle conversion specifiers (plus a few custom ones!) + ++i; + fmtStr[i] = __ByteRead(SEQ_P); + + if (fmtStr[i] == '\0') { + // Unexpected end of string! + break; + } + switch (fmtStr[i]) { + case 'd': // Decimal + fmtFlags[fmtCount] = 0; + break; + case 'x': // Hexadecimal + fmtFlags[fmtCount] = 1; + break; + case 's': // String + fmtFlags[fmtCount] = 2; + break; + case 'r': // ? + fmtFlags[fmtCount] = 3; + fmtStr[i] = 'd'; + break; + case 'R': // ? + fmtFlags[fmtCount] = 4; + fmtStr[i] = 'x'; + break; + case 't': // ? + fmtFlags[fmtCount] = 5; + fmtStr[i] = 'x'; + break; + } + ++fmtCount; + continue; + } + } + for (i = 0; i < fmtCount; ++i) { + fmtParms[i] = __ByteRead(SEQ_P); + if (fmtFlags[i] == 2) { + fmtParms[i] = (u32)Jam_OfsToAddr(SEQ_P, fmtParms[i]); + } else if (fmtFlags[i] == 5) { + fmtParms[i] = SEQ_P->trackId; + } else if (fmtFlags[i] >= 3) { + fmtParms[i] = __ExchangeRegisterValue(SEQ_P, fmtParms[i]); + } + } + // A restoration of this command's functionality can be enabled below: +#if 0 + OSReport(fmtStr, fmtParms[0], fmtParms[1], fmtParms[2], fmtParms[3]); +#endif + return 0; +} + +static ArgListPair Arglist[CMD_COUNT] = { + { 0, 0x0000 }, // + { 2, 0x0008 }, // OpenTrack + { 2, 0x0008 }, // OpenTrackBros + { 1, 0x0002 }, // Call + { 0, 0x0000 }, // CallF + { 0, 0x0000 }, // Ret + { 1, 0x0000 }, // RetF + { 1, 0x0002 }, // Jmp + { 0, 0x0000 }, // JmpF + { 1, 0x0001 }, // LoopS + { 0, 0x0000 }, // LoopE + { 2, 0x0000 }, // ReadPort + { 2, 0x000c }, // WritePort + { 1, 0x0000 }, // CheckPortImport + { 1, 0x0000 }, // CheckPortExport + { 1, 0x0003 }, // WaitReg + { 2, 0x0005 }, // ConnectName + { 2, 0x000c }, // ParentWritePort + { 2, 0x000c }, // ChildWritePort + { 2, 0x000f }, // + { 1, 0x0000 }, // SetLastNote + { 1, 0x0000 }, // TimeRelate + { 1, 0x0000 }, // SimpleOsc + { 2, 0x0008 }, // SimpleEnv + { 5, 0x0155 }, // SimpleADSR + { 1, 0x0000 }, // Transpose + { 1, 0x0000 }, // CloseTrack + { 1, 0x0000 }, // OutSwitch + { 1, 0x0001 }, // UpdateSync + { 2, 0x0004 }, // BusConnect + { 1, 0x0000 }, // PauseStatus + { 2, 0x0008 }, // SetInterrupt + { 1, 0x0000 }, // DisInterrupt + { 0, 0x0000 }, // ClrI + { 0, 0x0000 }, // SetI + { 0, 0x0000 }, // RetI + { 2, 0x0004 }, // IntTimer + { 0, 0x0000 }, // ConnectOpen + { 0, 0x0000 }, // ConnectClose + { 1, 0x0001 }, // SyncCPU + { 0, 0x0000 }, // FlushAll + { 0, 0x0000 }, // FlushRelease + { 1, 0x0002 }, // Wait3 + { 5, 0x0000 }, // PanPowSet + { 4, 0x0055 }, // IIRSet + { 1, 0x0002 }, // FIRSet + { 1, 0x0002 }, // EXTSet + { 3, 0x0000 }, // PanSwSet + { 1, 0x0000 }, // OscRoute + { 1, 0x0000 }, // IIRCutOff + { 3, 0x0028 }, // OscFull + { 0, 0x0000 }, // + { 0, 0x0000 }, // + { 0, 0x0000 }, // + { 0, 0x0000 }, // + { 0, 0x0000 }, // + { 0, 0x0000 }, // + { 0, 0x0000 }, // + { 1, 0x0001 }, // CheckWave + { 0, 0x0000 }, // Printf + { 0, 0x0000 }, // Nop + { 1, 0x0001 }, // Tempo + { 1, 0x0001 }, // TimeBase + { 0, 0x0000 }, // Finish + +}; + +static CmdFunction CMDP_LIST[CMD_COUNT] = { + NULL, + Cmd_OpenTrack, + Cmd_OpenTrackBros, + Cmd_Call, + Cmd_CallF, + Cmd_Ret, + Cmd_RetF, + Cmd_Jmp, + Cmd_JmpF, + Cmd_LoopS, + Cmd_LoopE, + Cmd_ReadPort, + Cmd_WritePort, + Cmd_CheckPortImport, + Cmd_CheckPortExport, + Cmd_WaitReg, + Cmd_ConnectName, + Cmd_ParentWritePort, + Cmd_ChildWritePort, + NULL, + Cmd_SetLastNote, + Cmd_TimeRelate, + Cmd_SimpleOsc, + Cmd_SimpleEnv, + Cmd_SimpleADSR, + Cmd_Transpose, + Cmd_CloseTrack, + Cmd_OutSwitch, + Cmd_UpdateSync, + Cmd_BusConnect, + Cmd_PauseStatus, + Cmd_SetInterrupt, + Cmd_DisInterrupt, + Cmd_ClrI, + Cmd_SetI, + Cmd_RetI, + Cmd_IntTimer, + Cmd_ConnectOpen, + Cmd_ConnectClose, + Cmd_SyncCPU, + Cmd_FlushAll, + Cmd_FlushRelease, + Cmd_Wait3, + Cmd_PanPowSet, + Cmd_IIRSet, + Cmd_FIRSet, + Cmd_EXTSet, + Cmd_PanSwSet, + Cmd_OscRoute, + Cmd_IIRCutOff, + Cmd_OscFull, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + Cmd_CheckWave, + Cmd_Printf, + Cmd_Nop, + Cmd_Tempo, + Cmd_TimeBase, + Cmd_Finish, +}; + +/* + * --INFO-- + * Address: 80012CC0 + * Size: 000130 + */ +u32 Cmd_Process(seqp_* track, u8 cmd, u16 param_3) +{ + ArgListPair argpair; + u16 argTypes; + size_t i; + u32 arg; + CmdFunction function; + seqp_** REF_track; + u8* REF_cmd; + + REF_track = &track; + REF_cmd = &cmd; + + argpair = Arglist[cmd - 0xC0]; + argTypes = argpair.argTypes | param_3; + for (i = 0; i < argpair.argCount; ++i) { + switch (argTypes & 0x03) { + case 0: // 8-bit immediate value + arg = __ByteRead(track); + break; + case 1: // 16-bit immediate value + arg = __WordRead(track); + break; + case 2: // 24-bit immediate value + arg = __24Read(track); + break; + case 3: // Register value + arg = __ExchangeRegisterValue(track, __ByteRead(track)); + break; + } + + argTypes = argTypes >> 2; + SEQ_ARG[i] = arg; + } + + // Me when I have to introduce global state because I'm bored. + SEQ_CMD = cmd; + SEQ_P = track; + + function = CMDP_LIST[cmd - 0xC0]; + if (!function) { + return 0; + } + return function(); +} + +/* + * --INFO-- + * Address: 80012E00 + * Size: 0000A8 + */ +u32 RegCmd_Process(seqp_* track, BOOL param_2, u32 param_3) +{ + size_t i; + u8 uVar4; + u8 uVar3; + u16 uVar5; + u16 uVar6; // Uninitialized! Naughty! + + uVar4 = __ByteRead(track); + if (param_2 == TRUE) { + uVar4 = __ExchangeRegisterValue(track, uVar4); + } + if (param_2 != TRUE || param_3 != 0) { + uVar3 = __ByteRead(track); + uVar5 = 0b11; + for (i = 0; i < param_3 + 1; ++i) { + if (uVar3 & 0b10000000) { + uVar6 |= uVar5; + } + uVar3 = uVar3 << 1; + uVar5 = uVar5 << 2; + } + } + return Cmd_Process(track, uVar4, uVar6); +} + +// TODO: These five values appear all over this file. They mean something. +static u8 osc_table[] = { 0x01, 0x02, 0x08, 0x04, 0x10 }; + +/* + * --INFO-- + * Address: 80012EC0 + * Size: 0008C0 + * Note: (Roughly) Equivalent to `JASTrack::mainProc` in later JAudio. + */ +s32 Jam_SeqmainNote(seqp_* track, u8 isMuted) +{ + BOOL var_r26; + u8 bVar9; + u8 velocity; + u32 uVar2; + s32 uVar5; + u8 bVar10_2; + f32 tempoProportion; + u8 opcode; + u8 uVar6; + u8 keyTarget; + u8 pitch; + u8 bVar10; + int local_64; + int iVar11; + int iVar11_2; + int iVar12; + u32 seqRes; + int duration; + jc_* pjVar3; + int iVar11_3; + u8 voice; + + if (0) { + (void)&bVar10; + } + if (0) { + (void)&keyTarget; + } + if (0) { + (void)&local_64; + } + + seqRes = 0; + if (track->parent && track->doChangeTempo == TRUE) { + tempoProportion = (float)track->tempo / (float)track->parent->tempo; + if (tempoProportion > 1.0f) { + tempoProportion = 1.0f; + } + track->tempoAccumulator += tempoProportion; + if (track->tempoAccumulator < 1.0f) { + return 0; + } + track->tempoAccumulator -= 1.0f; + } + + { // This whole part is not present(?) in later JAudio. + if (track->parent) { + track->isMuted = isMuted; + } + if (track->parent && track->parentController.chanCount != 0) { + pjVar3 = List_GetChannel(&track->parentController.freeChannels); + if (pjVar3) { + List_AddChannel(&track->parent->parentController.freeChannels, pjVar3); + pjVar3->mMgr = &track->parent->parentController; + track->parentController.chanCount--; + track->parent->parentController.chanCount++; + } + } + // This resembles `JASTrack::getTranspose` of later JAudio. + if (track->parent) { + track->finalTranspose = track->transpose + track->parent->finalTranspose; + } else { + track->finalTranspose = track->transpose; + } + } + + Jam_SetInterrupt(track, 7); + { // This resembles `JASIntrMgr::timerProcess` of later JAudio. + if (track->timer != 0) { + if (--track->timer == 0) { + Jam_SetInterrupt(track, 6); + if (track->timerCount != 0) { + if (--track->timerCount != 0) { + track->timer = track->maxTime; + } + } else { + track->timer = track->maxTime; + } + } + } + } + +try_interrupt: + Jam_TryInterrupt(track); + if (track->isPaused && (track->pauseStatus & 2)) { + goto LAB_800136e0; + } + track->tickCounter++; + if (track->waitTimer == -1) { + if ((u8)CheckNoteStop(track, 0)) { // TODO: CheckNoteStop should return u8 or C++ bool + track->waitTimer = 0; + } else { + goto timed; + } + } + + if (track->waitTimer > 0) { + --track->waitTimer; + if (track->waitTimer != 0) { + goto timed; + } + if (track->_D0 != -1 && track->_D4 == 0) { + for (local_64 = 0; local_64 < (int)track->_90; local_64++) { + track->_94[local_64] = -1; + track->channels[local_64] = NULL; + } + } + } + + while (TRUE) { + opcode = __ByteRead(track); + if (!(opcode & 0x80)) { + // MIDI pitch (0-127) + pitch = opcode; + pitch += track->finalTranspose; + + if ((bVar10 = __ByteRead(track)) & 0x80) { + pitch = __ExchangeRegisterValue(track, pitch); + pitch += track->finalTranspose; + } + + (void)pitch; + + if (bVar10 >> 5 & 2) { + keyTarget = pitch; + pitch = track->_D5; + } + + velocity = __ByteRead(track); + if (velocity >= 0x80) { + velocity = __ExchangeRegisterValue(track, velocity - 0x80); + } + + u32 lowBits = bVar10; + lowBits &= 7; + if (lowBits == 0) { + voice = 0; + bVar9 = __ByteRead(track); + if (bVar9 >= 0x80) { + bVar9 = __ExchangeRegisterValue(track, bVar9 - 0x80); + } + uVar2 = 0; + for (iVar11 = 0; iVar11 < (bVar10 >> 3 & 3); iVar11++) { + uVar2 = uVar2 << 8 | __ByteRead(track); + } + if ((u32)(bVar10 >> 3 & 3) == 1 && uVar2 >= 0x80) { + uVar2 = __ExchangeRegisterValue(track, uVar2 - 0x80); + } + } else { + voice = lowBits; + // fake volatile for matching + if (*(volatile u8*)&bVar10 >> 3 & 3) { + voice = __ExchangeRegisterValue(track, voice - 1); + if (voice >= 8) { + break; + } + } + uVar2 = -1; + bVar9 = 100; + } + + track->_D4 = bVar10 >> 5 & 3; + + BOOL cond = track->_D6 ? TRUE : FALSE; + var_r26 = FALSE; + + for (int j = 0; j < 1; j++) { + int unused = j * 2; + (void)&pitch; + (void)(s32)velocity; + (void)track->_94[voice]; + + if (cond) { + duration = uVar2; + if (track->_D4 & 1) { + duration = -1; + } + if (duration != -1) { + duration = Jam_SEQtimeToDSPtime(track, duration, bVar9); + } + if (track->isPaused && (track->pauseStatus & 0x10)) { + iVar11_2 = -1; + } else { + iVar11_2 = GateON(track, voice, pitch, velocity, duration); + } + } else { + if ((duration = uVar2) != -1) { + duration = Jam_SEQtimeToDSPtime(track, duration, bVar9); + } + if (track->_D4 & 1) { + duration = -1; + } + if (track->isPaused && (track->pauseStatus & 0x10)) { + iVar11_2 = -1; + } else { + iVar11_2 = NoteON(track, voice, pitch, velocity, duration); + } + } + + if (iVar11_2 != -1) { + track->_94[voice] = pitch; + var_r26 = TRUE; + } + !unused; + } + + track->_90 = var_r26; + track->_CC = bVar9; + track->_CD = velocity; + track->_D0 = uVar2; + + if (track->_D4 & 1) { + track->_D6 = TRUE; + } else { + track->_D6 = FALSE; + } + + if (track->_D4 & 2) { + s32 steps = duration; + if (steps == -1) { + steps = Jam_SEQtimeToDSPtime(track, uVar2, track->_CC); + } + SetKeyTarget_1Shot(track->channels[0], keyTarget + track->finalTranspose, steps); + pitch = keyTarget; + } + + track->_D5 = pitch; + + if (uVar2 != -1) { + track->waitTimer = uVar2; + if (uVar2 == 0) { + track->waitTimer = -1; + } + break; + } + } else if ((opcode & 0xf0) == 0x80 || opcode == 0xf9) { + iVar11_3 = 1; + uVar5 = 0; + if (opcode == 0xf9) { + bVar10_2 = __ByteRead(track); + uVar6 = __ExchangeRegisterValue(track, bVar10_2 & 7); + if (uVar6 > 7 || uVar6 == 0) { + if ((bVar10_2 & 0x80) != 0) { + __ByteRead(track); + } + continue; + } + opcode = uVar6 + 0x80; + if (bVar10_2 & 0x80) { + opcode += 8; + } + } + uVar6 = opcode & 0x0f; + if (uVar6 == 8) { + iVar11_3 = 2; + uVar6 -= 8; + } + if (uVar6 > 8) { + uVar6 -= 8; + uVar5 = __ByteRead(track); + if (uVar5 > 100) { + uVar5 = (uVar5 - 98) * 20; + } + } + if (uVar6 == 0) { + // This for loop init feels fake... but idk. Check this again later. + for (track->waitTimer = iVar12 = 0; iVar12 < iVar11_3; iVar12++) { + track->waitTimer = track->waitTimer << 8 | __ByteRead(track); + } + if (track->waitTimer == 0) { + continue; + } + break; + } + if (uVar5 == 0) { + NoteOFF(track, uVar6); + } else { + NoteOFF_R(track, uVar6, uVar5); + } + } else { + // This portion is equivalent to `JASSeqParser::parseSeq` in later JAudio. + u32 cmdResult = 0; + if ((opcode & 0xf0) == 0x90) { + Jam_WriteTimeParam(track, opcode & 0x0f); + } else if ((opcode & 0xf0) == 0xa0) { + Jam_WriteRegParam(track, opcode & 0x0f); + } else if ((opcode & 0xf0) == 0xb0) { + u32 param_3 = opcode & 7; + cmdResult = RegCmd_Process(track, (opcode & 8) ? TRUE : FALSE, param_3); + } else { + cmdResult = Cmd_Process(track, opcode, 0); + } + + if (cmdResult == 0) { + continue; + } else if (cmdResult == 1) { + break; + } else if (cmdResult == 2) { + goto try_interrupt; + } else if (cmdResult == 3) { + return -1; + } + } + } + +timed: + // This portion is equivalent to `JASTrack::updateTimedParam` in later JAudio. + for (int i = 0; i < 18; i++) { + MoveParam_* move = &track->timedParam.move[i]; + if (move->duration > 0.0f) { + move->currentValue += move->stepSize; + move->duration -= 1.0f; + if (i <= 5 || i >= 11) { + seqRes |= (1 << i); + } else { + Osc_Update_Param(track, i, move->currentValue); + } + } + } + + if (track->oscillatorRouting[0] == 0x0E) { + seqRes |= osc_table[track->oscillators[0].mode]; + } + if (track->oscillatorRouting[1] == 0x0E) { + seqRes |= osc_table[track->oscillators[1].mode]; + } + +LAB_800136e0: + track->updateFlags |= seqRes; + + for (int i = 0; i < 16; i++) { + if (track->children[i] && track->children[i]->trackState != 0) { + // Return of the worst bit extract extraction method known to man. + BOOL childIsMuted = track->isMuted | ((track->childMuteMask & (1 << i)) >> i); + if (Jam_SeqmainNote(track->children[i], childIsMuted) == -1) { + Jaq_CloseTrack(track->children[i]); + track->children[i] = NULL; + } + } + } + + return 0; +} + +/* + * --INFO-- + * Address: 80013780 + * Size: 0000A8 + */ +void SeqUpdate(seqp_* track, u32 updateFlags) +{ + u32 finalFlags; + size_t i; + + finalFlags = updateFlags | track->updateFlags; + if (track->outerParams) { + finalFlags |= track->outerParams->updateFlags; + track->outerParams->updateFlags = 0; + } + + track->updateFlags = OuterParamFlag_None; + if (finalFlags) { + Jam_UpdateTrack(track, finalFlags); + } + + for (i = 0; i < 16; ++i) { + if (track->children[i] && track->children[i]->trackState) { + SeqUpdate(track->children[i], finalFlags); + } + } +} diff --git a/src/static/jaudio_NES/internal/jamosc.c b/src/static/jaudio_NES/internal/jamosc.c new file mode 100644 index 00000000..1dd6caf2 --- /dev/null +++ b/src/static/jaudio_NES/internal/jamosc.c @@ -0,0 +1,195 @@ +#include "jaudio_NES/jamosc.h" +#include "jaudio_NES/jammain_2.h" + +s16 VIB_TABLE[] = { 0, 0, 0, 0, 20, 0x7fff, 0, 20, 0, 0, 0x14, 0xc000, 0, 20, 0, 13, 0, 1 }; +s16 TRE_TABLE[] = { 0, 0, 0x7fff, 0, 20, 0, 0, 20, 0x8001, 0, 0x14, 0, 0, 0x14, 0x7fff, 13, 0, 1 }; +s16 REL_TABLE[] = { 0, 10, 0, 15, 1, 0 }; + +Osc_ VIBRATO_DEF = { 1, 0.8f, VIB_TABLE, VIB_TABLE, 0.0f, 1.0f }; +Osc_ TREMOLO_DEF = { 0, 1.0f, TRE_TABLE, TRE_TABLE, 0.0f, 1.0f }; +Osc_ ENVELOPE_DEF = { 0, 1.0f, NULL, REL_TABLE, 1.0f, 0.0f }; + +s16 ADS_TABLE[] = { 0, 0, 0x7fff, 0, 0, 0x7fff, 0, 0, 0, 14, 0, 0 }; +Osc_ ADSR_DEF = { 0, 1.0f, NULL, NULL, 1.0f, 0.0f }; +Osc_ OSC_DEF = { 0, 1.0f, NULL, REL_TABLE, 1.0f, 0.0f }; + +/* + * --INFO-- + * Address: 80014CA0 + * Size: 000090 + * Note: Equivalent to `JASTrack::updateOscParam` in later JAudio. + */ +void Osc_Update_Param(seqp_* track, u8 id, f32 val) +{ + u8* REF_id = &id; + f32* REF_val = &val; + + switch (id) { + case 6: + track->oscillators[0].width = val; + break; + case 7: + track->oscillators[0].rate = val; + break; + case 8: + track->oscillators[0].vertex = val; + break; + case 9: + track->oscillators[1].width = val; + break; + case 10: + track->oscillators[1].rate = val; + break; + case 11: + track->oscillators[1].vertex = val; + break; + } +} + +/* + * --INFO-- + * Address: 80014D40 + * Size: 00003C + */ +void Osc_Setup_Vibrato(seqp_* track, u8 id) +{ + track->oscillators[id] = VIBRATO_DEF; +} + +/* + * --INFO-- + * Address: 80014D80 + * Size: 00003C + */ +void Osc_Setup_Tremolo(seqp_* track, u8 id) +{ + track->oscillators[id] = TREMOLO_DEF; +} + +/* + * --INFO-- + * Address: 80014DC0 + * Size: 000064 + * Note: Equivalent to `JASTrack::oscSetupSimple` in later JAudio. + */ +void Osc_Setup_Simple(seqp_* track, u8 id) +{ + switch (id) { + case 0: + Osc_Setup_Vibrato(track, 1); + break; + case 1: + Osc_Setup_Tremolo(track, 0); + break; + case 2: + Osc_Setup_Tremolo(track, 1); + break; + } +} + +/* + * --INFO-- + * Address: 80014E40 + * Size: 000010 + */ +void Osc_Clear_Overwrite(seqp_* track) +{ + track->oscillatorRouting[0] = 15; + track->oscillatorRouting[1] = 15; +} + +/* + * --INFO-- + * Address: 80014E60 + * Size: 00004C + */ +void Osc_Init_Env(seqp_* track) +{ + track->oscillators[0] = ENVELOPE_DEF; + + Osc_Clear_Overwrite(track); +} + +/* + * --INFO-- + * Address: 80014EC0 + * Size: 000094 + */ +void Osc_Setup_SimpleEnv(seqp_* track, u8 id, u32 val) +{ + switch (id) { + case 0: + track->oscillators[0] = ENVELOPE_DEF; + track->oscillators[0].attackVecOffset = (s16*)Jam_OfsToAddr(track, val); + break; + + case 1: + track->oscillators[0].releaseVecOffset = (s16*)Jam_OfsToAddr(track, val); + break; + } +} + +/* + * --INFO-- + * Address: 80014F60 + * Size: 0000B0 + */ +void Osc_Setup_ADSR(seqp_* track, s16* addr) +{ + track->oscillators[0] = ADSR_DEF; + + track->oscillators[0].attackVecOffset = track->adsTable; + track->oscillators[0].releaseVecOffset = track->relTable; + + for (int i = 0; i < 12; i++) { + track->adsTable[i] = ADS_TABLE[i]; + } + + for (int i = 0; i < 6; i++) { + track->relTable[i] = REL_TABLE[i]; + } + + track->adsTable[1] = addr[0]; + track->adsTable[4] = addr[1]; + track->adsTable[7] = addr[2]; + track->adsTable[8] = addr[3]; + track->relTable[1] = addr[4]; +} + +/* + * --INFO-- + * Address: 80015020 + * Size: 00010C + */ +void Osc_Setup_Full(seqp_* track, u8 flag, u32 offs1, u32 offs2) +{ + u32 a = flag & 0xF; + u32 b = flag & 0x40; + u32 idx = (flag >> 4) & 0x1; + u32 c = flag & 0x20; + u32 d = flag & 0x80; + if (d) { + track->oscillators[idx] = ENVELOPE_DEF; + + track->oscillators[idx].mode = a; + switch (a) { + case 1: + track->oscillators[idx].vertex = 1.0f; + break; + } + } + + if (b) { + if (offs1 == 0) { + track->oscillators[idx].attackVecOffset = NULL; + } + track->oscillators[idx].attackVecOffset = (s16*)Jam_OfsToAddr(track, offs1); + } + + if (c) { + if (offs2 == 0) { + track->oscillators[idx].releaseVecOffset = REL_TABLE; + } + track->oscillators[idx].releaseVecOffset = (s16*)Jam_OfsToAddr(track, offs2); + } +} diff --git a/src/static/jaudio_NES/internal/memory.c b/src/static/jaudio_NES/internal/memory.c new file mode 100644 index 00000000..642427e0 --- /dev/null +++ b/src/static/jaudio_NES/internal/memory.c @@ -0,0 +1,604 @@ +#include "jaudio_NES/memory.h" + +/* + * --INFO-- + * Address: ........ + * Size: 00001C + */ +void __CalcRelf(f32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000170 + */ +void MakeReleaseTable() +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000A0 + */ +void Nas_ResetIDtable() +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000E0 + */ +void Nas_ForceStopChannel(s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00006C + */ +void Nas_ForceReleaseChannel(s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000084 + */ +void Nas_ForceStopSeq(s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000030 + */ +void* Nas_CacheOff(u8*, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00006C + */ +void Nas_2ndHeapAlloc_CL(ALHeap*, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00006C + */ +void* Nas_2ndHeapAlloc(ALHeap*, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00003C + */ +void Nas_NcHeapAlloc(ALHeap*, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00003C + */ +void Nas_NcHeapAlloc_CL(ALHeap*, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000054 + */ +void* Nas_HeapAlloc_CL(ALHeap*, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000048 + */ +void Nas_TmpAlloc(ALHeap*, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000034 + */ +void Nas_HeapFree(ALHeap*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 80005640 + * Size: 00006C + */ +void* Nas_HeapAlloc(ALHeap* heap, s32 size) +{ + s32* REF_size; + + REF_size = &size; + u32 roundedSize = ALIGN_NEXT(size, 32); + if (!heap->base) { + return NULL; + } + + u8* prev = heap->current; + if (prev + roundedSize <= heap->base + heap->length) { + heap->current = prev + roundedSize; + } else { + return NULL; + } + + heap->count++; + heap->last = prev; + return prev; +} + +/* + * --INFO-- + * Address: 800056C0 + * Size: 000058 + */ +void Nas_HeapInit(ALHeap* heap, u8* p2, s32 p3) +{ + ALHeap** REF_heap; + + int length; + + REF_heap = &heap; + heap->count = 0; + if (!p2) { + heap->length = 0; + heap->current = NULL; + heap->last = NULL; + } else { + length = p3 - ((u32)p2 & 0x1F); + heap->base = (u8*)ALIGN_NEXT((u32)p2, 32); + heap->current = heap->base; + heap->length = length; + heap->last = NULL; + } +} + +/* + * --INFO-- + * Address: ........ + * Size: 000018 + */ +void Nas_SzStayClear(SZStay*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00003C + */ +void Nas_SzAutoClear(SZAuto*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000014 + */ +// void Nas_SzCustomClear(SZCustom*) +// { +// // UNUSED FUNCTION +// } + +/* + * --INFO-- + * Address: ........ + * Size: 00010C + */ +void Nas_SzStayDelete(s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000068 + */ +void Nas_SzHeapReset(u32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000058 + */ +void Nas_SzHeapDivide(AudioHeapstrc*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000014 + */ +void Nas_SzDataDivide(DataHeapstrc*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000B4 + */ +void Nas_SzStayDivide(StayHeapstrc*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000B4 + */ +void Nas_SzAutoDivide(AutoHeapstrc*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0006CC + */ +void* Nas_SzHeapAlloc(s32, s32, s32, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000064 + */ +u32 Nas_SzCacheCheck(s32, s32, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000114 + */ +void __Nas_SzCacheCheck_Inner(s32, s32, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000D4 + */ +void Nas_InitFilterCoef(f32, f32, u16*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000020 + */ +void Nas_ClearFilter(s16*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000040 + */ +void Nas_SetLPFilter(s16*, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000044 + */ +void Nas_SetHPFilter(s16*, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000134 + */ +void Nas_SetBPFilter(s16*, s32, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000004 + */ +void __DownDelay(delay*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000A0 + */ +void __Nas_DelayDown() +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000048 + */ +void __Nas_DacClear() +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000258 + */ +s32 Nas_SpecChange() +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0006B4 + */ +void __Nas_MemoryReconfig() +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00005C + */ +void* EmemOnCheck(s32, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00007C + */ +void* EmemAlloc(s32, s32, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000064 + */ +void Nas_Alloc_Single(s32, s32, u8*, char, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000C4 + */ +void Nas_Init_Single(s32, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000200 + */ +void __Nas_Alloc_Single_Auto_Inner(s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00012C + */ +void __SearchBank(SwMember*, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000EC + */ +void __KillSwMember(SwMember*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000034 + */ +void __RomAddrSet(SwMember*, smzwavetable*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000094 + */ +void __Nas_Alloc_Single_Stay_Inner(s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000040 + */ +void __Do_EmemKill(SwMember*, s32, s32, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000128 + */ +void Emem_KillSwMember() +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000A0 + */ +void __RestoreAddr(Wavelookuptable*, smzwavetable*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000030 + */ +void DirtyWave(s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000030 + */ +void EntryWave(s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000238 + */ +void __ExchangeWave(s32, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000088 + */ +void Dirty_AllWave() +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000AC + */ +void __Nas_GetCompressBuffer(delay*) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00028C + */ +void Nas_SetDelayLineParam(s32, s32, s32, s32) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0001E0 + */ +void Nas_SetDelayLine(s32, fxconfig_*, s32) +{ + // UNUSED FUNCTION +} diff --git a/src/static/jaudio_NES/internal/midplay.c b/src/static/jaudio_NES/internal/midplay.c new file mode 100644 index 00000000..b4178243 --- /dev/null +++ b/src/static/jaudio_NES/internal/midplay.c @@ -0,0 +1,47 @@ +#include "types.h" + +s16 CUTOFF_TO_IIR_TABLE[128][4] = { + { 0x0f5c, 0x0a3d, 0x4665, 0x3999 }, { 0x103f, 0x0a28, 0x45d7, 0x3925 }, { 0x1122, 0x0a14, 0x454a, 0x38b0 }, + { 0x1205, 0x09ff, 0x44bc, 0x383c }, { 0x12e8, 0x09ea, 0x442e, 0x37c8 }, { 0x13cb, 0x09d6, 0x43a0, 0x3754 }, + { 0x14ae, 0x09c1, 0x4312, 0x36e0 }, { 0x1591, 0x09ac, 0x4284, 0x366c }, { 0x1674, 0x0998, 0x41f6, 0x35f8 }, + { 0x1757, 0x0983, 0x4168, 0x3584 }, { 0x183a, 0x096e, 0x40da, 0x3510 }, { 0x191d, 0x095a, 0x404c, 0x349c }, + { 0x1a00, 0x0945, 0x3fbe, 0x3427 }, { 0x1ae3, 0x0931, 0x3f31, 0x33b3 }, { 0x1bc6, 0x091c, 0x3ea3, 0x333f }, + { 0x1ca9, 0x0907, 0x3e15, 0x32cb }, { 0x1d8c, 0x08f3, 0x3d87, 0x3257 }, { 0x1e6f, 0x08de, 0x3cf9, 0x31e3 }, + { 0x1f52, 0x08c9, 0x3c6b, 0x316f }, { 0x2035, 0x08b5, 0x3bdd, 0x30fb }, { 0x2118, 0x08a0, 0x3b4f, 0x3087 }, + { 0x21fc, 0x088b, 0x3ac1, 0x3012 }, { 0x22df, 0x0877, 0x3a33, 0x2f9e }, { 0x23c2, 0x0862, 0x39a6, 0x2f2a }, + { 0x24a5, 0x084d, 0x3918, 0x2eb6 }, { 0x2588, 0x0839, 0x388a, 0x2e42 }, { 0x266b, 0x0824, 0x37fc, 0x2dce }, + { 0x274e, 0x0810, 0x376e, 0x2d5a }, { 0x2831, 0x07fb, 0x36e0, 0x2ce6 }, { 0x2914, 0x07e6, 0x3652, 0x2c72 }, + { 0x29f7, 0x07d2, 0x35c4, 0x2bfe }, { 0x2ada, 0x07bd, 0x3536, 0x2b89 }, { 0x2bbd, 0x07a8, 0x34a8, 0x2b15 }, + { 0x2ca0, 0x0794, 0x341b, 0x2aa1 }, { 0x2d83, 0x077f, 0x338d, 0x2a2d }, { 0x2e66, 0x076a, 0x32ff, 0x29b9 }, + { 0x2f49, 0x0756, 0x3271, 0x2945 }, { 0x302c, 0x0741, 0x31e3, 0x28d1 }, { 0x310f, 0x072d, 0x3155, 0x285d }, + { 0x31f2, 0x0718, 0x30c7, 0x27e9 }, { 0x32d5, 0x0703, 0x3039, 0x2775 }, { 0x33b8, 0x06ef, 0x2fab, 0x2700 }, + { 0x349c, 0x06da, 0x2f1d, 0x268c }, { 0x357f, 0x06c5, 0x2e8f, 0x2618 }, { 0x3662, 0x06b1, 0x2e02, 0x25a4 }, + { 0x3745, 0x069c, 0x2d74, 0x2530 }, { 0x3828, 0x0687, 0x2ce6, 0x24bc }, { 0x390b, 0x0673, 0x2c58, 0x2448 }, + { 0x39ee, 0x065e, 0x2bca, 0x23d4 }, { 0x3ad1, 0x0649, 0x2b3c, 0x2360 }, { 0x3bb4, 0x0635, 0x2aae, 0x22eb }, + { 0x3c97, 0x0620, 0x2a20, 0x2277 }, { 0x3d7a, 0x060c, 0x2992, 0x2203 }, { 0x3e5d, 0x05f7, 0x2904, 0x218f }, + { 0x3f40, 0x05e2, 0x2877, 0x211b }, { 0x4023, 0x05ce, 0x27e9, 0x20a7 }, { 0x4106, 0x05b9, 0x275b, 0x2033 }, + { 0x41e9, 0x05a4, 0x26cd, 0x1fbf }, { 0x42cc, 0x0590, 0x263f, 0x1f4b }, { 0x43af, 0x057b, 0x25b1, 0x1ed7 }, + { 0x4492, 0x0566, 0x2523, 0x1e62 }, { 0x4575, 0x0552, 0x2495, 0x1dee }, { 0x4658, 0x053d, 0x2407, 0x1d7a }, + { 0x473b, 0x0529, 0x2379, 0x1d06 }, { 0x481f, 0x0514, 0x22eb, 0x1c92 }, { 0x4902, 0x04ff, 0x225e, 0x1c1e }, + { 0x49e5, 0x04eb, 0x21d0, 0x1baa }, { 0x4ac8, 0x04d6, 0x2142, 0x1b36 }, { 0x4bab, 0x04c1, 0x20b4, 0x1ac2 }, + { 0x4c8e, 0x04ad, 0x2026, 0x1a4e }, { 0x4d71, 0x0498, 0x1f98, 0x19d9 }, { 0x4e54, 0x0483, 0x1f0a, 0x1965 }, + { 0x4f37, 0x046f, 0x1e7c, 0x18f1 }, { 0x501a, 0x045a, 0x1dee, 0x187d }, { 0x50fd, 0x0445, 0x1d60, 0x1809 }, + { 0x51e0, 0x0431, 0x1cd3, 0x1795 }, { 0x52c3, 0x041c, 0x1c45, 0x1721 }, { 0x53a6, 0x0408, 0x1bb7, 0x16ad }, + { 0x5489, 0x03f3, 0x1b29, 0x1639 }, { 0x556c, 0x03de, 0x1a9b, 0x15c4 }, { 0x564f, 0x03ca, 0x1a0d, 0x1550 }, + { 0x5732, 0x03b5, 0x197f, 0x14dc }, { 0x5815, 0x03a0, 0x18f1, 0x1468 }, { 0x58f8, 0x038c, 0x1863, 0x13f4 }, + { 0x59db, 0x0377, 0x17d5, 0x1380 }, { 0x5abf, 0x0362, 0x1747, 0x130c }, { 0x5ba2, 0x034e, 0x16ba, 0x1298 }, + { 0x5c85, 0x0339, 0x162c, 0x1224 }, { 0x5d68, 0x0324, 0x159e, 0x11b0 }, { 0x5e4b, 0x0310, 0x1510, 0x113b }, + { 0x5f2e, 0x02fb, 0x1482, 0x10c7 }, { 0x6011, 0x02e7, 0x13f4, 0x1053 }, { 0x60f4, 0x02d2, 0x1366, 0x0fdf }, + { 0x61d7, 0x02bd, 0x12d8, 0x0f6b }, { 0x62ba, 0x02a9, 0x124a, 0x0ef7 }, { 0x639d, 0x0294, 0x11bc, 0x0e83 }, + { 0x6480, 0x027f, 0x112f, 0x0e0f }, { 0x6563, 0x026b, 0x10a1, 0x0d9b }, { 0x6646, 0x0256, 0x1013, 0x0d27 }, + { 0x6729, 0x0241, 0x0f85, 0x0cb2 }, { 0x680c, 0x022d, 0x0ef7, 0x0c3e }, { 0x68ef, 0x0218, 0x0e69, 0x0bca }, + { 0x69d2, 0x0204, 0x0ddb, 0x0b56 }, { 0x6ab5, 0x01ef, 0x0d4d, 0x0ae2 }, { 0x6b98, 0x01da, 0x0cbf, 0x0a6e }, + { 0x6c7b, 0x01c6, 0x0c31, 0x09fa }, { 0x6d5f, 0x01b1, 0x0ba3, 0x0986 }, { 0x6e42, 0x019c, 0x0b16, 0x0912 }, + { 0x6f25, 0x0188, 0x0a88, 0x089d }, { 0x7008, 0x0173, 0x09fa, 0x0829 }, { 0x70eb, 0x015e, 0x096c, 0x07b5 }, + { 0x71ce, 0x014a, 0x08de, 0x0741 }, { 0x72b1, 0x0135, 0x0850, 0x06cd }, { 0x7394, 0x0120, 0x07c2, 0x0659 }, + { 0x7477, 0x010c, 0x0734, 0x05e5 }, { 0x755a, 0x00f7, 0x06a6, 0x0571 }, { 0x763d, 0x00e3, 0x0618, 0x04fd }, + { 0x7720, 0x00ce, 0x058b, 0x0489 }, { 0x7803, 0x00b9, 0x04fd, 0x0414 }, { 0x78e6, 0x00a5, 0x046f, 0x03a0 }, + { 0x79c9, 0x0090, 0x03e1, 0x032c }, { 0x7aac, 0x007b, 0x0353, 0x02b8 }, { 0x7b8f, 0x0067, 0x02c5, 0x0244 }, + { 0x7c72, 0x0052, 0x0237, 0x01d0 }, { 0x7d55, 0x003d, 0x01a9, 0x015c }, { 0x7e38, 0x0029, 0x011b, 0x00e8 }, + { 0x7f1b, 0x0014, 0x008d, 0x0074 }, { 0x7fff, 0x0000, 0x0000, 0x0000 }, +}; diff --git a/src/static/jaudio_NES/internal/noteon.c b/src/static/jaudio_NES/internal/noteon.c new file mode 100644 index 00000000..235be219 --- /dev/null +++ b/src/static/jaudio_NES/internal/noteon.c @@ -0,0 +1,201 @@ +#include "jaudio_NES/noteon.h" + +#include "jaudio_NES/audiostruct.h" +#include "jaudio_NES/jammain_2.h" +#include "jaudio_NES/oneshot.h" +#include "jaudio_NES/connect.h" +#include "jaudio_NES/driverinterface.h" + +/* + * --INFO-- + * Address: 80013840 + * Size: 000394 + */ +s32 NoteON(seqp_* track, s32 channel, s32 flag1, s32 flag2, s32 playFlag) +{ + if (track->isMuted && (track->pauseStatus & 0x40)) { + return -1; + } + + if (track->channels[channel]) { + NoteOFF(track, channel); + } + + seqp_* parent = track->parent; + jcs_* jcs = &track->parentController; + u32 reg; + + seqp_* temp = parent; + while (jcs->chanCount == 0 || jcs->freeChannels == 0) { + if (temp == NULL) { + jcs = &track->parentController; + break; + } + jcs = &temp->parentController; + temp = temp->parent; + } + + if (track->flags == 4) { + if (parent == NULL) { + return -1; + } + + if (jcs != &parent->parentController) { + jc_* chan = List_GetChannel(&jcs->freeChannels); + if (chan) { + jcs->chanCount--; + List_AddChannel(&track->parentController.freeChannels, chan); + parent->parentController.chanCount++; + chan->mMgr = &parent->parentController; + } + jcs = &parent->parentController; + } + } else if (jcs != &track->parentController) { + jc_* chan = List_GetChannel(&jcs->freeChannels); + if (chan) { + jcs->chanCount--; + List_AddChannel(&track->parentController.freeChannels, chan); + track->parentController.chanCount++; + chan->mMgr = &track->parentController; + } + jcs = &track->parentController; + } + + reg = Jam_ReadRegDirect(track, 6); + u16 phys = Jac_BnkVirtualToPhysical(reg >> 8); + u32 b = (phys & 0xff) << 8 | reg & 0xff; + u32 a = b << 16 | flag1 << 8 | flag2; + + jc_* sound; + SOUNDID_ id; + id.value = a; + if ((u8)reg >= 0xf0) { + sound = Play_1shot_Osc(jcs, id, playFlag); + } else if ((u8)reg >= 0xe4) { + sound = Play_1shot_Perc(jcs, id, playFlag); + } else { + sound = Play_1shot(jcs, id, playFlag); + } + track->channels[channel] = sound; + if (sound == NULL) { + return -1; + } + track->activeSoundIds[channel] = sound->channelId; + UpdatePanPower_1Shot(sound, track->regParam.param.arguments[0], track->regParam.param.arguments[1], track->regParam.param.arguments[2], + track->regParam.param.arguments[3]); + + for (u32 i = 0; i < 2; i++) { + u32 flag = track->oscillatorRouting[i]; + if (flag == 15 || flag == 14) { + continue; + } + + if (flag >= 8) { + flag -= 8; + if (sound->mOscillators[flag]) { + track->oscillators[i] = *sound->mOscillators[flag]; + } + } else if (flag >= 4) { + flag -= 4; + s16* prev = track->oscillators[i].releaseVecOffset; + if (sound->mOscillators[flag]) { + track->oscillators[i] = *sound->mOscillators[flag]; + track->oscillators[i].releaseVecOffset = prev; + } + } + + Effecter_Overwrite_1ShotD(sound, &track->oscillators[i], flag); + } + + Jam_UpdateTrack(track, 3); + ResetInitialVolume(sound); + return 0; + + s32* REF_channel = &channel; +} + +/* + * --INFO-- + * Address: 80013BE0 + * Size: 000090 + */ +s32 NoteOFF_R(seqp_* track, u8 param_2, u16 param_3) +{ + u8* REF_param_2; + jc_* jc; + + REF_param_2 = ¶m_2; + if (jc = track->channels[param_2]) { + if (jc->channelId == track->activeSoundIds[param_2]) { + if (param_3 == 0) { + Stop_1Shot(jc); + } else { + Stop_1Shot_R(jc, param_3); + } + } + track->channels[param_2] = NULL; + track->activeSoundIds[param_2] = 0; + return 1; + } + return 0; +} + +/* + * --INFO-- + * Address: 80013C80 + * Size: 000024 + */ +s32 NoteOFF(seqp_* track, u8 param_2) +{ + return NoteOFF_R(track, param_2, 0); +} + +/* + * --INFO-- + * Address: 80013CC0 + * Size: 000058 + */ +s32 GateON(seqp_* track, s32 param_2, s32 param_3, s32 param_4, s32 param_5) +{ + s32* REF_param_3 = ¶m_3; + + if (track->channels[param_2]) { + Gate_1Shot(track->channels[param_2], param_3, param_4, param_5); + } else { + return -1; + } + return 0; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +void ProgramChange(s32 chan) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 80013D20 + * Size: 000064 + */ +BOOL CheckNoteStop(seqp_* track, s32 param_2) +{ + jc_* jc; + + if (jc = track->channels[param_2]) { + if (jc->channelId != track->activeSoundIds[param_2]) { + track->channels[param_2] = NULL; + track->activeSoundIds[param_2] = 0; + return TRUE; + } + if (jc->note == 0xff) { + return TRUE; + } + return FALSE; + } + return TRUE; +} diff --git a/src/static/jaudio_NES/internal/oneshot.c b/src/static/jaudio_NES/internal/oneshot.c new file mode 100644 index 00000000..984e280f --- /dev/null +++ b/src/static/jaudio_NES/internal/oneshot.c @@ -0,0 +1,1043 @@ +#include "jaudio_NES/oneshot.h" +#include "jaudio_NES/bankdrv.h" +#include "jaudio_NES/audiostruct.h" +#include "jaudio_NES/driverinterface.h" +#include "jaudio_NES/tables.h" +#include "jaudio_NES/bankread.h" +#include "jaudio_NES/waveread.h" +#include "jaudio_NES/connect.h" +#include "jaudio_NES/dspdriver.h" +#include "jaudio_NES/rate.h" +#include "jaudio_NES/bx.h" + +static int Jesus1Shot_Update(jc_*, JCSTATUS); + +static s16 OSC_REL[] = { 1, 10, 0, 15 }; + +Osc_ PERC_ENV = { 0, 1.0f, 0, 0, 1.0f, 0 }; +Osc_ OSC_ENV = { 0, 1.0f, 0, OSC_REL, 1.0f, 0 }; +u8 polys_table[] = { 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32 }; + +/* + * --INFO-- + * Address: 80015140 + * Size: 000034 + */ +static u8 __GetTrigger(jc_* jc, u8 n) +{ + switch (n) { + case 1: + return jc->velocity; + case 2: + return jc->note; + } + + return 0; +} + +/* + * --INFO-- + * Address: 80015180 + * Size: 000028 + */ +static f32 __Clamp01(f32 val) +{ + if (val < 0.0f) { + return 0.0f; + } + if (val > 1.0f) { + return 1.0f; + } + return val; +} + +/* + * --INFO-- + * Address: 800151C0 + * Size: 000054 + */ +static void __Clamp01InitPan(jc_* jc) +{ + for (u32 i = 1; i < 3; i++) { + jc->panMatrices[i].values[0] = __Clamp01(jc->panMatrices[i].values[0]); + } +} + +/* + * --INFO-- + * Address: 80015220 + * Size: 000068 + */ +static void __DoEffect(jc_* jc, u8 id, f32 val) +{ + switch (id) { + case 1: + jc->currentPitch *= val; + break; + case 0: + jc->currentVolume *= val; + break; + case 2: + jc->panMatrices[1].values[1] = val; + break; + case 3: + jc->panMatrices[2].values[1] = val; + break; + case 4: + jc->panMatrices[3].values[1] = val; + break; + } +} + +/* + * --INFO-- + * Address: 800152A0 + * Size: 000138 + */ +static void EffecterInit(jc_* jc, Inst_* inst) +{ + jc->pitchModifier = 1.0f; + jc->volumeModifier = 1.0f; + jc->panMatrices[1].values[1] = 0.5f; + jc->panMatrices[2].values[1] = 0.0f; + jc->panMatrices[3].values[1] = 0.0f; + for (u32 i = 0; i < 2; i++) { + if (inst->mSensors[i]) { + u8 trigger = __GetTrigger(jc, inst->mSensors[i]->type); + f32 sense = Bank_SenseToOfs(inst->mSensors[i], trigger); + f32* REF_sense = &sense; + __DoEffect(jc, inst->mSensors[i]->id, sense); + } + + if (inst->mEffects[i]) { + f32 r = Bank_RandToOfs(inst->mEffects[i]); + __DoEffect(jc, inst->mEffects[i]->id, r); + } + + if (inst->mOscillators[i]) { + jc->mOscBuffers[i].state = 1; + jc->mOscillators[i] = inst->mOscillators[i]; + f32 ofs = Bank_OscToOfs(jc->mOscillators[i], &jc->mOscBuffers[i]); + DoEffectOsc(jc, jc->mOscillators[i]->mode, ofs); + } else { + jc->mOscillators[i] = NULL; + } + } + __Clamp01InitPan(jc); +} + +/* + * --INFO-- + * Address: 800153E0 + * Size: 0000D0 + */ +static void EffecterInit_Perc(jc_* jc, Pmap_* pmap, u16 id) +{ + jc->pitchModifier = 1.0f; + jc->volumeModifier = 1.0f; + jc->panMatrices[1].values[1] = 0.5f; + jc->panMatrices[2].values[1] = 0.0f; + jc->panMatrices[3].values[1] = 0.0f; + + // PERC instruments only have rand and not osc + for (u32 i = 0; i < 2; i++) { + Pmap_* map = (Pmap_*)((int*)pmap + i + 2); + if (map->_00) { + f32 r = Bank_RandToOfs(map->_00); + f32* REF_r = &r; + __DoEffect(jc, map->_00->id, r); + } + + jc->mOscillators[i] = NULL; + } + jc->mOscillators[0] = &PERC_ENV; + jc->mOscBuffers[0].state = TRUE; + Bank_OscToOfs(jc->mOscillators[0], &jc->mOscBuffers[0]); + jc->mOscBuffers[0].releaseParam = id; + __Clamp01InitPan(jc); +} + +/* + * --INFO-- + * Address: 800154C0 + * Size: 00007C + */ +static void EffecterInit_Osc(jc_* jc) +{ + jc->pitchModifier = 1.0f; + jc->volumeModifier = 1.0f; + jc->panMatrices[1].values[1] = 0.5f; + jc->panMatrices[2].values[1] = 0.0f; + jc->panMatrices[3].values[1] = 0.0f; + + for (u32 i = 0; i < 2; i++) { + jc->mOscillators[i] = NULL; + } + + jc->mOscillators[0] = &OSC_ENV; + jc->mOscBuffers[0].state = TRUE; + Bank_OscToOfs(jc->mOscillators[0], &jc->mOscBuffers[0]); +} + +/* + * --INFO-- + * Address: 80015540 + * Size: 00006C + */ +void Effecter_Overwrite_1ShotD(jc_* jc, Osc_* osc, u32 id) +{ + if (id < 4) { + jc->mOscBuffers[id].state = TRUE; + jc->mOscillators[id] = osc; + DoEffectOsc(jc, jc->mOscillators[id]->mode, Bank_OscToOfs(jc->mOscillators[id], &jc->mOscBuffers[id])); + } +} + +/* + * --INFO-- + * Address: ........ + * Size: 000060 + */ +void Effecter_Overwrite_1Shot(jc_* jc, Osc_* osc1, Osc_* osc2) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 800155C0 + * Size: 00010C + */ +static jc_* __Oneshot_Play_Start(jcs_* jcs, jc_* jc, u32 id) +{ + BOOL play; + + if (id == 0) { + id = -1; + } + jc->playId = id; + jc->savedPlayId = jc->playId; + jc->updateCallback = Jesus1Shot_Update; + jc->dspChannel = AllocDSPchannel(0, (u32)jc); + + if (jc->dspChannel == NULL) { + play = CheckLogicalChannel(jc); + } else { + play = PlayLogicalChannel(jc); + } + + if (jc->dspChannel == NULL && play == TRUE) { + if (Add_WaitDSPChannel(jc) == TRUE) { + List_AddChannelTail(&jcs->waitingChannels, jc); + return jc; + } else { + List_AddChannelTail(&jcs->freeChannels, jc); + return NULL; + } + } else if (play == FALSE) { + DeAllocDSPchannel(jc->dspChannel, (u32)jc); + jc->dspChannel = NULL; + List_AddChannelTail(&jcs->freeChannels, jc); + return NULL; + } else { + List_AddChannelTail(&jcs->activeChannels, jc); + } + return jc; +} + +/* + * --INFO-- + * Address: 800156E0 + * Size: 000154 + */ +static jc_* __Oneshot_GetLogicalChannel(jcs_* jcs, CtrlWave_* wave) +{ + if (wave && wave->_0C == NULL) { + return FALSE; + } + + jc_* chan = List_GetChannel(&jcs->freeChannels); + jc_* chan2; + jc_** REF_chan2 = &chan2; + if (chan == NULL) { + + if (FixAllocChannel(jcs, 1) == FALSE) { + return 0; + } + jcs->chanAllocCount++; + chan = List_GetChannel(&jcs->freeChannels); + if (chan == NULL) { + return 0; + } + + if (jcs->voiceStealingMode == 1) { + chan2 = List_GetChannel(&jcs->releasingChannels); + if (chan2 == NULL) { + chan2 = List_GetChannel(&jcs->activeChannels); + if (chan2) { + List_CountChannel(&jcs->waitingChannels); + } + } + + if (chan2) { + chan2->mOscBuffers[0].state = 6; + List_AddChannel(&jcs->waitingChannels, chan2); + if (chan2->dspChannel) { + ForceStopDSPchannel(chan2->dspChannel); + } + } + } + } + Channel_Init(chan); + if (wave) { + chan->waveData = (Wave_*)wave->_34; + chan->_14 = wave->_0C; + chan->logicalChanType = 0; + } + chan->_18 = 0; + UpdatePanPower_1Shot(chan, 1.0f, 1.0f, 1.0f, 1.0f); + return chan; +} + +/* + * --INFO-- + * Address: 80015840 + * Size: 000044 + */ +Perc_* PercRead(u32 a1, u32 a2) +{ + Bank_* bank = Bank_Get(a1); + if (bank == NULL) { + return NULL; + } + + return Bank_PercChange(bank, a2); +} + +/* + * --INFO-- + * Address: 800158A0 + * Size: 000044 + */ +Inst_* InstRead(u32 a1, u32 a2) +{ + + Bank_* bank = Bank_Get(a1); + if (bank == NULL) { + return NULL; + } + + return Bank_InstChange(bank, a2); +} + +/* + * --INFO-- + * Address: 80015900 + * Size: 00002C + */ +Vmap_* VmapRead(Inst_* inst, u8 a1, u8 a2) +{ + Vmap_* map = (Vmap_*)Bank_GetInstVmap(inst, a1, a2); + return !map ? NULL : map; +} + +/* + * --INFO-- + * Address: 80015940 + * Size: 000010 + */ +static void __Oneshot_WavePause(jc_* jc, u8 a) +{ + jc->pauseFlag = a; + jc->toFlush = 1; +} + +/* + * --INFO-- + * Address: 80015960 + * Size: 00014C + */ +static BOOL __Oneshot_StartMonoPolyCheck(jc_* jc, u32 id) +{ + jcs_* mgr = jc->mMgr; + jc_* chan = mgr->activeChannels; + u8 flag = id >> 0x18; + u8 poly = polys_table[flag & 0xf]; + + u32 index = 0; + + if (poly == 0) { + return TRUE; + } + + while (TRUE) { + if (chan == NULL) { + break; + } + + if (chan->soundId == id) { + if (flag & 0x20) { + index++; + } else { + chan->polyphonyCounter++; + if (chan->polyphonyCounter == poly) { + if (flag & 0x10) { + ForceStopLogicalChannel(chan); + } else { + __Oneshot_WavePause(chan, 1); + } + } + } + } + chan = (jc_*)chan->mNext; + } + + chan = mgr->releasingChannels; + while (TRUE) { + if (chan == NULL) { + break; + } + + if (chan->soundId == id) { + if (flag & 0x20) { + index++; + } else { + chan->polyphonyCounter++; + if (chan->polyphonyCounter == poly) { + ForceStopLogicalChannel(chan); + } + } + } + + chan = (jc_*)chan->mNext; + } + + if (flag & 0x20) { + jc->polyphonyCounter = index; + if (index < poly) { + return TRUE; + } + return FALSE; + } + + jc->polyphonyCounter = 0; + return TRUE; +} + +/* + * --INFO-- + * Address: 80015AC0 + * Size: 0000E8 + */ +static void __Oneshot_StopMonoPolyCheck(jc_* jc, u32 id) +{ + jc_* chan; + u8 poly; + + chan = jc->mMgr->activeChannels; + poly = polys_table[id >> 0x18 & 0xf]; + + if (id && poly) { + + while (TRUE) { + if (chan == NULL) { + break; + } + + int flag = id >> 0x18 & 0x20; + if (chan->soundId == id) { + if (flag) { + if (chan->polyphonyCounter > jc->polyphonyCounter) { + chan->polyphonyCounter--; + if (chan->polyphonyCounter == poly - 1) { + __Oneshot_WavePause(chan, 0); + } + } + } else { + if (chan->polyphonyCounter > jc->polyphonyCounter) { + chan->polyphonyCounter--; + if (chan->polyphonyCounter < poly) { + __Oneshot_WavePause(chan, 0); + } + } + } + } + + chan = (jc_*)chan->mNext; + } + } +} + +/* + * --INFO-- + * Address: 80015BC0 + * Size: 000070 + */ +void Init_1shot(jcs_* jcs, u32 id) +{ + if (jcs->chanCount != 0) { + FixReleaseChannelAll(jcs); + } + InitJcs(jcs); + FixAllocChannel(jcs, id); + if (id == 0) { + jcs->voiceStealingMode = 0; + } else { + jcs->voiceStealingMode = 1; + } +} + +/* + * --INFO-- + * Address: 80015C40 + * Size: 00003C + */ +void Stop_1Shot(jc_* jc) +{ + if (jc->dspChannel == 0) { + Jesus1Shot_Update(jc, JCSTAT_Unk6); + } else { + Jesus1Shot_Update(jc, JCSTAT_Unk0); + } +} + +/* + * --INFO-- + * Address: 80015C80 + * Size: 000040 + */ +void Stop_1Shot_R(jc_* jc, u16 id) +{ + if (jc->dspChannel == 0) { + Jesus1Shot_Update(jc, JCSTAT_Unk6); + } else { + jc->mOscBuffers[0].releaseParam = id; + Jesus1Shot_Update(jc, JCSTAT_Unk0); + } +} + +/* + * --INFO-- + * Address: 80015CC0 + * Size: 00006C + */ +void AllStop_1Shot(jcs_* jcs) +{ + List_CountChannel(&jcs->freeChannels); + List_CountChannel(&jcs->activeChannels); + List_CountChannel(&jcs->releasingChannels); + List_CountChannel(&jcs->waitingChannels); + + jc_* jc = jcs->activeChannels; + jc_* next; + jc_** REF_jc = &jc; + while (jc) { + next = (jc_*)jc->mNext; + Stop_1Shot(jc); + jc = next; + } +} + +/* + * --INFO-- + * Address: 80015D40 + * Size: 00006C + * Note: Equivalent to `JASChannel::sweepProc` in later JAudio. + */ +static BOOL Extra_Update(jc_* jc, JCSTATUS status) +{ + if (jc->pitchSweepSteps != 0) { + f32 pitch = jc->targetPitch; + pitch -= jc->currentPitch; + pitch /= jc->pitchSweepSteps; + jc->currentPitch += pitch; + jc->pitchSweepSteps--; + + if (jc->pitchSweepSteps == 0) { + jc->pitchSweepUpdater = NULL; + } + } + return FALSE; +} + +/* + * --INFO-- + * Address: 80015DC0 + * Size: 000030 + */ +void SetPitchTarget_1Shot(jc_* jc, f32 pitch, u32 steps) +{ + if (steps == 0) { + jc->currentPitch = pitch; + jc->pitchSweepUpdater = NULL; + return; + } + + jc->targetPitch = pitch; + jc->pitchSweepSteps = steps; + jc->pitchSweepUpdater = Extra_Update; +} + +/* + * --INFO-- + * Address: 80015E00 + * Size: 000090 + * Note: (Roughly) Equivalent to `JASChannel::setKeySweepTarget` in later JAudio. + */ +void SetKeyTarget_1Shot(jc_* jc, u8 key, u32 steps) +{ + int pitchKey; + if (jc == 0) { + return; + } + + if (jc->logicalChanType == 2 || jc->waveData == NULL) { + pitchKey = key; + } else { + pitchKey = key + 60 - jc->waveData->key; + } + + if (pitchKey < 0) { + pitchKey = 0; + } + if (pitchKey > 0x7f) { + pitchKey = 0x7f; + } + + f32 pitch = C5BASE_PITCHTABLE[pitchKey]; + SetPitchTarget_1Shot(jc, jc->basePitch * pitch, steps); +} + +/* + * --INFO-- + * Address: 80015EA0 + * Size: 0000C8 + */ +void Gate_1Shot(jc_* jc, u8 key, u8 a2, s32 a3) +{ + if (jc->playId == -1) { + jc->playId = a3; + jc->savedPlayId = jc->playId; + int pitchKey; + if (jc->logicalChanType == 2) { + pitchKey = key; + } else { + pitchKey = key + 60 - jc->waveData->key; + } + if (pitchKey < 0) { + pitchKey = 0; + } + if (pitchKey > 0x7f) { + pitchKey = 0x7f; + } + + f32 pitch = C5BASE_PITCHTABLE[pitchKey]; + jc->velocity = a2; + jc->note = key; + jc->currentPitch = jc->basePitch * pitch; + jc->currentVolume = jc->velocity / 127.0f; + jc->currentVolume = jc->currentVolume * jc->currentVolume * jc->baseVolume; + } +} + +/* + * --INFO-- + * Address: 80015F80 + * Size: 000008 + */ +void UpdatePause_1Shot(jc_* jc, u8 a1) +{ + jc->pauseFlag = a1; +} + +/* + * --INFO-- + * Address: 80015FA0 + * Size: 000030 + */ +void UpdatePanPower_1Shot(jc_* channel, f32 leftPower, f32 rightPower, f32 centerPower, f32 v4) +{ + f32 val = leftPower + rightPower + centerPower; + if (val == 0.0f) { + return; + } + + channel->panMatrices[0].values[0] = leftPower / val; + channel->panMatrices[0].values[1] = rightPower / val; + channel->panMatrices[0].values[2] = centerPower / val; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000068 + */ +void CountChan(jc_* jc) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000068 + */ +void CountChanD(jc_* jc) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000080 + */ +void CheckChan(jc_* jc) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 0000AC + */ +void PrintChan(char* str, jc_* jc, u32 id) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 80015FE0 + * Size: 0000B0 + */ +void FlushRelease_1Shot(jcs_* jcs) +{ + int count = List_CountChannel(&jcs->releasingChannels); + + for (u32 i = 0; i < count; i++) { + jc_* chan = List_GetChannel(&jcs->releasingChannels); + if (chan == NULL) { + break; + } + + for (int j = 0; j < 2; j++) { + if (chan->mOscillators[j]) { + if (chan->mOscBuffers[j].state != 6 && chan->mOscBuffers[j].state != 7) { + chan->mOscBuffers[j].state = 6; + } + } + } + + List_AddChannelTail(&jcs->releasingChannels, chan); + } +} + +/* + * --INFO-- + * Address: 800160A0 + * Size: 0001C4 + */ +static BOOL Jesus1Shot_Update(jc_* jc, JCSTATUS jstatus) +{ + u32 test = FALSE; + jc_** jcptr = &jc; + s32 status = jstatus; + + if (status == 0) { + for (u32 i = 0; i < 2; i++) { + if (jc->mOscillators[i]) { + Oscbuf_* buf = &jc->mOscBuffers[i]; + if (buf->state != 6 && buf->state != 7) { + buf->state = 4; + test = TRUE; + } + } + } + + if (test && List_CutChannel(jc) != -1) { + List_AddChannelTail(&jc->mMgr->releasingChannels, jc); + if (jc->dspChannel) { + u8 flag = jc->channelPriority >> 8; + u32 test2 = flag; + if ((flag & 0xff) == 0) { + test2 = 1; + } + jc->dspChannel->_03 = test2; + } + } + jc->playId = -1; + return FALSE; + } else if (status == 1 || status == 2 || status == 6) { + if (jc->mMgr->chanAllocCount) { + if (List_CutChannel(jc) != -1) { + jc->mMgr->chanAllocCount--; + int id = jc->soundId; + jc->soundId = 0; + __Oneshot_StopMonoPolyCheck(jc, id); + FixReleaseChannel(jc); + } + } else { + if (List_CutChannel(jc) != -1) { + int id = jc->soundId; + jc->soundId = 0; + __Oneshot_StopMonoPolyCheck(jc, id); + List_AddChannel(&jc->mMgr->freeChannels, jc); + } + } + if (status != 6) { + StopLogicalChannel(jc); + } else { + Del_WaitDSPChannel(jc); + } + jc->note = -1; + jc->playId = -1; + jc->updateCallback = NULL; + } + return FALSE; +} + +/* + * --INFO-- + * Address: 80016280 + * Size: 000098 + */ +u32 One_CheckInstWave(SOUNDID_ sound) +{ + Inst_* inst = InstRead(sound.bytes[0], sound.bytes[1]); + if (inst == NULL) { + return 1; + } + + // TODO: fix this conversion to something wave-related once we've sorted that out + int* map = (int*)VmapRead(inst, sound.bytes[2], sound.bytes[3]); + if (map == NULL) { + return 2; + } + + // clearly need something better than map[1] + CtrlGroup_* group = WaveidToWavegroup(map[1], sound.bytes[0]); + if (group == NULL) { + return 3; + } + + WaveID_* handle = GetSoundHandle(group, map[1]); + if (handle == 0) { + return 4; + } + + return 0; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000090 + */ +void Get_CtrlWave(SOUNDID_ sound) +{ + // UNUSED FUNCTION +} + +typedef struct testPercMap { + int _00; // this clearly should one of the existing structs, but Vmap doesnt work so I have no idea + int _04; + f32 _08; + f32 _0C; +} testPercMap; + +/* + * --INFO-- + * Address: 80016320 + * Size: 00027C + */ +jc_* Play_1shot(jcs_* jcs, SOUNDID_ sound, u32 id) +{ + jc_* chan; + Inst_* inst; + WaveID_* wave; + BOOL test = FALSE; + + inst = InstRead(sound.bytes[0], sound.bytes[1]); + if (inst == NULL) { + return NULL; + } + + testPercMap* map = (testPercMap*)VmapRead(inst, sound.bytes[2], sound.bytes[3]); + if (map == NULL) { + return NULL; + } + + CtrlGroup_* group = WaveidToWavegroup(map->_04, sound.bytes[0]); + if (group == NULL) { + return NULL; + } + + wave = GetSoundHandle(group, map->_04); + if (wave == NULL) { + return NULL; + } + + chan = __Oneshot_GetLogicalChannel(jcs, (CtrlWave_*)wave); + if (chan == NULL) { + return NULL; + } + + int val = sound.bytes[2] + 60 - wave->data->key; + if (val < 0) { + val = 0; + } + if (val > 127) { + val = 127; + } + f32 pitch = C5BASE_PITCHTABLE[val]; + chan->velocity = sound.bytes[3]; + chan->note = sound.bytes[2]; + chan->basePitch = map->_0C * (wave->data->_04 / JAC_DAC_RATE) * inst->mGainMultiplier; + chan->currentPitch = chan->basePitch * pitch; + chan->baseVolume = map->_08 * inst->mFreqMultiplier; + chan->currentVolume = chan->velocity / 127.0f; + chan->currentVolume = chan->currentVolume * chan->currentVolume * chan->baseVolume; + chan->panMatrices[1].values[0] = 0.5f; + chan->panMatrices[2].values[0] = 0.0f; + chan->panMatrices[3].values[0] = 0.0f; + EffecterInit(chan, inst); + + int flag = sound.value >> 0x10 | inst->mFlag << 0x18; + switch (inst->mFlag & 0xc0) { + case 0xc0: + flag |= 0xffffff; + break; + case 0x80: + flag |= 0xff; + break; + case 0x40: + flag |= Bank_GetInstKeymap(inst, sound.bytes[2]) << 0x10; + break; + } + + chan->soundId = 0; + if (__Oneshot_StartMonoPolyCheck(chan, flag) == FALSE) { + if (inst->mFlag & 0x10) { + List_AddChannelTail(&jcs->freeChannels, chan); + return FALSE; + } + test = TRUE; + } + chan->soundId = flag; + + jc_* newjc = __Oneshot_Play_Start(jcs, chan, id); + if (test) { + __Oneshot_WavePause(newjc, 1); + } + return newjc; +} + +/* + * --INFO-- + * Address: 800165A0 + * Size: 00020C + */ +jc_* Play_1shot_Perc(jcs_* jcs, SOUNDID_ sound, u32 id) +{ + jc_* chan; + Perc_* perc; + u32* idp = &id; + + perc = PercRead(sound.bytes[0], sound.bytes[1]); + if (perc == NULL) { + return NULL; + } + + testPercMap* map = (testPercMap*)Bank_GetPercVmap(perc, sound.bytes[2], sound.bytes[3]); + testPercMap** mapp = ↦ + if (map == NULL) { + return NULL; + } + + u32 x; + + CtrlGroup_* group = WaveidToWavegroup(map->_04, sound.bytes[0]); + if (group == NULL) { + return NULL; + } + + WaveID_* wave = GetSoundHandle(group, map->_04); + if (wave == NULL) { + return NULL; + } + + chan = __Oneshot_GetLogicalChannel(jcs, (CtrlWave_*)wave); + if (chan == NULL) { + return NULL; + } + + chan->velocity = sound.bytes[3]; + chan->note = sound.bytes[2]; + + chan->basePitch = (wave->data->_04 / JAC_DAC_RATE) * map->_0C * perc->mKeyRegions[sound.bytes[2]]->mVolume; + chan->currentPitch = chan->basePitch; + + chan->baseVolume = map->_08 * perc->mKeyRegions[sound.bytes[2]]->mPitch; + chan->currentVolume = chan->velocity / 127.0f; + chan->currentVolume = chan->currentVolume * chan->currentVolume * chan->baseVolume; + + u16 flag; + if (perc->mMagic == 'PER2') { + chan->panMatrices[1].values[0] = perc->_288[sound.bytes[2]] / 127.0f; + flag = perc->_308[sound.bytes[2]]; + } else { + flag = 1000; + chan->panMatrices[1].values[0] = 0.5f; + } + chan->panMatrices[2].values[0] = 0.0f; + chan->panMatrices[3].values[0] = 0.0f; + EffecterInit_Perc(chan, (Pmap_*)perc->mKeyRegions[sound.bytes[2]], flag); + chan->soundId = 0; + + return __Oneshot_Play_Start(jcs, chan, id); +} + +/* + * --INFO-- + * Address: 800167C0 + * Size: 000128 + */ +jc_* Play_1shot_Osc(jcs_* jcs, SOUNDID_ sound, u32 id) +{ + jc_* chan; + u32 ids = id; + int pit; + jcs_* mgr = jcs; + + chan = __Oneshot_GetLogicalChannel(mgr, NULL); + if (chan == NULL) { + return NULL; + } + + chan->_14 = sound.bytes[1] - 0xf0; + chan->logicalChanType = 2; + + pit = sound.bytes[2]; + if (pit < 0) { + pit = 0; + } + if (pit > 127) { + pit = 127; + } + f32 pitch = C5BASE_PITCHTABLE[pit]; + chan->velocity = sound.bytes[3]; + chan->note = sound.bytes[2]; + chan->basePitch = 16736.016f / JAC_DAC_RATE; + chan->currentPitch = chan->basePitch * pitch; + chan->baseVolume = 1.0f; + chan->currentVolume = chan->velocity / 127.0f; + chan->currentVolume = chan->currentVolume * chan->currentVolume; + chan->panMatrices[1].values[0] = 0.5f; + chan->panMatrices[2].values[0] = 0.0f; + chan->panMatrices[3].values[0] = 0.0f; + EffecterInit_Osc(chan); + chan->soundId = 0; + return __Oneshot_Play_Start(mgr, chan, ids); +} diff --git a/src/static/jaudio_NES/internal/rate.c b/src/static/jaudio_NES/internal/rate.c new file mode 100644 index 00000000..bb2a2db3 --- /dev/null +++ b/src/static/jaudio_NES/internal/rate.c @@ -0,0 +1,7 @@ +#include "jaudio_NES/rate.h" + +u32 JAC_AI_SETTING = 0; +f32 JAC_DAC_RATE = 32028.5f; +u32 JAC_SUBFRAMES = 7; +u32 JAC_FRAMESAMPLES = 560; +u32 DAC_SIZE = 1120; diff --git a/src/static/jaudio_NES/internal/seqsetup.c b/src/static/jaudio_NES/internal/seqsetup.c new file mode 100644 index 00000000..58880798 --- /dev/null +++ b/src/static/jaudio_NES/internal/seqsetup.c @@ -0,0 +1,648 @@ +#include "jaudio_NES/seqsetup.h" + +#include "jaudio_NES/jammain_2.h" +#include "jaudio_NES/noteon.h" +#include "jaudio_NES/fat.h" +#include "jaudio_NES/playercall.h" +#include "jaudio_NES/jamosc.h" +#include "jaudio_NES/driverinterface.h" +#include "jaudio_NES/oneshot.h" +#include "jaudio_NES/fat.h" + +#include "dolphin/os/OSInterrupt.h" + +#define SEQ_SIZE (256) +#define ROOT_OUTER_SIZE (16) +#define ROOTSEQ_SIZE (16) +#define FREE_SEQP_QUEUE_SIZE (256) + +static seqp_ seq[SEQ_SIZE]; +static OuterParam_ ROOT_OUTER[ROOT_OUTER_SIZE]; +static seqp_* rootseq[ROOTSEQ_SIZE]; +static seqp_* FREE_SEQP_QUEUE[FREE_SEQP_QUEUE_SIZE]; + +static u32 BACK_P; +static u32 GET_P; +static u32 SEQ_REMAIN; + +/* + * --INFO-- + * Address: 80013DA0 + * Size: 0000A0 + */ +void Jaq_Reset(void) +{ + int i; + + for (i = 0; i < SEQ_SIZE; ++i) { + seq[i].trackState = 0; + seq[i].childMuteMask = 0; + seq[i].isMuted = 0; + FREE_SEQP_QUEUE[i] = &seq[i]; + } + + BACK_P = 0; + GET_P = 0; + SEQ_REMAIN = FREE_SEQP_QUEUE_SIZE; + + for (i = 0; i < ROOTSEQ_SIZE; ++i) { + rootseq[i] = NULL; + } + + Jam_InitRegistTrack(); +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +void Jaq_GetRemainFreeTracks(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 80013E40 + * Size: 000088 + */ +static BOOL BackTrack(seqp_* track) +{ + seqp_** REF_track; + + REF_track = &track; + track->trackState = 0; + if (track->_3E4 == 1) { + if (SEQ_REMAIN == FREE_SEQP_QUEUE_SIZE) { + return FALSE; + } + + FREE_SEQP_QUEUE[BACK_P] = track; + ++SEQ_REMAIN; + ++BACK_P; + + if (BACK_P == FREE_SEQP_QUEUE_SIZE) { + BACK_P = 0; + } + return TRUE; + } + return FALSE; +} + +/* + * --INFO-- + * Address: 80013EE0 + * Size: 000064 + */ +static seqp_* GetNewTrack() +{ + seqp_* track; + + if (SEQ_REMAIN == 0) { + return NULL; + } + + track = FREE_SEQP_QUEUE[GET_P]; + ++GET_P; + --SEQ_REMAIN; + + if (GET_P == FREE_SEQP_QUEUE_SIZE) { + GET_P = 0; + } + + track->trackState = 2; + track->_3E4 = 1; + return track; +} + +/* + * --INFO-- + * Address: 80013F60 + * Size: 000048 + */ +int AllocNewRoot(seqp_* track) +{ + int i; + + for (i = 0; i < ROOTSEQ_SIZE; ++i) { + if (!rootseq[i]) { + rootseq[i] = track; + return i; + } + } + return -1; +} + +/* + * --INFO-- + * Address: 80013FC0 + * Size: 00004C + */ +int DeAllocRoot(seqp_* track) +{ + int i; + + for (i = 0; i < ROOTSEQ_SIZE; ++i) { + if (rootseq[i] == track) { + rootseq[i] = NULL; + return i; + } + } + return -1; +} + +/* + * --INFO-- + * Address: 80014020 + * Size: 000018 + */ +seqp_* Jaq_HandleToSeq(u32 handle) +{ + return rootseq[handle]; +} + +/* + * --INFO-- + * Address: 80014040 + * Size: 000368 + */ +static void Init_Track(seqp_* track, u32 dataAddress, seqp_* parent) +{ + int i; + + if (!parent) { + track->baseData = (u8*)dataAddress; + track->programCounter = 0; + track->tempo = 120; + track->timeBase = 48; + track->timeRelationMode = 1; + track->isPaused = FALSE; + track->pauseStatus = 10; + track->childMuteMask = 0; + track->isMuted = 0; + } else { + track->baseData = parent->baseData; + track->programCounter = dataAddress; + track->fileHandle = parent->fileHandle; + track->tempo = parent->tempo; + track->doChangeTempo = FALSE; + track->tempoFactor = parent->tempoFactor; + track->timeBase = parent->timeBase; + track->timeRelationMode = parent->timeRelationMode; + track->isPaused = parent->isPaused; + track->pauseStatus = parent->pauseStatus; + track->childMuteMask = 0; + } + track->callStackDepth = 0; + track->_D0 = 0; + track->waitTimer = 0; + track->trackState = 1; + track->parent = parent; + track->interruptEnable = 0; + track->interruptActive = 0; + track->timer = 0; + + // Initialize all MoveParams with default values. + for (i = 0; i < 18; ++i) { + track->timedParam.move[i].duration = 0.0f; + track->timedParam.move[i].currentValue = 1.0f; + track->timedParam.move[i].targetValue = 1.0f; + } + + track->timedParam.inner.pitch.currentValue = 0.0f; + track->timedParam.inner.pitch.targetValue = 0.0f; + track->timedParam.inner.pitch.currentValue = 0.0f; // Just to be sure. + track->timedParam.inner.pitch.targetValue = 0.0f; // Just to be sure. + track->timedParam.inner.pan.currentValue = 0.5f; + track->timedParam.inner.pan.targetValue = 0.5f; + + track->timedParam.inner._100.currentValue = 0.5f; + track->timedParam.inner._100.targetValue = 0.5f; + track->timedParam.inner._110.currentValue = 0.0f; + track->timedParam.inner._110.targetValue = 0.0f; + + track->timedParam.inner.fxmix.currentValue = 0.0f; + track->timedParam.inner.fxmix.targetValue = 0.0f; + track->timedParam.inner.dolby.currentValue = 0.0f; + track->timedParam.inner.dolby.targetValue = 0.0f; + + // Initialize IIRs (skipping the first one) + for (i = 1; i < 4; ++i) { + track->timedParam.inner.IIRs[i].currentValue = 0.0f; + track->timedParam.inner.IIRs[i].targetValue = 0.0f; + } + + track->timedParam.inner.distFilter.currentValue = 0.0f; + track->timedParam.inner.distFilter.targetValue = 0.0f; + + for (i = 0; i < 32; ++i) { + track->regParam.reg[i] = 0; + } + + if ((track->flags & 2) || !track->parent) { + track->regParam.param.arguments[0] = 0; + track->regParam.param.arguments[1] = 1; + track->regParam.param.arguments[2] = 1; + track->regParam.param.arguments[3] = 0x7fff; + track->regParam.param.arguments[4] = 0x4000; + for (i = 0; i < 3; ++i) { + track->panCalcTypes[i] = 2; + track->parentPanCalcTypes[i] = 2; + track->parentController.panCalcTypes[i] = 26; + } + track->regParam.param.bankNumber = 0xf0; + track->regParam.param.pitchScale = 0x0c; + track->regParam.param.basePriority = 0x40; + } else { + for (i = 0; i < 5; ++i) { + track->regParam.param.arguments[i] = track->parent->regParam.param.arguments[i]; + } + track->regParam.param.bankNumber = track->parent->regParam.param.bankNumber; + track->regParam.param.pitchScale = track->parent->regParam.param.pitchScale; + track->regParam.param.basePriority = track->parent->regParam.param.basePriority; + for (i = 0; i < 3; ++i) { + track->panCalcTypes[i] = track->parent->panCalcTypes[i]; + track->parentPanCalcTypes[i] = track->parent->parentPanCalcTypes[i]; + track->parentController.panCalcTypes[i] = track->parent->parentController.panCalcTypes[i]; + } + } + + for (i = 0; i < 16; ++i) { + track->childOuterParams[i] = NULL; + track->children[i] = 0; + } + + for (i = 0; i < 8; ++i) { + track->_94[i] = -1; + track->channels[i] = NULL; + track->activeSoundIds[i] = 0; + } + track->_D4 = 0; + track->_D5 = 0; + track->_90 = 0; + track->_D6 = FALSE; + Osc_Init_Env(track); + track->transpose = 0; + track->finalTranspose = 0; + track->tickCounter = -1; + + for (i = 0; i < 16; ++i) { + track->trackPort[i].importFlag = 0; + track->trackPort[i].exportFlag = 0; + } + + track->isRegistered = 0; +} + +/* + * --INFO-- + * Address: 800143C0 + * Size: 0000A0 + */ +BOOL Jaq_StopSeq(s32 index) +{ + seqp_* track; + + if (index == -1) { + return FALSE; + } + track = rootseq[index]; + if (!track) { + return FALSE; + } + + switch (track->trackState) { + case 0: + break; + case 2: + BackTrack(track); + DeAllocRoot(track); + break; + default: + track->trackState = 3; + break; + } + return TRUE; +} + +/* + * --INFO-- + * Address: 80014460 + * Size: 000054 + */ +static void __StopSeq(seqp_* track) +{ + SeqUpdate(track, 0); + Jaq_CloseTrack(track); + DeAllocRoot(track); + if (track->dataSourceMode == 1) { + FAT_FreeMemory(track->fileHandle); + } +} + +/* + * --INFO-- + * Address: 800144C0 + * Size: 000024 + */ +s32 Jaq_SetSeqData(seqp_* param_1, u8* param_2, u32 param_3, u32 param_4) +{ + return Jaq_SetSeqData_Limit(param_1, param_2, param_3, param_4, 0); +} + +/* + * --INFO-- + * Address: 80014500 + * Size: 000170 + */ +s32 Jaq_SetSeqData_Limit(seqp_* track, u8* param_2, u32 param_3, u32 param_4, u8 param_5) +{ + s32 root; + BOOL level; + u8* puVar2; + + if (!track) { + level = OSDisableInterrupts(); + track = GetNewTrack(); + OSRestoreInterrupts(level); + if (!track) { + return -1; + } + } else { + track->_3E4 = 0; + } + + root = AllocNewRoot(track); + if (root == -1) { + return -1; + } + + track->dataSourceMode = param_4; + switch (param_4) { + case 0: + puVar2 = param_2; + break; + case 1: + track->fileHandle = FAT_AllocateMemory(param_3); + if (track->fileHandle == 0xffff) { // Isn't this literally impossible? + return -1; + } + FAT_StoreBlock(param_2, track->fileHandle, 0, param_3); + puVar2 = NULL; + break; + case 2: + track->fileHandle = (u8)param_2; + puVar2 = NULL; + break; + } + track->trackId = root; + track->flags = 3; + Init_Track(track, (u32)puVar2, NULL); + Jam_InitExtBuffer(&ROOT_OUTER[root]); + Jam_AssignExtBuffer(track, &ROOT_OUTER[root]); + Init_1shot(&track->parentController, param_5); + track->tempoAccumulator = 0.0f; + track->tempoFactor = 1.0f; + Jam_UpdateTrackAll(track); + track->trackState = 2; + return root; +} + +/* + * --INFO-- + * Address: 80014680 + * Size: 00002C + */ +BOOL Jaq_SetBankNumber(seqp_* track, u8 bankNum) +{ + u8 lo; + + // Let's get ahead of ourselves here. + lo = track->regParam.param.bankNumber & 0xFF; + if (!track) { + return FALSE; + } + + track->regParam.param.bankNumber = (bankNum << 8) | lo; + return TRUE; +} + +static s32 Jaq_RootCallback(void* track); + +/* + * --INFO-- + * Address: 800146C0 + * Size: 0000B4 + */ +BOOL Jaq_StartSeq(u32 param_1) +{ + seqp_* track; + u8* lbzu; + + if (param_1 == -1) { + return FALSE; + } + + track = rootseq[param_1]; + if (!track) { + return FALSE; + }; + + // This feels like a fakematch, but oh well. + switch (*(lbzu = &track->trackState)) { + case 0: + return FALSE; + case 1: + return FALSE; + case 3: + return FALSE; + case 2: + *lbzu = 1; + } + Jac_RegisterDspPlayerCallback(&Jaq_RootCallback, rootseq[param_1]); + return TRUE; +} + +/* Flags bit layout (u32): + * ----------------------- + * Bits 0-3 : Index Selector (0 to 15) + * Bit 5 : Direct Register Read Flag + * - If set, index is read from hardware register + * - Forces mode to 4 + * Bits 6-7 : Mode Flags (0 to 3) + */ + +/* + * --INFO-- + * Address: 80014780 + * Size: 00014C + */ +s32 Jaq_OpenTrack(seqp_* track, u32 flags, u32 source) +{ + + seqp_* oldChildTrack; + seqp_* newChildTrack; + u8 childIndex; + u8 trackFlags; + + u8* REF_index; + + childIndex = (flags & 0b00001111); + trackFlags = (flags & 0b11000000) >> 6; + if ((flags & 0b00100000)) { + trackFlags = 4; + } + + if ((u8)(flags & 0b00100000)) { // This u8 cast is a repeating pattern across JAudio... Mysterious. + childIndex = Jam_ReadRegDirect(track, childIndex); + } + + REF_index = &childIndex; + if (childIndex >= 16) { + return -1; + } + + oldChildTrack = track->children[childIndex]; + if (oldChildTrack) { + Jaq_CloseTrack(oldChildTrack); + } + + newChildTrack = GetNewTrack(); + if (!newChildTrack) { + return -1; + } + + track->children[childIndex] = newChildTrack; + + newChildTrack->trackId = ((track->trackId << 4 | childIndex) & 0xFFFFFFF) | ((track->trackId & 0xF0000000) + 0x10000000); + newChildTrack->connectionId = 0; + newChildTrack->dataSourceMode = track->dataSourceMode; + newChildTrack->flags = trackFlags; + + Init_Track(newChildTrack, source, track); + + // Dev rolls "worst bit extraction method", asked to leave Nintendo EAD. + newChildTrack->isMuted = newChildTrack->parent->isMuted | ((newChildTrack->parent->childMuteMask & (1 << childIndex)) >> childIndex); + newChildTrack->outerParams = newChildTrack->parent->childOuterParams[childIndex]; + if (newChildTrack->outerParams) { + ++newChildTrack->outerParams->refCount; + } + + Init_1shot(&newChildTrack->parentController, 0); + Jam_UpdateTrackAll(newChildTrack); + return 0; +} + +/* + * --INFO-- + * Address: 800148E0 + * Size: 0000B4 + */ +void __AllNoteOff(seqp_* track) +{ + u32 i; + + if (!track->parent) { + for (i = 0; i < 8; ++i) { + NoteOFF_R(track, i, 10); + track->_94[i] = -1; + track->channels[i] = NULL; + } + } else { + for (i = 0; i < 8; ++i) { + NoteOFF(track, i); + track->_94[i] = -1; + track->channels[i] = NULL; + } + } +} + +/* + * --INFO-- + * Address: 800149A0 + * Size: 000120 + */ +u32 Jaq_CloseTrack(seqp_* track) +{ + size_t i; + + // Specifically two separate conditional blocks, because why not. + if (!track) { + return 0; + } + if (track->trackState == 0) { + return 0; + } + + __AllNoteOff(track); + BackTrack(track); + + for (i = 0; i < 16; ++i) { + if (track->children[i]) { + Jaq_CloseTrack(track->children[i]); + track->children[i] = NULL; + } + } + + if (track->outerParams) { + // This smells like refcounting. + track->outerParams->refCount -= 1; + track->outerParams = NULL; + } + + for (i = 0; i < 16; ++i) { + if (track->childOuterParams[i]) { + track->childOuterParams[i]->isAssigned = FALSE; + track->childOuterParams[i] = NULL; + } + } + track->isMuted = 0; + track->childMuteMask = 0; + if (track->parent) { + FixMoveChannelAll(&track->parentController, &track->parent->parentController); + } else { + FixReleaseChannelAll(&track->parentController); + } + Jam_UnRegistTrack(track); + return 0; +} + +/* + * --INFO-- + * Address: 80014AC0 + * Size: 0000E8 + * + * Note: While this function accepts `void*`, it really expects `seqp_*`. + */ +static s32 Jaq_RootCallback(void* VOID_track) +{ + seqp_* track; + + track = (seqp_*)VOID_track; + if (track && track->trackState != 0) { + if (track->trackState == 3) { + __StopSeq(track); + return -1; + } + + track->tempoAccumulator += track->tempoFactor; + if (track->tempoAccumulator < 1.0f) { + SeqUpdate(track, 0); + } else { + while (track->tempoAccumulator >= 1.0f) { + track->tempoAccumulator -= 1.0f; + if (Jam_SeqmainNote(track, 0) == -1) { + __StopSeq(track); + return -1; + } + } + + SeqUpdate(track, 0); + } + } else { + return -1; + } + + return 0; +} diff --git a/src/static/jaudio_NES/internal/tables.c b/src/static/jaudio_NES/internal/tables.c new file mode 100644 index 00000000..05056c86 --- /dev/null +++ b/src/static/jaudio_NES/internal/tables.c @@ -0,0 +1,20 @@ +#include "jaudio_NES/tables.h" + +// TODO: This is probably some curve that can be expressed in better terms than a bunch of constant values copied from the DOL. +f32 C5BASE_PITCHTABLE[C5BASE_PITCHTABLE_LENGTH] = { + 0.031250000f, 0.033108000f, 0.035076998f, 0.037161998f, 0.039372000f, 0.041712999f, 0.044194000f, 0.046822000f, 0.049605999f, + 0.052556000f, 0.055681000f, 0.058991998f, 0.062500000f, 0.066215999f, 0.070153996f, 0.074325000f, 0.078745000f, 0.083426997f, + 0.088388000f, 0.093644000f, 0.099212997f, 0.105112000f, 0.111362000f, 0.117984000f, 0.125000000f, 0.132433000f, 0.140307990f, + 0.148651000f, 0.157490000f, 0.166855000f, 0.176777000f, 0.187288000f, 0.198424990f, 0.210224000f, 0.222725000f, 0.235969000f, + 0.250000000f, 0.264865990f, 0.280615990f, 0.297302000f, 0.314980000f, 0.333710000f, 0.353553000f, 0.374576990f, 0.396849990f, + 0.420448000f, 0.445448990f, 0.471937000f, 0.500000000f, 0.529731990f, 0.561231000f, 0.594604000f, 0.629961000f, 0.667420000f, + 0.707107000f, 0.749153970f, 0.793700990f, 0.840897000f, 0.890899000f, 0.943875000f, 1.000000000f, 1.059463000f, 1.122462000f, + 1.189207000f, 1.259921000f, 1.334840000f, 1.414214000f, 1.498307000f, 1.587401000f, 1.681793000f, 1.781798000f, 1.887749000f, + 2.000000000f, 2.118926000f, 2.244924000f, 2.378413900f, 2.519841900f, 2.669680000f, 2.828428000f, 2.996614900f, 3.174803000f, + 3.363585900f, 3.563596000f, 3.775497900f, 4.000000000f, 4.237853000f, 4.489849000f, 4.756828800f, 5.039684800f, 5.339360000f, + 5.656855000f, 5.993228900f, 6.349606000f, 6.727172900f, 7.127192000f, 7.550995800f, 8.000000000f, 8.475705000f, 8.979697000f, + 9.513657600f, 10.07937000f, 10.67872000f, 11.31371000f, 11.98645900f, 12.69921100f, 13.45434600f, 14.25438300f, 15.10199300f, + 16.00000000f, 16.95141000f, 17.95939400f, 19.02731500f, 20.15873900f, 21.35744000f, 22.62742000f, 23.97291800f, 25.39842200f, + 26.90869100f, 28.50876600f, 30.20398500f, 32.00000000f, 33.90282000f, 35.91878900f, 38.05463000f, 40.31747800f, 42.71488000f, + 45.25484000f, 47.94583500f, +}; diff --git a/src/static/jaudio_NES/internal/waveread.c b/src/static/jaudio_NES/internal/waveread.c new file mode 100644 index 00000000..94ed4163 --- /dev/null +++ b/src/static/jaudio_NES/internal/waveread.c @@ -0,0 +1,261 @@ +#include "jaudio_NES/waveread.h" + +#include "jaudio_NES/connect.h" +#include "jaudio_NES/heapctrl.h" +#include "jaudio_NES/bx.h" + +#define WAVEARC_SIZE (0x100) +#define WAVEGROUP_SIZE (0x100) + +static WaveArchiveBank_* wavearc[WAVEARC_SIZE]; +static CtrlGroup_* wavegroup[WAVEGROUP_SIZE]; +CtrlGroup_* CGRP_ARRAY[16]; + +/* + * --INFO-- + * Address: 8000C200 + * Size: 000038 + */ + +static void PTconvert(void** pointer, u32 base_address) +{ + if (*pointer == NULL) { + *pointer = NULL; + return; + } + if (*pointer >= (void*)base_address || *pointer == NULL) { + return; + } + *pointer = *(char**)pointer + base_address; +} + +/* + * --INFO-- + * Address: 8000C240 + * Size: 0002A0 + */ +CtrlGroup_* Wave_Test(u8* data) +{ + u32 i, j; + u32 base_addr = (u32)data; + WaveArchiveBank_* arcBank; + CtrlGroup_* group; + WaveArchive_* arc; + WaveArchive_** REF_arc; + SCNE_* scene; + Ctrl_* cdf; + Ctrl_* cex; + Ctrl_* cst; + + PTconvert((void**)&((Wsys_*)data)->waveArcBank, base_addr); + PTconvert((void**)&((Wsys_*)data)->ctrlGroup, base_addr); + arcBank = *(WaveArchiveBank_**)(data + 0x10); + group = *(CtrlGroup_**)(data + 0x14); + CGRP_ARRAY[0] = group; + + if (arcBank->magic != 'WINF') { + return NULL; + } + if (group->magic != 'WBCT') { + return NULL; + } + + for (i = 0; i < arcBank->count; i++) { + PTconvert((void**)&arcBank->waveGroups[i], base_addr); + arc = arcBank->waveGroups[i]; + REF_arc = &arc; + Jac_InitHeap(&arc->heap); + arc->heap.startAddress = 0; + + for (j = 0; j < arc->waveCount; j++) { + PTconvert((void**)&arc->waves[j], base_addr); + } + } + + for (i = 0; i < group->count; i++) { + PTconvert((void**)&group->scenes[i], base_addr); + scene = group->scenes[i]; + PTconvert((void**)&scene->cdf, base_addr); + PTconvert((void**)&scene->cex, base_addr); + PTconvert((void**)&scene->cst, base_addr); + + cdf = scene->cdf; + if (cdf && cdf->magic == 'C-DF') { + for (j = 0; j < cdf->count; j++) { + PTconvert((void**)&cdf->waveIDs[j], base_addr); + Jac_InitHeap(&cdf->waveIDs[j]->heap); + cdf->waveIDs[j]->heap.startAddress = 0; + } + } + + cex = scene->cex; + if (cex && cex->magic == 'C-EX') { + for (j = 0; j < cex->count; j++) { + PTconvert((void**)&cex->waveIDs[j], base_addr); + Jac_InitHeap(&cex->waveIDs[j]->heap); + cex->waveIDs[j]->heap.startAddress = 0; + } + } + + cst = scene->cst; + if (cst && cst->magic == 'C-ST') { + for (j = 0; j < cst->count; j++) { + PTconvert((void**)&cst->waveIDs[j], base_addr); + Jac_InitHeap(&cst->waveIDs[j]->heap); + cst->waveIDs[j]->heap.startAddress = 0; + } + } + } + return CGRP_ARRAY[0]; +} + +/* + * --INFO-- + * Address: ........ + * Size: 000030 + */ +void GetSound_Test(u32 id) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8000C4E0 + * Size: 000084 + */ +BOOL Wavegroup_Regist(void* wsysData, u32 id) +{ + Wsys_* wsys = (Wsys_*)wsysData; + Jac_WsConnectTableSet(wsys->globalID, id); + wavegroup[id] = Wave_Test((u8*)wsys); + wavearc[id] = wsys->waveArcBank; + + if (wavegroup[id] == NULL) { + return FALSE; + } + wavegroup[id]->_04 = 0; + return TRUE; +} + +/* + * --INFO-- + * Address: 8000C580 + * Size: 00002C + */ +void Wavegroup_Init() +{ + for (int i = 0; i < WAVEGROUP_SIZE; ++i) { + wavegroup[i] = NULL; + } +} + +/* + * --INFO-- + * Address: 8000C5C0 + * Size: 000064 + */ +CtrlGroup_* WaveidToWavegroup(u32 param_1, u32 param_2) +{ + u16 virtID = param_1 >> 16; + u16 index; + u16* REF_virtID = &virtID; + + if (virtID == 0xFFFF) { + index = param_2; + } else { + index = Jac_WsVirtualToPhysical(virtID); + } + + return index >= WAVEGROUP_SIZE ? NULL : wavegroup[index]; +} + +/* + * --INFO-- + * Address: 8000C640 + * Size: 00008C + */ +static BOOL __WaveScene_Set(u32 waveIndex, u32 ctrlIndex, BOOL doSet) +{ + u32* REF_param_1; + u32* REF_param_2; + + CtrlGroup_* group; + + REF_param_1 = &waveIndex; + if (waveIndex >= WAVEGROUP_SIZE) { + return FALSE; + } + if (!(group = wavegroup[waveIndex])) { + return FALSE; + } + REF_param_2 = &ctrlIndex; + if (ctrlIndex >= group->count) { + return FALSE; + } + return Jac_SceneSet(wavearc[waveIndex], group, ctrlIndex, doSet); +} + +/* + * --INFO-- + * Address: 8000C6E0 + * Size: 000024 + */ +BOOL WaveScene_Set(u32 waveIndex, u32 ctrlIndex) +{ + return __WaveScene_Set(waveIndex, ctrlIndex, TRUE); +} + +/* + * --INFO-- + * Address: 8000C720 + * Size: 000024 + */ +BOOL WaveScene_Load(u32 waveIndex, u32 ctrlIndex) +{ + return __WaveScene_Set(waveIndex, ctrlIndex, FALSE); +} + +/* + * --INFO-- + * Address: 8000C760 + * Size: 000074 + */ +static void __WaveScene_Close(u32 waveIndex, u32 ctrlIndex, BOOL param_3) +{ + u32* REF_param_1; + u32* REF_param_2; + + CtrlGroup_* group; + + REF_param_1 = &waveIndex; + if (waveIndex >= WAVEGROUP_SIZE) { + return; + } + if (group = wavegroup[waveIndex]) { + REF_param_2 = &ctrlIndex; + if (ctrlIndex < group->count) { + Jac_SceneClose(wavearc[waveIndex], group, ctrlIndex, param_3); + } + } +} + +/* + * --INFO-- + * Address: 8000C7E0 + * Size: 000024 + */ +void WaveScene_Close(u32 waveIndex, u32 ctrlIndex) +{ + __WaveScene_Close(waveIndex, ctrlIndex, TRUE); +} + +/* + * --INFO-- + * Address: 8000C820 + * Size: 000024 + */ +void WaveScene_Erase(u32 waveIndex, u32 ctrlIndex) +{ + __WaveScene_Close(waveIndex, ctrlIndex, FALSE); +} diff --git a/src/static/libforest/emu64/emu64.c b/src/static/libforest/emu64/emu64.c index 16f7eaec..4bed6218 100644 --- a/src/static/libforest/emu64/emu64.c +++ b/src/static/libforest/emu64/emu64.c @@ -1,6 +1,7 @@ #include "libforest/emu64/emu64.hpp" #include "libforest/emu64.h" +// #include "MSL_C/w_math.h" #include "libultra/libultra.h" #include "terminal.h" #include "boot.h"