PedalKernel DSL Reference

PedalKernel uses two file formats: .pedal files define individual guitar pedal circuits, and .board files chain multiple pedals into a pedalboard.

.pedal File Format

A .pedal file describes a guitar pedal’s circuit topology as a netlist. The compiler transforms this into a real-time Wave Digital Filter (WDF) audio processor.

The keywords pedal, synth, and equipment are interchangeable — all produce the same AST. Use synth for synthesizer modules and equipment for studio gear like compressors and preamps.

Structure

pedal "<Name>" {
  supply <voltage>V        # single supply (optional — defaults to 9V)
  # OR for multiple rails:
  supplies {
    <rail_name>: <voltage>V [{ sag params }]
    ...
  }
  components {
    <component declarations>
  }
  nets {
    <net connections>
  }
  controls {
    <control mappings>
  }
}

All three sections are required (though controls may be omitted if the pedal has no knobs). Comments use # and extend to end of line.

Supply Voltage

The supply keyword specifies the circuit’s DC supply voltage. This affects the headroom for clipping/saturation modeling and should match the actual power supply of the equipment being modeled:

Equipment TypeTypical SupplyExample
Guitar pedals9Vsupply 9V
12V modded pedals12Vsupply 12V
Transistor preamps24-30Vsupply 24V
Tube preamps250-400Vsupply 285V

If omitted, the supply defaults to 9V (standard guitar pedal voltage).

# Tube amplifier preamp
pedal "Tweed Deluxe" {
  supply 350V    # B+ for tube stages
  ...
}

# Standard guitar pedal (9V is default, but explicit is clearer)
pedal "Tube Screamer" {
  supply 9V
  ...
}

Voltage Sag

Voltage sag is the dynamic drop in B+ voltage when tubes draw current under load. The WDF engine models this automatically based on circuit topology:

  1. Loud signal → tubes conduct more → increased plate current
  2. Current flows through power supply impedance
  3. Voltage drop: ΔV = I × Z_supply
  4. Lower plate voltage → reduced gain → natural compression
  5. Signal quiets → voltage recovers (slowly)

Sag is more pronounced with:

Sag creates the “breathing” feel of vintage tube amps and contributes to dynamic compression in studio compressors like the Fairchild 670.

Supply block syntax for explicit sag modeling:

pedal "Tube Amp Sag" {
  supply 480V {
    impedance: 150      # ohms (rectifier + transformer + ESR)
    filter_cap: 40u     # main filter capacitance in farads
    rectifier: tube     # or solid_state
  }
  ...
}
ParameterDescriptionTypical Values
impedanceSupply output impedanceTube rectifier: 50–200Ω, solid-state: 1–10Ω
filter_capMain filter capacitance40µF (vintage) to 220µF (modern)
rectifierRectifier type: tube or solid_statetube for sag, solid_state for stiff supply

Multiple Supply Rails

For circuits requiring multiple voltage rails (bipolar op-amp supplies, tube amps with separate B+ voltages, or isolated supply domains), use the supplies { } block:

pedal "Bipolar Op-Amp Circuit" {
  supplies {
    V+: 15V
    V-: -15V           # Negative voltages supported
  }
  components {
    R1: resistor(10k)
    U1: opamp(tl072)
  }
  nets {
    R1.a -> V+         # Connect to positive rail
    R1.b -> V-         # Connect to negative rail
    ...
  }
}

Tube amplifier with multiple rails:

pedal "Tube Preamp Multi-Rail" {
  supplies {
    B+: 300V { impedance: 100, rectifier: tube }
    bias: -50V         # Grid bias supply
    filament: 6.3V     # Heater supply
  }
  components {
    V1: triode(12ax7)
    R1: resistor(100k)
    ...
  }
  nets {
    V1.plate -> R1.a
    R1.b -> B+         # Plate load to B+ rail
    ...
  }
}

Key features:

Backwards compatibility: The single supply 9V syntax still works and creates a “vcc” rail:

# These are equivalent:
supply 9V
# Same as:
supplies { vcc: 9V }

If no supply is specified, the compiler defaults to 9V on a “vcc” rail.

