sm64pc/src/audio/load.c

778 lines
27 KiB
C

#include <ultra64.h>
#include <macros.h>
#include "load.h"
#include "memory.h"
#include "data.h"
#include "seqplayer.h"
#define ALIGN16(val) (((val) + 0xF) & ~0xF)
struct SharedDma {
/*0x0*/ u8 *buffer; // target, points to pre-allocated buffer
/*0x4*/ u32 source; // device address
/*0x8*/ u16 sizeUnused; // set to bufSize, never read
/*0xA*/ u16 bufSize;
/*0xC*/ u8 unused2; // set to 0, never read
/*0xD*/ u8 reuseIndex; // position in sSampleDmaReuseQueue1/2, if ttl == 0
/*0xE*/ u8 ttl; // duration after which the DMA can be discarded
}; // size = 0x10
struct Note *gNotes;
struct SequencePlayer gSequencePlayers[SEQUENCE_PLAYERS];
struct SequenceChannel gSequenceChannels[32];
#ifdef VERSION_JP
struct SequenceChannelLayer D_802245D8[48];
#else
struct SequenceChannelLayer D_802245D8[52];
#endif
struct SequenceChannel gSequenceChannelNone;
struct AudioListItem gLayerFreeList;
struct NotePool gNoteFreeLists;
OSMesgQueue gCurrAudioFrameDmaQueue;
OSMesg gCurrAudioFrameDmaMesgBufs[AUDIO_FRAME_DMA_QUEUE_SIZE];
OSIoMesg gCurrAudioFrameDmaIoMesgBufs[AUDIO_FRAME_DMA_QUEUE_SIZE];
OSMesgQueue gAudioDmaMesgQueue;
OSMesg gAudioDmaMesg;
OSIoMesg gAudioDmaIoMesg;
struct SharedDma sSampleDmas[0x60];
u32 gSampleDmaNumListItems;
u32 sSampleDmaListSize1;
u32 sUnused80226B40; // set to 0, never read
// Circular buffer of DMAs with ttl = 0. tail <= head, wrapping around mod 256.
u8 sSampleDmaReuseQueue1[256];
u8 sSampleDmaReuseQueue2[256];
u8 sSampleDmaReuseQueueTail1;
u8 sSampleDmaReuseQueueTail2;
u8 sSampleDmaReuseQueueHead1;
u8 sSampleDmaReuseQueueHead2;
ALSeqFile *gSeqFileHeader;
ALSeqFile *gAlCtlHeader;
ALSeqFile *gAlTbl;
u8 *gAlBankSets;
u16 gSequenceCount;
extern u64 gAudioGlobalsStartMarker;
extern u64 gAudioGlobalsEndMarker;
extern u8 gSoundDataADSR[]; // sound_data.ctl
extern u8 gSoundDataRaw[]; // sound_data.tbl
extern u8 gMusicData[]; // sequences.s
extern u8 gBankSetsData[]; // bank_sets.s
/**
* Performs an immediate DMA copy
*/
void audio_dma_copy_immediate(u32 devAddr, void *vAddr, u32 nbytes) {
osInvalDCache(vAddr, (s32) nbytes);
osPiStartDma(&gAudioDmaIoMesg, OS_MESG_PRI_HIGH, OS_READ, devAddr, vAddr, nbytes,
&gAudioDmaMesgQueue);
osRecvMesg(&gAudioDmaMesgQueue, NULL, OS_MESG_BLOCK);
}
/**
* Performs an asynchronus (normal priority) DMA copy
*/
void audio_dma_copy_async(u32 devAddr, void *vAddr, u32 nbytes, OSMesgQueue *queue, OSIoMesg *mesg) {
osInvalDCache(vAddr, (s32) nbytes);
osPiStartDma(mesg, OS_MESG_PRI_NORMAL, OS_READ, devAddr, vAddr, nbytes, queue);
}
/**
* Performs a partial asynchronous (normal priority) DMA copy. This is limited
* to 0x1000 bytes transfer at once.
*/
void audio_dma_partial_copy_async(u32 *devAddr, u8 **vAddr, s32 *remaining, OSMesgQueue *queue,
OSIoMesg *mesg) {
s32 transfer = (*remaining < 0x1000 ? *remaining : 0x1000);
*remaining -= transfer;
osInvalDCache(*vAddr, transfer);
osPiStartDma(mesg, OS_MESG_PRI_NORMAL, OS_READ, *devAddr, *vAddr, transfer, queue);
*devAddr += transfer;
*vAddr += transfer;
}
void decrease_sample_dma_ttls() {
u32 i;
for (i = 0; i < sSampleDmaListSize1; i++) {
struct SharedDma *temp = sSampleDmas + i;
if (temp->ttl != 0) {
temp->ttl--;
if (temp->ttl == 0) {
temp->reuseIndex = sSampleDmaReuseQueueHead1;
sSampleDmaReuseQueue1[sSampleDmaReuseQueueHead1++] = (u8) i;
}
}
}
for (i = sSampleDmaListSize1; i < gSampleDmaNumListItems; i++) {
struct SharedDma *temp = sSampleDmas + i;
if (temp->ttl != 0) {
temp->ttl--;
if (temp->ttl == 0) {
temp->reuseIndex = sSampleDmaReuseQueueHead2;
sSampleDmaReuseQueue2[sSampleDmaReuseQueueHead2++] = (u8) i;
}
}
}
sUnused80226B40 = 0;
}
#ifdef NON_MATCHING
void *dma_sample_data(u8 *devAddr, u32 size, s32 arg2, u8 *arg3) {
s32 bufferPos; // v0
struct SharedDma *dma; // sp58, v1, t0
u32 transfer; // v0
u32 dmaDevAddr; // s0
u32 i; // a0
u32 dmaIndex; // sp48, t2
s32 hasDma = 0; // t4
UNUSED s32 pad;
if (arg2 != 0 || *arg3 >= sSampleDmaListSize1) {
for (i = sSampleDmaListSize1; i < gSampleDmaNumListItems; i++) {
dma = sSampleDmas + i;
bufferPos = (u32) devAddr - dma->source;
if (0 <= bufferPos && (u32) bufferPos <= dma->bufSize - size) {
// We already have a DMA request for this memory range.
if (dma->ttl == 0 && sSampleDmaReuseQueueHead2 != sSampleDmaReuseQueueTail2) {
// Move the DMA out of the reuse queue, by swapping it with the
// tail, and then incrementing the tail.
if (dma->reuseIndex != sSampleDmaReuseQueueTail2) {
sSampleDmaReuseQueue2[dma->reuseIndex] =
sSampleDmaReuseQueue2[sSampleDmaReuseQueueTail2];
sSampleDmas[sSampleDmaReuseQueue2[sSampleDmaReuseQueueTail2]].reuseIndex =
dma->reuseIndex;
}
sSampleDmaReuseQueueTail2++;
}
dma->ttl = 60;
*arg3 = (u8) i;
bufferPos = (u32) devAddr - dma->source;
return dma->buffer + bufferPos;
}
}
if (sSampleDmaReuseQueueHead2 != sSampleDmaReuseQueueTail2 && arg2 != 0) {
// Allocate a DMA from reuse queue 2. This queue can be empty, since
// TTL 60 is pretty large.
dmaIndex = sSampleDmaReuseQueue2[sSampleDmaReuseQueueTail2++];
dma = &sSampleDmas[dmaIndex];
hasDma = 1;
}
} else {
dma = &sSampleDmas[*arg3];
bufferPos = (u32) devAddr - dma->source;
if (0 <= bufferPos && (u32) bufferPos <= dma->bufSize - size) {
// We already have DMA for this memory range.
if (dma->ttl == 0) {
// Move the DMA out of the reuse queue, by swapping it with the
// tail, and then incrementing the tail.
if (dma->reuseIndex != sSampleDmaReuseQueueTail1) {
sSampleDmaReuseQueue1[dma->reuseIndex] =
sSampleDmaReuseQueue1[sSampleDmaReuseQueueTail1];
sSampleDmas[sSampleDmaReuseQueue1[sSampleDmaReuseQueueTail1]].reuseIndex =
dma->reuseIndex;
}
sSampleDmaReuseQueueTail1++;
bufferPos = (u32) devAddr - dma->source;
}
dma->ttl = 2;
return dma->buffer + bufferPos;
}
}
if (!hasDma) {
// Allocate a DMA from reuse queue 1. This queue will hopefully never
// be empty, since TTL 2 is so small.
dmaIndex = sSampleDmaReuseQueue1[sSampleDmaReuseQueueTail1++];
dma = &sSampleDmas[dmaIndex];
hasDma = 1;
}
transfer = dma->bufSize;
dmaDevAddr = (u32) devAddr & ~0xF;
dma->ttl = 2;
dma->source = dmaDevAddr;
dma->sizeUnused = transfer;
#ifndef VERSION_JP
osInvalDCache(dma->buffer, transfer);
#endif
gCurrAudioFrameDmaCount++;
osPiStartDma(&gCurrAudioFrameDmaIoMesgBufs[gCurrAudioFrameDmaCount - 1], OS_MESG_PRI_NORMAL,
OS_READ, dmaDevAddr, dma->buffer, transfer, &gCurrAudioFrameDmaQueue);
*arg3 = dmaIndex;
return dma->buffer + (u32) devAddr - dmaDevAddr;
}
#elif defined(VERSION_JP)
GLOBAL_ASM("asm/non_matchings/dma_sample_data_jp.s")
#else
GLOBAL_ASM("asm/non_matchings/dma_sample_data_us.s")
#endif
// called from sound_reset
void func_8031758C(UNUSED s32 arg0) {
s32 i;
s32 j;
D_80226D68 = 144 * 9;
for (i = 0; i < gMaxSimultaneousNotes * 3; i++) {
sSampleDmas[gSampleDmaNumListItems].buffer = soundAlloc(&D_802212C8, D_80226D68);
if (sSampleDmas[gSampleDmaNumListItems].buffer == NULL) {
goto out1;
}
sSampleDmas[gSampleDmaNumListItems].source = 0;
sSampleDmas[gSampleDmaNumListItems].sizeUnused = 0;
sSampleDmas[gSampleDmaNumListItems].unused2 = 0;
sSampleDmas[gSampleDmaNumListItems].ttl = 0;
sSampleDmas[gSampleDmaNumListItems].bufSize = D_80226D68;
gSampleDmaNumListItems++;
}
out1:
for (i = 0; (u32) i < gSampleDmaNumListItems; i++) {
sSampleDmaReuseQueue1[i] = (u8) i;
sSampleDmas[i].reuseIndex = (u8) i;
}
for (j = gSampleDmaNumListItems; j < 0x100; j++) {
sSampleDmaReuseQueue1[j] = 0;
}
sSampleDmaReuseQueueTail1 = 0;
sSampleDmaReuseQueueHead1 = (u8) gSampleDmaNumListItems;
sSampleDmaListSize1 = gSampleDmaNumListItems;
D_80226D68 = 160 * 9;
for (i = 0; i < gMaxSimultaneousNotes; i++) {
sSampleDmas[gSampleDmaNumListItems].buffer = soundAlloc(&D_802212C8, D_80226D68);
if (sSampleDmas[gSampleDmaNumListItems].buffer == NULL) {
goto out2;
}
sSampleDmas[gSampleDmaNumListItems].source = 0;
sSampleDmas[gSampleDmaNumListItems].sizeUnused = 0;
sSampleDmas[gSampleDmaNumListItems].unused2 = 0;
sSampleDmas[gSampleDmaNumListItems].ttl = 0;
sSampleDmas[gSampleDmaNumListItems].bufSize = D_80226D68;
gSampleDmaNumListItems++;
}
out2:
for (i = sSampleDmaListSize1; (u32) i < gSampleDmaNumListItems; i++) {
sSampleDmaReuseQueue2[i - sSampleDmaListSize1] = (u8) i;
sSampleDmas[i].reuseIndex = (u8)(i - sSampleDmaListSize1);
}
// This probably meant to touch the range size1..size2 as well... but it
// doesn't matter, since these values are never read anyway.
for (j = gSampleDmaNumListItems; j < 0x100; j++) {
sSampleDmaReuseQueue2[j] = sSampleDmaListSize1;
}
sSampleDmaReuseQueueTail2 = 0;
sSampleDmaReuseQueueHead2 = gSampleDmaNumListItems - sSampleDmaListSize1;
}
#ifndef static
// Keep supporting the good old "#define static" hack.
#undef static
#endif
static void unused_80317844(void) {
// With -O2 -framepointer, this never-invoked static function gets *almost*
// optimized out, regardless of contents, leaving only "jr $ra, nop".
// If not declared as static, it unnecessarily moves the stack pointer up
// and down by 8.
}
#ifdef NON_MATCHING
void func_8031784C(struct AudioBank *mem, u8 *offset, u32 numInstruments, u32 numDrums) {
// Make pointers into real pointers rather than indices
struct Instrument *instrument;
struct Instrument **itInstrs;
u32 i;
u32 memBase = (u32) mem;
u32 offsetBase = (u32) offset;
#define INIT_SOUND(sound) \
{ \
struct AudioBankSample **itSample = &sound.sample; \
if ((*itSample) != 0) { \
/* Making these volatile gives correct codegen further down; it makes \
* lw/addiu/sw's happen in source order, and uses two registers... \
* It looks odd, though, so maybe they should not be volatile. \
* It might also be causing the extra register use. \
* Presumably sample and sample2 ought to have different types, \
* but that doesn't matter for codegen. */ \
volatile struct AudioBankSample *sample, *sample2; \
*itSample = (void *) (memBase + (u32)(*itSample)); \
sample = *itSample; \
sample2 = *itSample; \
if (sample2->loaded == FALSE) { \
void *a = sample2->sampleAddr; \
void *b = sample->loop; \
void *c = sample->book; \
sample->sampleAddr = (void *) (offsetBase + (u32) a); \
sample->loop = (void *) (memBase + (u32) b); \
sample->book = (void *) (memBase + (u32) c); \
sample->loaded = TRUE; \
} \
} \
}
if (mem->drums != NULL) {
if (numDrums != 0) {
mem->drums = (struct Drum **) (memBase + (u32) mem->drums);
if (numDrums != 0) {
for (i = 0; i < numDrums; i++) {
#if 0
// This doesn't work: Taking the address to mem->drums[i]
// does an sll to figure out the lower loop limit.
volatile struct Drum *drum, *drum2;
struct Drum **h = &mem->drums[i];
if (*h == 0) continue;
{
*h = (void *)(memBase + (u32)*h);
drum = *h;
drum2 = *h;
if (drum2->loaded == FALSE)
{
void *d;
INIT_SOUND(((struct Drum *)drum2)->sound);
d = drum2->envelope;
drum->loaded = TRUE;
drum->envelope = (void *) (memBase + (u32)d);
}
}
#else
// Neither does this: Using mem->drums[i] directly
// deduplicates it -- drum and drum2 end up in the same
// register.
struct Drum **drums = mem->drums;
u32 h = (u32) drums[i];
if (h != 0) {
volatile struct Drum *drum, *drum2;
drums[i] = (struct Drum *) (memBase + h);
drum = drums[i];
drum2 = drums[i];
if (drum->loaded == FALSE) {
void *d;
INIT_SOUND(((struct Drum *) drum)->sound);
d = drum->envelope;
drum2->loaded = TRUE;
drum2->envelope = (void *) (memBase + (u32) d);
}
}
#endif
}
}
}
}
if ((numInstruments >= 1) && (numInstruments >= 1) != 0) {
itInstrs = mem->instruments;
do {
if (*itInstrs) {
*itInstrs = (void *) (memBase + (u32) *itInstrs);
instrument = *itInstrs;
if (instrument->loaded == FALSE) {
INIT_SOUND(instrument->lowNotesSound);
INIT_SOUND(instrument->normalNotesSound);
INIT_SOUND(instrument->highNotesSound);
instrument->loaded = TRUE;
instrument->envelope = (void *) (memBase + (u32) instrument->envelope);
}
}
itInstrs++;
} while (itInstrs != &mem->instruments[numInstruments]);
}
#undef INIT_SOUND
}
#else
GLOBAL_ASM("asm/non_matchings/func_8031784C.s")
#endif
struct AudioBank *bank_load_immediate(s32 bankId, s32 arg1) {
UNUSED u32 pad1[4];
u32 buf[4];
u32 numInstruments, numDrums;
struct AudioBank *ret;
u8 *ctlData;
s32 alloc;
// (This is broken if the length is 1 (mod 16), but that never happens --
// it's always divisible by 4.)
alloc = gAlCtlHeader->seqArray[bankId].len + 0xf;
alloc = ALIGN16(alloc);
alloc -= 0x10;
ctlData = gAlCtlHeader->seqArray[bankId].offset;
ret = alloc_bank_or_seq(&gBankLoadedPool, 1, alloc, arg1, bankId);
if (ret == NULL) {
return NULL;
}
audio_dma_copy_immediate((u32) ctlData, buf, 0x10);
numInstruments = buf[0];
numDrums = buf[1];
audio_dma_copy_immediate((u32)(ctlData + 0x10), ret, alloc);
func_8031784C(ret, gAlTbl->seqArray[bankId].offset, numInstruments, numDrums);
gCtlEntries[bankId].numInstruments = (u8) numInstruments;
gCtlEntries[bankId].numDrums = (u8) numDrums;
gCtlEntries[bankId].instruments = ret->instruments;
gCtlEntries[bankId].drums = ret->drums;
gBankLoadStatus[bankId] = SOUND_LOAD_STATUS_COMPLETE;
return ret;
}
struct AudioBank *bank_load_async(s32 bankId, s32 arg1, struct SequencePlayer *seqPlayer) {
u32 numInstruments, numDrums;
UNUSED u32 pad1[2];
u32 buf[4];
UNUSED u32 pad2;
s32 alloc;
struct AudioBank *ret;
u8 *ctlData;
OSMesgQueue *mesgQueue;
alloc = gAlCtlHeader->seqArray[bankId].len + 0xf;
alloc = ALIGN16(alloc);
alloc -= 0x10;
ctlData = gAlCtlHeader->seqArray[bankId].offset;
ret = alloc_bank_or_seq(&gBankLoadedPool, 1, alloc, arg1, bankId);
if (ret == NULL) {
return NULL;
}
audio_dma_copy_immediate((u32) ctlData, buf, 0x10);
numInstruments = buf[0];
numDrums = buf[1];
seqPlayer->loadingBankId = (u8) bankId;
seqPlayer->loadingBankNumInstruments = numInstruments;
seqPlayer->loadingBankNumDrums = numDrums;
seqPlayer->bankDmaCurrMemAddr = (u8 *) ret;
seqPlayer->loadingBank = ret;
seqPlayer->bankDmaCurrDevAddr = (u32)(ctlData + 0x10);
seqPlayer->bankDmaRemaining = alloc;
mesgQueue = &seqPlayer->bankDmaMesgQueue;
osCreateMesgQueue(mesgQueue, &seqPlayer->bankDmaMesg, 1);
seqPlayer->bankDmaMesg = NULL;
seqPlayer->bankDmaInProgress = TRUE;
audio_dma_partial_copy_async(&seqPlayer->bankDmaCurrDevAddr, &seqPlayer->bankDmaCurrMemAddr,
&seqPlayer->bankDmaRemaining, mesgQueue, &seqPlayer->bankDmaIoMesg);
gBankLoadStatus[bankId] = SOUND_LOAD_STATUS_IN_PROGRESS;
return ret;
}
void *sequence_dma_immediate(s32 seqId, s32 arg1) {
s32 seqLength;
void *ptr;
u8 *seqData;
seqLength = gSeqFileHeader->seqArray[seqId].len + 0xf;
seqLength = ALIGN16(seqLength);
seqData = gSeqFileHeader->seqArray[seqId].offset;
ptr = alloc_bank_or_seq(&gSeqLoadedPool, 1, seqLength, arg1, seqId);
if (ptr == NULL) {
return NULL;
}
audio_dma_copy_immediate((u32) seqData, ptr, seqLength);
gSeqLoadStatus[seqId] = SOUND_LOAD_STATUS_COMPLETE;
return ptr;
}
void *sequence_dma_async(s32 seqId, s32 arg1, struct SequencePlayer *seqPlayer) {
s32 seqLength;
void *ptr;
u8 *seqData;
OSMesgQueue *mesgQueue;
seqLength = gSeqFileHeader->seqArray[seqId].len + 0xf;
seqLength = ALIGN16(seqLength);
seqData = gSeqFileHeader->seqArray[seqId].offset;
ptr = alloc_bank_or_seq(&gSeqLoadedPool, 1, seqLength, arg1, seqId);
if (ptr == NULL) {
return NULL;
}
if (seqLength <= 0x40) {
// Immediately load short sequenece
audio_dma_copy_immediate((u32) seqData, ptr, seqLength);
gSeqLoadStatus[seqId] = SOUND_LOAD_STATUS_COMPLETE;
} else {
audio_dma_copy_immediate((u32) seqData, ptr, 0x40);
mesgQueue = &seqPlayer->seqDmaMesgQueue;
osCreateMesgQueue(mesgQueue, &seqPlayer->seqDmaMesg, 1);
seqPlayer->seqDmaMesg = NULL;
seqPlayer->seqDmaInProgress = TRUE;
audio_dma_copy_async((u32)(seqData + 0x40), (u8 *) ptr + 0x40, seqLength - 0x40, mesgQueue,
&seqPlayer->seqDmaIoMesg);
gSeqLoadStatus[seqId] = SOUND_LOAD_STATUS_IN_PROGRESS;
}
return ptr;
}
u8 get_missing_bank(u32 seqId, s32 *nonNullCount, s32 *nullCount) {
void *temp;
u32 bankId;
u16 offset;
u8 i;
u8 ret;
*nullCount = 0;
*nonNullCount = 0;
offset = ((u16 *) gAlBankSets)[seqId] + 1;
for (i = gAlBankSets[offset - 1], ret = 0; i != 0; i--) {
offset++;
bankId = gAlBankSets[offset - 1];
if (IS_BANK_LOAD_COMPLETE(bankId) == TRUE) {
temp = get_bank_or_seq(&gBankLoadedPool, 2, gAlBankSets[offset - 1]);
} else {
temp = NULL;
}
if (temp == NULL) {
(*nullCount)++;
ret = bankId;
} else {
(*nonNullCount)++;
}
}
return ret;
}
struct AudioBank *load_banks_immediate(s32 seqId, u8 *arg1) {
void *ret;
u32 bankId;
u16 offset;
u8 i;
offset = ((u16 *) gAlBankSets)[seqId] + 1;
for (i = gAlBankSets[offset - 1]; i != 0; i--) {
offset++;
bankId = gAlBankSets[offset - 1];
if (IS_BANK_LOAD_COMPLETE(bankId) == TRUE) {
ret = get_bank_or_seq(&gBankLoadedPool, 2, gAlBankSets[offset - 1]);
} else {
ret = NULL;
}
if (ret == NULL) {
ret = bank_load_immediate(bankId, 2);
}
}
*arg1 = bankId;
return ret;
}
void preload_sequence(u32 seqId, u8 preloadMask) {
void *sequenceData;
u8 temp;
if (seqId >= gSequenceCount) {
return;
}
gAudioLoadLock = AUDIO_LOCK_LOADING;
if (preloadMask & PRELOAD_BANKS) {
load_banks_immediate(seqId, &temp);
}
if (preloadMask & PRELOAD_SEQUENCE) {
// @bug should be IS_SEQ_LOAD_COMPLETE
if (IS_BANK_LOAD_COMPLETE(seqId) == TRUE) {
sequenceData = get_bank_or_seq(&gSeqLoadedPool, 2, seqId);
} else {
sequenceData = NULL;
}
if (sequenceData == NULL && sequence_dma_immediate(seqId, 2) == NULL) {
gAudioLoadLock = AUDIO_LOCK_NOT_LOADING;
return;
}
}
gAudioLoadLock = AUDIO_LOCK_NOT_LOADING;
}
void load_sequence_internal(u32 player, u32 seqId, s32 loadAsync);
void load_sequence(u32 player, u32 seqId, s32 loadAsync) {
if (!loadAsync) {
gAudioLoadLock = AUDIO_LOCK_LOADING;
}
load_sequence_internal(player, seqId, loadAsync);
if (!loadAsync) {
gAudioLoadLock = AUDIO_LOCK_NOT_LOADING;
}
}
void load_sequence_internal(u32 player, u32 seqId, s32 loadAsync) {
void *sequenceData;
struct SequencePlayer *seqPlayer = &gSequencePlayers[player];
UNUSED u32 padding[2];
if (seqId >= gSequenceCount) {
return;
}
sequence_player_disable(seqPlayer);
if (loadAsync) {
s32 numMissingBanks = 0;
s32 dummy = 0;
s32 bankId = get_missing_bank(seqId, &dummy, &numMissingBanks);
if (numMissingBanks == 1) {
if (bank_load_async(bankId, 2, seqPlayer) == NULL) {
return;
}
// @bug This should set the last bank (i.e. the first in the JSON)
// as default, not the missing one. This code path never gets
// taken, though -- all sequence loading is synchronous.
seqPlayer->anyBank[0] = bankId;
} else if (load_banks_immediate(seqId, &seqPlayer->anyBank[0]) == NULL) {
return;
}
} else if (load_banks_immediate(seqId, &seqPlayer->anyBank[0]) == NULL) {
return;
}
seqPlayer->seqId = seqId;
sequenceData = get_bank_or_seq(&gSeqLoadedPool, 2, seqId);
if (sequenceData == NULL) {
if (seqPlayer->seqDmaInProgress) {
return;
}
if (loadAsync) {
sequenceData = sequence_dma_async(seqId, 2, seqPlayer);
} else {
sequenceData = sequence_dma_immediate(seqId, 2);
}
if (sequenceData == NULL) {
return;
}
}
init_sequence_player(player);
seqPlayer->scriptState.depth = 0;
seqPlayer->delay = 0;
seqPlayer->enabled = TRUE;
seqPlayer->seqData = sequenceData;
seqPlayer->scriptState.pc = sequenceData;
}
void audio_init() {
UNUSED s8 pad[32];
u8 buf[0x10];
s32 i, j, k;
s32 lim1, lim2, lim3;
u32 size;
u64 *ptr64;
void *data;
UNUSED s32 pad2;
gAudioLoadLock = AUDIO_LOCK_UNINITIALIZED;
lim1 = gUnusedCount80333EE8;
for (i = 0; i < lim1; i++) {
gUnused80226E58[i] = 0;
gUnused80226E98[i] = 0;
}
lim2 = gAudioHeapSize;
for (i = 0; i <= lim2 / 8 - 1; i++) {
((u64 *) gAudioHeap)[i] = 0;
}
i = 0;
lim3 = ((u32) &gAudioGlobalsEndMarker - (u32) &gAudioGlobalsStartMarker) / 8;
ptr64 = &gAudioGlobalsStartMarker - 1;
for (k = lim3; k >= 0; k--) {
i++;
ptr64[i] = 0;
}
for (i = 0; i < NUMAIBUFFERS; i++) {
gAiBufferLengths[i] = 0x00a0;
}
gActiveAudioFrames = 0;
gAudioTaskIndex = 0;
gCurrAiBufferIndex = 0;
gSoundMode = 0;
gAudioTask = NULL;
gAudioTasks[0].task.t.data_size = 0;
gAudioTasks[1].task.t.data_size = 0;
osCreateMesgQueue(&gAudioDmaMesgQueue, &gAudioDmaMesg, 1);
osCreateMesgQueue(&gCurrAudioFrameDmaQueue, gCurrAudioFrameDmaMesgBufs,
ARRAY_COUNT(gCurrAudioFrameDmaMesgBufs));
gCurrAudioFrameDmaCount = 0;
gSampleDmaNumListItems = 0;
func_80316108(D_80333EF0);
for (i = 0; i < NUMAIBUFFERS; i++) {
gAiBuffers[i] = soundAlloc(&gSoundPool, 0xa00);
for (j = 0; j < 0x500; j++) {
gAiBuffers[i][j] = 0;
}
}
func_80316928(&D_80332190[0]);
// Load header for sequence data (assets/music_data.sbk.s)
gSeqFileHeader = (ALSeqFile *) buf;
data = gMusicData;
audio_dma_copy_immediate((u32) data, gSeqFileHeader, 0x10);
gSequenceCount = gSeqFileHeader->seqCount;
size = ALIGN16(gSequenceCount * sizeof(ALSeqData) + 4);
gSeqFileHeader = soundAlloc(&gSoundPool, size);
audio_dma_copy_immediate((u32) data, gSeqFileHeader, size);
alSeqFileNew(gSeqFileHeader, data);
// Load header for CTL (assets/sound_data.ctl.s, i.e. ADSR)
gAlCtlHeader = (ALSeqFile *) buf;
data = gSoundDataADSR;
audio_dma_copy_immediate((u32) data, gAlCtlHeader, 0x10);
size = gAlCtlHeader->seqCount * sizeof(ALSeqData) + 4;
size = ALIGN16(size);
gCtlEntries = soundAlloc(&gSoundPool, gAlCtlHeader->seqCount * sizeof(struct CtlEntry));
gAlCtlHeader = soundAlloc(&gSoundPool, size);
audio_dma_copy_immediate((u32) data, gAlCtlHeader, size);
alSeqFileNew(gAlCtlHeader, data);
// Load header for TBL (assets/sound_data.tbl.s, i.e. raw data)
gAlTbl = (ALSeqFile *) buf;
audio_dma_copy_immediate((u32) data, gAlTbl, 0x10);
size = gAlTbl->seqCount * sizeof(ALSeqData) + 4;
size = ALIGN16(size);
gAlTbl = soundAlloc(&gSoundPool, size);
audio_dma_copy_immediate((u32) gSoundDataRaw, gAlTbl, size);
alSeqFileNew(gAlTbl, gSoundDataRaw);
// Load bank sets for each sequence (assets/bank_sets.s)
gAlBankSets = soundAlloc(&gSoundPool, 0x100);
audio_dma_copy_immediate((u32) gBankSetsData, gAlBankSets, 0x100);
func_8031D4B8();
gAudioLoadLock = AUDIO_LOCK_NOT_LOADING;
}