use super::ops::Op; use super::theory; use super::types::{Dictionary, SourceSpan}; pub enum WordCompile { Simple, Context(&'static str), Param, Probability(f64), } pub struct Word { pub name: &'static str, pub aliases: &'static [&'static str], pub category: &'static str, pub stack: &'static str, pub desc: &'static str, pub example: &'static str, pub compile: WordCompile, pub varargs: bool, } use WordCompile::*; pub const WORDS: &[Word] = &[ // Stack manipulation Word { name: "dup", aliases: &[], category: "Stack", stack: "(a -- a a)", desc: "Duplicate top of stack", example: "3 dup => 3 3", compile: Simple, varargs: false, }, Word { name: "dupn", aliases: &["!"], category: "Stack", stack: "(a n -- a a ... a)", desc: "Duplicate a onto stack n times", example: "2 4 dupn => 2 2 2 2", compile: Simple, varargs: true, }, Word { name: "drop", aliases: &[], category: "Stack", stack: "(a --)", desc: "Remove top of stack", example: "1 2 drop => 1", compile: Simple, varargs: false, }, Word { name: "swap", aliases: &[], category: "Stack", stack: "(a b -- b a)", desc: "Exchange top two items", example: "1 2 swap => 2 1", compile: Simple, varargs: false, }, Word { name: "over", aliases: &[], category: "Stack", stack: "(a b -- a b a)", desc: "Copy second to top", example: "1 2 over => 1 2 1", compile: Simple, varargs: false, }, Word { name: "rot", aliases: &[], category: "Stack", stack: "(a b c -- b c a)", desc: "Rotate top three", example: "1 2 3 rot => 2 3 1", compile: Simple, varargs: false, }, Word { name: "nip", aliases: &[], category: "Stack", stack: "(a b -- b)", desc: "Remove second item", example: "1 2 nip => 2", compile: Simple, varargs: false, }, Word { name: "tuck", aliases: &[], category: "Stack", stack: "(a b -- b a b)", desc: "Copy top under second", example: "1 2 tuck => 2 1 2", compile: Simple, varargs: false, }, // Arithmetic Word { name: "+", aliases: &[], category: "Arithmetic", stack: "(a b -- a+b)", desc: "Add", example: "2 3 + => 5", compile: Simple, varargs: false, }, Word { name: "-", aliases: &[], category: "Arithmetic", stack: "(a b -- a-b)", desc: "Subtract", example: "5 3 - => 2", compile: Simple, varargs: false, }, Word { name: "*", aliases: &[], category: "Arithmetic", stack: "(a b -- a*b)", desc: "Multiply", example: "3 4 * => 12", compile: Simple, varargs: false, }, Word { name: "/", aliases: &[], category: "Arithmetic", stack: "(a b -- a/b)", desc: "Divide", example: "10 2 / => 5", compile: Simple, varargs: false, }, Word { name: "mod", aliases: &[], category: "Arithmetic", stack: "(a b -- a%b)", desc: "Modulo", example: "7 3 mod => 1", compile: Simple, varargs: false, }, Word { name: "neg", aliases: &[], category: "Arithmetic", stack: "(a -- -a)", desc: "Negate", example: "5 neg => -5", compile: Simple, varargs: false, }, Word { name: "abs", aliases: &[], category: "Arithmetic", stack: "(a -- |a|)", desc: "Absolute value", example: "-5 abs => 5", compile: Simple, varargs: false, }, Word { name: "floor", aliases: &[], category: "Arithmetic", stack: "(f -- n)", desc: "Round down to integer", example: "3.7 floor => 3", compile: Simple, varargs: false, }, Word { name: "ceil", aliases: &[], category: "Arithmetic", stack: "(f -- n)", desc: "Round up to integer", example: "3.2 ceil => 4", compile: Simple, varargs: false, }, Word { name: "round", aliases: &[], category: "Arithmetic", stack: "(f -- n)", desc: "Round to nearest integer", example: "3.5 round => 4", compile: Simple, varargs: false, }, Word { name: "min", aliases: &[], category: "Arithmetic", stack: "(a b -- min)", desc: "Minimum of two values", example: "3 5 min => 3", compile: Simple, varargs: false, }, Word { name: "max", aliases: &[], category: "Arithmetic", stack: "(a b -- max)", desc: "Maximum of two values", example: "3 5 max => 5", compile: Simple, varargs: false, }, Word { name: "pow", aliases: &[], category: "Arithmetic", stack: "(a b -- a^b)", desc: "Exponentiation", example: "2 3 pow => 8", compile: Simple, varargs: false, }, Word { name: "sqrt", aliases: &[], category: "Arithmetic", stack: "(a -- √a)", desc: "Square root", example: "16 sqrt => 4", compile: Simple, varargs: false, }, Word { name: "sin", aliases: &[], category: "Arithmetic", stack: "(a -- sin(a))", desc: "Sine (radians)", example: "3.14159 2 / sin => 1.0", compile: Simple, varargs: false, }, Word { name: "cos", aliases: &[], category: "Arithmetic", stack: "(a -- cos(a))", desc: "Cosine (radians)", example: "0 cos => 1.0", compile: Simple, varargs: false, }, Word { name: "log", aliases: &[], category: "Arithmetic", stack: "(a -- ln(a))", desc: "Natural logarithm", example: "2.718 log => 1.0", compile: Simple, varargs: false, }, // Comparison Word { name: "=", aliases: &[], category: "Comparison", stack: "(a b -- bool)", desc: "Equal", example: "3 3 = => 1", compile: Simple, varargs: false, }, Word { name: "!=", aliases: &["<>"], category: "Comparison", stack: "(a b -- bool)", desc: "Not equal", example: "3 4 != => 1", compile: Simple, varargs: false, }, Word { name: "lt", aliases: &[], category: "Comparison", stack: "(a b -- bool)", desc: "Less than", example: "2 3 lt => 1", compile: Simple, varargs: false, }, Word { name: "gt", aliases: &[], category: "Comparison", stack: "(a b -- bool)", desc: "Greater than", example: "3 2 gt => 1", compile: Simple, varargs: false, }, Word { name: "<=", aliases: &[], category: "Comparison", stack: "(a b -- bool)", desc: "Less or equal", example: "3 3 <= => 1", compile: Simple, varargs: false, }, Word { name: ">=", aliases: &[], category: "Comparison", stack: "(a b -- bool)", desc: "Greater or equal", example: "3 3 >= => 1", compile: Simple, varargs: false, }, // Logic Word { name: "and", aliases: &[], category: "Logic", stack: "(a b -- bool)", desc: "Logical and", example: "1 1 and => 1", compile: Simple, varargs: false, }, Word { name: "or", aliases: &[], category: "Logic", stack: "(a b -- bool)", desc: "Logical or", example: "0 1 or => 1", compile: Simple, varargs: false, }, Word { name: "not", aliases: &[], category: "Logic", stack: "(a -- bool)", desc: "Logical not", example: "0 not => 1", compile: Simple, varargs: false, }, Word { name: "xor", aliases: &[], category: "Logic", stack: "(a b -- bool)", desc: "Exclusive or", example: "1 0 xor => 1", compile: Simple, varargs: false, }, Word { name: "nand", aliases: &[], category: "Logic", stack: "(a b -- bool)", desc: "Not and", example: "1 1 nand => 0", compile: Simple, varargs: false, }, Word { name: "nor", aliases: &[], category: "Logic", stack: "(a b -- bool)", desc: "Not or", example: "0 0 nor => 1", compile: Simple, varargs: false, }, Word { name: "ifelse", aliases: &[], category: "Logic", stack: "(true-quot false-quot bool --)", desc: "Execute true-quot if true, else false-quot", example: "{ 1 } { 2 } coin ifelse", compile: Simple, varargs: false, }, Word { name: "pick", aliases: &[], category: "Logic", stack: "(..quots n --)", desc: "Execute nth quotation (0-indexed)", example: "{ 1 } { 2 } { 3 } 2 pick => 3", compile: Simple, varargs: true, }, // Sound Word { name: "sound", aliases: &["s"], category: "Sound", stack: "(name --)", desc: "Begin sound command", example: "\"kick\" sound", compile: Simple, varargs: false, }, Word { name: ".", aliases: &[], category: "Sound", stack: "(--)", desc: "Emit current sound", example: "\"kick\" s . . . .", compile: Simple, varargs: false, }, // Variables (prefix syntax: @name to fetch, !name to store) Word { name: "@", aliases: &[], category: "Variables", stack: "( -- val)", desc: "Fetch variable value", example: "@freq => 440", compile: Simple, varargs: false, }, Word { name: "!", aliases: &[], category: "Variables", stack: "(val --)", desc: "Store value in variable", example: "440 !freq", compile: Simple, varargs: false, }, // Randomness Word { name: "rand", aliases: &[], category: "Randomness", stack: "(min max -- n|f)", desc: "Random in range. Int if both args are int, float otherwise", example: "1 6 rand => 4 | 0.0 1.0 rand => 0.42", compile: Simple, varargs: false, }, Word { name: "seed", aliases: &[], category: "Randomness", stack: "(n --)", desc: "Set random seed", example: "12345 seed", compile: Simple, varargs: false, }, Word { name: "coin", aliases: &[], category: "Randomness", stack: "(-- bool)", desc: "50/50 random boolean", example: "coin => 0 or 1", compile: Simple, varargs: false, }, Word { name: "chance", aliases: &[], category: "Probability", stack: "(quot prob --)", desc: "Execute quotation with probability (0.0-1.0)", example: "{ 2 distort } 0.75 chance", compile: Simple, varargs: false, }, Word { name: "prob", aliases: &[], category: "Probability", stack: "(quot pct --)", desc: "Execute quotation with probability (0-100)", example: "{ 2 distort } 75 prob", compile: Simple, varargs: false, }, Word { name: "choose", aliases: &[], category: "Randomness", stack: "(..n n -- val)", desc: "Random pick from n items", example: "1 2 3 3 choose", compile: Simple, varargs: true, }, Word { name: "cycle", aliases: &[], category: "Selection", stack: "(v1..vn n -- selected)", desc: "Cycle through n items by step runs", example: "60 64 67 3 cycle", compile: Simple, varargs: true, }, Word { name: "pcycle", aliases: &[], category: "Selection", stack: "(v1..vn n -- selected)", desc: "Cycle through n items by pattern iteration", example: "60 64 67 3 pcycle", compile: Simple, varargs: true, }, Word { name: "tcycle", aliases: &[], category: "Selection", stack: "(v1..vn n -- CycleList)", desc: "Create cycle list for emit-time resolution", example: "60 64 67 3 tcycle note", compile: Simple, varargs: true, }, Word { name: "every", aliases: &[], category: "Time", stack: "(n -- bool)", desc: "True every nth iteration", example: "4 every", compile: Simple, varargs: false, }, // Probability shortcuts Word { name: "always", aliases: &[], category: "Probability", stack: "(quot --)", desc: "Always execute quotation", example: "{ 2 distort } always", compile: Probability(1.0), varargs: false, }, Word { name: "never", aliases: &[], category: "Probability", stack: "(quot --)", desc: "Never execute quotation", example: "{ 2 distort } never", compile: Probability(0.0), varargs: false, }, Word { name: "often", aliases: &[], category: "Probability", stack: "(quot --)", desc: "Execute quotation 75% of the time", example: "{ 2 distort } often", compile: Probability(0.75), varargs: false, }, Word { name: "sometimes", aliases: &[], category: "Probability", stack: "(quot --)", desc: "Execute quotation 50% of the time", example: "{ 2 distort } sometimes", compile: Probability(0.5), varargs: false, }, Word { name: "rarely", aliases: &[], category: "Probability", stack: "(quot --)", desc: "Execute quotation 25% of the time", example: "{ 2 distort } rarely", compile: Probability(0.25), varargs: false, }, Word { name: "almostNever", aliases: &[], category: "Probability", stack: "(quot --)", desc: "Execute quotation 10% of the time", example: "{ 2 distort } almostNever", compile: Probability(0.1), varargs: false, }, Word { name: "almostAlways", aliases: &[], category: "Probability", stack: "(quot --)", desc: "Execute quotation 90% of the time", example: "{ 2 distort } almostAlways", compile: Probability(0.9), varargs: false, }, // Context Word { name: "step", aliases: &[], category: "Context", stack: "(-- n)", desc: "Current step index", example: "step => 0", compile: Context("step"), varargs: false, }, Word { name: "beat", aliases: &[], category: "Context", stack: "(-- f)", desc: "Current beat position", example: "beat => 4.5", compile: Context("beat"), varargs: false, }, Word { name: "bank", aliases: &[], category: "Sample", stack: "(str --)", desc: "Set sample bank suffix", example: "\"a\" bank", compile: Param, varargs: false, }, Word { name: "pattern", aliases: &[], category: "Context", stack: "(-- n)", desc: "Current pattern index", example: "pattern => 0", compile: Context("pattern"), varargs: false, }, Word { name: "pbank", aliases: &[], category: "Context", stack: "(-- n)", desc: "Current pattern's bank index", example: "pbank => 0", compile: Context("bank"), varargs: false, }, Word { name: "tempo", aliases: &[], category: "Context", stack: "(-- f)", desc: "Current BPM", example: "tempo => 120.0", compile: Context("tempo"), varargs: false, }, Word { name: "phase", aliases: &[], category: "Context", stack: "(-- f)", desc: "Phase in bar (0-1)", example: "phase => 0.25", compile: Context("phase"), varargs: false, }, Word { name: "slot", aliases: &[], category: "Context", stack: "(-- n)", desc: "Current slot number", example: "slot => 0", compile: Context("slot"), varargs: false, }, Word { name: "runs", aliases: &[], category: "Context", stack: "(-- n)", desc: "Times this step ran", example: "runs => 3", compile: Context("runs"), varargs: false, }, Word { name: "iter", aliases: &[], category: "Context", stack: "(-- n)", desc: "Pattern iteration count", example: "iter => 2", compile: Context("iter"), varargs: false, }, Word { name: "stepdur", aliases: &[], category: "Context", stack: "(-- f)", desc: "Step duration in seconds", example: "stepdur => 0.125", compile: Context("stepdur"), varargs: false, }, // Live keys Word { name: "fill", aliases: &[], category: "Context", stack: "(-- bool)", desc: "True when fill is on (f key)", example: "\"snare\" s . fill ?", compile: Context("fill"), varargs: false, }, // Music Word { name: "mtof", aliases: &[], category: "Music", stack: "(midi -- hz)", desc: "MIDI note to frequency", example: "69 mtof => 440.0", compile: Simple, varargs: false, }, Word { name: "ftom", aliases: &[], category: "Music", stack: "(hz -- midi)", desc: "Frequency to MIDI note", example: "440 ftom => 69.0", compile: Simple, varargs: false, }, // LFO Word { name: "ramp", aliases: &[], category: "LFO", stack: "(freq curve -- val)", desc: "Ramp [0,1]: fract(freq*beat)^curve", example: "0.25 2.0 ramp", compile: Simple, varargs: false, }, Word { name: "range", aliases: &[], category: "LFO", stack: "(val min max -- scaled)", desc: "Scale [0,1] to [min,max]", example: "0.5 200 800 range => 500", compile: Simple, varargs: false, }, Word { name: "linramp", aliases: &[], category: "LFO", stack: "(freq -- val)", desc: "Linear ramp (curve=1)", example: "1.0 linramp", compile: Simple, varargs: false, }, Word { name: "expramp", aliases: &[], category: "LFO", stack: "(freq -- val)", desc: "Exponential ramp (curve=3)", example: "0.25 expramp", compile: Simple, varargs: false, }, Word { name: "logramp", aliases: &[], category: "LFO", stack: "(freq -- val)", desc: "Logarithmic ramp (curve=0.3)", example: "2.0 logramp", compile: Simple, varargs: false, }, Word { name: "tri", aliases: &[], category: "LFO", stack: "(freq -- val)", desc: "Triangle wave [0,1]: 0→1→0", example: "0.5 tri", compile: Simple, varargs: false, }, Word { name: "perlin", aliases: &[], category: "LFO", stack: "(freq -- val)", desc: "Perlin noise [0,1] sampled at freq*beat", example: "0.25 perlin", compile: Simple, varargs: false, }, Word { name: "loop", aliases: &[], category: "Time", stack: "(n --)", desc: "Fit sample to n beats", example: "\"break\" s 4 loop @", compile: Simple, varargs: false, }, Word { name: "tempo!", aliases: &[], category: "Time", stack: "(bpm --)", desc: "Set global tempo", example: "140 tempo!", compile: Simple, varargs: false, }, Word { name: "speed!", aliases: &[], category: "Time", stack: "(multiplier --)", desc: "Set pattern speed multiplier", example: "2.0 speed!", compile: Simple, varargs: false, }, Word { name: "chain", aliases: &[], category: "Time", stack: "(bank pattern --)", desc: "Chain to bank/pattern (1-indexed) when current pattern ends", example: "1 4 chain", compile: Simple, varargs: false, }, Word { name: "at", aliases: &[], category: "Time", stack: "(v1..vn n --)", desc: "Set delta context for emit timing", example: "0 0.5 2 at kick s . => emits at 0 and 0.5 of step", compile: Simple, varargs: true, }, // Quotations Word { name: "?", aliases: &[], category: "Logic", stack: "(quot bool --)", desc: "Execute quotation if true", example: "{ 2 distort } 0.5 chance ?", compile: Simple, varargs: false, }, Word { name: "!?", aliases: &[], category: "Logic", stack: "(quot bool --)", desc: "Execute quotation if false", example: "{ 1 distort } 0.5 chance !?", compile: Simple, varargs: false, }, // Sample playback Word { name: "time", aliases: &[], category: "Sample", stack: "(f --)", desc: "Set time offset", example: "0.1 time", compile: Param, varargs: false, }, Word { name: "repeat", aliases: &[], category: "Sample", stack: "(n --)", desc: "Set repeat count", example: "4 repeat", compile: Param, varargs: false, }, Word { name: "dur", aliases: &[], category: "Sample", stack: "(f --)", desc: "Set duration", example: "0.5 dur", compile: Param, varargs: false, }, Word { name: "gate", aliases: &[], category: "Sample", stack: "(f --)", desc: "Set gate time", example: "0.8 gate", compile: Param, varargs: false, }, Word { name: "freq", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set frequency (Hz)", example: "440 freq", compile: Param, varargs: false, }, Word { name: "detune", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set detune amount", example: "0.01 detune", compile: Param, varargs: false, }, Word { name: "speed", aliases: &[], category: "Sample", stack: "(f --)", desc: "Set playback speed", example: "1.5 speed", compile: Param, varargs: false, }, Word { name: "glide", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set glide/portamento", example: "0.1 glide", compile: Param, varargs: false, }, Word { name: "pw", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set pulse width", example: "0.5 pw", compile: Param, varargs: false, }, Word { name: "spread", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set stereo spread", example: "0.5 spread", compile: Param, varargs: false, }, Word { name: "mult", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set multiplier", example: "2 mult", compile: Param, varargs: false, }, Word { name: "warp", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set warp amount", example: "0.5 warp", compile: Param, varargs: false, }, Word { name: "mirror", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set mirror", example: "1 mirror", compile: Param, varargs: false, }, Word { name: "harmonics", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set harmonics (mutable only)", example: "4 harmonics", compile: Param, varargs: false, }, Word { name: "timbre", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set timbre (mutable only)", example: "0.5 timbre", compile: Param, varargs: false, }, Word { name: "morph", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set morph (mutable only)", example: "0.5 morph", compile: Param, varargs: false, }, Word { name: "scan", aliases: &[], category: "Wavetable", stack: "(f --)", desc: "Set wavetable scan position (0-1)", example: "0.5 scan", compile: Param, varargs: false, }, Word { name: "wtlen", aliases: &[], category: "Wavetable", stack: "(n --)", desc: "Set wavetable cycle length in samples", example: "2048 wtlen", compile: Param, varargs: false, }, Word { name: "scanlfo", aliases: &[], category: "Wavetable", stack: "(f --)", desc: "Set scan LFO rate (Hz)", example: "0.2 scanlfo", compile: Param, varargs: false, }, Word { name: "scandepth", aliases: &[], category: "Wavetable", stack: "(f --)", desc: "Set scan LFO depth (0-1)", example: "0.4 scandepth", compile: Param, varargs: false, }, Word { name: "scanshape", aliases: &[], category: "Wavetable", stack: "(s --)", desc: "Set scan LFO shape (sine/tri/saw/square/sh)", example: "\"tri\" scanshape", compile: Param, varargs: false, }, Word { name: "begin", aliases: &[], category: "Sample", stack: "(f --)", desc: "Set sample start (0-1)", example: "0.25 begin", compile: Param, varargs: false, }, Word { name: "end", aliases: &[], category: "Sample", stack: "(f --)", desc: "Set sample end (0-1)", example: "0.75 end", compile: Param, varargs: false, }, Word { name: "gain", aliases: &[], category: "Gain", stack: "(f --)", desc: "Set volume (0-1)", example: "0.8 gain", compile: Param, varargs: false, }, Word { name: "postgain", aliases: &[], category: "Gain", stack: "(f --)", desc: "Set post gain", example: "1.2 postgain", compile: Param, varargs: false, }, Word { name: "velocity", aliases: &[], category: "Gain", stack: "(f --)", desc: "Set velocity", example: "100 velocity", compile: Param, varargs: false, }, Word { name: "pan", aliases: &[], category: "Gain", stack: "(f --)", desc: "Set pan (-1 to 1)", example: "0.5 pan", compile: Param, varargs: false, }, Word { name: "attack", aliases: &["att"], category: "Envelope", stack: "(f --)", desc: "Set attack time", example: "0.01 attack", compile: Param, varargs: false, }, Word { name: "decay", aliases: &["dec"], category: "Envelope", stack: "(f --)", desc: "Set decay time", example: "0.1 decay", compile: Param, varargs: false, }, Word { name: "sustain", aliases: &["sus"], category: "Envelope", stack: "(f --)", desc: "Set sustain level", example: "0.5 sustain", compile: Param, varargs: false, }, Word { name: "release", aliases: &["rel"], category: "Envelope", stack: "(f --)", desc: "Set release time", example: "0.3 release", compile: Param, varargs: false, }, Word { name: "adsr", aliases: &[], category: "Envelope", stack: "(a d s r --)", desc: "Set attack, decay, sustain, release", example: "0.01 0.1 0.5 0.3 adsr", compile: Simple, varargs: false, }, Word { name: "ad", aliases: &[], category: "Envelope", stack: "(a d --)", desc: "Set attack, decay (sustain=0)", example: "0.01 0.1 ad", compile: Simple, varargs: false, }, Word { name: "lpf", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set lowpass frequency", example: "2000 lpf", compile: Param, varargs: false, }, Word { name: "lpq", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set lowpass resonance", example: "0.5 lpq", compile: Param, varargs: false, }, Word { name: "lpe", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set lowpass envelope", example: "0.5 lpe", compile: Param, varargs: false, }, Word { name: "lpa", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set lowpass attack", example: "0.01 lpa", compile: Param, varargs: false, }, Word { name: "lpd", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set lowpass decay", example: "0.1 lpd", compile: Param, varargs: false, }, Word { name: "lps", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set lowpass sustain", example: "0.5 lps", compile: Param, varargs: false, }, Word { name: "lpr", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set lowpass release", example: "0.3 lpr", compile: Param, varargs: false, }, Word { name: "hpf", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set highpass frequency", example: "100 hpf", compile: Param, varargs: false, }, Word { name: "hpq", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set highpass resonance", example: "0.5 hpq", compile: Param, varargs: false, }, Word { name: "hpe", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set highpass envelope", example: "0.5 hpe", compile: Param, varargs: false, }, Word { name: "hpa", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set highpass attack", example: "0.01 hpa", compile: Param, varargs: false, }, Word { name: "hpd", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set highpass decay", example: "0.1 hpd", compile: Param, varargs: false, }, Word { name: "hps", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set highpass sustain", example: "0.5 hps", compile: Param, varargs: false, }, Word { name: "hpr", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set highpass release", example: "0.3 hpr", compile: Param, varargs: false, }, Word { name: "bpf", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set bandpass frequency", example: "1000 bpf", compile: Param, varargs: false, }, Word { name: "bpq", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set bandpass resonance", example: "0.5 bpq", compile: Param, varargs: false, }, Word { name: "bpe", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set bandpass envelope", example: "0.5 bpe", compile: Param, varargs: false, }, Word { name: "bpa", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set bandpass attack", example: "0.01 bpa", compile: Param, varargs: false, }, Word { name: "bpd", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set bandpass decay", example: "0.1 bpd", compile: Param, varargs: false, }, Word { name: "bps", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set bandpass sustain", example: "0.5 bps", compile: Param, varargs: false, }, Word { name: "bpr", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set bandpass release", example: "0.3 bpr", compile: Param, varargs: false, }, Word { name: "llpf", aliases: &[], category: "Ladder Filter", stack: "(f --)", desc: "Set ladder lowpass frequency", example: "2000 llpf", compile: Param, varargs: false, }, Word { name: "llpq", aliases: &[], category: "Ladder Filter", stack: "(f --)", desc: "Set ladder lowpass resonance", example: "0.5 llpq", compile: Param, varargs: false, }, Word { name: "lhpf", aliases: &[], category: "Ladder Filter", stack: "(f --)", desc: "Set ladder highpass frequency", example: "100 lhpf", compile: Param, varargs: false, }, Word { name: "lhpq", aliases: &[], category: "Ladder Filter", stack: "(f --)", desc: "Set ladder highpass resonance", example: "0.5 lhpq", compile: Param, varargs: false, }, Word { name: "lbpf", aliases: &[], category: "Ladder Filter", stack: "(f --)", desc: "Set ladder bandpass frequency", example: "1000 lbpf", compile: Param, varargs: false, }, Word { name: "lbpq", aliases: &[], category: "Ladder Filter", stack: "(f --)", desc: "Set ladder bandpass resonance", example: "0.5 lbpq", compile: Param, varargs: false, }, Word { name: "ftype", aliases: &[], category: "Filter", stack: "(n --)", desc: "Set filter type", example: "1 ftype", compile: Param, varargs: false, }, Word { name: "penv", aliases: &[], category: "Pitch Env", stack: "(f --)", desc: "Set pitch envelope", example: "0.5 penv", compile: Param, varargs: false, }, Word { name: "patt", aliases: &[], category: "Pitch Env", stack: "(f --)", desc: "Set pitch attack", example: "0.01 patt", compile: Param, varargs: false, }, Word { name: "pdec", aliases: &[], category: "Pitch Env", stack: "(f --)", desc: "Set pitch decay", example: "0.1 pdec", compile: Param, varargs: false, }, Word { name: "psus", aliases: &[], category: "Pitch Env", stack: "(f --)", desc: "Set pitch sustain", example: "0 psus", compile: Param, varargs: false, }, Word { name: "prel", aliases: &[], category: "Pitch Env", stack: "(f --)", desc: "Set pitch release", example: "0.1 prel", compile: Param, varargs: false, }, Word { name: "vib", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set vibrato rate", example: "5 vib", compile: Param, varargs: false, }, Word { name: "vibmod", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set vibrato depth", example: "0.5 vibmod", compile: Param, varargs: false, }, Word { name: "vibshape", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set vibrato shape", example: "0 vibshape", compile: Param, varargs: false, }, Word { name: "fm", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set FM frequency", example: "200 fm", compile: Param, varargs: false, }, Word { name: "fmh", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set FM harmonic ratio", example: "2 fmh", compile: Param, varargs: false, }, Word { name: "fmshape", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set FM shape", example: "0 fmshape", compile: Param, varargs: false, }, Word { name: "fme", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set FM envelope", example: "0.5 fme", compile: Param, varargs: false, }, Word { name: "fma", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set FM attack", example: "0.01 fma", compile: Param, varargs: false, }, Word { name: "fmd", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set FM decay", example: "0.1 fmd", compile: Param, varargs: false, }, Word { name: "fms", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set FM sustain", example: "0.5 fms", compile: Param, varargs: false, }, Word { name: "fmr", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set FM release", example: "0.1 fmr", compile: Param, varargs: false, }, Word { name: "am", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set AM frequency", example: "10 am", compile: Param, varargs: false, }, Word { name: "amdepth", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set AM depth", example: "0.5 amdepth", compile: Param, varargs: false, }, Word { name: "amshape", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set AM shape", example: "0 amshape", compile: Param, varargs: false, }, Word { name: "rm", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set RM frequency", example: "100 rm", compile: Param, varargs: false, }, Word { name: "rmdepth", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set RM depth", example: "0.5 rmdepth", compile: Param, varargs: false, }, Word { name: "rmshape", aliases: &[], category: "Modulation", stack: "(f --)", desc: "Set RM shape", example: "0 rmshape", compile: Param, varargs: false, }, Word { name: "phaser", aliases: &[], category: "Mod FX", stack: "(f --)", desc: "Set phaser rate", example: "1 phaser", compile: Param, varargs: false, }, Word { name: "phaserdepth", aliases: &[], category: "Mod FX", stack: "(f --)", desc: "Set phaser depth", example: "0.5 phaserdepth", compile: Param, varargs: false, }, Word { name: "phasersweep", aliases: &[], category: "Mod FX", stack: "(f --)", desc: "Set phaser sweep", example: "0.5 phasersweep", compile: Param, varargs: false, }, Word { name: "phasercenter", aliases: &[], category: "Mod FX", stack: "(f --)", desc: "Set phaser center", example: "1000 phasercenter", compile: Param, varargs: false, }, Word { name: "flanger", aliases: &[], category: "Mod FX", stack: "(f --)", desc: "Set flanger rate", example: "0.5 flanger", compile: Param, varargs: false, }, Word { name: "flangerdepth", aliases: &[], category: "Mod FX", stack: "(f --)", desc: "Set flanger depth", example: "0.5 flangerdepth", compile: Param, varargs: false, }, Word { name: "flangerfeedback", aliases: &[], category: "Mod FX", stack: "(f --)", desc: "Set flanger feedback", example: "0.5 flangerfeedback", compile: Param, varargs: false, }, Word { name: "chorus", aliases: &[], category: "Mod FX", stack: "(f --)", desc: "Set chorus rate", example: "1 chorus", compile: Param, varargs: false, }, Word { name: "chorusdepth", aliases: &[], category: "Mod FX", stack: "(f --)", desc: "Set chorus depth", example: "0.5 chorusdepth", compile: Param, varargs: false, }, Word { name: "chorusdelay", aliases: &[], category: "Mod FX", stack: "(f --)", desc: "Set chorus delay", example: "0.02 chorusdelay", compile: Param, varargs: false, }, Word { name: "eqlo", aliases: &[], category: "EQ", stack: "(f --)", desc: "Set low shelf gain (dB)", example: "3 eqlo", compile: Param, varargs: false, }, Word { name: "eqmid", aliases: &[], category: "EQ", stack: "(f --)", desc: "Set mid peak gain (dB)", example: "-2 eqmid", compile: Param, varargs: false, }, Word { name: "eqhi", aliases: &[], category: "EQ", stack: "(f --)", desc: "Set high shelf gain (dB)", example: "1 eqhi", compile: Param, varargs: false, }, Word { name: "tilt", aliases: &[], category: "EQ", stack: "(f --)", desc: "Set tilt EQ (-1 dark, 1 bright)", example: "-0.5 tilt", compile: Param, varargs: false, }, Word { name: "width", aliases: &[], category: "Stereo", stack: "(f --)", desc: "Set stereo width (0 mono, 1 normal, 2 wide)", example: "0 width", compile: Param, varargs: false, }, Word { name: "haas", aliases: &[], category: "Stereo", stack: "(f --)", desc: "Set Haas delay in ms (spatial placement)", example: "8 haas", compile: Param, varargs: false, }, Word { name: "comb", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set comb filter mix", example: "0.5 comb", compile: Param, varargs: false, }, Word { name: "combfreq", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set comb frequency", example: "200 combfreq", compile: Param, varargs: false, }, Word { name: "combfeedback", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set comb feedback", example: "0.5 combfeedback", compile: Param, varargs: false, }, Word { name: "combdamp", aliases: &[], category: "Filter", stack: "(f --)", desc: "Set comb damping", example: "0.5 combdamp", compile: Param, varargs: false, }, Word { name: "coarse", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set coarse tune", example: "12 coarse", compile: Param, varargs: false, }, Word { name: "crush", aliases: &[], category: "Lo-fi", stack: "(f --)", desc: "Set bit crush", example: "8 crush", compile: Param, varargs: false, }, Word { name: "sub", aliases: &[], category: "Oscillator", stack: "(f --)", desc: "Set sub oscillator level", example: "0.5 sub", compile: Param, varargs: false, }, Word { name: "suboct", aliases: &[], category: "Oscillator", stack: "(n --)", desc: "Set sub oscillator octave", example: "2 suboct", compile: Param, varargs: false, }, Word { name: "subwave", aliases: &[], category: "Oscillator", stack: "(n --)", desc: "Set sub oscillator waveform", example: "1 subwave", compile: Param, varargs: false, }, Word { name: "fold", aliases: &[], category: "Lo-fi", stack: "(f --)", desc: "Set wave fold", example: "2 fold", compile: Param, varargs: false, }, Word { name: "wrap", aliases: &[], category: "Lo-fi", stack: "(f --)", desc: "Set wave wrap", example: "0.5 wrap", compile: Param, varargs: false, }, Word { name: "distort", aliases: &[], category: "Lo-fi", stack: "(f --)", desc: "Set distortion", example: "0.5 distort", compile: Param, varargs: false, }, Word { name: "distortvol", aliases: &[], category: "Lo-fi", stack: "(f --)", desc: "Set distortion volume", example: "0.8 distortvol", compile: Param, varargs: false, }, Word { name: "delay", aliases: &[], category: "Delay", stack: "(f --)", desc: "Set delay mix", example: "0.3 delay", compile: Param, varargs: false, }, Word { name: "delaytime", aliases: &[], category: "Delay", stack: "(f --)", desc: "Set delay time", example: "0.25 delaytime", compile: Param, varargs: false, }, Word { name: "delayfeedback", aliases: &[], category: "Delay", stack: "(f --)", desc: "Set delay feedback", example: "0.5 delayfeedback", compile: Param, varargs: false, }, Word { name: "delaytype", aliases: &[], category: "Delay", stack: "(n --)", desc: "Set delay type", example: "1 delaytype", compile: Param, varargs: false, }, Word { name: "verb", aliases: &[], category: "Reverb", stack: "(f --)", desc: "Set reverb mix", example: "0.3 verb", compile: Param, varargs: false, }, Word { name: "verbdecay", aliases: &[], category: "Reverb", stack: "(f --)", desc: "Set reverb decay", example: "2 verbdecay", compile: Param, varargs: false, }, Word { name: "verbdamp", aliases: &[], category: "Reverb", stack: "(f --)", desc: "Set reverb damping", example: "0.5 verbdamp", compile: Param, varargs: false, }, Word { name: "verbpredelay", aliases: &[], category: "Reverb", stack: "(f --)", desc: "Set reverb predelay", example: "0.02 verbpredelay", compile: Param, varargs: false, }, Word { name: "verbdiff", aliases: &[], category: "Reverb", stack: "(f --)", desc: "Set reverb diffusion", example: "0.7 verbdiff", compile: Param, varargs: false, }, Word { name: "voice", aliases: &[], category: "Sample", stack: "(n --)", desc: "Set voice number", example: "1 voice", compile: Param, varargs: false, }, Word { name: "orbit", aliases: &[], category: "Sample", stack: "(n --)", desc: "Set orbit/bus", example: "0 orbit", compile: Param, varargs: false, }, Word { name: "note", aliases: &[], category: "Oscillator", stack: "(n --)", desc: "Set MIDI note", example: "60 note", compile: Param, varargs: false, }, Word { name: "size", aliases: &[], category: "Reverb", stack: "(f --)", desc: "Set size", example: "1 size", compile: Param, varargs: false, }, Word { name: "n", aliases: &[], category: "Sample", stack: "(n --)", desc: "Set sample number", example: "0 n", compile: Param, varargs: false, }, Word { name: "cut", aliases: &[], category: "Sample", stack: "(n --)", desc: "Set cut group", example: "1 cut", compile: Param, varargs: false, }, Word { name: "reset", aliases: &[], category: "Sample", stack: "(n --)", desc: "Reset parameter", example: "1 reset", compile: Param, varargs: false, }, Word { name: "clear", aliases: &[], category: "Sound", stack: "(--)", desc: "Clear sound register (sound and all params)", example: "\"kick\" s 0.5 gain . clear \"hat\" s .", compile: Simple, varargs: false, }, // Quotation execution Word { name: "apply", aliases: &[], category: "Logic", stack: "(quot --)", desc: "Execute quotation unconditionally", example: "{ 2 * } apply", compile: Simple, varargs: false, }, // Word definitions Word { name: ":", aliases: &[], category: "Definitions", stack: "( -- )", desc: "Begin word definition", example: ": kick \"kick\" s emit ;", compile: Simple, varargs: false, }, Word { name: ";", aliases: &[], category: "Definitions", stack: "( -- )", desc: "End word definition", example: ": kick \"kick\" s emit ;", compile: Simple, varargs: false, }, // Generator Word { name: "..", aliases: &[], category: "Generator", stack: "(start end -- start start+1 ... end)", desc: "Push arithmetic sequence from start to end", example: "1 4 .. => 1 2 3 4", compile: Simple, varargs: false, }, Word { name: "gen", aliases: &[], category: "Generator", stack: "(quot n -- results...)", desc: "Execute quotation n times, push all results", example: "{ 1 6 rand } 4 gen => 4 random values", compile: Simple, varargs: true, }, Word { name: "geom..", aliases: &[], category: "Generator", stack: "(start ratio count -- start start*r start*r^2 ...)", desc: "Push geometric sequence", example: "1 2 4 geom.. => 1 2 4 8", compile: Simple, varargs: false, }, Word { name: "times", aliases: &[], category: "Control", stack: "(n quot --)", desc: "Execute quotation n times, @i holds current index", example: "4 { @i . } times => 0 1 2 3", compile: Simple, varargs: false, }, ]; pub(super) fn simple_op(name: &str) -> Option { Some(match name { "dup" => Op::Dup, "dupn" => Op::Dupn, "drop" => Op::Drop, "swap" => Op::Swap, "over" => Op::Over, "rot" => Op::Rot, "nip" => Op::Nip, "tuck" => Op::Tuck, "+" => Op::Add, "-" => Op::Sub, "*" => Op::Mul, "/" => Op::Div, "mod" => Op::Mod, "neg" => Op::Neg, "abs" => Op::Abs, "floor" => Op::Floor, "ceil" => Op::Ceil, "round" => Op::Round, "min" => Op::Min, "max" => Op::Max, "pow" => Op::Pow, "sqrt" => Op::Sqrt, "sin" => Op::Sin, "cos" => Op::Cos, "log" => Op::Log, "=" => Op::Eq, "!=" => Op::Ne, "lt" => Op::Lt, "gt" => Op::Gt, "<=" => Op::Le, ">=" => Op::Ge, "and" => Op::And, "or" => Op::Or, "not" => Op::Not, "xor" => Op::Xor, "nand" => Op::Nand, "nor" => Op::Nor, "ifelse" => Op::IfElse, "pick" => Op::Pick, "sound" => Op::NewCmd, "." => Op::Emit, "rand" => Op::Rand, "seed" => Op::Seed, "cycle" => Op::Cycle, "pcycle" => Op::PCycle, "tcycle" => Op::TCycle, "choose" => Op::Choose, "every" => Op::Every, "chance" => Op::ChanceExec, "prob" => Op::ProbExec, "coin" => Op::Coin, "mtof" => Op::Mtof, "ftom" => Op::Ftom, "?" => Op::When, "!?" => Op::Unless, "tempo!" => Op::SetTempo, "speed!" => Op::SetSpeed, "at" => Op::At, "adsr" => Op::Adsr, "ad" => Op::Ad, "apply" => Op::Apply, "ramp" => Op::Ramp, "tri" => Op::Tri, "range" => Op::Range, "perlin" => Op::Perlin, "chain" => Op::Chain, "loop" => Op::Loop, "oct" => Op::Oct, "clear" => Op::ClearCmd, ".." => Op::IntRange, "gen" => Op::Generate, "geom.." => Op::GeomRange, "times" => Op::Times, _ => return None, }) } /// Parse note names like c4, c#4, cs4, eb4 into MIDI numbers. /// C4 = 60 (middle C), A4 = 69 (440 Hz reference). fn parse_note_name(name: &str) -> Option { let name = name.to_lowercase(); let bytes = name.as_bytes(); if bytes.len() < 2 { return None; } let base = match bytes[0] { b'c' => 0, b'd' => 2, b'e' => 4, b'f' => 5, b'g' => 7, b'a' => 9, b'b' => 11, _ => return None, }; let (modifier, octave_start) = match bytes[1] { b'#' | b's' => (1, 2), b'b' if bytes.len() > 2 && bytes[2].is_ascii_digit() => (-1, 2), // flat: eb4, bb4 b'0'..=b'9' => (0, 1), _ => return None, }; let octave_str = &name[octave_start..]; let octave: i64 = octave_str.parse().ok()?; if !(-1..=9).contains(&octave) { return None; } // MIDI: C4 = 60, so C-1 = 0 Some((octave + 1) * 12 + base + modifier) } /// Parse interval names like m3, M3, P5 into semitone counts. /// Supports simple intervals (1-8) and compound intervals (9-15). fn parse_interval(name: &str) -> Option { // Simple intervals: unison through octave let simple = match name { "P1" | "unison" => 0, "m2" => 1, "M2" => 2, "m3" => 3, "M3" => 4, "P4" => 5, "aug4" | "dim5" | "tritone" => 6, "P5" => 7, "m6" => 8, "M6" => 9, "m7" => 10, "M7" => 11, "P8" => 12, // Compound intervals (octave + simple) "m9" => 13, "M9" => 14, "m10" => 15, "M10" => 16, "P11" => 17, "aug11" => 18, "P12" => 19, "m13" => 20, "M13" => 21, "m14" => 22, "M14" => 23, "P15" => 24, _ => return None, }; Some(simple) } pub(super) fn compile_word( name: &str, span: Option, ops: &mut Vec, dict: &Dictionary, ) -> bool { match name { "linramp" => { ops.push(Op::PushFloat(1.0, span)); ops.push(Op::Ramp); return true; } "expramp" => { ops.push(Op::PushFloat(3.0, span)); ops.push(Op::Ramp); return true; } "logramp" => { ops.push(Op::PushFloat(0.3, span)); ops.push(Op::Ramp); return true; } _ => {} } if let Some(pattern) = theory::lookup(name) { ops.push(Op::Degree(pattern)); return true; } for word in WORDS { if word.name == name || word.aliases.contains(&name) { match &word.compile { Simple => { if let Some(op) = simple_op(word.name) { ops.push(op); } } Context(ctx) => ops.push(Op::GetContext((*ctx).into())), Param => ops.push(Op::SetParam(word.name.into())), Probability(p) => { ops.push(Op::PushFloat(*p, None)); ops.push(Op::ChanceExec); } } return true; } } // @varname - fetch variable if let Some(var_name) = name.strip_prefix('@') { if !var_name.is_empty() { ops.push(Op::PushStr(var_name.to_string(), span)); ops.push(Op::Get); return true; } } // !varname - store into variable if let Some(var_name) = name.strip_prefix('!') { if !var_name.is_empty() { ops.push(Op::PushStr(var_name.to_string(), span)); ops.push(Op::Set); return true; } } // Note names: c4, c#4, cs4, eb4, etc. -> MIDI number if let Some(midi) = parse_note_name(name) { ops.push(Op::PushInt(midi, span)); return true; } // Intervals: m3, M3, P5, etc. -> dup top, add semitones (for chord building) if let Some(semitones) = parse_interval(name) { ops.push(Op::Dup); ops.push(Op::PushInt(semitones, span)); ops.push(Op::Add); return true; } // Internal ops not exposed in WORDS if let Some(op) = simple_op(name) { ops.push(op); return true; } // User-defined words from dictionary if let Some(body) = dict.lock().unwrap().get(name) { ops.extend(body.iter().cloned()); return true; } // Unrecognized token becomes a string ops.push(Op::PushStr(name.to_string(), span)); true }