Program Structure
| Component | Syntax | Purpose |
| Lua block | {...} | Define atoms, timing, effects |
| Atom stream | a=b=c=d | Sequence of sounds + rests |
| PAL action | /cmd/args/ | Patterns, tracks, playback |
| Comment | -- text | Ignored to end of line |
Atoms & Naming
| Form | Example | Notes |
| Single char | a–z | Defined in Lua: {a=saw("A4")} |
| Uppercase | A–Z | Loud variant of lowercase (redefinable) |
| Complex name | $kick | Lua: {$kick=env(...)}, stream: $kick |
| Volume (0-9) | a5, A3 | Number overrides case-based volume |
Notation Operators
| Op | Cells | Effect |
= | 1 | Rest (silence) |
_ | 2 | Long rest |
__ | 4 | Extra-long rest |
=xN | N | N cells of rest: =x16 |
ax4 | 4 | Sustain atom for 4 cells |
! or space | — | Hard cut (no morph) |
| newline | — | Hard cut |
. | — | Staccato (short note) |
~ | — | Tremolo |
/ \ | — | Pitch bend up / down |
^ | — | Break sustain |
| tab | — | Ignored (use for indentation) |
Transitions
| Type | Syntax | Result |
| Sustain | aaaa | One voice held 4 beats |
| Morph | abcd | Smooth glide a→b→c→d |
| Hard cut | a!b / a b | Separate attacks, no glide |
| Rest | a=b=c | Attacks with silence gaps |
Timing
{bpm=120; div=16} -- ms/cell = 240000 / (bpm × div)
| div | Note | @120 BPM | Cells/bar |
| 4 | Quarter | 500ms | 4 |
| 8 | Eighth | 250ms | 8 |
| 16 | 16th | 125ms | 16 |
| 32 | 32nd | 62.5ms | 32 |
Legacy: rate=8 = 8 beats/sec = 125ms/cell
Oscillators
Frequency accepts note strings or Hz: saw("A4"), saw("C4+7"), saw(440)
| Function | Sound | Example |
sine(f) | Pure tone, smooth | sine("A4") |
saw(f) | Rich harmonics, buzzy | saw("C3") |
square(f) | Hollow, clarinet-like | square("E4") |
tri(f) | Soft, flute-like | tri("G4") |
pulse(f, pw) | Variable duty (0.0–1.0) | pulse("A3", 0.3) |
Note offsets: "C4+7" = G4, "A4-12" = A3. Sharps/flats: "F#3", "Bb4"
Noise Generators
| Function | Spectrum |
noise() / white_noise() | Flat (equal energy) |
pink_noise() | −3 dB/oct (natural) |
brown_noise() / red_noise() | −6 dB/oct (deep rumble) |
blue_noise() | +3 dB/oct (bright) |
violet_noise() | +6 dB/oct (very bright) |
Filters
| Function | Type |
lpf(cutoff, src) | Low-pass |
hpf(cutoff, src) | High-pass |
bpf(cutoff, q, src) | Band-pass |
notch(cutoff, q, src) | Band-stop |
allpass(cutoff, q, src) | All-pass (phase shift) |
peak(cutoff, q, dB, src) | Parametric EQ bell |
Optional last param: key_follow (−1.0 to 1.0). 1.0 = cutoff tracks pitch.
Formant (Vowel) Filter
formant("ah", src) -- single vowel
formant("oh", 3, src) -- with tract shift (semitones)
Vowels: "ah" "eh" "ee" "oh" "oo" "ae" "uh" "er" "aw" "mm" "nn" "ng"
Envelopes
env(attack_ms, decay_ms, sustain_level, release_ms, source)
| Preset | A | D | S | R |
| Instant | 1 | 50 | 0.8 | 100 |
| Pluck | 2 | 150 | 0 | 100 |
| Pad | 500 | 800 | 0.8 | 1000 |
| Organ | 5 | 0 | 1.0 | 50 |
| Bell | 1 | 1500 | 0 | 2000 |
| Kick | 1 | 80 | 0 | 50 |
| Snare | 1 | 60 | 0 | 40 |
| Hi-hat | 1 | 20 | 0 | 10 |
Mixing & Gain
mix(src1, src2, ...) -- combine sources (auto-normalizes)
gain(0.5, src) -- apply volume (0.0-1.0, LFO-modulatable)
Simultaneity Groups (Chords)
(abc) -- three voices triggered at once (1 cell)
(abc)x4 -- sustain chord for 4 cells
(a)x4 -- sustain single atom for 4 cells
($pat)x4 -- if $pat is a PAL pattern: repeat 4× sequentially
Distortion
| Function | Effect |
soft_clip(drive, src) | Warm saturation (0.0–1.0) |
hard_clip(drive, src) | Aggressive clipping |
bitcrush(bits, src) | Lo-fi (2–16 bits) |
wavefold(amount, src) | Wave folding |
Time-Based Effects
delay(ms, feedback, src)
delay(ms, feedback, mix, src) -- with wet/dry
reverb(size, src)
reverb(size, damping, wet, width, src) -- full control
chorus(depth, src)
chorus(mix, delay_ms, depth_ms, rate, src)
flanger(depth, src)
flanger(mix, depth_ms, rate, fb, src)
Master Effects
master_gain(0.25) -- output volume (SET FIRST!)
master_reverb(size, damping)
master_delay(ms, feedback, mix)
master_limiter(threshold)
master_compress(ratio, threshold)
master_lpf(cutoff) -- also: hpf, bpf, notch, peak
master_lpf_bypass() -- disable default master LPF
master_chain("filter","delay","reverb") -- processing order
master_parallel(true) -- parallel filter+reverb
Group Effects (Bus Processing)
group("drums", {"k", "s", "h"}) -- define group
group_reverb("drums", size, damp)
group_lpf("drums", cutoff)
group_compress("drums", ratio, threshold)
LFOs (Low Frequency Oscillators)
name = lfo_sine(rate, depth, "mode")
a = sine(440 + 20 * name) -- modulate frequency
Waveforms
| Function | Shape |
lfo_sine | Smooth sine |
lfo_square | Gating / stepped |
lfo_saw | Rising ramp |
lfo_rsaw | Falling ramp |
lfo_tri | Triangle (linear) |
lfo_random | Sample & hold |
lfo_smooth_random | Smooth random drift |
lfo_exp | Exponential (sidechain) |
Unipolar: append _uni for 0-to-depth range (e.g., lfo_sine_uni)
Trigger Modes
| Mode | Behavior |
"retrigger" | Reset phase per voice |
"free" | Continuous (global phase) |
"sync" | Tempo-synced (rate = cycles/beat) |
"oneshot" | One cycle, then hold |
"key" | Phase seeded by MIDI note |
Shape Options
lfo_square(4,1,"sync", {pulsewidth=0.25})
lfo_exp(4,1,"sync", {direction="rise", curve_amount=3})
lfo_tri(2,1,"retrigger", {skew=0.2})
Params: pulsewidth, curve, skew, slew, smoothness, octaves, direction, curve_amount, phase
Envelope-Wrapped LFO
vib_raw = lfo_sine(6, 1.0, "retrigger")
vib = env_lfo(0, 200, 1.0, 50, vib_raw) -- fades in over 200ms
Common LFO Recipes
-- Vibrato
vib = lfo_sine(5,1,"retrigger"); a = sine(440+20*vib)
-- Filter wobble (tempo-synced)
w = lfo_sine(2,1,"sync"); a = lpf(300+1200*w, saw(55))
-- Sidechain pump
p = lfo_exp(4,1,"sync",{direction="rise",curve_amount=3})
a = gain(0.2+0.7*p, saw(110))
-- Tremolo
t = lfo_sine(4,0.3,"retrigger"); a = gain(0.5+0.3*t, sine(440))
Expressions (Per-Note Overrides)
`atom:pitch:velocity:duration:modifier=value`
| Example | Meaning |
`a:C4` | Atom a at C4 |
`a::100` | Default pitch, velocity 100 |
`a:::2` | Duration 2 units |
`a:G3:100:1:vib=4` | G3, vel 100, 1 unit, 4Hz vibrato |
Pitch: note (C4, F#3), offset (+7, -5), Hz (440hz)
Modifiers: vib, pan, att, rel, bend, cut
PAL — Playback Actions Language
Patterns & Tracks
/pa/$kick/k===k===k===k===/ -- define pattern
/tr/@drums/+$kick/ -- track with pattern ref (+)
/tr/@drums/*$kick/ -- track with pattern copy (*)
/tr/@lead/a=b=c=d/ -- track with inline atoms
Playback & Control
| Action | Effect |
/pp/ /pp/@t/ | Play all / specific track |
/ps/ /ps/@t/ | Pause all / specific |
/st/ /st/@t/ | Stop all / specific (rewind) |
/lp/on/ /lp/off/ | Enable / disable looping |
/tp/120/ | Set tempo |
/qt/16/ | Set quantize grid |
/mu/@t/ | Mute track |
/so/@t/ | Solo track |
Arpeggio Builder
/ar/$arp/u/ceg/ -- up: c!e!g
/ar/$arp/d/ceg/ -- down: g!e!c
/ar/$arp/ud/ceg/ -- up-down (ping-pong)
/ar/$arp/r/ceg/ -- random order
/ar/$arp/u/ceg/=/ -- rested: c=e=g
/ar/$arp/u/ceg// -- morph: ceg
FM Synthesis
a = fm({carrier=440, modulator=880, index=2.5})
a = fm({carrier=440, modulator=880, index=3.0,
algorithm="feedback", feedback=0.5}) -- with algorithm
Algorithms
| Name | Routing | Character |
stack2 | Op2 → Op1 | Standard 2-op (default) |
stack3 | Op3 → Op2 → Op1 | Brass, rich chain |
stack4 | Op4 → … → Op1 | Maximum depth |
parallel | Op2+Op3 → Op1 | Dual modulator |
feedback | Op2(self) → Op1 | Sawtooth-like |
additive | Op1+2+3+4 | Organ (no mod) |
twin | (Op2→1)+(Op4→3) | Two FM pairs |
diamond | Op3,4 → Op2 → Op1 | Complex intermod |
Operator Envelopes
a = fm({carrier=330, modulator=660, index=3.5,
operators={
{ratio=1.0, level=1.0}, -- carrier: full sustain
{ratio=2.0, level=1.0, -- modulator: fast decay
attack=1, decay=250, sustain=0.05, release=80}
}})
Modulation Index
| Index | Character | Use |
| 0.1–0.5 | Subtle shimmer | Warm pads |
| 1.0–2.0 | Classic FM | E-piano, vibes |
| 3.0–5.0 | Bright, brassy | Brass, leads |
| 5.0–10.0 | Metallic | Bells, gongs |
FM Ratios
| Mod:Car | Character | Use |
| 1:1 | Saw-like | Bass, leads |
| 2:1 | Bright octave | Electric piano |
| 3:1 | Hollow | Clarinet, reed |
| 1.41:1 | Bell-like | Bells, chimes |
FM Recipes
-- DX7 Electric Piano
e = env(5,600,0.3,300, fm({carrier=330,modulator=660,index=3.5,
operators={{ratio=1,level=1},{ratio=2,level=1,
attack=1,decay=250,sustain=0.05,release=80}}}))
-- FM Bass (1:1 ratio + LPF)
b = env(2,150,0.5,100, lpf(600, fm({carrier=55,modulator=55,
index=4.0,operators={{ratio=1,level=1},{ratio=1,level=1,
attack=1,decay=80,sustain=0.2,release=50}}})))
-- FM Bell (inharmonic ratio)
c = env(1,1500,0,800, fm({carrier=880,modulator=1241,index=5.0}))
Carrier op sustain=1.0 (Voice env shapes volume). Modulator decay shapes timbre.
Vocal / Apparatus Synthesis
a = apparatus("ah", 120) -- phoneme at Hz
b = vocal("ee", 220) -- alias
c = apparatus("oh", 150, "jitter=1.5;breathiness=0.8")
d = apparatus("mm", 110, "breathy") -- preset
Phonemes: same as formant vowel list. Params: jitter, breathiness, tremor=RATE,DEPTH. Presets: "breathy", "pressed"
Sample Playback
a = sample("kick.wav", 220) -- file, reference pitch
Utilities
note_to_hz("C4") -- returns 261.63
hz_to_note(440) -- returns "A4"
Lua Helper Functions
function lead(note)
local f = note_to_hz(note)
return env(10,80,0.6,60, lpf(2000, saw(f)))
end
a = lead("C4"); b = lead("E4")
Per-Atom Configuration
a.duration = 60 -- sustain 60ms
a.attack = 10 -- per-atom ADSR overrides
a.decay = 5; a.sustain = 60; a.release = 5
a.level = {3.5, 6.25} -- default volume {lowercase, UPPERCASE}
a.poly = 4 -- max simultaneous voices
Global Configuration
root = 440 -- A4 tuning reference in Hz (default: 440)
Cell Counts
| Element | Cells |
Atom (a, k) | 1 |
Rest = | 1 |
Rest _ | 2 |
Rest __ | 4 |
Staccato a. | 1 (modifier only) |
Chord (abc) | 1 |
Sustain ax4 / (abc)x4 | 4 |
Rest =x4 | 4 |
Pattern ($pat)x4 | 4 × pattern length |
One bar = div cells. Patterns in a multi-track composition should be the same cell count (or intentional multiples for polymetric effects).
Frequency Reference
| Note | Hz | Note | Hz | Note | Hz |
| A1 | 55 | A3 | 220 | A5 | 880 |
| C2 | 65 | C4 | 262 | C6 | 1047 |
| E2 | 82 | E4 | 330 | | |
| A2 | 110 | G4 | 392 | | |
| C3 | 131 | A4 | 440 | | |
| E3 | 165 | C5 | 523 | | |
Note string offsets: "C4+7" = G4, "A4-12" = A3