Skip to content

Scale enemy bgm to the current distance when it starts - #7115

Closed
bassdr wants to merge 1 commit into
HarbourMasters:developfrom
bassdr:fix/enemy-bgm-stale-volume
Closed

Scale enemy bgm to the current distance when it starts#7115
bassdr wants to merge 1 commit into
HarbourMasters:developfrom
bassdr:fix/enemy-bgm-stale-volume

Conversation

@bassdr

@bassdr bassdr commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Fixes #5706.

Enemy bgm starts at the volume of the previous encounter.

Every frame an enemy is within range, z_player.c calls Audio_SetBgmEnemyVolume() and then Audio_SetSequenceMode(). The first records the distance unconditionally but only rescales while enemy bgm is already playing:

if (sPrevSeqMode == (0x80 | SEQ_MODE_ENEMY)) {
    if (dist != sAudioEnemyDist) { ...rescale... }
}
sAudioEnemyDist = dist;

On the frame enemy mode begins, sPrevSeqMode is still the old mode, so it stores the new distance and returns without touching sAudioEnemyVol. Audio_SetSequenceMode() then runs its crossfade against a value that belongs to the last encounter. It also never corrects itself if nothing moves afterwards, because the rescale is guarded on the distance having changed.

Both directions are audible. Entering far from an enemy after an encounter that ended close, the area music is ducked to zero while the enemy bgm fades in loud and then straight back down to nothing - the area goes quiet with nothing replacing it, which is what #5706 describes. Entering next to an enemy after one that ended far, the enemy bgm starts inaudible.

Reproduction. Instrumented build logging the distance, the volume in use, and the volume that distance actually calls for:

before   ENTER dist=0   inUse=2  forThisDistance=127  -> enemy=2  area=125
after    ENTER dist=495 inUse=1  forThisDistance=1    -> enemy=1  area=126

The first is an enemy spawned on top of the player right after an encounter that ended 494 units away: adjacent enemy, enemy bgm at 2/127. The second is the reported case - an enemy picked up at 495 units, where the previous encounter had ended at full volume; before the change that entry used 127, silencing the area music.

Behind a switch. This is original game behaviour, not a port regression, so the rescale sits behind FixEnemyBgmVolume under Enhancements -> Fixes, off by default. Lifting the curve into a helper is unconditional, since it changes nothing on its own.

It is easiest to notice with a custom music pack, because each track is a single streamed channel, so a player scaled to zero goes silent rather than merely thinning out. Nothing about the bug is specific to custom sequences.

Thanks @lankv2 for the log that pinned this down.

Build Artifacts

…s#5706)

Enemy bgm starts at the wrong volume because sAudioEnemyVol still holds
whatever the previous encounter ended on.

Every frame an enemy is in range, the player calls Audio_SetBgmEnemyVolume()
and then Audio_SetSequenceMode(). The first records the distance
unconditionally but only rescales while enemy bgm is already playing, so on
the frame enemy mode begins it stores the new distance and returns without
touching the volume. Audio_SetSequenceMode() then crossfades using the old
one.

Both directions are audible. Entering far from an enemy after an encounter
that ended close, the area music is ducked to zero and the enemy bgm fades
in loud and then straight back down to nothing - the area goes quiet with
nothing replacing it. Entering next to an enemy after one that ended far,
the enemy bgm starts inaudible. It corrects itself once the distance
changes, and never corrects at all while both stand still, since the
rescale is guarded on the distance having moved.

This is original game behaviour rather than a port regression, so the
rescale sits behind FixEnemyBgmVolume, off by default.

The curve moves to a helper so both callers share it.
@bassdr
bassdr force-pushed the fix/enemy-bgm-stale-volume branch from ece6c22 to 5ce2295 Compare August 24, 2026 15:21
@bassdr

bassdr commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Closing this: tested by ear and the effect is not audible, so the checkbox would promise something it does not deliver.

What was tested. Kid, Hyrule Field at night, Stalchild encounters, toggling FixEnemyBgmVolume between runs: trigger the encounter, walk away until the enemy bgm is gone, let the next Stalchild appear, listen to the fade-in. Repeated several times with the option on and off. The difference is at most a slightly different fade-in shape.

Why. The stale sAudioEnemyVol only survives one frame. Audio_SetBgmEnemyVolume() recomputes it on the next frame whenever dist != sAudioEnemyDist and re-issues Audio_SetVolScale(SEQ_PLAYER_BGM_SUB, 3, sAudioEnemyVol, 10), so with either the player or the enemy moving - i.e. always, in practice - the correct volume lands before the wrong one is audible. What is left is a marginally different fade curve. The stale value would only persist if the distance stopped changing entirely.

The description here claimed more than that. I confirmed the mechanism with logging but never checked how long the wrong value survives, which is the part that decides whether it matters.

There is one case with a real audible symptom: sAudioEnemyVol is initialised to 127, so on the first encounter of a session the main bgm is ducked to 0x7F - 127 = 0 for a frame. If that first encounter starts at long range the field music dips briefly before recovering. That is once per session and one frame long, which does not justify a decomp change plus a user-facing option.

Not worth the cost, so dropping it rather than leaving it open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Custom Audio: Battle music playback issues

1 participant