helm
helm · sources · schema v1Polyphonic subtractive synth — algorithm port of Matt Tytel's Helm (helm_engine.cpp / helm_voice_handler.cpp / helm_oscillators.cpp / helm_lfo.cpp / state_variable_filter.cpp / envelope.cpp / step_generator.cpp, originally GPL-3.0, ported to AGPL-3.0-or-later per the project's license relicense). v1 ships: 4-8 voice polyphony (Voices knob); 2 morphing oscillators (saw/square/triangle/sine continuous morph) with per-osc transpose (±24 st), tune (±100 ¢), unison (1..7 voices, detune ±50 ¢ spread), and volume; 1 sub oscillator (-2 oct, selectable wave); white-noise source; state-variable filter (Andy Simper TPT topology, Cytomic formulation) with 12dB / 24dB pole select, LP↔BP↔HP continuous blend, drive, resonance, key-track; three ADSR envelopes (amplitude, filter, mod) with depth knobs for filter-env → cutoff and mod-env → osc1 pitch; two mono LFOs pre-wired (LFO1 → filter cutoff, LFO2 → osc2 pitch); 16-step step sequencer with smoothing + frequency division pre-wired to osc2 transpose; stereo output with adjustable voice-pan spread. Polyphonic MIDI input via the gear-icon settings panel — pick a connected Web MIDI device + select which of channels 1-16 to receive on (multi-select; ALL is the default). Multiple held notes simultaneously trigger multiple voices via a free-slot / steal-oldest allocator. Optional pitch_cv (V/oct) + gate fallback inputs let the module be driven by SCORE / sequencer cables when no MIDI is connected. DEFERRED to follow-up PRs: effects bus (distortion / delay / reverb / stutter / formant / feedback), arpeggiator, poly LFO, mod sources panel (aftertouch / mod wheel / pitch wheel / random), BPM-locked LFO frequencies, and a freeform modulation matrix (v1 hard-wires mod sources to musically sensible defaults — see the helm.ts worklet header for the routing table).
the faceplate
inputs
| id | cable | what it does |
|---|---|---|
pitch_cv | cv | Monophonic V/oct pitch for the fallback CV/gate path used when no MIDI device is connected: while the GATE input is high it plays a single voice at midi note 60 + (pitch_cv × 12 semitones). MIDI note input (via the gear-icon device picker) takes priority and drives true polyphony; this CV path is a single-note fallback for patching from a sequencer or keyboard CV. control voltage (CV) |
gate | gate | Note on/off gate for the fallback CV/gate path (level-sensitive): a rising edge starts a note at the current pitch_cv and a falling edge releases it. It is ALSO the sequencer's clock — every rising edge here advances the built-in step sequencer one step (and re-attacks the envelopes), so the same gate that plays notes also walks the pattern. gate / trigger |
midi_in | cv | A presentation-only port that exists so MIDI shows up as a first-class cable on the panel; it carries no audio or CV and nothing is read from it. Actual MIDI flows through the Web MIDI API (open the gear icon to pick a device and receive channels), not through this cable. control voltage (CV) |
seq_reset | gate | Reset gate for the built-in step sequencer (trigger): a rising edge snaps the step pointer back so the next gate advance lands on step 0. Honored whether or not the sequencer is switched on, so you can sync the pattern's start to a clock or another sequencer. gate / trigger |
outputs
| id | cable | what it does |
|---|---|---|
out_l | audio | Left channel of the stereo mix of all sounding voices. The stereo image comes from spreading each oscillator's unison voices across the field by the SPR (spread) amount; with no unison and spread at 0 the output is effectively centered/mono. audio signal |
out_r | audio | Right channel of the stereo mix of all sounding voices (the spread partner of out_l). Patch both out_l and out_r to keep the unison/pan stereo image. audio signal |
params
| id | label | range | default | curve |
|---|---|---|---|---|
voiceCount | Voices | 1..8 | 6 | discrete |
volume | Vol | 0..2 | 0.7 | linear |
osc1Wave | O1 Wav | 0..3 | 0 | discrete |
osc1Trans | O1 Tr | -24..24st | 0 | linear |
osc1Tune | O1 Tu | -100..100c | 0 | linear |
osc1Unison | O1 Uni | 1..7 | 1 | discrete |
osc1Detune | O1 Det | 0..50c | 10 | linear |
osc1Vol | O1 Vol | 0..1 | 0.8 | linear |
osc2Wave | O2 Wav | 0..3 | 1 | discrete |
osc2Trans | O2 Tr | -24..24st | 0 | linear |
osc2Tune | O2 Tu | -100..100c | 7 | linear |
osc2Unison | O2 Uni | 1..7 | 1 | discrete |
osc2Detune | O2 Det | 0..50c | 10 | linear |
osc2Vol | O2 Vol | 0..1 | 0.6 | linear |
subWave | Sub W | 0..3 | 3 | discrete |
subVol | Sub V | 0..1 | 0.4 | linear |
noiseVol | Noise | 0..1 | 0 | linear |
filterCutoff | Cut | 20..20000Hz | 4000 | log |
filterRes | Res | 0.5..16 | 1 | linear |
filterBlend | Mode | 0..2 | 0 | linear |
filterStyle | Pole | 0..1 | 0 | discrete |
filterDrive | Drv | 0.5..6 | 1 | linear |
filterKeyTrack | Key | -1..1 | 0 | linear |
ampAttack | A A | 0..8s | 0.005 | linear |
ampDecay | A D | 0..8s | 0.2 | linear |
ampSustain | A S | 0..1 | 0.6 | linear |
ampRelease | A R | 0..8s | 0.3 | linear |
filAttack | F A | 0..8s | 0.005 | linear |
filDecay | F D | 0..8s | 0.5 | linear |
filSustain | F S | 0..1 | 0 | linear |
filRelease | F R | 0..8s | 0.3 | linear |
filEnvDepth | F Dpth | -1..1 | 0 | linear |
modAttack | M A | 0..8s | 0.005 | linear |
modDecay | M D | 0..8s | 0.5 | linear |
modSustain | M S | 0..1 | 0 | linear |
modRelease | M R | 0..8s | 0.3 | linear |
modEnvDepth | M Dpth | -1..1 | 0 | linear |
lfo1Wave | L1 W | 0..3 | 3 | discrete |
lfo1Freq | L1 Hz | 0.01..30Hz | 1 | log |
lfo1Amp | L1 Amt | 0..1 | 0 | linear |
lfo2Wave | L2 W | 0..3 | 3 | discrete |
lfo2Freq | L2 Hz | 0.01..30Hz | 4 | log |
lfo2Amp | L2 Amt | 0..1 | 0 | linear |
stepNumSteps | Steps | 1..16 | 8 | discrete |
stepRate | St Hz | 0.1..30Hz | 4 | log |
stepSmooth | St Smth | 0..1 | 0 | linear |
stepDepth | St Dpth | -1..1 | 0 | linear |
spread | Spr | 0..1 | 0.3 | linear |
controls
| control | what it does |
|---|---|
| A A | Amplitude envelope attack time in seconds (0–8): how quickly each note fades in on note-on. |
| A D | Amplitude envelope decay time in seconds (0–8): how quickly the level falls from peak to the sustain level after the attack. |
| A R | Amplitude envelope release time in seconds (0–8): how long the note takes to fade out after note-off. |
| A S | Amplitude envelope sustain level (0–1): the steady loudness held while the note is on, after the decay. |
| F A | Filter envelope attack time in seconds (0–8): how fast the filter-env contour rises on note-on (its effect on cutoff is scaled by F Dpth). |
| F D | Filter envelope decay time in seconds (0–8): fall from the envelope's peak to its sustain. |
| F Dpth | How much (and which direction) the filter envelope modulates the cutoff (−1 to +1, labeled F Dpth): positive sweeps the cutoff up with the envelope, negative sweeps it down, 0 disables the filter envelope's effect. |
| F R | Filter envelope release time in seconds (0–8) after note-off. |
| F S | Filter envelope sustain level (0–1) held while the note is on (default 0, so by default the filter sweep decays away). |
| Mode | Continuously crossfades the filter response across 0 = low-pass, 1 = band-pass, 2 = high-pass, so in-between values are blends of two modes (labeled MODE on the panel). |
| Cut | Filter cutoff frequency (20 Hz–20 kHz, log) — the corner where the filter starts acting. The filter envelope and LFO 1 add to this around the knob value. |
| Drv | Pre-filter drive/gain (0.5–6) pushing harder into the filter for added saturation and bite. |
| Key | How much the cutoff follows the played pitch (−1 to +1): positive opens the filter as you play higher (keeping brightness consistent up the keyboard), negative inverts it, 0 is no tracking. |
| Res | Filter resonance / emphasis at the cutoff (0.5–16); higher values peak harder and can self-oscillate-like ring. |
| Pole | Filter slope / pole count: 0 = 12 dB/oct (2-pole, gentler) and 1 = 24 dB/oct (4-pole, steeper, more aggressive). Labeled POLE. |
| Helm gear btn {n} | Gear icon (header) — opens the MIDI settings panel: pick the input device and which MIDI channels to receive on, and view the last note / active-voice count. |
| Helm seq onoff {n} | SEQ ON/OFF — switches the built-in step sequencer on or off. When off the pattern contributes no modulation and doesn't advance; default off. |
| Helm seq reset {n} | RST — resets the step pointer so the next gate advance starts the pattern at step 0 (same effect as a rising edge on the SEQ RESET input). |
| Helm step {n} | Step {n} value slider — sets this step's modulation amount (−1..+1). With the sequencer on, the step values are walked one-per-gate and sent to the sequencer's destination (osc-2 transpose, scaled by St Dpth/Amt). |
| L1 Amt | LFO 1 depth (0–1): how much LFO 1 modulates its destination — the filter cutoff in v1 (0 = off). |
| L1 Hz | LFO 1 rate in Hz (0.01–30, log). |
| L1 W | LFO 1 waveform (0 = saw, 1 = square, 2 = triangle, 3 = sine, default sine). |
| L2 Amt | LFO 2 depth (0–1): how much LFO 2 modulates its destination — oscillator-2 pitch (±1 semitone) in v1 (0 = off). |
| L2 Hz | LFO 2 rate in Hz (0.01–30, log, default 4 Hz). |
| L2 W | LFO 2 waveform (0 = saw, 1 = square, 2 = triangle, 3 = sine, default sine). |
| M A | Mod envelope attack time in seconds (0–8). The mod envelope is a spare ADSR; in v1 it is pre-wired to oscillator-1 pitch (depth set by M Dpth). |
| M D | Mod envelope decay time in seconds (0–8). |
| M Dpth | How much the mod envelope modulates its destination — oscillator-1 pitch in v1 — over ±12 semitones (−1 to +1, labeled M Dpth); 0 disables it. |
| M R | Mod envelope release time in seconds (0–8) after note-off. |
| M S | Mod envelope sustain level (0–1, default 0). |
| Noise | White-noise level in the mix (0–1, default 0) — adds breath/hiss or, through a resonant filter, percussive/wind textures. |
| O1 Det | How far apart the oscillator 1 unison copies are spread in cents (0–50); 0 stacks them in tune, higher values fatten and detune the stack. No effect when unison is 1. |
| O1 Tr | Oscillator 1 coarse transpose in semitones (−24 to +24), shifting it by whole steps relative to the played note. |
| O1 Tu | Oscillator 1 fine tune in cents (−100 to +100) for slight detuning or beating against osc 2. |
| O1 Uni | Number of stacked unison copies of oscillator 1 (1–7); higher counts thicken the tone and, with detune, widen it. |
| O1 Vol | Oscillator 1 level in the pre-filter mix (0–1). |
| O1 Wav | Oscillator 1 waveform, morphing across 0 = saw, 1 = square, 2 = triangle, 3 = sine (the knob crossfades between adjacent shapes at in-between values). |
| O2 Det | Cents spread between oscillator 2's unison copies (0–50); no effect when unison is 1. |
| O2 Tr | Oscillator 2 coarse transpose in semitones (−24 to +24) — e.g. +12 for an octave-up layer. |
| O2 Tu | Oscillator 2 fine tune in cents (−100 to +100); defaults to +7 c so the two oscillators beat slightly out of the box. |
| O2 Uni | Number of stacked unison copies of oscillator 2 (1–7). |
| O2 Vol | Oscillator 2 level in the pre-filter mix (0–1). |
| O2 Wav | Oscillator 2 waveform, morphing across 0 = saw, 1 = square, 2 = triangle, 3 = sine, just like osc 1 (defaults to square). |
| Spr | Stereo width (0–1): how far each oscillator's unison voices are panned across the stereo field. 0 collapses toward center/mono; higher values widen the image. |
| St Dpth | How much the step sequencer modulates its destination — oscillator-2 transpose over ±12 semitones (−1 to +1, labeled Amt); 0 disables it. |
| Steps | Number of active steps in the built-in step sequencer (1–16) before the pattern loops. |
| St Hz | Step sequencer rate knob (0.1–30 Hz). Retained from v1's free-running mode; in the current gate-clocked mode the sequencer advances on GATE rising edges, so this is effectively inactive. |
| St Smth | Glide/smoothing between step values (0–1): 0 jumps instantly between steps, higher values slew the modulation for portamento-like motion. |
| Sub V | Sub-oscillator level in the mix (0–1). |
| Sub W | Sub-oscillator waveform (0 = saw, 1 = square, 2 = triangle, 3 = sine; defaults to sine). The sub plays two octaves below the note for low-end weight. |
| Voices | Polyphony cap (1–8): the maximum number of notes that can sound simultaneously. When more notes are held than voices available, the synth steals a voice (a releasing voice first, otherwise the oldest-held note). Set it to 1 for a strictly monophonic patch. |
| Vol | Master output level for the whole synth (0–2, default 0.7); above 1 it boosts past unity. |
source
helm.ts on GitHub.