Case study: TR-909 drum synthesiser

The examples/909.ttl circuit models the Roland TR-909 drum machine as nine independent voice sub-circuits inside a single Valis circuit. It demonstrates the val:NoteGate element, the Envelope gate-override input, val:AsymClip waveshaping, and the val:section parameter grouping used by multi-instrument circuits.

Problem: per-note routing

The Valis engine broadcasts a single MIDI state (gate, noteNumber, velocity) to every element in a circuit. In a synthesiser, that is the right design — one note drives the whole circuit. In a drum machine, nine separate instruments must respond to nine different note numbers simultaneously.

The solution is val:NoteGate, a source element that filters the global gate by note number:

:bdGate a val:NoteGate ; val:note 36 .

NoteGate has two control outputs:

A control arc connects NoteGate.gate to Envelope.gate, which is a new optional input port on the existing Envelope element:

:aBdGateAmpEnv a val:ControlArc ;
    val:from [ val:node :bdGate   ; val:port "gate" ] ;
    val:to   [ val:node :bdAmpEnv ; val:port "gate" ] .

The Envelope gate port has a default of -1.0, which acts as a sentinel: -1 means "use the host MIDI gate" and 0 or 1 means "use this value". Existing circuits that do not connect anything to gate continue to work without change.

General MIDI channel 10 map

MIDI note Instrument Circuit blocks
36 Bass Drum Triangle oscillator + pitch sweep, AsymClip, VCA
37 Rim Shot Noise through highpass filter, short VCA
38 Snare Drum Oscillator + band-passed noise mixed, VCA
39 Hand Clap Noise through bandpass filter, VCA
41 Low Tom TwinTBridge + pitch envelope sweep, amplitude decay
43 Mid Tom TwinTBridge + pitch envelope sweep, amplitude decay
50 High Tom TwinTBridge + pitch envelope sweep, amplitude decay
42 Closed HH Six square oscillators, highpass, very short decay
46 Open HH Six square oscillators, highpass, longer decay

Instrument circuit blocks

Bass Drum

The 909 BD uses a triangle-wave VCO. A fast pitch envelope sweeps from about 210 Hz at the attack down to the body frequency (about 55 Hz) in about 20 ms, producing the characteristic "thump". An val:AsymClip element models the asymmetric diode waveshaping in the original's output stage — the positive half of the triangle is clipped sooner than the negative, altering the waveform character:

NoteGate → pitchEnv.gate    → Scale(55-210 Hz) → Oscillator.frequency
NoteGate → ampEnv.gate      → VCA.cv
Oscillator(triangle) → AsymClip → VCA → Level

The body pitch is the val:min of the Scale element, exposed as the "Tune" parameter. The TR-808 used a bridged-T resonant network instead; that design is in examples/808-bd.ttl.

Snare Drum

Two sine oscillators at 180 Hz and 200 Hz are mixed before the tone VCA. Their 20 Hz beat produces a characteristic pitch wobble during the decay. The noise path uses white noise through a bandpass filter at 2 kHz, with its own shorter envelope (the "Snappy" control). The two paths have independent envelopes:

NoteGate → toneEnv.gate     → toneVCA.cv
NoteGate → noiseEnv.gate    → noiseVCA.cv
Oscillator(180 Hz, sine) ──┐
Oscillator(200 Hz, sine) ──┘→ oscMixer → toneVCA ──┐
Noise → StateVariable(BP 2 kHz) → noiseVCA ─────────┘→ Mixer → output

The "Snappy" parameter controls noiseEnv.decay; shorter gives a dry, cracking snare. The "Tone" parameter controls the BPF cutoff.

Toms

Low, Mid and High Toms use the same architecture as the BD, with a TwinTBridge resonator and a pitch sweep, at higher body frequencies (70, 110, 160 Hz respectively). The pitch decay time is slightly faster (15-20 ms) than the BD, and the amplitude decay is shorter.

Rim Shot

White noise through a OnePole highpass filter at 1.2 kHz gives the dry click of a stick on the rim. The amplitude decay is 20 ms.

Hand Clap

White noise through a resonant StateVariable bandpass at 1.2 kHz (Q ≈ 1.2). The original circuit produced multiple short noise bursts; approximated here as a single filtered burst with an 80 ms decay.

Hi-Hats

The 909 hi-hat section uses six square-wave oscillators at inharmonic ratios from circuit analysis. They are tuned to 562, 834, 1124, 1395, 1668 and 1995 Hz. All six oscillators sum in a Mixer before a 7 kHz highpass filter removes the fundamental and low partials:

NoteGate → Envelope.gate → VCA.cv
Oscillator(562 Hz, sq)  ──┐
Oscillator(834 Hz, sq)  ──┤
Oscillator(1124 Hz, sq) ──┤→ Mixer → StateVariable(HP 7 kHz) → VCA
Oscillator(1395 Hz, sq) ──┤
Oscillator(1668 Hz, sq) ──┤
Oscillator(1995 Hz, sq) ──┘

Closed and Open hats share the same spectral source but differ in decay time (45 ms vs 500 ms). The original hi-hat choke that mutes the open hat on a closed-hat trigger is not modelled yet because the current control arcs replace one destination value and do not combine multiple gate sources.

Section labels in the Controls panel

A circuit with 23 parameters across nine instruments is difficult to navigate as a flat list. The val:section property on val:Param bindings groups parameters under named headings in the Controls panel:

:pBdDecay a val:Param ; val:slot 1 ;
    val:target :bdAmpEnv ; val:property val:decay ;
    lv2:name "Decay" ; lv2:symbol "bd_decay" ; val:section "Bass Drum" ;
    units:unit units:ms ; lv2:minimum 50.0 ; lv2:maximum 2000.0 .

The Controls panel renders a coloured label and a divider line at the start of each new section. Bindings without a val:section are displayed ungrouped. Each instrument now exposes a Level parameter as a val:Gain trim before the main mixer.

Known simplifications

Testing with MCP tools

To load and play the circuit using the Transmission host:

mcp__transmission__project_open(path: ".../examples/909.ttl")
mcp__transmission__transport_play()

Send MIDI note 36 (bass drum), 38 (snare), 42 (closed hat) on channel 10. Each instrument should respond independently; others should remain silent during each note.

Inspect the compiled circuit graph to verify NoteGate appears in each instrument chain and that control arcs connect to Envelope gate ports:

mcp__transmission__project_get()