Documentation

SFZ compatibility inventory

sfz-opcodes.json is an implementation inventory, not a full-compatibility claim. It records the pinned SFZ Format syntax database, including aliases and nested modulation families, alongside author-published sfizz and LinuxSampler support claims. Source revisions, URLs, licensing, snapshot hashes, and limitations are in the file.

comparisonContract freezes the finite sfz-public-2026-10-31 baseline:898 opcode/family spellings,9 headers, named reference profiles and the SFZ-applicable NKSP language surface. Per-row evidence remains incomplete; the current profile updates below supersede historical implementation labels for the rows they explicitly name. New source publications require a deliberate new baseline rather than silently moving the completion target. This developer specification is outside DSP digest inputs.

columns names the fields of each compact rows entry. details adds enum options and alias/index relationships. coverageProfiles separates parser acceptance, native implementation, WASM, live playback, and offline rendering. Representative fixtures do not prove every row or interaction. unimplemented rows remain requirements; rejecting them cleanly does not count as implementing them.

Names containing N, X, or NN represent indexed families. Numeric domains, scope exceptions, controller curves, smoothing, step behavior, and dialect conflicts still need individual semantic evidence. The second filter and indexed LFO sub-oscillators are distinct semantic instances even where the source database groups their documentation under an alias. Do not inflate coverage by counting aliases as separate functions.

The inventory deliberately retains missing values as null and unpublished reference behavior as unknown. ARIA/Cakewalk extension names in a public database are not evidence that a closed reference engine was run. No build, test, or application command reads local files under tmp/ to consume this inventory.

The earlier unresolved list contained 33 spellings. Nineteen now have implemented, tested behavior under the profiles below: amp_veltrack_random; position_keycenter, position_keytrack, position_veltrack, position_random; load_start, load_end, load_mode; the four varNN families; and the seven effect settings rectify, rectify_mode, rectify_onccN, filter_gain, filter_gain_onccN, gain, and gate_hold. The amplifier tests, storage runtime tests, variable tests, and effect tests provide owning evidence for their specified behavior. Historical unimplemented labels in the pinned source inventory are not the current status of these nineteen rows. Representative native and WASM audio checks do not establish every target combination, proprietary random sequence or complete reference-engine equivalence.

Fourteen entries remain unimplemented: the EG rectify/ringmod spellings and their CC forms; the sample_dyn_param destinations and their EG/LFO forms; internal, param_offset, vendor_specific, and waveguide. The EG operation, depth and application order and the external destination/algorithm contracts remain insufficiently established. A reference probe without a working same-context positive control is inconclusive. Existing oscillator ring modulation and strings processing do not implement these spellings. Unsupported declarations are diagnosed, and incomplete instruments are rejected rather than played with those declarations silently omitted. These rows remain in the completion denominator. The four hint_* rows are separate vendor hints that primary documentation permits other engines to ignore. Undefined values such as ARIA curves 4–6 likewise remain explicit limits.

The inventory’s modulationCompiler entry describes the earlier metadata-only section. The current compiler contract is authored in modulation-schema.js; gen-sfz-schema.mjs, invoked by the normal DSP parameter generator, emits SFZModulationSchema.h. Property IDs, per-kind defaults, units, sampling rules, filter types and state-storage bounds have one source. SFZ section v3 uses existing bank v7/v8 h10/h11; SF2 retains bank v9 and its separate section v2/raw-generator semantics. Compiler representation does not establish native, WASM, live or offline coverage.

The profile definitions below specify independently authored behavior; they do not declare every consumer enabled or verified. Native preparation validates typed records separately from the engine’s implemented-kind and property admission gates. Compiler tests check representation; native preparation tests check exact decoding and memory admission using a fixture generated by the tracked production compiler generator. Actual audio, streaming retry, checkpoint and live/offline tests must establish the corresponding runtime claims. No compatibility result follows solely from an enum, accepted field or helper test.

Section v3 contains a 14-word header, six-word region directory, ten-word routes, 129-word custom curves, six-word instances and four-word parameters. Offsets are section-relative words; region directories index records. Route destinations and generator references are region-local. Only used instances are allocated, with their typed default parameters and semantically required intermediate stages. Legacy modulation CC records are omitted when v3 is present; controller conditions and initialization remain separate.

The independent modulation profile applies source curves, two-source products, depth, nearest target-unit steps and linear smoothing in milliseconds. A new voice starts at the current controller value without an artificial ramp. Cross-generator parameter dependencies use the previous-sample source vector, followed by simultaneous generator advancement; direct audio destinations use the current output. This defines feedback without index-order bias and is not a claim of proprietary-engine parity. Explicit *_mod overrides authored routes; the required amplitude envelope remains multiplicative. Percent-valued multiplicative routes divide by 100, while a multiplicative cents route into filter cutoff converts cents to a frequency ratio.