Components

Each component is declared as <id>: <type>(<params>).

TypeSyntaxDescription
Resistorresistor(<value>)Fixed resistor
Capacitorcap(<value>)Capacitor
Inductorinductor(<value>)Inductor
Switched Resistorresistor_switched(<v1>, <v2>, ...)Resistor with switchable values
Switched Capacitorcap_switched(<v1>, <v2>, ...)Capacitor with switchable values
Switched Inductorinductor_switched(<v1>, <v2>, ...)Inductor with switchable values
Potentiometerpot(<value>)Variable resistor (controllable knob)
Diode pairdiode_pair(<type>)Symmetric clipping diode pair
Single diodediode(<type>)Asymmetric single diode
Zener diodezener(<voltage>)Zener diode with breakdown voltage (e.g., zener(5.1))
NPN transistornpn() or npn(<type>)NPN BJT (modeled as gain stage)
PNP transistorpnp() or pnp(<type>)PNP BJT (modeled as gain stage)
N-channel MOSFETnmos(<model>)N-channel MOSFET
P-channel MOSFETpmos(<model>)P-channel MOSFET
Op-ampopamp() or opamp(<type>)Operational amplifier
N-channel JFETnjfet(<model>)N-channel JFET (nonlinear WDF root)
P-channel JFETpjfet(<model>)P-channel JFET (nonlinear WDF root)
Triodetriode(<type>)Vacuum tube triode (see below)
Pentodepentode(<type>)Vacuum tube pentode (see below)
Photocouplerphotocoupler(<model>)Vactrol / optocoupler (controlled resistance)
Neon bulbneon() or neon(<model>)Neon lamp for relaxation oscillators
BBDbbd(<model>)Bucket-brigade device delay line
Delay linedelay_line(<min>, <max> [, <interp>] [, medium: <medium>])Generic ring-buffer delay
Taptap(<delay_id>, <ratio>)Read-only tap into a delay line
LFOlfo(<waveform>, <R>, <C>)LFO with RC timing (f = 1/2piRC)
Envelope Followerenvelope_follower(<atk_R>, <atk_C>, <rel_R>, <rel_C>, <sens_R>)Envelope detector with RC timing
Switchswitch(<positions>)Simple n-position mechanical switch
Rotary Switchrotary(<label1>, <label2>, ...)Labeled rotary switch
Analog Switchswitch(<model>)Analog switch IC (CD4066, DG411)
VCOvco(<model>)Voltage-controlled oscillator IC
VCFvcf(<model>)Voltage-controlled filter IC
VCAvca(<model>)Voltage-controlled amplifier IC
Comparatorcomparator(<model>)Comparator IC
Matched NPNmatched_npn(<model>)Matched NPN transistor pair/array
Matched PNPmatched_pnp(<model>)Matched PNP transistor pair
Tempco Resistortempco(<resistance>, <ppm>)Temperature-compensating resistor
Transformertransformer(<ratio>, <inductance> [, ...])Audio transformer (see below)

Engineering notation is supported for component values:

SuffixMultiplierExample
p10^-12 (pico)100p = 100 pF
n10^-9 (nano)47n = 47 nF
u10^-6 (micro)10u = 10 uF
m10^-3 (milli)100m = 100 mH
k10^3 (kilo)4.7k = 4.7 kOhm
M10^6 (mega)1M = 1 MOhm
inf∞ (infinity)Open circuit

The inf keyword represents infinite impedance (open circuit). This is useful for switched components where one position should disconnect the signal:

R_sel: resistor_switched([10k, inf, 47k])  # Position 1 = open circuit

Capacitor types: film (default), electrolytic, ceramic, tantalum

Capacitors support optional parasitic parameters:

C1: cap(22u)                              # Film cap (default), ideal
C2: cap(22u, electrolytic)                # Electrolytic, default parasitics
C3: cap(22u, electrolytic, leakage: 100k) # With explicit leakage resistance
C4: cap(22u, electrolytic, leakage: 10k, da: 0.05)  # With dielectric absorption
ParameterDescriptionTypical Values
leakageParallel leakage resistance (Ω)100kΩ (worn) to 10MΩ (new electrolytic)
daDielectric absorption coefficient (0-1)0.01-0.05 (electrolytic), <0.001 (film)

