diff options
| author | engineer124 <47598039+engineer124@users.noreply.github.com> | 2023-03-30 19:53:47 +1100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-30 19:53:47 +1100 |
| commit | 6685a4775e440b247f3db62db4162dccbf0775ea (patch) | |
| tree | 14c20e33d91b6914f272d8301b7c3a0cfb544e01 /src/audio | |
| parent | 045c3537a9bae4fa7fb33985c7834f3c956d42f1 (diff) | |
Audio `sequence.c` OK and documented (#1201)
* import sequence docs
* cleanup
* do not need raw hex
Diffstat (limited to 'src/audio')
| -rw-r--r-- | src/audio/code_8019AF00.c | 306 | ||||
| -rw-r--r-- | src/audio/sequence.c | 921 | ||||
| -rw-r--r-- | src/audio/sfx.c | 8 | ||||
| -rw-r--r-- | src/audio/voice_internal.c | 2 |
4 files changed, 1108 insertions, 129 deletions
diff --git a/src/audio/code_8019AF00.c b/src/audio/code_8019AF00.c index 801e2b076..5af712e99 100644 --- a/src/audio/code_8019AF00.c +++ b/src/audio/code_8019AF00.c @@ -70,7 +70,7 @@ s32 Audio_SetGanonsTowerBgmVolume(u8 targetVolume); void Audio_StartMorningSceneSequence(u16 seqId); void Audio_StartSceneSequence(u16 seqId); -void Audio_PlaySequenceWithSeqPlayerIO(s8 playerIndex, u16 seqId, u8 fadeInDuration, s8 ioPort, u8 ioData); +void Audio_PlaySequenceWithSeqPlayerIO(s8 seqPlayerIndex, u16 seqId, u8 fadeInDuration, s8 ioPort, u8 ioData); void func_801A4428(u8 reverbIndex); void func_801A3038(void); void Audio_PlayAmbience(u8 ambienceId); @@ -2734,8 +2734,7 @@ void AudioOcarina_SetOcarinaDisableTimer(u8 unused, u8 timer) { void AudioOcarina_SetInstrument(u8 ocarinaInstrumentId) { if ((sOcarinaInstrumentId != ocarinaInstrumentId) || (ocarinaInstrumentId == OCARINA_INSTRUMENT_DEFAULT)) { - Audio_QueueSeqCmd(0x80000000 | ((u32)(SEQ_PLAYER_SFX) << 24) | ((u32)(1) << 16) | - ((u32)(SFX_CHANNEL_OCARINA) << 8) | (u32)(ocarinaInstrumentId)); + SEQCMD_SET_CHANNEL_IO(SEQ_PLAYER_SFX, SFX_CHANNEL_OCARINA, 1, ocarinaInstrumentId); sOcarinaInstrumentId = ocarinaInstrumentId; if (ocarinaInstrumentId == OCARINA_INSTRUMENT_OFF) { @@ -3303,7 +3302,10 @@ s32 AudioOcarina_MemoryGameNextNote(void) { sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcarinaMemoryGameAppendPos].length = 0; sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcarinaMemoryGameAppendPos + 1].pitch = OCARINA_PITCH_NONE; sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcarinaMemoryGameAppendPos + 1].length = 0; + + //! FAKE: if (1) {} + return false; } #undef OCARINA_SONG_MEMORY_GAME @@ -3407,8 +3409,7 @@ void AudioOcarina_SetCustomSequence(void) { // Called by unused function void AudioOcarina_PlayCustomSequence(void) { sRequestCustomSequence = true; - Audio_QueueSeqCmd(0x00000000 | ((u32)(SEQ_PLAYER_FANFARE) << 24) | ((u32)(0) << 0x10) | - (u32)(NA_BGM_DUNGEON_APPEAR)); + SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_FANFARE, 0, NA_BGM_DUNGEON_APPEAR); } // Unused @@ -3586,8 +3587,7 @@ s32 AudioOcarina_CreateCustomSequence(void) { void AudioOcarina_ResetInstrument(void) { if (sOcarinaInstrumentId != OCARINA_INSTRUMENT_OFF) { - Audio_QueueSeqCmd(0x80000000 | ((u32)(SEQ_PLAYER_SFX) << 24) | ((u32)(1) << 16) | - ((u32)(SFX_CHANNEL_OCARINA) << 8) | (u32)(0)); + SEQCMD_SET_CHANNEL_IO(SEQ_PLAYER_SFX, SFX_CHANNEL_OCARINA, 1, 0); sOcarinaInstrumentId = OCARINA_INSTRUMENT_OFF; AudioOcarina_ResetAndMute(); } @@ -3629,7 +3629,7 @@ void Audio_Noop3(void) { } void Audio_Update(void) { - if ((func_801A9768() == 0) && (func_801A982C() == 0)) { + if ((AudioSeq_UpdateAudioHeapReset() == 0) && !AudioSeq_ResetReverb()) { AudioOcarina_SetCustomSequence(); AudioOcarina_Update(); func_801A5118(); @@ -3646,9 +3646,9 @@ void Audio_Update(void) { func_801A1290(); Audio_ResetRequestedSceneSeqId(); AudioSfx_ProcessRequests(); - func_801A89D0(); + AudioSeq_ProcessSeqCmds(); AudioSfx_ProcessActiveSfx(); - func_801A8D5C(); + AudioSeq_UpdateActiveSequences(); AudioSfx_ProcessSfxSettings(); AudioThread_ScheduleProcessCmds(); } @@ -3660,7 +3660,14 @@ void Audio_Noop4(s32 arg0) { void Audio_Noop5(s32 arg0, s32 arg1) { } -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E110.s") +/** + * Queues a bgm sequence directly to the internal audio queue system. + * Skips the external audio command process + * Unused + */ +void Audio_PlayMainBgm(s8 seqId) { + AUDIOCMD_GLOBAL_INIT_SEQPLAYER(SEQ_PLAYER_BGM_MAIN, (u8)seqId, 1); +} f32 AudioSfx_ComputeVolume(u8 bankId, u8 entryIndex) { SfxBankEntry* bankEntry = &gSfxBanks[bankId][entryIndex]; @@ -4290,13 +4297,23 @@ f32 sBigBellsVolume[8] = { }; #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0124.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0184.s") +void Audio_SetBgmVolumeOff(void) { + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_FANFARE, 0, 10); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_SUB, VOL_SCALE_INDEX_FANFARE, 0, 10); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A01C4.s") +void Audio_SetBgmVolumeOn(void) { + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_FANFARE, 0x7F, 3); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_SUB, VOL_SCALE_INDEX_FANFARE, 0x7F, 3); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0204.s") +void func_801A0204(s8 seqId) { + AUDIOCMD_SEQPLAYER_SET_IO(SEQ_PLAYER_BGM_MAIN, 2, (u8)seqId); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0238.s") +void Audio_SetMainBgmVolume(u8 targetVolume, u8 volumeFadeTimer) { + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_BGM_MAIN, targetVolume, volumeFadeTimer); +} /** * Unused remnant from OoT's EnRiverSound @@ -4338,7 +4355,7 @@ s32 Audio_SetGanonsTowerBgmVolume(u8 targetVolume) { if (sGanonsTowerVol != targetVolume) { // Sets the volume - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 0, targetVolume, 2); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_BGM_MAIN, targetVolume, 2); // Sets the filter cutoff of the form (lowPassFilterCutoff << 4) | (highPassFilter & 0xF). highPassFilter is // always set to 0 @@ -4350,8 +4367,7 @@ s32 Audio_SetGanonsTowerBgmVolume(u8 targetVolume) { lowPassFilterCutoff = (((targetVolume - 0x40) >> 2) + 1) << 4; } - Audio_QueueSeqCmd((8 << 28) | ((u8)(SEQ_PLAYER_BGM_MAIN) << 24) | ((u8)(4) << 16) | ((u8)(15) << 8) | - (u8)(lowPassFilterCutoff)); + SEQCMD_SET_CHANNEL_IO(SEQ_PLAYER_BGM_MAIN, 15, 4, lowPassFilterCutoff); // Sets the reverb for (channelIndex = 0; channelIndex < ARRAY_COUNT(gAudioCtx.seqPlayers[SEQ_PLAYER_BGM_MAIN].channels); @@ -4399,14 +4415,14 @@ void Audio_UpdateRiverSoundVolumes(void) { if (sRiverSoundMainBgmLower == true) { if (sRiverSoundMainBgmCurrentVol != sRiverSoundMainBgmVol) { // lowers the volume for 1 frame - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 0, sRiverSoundMainBgmVol, 10); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_BGM_MAIN, sRiverSoundMainBgmVol, 10); sRiverSoundMainBgmCurrentVol = sRiverSoundMainBgmVol; sRiverSoundMainBgmRestore = true; } sRiverSoundMainBgmLower = false; } else if ((sRiverSoundMainBgmRestore == true) && !sAudioIsWindowOpen) { // restores the volume every frame - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 0, 0x7F, 10); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_BGM_MAIN, 0x7F, 10); sRiverSoundMainBgmCurrentVol = 0x7F; sRiverSoundMainBgmRestore = false; } @@ -4488,10 +4504,9 @@ void func_801A09D4(Vec3f* pos, f32 xzDistToPlayer) { volumeRel = ((1.0f - ((sRiverSoundXZDistToPlayer - 120.0f) / 280.0f)) * 0.9f) + 0.1f; } - for (channelIndex = 0; channelIndex < 16; channelIndex++) { + for (channelIndex = 0; channelIndex < SEQ_NUM_CHANNELS; channelIndex++) { if (channelIndex != 9) { - Audio_QueueSeqCmd(((u32)(6) << 28) | ((u32)(SEQ_PLAYER_BGM_MAIN) << 24) | ((u32)(2) << 16) | - ((u32)(channelIndex) << 8) | ((u8)(127.0f * volumeRel))); + SEQCMD_SET_CHANNEL_VOLUME(SEQ_PLAYER_BGM_MAIN, channelIndex, 2, (u8)(127.0f * volumeRel)); AUDIOCMD_CHANNEL_SET_PAN(SEQ_PLAYER_BGM_MAIN, channelIndex, pan); } } @@ -4527,8 +4542,8 @@ void Audio_SplitBgmChannels(s8 volumeSplit) { u8 i; u8 channelIndex; - if ((Audio_GetActiveSequence(SEQ_PLAYER_FANFARE) == NA_BGM_DISABLED) && - (Audio_GetActiveSequence(SEQ_PLAYER_BGM_SUB) != NA_BGM_ROMANI_RANCH)) { + if ((AudioSeq_GetActiveSeqId(SEQ_PLAYER_FANFARE) == NA_BGM_DISABLED) && + (AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_SUB) != NA_BGM_ROMANI_RANCH)) { for (i = 0; i < ARRAY_COUNT(sBgmPlayers); i++) { if (i == 0) { // Main Bgm SeqPlayer @@ -4556,7 +4571,7 @@ void Audio_SplitBgmChannels(s8 volumeSplit) { } } - Audio_QueueSeqCmd(0xA0000000 | ((u32)(sBgmPlayers[i]) << 24) | ((u32)(channelBits))); + SEQCMD_SET_CHANNEL_DISABLE_MASK(sBgmPlayers[i], channelBits); } } } @@ -4635,8 +4650,8 @@ void Audio_PlaySariaBgm(Vec3f* pos, u16 seqId, u16 distMax) { Audio_SplitBgmChannels(targetVolume); } - Audio_SetVolumeScale(SEQ_PLAYER_BGM_SUB, 3, targetVolume, 0); - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 3, 0x7F - targetVolume, 0); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_SUB, VOL_SCALE_INDEX_BGM_SUB, targetVolume, 0); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_BGM_SUB, 0x7F - targetVolume, 0); } /** @@ -4650,12 +4665,12 @@ void Audio_ClearSariaBgm2(void) { void Audio_PlayMorningSceneSequence(u16 seqId, u8 dayMinusOne) { Audio_StartMorningSceneSequence(seqId); - Audio_QueueSeqCmd(0x70000000 | ((u32)(SEQ_PLAYER_BGM_MAIN) << 24) | ((u32)(4) << 0x10) | (u32)(dayMinusOne)); + SEQCMD_SET_SEQPLAYER_IO(SEQ_PLAYER_BGM_MAIN, 4, dayMinusOne); } void Audio_StartMorningSceneSequence(u16 seqId) { if (seqId != NA_BGM_AMBIENCE) { - Audio_QueueSeqCmd(0x100000FF | ((u8)(SEQ_PLAYER_AMBIENCE) << 24) | ((0) << 16)); + SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_AMBIENCE, 0); Audio_StartSceneSequence(seqId); Audio_PlaySequenceWithSeqPlayerIO(SEQ_PLAYER_BGM_MAIN, seqId, 0, 0, 1); } else { @@ -4669,8 +4684,7 @@ void Audio_PlaySceneSequence(u16 seqId, u8 dayMinusOne) { Audio_PlayAmbience(AMBIENCE_ID_08); } else if ((seqId != NA_BGM_FINAL_HOURS) || (sPrevMainBgmSeqId == NA_BGM_DISABLED)) { Audio_StartSceneSequence(seqId); - Audio_QueueSeqCmd(0x70000000 | ((u32)(SEQ_PLAYER_BGM_MAIN) << 24) | ((u32)(4) << 0x10) | - (u32)(dayMinusOne)); + SEQCMD_SET_SEQPLAYER_IO(SEQ_PLAYER_BGM_MAIN, 4, dayMinusOne); } sRequestedSceneSeqId = seqId; } @@ -4710,7 +4724,7 @@ void Audio_StartSceneSequence(u16 seqId) { } void Audio_UpdateSceneSequenceResumePoint(void) { - u16 seqId = Audio_GetActiveSequence(SEQ_PLAYER_BGM_MAIN); + u16 seqId = AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_MAIN); if ((seqId != NA_BGM_DISABLED) && (sSeqFlags[seqId & 0xFF & 0xFF] & SEQ_FLAG_RESUME)) { if (sSeqResumePoint != SEQ_RESUME_POINT_NONE) { @@ -4723,55 +4737,95 @@ void Audio_UpdateSceneSequenceResumePoint(void) { } } -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A27E8.s") +// Unused +void Audio_PlayBgmForSongOfStorms(void) { + if (AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_MAIN) != NA_BGM_SONG_OF_STORMS) { + SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 0, NA_BGM_SONG_OF_STORMS | SEQ_FLAG_ASYNC); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A281C.s") +/** + * Specifically for SEQ_PLAYER_BGM_MAIN + */ +void Audio_ScaleTempoAndFreqForMainBgm(f32 freqTempoScale, u8 duration) { + if (freqTempoScale == 1.0f) { + SEQCMD_RESET_TEMPO(SEQ_PLAYER_BGM_MAIN, duration); + } else { + SEQCMD_SCALE_TEMPO(SEQ_PLAYER_BGM_MAIN, duration, freqTempoScale * 100.0f); + } -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A29D4.s") + SEQCMD_SET_SEQPLAYER_FREQ(SEQ_PLAYER_BGM_MAIN, duration, freqTempoScale * 1000.0f); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A2BB8.s") +void Audio_SetSeqTempoAndFreq(u8 seqPlayerIndex, f32 freqTempoScale, u8 duration) { + if (freqTempoScale == 1.0f) { + SEQCMD_RESET_TEMPO(seqPlayerIndex, duration); + } else { + SEQCMD_SCALE_TEMPO(seqPlayerIndex, duration, freqTempoScale * 100.0f); + } + + SEQCMD_SET_SEQPLAYER_FREQ(seqPlayerIndex, duration, freqTempoScale * 1000.0f); +} + +void Audio_PlaySubBgm(u16 seqId) { + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_SUB, VOL_SCALE_INDEX_BGM_SUB, 0x7F, 0); + SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_SUB, 0, seqId); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_BGM_SUB, 0, 5); + + SEQCMD_SETUP_RESTORE_SEQPLAYER_VOLUME_WITH_SCALE_INDEX(SEQ_PLAYER_BGM_SUB, SEQ_PLAYER_BGM_MAIN, 3, 10); + SEQCMD_SETUP_SET_CHANNEL_DISABLE_MASK(SEQ_PLAYER_BGM_SUB, SEQ_PLAYER_BGM_MAIN, 0); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A2C20.s") +void Audio_StopSubBgm(void) { + SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_BGM_SUB, 0); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A2C44.s") +// Unused remnant of OoT +void Audio_IncreaseTempoForTimedMinigame(void) { + if ((AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_MAIN) == NA_BGM_TIMED_MINI_GAME) && + AudioSeq_IsSeqCmdNotQueued(SEQCMD_OP_PLAY_SEQUENCE << 28, SEQCMD_OP_MASK)) { + // Set tempo to be higher than the default tempo for th timed mini-game sequence + SEQCMD_SET_TEMPO(SEQ_PLAYER_BGM_MAIN, 5, 210); + } +} void Audio_PlaySequenceInCutscene(u16 seqId) { if (sSeqFlags[seqId & 0xFF & 0xFF] & SEQ_FLAG_FANFARE) { Audio_PlayFanfare(seqId); } else if (sSeqFlags[seqId & 0xFF & 0xFF] & SEQ_FLAG_FANFARE_KAMARO) { - Audio_QueueSeqCmd(0x00000000 | ((u32)(SEQ_PLAYER_FANFARE) << 24) | ((u32)(0) << 0x10) | (u32)(seqId)); + SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_FANFARE, 0, seqId); } else if (sSeqFlags[seqId & 0xFF & 0xFF] & SEQ_FLAG_NO_AMBIENCE) { - Audio_QueueSeqCmd(0x00000000 | ((u32)(SEQ_PLAYER_BGM_SUB) << 24) | ((u32)(0) << 0x10) | (u32)(seqId)); + SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_SUB, 0, seqId); } else { Audio_PlaySequenceWithSeqPlayerIO(SEQ_PLAYER_BGM_MAIN, seqId, 0, 7, SEQ_IO_VAL_NONE); - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 1, 0x7F, 0); - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 3, 0x7F, 0); - Audio_QueueSeqCmd(0x100000FF | ((u8)(SEQ_PLAYER_FANFARE) << 24) | ((0) << 16)); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_FANFARE, 0x7F, 0); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_BGM_SUB, 0x7F, 0); + SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_FANFARE, 0); } } void Audio_StopSequenceInCutscene(u16 seqId) { if (sSeqFlags[seqId & 0xFF & 0xFF] & SEQ_FLAG_FANFARE) { - Audio_QueueSeqCmd(0x100000FF | ((u8)(SEQ_PLAYER_FANFARE) << 24) | ((0) << 16)); + SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_FANFARE, 0); } else if (sSeqFlags[seqId & 0xFF & 0xFF] & SEQ_FLAG_FANFARE_KAMARO) { - Audio_QueueSeqCmd(0x100000FF | ((u8)(SEQ_PLAYER_FANFARE) << 24) | ((0) << 16)); + SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_FANFARE, 0); } else if (sSeqFlags[seqId & 0xFF & 0xFF] & SEQ_FLAG_NO_AMBIENCE) { - Audio_QueueSeqCmd(0x100000FF | ((u8)(SEQ_PLAYER_BGM_SUB) << 24) | ((0) << 16)); + SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_BGM_SUB, 0); } else { - Audio_QueueSeqCmd(0x100000FF | ((u8)(SEQ_PLAYER_BGM_MAIN) << 24) | ((0) << 16)); + SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 0); } } s32 Audio_IsSequencePlaying(u8 seqId) { - u8 playerIndex = SEQ_PLAYER_BGM_MAIN; + u8 seqPlayerIndex = SEQ_PLAYER_BGM_MAIN; if (sSeqFlags[seqId & 0xFF] & SEQ_FLAG_FANFARE) { - playerIndex = SEQ_PLAYER_FANFARE; + seqPlayerIndex = SEQ_PLAYER_FANFARE; } else if (sSeqFlags[seqId & 0xFF] & SEQ_FLAG_FANFARE_KAMARO) { - playerIndex = SEQ_PLAYER_FANFARE; + seqPlayerIndex = SEQ_PLAYER_FANFARE; } - if (seqId == (Audio_GetActiveSequence(playerIndex) & 0xFF)) { + if (seqId == (AudioSeq_GetActiveSeqId(seqPlayerIndex) & 0xFF)) { return true; } else { return false; @@ -4779,7 +4833,7 @@ s32 Audio_IsSequencePlaying(u8 seqId) { } void Audio_PlayBgm_StorePrevBgm(u16 seqId) { - u16 curSeqId = Audio_GetActiveSequence(SEQ_PLAYER_BGM_MAIN); + u16 curSeqId = AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_MAIN); if (curSeqId == NA_BGM_DISABLED) { curSeqId = NA_BGM_GENERAL_SFX; @@ -4793,7 +4847,7 @@ void Audio_PlayBgm_StorePrevBgm(u16 seqId) { sPrevMainBgmSeqId = curSeqId; } - Audio_QueueSeqCmd(0x00000000 | ((u32)(SEQ_PLAYER_BGM_MAIN) << 24) | ((u32)(0) << 0x10) | (u32)(seqId + 0x8000)); + SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 0, seqId + SEQ_FLAG_ASYNC); } } @@ -4801,16 +4855,15 @@ void Audio_PlayBgm_StorePrevBgm(u16 seqId) { * To be used in conjunction with Audio_PlayBgm_StorePrevBgm */ void Audio_RestorePrevBgm(void) { - if ((Audio_GetActiveSequence(SEQ_PLAYER_BGM_MAIN) != NA_BGM_DISABLED) && - (sSeqFlags[Audio_GetActiveSequence(SEQ_PLAYER_BGM_MAIN) & 0xFF] & SEQ_FLAG_RESTORE)) { + if ((AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_MAIN) != NA_BGM_DISABLED) && + (sSeqFlags[AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_MAIN) & 0xFF] & SEQ_FLAG_RESTORE)) { if ((sPrevMainBgmSeqId == NA_BGM_DISABLED) || (sPrevMainBgmSeqId == NA_BGM_GENERAL_SFX)) { - Audio_QueueSeqCmd(0x100000FF | ((u8)(SEQ_PLAYER_BGM_MAIN) << 24) | ((0) << 16)); + SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 0); } else { if (sPrevMainBgmSeqId == NA_BGM_AMBIENCE) { sPrevMainBgmSeqId = sPrevAmbienceSeqId; } - Audio_QueueSeqCmd(0x00000000 | ((u32)(SEQ_PLAYER_BGM_MAIN) << 24) | ((u32)(0) << 0x10) | - (u32)(sPrevMainBgmSeqId + 0x8000)); + SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 0, sPrevMainBgmSeqId + SEQ_FLAG_ASYNC); } sPrevMainBgmSeqId = NA_BGM_DISABLED; } @@ -4818,7 +4871,7 @@ void Audio_RestorePrevBgm(void) { // Unused void Audio_PlayAmbience_StorePrevBgm(u8 ambienceId) { - u16 seqId = Audio_GetActiveSequence(SEQ_PLAYER_BGM_MAIN); + u16 seqId = AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_MAIN); if (seqId != NA_BGM_AMBIENCE) { sPrevMainBgmSeqId = seqId; @@ -4830,8 +4883,7 @@ void Audio_PlayAmbience_StorePrevBgm(u8 ambienceId) { // Unused void Audio_ForceRestorePreviousBgm(void) { if (sPrevMainBgmSeqId != NA_BGM_DISABLED) { - Audio_QueueSeqCmd(0x00000000 | ((u32)(SEQ_PLAYER_BGM_MAIN) << 24) | ((u32)(0) << 0x10) | - (u32)(sPrevMainBgmSeqId + 0x8000)); + SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 0, sPrevMainBgmSeqId + SEQ_FLAG_ASYNC); } sPrevMainBgmSeqId = NA_BGM_DISABLED; @@ -4847,16 +4899,16 @@ void Audio_ForceRestorePreviousBgm(void) { #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A31EC.s") -void Audio_PlaySequenceWithSeqPlayerIO(s8 playerIndex, u16 seqId, u8 fadeInDuration, s8 ioPort, u8 ioData) { +void Audio_PlaySequenceWithSeqPlayerIO(s8 seqPlayerIndex, u16 seqId, u8 fadeInDuration, s8 ioPort, u8 ioData) { u16 flaggedSeqId; - Audio_QueueSeqCmd(0x70000000 | ((u32)(playerIndex) << 24) | ((u32)(ioPort) << 0x10) | (u32)(ioData)); + SEQCMD_SET_SEQPLAYER_IO(seqPlayerIndex, ioPort, ioData); if ((seqId & 0xFF) < 2) { flaggedSeqId = seqId; } else { flaggedSeqId = seqId | 0x8000; } - Audio_QueueSeqCmd(0x00000000 | ((u32)(playerIndex) << 24) | ((u32)(fadeInDuration) << 0x10) | (u32)(flaggedSeqId)); + SEQCMD_PLAY_SEQUENCE((u32)seqPlayerIndex, fadeInDuration, flaggedSeqId); } void Audio_SetSequenceMode(u8 seqMode) { @@ -4884,17 +4936,18 @@ void Audio_SetSequenceMode(u8 seqMode) { volumeFadeInTimer = gActiveSeqs[SEQ_PLAYER_BGM_SUB].volScales[1] - sBgmEnemyVolume; } - Audio_SetVolumeScale(SEQ_PLAYER_BGM_SUB, 3, sBgmEnemyVolume, volumeFadeInTimer); - Audio_QueueSeqCmd(0x00000000 | ((u32)(SEQ_PLAYER_BGM_SUB) << 24) | ((u32)(10) << 0x10) | - (u32)(NA_BGM_ENEMY | 0x800)); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_SUB, VOL_SCALE_INDEX_BGM_SUB, sBgmEnemyVolume, + volumeFadeInTimer); + SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_SUB, 10, NA_BGM_ENEMY | 0x800); if (seqId >= NA_BGM_TERMINA_FIELD) { - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 3, 0x7F - sBgmEnemyVolume, 10); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_BGM_SUB, 0x7F - sBgmEnemyVolume, + 10); Audio_SplitBgmChannels(sBgmEnemyVolume); } } else if ((sPrevSeqMode & 0x7F) == SEQ_MODE_ENEMY) { // If only sPrevSeqMode = SEQ_MODE_ENEMY (End) - Audio_QueueSeqCmd(0x100000FF | ((u8)(SEQ_PLAYER_BGM_SUB) << 24) | ((10) << 16)); + SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_BGM_SUB, 10); if (seqMode == SEQ_MODE_IGNORE) { volumeFadeOutTimer = 0; @@ -4902,7 +4955,7 @@ void Audio_SetSequenceMode(u8 seqMode) { volumeFadeOutTimer = 10; } - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 3, 0x7F, volumeFadeOutTimer); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_BGM_SUB, 0x7F, volumeFadeOutTimer); Audio_SplitBgmChannels(0); } @@ -4910,10 +4963,9 @@ void Audio_SetSequenceMode(u8 seqMode) { } else { if (seqMode == SEQ_MODE_ENEMY) { // If both seqMode = sPrevSeqMode = SEQ_MODE_ENEMY - if ((Audio_GetActiveSequence(SEQ_PLAYER_BGM_SUB) == NA_BGM_DISABLED) && + if ((AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_SUB) == NA_BGM_DISABLED) && (seqId != NA_BGM_DISABLED) && (sSeqFlags[seqId & 0xFF & 0xFF] & SEQ_FLAG_ENEMY)) { - Audio_QueueSeqCmd(0x00000000 | ((u32)(SEQ_PLAYER_BGM_SUB) << 24) | ((u32)(10) << 0x10) | - (u32)(NA_BGM_ENEMY | 0x800)); + SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_SUB, 10, NA_BGM_ENEMY | 0x800); sPrevSeqMode = seqMode + 0x80; } } @@ -4935,7 +4987,7 @@ void Audio_SetSequenceMode(u8 seqMode) { } sPrevSeqMode = seqMode; - Audio_QueueSeqCmd(0x70000000 | ((u32)(SEQ_PLAYER_BGM_MAIN) << 24) | ((u32)(2) << 0x10) | (u32)(seqMode)); + SEQCMD_SET_SEQPLAYER_IO(SEQ_PLAYER_BGM_MAIN, 2, seqMode); } } } @@ -4956,10 +5008,10 @@ void Audio_UpdateEnemyBgmVolume(f32 dist) { } sBgmEnemyVolume = ((350.0f - adjDist) * 127.0f) / 350.0f; - Audio_SetVolumeScale(SEQ_PLAYER_BGM_SUB, 3, sBgmEnemyVolume, 10); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_SUB, VOL_SCALE_INDEX_BGM_SUB, sBgmEnemyVolume, 10); if ((seqId >= NA_BGM_TERMINA_FIELD) && !(sSeqFlags[seqId & 0xFF & 0xFF] & SEQ_FLAG_FANFARE_KAMARO)) { - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 3, (0x7F - sBgmEnemyVolume), 10); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_BGM_SUB, (0x7F - sBgmEnemyVolume), 10); } } @@ -5032,7 +5084,8 @@ void Audio_ResetRequestedSceneSeqId(void) { sRequestedSceneSeqId = NA_BGM_DISABLED; } -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A44D4.s") +void Audio_ResetData(void); +#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/Audio_ResetData.s") #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A46F8.s") @@ -5046,13 +5099,15 @@ void Audio_SetAmbienceChannelIO(u8 channelIndexRange, u8 ioPort, u8 ioData) { u8 lastChannelIndex; u8 channelIndex; - if ((gActiveSeqs[SEQ_PLAYER_AMBIENCE].seqId != NA_BGM_AMBIENCE) && func_801A8ABC(NA_BGM_AMBIENCE, 0xF00000FF)) { + if ((gActiveSeqs[SEQ_PLAYER_AMBIENCE].seqId != NA_BGM_AMBIENCE) && + AudioSeq_IsSeqCmdNotQueued((SEQCMD_OP_PLAY_SEQUENCE << 28) | NA_BGM_AMBIENCE, + SEQCMD_OP_MASK | SEQCMD_SEQID_MASK)) { return; } // channelIndexRange = 01 on ioPort 1 if ((((channelIndexRange << 8) + (u32)ioPort) == ((1 << 8) | (u32)1)) && - (Audio_GetActiveSequence(SEQ_PLAYER_BGM_SUB) != NA_BGM_ROMANI_RANCH)) { + (AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_SUB) != NA_BGM_ROMANI_RANCH)) { D_801FD3A8 = 0; } @@ -5064,38 +5119,33 @@ void Audio_SetAmbienceChannelIO(u8 channelIndexRange, u8 ioPort, u8 ioData) { } for (channelIndex = firstChannelIndex; channelIndex <= lastChannelIndex; channelIndex++) { - Audio_QueueSeqCmd(0x80000000 | ((u32)(SEQ_PLAYER_AMBIENCE) << 24) | ((u32)(ioPort) << 16) | - ((u32)(channelIndex) << 8) | (u32)(ioData)); + SEQCMD_SET_CHANNEL_IO(SEQ_PLAYER_AMBIENCE, channelIndex, ioPort, ioData); } } void Audio_StartAmbience(u16 initChannelMask, u16 initMuteChannelMask) { u8 channelIndex; - Audio_QueueSeqCmd(0x70000000 | ((u32)(SEQ_PLAYER_AMBIENCE) << 24) | ((u32)(SEQ_PLAYER_IO_PORT_0) << 0x10) | - (u32)(1)); - Audio_QueueSeqCmd(0x70000000 | ((u32)(SEQ_PLAYER_AMBIENCE) << 24) | ((u32)(SEQ_PLAYER_IO_PORT_4) << 0x10) | - (u32)((u8)(initChannelMask >> 8))); - Audio_QueueSeqCmd(0x70000000 | ((u32)(SEQ_PLAYER_AMBIENCE) << 24) | ((u32)(SEQ_PLAYER_IO_PORT_5) << 0x10) | - (u32)((u8)(initChannelMask & 0xFF))); - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 0, 0x7F, 1); - - if ((Audio_GetActiveSequence(SEQ_PLAYER_AMBIENCE) != NA_BGM_DISABLED) && - (Audio_GetActiveSequence(SEQ_PLAYER_AMBIENCE) != NA_BGM_AMBIENCE)) { - Audio_StopSequence(SEQ_PLAYER_AMBIENCE, 0); + SEQCMD_SET_SEQPLAYER_IO(SEQ_PLAYER_AMBIENCE, SEQ_PLAYER_IO_PORT_0, 1); + SEQCMD_SET_SEQPLAYER_IO(SEQ_PLAYER_AMBIENCE, SEQ_PLAYER_IO_PORT_4, (u8)(initChannelMask >> 8)); + SEQCMD_SET_SEQPLAYER_IO(SEQ_PLAYER_AMBIENCE, SEQ_PLAYER_IO_PORT_5, (u8)(initChannelMask & 0xFF)); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_BGM_MAIN, 0x7F, 1); + + if ((AudioSeq_GetActiveSeqId(SEQ_PLAYER_AMBIENCE) != NA_BGM_DISABLED) && + (AudioSeq_GetActiveSeqId(SEQ_PLAYER_AMBIENCE) != NA_BGM_AMBIENCE)) { + AudioSeq_StopSequence(SEQ_PLAYER_AMBIENCE, 0); AUDIOCMD_GLOBAL_STOP_AUDIOCMDS(); } - if (Audio_GetActiveSequence(SEQ_PLAYER_BGM_SUB) == (NA_BGM_ENEMY | 0x800)) { - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 3, 0x7F, 1); + if (AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_SUB) == (NA_BGM_ENEMY | 0x800)) { + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_BGM_SUB, 0x7F, 1); } - Audio_QueueSeqCmd(0x00000000 | ((u32)(SEQ_PLAYER_AMBIENCE) << 24) | ((u32)(0) << 0x10) | (u32)(NA_BGM_AMBIENCE)); + SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_AMBIENCE, 0, NA_BGM_AMBIENCE); - for (channelIndex = 0; channelIndex < 16; channelIndex++) { + for (channelIndex = 0; channelIndex < SEQ_NUM_CHANNELS; channelIndex++) { if (!(initMuteChannelMask & (1 << channelIndex)) && (initChannelMask & (1 << channelIndex))) { - Audio_QueueSeqCmd(0x80000000 | ((u32)(SEQ_PLAYER_AMBIENCE) << 24) | ((u32)(CHANNEL_IO_PORT_1) << 16) | - ((u32)(channelIndex) << 8) | (u32)(1)); + SEQCMD_SET_CHANNEL_IO(SEQ_PLAYER_AMBIENCE, channelIndex, CHANNEL_IO_PORT_1, 1); } } } @@ -5119,12 +5169,10 @@ void Audio_PlayAmbience(u8 ambienceId) { channelIndex = sAmbienceData[ambienceId].channelProperties[i++]; ioPort = sAmbienceData[ambienceId].channelProperties[i++]; ioData = sAmbienceData[ambienceId].channelProperties[i++]; - Audio_QueueSeqCmd(0x80000000 | ((u32)(SEQ_PLAYER_AMBIENCE) << 24) | ((u32)(ioPort) << 16) | - ((u32)(channelIndex) << 8) | (u32)(ioData)); + SEQCMD_SET_CHANNEL_IO(SEQ_PLAYER_AMBIENCE, channelIndex, ioPort, ioData); } - Audio_QueueSeqCmd(0x80000000 | ((u32)(SEQ_PLAYER_AMBIENCE) << 24) | ((u32)(CHANNEL_IO_PORT_7) << 16) | - ((u32)(AMBIENCE_CHANNEL_SOUND_MODE) << 8) | (u32)(sSoundMode)); + SEQCMD_SET_CHANNEL_IO(SEQ_PLAYER_AMBIENCE, AMBIENCE_CHANNEL_SOUND_MODE, CHANNEL_IO_PORT_7, sSoundMode); } } @@ -5155,7 +5203,7 @@ void AudioSfx_Init(u16 fadeTimer) { u8 channelIndex; AudioThread_ScheduleProcessCmds(); - Audio_StartSequence(SEQ_PLAYER_SFX, NA_BGM_GENERAL_SFX, 0x70, fadeTimer); + AudioSeq_StartSequence(SEQ_PLAYER_SFX, NA_BGM_GENERAL_SFX, 0x70, fadeTimer); for (channelIndex = 0; channelIndex < ARRAY_COUNT(sSfxChannelState); channelIndex++) { AUDIOCMD_CHANNEL_SET_SFX_STATE(SEQ_PLAYER_SFX, channelIndex, &sSfxChannelState[channelIndex]); @@ -5165,12 +5213,52 @@ void AudioSfx_Init(u16 fadeTimer) { AUDIOCMD_GLOBAL_SET_CUSTOM_FUNCTION(AUDIO_CUSTOM_FUNCTION_SEQ_1, Audio_SetAmbienceRandomBend); } -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4D00.s") +void Audio_InitSound(void) { + Audio_ResetData(); + AudioOcarina_ResetStaffs(); + AudioSfx_ResetSfxChannelState(); + AudioSeq_ResetActiveSequencesAndVolume(); + AudioSfx_Reset(); + AudioVoice_ResetData(); + AudioSfx_Init(10); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4D50.s") +void Audio_ResetForAudioHeapStep3(void) { + AudioSfx_Init(1); + AUDIOCMD_GLOBAL_UNMUTE(AUDIOCMD_ALL_SEQPLAYERS, true); + AudioThread_ScheduleProcessCmds(); + AUDIOCMD_GLOBAL_STOP_AUDIOCMDS(); + sIsFinalHoursOrSoaring = false; + sObjSoundMainBgmSeqId = NA_BGM_GENERAL_SFX; + sMuteOnlySfxAndAmbienceSeq = false; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4DA4.s") +void Audio_ResetForAudioHeapStep2(void) { + Audio_ResetForAudioHeapStep3(); + if (gAudioSpecId < ARRAY_COUNT(gReverbSettingsTable)) { + AUDIOCMD_GLOBAL_SET_REVERB_DATA(1, REVERB_DATA_TYPE_SETTINGS, &gReverbSettingsTable[gAudioSpecId][1]); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4DF4.s") +void Audio_ResetForAudioHeapStep1(s32 specId) { + gAudioHeapResetState = AUDIO_HEAP_RESET_STATE_RESETTING; + Audio_ResetData(); + AudioOcarina_ResetStaffs(); + AudioSfx_ResetSfxChannelState(); + AudioSeq_ResetActiveSequences(); + AudioSfx_Reset(); + func_801A4FD8(); + if (gAudioSpecId == 0xB) { + AudioSfx_MuteBanks((1 << BANK_PLAYER) | (1 << BANK_ITEM) | (1 << BANK_ENV) | (1 << BANK_ENEMY) | + (1 << BANK_OCARINA) | (1 << BANK_VOICE)); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4E64.s") +void Audio_UnusedReset(void) { + AudioSeq_ResetActiveSequences(); + AUDIOCMD_GLOBAL_UNMUTE(AUDIOCMD_ALL_SEQPLAYERS, true); + Audio_ResetData(); + AudioSfx_ResetSfxChannelState(); + AudioSfx_Init(1); + func_801A4FD8(); +} diff --git a/src/audio/sequence.c b/src/audio/sequence.c index 613f1ef1d..7d37a0ae9 100644 --- a/src/audio/sequence.c +++ b/src/audio/sequence.c @@ -1,31 +1,922 @@ +/** + * @file sequence.c + * + * This file implements a set of high-level audio sequence commands that allow sequences to be modified in real-time. + * These commands are intended to interface external to the audio library. + * + * These commands are generated using `AudioSeq_QueueSeqCmd`, and a user-friendly interface for this function + * can be found in `seqcmd.h` + * + * These commands change sequences by generating internal audio commands `AudioThread_QueueCmd` which allows these + * sequence requests to be passed onto the audio thread. It is worth noting all functions in this file are + * called from the graph thread. + * + * These commands are not to be confused with the sequence instructions used by the sequences themselves + * which are a midi-based scripting language. + * + * Nor are these commands to be confused with the internal audio commands used to transfer requests from + * the graph thread to the audio thread. + */ #include "global.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/Audio_StartSequence.s") +// Direct audio command (skips the queueing system) +#define SEQCMD_SET_SEQPLAYER_VOLUME_NOW(seqPlayerIndex, duration, volume) \ + AudioSeq_ProcessSeqCmd((SEQCMD_OP_SET_SEQPLAYER_VOLUME << 28) | ((u8)(seqPlayerIndex) << 24) | \ + ((u8)(duration) << 16) | ((u8)((volume)*127.0f))); -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/Audio_StopSequence.s") +u8 sSeqCmdWritePos = 0; +u8 sSeqCmdReadPos = 0; +u8 sStartSeqDisabled = 0; +u8 sSoundModeList[] = { + SOUNDMODE_STEREO, SOUNDMODE_HEADSET, SOUNDMODE_SURROUND_EXTERNAL, SOUNDMODE_MONO, SOUNDMODE_SURROUND, +}; +u8 gAudioSpecId = 0; +u8 gAudioHeapResetState = AUDIO_HEAP_RESET_STATE_NONE; +u32 sResetAudioHeapSeqCmd = 0; -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/func_801A7D84.s") +void AudioSeq_StartSequence(u8 seqPlayerIndex, u8 seqId, u8 seqArgs, u16 fadeInDuration) { + u8 channelIndex; + u16 skipTicks; + s32 pad; -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/Audio_QueueSeqCmd.s") + if (!sStartSeqDisabled || (seqPlayerIndex == SEQ_PLAYER_SFX)) { + seqArgs &= 0x7F; + if (seqArgs == 0x7F) { + // `fadeInDuration` interpreted as seconds, 60 is refresh rate and does not account for PAL + skipTicks = (fadeInDuration >> 3) * 60 * gAudioCtx.audioBufferParameters.updatesPerFrame; + AUDIOCMD_GLOBAL_INIT_SEQPLAYER_SKIP_TICKS(seqPlayerIndex, seqId, skipTicks); + } else { + // `fadeInDuration` interpreted as 1/30th of a second, does not account for change in refresh rate for PAL + AUDIOCMD_GLOBAL_INIT_SEQPLAYER(seqPlayerIndex, seqId, + (fadeInDuration * (u16)gAudioCtx.audioBufferParameters.updatesPerFrame) / 4); + } -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/func_801A89D0.s") + gActiveSeqs[seqPlayerIndex].seqId = seqId | (seqArgs << 8); + gActiveSeqs[seqPlayerIndex].prevSeqId = seqId | (seqArgs << 8); + gActiveSeqs[seqPlayerIndex].isSeqPlayerInit = true; -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/Audio_GetActiveSequence.s") + if (gActiveSeqs[seqPlayerIndex].volCur != 1.0f) { + AUDIOCMD_SEQPLAYER_FADE_VOLUME_SCALE(seqPlayerIndex, gActiveSeqs[seqPlayerIndex].volCur); + } -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/func_801A8ABC.s") + gActiveSeqs[seqPlayerIndex].tempoTimer = 0; + gActiveSeqs[seqPlayerIndex].tempoOriginal = 0; + gActiveSeqs[seqPlayerIndex].tempoCmd = 0; -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/func_801A8B14.s") + for (channelIndex = 0; channelIndex < SEQ_NUM_CHANNELS; channelIndex++) { + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volCur = 1.0f; + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volTimer = 0; + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleCur = 1.0f; + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleTimer = 0; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/func_801A8B2C.s") + gActiveSeqs[seqPlayerIndex].freqScaleChannelFlags = 0; + gActiveSeqs[seqPlayerIndex].volChannelFlags = 0; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/Audio_SetVolumeScale.s") +void AudioSeq_StopSequence(u8 seqPlayerIndex, u16 fadeOutDuration) { + AUDIOCMD_GLOBAL_DISABLE_SEQPLAYER(seqPlayerIndex, + (fadeOutDuration * (u16)gAudioCtx.audioBufferParameters.updatesPerFrame) / 4); + gActiveSeqs[seqPlayerIndex].seqId = NA_BGM_DISABLED; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/func_801A8D5C.s") +void AudioSeq_ProcessSeqCmd(u32 cmd) { + s32 priority; + s32 channelMaskEnable; + u16 channelMaskDisable; + u16 fadeTimer; + u16 val; + u8 oldSpecId; + u8 specId; + u8 fadeReverb; + u8 op; + u8 subOp; + u8 seqPlayerIndex; + u8 seqId; + u8 seqArgs; + u8 found; + u8 ioPort; + u8 duration; + u8 channelIndex; + u8 i; + f32 freqScaleTarget; + u32 outNumFonts; -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/func_801A9768.s") + op = cmd >> 28; + seqPlayerIndex = (cmd & SEQCMD_SEQPLAYER_MASK) >> 24; -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/func_801A982C.s") + switch (op) { + case SEQCMD_OP_PLAY_SEQUENCE: + // Play a new sequence + seqId = cmd & SEQCMD_SEQID_MASK; + seqArgs = (cmd & 0xFF00) >> 8; + // `fadeTimer` is only shifted 13 bits instead of 16 bits. + // `fadeTimer` continues to be scaled in `AudioSeq_StartSequence` + fadeTimer = (cmd & 0xFF0000) >> 13; + if (!gActiveSeqs[seqPlayerIndex].isWaitingForFonts && !sStartSeqDisabled) { + if (seqArgs < 0x80) { + AudioSeq_StartSequence(seqPlayerIndex, seqId, seqArgs, fadeTimer); + } else { + // Store the cmd to be called again once the fonts are loaded + // but changes the command so that next time, the (seqArgs < 0x80) case is taken + gActiveSeqs[seqPlayerIndex].startAsyncSeqCmd = + (cmd & ~(SEQ_FLAG_ASYNC | SEQCMD_ASYNC_ACTIVE)) + SEQCMD_ASYNC_ACTIVE; + gActiveSeqs[seqPlayerIndex].isWaitingForFonts = true; + gActiveSeqs[seqPlayerIndex].fontId = *AudioThread_GetFontsForSequence(seqId, &outNumFonts); + AudioSeq_StopSequence(seqPlayerIndex, 1); -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/func_801A99B8.s") + if (gActiveSeqs[seqPlayerIndex].prevSeqId != NA_BGM_DISABLED) { + if (*AudioThread_GetFontsForSequence(seqId, &outNumFonts) != + *AudioThread_GetFontsForSequence(gActiveSeqs[seqPlayerIndex].prevSeqId & 0xFF, + &outNumFonts)) { + // Discard Seq Fonts + AUDIOCMD_GLOBAL_DISCARD_SEQ_FONTS((s32)seqId); + } + } -#pragma GLOBAL_ASM("asm/non_matchings/code/sequence/func_801A9A74.s") + AUDIOCMD_GLOBAL_ASYNC_LOAD_FONT(*AudioThread_GetFontsForSequence(seqId, &outNumFonts), + (u8)((seqPlayerIndex + 1) & 0xFF)); + } + } + break; + + case SEQCMD_OP_STOP_SEQUENCE: + // Stop a sequence and disable the sequence player + fadeTimer = (cmd & 0xFF0000) >> 13; + AudioSeq_StopSequence(seqPlayerIndex, fadeTimer); + break; + + case SEQCMD_OP_QUEUE_SEQUENCE: + // Queue a sequence into `sSeqRequests` + seqId = cmd & SEQCMD_SEQID_MASK; + seqArgs = (cmd & 0xFF00) >> 8; + fadeTimer = (cmd & 0xFF0000) >> 13; + priority = seqArgs; + + // Checks if the requested sequence is first in the list of requests + // If it is already queued and first in the list, then play the sequence immediately + for (i = 0; i < sNumSeqRequests[seqPlayerIndex]; i++) { + if (sSeqRequests[seqPlayerIndex][i].seqId == seqId) { + if (i == 0) { + AudioSeq_StartSequence(seqPlayerIndex, seqId, seqArgs, fadeTimer); + } + return; + } + } + + // Searches the sequence requests for the first request that does not have a higher priority + // than the current incoming request + found = sNumSeqRequests[seqPlayerIndex]; + for (i = 0; i < sNumSeqRequests[seqPlayerIndex]; i++) { + if (priority >= sSeqRequests[seqPlayerIndex][i].priority) { + found = i; + i = sNumSeqRequests[seqPlayerIndex]; // "break;" + } + } + + // Check if the queue is full + if (sNumSeqRequests[seqPlayerIndex] < ARRAY_COUNT(sSeqRequests[seqPlayerIndex])) { + sNumSeqRequests[seqPlayerIndex]++; + } + + for (i = sNumSeqRequests[seqPlayerIndex] - 1; i != found; i--) { + // Move all requests of lower priority backwards 1 place in the queue + // If the queue is full, overwrite the entry with the lowest priority + sSeqRequests[seqPlayerIndex][i].priority = sSeqRequests[seqPlayerIndex][i - 1].priority; + sSeqRequests[seqPlayerIndex][i].seqId = sSeqRequests[seqPlayerIndex][i - 1].seqId; + } + + // Fill the newly freed space in the queue with the new request + sSeqRequests[seqPlayerIndex][found].priority = seqArgs; + sSeqRequests[seqPlayerIndex][found].seqId = seqId; + + // The sequence is first in queue, so start playing. + if (found == 0) { + AudioSeq_StartSequence(seqPlayerIndex, seqId, seqArgs, fadeTimer); + } + break; + + case SEQCMD_OP_UNQUEUE_SEQUENCE: + // Unqueue sequence + fadeTimer = (cmd & 0xFF0000) >> 13; + + found = sNumSeqRequests[seqPlayerIndex]; + for (i = 0; i < sNumSeqRequests[seqPlayerIndex]; i++) { + seqId = cmd & SEQCMD_SEQID_MASK; + if (sSeqRequests[seqPlayerIndex][i].seqId == seqId) { + found = i; + i = sNumSeqRequests[seqPlayerIndex]; // "break;" + } + } + + if (found != sNumSeqRequests[seqPlayerIndex]) { + // Move all requests of lower priority forward 1 place in the queue + for (i = found; i < sNumSeqRequests[seqPlayerIndex] - 1; i++) { + sSeqRequests[seqPlayerIndex][i].priority = sSeqRequests[seqPlayerIndex][i + 1].priority; + sSeqRequests[seqPlayerIndex][i].seqId = sSeqRequests[seqPlayerIndex][i + 1].seqId; + } + sNumSeqRequests[seqPlayerIndex]--; + } + + // If the sequence was first in queue (it is currently playing), + // Then stop the sequence and play the next sequence in the queue. + if (found == 0) { + AudioSeq_StopSequence(seqPlayerIndex, fadeTimer); + if (sNumSeqRequests[seqPlayerIndex] != 0) { + AudioSeq_StartSequence(seqPlayerIndex, sSeqRequests[seqPlayerIndex][0].seqId, + sSeqRequests[seqPlayerIndex][0].priority, fadeTimer); + } + } + break; + + case SEQCMD_OP_SET_SEQPLAYER_VOLUME: + // Transition volume to a target volume for an entire player + duration = (cmd & 0xFF0000) >> 15; + val = cmd & 0xFF; + if (duration == 0) { + duration++; + } + // Volume is scaled relative to 127 + gActiveSeqs[seqPlayerIndex].volTarget = (f32)val / 127.0f; + if (gActiveSeqs[seqPlayerIndex].volCur != gActiveSeqs[seqPlayerIndex].volTarget) { + gActiveSeqs[seqPlayerIndex].volStep = + (gActiveSeqs[seqPlayerIndex].volCur - gActiveSeqs[seqPlayerIndex].volTarget) / (f32)duration; + gActiveSeqs[seqPlayerIndex].volTimer = duration; + } + break; + + case SEQCMD_OP_SET_SEQPLAYER_FREQ: + // Transition freq scale to a target freq for all channels + duration = (cmd & 0xFF0000) >> 15; + val = cmd & 0xFFFF; + if (duration == 0) { + duration++; + } + // Frequency is scaled relative to 1000 + freqScaleTarget = (f32)val / 1000.0f; + for (i = 0; i < SEQ_NUM_CHANNELS; i++) { + gActiveSeqs[seqPlayerIndex].channelData[i].freqScaleTarget = freqScaleTarget; + gActiveSeqs[seqPlayerIndex].channelData[i].freqScaleTimer = duration; + gActiveSeqs[seqPlayerIndex].channelData[i].freqScaleStep = + (gActiveSeqs[seqPlayerIndex].channelData[i].freqScaleCur - freqScaleTarget) / (f32)duration; + } + gActiveSeqs[seqPlayerIndex].freqScaleChannelFlags = 0xFFFF; + break; + + case SEQCMD_OP_SET_CHANNEL_FREQ: + // Transition freq scale to a target for a specific channel + duration = (cmd & 0xFF0000) >> 15; + channelIndex = (cmd & 0xF000) >> 12; + val = cmd & 0xFFF; + if (duration == 0) { + duration++; + } + // Frequency is scaled relative to 1000 + freqScaleTarget = (f32)val / 1000.0f; + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleTarget = freqScaleTarget; + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleStep = + (gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleCur - freqScaleTarget) / (f32)duration; + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleTimer = duration; + gActiveSeqs[seqPlayerIndex].freqScaleChannelFlags |= 1 << channelIndex; + break; + + case SEQCMD_OP_SET_CHANNEL_VOLUME: + // Transition volume to a target volume for a specific channel + duration = (cmd & 0xFF0000) >> 15; + channelIndex = (cmd & 0xF00) >> 8; + val = cmd & 0xFF; + if (duration == 0) { + duration++; + } + // Volume is scaled relative to 127 + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volTarget = (f32)val / 127.0f; + if (gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volCur != + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volTarget) { + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volStep = + (gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volCur - + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volTarget) / + (f32)duration; + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volTimer = duration; + gActiveSeqs[seqPlayerIndex].volChannelFlags |= 1 << channelIndex; + } + break; + + case SEQCMD_OP_SET_SEQPLAYER_IO: + // Set global io port + ioPort = (cmd & 0xFF0000) >> 16; + val = cmd & 0xFF; + AUDIOCMD_SEQPLAYER_SET_IO(seqPlayerIndex, ioPort, val); + break; + + case SEQCMD_OP_SET_CHANNEL_IO: + // Set io port if channel masked + channelIndex = (cmd & 0xF00) >> 8; + ioPort = (cmd & 0xFF0000) >> 16; + val = cmd & 0xFF; + if (!(gActiveSeqs[seqPlayerIndex].channelPortMask & (1 << channelIndex))) { + AUDIOCMD_CHANNEL_SET_IO(seqPlayerIndex, channelIndex, ioPort, val); + } + break; + + case SEQCMD_OP_SET_CHANNEL_IO_DISABLE_MASK: + // Disable channel io specifically for `SEQCMD_OP_SET_CHANNEL_IO`. + // This can be bypassed by setting channel io through using `AUDIOCMD_CHANNEL_SET_IO` directly. + // This is accomplished by setting a channel mask. + gActiveSeqs[seqPlayerIndex].channelPortMask = cmd & 0xFFFF; + break; + + case SEQCMD_OP_SET_CHANNEL_DISABLE_MASK: + // Disable or Reenable channels + + // Disable channels + channelMaskDisable = cmd & 0xFFFF; + if (channelMaskDisable != 0) { + // Apply channel mask `channelMaskDisable` + AUDIOCMD_GLOBAL_SET_CHANNEL_MASK(seqPlayerIndex, channelMaskDisable); + // Disable channels + AUDIOCMD_CHANNEL_SET_MUTE(seqPlayerIndex, AUDIOCMD_ALL_CHANNELS, true); + } + + // Reenable channels + channelMaskEnable = channelMaskDisable ^ 0xFFFF; + if (channelMaskEnable != 0) { + // Apply channel mask `channelMaskEnable` + AUDIOCMD_GLOBAL_SET_CHANNEL_MASK(seqPlayerIndex, channelMaskEnable); + // Enable channels + AUDIOCMD_CHANNEL_SET_MUTE(seqPlayerIndex, AUDIOCMD_ALL_CHANNELS, false); + } + break; + + case SEQCMD_OP_TEMPO_CMD: + // Update a tempo using a sub-command system. + // Stores the cmd for processing elsewhere. + gActiveSeqs[seqPlayerIndex].tempoCmd = cmd; + break; + + case SEQCMD_OP_SETUP_CMD: + // Queue a sub-command to execute once the sequence is finished playing + subOp = (cmd & 0xF00000) >> 20; + if (subOp != SEQCMD_SUB_OP_SETUP_RESET_SETUP_CMDS) { + // Ensure the maximum number of setup commands is not exceeded + if (gActiveSeqs[seqPlayerIndex].setupCmdNum < (ARRAY_COUNT(gActiveSeqs[seqPlayerIndex].setupCmd) - 1)) { + found = gActiveSeqs[seqPlayerIndex].setupCmdNum++; + if (found < ARRAY_COUNT(gActiveSeqs[seqPlayerIndex].setupCmd)) { + gActiveSeqs[seqPlayerIndex].setupCmd[found] = cmd; + // Adds a delay of 2 frames before executing any setup commands. + // This allows setup commands to be requested along with a new sequence on a seqPlayerIndex. + // This 2 frame delay ensures the player is enabled before its state is checked for + // the purpose of deciding if the setup commands should be run. + // Otherwise, the setup commands will be executed before the sequence starts, + // when the player is still disabled, instead of when the newly played sequence ends. + gActiveSeqs[seqPlayerIndex].setupCmdTimer = 2; + } + } + } else { + // `SEQCMD_SUB_OP_SETUP_RESET_SETUP_CMDS` + // Discard all setup command requests on `seqPlayerIndex` + gActiveSeqs[seqPlayerIndex].setupCmdNum = 0; + } + break; + + case SEQCMD_OP_GLOBAL_CMD: + // Apply a command that applies to all sequence players + subOp = (cmd & 0xF00) >> 8; + val = cmd & 0xFF; + switch (subOp) { + case SEQCMD_SUB_OP_GLOBAL_SET_SOUND_MODE: + // Set sound mode + AUDIOCMD_GLOBAL_SET_SOUND_MODE(sSoundModeList[val]); + break; + + case SEQCMD_SUB_OP_GLOBAL_DISABLE_NEW_SEQUENCES: + // Set sequence disabled in (sStartSeqDisabled & 1) bit + sStartSeqDisabled = (sStartSeqDisabled & (u8)~1) | (u8)(val & 1); + break; + + case SEQCMD_SUB_OP_GLOBAL_DISABLE_NEW_SEQUENCES_2: + // Set sequence disabled in (sStartSeqDisabled & 2) bit + sStartSeqDisabled = (sStartSeqDisabled & (u8)~2) | (u8)((val & 1) << 1); + break; + } + break; + + case SEQCMD_OP_RESET_AUDIO_HEAP: + // Resets the audio heap based on the audio specifications, audio mode, and sfx channel layout + specId = cmd & 0xFF; + fadeReverb = (cmd & 0xFF0000) >> 16; + if (fadeReverb == 0) { + gSfxChannelLayout = (cmd & 0xFF00) >> 8; + oldSpecId = gAudioSpecId; + gAudioSpecId = specId; + AudioThread_ResetAudioHeap(specId); + Audio_ResetForAudioHeapStep1(oldSpecId); + AUDIOCMD_GLOBAL_STOP_AUDIOCMDS(); + } else { + sResetAudioHeapSeqCmd = cmd; + sResetAudioHeapFadeReverbVolume = 0x7FFF; + sResetAudioHeapTimer = 20; + sResetAudioHeapFadeReverbVolumeStep = 0x666; + } + break; + } +} + +/** + * Add the sequence cmd to the `sAudioSeqCmds` queue + */ +void AudioSeq_QueueSeqCmd(u32 cmd) { + sAudioSeqCmds[sSeqCmdWritePos++] = cmd; +} + +void AudioSeq_ProcessSeqCmds(void) { + while (sSeqCmdWritePos != sSeqCmdReadPos) { + AudioSeq_ProcessSeqCmd(sAudioSeqCmds[sSeqCmdReadPos++]); + } +} + +u16 AudioSeq_GetActiveSeqId(u8 seqPlayerIndex) { + if (gActiveSeqs[seqPlayerIndex].isWaitingForFonts == true) { + return gActiveSeqs[seqPlayerIndex].startAsyncSeqCmd & SEQCMD_SEQID_MASK; + } + + if (gActiveSeqs[seqPlayerIndex].seqId != NA_BGM_DISABLED) { + return gActiveSeqs[seqPlayerIndex].seqId; + } + + return NA_BGM_DISABLED; +} + +s32 AudioSeq_IsSeqCmdNotQueued(u32 cmdVal, u32 cmdMask) { + u8 i; + + for (i = sSeqCmdReadPos; i != sSeqCmdWritePos; i++) { + if ((sAudioSeqCmds[i] & cmdMask) == cmdVal) { + return false; + } + } + + return true; +} + +// Unused +void AudioSeq_ResetSequenceRequests(u8 seqPlayerIndex) { + sNumSeqRequests[seqPlayerIndex] = 0; +} + +/** + * Check if the setup command is queued. If it is, then replace the command + * with `SEQCMD_SUB_OP_SETUP_RESTORE_SEQPLAYER_VOLUME`. + * Unused + */ +void AudioSeq_ReplaceSeqCmdSetupOpVolRestore(u8 seqPlayerIndex, u8 setupOpDisabled) { + u8 i; + + for (i = 0; i < gActiveSeqs[seqPlayerIndex].setupCmdNum; i++) { + u8 setupOp = (gActiveSeqs[seqPlayerIndex].setupCmd[i] & 0xF00000) >> 20; + + if (setupOp == setupOpDisabled) { + gActiveSeqs[seqPlayerIndex].setupCmd[i] = 0xFF000000; + } + } +} + +void AudioSeq_SetVolumeScale(u8 seqPlayerIndex, u8 scaleIndex, u8 targetVol, u8 volFadeTimer) { + f32 volScale; + u8 i; + + gActiveSeqs[seqPlayerIndex].volScales[scaleIndex] = targetVol & 0x7F; + + if (volFadeTimer != 0) { + gActiveSeqs[seqPlayerIndex].fadeVolUpdate = true; + gActiveSeqs[seqPlayerIndex].volFadeTimer = volFadeTimer; + } else { + for (i = 0, volScale = 1.0f; i < VOL_SCALE_INDEX_MAX; i++) { + volScale *= gActiveSeqs[seqPlayerIndex].volScales[i] / 127.0f; + } + + SEQCMD_SET_SEQPLAYER_VOLUME_NOW(seqPlayerIndex, volFadeTimer, volScale); + } +} + +/** + * Update different commands and requests for active sequences + */ +void AudioSeq_UpdateActiveSequences(void) { + u32 tempoCmd; + u16 tempoPrev; + u16 seqId; + u16 channelMask; + u16 tempoTarget; + u8 setupOp; + u8 targetSeqPlayerIndex; + u8 setupVal2; + u8 setupVal1; + u8 tempoOp; + s32 pad[2]; + u32 retMsg; + f32 volume; + u8 tempoTimer; + u8 seqPlayerIndex; + u8 j; + u8 channelIndex; + + for (seqPlayerIndex = 0; seqPlayerIndex < SEQ_PLAYER_MAX; seqPlayerIndex++) { + + // The seqPlayer has finished initializing and is currently playing the active sequences + if (gActiveSeqs[seqPlayerIndex].isSeqPlayerInit && gAudioCtx.seqPlayers[seqPlayerIndex].enabled) { + gActiveSeqs[seqPlayerIndex].isSeqPlayerInit = false; + } + + // The seqPlayer is no longer playing the active sequences + if ((AudioSeq_GetActiveSeqId(seqPlayerIndex) != NA_BGM_DISABLED) && + !gAudioCtx.seqPlayers[seqPlayerIndex].enabled && (!gActiveSeqs[seqPlayerIndex].isSeqPlayerInit)) { + gActiveSeqs[seqPlayerIndex].seqId = NA_BGM_DISABLED; + } + + // Check if the requested sequences is waiting for fonts to load + if (gActiveSeqs[seqPlayerIndex].isWaitingForFonts) { + switch ((s32)AudioThread_GetExternalLoadQueueMsg(&retMsg)) { + case SEQ_PLAYER_BGM_MAIN + 1: + case SEQ_PLAYER_FANFARE + 1: + case SEQ_PLAYER_SFX + 1: + case SEQ_PLAYER_BGM_SUB + 1: + case SEQ_PLAYER_AMBIENCE + 1: + // The fonts have been loaded successfully. + gActiveSeqs[seqPlayerIndex].isWaitingForFonts = false; + // Queue the same command that was stored previously, but without the 0x8000 + AudioSeq_ProcessSeqCmd(gActiveSeqs[seqPlayerIndex].startAsyncSeqCmd); + break; + case 0xFF: + // There was an error in loading the fonts + gActiveSeqs[seqPlayerIndex].isWaitingForFonts = false; + break; + } + } + + // Update global volume + if (gActiveSeqs[seqPlayerIndex].fadeVolUpdate) { + volume = 1.0f; + for (j = 0; j < VOL_SCALE_INDEX_MAX; j++) { + volume *= (gActiveSeqs[seqPlayerIndex].volScales[j] / 127.0f); + } + + SEQCMD_SET_SEQPLAYER_VOLUME((u8)(seqPlayerIndex + (SEQCMD_ASYNC_ACTIVE >> 24)), + gActiveSeqs[seqPlayerIndex].volFadeTimer, (u8)(volume * 127.0f)); + gActiveSeqs[seqPlayerIndex].fadeVolUpdate = false; + } + + if (gActiveSeqs[seqPlayerIndex].volTimer != 0) { + gActiveSeqs[seqPlayerIndex].volTimer--; + + if (gActiveSeqs[seqPlayerIndex].volTimer != 0) { + gActiveSeqs[seqPlayerIndex].volCur -= gActiveSeqs[seqPlayerIndex].volStep; + } else { + gActiveSeqs[seqPlayerIndex].volCur = gActiveSeqs[seqPlayerIndex].volTarget; + } + + AUDIOCMD_SEQPLAYER_FADE_VOLUME_SCALE(seqPlayerIndex, gActiveSeqs[seqPlayerIndex].volCur); + } + + // Process tempo + if (gActiveSeqs[seqPlayerIndex].tempoCmd != 0) { + tempoCmd = gActiveSeqs[seqPlayerIndex].tempoCmd; + tempoTimer = (tempoCmd & 0xFF0000) >> 15; + tempoTarget = tempoCmd & 0xFFF; + if (tempoTimer == 0) { + tempoTimer++; + } + + // Process tempo commands + if (gAudioCtx.seqPlayers[seqPlayerIndex].enabled) { + tempoPrev = gAudioCtx.seqPlayers[seqPlayerIndex].tempo / TATUMS_PER_BEAT; + tempoOp = (tempoCmd & 0xF000) >> 12; + switch (tempoOp) { + case SEQCMD_SUB_OP_TEMPO_SPEED_UP: + // Speed up tempo by `tempoTarget` amount + tempoTarget += tempoPrev; + break; + + case SEQCMD_SUB_OP_TEMPO_SLOW_DOWN: + // Slow down tempo by `tempoTarget` amount + if (tempoTarget < tempoPrev) { + tempoTarget = tempoPrev - tempoTarget; + } + break; + + case SEQCMD_SUB_OP_TEMPO_SCALE: + // Scale tempo by a multiplicative factor + tempoTarget = tempoPrev * (tempoTarget / 100.0f); + break; + + case SEQCMD_SUB_OP_TEMPO_RESET: + // Reset tempo to original tempo + tempoTarget = (gActiveSeqs[seqPlayerIndex].tempoOriginal != 0) + ? gActiveSeqs[seqPlayerIndex].tempoOriginal + : tempoPrev; + break; + + default: // `SEQCMD_SUB_OP_TEMPO_SET` + // `tempoTarget` is the new tempo + break; + } + + if (gActiveSeqs[seqPlayerIndex].tempoOriginal == 0) { + gActiveSeqs[seqPlayerIndex].tempoOriginal = tempoPrev; + } + + gActiveSeqs[seqPlayerIndex].tempoTarget = tempoTarget; + gActiveSeqs[seqPlayerIndex].tempoCur = gAudioCtx.seqPlayers[seqPlayerIndex].tempo / 0x30; + gActiveSeqs[seqPlayerIndex].tempoStep = + (gActiveSeqs[seqPlayerIndex].tempoCur - gActiveSeqs[seqPlayerIndex].tempoTarget) / tempoTimer; + gActiveSeqs[seqPlayerIndex].tempoTimer = tempoTimer; + gActiveSeqs[seqPlayerIndex].tempoCmd = 0; + } + } + + // Step tempo to target + if (gActiveSeqs[seqPlayerIndex].tempoTimer != 0) { + gActiveSeqs[seqPlayerIndex].tempoTimer--; + if (gActiveSeqs[seqPlayerIndex].tempoTimer != 0) { + gActiveSeqs[seqPlayerIndex].tempoCur -= gActiveSeqs[seqPlayerIndex].tempoStep; + } else { + gActiveSeqs[seqPlayerIndex].tempoCur = gActiveSeqs[seqPlayerIndex].tempoTarget; + } + + AUDIOCMD_SEQPLAYER_SET_TEMPO(seqPlayerIndex, gActiveSeqs[seqPlayerIndex].tempoCur); + } + + // Update channel volumes + if (gActiveSeqs[seqPlayerIndex].volChannelFlags != 0) { + for (channelIndex = 0; channelIndex < SEQ_NUM_CHANNELS; channelIndex++) { + if (gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volTimer != 0) { + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volTimer--; + if (gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volTimer != 0) { + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volCur -= + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volStep; + } else { + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volCur = + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volTarget; + gActiveSeqs[seqPlayerIndex].volChannelFlags ^= (1 << channelIndex); + } + + AUDIOCMD_CHANNEL_SET_VOL_SCALE(seqPlayerIndex, channelIndex, + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volCur); + } + } + } + + // Update frequencies + if (gActiveSeqs[seqPlayerIndex].freqScaleChannelFlags != 0) { + for (channelIndex = 0; channelIndex < SEQ_NUM_CHANNELS; channelIndex++) { + if (gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleTimer != 0) { + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleTimer--; + if (gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleTimer != 0) { + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleCur -= + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleStep; + } else { + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleCur = + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleTarget; + gActiveSeqs[seqPlayerIndex].freqScaleChannelFlags ^= (1 << channelIndex); + } + + AUDIOCMD_CHANNEL_SET_FREQ_SCALE(seqPlayerIndex, channelIndex, + gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleCur); + } + } + } + + // Process setup commands + if (gActiveSeqs[seqPlayerIndex].setupCmdNum != 0) { + // If there is a SeqCmd to reset the audio heap queued, then drop all setup commands + if (!AudioSeq_IsSeqCmdNotQueued(SEQCMD_OP_RESET_AUDIO_HEAP << 28, SEQCMD_OP_MASK)) { + gActiveSeqs[seqPlayerIndex].setupCmdNum = 0; + break; + } + + // Only process setup commands once the timer reaches zero + if (gActiveSeqs[seqPlayerIndex].setupCmdTimer != 0) { + gActiveSeqs[seqPlayerIndex].setupCmdTimer--; + continue; + } + + // Only process setup commands if `seqPlayerIndex` if no longer playing + // i.e. the `seqPlayer` is no longer enabled + if (gAudioCtx.seqPlayers[seqPlayerIndex].enabled) { + continue; + } + + for (j = 0; j < gActiveSeqs[seqPlayerIndex].setupCmdNum; j++) { + setupOp = (gActiveSeqs[seqPlayerIndex].setupCmd[j] & 0xF00000) >> 20; + targetSeqPlayerIndex = (gActiveSeqs[seqPlayerIndex].setupCmd[j] & 0xF0000) >> 16; + setupVal2 = (gActiveSeqs[seqPlayerIndex].setupCmd[j] & 0xFF00) >> 8; + setupVal1 = gActiveSeqs[seqPlayerIndex].setupCmd[j] & 0xFF; + + switch (setupOp) { + case SEQCMD_SUB_OP_SETUP_RESTORE_SEQPLAYER_VOLUME: + // Restore `targetSeqPlayerIndex` volume back to normal levels + AudioSeq_SetVolumeScale(targetSeqPlayerIndex, VOL_SCALE_INDEX_FANFARE, 0x7F, setupVal1); + break; + + case SEQCMD_SUB_OP_SETUP_RESTORE_SEQPLAYER_VOLUME_IF_QUEUED: + // Restore `targetSeqPlayerIndex` volume back to normal levels, + // but only if the number of sequence queue requests from `sSeqRequests` + // exactly matches the argument to the command + if (setupVal1 == sNumSeqRequests[seqPlayerIndex]) { + AudioSeq_SetVolumeScale(targetSeqPlayerIndex, VOL_SCALE_INDEX_FANFARE, 0x7F, setupVal2); + } + break; + + case SEQCMD_SUB_OP_SETUP_SEQ_UNQUEUE: + // Unqueue `seqPlayerIndex` from sSeqRequests + //! @bug this command does not work as intended as unqueueing + //! the sequence relies on `gActiveSeqs[seqPlayerIndex].seqId` + //! However, `gActiveSeqs[seqPlayerIndex].seqId` is reset before the sequence on + //! `seqPlayerIndex` is requested to stop, i.e. before the sequence is disabled and setup + //! commands (including this command) can run. A simple fix would have been to unqueue based on + //! `gActiveSeqs[seqPlayerIndex].prevSeqId` instead + SEQCMD_UNQUEUE_SEQUENCE((u8)(seqPlayerIndex + (SEQCMD_ASYNC_ACTIVE >> 24)), 0, + gActiveSeqs[seqPlayerIndex].seqId); + break; + + case SEQCMD_SUB_OP_SETUP_RESTART_SEQ: + // Restart the currently active sequence on `targetSeqPlayerIndex` with full volume. + // Sequence on `targetSeqPlayerIndex` must still be active to play (can be muted) + SEQCMD_PLAY_SEQUENCE((u8)(targetSeqPlayerIndex + (SEQCMD_ASYNC_ACTIVE >> 24)), 1, + gActiveSeqs[targetSeqPlayerIndex].seqId); + gActiveSeqs[targetSeqPlayerIndex].fadeVolUpdate = true; + gActiveSeqs[targetSeqPlayerIndex].volScales[1] = 0x7F; + break; + + case SEQCMD_SUB_OP_SETUP_TEMPO_SCALE: + // Scale tempo by a multiplicative factor + SEQCMD_SCALE_TEMPO((u8)(targetSeqPlayerIndex + (SEQCMD_ASYNC_ACTIVE >> 24)), setupVal2, + setupVal1); + break; + + case SEQCMD_SUB_OP_SETUP_TEMPO_RESET: + // Reset tempo to previous tempo + SEQCMD_RESET_TEMPO((u8)(targetSeqPlayerIndex + (SEQCMD_ASYNC_ACTIVE >> 24)), setupVal1); + break; + + case SEQCMD_SUB_OP_SETUP_PLAY_SEQ: + // Play the requested sequence + // Uses the fade timer set by `SEQCMD_SUB_OP_SETUP_SET_FADE_TIMER` + seqId = gActiveSeqs[seqPlayerIndex].setupCmd[j] & 0xFFFF; + SEQCMD_PLAY_SEQUENCE((u8)(targetSeqPlayerIndex + (SEQCMD_ASYNC_ACTIVE >> 24)), + gActiveSeqs[targetSeqPlayerIndex].setupFadeTimer, seqId); + AudioSeq_SetVolumeScale(targetSeqPlayerIndex, VOL_SCALE_INDEX_FANFARE, 0x7F, 0); + gActiveSeqs[targetSeqPlayerIndex].setupFadeTimer = 0; + break; + + case SEQCMD_SUB_OP_SETUP_SET_FADE_TIMER: + // A command specifically to support `SEQCMD_SUB_OP_SETUP_PLAY_SEQ` + // Sets the fade timer for the sequence requested in `SEQCMD_SUB_OP_SETUP_PLAY_SEQ` + gActiveSeqs[seqPlayerIndex].setupFadeTimer = setupVal2; + break; + + case SEQCMD_SUB_OP_SETUP_RESTORE_SEQPLAYER_VOLUME_WITH_SCALE_INDEX: + // Restore the volume back to default levels + // Allows a `scaleIndex` to be specified. + AudioSeq_SetVolumeScale(targetSeqPlayerIndex, setupVal2, 0x7F, setupVal1); + break; + + case SEQCMD_SUB_OP_SETUP_POP_PERSISTENT_CACHE: + // Discard audio data by popping one more audio caches from the audio heap + if (setupVal1 & (1 << SEQUENCE_TABLE)) { + AUDIOCMD_GLOBAL_POP_PERSISTENT_CACHE(SEQUENCE_TABLE); + } + if (setupVal1 & (1 << FONT_TABLE)) { + AUDIOCMD_GLOBAL_POP_PERSISTENT_CACHE(FONT_TABLE); + } + if (setupVal1 & (1 << SAMPLE_TABLE)) { + AUDIOCMD_GLOBAL_POP_PERSISTENT_CACHE(SAMPLE_TABLE); + } + break; + + case SEQCMD_SUB_OP_SETUP_SET_CHANNEL_DISABLE_MASK: + // Disable (or reenable) specific channels of `targetSeqPlayerIndex` + channelMask = gActiveSeqs[seqPlayerIndex].setupCmd[j] & 0xFFFF; + SEQCMD_SET_CHANNEL_DISABLE_MASK((u8)(targetSeqPlayerIndex + (SEQCMD_ASYNC_ACTIVE >> 24)), + channelMask); + break; + + case SEQCMD_SUB_OP_SETUP_SET_SEQPLAYER_FREQ: + // Scale all channels of `targetSeqPlayerIndex` + SEQCMD_SET_SEQPLAYER_FREQ((u8)(targetSeqPlayerIndex + (SEQCMD_ASYNC_ACTIVE >> 24)), setupVal2, + setupVal1 * 10); + break; + + default: + break; + } + } + + gActiveSeqs[seqPlayerIndex].setupCmdNum = 0; + } + } +} + +u8 AudioSeq_UpdateAudioHeapReset(void) { + if (gAudioHeapResetState != AUDIO_HEAP_RESET_STATE_NONE) { + if (gAudioHeapResetState == AUDIO_HEAP_RESET_STATE_RESETTING) { + if (func_80193C5C() == 1) { + gAudioHeapResetState = AUDIO_HEAP_RESET_STATE_NONE; + AUDIOCMD_SEQPLAYER_SET_IO(SEQ_PLAYER_SFX, 0, gSfxChannelLayout); + Audio_ResetForAudioHeapStep2(); + } + } else if (gAudioHeapResetState == AUDIO_HEAP_RESET_STATE_RESETTING_ALT) { + while (func_80193C5C() != 1) {} + gAudioHeapResetState = AUDIO_HEAP_RESET_STATE_NONE; + AUDIOCMD_SEQPLAYER_SET_IO(SEQ_PLAYER_SFX, 0, gSfxChannelLayout); + Audio_ResetForAudioHeapStep2(); + } + } + + return gAudioHeapResetState; +} + +u8 AudioSeq_ResetReverb(void) { + u8 isReverbFading = false; + u8 fadeReverb = ((sResetAudioHeapSeqCmd & 0xFF0000) >> 16); + u8 reverbIndex = 0; + u8 specId; + + if (sResetAudioHeapSeqCmd != 0) { + if (sResetAudioHeapTimer--) { + while (fadeReverb != 0) { + if (fadeReverb & 1) { + AUDIOCMD_GLOBAL_SET_REVERB_DATA(reverbIndex, REVERB_DATA_TYPE_VOLUME, + sResetAudioHeapFadeReverbVolume); + AudioThread_ScheduleProcessCmds(); + } + reverbIndex++; + fadeReverb = fadeReverb >> 1; + } + + sResetAudioHeapFadeReverbVolume -= sResetAudioHeapFadeReverbVolumeStep; + isReverbFading = true; + } else { + while (fadeReverb != 0) { + if (fadeReverb & 1) { + AUDIOCMD_GLOBAL_SET_REVERB_DATA( + reverbIndex, REVERB_DATA_TYPE_SETTINGS, + (s32)(gReverbSettingsTable[(u8)(sResetAudioHeapSeqCmd & 0xFF)] + reverbIndex)); + AudioThread_ScheduleProcessCmds(); + } + reverbIndex++; + fadeReverb = fadeReverb >> 1; + } + + sResetAudioHeapSeqCmd = 0; + AUDIOCMD_SEQPLAYER_SET_IO(SEQ_PLAYER_SFX, 0, gSfxChannelLayout); + Audio_ResetForAudioHeapStep3(); + } + } + + return isReverbFading; +} + +void AudioSeq_ResetActiveSequences(void) { + u8 seqPlayerIndex; + u8 scaleIndex; + + for (seqPlayerIndex = 0; seqPlayerIndex < SEQ_PLAYER_MAX; seqPlayerIndex++) { + sNumSeqRequests[seqPlayerIndex] = 0; + + gActiveSeqs[seqPlayerIndex].seqId = NA_BGM_DISABLED; + gActiveSeqs[seqPlayerIndex].prevSeqId = NA_BGM_DISABLED; + gActiveSeqs[seqPlayerIndex].tempoTimer = 0; + gActiveSeqs[seqPlayerIndex].tempoOriginal = 0; + gActiveSeqs[seqPlayerIndex].tempoCmd = 0; + gActiveSeqs[seqPlayerIndex].channelPortMask = 0; + gActiveSeqs[seqPlayerIndex].setupCmdNum = 0; + gActiveSeqs[seqPlayerIndex].setupFadeTimer = 0; + gActiveSeqs[seqPlayerIndex].freqScaleChannelFlags = 0; + gActiveSeqs[seqPlayerIndex].volChannelFlags = 0; + gActiveSeqs[seqPlayerIndex].isWaitingForFonts = false; + gActiveSeqs[seqPlayerIndex].isSeqPlayerInit = false; + + for (scaleIndex = 0; scaleIndex < VOL_SCALE_INDEX_MAX; scaleIndex++) { + gActiveSeqs[seqPlayerIndex].volScales[scaleIndex] = 0x7F; + } + + gActiveSeqs[seqPlayerIndex].volFadeTimer = 1; + gActiveSeqs[seqPlayerIndex].fadeVolUpdate = true; + } +} + +void AudioSeq_ResetActiveSequencesAndVolume(void) { + u8 seqPlayerIndex; + u8 scaleIndex; + + for (seqPlayerIndex = 0; seqPlayerIndex < SEQ_PLAYER_MAX; seqPlayerIndex++) { + gActiveSeqs[seqPlayerIndex].volCur = 1.0f; + gActiveSeqs[seqPlayerIndex].volTimer = 0; + gActiveSeqs[seqPlayerIndex].fadeVolUpdate = false; + for (scaleIndex = 0; scaleIndex < VOL_SCALE_INDEX_MAX; scaleIndex++) { + gActiveSeqs[seqPlayerIndex].volScales[scaleIndex] = 0x7F; + } + } + AudioSeq_ResetActiveSequences(); +} diff --git a/src/audio/sfx.c b/src/audio/sfx.c index 76597f5f3..537a9f394 100644 --- a/src/audio/sfx.c +++ b/src/audio/sfx.c @@ -102,8 +102,8 @@ void AudioSfx_MuteBanks(u16 muteMask) { void AudioSfx_LowerBgmVolume(u8 channelIndex) { sSfxChannelLowVolumeFlag |= (1 << channelIndex); - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 2, 0x40, 0xF); - Audio_SetVolumeScale(SEQ_PLAYER_BGM_SUB, 2, 0x40, 0xF); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_SFX, 0x40, 0xF); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_SUB, VOL_SCALE_INDEX_SFX, 0x40, 0xF); } /** @@ -114,8 +114,8 @@ void AudioSfx_RestoreBgmVolume(u8 channelIndex) { sSfxChannelLowVolumeFlag &= ((1 << channelIndex) ^ 0xFFFF); if (sSfxChannelLowVolumeFlag == 0) { - Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 2, 0x7F, 0xF); - Audio_SetVolumeScale(SEQ_PLAYER_BGM_SUB, 2, 0x7F, 0xF); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, VOL_SCALE_INDEX_SFX, 0x7F, 0xF); + AudioSeq_SetVolumeScale(SEQ_PLAYER_BGM_SUB, VOL_SCALE_INDEX_SFX, 0x7F, 0xF); } } diff --git a/src/audio/voice_internal.c b/src/audio/voice_internal.c index e09fdd68c..055b66ed1 100644 --- a/src/audio/voice_internal.c +++ b/src/audio/voice_internal.c @@ -37,6 +37,6 @@ UNK_TYPE func_801A51F0(UNK_TYPE arg0) { #pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A5808.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A5A10.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/AudioVoice_ResetData.s") #pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A5A1C.s") |
