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:
@@ -235,21 +235,108 @@ test_bank_roundtrip() {
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Test 6: stability sweep over bundled sample patches ------------------
|
||||
# --- Test 6: bank/patch round-trip via the raw VST2 chunk dispatcher ------
|
||||
# test_bank_roundtrip/test_patch_roundtrip above go through JUCE's generic
|
||||
# AudioProcessor::get/setStateInformation - which, it turns out, JaySynth's
|
||||
# usesChunks() flag genuinely is true for, so those already exercise the
|
||||
# real bankEncodeXml/bankDecodeXml (chunk) path, not a per-parameter
|
||||
# fallback (see tests/README.md's "corrected finding" note - an earlier
|
||||
# version of this comment claimed otherwise and was wrong). This test goes
|
||||
# one step further and calls effGetChunk/effSetChunk *directly* via
|
||||
# Vst2RawChunk (bypassing JUCE's host-side wrapper entirely), so it keeps
|
||||
# testing the real chunk path even if some future JUCE version's
|
||||
# usesChunks() gating ever changes. It also positively *proves* the chunk
|
||||
# path was used - not just that parameters round-trip - by checking the
|
||||
# saved file starts with a zlib stream header (0x78) and is far larger
|
||||
# than a raw 140-parameter float array (140*4=560 bytes) could be; the
|
||||
# regular/fallback format would look nothing like this.
|
||||
test_chunk_roundtrip() {
|
||||
# $1: "bank" or "patch"; $2: target parameter value (kept distinct
|
||||
# per call so a mixup between the two wouldn't silently pass)
|
||||
local kind="$1"
|
||||
local target_value="$2"
|
||||
local save_flag load_flag
|
||||
if [ "$kind" = "bank" ]; then
|
||||
save_flag="--saveBankChunk"; load_flag="--loadBankChunk"
|
||||
else
|
||||
save_flag="--savePatchChunk"; load_flag="--loadPatchChunk"
|
||||
fi
|
||||
|
||||
local name="${kind}_chunk_roundtrip (raw effGetChunk/effSetChunk, index=$([ "$kind" = bank ] && echo 0 || echo 1))"
|
||||
local chunk_file="$WORKDIR/roundtrip_${kind}.chunk"
|
||||
local log1="$WORKDIR/roundtrip_${kind}_chunk_save.log"
|
||||
local log2="$WORKDIR/roundtrip_${kind}_chunk_load.log"
|
||||
local tolerance="0.02"
|
||||
|
||||
if ! run_testhost 10 --param 0 "$target_value" $save_flag "$chunk_file" --duration 0.05 > "$log1" 2>&1; then
|
||||
fail "$name (save step failed, exit $? - see $log1)"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ ! -s "$chunk_file" ]; then
|
||||
fail "$name (no chunk file written)"
|
||||
return
|
||||
fi
|
||||
|
||||
local first_byte
|
||||
first_byte="$(od -An -tx1 -N1 "$chunk_file" | tr -d ' ')"
|
||||
local chunk_size
|
||||
chunk_size="$(stat -c%s "$chunk_file" 2>/dev/null || echo 0)"
|
||||
|
||||
if [ "$first_byte" != "78" ]; then
|
||||
fail "$name (saved file doesn't start with a zlib header (0x78) - got 0x$first_byte, this didn't go through bankEncodeXml/GZIP at all)"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$chunk_size" -le 1000 ]; then
|
||||
fail "$name (saved file is only $chunk_size bytes - too small to be the real XML/chunk format, looks like a per-parameter fallback)"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! run_testhost 10 $load_flag "$chunk_file" --printParams --duration 0.01 > "$log2" 2>&1; then
|
||||
fail "$name (load step failed, exit $? - see $log2)"
|
||||
return
|
||||
fi
|
||||
|
||||
local readback
|
||||
readback="$(grep '^PARAM 0 ' "$log2" | awk '{print $3}')"
|
||||
|
||||
if [ -z "$readback" ]; then
|
||||
fail "$name (PARAM 0 not found in output - see $log2)"
|
||||
return
|
||||
fi
|
||||
|
||||
local diff
|
||||
diff="$(awk -v a="$readback" -v b="$target_value" 'BEGIN { d = a - b; if (d < 0) d = -d; print d }')"
|
||||
local within_tolerance
|
||||
within_tolerance="$(awk -v d="$diff" -v t="$tolerance" 'BEGIN { print (d <= t) ? "1" : "0" }')"
|
||||
|
||||
if [ "$within_tolerance" = "1" ]; then
|
||||
pass "$name (chunk is $chunk_size bytes, starts 0x78; wrote $target_value, read back $readback)"
|
||||
else
|
||||
fail "$name (wrote $target_value, read back $readback - outside +-$tolerance tolerance - see $log1 / $log2)"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Test 7: stability sweep over bundled sample patches ------------------
|
||||
# Broad regression net: load every bundled .fxp under extras/sounds/ and
|
||||
# render a held note through it. NOTE: as discovered while building this
|
||||
# suite, these particular sample files are in VST2's opaque-chunk ("FPCh")
|
||||
# format, but JUCE 3.1.1's plugin-side VST wrapper (compiled into
|
||||
# JaySynth.so) never sets effFlagsProgramChunks, so JUCE's *host*-side
|
||||
# VSTPluginInstance::usesChunks() sees false and silently ignores the
|
||||
# chunk data entirely - confirmed by diffing --printParams output with and
|
||||
# without --patch: zero parameters differ. This is a real, separate
|
||||
# finding (see tests/README.md and testhost/TODO.md) - NOT one of the
|
||||
# tracked TODO.md findings, and NOT something this suite attempts to fix.
|
||||
# So this test only checks "loading this file doesn't crash the process",
|
||||
# not "loading this file changes the patch" - it still exercises the
|
||||
# malloc/delete[] paths touched by the Memory-management fixes as a broad
|
||||
# smoke test, just not the patch-content-application path.
|
||||
# render a held note through it. NOTE: these particular sample files
|
||||
# (10+ years old) load without crashing but - confirmed by diffing
|
||||
# --printParams output with and without --patch - have no effect on the
|
||||
# patch's parameters. This is NOT the effFlagsProgramChunks/usesChunks()
|
||||
# gap an earlier version of this comment claimed (that was wrong - see
|
||||
# tests/README.md's "corrected finding" note; usesChunks() genuinely is
|
||||
# true, and test_chunk_roundtrip above proves the real chunk path works
|
||||
# with files this same build produces). The actual cause is still
|
||||
# unidentified - most likely these specific old files use a compression
|
||||
# or XML-schema shape that JaySynthAudioProcessor::setCurrentProgramState-
|
||||
# Information/getXmlFromBinary no longer parses, not a host-vs-plugin
|
||||
# capability mismatch. Tracked in tools/testhost/TODO.md's Investigate
|
||||
# section. So this test only checks "loading this file doesn't crash the
|
||||
# process", not "loading this file changes the patch" - it still
|
||||
# exercises the malloc/delete[] paths touched by the Memory-management
|
||||
# fixes as a broad smoke test, just not the patch-content-application
|
||||
# path.
|
||||
test_stability_sweep() {
|
||||
local sounds_dir="$REPO_ROOT/extras/sounds"
|
||||
local any=0
|
||||
@@ -298,6 +385,11 @@ test_patch_roundtrip
|
||||
test_bank_roundtrip
|
||||
log ""
|
||||
|
||||
log "Raw VST2 chunk dispatcher - proves the actual chunk-based path:"
|
||||
test_chunk_roundtrip bank 0.81
|
||||
test_chunk_roundtrip patch 0.44
|
||||
log ""
|
||||
|
||||
log "General stability sweep over bundled sample patches:"
|
||||
test_stability_sweep
|
||||
log ""
|
||||
|
||||
Reference in New Issue
Block a user