From 94502725030b2778d8f15694e10499f76d69090f Mon Sep 17 00:00:00 2001 From: engineer124 <47598039+engineer124@users.noreply.github.com> Date: Sat, 15 Jan 2022 09:13:04 +1100 Subject: [PATCH] Improve River_Sound Docs (#1100) * river_sound docs * Small touch-up * PR Suggestions * Improve comments on river line calculations * More PR Feedback * after analyzing the filter data for MM, lowPassFilter is reverse to what I thought it was --- include/functions.h | 6 +- src/code/audio_seqplayer.c | 4 +- src/code/code_800EC960.c | 164 ++++++++----- .../ovl_En_River_Sound/z_en_river_sound.c | 232 +++++++++++------- .../ovl_En_River_Sound/z_en_river_sound.h | 27 +- 5 files changed, 255 insertions(+), 178 deletions(-) diff --git a/include/functions.h b/include/functions.h index d321a49752..18e75bd7c7 100644 --- a/include/functions.h +++ b/include/functions.h @@ -1899,7 +1899,7 @@ void AudioHeap_InitMainPools(s32 sizeForAudioInitPool); void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id); void* AudioHeap_SearchCaches(s32 tableType, s32 arg1, s32 id); void* AudioHeap_SearchRegularCaches(s32 tableType, s32 cache, s32 id); -void AudioHeap_LoadFilter(s16* filter, s32 filter1, s32 filter2); +void AudioHeap_LoadFilter(s16* filter, s32 lowPassCutoff, s32 highPassCutoff); s32 AudioHeap_ResetStep(void); void AudioHeap_Init(void); void* AudioHeap_SearchPermanentCache(s32 tableType, s32 id); @@ -2032,8 +2032,8 @@ void Audio_PlaySoundWaterfall(Vec3f* pos, f32 freqScale); void func_800F47BC(void); void func_800F47FC(void); void func_800F483C(u8 targetVol, u8 volFadeTimer); -void func_800F4870(u8); -void func_800F4A54(u8); +void Audio_SetGanonsTowerBgmVolumeLevel(u8 ganonsTowerLevel); +void Audio_LowerMainBgmVolume(u8 volume); void Audio_PlaySoundIncreasinglyTransposed(Vec3f* pos, s16 sfxId, u8* semitones); void Audio_ResetIncreasingTranspose(void); void Audio_PlaySoundTransposed(Vec3f* pos, u16 sfxId, s8 semitone); diff --git a/src/code/audio_seqplayer.c b/src/code/audio_seqplayer.c index 091cd97248..e405309ca5 100644 --- a/src/code/audio_seqplayer.c +++ b/src/code/audio_seqplayer.c @@ -1313,8 +1313,8 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { command = parameters[0]; if (channel->filter != NULL) { - lowBits = (command >> 4) & 0xF; - command &= 0xF; + lowBits = (command >> 4) & 0xF; // LowPassCutoff + command &= 0xF; // HighPassCutoff AudioHeap_LoadFilter(channel->filter, lowBits, command); } break; diff --git a/src/code/code_800EC960.c b/src/code/code_800EC960.c index 583d871bf5..a07583921a 100644 --- a/src/code/code_800EC960.c +++ b/src/code/code_800EC960.c @@ -111,8 +111,8 @@ u8 gMorphaTransposeTable[16] = { 0, 0, 0, 1, 1, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8 u8 sPrevChargeLevel = 0; f32 D_801305E4[4] = { 1.0f, 1.12246f, 1.33484f, 1.33484f }; // 2**({0, 2, 5, 5}/12) f32 D_801305F4 = 1.0f; -u8 D_801305F8[8] = { 127, 80, 75, 73, 70, 68, 65, 60 }; -u8 D_80130600 = 0; +u8 sGanonsTowerLevelsVol[8] = { 127, 80, 75, 73, 70, 68, 65, 60 }; +u8 sEnterGanonsTowerTimer = 0; s8 D_80130604 = 2; s8 D_80130608 = 0; s8 sAudioCutsceneFlag = 0; @@ -1187,11 +1187,11 @@ struct { s8 str[5]; u16 num; } sAudioScrPrtBuf[SCROLL_PRINT_BUF_SIZE]; -u8 D_8016B8B0; -u8 D_8016B8B1; -u8 D_8016B8B2; -u8 D_8016B8B3; -u8 sAudioGanonDistVol; +u8 sRiverSoundMainBgmVol; +u8 sRiverSoundMainBgmCurrentVol; +u8 sRiverSoundMainBgmLower; +u8 sRiverSoundMainBgmRestore; +u8 sGanonsTowerVol; SfxPlayerState sSfxChannelState[0x10]; char sBinToStrBuf[0x20]; @@ -1243,7 +1243,7 @@ void PadMgr_RequestPadData(PadMgr* padmgr, Input* inputs, s32 mode); void Audio_StepFreqLerp(FreqLerp* lerp); void func_800F56A8(void); void Audio_PlayNatureAmbienceSequence(u8 natureAmbienceId); -s32 Audio_SetGanonDistVol(u8 targetVol); +s32 Audio_SetGanonsTowerBgmVolume(u8 targetVol); void func_800EC960(u8 custom) { if (!custom) { @@ -2852,7 +2852,7 @@ void AudioDebug_Draw(GfxPrint* printer) { GfxPrint_Printf(printer, "ENEMY DIST %f VOL %3d", sAudioEnemyDist, sAudioEnemyVol); GfxPrint_SetPos(printer, 3, 11); - GfxPrint_Printf(printer, "GANON DIST VOL %3d", sAudioGanonDistVol); + GfxPrint_Printf(printer, "GANON DIST VOL %3d", sGanonsTowerVol); GfxPrint_SetPos(printer, 3, 12); GfxPrint_Printf(printer, "DEMO FLAG %d", sAudioCutsceneFlag); @@ -3490,7 +3490,7 @@ void AudioDebug_ProcessInput(void) { D_8013340C = sAudioScrPrtWork[10]; } -void func_800F4A70(void); +void Audio_UpdateRiverSoundVolumes(void); void func_800F5CF8(void); void func_800F3054(void) { @@ -3500,7 +3500,7 @@ void func_800F3054(void) { func_800EE6F4(); Audio_StepFreqLerp(&sRiverFreqScaleLerp); Audio_StepFreqLerp(&sWaterfallFreqScaleLerp); - func_800F4A70(); + Audio_UpdateRiverSoundVolumes(); func_800F56A8(); func_800F5CF8(); if (gAudioSpecId == 7) { @@ -4064,88 +4064,116 @@ void func_800F483C(u8 targetVol, u8 volFadeTimer) { Audio_SetVolScale(SEQ_PLAYER_BGM_MAIN, 0, targetVol, volFadeTimer); } -void func_800F4870(u8 arg0) { - s8 pan; - u8 i; +/** + * Incrementally increase volume of NA_BGM_GANON_TOWER for each new room during the climb of Ganon's Tower + */ +void Audio_SetGanonsTowerBgmVolumeLevel(u8 ganonsTowerLevel) { + u8 channelIdx; + s8 pan = 0; - pan = 0; - if (arg0 == 0) { + // Ganondorf's Lair + if (ganonsTowerLevel == 0) { pan = 0x7F; } - for (i = 0; i < 16; i++) { + for (channelIdx = 0; channelIdx < 16; channelIdx++) { // CHAN_UPD_PAN_UNSIGNED - Audio_QueueCmdS8( - _SHIFTL(0x7, 24, 8) | _SHIFTL(SEQ_PLAYER_BGM_MAIN, 16, 8) | _SHIFTL(i, 8, 8) | _SHIFTL(0, 0, 8), pan); + Audio_QueueCmdS8(_SHIFTL(0x7, 24, 8) | _SHIFTL(SEQ_PLAYER_BGM_MAIN, 16, 8) | _SHIFTL(channelIdx, 8, 8) | + _SHIFTL(0, 0, 8), + pan); } - if (arg0 == 7) { - D_80130600 = 2; + // Lowest room in Ganon's Tower (Entrance Room) + if (ganonsTowerLevel == 7) { + // Adds a delay to setting the volume in the first room + sEnterGanonsTowerTimer = 2; } else { - Audio_SetGanonDistVol(D_801305F8[arg0 & 7]); + Audio_SetGanonsTowerBgmVolume(sGanonsTowerLevelsVol[ganonsTowerLevel % ARRAY_COUNTU(sGanonsTowerLevelsVol)]); } } -// (name derived from debug strings, should probably update. used in ganon/ganon_boss scenes) -s32 Audio_SetGanonDistVol(u8 targetVol) { - u8 phi_v0; - u16 phi_v0_2; - u8 i; +/** + * If a new volume is requested for ganon's tower, update the volume and + * calculate a new low-pass filter cutoff and reverb based on the new volume + */ +s32 Audio_SetGanonsTowerBgmVolume(u8 targetVol) { + u8 lowPassFilterCutoff; + u16 reverb; + u8 channelIdx; - if (sAudioGanonDistVol != targetVol) { + if (sGanonsTowerVol != targetVol) { + // Sets the volume Audio_SetVolScale(SEQ_PLAYER_BGM_MAIN, 0, targetVol, 2); - if (targetVol < 0x40) { - phi_v0 = 0x10; - } else { - phi_v0 = (((targetVol - 0x40) >> 2) + 1) << 4; - } - Audio_SeqCmd8(SEQ_PLAYER_BGM_MAIN, 4, 15, phi_v0); - for (i = 0; i < 0x10; i++) { - if (gAudioContext.seqPlayers[SEQ_PLAYER_BGM_MAIN].channels[i] != &gAudioContext.sequenceChannelNone) { - if ((u8)gAudioContext.seqPlayers[SEQ_PLAYER_BGM_MAIN].channels[i]->soundScriptIO[5] != 0xFF) { - // this looks like some kind of macro? - phi_v0_2 = - ((u16)gAudioContext.seqPlayers[SEQ_PLAYER_BGM_MAIN].channels[i]->soundScriptIO[5] - targetVol) + + // Sets the filter cutoff of the form (lowPassFilterCutoff << 4) | (highPassFilter & 0xF). highPassFilter is + // always set to 0 + if (targetVol < 0x40) { + // Only the first room + lowPassFilterCutoff = 1 << 4; + } else { + // Higher volume leads to a higher cut-off frequency in the low-pass filtering + lowPassFilterCutoff = (((targetVol - 0x40) >> 2) + 1) << 4; + } + // Set lowPassFilterCutoff to io port 4 from channel 15 + Audio_SeqCmd8(SEQ_PLAYER_BGM_MAIN, 4, 15, lowPassFilterCutoff); + + // Sets the reverb + for (channelIdx = 0; channelIdx < 16; channelIdx++) { + if (gAudioContext.seqPlayers[SEQ_PLAYER_BGM_MAIN].channels[channelIdx] != + &gAudioContext.sequenceChannelNone) { + // soundScriptIO[5] is set to 0x40 in channels 0, 1, and 4 + if ((u8)gAudioContext.seqPlayers[SEQ_PLAYER_BGM_MAIN].channels[channelIdx]->soundScriptIO[5] != 0xFF) { + // Higher volume leads to lower reverb + reverb = + ((u16)gAudioContext.seqPlayers[SEQ_PLAYER_BGM_MAIN].channels[channelIdx]->soundScriptIO[5] - + targetVol) + 0x7F; - if (phi_v0_2 >= 0x80) { - phi_v0_2 = 0x7F; + if (reverb > 0x7F) { + reverb = 0x7F; } // CHAN_UPD_REVERB - Audio_QueueCmdS8(_SHIFTL(0x5, 24, 8) | _SHIFTL(SEQ_PLAYER_BGM_MAIN, 16, 8) | _SHIFTL(i, 8, 8) | - _SHIFTL(0, 0, 8), - (u8)phi_v0_2); + Audio_QueueCmdS8(_SHIFTL(0x5, 24, 8) | _SHIFTL(SEQ_PLAYER_BGM_MAIN, 16, 8) | + _SHIFTL(channelIdx, 8, 8) | _SHIFTL(0, 0, 8), + (u8)reverb); } } } - sAudioGanonDistVol = targetVol; + sGanonsTowerVol = targetVol; } return -1; } -void func_800F4A54(u8 arg0) { - D_8016B8B0 = arg0; - D_8016B8B2 = 1; +/** + * Responsible for lowering market bgm in Child Market Entrance and Child Market Back Alley + * Only lowers volume for 1 frame, so must be called every frame to maintain lower volume + */ +void Audio_LowerMainBgmVolume(u8 volume) { + sRiverSoundMainBgmVol = volume; + sRiverSoundMainBgmLower = true; } -void func_800F4A70(void) { - if (D_8016B8B2 == 1) { - if (D_8016B8B1 != D_8016B8B0) { - Audio_SetVolScale(SEQ_PLAYER_BGM_MAIN, 0, D_8016B8B0, 0xA); - D_8016B8B1 = D_8016B8B0; - D_8016B8B3 = 1; +void Audio_UpdateRiverSoundVolumes(void) { + // Updates Main Bgm Volume (RiverSound of type RS_LOWER_MAIN_BGM_VOLUME) + if (sRiverSoundMainBgmLower == true) { + if (sRiverSoundMainBgmCurrentVol != sRiverSoundMainBgmVol) { + // lowers the volume for 1 frame + Audio_SetVolScale(SEQ_PLAYER_BGM_MAIN, 0, sRiverSoundMainBgmVol, 0xA); + sRiverSoundMainBgmCurrentVol = sRiverSoundMainBgmVol; + sRiverSoundMainBgmRestore = true; } - D_8016B8B2 = 0; - } else if (D_8016B8B3 == 1 && D_80130608 == 0) { + sRiverSoundMainBgmLower = false; + } else if (sRiverSoundMainBgmRestore == true && D_80130608 == 0) { + // restores the volume every frame Audio_SetVolScale(SEQ_PLAYER_BGM_MAIN, 0, 0x7F, 0xA); - D_8016B8B1 = 0x7F; - D_8016B8B3 = 0; + sRiverSoundMainBgmCurrentVol = 0x7F; + sRiverSoundMainBgmRestore = false; } - if (D_80130600 != 0) { - D_80130600--; - if (D_80130600 == 0) { - Audio_SetGanonDistVol(D_801305F8[7]); + // Update Ganon's Tower Volume (RiverSound of type RS_GANON_TOWER_7) + if (sEnterGanonsTowerTimer != 0) { + sEnterGanonsTowerTimer--; + if (sEnterGanonsTowerTimer == 0) { + Audio_SetGanonsTowerBgmVolume(sGanonsTowerLevelsVol[7]); } } } @@ -4915,11 +4943,11 @@ void func_800F6C34(void) { sRiverFreqScaleLerp.value = 1.0f; sWaterfallFreqScaleLerp.value = 1.0f; D_8016B7D8 = 1.0f; - D_8016B8B0 = 0x7F; - D_8016B8B1 = 0x7F; - D_8016B8B2 = 0; - D_8016B8B3 = 0; - sAudioGanonDistVol = 0xFF; + sRiverSoundMainBgmVol = 0x7F; + sRiverSoundMainBgmCurrentVol = 0x7F; + sRiverSoundMainBgmLower = false; + sRiverSoundMainBgmRestore = false; + sGanonsTowerVol = 0xFF; D_8016B9D8 = 0; sSpecReverb = sSpecReverbs[gAudioSpecId]; D_80130608 = 0; diff --git a/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.c b/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.c index 9aea2df41a..d7e35c2647 100644 --- a/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.c +++ b/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.c @@ -1,7 +1,7 @@ /* * File: z_en_river_sound.c * Overlay: ovl_En_River_Sound - * Description: Ambient Sound Effects + * Description: Controls various sounds. Includes sound effects and bgms */ #include "z_en_river_sound.h" @@ -28,17 +28,18 @@ const ActorInit En_River_Sound_InitVars = { void EnRiverSound_Init(Actor* thisx, GlobalContext* globalCtx) { EnRiverSound* this = (EnRiverSound*)thisx; - this->playSound = 0; + this->playSound = false; this->pathIndex = (this->actor.params >> 8) & 0xFF; this->actor.params = this->actor.params & 0xFF; - if (this->actor.params >= RS_MAX) { // used for ganon and ganon_boss scenes - func_800F4870(this->actor.params - RS_MAX); + if (this->actor.params >= RS_GANON_TOWER_0) { + // Incrementally increase volume of NA_BGM_GANON_TOWER for each new room during the climb of Ganon's Tower + Audio_SetGanonsTowerBgmVolumeLevel(this->actor.params - RS_GANON_TOWER_0); Actor_Kill(&this->actor); - } else if (this->actor.params == RS_UNK_F7) { + } else if (this->actor.params == RS_NATURE_AMBIENCE) { Audio_PlayNatureAmbienceSequence(NATURE_ID_KOKIRI_REGION); Actor_Kill(&this->actor); - } else if (this->actor.params == RS_SARIAS_SONG) { + } else if (this->actor.params == RS_LOST_WOODS_SARIAS_SONG) { if (!CHECK_QUEST_ITEM(QUEST_SONG_LULLABY) || CHECK_QUEST_ITEM(QUEST_SONG_SARIA)) { Actor_Kill(&this->actor); } @@ -48,37 +49,57 @@ void EnRiverSound_Init(Actor* thisx, GlobalContext* globalCtx) { void EnRiverSound_Destroy(Actor* thisx, GlobalContext* globalCtx) { EnRiverSound* this = (EnRiverSound*)thisx; - if (this->actor.params == RS_SARIAS_SONG) { + if (this->actor.params == RS_LOST_WOODS_SARIAS_SONG) { Audio_ClearSariaBgmAtPos(&this->actor.projectedPos); - } else if (this->actor.params == RS_UNK_13) { + } else if (this->actor.params == RS_GORON_CITY_SARIAS_SONG) { Audio_ClearSariaBgm2(); } } -s32 func_80AE6A54(Vec3f* arg0, Vec3f* arg1, Vec3f* arg2, Vec3f* arg3) { - Vec3f vec[3]; +/** + * Determines the closest point to hearPos that is contained on the line connecting points A & B + * If the closest point on the line will not be on the line segment connecting points A or B, return false. + * Otherwise, calculate the point between A & B, assign it to `newSoundPos`, and return true + */ +s32 EnRiverSound_FindClosestPointOnLineSegment(Vec3f* pointA, Vec3f* pointB, Vec3f* hearPos, Vec3f* newSoundPos) { + Vec3f lineSeg[3]; f32 temp; - vec[0].x = arg0->x - arg2->x; - vec[0].y = arg0->y - arg2->y; - vec[0].z = arg0->z - arg2->z; + // Line Segment from the hearPos to the first point in the path + lineSeg[0].x = pointA->x - hearPos->x; + lineSeg[0].y = pointA->y - hearPos->y; + lineSeg[0].z = pointA->z - hearPos->z; - vec[1].x = arg1->x - arg2->x; - vec[1].y = arg1->y - arg2->y; - vec[1].z = arg1->z - arg2->z; + // Line Segment from the hearPos to the second point in the path + lineSeg[1].x = pointB->x - hearPos->x; + lineSeg[1].y = pointB->y - hearPos->y; + lineSeg[1].z = pointB->z - hearPos->z; - vec[2].x = vec[1].x - vec[0].x; - vec[2].y = vec[1].y - vec[0].y; - vec[2].z = vec[1].z - vec[0].z; + // Line Segment from the first point to the second point in the path + lineSeg[2].x = lineSeg[1].x - lineSeg[0].x; + lineSeg[2].y = lineSeg[1].y - lineSeg[0].y; + lineSeg[2].z = lineSeg[1].z - lineSeg[0].z; - temp = DOTXYZ(vec[2], vec[0]); + temp = DOTXYZ(lineSeg[2], lineSeg[0]); - if ((DOTXYZ(vec[2], vec[1]) * temp) < 0.0f) { - temp = -temp / (SQ(vec[2].x) + SQ(vec[2].y) + SQ(vec[2].z)); + /** + * | | + * | | + * | | + * A ----------------- B + * | | + * | | + * | | + * This condition uses dot products to check to see that `hearPos` is contained within the above region + * i.e. The closest point on line AB must be between A & B + */ + if ((DOTXYZ(lineSeg[2], lineSeg[1]) * temp) < 0.0f) { + temp = -temp / SQXYZ(lineSeg[2]); - arg3->x = (vec[2].x * temp) + arg0->x; - arg3->y = (vec[2].y * temp) + arg0->y; - arg3->z = (vec[2].z * temp) + arg0->z; + // Closest point to hearPos contained on line segment A-B + newSoundPos->x = (lineSeg[2].x * temp) + pointA->x; + newSoundPos->y = (lineSeg[2].y * temp) + pointA->y; + newSoundPos->z = (lineSeg[2].z * temp) + pointA->z; return true; } @@ -93,70 +114,78 @@ s32 func_80AE6A54(Vec3f* arg0, Vec3f* arg1, Vec3f* arg2, Vec3f* arg3) { */ s32 EnRiverSound_GetSoundPos(Vec3s* points, s32 numPoints, Vec3f* hearPos, Vec3f* soundPos) { s32 i; - s32 pointIdx; - s32 sp78[2] = { 0, 0 }; - Vec3f pointLoc; - Vec3f sp60; - Vec3f sp54; - Vec3f vec; - f32 pointDist = 10000.0f; - Vec3s* point; + s32 closestPointIdx; + s32 useAdjacentPoints[2] = { + false, // use previous point + false, // use next point + }; + Vec3f closestPointPos; + Vec3f nextLineSegClosestPos; + Vec3f prevLineSegClosestPos; + Vec3f point; + f32 closestPointDist = 10000.0f; + Vec3s* closestPoint; for (i = 0; i < numPoints; i++) { f32 dist; - vec.x = points[i].x; - vec.y = points[i].y; - vec.z = points[i].z; - dist = Math_Vec3f_DistXYZ(hearPos, &vec); + point.x = points[i].x; + point.y = points[i].y; + point.z = points[i].z; + dist = Math_Vec3f_DistXYZ(hearPos, &point); - if (dist < pointDist) { - pointDist = dist; - pointIdx = i; + if (dist < closestPointDist) { + closestPointDist = dist; + closestPointIdx = i; } } - if (pointDist >= 10000.0f) { + if (closestPointDist >= 10000.0f) { return false; } - point = &points[pointIdx]; - pointLoc.x = point->x; - pointLoc.y = point->y; - pointLoc.z = point->z; + closestPoint = &points[closestPointIdx]; + closestPointPos.x = closestPoint->x; + closestPointPos.y = closestPoint->y; + closestPointPos.z = closestPoint->z; - if (pointIdx != 0) { - vec.x = point[-1].x; - vec.y = point[-1].y; - vec.z = point[-1].z; - sp78[0] = func_80AE6A54(&vec, &pointLoc, hearPos, &sp54); + // point on path before closest point + if (closestPointIdx != 0) { + point.x = closestPoint[-1].x; + point.y = closestPoint[-1].y; + point.z = closestPoint[-1].z; + useAdjacentPoints[0] = + EnRiverSound_FindClosestPointOnLineSegment(&point, &closestPointPos, hearPos, &prevLineSegClosestPos); } - if (pointIdx + 1 != numPoints) { - vec.x = point[1].x; - vec.y = point[1].y; - vec.z = point[1].z; - sp78[1] = func_80AE6A54(&pointLoc, &vec, hearPos, &sp60); + // point on path after closest point + if (closestPointIdx + 1 != numPoints) { + point.x = closestPoint[1].x; + point.y = closestPoint[1].y; + point.z = closestPoint[1].z; + useAdjacentPoints[1] = + EnRiverSound_FindClosestPointOnLineSegment(&closestPointPos, &point, hearPos, &nextLineSegClosestPos); } - if (sp78[0] && sp78[1]) { - if (!func_80AE6A54(&sp54, &sp60, hearPos, soundPos)) { - soundPos->x = (sp54.x + sp60.x) * 0.5f; - soundPos->y = (sp54.y + sp60.y) * 0.5f; - soundPos->z = (sp54.z + sp60.z) * 0.5f; + if (useAdjacentPoints[0] && useAdjacentPoints[1]) { + if (!EnRiverSound_FindClosestPointOnLineSegment(&prevLineSegClosestPos, &nextLineSegClosestPos, hearPos, + soundPos)) { + soundPos->x = (prevLineSegClosestPos.x + nextLineSegClosestPos.x) * 0.5f; + soundPos->y = (prevLineSegClosestPos.y + nextLineSegClosestPos.y) * 0.5f; + soundPos->z = (prevLineSegClosestPos.z + nextLineSegClosestPos.z) * 0.5f; } - } else if (sp78[0]) { - soundPos->x = sp54.x; - soundPos->y = sp54.y; - soundPos->z = sp54.z; - } else if (sp78[1]) { - soundPos->x = sp60.x; - soundPos->y = sp60.y; - soundPos->z = sp60.z; + } else if (useAdjacentPoints[0]) { + soundPos->x = prevLineSegClosestPos.x; + soundPos->y = prevLineSegClosestPos.y; + soundPos->z = prevLineSegClosestPos.z; + } else if (useAdjacentPoints[1]) { + soundPos->x = nextLineSegClosestPos.x; + soundPos->y = nextLineSegClosestPos.y; + soundPos->z = nextLineSegClosestPos.z; } else { - soundPos->x = pointLoc.x; - soundPos->y = pointLoc.y; - soundPos->z = pointLoc.z; + soundPos->x = closestPointPos.x; + soundPos->y = closestPointPos.y; + soundPos->z = closestPointPos.z; } return true; @@ -167,35 +196,37 @@ void EnRiverSound_Update(Actor* thisx, GlobalContext* globalCtx) { Vec3f* pos; Player* player = GET_PLAYER(globalCtx); EnRiverSound* this = (EnRiverSound*)thisx; - s32 sp34; + s32 bgId; - if ((thisx->params == RS_UNK_0) || (thisx->params == RS_UNK_4) || (thisx->params == RS_UNK_5)) { + if ((thisx->params == RS_RIVER_DEFAULT_LOW_FREQ) || (thisx->params == RS_RIVER_DEFAULT_MEDIUM_FREQ) || + (thisx->params == RS_RIVER_DEFAULT_HIGH_FREQ)) { path = &globalCtx->setupPathList[this->pathIndex]; pos = &thisx->world.pos; if (EnRiverSound_GetSoundPos(SEGMENTED_TO_VIRTUAL(path->points), path->count, &player->actor.world.pos, pos)) { - if (BgCheck_EntityRaycastFloor4(&globalCtx->colCtx, &thisx->floorPoly, &sp34, thisx, pos) != + if (BgCheck_EntityRaycastFloor4(&globalCtx->colCtx, &thisx->floorPoly, &bgId, thisx, pos) != BGCHECK_Y_MIN) { - // Get the sound volume pitch based on the speed of the river current under the actor - this->soundPitchIndex = SurfaceType_GetConveyorSpeed(&globalCtx->colCtx, thisx->floorPoly, sp34); + // Get the river sfx frequency based on the speed of the river current under the actor + this->soundFreqIndex = SurfaceType_GetConveyorSpeed(&globalCtx->colCtx, thisx->floorPoly, bgId); } else { - this->soundPitchIndex = 0; + this->soundFreqIndex = 0; } - if (this->soundPitchIndex == 0) { - if (thisx->params == RS_UNK_4) { - this->soundPitchIndex = 0; - } else if (thisx->params == RS_UNK_0) { - this->soundPitchIndex = 1; + if (this->soundFreqIndex == 0) { + if (thisx->params == RS_RIVER_DEFAULT_MEDIUM_FREQ) { + this->soundFreqIndex = 0; + } else if (thisx->params == RS_RIVER_DEFAULT_LOW_FREQ) { + this->soundFreqIndex = 1; } else { - this->soundPitchIndex = 2; + // RS_RIVER_DEFAULT_HIGH_FREQ + this->soundFreqIndex = 2; } } else { - this->soundPitchIndex--; - this->soundPitchIndex = CLAMP_MAX(this->soundPitchIndex, 2); + this->soundFreqIndex--; + this->soundFreqIndex = CLAMP_MAX(this->soundFreqIndex, 2); } } - } else if ((thisx->params == RS_UNK_13) || (thisx->params == RS_UNK_19)) { + } else if ((thisx->params == RS_GORON_CITY_SARIAS_SONG) || (thisx->params == RS_GREAT_FAIRY)) { func_8002DBD0(&player->actor, &thisx->home.pos, &thisx->world.pos); } else if (globalCtx->sceneNum == SCENE_DDAN_BOSS && Flags_GetClear(globalCtx, thisx->room)) { Actor_Kill(thisx); @@ -227,26 +258,37 @@ void EnRiverSound_Draw(Actor* thisx, GlobalContext* globalCtx) { NA_SE_EV_TORCH - SFX_FLAG, NA_SE_EV_COW_CRY_LV - SFX_FLAG, }; - static f32 soundPitch[] = { 0.7f, 1.0f, 1.4f }; + static f32 soundFreq[] = { 0.7f, 1.0f, 1.4f }; EnRiverSound* this = (EnRiverSound*)thisx; if (!(this->playSound)) { this->playSound = true; - } else if ((this->actor.params == RS_UNK_0) || (this->actor.params == RS_UNK_4) || - (this->actor.params == RS_UNK_5)) { - Audio_PlaySoundRiver(&this->actor.projectedPos, soundPitch[this->soundPitchIndex]); - } else if (this->actor.params == RS_UNK_11) { - func_800F4A54(90); - } else if (this->actor.params == RS_SARIAS_SONG) { + } else if ((this->actor.params == RS_RIVER_DEFAULT_LOW_FREQ) || + (this->actor.params == RS_RIVER_DEFAULT_MEDIUM_FREQ) || + (this->actor.params == RS_RIVER_DEFAULT_HIGH_FREQ)) { + Audio_PlaySoundRiver(&this->actor.projectedPos, soundFreq[this->soundFreqIndex]); + } else if (this->actor.params == RS_LOWER_MAIN_BGM_VOLUME) { + // Responsible for lowering market bgm in Child Market Entrance and Child Market Back Alley + // Lower volume from default 127 to a volume of 90 + Audio_LowerMainBgmVolume(90); + } else if (this->actor.params == RS_LOST_WOODS_SARIAS_SONG) { + // Play Sarias Song at the next correct Lost Woods path to Sacred Forest Meadow + // Volume depends on distance to source func_800F4E30(&this->actor.projectedPos, this->actor.xzDistToPlayer); - } else if (this->actor.params == RS_UNK_13) { + } else if (this->actor.params == RS_GORON_CITY_SARIAS_SONG) { + // Play Sarias Song in Goron City at the entrance to lost woods + // Volume depends on distance to source Audio_PlaySariaBgm(&this->actor.home.pos, NA_BGM_SARIA_THEME, 1000); - } else if (this->actor.params == RS_UNK_19) { + } else if (this->actor.params == RS_GREAT_FAIRY) { + // Play the Great Fairy Song inside the fairy fountain + // Volume depends on distance to source Audio_PlaySariaBgm(&this->actor.home.pos, NA_BGM_GREAT_FAIRY, 800); } else if ((this->actor.params == RS_SANDSTORM) || (this->actor.params == RS_CHAMBER_OF_SAGES_1) || (this->actor.params == RS_CHAMBER_OF_SAGES_2) || (this->actor.params == RS_RUMBLING)) { + // Play sfx in the fixed center of the screen func_800788CC(soundEffects[this->actor.params]); } else { + // Play sfx at the location of riverSounds projected position Audio_PlayActorSound2(&this->actor, soundEffects[this->actor.params]); } } diff --git a/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.h b/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.h index 48cdec740a..2af5ab9ac8 100644 --- a/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.h +++ b/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.h @@ -9,35 +9,42 @@ struct EnRiverSound; typedef struct EnRiverSound { /* 0x0000 */ Actor actor; /* 0x014C */ u8 playSound; - /* 0x014D */ u8 soundPitchIndex; + /* 0x014D */ u8 soundFreqIndex; /* 0x014E */ s16 pathIndex; } EnRiverSound; // size = 0x0150 typedef enum { - /* 0x00 */ RS_UNK_0, + /* 0x00 */ RS_RIVER_DEFAULT_LOW_FREQ, /* 0x01 */ RS_SMALL_WATERFALL, /* 0x02 */ RS_LAVA_BUBBLES_1, /* 0x03 */ RS_LARGE_WATERFALL, - /* 0x04 */ RS_UNK_4, - /* 0x05 */ RS_UNK_5, + /* 0x04 */ RS_RIVER_DEFAULT_MEDIUM_FREQ, + /* 0x05 */ RS_RIVER_DEFAULT_HIGH_FREQ, /* 0x06 */ RS_LAVA_BUBBLES_2, /* 0x07 */ RS_LAVA_BUBBLES_3, /* 0x08 */ RS_DRIPPING_WATER, /* 0x09 */ RS_FOUNTAIN_WATER, /* 0x0A */ RS_MARKET_CROWD, - /* 0x0B */ RS_UNK_11, - /* 0x0C */ RS_SARIAS_SONG, - /* 0x0D */ RS_UNK_13, + /* 0x0B */ RS_LOWER_MAIN_BGM_VOLUME, + /* 0x0C */ RS_LOST_WOODS_SARIAS_SONG, + /* 0x0D */ RS_GORON_CITY_SARIAS_SONG, /* 0x0E */ RS_SANDSTORM, /* 0x0F */ RS_LAKESIDE_LAB_TANK, /* 0x10 */ RS_CHAMBER_OF_SAGES_1, /* 0x11 */ RS_CHAMBER_OF_SAGES_2, /* 0x12 */ RS_RUMBLING, - /* 0x13 */ RS_UNK_19, + /* 0x13 */ RS_GREAT_FAIRY, /* 0x14 */ RS_TORCH_CRACKLING, /* 0x15 */ RS_COW_MOOING, - /* 0xF7 */ RS_UNK_F7 = 0xF7, - /* 0xF8 */ RS_MAX + /* 0xF7 */ RS_NATURE_AMBIENCE = 0xF7, + /* 0xF8 */ RS_GANON_TOWER_0, // Ganondorf's Lair + /* 0xF9 */ RS_GANON_TOWER_1, // Top of Ganon's Tower + /* 0xFA */ RS_GANON_TOWER_2, + /* 0xFB */ RS_GANON_TOWER_3, + /* 0xFC */ RS_GANON_TOWER_4, + /* 0xFD */ RS_GANON_TOWER_5, + /* 0xFE */ RS_GANON_TOWER_6, + /* 0xFF */ RS_GANON_TOWER_7 // Bottom of Ganon's Tower } RiverSoundType; #endif