Three related observations in WrapAsAUV2::Render() (src/wrapasauv2.cpp), collected while fixing AUV2-1 in the 0.16 release review. Grouped because they all concern the same function.
1. A host passing action flags gets silence
Render() gates on if (_initialized && (inFlags == 0)). AUV2-1 added an else branch that zeroes the output and raises kAudioUnitRenderAction_OutputIsSilence — which fixed the stale-audio bug, but it also means a host passing e.g. kAudioUnitRenderAction_DoNotCheckRenderArgs is now silently muted rather than silently stale.
Arguably still wrong: those flags do not mean "do not process". There is an assert(inFlags == 0) at the top of the function recording the expectation that no host does this, but an assert is not a plan for release builds.
Suggested fix: decide which flags are genuinely incompatible with processing and handle the rest normally, rather than treating any non-zero inFlags as unrenderable.
2. OutputIsSilence can leak in from upstream
ProcessData::flags is a reference passed through to PullInput. An upstream unit setting kAudioUnitRenderAction_OutputIsSilence on its own output can therefore surface as this wrapper's output flag, telling the host the plugin produced silence when it did not — a synth fed by a silent input bus, for instance.
Suggested fix: take a local copy of the flags for the input pull and set the wrapper's own output flag deliberately.
3. The render thread spins on a lock the main thread can hold indefinitely
(This is AUV2-3 from the review.) Render() spins on _processLock, and onIdle() can hold that lock across clap_plugin_params.flush() — plugin code of unbounded duration. If the main thread is preempted while holding it, the render thread spins a whole scheduler quantum.
Scenario: Logic idles a track for more than three blocks, onIdle() starts a flush, the user presses play at that moment.
Suggested fix: try_lock in Render() and skip-and-zero on failure, rather than a blocking spin. AUV2-1 already added a correct "produce silence" path this can reuse.
Notes
macOS-only; none of this was compiled or run here.
Part of the 0.16 review: https://claude.ai/code/artifact/2852de97-bdd0-4364-8c89-6892776b03d5
Three related observations in
WrapAsAUV2::Render()(src/wrapasauv2.cpp), collected while fixing AUV2-1 in the 0.16 release review. Grouped because they all concern the same function.1. A host passing action flags gets silence
Render()gates onif (_initialized && (inFlags == 0)). AUV2-1 added anelsebranch that zeroes the output and raiseskAudioUnitRenderAction_OutputIsSilence— which fixed the stale-audio bug, but it also means a host passing e.g.kAudioUnitRenderAction_DoNotCheckRenderArgsis now silently muted rather than silently stale.Arguably still wrong: those flags do not mean "do not process". There is an
assert(inFlags == 0)at the top of the function recording the expectation that no host does this, but an assert is not a plan for release builds.Suggested fix: decide which flags are genuinely incompatible with processing and handle the rest normally, rather than treating any non-zero
inFlagsas unrenderable.2.
OutputIsSilencecan leak in from upstreamProcessData::flagsis a reference passed through toPullInput. An upstream unit settingkAudioUnitRenderAction_OutputIsSilenceon its own output can therefore surface as this wrapper's output flag, telling the host the plugin produced silence when it did not — a synth fed by a silent input bus, for instance.Suggested fix: take a local copy of the flags for the input pull and set the wrapper's own output flag deliberately.
3. The render thread spins on a lock the main thread can hold indefinitely
(This is AUV2-3 from the review.)
Render()spins on_processLock, andonIdle()can hold that lock acrossclap_plugin_params.flush()— plugin code of unbounded duration. If the main thread is preempted while holding it, the render thread spins a whole scheduler quantum.Scenario: Logic idles a track for more than three blocks,
onIdle()starts a flush, the user presses play at that moment.Suggested fix:
try_lockinRender()and skip-and-zero on failure, rather than a blocking spin. AUV2-1 already added a correct "produce silence" path this can reuse.Notes
macOS-only; none of this was compiled or run here.
Part of the 0.16 review: https://claude.ai/code/artifact/2852de97-bdd0-4364-8c89-6892776b03d5