Patches
7 · Patch Management (.gvp)
← Parameters · Manual index · Next: MIDI →
A GDVP patch is a .gvp file: human-readable JSON describing a node graph, its wiring, and its
voice-allocation settings. This chapter is the file format reference plus a guide to the bundled
example library. Parser source: gdvp_gvp_parser.c/.h; writer: gdvp_gvp_writer.c/.h.
7.1 The .gvp format
A patch is one JSON object under the key gdvp_patch, with up to four sections:
{"gdvp_patch": {
"meta": { "name": "...", "version": "", "author": "", "category": "" },
"nodes": [ { "id": 0, "type": "oscillator", "params": { ... } }, ... ],
"routing": [ { "src": 0, "dst": 1, "src_port": 0, "dst_port": 0 }, ... ],
"voice": { "mode": 1, "glide_time": 47, ... }
}}
meta
Display metadata, not consumed by the engine — name, version, author, category
(strings; category values like "fx" appear in the library). Buffer limits: name ≤ 64 chars,
the others ≤ 32.
nodes
An array of node objects. Each has:
- id — an arbitrary unique integer. Order is irrelevant; wiring defines execution
(DAG §2.3). Duplicate IDs are a
parse error.
- type — a string naming the node: oscillator, filter, envelope, lfo, vca,
mixer, panner, exciter, the active gfx_* types, and the inactive master_bus type.
- params — type-specific fields. The names match the node pages; e.g. an oscillator takes
waveform, pitch, amplitude, fm_depth, pulse_width, detune; a filter takes mode,
cutoff, resonance, slope; an envelope takes attack, decay, sustain, release,
*_curve, velocity_scale.
Parameter values are the 14-bit CV (or the discrete enum) described in
Parameters §6. Out-of-range values are a parse error (GVP_ERR_PARAM_OUT_OF_RANGE).
routing
The edge list. Each edge is {src, dst, src_port, dst_port} — connect output src_port of node
src to input dst_port of node dst. Port convention: 0 = audio, 1 = control/gate
(DAG §2.1). An edge referencing a non-existent node is a dangling-edge
error. These are your user edges; the compiler may inject extra mixer/up/down edges at load
(DAG §2.3), but those injected edges are not stored in your file.
voice
Optional voice-allocation block (parsed into gvp_patch_meta_t). Fields:
mode, glide_time, unison_count, unison_spread, chord_preset, arp_enabled, arp_type,
arp_gate, arp_latch, arp_octaves, arp_voicing, arp_steps, arp_tempo, delay_enabled,
delay_time, delay_voices, delay_drift.
Note mode and the arp_enabled/delay_enabled flags are independent — Arp and Delay are
interceptors layered on the base allocation mode (Performance §3.1).
All these are UI-space 0–255 / small enums, not 14-bit CV.
7.2 Limits and errors
The parser is zero-allocation and bounded (CR-002/CR-003):
- File size: ≤ 32 KB (
GVP_MAX_FILE_SIZE). Larger →GVP_ERR_FILE_TOO_LARGE. - Tokens: ≤ 1024 JSON tokens (
GVP_MAX_TOKENS). - Nodes: ≤ 64 in the compiled graph (
GDVP_MAX_PATCH_NODES); parsing uses a 256-node sandbox first. Over →GVP_ERR_NODE_OVERFLOW. - Edges: bounded by
GDVP_MAX_EDGES; over →GVP_ERR_EDGE_OVERFLOW.
Common parse errors (gvp_error_t) and what they mean:
| Error | Meaning |
|---|---|
GVP_ERR_MALFORMED_JSON |
Not valid JSON / structure broken |
GVP_ERR_MISSING_NODES |
No nodes array |
GVP_ERR_DUPLICATE_NODE_ID |
Two nodes share an id |
GVP_ERR_UNKNOWN_NODE_TYPE |
type string not recognised |
GVP_ERR_PARAM_OUT_OF_RANGE |
A param value exceeds its valid range |
GVP_ERR_DANGLING_EDGE |
An edge references a missing node |
GVP_ERR_MISSING_NODE_ID / _TYPE |
A node lacks id / type |
The result struct also reports a byte offset and a context detail (e.g. the offending node ID) so the UI can point at the fault.
7.3 Loading and saving
- Load:
gvp_load(path, &ast, &meta, staging_pool)reads the file (the only stdio touchpoint,gvp_read_file) and parses straight into the AST, optionally deserialising parameters directly into a Part's staging pool. The AST then goes to the DAG compiler and is swapped in via the Airlock. - Save: the writer (
gdvp_gvp_writer.c) serialises a Part back to.gvp. It writes from the Part's user edge list (user_edge_*), so what you save is what you drew — the compiler's injected mixer/up/down nodes are not persisted, keeping files clean and re-compilable. The front-panel Save / Save-As flow is in the GUI chapter.
When in doubt about an exact serialized field name or numeric encoding, the authoritative sources are
gdvp_gvp_parser.c(read side) andgdvp_gvp_writer.c(write side). The schema JSON undergdvp/docs/schema/mis/documents the MIDI side.
7.4 The example library
The engine ships ~50 example patches in gdvp/examples/. They double as a tutorial: open them in
the front panel and read the graph. Grouped by what they teach:
Subtractive / classic
simple_synth, bass_lead, super_bass, pluck, analog_brass, detuned_strings,
overdriven_organ, organic_analog_pad, aurora_pad_pink.
Acid / resonant filter
acid_squelch, random_squelch, psycho_lead, Hyperkinetic.
FM (DX-style)
dx7_bell, dx7_brass, dx7_choir, dx7_epiano, dx7_marimba, fm_pad, fm_rim.
LFO routing demos
lfo_vibrato, lfo_tremolo, lfo_pwm, lfo_filter_sweep.
Unison / supersaw
SuperSaw, revolution, french_stapple.
Percussion / noise (Exciter)
808_kick, Grime 808 kick, sub_kick, noise_snare, metallic_hat, vinyl_dust.
Effects-suffixed (✅ GFX effects active)
*_chorus, *_phaser, *_reverb, *_hall, *_echo, *_fuzz, *_fold, *_saturated,
*_compressed, *_tremolo, *_warm (e.g. bass_lead_chorus, organic_pad_reverb,
acid_squelch_hall, simple_synth_echo, overdriven_organ_fuzz).
✅ Effects-suffixed patches. These declare GFX nodes (delay, FDN reverb, phaser, fold, etc.). The GFX family is now fully wired in the dispatch tables and runs on the Global EFX Bus (master-domain, post-mix). The synthesis graph plus the effect tail are rendered. Patches that also include a
master_buswill skip only that inactive node. See Effects §5.2 and Appendix A.
← Parameters · Manual index · Next: MIDI →