diff --git a/soh/include/z64audio.h b/soh/include/z64audio.h index 6fed61399d6..74781a6d439 100644 --- a/soh/include/z64audio.h +++ b/soh/include/z64audio.h @@ -26,6 +26,9 @@ extern "C" { //#define MAX_SEQUENCES 0x800 extern size_t sequenceMapSize; +// Streamed audio rather than a sequence script, per sequence and per sequence player. +extern u8* gSeqIsStreamed; +extern u8 gSeqPlayerIsStreamed[4]; extern size_t fontMapSize; extern char** fontMap; diff --git a/soh/src/code/audio_load.c b/soh/src/code/audio_load.c index 239e312f32a..e54a3c9aa67 100644 --- a/soh/src/code/audio_load.c +++ b/soh/src/code/audio_load.c @@ -85,6 +85,7 @@ void* sUnusedHandler = NULL; s32 gAudioContextInitalized = false; char** sequenceMap; +u8* gSeqIsStreamed; size_t sequenceMapSize; // A map of authentic sequence IDs to their cache policies, for use with sequence swapping. u8 seqCachePolicyMap[MAX_AUTHENTIC_SEQID]; @@ -1344,6 +1345,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) { sequenceMapSize = (size_t)(seqListSize + customSeqListSize); // calloc: unassigned slots stay NULL for the guard in AudioLoad_SyncInitSeqPlayerInternal(). sequenceMap = calloc(sequenceMapSize + 0xF, sizeof(char*)); + gSeqIsStreamed = calloc(sequenceMapSize + 0xF, sizeof(u8)); // SOH [Bugfix] Size to match sequenceMap (+ 0xF); custom ids can exceed sequenceMapSize. gAudioContext.seqLoadStatus = malloc(sequenceMapSize + 0xF); @@ -1405,6 +1407,8 @@ void AudioLoad_Init(void* heap, size_t heapSize) { // ensure that what would be the next sequence number is actually unassigned in AudioCollection int j = i - startingSeqNum; SequenceData* sDat = ResourceMgr_LoadSeqPtrByName(customSeqList[j]); + // Read before the branch below rewrites numFonts. + u8 isStreamed = (sDat->numFonts == -1); if (sDat->numFonts == -1) { uint64_t crc; @@ -1449,6 +1453,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) { sDat->seqNumber = seqNum; LUSLOG_DEBUG("Registered custom sequence \"%s\" as seqNum %d", customSeqList[j], seqNum); sequenceMap[sDat->seqNumber] = strdup(customSeqList[j]); + gSeqIsStreamed[sDat->seqNumber] = isStreamed; seqNum++; } diff --git a/soh/src/code/code_800EC960.c b/soh/src/code/code_800EC960.c index 3fea838e192..314d7c8bac7 100644 --- a/soh/src/code/code_800EC960.c +++ b/soh/src/code/code_800EC960.c @@ -4760,12 +4760,18 @@ void Audio_SplitBgmChannels(s8 volSplit) { } channelBits = 0; - for (channelIdx = 0; channelIdx < 16; channelIdx++) { - if (notePriority > gAudioContext.seqPlayers[bgmPlayers[i]].channels[channelIdx]->notePriority) { - // If the note currently playing in the channel is a high enough priority, - // then keep the channel on by setting a channelBit - // If this condition fails, then the channel will be shut off - channelBits += (1 << channelIdx); + + // Streamed music is one note for the whole song, so stopping a channel ends it + // for good. An empty player is about to be handed one: the enemy sequence is + // queued a step before this runs. + if (gAudioContext.seqPlayers[bgmPlayers[i]].enabled && !gSeqPlayerIsStreamed[bgmPlayers[i]]) { + for (channelIdx = 0; channelIdx < 16; channelIdx++) { + if (notePriority > gAudioContext.seqPlayers[bgmPlayers[i]].channels[channelIdx]->notePriority) { + // If the note currently playing in the channel is a high enough priority, + // then keep the channel on by setting a channelBit + // If this condition fails, then the channel will be shut off + channelBits += (1 << channelIdx); + } } } diff --git a/soh/src/code/code_800F9280.c b/soh/src/code/code_800F9280.c index 5cf4622992a..b9997751915 100644 --- a/soh/src/code/code_800F9280.c +++ b/soh/src/code/code_800F9280.c @@ -15,6 +15,8 @@ Struct_8016E320 D_8016E320[4][5]; u8 sNumSeqRequests[4]; u32 sAudioSeqCmds[0x100]; ActiveSequence gActiveSeqs[4]; +// Filled in here because this is where the audio editor mapping is resolved. +u8 gSeqPlayerIsStreamed[4]; u8 sSeqCmdWrPos = 0; u8 sSeqCmdRdPos = 0; @@ -64,6 +66,8 @@ void Audio_StartSequence(u8 playerIdx, u8 seqId, u8 arg2, u16 fadeTimer) { gActiveSeqs[playerIdx].seqId = seqId | (arg2 << 8); gActiveSeqs[playerIdx].prevSeqId = seqId | (arg2 << 8); + gSeqPlayerIsStreamed[playerIdx] = (gSeqIsStreamed != NULL) && ((size_t)resolvedSeqId < sequenceMapSize + 0xF) && + (gSeqIsStreamed[resolvedSeqId] != 0); if (gActiveSeqs[playerIdx].volCur != 1.0f) { Audio_QueueCmdF32(0x41000000 | _SHIFTL(playerIdx, 16, 8), gActiveSeqs[playerIdx].volCur); @@ -89,6 +93,7 @@ void func_800F9474(u8 playerIdx, u16 arg1) { Audio_QueueCmdS32(0x83000000 | ((u8)playerIdx << 16), (arg1 * (u16)gAudioContext.audioBufferParameters.updatesPerFrame) / 4); gActiveSeqs[playerIdx].seqId = NA_BGM_DISABLED; + gSeqPlayerIsStreamed[playerIdx] = false; } typedef enum {