Skip to content

Fix processor sample position and latency units with host oversampling - #1211

Open
jiri-god wants to merge 4 commits into
kushview:mainfrom
jiri-god:fix/oversampling-sample-units
Open

jiri-god wants to merge 4 commits into
kushview:mainfrom
jiri-god:fix/oversampling-sample-units

Conversation

@jiri-god

@jiri-god jiri-god commented Oct 29, 2026 •

Copy link
Copy Markdown

With 2x host oversampling, a processor prepared at 96 kHz receives a 48 kHz sample position, and a reported 257-sample intrinsic latency is added to the parent graph as 257 samples rather than 129. This affects sample-based timing and graph delay compensation.

The conversion now lives in element::Processor, covering direct implementations (including the CLAP/native-node path) as well as AudioProcessorNode wrappers. Each processor exposes a stable playhead adapter that scales only timeInSamples by its prepared processing factor; seconds, PPQ, BPM and absent position fields are preserved. Nested graphs compose their local factors once per boundary. Multiplication is bounded to avoid signed overflow.

Intrinsic latency is stored atomically in rendering-rate samples and converted to parent-rate samples, rounding up, in Processor::getLatencySamples(). Manual delay compensation and oversampling-filter latency are already in parent-rate units and remain separate. AudioProcessorNode and ScriptNode forward the common playhead and the audio-processor wrapper reports raw plugin latency, including latency-change notifications, without a second conversion.

Validation on Apple Silicon macOS, RelWithDebInfo, JUCE 8.0.13:

The final independent branch passes all 59 CTest suites (3.42 s).

  • PluginSampleUnitsTests covers wrapped plugins, direct Processor subclasses, 1x/2x/4x/8x and returning to 1x, latency notifications, manual-delay units, cached playhead rebinding/detachment, optional position fields and integer boundaries.
  • Nested 2x graphs with 1x/2x/4x children verify both direct and wrapped processors receive the composite sample rate/position, while seconds and the source clock remain unchanged.
  • Applying the new tests to the pre-review PR revision f1e3cf3 produces 22 failures in the direct/nested cases; the original wrapped-plugin case still passes. The new direct/nested cases pass with the revision.
  • A Lua DSP regression observes the actual script position before/after reload and playhead rebinding. It reproduces four failures with the old ScriptNode forwarding override and passes with the shared clock.
  • Original regression evidence on upstream d0226686: six assertions failed, including -48000 != -96000 and 257 != 129 at 2x.

The direct-subclass test exercises the shared path used by CLAP; it is not an audition of a third-party CLAP binary. Graph compensation still uses integer samples; no fractional delay lines are introduced. Linux/Windows validation is left to CI. This remains an independent host-only change based on upstream main; no private extensions are included.

The final change also merges without conflicts with #1212–#1214; all 62 CTest suites pass together (3.34 s).

@mfisher31

Copy link
Copy Markdown
Member

Hey thanks for all the new PRs. Gonna try and get those reviewed tonight!

@mfisher31 mfisher31 left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like where this is going @jiri-god, but doing the playhead work in audioprocessornode will only affect VST, VST3, AU, and LV2 plugins. Clap implements element::Processor directly, and all internal nodes (mostly) are element::Processor's as well. The good thing is, all of the latency information you're using already exists in the base class. Should me a relatively simple move of this code up a level to the the Processor class.

@jiri-god jiri-god changed the title Fix plugin sample position and latency units with host oversampling Fix processor sample position and latency units with host oversampling Oct 30, 2026
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

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.

3 participants