Phase 9: Add native processors and reproducible Linux release tooling
This commit is contained in:
parent
7db5fb7738
commit
de403b37d7
43 changed files with 1656 additions and 19 deletions
83
docs/NATIVE_API.md
Normal file
83
docs/NATIVE_API.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Native C processor API, version 1
|
||||
|
||||
`xtc_native.h` defines a small compile-time extension boundary for trusted C99
|
||||
sources, effects and instruments. Build `make build/native-gain` and run it for a
|
||||
complete graph-effect example in `examples/native_gain.c`. This is a source API
|
||||
for this release, not a promise of binary compatibility across builds/platforms.
|
||||
There is no module scanner, dynamic loader, SDK dependency or sandbox.
|
||||
|
||||
## Descriptor and ownership
|
||||
|
||||
Set `abi_version = XTC_NATIVE_ABI_VERSION`, `struct_size = sizeof(descriptor)`,
|
||||
a terminated printable non-space ASCII identifier (1..63 bytes), kind and all
|
||||
four callbacks. Unknown ABI/size returns UNSUPPORTED; invalid fields return
|
||||
INVALID_ARGUMENT. The host copies the entire descriptor, including its name.
|
||||
Callback code must remain loaded until all graphs, plans and instances are gone.
|
||||
No plugin/global registry is consulted or mutated by rendering.
|
||||
|
||||
`xtc_native_create` validates rate (positive, <=768000), frames (1..65536) and a
|
||||
finite scalar parameter. It runs prepare on the control thread with a NULL
|
||||
initial state pointer. Prepare may allocate/preload; on failure the host calls
|
||||
destroy even for NULL state. Destroy must accept NULL. The host then resets the
|
||||
new instance. On failure the output handle is NULL; successful instances belong
|
||||
to the caller. Destroy only after the processing owner is stopped/joined.
|
||||
|
||||
Reset and process have one audio owner (or run while stopped). They must never
|
||||
allocate/free, perform I/O/logging, block, call GUI functions or mutate shared
|
||||
control data. Reset must be idempotent. Prepare/destroy run only on the control
|
||||
thread, including failed compilation and retired-plan collection. Code executed
|
||||
inside callbacks is trusted: xtc cannot enforce its realtime behavior or protect
|
||||
against memory corruption. C++ processors must use C linkage and never throw
|
||||
across this boundary; domain/DSP code in this repository remains C.
|
||||
|
||||
## Block contract
|
||||
|
||||
A block contains mono input/output, frames, absolute sample position and optional
|
||||
MIDI events. Input NULL means silence; exact input/output aliasing is allowed and
|
||||
processors must support it. Output is writable for every frame, including silent
|
||||
frames; do not retain any borrowed block pointers. Other overlapping buffers are
|
||||
not supported. Only instruments receive events; event count <=256, offsets are
|
||||
sorted and strictly less than frames, with equal offsets retaining caller order.
|
||||
Pitch/velocity/channel/type bounds follow xtc_midi.h. Zero frames is a no-op.
|
||||
|
||||
The host rejects invalid blocks before changing state/output, and reports
|
||||
CAPACITY above the prepared block limit. Position arithmetic cannot overflow.
|
||||
A discontinuous position resets held voices/state before processing. Call reset
|
||||
for Stop/panic when hosting instruments yourself; send channel ALL_OFF for
|
||||
channel-specific panic. The native host does not implement sustain or routing.
|
||||
|
||||
On successful processing, nonfinite samples become silence. Callback failure
|
||||
silences the block, resets that processor and returns its error. Already advanced
|
||||
processors in a graph are not rolled back. Never rely on failure to transactionally
|
||||
rewind DSP; prepare fallible resources before publication. There is no latency
|
||||
compensation, tail protocol, parameter ramp or dynamic port negotiation in ABI 1.
|
||||
|
||||
## Graph and instrument integration
|
||||
|
||||
`xtc_graph_add_native` adds effects (input 0/output 1) or sources (output 1), with
|
||||
a scalar immutable parameter. Compilation creates two independent mono instances
|
||||
for stereo; no mutable state is shared between sides. Graph-only edits retain
|
||||
the existing pending/retired publication contract. Reset clears native state and
|
||||
its graph-local frame clock; graph positions count successfully rendered frames
|
||||
since compilation/reset, independently of backend seek/transport. Sources needing
|
||||
transport time should be hosted explicitly with a block position.
|
||||
|
||||
For an instrument, use create/process directly with sample-offset events, then
|
||||
feed its output to an existing XTC_NODE_INSTRUMENT through process_sources or
|
||||
process_stereo. The host owns event routing and panic/reset delivery. Graph-native
|
||||
instrument addition returns UNSUPPORTED because current graph ports carry audio,
|
||||
not MIDI. This separation avoids silently dropping instrument events. The built-in
|
||||
JACK MIDI sine instrument remains the GUI's instrument; custom instrument selection
|
||||
and event graph ports are future work.
|
||||
|
||||
Descriptors survive graph/project cloning and transactional remove/connect edits;
|
||||
custom ADD_NODE commands use the dedicated constructor rather than a GUI menu.
|
||||
Native nodes have no project-file representation: Save returns UNSUPPORTED and
|
||||
preserves the destination. Format v4 still accepts only builtin types 1..6.
|
||||
A durable identifier/registry, versioned processor state and missing-module policy
|
||||
must precede serialized native extensions or external plugin hosting.
|
||||
|
||||
Tests cover ABI/size/field rejection, descriptor copying, aliased buffers,
|
||||
prepare/process failures, stereo compile cleanup, retirement/destruction outside
|
||||
processing, event offsets, seek note reset, source ports, instrument-buffer graph
|
||||
routing and unsupported-save preservation. Run `make test`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue