Apply pre-render object positions and head rotation from the first frame - #24
Open
trsonic wants to merge 2 commits into
Open
Apply pre-render object positions and head rotation from the first frame#24trsonic wants to merge 2 commits into
trsonic wants to merge 2 commits into
Conversation
An object source is registered with the ambisonic encoder at its default position (azimuth 0, elevation 0, distance 1) as soon as the audio element is added. A position update arriving before the first render call therefore only moved the ramp target, and the first processed block audibly glided the object from front-center to its configured position. Loudspeaker rendering (OLR) applies pre-render metadata immediately, so binaural output disagreed with loudspeaker output over the first block. Track whether the encoder has processed any audio yet; until it has, SetSource() snaps the current parameters to the new target instead of scheduling a ramp. There is no previously audible position to interpolate from, so metadata applied before the first render now takes effect from the first frame, matching OLR. Updates arriving after audio has been rendered still ramp across one block to avoid clicks. Reported upstream as #21.
The ambisonic rotator's current rotation starts at identity and only the target rotation is supplied per Process() call, so a head pose set before the first render call made the whole scene slerp from identity to that pose across the first processed block. Apply the same rule as for object positions: until any audio has been rendered there is no previously audible rotation to interpolate from, so the first processed block applies the target rotation in full from the first frame. Rotation changes after audio has been rendered still slerp across the block in 32-frame intervals. Blocks rendered with head tracking disabled bypass the rotator but are audible at the identity rotation, so the processing group marks them via MarkAudioRendered(); enabling head tracking with a stored pose after such blocks still slerps instead of snapping.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #21.
Problem
As analyzed in #21, OLR and OBR disagree on metadata applied before the first render call. When an audio element is added, OBR registers each object source with the ambisonic encoder at the default position (azimuth 0, elevation 0, distance 1). A position update arriving before the first
Process()call only moves the ramp target, so the first rendered block audibly glides the object from front-center to its configured position. OLR applies pre-render metadata immediately, so loudspeaker and binaural output differ over the first block. The same pattern exists in the ambisonic rotator: a head pose set before the first render slerps in from identity.Fix
Until a component has rendered any audio there is no previously audible state to interpolate from, so updates snap instead of scheduling a ramp:
AmbisonicEncodertracks whether it has processed a block; while it hasn't,SetSource()setscurrentalong withtarget. This covers every pre-render update path (object channels, loudspeaker-channel positions, gains) since they all funnel throughSetSource().AmbisonicRotatordoes the same for the target rotation on its first processed block.ProcessingGroupmarks them viaMarkAudioRendered(); enabling head tracking with a stored pose after such blocks still slerps instead of snapping.Updates arriving after audio has been rendered still ramp/slerp across one block to avoid clicks, and mid-stream update semantics are unchanged.
Tests
AmbisonicEncoderTest.PreRenderPositionUpdateTakesEffectImmediately— reproduces the Question: Initial object position OLR vs OBR #21 glide on unfixed code (frame 0 carries the front-position coefficients instead of the configured position).AmbisonicEncoderTest.PostRenderPositionUpdateRampsAcrossBlock— guards the click-avoidance ramp after audio has flowed.AmbisonicRotatorTest.FirstProcessedBlockAppliesTargetRotationInFull,RotationAfterBypassedBlocksStillSlerps,RotationChangeAfterFirstBlockStillSlerps— same contract for the rotator, including the head-tracking-disabled case.Each "first block" test fails without its fix; the existing encoder and rotator tests pass unchanged.