fix: use Hermite interpolation at loop boundaries to eliminate clicks#1055
Open
mvanhoolwerff wants to merge 1 commit intosoftware-mansion:mainfrom
Open
fix: use Hermite interpolation at loop boundaries to eliminate clicks#1055mvanhoolwerff wants to merge 1 commit intosoftware-mansion:mainfrom
mvanhoolwerff wants to merge 1 commit intosoftware-mansion:mainfrom
Conversation
When playbackRate != 1.0, AudioBufferSourceNode uses the interpolation path for sample playback. At the loop boundary, linear interpolation between the last and first frame creates an audible click because it only ensures value (C0) continuity — the slope can change abruptly. This replaces linear interpolation with 4-point Hermite spline interpolation for looping sources. Hermite ensures both value AND slope (C1) continuity at the loop point, eliminating the click artifact. The fix wraps sample indices correctly through the loop boundary so all 4 points are always valid. Non-looping sources continue to use linear interpolation (no behavior change). Reproducer: play any AudioBufferSourceNode with loop=true and playbackRate=0.8 or 1.2 — audible periodic click at each loop cycle. With this fix, the loop is smooth.
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.
Summary
When
playbackRate != 1.0,AudioBufferSourceNodeuses the interpolation path for sample playback. At the loop boundary, linear interpolation between the last and first frame creates an audible click because it only ensures value (C0) continuity — the slope can change abruptly.This replaces linear interpolation with 4-point Hermite spline interpolation for looping sources. Hermite ensures both value AND slope (C1) continuity at the loop point, eliminating the click artifact.
Changes
AudioUtils.hpp: AddedhermiteInterpolate()function using cubic Hermite spline with 4 sample pointsAudioBufferSourceNode.cpp:processWithInterpolation()now uses Hermite interpolation with proper loop-wrapping for looping sources. Non-looping sources continue to use linear interpolation (no behavior change).Reproducer
AudioBufferSourceNodewithloop = trueplaybackRateto anything other than1.0(e.g.,0.8or1.2)With this fix, the loop is smooth at any playback rate.
Why Hermite?
At the loop boundary, the interpolation reads
source[lastFrame]andsource[firstFrame]. Even if these values are identical, the slope (derivative) at the boundary can jump — the waveform might be going down at the end and up at the start. Linear interpolation produces a sharp "kink" that's audible as a click.Hermite uses 4 surrounding samples to estimate the slope, producing a smooth curve through the boundary. The wrap function ensures all 4 indices are valid across the loop point.
Test plan
loop=trueandplaybackRate=0.8loop=trueandplaybackRate=1.2playbackRate=1.0still uses the cleanprocessWithoutInterpolationpath🤖 Generated with Claude Code