Controller variables combine weighted, individually curved controller inputs with add (the default) or mult, then route the result to existing audio targets. Definitions inherit through global, master, group and region scope and remain region-local. More than two inputs are supported. Variables do not target other variables, EGs or LFOs, and existing controller/curve validation still applies. Reference comparisons establish the tested add/product/default/curve and controller-change cases; they do not establish all possible target interactions.

Flexible envelope curve references use the declared custom LUTs; shape is applied before the curve under this profile. The independently defined loop runs from its loop node through its sustain node while held: zero loop count repeats indefinitely, a positive count limits complete repeats, and release exits to the segment after sustain from the current level. Undefined ARIA controller curves 4–6 are diagnosed. LFO waves 8/9 have no published algorithm and 10/11 are reserved; they are diagnosed rather than assigned invented waveforms. Publicly defined waves and custom curves remain implementation requirements. Coverage rows stay unchanged until their owning rendered evidence exists.

The public egN_pan_curve page names the parameter without defining its mathematics. This profile applies the referenced existing curve LUT to that EG source’s pan contribution before depth and combination, using the same index validation as other curve references; omission leaves the source unchanged.

Virtual CC128 uses (bend + 8192) / 16383, with center 8192 / 16383; curve 1 supplies bipolar conversion when selected. The ordinary implicit MIDI pitch-bend path is separate and unchanged, without an additional implicit modulation route. Virtual CC155 uses source-sample frames, matching sample-offset units. These normalization and unit choices are explicit independent profile decisions, not verified proprietary-reference behavior.

Pitch controls append typed region properties without changing the section layout. Public bend_step defaults to one cent; bend_stepup and bend_stepdown select each wheel direction independently. The effective authored order resolves shared versus directional step assignments. This profile rounds the ordinary bend to the nearest step, with ties away from zero, then applies the existing linear ramp for bend_smooth milliseconds. A new voice starts at its current bend, including the existing channel RPN bend-range scaling. global_tune, master_tune and group_tune inherit independently and add once to ordinary region tuning; a more local assignment replaces the same named setting.

note_offset and octave_offset are control-header settings. They combine as semitones plus twelve times octaves, independently of sw_note_offset and sw_octave_offset. This profile gives the switch variants the corresponding ordinary offset defaults and ranges. Physical MIDI identity owns note-off correspondence, polyphonic pressure and held-key bookkeeping. The shifted musical key drives region selection, sounding pitch, script note values, born-key modulation and accepted-note/sequence facts, including virtual CC133/140/141. Switch recognition instead uses the physical key plus the separate switch offset. Out-of-range shifted notes are absent rather than clamped to an endpoint. Control settings apply to the whole collection; the last assignment to each setting wins. This defines the unspecified interactions explicitly without claiming proprietary-engine parity.

Oscillator sources use a separate used-instance kind and per-voice phase/RNG state. File cycles require oscillator=on; built-in source names remain generators. The selected sample interval is one complete cycle, with its original sample rate disregarded and middle C as the root. oscillator_table_size=0 retains the cycle length; positive sizes resample periodically during preparation, subject to the bank budget and the unsigned 32-bit sample-frame representation. Prepared cycles contain successive cyclic half-rate levels of lengths N, ceil(N/2), through 1; their total is approximately 2N plus rounding, and memory admission includes the source and all prepared levels. Logical playback still spans the original N frames. The final level retains the original cycle mean, while the reader blends adjacent levels for continuous pitch changes. Streamed cycles pin every prepared page before playback. White noise advances continuously through the project’s seeded RNG rather than looping a noise buffer.

The oscillator profile uses the published unison detuning and stereo gains without gain normalization. Phase is in degrees, with negative values selecting a reproducible random initial phase. Modes 1/2 use two operators for PM/FM; mode 0 with two oscillators uses ring modulation. Detuning is in cents. Modulation depth is a percentage, with 100 representing index one: PM adds that index times the modulator in radians, FM adds index times modulator frequency times its sample value, and ring modulation blends dry carrier with the product. The LinuxSampler-published table’s cents description conflicts with the modern authored reference profile; this implementation explicitly chooses the latter units, without adopting implementation code or claiming binary parity. Quality 0/1 select nearest/linear lookup, 2 uses the existing band-limited FIR, and 3 interpolates adjacent FIR coefficient phases. The native consumer owns rendered quality evidence. Public waveguide documentation does not define its algorithm; it remains a precise unsupported profile rather than an invented string model.

