Docs file normalization.

This commit is contained in:
Johannes Findeisen 2026-11-06 15:20:20 +01:00
commit 619c2d0808
46 changed files with 3587 additions and 2579 deletions

View file

@ -1,12 +1,15 @@
# Native C processor API, version 1
# 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.
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
---
## 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
@ -30,59 +33,68 @@ 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.
## 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
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.
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.
## 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.
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.
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`.
processing, event offsets, seek note reset, source ports, instrument-buffer
graph routing and unsupported-save preservation. Run `make test`.
## Structured parameter processors
---
## Structured Parameter Processors
`xtc_processor.h` is the public C99 parameter-only extension interface (ABI 2).
It complements the ABI 1 graph adapter without changing its layout or behavior.
@ -90,27 +102,28 @@ It complements the ABI 1 graph adapter without changing its layout or behavior.
instrument using only public headers; `make test-processor` builds and exercises
both. The instrument has immediate note-off and no voice stealing/release tail.
Descriptors have an exact ABI version and structure size, a persistent identifier,
and up to 16 parameters with unique unsigned IDs, names, units, finite ranges and
defaults. Unsupported ABI versions/sizes are rejected before initialization.
Changing identifier, parameter order, IDs or ranges requires an explicit migration
by the extension author. There is no promise of binary compatibility across
compiler architectures, and no C++/FLTK types in either API.
Descriptors have an exact ABI version and structure size, a persistent
identifier, and up to 16 parameters with unique unsigned IDs, names, units,
finite ranges and defaults. Unsupported ABI versions/sizes are rejected before
initialization. Changing identifier, parameter order, IDs or ranges requires an
explicit migration by the extension author. There is no promise of binary
compatibility across compiler architectures, and no C++/FLTK types in either
API.
Create prepares a copied descriptor on the control thread. Failed preparation
calls destroy, including with NULL: callbacks must implement partial cleanup.
Reset/process/parameter have one audio owner and must never allocate, free, block,
perform I/O or call GUI functions. Destroy is control-thread only after callback
quiescence. Reconfiguration prepares a new independent instance; publish it with
an appropriate owner handoff and retire the old instance after quiescence. The
callback code must remain loaded throughout that lifetime.
Reset/process/parameter have one audio owner and must never allocate, free,
block, perform I/O or call GUI functions. Destroy is control-thread only after
callback quiescence. Reconfiguration prepares a new independent instance;
publish it with an appropriate owner handoff and retire the old instance after
quiescence. The callback code must remain loaded throughout that lifetime.
Each instance has one mono output and either one optional input (effect) or no
input (source/instrument). NULL input means silence. Stereo effects use two
independent instances; multichannel interdependent effects have no adapter.
Instruments receive at most 256 sorted sample-offset MIDI events per block.
The API intentionally has no channel-count argument: unsupported layouts cannot
be represented. Graph ABI 1 rejects instrument descriptors; explicitly render
Instruments receive at most 256 sorted sample-offset MIDI events per block. The
API intentionally has no channel-count argument: unsupported layouts cannot be
represented. Graph ABI 1 rejects instrument descriptors; explicitly render
instrument output and feed the existing instrument source buffers.
Up to 256 sorted parameter events split the process block at exact sample
@ -122,13 +135,14 @@ reset retains current parameters. Callback errors silence the whole output and
reset voices/history; already applied parameters persist. Nonfinite/subnormal
successful samples become zero. Input/output may alias exactly.
`xtc_processor_save`/`restore` run only while quiescent and serialize configuration,
not DSP history. Format: `XTCN`, little-endian uint32 version 2, zero-padded
64-byte identifier, uint32 parameter count, zero uint32 reserved, then ordered
pairs of uint32 ID and IEEE float32 bits. Header is 80 bytes, pairs 8 bytes.
Restore validates exact length, identity, IDs, ranges and defaults/descriptor
compatibility before preparing a new instance; failure leaves existing handles
intact. Opaque assets and hidden state are outside this ABI. ABI 1 graph nodes
remain session-only and fail project saves explicitly; ABI 2 configuration blobs
are a separate public facility, not automatically embedded in project files.
GUI graph access continues through public C APIs only.
`xtc_processor_save`/`restore` run only while quiescent and serialize
configuration, not DSP history. Format: `XTCN`, little-endian uint32 version 2,
zero-padded 64-byte identifier, uint32 parameter count, zero uint32 reserved,
then ordered pairs of uint32 ID and IEEE float32 bits. Header is 80 bytes, pairs
8 bytes. Restore validates exact length, identity, IDs, ranges and
defaults/descriptor compatibility before preparing a new instance; failure
leaves existing handles intact. Opaque assets and hidden state are outside this
ABI. ABI 1 graph nodes remain session-only and fail project saves explicitly;
ABI 2 configuration blobs are a separate public facility, not automatically
embedded in project files. GUI graph access continues through public C APIs
only.