AUDIO
Source snapshot · 12 October 2026

Parameters, state, bypass and metering

Foundation now provides borrowed ParameterSchema<N> descriptions with permanent IDs, names, units, defaults, automation metadata and validated physical ranges. ParameterRange maps normalized values through linear or positive logarithmic scales. Linear discrete ranges describe equally spaced steps (including a boolean range with one interval). Finite mapping inputs clamp and snap; nonfinite inputs return None. Mapping uses f64 intermediates and returns f32 values. At extreme ranges, discrete choices remain subject to f32 precision. This is metadata and value conversion, not a general host gesture dispatcher or parameter attachment system. The gain CLAP product has a separate editor control bridge.

Schemas reject duplicate IDs, empty names and invalid defaults. Fixed-size ParameterState<N> is tied to a schema and strictly validates every physical value. State validation does not clamp or snap damaged records. A failed set leaves values unchanged; a failed decode or migration returns no partial result. All these operations use borrowed metadata or stack arrays and do not allocate. Lookup, schema validation, decode and migration have costs proportional to schema size (some are quadratic); select a bounded N before using them in callbacks. No callback deadline is implied.

Topics in this guide

Reusable record and migration

The exact-length little-endian record contains an eight-byte product identity, a nonzero u32 schema version, a u32 field count, then u32 stable-ID/f32 physical value pairs. Its length is 16 + 8*N. Decoding accepts any field order but rejects unknown or duplicate IDs, unexpected versions, incorrect counts, invalid values, truncation and trailing data. Encoding validates destination length and version before writing anything. It performs no stream I/O or allocation.

Products explicitly select a known old version and its schema before decoding. migrate then matches stable IDs to a target schema: additions use defaults, removals are dropped, and existing values must satisfy the target range. Unit changes, ID renames and other semantic transformations require product-specific migration code. Product identity and version selection belong to the consumer; there is no automatic version registry, preset discovery or editor-state format.

Portable gain product

ravet_gain::parameter_schema() describes gain (ID 1, 0 through 4, default 1) and bypass (ID 2, boolean 0/1, default off). GainProcessor::parameter_state() captures both requested values. restore_parameters revalidates against the product schema before changing either value and snaps smoothing to restored gain. Call it only from the thread that owns the processor, after receiving a complete snapshot. For cross-thread state transfer, use the snapshot mailbox, retain old data on contention, and apply accepted restores at callback boundaries. The processor does not own a cross-thread restore mailbox.

state::encode_parameters writes a 32-byte version-two complete record using the existing RAVETGN\0 identity. decode_parameters reads version two or explicitly migrates the existing 20-byte version-one gain record with bypass off. The legacy GainState encoder/decoder remain version one. CLAP now advertises both gain and stepped bypass, saves version two and loads both versions. Its product control bridge provides committed-edit gestures and meter reads; a default macOS embedded gain GUI now supplies graphical controls. See gain session state for the coherent host restore protocol.

Bypass parameter events switch before their sample. Values below 0.5 mean off; values at or above 0.5 mean on. Nonfinite values reject the whole event stream. Bypass copies dry input, with no crossfade, latency compensation or tail policy. Gain smoothing continues while bypassed, so leaving bypass uses the gain reached at that point. Zero-frame events update parameters without advancing smoothing. Reset and reprepare preserve bypass; reset snaps gain and clears meter readings. Abrupt bypass changes can click.

Meter windows and transfer

ravet_signal::PeakRmsMeter accumulates sample peak and RMS over a caller-selected window, using f64 sum-of-squares and a u64 sample count. Nonfinite samples count as silence and set a flag; finite audio samples are not clipped. The meter stops accepting samples at u64::MAX. Reset starts a new window. These are sample peak and RMS, without true-peak detection, decay, loudness weighting or smoothing.

The gain processor exposes input/output readings per channel for the latest successful nonempty block. Unused channels are zero. Empty or rejected blocks retain the previous reading; preparation and reset clear it. Nonfinite audio is flagged in telemetry without modifying the audio signal. Changing block length changes the measurement window, so displays must choose their own ballistics.

On targets with 64-bit atomics, GainMeterMailbox transports all four readings as one coherent 20-word snapshot. The audio owner explicitly calls try_publish(processor.meters()); control/editor code calls try_read() and retains the previous reading on None. Publication makes one attempt and may fail immediately on contention. Intermediate blocks coalesce: this does not retain every peak, schedule UI work, or guarantee delivery of every block. Keep meter publication separate from parameter restore publication.

Tests cover mappings and range extremes, malformed schemas/records, ID-based migration, legacy state migration, sample-timed bypass with continued smoothing, stereo meter windows, output tails, faults and nonfinite audio. Heap probes cover 1,000 complete state encode/decode/restore, bypass, meter publication/read and reset cycles. These are offline framework tests, not device or DAW evidence.

Native f64 gain and metering

GainProcessor64 provides the same mono/stereo gain/bypass IDs, schema, state record, event timing and f32 parameter/smoother policy as GainProcessor. Its sample copying/multiplication stays native f64; each f32 smoother value promotes exactly before multiplication. This does not increase parameter resolution. Reset/reprepare snap smoothing as before. Dry bypass retains exact f64 samples while smoothing continues. Validation rejects before DSP state mutation; rejected and zero-frame blocks retain the last complete meter snapshot.

