Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp_node_v1.h
Go to the documentation of this file.
1/*
2 * pulp/native_components/pulp_node_v1.h — Pulp public node ABI, generation 1.
3 *
4 * The stable, language-neutral C contract a precompiled custom `SignalGraph`
5 * node implements (Rust, C, Zig, generated DSP). Derived from the
6 * source-level `CustomNodeType` contract (lifecycle + opaque state +
7 * serialization) and frozen here as `pulp_node_v1`.
8 *
9 * SCOPE: custom `SignalGraph` nodes only. This is NOT the Processor-level FFI
10 * (`native_core.h`), NOT a format-adapter replacement, and NOT a JS widget
11 * callback surface. A node is a small DSP block with audio ports, opaque
12 * versioned state, and an optional host-services handle.
13 *
14 * COMPATIBILITY: same-major promise. Within ABI major 1, the contract is
15 * append-only — fields are added by growing a struct's leading `size`, behavior
16 * by capability flags; existing fields, callback order, and semantics never
17 * change. A host accepts any node whose `abi_major` matches and whose entry
18 * `size` is at least the host's minimum. Loaders that find a higher minor simply
19 * ignore trailing fields they do not know.
20 *
21 * REPRESENTATION RULES (binding):
22 * - POD only. No C++ types, templates, exceptions, RTTI, virtuals,
23 * `std::function`, or references cross this boundary.
24 * - Every versioned struct leads with `uint32_t size` then `uint32_t abi_major`.
25 * - Integers are little-endian. Structs use natural C alignment; a `reserved`
26 * field pads to 8-byte alignment where noted and MUST be zero.
27 * - Strings are UTF-8, passed as `ptr` + `byte_len`; NUL termination is NOT
28 * required. `ptr==NULL,len==0` is the empty string; `ptr==NULL,len>0` is
29 * invalid. String lifetime: descriptor/port strings are owned by the node
30 * and valid for the node's whole load; per-call strings are valid only for
31 * that call.
32 * - The host owns all audio buffers and borrows them to the node for the
33 * duration of one `process` call; the node never retains or frees them.
34 * - Status codes, never error returns by sentinel. No callback allocates or
35 * blocks on the audio thread.
36 */
37#ifndef PULP_NATIVE_COMPONENTS_PULP_NODE_V1_H
38#define PULP_NATIVE_COMPONENTS_PULP_NODE_V1_H
39
40#include <stddef.h>
41#include <stdint.h>
42
43#ifdef __cplusplus
44extern "C" {
45#endif
46
47#ifndef PULP_NODE_V1_EXPORT
48#define PULP_NODE_V1_EXPORT
49#endif
50
51/* ───────────────────────── ABI version ───────────────────────── */
52
53#define PULP_NODE_V1_ABI_MAJOR 1u
54/* Minor bumps are additive only (new trailing fields / new capability bits). */
55#define PULP_NODE_V1_ABI_MINOR 0u
56
57/* ───────────────────────── Status codes ──────────────────────── */
58
59typedef int32_t pulp_node_status_v1;
60enum {
69};
70
71/* ───────────────────────── Capability flags ──────────────────────────
72 * Additive negotiation: optional behavior is a bit, never a required field. */
73typedef uint32_t pulp_node_caps_v1;
74enum {
75 PULP_NODE_CAP_STATE_V1 = 1u << 0, /* implements save_state / load_state */
76 PULP_NODE_CAP_RESET_V1 = 1u << 1, /* implements reset */
77 PULP_NODE_CAP_EVENTS_V1 = 1u << 2, /* consumes the event port (extension) */
78 PULP_NODE_CAP_LATENCY_V1 = 1u << 3 /* reports a non-zero latency */
79};
80
81/* ───────────────────────── Opaque handles ────────────────────── */
82
83typedef struct pulp_node_instance_v1 pulp_node_instance_v1; /* node-owned */
84typedef struct pulp_node_host_v1 pulp_node_host_v1; /* host-owned */
85
86/* ───────────────────────── Host services (decision: explicit RT labels) ──
87 * The host hands this to the node at create(). Each callback is labeled
88 * RT-callable or NON-RT-ONLY; calling a NON-RT-ONLY callback from process() is a
89 * contract violation. `host_context` is opaque and passed back to each. */
91 uint32_t size;
92 uint32_t abi_major;
94
95 /* NON-RT-ONLY. Allocate / free host memory for state side-channels. The node
96 * must not pass these pointers to its own allocator, or vice versa. */
97 void* (*alloc)(void* host_context, size_t bytes);
98 void (*free)(void* host_context, void* ptr);
99 /* NON-RT-ONLY. Diagnostic log (UTF-8 ptr+len). Never call from process(). */
100 void (*log)(void* host_context, int32_t level, const char* utf8, size_t len);
101 /* RT-callable. Monotonic nanosecond clock for profiling; allocation-free. */
102 uint64_t (*now_ns)(void* host_context);
104
105/* ───────────────────────── Descriptor ────────────────────────── */
106
108 uint32_t size;
109 uint32_t abi_major;
110 const char* stable_id; /* UTF-8 reverse-DNS-ish id; ptr+len */
112 const char* display_name;
114 uint32_t node_version; /* node-defined, distinct from the ABI version */
116 uint32_t audio_input_count; /* number of mono audio input ports */
117 uint32_t audio_output_count; /* number of mono audio output ports */
119
120/* ───────────────────────── Audio (host-owned, borrowed) ───────────────
121 * Planar float32. `channels[c]` points to `frame_count` contiguous floats.
122 * Channel pointers are never NULL when the count is > 0. In-place processing
123 * (an output aliasing an input) is legal; the node must tolerate it. */
124typedef struct pulp_node_audio_v1 {
125 uint32_t size;
126 uint32_t abi_major;
127 uint32_t frame_count;
128 uint32_t input_count;
129 uint32_t output_count;
130 uint32_t reserved; /* must be 0 (8-byte alignment) */
131 const float* const* inputs; /* input_count planar pointers, read-only */
132 float* const* outputs; /* output_count planar pointers, written */
134
135/* ───────────────────────── prepare() config ───────────────────────────
136 * Any sample-rate or block-size change is a fresh prepare(); the node must
137 * not assume a fixed configuration across prepare() calls. */
138typedef struct pulp_node_prepare_v1 {
139 uint32_t size;
140 uint32_t abi_major;
143 uint32_t reserved; /* must be 0 */
145
146/* ───────────────────────── State writer (decision: bounded ownership) ──
147 * save_state pushes its bytes through this host-provided writer instead of
148 * allocating across the boundary. The host owns the writer; the node calls
149 * `write(ctx, bytes, len)` zero or more times. RT-illegal (NON-RT-ONLY). */
150typedef struct pulp_node_writer_v1 {
151 uint32_t size;
152 uint32_t abi_major;
154 void (*write)(void* writer_context, const uint8_t* bytes, size_t len);
156
157/* ───────────────────────── The node vtable / entry ────────────────────
158 * A node binary exports ONE symbol, `pulp_node_v1_entry`, returning a const
159 * pointer to this table. The host checks `abi_major` + `size`, reads the
160 * descriptor, then drives the lifecycle. Growth is additive via `size`. */
161typedef struct pulp_node_entry_v1 {
162 uint32_t size;
163 uint32_t abi_major;
164
165 /* Static identity. */
166 const pulp_node_descriptor_v1* (*descriptor)(void);
167
168 /* Lifecycle. create() returns a fresh instance (NON-RT). The host-services
169 * pointer stays valid for the instance's lifetime. */
171 pulp_node_instance_v1** out_instance);
172 void (*destroy)(pulp_node_instance_v1* instance);
173
174 /* NON-RT. Allocate scratch for this configuration. */
176 const pulp_node_prepare_v1* config);
177 /* RT-callable. Clear runtime history without reallocating
178 * (PULP_NODE_CAP_RESET_V1). May be NULL. */
179 void (*reset)(pulp_node_instance_v1* instance);
180 /* RT-callable. The audio callback. Host owns buffers. No alloc / lock / log
181 * / IO / panic. On failure, return a status and leave outputs silent. */
183 const pulp_node_audio_v1* audio);
184 /* NON-RT. Release scratch (symmetric with prepare). May be NULL. */
185 void (*release)(pulp_node_instance_v1* instance);
186
187 /* NON-RT, optional (PULP_NODE_CAP_STATE_V1). Opaque versioned state via the
188 * host writer; load validates-before-commit and never unwinds on malformed
189 * input. May be NULL. */
191 const pulp_node_writer_v1* writer);
193 const uint8_t* bytes, size_t byte_len);
194
195 /* NON-RT, optional (PULP_NODE_CAP_LATENCY_V1). Latency in frames. May be
196 * NULL (treated as 0). */
197 uint32_t (*report_latency)(pulp_node_instance_v1* instance);
199
200/* ───────────────────────── Symbol / version handshake ─────────────────
201 * The ONE exported symbol. A node binary defines it; the host resolves it,
202 * checks abi_major + size, and refuses on mismatch. Referencing the symbol
203 * directly lets a static node link without --whole-archive. */
205
206/* Convenience: the ABI major the host was built against. A node can compare
207 * against the entry it returns; the host compares against the node's. */
208static inline uint32_t pulp_node_v1_abi_major(void) { return PULP_NODE_V1_ABI_MAJOR; }
209
210#ifdef __cplusplus
211} /* extern "C" */
212#endif
213
214#endif /* PULP_NATIVE_COMPONENTS_PULP_NODE_V1_H */
struct pulp_node_host_v1 pulp_node_host_v1
Definition pulp_node_v1.h:84
@ PULP_NODE_CAP_LATENCY_V1
Definition pulp_node_v1.h:78
@ PULP_NODE_CAP_STATE_V1
Definition pulp_node_v1.h:75
@ PULP_NODE_CAP_EVENTS_V1
Definition pulp_node_v1.h:77
@ PULP_NODE_CAP_RESET_V1
Definition pulp_node_v1.h:76
uint32_t pulp_node_caps_v1
Definition pulp_node_v1.h:73
const pulp_node_entry_v1 * pulp_node_v1_entry(void)
struct pulp_node_instance_v1 pulp_node_instance_v1
Definition pulp_node_v1.h:83
#define PULP_NODE_V1_EXPORT
Definition pulp_node_v1.h:48
@ PULP_NODE_ERR_OUT_OF_MEMORY_V1
Definition pulp_node_v1.h:64
@ PULP_NODE_ERR_INVALID_ARGUMENT_V1
Definition pulp_node_v1.h:63
@ PULP_NODE_ERR_UNSUPPORTED_V1
Definition pulp_node_v1.h:62
@ PULP_NODE_ERR_INVALID_STATE_V1
Definition pulp_node_v1.h:65
@ PULP_NODE_ERR_MALFORMED_STATE_V1
Definition pulp_node_v1.h:66
@ PULP_NODE_OK_V1
Definition pulp_node_v1.h:61
@ PULP_NODE_ERR_VERSION_MISMATCH_V1
Definition pulp_node_v1.h:67
@ PULP_NODE_ERR_INTERNAL_V1
Definition pulp_node_v1.h:68
static uint32_t pulp_node_v1_abi_major(void)
Definition pulp_node_v1.h:208
int32_t pulp_node_status_v1
Definition pulp_node_v1.h:59
#define PULP_NODE_V1_ABI_MAJOR
Definition pulp_node_v1.h:53
Definition pulp_node_v1.h:124
uint32_t frame_count
Definition pulp_node_v1.h:127
uint32_t input_count
Definition pulp_node_v1.h:128
float *const * outputs
Definition pulp_node_v1.h:132
const float *const * inputs
Definition pulp_node_v1.h:131
uint32_t output_count
Definition pulp_node_v1.h:129
uint32_t size
Definition pulp_node_v1.h:125
uint32_t abi_major
Definition pulp_node_v1.h:126
uint32_t reserved
Definition pulp_node_v1.h:130
Definition pulp_node_v1.h:107
uint32_t audio_input_count
Definition pulp_node_v1.h:116
const char * stable_id
Definition pulp_node_v1.h:110
uint32_t size
Definition pulp_node_v1.h:108
size_t display_name_len
Definition pulp_node_v1.h:113
uint32_t abi_major
Definition pulp_node_v1.h:109
uint32_t audio_output_count
Definition pulp_node_v1.h:117
uint32_t node_version
Definition pulp_node_v1.h:114
pulp_node_caps_v1 capability_flags
Definition pulp_node_v1.h:115
const char * display_name
Definition pulp_node_v1.h:112
size_t stable_id_len
Definition pulp_node_v1.h:111
Definition pulp_node_v1.h:161
uint32_t abi_major
Definition pulp_node_v1.h:163
pulp_node_status_v1(* save_state)(pulp_node_instance_v1 *instance, const pulp_node_writer_v1 *writer)
Definition pulp_node_v1.h:190
pulp_node_status_v1(* create)(const pulp_node_host_services_v1 *host, pulp_node_instance_v1 **out_instance)
Definition pulp_node_v1.h:170
pulp_node_status_v1(* prepare)(pulp_node_instance_v1 *instance, const pulp_node_prepare_v1 *config)
Definition pulp_node_v1.h:175
pulp_node_status_v1(* load_state)(pulp_node_instance_v1 *instance, const uint8_t *bytes, size_t byte_len)
Definition pulp_node_v1.h:192
pulp_node_status_v1(* process)(pulp_node_instance_v1 *instance, const pulp_node_audio_v1 *audio)
Definition pulp_node_v1.h:182
void(* release)(pulp_node_instance_v1 *instance)
Definition pulp_node_v1.h:185
void(* destroy)(pulp_node_instance_v1 *instance)
Definition pulp_node_v1.h:172
uint32_t size
Definition pulp_node_v1.h:162
void(* reset)(pulp_node_instance_v1 *instance)
Definition pulp_node_v1.h:179
uint32_t(* report_latency)(pulp_node_instance_v1 *instance)
Definition pulp_node_v1.h:197
Definition pulp_node_v1.h:90
void * host_context
Definition pulp_node_v1.h:93
void(* free)(void *host_context, void *ptr)
Definition pulp_node_v1.h:98
void(* log)(void *host_context, int32_t level, const char *utf8, size_t len)
Definition pulp_node_v1.h:100
uint32_t abi_major
Definition pulp_node_v1.h:92
uint64_t(* now_ns)(void *host_context)
Definition pulp_node_v1.h:102
uint32_t size
Definition pulp_node_v1.h:91
Definition pulp_node_v1.h:138
uint32_t reserved
Definition pulp_node_v1.h:143
uint32_t max_block_size
Definition pulp_node_v1.h:142
uint32_t abi_major
Definition pulp_node_v1.h:140
double sample_rate
Definition pulp_node_v1.h:141
uint32_t size
Definition pulp_node_v1.h:139
Definition pulp_node_v1.h:150
void * writer_context
Definition pulp_node_v1.h:153
void(* write)(void *writer_context, const uint8_t *bytes, size_t len)
Definition pulp_node_v1.h:154
uint32_t size
Definition pulp_node_v1.h:151
uint32_t abi_major
Definition pulp_node_v1.h:152