Performance
3 · Performance & Expression
← The Node Graph · Manual index · Next: Node Reference →
This chapter covers how GDVP turns your playing into voices: the eight voice modes, glide,
unison, chords, the arpeggiator, the strum/delay allocator, and expressive control (velocity,
pitch bend, pressure). All of this is per-Part and lives in the Voice Allocation Manager (VAM),
gdvp_voice_manager.c/.h.
3.1 Voice modes
Each Part runs in exactly one of eight voice modes (gdvp_voice_mode_t). The mode decides
how incoming notes claim voices from the pool.
| # | Mode | Behaviour |
|---|---|---|
| 0 | MONO | One voice. Re-triggers itself on each new note. No portamento — glide is LEGATO-only (see GLIDE). |
| 1 | LEGATO | One voice. Overlapping notes glide without re-triggering envelopes or resetting oscillator phase. |
| 2 | POLY | Standard polyphony, LRU voice stealing, up to 16 simultaneous voices. The default for most patches. |
| 3 | UNISON | One note → N detuned voices stacked. Spread set by the unison spread parameter. |
| 4 | DUO | Two-note polyphony; the voice budget is split, ~N/2 voices per held note. |
| 5 | CHORD | One note triggers N voices at fixed harmonic intervals from a chord preset. |
| 6 | DELAY | Strum/echo: one note spawns several voices with staggered onset times. |
| 7 | ARP | Arpeggiator: held notes are played back as a timed sequence. |
Source: gdvp_voice_mode_t in gdvp_voice_manager.h. Internally the engine separates the
allocation strategy (poly/mono/legato/unison/duo/chord, gdvp_voice_allocation_t) from two
interceptors (Arp and Delay) that sit in front of allocation — which is why, in patches,
you'll see both a mode field and independent arp_enabled / delay_enabled flags
(patch voice section).
Switching mode performs a clean state-transition flush: all active voices are hard-cut and
mode-specific buffers (e.g. arpeggiator memory) are cleared, so you never get ghost notes
bleeding across a mode change (gdvp_part_set_voice_mode).
3.2 Glide / portamento
In MONO and LEGATO, successive notes glide in pitch instead of jumping. Glide is a single parameter:
- Glide time — UI range
0–255, where0= instant (no glide) and255= slowest. It maps to the oscillator'sportamento_shift(an EMA slew factor). Because the engine slews the linear pitch CV in Q16.16, the resulting frequency contour is exponential — i.e. constant-time, musically correct portamento. See Oscillator: pitch slewing.
Voice-param key 0 (glide_time) via gdvp_param_bridge_update_voice_param.
3.3 Unison
UNISON stacks several detuned copies of every note for thickness.
- Unison count —
2–16voices, default 4. (Voice-param key1.) - Unison spread — UI
0–255, scaled internally to a 14-bit detune CV that fans the voices symmetrically around the played pitch. (Voice-param key2.)
Spread is in the same pitch-CV currency as everything else (128 CV = 1 semitone), so modest
spread values stay within a few cents — the classic "supersaw" thickening rather than a chord.
The SuperSaw.gvp example is built on this (library).
3.4 Chords
CHORD mode turns a single key into a voiced chord using one of 12 built-in presets
(gdvp_chord_presets[]). Intervals are expressed in pitch CV (128 = 1 semitone):
| Idx | Name | Notes | Intervals (CV) | In semitones |
|---|---|---|---|---|
| 0 | MAJ | 3 | 512, 896 | +4, +7 |
| 1 | MIN | 3 | 384, 896 | +3, +7 |
| 2 | MAJ7 | 4 | 512, 896, 1408 | +4, +7, +11 |
| 3 | MIN7 | 4 | 384, 896, 1280 | +3, +7, +10 |
| 4 | DOM7 | 4 | 512, 896, 1280 | +4, +7, +10 |
| 5 | DIM | 4 | 384, 768, 1152 | +3, +6, +9 |
| 6 | AUG | 3 | 512, 1024 | +4, +8 |
| 7 | SUS4 | 3 | 640, 896 | +5, +7 |
| 8 | SUS2 | 3 | 256, 896 | +2, +7 |
| 9 | PWR | 2 | 896 | +7 (fifth) |
| 10 | OCT | 2 | 1536 | +12 (octave) |
| 11 | 5+OCT | 3 | 896, 1536 | +7, +12 |
The played note is the root; intervals add on top. Each chord tone consumes a voice, so a MAJ7
chord uses four voices per key. Chord preset is voice-param key 3. Source:
gdvp_chord_presets[] in gdvp_voice_manager.h.
3.5 The arpeggiator
ARP mode (mode 7, or the arp_enabled interceptor) is a true multi-key arpeggiator with its own
DSP-side state (gdvp_arp_dsp_state_t): it holds up to 16 depressed keys (sorted, with
velocities), a playhead, and a tick countdown synced to transport.
Arp parameters
| Parameter | Values | Notes | Key |
|---|---|---|---|
| Type | UP / DOWN / UP+DOWN / RANDOM | Sequence direction (gdvp_arp_type_t). RANDOM uses an LCG PRNG. |
4 |
| Tempo / division | 0=1/4, 1=1/8, 2=1/8T, 3=1/16, 4=1/16T, 5=1/32 | Step length against the 96-PPQN clock. | 10 |
| Gate | 0–255 (128 = 50%) |
Fraction of each step the note sounds. | 5 |
| Latch | on/off | Keeps the arp running after you release the keys. | 6 |
| Octaves | 0=1oct … 3=4oct | Octave-span the pattern walks through. | 7 |
| Voicing | 0=MONO, 1=MULTI, 2+=chord preset | Each step can be a single note or a voiced chord. | 8 |
| Steps | 0=Auto, 1–64 | Truncate the pattern to a fixed number of steps. | 9 |
| Env mode | 0=Legato (sustain-through), 1=Soft-retrigger | Whether each step re-strikes the envelope. | — |
Division maps to PPQN ticks directly (1/16 = 24 ticks; see gdvp_arp_division_t). Configure via
gdvp_vam_set_arp_config (host) or the per-mode voice params; latching is also intercepted so
releasing all physical keys clears the latch tracking (physical_keys_down). Source:
gdvp_arp_dsp_state_t, gdvp_voice_manager_state_t.
3.6 Strum / Delay allocation
DELAY mode (mode 6, or the delay_enabled interceptor) spawns several voices from one note with
staggered onsets — a strum or echo built from real voices rather than a delay line.
| Parameter | Values | Meaning | Key |
|---|---|---|---|
| Delay time | 0–255 |
Stagger interval between successive voices (maps to a PPQN offset). | 11 |
| Delay voices | 1–6 |
How many strummed voices. | 12 |
| Delay drift | 0–255 |
Pitch drift added per successive voice, for human-strum detune. | 13 |
Source: gdvp_voice_manager_state_t delay fields. This is distinct from the audio
delay effect node — DELAY mode is a voice-allocation effect.
3.7 Expression: velocity, pitch bend, pressure
Velocity
Note-on velocity is carried into the voice and read by the envelope as velocity_scale,
scaling dynamic range. With the envelope's Expressive flag set, the envelope also tracks
continuous pressure (MPE). See Envelope.
Pitch bend
Pitch bend is applied per Part, in the voice executor, as a signed CV offset added to every voice's note CV each block:
- Bend offset — signed CV (
pitch_bend_offset_cv). - Bend range —
0–48semitones, default 2 (pitch_bend_range).
Because bend is added downstream of allocation, it tracks all sounding voices uniformly. Source:
gdvp_voice_manager_state_t pitch-bend fields. MIDI pitch-bend routing: MIDI.
MPE / per-note expression
The parameter space includes MPE targets — channel pressure, poly pressure, and a
dedicated pitch-bend CV (GDVP_PARAM_CHANNEL_PRESSURE_CV, GDVP_PARAM_POLY_PRESSURE_CV,
GDVP_PARAM_PITCH_BEND_CV). See Parameters. Continuous pressure reaches the
envelope when its Expressive flag is enabled.
3.8 Tempo & transport
The engine keeps a fixed-point sequencer at 96 PPQN. Tempo is set with
gdvp_system_set_tempo(system, bpm). Each audio block the executor computes a 64-bit
tick pulse mask (one bit per sample-frame that lands on a tick) and passes it by value to
every node, so tempo-synced features can resolve within the block, sample-accurately.
⚠️ Status note. The transport bus and tick mask are fully plumbed, and the arpeggiator uses them. The LFO transport-sync path, however, is staged but not yet active in the LFO kernel —
tick_maskis currently received and cast to(void)there (see LFO §sync and Appendix A). Key-sync (phase reset on note) does work; tempo-sync does not yet.
Setting tempo
Tempo is shown at the right of the header bar as a BPM readout. Drag it vertically to change it, within 20–300 BPM.
Under the VST3 form, transport (play state and BPM) follows the host DAW: the readout
tracks the project tempo, is dimmed, and is tagged DAW to show where the value comes from.
Dragging it does nothing there by design — the DAW is the master clock, and the engine refuses
tempo writes from the UI for as long as the host is driving the transport. Change the tempo in
your DAW instead. Under standalone, tempo is internal and the readout is yours to set.
See Hosts.
← The Node Graph · Manual index · Next: Node Reference →