xtc/docs/CONTROL.md

147 lines
9.2 KiB
Markdown
Raw Normal View History

2026-11-06 14:12:22 +01:00
# Automation and expressive control
Track Gain/Pan lanes in the Mixer apply to audio and scheduled instrument voices.
They use absolute project ticks, linear or hold interpolation, hold-first/last outside
points and the constant project tempo snapshot. A clip trim/move does not move
track or effect automation: lanes belong to the project timeline. Instrument
volume is controlled by its track Gain lane; the current sine has no timbre
parameter. Track gain ramps and boundary fades are described in AUDIO_QUALITY.md.
Select a LADSPA node in Modular Graph and use Edit/Selected plugin automation.
Enter `port tick mode value`: mode 0 interpolates linearly, 1 holds until the next
point, and -1 removes the point at that port/tick (value ignored). Port names,
ranges and current tick are displayed. There are at most 32 points per plugin;
setting an existing port/tick replaces it. Integer/toggle controls require step
mode. Invalid values, ticks, ports or duplicate persisted points reject the edit
or file. Edits are undoable and rebuild on the control thread while stopped.
Effect lanes use the project tempo, hold first/last outside their range and
apply before run at each exact sample. Distinct ticks rounding to one sample
resolve to the later tick. Linear curves avoid stepping continuous controls;
intentional step curves may click. The initial implementation calls run(1) while
any lane exists, with connected preallocated buffers. CPU cost can be significant;
only the documented LADSPA set is qualified. No worker, allocator, loader or
clock is called from the host audio path. Native ABI 2 callers continue to use
sample-offset parameter events, applied before equal-offset MIDI events.
Live MIDI input maps CC7 to per-channel volume (0..1), CC10 to pan (64 center),
and CC64 to sustain (>=64 down). Volume/pan ramp over 5 ms. These default mappings
apply to live sine voices, not track faders or prerecorded clips; controller
capture, automatic learn and plugin MIDI are not supported. CC120/123 and
Panic release all live voices and sustain and suppress already-started scheduled
notes. Note-on velocity zero decodes to note-off. Repeated live note-on on one
channel/pitch retriggers one voice; note-off releases it or marks it pending while
sustain is held. Sustain-up releases pending voices, never newer retriggers.
Seek, stop, teardown and disconnect clear live voices; plan reset returns controller
values to unity/center. Equal-offset live events execute in input order before
the sample; arrange note ends precede starts, and scheduled mixer values are
evaluated at that sample. Overlapping arranged notes are independent.
Format v6 preserves v5 data plus effect lanes. A v5 plugin migrates with no lane
and the project tempo. Repeated render/save/reopen, odd block partition, exact
endpoints, seek/plan replacement, sustain/retrigger and controller ramp tests:
```sh
make test test-control test-plugins test-gui-plugins test-plugins-real
```
Physical controller devices and listening remain unqualified; no tempo map,
latency compensation, MIDI capture, pitch bend or plugin crash isolation is added.
2026-11-06 14:12:22 +01:00
## Common parameter targets
`xtc_control.h` identifies a parameter by `(kind, stable owner ID, parameter ID)`.
IDs never mean a dense list index and are not DSP pointers:
| Kind | Owner | Parameter IDs | Metadata/reset defaults |
| --- | --- | --- | --- |
| TRACK | Track or mix-bus stable uint64 ID | 0 gain, 1 pan | Gain 0..4 linear, default 1; pan -1..1 balance, default 0 |
| PLUGIN | LADSPA graph node ID | Actual input-control port | Descriptor name, bounds, default and discrete/logarithmic hints; units unspecified |
| LIVE | MIDI channel 0..15 | 0 volume, 1 pan, 2 sustain | Volume 0..1 default 1; pan -1..1 default 0; sustain boolean default 0 |
`xtc_project_parameter` returns copied metadata, static configuration and whether
a lane exists. LIVE values are reset defaults, not callback-owned controller
readbacks. `xtc_project_set_parameter` changes TRACK/PLUGIN static configuration
without deleting automation. `xtc_project_automate` sets/replaces/removes points
for TRACK/PLUGIN through one C contract. LIVE static setters and timeline lanes
are unsupported: these controls belong to incoming MIDI events, not the arranged
instrument. Plugin metadata/control edits execute trusted discovery on the
control thread; they never run inside audio. Model-only clients must compile and
publish accepted snapshots before rendering; GUI edits do this transactionally.
Unknown owners/ports fail without touching the destination model/output. Missing
plugin modules fail discovery rather than guessing ranges or installing a dummy.
Track deletion removes its lanes; plugin deletion removes its embedded lanes.
Compatible plugin replacement resets controls/automation as described in
PLUGIN_HOSTING.md. Persisted dangling references reject the complete load;
the current project remains intact. The GUI reports rejected edits/Open failures.
## Interpolation and precedence
The Mixer Interpolation chooser selects Linear or Hold (step) for the point
being added/replaced. A point owns the segment beginning there. At a hold point,
its value remains until the next point's exact sample. Linear segments interpolate
between endpoint values without an extra smoothing stage. Hold first/last before/
after the lane. Gain/pan for tracks and buses support both; integer/toggle LADSPA
controls require hold. Existing files migrate mixer points to linear.
Automation is absolute project time, independent of clip starts, ends, trims,
splits and moves; it neither restarts nor resets at a clip boundary. Tick-to-sample
rounding uses the prepared constant tempo/rate; distinct ticks landing on the
same sample choose the greatest tick. Empty lanes restore the static value.
Static edits while a lane exists change the fallback value, not the audible lane.
GUI changes stop/rebuild snapshots; live mutation of faders/plugin instances is
not introduced. Plugin reset removes lanes only when explicitly applied.
At each sample, arranged track/bus and plugin lanes apply to their own targets.
Incoming MIDI volume/pan/sustain affect only live sine voices on that channel,
never those lanes or the static project controls. Equal-offset MIDI events run
in input order before synthesis. A controller event then affects that sample's
ramp; gain/pan reach the target over max(1, rate/200) frames. Sustain changes at
the event sample. Panic CC120/123 remains reserved and also suppresses already
started arranged notes according to the existing panic contract.
Seek/discontinuous positions clear live voices and runtime controllers to their
reset values but retain prepared bindings. Arranged lanes evaluate directly at
the new position. Backward jumps evaluate the earlier timeline again; tests
exercise explicit wraps. There is no loop transport feature or promise to
restore opaque LADSPA delay history across jumps (transport reset retains it).
## Configurable live MIDI bindings
Audio → MIDI controller mapping lists the current 16 channels. Enter
`channel volume_CC pan_CC sustain_CC`, for example `2 1 74 11`. Channels are
zero-based; CCs are 0..127, or 128 to disable a target. Enabled CCs must be distinct
within a channel; CC120 and CC123 cannot be rebound. All channels default to
7/10/64. Rebinding replaces the old binding; it is not an additional route. An
unmapped CC does nothing. Other channels remain independent. The same volume,
pan and sustain transfer functions apply regardless of the chosen CC number.
Disabling a target leaves it at its runtime reset value until plan replacement.
Changing a map stops/rebuilds playback and is one undoable edit; maps survive
save/Open and undo/redo. Cancel and invalid/duplicate/reserved bindings retain
the prior configuration. There is no automatic learn, arbitrary plugin/track CC
mapping, MIDI capture or write/touch/latch automation mode.
Plans copy only 48 binding bytes on the control thread. The callback compares
at most three CC numbers per control event, uses existing preallocated ramps/
voices and the existing 256-event block budget. Decode now accepts all valid
three-byte CC messages; even unmapped CCs count against that event budget.
Mixer points compile to bounded sorted arrays with binary lane lookup; processing
does no allocation, sort, file/module I/O, locking or GUI work. LADSPA automated
run(1) cost and native plugin trust limits remain unchanged.
## Persistence and verification
Project v10 appends a mixer interpolation field and 16 controller-map records;
v1–v9 migrate to linear mixer lanes and default 7/10/64 maps. LADSPA point encoding
is unchanged. Public `xtc_automation_point` gains `step`: rebuild clients and
initialize it to 0 (linear) or 1 (hold). See PROJECT_FORMAT.md for exact grammar.
`test_parameters` covers metadata, missing targets, static/automation precedence,
exact hold/linear boundaries, save/reopen, malformed maps, low-rate sample
collisions, odd blocks, seeks and backward jumps. `test_control` compares default
and remapped event streams, stereo pan, disabled/unmapped controls and immutable
plan maps across resets. Plugin tests cover common-target edits and persistence;
GUI tests cover interpolation, map rollback, undo/redo and save/Open. Existing
callback guards and sanitizers verify host ownership constraints. Physical
controller devices, listening and extended high-density endurance are pending.