Sample timing uses actual transport PPQ: the next sync_beats grid shifted by sync_offset establishes the origin, followed by beat delay and then seconds/sample delay. An exact grid position starts immediately. stop_beats is measured from that same origin. Pending attack notes are cancelled by their corresponding note-off; release-trigger regions remain separate. Sample delays use host-rate frames. Whole-sample count repeats the selected sample interval without retriggering the envelope; positive counts imply one-shot lifetime, while zero leaves normal playback unchanged. Loop direction affects only the loop segment; alternate loops visit each endpoint once on reversal. loop_lengthccN changes the end address. Percent offset applies to the fixed and controller offset, while random offset remains source frames. Sample fadeout is linear in seconds and ends with the sample.

Typed integer settings do not pass through float32: UInt32 uses parameter word 2 with word 3 zero; UInt33 uses word 2 as the low 32 bits and word 3 bit zero as the high bit, limited to 2^32. The storage tag comes from the generated property table; other word-3 bits are reserved. These apply to table size, loop repeat limits and the full-width sample delay, random offset and play count. Integer sample-delay and sample-mode offset controller depths use route flag 8 with magnitude in word 3, flag 16 for the high bit and flag 32 for a negative sign. Percent offsets and ordinary continuous routes retain float32 amounts. Exact integer birth values combine with controller contributions in double precision before flooring and range clamping; ordinary MIDI controllers use the exact integer value divided by 127 in that arithmetic.

Reverse-controller conditions are evaluated at voice birth. This profile requires all declared reverse ranges to match, while an unconditional reverse direction remains unconditional. Loop repeat limits count additional traversals, independently of whole-sample play count. Full signed 32-bit group and off_by identities are mapped to compact equality tokens during preparation, with zero reserved; authored IDs remain intact in source metadata.

Global, master and group volume and amplitude settings inherit independently. Their volumes add in dB and their amplitude percentages multiply, separately from ordinary region volume/amplitude and before the corresponding script adjustment. High-resolution controller initialization retains its normalized value alongside rounded ordinary MIDI identity; later MIDI controller messages replace both. The last effective initialization assignment wins across ordinary and high-resolution spellings.

The pedal threshold definition uses raw CC units 0–127, with default 0.5: value 0 is up, value 1 is down; threshold 64 instead switches between 63 and 64. SF2 retains its separate GM pedal semantics. note_selfmask=on protects louder same-key voices from a softer retrigger. Release decay uses the corresponding attack’s age; indexed segments accumulate signed dB-per-second rates, including the published negative-rate example. Missing final duration means an indefinite final segment. The published polyphony-stealing fixture defines mode 0 as oldest-first and mode 1 as protection for sustained notes; other mask bits remain undefined.

For sw_vel=previous, this profile uses the last accepted keyswitch velocity for musical velocity selection, modulation and gain, falling back to the current velocity when no prior switch exists. Physical MIDI identity and ownership remain unchanged. This follows the published Cakewalk interpretation rather than ARIA’s gain-only interpretation.

Off curves retain positive and negative shape values. The independent release profile uses a static hold for -2, linear release for -1, a power curve for 0 (negative shape mirrors the positive power), normalized exponential base magnitude for 1 (negative shape reverses curvature), normalized logarithm for 2, and the existing normalized exponential for vendor mode 10. Endpoints remain one and zero, with zero shape interpreted linearly. This supplies explicit bounded behavior without claiming proprietary curve parity.

Embedded <sample> content follows the published byte alphabet, isolated before text decoding, comments and macros. Original definitions remain the saved source; embedded audio uses the ordinary decoder and bounded sample readers. Instrument labels and the last declared image are presentation metadata, displayed after the main controls. Active keyswitch labels require native accepted-switch observations, not an independent UI interpretation of MIDI. The published hint rule explicitly permits other engines to ignore ARIA-specific hint_* settings; they remain recorded as intentionally ignored vendor hints.

Declared md5 values verify the original encoded audio-file bytes, including decoded embedded payload bytes, before audio decoding. A missing named sample may be resolved by its fingerprint among already granted candidate files. Renamed-file searches use the caller’s existing I/O budget and bounded directory enumeration; saved source definitions retain their authored paths and fingerprints. A mismatch is an integrity failure, not a silently omitted region.

