773 lines
30 KiB
C
773 lines
30 KiB
C
#include <libultraship.h>
|
|
#include <macros.h>
|
|
#include <stubs.h>
|
|
|
|
#include "mk64.h"
|
|
#include "audio/data.h"
|
|
#include "audio/effects.h"
|
|
#include "audio/heap.h"
|
|
#include "audio/load.h"
|
|
#include "audio/synthesis.h"
|
|
#include "audio/playback.h"
|
|
#include "audio/seqplayer.h"
|
|
|
|
s16 gVolume;
|
|
s8 gUseReverb;
|
|
s8 gNumSynthesisReverbs;
|
|
struct NoteSubEu* gNoteSubsEu;
|
|
|
|
struct SoundAllocPool gAudioSessionPool;
|
|
struct SoundAllocPool gAudioInitPool;
|
|
struct SoundAllocPool gNotesAndBuffersPool;
|
|
u8 sAudioHeapPad[0x20]; // probably two unused pools
|
|
struct SoundAllocPool gSeqAndBankPool;
|
|
struct SoundAllocPool gPersistentCommonPool;
|
|
struct SoundAllocPool gTemporaryCommonPool;
|
|
|
|
struct SoundMultiPool gSeqLoadedPool;
|
|
struct SoundMultiPool gBankLoadedPool;
|
|
struct SoundMultiPool gUnusedLoadedPool;
|
|
|
|
struct Unk1Pool gUnkPool1;
|
|
|
|
struct PoolSplit sSessionPoolSplit;
|
|
struct PoolSplit2 sSeqAndBankPoolSplit;
|
|
struct PoolSplit sPersistentCommonPoolSplit;
|
|
struct PoolSplit sTemporaryCommonPoolSplit;
|
|
|
|
u8 gUnkLoadStatus[0x40];
|
|
u8 gBankLoadStatus[0x40];
|
|
u8 gSeqLoadStatus[0x100];
|
|
|
|
volatile u8 gAudioResetStatus;
|
|
u8 gAudioResetPresetIdToLoad;
|
|
s32 gAudioResetFadeOutFramesLeft;
|
|
|
|
u8 gAudioUnusedBuffer[0x1000];
|
|
|
|
struct Note* gNotes;
|
|
|
|
/**
|
|
* Given that (almost) all of these are format strings, it is highly likely
|
|
* that they are meant to be used in some sort of printf variant. But I don't
|
|
* care to try and figure out which function gets which string(s)
|
|
* So I've place them all here instead.
|
|
**/
|
|
char heapAudioString00[] = "Warning:Kill Note %x \n";
|
|
char heapAudioString01[] = "Kill Voice %d (ID %d) %d\n";
|
|
char heapAudioString02[] = "Warning: Running Sequence's data disappear!\n";
|
|
char heapAudioString03[] = "Audio:Memory:Heap OverFlow : Not Allocate %d!\n";
|
|
char heapAudioString04[] = "Audio:Memory:DataHeap Not Allocate \n";
|
|
char heapAudioString05[] = "StayHeap Not Allocate %d\n";
|
|
char heapAudioString06[] = "AutoHeap Not Allocate %d\n";
|
|
char heapAudioString07[] = "Status ID0 : %d ID1 : %d\n";
|
|
char heapAudioString08[] = "id 0 is Stopping\n";
|
|
char heapAudioString09[] = "id 0 is Stop\n";
|
|
char heapAudioString10[] = "id 1 is Stopping\n";
|
|
char heapAudioString11[] = "id 1 is Stop\n";
|
|
char heapAudioString12[] = "WARNING: NO FREE AUTOSEQ AREA.\n";
|
|
char heapAudioString13[] = "WARNING: NO STOP AUTO AREA.\n";
|
|
char heapAudioString14[] = " AND TRY FORCE TO STOP SIDE \n";
|
|
char heapAudioString15[] = "Check ID0 (seq ID %d) Useing ...\n";
|
|
char heapAudioString16[] = "Check ID1 (seq ID %d) Useing ...\n";
|
|
char heapAudioString17[] = "No Free Seq area.\n";
|
|
char heapAudioString18[] = "CH %d: ID %d\n";
|
|
char heapAudioString19[] = "TWO SIDES ARE LOADING... ALLOC CANCELED.\n";
|
|
char heapAudioString20[] = "WARNING: Before Area Overlaid After.";
|
|
char heapAudioString21[] = "WARNING: After Area Overlaid Before.";
|
|
char heapAudioString22[] = "MEMORY:SzHeapAlloc ERROR: sza->side %d\n";
|
|
char heapAudioString23[] = "Audio:MEMORY:SzHeap Overflow error. (%d bytes)\n";
|
|
char heapAudioString24[] = "Auto Heap Unhit for ID %d\n";
|
|
char heapAudioString25[] = "Heap Reconstruct Start %x\n";
|
|
char heapAudioString26[] = "AHPBASE %x\n";
|
|
char heapAudioString27[] = "AHPCUR %x\n";
|
|
char heapAudioString28[] = "HeapTop %x\n";
|
|
char heapAudioString29[] = "SynoutRate %d / %d \n";
|
|
char heapAudioString30[] = "FXSIZE %d\n";
|
|
char heapAudioString31[] = "FXCOMP %d\n";
|
|
char heapAudioString32[] = "FXDOWN %d\n";
|
|
char heapAudioString33[] = "WaveCacheLen: %d\n";
|
|
char heapAudioString34[] = "SpecChange Finished\n";
|
|
char heapAudioString35[] = "Fbank Seq %x\n";
|
|
char heapAudioString36[] = "Already Load Type %d,ID %d\n";
|
|
char heapAudioString37[] = "Warning:Emem Over,not alloc %d\n";
|
|
char heapAudioString38[] = "Write %d\n";
|
|
|
|
extern u8 gUnkLoadStatus[];
|
|
|
|
void reset_bank_and_seq_load_status(void) {
|
|
s32 i;
|
|
for (i = 0; i < 64; i++) {
|
|
if (gBankLoadStatus[i] != 5) {
|
|
gBankLoadStatus[i] = 0;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
if (gUnkLoadStatus[i] != 5) {
|
|
gUnkLoadStatus[i] = 0;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
if (gSeqLoadStatus[i] != 5) {
|
|
gSeqLoadStatus[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void discard_bank(s32 bankId) {
|
|
s32 i;
|
|
|
|
for (i = 0; i < gMaxSimultaneousNotes; i++) {
|
|
struct Note* note = &gNotes[i];
|
|
|
|
if (note->noteSubEu.bankId == bankId) {
|
|
// (These prints are unclear. Arguments are picked semi-randomly.)
|
|
// eu_stubbed_printf_1("Warning:Kill Note %x \n", i);
|
|
if (note->priority >= NOTE_PRIORITY_MIN) {
|
|
// eu_stubbed_printf_3("Kill Voice %d (ID %d) %d\n", note->waveId, bankId, note->priority);
|
|
// eu_stubbed_printf_0("Warning: Running Sequence's data disappear!\n");
|
|
note->parentLayer->enabled = false; // is 0x48, should be 0x44
|
|
note->parentLayer->finished = true;
|
|
}
|
|
note_disable(note);
|
|
audio_list_remove(¬e->listItem);
|
|
audio_list_push_back(&gNoteFreeLists.disabled, ¬e->listItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
void discard_sequence(s32 seqId) {
|
|
s32 i;
|
|
|
|
for (i = 0; i < SEQUENCE_PLAYERS; i++) {
|
|
if (gSequencePlayers[i].enabled && gSequencePlayers[i].seqId == seqId) {
|
|
sequence_player_disable(&gSequencePlayers[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void* soundAlloc(struct SoundAllocPool* pool, u32 size) {
|
|
u8* start;
|
|
u8* pos;
|
|
u32 alignedSize = ALIGN16(size);
|
|
|
|
start = pool->cur;
|
|
if (start + alignedSize <= pool->start + pool->size) {
|
|
pool->cur += alignedSize;
|
|
for (pos = start; pos < pool->cur; pos++) {
|
|
*pos = 0;
|
|
}
|
|
} else {
|
|
printf("audio/heap.c: Heap OverFlow : Not Allocate %d!\n", size);
|
|
return NULL;
|
|
}
|
|
pool->numAllocatedEntries++;
|
|
return start;
|
|
}
|
|
|
|
void sound_alloc_pool_init(struct SoundAllocPool* pool, void* memAddr, u32 size) {
|
|
pool->cur = pool->start = (u8*) ALIGN16((uintptr_t) memAddr);
|
|
pool->size = size;
|
|
pool->numAllocatedEntries = 0;
|
|
}
|
|
|
|
void persistent_pool_clear(struct PersistentPool* persistent) {
|
|
persistent->pool.numAllocatedEntries = 0;
|
|
persistent->pool.cur = persistent->pool.start;
|
|
persistent->numEntries = 0;
|
|
}
|
|
|
|
void temporary_pool_clear(struct TemporaryPool* temporary) {
|
|
temporary->pool.numAllocatedEntries = 0;
|
|
temporary->pool.cur = temporary->pool.start;
|
|
temporary->nextSide = 0;
|
|
temporary->entries[0].ptr = temporary->pool.start;
|
|
temporary->entries[1].ptr = temporary->pool.start + temporary->pool.size;
|
|
temporary->entries[0].id = -1; // should be at 1e not 1c
|
|
temporary->entries[1].id = -1;
|
|
}
|
|
|
|
void func_800B90E0(struct SoundAllocPool* pool) {
|
|
pool->numAllocatedEntries = 0;
|
|
pool->cur = pool->start;
|
|
}
|
|
|
|
// inspired by sound_init_main_pools in sm64
|
|
void sound_init_main_pools(s32 arg0) {
|
|
sound_alloc_pool_init(&gAudioInitPool, &gAudioHeap, arg0);
|
|
sound_alloc_pool_init(&gAudioSessionPool, gAudioHeap + arg0, gAudioHeapSize - arg0);
|
|
}
|
|
|
|
// inspired by session_pools_init in sm64
|
|
void func_800B914C(struct PoolSplit* arg0) {
|
|
gAudioSessionPool.cur = gAudioSessionPool.start;
|
|
sound_alloc_pool_init(&gNotesAndBuffersPool, soundAlloc(&gAudioSessionPool, arg0->wantSeq), arg0->wantSeq);
|
|
sound_alloc_pool_init(&gSeqAndBankPool, soundAlloc(&gAudioSessionPool, arg0->wantCustom), arg0->wantCustom);
|
|
}
|
|
|
|
void seq_and_bank_pool_init(struct PoolSplit2* a) {
|
|
gSeqAndBankPool.cur = gSeqAndBankPool.start;
|
|
sound_alloc_pool_init(&gPersistentCommonPool, soundAlloc(&gSeqAndBankPool, a->wantPersistent), a->wantPersistent);
|
|
sound_alloc_pool_init(&gTemporaryCommonPool, soundAlloc(&gSeqAndBankPool, a->wantTemporary), a->wantTemporary);
|
|
}
|
|
|
|
void persistent_pools_init(struct PoolSplit* a) {
|
|
gPersistentCommonPool.cur = gPersistentCommonPool.start;
|
|
sound_alloc_pool_init(&gSeqLoadedPool.persistent.pool, soundAlloc(&gPersistentCommonPool, a->wantSeq), a->wantSeq);
|
|
sound_alloc_pool_init(&gBankLoadedPool.persistent.pool, soundAlloc(&gPersistentCommonPool, a->wantBank),
|
|
a->wantBank);
|
|
sound_alloc_pool_init(&gUnusedLoadedPool.persistent.pool, soundAlloc(&gPersistentCommonPool, a->wantUnused),
|
|
a->wantUnused);
|
|
persistent_pool_clear(&gSeqLoadedPool.persistent);
|
|
persistent_pool_clear(&gBankLoadedPool.persistent);
|
|
persistent_pool_clear(&gUnusedLoadedPool.persistent);
|
|
}
|
|
|
|
void temporary_pools_init(struct PoolSplit* a) {
|
|
gTemporaryCommonPool.cur = gTemporaryCommonPool.start;
|
|
sound_alloc_pool_init(&gSeqLoadedPool.temporary.pool, soundAlloc(&gTemporaryCommonPool, a->wantSeq), a->wantSeq);
|
|
sound_alloc_pool_init(&gBankLoadedPool.temporary.pool, soundAlloc(&gTemporaryCommonPool, a->wantBank), a->wantBank);
|
|
sound_alloc_pool_init(&gUnusedLoadedPool.temporary.pool, soundAlloc(&gTemporaryCommonPool, a->wantUnused),
|
|
a->wantUnused);
|
|
temporary_pool_clear(&gSeqLoadedPool.temporary);
|
|
temporary_pool_clear(&gBankLoadedPool.temporary);
|
|
temporary_pool_clear(&gUnusedLoadedPool.temporary);
|
|
}
|
|
|
|
void* alloc_bank_or_seq(struct SoundMultiPool* arg0, s32 arg1, s32 size, s32 arg3, s32 id) {
|
|
struct TemporaryPool* tp;
|
|
struct SoundAllocPool* pool;
|
|
void* ret;
|
|
u16 UNUSED _firstVal;
|
|
u16 UNUSED _secondVal;
|
|
u16 firstVal;
|
|
u16 secondVal;
|
|
s32 var_v1_2;
|
|
u8* table;
|
|
u8 isSound;
|
|
|
|
if (arg3 == 0) {
|
|
tp = &arg0->temporary;
|
|
// clang-format off
|
|
if (arg0 == &gSeqLoadedPool) {
|
|
table = gSeqLoadStatus; isSound = 0;
|
|
} else {
|
|
// wtf?
|
|
firstVal += 0;
|
|
if (arg0 == &gBankLoadedPool) {
|
|
isSound = 1; table = gBankLoadStatus;
|
|
} else if (arg0 == &gUnusedLoadedPool) {
|
|
table = gUnkLoadStatus; isSound = 2;
|
|
}
|
|
}
|
|
// clang-format on
|
|
if (tp->entries[0].id == -1) {
|
|
firstVal = 0;
|
|
} else {
|
|
firstVal = table[tp->entries[0].id];
|
|
}
|
|
if (tp->entries[1].id == -1) {
|
|
secondVal = 0;
|
|
} else {
|
|
secondVal = table[tp->entries[1].id];
|
|
}
|
|
if (isSound == 1) {
|
|
if (firstVal == 4) {
|
|
for (var_v1_2 = 0; var_v1_2 < gMaxSimultaneousNotes; var_v1_2++) {
|
|
if (gNotes[var_v1_2].noteSubEu.bankId == tp->entries[0].id && gNotes[var_v1_2].noteSubEu.enabled) {
|
|
break;
|
|
}
|
|
}
|
|
if (var_v1_2 == gMaxSimultaneousNotes) {
|
|
if (gBankLoadStatus[tp->entries[0].id] != SOUND_LOAD_STATUS_5) {
|
|
gBankLoadStatus[tp->entries[0].id] = SOUND_LOAD_STATUS_DISCARDABLE;
|
|
}
|
|
firstVal = SOUND_LOAD_STATUS_DISCARDABLE;
|
|
}
|
|
}
|
|
if (secondVal == 4) {
|
|
for (var_v1_2 = 0; var_v1_2 < gMaxSimultaneousNotes; var_v1_2++) {
|
|
if (gNotes[var_v1_2].noteSubEu.bankId == tp->entries[1].id && gNotes[var_v1_2].noteSubEu.enabled) {
|
|
break;
|
|
}
|
|
}
|
|
if (var_v1_2 == gMaxSimultaneousNotes) {
|
|
if (gBankLoadStatus[tp->entries[1].id] != SOUND_LOAD_STATUS_5) {
|
|
gBankLoadStatus[tp->entries[1].id] = SOUND_LOAD_STATUS_DISCARDABLE;
|
|
}
|
|
secondVal = SOUND_LOAD_STATUS_DISCARDABLE;
|
|
}
|
|
}
|
|
}
|
|
if (firstVal == 0) {
|
|
tp->nextSide = 0;
|
|
} else if (secondVal == 0) {
|
|
tp->nextSide = 1;
|
|
} else {
|
|
if ((firstVal == 3) && (secondVal == 3)) {
|
|
// ?
|
|
} else if (firstVal == 3) {
|
|
tp->nextSide = 0;
|
|
} else if (secondVal == 3) {
|
|
tp->nextSide = 1;
|
|
} else {
|
|
if (isSound == 0) {
|
|
if (firstVal == SOUND_LOAD_STATUS_COMPLETE) {
|
|
for (var_v1_2 = 0; var_v1_2 < SEQUENCE_PLAYERS; var_v1_2++) {
|
|
if (gSequencePlayers[var_v1_2].enabled &&
|
|
gSequencePlayers[var_v1_2].seqId == tp->entries[0].id) {
|
|
break;
|
|
}
|
|
}
|
|
if (var_v1_2 == SEQUENCE_PLAYERS) {
|
|
tp->nextSide = 0;
|
|
goto out;
|
|
}
|
|
}
|
|
if (secondVal == SOUND_LOAD_STATUS_COMPLETE) {
|
|
for (var_v1_2 = 0; var_v1_2 < SEQUENCE_PLAYERS; var_v1_2++) {
|
|
if (gSequencePlayers[var_v1_2].enabled &&
|
|
gSequencePlayers[var_v1_2].seqId == tp->entries[1].id) {
|
|
break;
|
|
}
|
|
}
|
|
if (var_v1_2 == SEQUENCE_PLAYERS) {
|
|
tp->nextSide = 1;
|
|
goto out;
|
|
}
|
|
}
|
|
} else if (isSound == 1) {
|
|
if (firstVal == SOUND_LOAD_STATUS_COMPLETE) {
|
|
for (var_v1_2 = 0; var_v1_2 < gMaxSimultaneousNotes; var_v1_2++) {
|
|
if (gNotes[var_v1_2].noteSubEu.bankId == tp->entries[0].id &&
|
|
gNotes[var_v1_2].noteSubEu.enabled) {
|
|
break;
|
|
}
|
|
}
|
|
if (var_v1_2 == gMaxSimultaneousNotes) {
|
|
tp->nextSide = 0;
|
|
goto out;
|
|
}
|
|
}
|
|
if (secondVal == SOUND_LOAD_STATUS_COMPLETE) {
|
|
for (var_v1_2 = 0; var_v1_2 < gMaxSimultaneousNotes; var_v1_2++) {
|
|
if (gNotes[var_v1_2].noteSubEu.bankId == tp->entries[1].id &&
|
|
gNotes[var_v1_2].noteSubEu.enabled) {
|
|
break;
|
|
}
|
|
}
|
|
if (var_v1_2 == gMaxSimultaneousNotes) {
|
|
tp->nextSide = 1;
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
if (tp->nextSide == 0) {
|
|
if (firstVal == SOUND_LOAD_STATUS_IN_PROGRESS) {
|
|
if (secondVal != SOUND_LOAD_STATUS_IN_PROGRESS) {
|
|
tp->nextSide = 1;
|
|
goto out;
|
|
}
|
|
} else {
|
|
goto out;
|
|
}
|
|
} else {
|
|
if (secondVal == SOUND_LOAD_STATUS_IN_PROGRESS) {
|
|
if (firstVal != SOUND_LOAD_STATUS_IN_PROGRESS) {
|
|
tp->nextSide = 0;
|
|
goto out;
|
|
}
|
|
} else {
|
|
goto out;
|
|
}
|
|
}
|
|
return NULL;
|
|
out:;
|
|
}
|
|
}
|
|
|
|
pool = &arg0->temporary.pool;
|
|
if (tp->entries[tp->nextSide].id != (s8) -1) {
|
|
table[tp->entries[tp->nextSide].id] = SOUND_LOAD_STATUS_NOT_LOADED;
|
|
if (isSound == true) {
|
|
discard_bank(tp->entries[tp->nextSide].id);
|
|
}
|
|
}
|
|
switch (tp->nextSide) {
|
|
case 0:
|
|
tp->entries[0].ptr = pool->start;
|
|
tp->entries[0].id = (s16) id;
|
|
tp->entries[0].size = (u32) size;
|
|
pool->cur = pool->start + size;
|
|
if (tp->entries[1].ptr < pool->cur) {
|
|
table[tp->entries[1].id] = 0;
|
|
switch (isSound) { /* irregular */
|
|
case 0:
|
|
discard_sequence((s32) tp->entries[1].id);
|
|
break;
|
|
case 1:
|
|
discard_bank((s32) tp->entries[1].id);
|
|
break;
|
|
}
|
|
tp->entries[1].id = -1;
|
|
tp->entries[1].ptr = pool->start + pool->size;
|
|
}
|
|
ret = tp->entries[0].ptr;
|
|
break;
|
|
case 1:
|
|
tp->entries[1].ptr = pool->start + pool->size - size - 0x10;
|
|
tp->entries[1].id = (s16) id;
|
|
tp->entries[1].size = (u32) size;
|
|
if ((u32) tp->entries[1].ptr < (u32) pool->cur) {
|
|
table[tp->entries[0].id] = 0;
|
|
switch (isSound) { /* switch 1; irregular */
|
|
case 0: /* switch 1 */
|
|
discard_sequence((s32) tp->entries[0].id);
|
|
break;
|
|
case 1: /* switch 1 */
|
|
discard_bank((s32) tp->entries[0].id);
|
|
break;
|
|
}
|
|
tp->entries[0].id = -1;
|
|
pool->cur = pool->start;
|
|
}
|
|
ret = tp->entries[1].ptr;
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
tp->nextSide ^= 1;
|
|
return ret;
|
|
}
|
|
ret = soundAlloc(&arg0->persistent.pool, arg1 * size);
|
|
arg0->persistent.entries[arg0->persistent.numEntries].ptr = ret;
|
|
if (ret == NULL) {
|
|
switch (arg3) {
|
|
case 2:
|
|
return alloc_bank_or_seq(arg0, arg1, size, 0, id);
|
|
case 1:
|
|
case 0:
|
|
return NULL;
|
|
}
|
|
}
|
|
arg0->persistent.entries[arg0->persistent.numEntries].id = (s16) id;
|
|
arg0->persistent.entries[arg0->persistent.numEntries].size = (u32) size;
|
|
return arg0->persistent.entries[arg0->persistent.numEntries++].ptr;
|
|
}
|
|
|
|
void* get_bank_or_seq(s32 poolIdx, s32 arg1, s32 id) {
|
|
void* ret;
|
|
|
|
ret = unk_pool1_lookup(poolIdx, id);
|
|
if (ret != NULL) {
|
|
return ret;
|
|
}
|
|
return get_bank_or_seq_inner(poolIdx, arg1, id);
|
|
}
|
|
|
|
void* get_bank_or_seq_inner(s32 poolIdx, s32 arg1, s32 bankId) {
|
|
u32 i;
|
|
struct SoundMultiPool* loadedPool;
|
|
struct TemporaryPool* temporary;
|
|
struct PersistentPool* persistent;
|
|
|
|
switch (poolIdx) {
|
|
case 0:
|
|
loadedPool = &gSeqLoadedPool;
|
|
break;
|
|
case 1:
|
|
loadedPool = &gBankLoadedPool;
|
|
break;
|
|
case 2:
|
|
loadedPool = &gUnusedLoadedPool;
|
|
break;
|
|
}
|
|
|
|
temporary = &loadedPool->temporary;
|
|
if (arg1 == 0) {
|
|
if (temporary->entries[0].id == bankId) {
|
|
temporary->nextSide = 1;
|
|
return temporary->entries[0].ptr;
|
|
} else if (temporary->entries[1].id == bankId) {
|
|
temporary->nextSide = 0;
|
|
return temporary->entries[1].ptr;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
persistent = &loadedPool->persistent;
|
|
for (i = 0; i < persistent->numEntries; i++) {
|
|
if (persistent->entries[i].id == bankId) {
|
|
return persistent->entries[i].ptr;
|
|
}
|
|
}
|
|
|
|
if (arg1 == 2) {
|
|
return get_bank_or_seq(poolIdx, 0, bankId);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void func_800B9BE4(f32 arg0, f32 arg1, u16* arg2) {
|
|
s32 i;
|
|
f32 tmp[16];
|
|
|
|
tmp[0] = arg1 * 262159.0f;
|
|
tmp[8] = arg0 * 262159.0f;
|
|
tmp[1] = (arg1 * arg0) * 262159.0f;
|
|
tmp[9] = ((arg0 * arg0) + arg1) * 262159.0f;
|
|
|
|
for (i = 2; i < 8; i++) {
|
|
//! @bug they probably meant to store the value to tmp[i] and tmp[8 + i]
|
|
arg2[i] = arg1 * tmp[i - 2] + arg0 * tmp[i - 1];
|
|
arg2[8 + i] = arg1 * tmp[6 + i] + arg0 * tmp[7 + i];
|
|
}
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
arg2[i] = tmp[i];
|
|
}
|
|
}
|
|
|
|
void decrease_reverb_gain(void) {
|
|
s32 i;
|
|
for (i = 0; i < gNumSynthesisReverbs; i++) {
|
|
gSynthesisReverbs[i].reverbGain -= gSynthesisReverbs[i].reverbGain / 4;
|
|
}
|
|
}
|
|
|
|
s32 audio_shut_down_and_reset_step(void) {
|
|
s32 i;
|
|
s32 j;
|
|
|
|
switch (gAudioResetStatus) {
|
|
case 5:
|
|
for (i = 0; i < SEQUENCE_PLAYERS; i++) {
|
|
sequence_player_disable(&gSequencePlayers[i]);
|
|
}
|
|
gAudioResetFadeOutFramesLeft = 4;
|
|
gAudioResetStatus--;
|
|
break;
|
|
case 4:
|
|
if (gAudioResetFadeOutFramesLeft != 0) {
|
|
gAudioResetFadeOutFramesLeft--;
|
|
decrease_reverb_gain();
|
|
} else {
|
|
for (i = 0; i < gMaxSimultaneousNotes; i++) {
|
|
if (gNotes[i].noteSubEu.enabled && gNotes[i].adsr.state != ADSR_STATE_DISABLED) {
|
|
gNotes[i].adsr.fadeOutVel = gAudioBufferParameters.updatesPerFrameInv;
|
|
gNotes[i].adsr.action |= ADSR_ACTION_RELEASE;
|
|
}
|
|
}
|
|
gAudioResetFadeOutFramesLeft = 0x00000010;
|
|
gAudioResetStatus--;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (gAudioResetFadeOutFramesLeft != 0) {
|
|
gAudioResetFadeOutFramesLeft--;
|
|
decrease_reverb_gain();
|
|
} else {
|
|
for (i = 0; i < NUMAIBUFFERS; i++) {
|
|
for (j = 0; j < (s32) (AIBUFFER_LEN / sizeof(s16)); j++) {
|
|
gAiBuffers[i][j] = 0;
|
|
}
|
|
}
|
|
gAudioResetFadeOutFramesLeft = 4;
|
|
gAudioResetStatus--;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (gAudioResetFadeOutFramesLeft != 0) {
|
|
gAudioResetFadeOutFramesLeft--;
|
|
} else {
|
|
gAudioResetStatus--;
|
|
}
|
|
break;
|
|
case 1:
|
|
audio_reset_session();
|
|
gAudioResetStatus = 0;
|
|
break;
|
|
}
|
|
if (gAudioResetStatus < 3) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void audio_reset_session(void) {
|
|
s32 var_s1;
|
|
s32 var_s5;
|
|
s32 temp;
|
|
s32 totalMem;
|
|
s32 temporaryMem;
|
|
s32 persistentMem;
|
|
s16* mem;
|
|
struct SynthesisReverb* reverb;
|
|
struct ReverbSettingsEU* reverbSettings;
|
|
struct AudioSessionSettingsEU* temp_s6 = &gAudioSessionPresets[gAudioResetPresetIdToLoad];
|
|
|
|
gSampleDmaNumListItems = 0;
|
|
gAudioBufferParameters.frequency = temp_s6->frequency;
|
|
gAudioBufferParameters.aiFrequency = osAiSetFrequency(gAudioBufferParameters.frequency);
|
|
gAudioBufferParameters.samplesPerFrameTarget = ALIGN16(gAudioBufferParameters.frequency / gRefreshRate);
|
|
gAudioBufferParameters.minAiBufferLength = gAudioBufferParameters.samplesPerFrameTarget - 0x10;
|
|
gAudioBufferParameters.maxAiBufferLength = gAudioBufferParameters.samplesPerFrameTarget + 0x10;
|
|
gAudioBufferParameters.updatesPerFrame = ((gAudioBufferParameters.samplesPerFrameTarget + 0x10) / 192) + 1;
|
|
gAudioBufferParameters.samplesPerUpdate =
|
|
(gAudioBufferParameters.samplesPerFrameTarget / gAudioBufferParameters.updatesPerFrame) & ~0x0007;
|
|
gAudioBufferParameters.samplesPerUpdateMax = gAudioBufferParameters.samplesPerUpdate + 8;
|
|
gAudioBufferParameters.samplesPerUpdateMin = gAudioBufferParameters.samplesPerUpdate - 8;
|
|
gAudioBufferParameters.resampleRate = 32000.0f / ((f32) (s32) gAudioBufferParameters.frequency);
|
|
gAudioBufferParameters.unkUpdatesPerFrameScaled = 0.001171875f / gAudioBufferParameters.updatesPerFrame;
|
|
gAudioBufferParameters.updatesPerFrameInv = 1.0f / gAudioBufferParameters.updatesPerFrame;
|
|
gMaxSimultaneousNotes = temp_s6->maxSimultaneousNotes;
|
|
gVolume = temp_s6->volume;
|
|
gTempoInternalToExternal =
|
|
(u32) (((gAudioBufferParameters.updatesPerFrame * 2880000.0f) / gTatumsPerBeat) / D_803B7178);
|
|
gAudioBufferParameters.presetUnk4 = temp_s6->unk1;
|
|
gAudioBufferParameters.samplesPerFrameTarget *= gAudioBufferParameters.presetUnk4;
|
|
gAudioBufferParameters.maxAiBufferLength *= gAudioBufferParameters.presetUnk4;
|
|
gAudioBufferParameters.minAiBufferLength *= gAudioBufferParameters.presetUnk4;
|
|
gAudioBufferParameters.updatesPerFrame *= gAudioBufferParameters.presetUnk4;
|
|
gMaxAudioCmds =
|
|
(gMaxSimultaneousNotes * 0x14 * gAudioBufferParameters.updatesPerFrame) + (temp_s6->numReverbs * 0x20) + 0x1E0;
|
|
persistentMem = DOUBLE_SIZE_ON_64_BIT(temp_s6->persistentSeqMem + temp_s6->persistentBankMem + temp_s6->unk_18);
|
|
temporaryMem = DOUBLE_SIZE_ON_64_BIT(temp_s6->temporarySeqMem + temp_s6->temporaryBankMem + temp_s6->unk_24);
|
|
totalMem = persistentMem + temporaryMem;
|
|
temp = (gAudioSessionPool.size - totalMem) - 0x100;
|
|
sSessionPoolSplit.wantSeq = temp;
|
|
sSessionPoolSplit.wantCustom = totalMem;
|
|
func_800B914C(&sSessionPoolSplit);
|
|
sSeqAndBankPoolSplit.wantPersistent = persistentMem;
|
|
sSeqAndBankPoolSplit.wantTemporary = temporaryMem;
|
|
seq_and_bank_pool_init(&sSeqAndBankPoolSplit);
|
|
sPersistentCommonPoolSplit.wantSeq = DOUBLE_SIZE_ON_64_BIT(temp_s6->persistentSeqMem);
|
|
sPersistentCommonPoolSplit.wantBank = DOUBLE_SIZE_ON_64_BIT(temp_s6->persistentBankMem);
|
|
sPersistentCommonPoolSplit.wantUnused = temp_s6->unk_18;
|
|
persistent_pools_init(&sPersistentCommonPoolSplit);
|
|
sTemporaryCommonPoolSplit.wantSeq = DOUBLE_SIZE_ON_64_BIT(temp_s6->temporarySeqMem);
|
|
sTemporaryCommonPoolSplit.wantBank = DOUBLE_SIZE_ON_64_BIT(temp_s6->temporaryBankMem);
|
|
sTemporaryCommonPoolSplit.wantUnused = temp_s6->unk_24;
|
|
temporary_pools_init(&sTemporaryCommonPoolSplit);
|
|
reset_bank_and_seq_load_status();
|
|
gNotes = soundAlloc(&gNotesAndBuffersPool, gMaxSimultaneousNotes * sizeof(struct Note));
|
|
note_init_all();
|
|
init_note_free_list();
|
|
gNoteSubsEu =
|
|
soundAlloc(&gNotesAndBuffersPool, gAudioBufferParameters.updatesPerFrame * gMaxSimultaneousNotes * 0x10);
|
|
for (var_s5 = 0; var_s5 != 2; var_s5++) {
|
|
gAudioCmdBuffers[var_s5] = soundAlloc(&gNotesAndBuffersPool, gMaxAudioCmds * sizeof(u64));
|
|
}
|
|
for (var_s5 = 0; var_s5 < 4; var_s5++) {
|
|
gSynthesisReverbs[var_s5].useReverb = 0;
|
|
}
|
|
|
|
gNumSynthesisReverbs = temp_s6->numReverbs;
|
|
for (var_s5 = 0; var_s5 < gNumSynthesisReverbs; var_s5++) {
|
|
reverb = &gSynthesisReverbs[var_s5];
|
|
reverbSettings = &temp_s6->reverbSettings[var_s5];
|
|
reverb->windowSize = reverbSettings->windowSize * 64;
|
|
reverb->downsampleRate = reverbSettings->downsampleRate;
|
|
reverb->reverbGain = reverbSettings->gain;
|
|
reverb->useReverb = 8;
|
|
reverb->ringBuffer.left = soundAlloc(&gNotesAndBuffersPool, reverb->windowSize * 2);
|
|
reverb->ringBuffer.right = soundAlloc(&gNotesAndBuffersPool, reverb->windowSize * 2);
|
|
reverb->nextRingBufferPos = 0;
|
|
reverb->unkC = 0;
|
|
reverb->curFrame = 0;
|
|
reverb->bufSizePerChannel = reverb->windowSize;
|
|
reverb->framesLeftToIgnore = 2;
|
|
if (reverb->downsampleRate != 1) {
|
|
reverb->resampleFlags = 1;
|
|
reverb->resampleRate = 0x8000 / reverb->downsampleRate;
|
|
reverb->resampleStateLeft = soundAlloc(&gNotesAndBuffersPool, 0x00000020U);
|
|
reverb->resampleStateRight = soundAlloc(&gNotesAndBuffersPool, 0x00000020U);
|
|
reverb->unk24 = soundAlloc(&gNotesAndBuffersPool, 0x00000020U);
|
|
reverb->unk28 = soundAlloc(&gNotesAndBuffersPool, 0x00000020U);
|
|
for (var_s1 = 0; var_s1 < gAudioBufferParameters.updatesPerFrame; var_s1++) {
|
|
mem = soundAlloc(&gNotesAndBuffersPool, 0x00000300U);
|
|
reverb->items[0][var_s1].toDownsampleLeft = mem;
|
|
reverb->items[0][var_s1].toDownsampleRight = mem + (DEFAULT_LEN_1CH / sizeof(s16));
|
|
mem = soundAlloc(&gNotesAndBuffersPool, 0x00000300U);
|
|
reverb->items[1][var_s1].toDownsampleLeft = mem;
|
|
reverb->items[1][var_s1].toDownsampleRight = mem + (DEFAULT_LEN_1CH / sizeof(s16));
|
|
}
|
|
}
|
|
}
|
|
|
|
func_800BB030(gMaxSimultaneousNotes);
|
|
osWritebackDCacheAll();
|
|
}
|
|
|
|
void* unk_pool1_lookup(s32 poolIdx, s32 id) {
|
|
s32 i;
|
|
|
|
for (i = 0; i < gUnkPool1.pool.numAllocatedEntries; i++) {
|
|
if (gUnkPool1.entries[i].poolIndex == poolIdx && gUnkPool1.entries[i].id == id) {
|
|
return gUnkPool1.entries[i].ptr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// SM64 does not appear to have a function
|
|
// comparable to this one, not a clue what
|
|
// this one is doing.
|
|
void func_800BA8B0(s32 poolIdx, s32 id) {
|
|
ALSeqFile* sp3C;
|
|
s32 temp_a2;
|
|
u32 temp_a1;
|
|
u8* var_a3;
|
|
UNUSED u8* temp_v0;
|
|
UNUSED s32 pad;
|
|
|
|
switch (poolIdx) { /* irregular */
|
|
case 0:
|
|
sp3C = gSeqFileHeader;
|
|
break;
|
|
case 1:
|
|
sp3C = gAlCtlHeader;
|
|
break;
|
|
case 2:
|
|
sp3C = gAlTbl;
|
|
break;
|
|
}
|
|
if (sp3C->seqArray[id].len == 0) {
|
|
id = (s32) sp3C->seqArray[id].offset;
|
|
}
|
|
if (unk_pool1_lookup(poolIdx, id) == NULL) {
|
|
temp_a2 = gUnkPool1.pool.numAllocatedEntries;
|
|
temp_a1 = sp3C->seqArray[id].len;
|
|
var_a3 = sp3C->seqArray[id].offset;
|
|
if (poolIdx == 1) {
|
|
var_a3 += 0x10;
|
|
}
|
|
gUnkPool1.entries[temp_a2].ptr = soundAlloc(&gUnkPool1.pool, temp_a1);
|
|
if (gUnkPool1.entries[temp_a2].ptr != NULL) {
|
|
audio_dma_copy_immediate(var_a3, gUnkPool1.entries[temp_a2].ptr, temp_a1);
|
|
gUnkPool1.entries[temp_a2].poolIndex = poolIdx;
|
|
gUnkPool1.entries[temp_a2].id = id;
|
|
gUnkPool1.entries[temp_a2].size = temp_a1;
|
|
switch (poolIdx) { /* switch 1; irregular */
|
|
case 0: /* switch 1 */
|
|
if (gSeqLoadStatus[id] != 5) {
|
|
gSeqLoadStatus[id] = 5;
|
|
}
|
|
break;
|
|
case 1: /* switch 1 */
|
|
gCtlEntries[id].instruments = (struct Instrument**) (gUnkPool1.entries[temp_a2].ptr + 4);
|
|
func_800BB584(id);
|
|
if (gBankLoadStatus[id] != 5) {
|
|
gBankLoadStatus[id] = 5;
|
|
}
|
|
break;
|
|
case 2: /* switch 1 */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|