Diode types: silicon, germanium, led

Zener voltages: Common values are 3.3, 4.7, 5.1, 5.6, 6.2, 9.1, 12 (in volts)

JFET models: j201, 2n5457, 2n5460, 2sk30 (or 2sk30a, 2sk30-gr, 2sk30-y, 2sk30-bl for graded variants)

Triode types: 12ax7, 12at7, 12au7, 12bh7, 12ay7, 6386

Typeµ (mu)Use case
12AX7100High-gain preamp, voltage amplifier
12AT760Medium gain, phase inverter, driver
12AU717Low gain, cathode follower
12BH717High-current cathode follower
12AY744Lower-gain preamp (cleaner)
6386~50Remote-cutoff (variable-mu) triode

European equivalents: ecc83 (12AX7), ecc81 (12AT7), ecc82 (12AU7), 6072 (12AY7)

The 6386 is a remote-cutoff (variable-mu) dual triode used in the Fairchild 670 compressor. Unlike regular triodes, its mu varies with grid bias (~50 at low bias to ~5 at high bias), enabling gain control via bias modulation.

Triode pins: .grid, .plate, .cathode

Pentode types: ef86, el84, el34, 6l6gc, kt66, 6aq5a, 6973, 6550

TypeMax WattsUse case
EF861.2Low-noise preamp (Vox, Ampeg)
EL8412Small power amp (Champ, AC15)
EL3425Power amp (Marshall, Hiwatt)
6L6GC30Power amp (Bassman, Twin)
KT6635Power amp (early Marshall, Quad)
6AQ5A12Output stage, small amps
697312Power amp (Ampeg Reverberocket)
655035High-power output (SVT, Hiwatt)

Equivalents and variants:

Pentode pins: .grid, .plate, .cathode, .screen

The screen grid requires a dropping resistor from B+ and bypass cap to ground:

vcc -> R_screen.a
R_screen.b -> V1.screen, C_screen.a
C_screen.b -> gnd

Photocoupler models: vtl5c3, vtl5c1, nsl32, t4b

Neon bulb models: ne2 (default), ne51, ne83

Neon bulbs are used in vintage tremolo circuits (Fender Vibrato, Wurlitzer) as part of relaxation oscillators. When paired with an LDR (photocoupler), they create smooth optical modulation.

LFO waveforms: sine, triangle, square, saw_up, saw_down, sample_hold

Switched components: Values can be provided with or without brackets:

R_sel: resistor_switched(12k, 6.8k, 3.9k, 1.5k)
C_lf: cap_switched([27n, 68n, 220n, 1.5u])
L_hf: inductor_switched(27m, 47m, 82m, 150m)

Position is controlled via .position property in the controls section.

MOSFET models:

ModelTypeUse case
2n7000N-channelSmall-signal switching
irf520N-channelMedium power switching
bs250P-channelSmall-signal switching
irf9520P-channelMedium power switching

Op-amp models: tl072, tl082, jrc4558 (or 4558), rc4558, lm308, lm741, ne5532, ca3080, op07

VCO models: cem3340, as3340, v3340

VCF models: cem3320, as3320

VCA models: ssm2164, v2164

Comparator models: lm311, lm393

Analog switch models: cd4066, dg411

Matched transistor models: ssm2210, ca3046, lm394, that340

Switch types:

SW1: switch(3)                            # 3-position mechanical switch
MODE: rotary("Clean", "Crunch", "Lead")   # Labeled rotary switch
AS1: switch(cd4066)                       # Analog switch IC

Temperature-compensating resistor:

RT1: tempco(2k, 3500)   # 2kΩ nominal, 3500 ppm/°C

Used in exponential converters for temperature compensation.

Transformer syntax:

# Basic: ratio, primary inductance
T1: transformer(10:1, 2H)

# With parasitics: ratio, inductance, DCR, parasitic capacitance
T2: transformer(1:4, 2H, 75, 200p)