GainMeters64 exposes native f64 input/output levels. PeakRmsMeter64 uses a scaled sum of squares to avoid overflowing on finite f64 maxima and retain subnormal levels. Nonfinite samples count as silence and set the diagnostic, without sanitizing audio. At u64::MAX samples, further samples are ignored. MeterReading64::telemetry_f32 explicitly saturates finite levels to f32::MAX; this telemetry conversion does not narrow audio or imply nonfinite input. The existing f32 meter/mailbox and exported gain adapters remain separate APIs.

Tests cover sub-f32 audio differences, event gain/bypass, extreme finite RMS, nonfinite metering, subnormal levels, rejected-state/tail preservation, zero-frame edits, smoothing/state/reset and 10,000 prepared f64 workloads with no heap operations. Native format mapping requires separate ABI/host evidence. See decision 0065.

Borrowed CLAP metadata registration

ravet-clap::ClapParameterRegistration validates a portable schema with an ordered array of ClapParameterOptions, then provides complete count/info metadata for a product's PluginMainThreadParams implementation. Preparation borrows storage, without allocation; repeated metadata reads are heap-free. Physical f32 bounds/defaults promote exactly to CLAP f64 plain values, including continuous logarithmic schemas. Normalized editor mappings remain separate.

There are 0..1024 parameters. Names must fit 255 UTF-8 bytes and module paths 1023 bytes without NUL; the CLAP invalid ID is rejected. Discrete schemas need unit-spaced integer bounds; fractional/coarser steps require an explicit separate wire mapping. At most one bypass is allowed, with stepped 0/1 range. Automatable flags come from the schema; requires_process is explicit consumer policy. Explicit global/scoped modulation/automation flags are described below. No cookies, value storage, display formatting, flush, rescan or lifecycle scheduler is generated. The gain reference consumes the registration and advertises that active gain/bypass changes require processing.

Acceptance checks complete metadata, continuous/logarithmic/negative integer ranges, exact flags, wire/string/ID/bypass/capacity rejection, 10,000 heap-free reads and the linked actual gain host extension. See decision 0073.

Immutable complete parameter programs

ProgramBank<N> borrows ParameterProgram<N> entries and the same validated ParameterSchema<N> used for parameter state. Preparation validates all entries strictly before registration: 1..128 programs, 1..1024 parameters, <=65536 values total; complete canonical physical states, nonblank names <=255 UTF-8 bytes with no NUL, unique stable ProgramId and unique zero-based MIDI bank/number address (0..16383/0..127). Names may repeat; permanent IDs remain separate from indices and MIDI addresses. Signed zero normalizes when obtaining a ParameterState.

index and midi_index perform bounded exact lookups; state(index) proposes a complete copied state. Invalid/unavailable lookup yields None, preserving all consumer state. Editing a returned state never changes the bank. Construction, lookup and copying use no heap, locks or I/O. The bank has no mutable current program or sound engine. Consumers decide atomic publication, identity after edits, voice/history handling, host registration/notifications and persistence. See decision 0080 and the separate MIDI request decoder.

Complete gain reference programmes

ravet_gain::GAIN_PROGRAMS and factory_program_bank() provide Unity, Silence and Bypass as complete physical gain/bypass [1,0], [0,0], [1,1], with permanent IDs 1..3 and MIDI bank 0/numbers 0..2. These are selection proposals; the portable processors ignore raw MIDI program changes and have no current program identity. Consumers restore a complete state or schedule both control events under their existing lifecycle/timing/smoothing rules. The unchanged complete state codec persists actual controls, including custom edits, rather than a catalogue index.

Native SDK consumers use RavetGainPrograms.h: immutable count and atomic copied metadata include stable ID, complete controls/address and zero-padded 128-byte UTF8 name. Results 0/1/2 mean success/rejection/contained panic. A failed call preserves every output field; callers own live aligned writable ranges. Normal validation/copy is heap-free with no locks/I/O or live DSP access. This reference ABI does not generate host menu/selection/publication policy. See decision 0083.

Explicit parameter gesture events

EventData::ParameterGesture { id, phase } carries a raw global begin/end boundary with stable parameter identity and sample offset. It changes no scalar value and imposes no ownership, pairing or recording policy. Parameter graph filters include matching boundaries; performance filters exclude them. Complete worker event queues retain their identity, phase and order. Generated CLAP output maps boundaries without a MIDI port; hosted graph output requires an explicit opt-in and writable output mapping. See the hosting guide and decision 0121.

with_parameter_gesture_input(true) on ParameterEvents or any CLAP bridge also accepts raw native begin/end input; the default continues to ignore it. Process offsets and same-frame order are preserved; flush offsets normalize to zero. All native events still count against traversal capacity and timing checks. No pairing/base edits or automatic recording are inferred. Hosted native nodes use the same named builder option with an explicit writable input map; disabled or unknown input rejects the complete input before any native call. See decision 0130.

