#include #include #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; }