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
6.6 KiB
6.6 KiB
testhost TODO
Tracks known gaps and future work for tools/testhost/, the generic headless
plugin test host (see README.md for what it does and how to use it, and
/home/jens/.claude/plans/sharded-finding-tower.md for the original design
plan). Nothing here blocks current use — Phases 1-4 of the plan are done and
verified (PR #1).
Deferred by design (Phase 5 of the plan)
- LV2 plugin format support. JUCE 3.1.1 (the version currently
vendored at
sdk/juce/JUCE-3.1.1) has no LV2 hosting backend. Once JaySynth's own JUCE dependency is upgraded (or a customAudioPluginFormatsubclass is written against the current version), register it inPluginHost's constructor alongsideVSTPluginFormat- no other host code should need to change, since everything downstream talks to the format-agnosticAudioPluginInstance/AudioProcessorAPI already. - VST3/LADSPA format support. JUCE already ships
VST3PluginFormat/LADSPAPluginFormatin this same vendored version - registering them is a one-line addition toPluginHost's constructor, just not done yet since nothing has needed it. - Windows build (
Makefile.win). The plan calls for mirroringsrc/plug's Linux/Windows Makefile pattern; only the Linux side has been built and tested so far.
Test coverage gaps
- Only mono (1 in/1 out) and asymmetric (2 in/1 out) effect channel
configs have been smoke-tested (
ZamDelay-vst.so,ZamComp-vst.so,ZamEQ2-vst.so). A genuinely stereo-in/stereo-out effect hasn't been run through yet - worth doing before relying on this tool for a stereo effect plugin specifically. - No automated regression baseline comparison. The plan's stretch
goal: batch-render every
.fxp/.xmpunderextras/sounds/through a fixed note pattern and diff against stored baseline WAVs/checksums, to catch DSP or save-load regressions automatically instead of via one-off manual runs. Not built. - No CI wiring. Nothing currently runs
testhostautomatically on push/PR; it's a manual, opt-in tool for now. - No unit tests for
TestScenario's JSON parsing itself (malformed JSON, missing required fields, wrong types, out-of-range values) - only exercised indirectly via a couple of hand-written scenario files during development. Edge-case handling (e.g. a negativesample, an unterminatednoteOnwith no matchingnoteOff) is untested. - Polyphony/multiple simultaneous notes untested - only ever a single held note in all smoke tests so far.
tests/run_tests.shnever asserts specific expected values forPluginHost::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. Seetests/README.md'sPluginHostcoverage table.
Investigate
- Bundled sample
.fxpfiles underextras/sounds/silently have no effect when loaded via--patch(confirmed by diffing--printParamsoutput 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 setseffFlagsProgramChunks, so JUCE's host-sideusesChunks()would see false and skip the chunk mechanism entirely. That diagnosis was wrong - disproved directly:--saveBank/--savePatch(the exact same genericAudioProcessor::getStateInformationpath) produce realFBCh/FPCh- magic, GZIP-compressed-XML files (confirmed via hex dump and by feeding the raw inner chunk bytes straight toeffSetChunkvia the newVst2RawChunkbypass, added specifically to rule this out - still no effect). SousesChunks()genuinely is true, andtest_chunk_roundtripintests/run_tests.shproves the realbankEncodeXml/bankDecodeXmlpath 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 thatJaySynthAudioProcessor::setCurrentProgramState- Information/getXmlFromBinaryno longer parses, not a host/plugin capability mismatch. Not one of the tracked repo-rootTODO.mdfindings. 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. Seetests/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.hppduringPluginHost::load(), despite JUCE'sVSTPluginInstance::prepareToPlayalready sendingeffMainsChanged/effStartProcess. Rendering still completes correctly (confirmed via WAV output), so this looks like a DPF/JUCE VST2 lifecycle-ordering quirk rather than a testhost bug, but it hasn't been root-caused - worth a closer look if it turns out to affect correctness (not just log noise) for some other plugin. WavAudioFormat's base-class doc comment says channel count "must be either 1 or 2" (AudioFormat::createWriterFor's Doxygen comment).WavRecorderpasses through whateverPluginHost::getNumOutputChannels()reports with no clamping, and this has worked fine for the 1- and 2-channel plugins tested so far - but a plugin with more than 2 output channels hasn't been tried, so it's unconfirmed whether JUCE's WAV writer actually enforces that limit or the doc comment is just generic/stale boilerplate shared across format subclasses.
Nice-to-have (not planned, just noted)
- A
--list-paramsor similar introspection mode (print every parameter's index/name/current value) would help writing new scenario JSON files without cross-referencing the plugin's own GUI or source. Done:--printParams(printsPARAM <index> <value>for every parameter, after any initial--patch/--bankload) - added to make the patch/bank round-trip regression tests intests/possible; only prints values, not names, so cross-referencing the plugin's own parameter-name list is still occasionally needed.