mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-07-01 02:11:45 -04:00
647 lines
13 KiB
C
647 lines
13 KiB
C
#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];
|
|
--SEQ_REMAIN;
|
|
++GET_P;
|
|
|
|
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 = AUDIO_TATUMS_PER_BEAT;
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
if (childIndex >= 16) {
|
|
return -1;
|
|
}
|
|
|
|
oldChildTrack = track->children[childIndex];
|
|
if (oldChildTrack) {
|
|
Jaq_CloseTrack(oldChildTrack);
|
|
}
|
|
|
|
newChildTrack = GetNewTrack();
|
|
if (!newChildTrack) {
|
|
return -1;
|
|
}
|
|
|
|
track->children[childIndex] = newChildTrack;
|
|
|
|
u32 trackId = track->trackId;
|
|
newChildTrack->trackId = ((trackId << 4 | childIndex) & 0xFFFFFFF) | ((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;
|
|
}
|