Amplifier velocity curves linearly interpolate authored amplitude points with implicit endpoints 0/0 and 127/1. Without a custom curve, the default is squared normalized velocity. Ordinary and randomized velocity tracking share the signed affine profile: with curve value C, birth random U in [0,1], and t = amp_veltrack / 100 + amp_veltrack_random × U, gain is 1 − t × (1 − C) for t ≥ 0 and t × (1 − C) otherwise. A depth of 1 adds 100 percentage points; it is not divided by 100 or clamped. Zero random depth adds no random draw. Legitimate negative gain retains its polarity. This independently measured response does not claim the proprietary RNG sequence or unmeasured reference behavior of held-note controller changes. Pan key, velocity and born-random contributions add to ordinary pan before clamping. Explicit balance pan attenuates the opposite channel linearly, while MMA uses equal-power sine/cosine gains; omission retains the ordinary pan policy. Phase inversion changes polarity. Key, velocity and controller crossfades multiply their independently calculated weights; gain uses a linear weight and power its square root. Controller crossfades remain continuous audio controls, not region-trigger conditions.

The four position settings add a birth contribution to the existing position control before one clamp to −100…100: (musical key − key center) × key tracking + velocity / 127 × velocity tracking + U × random depth. The default key center is 60. Random depth is signed and one-sided; it does not reuse a bipolar pan draw. This defines the implemented profile without claiming a matching proprietary random sequence.

Loading mode 0 (default) uses F32 cache storage; mode 1 uses signed PCM16. CONTROL publication converts F32 to PCM16 by nearest-away-from-zero rounding and saturation, without dither. Authored load ranges use source-frame coordinates and an inclusive end, converted once to a half-open resident interval; missing bounds mean start 0 and end of source when either bound is authored. Without either bound, normal automatic streaming applies. These loading choices preserve playback offset, end and loop coordinates. Pages outside the resident window remain streamable. Precision conversion, endpoint/default rules and shared-window union are explicit implementation choices, not a claim of complete proprietary loading-policy equivalence. SFZ streamed bank v10 carries the storage mode and resident intervals; existing v8 and SF2 v9 remain separate supported formats.

High-resolution controller conditions retain normalized values instead of comparing rounded MIDI identities. Controller start and stop ranges act on each received matching controller event, including events with no MIDI note; they are distinct from note-birth range predicates. An unassigned bound is -1. BPM conditions include their lower bound and exclude their upper bound. The independent timer profile measures seconds since the last accepted sample birth in the same lexical group and MIDI channel. All layers of one event inspect the same prior timestamp, committed after selection. Initial age is infinite, so a finite recency upper bound excludes the first birth while an omitted upper bound permits it.

The documented key=-1 sentinel disables ordinary note selection while retaining controller-trigger actions. end=-1 performs a silent region action, including exclusive-group muting, without reading an irrelevant sample or creating an audible voice. Prepared key/sample geometry remains valid and separate typed flags preserve those actions; original source declarations are retained. These flags require actual native event handling, not merely successful parsing.

EQ types use the three existing EQ bands, with peak, low-shelf and high-shelf choices, independently of filters 1 and 2. The update profile evaluates explicitly static EQ settings at birth and dynamic settings during playback. Frequency modulation in Hz adds to the base frequency; cents mode applies a frequency ratio to the base. The mode and update policy are typed band settings rather than duplicated audio routes. Sample quality retains its distinct published 1–10 domain. Native interpolation and band processing still require their owning rendered evidence.

The first WAVE smpl loop supplies omitted region loop points and loop mode. Authored SFZ points override that metadata; loop_end_offset=-1 adjusts only the metadata-derived start and end points. Loop metadata is read through bounded chunk ranges without decoding sample PCM. SFZ effects use section v4, extending the v3 header with the offset and length of a typed FX section. Impulse responses share the bank’s sample storage, including dependencies used only by effects; streamed responses must have all pages prepared before activation. The separate SF2 modulation section remains unchanged. Producer serialization alone does not establish effect playback coverage.

The effect profile also accepts type=gain, with gain in dB and default 0; type=rectify, with a 0–100 blend amount and rectify_mode=half (default) or full; filter_gain in dB for the existing peaking/shelf response; and gate_hold in seconds, default 0. The CC forms use the existing typed effect routes. Rectification uses first-order antiderivative antialiasing, with half-sample smoothing phase and no integer-frame lookahead; amount 0 is exact bypass. Half rectification at amount 100 equals full rectification at amount 50. Gate hold counts processed frames before release. The implementation is independently authored from the published parameter contracts; its antialiasing, filter coefficients and complete PCM output are not claimed to match a proprietary or reference engine.

When behavior changes, update the relevant coverage profile or row and add the owning native/WASM/live/offline fixture evidence. Refresh source snapshots deliberately and review changed semantics before moving their comparison baseline. Keep test execution results separate from author-published support claims.