Global modulation signals

EventData::ParameterModulation { id, amount } carries a finite signed physical amount separately from saved base values. A new amount replaces the previous signal; the consumer implements combining, clipping, smoothing, reset and persistence. Parameter graph filters include the matching ID; performance filters exclude it. Complete worker queues preserve order and reject non-finite amounts.

CLAP input translation is opt-in through with_global_parameter_modulation(true) on ParameterEvents, EffectBridge, MainBusBridge or MultiBusBridge. Default input continues to ignore modulation. Only global targets map; native amounts must narrow to finite f32, and flush normalizes offsets to zero. Invalid whole input rejects before DSP. Generated output maps global amounts without a MIDI port and preserves host prefix refusal. Exporters must advertise compatible native flags and explicitly implement DSP; no reference processor support or saved-state changes are synthesized. See decision 0122.

ClapParameterOptions::global_modulation (default false) advertises the native modulatable flag for global physical amounts. It does not enable bridge input or implement DSP; exporters explicitly align the registration option with their processor and bridge. Hosted node input/output independently opt in to cached writable/modulatable maps. See the hosting guide and decision 0123.

Scoped values and modulation in exported CLAP adapters

ParameterValueScoped { id, target: NoteTarget, value: f64 } and ParameterModulationScoped { id, target, amount: f64 } retain finite full f64 physical values/amounts within a routed note input endpoint. Optional channel/key/ ID fields are matching wildcards. An all-wildcard target is still port-scoped; global values/modulation keep their existing separate f32 events. Scoped events neither edit saved base state nor combine/clip/smooth voices automatically. CLAP consumers must implement its global/polyphonic override rules explicitly.

Prepared event queues retain all bits, and parameter-ID graph filters include scoped events while performance filters exclude them. Exported translator/effect/ main/multibus with_scoped_parameter_input_port(Some(index)) and main/multibus with_scoped_parameter_output_port(Some(index)) select independent 0..256 note input indices. Generated scope targets originating input ports, independently of note output/MIDI/UMP selectors. Defaults ignore scoped native input and reject unrepresentable whole generated scoped streams before host prefixes. Invalid selected raw fields/IDs/nonfinite values reject input before DSP; unrelated or wildcard ports filter. Raw all--1 scope alone is global, so Clack negative-field normalization cannot turn malformed scope into a global edit.

Scoped input preserves process timing and normalizes parameter-flush offsets to zero. Generated scoped parameter flush is allowed at zero time; performance flush restrictions do not apply to these parameter events. Native note IDs must fit nonnegative i32. Missing scope routes/too-wide IDs/reserved parameter IDs reject whole delivery while retaining successful audio/DSP; host refusal still discards its undelivered suffix without replay. Native cookies are empty. Parameter ranges, metadata, voice precedence, lifecycle and saved-state behavior remain consumer-owned.

ClapParameterOptions::scoped_automation and scoped_modulation independently advertise ClapParameterScopes { note_id, key, channel, port }, all false by default. NONE/ALL are const presets for static options. These flags enable neither translation nor DSP and do not alter global automation/modulation flags. Current public gain options use NONE. Tests cover every eight-flag combination, portable ranges/queues/graph filters, exact native input/output/flush and malformed scopes with heap-free prepared workloads. Hosted metadata validation is a separate profile; no reference instrument/DAW/voice/deadline claim is introduced. See decision 0137 and the primary CLAP parameter flags.

Hosted graph builders can independently enable mapped scoped input/output on a selected CLAP note input port. Cached native scope flags, writable metadata, range/step and native identity limits validate before input callbacks and during output collection. This profile chooses the most specific target dimension (ID/key/channel/port); global flags do not imply scoped support. Full-f64 scoped process/flush values remain separate from saved base state. See mapped scoped parameters.

Optional native facades expose bounded global schema metadata, pure range mapping, complete stopped-owner snapshots/state and explicit consumer legacy decoding through the native processor companion. The portable processor stays backend-independent; live publication, scoped metadata and SDK registration remain separate consumer/backend work.

The optional native live-state companion adds an independent coherent publication object and explicit prepared audio apply/conditional reflection for facades that opt into heap-free base-state hooks. Its ownership, Busy/Stale retry and newer restore priority are described in native processing.

Native consumers can also prepare an immutable schema cache on control for provider-free scalar mapping and complete normalized-event conversion on audio. See cached native parameter mapping.

Consumers with an existing explicit controller publication protocol can opt into direct native audio-owner complete state. It uses a control-created immutable cache and exclusively prepared owner, with whole-state preflight before one atomic restore and revalidated ordered snapshots. No byte codec/provider runs on audio, and no implicit mailbox or host scheduling is added. This direct companion and its explicit audio hooks have no 64-bit atomic requirement; coherent live native publication retains its independent atomic gate.

Prepared native telemetry exposes complete stable-ID physical f64 readouts and exact measurement-window counts on exclusive prepared audio owners. Its independent metadata/cache/table keep meter observations separate from saved f32 parameter state; consumers explicitly own UI/host publication, display normalization and measurement/retention policy.