# Center-tapped secondary
T3: transformer(1:1, 4H, ct)

# Push-pull primary, center-tapped secondary
T4: transformer(1:1, 4H, pp, ct)

# Named parameters
T5: transformer(10:1, 2H, dcr=75, Cp=200p, k=0.98)

Winding modifiers: ct (center-tap secondary), pp (push-pull primary), ct_primary (center-tap primary)

Nets

Nets describe how component pins connect. Each net is <from> -> <to1>, <to2>, ....

Reserved nodes:

Component pins use dot notation: C1.a, R1.b, D1.a, Q1.base.

Two-terminal components (resistors, capacitors, inductors, diodes) have pins a and b. Potentiometers have pins a and b (2-terminal variable resistor), or a, w (wiper), and b (3-terminal pot for crossfade/blend). Transistors have base, collector, emitter. JFETs have gate, drain, source. Op-amps have pos, neg, out. LFOs and envelope followers have out (modulation output) which connects to modulation inputs like <jfet>.vgs or <photocoupler>.led.

3-terminal pots: When a pot uses the .w (wiper) pin in nets, it is modeled as two linked variable resistors sharing the wiper node. As position increases, R(a→w) increases and R(w→b) decreases, maintaining R(a→w) + R(w→b) = max_R. This enables crossfade/blend topologies where signals connect to both .a and .b with the output taken from .w.

in -> C1.a                       # input to capacitor pin a
C1.b -> R1.a, D1.a              # capacitor pin b fans out to R1 and D1
D1.b -> gnd                     # diode to ground
R1.b -> out                     # resistor to output

Dynamic routing with fork(): Routes signal to different destinations based on a switch position.

<from> -> fork(<switch_id>, [<dest1>, <dest2>, ...])

The switch component controls which destination receives the signal:

# Route signal based on MODE switch (3-position)
stage1.out -> fork(MODE, [clean.a, crunch.a, lead.a])

# Mute switch — routes to output or ground
amp.out -> fork(MUTE, [out, gnd])

# Time constant selector for phaser stages
B7.a -> fork(SW_time, [B8.a, B9.a])

This enables topology switching for multi-mode circuits without runtime recompilation.

Controls

Controls map component properties to named knobs with ranges and defaults:

<component>.<property> -> "<Label>" [<min>, <max>] = <default>

The position property is used for potentiometers (0.0 = fully CCW, 1.0 = fully CW):

Drive.position -> "Drive" [0.0, 1.0] = 0.5
Level.position -> "Level" [0.0, 1.0] = 0.8

Modulation Components

LFO — Specify waveform and physical RC timing components. Frequency is derived from the RC constant: f = 1/(2*pi*R*C). The R and C values appear in the KiCad netlist and Mouser BOM as real components.

LFO1: lfo(triangle, 100k, 220n)  # f ≈ 7.2 Hz triangle
LFO1.out -> OC1.led              # drive photocoupler LED

Envelope Follower — Specify attack/release RC timing and sensitivity resistor. All 5 component values are physical parts that appear in KiCad export and BOM.

# envelope_follower(attack_R, attack_C, release_R, release_C, sensitivity_R)
EF1: envelope_follower(1k, 4.7u, 100k, 1u, 20k)
# Attack τ = 1kΩ × 4.7µF = 4.7ms (fast attack)
# Release τ = 100kΩ × 1µF = 100ms (smooth release)
# Sensitivity = 20kΩ / 10kΩ = 2.0x gain
EF1.out -> J1.vgs                # modulate JFET gate voltage

Delay Components

BBD (Bucket-Brigade Device) — Models analog bucket-brigade delay ICs with compander, charge leakage, clock feedthrough, and noise. Internally uses a DelayLine for buffer management.

BBD1: bbd(mn3207)                # MN3207 (512 stages, typical chorus/flanger)
BBD1: bbd(mn3007)                # MN3007 (1024 stages, longer delays)
BBD1: bbd(mn3005)                # MN3005 (4096 stages, up to ~300ms)

BBD models: mn3207, mn3007, mn3005

