1
0
Fork 0
forked from hanez/xtc

Phase 26: add common parameter targets, step automation and MIDI control mapping

This commit is contained in:
Johannes Findeisen 2026-10-27 16:37:59 +01:00
commit 901a536f10
38 changed files with 740 additions and 67 deletions

View file

@ -1,7 +1,7 @@
# Automation and expressive control (Phase 16)
# Automation and expressive control (Phases 16 and 26)
Track Gain/Pan lanes in the Mixer apply to audio and scheduled instrument voices.
They use absolute project ticks, linear interpolation, hold-first/last outside
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
@ -25,9 +25,9 @@ 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 fixed mappings
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, configurable learn and plugin MIDI are not supported. CC120/123 and
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
@ -47,3 +47,101 @@ 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.
## Phase 26: 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.

View file

@ -11,7 +11,7 @@
events/block, 32 voices, 65536 frames/block. See API headers for exact bounds.
- WAV samples preload with the memory/format limits in AUDIO_FILES.md. Callback
overflow reports/silences; there is no CPU preemption or expensive-plugin rescue.
- Live MIDI fixed volume/pan/sustain mapping; no controller learn, capture, SMF
- Live MIDI configurable per-channel volume/pan/sustain CC mapping; no controller learn, capture, SMF
import, pitch bend, custom-instrument chooser or instrument timbre controls.
- Native ABI 1 graph nodes are session-only. ABI 2 state is parameter-only. LADSPA
supports the documented mono amp/inverter/sine set; no opaque state, native
@ -21,7 +21,7 @@
zoom/selection and graph positions are session UI state. Undo retains 32 edits
plus baseline; allocation failures are reported, not silently hidden. Media is
never removed by undo/delete. Broad screen-reader/accessibility testing is pending.
- Format v9 reads v1–v8 and uses relative local media references. External absolute
- Format v10 reads v1–v9 and uses relative local media references. External absolute
media/module paths need manual repair after relocation. Saving does not bundle
media; missing media stays referenced, missing plugins reject GUI installation.
Unknown data is rejected rather than stripped. Post-rename directory-sync errors
@ -54,3 +54,8 @@ PERFORMANCE.md, PLUGIN_HOSTING.md and RECOVERY.md for tested contracts/evidence.
requires the same mono audio layout and resets controls/automation. Missing
modules reject Open while retaining the current project; GUI module relink for
unopened documents is deferred. In-process plugin crashes/hangs are uncontained.
- Common parameter targets cover track/bus gain/pan, LADSPA controls and metadata
for live sine volume/pan/sustain. Live mappings do not drive arranged lanes,
faders or plugins. No automation capture, touch/latch/write modes or loop
transport. Backward jumps are deterministic for lanes, not opaque plugin tails.

View file

@ -131,3 +131,8 @@ repeats/fresh IDs, rejected batch rollback, capacity, undo snapshots, equal-offs
live order, adjacent/overlapping notes, exact block partitions and seek chase.
`make test-gui` covers mouse edits and the new commands with undo/redo and engine
reinstallation. Listening and physical MIDI-device validation remain pending.
Phase 26: CC7/10/64 are defaults, configurable per channel through Audio → MIDI
controller mapping. Disabled/unmapped CCs have no effect; CC120/123 stay panic.
Decode accepts valid CC0..127 messages within the existing event budget. See
CONTROL.md for the exact bindings, ramp, sustain and automation precedence rules.

View file

@ -26,7 +26,8 @@ static control. There are at most 1024 points globally, with one per
track/parameter/tick. Track deletion cascades to its automation.
A nonempty lane replaces that parameter's static value. Between points the C
engine interpolates linearly at each sample, holding the first/last value outside
engine interpolates linearly or holds each segment (Interpolation chooser),
holding the first/last value outside
their range. Preparation converts ticks to integer sample endpoints, sorts and
indexes lanes. When several ticks quantize to one sample at very low sample
rates, the last point wins at that sample. Rendering searches prepared bounded
@ -137,3 +138,8 @@ project performance remain unverified; no new dependency was introduced.
`test_buses` covers bus routing, exact taps, audio/MIDI cancellation, controls,
automation, persistence, invalid routes, deletion/undo and dBFS ballistics. Backend
tests cover consuming interval peaks; GUI tests cover routing undo and clipping.
Phase 26 adds Linear/Hold interpolation for each point added or replaced. The
point's mode applies to its following segment. Static controls remain fallbacks
while a lane exists; moving/splitting clips does not move absolute track/bus lanes.
See CONTROL.md for common parameter IDs and controller/automation precedence.

