Add opt-in "snap loops to zero-crossings" processing option#162
Open
douglas-carmichael wants to merge 1 commit into
Open
Add opt-in "snap loops to zero-crossings" processing option#162douglas-carmichael wants to merge 1 commit into
douglas-carmichael wants to merge 1 commit into
Conversation
Some sample libraries ship forward loops whose start and end land on
non-matching sample values, so the loop audibly clicks at the wrap-around
on every repeat (common with auto-sampled instruments whose loop was not
designed to be click-free). This adds a processing option that moves both
loop boundaries to a nearby zero-crossing so the loop end and start meet
near zero, removing the click without resampling the audio - only the
stored loop positions change.
The adjustment is conservative: it only touches forward loops, leaves
very short (single-cycle) loops untouched so their pitch is unchanged,
moves a boundary by at most an eighth of the loop length (capped at 512
frames), and only applies when it actually reduces the discontinuity at
the wrap. A loop end of -1 ("loop to sample end") is materialised to an
explicit zero-crossing when snapping helps.
Enabled with the "Snap loops to zero-crossings" check-box in the
processing dialog or -Zs on the command line; off by default.
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
Adds an opt-in Snap loops to zero-crossings processing option.
Some sample libraries ship forward loops whose start and end land on non-matching sample values, so the loop audibly clicks at the wrap-around on every repeat. This is common with auto-sampled instruments whose loop was not designed to be click-free — they rely on the host applying a cross-fade at play time. When the destination format has no loop cross-fade (and none is baked), that click is exported as-is.
This option moves both loop boundaries to a nearby rising zero-crossing so the loop end and start meet near zero, removing the click without resampling the audio — only the stored loop positions change. It complements the existing Set fixed loop-crossfade option (which bakes a cross-fade) for the cases where you would rather not alter the audio at all.
How it works
A new
core/algorithm/LoopZeroSnapperdecodes each zone to a mono mix and, for every forward loop, searches a small window around the existing start and end for the nearest rising zero-crossing. It is deliberately conservative:< 4096frames);-1("loop to sample end") is materialised to an explicit zero-crossing only when snapping helps.It runs after the existing resample / bit-depth stage in
ConverterBackend.processSamples, so it always sees the final audio.Wiring
ProcessingDialog/MainFrame), persisted like the other processing options.-Zs(gated by-Ze, like the others).DetectSettings.snapLoopsToZero+needsProcessing()gate.Example
A real 12-zone Synthstrom Deluge pad whose loops wrap with an audible step. The numbers below are the absolute sample-value jump at each loop wrap, measured on the source audio, before and after enabling the option (16-bit samples, full scale 32768):
11 of 12 loops improved (−79% total); the C4 zone is left exactly as it was, because no nearby crossing reduced its jump — the conservative guard in action. No loop is ever made worse.
Notes
Happy to adjust the naming, the window / threshold constants, or move the algorithm elsewhere if you'd prefer.