#ifdef VERSION_SH #include #include "data.h" #include "external.h" #include "heap.h" #include "load.h" #include "seqplayer.h" #define ALIGN16(val) (((val) + 0xF) & ~0xF) struct SharedDma { /*0x0*/ u8 *buffer; // target, points to pre-allocated buffer /*0x4*/ uintptr_t source; // device address /*0x8*/ u16 sizeUnused; // set to bufSize, never read /*0xA*/ u16 bufSize; // size of buffer /*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 void port_eu_init(void); void patch_sound(struct AudioBankSound *sound, struct AudioBank *memBase, struct PatchStruct *patchInfo); void *func_802f3f08(s32 poolIdx, s32 idx, s32 numChunks, s32 arg3, OSMesgQueue *retQueue); struct Note *gNotes; UNUSED static u32 pad; struct SequencePlayer gSequencePlayers[SEQUENCE_PLAYERS]; struct SequenceChannel gSequenceChannels[SEQUENCE_CHANNELS]; struct SequenceChannelLayer gSequenceLayers[SEQUENCE_LAYERS]; struct SequenceChannel gSequenceChannelNone; struct AudioListItem gLayerFreeList; struct NotePool gNoteFreeLists; struct AudioBankSample *D_SH_8034EA88[0x80]; struct UnkStructSH8034EC88 D_SH_8034EC88[0x80]; s32 D_SH_8034F688; // index into D_SH_8034EA88 s32 D_SH_8034F68C; // index or size for D_SH_8034EC88 struct PendingDmaAudioBank { s8 inProgress; s8 timer; s8 medium; struct AudioBank *audioBank; uintptr_t devAddr; void *vAddr; u32 remaining; u32 transferSize; u32 encodedInfo; OSMesgQueue *retQueue; OSMesgQueue dmaRetQueue; OSMesg mesgs[1]; OSIoMesg ioMesg; }; struct PendingDmaAudioBank sPendingDmaAudioBanks[16]; OSMesgQueue gUnkQueue1; OSMesg gUnkMesgBufs1[0x10]; OSMesgQueue gUnkQueue2; OSMesg gUnkMesgBufs2[0x10]; 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; 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; struct CtlEntry *gCtlEntries; struct AudioBufferParametersEU gAudioBufferParameters; u32 sDmaBufSize; s32 gMaxAudioCmds; s32 gMaxSimultaneousNotes; s16 gTempoInternalToExternal; s8 gSoundMode; s8 gAudioUpdatesPerFrame; extern u64 gAudioGlobalsStartMarker; extern u64 gAudioGlobalsEndMarker; extern u8 gSoundDataADSR[]; // ctl extern u8 gSoundDataRaw[]; // tbl extern u8 gMusicData[]; // sequences ALSeqFile *get_audio_file_header(s32 arg0); void *func_sh_802f3688(s32 bankId); void *get_bank_or_seq_wrapper(s32 arg0, s32 arg1); void func_sh_802f3d78(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3); void func_sh_802f3c38(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 medium); s32 func_sh_802f3dd0( OSIoMesg *m, s32 pri, s32 direction, uintptr_t devAddr, void *dramAddr, s32 size, OSMesgQueue *retQueue, s32 medium, UNUSED const char *reason); void func_sh_802f4a4c(s32 audioResetStatus); void func_sh_802f4bd8(struct PendingDmaSample *arg0, s32 len); void func_sh_802f4c5c(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3); struct PendingDmaAudioBank *func_sh_802f4cb4( uintptr_t devAddr, void *vAddr, s32 size, s32 medium, s32 numChunks, OSMesgQueue *retQueue, s32 encodedInfo); void func_sh_802f4dcc(s32 audioResetStatus); void func_sh_802f4e50(struct PendingDmaAudioBank *audioBank, s32 audioResetStatus); void func_sh_802f50ec(struct PendingDmaAudioBank *arg0, size_t len); void func_sh_802f517c(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3); BAD_RETURN (s32) func_sh_802f5310(s32 bankId, struct AudioBank *mem, struct PatchStruct *patchInfo, s32 arg3); s32 func_sh_802f573c(s32 audioResetStatus); void *func_sh_802f3564(s32 seqId); s32 func_sh_802f3ec4(s32 arg0, uintptr_t *arg1); void func_sh_802f3ed4(UNUSED s32 arg0, UNUSED s32 arg1, UNUSED void *vAddr, UNUSED size_t nbytes); s32 canonicalize_index(s32 poolIdx, s32 idx); 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; } extern char shindouDebugPrint62[]; // "SUPERDMA" void *dma_sample_data(uintptr_t devAddr, u32 size, s32 arg2, u8 *dmaIndexRef, s32 medium) { UNUSED s32 sp60; struct SharedDma *dma; s32 hasDma = FALSE; uintptr_t dmaDevAddr; UNUSED u32 pad; u32 dmaIndex; u32 transfer; ssize_t bufferPos; u32 i; if (arg2 != 0 || *dmaIndexRef >= sSampleDmaListSize1) { for (i = sSampleDmaListSize1; i < gSampleDmaNumListItems; i++) { dma = &sSampleDmas[i]; bufferPos = devAddr - dma->source; if (0 <= bufferPos && (size_t)bufferPos <= dma->bufSize - size) { // We already have a DMA request for this memory range. if (dma->ttl == 0 && sSampleDmaReuseQueueTail2 != sSampleDmaReuseQueueHead2) { // 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; *dmaIndexRef = (u8)i; return &dma->buffer[(devAddr - dma->source)]; } } if (sSampleDmaReuseQueueTail2 != sSampleDmaReuseQueueHead2 && arg2 != 0) { // Allocate a DMA from reuse queue 2. This queue can be empty, since // TTL 60 is pretty large. dmaIndex = sSampleDmaReuseQueue2[sSampleDmaReuseQueueTail2]; sSampleDmaReuseQueueTail2++; dma = sSampleDmas + dmaIndex; hasDma = TRUE; } } else { dma = sSampleDmas + *dmaIndexRef; bufferPos = devAddr - dma->source; if (0 <= bufferPos && (size_t)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++; } dma->ttl = 2; return dma->buffer + (devAddr - dma->source); } } if (!hasDma) { if (1) { } // 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 = TRUE; } transfer = dma->bufSize; dmaDevAddr = devAddr & ~0xF; dma->ttl = 2; dma->source = dmaDevAddr; dma->sizeUnused = transfer; func_sh_802f3dd0(&gCurrAudioFrameDmaIoMesgBufs[gCurrAudioFrameDmaCount++], OS_MESG_PRI_NORMAL, OS_READ, dmaDevAddr, dma->buffer, transfer, &gCurrAudioFrameDmaQueue, medium, shindouDebugPrint62); *dmaIndexRef = dmaIndex; return (devAddr - dmaDevAddr) + dma->buffer; } void init_sample_dma_buffers(UNUSED s32 arg0) { s32 i; sDmaBufSize = 0x2D0; sSampleDmas = sound_alloc_uninitialized(&gNotesAndBuffersPool, gMaxSimultaneousNotes * 4 * sizeof(struct SharedDma) * gAudioBufferParameters.presetUnk4); for (i = 0; i < gMaxSimultaneousNotes * 3 * gAudioBufferParameters.presetUnk4; i++) { if ((sSampleDmas[gSampleDmaNumListItems].buffer = sound_alloc_uninitialized(&gNotesAndBuffersPool, sDmaBufSize)) == nullptr) { break; } sSampleDmas[gSampleDmaNumListItems].bufSize = sDmaBufSize; sSampleDmas[gSampleDmaNumListItems].source = 0; sSampleDmas[gSampleDmaNumListItems].sizeUnused = 0; sSampleDmas[gSampleDmaNumListItems].unused2 = 0; sSampleDmas[gSampleDmaNumListItems].ttl = 0; gSampleDmaNumListItems++; } for (i = 0; (u32)i < gSampleDmaNumListItems; i++) { sSampleDmaReuseQueue1[i] = (u8)i; sSampleDmas[i].reuseIndex = (u8)i; } for (i = gSampleDmaNumListItems; i < 0x100; i++) { sSampleDmaReuseQueue1[i] = 0; } sSampleDmaReuseQueueTail1 = 0; sSampleDmaReuseQueueHead1 = (u8)gSampleDmaNumListItems; sSampleDmaListSize1 = gSampleDmaNumListItems; sDmaBufSize = 0x2D0; for (i = 0; i < gMaxSimultaneousNotes; i++) { if ((sSampleDmas[gSampleDmaNumListItems].buffer = sound_alloc_uninitialized(&gNotesAndBuffersPool, sDmaBufSize)) == nullptr) { break; } sSampleDmas[gSampleDmaNumListItems].bufSize = sDmaBufSize; sSampleDmas[gSampleDmaNumListItems].source = 0; sSampleDmas[gSampleDmaNumListItems].sizeUnused = 0; sSampleDmas[gSampleDmaNumListItems].unused2 = 0; sSampleDmas[gSampleDmaNumListItems].ttl = 0; gSampleDmaNumListItems++; } 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 (i = gSampleDmaNumListItems; i < 0x100; i++) { sSampleDmaReuseQueue2[i] = sSampleDmaListSize1; } sSampleDmaReuseQueueTail2 = 0; sSampleDmaReuseQueueHead2 = gSampleDmaNumListItems - sSampleDmaListSize1; } void patch_seq_file(ALSeqFile *seqFile, u8 *data, u16 arg2) { s32 i; seqFile->unk2 = arg2; seqFile->data = data; for (i = 0; i < seqFile->seqCount; i++) { if (seqFile->seqArray[i].len != 0 && seqFile->seqArray[i].medium == 2) { seqFile->seqArray[i].offset += (uintptr_t)data; } } } struct AudioBank *load_banks_immediate(s32 seqId, s32 *outDefaultBank) { u8 bank; s32 offset; s32 i; void *ret; offset = ((u16 *)gAlBankSets)[canonicalize_index(0, seqId)]; bank = 0xFF; for (i = gAlBankSets[offset++]; i > 0; i--) { bank = gAlBankSets[offset++]; ret = func_sh_802f3688(bank); } *outDefaultBank = bank; return ret; } void preload_sequence(u32 seqId, s32 preloadMask) { UNUSED s32 pad; s32 temp; seqId = canonicalize_index(0, seqId); if (preloadMask & PRELOAD_BANKS) { load_banks_immediate(seqId, &temp); } if (preloadMask & PRELOAD_SEQUENCE) { func_sh_802f3564(seqId); } } s32 func_sh_802f2f38(struct AudioBankSample *sample, s32 bankId) { u8 *sp24; if (sample->isPatched == TRUE && sample->medium != 0) { sp24 = func_sh_802f1d90(sample->size, bankId, sample->sampleAddr, sample->medium); if (sp24 == nullptr) { return -1; } if (sample->medium == 1) { func_sh_802f3d78((uintptr_t)sample->sampleAddr, sp24, sample->size, gAlTbl->unk2); } else { func_sh_802f3c38((uintptr_t)sample->sampleAddr, sp24, sample->size, sample->medium); } sample->medium = 0; sample->sampleAddr = sp24; } #ifdef AVOID_UB return 0; #endif } s32 func_sh_802f3024(s32 bankId, s32 instId, s32 arg2) { struct Instrument *instr; struct Drum *drum; if (instId < 0x7F) { instr = get_instrument_inner(bankId, instId); if (instr == nullptr) { return -1; } if (instr->normalRangeLo != 0) { func_sh_802f2f38(instr->lowNotesSound.sample, bankId); } func_sh_802f2f38(instr->normalNotesSound.sample, bankId); if (instr->normalRangeHi != 0x7F) { func_sh_802f2f38(instr->highNotesSound.sample, bankId); } //! @bug missing return } else if (instId == 0x7F) { drum = get_drum(bankId, arg2); if (drum == nullptr) { return -1; } func_sh_802f2f38(drum->sound.sample, bankId); return 0; } #ifdef AVOID_UB return 0; #endif } void func_sh_802f30f4(s32 arg0, s32 arg1, s32 arg2, OSMesgQueue *arg3) { if (func_802f3f08(2, canonicalize_index(2, arg0), arg1, arg2, arg3) == 0) { osSendMesg(arg3, 0, 0); } } void func_sh_802f3158(s32 seqId, s32 numChunks, s32 arg2, OSMesgQueue *retQueue) { s32 val; s32 v; val = ((u16 *)gAlBankSets)[canonicalize_index(0, seqId)]; v = gAlBankSets[val++]; while (v > 0) { func_802f3f08(1, canonicalize_index(1, gAlBankSets[val++]), numChunks, arg2, retQueue); v--; } } u8 *func_sh_802f3220(u32 seqId, u32 *a1) { s32 val; val = ((u16 *)gAlBankSets)[canonicalize_index(0, seqId)]; *a1 = gAlBankSets[val++]; if (*a1 == 0) { return nullptr; } return &gAlBankSets[val]; } void func_sh_802f3288(s32 idx) { s32 bankId; s32 s2; idx = ((u16 *)gAlBankSets)[canonicalize_index(0, idx)]; s2 = gAlBankSets[idx++]; while (s2 > 0) { s2--; bankId = canonicalize_index(1, gAlBankSets[idx++]); if (unk_pool1_lookup(1, bankId) == nullptr) { func_sh_802f3368(bankId); if (gBankLoadStatus[bankId] != SOUND_LOAD_STATUS_5) { gBankLoadStatus[bankId] = SOUND_LOAD_STATUS_NOT_LOADED; } continue; } } } BAD_RETURN (s32) func_sh_802f3368(s32 bankId) { struct SoundMultiPool *pool = &gBankLoadedPool; struct TemporaryPool *temporary = &pool->temporary; struct PersistentPool *persistent; u32 i; if (temporary->entries[0].id == bankId) { temporary->entries[0].id = -1; } else if (temporary->entries[1].id == bankId) { temporary->entries[1].id = -1; } persistent = &pool->persistent; for (i = 0; i < persistent->numEntries; i++) { if (persistent->entries[i].id == bankId) { persistent->entries[i].id = -1; } } discard_bank(bankId); } void load_sequence_internal(s32 player, s32 seqId, s32 loadAsync); void load_sequence(u32 player, u32 seqId, s32 loadAsync) { load_sequence_internal(player, seqId, loadAsync); } void load_sequence_internal(s32 player, s32 seqId, UNUSED s32 loadAsync) { struct SequencePlayer *seqPlayer; u8 *sequenceData; u32 s0; s32 count; u8 bank; s32 i; seqPlayer = &gSequencePlayers[player]; seqId = canonicalize_index(0, seqId); sequence_player_disable(seqPlayer); s0 = ((u16 *)gAlBankSets)[seqId]; count = gAlBankSets[s0++]; bank = 0xff; while (count > 0) { bank = gAlBankSets[s0++]; func_sh_802f3688(bank); count--; } sequenceData = func_sh_802f3564(seqId); init_sequence_player(player); seqPlayer->seqId = seqId; seqPlayer->defaultBank[0] = bank; seqPlayer->enabled = 1; seqPlayer->seqData = sequenceData; seqPlayer->scriptState.pc = sequenceData; seqPlayer->scriptState.depth = 0; seqPlayer->delay = 0; seqPlayer->finished = 0; for (i = 0; i < 0x10; i++) { } } void *func_sh_802f3564(s32 seqId) { s32 seqId2 = canonicalize_index(0, seqId); s32 temp; return func_sh_802f3764(0, seqId2, &temp); } extern u8 gUnkLoadStatus[0x40]; void *func_sh_802f3598(s32 idx, s32 *medium) { void *ret; ALSeqFile *f; s32 temp; s32 sp28; f = get_audio_file_header(2); idx = canonicalize_index(2, idx); ret = get_bank_or_seq_wrapper(2, idx); if (ret != nullptr) { if (gUnkLoadStatus[idx] != SOUND_LOAD_STATUS_5) { gUnkLoadStatus[idx] = SOUND_LOAD_STATUS_COMPLETE; } *medium = 0; return ret; } temp = f->seqArray[idx].magic; if (temp == 4) { *medium = f->seqArray[idx].medium; return f->seqArray[idx].offset; } else { ret = func_sh_802f3764(2, idx, &sp28); if (ret != 0) { *medium = 0; return ret; } *medium = f->seqArray[idx].medium; } return f->seqArray[idx].offset; } void *func_sh_802f3688(s32 bankId) { void *ret; s32 bankId1; s32 bankId2; s32 sp38; struct PatchStruct patchInfo; bankId = canonicalize_index(1, bankId); bankId1 = gCtlEntries[bankId].bankId1; bankId2 = gCtlEntries[bankId].bankId2; patchInfo.bankId1 = bankId1; patchInfo.bankId2 = bankId2; if (patchInfo.bankId1 != 0xFF) { patchInfo.baseAddr1 = func_sh_802f3598(patchInfo.bankId1, &patchInfo.medium1); } else { patchInfo.baseAddr1 = nullptr; } if (bankId2 != 0xFF) { patchInfo.baseAddr2 = func_sh_802f3598(bankId2, &patchInfo.medium2); } else { patchInfo.baseAddr2 = nullptr; } if ((ret = func_sh_802f3764(1, bankId, &sp38)) == nullptr) { return nullptr; } if (sp38 == 1) { func_sh_802f5310(bankId, ret, &patchInfo, 0); } return ret; } void *func_sh_802f3764(s32 poolIdx, s32 idx, s32 *arg2) { s32 size; ALSeqFile *f; void *vAddr; s32 medium; UNUSED u32 pad2; u8 *devAddr; s8 loadStatus; s32 sp18; vAddr = get_bank_or_seq_wrapper(poolIdx, idx); if (vAddr != nullptr) { *arg2 = 0; loadStatus = SOUND_LOAD_STATUS_COMPLETE; } else { f = get_audio_file_header(poolIdx); size = f->seqArray[idx].len; size = ALIGN16(size); medium = f->seqArray[idx].medium; sp18 = f->seqArray[idx].magic; devAddr = f->seqArray[idx].offset; switch (sp18) { case 0: vAddr = unk_pool1_alloc(poolIdx, idx, size); if (vAddr == nullptr) { return vAddr; } break; case 1: vAddr = alloc_bank_or_seq(poolIdx, size, 1, idx); if (vAddr == nullptr) { return vAddr; } break; case 2: vAddr = alloc_bank_or_seq(poolIdx, size, 0, idx); if (vAddr == nullptr) { return vAddr; } break; case 3: case 4: vAddr = alloc_bank_or_seq(poolIdx, size, 2, idx); if (vAddr == nullptr) { return vAddr; } break; } *arg2 = 1; if (medium == 1) { func_sh_802f3d78((uintptr_t)devAddr, vAddr, size, f->unk2); } else { func_sh_802f3c38((uintptr_t)devAddr, vAddr, size, medium); } switch (sp18) { case 0: loadStatus = SOUND_LOAD_STATUS_5; break; default: loadStatus = SOUND_LOAD_STATUS_COMPLETE; break; } } switch (poolIdx) { case 0: if (gSeqLoadStatus[idx] != SOUND_LOAD_STATUS_5) { gSeqLoadStatus[idx] = loadStatus; } break; case 1: if (gBankLoadStatus[idx] != SOUND_LOAD_STATUS_5) { gBankLoadStatus[idx] = loadStatus; } break; case 2: if (gUnkLoadStatus[idx] != SOUND_LOAD_STATUS_5) { gUnkLoadStatus[idx] = loadStatus; } break; } return vAddr; } s32 canonicalize_index(s32 poolIdx, s32 idx) { ALSeqFile *f; f = get_audio_file_header(poolIdx); if (f->seqArray[idx].len == 0) { idx = (s32)(uintptr_t) f->seqArray[idx].offset; } return idx; } void *get_bank_or_seq_wrapper(s32 poolIdx, s32 id) { void *ret; ret = unk_pool1_lookup(poolIdx, id); if (ret != nullptr) { return ret; } ret = get_bank_or_seq(poolIdx, 2, id); if (ret != 0) { return ret; } return nullptr; } ALSeqFile *get_audio_file_header(s32 poolIdx) { ALSeqFile *ret; switch (poolIdx) { default: ret = nullptr; break; case 0: ret = gSeqFileHeader; break; case 1: ret = gAlCtlHeader; break; case 2: ret = gAlTbl; break; } return ret; } void patch_audio_bank(s32 bankId, struct AudioBank *mem, struct PatchStruct *patchInfo) { struct Instrument *instrument; void **itInstrs; struct Instrument **end; s32 i; void *patched; struct Drum *drum; s32 numDrums; s32 numInstruments; #define BASE_OFFSET(x, base) (void *)((uintptr_t) (x) + (uintptr_t) base) #define PATCH(x, base) (patched = BASE_OFFSET(x, base)) #define PATCH_MEM(x) x = PATCH(x, mem) numDrums = gCtlEntries[bankId].numDrums; numInstruments = gCtlEntries[bankId].numInstruments; itInstrs = (void **)mem->drums; if (mem->drums) { } if (itInstrs != nullptr && numDrums != 0) { if (1) { mem->drums = PATCH(itInstrs, mem); } for (i = 0; i < numDrums; i++) { patched = mem->drums[i]; if (patched != nullptr) { drum = PATCH(patched, mem); mem->drums[i] = drum; if (drum->loaded == 0) { patch_sound(&drum->sound, mem, patchInfo); patched = drum->envelope; drum->envelope = BASE_OFFSET(patched, mem); drum->loaded = 1; } } } } if (numInstruments > 0) { itInstrs = (void **)mem->instruments; end = numInstruments + (struct Instrument **)itInstrs; do { if (*itInstrs != nullptr) { *itInstrs = BASE_OFFSET(*itInstrs, mem); instrument = *itInstrs; if (instrument->loaded == 0) { if (instrument->normalRangeLo != 0) { patch_sound(&instrument->lowNotesSound, mem, patchInfo); } patch_sound(&instrument->normalNotesSound, mem, patchInfo); if (instrument->normalRangeHi != 0x7F) { patch_sound(&instrument->highNotesSound, mem, patchInfo); } patched = instrument->envelope; instrument->envelope = BASE_OFFSET(patched, mem); instrument->loaded = 1; } } itInstrs = (void **)((struct Instrument **)itInstrs) + 1; } while ((struct Instrument **)itInstrs != ((void)0, end)); //! This is definitely fake } gCtlEntries[bankId].drums = mem->drums; gCtlEntries[bankId].instruments = mem->instruments; #undef PATCH_MEM #undef PATCH #undef BASE_OFFSET } extern char shindouDebugPrint81[]; // "FastCopy" extern char shindouDebugPrint82[]; // "FastCopy" void func_sh_802f3c38(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 medium) { nbytes = ALIGN16(nbytes); osInvalDCache(vAddr, nbytes); again: if (gAudioLoadLockSH != 0) { goto again; } if (nbytes >= 0x400U) { func_sh_802f3dd0(&gAudioDmaIoMesg, 1, 0, devAddr, vAddr, 0x400, &gAudioDmaMesgQueue, medium, shindouDebugPrint81); osRecvMesg(&gAudioDmaMesgQueue, nullptr, 1); nbytes = nbytes - 0x400; devAddr = devAddr + 0x400; vAddr = (u8 *)vAddr + 0x400; goto again; } if (nbytes != 0) { func_sh_802f3dd0(&gAudioDmaIoMesg, 1, 0, devAddr, vAddr, nbytes, &gAudioDmaMesgQueue, medium, shindouDebugPrint82); osRecvMesg(&gAudioDmaMesgQueue, nullptr, 1); } } void func_sh_802f3d78(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3) { uintptr_t sp1C; sp1C = devAddr; osInvalDCache(vAddr, nbytes); func_sh_802f3ed4(func_sh_802f3ec4(arg3, &sp1C), sp1C, vAddr, nbytes); } s32 func_sh_802f3dd0(OSIoMesg *m, s32 pri, s32 direction, uintptr_t devAddr, void *dramAddr, s32 size, OSMesgQueue *retQueue, s32 medium, UNUSED const char *reason) { OSPiHandle *handle; if (gAudioLoadLockSH >= 0x11U) { return -1; } switch (medium) { case 2: handle = osCartRomInit(); break; case 3: handle = osDriveRomInit(); break; default: return 0; } if ((size & 0xf) != 0) { size = ALIGN16(size); } m->hdr.pri = pri; m->hdr.retQueue = retQueue; m->dramAddr = dramAddr; m->devAddr = devAddr; m->size = size; handle->transferInfo.cmdType = 2; osEPiStartDma(handle, m, direction); return 0; } s32 func_sh_802f3ec4(UNUSED s32 arg0, UNUSED uintptr_t *arg1) { return 0; } void func_sh_802f3ed4(UNUSED s32 arg0, UNUSED s32 arg1, UNUSED void *vAddr, UNUSED size_t nbytes) { } void *func_sh_802f3ee8(s32 poolIdx, s32 idx) { s32 temp; return func_sh_802f3764(poolIdx, idx, &temp); } void *func_802f3f08(s32 poolIdx, s32 idx, s32 numChunks, s32 arg3, OSMesgQueue *retQueue) { s32 size; ALSeqFile *f; void *vAddr; s32 medium; s32 sp18; uintptr_t devAddr; s32 loadStatus; switch (poolIdx) { case 0: if (gSeqLoadStatus[idx] == SOUND_LOAD_STATUS_IN_PROGRESS) { return 0; } break; case 1: if (gBankLoadStatus[idx] == SOUND_LOAD_STATUS_IN_PROGRESS) { return 0; } break; case 2: if (gUnkLoadStatus[idx] == SOUND_LOAD_STATUS_IN_PROGRESS) { return 0; } break; } vAddr = get_bank_or_seq_wrapper(poolIdx, idx); if (vAddr != nullptr) { loadStatus = 2; osSendMesg(retQueue, (OSMesg)(arg3 << 0x18), 0); } else { f = get_audio_file_header(poolIdx); size = f->seqArray[idx].len; size = ALIGN16(size); medium = f->seqArray[idx].medium; sp18 = f->seqArray[idx].magic; devAddr = (uintptr_t)f->seqArray[idx].offset; loadStatus = 2; switch (sp18) { case 0: vAddr = unk_pool1_alloc(poolIdx, idx, size); if (vAddr == nullptr) { return vAddr; } loadStatus = SOUND_LOAD_STATUS_5; break; case 1: vAddr = alloc_bank_or_seq(poolIdx, size, 1, idx); if (vAddr == nullptr) { return vAddr; } break; case 2: vAddr = alloc_bank_or_seq(poolIdx, size, 0, idx); if (vAddr == nullptr) { return vAddr; } break; case 4: case 3: vAddr = alloc_bank_or_seq(poolIdx, size, 2, idx); if (vAddr == nullptr) { return vAddr; } break; } func_sh_802f4cb4(devAddr, vAddr, size, medium, numChunks, retQueue, (arg3 << 0x18) | (poolIdx << 0x10) | (idx << 8) | loadStatus); loadStatus = SOUND_LOAD_STATUS_IN_PROGRESS; } switch (poolIdx) { case 0: if (gSeqLoadStatus[idx] != SOUND_LOAD_STATUS_5) { gSeqLoadStatus[idx] = loadStatus; } break; case 1: if (gBankLoadStatus[idx] != SOUND_LOAD_STATUS_5) { gBankLoadStatus[idx] = loadStatus; } break; case 2: if (gUnkLoadStatus[idx] != SOUND_LOAD_STATUS_5) { gUnkLoadStatus[idx] = loadStatus; } break; } return vAddr; } void func_sh_802f41e4(s32 audioResetStatus) { func_sh_802f4a4c(audioResetStatus); func_sh_802f573c(audioResetStatus); func_sh_802f4dcc(audioResetStatus); } #if defined(VERSION_SH) u8 gShindouSoundBanksHeader[] = { #include "sound/ctl_header.inc.c" }; u8 gBankSetsData[] = { #include "sound/bank_sets.inc.c" }; u8 gShindouSampleBanksHeader[] = { #include "sound/tbl_header.inc.c" }; u8 gShindouSequencesHeader[] = { #include "sound/sequences_header.inc.c" }; #endif // (void) must be omitted from parameters void audio_init() { UNUSED s8 pad[0x34]; s32 i, j, k; s32 lim; u64 *ptr64; void *data; UNUSED u8 pad2[4]; s32 seqCount; gAudioLoadLockSH = 0; for (i = 0; i < gAudioHeapSize / 8; i++) { ((u64 *)gAudioHeap)[i] = 0; } #ifdef TARGET_N64 // It seems boot.s doesn't clear the .bss area for audio, so do it here. lim= ((uintptr_t)&gAudioGlobalsEndMarker- (uintptr_t) &gAudioGlobalsStartMarker) / 8; ptr64=&gAudioGlobalsStartMarker; for (k = lim; k>= 0; k--) { *ptr64++ = 0; } #endif D_EU_802298D0=16.713f; gRefreshRate=60; port_eu_init(); #ifdef TARGET_N64 eu_stubbed_printf_3 ("Clear Workarea %x -%x size %x \n", (uintptr_t) &gAudioGlobalsStartMarker, (uintptr_t) &gAudioGlobalsEndMarker, (uintptr_t) &gAudioGlobalsEndMarker- (uintptr_t) &gAudioGlobalsStartMarker ); #endif eu_stubbed_printf_1 ("AudioHeap is %x\n", gAudioHeapSize); for (i =0; iseqCount; patch_seq_file(gSeqFileHeader, gMusicData, D_SH_80315EF4); patch_seq_file(gAlCtlHeader, gSoundDataADSR, D_SH_80315EF8); patch_seq_file(gAlTbl, gSoundDataRaw, D_SH_80315EFC); seqCount= gAlCtlHeader->seqCount; gCtlEntries= sound_alloc_uninitialized(&gAudioInitPool, seqCount *sizeof(struct CtlEntry)); for (i =0; iseqArray[i].ctl.as_s16.bankAndFf >> 8) & 0xff); gCtlEntries[i].bankId2 = (u8) (gAlCtlHeader->seqArray[i].ctl.as_s16.bankAndFf & 0xff); gCtlEntries[i].numInstruments = (u8) ((gAlCtlHeader->seqArray[i].ctl.as_s16.numInstrumentsAndDrums >> 8) & 0xff); gCtlEntries[i].numDrums = (u8) (gAlCtlHeader->seqArray[i].ctl.as_s16.numInstrumentsAndDrums & 0xff); } data= sound_alloc_uninitialized(&gAudioInitPool, D_SH_80315EF0); if (data== nullptr) { D_SH_80315EF0 = 0; } sound_alloc_pool_init (&gUnkPool1.pool, data, D_SH_80315EF0); init_sequence_players(); } s32 func_sh_802f47c8(s32 bankId, u8 idx, s8 *io) { struct AudioBankSample *sample = func_sh_802f4978(bankId, idx); struct PendingDmaSample *temp; if (sample == nullptr) { *io = 0; return -1; } if (sample->medium == 0) { *io = 2; return 0; } temp = &D_SH_80343D00.arr[D_SH_80343D00.someIndex]; if (temp->state == 3) { temp->state = 0; } temp->sample = *sample; temp->io = io; temp->vAddr = func_sh_802f1d40(sample->size, bankId, sample->sampleAddr, sample->medium); if (temp->vAddr == nullptr) { if (sample->medium == 1 || sample->codec == CODEC_SKIP) { *io = 0; return -1; } else { *io = 3; return -1; } } temp->state = 1; temp->remaining = ALIGN16(sample->size); temp->resultSampleAddr = (u8 *)temp->vAddr; temp->devAddr = (uintptr_t)sample->sampleAddr; temp->medium = sample->medium; temp->bankId = bankId; temp->idx = idx; D_SH_80343D00.someIndex ^= 1; return 0; } struct AudioBankSample *func_sh_802f4978(s32 bankId, s32 idx) { struct Drum *drum; struct Instrument *inst; struct AudioBankSample *ret; if (idx < 128) { inst = get_instrument_inner(bankId, idx); if (inst == 0) { return nullptr; } ret = inst->normalNotesSound.sample; } else { drum = get_drum(bankId, idx - 128); if (drum == 0) { return nullptr; } ret = drum->sound.sample; } return ret; } void stub_sh_802f49dc(void) { } void func_sh_802f49e4(struct PendingDmaSample *arg0) { struct AudioBankSample *sample = func_sh_802f4978(arg0->bankId, arg0->idx); if (sample != nullptr) { arg0->sample = *sample; sample->sampleAddr = arg0->resultSampleAddr; sample->medium = 0; } } void func_sh_802f4a4c(s32 audioResetStatus) { ALSeqFile *alTbl; struct PendingDmaSample *entry; s32 i; alTbl = gAlTbl; for (i = 0; i < 2; i++) { entry = &D_SH_80343D00.arr[i]; switch (entry->state) { case 2: osRecvMesg(&entry->queue, nullptr, 1); if (audioResetStatus != 0) { entry->state = 3; break; } // fallthrough case 1: entry->state = 2; if (entry->remaining == 0) { func_sh_802f49e4(entry); entry->state = 3; *entry->io = 1; } else if (entry->remaining < 0x1000) { if (entry->medium == 1) { func_sh_802f4c5c(entry->devAddr, entry->vAddr, entry->remaining, alTbl->unk2); } else { func_sh_802f4bd8(entry, entry->remaining); } entry->remaining = 0; } else { if (entry->medium == 1) { func_sh_802f4c5c(entry->devAddr, entry->vAddr, 0x1000, alTbl->unk2); } else { func_sh_802f4bd8(entry, 0x1000); } entry->remaining = (s32)(entry->remaining - 0x1000); entry->vAddr = (u8 *)entry->vAddr + 0x1000; entry->devAddr = entry->devAddr + 0x1000; } break; } } } extern char shindouDebugPrint102[]; // "SLOWCOPY" void func_sh_802f4bd8(struct PendingDmaSample *arg0, s32 len) { // len must be signed osInvalDCache(arg0->vAddr, len); osCreateMesgQueue(&arg0->queue, arg0->mesgs, 1); func_sh_802f3dd0(&arg0->ioMesg, 0, 0, arg0->devAddr, arg0->vAddr, len, &arg0->queue, arg0->medium, shindouDebugPrint102); } void func_sh_802f4c5c(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3) { uintptr_t sp1C; sp1C = devAddr; osInvalDCache(vAddr, nbytes); func_sh_802f3ed4(func_sh_802f3ec4(arg3, &sp1C), sp1C, vAddr, nbytes); } struct PendingDmaAudioBank *func_sh_802f4cb4(uintptr_t devAddr, void *vAddr, s32 size, s32 medium, s32 numChunks, OSMesgQueue *retQueue, s32 encodedInfo) { struct PendingDmaAudioBank *item; s32 i; for (i = 0; i < ARRAY_COUNT(sPendingDmaAudioBanks); i++) { if (sPendingDmaAudioBanks[i].inProgress == 0) { item = &sPendingDmaAudioBanks[i]; break; } } if (i == ARRAY_COUNT(sPendingDmaAudioBanks)) { return nullptr; } item->inProgress = 1; item->devAddr = devAddr; item->audioBank = vAddr; item->vAddr = vAddr; item->remaining = size; if (numChunks == 0) { item->transferSize = 0x1000; } else { item->transferSize = ((size / numChunks) + 0xFF) & ~0xFF; if (item->transferSize < 0x100) { item->transferSize = 0x100; } } item->retQueue = retQueue; item->timer = 3; item->medium = medium; item->encodedInfo = encodedInfo; osCreateMesgQueue(&item->dmaRetQueue, item->mesgs, 1); return item; } void func_sh_802f4dcc(s32 audioResetStatus) { s32 i; if (gAudioLoadLockSH != 1) { for (i = 0; i < ARRAY_COUNT(sPendingDmaAudioBanks); i++) { if (sPendingDmaAudioBanks[i].inProgress == 1) { func_sh_802f4e50(&sPendingDmaAudioBanks[i], audioResetStatus); } } } } void func_sh_802f4e50(struct PendingDmaAudioBank *audioBank, s32 audioResetStatus) { ALSeqFile *alSeqFile; u32 *encodedInfo; OSMesg mesg; u32 temp; u32 bankId; s32 bankId1; s32 bankId2; struct PatchStruct patchStruct; alSeqFile = gAlTbl; if (audioBank->timer >= 2) { audioBank->timer--; return; } if (audioBank->timer == 1) { audioBank->timer = 0; } else { if (audioResetStatus != 0) { osRecvMesg(&audioBank->dmaRetQueue, nullptr, OS_MESG_BLOCK); audioBank->inProgress = 0; return; } if (osRecvMesg(&audioBank->dmaRetQueue, nullptr, OS_MESG_NOBLOCK) == -1) { return; } } encodedInfo = &audioBank->encodedInfo; if (audioBank->remaining == 0) { mesg = (OSMesg)audioBank->encodedInfo; #pragma GCC diagnostic push #if defined(__clang__) #pragma GCC diagnostic ignored "-Wself-assign" #endif mesg= mesg; //! needs an extra read from mesg here to match... #pragma GCC diagnostic pop temp=*encodedInfo; bankId= (temp>> 8) & 0xFF; switch ((u8) (temp>> 0x10)) { case 0: if (gSeqLoadStatus[bankId] != SOUND_LOAD_STATUS_5) { gSeqLoadStatus[bankId] = (u8) (temp & 0xFF); } break; case 2: if (gUnkLoadStatus[bankId] != SOUND_LOAD_STATUS_5) { gUnkLoadStatus[bankId] = (u8) (temp & 0xFF); } break; case 1: if (gBankLoadStatus[bankId] != SOUND_LOAD_STATUS_5) { gBankLoadStatus[bankId] = (u8) (temp & 0xFF); } bankId1 = gCtlEntries[bankId].bankId1; bankId2 = gCtlEntries[bankId].bankId2; patchStruct.bankId1 = bankId1; patchStruct.bankId2 = bankId2; if (bankId1 != 0xFF) { patchStruct.baseAddr1 = func_sh_802f3598(bankId1, &patchStruct.medium1); } else { patchStruct.baseAddr1 = nullptr; } if (bankId2 != 0xFF) { patchStruct.baseAddr2 = func_sh_802f3598(bankId2, &patchStruct.medium2); } else { patchStruct.baseAddr2 = nullptr; } func_sh_802f5310(bankId, audioBank->audioBank, &patchStruct, 1); break; } mesg= (OSMesg) audioBank->encodedInfo; audioBank->inProgress=0; osSendMesg (audioBank->retQueue, mesg, OS_MESG_NOBLOCK); } else if (audioBank->remainingtransferSize) { if (audioBank->medium == 1) { func_sh_802f517c(audioBank->devAddr, audioBank->vAddr, audioBank->remaining, alSeqFile->unk2); } else { func_sh_802f50ec(audioBank, audioBank->remaining); } audioBank->remaining = 0; } else { if (audioBank->medium == 1) { func_sh_802f517c(audioBank->devAddr, audioBank->vAddr, audioBank->transferSize, alSeqFile->unk2); } else { func_sh_802f50ec(audioBank, audioBank->transferSize); } audioBank->remaining -= audioBank->transferSize; audioBank->devAddr += audioBank->transferSize; audioBank->vAddr = ((u8 *) audioBank->vAddr) + audioBank->transferSize; } } extern char shindouDebugPrint110[]; // "BGCOPY" void func_sh_802f50ec(struct PendingDmaAudioBank *arg0, size_t len) { len += 0xf; len &= ~0xf; osInvalDCache(arg0->vAddr, len); osCreateMesgQueue(&arg0->dmaRetQueue, arg0->mesgs, 1); func_sh_802f3dd0(&arg0->ioMesg, 0, 0, arg0->devAddr, arg0->vAddr, len, &arg0->dmaRetQueue, arg0->medium, shindouDebugPrint110); } void func_sh_802f517c(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3) { uintptr_t sp1C; sp1C = devAddr; osInvalDCache(vAddr, nbytes); func_sh_802f3ed4(func_sh_802f3ec4(arg3, &sp1C), sp1C, vAddr, nbytes); } void patch_sound(struct AudioBankSound *sound, struct AudioBank *memBase, struct PatchStruct *patchInfo) { struct AudioBankSample *sample; void *patched; #define PATCH(x, base) (patched = (void *)((uintptr_t) (x) + (uintptr_t) base)) if ((uintptr_t)sound->sample <= 0x80000000) { sample = sound->sample = PATCH(sound->sample, memBase); if (sample->size != 0 && sample->isPatched != TRUE) { sample->loop = PATCH(sample->loop, memBase); sample->book = PATCH(sample->book, memBase); switch (sample->medium) { case 0: sample->sampleAddr = PATCH(sample->sampleAddr, patchInfo->baseAddr1); sample->medium = patchInfo->medium1; break; case 1: sample->sampleAddr = PATCH(sample->sampleAddr, patchInfo->baseAddr2); sample->medium = patchInfo->medium2; break; case 2: case 3: break; } sample->isPatched = TRUE; if (sample->bit1 && sample->medium != 0) { D_SH_8034EA88[D_SH_8034F688++] = sample; } } } #undef PATCH } BAD_RETURN (s32) func_sh_802f5310(s32 bankId, struct AudioBank *mem, struct PatchStruct *patchInfo, s32 arg3) { UNUSED u32 pad[2]; u8 * addr; UNUSED u32 pad1[3]; s32 sp4C; struct AudioBankSample *temp_s0; s32 i; uintptr_t count; s32 temp; sp4C = 0; if (D_SH_8034F68C != 0) { sp4C = 1; } else { D_SH_80343CF0 = 0; } D_SH_8034F688 = 0; patch_audio_bank(bankId, mem, patchInfo); count = 0; for (i = 0; i < D_SH_8034F688; i++) { count += ALIGN16(D_SH_8034EA88[i]->size); } for (i = 0; i < D_SH_8034F688; i++) { if (D_SH_8034F68C != 0x78) { temp_s0 = D_SH_8034EA88[i]; switch (arg3) { case 0: temp = temp_s0->medium = patchInfo->medium1; if (temp != 0) { if (temp_s0->size) { } addr = func_sh_802f1d90(temp_s0->size, patchInfo->bankId1, temp_s0->sampleAddr, temp_s0->medium); } else { temp = temp_s0->medium = patchInfo->medium2; if (temp != 0) { addr = func_sh_802f1d90(temp_s0->size, patchInfo->bankId2, temp_s0->sampleAddr, temp_s0->medium); } } break; case 1: temp = temp_s0->medium = patchInfo->medium1; if (temp != 0) { addr = func_sh_802f1d40(temp_s0->size, patchInfo->bankId1, temp_s0->sampleAddr, temp_s0->medium); } else { temp = temp_s0->medium = patchInfo->medium2; if (temp != 0) { addr = func_sh_802f1d40(temp_s0->size, patchInfo->bankId2, temp_s0->sampleAddr, temp_s0->medium); } } break; } switch ((uintptr_t)addr) { case 0: break; default: switch (arg3) { case 0: if (temp_s0->medium == 1) { func_sh_802f3d78((uintptr_t)temp_s0->sampleAddr, addr, temp_s0->size, gAlTbl->unk2); temp_s0->sampleAddr = addr; temp_s0->medium = 0; } else { func_sh_802f3c38((uintptr_t)temp_s0->sampleAddr, addr, temp_s0->size, temp_s0->medium); temp_s0->sampleAddr = addr; temp_s0->medium = 0; } break; case 1: D_SH_8034EC88[D_SH_8034F68C].sample = temp_s0; D_SH_8034EC88[D_SH_8034F68C].ramAddr = addr; D_SH_8034EC88[D_SH_8034F68C].encodedInfo = (D_SH_8034F68C << 24) | 0xffffff; D_SH_8034EC88[D_SH_8034F68C].isFree = FALSE; D_SH_8034EC88[D_SH_8034F68C].endAndMediumIdentification = temp_s0->sampleAddr + temp_s0->size + temp_s0->medium; D_SH_8034F68C++; break; } } continue; } break; } D_SH_8034F688 = 0; if (D_SH_8034F68C != 0 && sp4C == 0) { temp_s0 = D_SH_8034EC88[D_SH_8034F68C - 1].sample; temp = (temp_s0->size >> 12); temp += 1; count = (uintptr_t)temp_s0->sampleAddr; func_sh_802f4cb4( count, D_SH_8034EC88[D_SH_8034F68C - 1].ramAddr, temp_s0->size, temp_s0->medium, temp, &gUnkQueue2, D_SH_8034EC88[D_SH_8034F68C - 1].encodedInfo); } } s32 func_sh_802f573c(s32 audioResetStatus) { struct AudioBankSample *sample; u32 idx; u8 * sampleAddr; u32 size; s32 unk; u8 * added; if (D_SH_8034F68C > 0) { if (audioResetStatus != 0) { if (osRecvMesg(&gUnkQueue2, (OSMesg *)&idx, OS_MESG_NOBLOCK)) { } D_SH_8034F68C = 0; return 0; } if (osRecvMesg(&gUnkQueue2, (OSMesg *)&idx, OS_MESG_NOBLOCK) == -1) { return 0; } idx >>= 0x18; if (D_SH_8034EC88[idx].isFree == FALSE) { sample = D_SH_8034EC88[idx].sample; added = (sample->sampleAddr + sample->size + sample->medium); if (added == D_SH_8034EC88[idx].endAndMediumIdentification) { sample->sampleAddr = D_SH_8034EC88[idx].ramAddr; sample->medium = 0; } D_SH_8034EC88[idx].isFree = TRUE; } next: if (D_SH_8034F68C > 0) { if (D_SH_8034EC88[D_SH_8034F68C - 1].isFree == TRUE) { D_SH_8034F68C--; goto next; } sample = D_SH_8034EC88[D_SH_8034F68C - 1].sample; sampleAddr = sample->sampleAddr; size = sample->size; unk = size >> 0xC; unk += 1; added = ((sampleAddr + size) + sample->medium); if (added != D_SH_8034EC88[D_SH_8034F68C - 1].endAndMediumIdentification) { D_SH_8034EC88[D_SH_8034F68C - 1].isFree = TRUE; D_SH_8034F68C--; goto next; } size = sample->size; func_sh_802f4cb4((uintptr_t)sampleAddr, D_SH_8034EC88[D_SH_8034F68C - 1].ramAddr, size, sample->medium, unk, &gUnkQueue2, D_SH_8034EC88[D_SH_8034F68C - 1].encodedInfo); } } return 1; } s32 func_sh_802f5900(struct AudioBankSample *sample, s32 numLoaded, struct AudioBankSample *arg2[]) { s32 i; for (i = 0; i < numLoaded; i++) { if (sample->sampleAddr == arg2[i]->sampleAddr) { break; } } if (i == numLoaded) { arg2[numLoaded++] = sample; } return numLoaded; } s32 func_sh_802f5948(s32 bankId, struct AudioBankSample *list[]) { s32 i; struct Drum *drum; struct Instrument *inst; s32 numLoaded; s32 numDrums; s32 numInstruments; numLoaded = 0; numDrums = gCtlEntries[bankId].numDrums; numInstruments = gCtlEntries[bankId].numInstruments; for (i = 0; i < numDrums; i++) { drum = get_drum(bankId, i); if (drum == nullptr) { continue; } numLoaded = func_sh_802f5900(drum->sound.sample, numLoaded, list); } for (i = 0; i < numInstruments; i++) { inst = get_instrument_inner(bankId, i); if (inst == nullptr) { continue; } if (inst->normalRangeLo != 0) { numLoaded = func_sh_802f5900(inst->lowNotesSound.sample, numLoaded, list); } if (inst->normalRangeHi != 127) { numLoaded = func_sh_802f5900(inst->highNotesSound.sample, numLoaded, list); } numLoaded = func_sh_802f5900(inst->normalNotesSound.sample, numLoaded, list); } return numLoaded; } #endif