diff options
| author | engineer124 <47598039+engineer124@users.noreply.github.com> | 2022-08-15 14:39:57 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-15 14:39:57 -0400 |
| commit | 82fe521721ecd8506e4bc5954e406db1e8de8edc (patch) | |
| tree | 8c9d59f81335145084e25fa2142b9bb03cf73e6b /src/code | |
| parent | 0082c299c62ca5debfbaee1ce21d67df7fb0b441 (diff) | |
Audio Sfx (code_801A5BD0 and selected sfx functions in code_8019AF00.c) OK and Documented (#798)
* Rename functions
* code_801A5BD0 OK
* PR 1, improve spacing
* Rename unused struct
* Rename Sfx Variables
* PR Feedback, update names
* Add comment
* cleanup vars
* Fix merge
* Rework documentation, include more functions in sfx system
* PR suggestions
* fix AudioSfx_MuteBanks
* missed enum
* more cleanup
* more suggestions
Diffstat (limited to 'src/code')
| -rw-r--r-- | src/code/audio/audio_load.c | 4 | ||||
| -rw-r--r-- | src/code/audio/audio_playback.c | 6 | ||||
| -rw-r--r-- | src/code/audio/audio_seqplayer.c | 2 | ||||
| -rw-r--r-- | src/code/audio/audio_sfx_params.c | 8 | ||||
| -rw-r--r-- | src/code/audio/code_80192BE0.c | 10 | ||||
| -rw-r--r-- | src/code/audio/code_8019AF00.c | 675 | ||||
| -rw-r--r-- | src/code/audio/code_801A5BD0.c | 950 | ||||
| -rw-r--r-- | src/code/audio/code_801A7B10.c | 2 | ||||
| -rw-r--r-- | src/code/audioMgr.c | 2 | ||||
| -rw-r--r-- | src/code/code_80172BC0.c | 2 | ||||
| -rw-r--r-- | src/code/z_actor.c | 8 | ||||
| -rw-r--r-- | src/code/z_effect_soft_sprite.c | 4 | ||||
| -rw-r--r-- | src/code/z_sound_source.c | 4 |
13 files changed, 1558 insertions, 119 deletions
diff --git a/src/code/audio/audio_load.c b/src/code/audio/audio_load.c index b4997a94e..9ebdd1d85 100644 --- a/src/code/audio/audio_load.c +++ b/src/code/audio/audio_load.c @@ -1208,7 +1208,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) { gAudioContext.refreshRate = 60; } - Audio_InitMesgQueues(); + AudioThread_InitMesgQueues(); for (i = 0; i < ARRAY_COUNT(gAudioContext.aiBufLengths); i++) { gAudioContext.aiBufLengths[i] = 0xA0; @@ -1217,7 +1217,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) { gAudioContext.totalTaskCount = 0; gAudioContext.rspTaskIndex = 0; gAudioContext.curAiBuffferIndex = 0; - gAudioContext.soundMode = AUDIO_MODE_STEREO; + gAudioContext.soundMode = SOUNDMODE_STEREO; gAudioContext.curTask = NULL; gAudioContext.rspTask[0].task.t.dataSize = 0; gAudioContext.rspTask[1].task.t.dataSize = 0; diff --git a/src/code/audio/audio_playback.c b/src/code/audio/audio_playback.c index c7789bd36..e7f5153ac 100644 --- a/src/code/audio/audio_playback.c +++ b/src/code/audio/audio_playback.c @@ -34,7 +34,7 @@ void AudioPlayback_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* at sub->bitField0.stereoStrongLeft = false; sub->bitField0.stereoHeadsetEffects = stereoData.stereoHeadsetEffects; sub->bitField0.usesHeadsetPanEffects = stereoData.usesHeadsetPanEffects; - if (stereoHeadsetEffects && gAudioContext.soundMode == AUDIO_MODE_HEADSET) { + if (stereoHeadsetEffects && gAudioContext.soundMode == SOUNDMODE_HEADSET) { smallPanIndex = pan >> 1; if (smallPanIndex > 0x3F) { smallPanIndex = 0x3F; @@ -46,7 +46,7 @@ void AudioPlayback_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* at volLeft = gHeadsetPanVolume[pan]; volRight = gHeadsetPanVolume[0x7F - pan]; - } else if (stereoHeadsetEffects && gAudioContext.soundMode == AUDIO_MODE_STEREO) { + } else if (stereoHeadsetEffects && gAudioContext.soundMode == SOUNDMODE_STEREO) { strongLeft = strongRight = false; sub->headsetPanRight = 0; sub->headsetPanLeft = 0; @@ -80,7 +80,7 @@ void AudioPlayback_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* at break; } - } else if (gAudioContext.soundMode == AUDIO_MODE_MONO) { + } else if (gAudioContext.soundMode == SOUNDMODE_MONO) { sub->bitField0.stereoHeadsetEffects = false; sub->bitField0.usesHeadsetPanEffects = false; volLeft = 0.707f; // approx 1/sqrt(2) diff --git a/src/code/audio/audio_seqplayer.c b/src/code/audio/audio_seqplayer.c index d504f9f3a..ebcc9a8d1 100644 --- a/src/code/audio/audio_seqplayer.c +++ b/src/code/audio/audio_seqplayer.c @@ -1633,7 +1633,7 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { break; case 0xA8: // channel: random range large (only cmd that differs from OoT) - rand = Audio_NextRandom(); + rand = AudioThread_NextRandom(); channel->unk_22 = (cmdArgs[0] == 0) ? (rand & 0xFFFF) : (rand % cmdArgs[0]); channel->unk_22 += cmdArgs[1]; temp2 = (channel->unk_22 / 0x100) + 0x80; diff --git a/src/code/audio/audio_sfx_params.c b/src/code/audio/audio_sfx_params.c index 94a8f26bc..0066328b1 100644 --- a/src/code/audio/audio_sfx_params.c +++ b/src/code/audio/audio_sfx_params.c @@ -1,9 +1,9 @@ #include "global.h" -#define DEFINE_SFX(_0, importance, distParam, randParam, flags2, flags1) \ - { importance, flags2, \ - ((((distParam) << SFX_PARAM_01_SHIFT) & SFX_PARAM_01_MASK) | \ - (((randParam) << SFX_PARAM_67_SHIFT) & SFX_PARAM_67_MASK) | (flags1)) }, +#define DEFINE_SFX(_0, importance, distParam, randParam, flags2, flags1) \ + { importance, flags2, \ + ((((distParam) << SFX_PARAM_DIST_RANGE_SHIFT) & SFX_PARAM_DIST_RANGE_MASK) | \ + (((randParam) << SFX_PARAM_RAND_FREQ_RAISE_SHIFT) & SFX_PARAM_RAND_FREQ_RAISE_MASK) | (flags1)) }, SfxParams sEnemyBankParams[] = { #include "tables/sfx/enemybank_table.h" diff --git a/src/code/audio/code_80192BE0.c b/src/code/audio/code_80192BE0.c index 20b4239da..e69f678ff 100644 --- a/src/code/audio/code_80192BE0.c +++ b/src/code/audio/code_80192BE0.c @@ -16,13 +16,13 @@ #pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_80193858.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_8019387C.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/AudioThread_QueueCmdS32.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/Audio_QueueCmdS8.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/AudioThread_QueueCmdS8.s") #pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_801938D0.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_80193900.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/AudioThread_ScheduleProcessCmds.s") #pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_80193990.s") @@ -76,6 +76,6 @@ #pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_80194568.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/Audio_NextRandom.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/AudioThread_NextRandom.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/Audio_InitMesgQueues.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/AudioThread_InitMesgQueues.s") diff --git a/src/code/audio/code_8019AF00.c b/src/code/audio/code_8019AF00.c index 65c3a6de8..b896facbc 100644 --- a/src/code/audio/code_8019AF00.c +++ b/src/code/audio/code_8019AF00.c @@ -18,15 +18,15 @@ typedef struct { } SfxSettings; // size = 0x9 typedef struct { - /* 0x0 */ f32 vol; + /* 0x0 */ f32 volume; /* 0x4 */ f32 freqScale; /* 0x8 */ s8 reverb; /* 0x9 */ s8 panSigned; /* 0xA */ s8 stereoBits; /* 0xB */ u8 filter; - /* 0xC */ u8 unk_0C; - /* 0xD */ u8 unk_0D; -} SfxPlayerState; // size = 0xE + /* 0xC */ u8 combFilterGain; + /* 0xD */ u8 zVolume; +} SfxChannelState; // size = 0xE typedef enum { /* 0x0 */ SFX_CHANNEL_PLAYER0, // SfxPlayerBank @@ -91,7 +91,7 @@ f32* sSfxVolumeCur; f32 sSfxVolumeTarget; f32 sSfxVolumeRate; u16 sSceneSeqId1; -SfxPlayerState sSfxChannelState[16]; +SfxChannelState sSfxChannelState[16]; // Sequence bss u8 D_801FD3A8; @@ -154,7 +154,8 @@ OcarinaNote sScarecrowsLongSongSecondNote; u16 sCustomSequencePc; // Sfx Data -u8 D_801D6600[] = { +// If the Sfx Bank has more than 255 values (max value of u8) +u8 gIsLargeSfxBank[] = { true, false, true, true, false, false, true, }; u8 D_801D6608[] = { @@ -192,7 +193,7 @@ u8 sEnterGanonsTowerTimer = 0; u16 sSfxVolumeDuration = 0; // System Data -s8 sAudioFileSelectSetting = AUDIO_FS_STEREO; +s8 sSoundMode = SOUNDMODE_STEREO; s8 sAudioIsWindowOpen = false; s8 sAudioCutsceneFlag = false; s8 sSpecReverb = 0; @@ -2495,7 +2496,7 @@ void AudioOcarina_PlayControllerInput(u8 isOcarinaSfxSuppressedWhenCancelled) { // Add vibrato of the ocarina note based on the x control stick sCurOcarinaVibrato = ABS_ALT(sOcarinaInputStickRel.x) >> 2; // Sets vibrato to io port 6 - Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 6, sCurOcarinaVibrato); + AudioThread_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 6, sCurOcarinaVibrato); } else { // no bending or vibrato for recording state OCARINA_RECORD_SCARECROW_SPAWN sCurOcarinaBendIndex = 0; @@ -2507,15 +2508,16 @@ void AudioOcarina_PlayControllerInput(u8 isOcarinaSfxSuppressedWhenCancelled) { if ((sCurOcarinaPitch != OCARINA_PITCH_NONE) && (sPrevOcarinaPitch != sCurOcarinaPitch)) { // Sets ocarina instrument Id to io port 7, which is used // as an index in seq 0 to get the true instrument Id - Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 7, sOcarinaInstrumentId - 1); + AudioThread_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 7, + sOcarinaInstrumentId - 1); // Sets pitch to io port 5 - Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 5, sCurOcarinaPitch); - Audio_PlaySfxGeneral(NA_SE_OC_OCARINA, &gSfxDefaultPos, 4, &sCurOcarinaBendFreq, &sDefaultOcarinaVolume, - &gSfxDefaultReverb); + AudioThread_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 5, sCurOcarinaPitch); + AudioSfx_PlaySfx(NA_SE_OC_OCARINA, &gSfxDefaultPos, 4, &sCurOcarinaBendFreq, &sDefaultOcarinaVolume, + &gSfxDefaultReverb); } else if ((sPrevOcarinaPitch != OCARINA_PITCH_NONE) && (sCurOcarinaPitch == OCARINA_PITCH_NONE) && !isOcarinaSfxSuppressedWhenCancelled) { // Stops ocarina sound when transitioning from playing to not playing a note - Audio_StopSfxById(NA_SE_OC_OCARINA); + AudioSfx_StopById(NA_SE_OC_OCARINA); } } } @@ -2540,10 +2542,10 @@ void AudioOcarina_ResetAndMute(void) { sOcarinaInputButtonStart = 0xFFFF; AudioOcarina_PlayControllerInput(false); - Audio_StopSfxById(NA_SE_OC_OCARINA); + AudioSfx_StopById(NA_SE_OC_OCARINA); if (gAudioSpecId != 12) { - Audio_SetSfxBanksMute(0); + AudioSfx_MuteBanks(0); } sPlaybackState = 0; @@ -2553,7 +2555,7 @@ void AudioOcarina_ResetAndMute(void) { sOcarinaFlags = 0; // return to full volume for both bgm players after ocarina is finished - Audio_ClearFlagForBgmVolumeLow(SFX_CHANNEL_OCARINA); + AudioSfx_RestoreBgmVolume(SFX_CHANNEL_OCARINA); // return to full volume for all sfx channels except system & ocarina banks Audio_SetSfxVolumeExceptSystemAndOcarinaBanks(0x7F); } @@ -2602,7 +2604,7 @@ u32 AudioOcarina_SetInstrument(u8 ocarinaInstrumentId) { // lowers volume of all sfx channels except system & ocarina banks Audio_SetSfxVolumeExceptSystemAndOcarinaBanks(0x40); // lowers volume of bgm players while playing ocarina - Audio_SetFlagForBgmVolumeLow(SFX_CHANNEL_OCARINA); + AudioSfx_LowerBgmVolume(SFX_CHANNEL_OCARINA); } } } @@ -2612,7 +2614,7 @@ void AudioOcarina_SetPlaybackSong(s8 songIndexPlusOne, u8 playbackState) { if (songIndexPlusOne == 0) { sPlaybackState = 0; - Audio_StopSfxById(NA_SE_OC_OCARINA); + AudioSfx_StopById(NA_SE_OC_OCARINA); return; } @@ -2700,7 +2702,7 @@ void AudioOcarina_PlaybackSong(void) { sPlaybackStaffPos = 0; sPlaybackPitch = OCARINA_PITCH_NONE; } else { - Audio_StopSfxById(NA_SE_OC_OCARINA); + AudioSfx_StopById(NA_SE_OC_OCARINA); } return; } else { @@ -2716,7 +2718,7 @@ void AudioOcarina_PlaybackSong(void) { // Update vibrato sNotePlaybackVibrato = sPlaybackSong[sPlaybackNotePos].vibrato; // Sets vibrato to io port 6 - Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 6, sNotePlaybackVibrato); + AudioThread_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 6, sNotePlaybackVibrato); // Update bend if (sNotePlaybackBend != sPlaybackSong[sPlaybackNotePos].bend) { @@ -2746,14 +2748,14 @@ void AudioOcarina_PlaybackSong(void) { sPlaybackStaffPos++; // Sets ocarina instrument Id to io port 7, which is used // as an index in seq 0 to get the true instrument Id - Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 7, - sOcarinaInstrumentId - 1); - Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 5, - sPlaybackPitch & OCARINA_BUTTON_MASK_PITCH); - Audio_PlaySfxGeneral(NA_SE_OC_OCARINA, &gSfxDefaultPos, 4, &sRelativeNotePlaybackBend, - &sRelativeNotePlaybackVolume, &gSfxDefaultReverb); + AudioThread_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 7, + sOcarinaInstrumentId - 1); + AudioThread_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 5, + sPlaybackPitch & OCARINA_BUTTON_MASK_PITCH); + AudioSfx_PlaySfx(NA_SE_OC_OCARINA, &gSfxDefaultPos, 4, &sRelativeNotePlaybackBend, + &sRelativeNotePlaybackVolume, &gSfxDefaultReverb); } else { - Audio_StopSfxById(NA_SE_OC_OCARINA); + AudioSfx_StopById(NA_SE_OC_OCARINA); } } sPlaybackNotePos++; @@ -3073,7 +3075,7 @@ void AudioOcarina_TerminaWallGenerateNotes(void) { j = 0; for (; i < 8; i++) { - randomButtonIndex = Audio_NextRandom() % ARRAY_COUNT(sButtonToPitchMap); + randomButtonIndex = AudioThread_NextRandom() % ARRAY_COUNT(sButtonToPitchMap); sOcarinaSongNotes[OCARINA_SONG_TERMINA_WALL][j].pitch = sButtonToPitchMap[randomButtonIndex]; sOcarinaSongNotes[OCARINA_SONG_TERMINA_WALL][j].length = 19; sOcarinaSongNotes[OCARINA_SONG_TERMINA_WALL][j].volume = 80; @@ -3094,7 +3096,7 @@ void AudioOcarina_TerminaWallGenerateNotes(void) { sOcarinaSongNotes[OCARINA_SONG_TERMINA_WALL][j + 1].length = 0; AudioOcarina_MapSongFromPitchToButton(OCARINA_SONG_TERMINA_WALL, OCARINA_SONG_TERMINA_WALL, 8); } else { - j = Audio_NextRandom() % ARRAY_COUNT(sOoTOcarinaSongNotes); + j = AudioThread_NextRandom() % ARRAY_COUNT(sOoTOcarinaSongNotes); ocarinaNote = sOoTOcarinaSongNotes[j]; for (; ocarinaNote[i].length != 0; i++) { @@ -3140,7 +3142,7 @@ s32 AudioOcarina_MemoryGameNextNote(void) { return true; } - randomButtonIndex = Audio_NextRandom(); + randomButtonIndex = AudioThread_NextRandom(); randomPitch = sButtonToPitchMap[randomButtonIndex % ARRAY_COUNT(sButtonToPitchMap)]; if (sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcarinaMemoryGameAppendPos - 1].pitch == randomPitch) { @@ -3234,7 +3236,7 @@ void AudioOcarina_PlayLongScarecrowAfterCredits(void) { break; case 1: - Audio_SetSfxBanksMute(0); + AudioSfx_MuteBanks(0); AudioOcarina_SetInstrument(sScarecrowAfterCreditsIntrumentId); AudioOcarina_SetPlaybackSong(OCARINA_SONG_SCARECROW_LONG + 1, 1); sScarecrowAfterCreditsIntrumentId++; @@ -3475,20 +3477,6 @@ void AudioOcarina_ResetStaffs(void) { D_801D8534 = 0; } -s8 D_801D8B30[] = { - 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 60, 61, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, - 64, 65, 65, 65, 66, 66, 66, 67, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, -}; -f32 sBigBellsVolume[8] = { - 1.0f, 0.9f, 0.8f, 0.7f, 0.6f, 0.5f, 0.4f, 0.3f, -}; -u8 sBgmPlayers[2] = { SEQ_PLAYER_BGM_MAIN, SEQ_PLAYER_BGM_SUB }; -f32 sSfxOriginalPos[] = { 0.0f, 0.0f, 0.0f }; - #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019DFF8.s") #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E000.s") @@ -3503,23 +3491,447 @@ f32 sSfxOriginalPos[] = { 0.0f, 0.0f, 0.0f }; #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E110.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E14C.s") +f32 AudioSfx_ComputeVolume(u8 bankId, u8 entryIndex) { + SfxBankEntry* bankEntry = &gSfxBanks[bankId][entryIndex]; + f32 minDist; + f32 phi_f14; + f32 baseDist; + f32 phi_f12; + f32 volume; // Also acts as intermediate volumeSquared + s32 pad[3]; + + if (bankEntry->sfxParams & SFX_FLAG_VOLUME_NO_DIST) { + return 1.0f; + } + + if (bankEntry->dist > 10000.0f) { + volume = 0.0f; + } else { + if (bankEntry->sfxParams & SFX_PARAM_DIST_RANGE_MASK_UPPER) { + phi_f12 = 0.35f; + phi_f14 = 0.65f; + } else { + phi_f12 = 0.81f; + phi_f14 = 0.19f; + } + + switch (bankEntry->sfxParams & SFX_PARAM_DIST_RANGE_MASK) { + case 0: + baseDist = 500.0f; + break; + + case 1: + baseDist = 666.6667f; + break; + + case 2: + baseDist = 952.381f; + break; + + case 3: + baseDist = 3846.154f; + break; + + case 4: + baseDist = 1000.0f; + break; + + case 5: + baseDist = 666.6667f; + break; + + case 6: + baseDist = 500.0f; + break; + + case 7: + baseDist = 400.0f; + break; + } + + minDist = baseDist / 5.0f; + + if (bankEntry->dist < minDist) { + volume = 1.0f; + } else if (bankEntry->dist < baseDist) { + volume = + ((((baseDist - minDist) - (bankEntry->dist - minDist)) / (baseDist - minDist)) * phi_f14) + phi_f12; + } else { + volume = (1.0f - ((bankEntry->dist - baseDist) / (10000.0f - baseDist))) * phi_f12; + } + + volume = SQ(volume); + } + + return volume; +} + +s8 AudioSfx_ComputeReverb(u8 bankId, u8 entryIndex, u8 channelIndex) { + s8 distAdd = 0; + s32 scriptAdd = 0; + SfxBankEntry* entry = &gSfxBanks[bankId][entryIndex]; + s32 reverb; + + if (!(entry->sfxParams & SFX_FLAG_REVERB_NO_DIST)) { + if (entry->dist < 2500.0f) { + distAdd = *entry->posZ > 0.0f ? (entry->dist / 2500.0f) * 70.0f : (entry->dist / 2500.0f) * 91.0f; + } else { + distAdd = 70; + } + } + + if (IS_SEQUENCE_CHANNEL_VALID(gAudioContext.seqPlayers[SEQ_PLAYER_SFX].channels[channelIndex])) { + scriptAdd = gAudioContext.seqPlayers[SEQ_PLAYER_SFX].channels[channelIndex]->soundScriptIO[1]; + if (gAudioContext.seqPlayers[SEQ_PLAYER_SFX].channels[channelIndex]->soundScriptIO[1] < 0) { + scriptAdd = 0; + } + } + + reverb = (*entry->reverbAdd & 0x7F) + distAdd; + + if (entry->state != SFX_STATE_READY) { + reverb += scriptAdd; + } + + if ((bankId != BANK_OCARINA) || (SFX_INDEX(entry->sfxId) >= 2)) { + reverb += sAudioEnvReverb + (sAudioCodeReverb & 0x3F) + sSpecReverb; + } + + if (reverb > 0x7F) { + reverb = 0x7F; + } + + return reverb; +} + +s8 AudioSfx_ComputePanSigned(f32 x, f32 z, u8 token) { + f32 absX = ABS_ALT(x); + f32 absZ = ABS_ALT(z); + f32 pan; + + if (absX > 8000.0f) { + absX = 8000.0f; + } + + if (absZ > 8000.0f) { + absZ = 8000.0f; + } + + if ((x == 0.0f) && (z == 0.0f)) { + pan = 0.5f; + } else if (absZ <= absX) { + pan = (16000.0f - absX) / (4.5f * (16000.0f - absZ)); + if (x >= 0.0f) { + pan = 1.0f - pan; + } + } else { + pan = (x / (3.6f * absZ)) + 0.5f; + } + + if ((absZ < 50.0f) && (absX < 50.0f)) { + pan = ((pan - 0.5f) * SQ(absX / 50.0f)) + 0.5f; + } + + return (pan * 127.0f) + 0.5f; +} + +f32 AudioSfx_ComputeFreqScale(u8 bankId, u8 entryIndex) { + s32 applyRandScaling = false; + SfxBankEntry* entry = &gSfxBanks[bankId][entryIndex]; + f32 dist; + f32 freq = 1.0f; + + if (entry->sfxParams & SFX_PARAM_RAND_FREQ_LOWER) { + freq = 1.0f - ((gAudioContext.audioRandom & 0xF) / 192.0f); + } + + switch (bankId) { + case BANK_VOICE: + if (((entry->sfxId & 0xFF) < 0x40) && (sAudioBaseFilter2 != 0)) { + applyRandScaling = true; + } else if (((entry->sfxId & 0xFF) >= 0x40) && (sAudioExtraFilter2 != 0)) { + applyRandScaling = true; + } + break; + + case BANK_PLAYER: + case BANK_ITEM: + if (sAudioBaseFilter2 != 0) { + applyRandScaling = true; + } + break; + + case BANK_ENV: + case BANK_ENEMY: + if (((*entry->reverbAdd & 0x80) != 0) | (sAudioExtraFilter2 != 0)) { + applyRandScaling = true; + } + break; + + case BANK_SYSTEM: + case BANK_OCARINA: + break; + + default: + break; + } + + if ((applyRandScaling == true) && !(entry->sfxParams & SFX_PARAM_RAND_FREQ_SCALE)) { + freq *= 1.0293 - ((gAudioContext.audioRandom & 0xF) / 144.0f); + } + + dist = entry->dist; + if (!(entry->sfxParams & SFX_FLAG_VOLUME_NO_DIST) && !(entry->sfxParams & SFX_FLAG_FREQ_NO_DIST)) { + if (dist >= 10000.0f) { + freq += 0.2f; + } else { + freq += (0.2f * (dist / 10000.0f)); + } + } + + if ((entry->sfxParams & SFX_PARAM_RAND_FREQ_RAISE_MASK) != (0 << SFX_PARAM_RAND_FREQ_RAISE_SHIFT)) { + freq += (entry->randFreq / 192.0f); + } + + return freq; +} + +u8 AudioSfx_ComputeSurroundSoundFilter(f32 behindScreenZ, SfxBankEntry* entry, s8 panSigned) { + u8 lowPassCutoff; + u8 highPassCutoff; + u16* sfxParams; + f32 distParam; + f32 dist; + + // Remnant of OoT + if (*entry->posZ < behindScreenZ) { + lowPassCutoff = 0; + } else { + lowPassCutoff = 0; + } + + sfxParams = &entry->sfxParams; + + if (*sfxParams & SFX_FLAG_SURROUND_LOWPASS_FILTER) { + lowPassCutoff = 0xF; + } + + switch ((*sfxParams & SFX_PARAM_DIST_RANGE_MASK)) { + case 0: + distParam = 15.0f; + break; + + case 1: + distParam = 12.0f; + break; + + case 2: + distParam = 9.0f; + break; + + case 3: + distParam = 6.0f; + break; + + case 4: + distParam = 18.0f; + break; + + case 5: + distParam = 21.0f; + break; + + case 6: + distParam = 24.0f; + break; + + case 7: + distParam = 27.0f; + break; + + default: + break; + } + + if (!(entry->sfxFlags & SFX_FLAG2_SURROUND_NO_HIGHPASS_FILTER)) { + if (entry->dist > 1923.077f) { + dist = 1923.077f; + } else { + dist = entry->dist; + } + + highPassCutoff = (distParam * dist) / (2 * 1923.077f); + } else { + highPassCutoff = 0; + } + + return (lowPassCutoff << 4) + highPassCutoff; +} + +s8 AudioSfx_ComputeCombFilter(f32 posY, u16 sfxParams) { + s8 combFilterGain; + + if (posY < 0.0f) { + if (posY < -625.0f) { + combFilterGain = -32; + } else { + combFilterGain = (s8)(((625.0f + posY) / 625.0f) * 31.0f) + 0xE0; + } + } else if (posY > 1250.0f) { + combFilterGain = 127; + } else { + combFilterGain = (posY / 1250.0f) * 126.0f; + } + + return combFilterGain | 1; +} + +void AudioSfx_SetProperties(u8 bankId, u8 entryIndex, u8 channelIndex) { + static s8 sZVolumes[] = { + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 60, 61, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, + 64, 65, 65, 65, 66, 66, 66, 67, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, + }; + f32 volume = 1.0f; + s8 volumeS8; + s8 reverb = 0; + f32 freqScale = 1.0f; + s8 panSigned = 0x40; + u8 pad; + u8 filter = 0; + s8 combFilterGain = 0; + s8 zVolume = -1; + f32 behindScreenZ; + u8 baseFilter = 0; + SfxBankEntry* entry = &gSfxBanks[bankId][entryIndex]; + s32 pad2; + + switch (bankId) { + case BANK_PLAYER: + case BANK_ITEM: + case BANK_ENV: + case BANK_ENEMY: + case BANK_VOICE: + if (sSoundMode == SOUNDMODE_SURROUND) { + combFilterGain = AudioSfx_ComputeCombFilter(*entry->posY, entry->sfxParams); + } + // fallthrough + case BANK_OCARINA: + entry->dist = sqrtf(entry->dist * 10.0f); + volume = AudioSfx_ComputeVolume(bankId, entryIndex) * *entry->volume; + reverb = AudioSfx_ComputeReverb(bankId, entryIndex, channelIndex); + panSigned = AudioSfx_ComputePanSigned(*entry->posX, *entry->posZ, entry->token); + freqScale = AudioSfx_ComputeFreqScale(bankId, entryIndex) * *entry->freqScale; + + if (sSoundMode == SOUNDMODE_SURROUND) { + if (*entry->posZ >= 0.0f) { + if (*entry->posZ < 200.0f) { + zVolume = 32.0f - ((*entry->posZ / 300.0f) * 32.0f); + } else { + zVolume = 0; + } + } else if (*entry->posZ < 0.0f) { + if (*entry->posZ > -300.0f) { + zVolume = 32.0f - ((*entry->posZ / 300.0f) * 95.0f); + } else { + zVolume = 127; + } + } + zVolume = sZVolumes[zVolume]; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E324.s") + if (sAudioBaseFilter != 0) { + if ((bankId == BANK_PLAYER) || (bankId == BANK_ITEM) || + ((bankId == BANK_VOICE) && (((entry->sfxId & 0xFF) < 0x40) || ((entry->sfxId & 0xFF) >= 0x80)))) { + baseFilter = sAudioBaseFilter; + if (sAudioExtraFilter) { + reverb >>= 2; + } + } + } -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E4B0.s") + if (((*entry->reverbAdd & 0x80) | baseFilter | sAudioExtraFilter | + (entry->sfxFlags & SFX_FLAG2_APPLY_LOWPASS_FILTER)) != 0) { + filter = ((((*entry->reverbAdd & 0x80) >> 2) | baseFilter | sAudioExtraFilter | + ((entry->sfxFlags & SFX_FLAG2_APPLY_LOWPASS_FILTER) >> 2)) * + 2); + filter &= 0xFF; + } else if ((sSoundMode == SOUNDMODE_SURROUND) && !(entry->sfxParams & SFX_FLAG_VOLUME_NO_DIST)) { + filter = AudioSfx_ComputeSurroundSoundFilter(behindScreenZ, entry, panSigned); + } + break; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E634.s") + case BANK_SYSTEM: + break; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E864.s") + if (sSfxChannelState[channelIndex].volume != volume) { + volumeS8 = (u8)(volume * 127.0f); + sSfxChannelState[channelIndex].volume = volume; + } else { + volumeS8 = -1; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019EA40.s") + //! FAKE: + if (1) {} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019EB2C.s") + // CHAN_UPD_SCRIPT_IO (slot 2, sets volume) + AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | (channelIndex << 8) | 2, volumeS8); -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F024.s") + if (sSfxChannelState[channelIndex].reverb != reverb) { + sSfxChannelState[channelIndex].reverb = reverb; + } + if (sSfxChannelState[channelIndex].freqScale != freqScale) { + sSfxChannelState[channelIndex].freqScale = freqScale; + } + if (sSfxChannelState[channelIndex].stereoBits != 0) { + sSfxChannelState[channelIndex].stereoBits = 0; + } + if (sSfxChannelState[channelIndex].filter != filter) { + sSfxChannelState[channelIndex].filter = filter; + } + if (sSfxChannelState[channelIndex].combFilterGain != combFilterGain) { + sSfxChannelState[channelIndex].combFilterGain = combFilterGain; + } + if (sSfxChannelState[channelIndex].zVolume != zVolume) { + sSfxChannelState[channelIndex].zVolume = zVolume; + } + if (sSfxChannelState[channelIndex].panSigned != panSigned) { + sSfxChannelState[channelIndex].panSigned = panSigned; + } +} + +u32 AudioSfx_SetFreqAndStereoBits(u8 seqScriptValIn, SequenceChannel* channel) { + channel->stereo.asByte = sSfxChannelState[seqScriptValIn].stereoBits; + channel->freqScale = sSfxChannelState[seqScriptValIn].freqScale; + channel->changes.s.freqScale = true; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F05C.s") + return seqScriptValIn; +} + +void AudioSfx_ResetSfxChannelState(void) { + SfxChannelState* state; + u8 i; + + for (i = 0; i < ARRAY_COUNT(sSfxChannelState); i++) { + state = &sSfxChannelState[i]; + state->volume = 1.0f; + state->freqScale = 1.0f; + state->reverb = 0; + state->panSigned = 0x40; + state->stereoBits = 0; + state->filter = 0xFF; + state->combFilterGain = 0xFF; + state->zVolume = 0xFF; + } + + sSfxChannelState[SFX_CHANNEL_OCARINA].combFilterGain = 0; + sPrevSeqMode = SEQ_MODE_DEFAULT; + sAudioCodeReverb = 0; +} #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/play_sound.s") @@ -3533,9 +3945,75 @@ f32 sSfxOriginalPos[] = { 0.0f, 0.0f, 0.0f }; #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F230.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F258.s") +SfxSettings* AudioSfx_AddSfxSetting(Vec3f* pos) { + SfxSettings* sfxSettings; + u8 i = 0; + u8 sfxSettingIndex = 0xFF; + + for (; i < ARRAY_COUNT(sSfxSettings); i++) { + sfxSettings = &sSfxSettings[i]; + + if ((sfxSettings->pos == NULL) && (sfxSettingIndex == 0xFF)) { + sfxSettingIndex = i; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F300.s") + if (sfxSettings->pos == pos) { + return sfxSettings; + } + } + + if (sfxSettingIndex != 0xFF) { + sSfxSettingsFlags |= 1 << sfxSettingIndex; + sfxSettings = &sSfxSettings[sfxSettingIndex]; + sfxSettings->pos = pos; + return sfxSettings; + } + + return NULL; +} + +void AudioSfx_ProcessSfxSettings(void) { + SfxBankEntry* entry; + u8 sfxSettingsFlags; + u8 sfxSettingIndex = 0; + u8 bankId; + u8 entryIndex; + s32 found; + + if (sSfxSettingsFlags != 0) { + sfxSettingsFlags = sSfxSettingsFlags; + + while (sfxSettingsFlags != 0) { + bankId = BANK_ENV; + if ((sfxSettingsFlags & (1 << sfxSettingIndex))) { + + found = false; + while ((bankId <= BANK_ENEMY) && !found) { + entryIndex = gSfxBanks[bankId]->next; + + while (entryIndex != 0xFF) { + entry = &gSfxBanks[bankId][entryIndex]; + entryIndex = 0xFF; + if (entry->posX == &sSfxSettings[sfxSettingIndex].pos->x) { + found = true; + } else { + entryIndex = entry->next; + } + } + bankId++; + } + + if (!found) { + sSfxSettingsFlags ^= (1 << sfxSettingIndex); + sSfxSettings[sfxSettingIndex].pos = NULL; + } + + sfxSettingsFlags ^= (1 << sfxSettingIndex); + } + sfxSettingIndex++; + } + } +} #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F420.s") @@ -3543,7 +4021,17 @@ f32 sSfxOriginalPos[] = { 0.0f, 0.0f, 0.0f }; #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F540.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F570.s") +void AudioSfx_LowerSfxSettingsReverb(Vec3f* pos, s8 isReverbLowered) { + SfxSettings* sfxSettings = AudioSfx_AddSfxSetting(pos); + + if (sfxSettings != NULL) { + if (isReverbLowered) { + sfxSettings->reverbAdd = -0x80; + } else { + sfxSettings->reverbAdd = 0; + } + } +} #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F5AC.s") @@ -3585,15 +4073,15 @@ f32 sSfxOriginalPos[] = { 0.0f, 0.0f, 0.0f }; * Used for EnRiverSound */ void Audio_PlaySfxForRiver(Vec3f* pos, f32 freqScale) { - if (!Audio_IsSfxPlaying(NA_SE_EV_RIVER_STREAM - SFX_FLAG)) { + if (!AudioSfx_IsPlaying(NA_SE_EV_RIVER_STREAM - SFX_FLAG)) { sRiverFreqScaleLerp.value = freqScale; } else if (freqScale != sRiverFreqScaleLerp.value) { sRiverFreqScaleLerp.target = freqScale; sRiverFreqScaleLerp.remainingFrames = 40; sRiverFreqScaleLerp.step = (sRiverFreqScaleLerp.target - sRiverFreqScaleLerp.value) / 40; } - Audio_PlaySfxGeneral(NA_SE_EV_RIVER_STREAM - SFX_FLAG, pos, 4, &sRiverFreqScaleLerp.value, &D_801DB4B0, - &gSfxDefaultReverb); + AudioSfx_PlaySfx(NA_SE_EV_RIVER_STREAM - SFX_FLAG, pos, 4, &sRiverFreqScaleLerp.value, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultReverb); } /** @@ -3601,15 +4089,15 @@ void Audio_PlaySfxForRiver(Vec3f* pos, f32 freqScale) { * Used for Zora's River Waterfall */ void Audio_PlaySfxForWaterfall(Vec3f* pos, f32 freqScale) { - if (!Audio_IsSfxPlaying(NA_SE_EV_WATER_WALL_BIG - SFX_FLAG)) { + if (!AudioSfx_IsPlaying(NA_SE_EV_WATER_WALL_BIG - SFX_FLAG)) { sWaterfallFreqScaleLerp.value = freqScale; } else if (freqScale != sWaterfallFreqScaleLerp.value) { sWaterfallFreqScaleLerp.target = freqScale; sWaterfallFreqScaleLerp.remainingFrames = 40; sWaterfallFreqScaleLerp.step = (sWaterfallFreqScaleLerp.target - sWaterfallFreqScaleLerp.value) / 40; } - Audio_PlaySfxGeneral(NA_SE_EV_WATER_WALL_BIG - SFX_FLAG, pos, 4, &sWaterfallFreqScaleLerp.value, - &sWaterfallFreqScaleLerp.value, &gSfxDefaultReverb); + AudioSfx_PlaySfx(NA_SE_EV_WATER_WALL_BIG - SFX_FLAG, pos, 4, &sWaterfallFreqScaleLerp.value, + &sWaterfallFreqScaleLerp.value, &gSfxDefaultReverb); } /** @@ -3626,6 +4114,9 @@ void Audio_StepFreqLerp(FreqLerp* lerp) { } } +f32 sBigBellsVolume[8] = { + 1.0f, 0.9f, 0.8f, 0.7f, 0.6f, 0.5f, 0.4f, 0.3f, +}; #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0124.s") #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0184.s") @@ -3652,7 +4143,7 @@ void Audio_SetGanonsTowerBgmVolumeLevel(u8 ganonsTowerLevel) { for (channelIndex = 0; channelIndex < 16; channelIndex++) { // CHAN_UPD_PAN_UNSIGNED - Audio_QueueCmdS8(((u8)(u32)channelIndex << 8) | 0x7000000, pan); + AudioThread_QueueCmdS8(((u8)(u32)channelIndex << 8) | 0x7000000, pan); } // Lowest room in Ganon's Tower (Entrance Room) @@ -3710,9 +4201,9 @@ s32 Audio_SetGanonsTowerBgmVolume(u8 targetVolume) { } // CHAN_UPD_REVERB - Audio_QueueCmdS8(_SHIFTL(5, 24, 8) | _SHIFTL(SEQ_PLAYER_BGM_MAIN, 16, 8) | - _SHIFTL(channelIndex, 8, 8), - (u8)reverb); + AudioThread_QueueCmdS8(_SHIFTL(5, 24, 8) | _SHIFTL(SEQ_PLAYER_BGM_MAIN, 16, 8) | + _SHIFTL(channelIndex, 8, 8), + (u8)reverb); } } } @@ -3768,7 +4259,29 @@ void Audio_UpdateRiverSoundVolumes(void) { #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A05F0.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0654.s") +void AudioSfx_SetChannelIO(Vec3f* pos, u16 sfxId, u8 ioData) { + u8 channelIndex = 0; + u8 bankId = SFX_BANK_SHIFT(sfxId); + u8 entryIndex; + u8 i; + + for (i = 0; i < bankId; i++) { + channelIndex += gChannelsPerBank[gSfxChannelLayout][i]; + } + + for (i = 0; i < gChannelsPerBank[gSfxChannelLayout][bankId]; i++) { + entryIndex = gActiveSfx[bankId][i].entryIndex; + + if (entryIndex != 0xFF) { + if ((sfxId == gSfxBanks[bankId][entryIndex].sfxId) && (&pos->x == gSfxBanks[bankId][entryIndex].posX)) { + AudioThread_QueueCmdS8(_SHIFTL(6, 24, 8) | _SHIFTL(SEQ_PLAYER_SFX, 16, 8) | + _SHIFTL(channelIndex, 8, 8) | _SHIFTL(6, 0, 8), + ioData); + } + } + channelIndex++; + } +} #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0810.s") @@ -3814,7 +4327,7 @@ void func_801A09D4(Vec3f* pos, f32 xzDistToPlayer) { if (channelIndex != 9) { Audio_QueueSeqCmd(((u32)(6) << 28) | ((u32)(SEQ_PLAYER_BGM_MAIN) << 24) | ((u32)(2) << 16) | ((u32)(channelIndex) << 8) | ((u8)(127.0f * volumeRel))); - Audio_QueueCmdS8(0x03000000 | ((u8)((u32)channelIndex) << 8), pan); + AudioThread_QueueCmdS8(0x03000000 | ((u8)((u32)channelIndex) << 8), pan); } } } @@ -3837,6 +4350,7 @@ void Audio_ClearSariaBgmAtPos(Vec3f* pos) { } } +u8 sBgmPlayers[2] = { SEQ_PLAYER_BGM_MAIN, SEQ_PLAYER_BGM_SUB }; void Audio_SplitBgmChannels(s8 volumeSplit); #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/Audio_SplitBgmChannels.s") @@ -4043,6 +4557,7 @@ void Audio_ClearSariaBgm2(void) { #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A46F8.s") +f32 sSfxOriginalPos[] = { 0.0f, 0.0f, 0.0f }; #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4748.s") #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A479C.s") @@ -4053,11 +4568,27 @@ void Audio_ClearSariaBgm2(void) { #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4A28.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4B80.s") +u32 Audio_SetNatureAmbienceRandomBend(u8 seqScriptValIn, SequenceChannel* channel); +#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/Audio_SetNatureAmbienceRandomBend.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4C30.s") +void Audio_Init(void) { + AudioLoad_Init(NULL, 0); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4C54.s") +void AudioSfx_Init(u16 fadeTimer) { + u8 channelIndex; + + AudioThread_ScheduleProcessCmds(); + Audio_StartSequence(SEQ_PLAYER_SFX, NA_BGM_GENERAL_SFX, 0x70, fadeTimer); + + for (channelIndex = 0; channelIndex < ARRAY_COUNT(sSfxChannelState); channelIndex++) { + AudioThread_QueueCmdS32(0x10 << 24 | SEQ_PLAYER_SFX << 16 | ((u8)(u32)channelIndex << 8), + &sSfxChannelState[channelIndex]); + } + + AudioThread_QueueCmdS32(0xE4000000, AudioSfx_SetFreqAndStereoBits); + AudioThread_QueueCmdS32(0xE4000001, Audio_SetNatureAmbienceRandomBend); +} #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4D00.s") diff --git a/src/code/audio/code_801A5BD0.c b/src/code/audio/code_801A5BD0.c index 38e4ff187..4cf1147bf 100644 --- a/src/code/audio/code_801A5BD0.c +++ b/src/code/audio/code_801A5BD0.c @@ -1,45 +1,951 @@ #include "global.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_SetSfxBanksMute.s") +typedef struct { + /* 0x00 */ u16 sfxId; + /* 0x02 */ u8 token; + /* 0x04 */ s8* reverbAdd; + /* 0x08 */ Vec3f* pos; + /* 0x0C */ f32* freqScale; + /* 0x10 */ f32* volume; +} SfxRequest; // size = 0x14 -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_SetFlagForBgmVolumeLow.s") +typedef struct { + /* 0x0 */ f32 value; + /* 0x4 */ f32 target; + /* 0x8 */ f32 step; + /* 0xC */ u16 remainingFrames; +} SfxBankLerp; // size = 0x10 -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_ClearFlagForBgmVolumeLow.s") +typedef enum { + /* 0 */ SFX_RM_REQ_BY_BANK, + /* 1 */ SFX_RM_REQ_BY_POS_AND_BANK, + /* 2 */ SFX_RM_REQ_BY_POS, + /* 3 */ SFX_RM_REQ_BY_POS_AND_ID, + /* 4 */ SFX_RM_REQ_BY_TOKEN_AND_ID, + /* 5 */ SFX_RM_REQ_BY_ID +} SfxRemoveRequest; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_PlaySfxGeneral.s") +SfxBankEntry sSfxPlayerBank[9]; +SfxBankEntry sSfxItemBank[12]; +SfxBankEntry sSfxEnvironmentBank[32]; +SfxBankEntry sSfxEnemyBank[20]; +SfxBankEntry sSfxSystemBank[8]; +SfxBankEntry sSfxOcarinaBank[3]; +SfxBankEntry sSfxVoiceBank[5]; +SfxRequest sSfxRequests[0x100]; +u8 sSfxBankListEnd[7]; +u8 sSfxBankFreeListStart[7]; +u8 sSfxBankUnused[7]; +ActiveSfx gActiveSfx[7][3]; +u8 sCurSfxPlayerChannelIndex; +u8 gSfxBankMuted[7]; +SfxBankLerp sSfxBankLerp[7]; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A5DDC.s") +// sSfxRequests ring buffer endpoints. read index <= write index, wrapping around mod 256. +u8 sSfxRequestWriteIndex = 0; +u8 sSfxRequestReadIndex = 0; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A5F7C.s") +/** + * Array of pointers to arrays of SfxBankEntry of sizes: 9, 12, 32, 20, 8, 3, 5 + * + * 0 : Player Bank size 9 + * 1 : Item Bank size 12 + * 2 : Environment Bank size 32 + * 3 : Enemy Bank size 20 + * 4 : System Bank size 8 + * 5 : Ocarina Bank size 3 + * 6 : Voice Bank size 5 + */ +SfxBankEntry* gSfxBanks[7] = { + sSfxPlayerBank, sSfxItemBank, sSfxEnvironmentBank, sSfxEnemyBank, sSfxSystemBank, sSfxOcarinaBank, sSfxVoiceBank, +}; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A6430.s") +u8 sSfxBankSizes[ARRAY_COUNT(gSfxBanks)] = { + ARRAY_COUNT(sSfxPlayerBank), ARRAY_COUNT(sSfxItemBank), ARRAY_COUNT(sSfxEnvironmentBank), + ARRAY_COUNT(sSfxEnemyBank), ARRAY_COUNT(sSfxSystemBank), ARRAY_COUNT(sSfxOcarinaBank), + ARRAY_COUNT(sSfxVoiceBank), +}; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A65C8.s") +u8 gSfxChannelLayout = 0; +u16 sSfxChannelLowVolumeFlag = 0; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A6D0C.s") +// The center of the screen in projected coordinates. +// Gives the impression that the sfx has no specific location +Vec3f gSfxDefaultPos = { 0.0f, 0.0f, 0.0f }; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7084.s") +// Reused as either frequency or volume multiplicative scaling factor +// Does not alter or change frequency or volume +f32 gSfxDefaultFreqAndVolScale = 1.0f; +s32 D_801DB4B4 = 0; // unused -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7168.s") +// Adds no reverb to the existing reverb +s8 gSfxDefaultReverb = 0; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7284.s") +void AudioSfx_MuteBanks(u16 muteMask) { + u8 bankId; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_StopSfxByPos.s") + for (bankId = 0; bankId < ARRAY_COUNT(gSfxBanks); bankId++) { + if (muteMask & 1) { + gSfxBankMuted[bankId] = true; + } else { + gSfxBankMuted[bankId] = false; + } + muteMask = muteMask >> 1; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7328.s") +/** + * Lowers volumes of both bgm players so that sfx can be more pronounced. + * Each sfx channel stores its own bit to lower the volume. + * Only a single channel needs to request this to lower the volume. + */ +void AudioSfx_LowerBgmVolume(u8 channelIndex) { + sSfxChannelLowVolumeFlag |= (1 << channelIndex); -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7484.s") + Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 2, 0x40, 0xF); + Audio_SetVolumeScale(SEQ_PLAYER_BGM_SUB, 2, 0x40, 0xF); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_StopSfxById.s") +/** + * Clears the flag for the specific channel to lower volume. + * If all flags are cleared, then both bgm players return to full volume + */ +void AudioSfx_RestoreBgmVolume(u8 channelIndex) { + sSfxChannelLowVolumeFlag &= ((1 << channelIndex) ^ 0xFFFF); -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7720.s") + if (sSfxChannelLowVolumeFlag == 0) { + Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 2, 0x7F, 0xF); + Audio_SetVolumeScale(SEQ_PLAYER_BGM_SUB, 2, 0x7F, 0xF); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7794.s") +/** + * The main function to request a sfx. All sfx requests begin here. + */ +void AudioSfx_PlaySfx(u16 sfxId, Vec3f* pos, u8 token, f32* freqScale, f32* volume, s8* reverbAdd) { + u8 i; + SfxRequest* reqWrite; + SfxRequest* reqRead; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7828.s") + if (!gSfxBankMuted[SFX_BANK_SHIFT(sfxId)]) { + reqWrite = &sSfxRequests[sSfxRequestWriteIndex]; -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A787C.s") + for (i = sSfxRequestReadIndex; sSfxRequestWriteIndex != i; i++) { + reqRead = &sSfxRequests[i]; + if ((reqRead->pos == pos) && (reqRead->sfxId == sfxId)) { + return; + } + } -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_IsSfxPlaying.s") + reqWrite->sfxId = sfxId; + reqWrite->pos = pos; + reqWrite->token = token; + reqWrite->freqScale = freqScale; + reqWrite->volume = volume; + reqWrite->reverbAdd = reverbAdd; + sSfxRequestWriteIndex++; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A794C.s") +void AudioSfx_RemoveMatchingRequests(u8 aspect, SfxBankEntry* entry) { + SfxRequest* req; + s32 remove; + u8 i = sSfxRequestReadIndex; + + for (; i != sSfxRequestWriteIndex; i++) { + remove = false; + req = &sSfxRequests[i]; + + switch (aspect) { + case SFX_RM_REQ_BY_BANK: + if (SFX_BANK_MASK(req->sfxId) == SFX_BANK_MASK(entry->sfxId)) { + remove = true; + } + break; + + case SFX_RM_REQ_BY_POS_AND_BANK: + if ((SFX_BANK_MASK(req->sfxId) == SFX_BANK_MASK(entry->sfxId)) && (&req->pos->x == entry->posX)) { + remove = true; + } + break; + + case SFX_RM_REQ_BY_POS: + if (&req->pos->x == entry->posX) { + remove = true; + } + break; + + case SFX_RM_REQ_BY_POS_AND_ID: + if ((&req->pos->x == entry->posX) && (req->sfxId == entry->sfxId)) { + remove = true; + } + break; + + case SFX_RM_REQ_BY_TOKEN_AND_ID: + if ((req->token == entry->token) && (req->sfxId == entry->sfxId)) { + remove = true; + } + break; + + case SFX_RM_REQ_BY_ID: + if (req->sfxId == entry->sfxId) { + remove = true; + } + break; + + default: + break; + } + + if (remove) { + req->sfxId = 0; + } + } +} + +void AudioSfx_ProcessRequest(void) { + u16 sfxId; + u8 channelCount; + u8 index; + SfxRequest* req = &sSfxRequests[sSfxRequestReadIndex]; + SfxBankEntry* entry; + SfxParams* sfxParams; + s32 bankId; + u8 evictImportance; + u8 evictIndex = 0x80; + + if (req->sfxId == 0) { + return; + } + + bankId = SFX_BANK(req->sfxId); + channelCount = 0; + index = gSfxBanks[bankId][0].next; + + // Compare the sfx request to all sfx bank entries + while ((index != 0xFF) && (index != 0)) { + + // If an existing sfx from the same source exists in the bank, then we should either: + // renew if it is the same sfx, check if any sfx channels are available for that bank, + // interrupt that sfx and replace it with the new sfx request, or drop the new sfx request. + if (gSfxBanks[bankId][index].posX == &req->pos->x) { + + // If the new sfx has equal importance to the existing sfx, + // drop the request if the existing sfx has the "SFX_FLAG_BLOCK_EQUAL_IMPORTANCE" flag. + // Otherwise, keep processing the new sfx request + if ((gSfxParams[SFX_BANK_SHIFT(req->sfxId)][SFX_INDEX(req->sfxId)].params & + SFX_FLAG_BLOCK_EQUAL_IMPORTANCE) && + (gSfxParams[SFX_BANK_SHIFT(req->sfxId)][SFX_INDEX(req->sfxId)].importance == + gSfxBanks[bankId][index].sfxImportance)) { + // Drop the new request + return; + } + + if (gSfxBanks[bankId][index].sfxId == req->sfxId) { + // The new sfx is the same as the existing sfx + // Set channelCount to max value to reprocess the sfx + channelCount = gUsedChannelsPerBank[gSfxChannelLayout][bankId]; + } else { + // Determine which sfx to evict based on importance if there are no more channels available + if (channelCount == 0) { + // If this is the first sfx at the same source, than store the existing sfx info into evict temps + evictIndex = index; + sfxId = gSfxBanks[bankId][index].sfxId & 0xFFFF; + evictImportance = gSfxParams[SFX_BANK_SHIFT(sfxId)][SFX_INDEX(sfxId)].importance; + } else if (gSfxBanks[bankId][index].sfxImportance < evictImportance) { + // If a different existing sfx is at the same source, than update the evict temps if the next + // existing src has lower importance than the previous existing source + evictIndex = index; + sfxId = gSfxBanks[bankId][index].sfxId & 0xFFFF; + evictImportance = gSfxParams[SFX_BANK_SHIFT(sfxId)][SFX_INDEX(sfxId)].importance; + } + + channelCount++; + + // There are no channels available, evict the lowest importance + if (channelCount == gUsedChannelsPerBank[gSfxChannelLayout][bankId]) { + if (gSfxParams[SFX_BANK_SHIFT(req->sfxId)][SFX_INDEX(req->sfxId)].importance >= evictImportance) { + index = evictIndex; + } else { + index = 0; + } + } + } + + // Process this sfx by refreshing or replacing and existing sfx + if (channelCount == gUsedChannelsPerBank[gSfxChannelLayout][bankId]) { + sfxParams = &gSfxParams[SFX_BANK_SHIFT(req->sfxId)][SFX_INDEX(req->sfxId)]; + + // Interrupt existing sfx and play the new sfx instead. + if ((req->sfxId & SFX_FLAG_MASK) || (sfxParams->flags & SFX_FLAG2_FORCE_RESET) || + (index == evictIndex)) { + + // Restore bgm if the sfx about to be replaced has the right flag + if ((gSfxBanks[bankId][index].sfxParams & SFX_FLAG_LOWER_VOLUME_BGM) && + (gSfxBanks[bankId][index].state != SFX_STATE_QUEUED)) { + AudioSfx_RestoreBgmVolume(gSfxBanks[bankId][index].channelIndex); + } + + gSfxBanks[bankId][index].token = req->token; + gSfxBanks[bankId][index].sfxId = req->sfxId; + gSfxBanks[bankId][index].state = SFX_STATE_QUEUED; + gSfxBanks[bankId][index].freshness = 2; + gSfxBanks[bankId][index].freqScale = req->freqScale; + gSfxBanks[bankId][index].volume = req->volume; + gSfxBanks[bankId][index].reverbAdd = req->reverbAdd; + gSfxBanks[bankId][index].sfxParams = sfxParams->params; + gSfxBanks[bankId][index].sfxFlags = sfxParams->flags; + gSfxBanks[bankId][index].sfxImportance = sfxParams->importance; + } else if (gSfxBanks[bankId][index].state == SFX_STATE_PLAYING_ONE_FRAME) { + // The new sfx is "one-frame" and equals the existing sfx, + // continue playing the "one-frame" sfx by setting "SFX_STATE_PLAYING". + // This will avoid triggering deletion and get "SFX_STATE_REFRESH" + // The state will be set back to "SFX_STATE_PLAYING_ONE_FRAME" at the end of the cycle + gSfxBanks[bankId][index].state = SFX_STATE_PLAYING; + } + // Terminate loop, function is finished (nothing more is processed) + index = 0; + } + } + + if (index != 0) { + index = gSfxBanks[bankId][index].next; + } + } + + if ((gSfxBanks[bankId][sSfxBankFreeListStart[bankId]].next != 0xFF) && (index != 0)) { + // Allocate from free list + index = sSfxBankFreeListStart[bankId]; + + entry = &gSfxBanks[bankId][index]; + entry->posX = &req->pos->x; + entry->posY = &req->pos->y; + entry->posZ = &req->pos->z; + entry->token = req->token; + entry->freqScale = req->freqScale; + entry->volume = req->volume; + entry->reverbAdd = req->reverbAdd; + + sfxParams = &gSfxParams[SFX_BANK_SHIFT(req->sfxId)][SFX_INDEX(req->sfxId)]; + + entry->sfxParams = sfxParams->params; + entry->sfxFlags = sfxParams->flags; + entry->sfxImportance = sfxParams->importance; + entry->sfxId = req->sfxId; + entry->state = SFX_STATE_QUEUED; + entry->freshness = 2; + entry->prev = sSfxBankListEnd[bankId]; + + gSfxBanks[bankId][sSfxBankListEnd[bankId]].next = sSfxBankFreeListStart[bankId]; + sSfxBankListEnd[bankId] = sSfxBankFreeListStart[bankId]; + sSfxBankFreeListStart[bankId] = gSfxBanks[bankId][sSfxBankFreeListStart[bankId]].next; + gSfxBanks[bankId][sSfxBankFreeListStart[bankId]].prev = 0xFF; + + entry->next = 0xFF; + } +} + +void AudioSfx_RemoveBankEntry(u8 bankId, u8 entryIndex) { + SfxBankEntry* entry = &gSfxBanks[bankId][entryIndex]; + u8 i; + + if (entry->sfxParams & SFX_FLAG_LOWER_VOLUME_BGM) { + AudioSfx_RestoreBgmVolume(entry->channelIndex); + } + + if (entryIndex == sSfxBankListEnd[bankId]) { + sSfxBankListEnd[bankId] = entry->prev; + } else { + gSfxBanks[bankId][entry->next].prev = entry->prev; + } + + gSfxBanks[bankId][entry->prev].next = entry->next; + entry->next = sSfxBankFreeListStart[bankId]; + entry->prev = 0xFF; + gSfxBanks[bankId][sSfxBankFreeListStart[bankId]].prev = entryIndex; + sSfxBankFreeListStart[bankId] = entryIndex; + entry->state = SFX_STATE_EMPTY; + + for (i = 0; i < gChannelsPerBank[gSfxChannelLayout][bankId]; i++) { + if (gActiveSfx[bankId][i].entryIndex == entryIndex) { + gActiveSfx[bankId][i].entryIndex = 0xFF; + i = gChannelsPerBank[gSfxChannelLayout][bankId]; + } + } +} + +void AudioSfx_ChooseActiveSfx(u8 bankId) { + u8 numChosenSfx = 0; + u8 numChannels; + u8 entryIndex; + u8 i; + u8 j; + u8 k; + u8 sfxImportance; + u8 needNewSfx; + u8 chosenEntryIndex; + s32 pad; + SfxBankEntry* entry; + ActiveSfx chosenSfx[MAX_CHANNELS_PER_BANK]; + ActiveSfx* activeSfx; + f32 entryPosY; + f32 entryPosX; + + for (i = 0; i < MAX_CHANNELS_PER_BANK; i++) { + chosenSfx[i].priority = 0x7FFFFFFF; + chosenSfx[i].entryIndex = 0xFF; + } + + entryIndex = gSfxBanks[bankId][0].next; + k = 0; + + // Delete stale sfx and prioritize remaining sfx into the gActiveSfx arrays + while (entryIndex != 0xFF) { + + // Update the freshness for an "all-frame" sfx if it is still queued + if ((gSfxBanks[bankId][entryIndex].state == SFX_STATE_QUEUED) && + (gSfxBanks[bankId][entryIndex].sfxId & SFX_FLAG_MASK)) { + gSfxBanks[bankId][entryIndex].freshness--; + + // If a "one-frame" sfx is still in "SFX_STATE_PLAYING_ONE_FRAME", then remove the sfx + } else if (!(gSfxBanks[bankId][entryIndex].sfxId & SFX_FLAG_MASK) && + (gSfxBanks[bankId][entryIndex].state == SFX_STATE_PLAYING_ONE_FRAME)) { + // CHAN_UPD_SCRIPT_IO (ioPort 0, force stop sfx in seq 0) + AudioThread_QueueCmdS8( + (0x6 << 24) | (SEQ_PLAYER_SFX << 16) | (gSfxBanks[bankId][entryIndex].channelIndex << 8), 0); + AudioSfx_RemoveBankEntry(bankId, entryIndex); + } + + // If a "all-frame" sfx goes 2 frames in the "queued" state + // (because it is too low priority), then remove the sfx + if (gSfxBanks[bankId][entryIndex].freshness == 0) { + AudioSfx_RemoveBankEntry(bankId, entryIndex); + } else if (gSfxBanks[bankId][entryIndex].state != SFX_STATE_EMPTY) { + // process the entry + entry = &gSfxBanks[bankId][entryIndex]; + + // Recompute distSq each frame since the sound's position may have changed + // (later converted into dist) + if (&gSfxDefaultPos.x == entry[0].posX) { + entry->dist = 0.0f; + } else { + entryPosY = *entry->posY * 1; + entryPosX = *entry->posX * 0.5f; + entry->dist = (SQ(entryPosX) + SQ(entryPosY) + SQ(*entry->posZ)) / 10.0f; + } + + // Recompute priority, possibly based on sfx position relative to the camera. + // (Note that the priority is the opposite of importance; lower is more preserved) + sfxImportance = entry->sfxImportance; + + if (entry->sfxParams & SFX_FLAG_PRIORITY_NO_DIST) { + // Priority is independent of distance + entry->priority = SQ(0xFF - sfxImportance) * SQ(76); + } else { + // Priority value increases with distance (more likely to eject) + if (entry->dist > 0x7FFFFFD0) { + // max distance + entry->dist = 0x70000008; + } + + entry->priority = (u32)entry->dist + (SQ(0xFF - sfxImportance) * SQ(76)); + if (*entry->posZ < 0.0f) { + entry->priority += (s32)(-*entry->posZ * 6.0f); + } + } + + // Sfx is too far away, do not consider for chosen sfx + if (entry->dist > SQ(1e5f)) { + + // If too far away and also playing, stop playing + if (entry->state == SFX_STATE_PLAYING) { + // CHAN_UPD_SCRIPT_IO (ioPort 0, force stop sfx in seq 0) + AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | (entry->channelIndex << 8), 0); + if (entry->sfxId & SFX_FLAG_MASK) { + AudioSfx_RemoveBankEntry(bankId, entryIndex); + entryIndex = k; + } + } + } else { + // Loop through all channels allocated to a specific bank + // Choose which sfx from gSfxBanks to play + // This includes all sfx requests and sfx already playing + // Sort all current sfx entries in gSfxBanks by priority + // This is where the "active" sfx are chosen + numChannels = gChannelsPerBank[gSfxChannelLayout][bankId]; + + for (i = 0; i < numChannels; i++) { + // Sort all sfx entries by priority + if (chosenSfx[i].priority >= entry->priority) { + // Update the number of sfx to attampt to play + if (numChosenSfx < gChannelsPerBank[gSfxChannelLayout][bankId]) { + numChosenSfx++; + } + + for (j = numChannels - 1; j > i; j--) { + chosenSfx[j].priority = chosenSfx[j - 1].priority; + chosenSfx[j].entryIndex = chosenSfx[j - 1].entryIndex; + } + + chosenSfx[i].priority = entry->priority; + chosenSfx[i].entryIndex = entryIndex; + i = numChannels; // make this the last pass through the loop, here equivalent to "break" + } + } + } + + k = entryIndex; + } + + entryIndex = gSfxBanks[bankId][k].next; + } + + // If a sfx is chosen, update its state + for (i = 0; i < numChosenSfx; i++) { + entry = &gSfxBanks[bankId][chosenSfx[i].entryIndex]; + + if (entry->state == SFX_STATE_QUEUED) { + // sfx is a new entry + entry->state = SFX_STATE_READY; + } else if (entry->state == SFX_STATE_PLAYING) { + // sfx is already playing + entry->state = SFX_STATE_PLAYING_REFRESH; + } + } + + // Apply the chosenSfx to the activeSfx in each channel + numChannels = gChannelsPerBank[gSfxChannelLayout][bankId]; + for (i = 0; i < numChannels; i++) { + needNewSfx = false; + activeSfx = &gActiveSfx[bankId][i]; + + // Check if a sfx is already in the channel + if (activeSfx->entryIndex == 0xFF) { + // No sfx playing in the channel + // Available for use + needNewSfx = true; + } else { + // The channel is already playing a sfx + // Get the entry of the sfx playing + entry = &gSfxBanks[bankId][activeSfx[0].entryIndex]; + + // Check the state of the sfx playing + if (entry->state == SFX_STATE_PLAYING) { + if (entry->sfxId & SFX_FLAG_MASK) { + // For "all-frames" sfx, remove the entry + AudioSfx_RemoveBankEntry(bankId, activeSfx->entryIndex); + } else { + // For "one-frame" sfx, reset the state to queued + entry->state = SFX_STATE_QUEUED; + entry->freshness = 0x80; + } + needNewSfx = true; + } else if (entry->state == SFX_STATE_EMPTY) { + // The sfx already in the channel is empty + // Can replace the sfx + activeSfx->entryIndex = 0xFF; + needNewSfx = true; + } else { + // Sfx is already playing as it should, nothing to do. + for (j = 0; j < numChannels; j++) { + if (activeSfx->entryIndex == chosenSfx[j].entryIndex) { + chosenSfx[j].entryIndex = 0xFF; + j = numChannels; + } + } + + numChosenSfx--; + } + } + + // enter the new sfx into the activeSfx + if (needNewSfx == true) { + for (j = 0; j < numChannels; j++) { + chosenEntryIndex = chosenSfx[j].entryIndex; + if ((chosenEntryIndex != 0xFF) && + (gSfxBanks[bankId][chosenEntryIndex].state != SFX_STATE_PLAYING_REFRESH)) { + for (k = 0; k < numChannels; k++) { + if (chosenEntryIndex == gActiveSfx[bankId][k].entryIndex) { + needNewSfx = false; + k = numChannels; // "break; i.e. force for-loop to end" + } + } + + if (needNewSfx == true) { + activeSfx->entryIndex = chosenEntryIndex; + chosenSfx[j].entryIndex = 0xFF; + j = numChannels + 1; + numChosenSfx--; + } + } + } + if (j == numChannels) { + // nothing found + activeSfx->entryIndex = 0xFF; + } + } + } +} + +void AudioSfx_PlayActiveSfx(u8 bankId) { + u8 entryIndex; + SequenceChannel* channel; + SfxBankEntry* entry; + u8 i; + u8 ioPort5Data; + + for (i = 0; i < gChannelsPerBank[gSfxChannelLayout][bankId]; i++) { + entryIndex = gActiveSfx[bankId][i].entryIndex; + // If entry is not empty + if (entryIndex != 0xFF) { + entry = &gSfxBanks[bankId][entryIndex]; + channel = gAudioContext.seqPlayers[SEQ_PLAYER_SFX].channels[sCurSfxPlayerChannelIndex]; + + if (entry->state == SFX_STATE_READY) { + // Initialize a sfx (new sfx request) + entry->channelIndex = sCurSfxPlayerChannelIndex; + if (entry->sfxParams & SFX_FLAG_LOWER_VOLUME_BGM) { + AudioSfx_LowerBgmVolume(sCurSfxPlayerChannelIndex); + } + + // Add noise that will offset the frequency of the sfx + if ((entry->sfxParams & SFX_PARAM_RAND_FREQ_RAISE_MASK) != (0 << SFX_PARAM_RAND_FREQ_RAISE_SHIFT)) { + switch (entry->sfxParams & SFX_PARAM_RAND_FREQ_RAISE_MASK) { + case (1 << SFX_PARAM_RAND_FREQ_RAISE_SHIFT): + entry->randFreq = AudioThread_NextRandom() & 0xF; + break; + + case (2 << SFX_PARAM_RAND_FREQ_RAISE_SHIFT): + entry->randFreq = AudioThread_NextRandom() & 0x1F; + break; + + case (3 << SFX_PARAM_RAND_FREQ_RAISE_SHIFT): + entry->randFreq = AudioThread_NextRandom() & 0x3F; + break; + + default: + entry->randFreq = 0; + break; + } + } + + // Calculate all the properties of sfx + AudioSfx_SetProperties(bankId, entryIndex, sCurSfxPlayerChannelIndex); + + // CHAN_UPD_SCRIPT_IO (ioPort 0, enable the sfx to play in seq 0) + AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | ((sCurSfxPlayerChannelIndex & 0xFF) << 8), + 1); + + // CHAN_UPD_SCRIPT_IO (ioPort 4, write the lower bits sfx index to seq 0 so it can find the right code + // to execute) + AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | + ((sCurSfxPlayerChannelIndex & 0xFF) << 8) | 4, + entry->sfxId & 0xFF); + + // If the sfx bank has more than 255 entries (greater than a u8 can store), + // then store the Id in upper and lower bits + if (gIsLargeSfxBank[bankId]) { + // Store upper bits + ioPort5Data = ((u8)((entry->sfxId & 0x300) >> 7) + (u8)((entry->sfxId & 0xFF) >> 7)); + } else { + ioPort5Data = 0; + } + + if ((entry->sfxParams & SFX_FLAG_8) && (entry->freshness == 0x80)) { + ioPort5Data += 0x80; + } + + if (D_801D6608[bankId]) { + // CHAN_UPD_SCRIPT_IO (ioPort 5, write the upper bits sfx index and a flag to seq 0, for banks with + // > 0xFF entries) + AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | + ((sCurSfxPlayerChannelIndex & 0xFF) << 8) | 5, + ioPort5Data); + } + + // Update playing state + if (entry->sfxId & SFX_FLAG_MASK) { + // "all-frames" sfx + entry->state = SFX_STATE_PLAYING; + } else { + // "one-frame" sfx + entry->state = SFX_STATE_PLAYING_ONE_FRAME; + } + } else if ((u8)channel->soundScriptIO[1] == 0xFF) { + // Signal from seq 0 that the sfx is finished playing. Remove entry + AudioSfx_RemoveBankEntry(bankId, entryIndex); + } else if (entry->state == SFX_STATE_PLAYING_REFRESH) { + // Sfx is playing but a refresh is requested + AudioSfx_SetProperties(bankId, entryIndex, sCurSfxPlayerChannelIndex); + + // Update playing state + if (entry->sfxId & SFX_FLAG_MASK) { + // "all-frames" sfx + entry->state = SFX_STATE_PLAYING; + } else { + // "one-frame" sfx + entry->state = SFX_STATE_PLAYING_ONE_FRAME; + } + } + } + + sCurSfxPlayerChannelIndex++; + } +} + +void AudioSfx_StopByBank(u8 bankId) { + SfxBankEntry* entry; + s32 pad; + SfxBankEntry entryToRemove; + u8 entryIndex = gSfxBanks[bankId][0].next; + + while (entryIndex != 0xFF) { + entry = &gSfxBanks[bankId][entryIndex]; + if (entry->state >= SFX_STATE_PLAYING_REFRESH) { + AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | ((entry->channelIndex & 0xFF) << 8), 0); + } + + if (entry->state != SFX_STATE_EMPTY) { + AudioSfx_RemoveBankEntry(bankId, entryIndex); + } + entryIndex = gSfxBanks[bankId][0].next; + } + + entryToRemove.sfxId = bankId << 12; + AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_BANK, &entryToRemove); +} + +void AudioSfx_StopByPosAndBankImpl(u8 bankId, Vec3f* pos) { + SfxBankEntry* entry; + u8 entryIndex = gSfxBanks[bankId][0].next; + u8 prevEntryIndex = 0; + + while (entryIndex != 0xFF) { + entry = &gSfxBanks[bankId][entryIndex]; + if (entry->posX == &pos->x) { + if (entry->state >= SFX_STATE_PLAYING_REFRESH) { + AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | ((entry->channelIndex & 0xFF) << 8), 0); + } + + if (entry->state != SFX_STATE_EMPTY) { + AudioSfx_RemoveBankEntry(bankId, entryIndex); + } + } else { + prevEntryIndex = entryIndex; + } + + entryIndex = gSfxBanks[bankId][prevEntryIndex].next; + } +} + +void AudioSfx_StopByPosAndBank(u8 bankId, Vec3f* pos) { + SfxBankEntry entryToRemove; + + AudioSfx_StopByPosAndBankImpl(bankId, pos); + entryToRemove.sfxId = bankId << 12; + entryToRemove.posX = &pos->x; + AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_POS_AND_BANK, &entryToRemove); +} + +void AudioSfx_StopByPos(Vec3f* pos) { + u8 bankId; + SfxBankEntry entryToRemove; + + for (bankId = 0; bankId < ARRAY_COUNT(gSfxBanks); bankId++) { + AudioSfx_StopByPosAndBankImpl(bankId, pos); + } + + entryToRemove.posX = &pos->x; + AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_POS, &entryToRemove); +} + +void AudioSfx_StopByPosAndId(Vec3f* pos, u16 sfxId) { + SfxBankEntry* entry; + u8 entryIndex = gSfxBanks[SFX_BANK(sfxId)][0].next; + u8 prevEntryIndex = 0; + SfxBankEntry entryToRemove; + + while (entryIndex != 0xFF) { + entry = &gSfxBanks[SFX_BANK(sfxId)][entryIndex]; + if ((entry->posX == &pos->x) && (entry->sfxId == sfxId)) { + if (entry->state >= SFX_STATE_PLAYING_REFRESH) { + AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | ((entry->channelIndex & 0xFF) << 8), 0); + } + + if (entry->state != SFX_STATE_EMPTY) { + AudioSfx_RemoveBankEntry(SFX_BANK(sfxId), entryIndex); + } + entryIndex = 0xFF; + } else { + prevEntryIndex = entryIndex; + } + + if (entryIndex != 0xFF) { + entryIndex = gSfxBanks[SFX_BANK(sfxId)][prevEntryIndex].next; + } + } + + entryToRemove.posX = &pos->x; + entryToRemove.sfxId = sfxId; + AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_POS_AND_ID, &entryToRemove); +} + +void AudioSfx_StopByTokenAndId(u8 token, u16 sfxId) { + SfxBankEntry* entry; + u8 entryIndex = gSfxBanks[SFX_BANK(sfxId)][0].next; + u8 prevEntryIndex = 0; + SfxBankEntry entryToRemove; + + while (entryIndex != 0xFF) { + entry = &gSfxBanks[SFX_BANK(sfxId)][entryIndex]; + if ((entry->token == token) && (entry->sfxId == sfxId)) { + if (entry->state >= SFX_STATE_PLAYING_REFRESH) { + AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | ((entry->channelIndex & 0xFF) << 8), 0); + } + + if (entry->state != SFX_STATE_EMPTY) { + AudioSfx_RemoveBankEntry(SFX_BANK(sfxId), entryIndex); + } + } else { + prevEntryIndex = entryIndex; + } + + if (entryIndex != 0xFF) { + entryIndex = gSfxBanks[SFX_BANK(sfxId)][prevEntryIndex].next; + } + } + + entryToRemove.token = token; + entryToRemove.sfxId = sfxId; + AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_TOKEN_AND_ID, &entryToRemove); +} + +void AudioSfx_StopById(u32 sfxId) { + SfxBankEntry* entry; + u8 entryIndex = gSfxBanks[SFX_BANK(sfxId)][0].next; + u8 prevEntryIndex = 0; + SfxBankEntry entryToRemove; + + while (entryIndex != 0xFF) { + entry = &gSfxBanks[SFX_BANK(sfxId)][entryIndex]; + if (entry->sfxId == sfxId) { + if (entry->state >= SFX_STATE_PLAYING_REFRESH) { + AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | ((entry->channelIndex & 0xFF) << 8), 0); + } + if (entry->state != SFX_STATE_EMPTY) { + AudioSfx_RemoveBankEntry(SFX_BANK(sfxId), entryIndex); + } + } else { + prevEntryIndex = entryIndex; + } + + entryIndex = gSfxBanks[SFX_BANK(sfxId)][prevEntryIndex].next; + } + + entryToRemove.sfxId = sfxId; + AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_ID, &entryToRemove); +} + +void AudioSfx_ProcessRequests(void) { + if (gAudioContext.seqPlayers[SEQ_PLAYER_SFX].enabled) { + while (sSfxRequestWriteIndex != sSfxRequestReadIndex) { + AudioSfx_ProcessRequest(); + sSfxRequestReadIndex++; + } + } +} + +/** + * Unused + */ +void AudioSfx_SetBankLerp(u8 bankId, u8 target, u16 delay) { + if (delay == 0) { + delay++; + } + + sSfxBankLerp[bankId].target = target / 127.0f; + sSfxBankLerp[bankId].remainingFrames = delay; + sSfxBankLerp[bankId].step = ((sSfxBankLerp[bankId].value - sSfxBankLerp[bankId].target) / delay); +} + +/** + * Unused + */ +void AudioSfx_StepBankLerp(u8 bankId) { + if (sSfxBankLerp[bankId].remainingFrames != 0) { + sSfxBankLerp[bankId].remainingFrames--; + + if (sSfxBankLerp[bankId].remainingFrames != 0) { + sSfxBankLerp[bankId].value -= sSfxBankLerp[bankId].step; + } else { + sSfxBankLerp[bankId].value = sSfxBankLerp[bankId].target; + } + } +} + +void AudioSfx_ProcessActiveSfx(void) { + u8 bankId; + + if (gAudioContext.seqPlayers[SEQ_PLAYER_SFX].enabled) { + sCurSfxPlayerChannelIndex = 0; + + for (bankId = 0; bankId < ARRAY_COUNT(gSfxBanks); bankId++) { + AudioSfx_ChooseActiveSfx(bankId); + AudioSfx_PlayActiveSfx(bankId); + AudioSfx_StepBankLerp(bankId); + } + } +} + +u8 AudioSfx_IsPlaying(u32 sfxId) { + SfxBankEntry* entry; + u8 entryIndex = gSfxBanks[SFX_BANK(sfxId)][0].next; + + while (entryIndex != 0xFF) { + entry = &gSfxBanks[SFX_BANK(sfxId)][entryIndex]; + if (entry->sfxId == sfxId) { + return true; + } + entryIndex = entry->next; + } + + return false; +} + +void AudioSfx_Reset(void) { + u8 bankId; + u8 i; + u8 entryIndex; + + sSfxRequestWriteIndex = 0; + sSfxRequestReadIndex = 0; + sSfxChannelLowVolumeFlag = 0; + + for (bankId = 0; bankId < ARRAY_COUNT(gSfxBanks); bankId++) { + sSfxBankListEnd[bankId] = 0; + sSfxBankFreeListStart[bankId] = 1; + sSfxBankUnused[bankId] = 0; + gSfxBankMuted[bankId] = false; + sSfxBankLerp[bankId].value = 1.0f; + sSfxBankLerp[bankId].remainingFrames = 0; + } + + for (bankId = 0; bankId < ARRAY_COUNT(gSfxBanks); bankId++) { + for (i = 0; i < MAX_CHANNELS_PER_BANK; i++) { + gActiveSfx[bankId][i].entryIndex = 0xFF; + } + } + + for (bankId = 0; bankId < ARRAY_COUNT(gSfxBanks); bankId++) { + gSfxBanks[bankId][0].prev = 0xFF; + gSfxBanks[bankId][0].next = 0xFF; + + for (i = 1; i < sSfxBankSizes[bankId] - 1; i++) { + gSfxBanks[bankId][i].prev = i - 1; + gSfxBanks[bankId][i].next = i + 1; + } + + gSfxBanks[bankId][i].prev = i - 1; + gSfxBanks[bankId][i].next = 0xFF; + } +} diff --git a/src/code/audio/code_801A7B10.c b/src/code/audio/code_801A7B10.c index 6d3faaeab..f2f37a013 100644 --- a/src/code/audio/code_801A7B10.c +++ b/src/code/audio/code_801A7B10.c @@ -1,6 +1,6 @@ #include "global.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A7B10/func_801A7B10.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A7B10/Audio_StartSequence.s") #pragma GLOBAL_ASM("asm/non_matchings/code/code_801A7B10/func_801A7D04.s") diff --git a/src/code/audioMgr.c b/src/code/audioMgr.c index ee6014137..ce21bda37 100644 --- a/src/code/audioMgr.c +++ b/src/code/audioMgr.c @@ -78,7 +78,7 @@ void AudioMgr_ThreadEntry(void* arg) { s16* msg = NULL; s32 exit; - func_801A4C30(); + Audio_Init(); AudioLoad_SetDmaHandler(DmaMgr_DmaHandler); func_801A4D00(); osSendMesg(&audioMgr->lockMsgQ, NULL, OS_MESG_BLOCK); diff --git a/src/code/code_80172BC0.c b/src/code/code_80172BC0.c index 2ea9e6c67..94b55d4df 100644 --- a/src/code/code_80172BC0.c +++ b/src/code/code_80172BC0.c @@ -9,7 +9,7 @@ void AudioMgr_StopAllSfxExceptSystem(void) { for (bankIdPtr = sSfxBankIds; bankIdPtr < (sSfxBankIds + ARRAY_COUNT(sSfxBankIds)); bankIdPtr++) { if (*bankIdPtr != BANK_SYSTEM) { - func_801A7084(*bankIdPtr); + AudioSfx_StopByBank(*bankIdPtr); } } } diff --git a/src/code/z_actor.c b/src/code/z_actor.c index 751327552..fdd334b6e 100644 --- a/src/code/z_actor.c +++ b/src/code/z_actor.c @@ -2127,7 +2127,8 @@ void func_800B8E58(Player* player, u16 sfxId) { if (player->currentMask == PLAYER_MASK_GIANT) { func_8019F170(&player->actor.projectedPos, sfxId); } else { - Audio_PlaySfxGeneral(sfxId, &player->actor.projectedPos, 4, &D_801DB4B0, &D_801DB4B0, &gSfxDefaultReverb); + AudioSfx_PlaySfx(sfxId, &player->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } } @@ -2567,7 +2568,8 @@ void func_800B9D1C(Actor* actor) { if (sfxId != 0) { if (actor->audioFlags & 2) { - Audio_PlaySfxGeneral(sfxId, &actor->projectedPos, 4, &D_801DB4B0, &D_801DB4B0, &gSfxDefaultReverb); + AudioSfx_PlaySfx(sfxId, &actor->projectedPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultReverb); } else if (actor->audioFlags & 4) { play_sound(sfxId); } else if (actor->audioFlags & 8) { @@ -3338,7 +3340,7 @@ Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play) { actorCtx->targetContext.bgmEnemy = NULL; } - Audio_StopSfxByPos(&actor->projectedPos); + AudioSfx_StopByPos(&actor->projectedPos); Actor_Destroy(actor, play); newHead = Actor_RemoveFromCategory(play, actorCtx, actor); diff --git a/src/code/z_effect_soft_sprite.c b/src/code/z_effect_soft_sprite.c index 87f1958bd..ea8a546d6 100644 --- a/src/code/z_effect_soft_sprite.c +++ b/src/code/z_effect_soft_sprite.c @@ -59,11 +59,11 @@ EffectSs* EffectSS_GetTable() { void EffectSS_Delete(EffectSs* effectSs) { if (effectSs->flags & 2) { - Audio_StopSfxByPos(&effectSs->pos); + AudioSfx_StopByPos(&effectSs->pos); } if (effectSs->flags & 4) { - Audio_StopSfxByPos(&effectSs->vec); + AudioSfx_StopByPos(&effectSs->vec); } EffectSS_ResetEntry(effectSs); diff --git a/src/code/z_sound_source.c b/src/code/z_sound_source.c index 2cdc3ab3a..15ebd018a 100644 --- a/src/code/z_sound_source.c +++ b/src/code/z_sound_source.c @@ -16,7 +16,7 @@ void SoundSource_UpdateAll(PlayState* play) { for (i = 0; i < ARRAY_COUNT(play->soundSources); i++) { if (source->countdown != 0) { if (DECR(source->countdown) == 0) { - Audio_StopSfxByPos(&source->projectedPos); + AudioSfx_StopByPos(&source->projectedPos); } else { SkinMatrix_Vec3fMtxFMultXYZ(&play->viewProjectionMtxF, &source->worldPos, &source->projectedPos); if (source->playSfxEachFrame) { @@ -54,7 +54,7 @@ void SoundSource_Add(PlayState* play, Vec3f* worldPos, u32 duration, u16 sfxId, // If no sound source is available, replace the sound source with the smallest remaining countdown if (i >= ARRAY_COUNT(play->soundSources)) { source = backupSource; - Audio_StopSfxByPos(&source->projectedPos); + AudioSfx_StopByPos(&source->projectedPos); } source->worldPos = *worldPos; |
