2022-10-07 11:29:33 +00:00
|
|
|
/**
|
|
|
|
* @file code_800F9280.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 `Audio_QueueSeqCmd`, and a user-friendly interface for this function
|
|
|
|
* can be found in `seqcmd.h`
|
|
|
|
*
|
|
|
|
* These commands change sequences by generating internal audio commands `Audio_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.
|
|
|
|
*/
|
2020-10-03 15:22:44 +00:00
|
|
|
#include "ultra64.h"
|
|
|
|
#include "global.h"
|
2021-07-27 23:44:58 +00:00
|
|
|
#include "ultra64/abi.h"
|
2021-09-07 17:50:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// Direct audio command (skips the queueing system)
|
|
|
|
#define SEQCMD_SET_PLAYER_VOLUME_NOW(seqPlayerIndex, duration, volume) \
|
|
|
|
Audio_ProcessSeqCmd((SEQCMD_OP_SET_PLAYER_VOLUME << 28) | ((u8)(seqPlayerIndex) << 24) | ((u8)(duration) << 16) | \
|
|
|
|
((u8)((volume)*127.0f)));
|
|
|
|
|
2022-01-12 01:58:26 +00:00
|
|
|
typedef struct {
|
2022-10-07 11:29:33 +00:00
|
|
|
u8 seqId;
|
|
|
|
u8 priority; // higher values have higher priority
|
|
|
|
} SeqRequest;
|
2022-01-12 01:58:26 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
SeqRequest sSeqRequests[4][5];
|
|
|
|
u8 sNumSeqRequests[4];
|
2022-01-12 01:58:26 +00:00
|
|
|
u32 sAudioSeqCmds[0x100];
|
2022-10-07 11:29:33 +00:00
|
|
|
ActiveSequence gActiveSeqs[4];
|
|
|
|
|
|
|
|
void Audio_StartSequence(u8 seqPlayerIndex, u8 seqId, u8 seqArgs, u16 fadeInDuration) {
|
|
|
|
u8 channelIndex;
|
|
|
|
u16 duration;
|
2021-09-07 17:50:50 +00:00
|
|
|
s32 pad;
|
2021-07-27 23:44:58 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
if (!gStartSeqDisabled || (seqPlayerIndex == SEQ_PLAYER_SFX)) {
|
|
|
|
seqArgs &= 0x7F;
|
|
|
|
if (seqArgs == 0x7F) {
|
|
|
|
// `fadeInDuration` is interpreted as skip ticks
|
2022-10-07 17:43:17 +00:00
|
|
|
duration = (fadeInDuration >> 3) * 60 * gAudioCtx.audioBufferParameters.updatesPerFrame;
|
2022-10-07 11:29:33 +00:00
|
|
|
Audio_QueueCmdS32(0x85000000 | _SHIFTL(seqPlayerIndex, 16, 8) | _SHIFTL(seqId, 8, 8), duration);
|
2021-07-27 23:44:58 +00:00
|
|
|
} else {
|
2022-10-07 11:29:33 +00:00
|
|
|
// `fadeInDuration` is interpreted as number of frames at 30 fps
|
|
|
|
Audio_QueueCmdS32(0x82000000 | _SHIFTL(seqPlayerIndex, 16, 8) | _SHIFTL(seqId, 8, 8),
|
2022-10-07 17:43:17 +00:00
|
|
|
(fadeInDuration * (u16)gAudioCtx.audioBufferParameters.updatesPerFrame) / 4);
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].seqId = seqId | (seqArgs << 8);
|
|
|
|
gActiveSeqs[seqPlayerIndex].prevSeqId = seqId | (seqArgs << 8);
|
2021-07-27 23:44:58 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
if (gActiveSeqs[seqPlayerIndex].volCur != 1.0f) {
|
|
|
|
Audio_QueueCmdF32(0x41000000 | _SHIFTL(seqPlayerIndex, 16, 8), gActiveSeqs[seqPlayerIndex].volCur);
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].tempoTimer = 0;
|
|
|
|
gActiveSeqs[seqPlayerIndex].tempoOriginal = 0;
|
|
|
|
gActiveSeqs[seqPlayerIndex].tempoCmd = 0;
|
2021-07-27 23:44:58 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
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;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].freqScaleChannelFlags = 0;
|
|
|
|
gActiveSeqs[seqPlayerIndex].volChannelFlags = 0;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
void Audio_StopSequence(u8 seqPlayerIndex, u16 fadeOutDuration) {
|
|
|
|
Audio_QueueCmdS32(0x83000000 | ((u8)seqPlayerIndex << 16),
|
2022-10-07 17:43:17 +00:00
|
|
|
(fadeOutDuration * (u16)gAudioCtx.audioBufferParameters.updatesPerFrame) / 4);
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].seqId = NA_BGM_DISABLED;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
2021-09-07 17:50:50 +00:00
|
|
|
void Audio_ProcessSeqCmd(u32 cmd) {
|
2022-10-07 11:29:33 +00:00
|
|
|
s32 priority;
|
|
|
|
s32 channelMaskEnable;
|
|
|
|
u16 channelMaskDisable;
|
2021-09-07 17:50:50 +00:00
|
|
|
u16 fadeTimer;
|
|
|
|
u16 val;
|
|
|
|
u8 oldSpec;
|
|
|
|
u8 spec;
|
|
|
|
u8 op;
|
|
|
|
u8 subOp;
|
2022-10-07 11:29:33 +00:00
|
|
|
u8 seqPlayerIndex;
|
2021-09-07 17:50:50 +00:00
|
|
|
u8 seqId;
|
|
|
|
u8 seqArgs;
|
|
|
|
u8 found;
|
|
|
|
u8 port;
|
|
|
|
u8 duration;
|
2022-10-07 11:29:33 +00:00
|
|
|
u8 channelIndex;
|
2021-09-07 17:50:50 +00:00
|
|
|
u8 i;
|
2022-10-07 11:29:33 +00:00
|
|
|
f32 freqScaleTarget;
|
|
|
|
s32 pad;
|
2021-09-07 17:50:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
if (gAudioDebugPrintSeqCmd && (cmd & SEQCMD_OP_MASK) != (SEQCMD_OP_SET_PLAYER_IO << 28)) {
|
2022-07-30 00:35:09 +00:00
|
|
|
AudioDebug_ScrPrt("SEQ H", (cmd >> 16) & 0xFFFF);
|
|
|
|
AudioDebug_ScrPrt(" L", cmd & 0xFFFF);
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
op = cmd >> 28;
|
2022-10-07 11:29:33 +00:00
|
|
|
seqPlayerIndex = (cmd & 0xF000000) >> 24;
|
2021-09-07 17:50:50 +00:00
|
|
|
|
|
|
|
switch (op) {
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_PLAY_SEQUENCE:
|
|
|
|
// Play a new sequence
|
2021-09-07 17:50:50 +00:00
|
|
|
seqId = cmd & 0xFF;
|
|
|
|
seqArgs = (cmd & 0xFF00) >> 8;
|
2022-10-07 11:29:33 +00:00
|
|
|
// `fadeTimer` is only shifted 13 bits instead of 16 bits.
|
|
|
|
// `fadeTimer` continues to be scaled in `Audio_StartSequence`
|
2021-09-07 17:50:50 +00:00
|
|
|
fadeTimer = (cmd & 0xFF0000) >> 13;
|
2022-10-07 11:29:33 +00:00
|
|
|
if (!gActiveSeqs[seqPlayerIndex].isWaitingForFonts && (seqArgs < 0x80)) {
|
|
|
|
Audio_StartSequence(seqPlayerIndex, seqId, seqArgs, fadeTimer);
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_STOP_SEQUENCE:
|
|
|
|
// Stop a sequence and disable the sequence player
|
2021-09-07 17:50:50 +00:00
|
|
|
fadeTimer = (cmd & 0xFF0000) >> 13;
|
2022-10-07 11:29:33 +00:00
|
|
|
Audio_StopSequence(seqPlayerIndex, fadeTimer);
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_QUEUE_SEQUENCE:
|
|
|
|
// Queue a sequence into `sSeqRequests`
|
2021-09-07 17:50:50 +00:00
|
|
|
seqId = cmd & 0xFF;
|
|
|
|
seqArgs = (cmd & 0xFF00) >> 8;
|
|
|
|
fadeTimer = (cmd & 0xFF0000) >> 13;
|
2022-10-07 11:29:33 +00:00
|
|
|
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) {
|
2021-09-07 17:50:50 +00:00
|
|
|
if (i == 0) {
|
2022-10-07 11:29:33 +00:00
|
|
|
Audio_StartSequence(seqPlayerIndex, seqId, seqArgs, fadeTimer);
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// 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) {
|
2021-09-07 17:50:50 +00:00
|
|
|
found = i;
|
2022-10-07 11:29:33 +00:00
|
|
|
i = sNumSeqRequests[seqPlayerIndex]; // "break;"
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// Check if the queue is full
|
|
|
|
if (sNumSeqRequests[seqPlayerIndex] < ARRAY_COUNT(sSeqRequests[seqPlayerIndex])) {
|
|
|
|
sNumSeqRequests[seqPlayerIndex]++;
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
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;
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// 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.
|
2021-09-07 17:50:50 +00:00
|
|
|
if (found == 0) {
|
2022-10-07 11:29:33 +00:00
|
|
|
Audio_StartSequence(seqPlayerIndex, seqId, seqArgs, fadeTimer);
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_UNQUEUE_SEQUENCE:
|
|
|
|
// Unqueue sequence
|
2021-09-07 17:50:50 +00:00
|
|
|
fadeTimer = (cmd & 0xFF0000) >> 13;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
found = sNumSeqRequests[seqPlayerIndex];
|
|
|
|
for (i = 0; i < sNumSeqRequests[seqPlayerIndex]; i++) {
|
|
|
|
seqId = cmd & 0xFF;
|
|
|
|
if (sSeqRequests[seqPlayerIndex][i].seqId == seqId) {
|
2021-09-07 17:50:50 +00:00
|
|
|
found = i;
|
2022-10-07 11:29:33 +00:00
|
|
|
i = sNumSeqRequests[seqPlayerIndex]; // "break;"
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
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;
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
sNumSeqRequests[seqPlayerIndex]--;
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// If the sequence was first in queue (it is currently playing),
|
|
|
|
// Then stop the sequence and play the next sequence in the queue.
|
2021-09-07 17:50:50 +00:00
|
|
|
if (found == 0) {
|
2022-10-07 11:29:33 +00:00
|
|
|
Audio_StopSequence(seqPlayerIndex, fadeTimer);
|
|
|
|
if (sNumSeqRequests[seqPlayerIndex] != 0) {
|
|
|
|
Audio_StartSequence(seqPlayerIndex, sSeqRequests[seqPlayerIndex][0].seqId,
|
|
|
|
sSeqRequests[seqPlayerIndex][0].priority, fadeTimer);
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_SET_PLAYER_VOLUME:
|
|
|
|
// Transition volume to a target volume for an entire player
|
2021-09-07 17:50:50 +00:00
|
|
|
duration = (cmd & 0xFF0000) >> 15;
|
|
|
|
val = cmd & 0xFF;
|
|
|
|
if (duration == 0) {
|
|
|
|
duration++;
|
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
// 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;
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_SET_PLAYER_FREQ:
|
|
|
|
// Transition freq scale to a target freq for all channels
|
2021-09-07 17:50:50 +00:00
|
|
|
duration = (cmd & 0xFF0000) >> 15;
|
|
|
|
val = cmd & 0xFFFF;
|
|
|
|
if (duration == 0) {
|
|
|
|
duration++;
|
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
// 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;
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].freqScaleChannelFlags = 0xFFFF;
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_SET_CHANNEL_FREQ:
|
|
|
|
// Transition freq scale to a target for a specific channel
|
2021-09-07 17:50:50 +00:00
|
|
|
duration = (cmd & 0xFF0000) >> 15;
|
2022-10-07 11:29:33 +00:00
|
|
|
channelIndex = (cmd & 0xF000) >> 12;
|
2021-09-07 17:50:50 +00:00
|
|
|
val = cmd & 0xFFF;
|
|
|
|
if (duration == 0) {
|
|
|
|
duration++;
|
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
// 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;
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_SET_CHANNEL_VOLUME:
|
|
|
|
// Transition volume to a target volume for a specific channel
|
2021-09-07 17:50:50 +00:00
|
|
|
duration = (cmd & 0xFF0000) >> 15;
|
2022-10-07 11:29:33 +00:00
|
|
|
channelIndex = (cmd & 0xF00) >> 8;
|
2021-09-07 17:50:50 +00:00
|
|
|
val = cmd & 0xFF;
|
|
|
|
if (duration == 0) {
|
|
|
|
duration++;
|
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
// 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) /
|
2021-09-07 17:50:50 +00:00
|
|
|
(f32)duration;
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volTimer = duration;
|
|
|
|
gActiveSeqs[seqPlayerIndex].volChannelFlags |= 1 << channelIndex;
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_SET_PLAYER_IO:
|
|
|
|
// Set global io port
|
2021-09-07 17:50:50 +00:00
|
|
|
port = (cmd & 0xFF0000) >> 16;
|
|
|
|
val = cmd & 0xFF;
|
2022-10-07 11:29:33 +00:00
|
|
|
Audio_QueueCmdS8(0x46000000 | _SHIFTL(seqPlayerIndex, 16, 8) | _SHIFTL(port, 0, 8), val);
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_SET_CHANNEL_IO:
|
|
|
|
// Set io port if channel masked
|
|
|
|
channelIndex = (cmd & 0xF00) >> 8;
|
2021-09-07 17:50:50 +00:00
|
|
|
port = (cmd & 0xFF0000) >> 16;
|
|
|
|
val = cmd & 0xFF;
|
2022-10-07 11:29:33 +00:00
|
|
|
if (!(gActiveSeqs[seqPlayerIndex].channelPortMask & (1 << channelIndex))) {
|
|
|
|
Audio_QueueCmdS8(0x06000000 | _SHIFTL(seqPlayerIndex, 16, 8) | _SHIFTL(channelIndex, 8, 8) |
|
|
|
|
_SHIFTL(port, 0, 8),
|
2021-09-07 17:50:50 +00:00
|
|
|
val);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
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 `Audio_QueueCmdS8` 0x6
|
|
|
|
// directly. This is accomplished by setting a channel mask.
|
|
|
|
gActiveSeqs[seqPlayerIndex].channelPortMask = cmd & 0xFFFF;
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_SET_CHANNEL_DISABLE_MASK:
|
|
|
|
// Disable or Reenable channels
|
|
|
|
|
|
|
|
// Disable channels
|
|
|
|
channelMaskDisable = cmd & 0xFFFF;
|
|
|
|
if (channelMaskDisable != 0) {
|
|
|
|
// Apply channel mask `channelMaskDisable`
|
|
|
|
Audio_QueueCmdU16(0x90000000 | _SHIFTL(seqPlayerIndex, 16, 8), channelMaskDisable);
|
|
|
|
// Disable channels
|
|
|
|
Audio_QueueCmdS8(0x08000000 | _SHIFTL(seqPlayerIndex, 16, 8) | 0xFF00, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reenable channels
|
|
|
|
channelMaskEnable = (channelMaskDisable ^ 0xFFFF);
|
|
|
|
if (channelMaskEnable != 0) {
|
|
|
|
// Apply channel mask `channelMaskEnable`
|
|
|
|
Audio_QueueCmdU16(0x90000000 | _SHIFTL(seqPlayerIndex, 16, 8), channelMaskEnable);
|
|
|
|
// Enable channels
|
|
|
|
Audio_QueueCmdS8(0x08000000 | _SHIFTL(seqPlayerIndex, 16, 8) | 0xFF00, 0);
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_TEMPO_CMD:
|
|
|
|
// Update a tempo using a sub-command system.
|
|
|
|
// Stores the cmd for processing elsewhere.
|
|
|
|
gActiveSeqs[seqPlayerIndex].tempoCmd = cmd;
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_SETUP_CMD:
|
|
|
|
// Queue a sub-command to execute once the sequence is finished playing
|
2021-09-07 17:50:50 +00:00
|
|
|
subOp = (cmd & 0xF00000) >> 20;
|
2022-10-07 11:29:33 +00:00
|
|
|
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;
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2022-10-07 11:29:33 +00:00
|
|
|
// `SEQCMD_SUB_OP_SETUP_RESET_SETUP_CMDS`
|
|
|
|
// Discard all setup command requests on `seqPlayerIndex`
|
|
|
|
gActiveSeqs[seqPlayerIndex].setupCmdNum = 0;
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_GLOBAL_CMD:
|
|
|
|
// Apply a command that applies to all sequence players
|
2021-09-07 17:50:50 +00:00
|
|
|
subOp = (cmd & 0xF00) >> 8;
|
|
|
|
val = cmd & 0xFF;
|
|
|
|
switch (subOp) {
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_SUB_OP_GLOBAL_SET_SOUND_MODE:
|
|
|
|
// Set sound mode
|
2022-07-30 00:35:09 +00:00
|
|
|
Audio_QueueCmdS32(0xF0000000, gSoundModeList[val]);
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
case SEQCMD_SUB_OP_GLOBAL_DISABLE_NEW_SEQUENCES:
|
|
|
|
// Disable the starting of new sequences (except for the sfx player)
|
|
|
|
gStartSeqDisabled = val & 1;
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
case SEQCMD_OP_RESET_AUDIO_HEAP:
|
|
|
|
// Resets the audio heap based on the audio specifications and sfx channel layout
|
2021-09-07 17:50:50 +00:00
|
|
|
spec = cmd & 0xFF;
|
2021-11-07 16:58:50 +00:00
|
|
|
gSfxChannelLayout = (cmd & 0xFF00) >> 8;
|
2021-09-07 17:50:50 +00:00
|
|
|
oldSpec = gAudioSpecId;
|
|
|
|
gAudioSpecId = spec;
|
|
|
|
func_800E5F88(spec);
|
|
|
|
func_800F71BC(oldSpec);
|
|
|
|
Audio_QueueCmdS32(0xF8000000, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-07-27 23:44:58 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
/**
|
|
|
|
* Add the sequence cmd to the `sAudioSeqCmds` queue
|
|
|
|
*/
|
2021-07-27 23:44:58 +00:00
|
|
|
void Audio_QueueSeqCmd(u32 cmd) {
|
2022-10-07 11:29:33 +00:00
|
|
|
sAudioSeqCmds[gSeqCmdWritePos++] = cmd;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Audio_ProcessSeqCmds(void) {
|
2022-10-07 11:29:33 +00:00
|
|
|
while (gSeqCmdWritePos != gSeqCmdReadPos) {
|
|
|
|
Audio_ProcessSeqCmd(sAudioSeqCmds[gSeqCmdReadPos++]);
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
u16 Audio_GetActiveSeqId(u8 seqPlayerIndex) {
|
2022-10-07 17:43:17 +00:00
|
|
|
if (!gAudioCtx.seqPlayers[seqPlayerIndex].enabled) {
|
2021-11-01 17:54:19 +00:00
|
|
|
return NA_BGM_DISABLED;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
return gActiveSeqs[seqPlayerIndex].seqId;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
s32 Audio_IsSeqCmdNotQueued(u32 cmdVal, u32 cmdMask) {
|
2021-07-27 23:44:58 +00:00
|
|
|
u8 i;
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
for (i = gSeqCmdReadPos; i != gSeqCmdWritePos; i++) {
|
|
|
|
if ((sAudioSeqCmds[i] & cmdMask) == cmdVal) {
|
2021-07-27 23:44:58 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// Unused
|
|
|
|
void Audio_ResetSequenceRequests(u8 seqPlayerIndex) {
|
|
|
|
sNumSeqRequests[seqPlayerIndex] = 0;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
2020-07-20 01:08:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
/**
|
|
|
|
* Check if the setup command is queued. If it is, then replace the command
|
|
|
|
* with `SEQCMD_SUB_OP_SETUP_RESTORE_VOLUME`.
|
|
|
|
* Unused
|
|
|
|
*/
|
|
|
|
void Audio_ReplaceSeqCmdSetupOpVolRestore(u8 seqPlayerIndex, u8 setupOpDisabled) {
|
2021-07-27 23:44:58 +00:00
|
|
|
u8 i;
|
2020-07-20 01:08:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
for (i = 0; i < gActiveSeqs[seqPlayerIndex].setupCmdNum; i++) {
|
|
|
|
u8 setupOp = (gActiveSeqs[seqPlayerIndex].setupCmd[i] & 0xF00000) >> 20;
|
2020-07-20 01:08:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
if (setupOp == setupOpDisabled) {
|
|
|
|
gActiveSeqs[seqPlayerIndex].setupCmd[i] = 0xFF000000;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-20 01:08:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
void Audio_SetVolumeScale(u8 seqPlayerIndex, u8 scaleIndex, u8 targetVol, u8 volFadeTimer) {
|
2021-07-27 23:44:58 +00:00
|
|
|
f32 volScale;
|
|
|
|
u8 i;
|
2020-07-20 01:08:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].volScales[scaleIndex] = targetVol & 0x7F;
|
2020-07-20 01:08:50 +00:00
|
|
|
|
2021-07-27 23:44:58 +00:00
|
|
|
if (volFadeTimer != 0) {
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].fadeVolUpdate = true;
|
|
|
|
gActiveSeqs[seqPlayerIndex].volFadeTimer = volFadeTimer;
|
2021-07-27 23:44:58 +00:00
|
|
|
} else {
|
2022-10-07 11:29:33 +00:00
|
|
|
for (i = 0, volScale = 1.0f; i < VOL_SCALE_INDEX_MAX; i++) {
|
|
|
|
volScale *= gActiveSeqs[seqPlayerIndex].volScales[i] / 127.0f;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
2020-07-20 01:08:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
SEQCMD_SET_PLAYER_VOLUME_NOW(seqPlayerIndex, volFadeTimer, volScale);
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-20 01:08:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
/**
|
|
|
|
* Update different commands and requests for active sequences
|
|
|
|
*/
|
|
|
|
void Audio_UpdateActiveSequences(void) {
|
|
|
|
u32 tempoCmd;
|
|
|
|
u8 tempoOp;
|
|
|
|
u16 tempoPrev;
|
|
|
|
u16 tempoTarget;
|
|
|
|
u8 setupOp;
|
|
|
|
u8 targetSeqPlayerIndex;
|
|
|
|
u8 setupVal2;
|
|
|
|
u8 setupVal1;
|
|
|
|
u16 seqId;
|
|
|
|
s32 pad[2];
|
|
|
|
u16 channelMask;
|
|
|
|
u32 retMsg;
|
|
|
|
f32 volume;
|
|
|
|
u8 tempoTimer;
|
|
|
|
u8 seqPlayerIndex;
|
2021-07-27 23:44:58 +00:00
|
|
|
u8 j;
|
2022-10-07 11:29:33 +00:00
|
|
|
u8 channelIndex;
|
|
|
|
|
|
|
|
for (seqPlayerIndex = 0; seqPlayerIndex < 4; seqPlayerIndex++) {
|
|
|
|
|
|
|
|
// The setup for this block of code was not fully implemented until Majora's Mask.
|
|
|
|
// The intent was to load soundfonts asynchronously before playing a
|
|
|
|
// sequence in `Audio_StartSequence` using `(seqArgs & 0x80)`.
|
|
|
|
// Checks if the requested sequence is finished loading fonts
|
|
|
|
if (gActiveSeqs[seqPlayerIndex].isWaitingForFonts) {
|
|
|
|
switch (func_800E5E20(&retMsg)) {
|
|
|
|
case SEQ_PLAYER_BGM_MAIN + 1:
|
|
|
|
case SEQ_PLAYER_FANFARE + 1:
|
|
|
|
case SEQ_PLAYER_SFX + 1:
|
|
|
|
case SEQ_PLAYER_BGM_SUB + 1:
|
|
|
|
// The fonts have been loaded successfully.
|
|
|
|
gActiveSeqs[seqPlayerIndex].isWaitingForFonts = false;
|
|
|
|
// Queue the same command that was stored previously
|
|
|
|
// The code to store this command is missing in OoT, so no command is executed
|
|
|
|
Audio_ProcessSeqCmd(gActiveSeqs[seqPlayerIndex].startSeqCmd);
|
2021-07-27 23:44:58 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-07-20 01:08:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// 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);
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
SEQCMD_SET_PLAYER_VOLUME(seqPlayerIndex, gActiveSeqs[seqPlayerIndex].volFadeTimer, (u8)(volume * 127.0f));
|
|
|
|
gActiveSeqs[seqPlayerIndex].fadeVolUpdate = false;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
if (gActiveSeqs[seqPlayerIndex].volTimer != 0) {
|
|
|
|
gActiveSeqs[seqPlayerIndex].volTimer--;
|
2021-07-27 23:44:58 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
if (gActiveSeqs[seqPlayerIndex].volTimer != 0) {
|
|
|
|
gActiveSeqs[seqPlayerIndex].volCur -= gActiveSeqs[seqPlayerIndex].volStep;
|
2021-07-27 23:44:58 +00:00
|
|
|
} else {
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].volCur = gActiveSeqs[seqPlayerIndex].volTarget;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
Audio_QueueCmdF32(0x41000000 | _SHIFTL(seqPlayerIndex, 16, 8), gActiveSeqs[seqPlayerIndex].volCur);
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// 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
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.seqPlayers[seqPlayerIndex].enabled) {
|
|
|
|
tempoPrev = gAudioCtx.seqPlayers[seqPlayerIndex].tempo / TATUMS_PER_BEAT;
|
2022-10-07 11:29:33 +00:00
|
|
|
tempoOp = (tempoCmd & 0xF000) >> 12;
|
|
|
|
switch (tempoOp) {
|
|
|
|
case SEQCMD_SUB_OP_TEMPO_SPEED_UP:
|
|
|
|
// Speed up tempo by `tempoTarget` amount
|
|
|
|
tempoTarget += tempoPrev;
|
2021-07-27 23:44:58 +00:00
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
case SEQCMD_SUB_OP_TEMPO_SLOW_DOWN:
|
|
|
|
// Slow down tempo by `tempoTarget` amount
|
|
|
|
if (tempoTarget < tempoPrev) {
|
|
|
|
tempoTarget = tempoPrev - tempoTarget;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
case SEQCMD_SUB_OP_TEMPO_SCALE:
|
|
|
|
// Scale tempo by a multiplicative factor
|
|
|
|
tempoTarget = tempoPrev * (tempoTarget / 100.0f);
|
2021-07-27 23:44:58 +00:00
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
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
|
2021-07-27 23:44:58 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
if (tempoTarget > 300) {
|
|
|
|
tempoTarget = 300;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
if (gActiveSeqs[seqPlayerIndex].tempoOriginal == 0) {
|
|
|
|
gActiveSeqs[seqPlayerIndex].tempoOriginal = tempoPrev;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].tempoTarget = tempoTarget;
|
2022-10-07 17:43:17 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].tempoCur = gAudioCtx.seqPlayers[seqPlayerIndex].tempo / TATUMS_PER_BEAT;
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].tempoStep =
|
|
|
|
(gActiveSeqs[seqPlayerIndex].tempoCur - gActiveSeqs[seqPlayerIndex].tempoTarget) / tempoTimer;
|
|
|
|
gActiveSeqs[seqPlayerIndex].tempoTimer = tempoTimer;
|
|
|
|
gActiveSeqs[seqPlayerIndex].tempoCmd = 0;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// Step tempo to target
|
|
|
|
if (gActiveSeqs[seqPlayerIndex].tempoTimer != 0) {
|
|
|
|
gActiveSeqs[seqPlayerIndex].tempoTimer--;
|
|
|
|
if (gActiveSeqs[seqPlayerIndex].tempoTimer != 0) {
|
|
|
|
gActiveSeqs[seqPlayerIndex].tempoCur -= gActiveSeqs[seqPlayerIndex].tempoStep;
|
2021-07-27 23:44:58 +00:00
|
|
|
} else {
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].tempoCur = gActiveSeqs[seqPlayerIndex].tempoTarget;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
// Set tempo
|
|
|
|
Audio_QueueCmdS32(0x47000000 | _SHIFTL(seqPlayerIndex, 16, 8), gActiveSeqs[seqPlayerIndex].tempoCur);
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// 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;
|
2021-07-27 23:44:58 +00:00
|
|
|
} else {
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volCur =
|
|
|
|
gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volTarget;
|
|
|
|
gActiveSeqs[seqPlayerIndex].volChannelFlags ^= (1 << channelIndex);
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
// `CHAN_UPD_VOL_SCALE`
|
|
|
|
Audio_QueueCmdF32(0x01000000 | _SHIFTL(seqPlayerIndex, 16, 8) | _SHIFTL(channelIndex, 8, 8),
|
|
|
|
gActiveSeqs[seqPlayerIndex].channelData[channelIndex].volCur);
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-09-07 17:50:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// 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;
|
2021-07-27 23:44:58 +00:00
|
|
|
} else {
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleCur =
|
|
|
|
gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleTarget;
|
|
|
|
gActiveSeqs[seqPlayerIndex].freqScaleChannelFlags ^= (1 << channelIndex);
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
// `CHAN_UPD_FREQ_SCALE`
|
|
|
|
Audio_QueueCmdF32(0x04000000 | _SHIFTL(seqPlayerIndex, 16, 8) | _SHIFTL(channelIndex, 8, 8),
|
|
|
|
gActiveSeqs[seqPlayerIndex].channelData[channelIndex].freqScaleCur);
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// 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 (!Audio_IsSeqCmdNotQueued(SEQCMD_OP_RESET_AUDIO_HEAP << 28, SEQCMD_OP_MASK)) {
|
|
|
|
gActiveSeqs[seqPlayerIndex].setupCmdNum = 0;
|
2021-07-27 23:44:58 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// Only process setup commands once the timer reaches zero
|
|
|
|
if (gActiveSeqs[seqPlayerIndex].setupCmdTimer != 0) {
|
|
|
|
gActiveSeqs[seqPlayerIndex].setupCmdTimer--;
|
2021-09-07 17:50:50 +00:00
|
|
|
continue;
|
|
|
|
}
|
2021-07-27 23:44:58 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
// Only process setup commands if `seqPlayerIndex` if no longer playing
|
|
|
|
// i.e. the `seqPlayer` is no longer enabled
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.seqPlayers[seqPlayerIndex].enabled) {
|
2021-09-07 17:50:50 +00:00
|
|
|
continue;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
2021-09-07 17:50:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
for (j = 0; j < gActiveSeqs[seqPlayerIndex].setupCmdNum; j++) {
|
|
|
|
setupOp = (gActiveSeqs[seqPlayerIndex].setupCmd[j] & 0x00F00000) >> 20;
|
|
|
|
targetSeqPlayerIndex = (gActiveSeqs[seqPlayerIndex].setupCmd[j] & 0x000F0000) >> 16;
|
|
|
|
setupVal2 = (gActiveSeqs[seqPlayerIndex].setupCmd[j] & 0xFF00) >> 8;
|
|
|
|
setupVal1 = gActiveSeqs[seqPlayerIndex].setupCmd[j] & 0xFF;
|
2021-09-07 17:50:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
switch (setupOp) {
|
|
|
|
case SEQCMD_SUB_OP_SETUP_RESTORE_VOLUME:
|
|
|
|
// Restore `targetSeqPlayerIndex` volume back to normal levels
|
|
|
|
Audio_SetVolumeScale(targetSeqPlayerIndex, VOL_SCALE_INDEX_FANFARE, 0x7F, setupVal1);
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
case SEQCMD_SUB_OP_SETUP_RESTORE_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]) {
|
|
|
|
Audio_SetVolumeScale(targetSeqPlayerIndex, VOL_SCALE_INDEX_FANFARE, 0x7F, setupVal2);
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
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(seqPlayerIndex, 0, gActiveSeqs[seqPlayerIndex].seqId);
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
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(targetSeqPlayerIndex, 1, 0, gActiveSeqs[targetSeqPlayerIndex].seqId);
|
|
|
|
gActiveSeqs[targetSeqPlayerIndex].fadeVolUpdate = true;
|
|
|
|
gActiveSeqs[targetSeqPlayerIndex].volScales[VOL_SCALE_INDEX_FANFARE] = 0x7F;
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
case SEQCMD_SUB_OP_SETUP_TEMPO_SCALE:
|
|
|
|
// Scale tempo by a multiplicative factor
|
|
|
|
SEQCMD_SCALE_TEMPO(targetSeqPlayerIndex, setupVal2, setupVal1);
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
case SEQCMD_SUB_OP_SETUP_TEMPO_RESET:
|
|
|
|
// Reset tempo to previous tempo
|
|
|
|
SEQCMD_RESET_TEMPO(targetSeqPlayerIndex, setupVal1);
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
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(targetSeqPlayerIndex, gActiveSeqs[targetSeqPlayerIndex].setupFadeTimer, 0,
|
|
|
|
seqId);
|
|
|
|
Audio_SetVolumeScale(targetSeqPlayerIndex, VOL_SCALE_INDEX_FANFARE, 0x7F, 0);
|
|
|
|
gActiveSeqs[targetSeqPlayerIndex].setupFadeTimer = 0;
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
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;
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
case SEQCMD_SUB_OP_SETUP_RESTORE_VOLUME_WITH_SCALE_INDEX:
|
|
|
|
// Restore the volume back to default levels
|
|
|
|
// Allows a `scaleIndex` to be specified.
|
|
|
|
Audio_SetVolumeScale(targetSeqPlayerIndex, setupVal2, 0x7F, setupVal1);
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
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)) {
|
2021-11-07 16:58:50 +00:00
|
|
|
Audio_QueueCmdS32(0xE3000000, SEQUENCE_TABLE);
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
if (setupVal1 & (1 << FONT_TABLE)) {
|
2021-11-07 16:58:50 +00:00
|
|
|
Audio_QueueCmdS32(0xE3000000, FONT_TABLE);
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
if (setupVal1 & (1 << SAMPLE_TABLE)) {
|
2021-11-07 16:58:50 +00:00
|
|
|
Audio_QueueCmdS32(0xE3000000, SAMPLE_TABLE);
|
2021-09-07 17:50:50 +00:00
|
|
|
}
|
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
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(targetSeqPlayerIndex, channelMask);
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
case SEQCMD_SUB_OP_SETUP_SET_PLAYER_FREQ:
|
|
|
|
// Scale all channels of `targetSeqPlayerIndex`
|
|
|
|
SEQCMD_SET_PLAYER_FREQ(targetSeqPlayerIndex, setupVal2, (setupVal1 * 10) & 0xFFFF);
|
2021-09-07 17:50:50 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
gActiveSeqs[seqPlayerIndex].setupCmdNum = 0;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
u8 func_800FAD34(void) {
|
|
|
|
if (D_80133418 != 0) {
|
|
|
|
if (D_80133418 == 1) {
|
|
|
|
if (func_800E5EDC() == 1) {
|
|
|
|
D_80133418 = 0;
|
2021-11-07 16:58:50 +00:00
|
|
|
Audio_QueueCmdS8(0x46020000, gSfxChannelLayout);
|
2021-07-27 23:44:58 +00:00
|
|
|
func_800F7170();
|
|
|
|
}
|
|
|
|
} else if (D_80133418 == 2) {
|
|
|
|
while (func_800E5EDC() != 1) {}
|
|
|
|
D_80133418 = 0;
|
2021-11-07 16:58:50 +00:00
|
|
|
Audio_QueueCmdS8(0x46020000, gSfxChannelLayout);
|
2021-07-27 23:44:58 +00:00
|
|
|
func_800F7170();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return D_80133418;
|
|
|
|
}
|
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
void Audio_ResetActiveSequences(void) {
|
|
|
|
u8 seqPlayerIndex;
|
|
|
|
u8 scaleIndex;
|
|
|
|
|
|
|
|
for (seqPlayerIndex = 0; seqPlayerIndex < 4; 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;
|
|
|
|
for (scaleIndex = 0; scaleIndex < VOL_SCALE_INDEX_MAX; scaleIndex++) {
|
|
|
|
gActiveSeqs[seqPlayerIndex].volScales[scaleIndex] = 0x7F;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
|
|
|
|
gActiveSeqs[seqPlayerIndex].volFadeTimer = 1;
|
|
|
|
gActiveSeqs[seqPlayerIndex].fadeVolUpdate = true;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-20 01:08:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
void Audio_ResetActiveSequencesAndVolume(void) {
|
|
|
|
u8 seqPlayerIndex;
|
|
|
|
u8 scaleIndex;
|
2020-07-20 01:08:50 +00:00
|
|
|
|
2022-10-07 11:29:33 +00:00
|
|
|
for (seqPlayerIndex = 0; seqPlayerIndex < 4; 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;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-07 11:29:33 +00:00
|
|
|
Audio_ResetActiveSequences();
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|