View file

@ -193,3 +193,14 @@ replacements with host allocation/free/dlopen/dlclose guards. Native ABI tests
cover process-error silence/reset. The separately installed amp/inverter/sine
modules remain the qualified LADSPA set. Human listening, arbitrary third-party
editors/plugins and extended realtime endurance remain unverified.
## Phase 26 parameter targets
`xtc_control.h` supplies common stable owner/parameter IDs and control-thread
metadata/edit APIs for track/bus gain/pan and LADSPA input ports. The GUI's plugin
automation command uses this contract. Linear/hold LADSPA encoding and its
integer/toggle restrictions remain unchanged; v10 adds mixer interpolation and
live-sine CC maps without changing plugin state records. Direct static edits do
not override existing lanes. Live CCs do not map to plugins; missing targets or
modules fail without installing partial state. See CONTROL.md for timing,
precedence, reset and backward-jump behavior.

View file

@ -1,6 +1,6 @@
# Project format v9 (reads v1–v8)
# Project format v10 (reads v1–v9)
Phases 5–15 use a bounded text format implemented in C99 without a parser library.
Phases 5–26 use a bounded text format implemented in C99 without a parser library.
The extension is `.xtc`. File operations run exclusively on the control thread.
The project owns its graph, tracks and silent/audio arrangement regions. Audio samples remain in external WAV
files; MIDI notes are stored inline.
@ -12,7 +12,7 @@ Fields use ASCII spaces. Integers are unsigned decimal, without signs.
Counts determine the number of subsequent records:
```text
XTC_PROJECT 7
XTC_PROJECT 10
APP 0 1 0
TEMPO 120000
IDS 1 1
@ -23,12 +23,31 @@ EDGE 0 1
TRACKS 1
TRACK 0 547261636b
MIX 3f800000 00000000 0 0
ROUTE 0 18446744073709551615
CLIPS 1
CLIP 0 0 3840 2880 960 3840 526567696f6e
ASSET -
MIDI 0
AUDIO 3f800000 0 0
NOTES 0 0
AUTOMATION 0
CONTROL_MAPS 16
MAP 0 7 10 64
MAP 1 7 10 64
MAP 2 7 10 64
MAP 3 7 10 64
MAP 4 7 10 64
MAP 5 7 10 64
MAP 6 7 10 64
MAP 7 7 10 64
MAP 8 7 10 64
MAP 9 7 10 64
MAP 10 7 10 64
MAP 11 7 10 64
MAP 12 7 10 64
MAP 13 7 10 64
MAP 14 7 10 64
MAP 15 7 10 64
END
```
@ -47,6 +66,8 @@ END
- `TRACK`: ID and hex-encoded name bytes. In v4/v5 each is immediately followed
by `MIX gain_bits pan_bits mute solo`: finite binary32 gain 0..4, pan -1..1
encoded as eight hex digits, mute and solo unsigned 0/1.
- `ROUTE`: since v9, required after MIX: bus flag and destination bus ID;
UINT64_MAX denotes master. See Phase 24 constraints below.
- `CLIP`: ID, track ID, start tick, length tick, source offset tick, source
length tick, hex-encoded name bytes. Trimming
preserves source bounds, so a region can re-extend only within its original
@ -63,7 +84,8 @@ END
within source bounds. Pitch is 0..127, velocity 1..127, channel 0..15.
Note IDs are unique, monotonic uint64 IDs with UINT64_MAX reserved.
- `AUTOMATION`: global point count, after the last NOTE and before END in v4/v5.
Follow with `POINT track_id parameter tick value_bits` for each point.
Follow with `POINT track_id parameter tick value_bits step` in v10 (v4–v9
omit step and migrate to linear). Step is 0 linear or 1 hold for the next segment.
Parameter 0 is gain (0..4), 1 pan (-1..1); values use finite binary32 hex.
Track must exist; tick <= MAX_TICK; duplicate track/parameter/tick is invalid.
Record order is preserved; rendering sorts a separate prepared copy.
@ -227,3 +249,23 @@ Bus controls and automation use existing MIX and POINT records. Older readers
reject v9 rather than discard routing. The public `xtc_track_info` grew fields;
API consumers must rebuild. Fixtures cover v1–v8 migration and tests exercise
v9 exact roundtrips and malformed routing.
## Phase 26: version 10 interpolation and controller bindings
The current writer emits v10 and reads v1–v9. Track/bus automation points are
`POINT track_id parameter tick value_bits step`, where step is 0 linear or 1
hold for the segment starting there. v1–v9 points migrate to step=0. LADSPA
`PARAM` encoding remains unchanged (already has interpolation mode).
Immediately after all POINT records, before END, v10 requires `CONTROL_MAPS 16`
and exactly 16 records in ascending channel order:
`MAP channel volume_CC pan_CC sustain_CC`. Channels are 0..15. Controllers are
0..127 or 128 (disabled); enabled numbers must be distinct within a row and may
not be 120 or 123. Duplicate/missing/out-of-order channels, invalid CCs, reserved
bindings and invalid interpolation modes reject the complete candidate. v1–v9
supply default 7/10/64 bindings on every channel. No event history/current live
controller values are serialized. Older readers reject v10.
Fixtures cover v1–v9 migration. Exact roundtrips, malformed metadata, step/linear
renders and remapped live events cover the new writer/reader. Public clients
must rebuild and initialize the appended `xtc_automation_point.step` field.

