testhost: prove the actual chunk-based state path via raw VST2 dispatcher

Add Vst2RawChunk, a raw effGetChunk/effSetChunk bypass around JUCE's
VSTPluginInstance::usesChunks() gate, plus --loadBankChunk/--saveBankChunk/
--loadPatchChunk/--savePatchChunk CLI flags and a new test_chunk_roundtrip
regression test asserting the saved file is genuinely zlib/XML (0x78 header,
>1000 bytes), not a per-parameter fallback.

Building and using this bypass disproved an earlier documented finding: the
compiled VST2 wrapper does set effFlagsProgramChunks and usesChunks() is
genuinely true, so the previous "chunk-advertisement gap" theory in TODO.md
and tests/README.md was wrong. Corrected in both places. The real cause of
old bundled .fxp sample files having no effect remains open and is now
narrowed to a JaySynth-side XML/schema parsing question, not a host/plugin
capability mismatch.

Also adds a PluginHost-method-to-VST2-wiring-to-test coverage table in
tests/README.md, and documents the remaining "exercised but not asserted"
gaps (channel/param counts, DSP correctness) in TODO.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011dhtwRLARk4eiPngcQykLJ
This commit is contained in:
2026-07-27 21:22:24 +02:00
co-authored by Claude Sonnet 5
parent 2a0ea726f3
commit 8194bda9c8
7 changed files with 363 additions and 58 deletions
+32 -16
View File
@@ -44,25 +44,41 @@ verified (PR https://git.jayfield.org/jens/JaySynth/pulls/1).
`noteOn` with no matching `noteOff`) is untested.
- [ ] **Polyphony/multiple simultaneous notes untested** - only ever a single
held note in all smoke tests so far.
- [ ] **`tests/run_tests.sh` never asserts specific expected values for
`PluginHost::load()`/`getNumInputChannels()`/`getNumOutputChannels()`/
`getNumParameters()`** - every test exercises them (they're printed in
the load banner), but nothing pins e.g. "JaySynth must report exactly
0 in / 2 out / 140 parameters," so a regression there would only be
caught if it also broke something else. Same underlying gap as "no
automated regression baseline comparison" above, just called out
separately since it's about the load-time metadata rather than the
rendered audio. See `tests/README.md`'s `PluginHost` coverage table.
## Investigate
- [ ] **JaySynth's compiled VST2 wrapper never advertises chunk support to
the host, so real `.fxp`/`.fxb` sample files silently have no effect when
loaded generically.** Found while building `tests/run_tests.sh`: loading
a bundled sample under `extras/sounds/` via `--patch` produces byte-
identical output to not loading anything (confirmed by diffing
`--printParams`). The files are legitimately in VST2's opaque-chunk
("FPCh") format, but JUCE 3.1.1's plugin-side VST wrapper
(`juce_VST_Wrapper.cpp`, compiled into `JaySynth.so`) never sets
`effFlagsProgramChunks` on the `AEffect` struct, so JUCE's own host-side
`VSTPluginInstance::usesChunks()` returns false and silently no-ops both
load and save. Not one of the tracked `TODO.md` (repo root) findings, and
not attempted here - fixing it means patching JUCE's own VST wrapper,
a bigger and riskier change than this pass's scope. See
`tests/README.md` for the full writeup; `tests/run_tests.sh`'s round-trip
tests work around it by using `testhost`'s own save output as the
fixture instead of an external sample file.
- [ ] **Bundled sample `.fxp` files under `extras/sounds/` silently have no
effect when loaded via `--patch`** (confirmed by diffing `--printParams`
output with and without `--patch` - zero parameters differ), even though
loading doesn't crash. **Correction**: an earlier version of this entry
claimed this was because JaySynth's compiled VST2 wrapper never sets
`effFlagsProgramChunks`, so JUCE's host-side `usesChunks()` would see
false and skip the chunk mechanism entirely. That diagnosis was wrong -
disproved directly: `--saveBank`/`--savePatch` (the exact same generic
`AudioProcessor::getStateInformation` path) produce real `FBCh`/`FPCh`-
magic, GZIP-compressed-XML files (confirmed via hex dump and by feeding
the raw inner chunk bytes straight to `effSetChunk` via the new
`Vst2RawChunk` bypass, added specifically to rule this out - still no
effect). So `usesChunks()` genuinely is true, and `test_chunk_roundtrip`
in `tests/run_tests.sh` proves the real `bankEncodeXml`/`bankDecodeXml`
path round-trips correctly for files this build produces. The actual
cause of the *external* sample files failing is still unidentified -
most likely those specific (10+ year old) files use a compression or
XML-schema shape that `JaySynthAudioProcessor::setCurrentProgramState-
Information`/`getXmlFromBinary` no longer parses, not a host/plugin
capability mismatch. Not one of the tracked repo-root `TODO.md` findings.
Worth a closer look at some point (e.g. hex-diff one of these files'
decompressed XML against what this build produces), but not chased
further here. See `tests/README.md`'s "corrected finding" note.
- [ ] **DPF-based plugins print a non-fatal assertion on load.** All three
Zam*-vst.so plugins tested (built with the DISTRHO Plugin Framework) print
`assertion failure: "fIsActive" in .../DistrhoPluginInternal.hpp` during