2020-10-03 15:22:44 +00:00
|
|
|
#include "ultra64.h"
|
|
|
|
#include "global.h"
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-06-07 04:34:28 +00:00
|
|
|
void AudioHeap_InitSampleCaches(u32 persistentSampleCacheSize, u32 temporarySampleCacheSize);
|
2021-11-07 16:58:50 +00:00
|
|
|
SampleCacheEntry* AudioHeap_AllocTemporarySampleCacheEntry(u32 size);
|
|
|
|
SampleCacheEntry* AudioHeap_AllocPersistentSampleCacheEntry(u32 size);
|
|
|
|
void AudioHeap_DiscardSampleCacheEntry(SampleCacheEntry* entry);
|
2022-06-19 14:31:08 +00:00
|
|
|
void AudioHeap_UnapplySampleCache(SampleCacheEntry* entry, Sample* sample);
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_DiscardSampleCaches(void);
|
|
|
|
void AudioHeap_DiscardSampleBank(s32 sampleBankId);
|
|
|
|
void AudioHeap_DiscardSampleBanks(void);
|
|
|
|
|
2022-05-29 18:31:43 +00:00
|
|
|
/**
|
|
|
|
* Effectively scales `updatesPerFrameInv` by the reciprocal of `scaleInv`
|
|
|
|
* `updatesPerFrameInvScaled` is just `updatesPerFrameInv` scaled down by a factor of 256.0f
|
|
|
|
* i.e. (256.0f * `updatesPerFrameInvScaled`) is just `updatesPerFrameInv`
|
|
|
|
*/
|
|
|
|
f32 AudioHeap_CalculateAdsrDecay(f32 scaleInv) {
|
2022-10-07 17:43:17 +00:00
|
|
|
return (256.0f * gAudioCtx.audioBufferParameters.updatesPerFrameInvScaled) / scaleInv;
|
2022-05-29 18:31:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize the decay rate table used for decaying notes as part of adsr
|
|
|
|
*/
|
|
|
|
void AudioHeap_InitAdsrDecayTable(void) {
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.adsrDecayTable[255] = AudioHeap_CalculateAdsrDecay(0.25f);
|
|
|
|
gAudioCtx.adsrDecayTable[254] = AudioHeap_CalculateAdsrDecay(0.33f);
|
|
|
|
gAudioCtx.adsrDecayTable[253] = AudioHeap_CalculateAdsrDecay(0.5f);
|
|
|
|
gAudioCtx.adsrDecayTable[252] = AudioHeap_CalculateAdsrDecay(0.66f);
|
|
|
|
gAudioCtx.adsrDecayTable[251] = AudioHeap_CalculateAdsrDecay(0.75f);
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2020-09-20 17:22:09 +00:00
|
|
|
for (i = 128; i < 251; i++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.adsrDecayTable[i] = AudioHeap_CalculateAdsrDecay(251 - i);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2020-09-20 17:22:09 +00:00
|
|
|
for (i = 16; i < 128; i++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.adsrDecayTable[i] = AudioHeap_CalculateAdsrDecay(4 * (143 - i));
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2020-09-20 17:22:09 +00:00
|
|
|
for (i = 1; i < 16; i++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.adsrDecayTable[i] = AudioHeap_CalculateAdsrDecay(60 * (23 - i));
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.adsrDecayTable[0] = 0.0f;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_ResetLoadStatus(void) {
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2020-09-20 17:22:09 +00:00
|
|
|
for (i = 0; i < 0x30; i++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.fontLoadStatus[i] != LOAD_STATUS_PERMANENTLY_LOADED) {
|
|
|
|
gAudioCtx.fontLoadStatus[i] = LOAD_STATUS_NOT_LOADED;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2020-09-20 17:22:09 +00:00
|
|
|
for (i = 0; i < 0x30; i++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.sampleFontLoadStatus[i] != LOAD_STATUS_PERMANENTLY_LOADED) {
|
|
|
|
gAudioCtx.sampleFontLoadStatus[i] = LOAD_STATUS_NOT_LOADED;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2020-09-20 17:22:09 +00:00
|
|
|
for (i = 0; i < 0x80; i++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.seqLoadStatus[i] != LOAD_STATUS_PERMANENTLY_LOADED) {
|
|
|
|
gAudioCtx.seqLoadStatus[i] = LOAD_STATUS_NOT_LOADED;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_DiscardFont(s32 fontId) {
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.numNotes; i++) {
|
|
|
|
Note* note = &gAudioCtx.notes[i];
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
if (note->playbackState.fontId == fontId) {
|
2020-09-20 17:22:09 +00:00
|
|
|
if (note->playbackState.unk_04 == 0 && note->playbackState.priority != 0) {
|
|
|
|
note->playbackState.parentLayer->enabled = false;
|
|
|
|
note->playbackState.parentLayer->finished = true;
|
|
|
|
}
|
|
|
|
Audio_NoteDisable(note);
|
|
|
|
Audio_AudioListRemove(¬e->listItem);
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioSeq_AudioListPushBack(&gAudioCtx.noteFreeLists.disabled, ¬e->listItem);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_ReleaseNotesForFont(s32 fontId) {
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.numNotes; i++) {
|
|
|
|
Note* note = &gAudioCtx.notes[i];
|
2022-07-04 16:19:39 +00:00
|
|
|
NotePlaybackState* playbackState = ¬e->playbackState;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-07-04 16:19:39 +00:00
|
|
|
if (playbackState->fontId == fontId) {
|
|
|
|
if ((playbackState->priority != 0) && (playbackState->adsr.action.s.state == ADSR_STATE_DECAY)) {
|
|
|
|
playbackState->priority = 1;
|
2022-10-07 17:43:17 +00:00
|
|
|
playbackState->adsr.fadeOutVel = gAudioCtx.audioBufferParameters.updatesPerFrameInv;
|
2022-07-04 16:19:39 +00:00
|
|
|
playbackState->adsr.action.s.release = true;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_DiscardSequence(s32 seqId) {
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.audioBufferParameters.numSequencePlayers; i++) {
|
|
|
|
if (gAudioCtx.seqPlayers[i].enabled && gAudioCtx.seqPlayers[i].seqId == seqId) {
|
|
|
|
AudioSeq_SequencePlayerDisable(&gAudioCtx.seqPlayers[i]);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
/**
|
|
|
|
* Perform a writeback from the data cache to the ram.
|
|
|
|
*/
|
|
|
|
void AudioHeap_WritebackDCache(void* ramAddr, u32 size) {
|
|
|
|
Audio_WritebackDCache(ramAddr, size);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
/**
|
|
|
|
* Attempt to allocate space externally to the audio heap. If no external pool is available,
|
|
|
|
* then allocate space on the pool provided in the argument.
|
|
|
|
* The newly allocated space is zero'ed
|
|
|
|
*/
|
2021-11-07 16:58:50 +00:00
|
|
|
void* AudioHeap_AllocZeroedAttemptExternal(AudioAllocPool* pool, u32 size) {
|
2022-06-03 19:59:02 +00:00
|
|
|
void* ramAddr = NULL;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.externalPool.startRamAddr != NULL) {
|
|
|
|
ramAddr = AudioHeap_AllocZeroed(&gAudioCtx.externalPool, size);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
if (ramAddr == NULL) {
|
|
|
|
ramAddr = AudioHeap_AllocZeroed(pool, size);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
return ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void* AudioHeap_AllocAttemptExternal(AudioAllocPool* pool, u32 size) {
|
2022-06-03 19:59:02 +00:00
|
|
|
void* ramAddr = NULL;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.externalPool.startRamAddr != NULL) {
|
|
|
|
ramAddr = AudioHeap_Alloc(&gAudioCtx.externalPool, size);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
if (ramAddr == NULL) {
|
|
|
|
ramAddr = AudioHeap_Alloc(pool, size);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
return ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void* AudioHeap_AllocDmaMemory(AudioAllocPool* pool, u32 size) {
|
2022-06-03 19:59:02 +00:00
|
|
|
void* ramAddr = AudioHeap_Alloc(pool, size);
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (ramAddr != NULL) {
|
|
|
|
AudioHeap_WritebackDCache(ramAddr, size);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
return ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void* AudioHeap_AllocDmaMemoryZeroed(AudioAllocPool* pool, u32 size) {
|
2022-06-03 19:59:02 +00:00
|
|
|
void* ramAddr;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
ramAddr = AudioHeap_AllocZeroed(pool, size);
|
|
|
|
if (ramAddr != NULL) {
|
|
|
|
AudioHeap_WritebackDCache(ramAddr, size);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
return ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
/**
|
|
|
|
* Allocates space on a pool contained within the heap and sets all the allocated space to 0
|
|
|
|
*/
|
2021-11-07 16:58:50 +00:00
|
|
|
void* AudioHeap_AllocZeroed(AudioAllocPool* pool, u32 size) {
|
2022-06-03 19:59:02 +00:00
|
|
|
u8* ramAddr = AudioHeap_Alloc(pool, size);
|
2020-09-20 17:22:09 +00:00
|
|
|
u8* ptr;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (ramAddr != NULL) {
|
|
|
|
for (ptr = ramAddr; ptr < pool->curRamAddr; ptr++) {
|
2020-09-20 17:22:09 +00:00
|
|
|
*ptr = 0;
|
|
|
|
}
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
return ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void* AudioHeap_Alloc(AudioAllocPool* pool, u32 size) {
|
2020-09-20 17:22:09 +00:00
|
|
|
u32 aligned = ALIGN16(size);
|
2022-06-03 19:59:02 +00:00
|
|
|
u8* ramAddr = pool->curRamAddr;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (pool->startRamAddr + pool->size >= pool->curRamAddr + aligned) {
|
|
|
|
pool->curRamAddr += aligned;
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
pool->numEntries++;
|
|
|
|
return ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
/**
|
|
|
|
* Initialize a pool to allocate memory from the specified address, up to the specified size.
|
|
|
|
* Store the metadata of this pool in AudioAllocPool* pool
|
|
|
|
*/
|
2022-07-04 16:19:39 +00:00
|
|
|
void AudioHeap_InitPool(AudioAllocPool* pool, void* ramAddr, u32 size) {
|
2022-06-03 19:59:02 +00:00
|
|
|
pool->curRamAddr = pool->startRamAddr = (u8*)ALIGN16((u32)ramAddr);
|
|
|
|
pool->size = size - ((u32)ramAddr & 0xF);
|
|
|
|
pool->numEntries = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-07-04 16:19:39 +00:00
|
|
|
void AudioHeap_InitPersistentCache(AudioPersistentCache* persistent) {
|
2022-06-03 19:59:02 +00:00
|
|
|
persistent->pool.numEntries = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
persistent->numEntries = 0;
|
2022-06-03 19:59:02 +00:00
|
|
|
persistent->pool.curRamAddr = persistent->pool.startRamAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-07-04 16:19:39 +00:00
|
|
|
void AudioHeap_InitTemporaryCache(AudioTemporaryCache* temporary) {
|
2022-06-03 19:59:02 +00:00
|
|
|
temporary->pool.numEntries = 0;
|
|
|
|
temporary->pool.curRamAddr = temporary->pool.startRamAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
temporary->nextSide = 0;
|
2022-06-03 19:59:02 +00:00
|
|
|
temporary->entries[0].ramAddr = temporary->pool.startRamAddr;
|
|
|
|
temporary->entries[1].ramAddr = temporary->pool.startRamAddr + temporary->pool.size;
|
2020-09-20 17:22:09 +00:00
|
|
|
temporary->entries[0].id = -1;
|
|
|
|
temporary->entries[1].id = -1;
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_ResetPool(AudioAllocPool* pool) {
|
2022-06-03 19:59:02 +00:00
|
|
|
pool->numEntries = 0;
|
|
|
|
pool->curRamAddr = pool->startRamAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-07-04 16:19:39 +00:00
|
|
|
void AudioHeap_PopPersistentCache(s32 tableType) {
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioCache* loadedCache;
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioAllocPool* persistentPool;
|
|
|
|
AudioPersistentCache* persistent;
|
2022-06-03 19:59:02 +00:00
|
|
|
void* entryRamAddr;
|
|
|
|
u8* loadStatus;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
switch (tableType) {
|
|
|
|
case SEQUENCE_TABLE:
|
2022-10-07 17:43:17 +00:00
|
|
|
loadedCache = &gAudioCtx.seqCache;
|
|
|
|
loadStatus = gAudioCtx.seqLoadStatus;
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
case FONT_TABLE:
|
2022-10-07 17:43:17 +00:00
|
|
|
loadedCache = &gAudioCtx.fontCache;
|
|
|
|
loadStatus = gAudioCtx.fontLoadStatus;
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
case SAMPLE_TABLE:
|
2022-10-07 17:43:17 +00:00
|
|
|
loadedCache = &gAudioCtx.sampleBankCache;
|
|
|
|
loadStatus = gAudioCtx.sampleFontLoadStatus;
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
persistent = &loadedCache->persistent;
|
2020-09-20 17:22:09 +00:00
|
|
|
persistentPool = &persistent->pool;
|
|
|
|
|
|
|
|
if (persistent->numEntries == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
entryRamAddr = persistent->entries[persistent->numEntries - 1].ramAddr;
|
|
|
|
persistentPool->curRamAddr = entryRamAddr;
|
|
|
|
persistentPool->numEntries--;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
if (tableType == SAMPLE_TABLE) {
|
|
|
|
AudioHeap_DiscardSampleBank(persistent->entries[persistent->numEntries - 1].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2021-11-07 16:58:50 +00:00
|
|
|
if (tableType == FONT_TABLE) {
|
|
|
|
AudioHeap_DiscardFont(persistent->entries[persistent->numEntries - 1].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
|
|
|
|
loadStatus[persistent->entries[persistent->numEntries - 1].id] = LOAD_STATUS_NOT_LOADED;
|
2020-09-20 17:22:09 +00:00
|
|
|
persistent->numEntries--;
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_InitMainPools(s32 initPoolSize) {
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioHeap_InitPool(&gAudioCtx.initPool, gAudioCtx.audioHeap, initPoolSize);
|
|
|
|
AudioHeap_InitPool(&gAudioCtx.sessionPool, gAudioCtx.audioHeap + initPoolSize,
|
|
|
|
gAudioCtx.audioHeapSize - initPoolSize);
|
|
|
|
gAudioCtx.externalPool.startRamAddr = NULL;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-07-04 16:19:39 +00:00
|
|
|
void AudioHeap_InitSessionPools(AudioSessionPoolSplit* split) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.sessionPool.curRamAddr = gAudioCtx.sessionPool.startRamAddr;
|
|
|
|
AudioHeap_InitPool(&gAudioCtx.miscPool, AudioHeap_Alloc(&gAudioCtx.sessionPool, split->miscPoolSize),
|
2022-07-04 16:19:39 +00:00
|
|
|
split->miscPoolSize);
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioHeap_InitPool(&gAudioCtx.cachePool, AudioHeap_Alloc(&gAudioCtx.sessionPool, split->cachePoolSize),
|
2022-07-04 16:19:39 +00:00
|
|
|
split->cachePoolSize);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-07-04 16:19:39 +00:00
|
|
|
void AudioHeap_InitCachePools(AudioCachePoolSplit* split) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.cachePool.curRamAddr = gAudioCtx.cachePool.startRamAddr;
|
|
|
|
AudioHeap_InitPool(&gAudioCtx.persistentCommonPool,
|
|
|
|
AudioHeap_Alloc(&gAudioCtx.cachePool, split->persistentCommonPoolSize),
|
2022-07-04 16:19:39 +00:00
|
|
|
split->persistentCommonPoolSize);
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioHeap_InitPool(&gAudioCtx.temporaryCommonPool,
|
|
|
|
AudioHeap_Alloc(&gAudioCtx.cachePool, split->temporaryCommonPoolSize),
|
2022-07-04 16:19:39 +00:00
|
|
|
split->temporaryCommonPoolSize);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-07-04 16:19:39 +00:00
|
|
|
void AudioHeap_InitPersistentPoolsAndCaches(AudioCommonPoolSplit* split) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.persistentCommonPool.curRamAddr = gAudioCtx.persistentCommonPool.startRamAddr;
|
|
|
|
AudioHeap_InitPool(&gAudioCtx.seqCache.persistent.pool,
|
|
|
|
AudioHeap_Alloc(&gAudioCtx.persistentCommonPool, split->seqCacheSize), split->seqCacheSize);
|
|
|
|
AudioHeap_InitPool(&gAudioCtx.fontCache.persistent.pool,
|
|
|
|
AudioHeap_Alloc(&gAudioCtx.persistentCommonPool, split->fontCacheSize), split->fontCacheSize);
|
|
|
|
AudioHeap_InitPool(&gAudioCtx.sampleBankCache.persistent.pool,
|
|
|
|
AudioHeap_Alloc(&gAudioCtx.persistentCommonPool, split->sampleBankCacheSize),
|
2022-07-04 16:19:39 +00:00
|
|
|
split->sampleBankCacheSize);
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioHeap_InitPersistentCache(&gAudioCtx.seqCache.persistent);
|
|
|
|
AudioHeap_InitPersistentCache(&gAudioCtx.fontCache.persistent);
|
|
|
|
AudioHeap_InitPersistentCache(&gAudioCtx.sampleBankCache.persistent);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-07-04 16:19:39 +00:00
|
|
|
void AudioHeap_InitTemporaryPoolsAndCaches(AudioCommonPoolSplit* split) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.temporaryCommonPool.curRamAddr = gAudioCtx.temporaryCommonPool.startRamAddr;
|
|
|
|
AudioHeap_InitPool(&gAudioCtx.seqCache.temporary.pool,
|
|
|
|
AudioHeap_Alloc(&gAudioCtx.temporaryCommonPool, split->seqCacheSize), split->seqCacheSize);
|
|
|
|
AudioHeap_InitPool(&gAudioCtx.fontCache.temporary.pool,
|
|
|
|
AudioHeap_Alloc(&gAudioCtx.temporaryCommonPool, split->fontCacheSize), split->fontCacheSize);
|
|
|
|
AudioHeap_InitPool(&gAudioCtx.sampleBankCache.temporary.pool,
|
|
|
|
AudioHeap_Alloc(&gAudioCtx.temporaryCommonPool, split->sampleBankCacheSize),
|
2022-07-04 16:19:39 +00:00
|
|
|
split->sampleBankCacheSize);
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioHeap_InitTemporaryCache(&gAudioCtx.seqCache.temporary);
|
|
|
|
AudioHeap_InitTemporaryCache(&gAudioCtx.fontCache.temporary);
|
|
|
|
AudioHeap_InitTemporaryCache(&gAudioCtx.sampleBankCache.temporary);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id) {
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioCache* loadedCache;
|
|
|
|
AudioTemporaryCache* temporaryCache;
|
|
|
|
AudioAllocPool* temporaryPool;
|
|
|
|
void* persistentRamAddr;
|
|
|
|
void* temporaryRamAddr;
|
|
|
|
u8 loadStatusEntry0;
|
|
|
|
u8 loadStatusEntry1;
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
2022-06-03 19:59:02 +00:00
|
|
|
u8* loadStatus;
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 side;
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
switch (tableType) {
|
|
|
|
case SEQUENCE_TABLE:
|
2022-10-07 17:43:17 +00:00
|
|
|
loadedCache = &gAudioCtx.seqCache;
|
|
|
|
loadStatus = gAudioCtx.seqLoadStatus;
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
case FONT_TABLE:
|
2022-10-07 17:43:17 +00:00
|
|
|
loadedCache = &gAudioCtx.fontCache;
|
|
|
|
loadStatus = gAudioCtx.fontLoadStatus;
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
case SAMPLE_TABLE:
|
2022-10-07 17:43:17 +00:00
|
|
|
loadedCache = &gAudioCtx.sampleBankCache;
|
|
|
|
loadStatus = gAudioCtx.sampleFontLoadStatus;
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
if (cache == CACHE_TEMPORARY) {
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryCache = &loadedCache->temporary;
|
|
|
|
temporaryPool = &temporaryCache->pool;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (temporaryPool->size < size) {
|
2020-09-20 17:22:09 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
loadStatusEntry0 =
|
|
|
|
(temporaryCache->entries[0].id == -1) ? LOAD_STATUS_NOT_LOADED : loadStatus[temporaryCache->entries[0].id];
|
|
|
|
loadStatusEntry1 =
|
|
|
|
(temporaryCache->entries[1].id == -1) ? LOAD_STATUS_NOT_LOADED : loadStatus[temporaryCache->entries[1].id];
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
if (tableType == FONT_TABLE) {
|
2022-06-03 19:59:02 +00:00
|
|
|
if (loadStatusEntry0 == LOAD_STATUS_MAYBE_DISCARDABLE) {
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.numNotes; i++) {
|
|
|
|
if (gAudioCtx.notes[i].playbackState.fontId == temporaryCache->entries[0].id &&
|
|
|
|
gAudioCtx.notes[i].noteSubEu.bitField0.enabled) {
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
if (i == gAudioCtx.numNotes) {
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioLoad_SetFontLoadStatus(temporaryCache->entries[0].id, LOAD_STATUS_DISCARDABLE);
|
|
|
|
loadStatusEntry0 = LOAD_STATUS_DISCARDABLE;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (loadStatusEntry1 == LOAD_STATUS_MAYBE_DISCARDABLE) {
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.numNotes; i++) {
|
|
|
|
if (gAudioCtx.notes[i].playbackState.fontId == temporaryCache->entries[1].id &&
|
|
|
|
gAudioCtx.notes[i].noteSubEu.bitField0.enabled) {
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
if (i == gAudioCtx.numNotes) {
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioLoad_SetFontLoadStatus(temporaryCache->entries[1].id, LOAD_STATUS_DISCARDABLE);
|
|
|
|
loadStatusEntry1 = LOAD_STATUS_DISCARDABLE;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (loadStatusEntry0 == LOAD_STATUS_NOT_LOADED) {
|
|
|
|
temporaryCache->nextSide = 0;
|
|
|
|
} else if (loadStatusEntry1 == LOAD_STATUS_NOT_LOADED) {
|
|
|
|
temporaryCache->nextSide = 1;
|
|
|
|
} else if (loadStatusEntry0 == LOAD_STATUS_DISCARDABLE && loadStatusEntry1 == LOAD_STATUS_DISCARDABLE) {
|
2020-09-20 17:22:09 +00:00
|
|
|
// Use the opposite side from last time.
|
2022-06-03 19:59:02 +00:00
|
|
|
} else if (loadStatusEntry0 == LOAD_STATUS_DISCARDABLE) {
|
|
|
|
temporaryCache->nextSide = 0;
|
|
|
|
} else if (loadStatusEntry1 == LOAD_STATUS_DISCARDABLE) {
|
|
|
|
temporaryCache->nextSide = 1;
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
|
|
|
// Check if there is a side which isn't in active use, if so, evict that one.
|
2021-11-07 16:58:50 +00:00
|
|
|
if (tableType == SEQUENCE_TABLE) {
|
2022-06-03 19:59:02 +00:00
|
|
|
if (loadStatusEntry0 == LOAD_STATUS_COMPLETE) {
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.audioBufferParameters.numSequencePlayers; i++) {
|
|
|
|
if (gAudioCtx.seqPlayers[i].enabled &&
|
|
|
|
gAudioCtx.seqPlayers[i].seqId == temporaryCache->entries[0].id) {
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
if (i == gAudioCtx.audioBufferParameters.numSequencePlayers) {
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryCache->nextSide = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (loadStatusEntry1 == LOAD_STATUS_COMPLETE) {
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.audioBufferParameters.numSequencePlayers; i++) {
|
|
|
|
if (gAudioCtx.seqPlayers[i].enabled &&
|
|
|
|
gAudioCtx.seqPlayers[i].seqId == temporaryCache->entries[1].id) {
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
if (i == gAudioCtx.audioBufferParameters.numSequencePlayers) {
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryCache->nextSide = 1;
|
2020-09-20 17:22:09 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
2021-11-07 16:58:50 +00:00
|
|
|
} else if (tableType == FONT_TABLE) {
|
2022-06-03 19:59:02 +00:00
|
|
|
if (loadStatusEntry0 == LOAD_STATUS_COMPLETE) {
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.numNotes; i++) {
|
|
|
|
if (gAudioCtx.notes[i].playbackState.fontId == temporaryCache->entries[0].id &&
|
|
|
|
gAudioCtx.notes[i].noteSubEu.bitField0.enabled) {
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-10-07 17:43:17 +00:00
|
|
|
if (i == gAudioCtx.numNotes) {
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryCache->nextSide = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (loadStatusEntry1 == LOAD_STATUS_COMPLETE) {
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.numNotes; i++) {
|
|
|
|
if (gAudioCtx.notes[i].playbackState.fontId == temporaryCache->entries[1].id &&
|
|
|
|
gAudioCtx.notes[i].noteSubEu.bitField0.enabled) {
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-10-07 17:43:17 +00:00
|
|
|
if (i == gAudioCtx.numNotes) {
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryCache->nextSide = 1;
|
2020-09-20 17:22:09 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No such luck. Evict the side that wasn't chosen last time, except
|
|
|
|
// if it is being loaded into.
|
2022-06-03 19:59:02 +00:00
|
|
|
if (temporaryCache->nextSide == 0) {
|
|
|
|
if (loadStatusEntry0 == LOAD_STATUS_IN_PROGRESS) {
|
|
|
|
if (loadStatusEntry1 == LOAD_STATUS_IN_PROGRESS) {
|
2020-09-20 17:22:09 +00:00
|
|
|
goto fail;
|
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryCache->nextSide = 1;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
} else {
|
2022-06-03 19:59:02 +00:00
|
|
|
if (loadStatusEntry1 == LOAD_STATUS_IN_PROGRESS) {
|
|
|
|
if (loadStatusEntry0 == LOAD_STATUS_IN_PROGRESS) {
|
2020-09-20 17:22:09 +00:00
|
|
|
goto fail;
|
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryCache->nextSide = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0) {
|
|
|
|
fail:
|
|
|
|
// Both sides are being loaded into.
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
side = temporaryCache->nextSide;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (temporaryCache->entries[side].id != -1) {
|
2021-11-07 16:58:50 +00:00
|
|
|
if (tableType == SAMPLE_TABLE) {
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioHeap_DiscardSampleBank(temporaryCache->entries[side].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
|
|
|
|
loadStatus[temporaryCache->entries[side].id] = LOAD_STATUS_NOT_LOADED;
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
if (tableType == FONT_TABLE) {
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioHeap_DiscardFont(temporaryCache->entries[side].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (side) {
|
|
|
|
case 0:
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryCache->entries[0].ramAddr = temporaryPool->startRamAddr;
|
|
|
|
temporaryCache->entries[0].id = id;
|
|
|
|
temporaryCache->entries[0].size = size;
|
|
|
|
temporaryPool->curRamAddr = temporaryPool->startRamAddr + size;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (temporaryCache->entries[1].id != -1 &&
|
|
|
|
temporaryCache->entries[1].ramAddr < temporaryPool->curRamAddr) {
|
2021-11-07 16:58:50 +00:00
|
|
|
if (tableType == SAMPLE_TABLE) {
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioHeap_DiscardSampleBank(temporaryCache->entries[1].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
loadStatus[temporaryCache->entries[1].id] = LOAD_STATUS_NOT_LOADED;
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
switch (tableType) {
|
|
|
|
case SEQUENCE_TABLE:
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioHeap_DiscardSequence((s32)temporaryCache->entries[1].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
case FONT_TABLE:
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioHeap_DiscardFont((s32)temporaryCache->entries[1].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryCache->entries[1].id = -1;
|
|
|
|
temporaryCache->entries[1].ramAddr = temporaryPool->startRamAddr + temporaryPool->size;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryRamAddr = temporaryCache->entries[0].ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryCache->entries[1].ramAddr =
|
|
|
|
(u8*)((u32)(temporaryPool->startRamAddr + temporaryPool->size - size) & ~0xF);
|
|
|
|
temporaryCache->entries[1].id = id;
|
|
|
|
temporaryCache->entries[1].size = size;
|
|
|
|
if (temporaryCache->entries[0].id != -1 &&
|
|
|
|
temporaryCache->entries[1].ramAddr < temporaryPool->curRamAddr) {
|
2021-11-07 16:58:50 +00:00
|
|
|
if (tableType == SAMPLE_TABLE) {
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioHeap_DiscardSampleBank(temporaryCache->entries[0].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
loadStatus[temporaryCache->entries[0].id] = LOAD_STATUS_NOT_LOADED;
|
2021-11-07 16:58:50 +00:00
|
|
|
switch (tableType) {
|
|
|
|
case SEQUENCE_TABLE:
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioHeap_DiscardSequence(temporaryCache->entries[0].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
case FONT_TABLE:
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioHeap_DiscardFont(temporaryCache->entries[0].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryCache->entries[0].id = -1;
|
|
|
|
temporaryPool->curRamAddr = temporaryPool->startRamAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryRamAddr = temporaryCache->entries[1].ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
temporaryCache->nextSide ^= 1;
|
|
|
|
return temporaryRamAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
persistentRamAddr = AudioHeap_Alloc(&loadedCache->persistent.pool, size);
|
|
|
|
loadedCache->persistent.entries[loadedCache->persistent.numEntries].ramAddr = persistentRamAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (persistentRamAddr == NULL) {
|
2021-11-07 16:58:50 +00:00
|
|
|
switch (cache) {
|
|
|
|
case CACHE_EITHER:
|
|
|
|
return AudioHeap_AllocCached(tableType, size, CACHE_TEMPORARY, id);
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
case CACHE_TEMPORARY:
|
|
|
|
case CACHE_PERSISTENT:
|
2020-09-20 17:22:09 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
loadedCache->persistent.entries[loadedCache->persistent.numEntries].id = id;
|
|
|
|
loadedCache->persistent.entries[loadedCache->persistent.numEntries].size = size;
|
|
|
|
|
|
|
|
return loadedCache->persistent.entries[loadedCache->persistent.numEntries++].ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void* AudioHeap_SearchCaches(s32 tableType, s32 cache, s32 id) {
|
2022-06-03 19:59:02 +00:00
|
|
|
void* ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
// Always search the permanent cache in addition to the regular ones.
|
2022-06-03 19:59:02 +00:00
|
|
|
ramAddr = AudioHeap_SearchPermanentCache(tableType, id);
|
|
|
|
if (ramAddr != NULL) {
|
|
|
|
return ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2021-11-07 16:58:50 +00:00
|
|
|
if (cache == CACHE_PERMANENT) {
|
2020-09-20 17:22:09 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2021-11-07 16:58:50 +00:00
|
|
|
return AudioHeap_SearchRegularCaches(tableType, cache, id);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void* AudioHeap_SearchRegularCaches(s32 tableType, s32 cache, s32 id) {
|
2020-09-20 17:22:09 +00:00
|
|
|
u32 i;
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioCache* loadedCache;
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioTemporaryCache* temporary;
|
|
|
|
AudioPersistentCache* persistent;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
switch (tableType) {
|
|
|
|
case SEQUENCE_TABLE:
|
2022-10-07 17:43:17 +00:00
|
|
|
loadedCache = &gAudioCtx.seqCache;
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
case FONT_TABLE:
|
2022-10-07 17:43:17 +00:00
|
|
|
loadedCache = &gAudioCtx.fontCache;
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
case SAMPLE_TABLE:
|
2022-10-07 17:43:17 +00:00
|
|
|
loadedCache = &gAudioCtx.sampleBankCache;
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
temporary = &loadedCache->temporary;
|
2021-11-07 16:58:50 +00:00
|
|
|
if (cache == CACHE_TEMPORARY) {
|
|
|
|
if (temporary->entries[0].id == id) {
|
2020-09-20 17:22:09 +00:00
|
|
|
temporary->nextSide = 1;
|
2022-06-03 19:59:02 +00:00
|
|
|
return temporary->entries[0].ramAddr;
|
2021-11-07 16:58:50 +00:00
|
|
|
} else if (temporary->entries[1].id == id) {
|
2020-09-20 17:22:09 +00:00
|
|
|
temporary->nextSide = 0;
|
2022-06-03 19:59:02 +00:00
|
|
|
return temporary->entries[1].ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
persistent = &loadedCache->persistent;
|
2020-09-20 17:22:09 +00:00
|
|
|
for (i = 0; i < persistent->numEntries; i++) {
|
2021-11-07 16:58:50 +00:00
|
|
|
if (persistent->entries[i].id == id) {
|
2022-06-03 19:59:02 +00:00
|
|
|
return persistent->entries[i].ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
if (cache == CACHE_EITHER) {
|
|
|
|
return AudioHeap_SearchCaches(tableType, CACHE_TEMPORARY, id);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void func_800DF1D8(f32 p, f32 q, u16* out) {
|
|
|
|
// With the bug below fixed, this mysterious unused function computes two recurrences
|
|
|
|
// out[0..7] = a_i, out[8..15] = b_i, where
|
|
|
|
// a_{-2} = b_{-1} = 262159 = 2^18 + 15
|
|
|
|
// a_{-1} = b_{-2} = 0
|
|
|
|
// a_i = q * a_{i-1} + p * a_{i-2}
|
|
|
|
// b_i = q * b_{i-1} + p * b_{i-2}
|
|
|
|
// These grow exponentially if p < -1 or p + |q| > 1.
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
|
|
|
f32 tmp[16];
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
tmp[0] = (f32)(q * 262159.0f);
|
|
|
|
tmp[8] = (f32)(p * 262159.0f);
|
|
|
|
tmp[1] = (f32)((q * p) * 262159.0f);
|
|
|
|
tmp[9] = (f32)(((p * p) + q) * 262159.0f);
|
2020-09-20 17:22:09 +00:00
|
|
|
|
|
|
|
for (i = 2; i < 8; i++) {
|
2021-11-07 16:58:50 +00:00
|
|
|
//! @bug value should be stored to tmp[i] and tmp[8 + i], otherwise we read
|
|
|
|
//! garbage in later loop iterations.
|
|
|
|
out[i] = q * tmp[i - 2] + p * tmp[i - 1];
|
|
|
|
out[8 + i] = q * tmp[6 + i] + p * tmp[7 + i];
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++) {
|
2021-11-07 16:58:50 +00:00
|
|
|
out[i] = tmp[i];
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_ClearFilter(s16* filter) {
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++) {
|
2021-08-31 22:53:35 +00:00
|
|
|
filter[i] = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_LoadLowPassFilter(s16* filter, s32 cutoff) {
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
2022-06-03 19:59:02 +00:00
|
|
|
s16* ptr = &gLowPassFilterData[8 * cutoff];
|
2020-09-20 17:22:09 +00:00
|
|
|
|
|
|
|
for (i = 0; i < 8; i++) {
|
2021-08-31 22:53:35 +00:00
|
|
|
filter[i] = ptr[i];
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_LoadHighPassFilter(s16* filter, s32 cutoff) {
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
2022-06-03 19:59:02 +00:00
|
|
|
s16* ptr = &gHighPassFilterData[8 * (cutoff - 1)];
|
2020-09-20 17:22:09 +00:00
|
|
|
|
|
|
|
for (i = 0; i < 8; i++) {
|
2021-08-31 22:53:35 +00:00
|
|
|
filter[i] = ptr[i];
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_LoadFilter(s16* filter, s32 lowPassCutoff, s32 highPassCutoff) {
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
if (lowPassCutoff == 0 && highPassCutoff == 0) {
|
|
|
|
// Identity filter
|
|
|
|
AudioHeap_LoadLowPassFilter(filter, 0);
|
|
|
|
} else if (highPassCutoff == 0) {
|
|
|
|
AudioHeap_LoadLowPassFilter(filter, lowPassCutoff);
|
|
|
|
} else if (lowPassCutoff == 0) {
|
|
|
|
AudioHeap_LoadHighPassFilter(filter, highPassCutoff);
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
2022-06-03 19:59:02 +00:00
|
|
|
s16* ptr1 = &gLowPassFilterData[8 * lowPassCutoff];
|
|
|
|
s16* ptr2 = &gHighPassFilterData[8 * (highPassCutoff - 1)];
|
|
|
|
|
2020-09-20 17:22:09 +00:00
|
|
|
for (i = 0; i < 8; i++) {
|
2021-08-31 22:53:35 +00:00
|
|
|
filter[i] = (ptr1[i] + ptr2[i]) / 2;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_UpdateReverb(SynthesisReverb* reverb) {
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_UpdateReverbs(void) {
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 count;
|
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.audioBufferParameters.specUnk4 == 2) {
|
2020-09-20 17:22:09 +00:00
|
|
|
count = 2;
|
|
|
|
} else {
|
|
|
|
count = 1;
|
|
|
|
}
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.numSynthesisReverbs; i++) {
|
2020-09-20 17:22:09 +00:00
|
|
|
for (j = 0; j < count; j++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioHeap_UpdateReverb(&gAudioCtx.synthesisReverbs[i]);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
/**
|
|
|
|
* Clear the current Audio Interface Buffer
|
|
|
|
*/
|
|
|
|
void AudioHeap_ClearCurrentAiBuffer(void) {
|
2022-10-07 17:43:17 +00:00
|
|
|
s32 curAiBufferIndex = gAudioCtx.curAiBufIndex;
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.aiBufLengths[curAiBufferIndex] = gAudioCtx.audioBufferParameters.minAiBufferLength;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
for (i = 0; i < AIBUF_LEN; i++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.aiBuffers[curAiBufferIndex][i] = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
s32 AudioHeap_ResetStep(void) {
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
s32 sp24;
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.audioBufferParameters.specUnk4 == 2) {
|
2020-09-20 17:22:09 +00:00
|
|
|
sp24 = 2;
|
|
|
|
} else {
|
|
|
|
sp24 = 1;
|
|
|
|
}
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
switch (gAudioCtx.resetStatus) {
|
2020-09-20 17:22:09 +00:00
|
|
|
case 5:
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.audioBufferParameters.numSequencePlayers; i++) {
|
|
|
|
AudioSeq_SequencePlayerDisableAsFinished(&gAudioCtx.seqPlayers[i]);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.audioResetFadeOutFramesLeft = 2 / sp24;
|
|
|
|
gAudioCtx.resetStatus--;
|
2020-09-20 17:22:09 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.audioResetFadeOutFramesLeft != 0) {
|
|
|
|
gAudioCtx.audioResetFadeOutFramesLeft--;
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioHeap_UpdateReverbs();
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.numNotes; i++) {
|
|
|
|
if (gAudioCtx.notes[i].noteSubEu.bitField0.enabled &&
|
|
|
|
gAudioCtx.notes[i].playbackState.adsr.action.s.state != ADSR_STATE_DISABLED) {
|
|
|
|
gAudioCtx.notes[i].playbackState.adsr.fadeOutVel =
|
|
|
|
gAudioCtx.audioBufferParameters.updatesPerFrameInv;
|
|
|
|
gAudioCtx.notes[i].playbackState.adsr.action.s.release = true;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.audioResetFadeOutFramesLeft = 8 / sp24;
|
|
|
|
gAudioCtx.resetStatus--;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.audioResetFadeOutFramesLeft != 0) {
|
|
|
|
gAudioCtx.audioResetFadeOutFramesLeft--;
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioHeap_UpdateReverbs();
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.audioResetFadeOutFramesLeft = 2 / sp24;
|
|
|
|
gAudioCtx.resetStatus--;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioHeap_ClearCurrentAiBuffer();
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.audioResetFadeOutFramesLeft != 0) {
|
|
|
|
gAudioCtx.audioResetFadeOutFramesLeft--;
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.resetStatus--;
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioHeap_DiscardSampleCaches();
|
|
|
|
AudioHeap_DiscardSampleBanks();
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioHeap_Init();
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.resetStatus = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
for (i = 0; i < 3; i++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.aiBufLengths[i] = gAudioCtx.audioBufferParameters.maxAiBufferLength;
|
2021-11-07 16:58:50 +00:00
|
|
|
for (j = 0; j < AIBUF_LEN; j++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.aiBuffers[i][j] = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.resetStatus < 3) {
|
2022-06-03 19:59:02 +00:00
|
|
|
return false;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
return true;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_Init(void) {
|
2021-01-18 02:31:47 +00:00
|
|
|
s32 pad1[4];
|
2022-06-03 19:59:02 +00:00
|
|
|
s16* ramAddr;
|
|
|
|
s32 persistentSize;
|
|
|
|
s32 temporarySize;
|
|
|
|
s32 cachePoolSize;
|
|
|
|
s32 miscPoolSize;
|
2021-12-01 00:08:57 +00:00
|
|
|
OSIntMask intMask;
|
2021-01-18 02:31:47 +00:00
|
|
|
s32 i;
|
|
|
|
s32 j;
|
|
|
|
s32 pad2;
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioSpec* spec = &gAudioSpecs[gAudioCtx.audioResetSpecIdToLoad]; // Audio Specifications
|
2021-07-27 23:44:58 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.sampleDmaCount = 0;
|
2022-06-03 19:59:02 +00:00
|
|
|
|
|
|
|
// audio buffer parameters
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.audioBufferParameters.samplingFrequency = spec->samplingFrequency;
|
|
|
|
gAudioCtx.audioBufferParameters.aiSamplingFrequency =
|
|
|
|
osAiSetFrequency(gAudioCtx.audioBufferParameters.samplingFrequency);
|
|
|
|
gAudioCtx.audioBufferParameters.samplesPerFrameTarget =
|
|
|
|
ALIGN16(gAudioCtx.audioBufferParameters.samplingFrequency / gAudioCtx.refreshRate);
|
|
|
|
gAudioCtx.audioBufferParameters.minAiBufferLength = gAudioCtx.audioBufferParameters.samplesPerFrameTarget - 0x10;
|
|
|
|
gAudioCtx.audioBufferParameters.maxAiBufferLength = gAudioCtx.audioBufferParameters.samplesPerFrameTarget + 0x10;
|
|
|
|
gAudioCtx.audioBufferParameters.updatesPerFrame =
|
|
|
|
((gAudioCtx.audioBufferParameters.samplesPerFrameTarget + 0x10) / 0xD0) + 1;
|
|
|
|
gAudioCtx.audioBufferParameters.samplesPerUpdate =
|
|
|
|
(gAudioCtx.audioBufferParameters.samplesPerFrameTarget / gAudioCtx.audioBufferParameters.updatesPerFrame) & ~7;
|
|
|
|
gAudioCtx.audioBufferParameters.samplesPerUpdateMax = gAudioCtx.audioBufferParameters.samplesPerUpdate + 8;
|
|
|
|
gAudioCtx.audioBufferParameters.samplesPerUpdateMin = gAudioCtx.audioBufferParameters.samplesPerUpdate - 8;
|
|
|
|
gAudioCtx.audioBufferParameters.resampleRate = 32000.0f / (s32)gAudioCtx.audioBufferParameters.samplingFrequency;
|
|
|
|
gAudioCtx.audioBufferParameters.updatesPerFrameInvScaled =
|
|
|
|
(1.0f / 256.0f) / gAudioCtx.audioBufferParameters.updatesPerFrame;
|
|
|
|
gAudioCtx.audioBufferParameters.updatesPerFrameScaled = gAudioCtx.audioBufferParameters.updatesPerFrame / 4.0f;
|
|
|
|
gAudioCtx.audioBufferParameters.updatesPerFrameInv = 1.0f / gAudioCtx.audioBufferParameters.updatesPerFrame;
|
2022-06-03 19:59:02 +00:00
|
|
|
|
|
|
|
// SampleDma buffer size
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.sampleDmaBufSize1 = spec->sampleDmaBufSize1;
|
|
|
|
gAudioCtx.sampleDmaBufSize2 = spec->sampleDmaBufSize2;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.numNotes = spec->numNotes;
|
|
|
|
gAudioCtx.audioBufferParameters.numSequencePlayers = spec->numSequencePlayers;
|
|
|
|
if (gAudioCtx.audioBufferParameters.numSequencePlayers > 4) {
|
|
|
|
gAudioCtx.audioBufferParameters.numSequencePlayers = 4;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.unk_2 = spec->unk_14;
|
|
|
|
gAudioCtx.tempoInternalToExternal =
|
|
|
|
(u32)(gAudioCtx.audioBufferParameters.updatesPerFrame * 2880000.0f / gTatumsPerBeat / gAudioCtx.unk_2960);
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.unk_2870 = gAudioCtx.refreshRate;
|
|
|
|
gAudioCtx.unk_2870 *= gAudioCtx.audioBufferParameters.updatesPerFrame;
|
|
|
|
gAudioCtx.unk_2870 /= gAudioCtx.audioBufferParameters.aiSamplingFrequency;
|
|
|
|
gAudioCtx.unk_2870 /= gAudioCtx.tempoInternalToExternal;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.audioBufferParameters.specUnk4 = spec->unk_04;
|
|
|
|
gAudioCtx.audioBufferParameters.samplesPerFrameTarget *= gAudioCtx.audioBufferParameters.specUnk4;
|
|
|
|
gAudioCtx.audioBufferParameters.maxAiBufferLength *= gAudioCtx.audioBufferParameters.specUnk4;
|
|
|
|
gAudioCtx.audioBufferParameters.minAiBufferLength *= gAudioCtx.audioBufferParameters.specUnk4;
|
|
|
|
gAudioCtx.audioBufferParameters.updatesPerFrame *= gAudioCtx.audioBufferParameters.specUnk4;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.audioBufferParameters.specUnk4 >= 2) {
|
|
|
|
gAudioCtx.audioBufferParameters.maxAiBufferLength -= 0x10;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
// Determine the length of the buffer for storing the audio command list passed to the rsp audio microcode
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.maxAudioCmds =
|
|
|
|
gAudioCtx.numNotes * 0x10 * gAudioCtx.audioBufferParameters.updatesPerFrame + spec->numReverbs * 0x18 + 0x140;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
// Calculate sizes for various caches on the audio heap
|
|
|
|
persistentSize =
|
|
|
|
spec->persistentSeqCacheSize + spec->persistentFontCacheSize + spec->persistentSampleBankCacheSize + 0x10;
|
|
|
|
temporarySize =
|
|
|
|
spec->temporarySeqCacheSize + spec->temporaryFontCacheSize + spec->temporarySampleBankCacheSize + 0x10;
|
|
|
|
cachePoolSize = persistentSize + temporarySize;
|
2022-10-07 17:43:17 +00:00
|
|
|
miscPoolSize = gAudioCtx.sessionPool.size - cachePoolSize - 0x100;
|
2021-07-27 23:44:58 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
if (gAudioCtx.externalPool.startRamAddr != NULL) {
|
|
|
|
gAudioCtx.externalPool.curRamAddr = gAudioCtx.externalPool.startRamAddr;
|
2021-07-27 23:44:58 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
// Session Pool Split (split into Cache and Misc pools)
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.sessionPoolSplit.miscPoolSize = miscPoolSize;
|
|
|
|
gAudioCtx.sessionPoolSplit.cachePoolSize = cachePoolSize;
|
|
|
|
AudioHeap_InitSessionPools(&gAudioCtx.sessionPoolSplit);
|
2022-06-03 19:59:02 +00:00
|
|
|
|
|
|
|
// Cache Pool Split (split into Persistent and Temporary pools)
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.cachePoolSplit.persistentCommonPoolSize = persistentSize;
|
|
|
|
gAudioCtx.cachePoolSplit.temporaryCommonPoolSize = temporarySize;
|
|
|
|
AudioHeap_InitCachePools(&gAudioCtx.cachePoolSplit);
|
2022-06-03 19:59:02 +00:00
|
|
|
|
|
|
|
// Persistent Pool Split (split into Sequences, SoundFonts, Samples pools)
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.persistentCommonPoolSplit.seqCacheSize = spec->persistentSeqCacheSize;
|
|
|
|
gAudioCtx.persistentCommonPoolSplit.fontCacheSize = spec->persistentFontCacheSize;
|
|
|
|
gAudioCtx.persistentCommonPoolSplit.sampleBankCacheSize = spec->persistentSampleBankCacheSize;
|
|
|
|
AudioHeap_InitPersistentPoolsAndCaches(&gAudioCtx.persistentCommonPoolSplit);
|
2022-06-03 19:59:02 +00:00
|
|
|
|
|
|
|
// Temporary Pool Split (split into Sequences, SoundFonts, Samples pools)
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.temporaryCommonPoolSplit.seqCacheSize = spec->temporarySeqCacheSize;
|
|
|
|
gAudioCtx.temporaryCommonPoolSplit.fontCacheSize = spec->temporaryFontCacheSize;
|
|
|
|
gAudioCtx.temporaryCommonPoolSplit.sampleBankCacheSize = spec->temporarySampleBankCacheSize;
|
|
|
|
AudioHeap_InitTemporaryPoolsAndCaches(&gAudioCtx.temporaryCommonPoolSplit);
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioHeap_ResetLoadStatus();
|
2022-06-03 19:59:02 +00:00
|
|
|
|
|
|
|
// Initialize notes
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.notes = AudioHeap_AllocZeroed(&gAudioCtx.miscPool, gAudioCtx.numNotes * sizeof(Note));
|
2020-09-20 17:22:09 +00:00
|
|
|
Audio_NoteInitAll();
|
|
|
|
Audio_InitNoteFreeList();
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.noteSubsEu = AudioHeap_AllocZeroed(&gAudioCtx.miscPool, gAudioCtx.audioBufferParameters.updatesPerFrame *
|
|
|
|
gAudioCtx.numNotes * sizeof(NoteSubEu));
|
2022-06-03 19:59:02 +00:00
|
|
|
// Initialize audio binary interface command list buffers
|
2020-09-20 17:22:09 +00:00
|
|
|
for (i = 0; i != 2; i++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.abiCmdBufs[i] =
|
|
|
|
AudioHeap_AllocDmaMemoryZeroed(&gAudioCtx.miscPool, gAudioCtx.maxAudioCmds * sizeof(Acmd));
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-05-29 18:31:43 +00:00
|
|
|
// Initialize the decay rate table for adsr
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.adsrDecayTable = AudioHeap_Alloc(&gAudioCtx.miscPool, 256 * sizeof(f32));
|
2022-05-29 18:31:43 +00:00
|
|
|
AudioHeap_InitAdsrDecayTable();
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
// Initialize reverbs
|
2020-09-20 17:22:09 +00:00
|
|
|
for (i = 0; i < 4; i++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.synthesisReverbs[i].useReverb = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.numSynthesisReverbs = spec->numReverbs;
|
|
|
|
for (i = 0; i < gAudioCtx.numSynthesisReverbs; i++) {
|
2021-08-30 00:08:41 +00:00
|
|
|
ReverbSettings* settings = &spec->reverbSettings[i];
|
2022-10-07 17:43:17 +00:00
|
|
|
SynthesisReverb* reverb = &gAudioCtx.synthesisReverbs[i];
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2020-09-20 17:22:09 +00:00
|
|
|
reverb->downsampleRate = settings->downsampleRate;
|
|
|
|
reverb->windowSize = settings->windowSize * 64;
|
|
|
|
reverb->windowSize /= reverb->downsampleRate;
|
2022-06-03 19:59:02 +00:00
|
|
|
reverb->decayRatio = settings->decayRatio;
|
|
|
|
reverb->volume = settings->volume;
|
2020-09-20 17:22:09 +00:00
|
|
|
reverb->unk_14 = settings->unk_6 * 64;
|
|
|
|
reverb->unk_16 = settings->unk_8;
|
|
|
|
reverb->unk_18 = 0;
|
2021-08-31 22:53:35 +00:00
|
|
|
reverb->leakRtl = settings->leakRtl;
|
|
|
|
reverb->leakLtr = settings->leakLtr;
|
2020-09-20 17:22:09 +00:00
|
|
|
reverb->unk_05 = settings->unk_10;
|
|
|
|
reverb->unk_08 = settings->unk_12;
|
|
|
|
reverb->useReverb = 8;
|
2021-11-07 16:58:50 +00:00
|
|
|
reverb->leftRingBuf =
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioHeap_AllocZeroedAttemptExternal(&gAudioCtx.miscPool, reverb->windowSize * SAMPLE_SIZE);
|
2021-11-07 16:58:50 +00:00
|
|
|
reverb->rightRingBuf =
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioHeap_AllocZeroedAttemptExternal(&gAudioCtx.miscPool, reverb->windowSize * SAMPLE_SIZE);
|
2021-07-27 23:44:58 +00:00
|
|
|
reverb->nextRingBufPos = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
reverb->unk_20 = 0;
|
2021-07-27 23:44:58 +00:00
|
|
|
reverb->curFrame = 0;
|
|
|
|
reverb->bufSizePerChan = reverb->windowSize;
|
|
|
|
reverb->framesToIgnore = 2;
|
|
|
|
reverb->resampleFlags = 1;
|
2022-06-19 14:31:08 +00:00
|
|
|
reverb->tunedSample.sample = &reverb->sample;
|
2020-09-20 17:22:09 +00:00
|
|
|
reverb->sample.loop = &reverb->loop;
|
2022-06-19 14:31:08 +00:00
|
|
|
reverb->tunedSample.tuning = 1.0f;
|
2021-11-07 16:58:50 +00:00
|
|
|
reverb->sample.codec = CODEC_REVERB;
|
|
|
|
reverb->sample.medium = MEDIUM_RAM;
|
2022-07-27 21:53:56 +00:00
|
|
|
reverb->sample.size = reverb->windowSize * SAMPLE_SIZE;
|
2021-07-27 23:44:58 +00:00
|
|
|
reverb->sample.sampleAddr = (u8*)reverb->leftRingBuf;
|
2020-09-20 17:22:09 +00:00
|
|
|
reverb->loop.start = 0;
|
|
|
|
reverb->loop.count = 1;
|
|
|
|
reverb->loop.end = reverb->windowSize;
|
|
|
|
|
|
|
|
if (reverb->downsampleRate != 1) {
|
|
|
|
reverb->unk_0E = 0x8000 / reverb->downsampleRate;
|
2022-10-07 17:43:17 +00:00
|
|
|
reverb->unk_30 = AudioHeap_AllocZeroed(&gAudioCtx.miscPool, sizeof(RESAMPLE_STATE));
|
|
|
|
reverb->unk_34 = AudioHeap_AllocZeroed(&gAudioCtx.miscPool, sizeof(RESAMPLE_STATE));
|
|
|
|
reverb->unk_38 = AudioHeap_AllocZeroed(&gAudioCtx.miscPool, sizeof(RESAMPLE_STATE));
|
|
|
|
reverb->unk_3C = AudioHeap_AllocZeroed(&gAudioCtx.miscPool, sizeof(RESAMPLE_STATE));
|
|
|
|
for (j = 0; j < gAudioCtx.audioBufferParameters.updatesPerFrame; j++) {
|
|
|
|
ramAddr = AudioHeap_AllocZeroedAttemptExternal(&gAudioCtx.miscPool, DMEM_2CH_SIZE);
|
2022-06-03 19:59:02 +00:00
|
|
|
reverb->items[0][j].toDownsampleLeft = ramAddr;
|
2022-07-27 21:53:56 +00:00
|
|
|
reverb->items[0][j].toDownsampleRight = ramAddr + DMEM_1CH_SIZE / SAMPLE_SIZE;
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
ramAddr = AudioHeap_AllocZeroedAttemptExternal(&gAudioCtx.miscPool, DMEM_2CH_SIZE);
|
2022-06-03 19:59:02 +00:00
|
|
|
reverb->items[1][j].toDownsampleLeft = ramAddr;
|
2022-07-27 21:53:56 +00:00
|
|
|
reverb->items[1][j].toDownsampleRight = ramAddr + DMEM_1CH_SIZE / SAMPLE_SIZE;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
if (settings->lowPassFilterCutoffLeft != 0) {
|
2022-07-27 21:53:56 +00:00
|
|
|
reverb->filterLeftState =
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioHeap_AllocDmaMemoryZeroed(&gAudioCtx.miscPool, 2 * (FILTER_BUF_PART1 + FILTER_BUF_PART2));
|
|
|
|
reverb->filterLeft = AudioHeap_AllocDmaMemory(&gAudioCtx.miscPool, FILTER_SIZE);
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioHeap_LoadLowPassFilter(reverb->filterLeft, settings->lowPassFilterCutoffLeft);
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
2021-08-31 22:53:35 +00:00
|
|
|
reverb->filterLeft = NULL;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
if (settings->lowPassFilterCutoffRight != 0) {
|
2022-07-27 21:53:56 +00:00
|
|
|
reverb->filterRightState =
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioHeap_AllocDmaMemoryZeroed(&gAudioCtx.miscPool, 2 * (FILTER_BUF_PART1 + FILTER_BUF_PART2));
|
|
|
|
reverb->filterRight = AudioHeap_AllocDmaMemory(&gAudioCtx.miscPool, FILTER_SIZE);
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioHeap_LoadLowPassFilter(reverb->filterRight, settings->lowPassFilterCutoffRight);
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
2021-08-31 22:53:35 +00:00
|
|
|
reverb->filterRight = NULL;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
// Initialize sequence players
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioSeq_InitSequencePlayers();
|
2022-10-07 17:43:17 +00:00
|
|
|
for (j = 0; j < gAudioCtx.audioBufferParameters.numSequencePlayers; j++) {
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioSeq_InitSequencePlayerChannels(j);
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioSeq_ResetSequencePlayer(&gAudioCtx.seqPlayers[j]);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
// Initialize two additional sample caches for individual samples
|
|
|
|
AudioHeap_InitSampleCaches(spec->persistentSampleCacheSize, spec->temporarySampleCacheSize);
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioLoad_InitSampleDmaBuffers(gAudioCtx.numNotes);
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2022-08-30 21:35:00 +00:00
|
|
|
// Initialize Loads
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.preloadSampleStackTop = 0;
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioLoad_InitSlowLoads();
|
|
|
|
AudioLoad_InitScriptLoads();
|
|
|
|
AudioLoad_InitAsyncLoads();
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.unk_4 = 0x1000;
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioLoad_LoadPermanentSamples();
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2022-02-02 21:43:34 +00:00
|
|
|
intMask = osSetIntMask(OS_IM_NONE);
|
2020-09-20 17:22:09 +00:00
|
|
|
osWritebackDCacheAll();
|
|
|
|
osSetIntMask(intMask);
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void* AudioHeap_SearchPermanentCache(s32 tableType, s32 id) {
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 i;
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.permanentPool.numEntries; i++) {
|
|
|
|
if (gAudioCtx.permanentCache[i].tableType == tableType && gAudioCtx.permanentCache[i].id == id) {
|
|
|
|
return gAudioCtx.permanentCache[i].ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void* AudioHeap_AllocPermanent(s32 tableType, s32 id, u32 size) {
|
2022-06-03 19:59:02 +00:00
|
|
|
void* ramAddr;
|
2022-10-07 17:43:17 +00:00
|
|
|
s32 index = gAudioCtx.permanentPool.numEntries;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
ramAddr = AudioHeap_Alloc(&gAudioCtx.permanentPool, size);
|
|
|
|
gAudioCtx.permanentCache[index].ramAddr = ramAddr;
|
2022-06-03 19:59:02 +00:00
|
|
|
if (ramAddr == NULL) {
|
2020-09-20 17:22:09 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.permanentCache[index].tableType = tableType;
|
|
|
|
gAudioCtx.permanentCache[index].id = id;
|
|
|
|
gAudioCtx.permanentCache[index].size = size;
|
2022-02-19 21:50:56 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
//! @bug UB: missing return. "ramAddr" is in v0 at this point, but doing an
|
2022-05-01 22:06:35 +00:00
|
|
|
//! explicit return uses an additional register.
|
2022-02-19 21:50:56 +00:00
|
|
|
#ifdef AVOID_UB
|
2022-06-03 19:59:02 +00:00
|
|
|
return ramAddr;
|
2022-02-19 21:50:56 +00:00
|
|
|
#endif
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void* AudioHeap_AllocSampleCache(u32 size, s32 fontId, void* sampleAddr, s8 medium, s32 cache) {
|
|
|
|
SampleCacheEntry* entry;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
if (cache == CACHE_TEMPORARY) {
|
|
|
|
entry = AudioHeap_AllocTemporarySampleCacheEntry(size);
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
2021-11-07 16:58:50 +00:00
|
|
|
entry = AudioHeap_AllocPersistentSampleCacheEntry(size);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
if (entry != NULL) {
|
2021-11-07 16:58:50 +00:00
|
|
|
//! @bug Should use sampleBankId, not fontId
|
|
|
|
entry->sampleBankId = fontId;
|
|
|
|
entry->sampleAddr = sampleAddr;
|
|
|
|
entry->origMedium = medium;
|
|
|
|
return entry->allocatedAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
/**
|
|
|
|
* Initializes the persistent and temporary caches used for individual samples. Will attempt to use heap space available
|
|
|
|
* on the external pool. If no external pool is provided, then default to using space on the misc pool.
|
|
|
|
*/
|
|
|
|
void AudioHeap_InitSampleCaches(u32 persistentSampleCacheSize, u32 temporarySampleCacheSize) {
|
|
|
|
void* ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
ramAddr = AudioHeap_AllocAttemptExternal(&gAudioCtx.miscPool, persistentSampleCacheSize);
|
2022-06-03 19:59:02 +00:00
|
|
|
if (ramAddr == NULL) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.persistentSampleCache.pool.size = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioHeap_InitPool(&gAudioCtx.persistentSampleCache.pool, ramAddr, persistentSampleCacheSize);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-10-07 17:43:17 +00:00
|
|
|
ramAddr = AudioHeap_AllocAttemptExternal(&gAudioCtx.miscPool, temporarySampleCacheSize);
|
2022-06-03 19:59:02 +00:00
|
|
|
if (ramAddr == NULL) {
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.temporarySampleCache.pool.size = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
2022-10-07 17:43:17 +00:00
|
|
|
AudioHeap_InitPool(&gAudioCtx.temporarySampleCache.pool, ramAddr, temporarySampleCacheSize);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-10-07 17:43:17 +00:00
|
|
|
gAudioCtx.persistentSampleCache.numEntries = 0;
|
|
|
|
gAudioCtx.temporarySampleCache.numEntries = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
SampleCacheEntry* AudioHeap_AllocTemporarySampleCacheEntry(u32 size) {
|
2020-09-20 17:22:09 +00:00
|
|
|
u8* allocAfter;
|
|
|
|
u8* allocBefore;
|
2022-06-03 19:59:02 +00:00
|
|
|
void* ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 index;
|
|
|
|
s32 i;
|
2022-06-03 19:59:02 +00:00
|
|
|
SampleCacheEntry* entry;
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioPreloadReq* preload;
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioSampleCache* cache;
|
|
|
|
u8* startRamAddr;
|
|
|
|
u8* endRamAddr;
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
cache = &gAudioCtx.temporarySampleCache;
|
2022-06-03 19:59:02 +00:00
|
|
|
allocBefore = cache->pool.curRamAddr;
|
|
|
|
ramAddr = AudioHeap_Alloc(&cache->pool, size);
|
|
|
|
if (ramAddr == NULL) {
|
2021-11-07 16:58:50 +00:00
|
|
|
// Reset the pool and try again. We still keep pointers to within the
|
|
|
|
// pool, so we have to be careful to discard existing overlapping
|
|
|
|
// allocations further down.
|
2022-06-03 19:59:02 +00:00
|
|
|
u8* old = cache->pool.curRamAddr;
|
|
|
|
|
|
|
|
cache->pool.curRamAddr = cache->pool.startRamAddr;
|
|
|
|
ramAddr = AudioHeap_Alloc(&cache->pool, size);
|
|
|
|
if (ramAddr == NULL) {
|
|
|
|
cache->pool.curRamAddr = old;
|
2020-09-20 17:22:09 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
allocBefore = cache->pool.startRamAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
allocAfter = cache->pool.curRamAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
|
|
|
index = -1;
|
2022-10-07 17:43:17 +00:00
|
|
|
for (i = 0; i < gAudioCtx.preloadSampleStackTop; i++) {
|
|
|
|
preload = &gAudioCtx.preloadSampleStack[i];
|
2021-11-07 16:58:50 +00:00
|
|
|
if (preload->isFree == false) {
|
2022-06-03 19:59:02 +00:00
|
|
|
startRamAddr = preload->ramAddr;
|
|
|
|
endRamAddr = preload->ramAddr + preload->sample->size - 1;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (endRamAddr < allocBefore && startRamAddr < allocBefore) {
|
2020-09-20 17:22:09 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
if (endRamAddr >= allocAfter && startRamAddr >= allocAfter) {
|
2020-09-20 17:22:09 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
// Overlap, skip this preload.
|
|
|
|
preload->isFree = true;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
for (i = 0; i < cache->numEntries; i++) {
|
|
|
|
if (!cache->entries[i].inUse) {
|
2020-09-20 17:22:09 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
startRamAddr = cache->entries[i].allocatedAddr;
|
|
|
|
endRamAddr = startRamAddr + cache->entries[i].size - 1;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (endRamAddr < allocBefore && startRamAddr < allocBefore) {
|
2020-09-20 17:22:09 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
if (endRamAddr >= allocAfter && startRamAddr >= allocAfter) {
|
2020-09-20 17:22:09 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
// Overlap, discard existing entry.
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioHeap_DiscardSampleCacheEntry(&cache->entries[i]);
|
2020-09-20 17:22:09 +00:00
|
|
|
if (index == -1) {
|
|
|
|
index = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index == -1) {
|
2022-06-03 19:59:02 +00:00
|
|
|
index = cache->numEntries++;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
entry = &cache->entries[index];
|
|
|
|
entry->inUse = true;
|
|
|
|
entry->allocatedAddr = ramAddr;
|
|
|
|
entry->size = size;
|
|
|
|
|
|
|
|
return entry;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_UnapplySampleCacheForFont(SampleCacheEntry* entry, s32 fontId) {
|
2020-09-20 17:22:09 +00:00
|
|
|
Drum* drum;
|
|
|
|
Instrument* inst;
|
2022-06-19 14:31:08 +00:00
|
|
|
SoundEffect* soundEffect;
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 instId;
|
|
|
|
s32 drumId;
|
|
|
|
s32 sfxId;
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
for (instId = 0; instId < gAudioCtx.soundFontList[fontId].numInstruments; instId++) {
|
2021-11-07 16:58:50 +00:00
|
|
|
inst = Audio_GetInstrumentInner(fontId, instId);
|
2020-09-20 17:22:09 +00:00
|
|
|
if (inst != NULL) {
|
|
|
|
if (inst->normalRangeLo != 0) {
|
2022-06-19 14:31:08 +00:00
|
|
|
AudioHeap_UnapplySampleCache(entry, inst->lowPitchTunedSample.sample);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
if (inst->normalRangeHi != 0x7F) {
|
2022-06-19 14:31:08 +00:00
|
|
|
AudioHeap_UnapplySampleCache(entry, inst->highPitchTunedSample.sample);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-06-19 14:31:08 +00:00
|
|
|
AudioHeap_UnapplySampleCache(entry, inst->normalPitchTunedSample.sample);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
for (drumId = 0; drumId < gAudioCtx.soundFontList[fontId].numDrums; drumId++) {
|
2021-11-07 16:58:50 +00:00
|
|
|
drum = Audio_GetDrum(fontId, drumId);
|
2020-09-20 17:22:09 +00:00
|
|
|
if (drum != NULL) {
|
2022-06-19 14:31:08 +00:00
|
|
|
AudioHeap_UnapplySampleCache(entry, drum->tunedSample.sample);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
for (sfxId = 0; sfxId < gAudioCtx.soundFontList[fontId].numSfx; sfxId++) {
|
2022-06-19 14:31:08 +00:00
|
|
|
soundEffect = Audio_GetSoundEffect(fontId, sfxId);
|
|
|
|
if (soundEffect != NULL) {
|
|
|
|
AudioHeap_UnapplySampleCache(entry, soundEffect->tunedSample.sample);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_DiscardSampleCacheEntry(SampleCacheEntry* entry) {
|
|
|
|
s32 numFonts;
|
|
|
|
s32 sampleBankId1;
|
|
|
|
s32 sampleBankId2;
|
|
|
|
s32 fontId;
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
numFonts = gAudioCtx.soundFontTable->numEntries;
|
2021-11-07 16:58:50 +00:00
|
|
|
for (fontId = 0; fontId < numFonts; fontId++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
sampleBankId1 = gAudioCtx.soundFontList[fontId].sampleBankId1;
|
|
|
|
sampleBankId2 = gAudioCtx.soundFontList[fontId].sampleBankId2;
|
2021-11-07 16:58:50 +00:00
|
|
|
if (((sampleBankId1 != 0xFF) && (entry->sampleBankId == sampleBankId1)) ||
|
|
|
|
((sampleBankId2 != 0xFF) && (entry->sampleBankId == sampleBankId2)) || entry->sampleBankId == 0) {
|
|
|
|
if (AudioHeap_SearchCaches(FONT_TABLE, CACHE_EITHER, fontId) != NULL) {
|
|
|
|
if (AudioLoad_IsFontLoadComplete(fontId) != 0) {
|
|
|
|
AudioHeap_UnapplySampleCacheForFont(entry, fontId);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-19 14:31:08 +00:00
|
|
|
void AudioHeap_UnapplySampleCache(SampleCacheEntry* entry, Sample* sample) {
|
2020-09-20 17:22:09 +00:00
|
|
|
if (sample != NULL) {
|
2021-11-07 16:58:50 +00:00
|
|
|
if (sample->sampleAddr == entry->allocatedAddr) {
|
|
|
|
sample->sampleAddr = entry->sampleAddr;
|
|
|
|
sample->medium = entry->origMedium;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
SampleCacheEntry* AudioHeap_AllocPersistentSampleCacheEntry(u32 size) {
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioSampleCache* cache;
|
2021-11-07 16:58:50 +00:00
|
|
|
SampleCacheEntry* entry;
|
2022-06-03 19:59:02 +00:00
|
|
|
void* ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
cache = &gAudioCtx.persistentSampleCache;
|
2022-06-03 19:59:02 +00:00
|
|
|
ramAddr = AudioHeap_Alloc(&cache->pool, size);
|
|
|
|
if (ramAddr == NULL) {
|
2020-09-20 17:22:09 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2022-06-03 19:59:02 +00:00
|
|
|
entry = &cache->entries[cache->numEntries];
|
2021-11-07 16:58:50 +00:00
|
|
|
entry->inUse = true;
|
2022-06-03 19:59:02 +00:00
|
|
|
entry->allocatedAddr = ramAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
entry->size = size;
|
2022-06-03 19:59:02 +00:00
|
|
|
cache->numEntries++;
|
|
|
|
|
2020-09-20 17:22:09 +00:00
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_DiscardSampleCacheForFont(SampleCacheEntry* entry, s32 sampleBankId1, s32 sampleBankId2, s32 fontId) {
|
|
|
|
if ((entry->sampleBankId == sampleBankId1) || (entry->sampleBankId == sampleBankId2) ||
|
|
|
|
(entry->sampleBankId == 0)) {
|
|
|
|
AudioHeap_UnapplySampleCacheForFont(entry, fontId);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_DiscardSampleCaches(void) {
|
|
|
|
s32 numFonts;
|
|
|
|
s32 sampleBankId1;
|
|
|
|
s32 sampleBankId2;
|
|
|
|
s32 fontId;
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 j;
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
numFonts = gAudioCtx.soundFontTable->numEntries;
|
2021-11-07 16:58:50 +00:00
|
|
|
for (fontId = 0; fontId < numFonts; fontId++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
sampleBankId1 = gAudioCtx.soundFontList[fontId].sampleBankId1;
|
|
|
|
sampleBankId2 = gAudioCtx.soundFontList[fontId].sampleBankId2;
|
2021-11-07 16:58:50 +00:00
|
|
|
if ((sampleBankId1 == 0xFF) && (sampleBankId2 == 0xFF)) {
|
2020-09-20 17:22:09 +00:00
|
|
|
continue;
|
|
|
|
}
|
2021-11-07 16:58:50 +00:00
|
|
|
if (AudioHeap_SearchCaches(FONT_TABLE, CACHE_PERMANENT, fontId) == NULL ||
|
|
|
|
!AudioLoad_IsFontLoadComplete(fontId)) {
|
2020-09-20 17:22:09 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
for (j = 0; j < gAudioCtx.persistentSampleCache.numEntries; j++) {
|
|
|
|
AudioHeap_DiscardSampleCacheForFont(&gAudioCtx.persistentSampleCache.entries[j], sampleBankId1,
|
2021-11-07 16:58:50 +00:00
|
|
|
sampleBankId2, fontId);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-10-07 17:43:17 +00:00
|
|
|
for (j = 0; j < gAudioCtx.temporarySampleCache.numEntries; j++) {
|
|
|
|
AudioHeap_DiscardSampleCacheForFont(&gAudioCtx.temporarySampleCache.entries[j], sampleBankId1,
|
2021-11-07 16:58:50 +00:00
|
|
|
sampleBankId2, fontId);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct {
|
2021-11-07 16:58:50 +00:00
|
|
|
u32 oldAddr;
|
|
|
|
u32 newAddr;
|
|
|
|
u32 size;
|
|
|
|
u8 newMedium;
|
|
|
|
} StorageChange;
|
2020-09-20 17:22:09 +00:00
|
|
|
|
2022-06-19 14:31:08 +00:00
|
|
|
void AudioHeap_ChangeStorage(StorageChange* change, Sample* sample) {
|
2020-09-20 17:22:09 +00:00
|
|
|
if (sample != NULL) {
|
2022-06-03 19:59:02 +00:00
|
|
|
u32 startAddr = change->oldAddr;
|
|
|
|
u32 endAddr = change->oldAddr + change->size;
|
2021-11-30 23:40:42 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
if (startAddr <= (u32)sample->sampleAddr && (u32)sample->sampleAddr < endAddr) {
|
|
|
|
sample->sampleAddr = sample->sampleAddr - startAddr + change->newAddr;
|
2021-11-07 16:58:50 +00:00
|
|
|
sample->medium = change->newMedium;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-20 20:31:53 +00:00
|
|
|
void AudioHeap_ApplySampleBankCacheInternal(s32 apply, s32 sampleBankId);
|
2021-11-07 16:58:50 +00:00
|
|
|
|
|
|
|
void AudioHeap_DiscardSampleBank(s32 sampleBankId) {
|
|
|
|
AudioHeap_ApplySampleBankCacheInternal(false, sampleBankId);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_ApplySampleBankCache(s32 sampleBankId) {
|
|
|
|
AudioHeap_ApplySampleBankCacheInternal(true, sampleBankId);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_ApplySampleBankCacheInternal(s32 apply, s32 sampleBankId) {
|
|
|
|
AudioTable* sampleBankTable;
|
|
|
|
AudioTableEntry* entry;
|
|
|
|
s32 numFonts;
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 instId;
|
|
|
|
s32 drumId;
|
|
|
|
s32 sfxId;
|
2021-11-07 16:58:50 +00:00
|
|
|
StorageChange change;
|
|
|
|
s32 sampleBankId1;
|
|
|
|
s32 sampleBankId2;
|
|
|
|
s32 fontId;
|
2020-09-20 17:22:09 +00:00
|
|
|
Drum* drum;
|
|
|
|
Instrument* inst;
|
2022-06-19 14:31:08 +00:00
|
|
|
SoundEffect* soundEffect;
|
2021-11-07 16:58:50 +00:00
|
|
|
u32* fakematch;
|
2020-09-20 17:22:09 +00:00
|
|
|
s32 pad[4];
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
sampleBankTable = gAudioCtx.sampleBankTable;
|
|
|
|
numFonts = gAudioCtx.soundFontTable->numEntries;
|
2022-06-16 00:15:44 +00:00
|
|
|
change.oldAddr = (u32)AudioHeap_SearchCaches(SAMPLE_TABLE, CACHE_EITHER, sampleBankId);
|
2021-11-07 16:58:50 +00:00
|
|
|
if (change.oldAddr == 0) {
|
2020-09-20 17:22:09 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
entry = &sampleBankTable->entries[sampleBankId];
|
|
|
|
change.size = entry->size;
|
|
|
|
change.newMedium = entry->medium;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
if ((change.newMedium == MEDIUM_CART) || (change.newMedium == MEDIUM_DISK_DRIVE)) {
|
|
|
|
change.newAddr = entry->romAddr;
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
2021-11-07 16:58:50 +00:00
|
|
|
change.newAddr = 0;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
fakematch = &change.oldAddr;
|
|
|
|
if ((apply != false) && (apply == true)) {
|
|
|
|
u32 temp = change.newAddr;
|
2022-06-03 19:59:02 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
change.newAddr = *fakematch; // = change.oldAddr
|
|
|
|
change.oldAddr = temp;
|
|
|
|
change.newMedium = MEDIUM_RAM;
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
for (fontId = 0; fontId < numFonts; fontId++) {
|
2022-10-07 17:43:17 +00:00
|
|
|
sampleBankId1 = gAudioCtx.soundFontList[fontId].sampleBankId1;
|
|
|
|
sampleBankId2 = gAudioCtx.soundFontList[fontId].sampleBankId2;
|
2021-11-07 16:58:50 +00:00
|
|
|
if ((sampleBankId1 != 0xFF) || (sampleBankId2 != 0xFF)) {
|
|
|
|
if (!AudioLoad_IsFontLoadComplete(fontId) ||
|
|
|
|
AudioHeap_SearchCaches(FONT_TABLE, CACHE_EITHER, fontId) == NULL) {
|
2020-09-20 17:22:09 +00:00
|
|
|
continue;
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
if (sampleBankId1 == sampleBankId) {
|
|
|
|
} else if (sampleBankId2 == sampleBankId) {
|
2020-09-20 17:22:09 +00:00
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
for (instId = 0; instId < gAudioCtx.soundFontList[fontId].numInstruments; instId++) {
|
2021-11-07 16:58:50 +00:00
|
|
|
inst = Audio_GetInstrumentInner(fontId, instId);
|
2020-09-20 17:22:09 +00:00
|
|
|
if (inst != NULL) {
|
|
|
|
if (inst->normalRangeLo != 0) {
|
2022-06-19 14:31:08 +00:00
|
|
|
AudioHeap_ChangeStorage(&change, inst->lowPitchTunedSample.sample);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
if (inst->normalRangeHi != 0x7F) {
|
2022-06-19 14:31:08 +00:00
|
|
|
AudioHeap_ChangeStorage(&change, inst->highPitchTunedSample.sample);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2022-06-19 14:31:08 +00:00
|
|
|
AudioHeap_ChangeStorage(&change, inst->normalPitchTunedSample.sample);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
for (drumId = 0; drumId < gAudioCtx.soundFontList[fontId].numDrums; drumId++) {
|
2021-11-07 16:58:50 +00:00
|
|
|
drum = Audio_GetDrum(fontId, drumId);
|
2020-09-20 17:22:09 +00:00
|
|
|
if (drum != NULL) {
|
2022-06-19 14:31:08 +00:00
|
|
|
AudioHeap_ChangeStorage(&change, drum->tunedSample.sample);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
for (sfxId = 0; sfxId < gAudioCtx.soundFontList[fontId].numSfx; sfxId++) {
|
2022-06-19 14:31:08 +00:00
|
|
|
soundEffect = Audio_GetSoundEffect(fontId, sfxId);
|
|
|
|
if (soundEffect != NULL) {
|
|
|
|
AudioHeap_ChangeStorage(&change, soundEffect->tunedSample.sample);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2021-11-07 16:58:50 +00:00
|
|
|
void AudioHeap_DiscardSampleBanks(void) {
|
2022-06-03 19:59:02 +00:00
|
|
|
AudioCache* cache;
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioPersistentCache* persistent;
|
|
|
|
AudioTemporaryCache* temporary;
|
2020-09-20 17:22:09 +00:00
|
|
|
u32 i;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-10-07 17:43:17 +00:00
|
|
|
cache = &gAudioCtx.sampleBankCache;
|
2022-06-03 19:59:02 +00:00
|
|
|
temporary = &cache->temporary;
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2020-09-20 17:22:09 +00:00
|
|
|
if (temporary->entries[0].id != -1) {
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioHeap_DiscardSampleBank(temporary->entries[0].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2020-09-20 17:22:09 +00:00
|
|
|
if (temporary->entries[1].id != -1) {
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioHeap_DiscardSampleBank(temporary->entries[1].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
2020-08-15 18:06:26 +00:00
|
|
|
|
2022-06-03 19:59:02 +00:00
|
|
|
persistent = &cache->persistent;
|
2020-09-20 17:22:09 +00:00
|
|
|
for (i = 0; i < persistent->numEntries; i++) {
|
2021-11-07 16:58:50 +00:00
|
|
|
AudioHeap_DiscardSampleBank(persistent->entries[i].id);
|
2020-09-20 17:22:09 +00:00
|
|
|
}
|
|
|
|
}
|