View file

@ -672,10 +672,36 @@ Enable repeatable changes to mix and instrument parameters over time, with clear
- Document precedence rules for automation, controller input, and direct user changes.
### Acceptance criteria
- Supported parameters can be automated and saved in a project.
- Playback produces deterministic automation values for a given project and transport position.
- Missing targets fail safely and are reported to the user.
- Automation processing meets the engine's real-time safety requirements.
- [x] Supported parameters can be automated and saved in a project.
- [x] Playback produces deterministic automation values for a given project and transport position.
- [x] Missing targets fail safely and are reported to the user.
- [x] Automation processing meets the engine's real-time safety requirements.
Implemented: common stable owner/parameter keys and copied metadata for
track/bus gain/pan, LADSPA input controls and live sine controller targets;
validated common static/lane edit APIs; per-point linear/hold mixer automation;
per-channel saved volume/pan/sustain CC bindings with explicit disable and reserved
panic controllers. GUI adds Interpolation and Audio/MIDI controller mapping;
edits participate in undo/redo. Project v10 reads v1–v9 with linear/default-map
migration. CONTROL.md documents target identity, clip boundaries, precedence,
missing-target handling, controller ramps and real-time ownership.
Validation: warning-enabled core/GUI builds and full tests; common metadata,
missing owner/port/module failures and retained state; exact step/ramp endpoints,
low-rate collisions, odd blocks, seeks and explicit backward wraps; default/
remapped/disabled/unmapped CCs and stereo pan, immutable maps after preparation;
GUI map/interpolation/save/Open/undo/redo and invalid-edit rollback; v1–v9
migration, v10 exact persistence and malformed records; fixture/installed plugin
tests, callback-allocation guards, reliability/static analysis, performance and
capacity tests; software JACK GUI/audio/MIDI and workflow; dependency-free build,
installation/package relocation, core/GUI ASan+UBSan (existing fontconfig leak
suppression only for GUI/system font allocations).
No loop transport, MIDI learn/capture, write/touch/latch modes, arbitrary MIDI
mapping to arranged faders/plugins, timbre parameter for the built-in sine or
opaque-plugin seek restoration is claimed. Live MIDI targets have reset-default
metadata and controller bindings, not timeline lanes. Physical controllers,
listening and extended third-party-plugin endurance remain unverified.
## Phase 27 — Editing Workflow, Undo/Redo, and Usability

View file

@ -138,3 +138,10 @@ reset and insertion of an effect on a selected wire. Graph wires determine
processing order; Delete removes a selected plugin and its wires. Changes are
undoable. Replacement keeps compatible audio wiring but resets plugin controls
and automation. See PLUGIN_HOSTING.md for supported formats and failure behavior.
Phase 26: Mixer Interpolation selects Linear or Hold for each point added or
replaced. Audio → MIDI controller mapping lists all channel bindings; enter
`channel volume_CC pan_CC sustain_CC` (channels 0..15, 128 disables, enabled CCs
must be distinct, 120/123 reserved). Maps are undoable and saved. Controllers
modify live sine voices; arranged track/bus/plugin automation takes precedence
over its static controls and is unaffected by those MIDI bindings. See CONTROL.md.