Host state, transport ticks, and update() dispatch (CLAP + VST3)#173
Open
jcelerier wants to merge 13 commits into
Open
Host state, transport ticks, and update() dispatch (CLAP + VST3)#173jcelerier wants to merge 13 commits into
jcelerier wants to merge 13 commits into
Conversation
avnd::has_custom_state detects save_state/load_state member functions in several ergonomic spellings (byte-container or writer-callback save; pointer+size or span load, bool- or void-returning). avnd::save_state / avnd::load_state normalize them for the bindings. Static detection tests for accepted spellings and rejected shapes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CLAP gains CLAP_EXT_STATE (previously absent): a versioned container with the normalized parameter values followed by the processor's opaque blob. VST3 appends a magic-tagged trailer after the existing parameter doubles, keeping current session data byte-compatible (the controller's setComponentState never reads past the doubles; old sessions hit EOF before the trailer and load fine). Malformed blobs are rejected without partial application. Polyphonic containers save from the first instance and load into all. Adds the examples/Raw/CustomState.hpp reference example (compiled for both bindings) and a Catch2 round-trip test driving the real CLAP extension through in-memory streams with forced partial IO. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CMake 4 removed the bundled FindBoost module; the shim defers to Boost's own config files when installed and otherwise satisfies the header-only requirement from BOOST_ROOT. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The shim only probed <root>/boost/version.hpp, so a BOOST_ROOT pointing at an installed tree (<root>/include/boost/version.hpp) was rejected even though the headers were there. Probe with find_path, which covers both layouts and the default search paths, and report through find_package_handle_standard_args so the requested version is honoured. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
avnd::transport_tick is a plain aggregate holding one block's transport snapshot (tempo, time signature, playing state, musical and time-based positions, bar boundaries, flicks); current_tick() maps its members onto whatever tick type a processor declares. Also map a 'playing' member in current_tick so processor ticks can carry the transport running state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Track clap_process::transport at block start plus CLAP_EVENT_TRANSPORT in-events, and convert to an avnd::transport_tick handed to the process adapters: fixed-point beat/second positions (exact division by CLAP_BEATTIME_FACTOR), tempo/time-signature/playing flags with 120 BPM and 4/4 fallbacks, bar boundaries at block start and end, and end_position_in_quarters computed at constant tempo over the block. Hosts that never provide transport keep the previous frames-only tick. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Convert ProcessData::processContext to an avnd::transport_tick honoring the validity flags (kTempoValid, kTimeSigValid, kProjectTimeMusicValid, kBarPositionValid, kSystemTimeValid, kPlaying) with fallbacks: 120 BPM, 4/4, musical position derived from projectTimeSamples at the current tempo, bar boundaries assumed aligned at zero when unreported. The converter is templated over the context type so it stays testable without the SDK; without a ProcessContext the previous frames-only invocation is preserved. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixed-point beat conversion exactness, validity-flag fallbacks for both bindings, bar-boundary advancement across blocks, seconds-from-beats derivation, steady-time fallback, and end-to-end mapping of a transport tick onto a processor-declared tick type. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports with an update() member were only notified at initialization (init_controls) and by the ossia binding; host-driven parameter changes through the clap and vst3 bindings silently skipped the callback. Apply the same convention as init_controls: if_possible(ctl.update(state.effect)) right after the new value is written, for every effect instance. The vst3 parameter application moves to stv3::apply_control in param_apply.hpp, free of SDK types so the path is testable on its own. Bulk value restores (state loads) dispatch the callbacks too, through the new avnd::update_controls helper. Tests drive both bindings' application paths and verify one invocation per change with the new value in place. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The state container stored parameter values as dense-ordinal doubles while the params extension speaks raw field ids: on processors whose parameters follow other ports (audio, midi), restores could land values on the wrong fields and the two spaces drifted across versions. The container (version 2) now stores (raw id, plain value) pairs -- the same id and value space as the extension -- and skips unknown ids so states survive parameter removals. State restores are also no longer treated as host gestures: update() callbacks are not dispatched while restoring (CLAP load, VST3 setState). A derive-style handler -- one that rewrites other ports when its own value changes -- would otherwise clobber freshly restored values in save-order-dependent ways. Processors deriving internal state from their ports reconcile in their custom-state load instead. Event- and flush-driven changes keep dispatching update() as before. Tests: a mixed-shape processor (audio port before the parameters, so raw ids differ from ordinals, plus a derive-style int port) saves modified values and restores them into a fresh instance, asserting every value through the extension vtable and that the derive handler did not run. Adds the MixedParams example exercising the same shape as a plug-in. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Session persistence for custom processor state, host transport ticks, and
update()dispatch on host parameter changes.This branch now carries the transport work as well: #174 was merged into it rather than into
main, so the two features arrive together. Rebased ontomainafter #175 landed; the parameter-space commits it shares with #175 were dropped as already-upstream. The design rationale lives in the new "Host state" chapter of the manual.Host state
avnd::has_custom_state: a processor's opaque, self-versioned blob, detected through concepts and accepted in several spellings (byte-container return or zero-alloc writer; ptr+size or span load,bool- orvoid-returning).CLAP_EXT_STATE(it had none): a versioned container holding parameter values and the blob, tolerant of partial stream IO.update()is not dispatched while restoring: a port that derives other state from its own value would otherwise clobber freshly restored values in save-order-dependent ways.Transport
avnd::transport_tick, a host-independent carrier that the existingcurrent_tick()machinery maps onto whatever tick a processor declares.clap_process::transportplusCLAP_EVENT_TRANSPORT; VST3 fromProcessContext, honouring each validity flag with documented fallbacks.update()dispatchHost parameter changes now invoke a port's
update()callback in the CLAP and VST3 bindings, matching the ossia binding and the documented contract (the book previously listed ossia as the only support).Testing
test_state,test_state_clap,test_transport,test_update_controls, plus the pre-existing suites: 106 tests pass locally (MSVC 19.50, Windows). The CLAP state path is covered by a round-trip through the real extension with forced 3-byte partial transfers and corruption/truncation rejection.Validated against clap-validator 0.3.2 with a plug-in whose shape exercises the id-addressing path (audio and MIDI ports before ~14 mixed-type parameters, plus a large custom blob): 16 passed / 0 failed, and pluginval strictness 10 passes on its VST3 build.
Open
IBStream.last_signature_changestays 0.🤖 Generated with Claude Code