diff --git a/include/config/config_audio.h b/include/config/config_audio.h index 1d1f5270..5aa64360 100644 --- a/include/config/config_audio.h +++ b/include/config/config_audio.h @@ -4,12 +4,19 @@ * AUDIO SETTINGS * ******************/ -// Fixes the castle music sometimes triggering after getting a dialog +// Fixes the castle music sometimes triggering after getting a dialog. #define CASTLE_MUSIC_FIX -// Increase audio heap size to allow for more concurrent notes to be played and for more custom sequences/banks to be imported (not supported for SH) +// Increase audio heap size to allow for more concurrent notes to be played and for more custom sequences/banks to be imported (not supported for SH). #define EXPAND_AUDIO_HEAP +// The maximum number of notes (sfx inclusive) that can sound at any given time (not supported for SH). +// Lower values may cause notes to get cut more easily but can potentially improve performance slightly. +// Lower values may cause problems with streamed audio if a sequence used for it is missing channel priority data. +// Vanilla by default only generally allocates 16 or 20 notes at once. Memory usage is always determined by the largest of the two values here. +#define MAX_SIMULTANEOUS_NOTES_EMULATOR 40 +#define MAX_SIMULTANEOUS_NOTES_CONSOLE 32 + // Use a much better implementation of reverb over vanilla's fake echo reverb. Great for caves or eerie levels, as well as just a better audio experience in general. // Reverb parameters can be configured in audio/synthesis.c to meet desired aesthetic/performance needs. Currently US/JP only. Hurts emulator and console performance. //#define BETTER_REVERB diff --git a/include/config/config_safeguards.h b/include/config/config_safeguards.h index 0a5dd97d..23d6b989 100644 --- a/include/config/config_safeguards.h +++ b/include/config/config_safeguards.h @@ -10,6 +10,39 @@ */ +/***************** + * config_audio + */ + +#ifndef MAX_SIMULTANEOUS_NOTES_EMULATOR + #ifdef EXPAND_AUDIO_HEAP + #define MAX_SIMULTANEOUS_NOTES_EMULATOR 40 + #else + #define MAX_SIMULTANEOUS_NOTES_EMULATOR 20 + #endif +#endif // MAX_SIMULTANEOUS_NOTES_EMULATOR + +#ifndef MAX_SIMULTANEOUS_NOTES_CONSOLE + #ifdef EXPAND_AUDIO_HEAP + #define MAX_SIMULTANEOUS_NOTES_EMULATOR 32 + #else + #define MAX_SIMULTANEOUS_NOTES_EMULATOR 16 + #endif +#endif // MAX_SIMULTANEOUS_NOTES_CONSOLE + +#if (MAX_SIMULTANEOUS_NOTES_EMULATOR >= MAX_SIMULTANEOUS_NOTES_CONSOLE) + #define MAX_SIMULTANEOUS_NOTES MAX_SIMULTANEOUS_NOTES_EMULATOR +#else + #define MAX_SIMULTANEOUS_NOTES MAX_SIMULTANEOUS_NOTES_CONSOLE +#endif + +// Anything higher than 64 will most likely crash on boot. Even if it doesn't, it's still dangerous. +#if (MAX_SIMULTANEOUS_NOTES > 64) + #undef MAX_SIMULTANEOUS_NOTES + #define MAX_SIMULTANEOUS_NOTES 64 +#endif + + /***************** * config_graphics */ diff --git a/src/audio/data.c b/src/audio/data.c index 95917497..801c7233 100644 --- a/src/audio/data.c +++ b/src/audio/data.c @@ -38,9 +38,9 @@ struct ReverbSettingsEU sReverbSettings[8] = { struct AudioSessionSettingsEU gAudioSessionPresets[] = { #ifdef EXPAND_AUDIO_HEAP - { /*1*/ 32000,/*2*/ 1,/*3*/ 40,/*4*/ 1,/*5*/ 0, &sReverbSettings[0],/*6*/ 0x7FFF,/*7*/ 0,/*8*/ 0x8200,/*9*/ 0xDC00,/*10*/ 0xE800,/*11*/ 0x5500 }, + { /*1*/ 32000,/*2*/ 1,/*3*/ MAX_SIMULTANEOUS_NOTES,/*4*/ 1,/*5*/ 0, &sReverbSettings[0],/*6*/ 0x7FFF,/*7*/ 0,/*8*/ 0x8200,/*9*/ 0xDC00,/*10*/ 0xE800,/*11*/ 0x5500 }, #else - { /*1*/ 32000,/*2*/ 1,/*3*/ 20,/*4*/ 1,/*5*/ 0, &sReverbSettings[0],/*6*/ 0x7FFF,/*7*/ 0,/*8*/ 0x4100,/*9*/ 0x6E00,/*10*/ 0x7400,/*11*/ 0x2A80 }, + { /*1*/ 32000,/*2*/ 1,/*3*/ MAX_SIMULTANEOUS_NOTES,/*4*/ 1,/*5*/ 0, &sReverbSettings[0],/*6*/ 0x7FFF,/*7*/ 0,/*8*/ 0x4100,/*9*/ 0x6E00,/*10*/ 0x7400,/*11*/ 0x2A80 }, #endif }; #endif @@ -80,14 +80,13 @@ struct ReverbSettingsUS gReverbSettings[18] = { { 1, 0x0800, 0x2FFF }, }; -// TODO: Does using 40/20 instead of 32/16 for gMaxSimultaneousNotes cause memory problems at high capacities or is it good as is? #ifdef EXPAND_AUDIO_HEAP struct AudioSessionSettings gAudioSessionPresets[1] = { - { 32000, 40, 1, 0x1000, 0x2FFF, 0x7FFF, 0x8200, 0xDC00, 0xE800, 0x5500 }, + { 32000, MAX_SIMULTANEOUS_NOTES, 1, 0x1000, 0x2FFF, 0x7FFF, 0x8200, 0xDC00, 0xE800, 0x5500 }, }; #else struct AudioSessionSettings gAudioSessionPresets[1] = { - { 32000, 20, 1, 0x1000, 0x2FFF, 0x7FFF, 0x4100, 0x6E00, 0x7400, 0x2A80 }, + { 32000, MAX_SIMULTANEOUS_NOTES, 1, 0x1000, 0x2FFF, 0x7FFF, 0x4100, 0x6E00, 0x7400, 0x2A80 }, }; #endif #endif diff --git a/src/audio/data.h b/src/audio/data.h index 8e947aa9..ab31a82f 100644 --- a/src/audio/data.h +++ b/src/audio/data.h @@ -13,6 +13,14 @@ #define NUMAIBUFFERS 3 +#if defined(VERSION_EU) +#define DMA_BUF_SIZE_0 0x400 +#define DMA_BUF_SIZE_1 0x200 +#else +#define DMA_BUF_SIZE_0 (144 * 9) +#define DMA_BUF_SIZE_1 (160 * 9) +#endif + // constant .data #if defined(VERSION_EU) || defined(VERSION_SH) extern struct AudioSessionSettingsEU gAudioSessionPresets[]; @@ -108,18 +116,42 @@ extern s16 gAiBufferLengths[NUMAIBUFFERS]; extern u32 gAudioRandom; +#if defined(VERSION_US) || defined(VERSION_JP) +#define NOTES_BUFFER_SIZE \ +( \ + MAX_SIMULTANEOUS_NOTES * ((4 /* updatesPerFrame */ * 20 * 2 * sizeof(u64)) \ + + ALIGN16(sizeof(struct Note)) \ + + (DMA_BUF_SIZE_0 * 3) \ + + (DMA_BUF_SIZE_1) \ + + ALIGN16(sizeof(struct NoteSynthesisBuffers))) \ + + 320 * 2 * sizeof(u64) /* gMaxAudioCmds */ \ +) +#elif defined(VERSION_EU) +#define NOTES_BUFFER_SIZE \ +( \ + MAX_SIMULTANEOUS_NOTES * ((4 /* updatesPerFrame */ * 0x10 * 2 * sizeof(u64)) \ + + ALIGN16(sizeof(struct Note)) \ + + (DMA_BUF_SIZE_0 * 3 * 1 /* presetUnk4 */) \ + + (DMA_BUF_SIZE_1) \ + + ALIGN16(sizeof(struct NoteSynthesisBuffers)) \ + + ALIGN16(4 /* updatesPerFrame */ * sizeof(struct NoteSubEu))) \ + + (0x300 + 4 /* numReverbs */ * 0x20) * 2 * sizeof(u64) /* gMaxAudioCmds */ \ + + 0x4000 /* Extra space to hopefully tolerate whatever the note patch behavior is */ \ +) +#endif + #ifdef EXPAND_AUDIO_HEAP #if defined(VERSION_US) || defined(VERSION_JP) || defined(VERSION_EU) -#define EXT_AUDIO_HEAP_SIZE 0x27400 -#define EXT_AUDIO_INIT_POOL_SIZE 0x02000 +#define EXT_AUDIO_INIT_POOL_SIZE (0x1800 + 0x300) +#define EXT_AUDIO_HEAP_SIZE 0x14D80 #else // SH not yet supported for expanded audio heap -#define EXT_AUDIO_HEAP_SIZE 0x0 #define EXT_AUDIO_INIT_POOL_SIZE 0x0 +#define EXT_AUDIO_HEAP_SIZE 0x0 #endif #else -#define EXT_AUDIO_HEAP_SIZE 0x0 #define EXT_AUDIO_INIT_POOL_SIZE 0x0 +#define EXT_AUDIO_HEAP_SIZE 0x0 #endif #ifdef VERSION_SH @@ -148,14 +180,15 @@ extern OSMesgQueue *D_SH_80350FA8; #endif #if defined(VERSION_EU) || defined(VERSION_SH) -#define AUDIO_HEAP_BASE 0x36B00 -#define AUDIO_INIT_POOL_SIZE (0x2C00 + EXT_AUDIO_INIT_POOL_SIZE) +#define AUDIO_INIT_POOL_SIZE (0x1B00 + EXT_AUDIO_INIT_POOL_SIZE + ALIGN16(MAX_SIMULTANEOUS_NOTES * sizeof(struct Note))) #else -#define AUDIO_HEAP_BASE 0x30750 -#define AUDIO_INIT_POOL_SIZE (0x2500 + EXT_AUDIO_INIT_POOL_SIZE) +#define AUDIO_INIT_POOL_SIZE (0x1600 + EXT_AUDIO_INIT_POOL_SIZE + ALIGN16(MAX_SIMULTANEOUS_NOTES * sizeof(struct Note))) #endif -#define AUDIO_HEAP_SIZE (AUDIO_HEAP_BASE + EXT_AUDIO_HEAP_SIZE + EXT_AUDIO_INIT_POOL_SIZE + BETTER_REVERB_SIZE + REVERB_WINDOW_HEAP_SIZE) +// TODO: needs validation once EU can compile. EU is very likely incorrect! +#define AUDIO_HEAP_BASE (0x14D80 /* sound bank space */ + AUDIO_INIT_POOL_SIZE + EXT_AUDIO_HEAP_SIZE + NOTES_BUFFER_SIZE) + +#define AUDIO_HEAP_SIZE (AUDIO_HEAP_BASE + BETTER_REVERB_SIZE + REVERB_WINDOW_HEAP_SIZE) #ifdef VERSION_SH extern u32 D_SH_80315EF0; diff --git a/src/audio/heap.c b/src/audio/heap.c index b6aba644..3c08d8a7 100644 --- a/src/audio/heap.c +++ b/src/audio/heap.c @@ -1382,19 +1382,20 @@ void audio_reset_session(void) { #if defined(VERSION_JP) || defined(VERSION_US) for (j = 0; j < 2; j++) { - gAudioCmdBuffers[j] = soundAlloc(&gNotesAndBuffersPool, gMaxAudioCmds * sizeof(u64)); + gAudioCmdBuffers[j] = soundAlloc(&gNotesAndBuffersPool, ALIGN16(gMaxAudioCmds * sizeof(u64))); } #endif - gNotes = soundAlloc(&gNotesAndBuffersPool, gMaxSimultaneousNotes * sizeof(struct Note)); + gNotes = soundAlloc(&gNotesAndBuffersPool, ALIGN16(gMaxSimultaneousNotes * sizeof(struct Note))); note_init_all(); init_note_free_list(); #if defined(VERSION_EU) || defined(VERSION_SH) - gNoteSubsEu = soundAlloc(&gNotesAndBuffersPool, (gAudioBufferParameters.updatesPerFrame * gMaxSimultaneousNotes) * sizeof(struct NoteSubEu)); + // NOTE: Cannot be computed automatically in the audio heap define; approximation to be used instead + gNoteSubsEu = soundAlloc(&gNotesAndBuffersPool, ALIGN16((gAudioBufferParameters.updatesPerFrame * gMaxSimultaneousNotes) * sizeof(struct NoteSubEu))); for (j = 0; j != 2; j++) { - gAudioCmdBuffers[j] = soundAlloc(&gNotesAndBuffersPool, gMaxAudioCmds * sizeof(u64)); + gAudioCmdBuffers[j] = soundAlloc(&gNotesAndBuffersPool, ALIGN16(gMaxAudioCmds * sizeof(u64))); } init_reverb_eu(); @@ -1427,6 +1428,15 @@ void audio_reset_session(void) { append_puppyprint_log("Audio Initialised in %dus.", (s32)OS_CYCLES_TO_USEC(osGetTime() - first)); #endif #endif + + if (gIsConsole) + gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_CONSOLE; + else + gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES_EMULATOR; + + if (gMaxSimultaneousNotes > MAX_SIMULTANEOUS_NOTES) + gMaxSimultaneousNotes = MAX_SIMULTANEOUS_NOTES; + sAudioFirstBoot = 1; } diff --git a/src/audio/internal.h b/src/audio/internal.h index c9077872..d01da280 100644 --- a/src/audio/internal.h +++ b/src/audio/internal.h @@ -680,6 +680,7 @@ struct Note { /*0x18, 0x38*/ f32 portamentoFreqScale; /*0x1C, 0x3C*/ f32 vibratoFreqScale; /*0x20*/ u16 samplePosFrac; + /* */ u8 pad2[2]; /*0x24*/ struct AudioBankSound *sound; /*0x28, 0x40*/ struct SequenceChannelLayer *prevParentLayer; /*0x2C, 0x44*/ struct SequenceChannelLayer *parentLayer; @@ -690,6 +691,7 @@ struct Note { /*0x3E*/ u16 targetVolRight; // Q1.15, but will always be non-negative /*0x40*/ u8 reverbVol; // Q1.7 /*0x41*/ u8 unused1; // never read, set to 0x3f + /* */ u8 pad3[2]; /*0x44*/ struct NoteAttributes attributes; /*0x54, 0x58*/ struct AdsrState adsr; /*0x74, 0x7C*/ struct Portamento portamento; @@ -699,7 +701,7 @@ struct Note { /*0xA0*/ s16 reverbVolShifted; // Q1.15 /*0xA2*/ s16 unused2; // never read, set to 0 /*0xA4, 0x00*/ struct AudioListItem listItem; - /* */ u8 pad2[0xc]; + /* */ u8 pad4[0xc]; }; // size = 0xC0 #endif diff --git a/src/audio/load.c b/src/audio/load.c index 268fbf2a..d2003701 100644 --- a/src/audio/load.c +++ b/src/audio/load.c @@ -42,7 +42,7 @@ OSMesgQueue gAudioDmaMesgQueue; OSMesg gAudioDmaMesg; OSIoMesg gAudioDmaIoMesg; -struct SharedDma sSampleDmas[0x60]; +struct SharedDma sSampleDmas[MAX_SIMULTANEOUS_NOTES * 4]; u32 gSampleDmaNumListItems; // sh: 0x803503D4 u32 sSampleDmaListSize1; // sh: 0x803503D8 @@ -335,11 +335,7 @@ void init_sample_dma_buffers(UNUSED s32 arg0) { s32 j; #endif -#if defined(VERSION_EU) - sDmaBufSize = 0x400; -#else - sDmaBufSize = 144 * 9; -#endif + sDmaBufSize = DMA_BUF_SIZE_0; #if defined(VERSION_EU) for (i = 0; i < gMaxSimultaneousNotes * 3 * gAudioBufferParameters.presetUnk4; i++) { @@ -378,11 +374,8 @@ out1: sSampleDmaReuseQueueHead1 = (u8) gSampleDmaNumListItems; sSampleDmaListSize1 = gSampleDmaNumListItems; -#if defined(VERSION_EU) - sDmaBufSize = 0x200; -#else - sDmaBufSize = 160 * 9; -#endif + sDmaBufSize = DMA_BUF_SIZE_1; + for (i = 0; i < gMaxSimultaneousNotes; i++) { sSampleDmas[gSampleDmaNumListItems].buffer = soundAlloc(&gNotesAndBuffersPool, sDmaBufSize); if (sSampleDmas[gSampleDmaNumListItems].buffer == NULL) { @@ -442,7 +435,7 @@ void patch_sound(UNUSED struct AudioBankSound *sound, UNUSED u8 *memBase, UNUSED #if defined(VERSION_EU) else if (sample->loaded == 0x80) { PATCH(sample->sampleAddr, offsetBase); - u8 *mem = soundAlloc(&gNotesAndBuffersPool, sample->sampleSize); // TODO: Memory leak! + u8 *mem = soundAlloc(&gNotesAndBuffersPool, sample->sampleSize); // TODO: Memory issue most likely! if (mem == NULL) { sample->sampleAddr = patched; sample->loaded = 1; diff --git a/src/audio/playback.c b/src/audio/playback.c index 0c0b1fff..9a29f8c4 100644 --- a/src/audio/playback.c +++ b/src/audio/playback.c @@ -1443,9 +1443,9 @@ void note_init_all(void) { #if defined(VERSION_SH) note->synthesisState.synthesisBuffers = sound_alloc_uninitialized(&gNotesAndBuffersPool, sizeof(struct NoteSynthesisBuffers)); #elif defined(VERSION_EU) - note->synthesisState.synthesisBuffers = soundAlloc(&gNotesAndBuffersPool, sizeof(struct NoteSynthesisBuffers)); + note->synthesisState.synthesisBuffers = soundAlloc(&gNotesAndBuffersPool, ALIGN16(sizeof(struct NoteSynthesisBuffers))); #else - note->synthesisBuffers = soundAlloc(&gNotesAndBuffersPool, sizeof(struct NoteSynthesisBuffers)); + note->synthesisBuffers = soundAlloc(&gNotesAndBuffersPool, ALIGN16(sizeof(struct NoteSynthesisBuffers))); #endif } -} +} \ No newline at end of file diff --git a/src/audio/synthesis.h b/src/audio/synthesis.h index eb0242d3..b29cc399 100644 --- a/src/audio/synthesis.h +++ b/src/audio/synthesis.h @@ -63,7 +63,22 @@ extern u8 toggleBetterReverb; #endif -#define REVERB_WINDOW_HEAP_SIZE (REVERB_WINDOW_SIZE_MAX * sizeof(s16) * 2) +#if defined(VERSION_JP) || defined(VERSION_US) +#define REVERB_WINDOW_HEAP_SIZE \ +( \ + (REVERB_WINDOW_SIZE_MAX * sizeof(s16) * 2) \ + + (4 * (16 * sizeof(s16))) \ + + (4 /* gAudioUpdatesPerFrame */ * (2 * DEFAULT_LEN_2CH)) \ +) +#else +#define REVERB_WINDOW_HEAP_SIZE \ +( \ + ((REVERB_WINDOW_SIZE_MAX * sizeof(s16) * 2) \ + + (4 * (16 * sizeof(s16))) \ + + (4 /* gAudioUpdatesPerFrame */ * (2 * DEFAULT_LEN_2CH))) \ + * 4 /* gNumSynthesisReverbs */ \ +) +#endif struct ReverbRingBufferItem { s16 numSamplesAfterDownsampling; diff --git a/src/boot/main.c b/src/boot/main.c index 7761f07a..75a9dc54 100644 --- a/src/boot/main.c +++ b/src/boot/main.c @@ -13,6 +13,7 @@ #include "game/main.h" #include "game/rumble_init.h" #include "game/version.h" +#include "game/vc_check.h" #ifdef UNF #include "usb/usb.h" #include "usb/debug.h" @@ -317,6 +318,15 @@ void thread3_main(UNUSED void *arg) { osSyncPrintf("Linker : %s\n", __linker__); #endif + if (IO_READ(DPC_CLOCK_REG) == 0) { + gIsConsole = FALSE; + gBorderHeight = BORDER_HEIGHT_EMULATOR; + gIsVC = IS_VC(); + } else { + gIsConsole = TRUE; + gBorderHeight = BORDER_HEIGHT_CONSOLE; + } + create_thread(&gSoundThread, THREAD_4_SOUND, thread4_sound, NULL, gThread4Stack + 0x2000, 20); osStartThread(&gSoundThread); diff --git a/src/game/game_init.c b/src/game/game_init.c index 545e9e66..4a8934c6 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -391,15 +391,6 @@ void render_init(void) { #ifdef DEBUG_FORCE_CRASH_ON_BOOT FORCE_CRASH #endif - if (IO_READ(DPC_PIPEBUSY_REG) == 0) { - gIsConsole = FALSE; - gBorderHeight = BORDER_HEIGHT_EMULATOR; - gIsVC = IS_VC(); - } else { - gIsConsole = TRUE; - gBorderHeight = BORDER_HEIGHT_CONSOLE; - } - gGfxPool = &gGfxPools[0]; set_segment_base_addr(SEGMENT_RENDER, gGfxPool->buffer); gGfxSPTask = &gGfxPool->spTask;