BBD pins: in (audio input), out (audio output), clock (modulation target for LFO).

Delay Line — Generic ring-buffer delay with configurable interpolation and optional physical medium simulation. Splits the WDF tree at its boundaries: the write side accepts signal from one subtree, the read side feeds another.

# Basic (defaults: allpass interpolation, no medium)
DL1: delay_line(1ms, 1200ms)

# Explicit interpolation mode
DL1: delay_line(1ms, 1200ms, allpass)

# With physical medium simulation
DL1: delay_line(80ms, 1200ms, medium: tape_oxide)

# Both interpolation and medium
DL1: delay_line(80ms, 1200ms, allpass, medium: bbd_leakage)

Interpolation modes: linear, allpass (default — Thiran approximation, zipper-free), cubic (Hermite)

Medium types:

MediumDescription
noneClean digital buffer (default)
tape_oxideTape self-demagnetization — progressive HF loss with distance
bbd_leakageBBD charge leakage — amplitude decay across stages
digital_quantizeBit-depth reduction (placeholder)

Delay line pins: delay_time (control target), feedback (control target), speed_mod (modulation target for LFO wow/flutter).

Tap — Read-only output port into a parent delay line at a fixed ratio of the base delay time. Multiple taps model multi-head tape machines (e.g., RE-201 heads at 1×, 2×, 3× base delay — the three playback heads are evenly spaced along the tape path, per the Roland RE-201 service manual).

TAP1: tap(DL1, 1.0)    # reads at 1× base delay
TAP2: tap(DL1, 2.0)    # reads at 2× base delay
TAP3: tap(DL1, 4.0)    # reads at 4× base delay

Delay + Tap example (RE-201 Space Echo):

pedal "Space Echo" {
  components {
    DL1: delay_line(80ms, 1200ms, allpass, medium: tape_oxide)
    TAP1: tap(DL1, 1.0)     # Head 1 (3cm from write)
    TAP2: tap(DL1, 2.0)     # Head 2 (6cm from write)
    TAP3: tap(DL1, 4.0)     # Head 3 (12cm from write)
    LFO1: lfo(sine, 680k, 1u)  # wow/flutter
  }
  nets {
    in -> DL1.in
    TAP1.out -> out
    TAP2.out -> out
    TAP3.out -> out
    LFO1.out -> DL1.speed_mod
  }
  controls {
    DL1.delay_time -> "Repeat Rate" [0.0, 1.0] = 0.5
    DL1.feedback -> "Intensity" [0.0, 1.0] = 0.3
  }
}

Trims Section

Internal trim pots for factory adjustments (not user-facing):

trims {
  R_trim.position -> "Bias Adjust" [0.0, 1.0] = 0.5
  R_cal.position -> "Calibration" [0.0, 1.0] = 0.5
}

Same syntax as controls, but trims are not exposed in the UI.

Monitors Section

For real-time metering visualization (VU meters, gain reduction, etc.):

monitors {
  V1.plate_current -> "Tube 1" [vu]
  output -> "Output Level" [ppm]
  GR.reduction -> "Gain Reduction" [gr]
  V2.plate_current -> "Tube 2" [glow]
  supply -> "B+ Sag" [sag]
}

Meter types:

TypeDescription
vuVU meter (300ms rise/fall, RMS-responding)
ppmPeak Programme Meter (10ms rise, 1.5s fall)
peakTrue peak with hold
grGain reduction meter (for compressors)
glowTube glow visualization
sagSupply sag indicator

Complete Example

# Tube Screamer TS-808 clipping stage
pedal "Tube Screamer" {
  components {
    Drive: pot(4.7k)         # variable feedback resistor
    C1: cap(47n)             # feedback capacitor
    D1: diode_pair(silicon)  # symmetric silicon clipping diodes
    Level: pot(100k)         # output volume
  }
  nets {
    in -> Drive.a, C1.a
    Drive.b -> C1.b, D1.a, Level.a
    D1.b -> gnd
    Level.b -> out
  }
  controls {
    Drive.position -> "Drive" [0.0, 1.0] = 0.5
    Level.position -> "Level" [0.0, 1.0] = 0.8
  }
}

