From c952fd449049fd2306b95f1a0b4201b19faac705 Mon Sep 17 00:00:00 2001 From: MNGoldenEagle <17274702+MNGoldenEagle@users.noreply.github.com> Date: Mon, 12 Apr 2021 05:20:46 -0500 Subject: [PATCH] Add near-matching decomped functions for SeqPlayer (#729) * Add nearmatching decomped functions * improved match * greatly improved match * small thing * almost matching * small cleanup * remove commented array * pad -> unk Co-authored-by: petrie911 Co-authored-by: Fig02 --- include/functions.h | 6 +- include/z64audio.h | 85 ++-- src/code/audio_seqplayer.c | 787 +++++++++++++++++++++++++++++++++++++ 3 files changed, 844 insertions(+), 34 deletions(-) diff --git a/include/functions.h b/include/functions.h index a9ac0e9d6a..b84f4471ae 100644 --- a/include/functions.h +++ b/include/functions.h @@ -2069,7 +2069,7 @@ void Audio_SetSeqLoadStatus(s32 seqId, u8 status); // ? func_800E1F38(?); // ? func_800E1F7C(?); // ? func_800E202C(?); -// ? func_800E20D4(?); +void func_800E20D4(s32, s32, s32); // ? func_800E2124(?); // ? func_800E217C(?); // ? func_800E22C4(?); @@ -2096,7 +2096,7 @@ void func_800E3400(void); // ? func_800E36EC(?); // ? func_800E3874(?); // ? func_800E38F8(?); -// ? func_800E390C(?); +void func_800E390C(s32, void*, void*); void func_800E3A14(void); // ? func_800E3A44(?); // ? func_800E3AC8(?); @@ -2113,7 +2113,7 @@ void func_800E3A14(void); // ? func_800E48C0(?); // ? func_800E4918(?); void func_800E4D94(void); -// ? func_800E4EEC(?); +void func_800E4EEC(u32, u32, s8*); // ? func_800E4F58(?); void func_800E4FB0(void); Sub_AudioMgr_18* func_800E4FE0(void); diff --git a/include/z64audio.h b/include/z64audio.h index ccf58acc43..6183a9aec8 100644 --- a/include/z64audio.h +++ b/include/z64audio.h @@ -190,21 +190,38 @@ typedef struct { // Also known as a Group, according to sm64 debug strings. typedef struct { - /* 0x000 */ u8 enabled : 1; - /*?0x000 */ u8 finished : 1; - /* 0x000 */ u8 muted : 1; - /* 0x000 */ u8 seqDmaInProgress : 1; - /* 0x000 */ u8 bankDmaInProgress : 1; - /*?0x000 */ u8 recalculateVolume : 1; - /* 0x000 */ u8 unk_0b2 : 1; - /* 0x000 */ u8 unk_0b1 : 1; - /* 0x001 */ u8 state; - /* 0x002 */ u8 noteAllocPolicy; - /* 0x003 */ u8 muteBehavior; + union { + s32 playerState; + struct { + /* 0x000 */ u8 enabled : 1; + /*?0x000 */ u8 finished : 1; + /* 0x000 */ u8 muted : 1; + /* 0x000 */ u8 seqDmaInProgress : 1; + /* 0x000 */ u8 bankDmaInProgress : 1; + /*?0x000 */ u8 recalculateVolume : 1; + /* 0x000 */ u8 unk_0b2 : 1; + /* 0x000 */ u8 unk_0b1 : 1; + /* 0x001 */ u8 state; + /* 0x002 */ u8 noteAllocPolicy; + union { + /* 0x003 */ u8 muteBehavior; + struct { + u8 mute_u00 : 1; + u8 mute_u01 : 1; + u8 mute_u02 : 1; + u8 mute_u03 : 1; + u8 mute_u04 : 1; + u8 mute_u05 : 1; + u8 mute_u06 : 1; + u8 mute_u07 : 1; + }; + }; + }; + }; /* 0x004 */ u8 seqId; /* 0x005 */ u8 defaultBank; /*?0x006 */ u8 loadingBankId; - /*?0x007 */ s8 seqVariationEu[1]; + /*?0x007 */ s8 seqVariationEu; /* 0x008 */ u16 tempo; // tatums per minute /* 0x00A */ u16 tempoAcc; /* 0x00C */ u16 unk_0C; @@ -227,7 +244,7 @@ typedef struct { /* 0x098 */ u8* shortNoteDurationTable; /* 0x09C */ NotePool notePool; /* 0x0DC */ s32 unk_DC; - /* 0x0D0 */ u32 unk_E0; + /* 0x0E0 */ u32 unk_E0; /* 0x0E4 */ u8 pad_E4[0x10]; // OSMesgQueue seqDmaMesgQueue; /*?0x0F4 */ OSMesg seqDmaMesg; /*?0x0F8 */ OSIoMesg seqDmaIoMesg; @@ -300,24 +317,29 @@ typedef struct { // Also known as a SubTrack, according to sm64 debug strings. // Confusingly, a SubTrack is a container of Tracks. typedef struct SequenceChannel { - /* 0x00 */ u8 enabled : 1; - /* 0x00 */ u8 finished : 1; - /* 0x00 */ u8 stopScript : 1; - /* 0x00 */ u8 stopSomething2 : 1; // sets SequenceChannelLayer.stopSomething - /* 0x00 */ u8 hasInstrument : 1; - /* 0x00 */ u8 stereoHeadsetEffects : 1; - /* 0x00 */ u8 largeNotes : 1; // notes specify duration and velocity - /* 0x00 */ u8 unused : 1; // still unused? union { + s32 channelState; struct { - /* 0x01 */ u8 freqScale : 1; - /* 0x01 */ u8 volume : 1; - /* 0x01 */ u8 pan : 1; - } s; - /* 0x01 */ u8 asByte; - } changes; - /* 0x02 */ u8 noteAllocPolicy; - /* 0x03 */ u8 muteBehavior; + /* 0x00 */ u8 enabled : 1; + /* 0x00 */ u8 finished : 1; + /* 0x00 */ u8 stopScript : 1; + /* 0x00 */ u8 stopSomething2 : 1; // sets SequenceChannelLayer.stopSomething + /* 0x00 */ u8 hasInstrument : 1; + /* 0x00 */ u8 stereoHeadsetEffects : 1; + /* 0x00 */ u8 largeNotes : 1; // notes specify duration and velocity + /* 0x00 */ u8 unused : 1; // still unused? + union { + struct { + /* 0x01 */ u8 freqScale : 1; + /* 0x01 */ u8 volume : 1; + /* 0x01 */ u8 pan : 1; + } s; + /* 0x01 */ u8 asByte; + } changes; + /* 0x02 */ u8 noteAllocPolicy; + /* 0x03 */ u8 muteBehavior; + }; + }; /* 0x04 */ u8 reverb; // or dry/wet mix /* 0x05 */ u8 notePriority; // 0-3 /* 0x06 */ u8 someOtherPriority; @@ -339,7 +361,7 @@ typedef struct SequenceChannel { /* 0x1C */ u16 vibratoDelay; /* 0x1E */ u16 delay; /* 0x20 */ u16 unk_20; - /* 0x22 */ u16 pad_22; + /* 0x22 */ u16 unk_22; /* 0x24 */ s16 instOrWave; // either 0 (none), instrument index + 1, or // 0x80..0x83 for sawtooth/triangle/sine/square waves. /* 0x26 */ s16 transposition; @@ -671,7 +693,8 @@ typedef struct { /* 0x2624 */ char unk_2624[0x210]; /* 0x2834 */ s16* unk_2834; /* 0x2838 */ ManyStruct_800E0E0C_2* unk_2838; - /* 0x283C */ char unk_283C[0x8]; + /* 0x283C */ u8* unk_283C; + /* 0x2840 */ char unk_2840[0x4]; /* 0x2844 */ CtlEntry* gCtlEntries; /* 0x2848 */ AudioBufferParameters gAudioBufferParameters; /* 0x2870 */ f32 unk_2870; diff --git a/src/code/audio_seqplayer.c b/src/code/audio_seqplayer.c index 01fb8e39b1..e882e8daf2 100644 --- a/src/code/audio_seqplayer.c +++ b/src/code/audio_seqplayer.c @@ -374,6 +374,7 @@ s32 func_800E9F64(SequenceChannelLayer* layer, s32 arg1); s32 func_800EA0C0(SequenceChannelLayer* layer); s32 func_800EA440(SequenceChannelLayer* layer, s32 arg1); s32 func_800EAAE0(SequenceChannelLayer* layer, s32 arg1); +s32 func_800E3414(u8 bankId, s32 value, s8* value2); void Audio_SeqChannelLayerProcessScript(SequenceChannelLayer* layer) { s32 val; @@ -956,11 +957,797 @@ void Audio_SequenceChannelSetVolume(SequenceChannel* seqChannel, u8 volume) { seqChannel->volume = (f32)(s32)volume / 127.0f; } +#ifdef NON_MATCHING +// Two reg category errors and lots of t register shifting. +void Audio_SequenceChannelProcessScript(SequenceChannel* channel) { + s32 i; + u8* data; + u8* test; + SequencePlayer* player; + + if (channel->stopScript) { + goto exit_loop; + } + player = channel->seqPlayer; + if (player->muted && (channel->muteBehavior & 0x80)) { + return; + } + + if (channel->delay >= 2) { + channel->delay--; + goto exit_loop; + } + + while (true) { + M64ScriptState* scriptState = &channel->scriptState; + s32 param; + s16 pad1; + u16 offset; + s32 parameters[3]; + s8 signedParam; + u8 command = Audio_M64ReadU8(scriptState); + u8 lowBits; + u8 highBits; + s32 result; + s32 pad2; + + if (command >= 0xB0) { + highBits = D_80130470[(s32)command]; + lowBits = highBits & 3; + + for (i = 0; i < lowBits; i++, highBits <<= 1) { + if (!(highBits & 0x80)) { + parameters[i] = Audio_M64ReadU8(scriptState); + } else { + parameters[i] = Audio_M64ReadS16(scriptState); + } + } + if (command >= 0xF2) { + result = Audio_HandleScriptFlowControl(player, scriptState, command, parameters[0]); + + if (result != 0) { + if (result == -1) { + Audio_SequenceChannelDisable(channel); + } else { + channel->delay = result; + } + break; + } + } else { + switch (command) { + case 0xEA: + channel->stopScript = true; + goto exit_loop; + case 0xF1: + Audio_NotePoolClear(&channel->notePool); + command = (u8)parameters[0]; + Audio_NotePoolFill(&channel->notePool, command); + break; + case 0xF0: + Audio_NotePoolClear(&channel->notePool); + break; + case 0xC2: + offset = (u16)parameters[0]; + channel->dynTable = &player->seqData[offset]; + break; + case 0xC5: + if (scriptState->value != -1) { + + data = (*channel->dynTable)[scriptState->value]; + offset = (u16)((data[0] << 8) + data[1]); + + channel->dynTable = &player->seqData[offset]; + } + break; + case 0xEB: + result = (u8)parameters[0]; // category error: should be t not v + command = result; + + if (player->defaultBank != 0xFF) { + offset = ((u16*)gAudioContext.unk_283C)[player->seqId]; + lowBits = gAudioContext.unk_283C[offset]; + command = gAudioContext.unk_283C[offset + lowBits - result]; + } + + if (func_800DF074(1, 2, command)) { + channel->bankId = command; + } + + parameters[0] = parameters[1]; + // NOTE: Intentional fallthrough + case 0xC1: + command = (u8)parameters[0]; + Audio_SetInstrument(channel, command); + break; + case 0xC3: + channel->largeNotes = false; + break; + case 0xC4: + channel->largeNotes = true; + break; + case 0xDF: + command = (u8)parameters[0]; + Audio_SequenceChannelSetVolume(channel, command); + channel->changes.s.volume = true; + break; + case 0xE0: + command = (u8)parameters[0]; + channel->volumeScale = (f32)(s32)command / 128.0f; + channel->changes.s.volume = true; + break; + case 0xDE: + offset = (u16)parameters[0]; + channel->freqScale = (f32)(s32)offset / 32768.0f; + channel->changes.s.freqScale = true; + break; + case 0xD3: + command = (u8)parameters[0]; + command += 0x80; + channel->freqScale = gPitchBendFrequencyScale[command]; + channel->changes.s.freqScale = true; + break; + case 0xEE: + command = (u8)parameters[0]; + command += 0x80; + channel->freqScale = D_8012F4B4[command]; + channel->changes.s.freqScale = true; + break; + case 0xDD: + command = (u8)parameters[0]; + channel->newPan = command; + channel->changes.s.pan = true; + break; + case 0xDC: + command = (u8)parameters[0]; + channel->panChannelWeight = command; + channel->changes.s.pan = true; + break; + case 0xDB: + signedParam = (s8) parameters[0]; + channel->transposition = signedParam; + break; + case 0xDA: + offset = (u16)parameters[0]; + channel->adsr.envelope = &player->seqData[offset]; + break; + case 0xD9: + command = (u8)parameters[0]; + channel->adsr.releaseRate = command; + break; + case 0xD8: + command = (u8)parameters[0]; + channel->vibratoExtentTarget = command * 8; + channel->vibratoExtentStart = 0; + channel->vibratoExtentChangeDelay = 0; + break; + case 0xD7: + command = (u8)parameters[0]; + channel->vibratoRateChangeDelay = 0; + channel->vibratoRateTarget = command * 32; + channel->vibratoRateStart = command * 32; + break; + case 0xE2: + command = (u8)parameters[0]; + channel->vibratoExtentStart = command * 8; + command = (u8)parameters[1]; + channel->vibratoExtentTarget = command * 8; + command = (u8)parameters[2]; + channel->vibratoExtentChangeDelay = command * 16; + break; + case 0xE1: + command = (u8)parameters[0]; + channel->vibratoRateStart = command * 32; + command = (u8)parameters[1]; + channel->vibratoRateTarget = command * 32; + command = (u8)parameters[2]; + channel->vibratoRateChangeDelay = command * 16; + break; + case 0xE3: + command = (u8)parameters[0]; + channel->vibratoDelay = command * 16; + break; + case 0xD4: + command = (u8)parameters[0]; + channel->reverb = command; + break; + case 0xC6: + result = (u8)parameters[0]; // category error: should be t not v + command = result; + + if (player->defaultBank != 0xFF) { + offset = ((u16*)gAudioContext.unk_283C)[player->seqId]; + lowBits = gAudioContext.unk_283C[offset]; + command = gAudioContext.unk_283C[offset + lowBits - result]; + } + + if (func_800DF074(1, 2, command)) { + channel->bankId = command; + } + + break; + case 0xC7: + command = (u8)parameters[0]; + offset = (u16)parameters[1]; + test = &player->seqData[offset]; + test[0] = (u8)scriptState->value + command; + break; + case 0xC8: + case 0xCC: + case 0xC9: + signedParam = (s8)parameters[0]; + + if (command == 0xC8) { + scriptState->value -= signedParam; + } else if (command == 0xCC) { + scriptState->value = signedParam; + } else { + scriptState->value &= signedParam; + } + break; + case 0xCD: + command = (u8)parameters[0]; + Audio_SequenceChannelDisable(player->channels[command]); + break; + case 0xCA: + command = (u8)parameters[0]; + channel->muteBehavior = command; + channel->changes.s.volume = true; + break; + case 0xCB: + offset = (u16)parameters[0]; + + scriptState->value = *(offset + scriptState->value + player->seqData); + break; + case 0xCE: + offset = (u16)parameters[0]; + channel->unk_22 = offset; + break; + case 0xCF: + offset = (u16)parameters[0]; + test = &player->seqData[offset]; + test[0] = (channel->unk_22 >> 8) & 0xFF; + test[1] = channel->unk_22 & 0xFF; + break; + case 0xD0: + command = (u8)parameters[0]; + if (command & 0x80) { + channel->stereoHeadsetEffects = true; + } else { + channel->stereoHeadsetEffects = false; + } + channel->reverbBits.asByte = command & 0x7F; + break; + case 0xD1: + command = (u8)parameters[0]; + channel->noteAllocPolicy = command; + break; + case 0xD2: + command = (u8)parameters[0]; + channel->adsr.sustain = command; + break; + case 0xE5: + command = (u8)parameters[0]; + channel->reverbIndex = command; + break; + case 0xE4: + if (scriptState->value != -1) { + data = (*channel->dynTable)[scriptState->value]; + // @bug: Missing a stack depth check here + scriptState->stack[scriptState->depth++] = scriptState->pc; + offset = (u16)((data[0] << 8) + data[1]); + scriptState->pc = player->seqData + offset; + } + break; + case 0xE6: + command = (u8)parameters[0]; + channel->bookOffset = command; + break; + case 0xE7: + offset = (u16)parameters[0]; + data = &player->seqData[offset]; + channel->muteBehavior = data[0]; + data += 3; + channel->noteAllocPolicy = data[-2]; + func_800EAEF4(channel, data[-1]); + channel->transposition = (s8)data[0]; + data += 4; + channel->newPan = data[-3]; + channel->panChannelWeight = data[-2]; + channel->reverb = data[-1]; + channel->reverbIndex = data[0]; + //@bug: Not marking reverb state as changed + channel->changes.s.pan = true; + break; + case 0xE8: + channel->muteBehavior = parameters[0]; + channel->noteAllocPolicy = parameters[1]; + command = (u8)parameters[2]; + func_800EAEF4(channel, command); + channel->transposition = (s8)Audio_M64ReadU8(scriptState); + channel->newPan = Audio_M64ReadU8(scriptState); + channel->panChannelWeight = Audio_M64ReadU8(scriptState); + channel->reverb = Audio_M64ReadU8(scriptState); + channel->reverbIndex = Audio_M64ReadU8(scriptState); + //@bug: Not marking reverb state as changed + channel->changes.s.pan = true; + break; + case 0xEC: + channel->vibratoExtentTarget = 0; + channel->vibratoExtentStart = 0; + channel->vibratoExtentChangeDelay = 0; + channel->vibratoRateTarget = 0; + channel->vibratoRateStart = 0; + channel->vibratoRateChangeDelay = 0; + channel->unk_CC = NULL; + channel->unk_0C = 0; + channel->adsr.sustain = 0; + channel->velocityRandomVariance = 0; + channel->durationRandomVariance = 0; + channel->unk_0F = 0; + channel->unk_20 = 0; + channel->bookOffset = 0; + channel->freqScale = 1.0f; + break; + case 0xE9: + func_800EAEF4(channel, (u8)parameters[0]); + break; + case 0xED: + command = (u8)parameters[0]; + channel->unk_0C = command; + break; + case 0xB0: + offset = (u16)parameters[0]; + data = player->seqData + offset; + channel->unk_CC = (s16*)data; + break; + case 0xB1: + channel->unk_CC = NULL; + break; + case 0xB3: + command = parameters[0]; + + if (channel->unk_CC != NULL) { + lowBits = (command >> 4) & 0xF; + command &= 0xF; + func_800DF688(channel->unk_CC, lowBits, command); + } + break; + case 0xB2: + offset = (u16) parameters[0]; + channel->unk_22 = *(u16*)(offset + scriptState->value * 2 + player->seqData); + break; + case 0xB4: + channel->dynTable = (void*)&player->seqData[channel->unk_22]; + break; + case 0xB5: + channel->unk_22 = ((u16*)(channel->dynTable))[scriptState->value]; + break; + case 0xB6: + data = (*channel->dynTable)[0]; + scriptState->value = (*channel->dynTable)[0][scriptState->value]; + break; + case 0xB7: + channel->unk_22 = (parameters[0] == 0) ? gAudioContext.gAudioRandom // odd load here + : gAudioContext.gAudioRandom % parameters[0]; + break; + case 0xB8: + scriptState->value = (parameters[0] == 0) ? gAudioContext.gAudioRandom + : gAudioContext.gAudioRandom % parameters[0]; + break; + case 0xBD: { + result = Audio_NextRandom(); + channel->unk_22 = (parameters[0] == 0) ? (u32) result : (u32)result % parameters[0]; + channel->unk_22 += parameters[1]; + pad2 = (channel->unk_22 / 0x100) + 0x80; // i is wrong here + param = channel->unk_22 % 0x100; + channel->unk_22 = (pad2 << 8) | param; + } break; + case 0xB9: + channel->velocityRandomVariance = parameters[0]; + break; + case 0xBA: + channel->durationRandomVariance = parameters[0]; + break; + case 0xBB: + channel->unk_0F = parameters[0]; + channel->unk_20 = parameters[1]; + break; + case 0xBC: + channel->unk_22 += parameters[0]; + break; + } + } + } else if (command >= 0x70) { + lowBits = command & 0x7; + + if ((command & 0xF8) != 0x70 && lowBits >= 4) { + lowBits = 0; + } + + switch (command & 0xF8) { + case 0x80: + if (channel->layers[lowBits] != NULL) { + scriptState->value = channel->layers[lowBits]->finished; + } else { + scriptState->value = -1; + } + break; + case 0x88: + offset = Audio_M64ReadS16(scriptState); + if (!Audio_SeqChannelSetLayer(channel, lowBits)) { + channel->layers[lowBits]->scriptState.pc = &player->seqData[offset]; + } + break; + case 0x90: + Audio_SeqChannelLayerFree(channel, lowBits); + break; + case 0x98: + if (scriptState->value == -1 || Audio_SeqChannelSetLayer(channel, lowBits) == -1) { + break; + } + + data = (*channel->dynTable)[scriptState->value]; + offset = (data[0] << 8) + data[1]; + channel->layers[lowBits]->scriptState.pc = &player->seqData[offset]; + break; + case 0x70: + channel->soundScriptIO[lowBits] = scriptState->value; + break; + case 0x78: + pad1 = Audio_M64ReadS16(scriptState); + if (!Audio_SeqChannelSetLayer(channel, lowBits)) { + channel->layers[lowBits]->scriptState.pc = &scriptState->pc[pad1]; + } + break; + } + } else { + lowBits = command & 0xF; + + switch (command & 0xF0) { + case 0: { + channel->delay = lowBits; + goto exit_loop; + } + case 0x10: + if (lowBits < 8) { + channel->soundScriptIO[lowBits] = -1; + if (func_800E3414(channel->bankId, scriptState->value, + &channel->soundScriptIO[lowBits]) == -1) { + break; + } + } else { + lowBits -= 8; + channel->soundScriptIO[lowBits] = -1; + if (func_800E3414(channel->bankId, channel->unk_22 + 0x100, + &channel->soundScriptIO[lowBits]) == -1) { + break; + } + } + break; + case 0x60: + scriptState->value = channel->soundScriptIO[lowBits]; + if (lowBits < 2) { + channel->soundScriptIO[lowBits] = -1; + } + break; + case 0x50: + scriptState->value -= channel->soundScriptIO[lowBits]; + break; + case 0x20: + offset = Audio_M64ReadS16(scriptState); + Audio_SequenceChannelEnable(player, lowBits, + &player->seqData[offset]); + break; + case 0x30: + command = Audio_M64ReadU8(scriptState); + player->channels[lowBits]->soundScriptIO[command] = scriptState->value; + break; + case 0x40: + command = Audio_M64ReadU8(scriptState); + scriptState->value = player->channels[lowBits]->soundScriptIO[command]; + break; + } + } + } +exit_loop: + + for (i = 0; i < ARRAY_COUNT(channel->layers); i++) { + if (channel->layers[i] != NULL) { + Audio_SeqChannelLayerProcessScript(channel->layers[i]); + } + } +} +#else void Audio_SequenceChannelProcessScript(SequenceChannel* seqChannel); #pragma GLOBAL_ASM("asm/non_matchings/code/audio_seqplayer/Audio_SequenceChannelProcessScript.s") +#endif +#ifdef NON_MATCHING +// regalloc, redundant branch, and extra cast. The large number of pads suggests cases may have their own temp variables. +void Audio_SequencePlayerProcessSequence(SequencePlayer* seqPlayer) { + u8 command; + u8 commandLow; + u16 offset; + M64ScriptState* seqScript = &seqPlayer->scriptState; + s16 tempS; + u16 temp; + s32 i; + s32 value; + u8* data; + s32 pad1; + s32 pad2; + s32 pad3; + s32 pad4; + + if (!seqPlayer->enabled) { + return; + } + + if (!Audio_IsSeqLoadComplete(seqPlayer->seqId) || !Audio_IsBankLoadComplete(seqPlayer->defaultBank)) { + Audio_SequencePlayerDisable(seqPlayer); + return; + } + + Audio_SetSeqLoadStatus(seqPlayer->seqId, 2); + Audio_SetBankLoadStatus(seqPlayer->defaultBank, 2); + + if (seqPlayer->muted && (seqPlayer->muteBehavior & 0x80)) { + return; + } + + seqPlayer->unk_E0++; + seqPlayer->tempoAcc += seqPlayer->tempo; + seqPlayer->tempoAcc += (s16)seqPlayer->unk_0C; + + if (seqPlayer->tempoAcc < gAudioContext.gTempoInternalToExternal) { + return; + } + + seqPlayer->tempoAcc -= (u16)gAudioContext.gTempoInternalToExternal; + + if (seqPlayer->unk_0b2 == true) { + return; + } + + if (seqPlayer->delay > 1) { + seqPlayer->delay--; + } else { + seqPlayer->recalculateVolume = true; + + while (true) { + command = Audio_M64ReadU8(seqScript); + + // 0xF2 and above are "flow control" commands, including termination. + if (command >= 0xF2) { + s32 scriptHandled = + Audio_HandleScriptFlowControl(seqPlayer, seqScript, command, + Audio_GetScriptControlFlowArgument(&seqPlayer->scriptState, command)); + + if (scriptHandled != 0) { + if (scriptHandled == -1) { + Audio_SequencePlayerDisable(seqPlayer); + } else { + seqPlayer->delay = (u16)scriptHandled; + } + break; + } + } else if (command >= 0xC0) { + switch (command) { + case 0xF1: + Audio_NotePoolClear(&seqPlayer->notePool); + Audio_NotePoolFill(&seqPlayer->notePool, Audio_M64ReadU8(seqScript)); + break; + break; // This second break appears in the ASM, but the compiler currently optimizes it out. + case 0xF0: + Audio_NotePoolClear(&seqPlayer->notePool); + break; + case 0xDF: + seqPlayer->transposition = 0; + // Note: intentional fallthrough, also executes below command + case 0xDE: + seqPlayer->transposition += (s8)Audio_M64ReadU8(seqScript); + break; + case 0xDD: + seqPlayer->tempo = Audio_M64ReadU8(seqScript) * 48; + if (seqPlayer->tempo > gAudioContext.gTempoInternalToExternal) { + seqPlayer->tempo = (u16)gAudioContext.gTempoInternalToExternal; + } + if ((s16)seqPlayer->tempo <= 0) { + seqPlayer->tempo = 1; + } + break; + case 0xDC: + seqPlayer->unk_0C = (s8)Audio_M64ReadU8(seqScript) * 48; + break; + case 0xDA: + command = Audio_M64ReadU8(seqScript); + offset = Audio_M64ReadS16(seqScript); + switch (command) { + case 0: + case 1: + if (seqPlayer->state != 2) { + seqPlayer->fadeTimerUnkEu = offset; + seqPlayer->state = command; + } + break; + case 2: + seqPlayer->fadeTimer = offset; + seqPlayer->state = command; + seqPlayer->fadeVelocity = (0 - seqPlayer->fadeVolume) / (s32) seqPlayer->fadeTimer; + break; + } + break; + case 0xDB: + value = Audio_M64ReadU8(seqScript); + switch (seqPlayer->state) { + case 1: + seqPlayer->state = 0; + seqPlayer->fadeVolume = 0.0f; + // NOTE: Intentional fallthrough + case 0: + seqPlayer->fadeTimer = seqPlayer->fadeTimerUnkEu; + if (seqPlayer->fadeTimerUnkEu != 0) { + seqPlayer->fadeVelocity = ((value / 127.0f) - seqPlayer->fadeVolume) / + (s32)(seqPlayer->fadeTimer); + } else { + seqPlayer->fadeVolume = (s32)value / 127.0f; + } + break; + case 2: + break; + } + break; + case 0xD9: + seqPlayer->fadeVolumeScale = (s8)Audio_M64ReadU8(seqScript) / 127.0f; + break; + case 0xD7: + tempS = Audio_M64ReadS16(seqScript); + Audio_SequencePlayerInitChannels(seqPlayer, tempS); + break; + case 0xD6: + Audio_M64ReadS16(seqScript); + break; + case 0xD5: + seqPlayer->muteVolumeScale = (s8)Audio_M64ReadU8(seqScript) / 127.0f; + break; + case 0xD4: + seqPlayer->muted = true; + break; + case 0xD3: + seqPlayer->muteBehavior = Audio_M64ReadU8(seqScript); + break; + case 0xD1: + case 0xD2: + temp = Audio_M64ReadS16(seqScript); + data = &seqPlayer->seqData[temp]; + if (command == 0xD2) { + seqPlayer->shortNoteVelocityTable = data; + } else { + seqPlayer->shortNoteDurationTable = data; + } + break; + case 0xD0: + seqPlayer->noteAllocPolicy = Audio_M64ReadU8(seqScript); + break; + case 0xCE: { + command = Audio_M64ReadU8(seqScript); + // t register shift here + if (command == 0) { + seqScript->value = gAudioContext.gAudioRandom / 4; + } else { + seqScript->value = (gAudioContext.gAudioRandom / 4) % command; + } + } break; + case 0xCD: { + temp = Audio_M64ReadS16(seqScript); + + if ((seqScript->value != -1) && (seqScript->depth != 3)) { + // a/v registers are wrong here. may need to mess with temps + data = &seqPlayer->seqData[temp + seqScript->value * 2]; // should go in v0 + seqScript->stack[seqScript->depth] = seqScript->pc; + + seqScript->depth++; + offset = (data[0] << 8) + data[1]; + seqScript->pc = &seqPlayer->seqData[offset]; + } + } break; + case 0xCC: + seqScript->value = Audio_M64ReadU8(seqScript); + break; + case 0xC9: + seqScript->value &= Audio_M64ReadU8(seqScript); + break; + case 0xC8: + seqScript->value -= Audio_M64ReadU8(seqScript); + break; + case 0xC7: + command = Audio_M64ReadU8(seqScript); + offset = Audio_M64ReadS16(seqScript); + data = &seqPlayer->seqData[offset]; + data[0] = (u8)seqScript->value + command; + break; + case 0xC6: + seqPlayer->unk_0b2 = true; + return; + case 0xC5: + seqPlayer->unk_E0 = (u16)Audio_M64ReadS16(seqScript); + break; + case 0xEF: + Audio_M64ReadS16(seqScript); + Audio_M64ReadU8(seqScript); + break; + case 0xC4: + command = Audio_M64ReadU8(seqScript); + if (command == 0xFF) { + command = seqPlayer->seqVariationEu; + } + commandLow = Audio_M64ReadU8(seqScript); + func_800E20D4(command, commandLow, 0); + if (command == (u8)seqPlayer->seqVariationEu) { + return; + } + break; + } + } else { + commandLow = command & 0x0F; + + switch (command & 0xF0) { + case 0: + seqScript->value = seqPlayer->channels[commandLow]->enabled ^ 1; + break; + case 0x50: + seqScript->value -= seqPlayer->unk_158[commandLow]; + break; + case 0x70: + seqPlayer->unk_158[commandLow] = seqScript->value; + break; + case 0x80: + seqScript->value = seqPlayer->unk_158[commandLow]; + if (commandLow < 2) { + seqPlayer->unk_158[commandLow] = -1; + } + break; + case 0x40: + Audio_SequenceChannelDisable(seqPlayer->channels[commandLow]); + break; + case 0x90: + temp = Audio_M64ReadS16(seqScript); + Audio_SequenceChannelEnable(seqPlayer, commandLow, + (void*)&seqPlayer->seqData[temp]); + break; + case 0xA0: + tempS = Audio_M64ReadS16(seqScript); + Audio_SequenceChannelEnable(seqPlayer, commandLow, + (void*)&seqScript->pc[tempS]); + break; + case 0xB0: + command = Audio_M64ReadU8(seqScript); + temp = Audio_M64ReadS16(seqScript); + func_800E390C(command, &seqPlayer->seqData[temp], + &seqPlayer->unk_158[commandLow]); + break; + case 0x60: { + command = Audio_M64ReadU8(seqScript); // This shouldn't be cast to u8 when saved + temp = Audio_M64ReadU8(seqScript); + + func_800E4EEC(command, temp, &seqPlayer->unk_158[commandLow]); + break; + } + } + } + } + } + + for (i = 0; i < ARRAY_COUNT(seqPlayer->channels); i++) { + if (seqPlayer->channels[i]->enabled) { + Audio_SequenceChannelProcessScript(seqPlayer->channels[i]); + } + } +} +#else void Audio_SequencePlayerProcessSequence(SequencePlayer* seqPlayer); #pragma GLOBAL_ASM("asm/non_matchings/code/audio_seqplayer/Audio_SequencePlayerProcessSequence.s") +#endif void Audio_ProcessSequences(s32 arg0) { SequencePlayer* seqPlayer;