← All modules
AvailableInstrument

Pluck

A physical string model, rendered per note.

Engine preview

VST3

About

Pluck is a string, not a sample of one. Each note is an excitation, a pick pulse with as much nail noise as you ask for, driven into a delay line one period long, with a loss filter and an allpass in the loop. That is the extended Karplus-Strong of Jaffe and Smith, and the reason it is worth building rather than sampling is that every control is a physical property rather than a post-process: pluck position is not an EQ, damping is not a fade, and stiffness is not a detune.

Pluck position is the clearest case. Where you pluck decides which harmonics can exist at all, because the string cannot start in a shape that has a corner where your finger is. Pluck a fifth of the way along and the 5th, 10th and 15th harmonics are not quieter, they are absent. The module implements that as the physics does, by delaying the excitation by the pluck point's share of a period and subtracting it from itself, and the panel plots the resulting comb from the same maths the loop runs.

The one thing worth knowing before you play it: low notes run a genuinely different loop, not the same loop transposed. Two of the loop's coefficients are solved against the note's own frequency. Stiffness is scaled by the square root of 196 over the fundamental, because a bass string is thick relative to its length and its inharmonicity really is larger, so the Stiffness control stretches the partials audibly at the bottom of the keyboard and barely at all at the top. And the loss filter's corner is floored at two and a half times the fundamental, which binds on high notes and never on low ones, so a low string loses a much larger share of its partials on every trip round the loop. Transposing a Pluck note down an octave is a different instrument, deliberately.

Each note's loop is solved once at note-on from the frequency and the parameters at that instant, sample by sample in a bounded 12-voice bank, and a later parameter change cannot reach a voice already sounding, which is also true of a real plucked string. Pluck is a Processor: one target-neutral definition over @codex-music/dsp/voices/pluck, proven sample-exact against the frozen browser renderer it replaced. The excitation noise is seeded rather than random, so the same note at the same settings renders byte-identically every time; that is what makes the per-note render cache correct rather than merely fast.

System requirements.

The downloadable Pluck release supports the hosts and systems listed below.

  • VST3macOS · arm64

    Works in Ableton Live, Reaper, Cubase, Studio One, Bitwig and FL Studio.

Version 0.1.0

Build evidence

Every row below is a recorded build row or the recorded absence of one. Nothing here is inferred from what this module is meant to support.

Module
music.codex.pluck v0.1.0
Built at
Closure hash
edddc499edac…
Toolchain
  • scriptc 64acce1ae3b8…
  • moduleToolchainDist c621ffab721d…
  • pluginShellKitRuntime bca003784692…
  • faceShellGeneration 8533207ab81f…
  • uiPreservation cd28dbd7e3d6…
  • packagerVersion 3
Build result and download for each format
FormatResultDownload
Browser package (JS)
Builtweb

bundle sha256 283532169176… · 352 KB

Built, but no downloadable archive was recorded.
Browser package (WASM)
Builtweb

bundle sha256 f12c8b6ce19b… · 2.0 MB

Built, but no downloadable archive was recorded.
VST3
Builtdarwin-arm64Steinberg validator + VST3 host render: passed

bundle sha256 e7e8a4e397e8… · 2.2 MB

CodexPluck-vst3-darwin-arm64.zip

archive sha256 3910729e2d3b… · 2.2 MB · darwin-arm64

Audio UnitNot built

no recorded artifact row for au; native-lane-report.json is absent or records no au row for this module

Not built for macOS
CLAPNot built

no recorded artifact row for clap; native-lane-report.json is absent or records no clap row for this module

Not built for macOS, Windows or Linux
Standalone appNot built

no recorded artifact row for standalone; native-lane-report.json is absent or records no standalone row for this module

Not built for macOS, Windows or Linux

Parity

browser-js = browser-wasm = vst3 qualified against their own recorded digests. Not recorded: au, clap, standalone.

Presets

Start from a named sound, then adjust the instrument to make it yours.

InitNylonSteelHarpKotoMutedBassGlass HarpSitar Wire

Signal graph.

Experimental

Migration fallback: approximated from parameter groups, not a runtime wiring diagram.

How it works.

A pluck is an excitation entering a tuned feedback loop. The excitation is a raised-cosine pick pulse whose width comes from Hardness, a hard plectrum leaves in a few samples and is broadband, a fingertip stays in contact for a fraction of a period and rolls off early, blended with one-pole-filtered noise for the nail. Velocity shifts the effective hardness rather than only the gain, so a loud note is genuinely brighter. The noise is drawn from a seeded xorshift forked per consumer, never Math.random, which is what makes a note reproducible.

Pluck position is applied to that excitation as a delay-and-subtract: exc[n] − exc[n − d], with d the pluck point's share of one period, rounded to samples. Its magnitude response is 2·|sin(π·k·position)| at harmonic k, so every harmonic with a node at the pluck point is exactly zero rather than merely attenuated. The rounding to whole samples is negligible on a long loop and worth a couple of percent of the length on a short one, so the realised position drifts from the knob at the top of the keyboard, the panel draws the realised one. The maths and the plot both come from ui-kit's pluck-position library, which is pinned against a DFT of that filter rather than against a restatement of its own algebra.

The loop is a fractional delay line, a one-pole low-pass for loss, and a first-order allpass with a negative coefficient for stiffness. Both filters add delay of their own, a one-pole contributes a/(1−a) samples, the allpass (1−c)/(1+c), and a loop that ignored that would play flat by over a dozen samples on a dark, stiff, low patch, which is a quarter tone at 55 Hz. So the delay line is given the period minus what the filters contribute and the remainder rides on the interpolator. At the very top of the range the filters can want more delay than the note has, and stiffness is given up first: being in tune is not negotiable.

Loop gain is solved, not dialled. exp(−6.9078 / (f · T60)) puts the fundamental exactly 60 dB down after the Sustain time, and the renderer then allocates exactly that long plus a 20 ms raised-cosine fade onto true zero. A tail is therefore never truncated mid-ring and a buffer never holds seconds of silence, the note is as long as the physics says and not one sample longer.

Renders are cached per note, per velocity layer, per strike variant, and per timbre-parameter hash. Velocity is quantised into four layers because it changes the excitation's spectrum but not its level, level is a gain at playback, so it stays continuous. Repeated strikes of one key alternate between two seeds, which is the cheap and correct fix for the machine-gun artefact a single buffer would have. Moving any timbre parameter drops the whole cache, because those parameters change the samples themselves. The cache is bounded by total frames rather than by entry count: a Muted patch's buffers are a fifth of a second and a Harp's are five, so an entry cap would mean a different memory ceiling on every patch.

Voices are capped at twelve with oldest-first stealing. Re-plucking a ringing note stops the old one over 60 ms, one string has one vibration, which is the opposite of the Gamelan module where a bar struck twice really is two strikes ringing together. Key-up damps over a time that scales with the patch's own sustain, between 120 and 900 ms, so a Muted patch stops when you let go and a Harp patch is allowed the moment of ring a harpist would get.

Goes well with.

Preview

OSC Mini

A compact subtractive synth for learning the signal path.

Preview
Preview

Gamelan

Modelled bronze instruments with flexible tuning.

Preview
Preview

Space Mini

Convolution reverb: eight synthesized spaces, twenty-five real cabinets.

PreviewNo build recorded