Included Examples

Pedals (examples/pedals/):

FilePedalType
overdrive/tube_screamer.pedalTube Screamer TS-808Overdrive
overdrive/blues_driver.pedalBoss Blues DriverOverdrive
overdrive/klon_centaur.pedalKlon CentaurOverdrive
overdrive/fulltone_ocd.pedalFulltone OCDOverdrive
fuzz/fuzz_face.pedalFuzz FaceFuzz
fuzz/big_muff.pedalBig MuffFuzz
distortion/proco_rat.pedalProCo RATDistortion
compressor/dyna_comp.pedalMXR Dyna CompCompressor
modulation/boss_ce2.pedalBoss CE-2Chorus
phaser/phase90.pedalMXR Phase 90Phaser

Amplifiers (examples/amps/):

FileAmp
tweed_deluxe_5e3.pedalFender Tweed Deluxe 5E3
bassman_5f6a.pedalFender Bassman 5F6-A
marshall_jtm45.pedalMarshall JTM45

Synthesizer Modules (examples/synths/):

FileModule
cem3340_vco.pedalCEM3340 VCO
moog_ladder_vcf.pedalMoog Ladder VCF
minisynth.pedalComplete mini-synth

.board File Format

A .board file defines a pedalboard — a signal chain of multiple .pedal files processed in series.

Structure

board "<Name>" {
  <id>: "<path_to_pedal_file>"
  <id>: "<path_to_pedal_file>" { <Knob> = <value>, ... }
}

Knob Overrides

Override default knob values inline with { Knob = value, ... }:

ts: "tube_screamer.pedal" { Drive = 0.6, Level = 0.7 }

Complete Example

# Blues Rig — classic three-pedal chain
board "Blues Rig" {
  ts: "tube_screamer.pedal" { Drive = 0.6, Level = 0.7 }
  bd: "blues_driver.pedal" { Gain = 0.5, Level = 0.6 }
  comp: "dyna_comp.pedal" { Sensitivity = 0.4, Output = 0.8 }
}

CLI Usage

Offline Processing

# Single pedal
pedalkernel process <file.pedal> <input.wav> <output.wav> [--pedalhw <file.pedalhw>] [--preset <name>] [--mod <name> ...] [--no-calibrate] [Knob=value ...]

# Pedalboard
pedalkernel process <file.board> <input.wav> <output.wav> [pedal_id.Knob=value ...]

Pedal knob overrides use Knob=value:

pedalkernel process tube_screamer.pedal input.wav out.wav Drive=0.9 Level=0.5

Hardware presets and mods can be pulled from .pedalhw without generating another .pedal file. If --pedalhw is omitted, process looks for a sibling file with the same stem:

pedalkernel process screamer.pedal input.wav out.wav --preset "Classic TS" --mod "TS9 Conversion" --no-calibrate

--no-calibrate disables the .pedal file’s calibrate output normalization for that render only.

Board knob overrides use pedal_id.Knob=value (the pedal_id matches the identifier in the .board file):

pedalkernel process blues_rig.board input.wav out.wav ts.Drive=0.9 bd.Gain=0.7

Validation

# Validate a single file
pedalkernel validate my_pedal.pedal

# Validate a directory (recursive)
pedalkernel validate examples/

# Validate with glob pattern
pedalkernel validate "examples/**/*.pedal"

# Auto-fix obvious issues (pin renames, etc.)
pedalkernel validate my_pedal.pedal --fix

Interactive TUI (requires JACK)

# Single pedal
pedalkernel tui <file.pedal>

# Pedalboard
pedalkernel tui <file.board>

# Directory browser (opens folder picker)
pedalkernel tui examples/

# Loop a WAV file as input instead of JACK port
pedalkernel tui <file.pedal> --input test.wav

The TUI provides:

  1. Port selection — choose JACK input/output ports
  2. Live control — adjust knobs in real-time while audio plays

The pedalboard TUI adds a chain bar showing all pedals, with [/] to switch between pedals and Space to bypass individual pedals.