Skip to content

Technical review of the plugin, with its recommended fixes and sound-design measurements - #8

Merged
codeskine merged 5 commits into
mainfrom
claude/audio-plugin-vst3-au-review-9b137d
Nov 3, 2026
Merged

codeskine merged 5 commits into
mainfrom
claude/audio-plugin-vst3-au-review-9b137d

Conversation

@codeskine

@codeskine codeskine commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

What changed

A technical review of the plugin (DSP, real-time, VST3/AU, build), the fixes it recommended, and the measurements a sound designer would want next. The report and the experiments it cites are in review/; the build and test logs were kept out of the repository.

Fixes from the review (349127c)

  • Echo start-up (D-02): the echo's delay line started at 5 s and glided towards the knob for seconds, settling up to 3 ms short of it, so the first repeats after loading (or after a NaN recovery) came late and warped. It now jumps to the knob on the first tick. New test echoStartsAtKnobTime.
  • Bypass latency (D-04): processBlockBypassed delays the input by the declared latency, so hosts at rates other than 48 kHz keep the bypassed audio aligned. New ui_test checks.
  • Parameter registry (D-03): ParameterRegistry keeps its parameters in a fixed array and runs the handlers in an explicit order, the one libc++'s unordered_map happened to give, instead of depending on the standard library's iteration order.
  • Noise generator UB (D-01): DaisySP's WhiteNoise overflowed a signed int32_t on every sample, which stopped ASan/UBSan at the first sample. It now multiplies as uint32_t: same bits. Recorded in third_party/DaisySP/PATCHES.txt.
  • Sample rate 0 (D-06): prepareToPlay clamps a placeholder rate of 0 to 48 kHz.
  • AU in CI (D-05): CI builds Drosera_AU, installs it for the runner and runs auval and pluginval on it. Passed on its first run.
  • JUCE pin (D-10): fetched by the commit hash of 8.0.9, not by the tag.

Measurements and the fix they led to (ec6e150, 0237f49, bac7cf6)

  • The Standalone's output, recorded through BlackHole, matches the engine rendering the same state (levels, partials, echo period, stereo).
  • review/2026-11-03-sound-design-measurements.md: preset levels and birth times, the MIDI pitch map with and without reverb, repeatability of a loaded state, mono compatibility, ten-minute runs at the extremes, extreme settings, and the same presets at 44.1/48/96 kHz.
  • Repeatable loading: a host hands the plugin its state after prepareToPlay, so the parameters glided from the defaults and five presets settled on a different partial (up to an octave away) depending on when the state arrived. The block after setStateInformation now takes the parameters at once; presets chosen in the window still glide. New ui_test check.
  • Manual: the MIDI tab and the known limits give the measured detuning from Reverb Mix (dry, notes 18–84 within 17 cents; at 35 % Mix, notes below 48 up to 46 cents off).

Reference renders

Rule 2 of CLAUDE.md: the echo fix changes the three reference renders with echo (p05, p06, p10) throughout, because the old one-pole never reached the knob; the seven without echo are byte-identical, which also shows the registry change alters nothing. SHA256SUMS is regenerated. tests/fixtures/state-baseline.bin is untouched.

Verification

  • voice_allocator_test, render_test (472 checks), ui_test, plugin_host_test with the baseline fixture, check_reference.sh: all pass on every commit.
  • The three suites pass under ASan + UBSan with zero reports at 349127c (before that change UBSan halted on the noise generator). Not rerun for the later commits, which add a flag, documents and tests.
  • Not run locally: pluginval and auval (CI does), Intel build.

For the reviewer

  • The echo's one-pole still settles slightly short of the knob after a knob move (inaudible, noted under D-02); snapping it would change the checksums again, so it is left as is.
  • Still for the ear: a listening pass over the 16 presets with the measurement tables at hand, MIDI phrasing, knob movement, real sources into the Resonator, the PONG's aliasing at full Drive.

Stefano Veloccia added 4 commits November 3, 2026 15:11
…d a technical review

Applies the recommended items of the review in review/2026-11-03-code-review.md:

- The echo's delay line started at 5 s and glided towards the knob for seconds,
  settling up to 3 ms short of it: it now jumps to the knob on the first tick and
  after a NaN recovery. The three reference renders with echo change, the seven
  without are byte-identical; SHA256SUMS regenerated. New test echoStartsAtKnobTime.
- processBlockBypassed delays the input by the declared latency, so hosts at
  rates other than 48 kHz keep the bypassed audio aligned. New ui_test checks.
- ParameterRegistry stores its parameters in a fixed array and runs the handlers
  in an explicit order, the one libc++'s unordered_map happened to give, instead
  of depending on the standard library's hash-map iteration.
- DaisySP WhiteNoise multiplies as uint32_t: the signed product overflowed
  (undefined behaviour) and stopped ASan/UBSan at the first sample. Same bits.
  Recorded in PATCHES.txt.
- prepareToPlay clamps a sample rate of 0 to 48 kHz.
- CI builds the AU and validates it with auval and pluginval.
- JUCE is fetched by commit hash, not by tag.

The review folder holds the report, the experiments it cites and the test logs
before and after the fixes.
20 s of the Standalone's output, taken through BlackHole at 48 kHz, compared with
the engine rendering the same restored state: levels, partials, echo period and
stereo correlation match, with no clipping or dropouts. The scripts that render
the state and compute the comparison sit with the other experiments.
Automatic measurements on the engine and on the hosted VST3: preset levels and
birth times, the MIDI pitch map with and without reverb, repeatability of a
loaded state, mono compatibility, ten-minute runs at the extremes, extreme
settings and input, and the same presets at 44.1, 48 and 96 kHz. The two
findings worth acting on: five presets settle on a different partial depending
on when the host delivers the state, and the reverb in the loop detunes MIDI
notes below 48 by up to 46 cents at 35 % mix. The measurement programs sit with
the other experiments.
…nes low notes

A host hands the plugin its state after prepareToPlay, so the parameters glided
from the defaults to the project's values. The drone is chaotic: the path taken
decided which resonance it settled on, and five presets landed on a different
partial, up to an octave away, depending on when the state arrived. The next
block after setStateInformation now takes the parameters at once, as the first
block after Init does; presets chosen in the window still glide. New ui_test
checks that a restored state jumps while a knob move still glides.

The manual's MIDI tab and known limits give the measured detuning: dry, notes
18 to 84 stay within 17 cents; at 35 % Reverb Mix, notes below 48 read up to 46
cents off.
@codeskine codeskine changed the title Fix the echo's start, bypass latency, registry order and noise UB; add a technical review Technical review of the plugin, with its recommended fixes and sound-design measurements Nov 3, 2026
The report and the measurements stay; the 600 KB of logs they cited were
evidence for the review session, not something to carry in the history.
@codeskine
codeskine merged commit 92c4880 into main Nov 3, 2026
3 checks passed
@codeskine
codeskine deleted the claude/audio-plugin-vst3-au-review-9b137d branch November 3, 2026 15:28
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.

1 participant