diff --git a/include/sounds.h b/include/sounds.h index b164bd17e..82875b361 100644 --- a/include/sounds.h +++ b/include/sounds.h @@ -115,4 +115,38 @@ // Hey, you're very good. See you next time! #define SOUND_CREDITS_FAREWELL SOUND_ARG_LOAD(0x49, 0x00, 0x80, 0x26) +enum MusicSeq { + MUSIC_SEQ_UNKNOWN = -1, + MUSIC_SEQ_00, + MUSIC_SEQ_TITLE_SCREEN, + MUSIC_SEQ_MAIN_MENU, + MUSIC_SEQ_RACEWAYS_WARIO_STADIUM, + MUSIC_SEQ_MOO_MOO_FARM_YOSHI_VALLEY, + MUSIC_SEQ_CHOCO_MOUNTAIN, + MUSIC_SEQ_KOOPA_TROOPA_BEACH, + MUSIC_SEQ_BANSHEE_BOARDWALK, + MUSIC_SEQ_FRAPPE_SNOWLAND, + MUSIC_SEQ_BOWSERS_CASTLE, + MUSIC_SEQ_KALIMARI_DESERT, + MUSIC_SEQ_START_GRID_GP_VS, + MUSIC_SEQ_FINAL_LAP_FANFARE, + MUSIC_SEQ_FINISH_1ST_PLACE, + MUSIC_SEQ_FINISH_2ND_4TH_PLACE, + MUSIC_SEQ_FINISH_5TH_8TH_PLACE, + MUSIC_SEQ_16, + MUSIC_SEQ_STAR_JINGLE, + MUSIC_SEQ_RAINBOW_ROAD, + MUSIC_SEQ_DK_JUNGLE, + MUSIC_SEQ_GAME_OVER, + MUSIC_SEQ_TOADS_TURNPIKE, + MUSIC_SEQ_START_GIRD_TIME_ATTACK, + MUSIC_SEQ_VS_BATTLE_RESULTS, + MUSIC_SEQ_LOSING_RESULTS, + MUSIC_SEQ_BATTLE_ARENAS, + MUSIC_SEQ_AWARD_CEREMONY_BUILDUP, + MUSIC_SEQ_AWARD_CEREMONY_1ST_3RD, + MUSIC_SEQ_STAFF_ROLL, + MUSIC_SEQ_AWARD_CEREMONY_4TH_8TH, +}; + #endif // SOUNDS_H diff --git a/src/audio/GameAudio.h b/src/audio/GameAudio.h new file mode 100644 index 000000000..1135576f3 --- /dev/null +++ b/src/audio/GameAudio.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +static struct { + std::thread thread; + std::condition_variable cv_to_thread, cv_from_thread; + std::mutex mutex; + bool running; + bool processing; +} audio; diff --git a/src/audio/effects.c b/src/audio/effects.c index 4a5c2dcc3..822ca29be 100644 --- a/src/audio/effects.c +++ b/src/audio/effects.c @@ -12,7 +12,7 @@ void sequence_channel_process_sound(struct SequenceChannel* seqChannel, s32 reca s32 i; if (seqChannel->changes.as_bitfields.volume || recalculateVolume) { - channelVolume = seqChannel->volume * seqChannel->volumeScale * seqChannel->seqPlayer->appliedFadeVolume; + channelVolume = (seqChannel->volume * (seqChannel->volumeScale * seqChannel->seqPlayer->fadeVolume)) * seqChannel->seqPlayer->gameVolume; if (seqChannel->seqPlayer->muted && (seqChannel->muteBehavior & MUTE_BEHAVIOR_SOFTEN) != 0) { channelVolume = seqChannel->seqPlayer->muteVolumeScale * channelVolume; } diff --git a/src/audio/external.c b/src/audio/external.c index ec4ed3846..3b12d26b1 100644 --- a/src/audio/external.c +++ b/src/audio/external.c @@ -92,7 +92,7 @@ f32 D_800EA120[] = { 0.0f, 0.0f, 0.0f, 0.0f }; f32 D_800EA130[] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; f32 D_800EA150 = 1.4f; u8 D_800EA154[] = { 2, 2, 88, 90, 3, 48, 88, 48 }; -u16 D_800EA15C = 0; +u16 gCurrentMusicSeq = 0; u16 D_800EA160 = 0; u8 D_800EA164 = 0; s8 D_800EA168 = 0; @@ -565,7 +565,7 @@ void func_800C2474(void) { D_800EA16C = 0; func_800CBBB8(0xF2000000U, 0); D_800EA16C = 0; - D_800EA15C = 0; + gCurrentMusicSeq = 0; D_800EA160 = 0; D_800EA164 = 0; D_800EA178 = 1.0f; @@ -1253,7 +1253,7 @@ void func_800C4398(void) { u8 soundIndex; u8 var_a3; struct Sound* var_a2; - u8 var_t2; + u8 var_t2 = 0; u32 var_t3; var_a2 = &sSoundRequests[sNumProcessedSoundRequests]; @@ -2834,9 +2834,9 @@ void play_sound2(s32 soundBits) { play_sound(soundBits, &D_800EA1C8, 4, &D_800EA1D4, &D_800EA1D4, &D_800EA1DC); } -void func_800C8EAC(u16 arg0) { +void play_sequence(u16 arg0) { func_800C3448(arg0 | 0x10000); - D_800EA15C = arg0; + gCurrentMusicSeq = arg0; } void func_800C8EF8(u16 arg0) { @@ -3284,7 +3284,7 @@ void func_800CA49C(u8 arg0) { func_800C3448(0x100100FF); // 0x19000000 func_800C3448(0x110100FF); func_800C8EF8(0xC); - func_800C3448(D_800EA15C | 0xC1500000); + func_800C3448(gCurrentMusicSeq | 0xC1500000); func_800C3448(0xC130017D); } D_8018FC08 = D_8018FC08 + 1; @@ -3334,20 +3334,20 @@ void func_800CA730(u8 arg0) { if (D_8018FC08 != 0) { if (((u32) (gSequencePlayers[1].enabled)) == 0) { func_800C3608(1, 5); - func_800C8EAC(D_800EA15C); + play_sequence(gCurrentMusicSeq); func_800C3448(0xB001307DU); } else if ((func_800C3508(1) == 0xC) || (func_800C357C(0x0101000C) == 0)) { func_800C3448(0xC1F00000U); - func_800C3448(D_800EA15C | 0xC1500000); + func_800C3448(gCurrentMusicSeq | 0xC1500000); func_800C3448(0xC130017DU); } else { func_800C3448(0x110100FFU); - func_800C8EAC(D_800EA15C); + play_sequence(gCurrentMusicSeq); func_800C3448(0xB001307DU); } } else { func_800C3448(0x110100FFU); - func_800C8EAC(D_800EA15C); + play_sequence(gCurrentMusicSeq); } } D_800EA164 = 0; @@ -3512,11 +3512,11 @@ void func_800CB14C() { if (D_800EA174 != 0) { D_800EA174++; if (D_800EA174 == 3) { - func_800C8EAC(0x001AU); + play_sequence(MUSIC_SEQ_AWARD_CEREMONY_BUILDUP); func_800C3448(0x4000007F); } if (D_800EA174 == 0x012C) { - func_800C8EAC(0x001BU); + play_sequence(MUSIC_SEQ_AWARD_CEREMONY_1ST_3RD); func_800C3448(0x4000007F); func_800C8EF8(0x001DU); func_800C3448(0x41000000); @@ -3541,12 +3541,17 @@ void func_800CB14C() { func_800C3448(0x110100FF); } if (D_800EA174 == 0x04CE) { - func_800C8EAC(0x0014U); + play_sequence(MUSIC_SEQ_GAME_OVER); func_800C3448(0x4000007F); } } } +void audio_set_player_volume(u8 player, f32 volume) { + gSequencePlayers[player].gameVolume = volume; + gSequencePlayers[player].recalculateVolume = 1; +} + // run audio? void func_800CB2C4() { func_800C1F8C(); diff --git a/src/audio/external.h b/src/audio/external.h index b11bf6d02..01022cd8f 100644 --- a/src/audio/external.h +++ b/src/audio/external.h @@ -271,7 +271,7 @@ void func_800C8AE4(void); void func_800C8C7C(u8); void func_800C8CCC(void); void play_sound2(s32); -void func_800C8EAC(u16); +void play_sequence(u16); void func_800C8EF8(u16); void func_800C8F44(u8); void func_800C8F80(u8, u32); @@ -322,6 +322,8 @@ void func_800CB14C(void); void func_800CB2C4(void); void func_800CBC24(void); +extern void audio_set_player_volume(u8 player, f32 volume); + // This is some from other file, its definitely not part of audio's data/bss extern s8 D_801657E5; @@ -399,7 +401,7 @@ extern f32 D_800EA120[4]; extern f32 D_800EA130[8]; extern f32 D_800EA150; // = 1.4f; extern u8 D_800EA154[]; -extern u16 D_800EA15C; +extern u16 gCurrentMusicSeq; extern u16 D_800EA160; extern u8 D_800EA164; extern s8 D_800EA168; diff --git a/src/audio/heap.c b/src/audio/heap.c index edb2440f5..3e88dbf1e 100644 --- a/src/audio/heap.c +++ b/src/audio/heap.c @@ -663,6 +663,7 @@ void audio_reset_session(void) { 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]; @@ -695,6 +696,7 @@ void audio_reset_session(void) { } } } + func_800BB030(gMaxSimultaneousNotes); osWritebackDCacheAll(); } diff --git a/src/audio/heap.h b/src/audio/heap.h index 0113212ba..ae71257c4 100644 --- a/src/audio/heap.h +++ b/src/audio/heap.h @@ -12,8 +12,8 @@ #define SOUND_LOAD_STATUS_4 4 #define SOUND_LOAD_STATUS_5 5 -#define IS_BANK_LOAD_COMPLETE(bankId) (gBankLoadStatus[bankId] >= SOUND_LOAD_STATUS_COMPLETE) -#define IS_SEQ_LOAD_COMPLETE(seqId) (gSeqLoadStatus[seqId] >= SOUND_LOAD_STATUS_COMPLETE) +#define IS_BANK_LOAD_COMPLETE(bankId) GameEngine_IsBankLoaded(bankId) +#define IS_SEQ_LOAD_COMPLETE(seqId) GameEngine_IsSequenceLoaded(seqId) struct SoundAllocPool { u8* start; diff --git a/src/audio/internal.h b/src/audio/internal.h index 1c615c29e..8d0dfbc17 100644 --- a/src/audio/internal.h +++ b/src/audio/internal.h @@ -3,6 +3,7 @@ #include #include "common_structs.h" +#include "port/resource/type/AudioSequence.h" #define SEQUENCE_PLAYERS 4 #define SEQUENCE_CHANNELS 48 @@ -121,13 +122,13 @@ struct AdpcmLoop { u32 end; u32 count; u32 pad; - s16 state[16]; // only exists if count != 0. 8-byte aligned + s16* state; // only exists if count != 0. 8-byte aligned }; struct AdpcmBook { s32 order; s32 npredictors; - s16 book[1]; // size 8 * order * npredictors. 8-byte aligned + s16* book; // size 8 * order * npredictors. 8-byte aligned }; struct AudioBankSample { @@ -169,7 +170,7 @@ struct AudioBank { }; // dynamic size struct CtlEntry { - u8 unused; + u8 bankId; u8 numInstruments; u8 numDrums; struct Instrument** instruments; @@ -227,6 +228,7 @@ struct SequencePlayer { /*0x130, 0x13C*/ u8* bankDmaCurrMemAddr; /*0x138, 0x140*/ uintptr_t bankDmaCurrDevAddr; /*0x13C, 0x144*/ size_t bankDmaRemaining; + f32 gameVolume; }; // size = 0x140, 0x148 on EU, 0x14C on SH struct AdsrSettings { @@ -556,13 +558,14 @@ struct AudioBufferParametersEU { * The version of that function in MK64 is significantly different * from its SM64 counterpart * Or we just have a poor understanding of this part of the system. +**/ struct EuAudioCmd { union { #if IS_BIG_ENDIAN struct { u8 op; - u8 arg1; + u8 bankId; u8 arg2; u8 arg3; } s; @@ -570,7 +573,7 @@ struct EuAudioCmd { struct { u8 arg3; u8 arg2; - u8 arg1; + u8 bankId; u8 op; } s; #endif @@ -595,25 +598,7 @@ struct EuAudioCmd { #endif } u2; }; -**/ -struct EuAudioCmd { - union { - struct { - u8 op; - u8 bankId; - u8 arg2; - u8 arg3; - } s; - u32 first; - } u; - union { - s32 as_s32; - u32 as_u32; - f32 as_f32; - u8 as_u8; - s8 as_s8; - } u2; -}; +extern void create_next_audio_buffer(s16* samples, u32 num_samples); #endif // AUDIO_INTERNAL_H diff --git a/src/audio/load.c b/src/audio/load.c index 3d8c21d23..4ed6ed5a4 100644 --- a/src/audio/load.c +++ b/src/audio/load.c @@ -5,10 +5,12 @@ #include "audio/data.h" #include "audio/heap.h" #include "audio/internal.h" +#include "audio/external.h" #include "audio/playback.h" #include "audio/synthesis.h" #include "audio/seqplayer.h" #include "audio/port_eu.h" +#include "port/Engine.h" #include "buffers/gfx_output_buffer.h" #include @@ -598,58 +600,19 @@ void* sequence_dma_async(s32 seqId, s32 arg1, struct SequencePlayer* seqPlayer) return ptr; } -u8 get_missing_bank(u32 seqId, s32* nonNullCount, s32* nullCount) { - void* temp; - u32 bankId; - u16 offset; - u8 i; - u8 ret; - - *nullCount = 0; - *nonNullCount = 0; - offset = ((u16*) gAlBankSets)[seqId]; - for (i = gAlBankSets[offset++], ret = 0; i != 0; i--) { - bankId = gAlBankSets[offset++]; - - if (IS_BANK_LOAD_COMPLETE(bankId) == true) { - temp = get_bank_or_seq(1, 2, bankId); - } else { - temp = NULL; - } - - if (temp == NULL) { - (*nullCount)++; - ret = bankId; - } else { - (*nonNullCount)++; - } - } - - return ret; +uint8_t* load_sequence_immediate(s32 seqId, s32 arg1) { + return GameEngine_LoadSequence(seqId)->data; } -struct AudioBank* load_banks_immediate(s32 seqId, u8* outDefaultBank) { - void* ret; +struct CtlEntry* load_banks_immediate(s32 seqId, u8 *outDefaultBank) { u32 bankId; - u16 offset; - u8 i; - - offset = ((u16*) gAlBankSets)[seqId]; - for (i = gAlBankSets[offset++]; i != 0; i--) { - bankId = gAlBankSets[offset++]; - - if (IS_BANK_LOAD_COMPLETE(bankId) == true) { - ret = get_bank_or_seq(1, 2, bankId); - } else { - ret = NULL; - } - - if (ret == NULL) { - ret = bank_load_immediate(bankId, 2); - } + struct AudioSequenceData *seqData = GameEngine_LoadSequence(seqId); + struct CtlEntry *output; + for(size_t i = 0; i < seqData->bankCount; i++) { + output = GameEngine_LoadBank(bankId = seqData->banks[i]); } *outDefaultBank = bankId; - return ret; + return output; } void preload_sequence(u32 seqId, u8 preloadMask) { @@ -660,9 +623,9 @@ void preload_sequence(u32 seqId, u8 preloadMask) { return; } - if (gSeqFileHeader->seqArray[seqId].len == 0) { - seqId = (u32) gSeqFileHeader->seqArray[seqId].offset; - } + // if (gSeqFileHeader->seqArray[seqId].len == 0) { + // seqId = (u32) gSeqFileHeader->seqArray[seqId].offset; + // } gAudioLoadLock = AUDIO_LOCK_LOADING; if (preloadMask & PRELOAD_BANKS) { @@ -671,8 +634,8 @@ void preload_sequence(u32 seqId, u8 preloadMask) { if (preloadMask & PRELOAD_SEQUENCE) { //! @bug should be IS_SEQ_LOAD_COMPLETE - if (IS_BANK_LOAD_COMPLETE(seqId) == true) { - sequenceData = get_bank_or_seq(0, 2, seqId); + if (IS_SEQ_LOAD_COMPLETE(seqId) == true) { + sequenceData = load_sequence_immediate(seqId, 2); } else { sequenceData = NULL; } @@ -696,63 +659,32 @@ void load_sequence(u32 player, u32 seqId, s32 loadAsync) { } void load_sequence_internal(u32 player, u32 seqId, s32 loadAsync) { - void* sequenceData; - struct SequencePlayer* seqPlayer = &gSequencePlayers[player]; - UNUSED u32 padding[2]; + struct SequencePlayer *seqPlayer = &gSequencePlayers[player]; if (seqId >= gSequenceCount) { return; } - if (gSeqFileHeader->seqArray[seqId].len == 0) { - seqId = (u32) gSeqFileHeader->seqArray[seqId].offset; + sequence_player_disable(seqPlayer); + struct CtlEntry* bank = load_banks_immediate(seqId, &seqPlayer->defaultBank[0]); + + if (bank == NULL) { + return; } - sequence_player_disable(seqPlayer); - if (loadAsync) { - s32 numMissingBanks = 0; - s32 dummy = 0; - s32 bankId = get_missing_bank(seqId, &dummy, &numMissingBanks); - if (numMissingBanks == 1) { - if (bank_load_async(bankId, 2, seqPlayer) == NULL) { - return; - } - /** - * @bug This should set the last bank (i.e. the first in the JSON) - * as default, not the missing one. This code path never gets - * taken, though -- all sequence loading is synchronous. - */ - seqPlayer->defaultBank[0] = bankId; - } else { - if (load_banks_immediate(seqId, &seqPlayer->defaultBank[0]) == NULL) { - return; - } - } - } else if (load_banks_immediate(seqId, &seqPlayer->defaultBank[0]) == NULL) { + eu_stubbed_printf_2("Seq %d:Default Load Id is %d\n", seqId, seqPlayer->defaultBank[0]); + eu_stubbed_printf_0("Seq Loading Start\n"); + + uint8_t* sequenceData = load_sequence_immediate(seqId, 2); + if (sequenceData == NULL) { return; } seqPlayer->seqId = seqId; - sequenceData = get_bank_or_seq(0, 2, seqId); - if (sequenceData == NULL) { - if (seqPlayer->seqDmaInProgress) { - return; - } - if (loadAsync) { - sequenceData = sequence_dma_async(seqId, 2, seqPlayer); - } else { - sequenceData = sequence_dma_immediate(seqId, 2); - } - - if (sequenceData == NULL) { - return; - } - } - init_sequence_player(player); seqPlayer->scriptState.depth = 0; seqPlayer->delay = 0; - seqPlayer->enabled = true; + seqPlayer->enabled = 1; seqPlayer->seqData = sequenceData; seqPlayer->scriptState.pc = sequenceData; } @@ -801,21 +733,8 @@ void audio_init(void) { #endif // UTODO: Which is the correct one? - switch (0) { /* irregular */ - case 0: - D_803B7178 = 20.03042f; - gRefreshRate = 0x00000032; - break; - case 2: - D_803B7178 = 16.546f; - gRefreshRate = 0x0000003C; - break; - case 1: - default: - D_803B7178 = 16.713f; - gRefreshRate = 0x0000003C; - break; - } + D_803B7178 = 16.713f; + gRefreshRate = 60; port_eu_init(); for (i = 0; i < NUMAIBUFFERS; i++) { gAiBufferLengths[i] = 0xa0; @@ -845,6 +764,7 @@ void audio_init(void) { gAudioResetPresetIdToLoad = 0; gAudioResetStatus = one; audio_shut_down_and_reset_step(); + gSequenceCount = GameEngine_GetSequenceCount(); #ifdef TARGET_N64 gSeqFileHeader = (ALSeqFile*) sp60; test = &_sequencesSegmentRomStart; @@ -884,6 +804,11 @@ void audio_init(void) { sound_alloc_pool_init(&gUnkPool1.pool, soundAlloc(&gAudioInitPool, (u32) D_800EA5D8), (u32) D_800EA5D8); init_sequence_players(); gAudioLoadLock = 0x76557364; + + audio_set_player_volume(SEQ_PLAYER_LEVEL, CVarGetFloat("gMainMusicVolume", 1.0f)); + audio_set_player_volume(SEQ_PLAYER_ENV, CVarGetFloat("gEnvironmentVolume", 1.0f)); + audio_set_player_volume(SEQ_PLAYER_SFX, CVarGetFloat("gSFXMusicVolume", 1.0f)); + } #else #ifdef VERSION_EU diff --git a/src/audio/load.h b/src/audio/load.h index 81855ed30..e818e6806 100644 --- a/src/audio/load.h +++ b/src/audio/load.h @@ -39,8 +39,7 @@ struct AudioBank* bank_load_immediate(s32, s32); struct AudioBank* bank_load_async(s32, s32, struct SequencePlayer*); void* sequence_dma_immediate(s32, s32); void* sequence_dma_async(s32, s32, struct SequencePlayer*); -u8 get_missing_bank(u32 seqId, s32* nonNullCount, s32* nullCount); -struct AudioBank* load_banks_immediate(s32, u8*); +struct CtlEntry* load_banks_immediate(s32, u8*); void preload_sequence(u32, u8); void load_sequence(u32, u32, s32); void load_sequence_internal(u32, u32, s32); diff --git a/src/audio/mixer.c b/src/audio/mixer.c index 8ed6e12d6..a1154886e 100644 --- a/src/audio/mixer.c +++ b/src/audio/mixer.c @@ -1,7 +1,13 @@ -#include +#include +#include +#include +#include + #include "mixer.h" -#pragma GCC optimize("unroll-loops") +#ifndef __clang__ +#pragma GCC optimize ("unroll-loops") +#endif #define ROUND_UP_64(v) (((v) + 63) & ~63) #define ROUND_UP_32(v) (((v) + 31) & ~31) @@ -9,78 +15,561 @@ #define ROUND_UP_8(v) (((v) + 7) & ~7) #define ROUND_DOWN_16(v) ((v) & ~0xf) -#ifdef NEW_AUDIO_UCODE -#define BUF_SIZE 2880 -#define BUF_U8(a) (rspa.buf.as_u8 + ((a) - 0x450)) -#define BUF_S16(a) (rspa.buf.as_s16 + ((a) - 0x450) / sizeof(int16_t)) -#else -#define BUF_SIZE 2512 +//#define DMEM_BUF_SIZE (0x1000 - 0x0330 - 0x10 - 0x40) +#define DMEM_BUF_SIZE 0x17D0 #define BUF_U8(a) (rspa.buf.as_u8 + (a)) #define BUF_S16(a) (rspa.buf.as_s16 + (a) / sizeof(int16_t)) -#endif static struct { uint16_t in; uint16_t out; uint16_t nbytes; -#ifdef NEW_AUDIO_UCODE uint16_t vol[2]; uint16_t rate[2]; uint16_t vol_wet; uint16_t rate_wet; -#else - int16_t vol[2]; - uint16_t dry_right; - uint16_t wet_left; - uint16_t wet_right; - - int16_t target[2]; - int32_t rate[2]; - - int16_t vol_dry; - int16_t vol_wet; -#endif - - ADPCM_STATE* adpcm_loop_state; + ADPCM_STATE *adpcm_loop_state; int16_t adpcm_table[8][2][8]; -#ifdef NEW_AUDIO_UCODE uint16_t filter_count; int16_t filter[8]; -#endif union { - int16_t as_s16[BUF_SIZE / sizeof(int16_t)]; - uint8_t as_u8[BUF_SIZE]; + int16_t as_s16[DMEM_BUF_SIZE / sizeof(int16_t)]; + uint8_t as_u8[DMEM_BUF_SIZE]; } buf; } rspa; -void aDownsampleHalfImpl(uint16_t n_samples, uint16_t in_addr, uint16_t out_addr) { - int16_t* in = BUF_S16(in_addr); - int16_t* out = BUF_S16(out_addr); - int n = ROUND_UP_8(n_samples); +static int16_t resample_table[64][4] = { + {0x0c39, 0x66ad, 0x0d46, 0xffdf}, {0x0b39, 0x6696, 0x0e5f, 0xffd8}, + {0x0a44, 0x6669, 0x0f83, 0xffd0}, {0x095a, 0x6626, 0x10b4, 0xffc8}, + {0x087d, 0x65cd, 0x11f0, 0xffbf}, {0x07ab, 0x655e, 0x1338, 0xffb6}, + {0x06e4, 0x64d9, 0x148c, 0xffac}, {0x0628, 0x643f, 0x15eb, 0xffa1}, + {0x0577, 0x638f, 0x1756, 0xff96}, {0x04d1, 0x62cb, 0x18cb, 0xff8a}, + {0x0435, 0x61f3, 0x1a4c, 0xff7e}, {0x03a4, 0x6106, 0x1bd7, 0xff71}, + {0x031c, 0x6007, 0x1d6c, 0xff64}, {0x029f, 0x5ef5, 0x1f0b, 0xff56}, + {0x022a, 0x5dd0, 0x20b3, 0xff48}, {0x01be, 0x5c9a, 0x2264, 0xff3a}, + {0x015b, 0x5b53, 0x241e, 0xff2c}, {0x0101, 0x59fc, 0x25e0, 0xff1e}, + {0x00ae, 0x5896, 0x27a9, 0xff10}, {0x0063, 0x5720, 0x297a, 0xff02}, + {0x001f, 0x559d, 0x2b50, 0xfef4}, {0xffe2, 0x540d, 0x2d2c, 0xfee8}, + {0xffac, 0x5270, 0x2f0d, 0xfedb}, {0xff7c, 0x50c7, 0x30f3, 0xfed0}, + {0xff53, 0x4f14, 0x32dc, 0xfec6}, {0xff2e, 0x4d57, 0x34c8, 0xfebd}, + {0xff0f, 0x4b91, 0x36b6, 0xfeb6}, {0xfef5, 0x49c2, 0x38a5, 0xfeb0}, + {0xfedf, 0x47ed, 0x3a95, 0xfeac}, {0xfece, 0x4611, 0x3c85, 0xfeab}, + {0xfec0, 0x4430, 0x3e74, 0xfeac}, {0xfeb6, 0x424a, 0x4060, 0xfeaf}, + {0xfeaf, 0x4060, 0x424a, 0xfeb6}, {0xfeac, 0x3e74, 0x4430, 0xfec0}, + {0xfeab, 0x3c85, 0x4611, 0xfece}, {0xfeac, 0x3a95, 0x47ed, 0xfedf}, + {0xfeb0, 0x38a5, 0x49c2, 0xfef5}, {0xfeb6, 0x36b6, 0x4b91, 0xff0f}, + {0xfebd, 0x34c8, 0x4d57, 0xff2e}, {0xfec6, 0x32dc, 0x4f14, 0xff53}, + {0xfed0, 0x30f3, 0x50c7, 0xff7c}, {0xfedb, 0x2f0d, 0x5270, 0xffac}, + {0xfee8, 0x2d2c, 0x540d, 0xffe2}, {0xfef4, 0x2b50, 0x559d, 0x001f}, + {0xff02, 0x297a, 0x5720, 0x0063}, {0xff10, 0x27a9, 0x5896, 0x00ae}, + {0xff1e, 0x25e0, 0x59fc, 0x0101}, {0xff2c, 0x241e, 0x5b53, 0x015b}, + {0xff3a, 0x2264, 0x5c9a, 0x01be}, {0xff48, 0x20b3, 0x5dd0, 0x022a}, + {0xff56, 0x1f0b, 0x5ef5, 0x029f}, {0xff64, 0x1d6c, 0x6007, 0x031c}, + {0xff71, 0x1bd7, 0x6106, 0x03a4}, {0xff7e, 0x1a4c, 0x61f3, 0x0435}, + {0xff8a, 0x18cb, 0x62cb, 0x04d1}, {0xff96, 0x1756, 0x638f, 0x0577}, + {0xffa1, 0x15eb, 0x643f, 0x0628}, {0xffac, 0x148c, 0x64d9, 0x06e4}, + {0xffb6, 0x1338, 0x655e, 0x07ab}, {0xffbf, 0x11f0, 0x65cd, 0x087d}, + {0xffc8, 0x10b4, 0x6626, 0x095a}, {0xffd0, 0x0f83, 0x6669, 0x0a44}, + {0xffd8, 0x0e5f, 0x6696, 0x0b39}, {0xffdf, 0x0d46, 0x66ad, 0x0c39} +}; + +static inline int16_t clamp16(int32_t v) { + if (v < -0x8000) { + return -0x8000; + } else if (v > 0x7fff) { + return 0x7fff; + } + return (int16_t)v; +} + +static inline int32_t clamp32(int64_t v) { + if (v < -0x7fffffff - 1) { + return -0x7fffffff - 1; + } else if (v > 0x7fffffff) { + return 0x7fffffff; + } + return (int32_t)v; +} + +void aClearBufferImpl(uint16_t addr, int nbytes) { + nbytes = ROUND_UP_16(nbytes); + memset(BUF_U8(addr), 0, nbytes); +} + +void aLoadBufferImpl(const void *source_addr, uint16_t dest_addr, uint16_t nbytes) { +#if __SANITIZE_ADDRESS__ + for (size_t i = 0; i < ROUND_DOWN_16(nbytes); i++) { + BUF_U8(dest_addr)[i] = ((const unsigned char*)source_addr)[i]; + } +#else + memcpy(BUF_U8(dest_addr), source_addr, ROUND_DOWN_16(nbytes)); +#endif +} + +void aSaveBufferImpl(uint16_t source_addr, int16_t *dest_addr, uint16_t nbytes) { + //printf("source_addr: %x\n dest_addr; %x\n nbytes: %d\n", source_addr, dest_addr, nbytes); + //if (nbytes > 704) {nbytes = 704;} + memcpy(dest_addr, BUF_S16(source_addr), ROUND_DOWN_16(nbytes)); +} + +void aLoadADPCMImpl(int num_entries_times_16, const int16_t *book_source_addr) { + memcpy(rspa.adpcm_table, book_source_addr, num_entries_times_16); +} + +void aSetBufferImpl(uint8_t flags, uint16_t in, uint16_t out, uint16_t nbytes) { + rspa.in = in; + rspa.out = out; + rspa.nbytes = nbytes; +} + +void aInterleaveImpl(uint16_t left, uint16_t right) { + int count = ROUND_UP_16(rspa.nbytes) / sizeof(int16_t) / 8; + int16_t *l = BUF_S16(left); + int16_t *r = BUF_S16(right); + int16_t *d = BUF_S16(rspa.out); + + while (count > 0) { + int16_t l0 = *l++; + int16_t l1 = *l++; + int16_t l2 = *l++; + int16_t l3 = *l++; + int16_t l4 = *l++; + int16_t l5 = *l++; + int16_t l6 = *l++; + int16_t l7 = *l++; + int16_t r0 = *r++; + int16_t r1 = *r++; + int16_t r2 = *r++; + int16_t r3 = *r++; + int16_t r4 = *r++; + int16_t r5 = *r++; + int16_t r6 = *r++; + int16_t r7 = *r++; + *d++ = l0; + *d++ = r0; + *d++ = l1; + *d++ = r1; + *d++ = l2; + *d++ = r2; + *d++ = l3; + *d++ = r3; + *d++ = l4; + *d++ = r4; + *d++ = l5; + *d++ = r5; + *d++ = l6; + *d++ = r6; + *d++ = l7; + *d++ = r7; + --count; + } +} + +void aDMEMMoveImpl(uint16_t in_addr, uint16_t out_addr, int nbytes) { + nbytes = ROUND_UP_16(nbytes); + memmove(BUF_U8(out_addr), BUF_U8(in_addr), nbytes); +} + +void aSetLoopImpl(ADPCM_STATE *adpcm_loop_state) { + rspa.adpcm_loop_state = adpcm_loop_state; +} + +void aADPCMdecImpl(uint8_t flags, ADPCM_STATE state) { + uint8_t *in = BUF_U8(rspa.in); + int16_t *out = BUF_S16(rspa.out); + int nbytes = ROUND_UP_32(rspa.nbytes); + if (flags & A_INIT) { + memset(out, 0, 16 * sizeof(int16_t)); + } else if (flags & A_LOOP) { + memcpy(out, rspa.adpcm_loop_state, 16 * sizeof(int16_t)); + } else { + memcpy(out, state, 16 * sizeof(int16_t)); + } + out += 16; + + while (nbytes > 0) { + int shift = *in >> 4; // should be in 0..12 or 0..14 + int table_index = *in++ & 0xf; // should be in 0..7 + int16_t (*tbl)[8] = rspa.adpcm_table[table_index]; + int i; + + for (i = 0; i < 2; i++) { + int16_t ins[8]; + int16_t prev1 = out[-1]; + int16_t prev2 = out[-2]; + int j, k; + for (j = 0; j < 4; j++) { + ins[j * 2] = (((*in >> 4) << 28) >> 28) << shift; + ins[j * 2 + 1] = (((*in++ & 0xf) << 28) >> 28) << shift; + } + for (j = 0; j < 8; j++) { + int32_t acc = tbl[0][j] * prev2 + tbl[1][j] * prev1 + (ins[j] << 11); + for (k = 0; k < j; k++) { + acc += tbl[1][((j - k) - 1)] * ins[k]; + } + acc >>= 11; + *out++ = clamp16(acc); + } + } + nbytes -= 16 * sizeof(int16_t); + } + memcpy(state, out - 16, 16 * sizeof(int16_t)); +} + +void aResampleImpl(uint8_t flags, uint16_t pitch, RESAMPLE_STATE state) { + int16_t tmp[32]; + int16_t *in_initial = BUF_S16(rspa.in); + int16_t *in = in_initial; + int16_t *out = BUF_S16(rspa.out); + int nbytes = ROUND_UP_16(rspa.nbytes); + uint32_t pitch_accumulator; + int i; + int16_t *tbl; + int32_t sample; + + if (flags & A_INIT) { + memset(tmp, 0, 5 * sizeof(int16_t)); + } else { + memcpy(tmp, state, 16 * sizeof(int16_t)); + } + if (flags & 2) { + memcpy(in - 8, tmp + 8, 8 * sizeof(int16_t)); + in -= tmp[5] / sizeof(int16_t); + } + in -= 4; + pitch_accumulator = (uint16_t)tmp[4]; + memcpy(in, tmp, 4 * sizeof(int16_t)); do { - *out++ = *in++; - in++; - *out++ = *in++; - in++; - *out++ = *in++; - in++; - *out++ = *in++; - in++; - *out++ = *in++; - in++; - *out++ = *in++; - in++; - *out++ = *in++; - in++; - *out++ = *in++; - in++; + for (i = 0; i < 8; i++) { + tbl = resample_table[pitch_accumulator * 64 >> 16]; + sample = ((in[0] * tbl[0] + 0x4000) >> 15) + + ((in[1] * tbl[1] + 0x4000) >> 15) + + ((in[2] * tbl[2] + 0x4000) >> 15) + + ((in[3] * tbl[3] + 0x4000) >> 15); + *out++ = clamp16(sample); + + pitch_accumulator += (pitch << 1); + in += pitch_accumulator >> 16; + pitch_accumulator %= 0x10000; + } + nbytes -= 8 * sizeof(int16_t); + } while (nbytes > 0); + + state[4] = (int16_t)pitch_accumulator; + memcpy(state, in, 4 * sizeof(int16_t)); + i = (in - in_initial + 4) & 7; + in -= i; + if (i != 0) { + i = -8 - i; + } + state[5] = i; + memcpy(state + 8, in, 8 * sizeof(int16_t)); +} + +void aEnvSetup1Impl(uint8_t initial_vol_wet, uint16_t rate_wet, uint16_t rate_left, uint16_t rate_right) { + rspa.vol_wet = (uint16_t)(initial_vol_wet << 8); + rspa.rate_wet = 0; + rspa.rate[0] = rate_left; + rspa.rate[1] = rate_right; +} + +void aEnvSetup2Impl(uint16_t initial_vol_left, uint16_t initial_vol_right) { + rspa.vol[0] = initial_vol_left; + rspa.vol[1] = initial_vol_right; +} + +void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb, + bool neg_left, bool neg_right, + uint16_t dry_left_addr, uint16_t dry_right_addr, + uint16_t wet_left_addr, uint16_t wet_right_addr) +{ + swap_reverb = false; + int16_t *in = BUF_S16(in_addr); + int16_t *dry[2] = {BUF_S16(dry_left_addr), BUF_S16(dry_right_addr)}; + int16_t *wet[2] = {BUF_S16(wet_left_addr), BUF_S16(wet_right_addr)}; + int16_t negs[2] = {neg_left ? -1 : 0, neg_right ? -1 : 0}; + int swapped[2] = {swap_reverb ? 1 : 0, swap_reverb ? 0 : 1}; + int n = ROUND_UP_16(n_samples); + + uint16_t vols[2] = {rspa.vol[0], rspa.vol[1]}; + uint16_t rates[2] = {rspa.rate[0], rspa.rate[1]}; + uint16_t vol_wet = rspa.vol_wet; + uint16_t rate_wet = rspa.rate_wet; + + do { + for (int i = 0; i < 8; i++) { + int16_t samples[2] = {*in, *in}; in++; + for (int j = 0; j < 2; j++) { + samples[j] = (samples[j] * vols[j] >> 16) ^ negs[j]; + *dry[j] = clamp16(*dry[j] + samples[j]); dry[j]++; + *wet[j] = clamp16(*wet[j] + (samples[swapped[j]] * vol_wet >> 16)); wet[j]++; + } + } + vols[0] += rates[0]; + vols[1] += rates[1]; + vol_wet += rate_wet; n -= 8; } while (n > 0); } + +void aMixImpl(int16_t gain, uint16_t in_addr, uint16_t out_addr, uint16_t count) { + int nbytes = ROUND_UP_32(ROUND_DOWN_16(count)); + int16_t *in = BUF_S16(in_addr); + int16_t *out = BUF_S16(out_addr); + int i; + int32_t sample; + + if (gain == -0x8000) { + while (nbytes > 0) { + for (i = 0; i < 16; i++) { + sample = *out - *in++; + *out++ = clamp16(sample); + } + nbytes -= 16 * sizeof(int16_t); + } + } + + while (nbytes > 0) { + for (i = 0; i < 16; i++) { + sample = ((*out * 0x7fff + *in++ * gain) + 0x4000) >> 15; + *out++ = clamp16(sample); + } + + nbytes -= 16 * sizeof(int16_t); + } +} + +void aS8DecImpl(uint8_t flags, ADPCM_STATE state) { + uint8_t *in = BUF_U8(rspa.in); + int16_t *out = BUF_S16(rspa.out); + int nbytes = ROUND_UP_32(rspa.nbytes); + if (flags & A_INIT) { + memset(out, 0, 16 * sizeof(int16_t)); + } else if (flags & A_LOOP) { + memcpy(out, rspa.adpcm_loop_state, 16 * sizeof(int16_t)); + } else { + memcpy(out, state, 16 * sizeof(int16_t)); + } + out += 16; + + while (nbytes > 0) { + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + *out++ = (int16_t)(*in++ << 8); + + nbytes -= 16 * sizeof(int16_t); + } + + memcpy(state, out - 16, 16 * sizeof(int16_t)); +} + +void aAddMixerImpl(uint16_t count, uint16_t in_addr, uint16_t out_addr) { + int16_t *in = BUF_S16(in_addr); + int16_t *out = BUF_S16(out_addr); + int nbytes = ROUND_UP_64(ROUND_DOWN_16(count)); + + do { + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + *out = clamp16(*out + *in++); out++; + + nbytes -= 16 * sizeof(int16_t); + } while (nbytes > 0); +} + +void aDuplicateImpl(uint16_t count, uint16_t in_addr, uint16_t out_addr) { + uint8_t* in = BUF_U8(in_addr); + uint8_t *out = BUF_U8(out_addr); + + uint8_t tmp[128]; + memcpy(tmp, in, 128); + do { + memcpy(out, tmp, 128); + out += 128; + } while (count-- > 0); +} + +void aDMEMMove2Impl(uint8_t t, uint16_t in_addr, uint16_t out_addr, uint16_t count) { + uint8_t *in = BUF_U8(in_addr); + uint8_t *out = BUF_U8(out_addr); + int nbytes = ROUND_UP_32(count); + + do { + memmove(out, in, nbytes); + in += nbytes; + out += nbytes; + } while (t-- > 0); +} + +void aResampleZohImpl(uint16_t pitch, uint16_t start_fract) { + int16_t *in = BUF_S16(rspa.in); + int16_t *out = BUF_S16(rspa.out); + int nbytes = ROUND_UP_8(rspa.nbytes); + uint32_t pos = start_fract; + uint32_t pitch_add = pitch << 2; + + do { + *out++ = in[pos >> 17]; pos += pitch_add; + *out++ = in[pos >> 17]; pos += pitch_add; + *out++ = in[pos >> 17]; pos += pitch_add; + *out++ = in[pos >> 17]; pos += pitch_add; + + nbytes -= 4 * sizeof(int16_t); + } while (nbytes > 0); +} + +void aDownsampleHalfImpl(uint16_t n_samples, uint16_t in_addr, uint16_t out_addr) { + int16_t *in = BUF_S16(in_addr); + int16_t *out = BUF_S16(out_addr); + int n = ROUND_UP_8(n_samples); + + do { + *out++ = *in++; in++; + *out++ = *in++; in++; + *out++ = *in++; in++; + *out++ = *in++; in++; + *out++ = *in++; in++; + *out++ = *in++; in++; + *out++ = *in++; in++; + *out++ = *in++; in++; + + n -= 8; + } while (n > 0); +} + +void aInterlImpl(uint16_t in_addr, uint16_t out_addr, uint16_t n_samples) { + int16_t *in = BUF_S16(in_addr); + int16_t *out = BUF_S16(out_addr); + int n = ROUND_UP_8(n_samples); + + do { + *out++ = *in++; in++; + *out++ = *in++; in++; + *out++ = *in++; in++; + *out++ = *in++; in++; + *out++ = *in++; in++; + *out++ = *in++; in++; + *out++ = *in++; in++; + *out++ = *in++; in++; + + n -= 8; + } while (n > 0); +} + +void aFilterImpl(uint8_t flags, uint16_t count_or_buf, int16_t *state_or_filter) { + if (flags > A_INIT) { + rspa.filter_count = ROUND_UP_16(count_or_buf); + memcpy(rspa.filter, state_or_filter, sizeof(rspa.filter)); + } else { + int16_t tmp[16], tmp2[8]; + int count = rspa.filter_count; + int16_t *buf = BUF_S16(count_or_buf); + + if (flags == A_INIT) { +#ifndef __clang__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmemset-elt-size" +#endif + memset(tmp, 0, 8 * sizeof(int16_t)); +#ifndef __clang__ +#pragma GCC diagnostic pop +#endif + memset(tmp2, 0, 8 * sizeof(int16_t)); + } else { + memcpy(tmp, state_or_filter, 8 * sizeof(int16_t)); + memcpy(tmp2, state_or_filter + 8, 8 * sizeof(int16_t)); + } + + for (int i = 0; i < 8; i++) { + rspa.filter[i] = (tmp2[i] + rspa.filter[i]) / 2; + } + + do { + memcpy(tmp + 8, buf, 8 * sizeof(int16_t)); + for (int i = 0; i < 8; i++) { + int64_t sample = 0x4000; // round term + for (int j = 0; j < 8; j++) { + sample += tmp[i + j] * rspa.filter[7 - j]; + } + buf[i] = clamp16((int32_t)(sample >> 15)); + } + memcpy(tmp, tmp + 8, 8 * sizeof(int16_t)); + + buf += 8; + count -= 8 * sizeof(int16_t); + } while (count > 0); + + memcpy(state_or_filter, tmp, 8 * sizeof(int16_t)); + memcpy(state_or_filter + 8, rspa.filter, 8 * sizeof(int16_t)); + } +} + +void aHiLoGainImpl(uint8_t g, uint16_t count, uint16_t addr) { + int16_t *samples = BUF_S16(addr); + int nbytes = ROUND_UP_32(count); + + do { + *samples = clamp16((*samples * g) >> 4); samples++; + *samples = clamp16((*samples * g) >> 4); samples++; + *samples = clamp16((*samples * g) >> 4); samples++; + *samples = clamp16((*samples * g) >> 4); samples++; + *samples = clamp16((*samples * g) >> 4); samples++; + *samples = clamp16((*samples * g) >> 4); samples++; + *samples = clamp16((*samples * g) >> 4); samples++; + *samples = clamp16((*samples * g) >> 4); samples++; + + nbytes -= 8; + } while (nbytes > 0); +} + +void aUnkCmd3Impl(uint16_t a, uint16_t b, uint16_t c) { +} + +void aUnkCmd19Impl(uint8_t f, uint16_t count, uint16_t out_addr, uint16_t in_addr) { + int nbytes = ROUND_UP_64(count); + int16_t *in = BUF_S16(in_addr + f); + int16_t *out = BUF_S16(out_addr); + int16_t tbl[32]; + + memcpy(tbl, in, 32 * sizeof(int16_t)); + do { + for (int i = 0; i < 32; i++) { + out[i] = clamp16(out[i] * tbl[i]); + } + out += 32; + nbytes -= 32 * sizeof(int16_t); + } while (nbytes > 0); +} \ No newline at end of file diff --git a/src/audio/mixer.h b/src/audio/mixer.h index f19009aa1..9aabd51b9 100644 --- a/src/audio/mixer.h +++ b/src/audio/mixer.h @@ -1,11 +1,94 @@ -#ifndef MIXER_H -#define MIXER_H +#pragma once -#include - -void aDownsampleHalfImpl(uint16_t n_samples, uint16_t in_addr, uint16_t out_addr); +#include +#include +#include "libultraship/libultra/abi.h" +#undef aSegment +#undef aClearBuffer +#undef aSetBuffer +#undef aLoadBuffer +#undef aSaveBuffer +#undef aDMEMMove +#undef aMix +#undef aEnvMixer +#undef aResample +#undef aInterleave +#undef aSetVolume +#undef aSetVolume32 +#undef aSetLoop +#undef aLoadADPCM +#undef aADPCMdec +#undef aS8Dec +#undef aAddMixer +#undef aDuplicate +#undef aDMEMMove2 +#undef aResampleZoh #undef aDownsampleHalf -#define aDownsampleHalf(pkt, nSamples, i, o) aDownsampleHalfImpl(nSamples, i, o) +#undef aEnvSetup1 +#undef aEnvSetup2 +#undef aFilter +#undef aHiLoGain +#undef aInterl +#undef aUnkCmd3 +#undef aUnkCmd19 -#endif +void aClearBufferImpl(uint16_t addr, int nbytes); +void aLoadBufferImpl(const void* source_addr, uint16_t dest_addr, uint16_t nbytes); +void aSaveBufferImpl(uint16_t source_addr, int16_t* dest_addr, uint16_t nbytes); +void aLoadADPCMImpl(int num_entries_times_16, const int16_t* book_source_addr); +void aSetBufferImpl(uint8_t flags, uint16_t in, uint16_t out, uint16_t nbytes); +void aInterleaveImpl(uint16_t left, uint16_t right); +void aDMEMMoveImpl(uint16_t in_addr, uint16_t out_addr, int nbytes); +void aSetLoopImpl(ADPCM_STATE* adpcm_loop_state); +void aADPCMdecImpl(uint8_t flags, ADPCM_STATE state); +void aResampleImpl(uint8_t flags, uint16_t pitch, RESAMPLE_STATE state); +void aEnvSetup1Impl(uint8_t initial_vol_wet, uint16_t rate_wet, uint16_t rate_left, uint16_t rate_right); +void aEnvSetup2Impl(uint16_t initial_vol_left, uint16_t initial_vol_right); +void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb, + bool neg_left, bool neg_right, + uint16_t dry_left_addr, uint16_t dry_right_addr, + uint16_t wet_left_addr, uint16_t wet_right_addr); +void aMixImpl(int16_t gain, uint16_t in_addr, uint16_t out_addr, uint16_t count); +void aS8DecImpl(uint8_t flags, ADPCM_STATE state); +void aAddMixerImpl(uint16_t count, uint16_t in_addr, uint16_t out_addr); +void aDuplicateImpl(uint16_t count, uint16_t in_addr, uint16_t out_addr); +void aDMEMMove2Impl(uint8_t t, uint16_t in_addr, uint16_t out_addr, uint16_t count); +void aDownsampleHalfImpl(uint16_t n_samples, uint16_t in_addr, uint16_t out_addr); +void aResampleZohImpl(uint16_t pitch, uint16_t start_fract); +void aInterlImpl(uint16_t in_addr, uint16_t out_addr, uint16_t n_samples); +void aFilterImpl(uint8_t flags, uint16_t count_or_buf, int16_t* state_or_filter); +void aHiLoGainImpl(uint8_t g, uint16_t count, uint16_t addr); +void aUnkCmd3Impl(uint16_t a, uint16_t b, uint16_t c); +void aUnkCmd19Impl(uint8_t f, uint16_t count, uint16_t out_addr, uint16_t in_addr); + +#define aSegment(pkt, s, b) \ + do { \ + } while (0) +#define aClearBuffer(pkt, d, c) aClearBufferImpl(d, c) +#define aLoadBuffer(pkt, s, d, c) aLoadBufferImpl(s, d, c) +#define aSaveBuffer(pkt, s, d, c) aSaveBufferImpl(s, d, c) +#define aLoadADPCM(pkt, c, d) aLoadADPCMImpl(c, d) +#define aSetBuffer(pkt, f, i, o, c) aSetBufferImpl(f, i, o, c) +#define aInterleave(pkt, o, l, r, c) aInterleaveImpl(l, r) +#define aDMEMMove(pkt, i, o, c) aDMEMMoveImpl(i, o, c) +#define aSetLoop(pkt, a) aSetLoopImpl(a) +#define aADPCMdec(pkt, f, s) aADPCMdecImpl(f, s) +#define aResample(pkt, f, p, s) aResampleImpl(f, p, s) +#define aEnvSetup1(pkt, initialVolReverb, rampReverb, rampLeft, rampRight) \ + aEnvSetup1Impl(initialVolReverb, rampReverb, rampLeft, rampRight) +#define aEnvSetup2(pkt, initialVolLeft, initialVolRight) aEnvSetup2Impl(initialVolLeft, initialVolRight) +#define aEnvMixer(pkt, inBuf, nSamples, swapReverb, negLeft, negRight, dryLeft, dryRight, wetLeft, wetRight) \ + aEnvMixerImpl(inBuf, nSamples, swapReverb, negLeft, negRight, dryLeft, dryRight, wetLeft, wetRight) +#define aMix(pkt, g, i, o, c) aMixImpl(g, i, o, c) +#define aS8Dec(pkt, f, s) aS8DecImpl(f, s) +#define aAddMixer(pkt, s, d, c) aAddMixerImpl(s, d, c) +#define aDuplicate(pkt, s, d, c) aDuplicateImpl(s, d, c) +#define aDMEMMove2(pkt, t, i, o, c) aDMEMMove2Impl(t, i, o, c) +#define aResampleZoh(pkt, pitch, startFract) aResampleZohImpl(pitch, startFract) +#define aInterl(pkt, dmemi, dmemo, count) aInterlImpl(dmemi, dmemo, count) +#define aFilter(pkt, f, countOrBuf, addr) aFilterImpl(f, countOrBuf, addr) +#define aDownsampleHalf(pkt, nSamples, i, o) aDownsampleHalfImpl(nSamples, i, o) +#define aHiLoGain(pkt, g, buflen, i, a4) aHiLoGainImpl(g, buflen, i) +#define aUnkCmd3(pkt, a1, a2, a3) aUnkCmd3Impl(a1, a2, a3) +#define aUnkCmd19(pkt, a1, a2, a3, a4) aUnkCmd19Impl(a1, a2, a3, a4) \ No newline at end of file diff --git a/src/audio/playback.c b/src/audio/playback.c index 95c1214f7..30dcb388d 100644 --- a/src/audio/playback.c +++ b/src/audio/playback.c @@ -9,6 +9,7 @@ #include "audio/effects.h" #include "audio/data.h" #include "audio/seqplayer.h" +#include "port/Engine.h" void note_set_vel_pan_reverb(struct Note* note, f32 velocity, u8 pan, u8 reverbVol) { struct NoteSubEu* sub = ¬e->noteSubEu; @@ -70,6 +71,10 @@ void note_set_vel_pan_reverb(struct Note* note, f32 velocity, u8 pan, u8 reverbV velocity = 1.0f; } + float master_vol = CVarGetFloat("gGameMasterVolume", 1.0f); + volLeft *= master_vol; + volRight *= master_vol; + sub->targetVolLeft = ((s32) (velocity * volLeft * 4095.999f)); sub->targetVolRight = ((s32) (velocity * volRight * 4095.999f)); @@ -136,13 +141,15 @@ struct Instrument* get_instrument_inner(s32 bankId, s32 instId) { return NULL; } - if (instId >= gCtlEntries[bankId].numInstruments) { + struct CtlEntry* bank = GameEngine_LoadBank(bankId); + + if (instId >= bank->numInstruments) { stubbed_printf("Audio: voiceman: progNo. overflow %d,%d\n", instId, gCtlEntries[bankId].numInstruments); gAudioErrorFlags = ((bankId << 8) + instId) + 0x3000000; return NULL; } - inst = gCtlEntries[bankId].instruments[instId]; + inst = bank->instruments[instId]; if (inst == NULL) { stubbed_printf("Audio: voiceman: progNo. undefined %d,%d\n", bankId, instId); gAudioErrorFlags = ((bankId << 8) + instId) + 0x1000000; @@ -160,18 +167,15 @@ struct Drum* get_drum(s32 bankId, s32 drumId) { return NULL; } - if (drumId >= gCtlEntries[bankId].numDrums) { + struct CtlEntry* bank = GameEngine_LoadBank(bankId); + + if (drumId >= bank->numDrums) { stubbed_printf("Audio: voiceman: Percussion Overflow %d,%d\n", drumId, gCtlEntries[bankId].numDrums); gAudioErrorFlags = ((bankId << 8) + drumId) + 0x4000000; return NULL; } - if ((uintptr_t) gCtlEntries[bankId].drums < 0x80000000U) { - stubbed_printf("Audio: voiceman: Percussion table pointer (bank %d) is irregular.\n"); - return NULL; - } - - drum = gCtlEntries[bankId].drums[drumId]; + drum = bank->drums[drumId]; if (drum == NULL) { stubbed_printf("Audio: voiceman: Percpointer NULL %d,%d\n", bankId, drumId); gAudioErrorFlags = ((bankId << 8) + drumId) + 0x5000000; diff --git a/src/audio/port_eu.c b/src/audio/port_eu.c index 199e3facf..60fbc1dbd 100644 --- a/src/audio/port_eu.c +++ b/src/audio/port_eu.c @@ -46,6 +46,40 @@ s32 D_800EA4A4 = 0; char port_eu_unused_string7[] = "Undefined Port Command %d\n"; +void create_next_audio_buffer(s16* samples, u32 num_samples) { + static s32 gMaxAbiCmdCnt = 128; + s32 abiCmdCount; + OSMesg specId; + OSMesg msg; + + gAudioFrameCount++; + gCurrAiBufferIndex %= 3; + + gCurrAudioFrameDmaCount = 0; + + if (osRecvMesg(D_800EA3B0, &specId, 0) != -1) { + gAudioResetPresetIdToLoad = specId.data8; + gAudioResetStatus = 5; + } + + if (gAudioResetStatus != 0) { + if (audio_shut_down_and_reset_step() == 0) { + if (gAudioResetStatus == 0) { + osSendMesg(D_800EA3B4, OS_MESG_8(gAudioResetPresetIdToLoad), OS_MESG_NOBLOCK); + } + return; + } + } + + if (osRecvMesg(D_800EA3AC, &msg, 0) != -1) { + func_800CBCB0(msg.data32); + } + + gAudioCmd = gAudioCmdBuffers[gAudioTaskIndex]; + gAudioCmd = synthesis_execute((Acmd*) gAudioCmd, &abiCmdCount, samples, num_samples); + gAudioRandom = osGetCount() * (gAudioRandom + gAudioFrameCount); +} + struct SPTask* create_next_audio_frame_task(void) { u32 samplesRemainingInAI; s32 writtenCmds; @@ -126,7 +160,7 @@ struct SPTask* create_next_audio_frame_task(void) { gAiBufferLengths[index] = gAudioBufferParameters.maxAiBufferLength; } if (osRecvMesg(D_800EA3AC, &sp54, 0) != -1) { - func_800CBCB0((u32) sp54.data16); + func_800CBCB0(sp54.data32); } gAudioCmd = synthesis_execute((Acmd*) gAudioCmd, &writtenCmds, currAiBuffer, gAiBufferLengths[index]); gAudioRandom = osGetCount() * (gAudioRandom + gAudioFrameCount); @@ -266,26 +300,26 @@ void func_800CBBE8(u32 arg0, s8 arg1) { } //! @todo clenanup, something's weird with the variables. D_800EA4A4 is probably EuAudioCmd bc of the + 0x100 +#if 1 void func_800CBC24(void) { s32 temp_t6; s32 test; - OSMesg thing; temp_t6 = D_800EA3A0[0] - D_800EA3A4[0]; test = (u8) temp_t6; test = (test + 0x100) & 0xFF; - do { - } while (0); if (D_800EA4A4 < test) { D_800EA4A4 = test; } - OSMesg audioMesg; - audioMesg.ptr = ((D_800EA3A0[0] & 0xFF) | ((D_800EA3A4[0] & 0xFF) << 8)); - - thing = audioMesg; - osSendMesg(D_800EA3AC, thing, 0); + osSendMesg(D_800EA3AC, OS_MESG_32(((D_800EA3A0[0] & 0xFF) | ((D_800EA3A4[0] & 0xFF) << 8))), 0); D_800EA3A4[0] = D_800EA3A0[0]; } +#else +void func_800CBC24(void) { + osSendMesg(D_800EA3AC, OS_MESG_32(((D_800EA3A0[0] & 0xff) << 8 | (D_800EA3A4[0] & 0xff))), OS_MESG_NOBLOCK); + D_800EA3A4[0] = D_800EA3A0[0]; +} +#endif void func_800CBCB0(u32 arg0) { struct EuAudioCmd* cmd; diff --git a/src/audio/seqplayer.c b/src/audio/seqplayer.c index 91919dbec..c25eb8196 100644 --- a/src/audio/seqplayer.c +++ b/src/audio/seqplayer.c @@ -9,6 +9,7 @@ #include "audio/effects.h" #include "audio/playback.h" #include "audio/external.h" +#include "port/Engine.h" /** * Given that (almost) all of these are format strings, it is highly likely @@ -248,11 +249,11 @@ void sequence_player_disable(struct SequencePlayer* seqPlayer) { seqPlayer->enabled = false; if (IS_SEQ_LOAD_COMPLETE(seqPlayer->seqId) && gSeqLoadStatus[seqPlayer->seqId] != 5) { - gSeqLoadStatus[seqPlayer->seqId] = SOUND_LOAD_STATUS_DISCARDABLE; + GameEngine_UnloadSequence(seqPlayer->seqId); } if (IS_BANK_LOAD_COMPLETE(seqPlayer->defaultBank[0]) && gBankLoadStatus[seqPlayer->defaultBank[0]] != 5) { - gBankLoadStatus[seqPlayer->defaultBank[0]] = 4; + GameEngine_UnloadBank(seqPlayer->defaultBank[0]); } // (Note that if this is called from alloc_bank_or_seq, the side will get swapped @@ -732,11 +733,14 @@ void seq_channel_layer_process_script(struct SequenceChannelLayer* layer) { if (seqChannel) {} } -u8 get_instrument(struct SequenceChannel* seqChannel, u8 instId, struct Instrument** instOut, - struct AdsrSettings* adsr) { - struct Instrument* inst; - inst = get_instrument_inner(seqChannel->bankId, instId); - if (inst == NULL) { +u8 get_instrument(struct SequenceChannel *seqChannel, u8 instId, struct Instrument **instOut, struct AdsrSettings *adsr) { + struct CtlEntry *bank = GameEngine_LoadBank(seqChannel->bankId); + if(instId >= bank->numInstruments) { + *instOut = NULL; + return 0; + } + struct Instrument* inst = bank->instruments[instId]; + if(inst == NULL) { *instOut = NULL; return 0; } @@ -905,14 +909,14 @@ void sequence_channel_process_script(struct SequenceChannel* seqChannel) { } break; - case 0xEB: + case 0xEB: { cmd = m64_read_u8(state); - sp38 = ((u16*) gAlBankSets)[seqPlayer->seqId]; - loBits = *(sp38 + gAlBankSets); - cmd = gAlBankSets[(((s32) sp38) + loBits) - cmd]; - if (get_bank_or_seq(1, 2, cmd) != NULL) { + struct AudioSequenceData *sequence = GameEngine_LoadSequence(seqPlayer->seqId); + cmd = sequence->banks[cmd]; + if(IS_BANK_LOAD_COMPLETE(cmd)) { seqChannel->bankId = cmd; } + } case 0xC1: set_instrument(seqChannel, m64_read_u8(state)); @@ -1003,15 +1007,15 @@ void sequence_channel_process_script(struct SequenceChannel* seqChannel) { seqChannel->reverbVol = m64_read_u8(state); break; - case 0xC6: + case 0xC6: { cmd = m64_read_u8(state); - sp5A = ((u16*) gAlBankSets)[seqPlayer->seqId]; - loBits = *(sp5A + gAlBankSets); - cmd = gAlBankSets[(sp5A + loBits) - cmd]; - if (get_bank_or_seq(1, 2, cmd) != NULL) { + struct AudioSequenceData *sequence = GameEngine_LoadSequence(seqPlayer->seqId); + cmd = sequence->banks[cmd]; + if(IS_BANK_LOAD_COMPLETE(cmd)) { seqChannel->bankId = cmd; } break; + } case 0xC7: cmd = m64_read_u8(state); @@ -1210,6 +1214,9 @@ void sequence_player_process_sequence(struct SequencePlayer* seqPlayer) { if (seqPlayer->enabled == false) { return; } + + GameEngine_LoadSequence(seqPlayer->seqId); + GameEngine_LoadBank(seqPlayer->defaultBank[0]); if (seqPlayer->bankDmaInProgress == true) { if (osRecvMesg(&seqPlayer->bankDmaMesgQueue, NULL, 0) == -1) { diff --git a/src/audio/synthesis.c b/src/audio/synthesis.c index 0c7c653b1..18a5182bb 100644 --- a/src/audio/synthesis.c +++ b/src/audio/synthesis.c @@ -7,7 +7,7 @@ #include "audio/load.h" #include "audio/seqplayer.h" #include "audio/internal.h" -// #include "audio/external.h" +#include "port/Engine.h" #include #define aSetLoadBufferPair(pkt, c, off) \ @@ -161,8 +161,7 @@ Acmd* synthesis_execute(Acmd* acmd, s32* writtenCmds, s16* aiBuf, s32 bufLen) { process_sequences(i - 1); synthesis_load_note_subs_eu(gAudioBufferParameters.updatesPerFrame - i); } - // UTODO: Stubbed - // aSegment(cmd++, 0, 0); + aSegment(cmd++, 0, 0); aiBufPtr = (u32*) aiBuf; for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) { if (i == 1) { @@ -325,7 +324,7 @@ Acmd* synthesis_do_one_audio_update(s16* aiBuf, s32 bufLen, Acmd* acmd, s32 upda temp = bufLen * 2; aSetBuffer(acmd++, 0, 0, DMEM_ADDR_TEMP, temp); // UTODO: Stubbed - // aInterleave(acmd++, DMEM_ADDR_LEFT_CH, DMEM_ADDR_RIGHT_CH); + aInterleave(acmd++, 0, DMEM_ADDR_LEFT_CH, DMEM_ADDR_RIGHT_CH, 0); aSaveBuffer(acmd++, DMEM_ADDR_TEMP, VIRTUAL_TO_PHYSICAL2(aiBuf), temp * 2); return acmd; } @@ -344,7 +343,7 @@ Acmd* synthesis_process_note(s32 noteIndex, struct NoteSubEu* noteSubEu, struct u16 resamplingRateFixedPoint; s32 nSamplesToLoad; - s32 spFC; + s32 spFC = 0; UNUSED s32 pad2[2]; s32 loopInfo_2; @@ -613,8 +612,7 @@ Acmd* load_wave_samples(Acmd* acmd, struct NoteSubEu* noteSubEu, struct NoteSynt s32 nSamplesToLoad) { s32 a3; s32 repeats; - // UTODO: Stubbed - // aLoadBuffer(acmd++, VIRTUAL_TO_PHYSICAL2(noteSubEu->sound.samples), 0x1A0, 128); + aLoadBuffer(acmd++, VIRTUAL_TO_PHYSICAL2(noteSubEu->sound.samples), 0x1A0, 128); synthesisState->samplePosInt &= 0x3f; a3 = 64 - synthesisState->samplePosInt; @@ -622,7 +620,7 @@ Acmd* load_wave_samples(Acmd* acmd, struct NoteSubEu* noteSubEu, struct NoteSynt repeats = (nSamplesToLoad - a3 + 63) / 64; if (repeats != 0) { // UTODO: Stubbed - // aDMEMMove2(acmd++, repeats, 0x1A0, 0x1A0 + 128, 128); + aDMEMMove2(acmd++, repeats, 0x1A0, 0x1A0 + 128, 128); } } return acmd; diff --git a/src/audio/synthesis.h b/src/audio/synthesis.h index e35627bb9..870c6bfe0 100644 --- a/src/audio/synthesis.h +++ b/src/audio/synthesis.h @@ -20,6 +20,7 @@ #define DMEM_ADDR_WET_LEFT_CH 0x840 #define DMEM_ADDR_WET_RIGHT_CH 0x9C0 + /* Its not clear what values these macros should have. Neither version seem to line up for MK64. Maybe each game has unique values for these? I don't know diff --git a/src/engine/Engine.h b/src/engine/Engine.h index 9a220c1a4..5af480c23 100644 --- a/src/engine/Engine.h +++ b/src/engine/Engine.h @@ -6,6 +6,7 @@ #include "objects.h" #include "path_spawn_metadata.h" #include "waypoints.h" +#include "sounds.h" typedef struct { RGB8 TopRight; @@ -44,6 +45,7 @@ typedef struct { s32 MinimapFinishlineX; s32 MinimapFinishlineY; SkyboxColours Skybox; + enum MusicSeq Sequence; } CProperties; #endif // __ENGINE_H__ \ No newline at end of file diff --git a/src/engine/World.h b/src/engine/World.h index c339801d9..b6801a668 100644 --- a/src/engine/World.h +++ b/src/engine/World.h @@ -67,6 +67,7 @@ class World { int32_t MinimapFinishlineX; int32_t MinimapFinishlineY; SkyboxColours Skybox; + MusicSeq Sequence; } Properties; typedef struct { diff --git a/src/engine/courses/BansheeBoardwalk.cpp b/src/engine/courses/BansheeBoardwalk.cpp index 2211b3294..f1dc8287c 100644 --- a/src/engine/courses/BansheeBoardwalk.cpp +++ b/src/engine/courses/BansheeBoardwalk.cpp @@ -101,6 +101,7 @@ BansheeBoardwalk::BansheeBoardwalk() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; + Props.Sequence = MusicSeq::MUSIC_SEQ_BANSHEE_BOARDWALK; } void BansheeBoardwalk::Load() { diff --git a/src/engine/courses/BigDonut.cpp b/src/engine/courses/BigDonut.cpp index f01930c7b..56ff61a66 100644 --- a/src/engine/courses/BigDonut.cpp +++ b/src/engine/courses/BigDonut.cpp @@ -96,6 +96,7 @@ BigDonut::BigDonut() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; + Props.Sequence = MusicSeq::MUSIC_SEQ_BATTLE_ARENAS; } void BigDonut::Load() { diff --git a/src/engine/courses/BlockFort.cpp b/src/engine/courses/BlockFort.cpp index d6ebf2263..a61e26280 100644 --- a/src/engine/courses/BlockFort.cpp +++ b/src/engine/courses/BlockFort.cpp @@ -99,6 +99,7 @@ BlockFort::BlockFort() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {216, 232, 248}; + Props.Sequence = MusicSeq::MUSIC_SEQ_CHOCO_MOUNTAIN; } void BlockFort::Load() { diff --git a/src/engine/courses/BowsersCastle.cpp b/src/engine/courses/BowsersCastle.cpp index a12b233a8..9098c62e9 100644 --- a/src/engine/courses/BowsersCastle.cpp +++ b/src/engine/courses/BowsersCastle.cpp @@ -101,6 +101,7 @@ BowsersCastle::BowsersCastle() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; + Props.Sequence = MusicSeq::MUSIC_SEQ_BOWSERS_CASTLE; } void BowsersCastle::Load() { diff --git a/src/engine/courses/ChocoMountain.cpp b/src/engine/courses/ChocoMountain.cpp index bc88bf645..71e147f2d 100644 --- a/src/engine/courses/ChocoMountain.cpp +++ b/src/engine/courses/ChocoMountain.cpp @@ -101,6 +101,7 @@ ChocoMountain::ChocoMountain() { Props.Skybox.FloorBottomRight = {255, 255, 255}; Props.Skybox.FloorBottomLeft = {255, 255, 255}; Props.Skybox.FloorTopLeft = {255, 255, 255}; + Props.Sequence = MusicSeq::MUSIC_SEQ_CHOCO_MOUNTAIN; } void ChocoMountain::Load() { diff --git a/src/engine/courses/Course.cpp b/src/engine/courses/Course.cpp index 6cef03d6b..022ee016e 100644 --- a/src/engine/courses/Course.cpp +++ b/src/engine/courses/Course.cpp @@ -73,6 +73,7 @@ Course::Course() { Props.CloudList = NULL; Props.MinimapFinishlineX = 0; Props.MinimapFinishlineY = 0; + Props.Sequence = MusicSeq::MUSIC_SEQ_UNKNOWN; } void Course::Load(Vtx* vtx, Gfx* gfx) { diff --git a/src/engine/courses/Course.h b/src/engine/courses/Course.h index 3d3335854..e711dd510 100644 --- a/src/engine/courses/Course.h +++ b/src/engine/courses/Course.h @@ -75,6 +75,7 @@ public: int32_t MinimapFinishlineX; int32_t MinimapFinishlineY; SkyboxColours Skybox; + MusicSeq Sequence; } Properties; Properties Props; diff --git a/src/engine/courses/DKJungle.cpp b/src/engine/courses/DKJungle.cpp index 4c3d6797c..479c23b02 100644 --- a/src/engine/courses/DKJungle.cpp +++ b/src/engine/courses/DKJungle.cpp @@ -104,6 +104,7 @@ DKJungle::DKJungle() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {22, 145, 22}; + Props.Sequence = MusicSeq::MUSIC_SEQ_DK_JUNGLE; } void DKJungle::Load() { diff --git a/src/engine/courses/DoubleDeck.cpp b/src/engine/courses/DoubleDeck.cpp index 7d07cdc43..74fb7e714 100644 --- a/src/engine/courses/DoubleDeck.cpp +++ b/src/engine/courses/DoubleDeck.cpp @@ -99,6 +99,7 @@ DoubleDeck::DoubleDeck() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {255, 224, 240}; + Props.Sequence = MusicSeq::MUSIC_SEQ_CHOCO_MOUNTAIN; } void DoubleDeck::Load() { diff --git a/src/engine/courses/FrappeSnowland.cpp b/src/engine/courses/FrappeSnowland.cpp index 90fa51e6c..a0e698152 100644 --- a/src/engine/courses/FrappeSnowland.cpp +++ b/src/engine/courses/FrappeSnowland.cpp @@ -102,6 +102,7 @@ FrappeSnowland::FrappeSnowland() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 99, 164}; + Props.Sequence = MusicSeq::MUSIC_SEQ_FRAPPE_SNOWLAND; } void FrappeSnowland::Load() { diff --git a/src/engine/courses/KalimariDesert.cpp b/src/engine/courses/KalimariDesert.cpp index cfb7316e5..2562ab8f8 100644 --- a/src/engine/courses/KalimariDesert.cpp +++ b/src/engine/courses/KalimariDesert.cpp @@ -102,6 +102,7 @@ KalimariDesert::KalimariDesert() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {255, 192, 0}; + Props.Sequence = MusicSeq::MUSIC_SEQ_KALIMARI_DESERT; } void KalimariDesert::Load() { diff --git a/src/engine/courses/KoopaTroopaBeach.cpp b/src/engine/courses/KoopaTroopaBeach.cpp index 66bf99005..48f8c8b77 100644 --- a/src/engine/courses/KoopaTroopaBeach.cpp +++ b/src/engine/courses/KoopaTroopaBeach.cpp @@ -102,6 +102,7 @@ KoopaTroopaBeach::KoopaTroopaBeach() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {48, 152, 120}; + Props.Sequence = MusicSeq::MUSIC_SEQ_KOOPA_TROOPA_BEACH; } void KoopaTroopaBeach::Load() { diff --git a/src/engine/courses/LuigiRaceway.cpp b/src/engine/courses/LuigiRaceway.cpp index 72b6617c2..f98ceab21 100644 --- a/src/engine/courses/LuigiRaceway.cpp +++ b/src/engine/courses/LuigiRaceway.cpp @@ -105,6 +105,7 @@ LuigiRaceway::LuigiRaceway() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {216, 232, 248}; + Props.Sequence = MusicSeq::MUSIC_SEQ_RACEWAYS_WARIO_STADIUM; } void LuigiRaceway::Load() { diff --git a/src/engine/courses/MarioRaceway.cpp b/src/engine/courses/MarioRaceway.cpp index ea8593e17..bde10370d 100644 --- a/src/engine/courses/MarioRaceway.cpp +++ b/src/engine/courses/MarioRaceway.cpp @@ -102,6 +102,7 @@ MarioRaceway::MarioRaceway() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; + Props.Sequence = MusicSeq::MUSIC_SEQ_RACEWAYS_WARIO_STADIUM; } void MarioRaceway::Load() { diff --git a/src/engine/courses/MooMooFarm.cpp b/src/engine/courses/MooMooFarm.cpp index 6517eab82..d1b401342 100644 --- a/src/engine/courses/MooMooFarm.cpp +++ b/src/engine/courses/MooMooFarm.cpp @@ -102,6 +102,7 @@ MooMooFarm::MooMooFarm() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {255, 184, 99}; + Props.Sequence = MusicSeq::MUSIC_SEQ_MOO_MOO_FARM_YOSHI_VALLEY; } void MooMooFarm::Load() { diff --git a/src/engine/courses/PodiumCeremony.cpp b/src/engine/courses/PodiumCeremony.cpp index 9488b8b21..86bf403b3 100644 --- a/src/engine/courses/PodiumCeremony.cpp +++ b/src/engine/courses/PodiumCeremony.cpp @@ -96,6 +96,7 @@ PodiumCeremony::PodiumCeremony() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {255, 224, 240}; + Props.Sequence = MusicSeq::MUSIC_SEQ_UNKNOWN; } void PodiumCeremony::Load() { diff --git a/src/engine/courses/RainbowRoad.cpp b/src/engine/courses/RainbowRoad.cpp index 4836611fb..b8e9865c6 100644 --- a/src/engine/courses/RainbowRoad.cpp +++ b/src/engine/courses/RainbowRoad.cpp @@ -99,6 +99,7 @@ RainbowRoad::RainbowRoad() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; + Props.Sequence = MusicSeq::MUSIC_SEQ_RAINBOW_ROAD; } void RainbowRoad::Load() { diff --git a/src/engine/courses/RoyalRaceway.cpp b/src/engine/courses/RoyalRaceway.cpp index ded9ec464..c2f6b3c62 100644 --- a/src/engine/courses/RoyalRaceway.cpp +++ b/src/engine/courses/RoyalRaceway.cpp @@ -100,6 +100,7 @@ RoyalRaceway::RoyalRaceway() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {255, 224, 240}; + Props.Sequence = MusicSeq::MUSIC_SEQ_RACEWAYS_WARIO_STADIUM; } void RoyalRaceway::Load() { diff --git a/src/engine/courses/SherbetLand.cpp b/src/engine/courses/SherbetLand.cpp index d483d966c..be3cc7043 100644 --- a/src/engine/courses/SherbetLand.cpp +++ b/src/engine/courses/SherbetLand.cpp @@ -100,6 +100,7 @@ SherbetLand::SherbetLand() { Props.Skybox.FloorBottomRight = {128, 184, 248}; Props.Skybox.FloorBottomLeft = {128, 184, 248}; Props.Skybox.FloorTopLeft = {216, 232, 248}; + Props.Sequence = MusicSeq::MUSIC_SEQ_FRAPPE_SNOWLAND; } void SherbetLand::Load() { diff --git a/src/engine/courses/Skyscraper.cpp b/src/engine/courses/Skyscraper.cpp index df26ceccb..7af4fd53f 100644 --- a/src/engine/courses/Skyscraper.cpp +++ b/src/engine/courses/Skyscraper.cpp @@ -99,6 +99,7 @@ Skyscraper::Skyscraper() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; + Props.Sequence = MusicSeq::MUSIC_SEQ_BATTLE_ARENAS; } void Skyscraper::Load() { diff --git a/src/engine/courses/TestCourse.cpp b/src/engine/courses/TestCourse.cpp index 05f6c9ed2..742dc6735 100644 --- a/src/engine/courses/TestCourse.cpp +++ b/src/engine/courses/TestCourse.cpp @@ -112,6 +112,7 @@ TestCourse::TestCourse() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; + Props.Sequence = MusicSeq::MUSIC_SEQ_RACEWAYS_WARIO_STADIUM; } void TestCourse::Load() { diff --git a/src/engine/courses/ToadsTurnpike.cpp b/src/engine/courses/ToadsTurnpike.cpp index 257b6c990..7a19a54dc 100644 --- a/src/engine/courses/ToadsTurnpike.cpp +++ b/src/engine/courses/ToadsTurnpike.cpp @@ -104,6 +104,7 @@ ToadsTurnpike::ToadsTurnpike() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {209, 65, 23}; + Props.Sequence = MusicSeq::MUSIC_SEQ_TOADS_TURNPIKE; } void ToadsTurnpike::Load() { diff --git a/src/engine/courses/WarioStadium.cpp b/src/engine/courses/WarioStadium.cpp index f074fb31e..62c75143a 100644 --- a/src/engine/courses/WarioStadium.cpp +++ b/src/engine/courses/WarioStadium.cpp @@ -103,6 +103,7 @@ WarioStadium::WarioStadium() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {0, 0, 0}; + Props.Sequence = MusicSeq::MUSIC_SEQ_RACEWAYS_WARIO_STADIUM; } void WarioStadium::Load() { diff --git a/src/engine/courses/YoshiValley.cpp b/src/engine/courses/YoshiValley.cpp index 474d3f3d2..b372ec626 100644 --- a/src/engine/courses/YoshiValley.cpp +++ b/src/engine/courses/YoshiValley.cpp @@ -100,6 +100,7 @@ YoshiValley::YoshiValley() { Props.Skybox.FloorBottomRight = {0, 0, 0}; Props.Skybox.FloorBottomLeft = {0, 0, 0}; Props.Skybox.FloorTopLeft = {95, 40, 15}; + Props.Sequence = MusicSeq::MUSIC_SEQ_MOO_MOO_FARM_YOSHI_VALLEY; } void YoshiValley::Load() { diff --git a/src/main.c b/src/main.c index cdbc4115d..5b3a02a79 100644 --- a/src/main.c +++ b/src/main.c @@ -1239,7 +1239,7 @@ void thread5_game_loop(void) { } void thread5_iteration(void) { - // func_800CB2C4(); + func_800CB2C4(); calculate_delta_time(); #ifdef TARGET_N64 while (true) { diff --git a/src/menus.c b/src/menus.c index 9bbd14332..a42e86c96 100644 --- a/src/menus.c +++ b/src/menus.c @@ -60,7 +60,7 @@ s8 D_8018EE0C; struct_8018EE10_entry D_8018EE10[2]; /** Data **/ -s32 gMenuSelection = START_MENU; +s32 gMenuSelection = LOGO_INTRO_MENU; s32 D_800E86A4 = 0; s8 gCharacterSelections[4] = { MARIO, LUIGI, YOSHI, TOAD }; @@ -1851,7 +1851,7 @@ void func_800B3F74(s32 menuSelection) { } D_8018EDF1 = D_800F2BE0[gPlayerCount - 1]; func_800CA008(0, 0); - func_800C8EAC(1); + play_sequence(MUSIC_SEQ_TITLE_SCREEN); D_8018EDFC = 0; break; } @@ -1868,13 +1868,13 @@ void func_800B3F74(s32 menuSelection) { func_800CB2C4(); gGamestate = 0; gGamestateNext = 0; - func_800C8EAC(2); + play_sequence(MUSIC_SEQ_MAIN_MENU); } switch (D_8018EDE0) { case 0: { gMainMenuSelectionDepth = PLAYER_NUM_SELECTION; - func_800C8EAC(2); + play_sequence(MUSIC_SEQ_MAIN_MENU); gPlayerCount = 1; if (gScreenModeSelection >= NUM_SCREEN_MODES || gScreenModeSelection < 0) { gScreenModeSelection = SCREEN_MODE_1P; @@ -1926,7 +1926,7 @@ void func_800B3F74(s32 menuSelection) { func_800CB2C4(); gGamestate = 0; gGamestateNext = 0; - func_800C8EAC(2); + play_sequence(MUSIC_SEQ_MAIN_MENU); for (i = 0; i < ARRAY_COUNT(D_8018EDE8); i++) { D_8018EDE8[i] = false; } @@ -1966,7 +1966,7 @@ void func_800B3F74(s32 menuSelection) { func_800CB2C4(); gGamestate = 0; gGamestateNext = 0; - func_800C8EAC(2); + play_sequence(MUSIC_SEQ_MAIN_MENU); } play_sound2(SOUND_MENU_SELECT_MAP); D_8018EE0A = 0; diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 66b8cd2c3..59d76cfb9 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -5,6 +5,9 @@ #include "libultraship/src/Context.h" #include "resource/type/ResourceType.h" #include "resource/importers/GenericArrayFactory.h" +#include "resource/importers/AudioBankFactory.h" +#include "resource/importers/AudioSampleFactory.h" +#include "resource/importers/AudioSequenceFactory.h" #include "resource/importers/Vec3fFactory.h" #include "resource/importers/Vec3sFactory.h" #include "resource/importers/KartAIFactory.h" @@ -31,6 +34,8 @@ float gInterpolationStep = 0.0f; #include #include #include +#include "audio/internal.h" +#include "audio/GameAudio.h" } GameEngine* GameEngine::Instance; @@ -57,7 +62,7 @@ GameEngine::GameEngine() { } } - this->context = Ship::Context::CreateInstance("Spaghettify", "skart64", "spaghettify.cfg.json", OTRFiles, {}, 3); + this->context = Ship::Context::CreateInstance("Spaghettify", "skart64", "spaghettify.cfg.json", OTRFiles, {}, 3, { 26800, 512, 1100 }); auto wnd = std::dynamic_pointer_cast(Ship::Context::GetInstance()->GetWindow()); @@ -65,21 +70,33 @@ GameEngine::GameEngine() { this->context->InitGfxDebugger(); auto loader = context->GetResourceManager()->GetResourceLoader(); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, + "AudioBank", static_cast(SF64::ResourceType::Bank), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, + "AudioSample", static_cast(SF64::ResourceType::Sample), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, + "AudioSequence", static_cast(SF64::ResourceType::Sequence), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "Vec3f", static_cast(SF64::ResourceType::Vec3f), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "Vec3s", static_cast(SF64::ResourceType::Vec3s), 0); - loader->RegisterResourceFactory(std::make_shared(), - RESOURCE_FORMAT_BINARY, "GenericArray", - static_cast(SF64::ResourceType::GenericArray), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, + "GenericArray", static_cast(SF64::ResourceType::GenericArray), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "Texture", static_cast(LUS::ResourceType::Texture), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "Texture", static_cast(LUS::ResourceType::Texture), 1); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "Vertex", static_cast(LUS::ResourceType::Vertex), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_XML, + "Vertex", static_cast(LUS::ResourceType::Vertex), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "DisplayList", static_cast(LUS::ResourceType::DisplayList), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_XML, + "DisplayList", static_cast(LUS::ResourceType::DisplayList), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "Matrix", static_cast(LUS::ResourceType::Matrix), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, @@ -92,29 +109,27 @@ GameEngine::GameEngine() { "KartAI", static_cast(MK64::ResourceType::KartAI), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "CourseVtx", static_cast(MK64::ResourceType::CourseVertex), 0); - loader->RegisterResourceFactory(std::make_shared(), - RESOURCE_FORMAT_BINARY, "TrackSections", - static_cast(MK64::ResourceType::TrackSection), 0); - loader->RegisterResourceFactory(std::make_shared(), - RESOURCE_FORMAT_BINARY, "Waypoints", - static_cast(MK64::ResourceType::Waypoints), 0); - loader->RegisterResourceFactory(std::make_shared(), - RESOURCE_FORMAT_BINARY, "SpawnData", - static_cast(MK64::ResourceType::SpawnData), 0); - loader->RegisterResourceFactory(std::make_shared(), - RESOURCE_FORMAT_BINARY, "UnkSpawnData", - static_cast(MK64::ResourceType::UnkSpawnData), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, + "TrackSections", static_cast(MK64::ResourceType::TrackSection), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, + "Waypoints", static_cast(MK64::ResourceType::Waypoints), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, + "SpawnData", static_cast(MK64::ResourceType::SpawnData), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, + "UnkSpawnData", static_cast(MK64::ResourceType::UnkSpawnData), 0); } void GameEngine::Create() { const auto instance = Instance = new GameEngine(); + instance->AudioInit(); GameUI::SetupGuiElements(); #if defined(__SWITCH__) || defined(__WIIU__) CVarRegisterInteger("gControlNav", 1); // always enable controller nav on switch/wii u #endif } -void GameEngine::Destroy() { +void GameEngine::Destroy(){ + AudioExit(); } bool ShouldClearTextureCacheAtEndOfFrame = false; @@ -161,6 +176,106 @@ void GameEngine::ProcessGfxCommands(Gfx* commands) { } } +// Audio + +void GameEngine::HandleAudioThread(){ + while (audio.running) { + { + std::unique_lock Lock(audio.mutex); + while (!audio.processing && audio.running) { + audio.cv_to_thread.wait(Lock); + } + + if (!audio.running) { + break; + } + } + std::unique_lock Lock(audio.mutex); + + int samples_left = AudioPlayerBuffered(); + u32 num_audio_samples = samples_left < AudioPlayerGetDesiredBuffered() ? SAMPLES_HIGH : SAMPLES_LOW; + + s16 audio_buffer[SAMPLES_PER_FRAME]; + for (int i = 0; i < NUM_AUDIO_CHANNELS; i++) { + create_next_audio_buffer(audio_buffer + i * (num_audio_samples * 2), num_audio_samples); + } + + AudioPlayerPlayFrame((u8 *) audio_buffer, 2 * num_audio_samples * 4); + + audio.processing = false; + audio.cv_from_thread.notify_one(); + } +} + +void GameEngine::StartAudioFrame(){ + { + std::unique_lock Lock(audio.mutex); + audio.processing = true; + } + + audio.cv_to_thread.notify_one(); +} + +void GameEngine::EndAudioFrame(){ + { + std::unique_lock Lock(audio.mutex); + while (audio.processing) { + audio.cv_from_thread.wait(Lock); + } + } +} + +void GameEngine::AudioInit() { + const auto resourceMgr = Ship::Context::GetInstance()->GetResourceManager(); + resourceMgr->LoadDirectory("sound"); + const auto banksFiles = resourceMgr->GetArchiveManager()->ListFiles("sound/banks/*"); + const auto sequences_files = resourceMgr->GetArchiveManager()->ListFiles("sound/sequences/*"); + + Instance->sequenceTable.resize(512); + Instance->audioSequenceTable.resize(512); + Instance->banksTable.resize(512); + + for(auto& bank : *banksFiles){ + auto path = "__OTR__" + bank; + const auto ctl = static_cast(ResourceGetDataByName(path.c_str())); + this->bankMapTable[bank] = ctl->bankId; + SPDLOG_INFO("Loaded bank: {}", bank); + } + + for(auto& sequence : *sequences_files){ + auto path = "__OTR__" + sequence; + auto seq = static_cast(ResourceGetDataByName(path.c_str())); + Instance->sequenceTable[seq->id] = path; + SPDLOG_INFO("Loaded sequence: {}", sequence); + } + + if (!audio.running) { + audio.running = true; + audio.thread = std::thread(HandleAudioThread); + SPDLOG_INFO("Audio thread started"); + } +} + +void GameEngine::AudioExit() { + { + std::unique_lock lock(audio.mutex); + audio.running = false; + } + audio.cv_to_thread.notify_all(); + + // Wait until the audio thread quit + audio.thread.join(); +} + +uint8_t GameEngine::GetBankIdByName(const std::string& name) { + if(Instance->bankMapTable.contains(name)){ + return Instance->bankMapTable[name]; + } + return 0; +} + +// End + extern "C" uint32_t GameEngine_GetSampleRate() { auto player = Ship::Context::GetInstance()->GetAudio()->GetAudioPlayer(); if (player == nullptr) { @@ -178,7 +293,67 @@ extern "C" uint32_t GameEngine_GetSamplesPerFrame() { return SAMPLES_PER_FRAME; } -// End +extern "C" CtlEntry* GameEngine_LoadBank(const uint8_t bankId) { + const auto engine = GameEngine::Instance; + + if(bankId >= engine->bankMapTable.size()){ + return nullptr; + } + + if(engine->banksTable[bankId] != nullptr){ + return engine->banksTable[bankId]; + } + + for(auto& bank : engine->bankMapTable){ + if(bank.second == bankId){ + const auto ctl = static_cast(ResourceGetDataByName(("__OTR__" + bank.first).c_str())); + engine->banksTable[bankId] = ctl; + return ctl; + } + } + return nullptr; +} + +extern "C" uint8_t GameEngine_IsBankLoaded(const uint8_t bankId) { + const auto engine = GameEngine::Instance; + GameEngine_LoadBank(bankId); + return engine->banksTable[bankId] != nullptr; +} + +extern "C" void GameEngine_UnloadBank(const uint8_t bankId) { + const auto engine = GameEngine::Instance; + engine->banksTable[bankId] = nullptr; +} + +extern "C" AudioSequenceData* GameEngine_LoadSequence(const uint8_t seqId) { + auto engine = GameEngine::Instance; + + if(engine->sequenceTable[seqId].empty()){ + return nullptr; + } + + if(engine->audioSequenceTable[seqId] != nullptr){ + return engine->audioSequenceTable[seqId]; + } + + auto sequences = static_cast(ResourceGetDataByName(engine->sequenceTable[seqId].c_str())); + engine->audioSequenceTable[seqId] = sequences; + return sequences; +} + +extern "C" uint32_t GameEngine_GetSequenceCount(){ + auto engine = GameEngine::Instance; + return engine->sequenceTable.size(); +} + +extern "C" uint8_t GameEngine_IsSequenceLoaded(const uint8_t seqId) { + return GameEngine_LoadSequence(seqId) != nullptr; +} + +extern "C" void GameEngine_UnloadSequence(const uint8_t seqId) { + const auto engine = GameEngine::Instance; + engine->audioSequenceTable[seqId] = nullptr; +} extern "C" float GameEngine_GetAspectRatio() { return gfx_current_dimensions.aspect_ratio; diff --git a/src/port/Engine.h b/src/port/Engine.h index f466b0e6e..36d78d1fe 100644 --- a/src/port/Engine.h +++ b/src/port/Engine.h @@ -10,25 +10,41 @@ #include #include "libultraship/src/Context.h" -#define SAMPLES_HIGH 544 -#define SAMPLES_LOW 528 +#define SAMPLES_HIGH 448 +#define SAMPLES_LOW 432 #define AUDIO_FRAMES_PER_UPDATE 2 #define NUM_AUDIO_CHANNELS 2 #define SAMPLES_PER_FRAME (SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 2) +struct CtlEntry; +struct AudioBankSample; +struct AudioSequenceData; + class GameEngine { public: static GameEngine* Instance; std::shared_ptr context; + std::vector banksTable; + std::vector sequenceTable; + std::vector audioSequenceTable; + std::unordered_map bankMapTable; GameEngine(); static void Create(); + + void AudioInit(); + static void HandleAudioThread(); + static void StartAudioFrame(); + static void EndAudioFrame(); + static void AudioExit(); + void StartFrame() const; static void RunCommands(Gfx* Commands); void ProcessFrame(void (*run_one_game_iter)()) const; static void Destroy(); static void ProcessGfxCommands(Gfx* commands); + static uint8_t GetBankIdByName(const std::string& name); float OTRGetAspectRatio(void); float OTRGetDimensionFromLeftEdge(float v); float OTRGetDimensionFromRightEdge(float v); @@ -39,7 +55,16 @@ class GameEngine { }; #else void GameEngine_ProcessGfxCommands(Gfx* commands); +uint32_t GameEngine_GetSampleRate(); +uint32_t GameEngine_GetSamplesPerFrame(); float GameEngine_GetAspectRatio(); +struct CtlEntry* GameEngine_LoadBank(uint8_t bankId); +uint8_t GameEngine_IsBankLoaded(uint8_t bankId); +void GameEngine_UnloadBank(uint8_t bankId); +struct AudioSequenceData* GameEngine_LoadSequence(uint8_t seqId); +uint32_t GameEngine_GetSequenceCount(); +uint8_t GameEngine_IsSequenceLoaded(uint8_t seqId); +void GameEngine_UnloadSequence(uint8_t seqId); uint8_t GameEngine_OTRSigCheck(char* imgData); float OTRGetAspectRatio(void); float OTRGetDimensionFromLeftEdge(float v); diff --git a/src/port/Game.cpp b/src/port/Game.cpp index 445e1b805..0b5e8a32f 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -701,13 +701,13 @@ extern "C" { } void push_frame() { - // GameEngine::StartAudioFrame(); - GameEngine::Instance->StartFrame(); - thread5_iteration(); + GameEngine::StartAudioFrame(); + GameEngine::Instance->StartFrame(); + thread5_iteration(); + GameEngine::EndAudioFrame(); // thread5_game_loop(); // Graphics_ThreadUpdate();w // Timer_Update(); - // GameEngine::EndAudioFrame(); } #ifdef _WIN32 @@ -716,13 +716,12 @@ int SDL_main(int argc, char** argv) { #if defined(__cplusplus) && defined(PLATFORM_IOS) extern "C" #endif - int - main(int argc, char* argv[]) { +int main(int argc, char* argv[]) { #endif - //load_wasm(); + //load_wasm(); GameEngine::Create(); - // audio_init(); - // sound_init(); + audio_init(); + sound_init(); CustomEngineInit(); thread5_game_loop(); diff --git a/src/port/resource/importers/AudioBankFactory.cpp b/src/port/resource/importers/AudioBankFactory.cpp new file mode 100644 index 000000000..90d70b9aa --- /dev/null +++ b/src/port/resource/importers/AudioBankFactory.cpp @@ -0,0 +1,96 @@ +#include "AudioBankFactory.h" +#include "../type/AudioBank.h" +#include "spdlog/spdlog.h" +#include "resourcebridge.h" +#include "ResourceUtil.h" + +std::shared_ptr SM64::AudioBankFactoryV0::ReadResource(std::shared_ptr file) { + if (!FileHasValidFormatAndReader(file)) { + return nullptr; + } + + std::shared_ptr bank = std::make_shared(file->InitData); + auto reader = std::get>(file->Reader); + + uint8_t bankId = reader->ReadUInt32(); + uint32_t instrumentCount = reader->ReadUInt32(); + + for(size_t i = 0; i < instrumentCount; i++){ + auto* instrument = new Instrument(); + bool valid = reader->ReadUByte(); + if(!valid){ + bank->instruments.push_back(nullptr); + continue; + } + instrument->loaded = 1; + instrument->releaseRate = reader->ReadUByte(); + instrument->normalRangeLo = reader->ReadUByte(); + instrument->normalRangeHi = reader->ReadUByte(); + + uint32_t envelopeSize = reader->ReadUInt32(); + if(envelopeSize != 0){ + instrument->envelope = new AdsrEnvelope[envelopeSize]; + for(size_t j = 0; j < envelopeSize; j++){ + instrument->envelope[j].delay = BSWAP16(reader->ReadInt16()); + instrument->envelope[j].arg = BSWAP16(reader->ReadInt16()); + } + } + + uint32_t soundFlags = reader->ReadUInt32(); + bool hasLo = soundFlags & (1 << 0); + bool hasMed = soundFlags & (1 << 1); + bool hasHi = soundFlags & (1 << 2); + + if(hasLo){ + std::string lowSampleName = reader->ReadString(); + instrument->lowNotesSound.sample = LoadChild(lowSampleName.c_str()); + instrument->lowNotesSound.tuning = reader->ReadFloat(); + } + + if(hasMed){ + std::string normalSampleName = reader->ReadString(); + instrument->normalNotesSound.sample = LoadChild(normalSampleName.c_str()); + instrument->normalNotesSound.tuning = reader->ReadFloat(); + } + + if(hasHi){ + std::string highSampleName = reader->ReadString(); + instrument->highNotesSound.sample = LoadChild(highSampleName.c_str()); + instrument->highNotesSound.tuning = reader->ReadFloat(); + } + + bank->instruments.push_back(instrument); + } + + uint32_t drumCount = reader->ReadUInt32(); + + for(size_t i = 0; i < drumCount; i++){ + auto* drum = new Drum(); + drum->releaseRate = reader->ReadUByte(); + drum->pan = reader->ReadUByte(); + drum->loaded = 1; + + uint32_t envelopeSize = reader->ReadUInt32(); + if(envelopeSize != 0){ + drum->envelope = new AdsrEnvelope[envelopeSize]; + for(size_t j = 0; j < envelopeSize; j++){ + drum->envelope[j].delay = BSWAP16(reader->ReadInt16()); + drum->envelope[j].arg = BSWAP16(reader->ReadInt16()); + } + } + + std::string sampleName = reader->ReadString(); + drum->sound.sample = LoadChild(sampleName.c_str()); + drum->sound.tuning = reader->ReadFloat(); + + bank->drums.push_back(drum); + } + + bank->mData.bankId = bankId; + bank->mData.numInstruments = instrumentCount; + bank->mData.numDrums = drumCount; + bank->mData.instruments = bank->instruments.data(); + bank->mData.drums = bank->drums.data(); + + return bank; +} \ No newline at end of file diff --git a/src/port/resource/importers/AudioBankFactory.h b/src/port/resource/importers/AudioBankFactory.h new file mode 100644 index 000000000..f76e2d830 --- /dev/null +++ b/src/port/resource/importers/AudioBankFactory.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactoryBinary.h" + +namespace SM64 { +class AudioBankFactoryV0 : public Ship::ResourceFactoryBinary { + public: + std::shared_ptr ReadResource(std::shared_ptr file) override; +}; +} diff --git a/src/port/resource/importers/AudioSampleFactory.cpp b/src/port/resource/importers/AudioSampleFactory.cpp new file mode 100644 index 000000000..f21389666 --- /dev/null +++ b/src/port/resource/importers/AudioSampleFactory.cpp @@ -0,0 +1,47 @@ +#include "AudioSampleFactory.h" +#include +#include "../type/AudioSample.h" +#include "spdlog/spdlog.h" + +std::shared_ptr SM64::AudioSampleFactoryV0::ReadResource(std::shared_ptr file) { + if (!FileHasValidFormatAndReader(file)) { + return nullptr; + } + + std::shared_ptr bank = std::make_shared(file->InitData); + auto reader = std::get>(file->Reader); + + bank->loop.start = reader->ReadUInt32(); + bank->loop.end = reader->ReadUInt32(); + bank->loop.count = reader->ReadInt32(); + bank->loop.pad = reader->ReadInt32(); + + uint32_t stateSize = reader->ReadUInt32(); + std::vector state; + if(stateSize > 0){ + bank->loop.state = new int16_t[stateSize]; + reader->Read((char*) bank->loop.state, stateSize * sizeof(int16_t)); + } else { + bank->loop.state = nullptr; + } + + bank->book.order = reader->ReadInt32(); + bank->book.npredictors = reader->ReadInt32(); + + uint32_t tableSize = reader->ReadUInt32(); + bank->book.book = new int16_t[tableSize]; + reader->Read((char*) bank->book.book, tableSize * sizeof(int16_t)); + + int32_t sampleSize = reader->ReadInt32(); + char* sampleData = new char[sampleSize]; + reader->Read(sampleData, sampleSize); + + bank->mData.unused = 0; + bank->mData.loaded = 1; + bank->mData.loop = &bank->loop; + bank->mData.book = &bank->book; + bank->mData.sampleAddr = (uint8_t*) sampleData; + bank->mData.sampleSize = sampleSize; + + return bank; +} \ No newline at end of file diff --git a/src/port/resource/importers/AudioSampleFactory.h b/src/port/resource/importers/AudioSampleFactory.h new file mode 100644 index 000000000..cf640bd5c --- /dev/null +++ b/src/port/resource/importers/AudioSampleFactory.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactoryBinary.h" + +namespace SM64 { +class AudioSampleFactoryV0 : public Ship::ResourceFactoryBinary { + public: + std::shared_ptr ReadResource(std::shared_ptr file) override; +}; +} diff --git a/src/port/resource/importers/AudioSequenceFactory.cpp b/src/port/resource/importers/AudioSequenceFactory.cpp new file mode 100644 index 000000000..d021e8dc0 --- /dev/null +++ b/src/port/resource/importers/AudioSequenceFactory.cpp @@ -0,0 +1,33 @@ +#include "AudioSequenceFactory.h" +#include "../type/AudioSequence.h" +#include "../type/AudioBank.h" +#include "spdlog/spdlog.h" +#include "port/Engine.h" + +std::shared_ptr SM64::AudioSequenceFactoryV0::ReadResource(std::shared_ptr file) { + if (!FileHasValidFormatAndReader(file)) { + return nullptr; + } + + std::shared_ptr bank = std::make_shared(file->InitData); + auto reader = std::get>(file->Reader); + + uint8_t id = reader->ReadUInt32(); + size_t bankCount = reader->ReadUInt32(); + for(size_t i = 0; i < bankCount; i++){ + std::string bankName = reader->ReadString(); + bank->banks.push_back(GameEngine::GetBankIdByName(bankName)); + } + + size_t sampleSize = reader->ReadUInt32(); + for(size_t i = 0; i < sampleSize; i++){ + bank->sampleData.push_back(reader->ReadUByte()); + } + + bank->mData.bankCount = bankCount; + bank->mData.banks = bank->banks.data(); + bank->mData.data = bank->sampleData.data(); + bank->mData.id = id; + + return bank; +} \ No newline at end of file diff --git a/src/port/resource/importers/AudioSequenceFactory.h b/src/port/resource/importers/AudioSequenceFactory.h new file mode 100644 index 000000000..dd08e5152 --- /dev/null +++ b/src/port/resource/importers/AudioSequenceFactory.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactoryBinary.h" +#include "../type/AudioSequence.h" + +namespace SM64 { +class AudioSequenceFactoryV0 : public Ship::ResourceFactoryBinary { + public: + std::shared_ptr ReadResource(std::shared_ptr file) override; +}; +} diff --git a/src/port/resource/importers/ResourceUtil.h b/src/port/resource/importers/ResourceUtil.h index f856eccd3..69d03a7d9 100644 --- a/src/port/resource/importers/ResourceUtil.h +++ b/src/port/resource/importers/ResourceUtil.h @@ -3,7 +3,7 @@ #include "resourcebridge.h" #include "Context.h" -namespace SF64 { +namespace SM64 { template T LoadChild(uint64_t crc) { auto path = ResourceGetNameByCrc(crc); if (path == nullptr) { @@ -12,4 +12,11 @@ template T LoadChild(uint64_t crc) { auto asset = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(path); return asset ? static_cast(asset->GetRawPointer()) : nullptr; } -} // namespace SF64 +template T LoadChild(const char* path) { + if (path == nullptr) { + return nullptr; + } + auto asset = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(path); + return asset ? static_cast(asset->GetRawPointer()) : nullptr; +} +} diff --git a/src/port/resource/type/AudioBank.cpp b/src/port/resource/type/AudioBank.cpp new file mode 100644 index 000000000..f91b767d2 --- /dev/null +++ b/src/port/resource/type/AudioBank.cpp @@ -0,0 +1,11 @@ +#include "AudioBank.h" + +namespace SM64 { +CtlEntry* AudioBank::GetPointer() { + return &mData; +} + +size_t AudioBank::GetPointerSize() { + return sizeof(mData); +} +} \ No newline at end of file diff --git a/src/port/resource/type/AudioBank.h b/src/port/resource/type/AudioBank.h new file mode 100644 index 000000000..a8541fe84 --- /dev/null +++ b/src/port/resource/type/AudioBank.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include "AudioSample.h" +#include "resource/Resource.h" + +struct AudioBankSound { + AudioBankSample *sample; + float tuning; // frequency scale factor +}; // size = 0x8 + +struct AdsrEnvelope { + int16_t delay; + int16_t arg; +}; // size = 0x4 + +struct Instrument { + /*0x00*/ uint8_t loaded; + /*0x01*/ uint8_t normalRangeLo; + /*0x02*/ uint8_t normalRangeHi; + /*0x03*/ uint8_t releaseRate; + /*0x04*/ AdsrEnvelope *envelope; + /*0x08*/ AudioBankSound lowNotesSound; + /*0x10*/ AudioBankSound normalNotesSound; + /*0x18*/ AudioBankSound highNotesSound; +}; // size = 0x20 + +struct Drum { + uint8_t releaseRate; + uint8_t pan; + uint8_t loaded; + AudioBankSound sound; + AdsrEnvelope *envelope; +}; + +struct CtlEntry { + uint8_t bankId; + uint8_t numInstruments; + uint8_t numDrums; + struct Instrument **instruments; + struct Drum **drums; +}; // size = 0xC + +namespace SM64 { +class AudioBank : public Ship::Resource { + public: + using Resource::Resource; + + AudioBank() : Resource(std::shared_ptr()) {} + + CtlEntry* GetPointer(); + size_t GetPointerSize(); + + CtlEntry mData; + + std::vector instruments; + std::vector drums; +}; +} \ No newline at end of file diff --git a/src/port/resource/type/AudioSample.cpp b/src/port/resource/type/AudioSample.cpp new file mode 100644 index 000000000..cbdbd6573 --- /dev/null +++ b/src/port/resource/type/AudioSample.cpp @@ -0,0 +1,11 @@ +#include "AudioSample.h" + +namespace SM64 { +AudioBankSample* AudioSample::GetPointer() { + return &mData; +} + +size_t AudioSample::GetPointerSize() { + return sizeof(mData); +} +} \ No newline at end of file diff --git a/src/port/resource/type/AudioSample.h b/src/port/resource/type/AudioSample.h new file mode 100644 index 000000000..35f1d8d33 --- /dev/null +++ b/src/port/resource/type/AudioSample.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include "resource/Resource.h" + +struct AdpcmLoop { + uint32_t start; + uint32_t end; + uint32_t count; + uint32_t pad; + int16_t* state; // only exists if count != 0. 8-byte aligned +}; + +struct AdpcmBook { + int32_t order; + int32_t npredictors; + int16_t* book; // size 8 * order * npredictors. 8-byte aligned +}; + +struct AudioBankSample { + uint8_t unused; + uint8_t loaded; + uint8_t *sampleAddr; + AdpcmLoop *loop; + AdpcmBook *book; + uint32_t sampleSize; // never read. either 0 or 1 mod 9, depending on padding +}; + +namespace SM64 { + + +class AudioSample : public Ship::Resource { + public: + using Resource::Resource; + + AudioSample() : Resource(std::shared_ptr()) {} + + AudioBankSample* GetPointer(); + size_t GetPointerSize(); + + AudioBankSample mData; + + AdpcmLoop loop; + AdpcmBook book; + std::vector sampleAddr; +}; +} \ No newline at end of file diff --git a/src/port/resource/type/AudioSequence.cpp b/src/port/resource/type/AudioSequence.cpp new file mode 100644 index 000000000..263530cfa --- /dev/null +++ b/src/port/resource/type/AudioSequence.cpp @@ -0,0 +1,11 @@ +#include "AudioSequence.h" + +namespace SM64 { +AudioSequenceData* AudioSequence::GetPointer() { + return &mData; +} + +size_t AudioSequence::GetPointerSize() { + return sizeof(mData); +} +} \ No newline at end of file diff --git a/src/port/resource/type/AudioSequence.h b/src/port/resource/type/AudioSequence.h new file mode 100644 index 000000000..44ab130eb --- /dev/null +++ b/src/port/resource/type/AudioSequence.h @@ -0,0 +1,32 @@ +#pragma once + +#ifdef __cplusplus +#include +#endif + +struct AudioSequenceData { + uint32_t bankCount; + uint8_t* banks; + uint8_t* data; + uint8_t id; +}; + +#ifdef __cplusplus +#include "resource/Resource.h" +namespace SM64 { + +class AudioSequence : public Ship::Resource { + public: + using Resource::Resource; + + AudioSequence() : Resource(std::shared_ptr()) {} + + AudioSequenceData* GetPointer(); + size_t GetPointerSize(); + + AudioSequenceData mData; + std::vector banks; + std::vector sampleData; +}; +} +#endif \ No newline at end of file diff --git a/src/port/resource/type/ResourceType.h b/src/port/resource/type/ResourceType.h index 5c340c234..fe27a7930 100644 --- a/src/port/resource/type/ResourceType.h +++ b/src/port/resource/type/ResourceType.h @@ -17,6 +17,10 @@ enum class ResourceType { Vec3f = 0x56433346, // VC3F Vec3s = 0x56433353, // VC3S GenericArray = 0x47415252, // GARR + // NAudio v0 + Bank = 0x42414E4B, // BANK + Sample = 0x41554643, // AIFC + Sequence = 0x53455143, // SEQC }; } // namespace SF64 diff --git a/src/port/ui/ImguiUI.cpp b/src/port/ui/ImguiUI.cpp index 2284346bb..95d862a83 100644 --- a/src/port/ui/ImguiUI.cpp +++ b/src/port/ui/ImguiUI.cpp @@ -18,6 +18,7 @@ extern "C" { extern s32 gGamestateNext; extern s32 gMenuSelection; + #include "audio/external.h" #include "defines.h" } @@ -125,61 +126,60 @@ static const char* filters[3] = { void DrawSettingsMenu() { if (UIWidgets::BeginMenu("Settings")) { - // if (UIWidgets::BeginMenu("Audio")) { - // UIWidgets::CVarSliderFloat("Master Volume", "gGameMasterVolume", 0.0f, 1.0f, 1.0f, { - // .format = "%.0f%%", - // .isPercentage = true, - // }); - // if (UIWidgets::CVarSliderFloat("Main Music Volume", "gMainMusicVolume", 0.0f, 1.0f, 1.0f, - // { - // .format = "%.0f%%", - // .isPercentage = true, - // })) { - // audio_set_player_volume(SEQ_PLAYER_LEVEL, CVarGetFloat("gMainMusicVolume", 1.0f)); - // } - // if (UIWidgets::CVarSliderFloat("Sound Effects Volume", "gSFXMusicVolume", - // 0.0f, 1.0f, 1.0f, { - // .format = "%.0f%%", - // .isPercentage = true, - // })) { - // audio_set_player_volume(SEQ_PLAYER_SFX, CVarGetFloat("gSFXMusicVolume", 1.0f)); - // } - // if (UIWidgets::CVarSliderFloat("Environment Volume", "gEnvironmentVolume", - // 0.0f, 1.0f, 1.0f, { - // .format = "%.0f%%", - // .isPercentage = true, - // })) { - // audio_set_player_volume(SEQ_PLAYER_ENV, CVarGetFloat("gEnvironmentVolume", 1.0f)); - // } - // - // static std::unordered_map audioBackendNames = { - // { Ship::AudioBackend::WASAPI, "Windows Audio Session API" }, - // { Ship::AudioBackend::PULSE, "PulseAudio" }, - // { Ship::AudioBackend::SDL, "SDL" }, - // }; - // - // ImGui::Text("Audio API (Needs reload)"); - // auto currentAudioBackend = Ship::Context::GetInstance()->GetAudio()->GetAudioBackend(); - // - // if (Ship::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1) { - // UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f); - // } - // if (ImGui::BeginCombo("##AApi", audioBackendNames[currentAudioBackend])) { - // for (uint8_t i = 0; i < - // Ship::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size(); i++) { - // auto backend = Ship::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->data()[i]; - // if (ImGui::Selectable(audioBackendNames[backend], backend == currentAudioBackend)) { - // Ship::Context::GetInstance()->GetAudio()->SetAudioBackend(backend); - // } - // } - // ImGui::EndCombo(); - // } - // if (Ship::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1) { - // UIWidgets::ReEnableComponent(""); - // } - // - // ImGui::EndMenu(); - // } + if (UIWidgets::BeginMenu("Audio")) { + UIWidgets::CVarSliderFloat("Master Volume", "gGameMasterVolume", 0.0f, 1.0f, 1.0f, { + .format = "%.0f%%", + .isPercentage = true, + }); + if (UIWidgets::CVarSliderFloat("Main Music Volume", "gMainMusicVolume", 0.0f, 1.0f, 1.0f, + { + .format = "%.0f%%", + .isPercentage = true, + })) { + audio_set_player_volume(SEQ_PLAYER_LEVEL, CVarGetFloat("gMainMusicVolume", 1.0f)); + } + if (UIWidgets::CVarSliderFloat("Sound Effects Volume", "gSFXMusicVolume", + 0.0f, 1.0f, 1.0f, { + .format = "%.0f%%", + .isPercentage = true, + })) { + audio_set_player_volume(SEQ_PLAYER_SFX, CVarGetFloat("gSFXMusicVolume", 1.0f)); + } + if (UIWidgets::CVarSliderFloat("Environment Volume", "gEnvironmentVolume", + 0.0f, 1.0f, 1.0f, { + .format = "%.0f%%", + .isPercentage = true, + })) { + audio_set_player_volume(SEQ_PLAYER_ENV, CVarGetFloat("gEnvironmentVolume", 1.0f)); + } + + static std::unordered_map audioBackendNames = { + { Ship::AudioBackend::WASAPI, "Windows Audio Session API" }, + { Ship::AudioBackend::SDL, "SDL" }, + }; + + ImGui::Text("Audio API (Needs reload)"); + auto currentAudioBackend = Ship::Context::GetInstance()->GetAudio()->GetCurrentAudioBackend(); + + if (Ship::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1) { + UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f); + } + if (ImGui::BeginCombo("##AApi", audioBackendNames[currentAudioBackend])) { + for (uint8_t i = 0; i < + Ship::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size(); i++) { + auto backend = Ship::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->data()[i]; + if (ImGui::Selectable(audioBackendNames[backend], backend == currentAudioBackend)) { + Ship::Context::GetInstance()->GetAudio()->SetCurrentAudioBackend(backend); + } + } + ImGui::EndCombo(); + } + if (Ship::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1) { + UIWidgets::ReEnableComponent(""); + } + + ImGui::EndMenu(); + } UIWidgets::Spacer(0); diff --git a/src/racing/math_util.c b/src/racing/math_util.c index 4204e8670..54b6aa412 100644 --- a/src/racing/math_util.c +++ b/src/racing/math_util.c @@ -951,7 +951,7 @@ u16 atan2s(f32 x, f32 y) { return ret; } -f32 atan2f(f32 arg0, f32 arg1) { +f32 _atan2f(f32 arg0, f32 arg1) { return atan2s(arg0, arg1); } @@ -999,11 +999,11 @@ UNUSED f32 func_802B79F0(f32 arg0, f32 arg1) { #endif UNUSED u16 func_802B7B50(f32 arg0, f32 arg1) { - return ((atan2f(arg0, arg1) * 32768.0f) / M_PI); + return ((_atan2f(arg0, arg1) * 32768.0f) / M_PI); } UNUSED void func_802B7C18(f32 arg0) { - atan2f(arg0, 1.0f); + _atan2f(arg0, 1.0f); } s16 func_802B7C40(f32 arg0) { @@ -1011,7 +1011,7 @@ s16 func_802B7C40(f32 arg0) { } UNUSED void func_802B7C6C(f32 arg0) { - atan2f(arg0, sqrtf(1.0 - (arg0 * arg0))); + _atan2f(arg0, sqrtf(1.0 - (arg0 * arg0))); } s16 func_802B7CA8(f32 arg0) { @@ -1019,11 +1019,11 @@ s16 func_802B7CA8(f32 arg0) { } f32 calculate_vector_angle_xy(f32 vectorX) { - return atan2f(sqrtf(1.0 - (vectorX * vectorX)), vectorX); + return _atan2f(sqrtf(1.0 - (vectorX * vectorX)), vectorX); } UNUSED s16 func_802B7D28(f32 arg0) { - return atan2f(sqrtf(1.0 - (f64) (arg0 * arg0)), arg0) * 32768.0f / M_PI; + return _atan2f(sqrtf(1.0 - (f64) (arg0 * arg0)), arg0) * 32768.0f / M_PI; } u16 random_u16(void) { diff --git a/src/racing/math_util.h b/src/racing/math_util.h index a9c396ad6..71a203b62 100644 --- a/src/racing/math_util.h +++ b/src/racing/math_util.h @@ -55,7 +55,7 @@ void mtxf_multiplication(Mat4, Mat4, Mat4); void mtxf_to_mtx(Mtx*, Mat4); u16 atan2_lookup(f32, f32); u16 atan2s(f32, f32); -f32 atan2f(f32, f32); +f32 _atan2f(f32, f32); s16 func_802B7C40(f32); s16 func_802B7CA8(f32); f32 calculate_vector_angle_xy(f32); diff --git a/src/racing/race_logic.c b/src/racing/race_logic.c index 7565b4f5c..025b50d79 100644 --- a/src/racing/race_logic.c +++ b/src/racing/race_logic.c @@ -21,6 +21,7 @@ #include "effects.h" #include "math.h" #include "menus.h" +#include "sounds.h" #include "port/Game.h" #pragma intrinsic(sqrtf) @@ -423,31 +424,10 @@ void func_8028EC98(s32 arg0) { func_800029B0(); - if (GetCourse() == GetMarioRaceway() || GetCourse() == GetRoyalRaceway() || GetCourse() == GetLuigiRaceway() || - GetCourse() == GetWarioStadium()) { - func_800C8EAC(3); - } else if (GetCourse() == GetToadsTurnpike()) { - func_800C8EAC(21); - } else if (GetCourse() == GetYoshiValley() || GetCourse() == GetMooMooFarm()) { - func_800C8EAC(4); - } else if (GetCourse() == GetChocoMountain() || GetCourse() == GetBlockFort() || GetCourse() == GetDoubleDeck()) { - func_800C8EAC(5); - } else if (GetCourse() == GetKalimariDesert()) { - func_800C8EAC(10); - } else if (GetCourse() == GetKoopaTroopaBeach()) { - func_800C8EAC(6); - } else if (GetCourse() == GetBowsersCastle()) { - func_800C8EAC(9); - } else if (GetCourse() == GetBansheeBoardwalk()) { - func_800C8EAC(7); - } else if (GetCourse() == GetFrappeSnowland() || GetCourse() == GetSherbetLand()) { - func_800C8EAC(8); - } else if (GetCourse() == GetRainbowRoad()) { - func_800C8EAC(18); - } else if (GetCourse() == GetDkJungle()) { - func_800C8EAC(19); - } else if (GetCourse() == GetSkyscraper() || GetCourse() == GetBigDonut()) { - func_800C8EAC(25); + enum MusicSeq sequence = CourseManager_GetProps()->Sequence; + + if(sequence != MUSIC_SEQ_UNKNOWN){ + play_sequence(sequence); } } diff --git a/torch b/torch index 1d485d769..e466f58b2 160000 --- a/torch +++ b/torch @@ -1 +1 @@ -Subproject commit 1d485d7695699dbfe28407a62c312b6c3732d4a2 +Subproject commit e466f58b2cff026c37201154cc74096b1f7ac0ce diff --git a/yamls/us/sound/banks.yml b/yamls/us/sound/banks.yml new file mode 100644 index 000000000..a5e619d47 --- /dev/null +++ b/yamls/us/sound/banks.yml @@ -0,0 +1,88 @@ +:config: + external_files: + - "yamls/us/sound/root.yml" + - "yamls/us/sound/samples.yml" + +bank_0: + type: NAUDIO:V0:BANK + id: 0 + +bank_1: + type: NAUDIO:V0:BANK + id: 1 + +bank_2: + type: NAUDIO:V0:BANK + id: 2 + +bank_3: + type: NAUDIO:V0:BANK + id: 3 + +bank_4: + type: NAUDIO:V0:BANK + id: 4 + +bank_5: + type: NAUDIO:V0:BANK + id: 5 + +bank_6: + type: NAUDIO:V0:BANK + id: 6 + +bank_7: + type: NAUDIO:V0:BANK + id: 7 + +bank_8: + type: NAUDIO:V0:BANK + id: 8 + +bank_9: + type: NAUDIO:V0:BANK + id: 9 + +bank_10: + type: NAUDIO:V0:BANK + id: 10 + +bank_11: + type: NAUDIO:V0:BANK + id: 11 + +bank_12: + type: NAUDIO:V0:BANK + id: 12 + +bank_13: + type: NAUDIO:V0:BANK + id: 13 + +bank_14: + type: NAUDIO:V0:BANK + id: 14 + +bank_15: + type: NAUDIO:V0:BANK + id: 15 + +bank_16: + type: NAUDIO:V0:BANK + id: 16 + +bank_17: + type: NAUDIO:V0:BANK + id: 17 + +bank_18: + type: NAUDIO:V0:BANK + id: 18 + +bank_19: + type: NAUDIO:V0:BANK + id: 19 + +bank_20: + type: NAUDIO:V0:BANK + id: 20 \ No newline at end of file diff --git a/yamls/us/audio.yml b/yamls/us/sound/root.yml similarity index 64% rename from yamls/us/audio.yml rename to yamls/us/sound/root.yml index cda86c71e..d99080128 100644 --- a/yamls/us/audio.yml +++ b/yamls/us/sound/root.yml @@ -13,4 +13,7 @@ header: size: 0x13840 tbl: offset: 0x979AA0 - size: 0x24C4C0 \ No newline at end of file + size: 0x24C4C0 + +audio_seq_font_table: + { type: ARRAY, count: 0x80, array_type: u8, offset: 0xBE90E0, symbol: gSeqFontTableInit } \ No newline at end of file diff --git a/yamls/us/sound/samples.yml b/yamls/us/sound/samples.yml new file mode 100644 index 000000000..cf5ee5606 --- /dev/null +++ b/yamls/us/sound/samples.yml @@ -0,0 +1,807 @@ +sample_0: + type: NAUDIO:V0:SAMPLE + id: 0 + +sample_1: + type: NAUDIO:V0:SAMPLE + id: 1 + +sample_2: + type: NAUDIO:V0:SAMPLE + id: 2 + +sample_3: + type: NAUDIO:V0:SAMPLE + id: 3 + +sample_4: + type: NAUDIO:V0:SAMPLE + id: 4 + +sample_5: + type: NAUDIO:V0:SAMPLE + id: 5 + +sample_6: + type: NAUDIO:V0:SAMPLE + id: 6 + +sample_7: + type: NAUDIO:V0:SAMPLE + id: 7 + +sample_8: + type: NAUDIO:V0:SAMPLE + id: 8 + +sample_9: + type: NAUDIO:V0:SAMPLE + id: 9 + +sample_10: + type: NAUDIO:V0:SAMPLE + id: 10 + +sample_11: + type: NAUDIO:V0:SAMPLE + id: 11 + +sample_12: + type: NAUDIO:V0:SAMPLE + id: 12 + +sample_13: + type: NAUDIO:V0:SAMPLE + id: 13 + +sample_14: + type: NAUDIO:V0:SAMPLE + id: 14 + +sample_15: + type: NAUDIO:V0:SAMPLE + id: 15 + +sample_16: + type: NAUDIO:V0:SAMPLE + id: 16 + +sample_17: + type: NAUDIO:V0:SAMPLE + id: 17 + +sample_18: + type: NAUDIO:V0:SAMPLE + id: 18 + +sample_19: + type: NAUDIO:V0:SAMPLE + id: 19 + +sample_20: + type: NAUDIO:V0:SAMPLE + id: 20 + +sample_21: + type: NAUDIO:V0:SAMPLE + id: 21 + +sample_22: + type: NAUDIO:V0:SAMPLE + id: 22 + +sample_23: + type: NAUDIO:V0:SAMPLE + id: 23 + +sample_24: + type: NAUDIO:V0:SAMPLE + id: 24 + +sample_25: + type: NAUDIO:V0:SAMPLE + id: 25 + +sample_26: + type: NAUDIO:V0:SAMPLE + id: 26 + +sample_27: + type: NAUDIO:V0:SAMPLE + id: 27 + +sample_28: + type: NAUDIO:V0:SAMPLE + id: 28 + +sample_29: + type: NAUDIO:V0:SAMPLE + id: 29 + +sample_30: + type: NAUDIO:V0:SAMPLE + id: 30 + +sample_31: + type: NAUDIO:V0:SAMPLE + id: 31 + +sample_32: + type: NAUDIO:V0:SAMPLE + id: 32 + +sample_33: + type: NAUDIO:V0:SAMPLE + id: 33 + +sample_34: + type: NAUDIO:V0:SAMPLE + id: 34 + +sample_35: + type: NAUDIO:V0:SAMPLE + id: 35 + +sample_36: + type: NAUDIO:V0:SAMPLE + id: 36 + +sample_37: + type: NAUDIO:V0:SAMPLE + id: 37 + +sample_38: + type: NAUDIO:V0:SAMPLE + id: 38 + +sample_39: + type: NAUDIO:V0:SAMPLE + id: 39 + +sample_40: + type: NAUDIO:V0:SAMPLE + id: 40 + +sample_41: + type: NAUDIO:V0:SAMPLE + id: 41 + +sample_42: + type: NAUDIO:V0:SAMPLE + id: 42 + +sample_43: + type: NAUDIO:V0:SAMPLE + id: 43 + +sample_44: + type: NAUDIO:V0:SAMPLE + id: 44 + +sample_45: + type: NAUDIO:V0:SAMPLE + id: 45 + +sample_46: + type: NAUDIO:V0:SAMPLE + id: 46 + +sample_47: + type: NAUDIO:V0:SAMPLE + id: 47 + +sample_48: + type: NAUDIO:V0:SAMPLE + id: 48 + +sample_49: + type: NAUDIO:V0:SAMPLE + id: 49 + +sample_50: + type: NAUDIO:V0:SAMPLE + id: 50 + +sample_51: + type: NAUDIO:V0:SAMPLE + id: 51 + +sample_52: + type: NAUDIO:V0:SAMPLE + id: 52 + +sample_53: + type: NAUDIO:V0:SAMPLE + id: 53 + +sample_54: + type: NAUDIO:V0:SAMPLE + id: 54 + +sample_55: + type: NAUDIO:V0:SAMPLE + id: 55 + +sample_56: + type: NAUDIO:V0:SAMPLE + id: 56 + +sample_57: + type: NAUDIO:V0:SAMPLE + id: 57 + +sample_58: + type: NAUDIO:V0:SAMPLE + id: 58 + +sample_59: + type: NAUDIO:V0:SAMPLE + id: 59 + +sample_60: + type: NAUDIO:V0:SAMPLE + id: 60 + +sample_61: + type: NAUDIO:V0:SAMPLE + id: 61 + +sample_62: + type: NAUDIO:V0:SAMPLE + id: 62 + +sample_63: + type: NAUDIO:V0:SAMPLE + id: 63 + +sample_64: + type: NAUDIO:V0:SAMPLE + id: 64 + +sample_65: + type: NAUDIO:V0:SAMPLE + id: 65 + +sample_66: + type: NAUDIO:V0:SAMPLE + id: 66 + +sample_67: + type: NAUDIO:V0:SAMPLE + id: 67 + +sample_68: + type: NAUDIO:V0:SAMPLE + id: 68 + +sample_69: + type: NAUDIO:V0:SAMPLE + id: 69 + +sample_70: + type: NAUDIO:V0:SAMPLE + id: 70 + +sample_71: + type: NAUDIO:V0:SAMPLE + id: 71 + +sample_72: + type: NAUDIO:V0:SAMPLE + id: 72 + +sample_73: + type: NAUDIO:V0:SAMPLE + id: 73 + +sample_74: + type: NAUDIO:V0:SAMPLE + id: 74 + +sample_75: + type: NAUDIO:V0:SAMPLE + id: 75 + +sample_76: + type: NAUDIO:V0:SAMPLE + id: 76 + +sample_77: + type: NAUDIO:V0:SAMPLE + id: 77 + +sample_78: + type: NAUDIO:V0:SAMPLE + id: 78 + +sample_79: + type: NAUDIO:V0:SAMPLE + id: 79 + +sample_80: + type: NAUDIO:V0:SAMPLE + id: 80 + +sample_81: + type: NAUDIO:V0:SAMPLE + id: 81 + +sample_82: + type: NAUDIO:V0:SAMPLE + id: 82 + +sample_83: + type: NAUDIO:V0:SAMPLE + id: 83 + +sample_84: + type: NAUDIO:V0:SAMPLE + id: 84 + +sample_85: + type: NAUDIO:V0:SAMPLE + id: 85 + +sample_86: + type: NAUDIO:V0:SAMPLE + id: 86 + +sample_87: + type: NAUDIO:V0:SAMPLE + id: 87 + +sample_88: + type: NAUDIO:V0:SAMPLE + id: 88 + +sample_89: + type: NAUDIO:V0:SAMPLE + id: 89 + +sample_90: + type: NAUDIO:V0:SAMPLE + id: 90 + +sample_91: + type: NAUDIO:V0:SAMPLE + id: 91 + +sample_92: + type: NAUDIO:V0:SAMPLE + id: 92 + +sample_93: + type: NAUDIO:V0:SAMPLE + id: 93 + +sample_94: + type: NAUDIO:V0:SAMPLE + id: 94 + +sample_95: + type: NAUDIO:V0:SAMPLE + id: 95 + +sample_96: + type: NAUDIO:V0:SAMPLE + id: 96 + +sample_97: + type: NAUDIO:V0:SAMPLE + id: 97 + +sample_98: + type: NAUDIO:V0:SAMPLE + id: 98 + +sample_99: + type: NAUDIO:V0:SAMPLE + id: 99 + +sample_100: + type: NAUDIO:V0:SAMPLE + id: 100 + +sample_101: + type: NAUDIO:V0:SAMPLE + id: 101 + +sample_102: + type: NAUDIO:V0:SAMPLE + id: 102 + +sample_103: + type: NAUDIO:V0:SAMPLE + id: 103 + +sample_104: + type: NAUDIO:V0:SAMPLE + id: 104 + +sample_105: + type: NAUDIO:V0:SAMPLE + id: 105 + +sample_106: + type: NAUDIO:V0:SAMPLE + id: 106 + +sample_107: + type: NAUDIO:V0:SAMPLE + id: 107 + +sample_108: + type: NAUDIO:V0:SAMPLE + id: 108 + +sample_109: + type: NAUDIO:V0:SAMPLE + id: 109 + +sample_110: + type: NAUDIO:V0:SAMPLE + id: 110 + +sample_111: + type: NAUDIO:V0:SAMPLE + id: 111 + +sample_112: + type: NAUDIO:V0:SAMPLE + id: 112 + +sample_113: + type: NAUDIO:V0:SAMPLE + id: 113 + +sample_114: + type: NAUDIO:V0:SAMPLE + id: 114 + +sample_115: + type: NAUDIO:V0:SAMPLE + id: 115 + +sample_116: + type: NAUDIO:V0:SAMPLE + id: 116 + +sample_117: + type: NAUDIO:V0:SAMPLE + id: 117 + +sample_118: + type: NAUDIO:V0:SAMPLE + id: 118 + +sample_119: + type: NAUDIO:V0:SAMPLE + id: 119 + +sample_120: + type: NAUDIO:V0:SAMPLE + id: 120 + +sample_121: + type: NAUDIO:V0:SAMPLE + id: 121 + +sample_122: + type: NAUDIO:V0:SAMPLE + id: 122 + +sample_123: + type: NAUDIO:V0:SAMPLE + id: 123 + +sample_124: + type: NAUDIO:V0:SAMPLE + id: 124 + +sample_125: + type: NAUDIO:V0:SAMPLE + id: 125 + +sample_126: + type: NAUDIO:V0:SAMPLE + id: 126 + +sample_127: + type: NAUDIO:V0:SAMPLE + id: 127 + +sample_128: + type: NAUDIO:V0:SAMPLE + id: 128 + +sample_129: + type: NAUDIO:V0:SAMPLE + id: 129 + +sample_130: + type: NAUDIO:V0:SAMPLE + id: 130 + +sample_131: + type: NAUDIO:V0:SAMPLE + id: 131 + +sample_132: + type: NAUDIO:V0:SAMPLE + id: 132 + +sample_133: + type: NAUDIO:V0:SAMPLE + id: 133 + +sample_134: + type: NAUDIO:V0:SAMPLE + id: 134 + +sample_135: + type: NAUDIO:V0:SAMPLE + id: 135 + +sample_136: + type: NAUDIO:V0:SAMPLE + id: 136 + +sample_137: + type: NAUDIO:V0:SAMPLE + id: 137 + +sample_138: + type: NAUDIO:V0:SAMPLE + id: 138 + +sample_139: + type: NAUDIO:V0:SAMPLE + id: 139 + +sample_140: + type: NAUDIO:V0:SAMPLE + id: 140 + +sample_141: + type: NAUDIO:V0:SAMPLE + id: 141 + +sample_142: + type: NAUDIO:V0:SAMPLE + id: 142 + +sample_143: + type: NAUDIO:V0:SAMPLE + id: 143 + +sample_144: + type: NAUDIO:V0:SAMPLE + id: 144 + +sample_145: + type: NAUDIO:V0:SAMPLE + id: 145 + +sample_146: + type: NAUDIO:V0:SAMPLE + id: 146 + +sample_147: + type: NAUDIO:V0:SAMPLE + id: 147 + +sample_148: + type: NAUDIO:V0:SAMPLE + id: 148 + +sample_149: + type: NAUDIO:V0:SAMPLE + id: 149 + +sample_150: + type: NAUDIO:V0:SAMPLE + id: 150 + +sample_151: + type: NAUDIO:V0:SAMPLE + id: 151 + +sample_152: + type: NAUDIO:V0:SAMPLE + id: 152 + +sample_153: + type: NAUDIO:V0:SAMPLE + id: 153 + +sample_154: + type: NAUDIO:V0:SAMPLE + id: 154 + +sample_155: + type: NAUDIO:V0:SAMPLE + id: 155 + +sample_156: + type: NAUDIO:V0:SAMPLE + id: 156 + +sample_157: + type: NAUDIO:V0:SAMPLE + id: 157 + +sample_158: + type: NAUDIO:V0:SAMPLE + id: 158 + +sample_159: + type: NAUDIO:V0:SAMPLE + id: 159 + +sample_160: + type: NAUDIO:V0:SAMPLE + id: 160 + +sample_161: + type: NAUDIO:V0:SAMPLE + id: 161 + +sample_162: + type: NAUDIO:V0:SAMPLE + id: 162 + +sample_163: + type: NAUDIO:V0:SAMPLE + id: 163 + +sample_164: + type: NAUDIO:V0:SAMPLE + id: 164 + +sample_165: + type: NAUDIO:V0:SAMPLE + id: 165 + +sample_166: + type: NAUDIO:V0:SAMPLE + id: 166 + +sample_167: + type: NAUDIO:V0:SAMPLE + id: 167 + +sample_168: + type: NAUDIO:V0:SAMPLE + id: 168 + +sample_169: + type: NAUDIO:V0:SAMPLE + id: 169 + +sample_170: + type: NAUDIO:V0:SAMPLE + id: 170 + +sample_171: + type: NAUDIO:V0:SAMPLE + id: 171 + +sample_172: + type: NAUDIO:V0:SAMPLE + id: 172 + +sample_173: + type: NAUDIO:V0:SAMPLE + id: 173 + +sample_174: + type: NAUDIO:V0:SAMPLE + id: 174 + +sample_175: + type: NAUDIO:V0:SAMPLE + id: 175 + +sample_176: + type: NAUDIO:V0:SAMPLE + id: 176 + +sample_177: + type: NAUDIO:V0:SAMPLE + id: 177 + +sample_178: + type: NAUDIO:V0:SAMPLE + id: 178 + +sample_179: + type: NAUDIO:V0:SAMPLE + id: 179 + +sample_180: + type: NAUDIO:V0:SAMPLE + id: 180 + +sample_181: + type: NAUDIO:V0:SAMPLE + id: 181 + +sample_182: + type: NAUDIO:V0:SAMPLE + id: 182 + +sample_183: + type: NAUDIO:V0:SAMPLE + id: 183 + +sample_184: + type: NAUDIO:V0:SAMPLE + id: 184 + +sample_185: + type: NAUDIO:V0:SAMPLE + id: 185 + +sample_186: + type: NAUDIO:V0:SAMPLE + id: 186 + +sample_187: + type: NAUDIO:V0:SAMPLE + id: 187 + +sample_188: + type: NAUDIO:V0:SAMPLE + id: 188 + +sample_189: + type: NAUDIO:V0:SAMPLE + id: 189 + +sample_190: + type: NAUDIO:V0:SAMPLE + id: 190 + +sample_191: + type: NAUDIO:V0:SAMPLE + id: 191 + +sample_192: + type: NAUDIO:V0:SAMPLE + id: 192 + +sample_193: + type: NAUDIO:V0:SAMPLE + id: 193 + +sample_194: + type: NAUDIO:V0:SAMPLE + id: 194 + +sample_195: + type: NAUDIO:V0:SAMPLE + id: 195 + +sample_196: + type: NAUDIO:V0:SAMPLE + id: 196 + +sample_197: + type: NAUDIO:V0:SAMPLE + id: 197 + +sample_198: + type: NAUDIO:V0:SAMPLE + id: 198 + +sample_199: + type: NAUDIO:V0:SAMPLE + id: 199 + +sample_200: + type: NAUDIO:V0:SAMPLE + id: 200 + +sample_201: + type: NAUDIO:V0:SAMPLE + id: 201 \ No newline at end of file diff --git a/yamls/us/sound/sequences.yml b/yamls/us/sound/sequences.yml new file mode 100644 index 000000000..f57a42051 --- /dev/null +++ b/yamls/us/sound/sequences.yml @@ -0,0 +1,239 @@ +seq_00: + type: NAUDIO:V0:SEQUENCE + id: 0 + size: 0x2830 + offset: 0xBC6060 + banks: + - sound/banks/bank_0 + +title_screen: + type: NAUDIO:V0:SEQUENCE + id: 1 + size: 0x1B30 + offset: 0xBC8890 + banks: + - sound/banks/bank_1 + +main_menu: + type: NAUDIO:V0:SEQUENCE + id: 2 + size: 0x0D60 + offset: 0xBCA3C0 + banks: + - sound/banks/bank_2 + +raceways_wario_stadium: + type: NAUDIO:V0:SEQUENCE + id: 3 + size: 0x1A10 + offset: 0xBCB120 + banks: + - sound/banks/bank_3 + +moo_moo_farm_yoshi_valley: + type: NAUDIO:V0:SEQUENCE + id: 4 + size: 0x1CA0 + offset: 0xBCCB30 + banks: + - sound/banks/bank_4 + +choco_mountain: + type: NAUDIO:V0:SEQUENCE + id: 5 + size: 0x1F70 + offset: 0xBCE7D0 + banks: + - sound/banks/bank_5 + +koopa_troopa_beach: + type: NAUDIO:V0:SEQUENCE + id: 6 + size: 0x1EE0 + offset: 0xBD0740 + banks: + - sound/banks/bank_6 + +banshee_boardwalk: + type: NAUDIO:V0:SEQUENCE + id: 7 + size: 0x16D0 + offset: 0xBD2620 + banks: + - sound/banks/bank_7 + +frappe_snowland: + type: NAUDIO:V0:SEQUENCE + id: 8 + size: 0x23D0 + offset: 0xBD3CF0 + banks: + - sound/banks/bank_8 + +bowsers_castle: + type: NAUDIO:V0:SEQUENCE + id: 9 + size: 0x1800 + offset: 0xBD60C0 + banks: + - sound/banks/bank_9 + +kalimari_desert: + type: NAUDIO:V0:SEQUENCE + id: 10 + size: 0x1AE0 + offset: 0xBD78C0 + banks: + - sound/banks/bank_10 + +start_grid_gp_vs: + type: NAUDIO:V0:SEQUENCE + id: 11 + size: 0x05F0 + offset: 0xBD93A0 + banks: + - sound/banks/bank_11 + +final_lap_fanfare: + type: NAUDIO:V0:SEQUENCE + id: 12 + size: 0x03D0 + offset: 0xBD9990 + banks: + - sound/banks/bank_11 + +finish_1st_place: + type: NAUDIO:V0:SEQUENCE + id: 13 + size: 0x0360 + offset: 0xBD9D60 + banks: + - sound/banks/bank_11 + +finish_2nd_4th_place: + type: NAUDIO:V0:SEQUENCE + id: 14 + size: 0x02E0 + offset: 0xBDA0C0 + banks: + - sound/banks/bank_11 + +finish_5th_8th_place: + type: NAUDIO:V0:SEQUENCE + id: 15 + size: 0x04C0 + offset: 0xBDA3A0 + banks: + - sound/banks/bank_11 + +seq_16: + type: NAUDIO:V0:SEQUENCE + id: 16 + size: 0x1410 + offset: 0xBDA860 + banks: + - sound/banks/bank_12 + +star_jingle: + type: NAUDIO:V0:SEQUENCE + id: 17 + size: 0x06E0 + offset: 0xBDBC70 + banks: + - sound/banks/bank_14 + +rainbow_road: + type: NAUDIO:V0:SEQUENCE + id: 18 + size: 0x32F0 + offset: 0xBDC350 + banks: + - sound/banks/bank_15 + +dk_jungle: + type: NAUDIO:V0:SEQUENCE + id: 19 + size: 0x06C0 + offset: 0xBDF640 + banks: + - sound/banks/bank_16 + +game_over: + type: NAUDIO:V0:SEQUENCE + id: 20 + size: 0x04B0 + offset: 0xBDFD00 + banks: + - sound/banks/bank_11 + +toads_turnpike: + type: NAUDIO:V0:SEQUENCE + id: 21 + size: 0x1160 + offset: 0xBE01B0 + banks: + - sound/banks/bank_17 + +start_gird_time_attack: + type: NAUDIO:V0:SEQUENCE + id: 22 + size: 0x0310 + offset: 0xBE1310 + banks: + - sound/banks/bank_11 + +vs_battle_results: + type: NAUDIO:V0:SEQUENCE + id: 23 + size: 0x12B0 + offset: 0xBE1620 + banks: + - sound/banks/bank_13 + +losing_results: + type: NAUDIO:V0:SEQUENCE + id: 24 + size: 0x0600 + offset: 0xBE28D0 + banks: + - sound/banks/bank_12 + +battle_arenas: + type: NAUDIO:V0:SEQUENCE + id: 25 + size: 0x16E0 + offset: 0xBE2ED0 + banks: + - sound/banks/bank_18 + +award_ceremony_buildup: + type: NAUDIO:V0:SEQUENCE + id: 26 + size: 0x0AD0 + offset: 0xBE45B0 + banks: + - sound/banks/bank_19 + +award_ceremony_1st_3rd: + type: NAUDIO:V0:SEQUENCE + id: 27 + size: 0x0C80 + offset: 0xBE5080 + banks: + - sound/banks/bank_19 + +staff_roll: + type: NAUDIO:V0:SEQUENCE + id: 28 + size: 0x2750 + offset: 0xBE5D00 + banks: + - sound/banks/bank_20 + +award_ceremony_4th_8th: + type: NAUDIO:V0:SEQUENCE + id: 29 + size: 0x0C80 + offset: 0xBE8450 + banks: + - sound/banks/bank_19 \ No newline at end of file