What Is Muse
Muse is a domain-specific language for declaring audio plugins. A .muse file describes one plugin: identity, parameters, audio I/O, format metadata, and signal processing logic. The compiler (muse) parses, resolves, generates Rust/nih-plug code, and builds native CLAP + VST3 binaries.
Language Shape
plugin "Name" {
// metadata: vendor, version, url, email, category
// format blocks: clap { ... }, vst3 { ... }
// I/O: input stereo, output stereo
// voices N (polyphony, instruments only)
// unison { count N detune X } (voice stacking, requires voices)
// sample name "path" [external] (WAV sample declaration)
// wavetable name "path" [external] (WAV wavetable declaration)
// midi { note { ... } cc N { ... } } (instruments only)
// param name: type = default in min..max { smoothing/unit/display }
// gui { theme/accent/size/layout/panel/widgets/css } (custom editor)
// process { signal chain }
// test "name" { input/set/assert }
}
Signal chains use -> to pipe audio left-to-right:
input -> lowpass(param.cutoff) -> gain(param.volume) -> output
37 built-in DSP functions + 3 audio primitives: play, loop, wavetable_osc. DSP functions: sine, saw, square, triangle, noise, pulse, lfo, lowpass, highpass, bandpass, notch, peak_eq, low_shelf, high_shelf, adsr, ar, gain, pan, delay, mod_delay, allpass, comb, mix, crossfade, clip, tanh, fold, bitcrush, soft_clip, chorus, compressor, rms, peak_follow, gate, dc_block, sample_and_hold, semitones_to_ratio. Audio primitives operate on declared samples/wavetables (not in the DSP registry).
Key Constraints
- One plugin per file. Every
.muse file has exactly one plugin "Name" { ... } block.
- Brace-delimited. No significant whitespace. All blocks use
{ }.
- Category is a bare identifier —
category effect, not category "effect".
- Param types:
float, int, bool, enum [variant1, variant2].
- Unit suffixes on numbers:
440Hz, 50ms, 0.5s, -12dB, 50%, 2st. No space between number and suffix.
-> is lowest precedence. Arithmetic binds tighter than signal chains.
split/merge must pair. Every split { ... } needs a -> merge in the same chain.
- Instruments need a
midi block with note { ... } to receive MIDI. Implicit bindings: note.pitch, note.velocity, note.gate, note.pressure, note.bend, note.slide, note.number.
voices N enables polyphony. Process block runs per-voice. All DSP state is automatically per-voice. Requires midi block.
unison { count N detune X } stacks voices. Each note spawns N detuned voices. Requires voices.
- Process block implicit bindings:
input, output, sample_rate.
Known Limitations
- No CC test events. Test blocks support
note on/note off for MIDI injection but not control change events.
- macOS only. The build pipeline (
muse build) produces macOS CLAP + VST3 bundles. No Linux or Windows support.
- Polyphony is per-voice mono. Each voice outputs mono, summed to the output bus. No per-voice stereo panning yet.
- Avoid Rust reserved words as variable names. Don't use
mod, fn, type, etc. as let binding names in process blocks — they'll break the generated Rust code.
- GUI editor crashes in VST3 hosts. The web view editor (
gui { } block) works in muse preview standalone mode but crashes when opened inside Ableton Live's VST3 host. Use muse preview to verify GUI appearance. Headless plugins (without gui block) work fine in all DAWs.
muse preview audio input is macOS-only. The --input mic option requires microphone permission (macOS will prompt on first use). The --input file:<path> option accepts WAV files only — mono or stereo, any sample rate (resampling not applied; a rate mismatch warning is printed).
muse preview instruments ignore --input. Only effect plugins use audio input routing. Instruments generate audio from MIDI — the --input flag is silently ignored for instrument plugins.
- WAV only for samples and wavetables. No MP3, OGG, FLAC support.
- No sample rate conversion. If WAV sample rate differs from host, playback speed varies.
- External mode loads samples relative to current working directory at plugin load time. The host's CWD determines where external samples are found.
CLI Quick Reference
muse check <file> [--format json] # Parse + resolve only
muse compile <file> [--output-dir <dir>] [--format json] [--no-build] [--release]
muse test <file> [--format json] # Run test blocks
muse build <file> [--output-dir <dir>] [--format json] # Full build → CLAP + VST3
muse preview <file> [--format json] [--midi-port <name|list>] [--input <source>]
# Live audio preview with hot-reload (macOS)
Exit codes: 0 success, 1 compile/check/test error, 2 build/I/O error.
Plugin Template (Copy This)
plugin "My Effect" {
vendor "Your Name"
version "0.1.0"
category effect
clap {
id "com.yourname.my-effect"
description "Short description"
features [audio_effect, stereo]
}
vst3 {
id "YourMyEffect1"
subcategories [Fx]
}
input stereo
output stereo
param amount: float = 0.5 in 0.0..1.0 {
smoothing linear 10ms
}
process {
input -> gain(param.amount) -> output
}
test "passes signal" {
input sine 440Hz 1024 samples
set param.amount = 1.0
assert output.peak > 0.0
}
test "silence in produces silence out" {
input silence 512 samples
assert output.rms < -120dB
}
}
Before routing, determine what the user needs:
What do you want to do?
- Create a new plugin from a description →
workflows/create-plugin.md
- Debug a compiler error from muse check/compile/test output →
workflows/debug-errors.md
- Extend an existing plugin (add params, change DSP, add tests) →
workflows/extend-plugin.md
If the user's intent is clear from their message, skip the question and route directly.
Workflow Routing
| User Intent |
Workflow |
Required Reading |
| Create new plugin from description |
workflows/create-plugin.md |
references/language-reference.md, references/dsp-primitives.md, references/test-syntax.md, references/plugin-recipes.md |
| Fix compiler/test errors |
workflows/debug-errors.md |
references/error-codes.md, references/cli-commands.md |
| Add features to existing plugin |
workflows/extend-plugin.md |
references/language-reference.md, references/dsp-primitives.md, references/test-syntax.md |
| Create plugin with custom GUI |
workflows/create-gui-plugin.md |
references/language-reference.md, references/dsp-primitives.md, references/test-syntax.md, references/cli-commands.md, references/error-codes.md, references/plugin-recipes.md |
Reference Files
| File |
Contents |
references/language-reference.md |
Complete syntax guide: plugin structure, params, process blocks, signal chains, routing, MIDI, GUI blocks, metadata, type system |
references/test-syntax.md |
Test block grammar, signal types, assertion properties, operators, JSON output format |
references/dsp-primitives.md |
All 37 DSP functions + 3 audio primitives (play, loop, wavetable_osc) by category with signatures and descriptions |
references/error-codes.md |
E001–E015 with causes and fix patterns (E015: duplicate sample/wavetable names; E003: unknown sample/wavetable in play/loop/wavetable_osc) |
references/cli-commands.md |
All 5 CLI commands with flags, exit codes, JSON output schemas |
references/plugin-recipes.md |
21 annotated example patterns: gain, filter, synth, multiband, tremolo, distortion, chorus, dynamics, pulse synth, poly, MPE, unison, GUI (Tier 1), GUI (Tier 2), echo, EQ, gate, phaser, drum machine, wavetable synth, looping sampler |
1---2name: muse3description: Write, test, and build audio plugins in the Muse DSL. Use when asked to "create a plugin", "write an audio effect", "build a synth", "make a VST", "CLAP plugin", "audio processing", "DSP effect", or any task involving Muse .muse files.4---56<essential_principles>78## What Is Muse910Muse is a domain-specific language for declaring audio plugins. A `.muse` file describes one plugin: identity, parameters, audio I/O, format metadata, and signal processing logic. The compiler (`muse`) parses, resolves, generates Rust/nih-plug code, and builds native CLAP + VST3 binaries.1112## Language Shape1314```15plugin "Name" {16 // metadata: vendor, version, url, email, category17 // format blocks: clap { ... }, vst3 { ... }18 // I/O: input stereo, output stereo19 // voices N (polyphony, instruments only)20 // unison { count N detune X } (voice stacking, requires voices)21 // sample name "path" [external] (WAV sample declaration)22 // wavetable name "path" [external] (WAV wavetable declaration)23 // midi { note { ... } cc N { ... } } (instruments only)24 // param name: type = default in min..max { smoothing/unit/display }25 // gui { theme/accent/size/layout/panel/widgets/css } (custom editor)26 // process { signal chain }27 // test "name" { input/set/assert }28}29```3031Signal chains use `->` to pipe audio left-to-right:32```33input -> lowpass(param.cutoff) -> gain(param.volume) -> output34```353637 built-in DSP functions + 3 audio primitives: `play`, `loop`, `wavetable_osc`. DSP functions: `sine`, `saw`, `square`, `triangle`, `noise`, `pulse`, `lfo`, `lowpass`, `highpass`, `bandpass`, `notch`, `peak_eq`, `low_shelf`, `high_shelf`, `adsr`, `ar`, `gain`, `pan`, `delay`, `mod_delay`, `allpass`, `comb`, `mix`, `crossfade`, `clip`, `tanh`, `fold`, `bitcrush`, `soft_clip`, `chorus`, `compressor`, `rms`, `peak_follow`, `gate`, `dc_block`, `sample_and_hold`, `semitones_to_ratio`. Audio primitives operate on declared samples/wavetables (not in the DSP registry).3738## Key Constraints3940- **One plugin per file.** Every `.muse` file has exactly one `plugin "Name" { ... }` block.41- **Brace-delimited.** No significant whitespace. All blocks use `{ }`.42- **Category is a bare identifier** — `category effect`, not `category "effect"`.43- **Param types:** `float`, `int`, `bool`, `enum [variant1, variant2]`.44- **Unit suffixes on numbers:** `440Hz`, `50ms`, `0.5s`, `-12dB`, `50%`, `2st`. No space between number and suffix.45- **`->` is lowest precedence.** Arithmetic binds tighter than signal chains.46- **`split`/`merge` must pair.** Every `split { ... }` needs a `-> merge` in the same chain.47- **Instruments need a `midi` block** with `note { ... }` to receive MIDI. Implicit bindings: `note.pitch`, `note.velocity`, `note.gate`, `note.pressure`, `note.bend`, `note.slide`, `note.number`.48- **`voices N` enables polyphony.** Process block runs per-voice. All DSP state is automatically per-voice. Requires `midi` block.49- **`unison { count N detune X }` stacks voices.** Each note spawns N detuned voices. Requires `voices`.50- **Process block implicit bindings:** `input`, `output`, `sample_rate`.5152## Known Limitations5354- **No CC test events.** Test blocks support `note on`/`note off` for MIDI injection but not control change events.55- **macOS only.** The build pipeline (`muse build`) produces macOS CLAP + VST3 bundles. No Linux or Windows support.56- **Polyphony is per-voice mono.** Each voice outputs mono, summed to the output bus. No per-voice stereo panning yet.57- **Avoid Rust reserved words as variable names.** Don't use `mod`, `fn`, `type`, etc. as `let` binding names in process blocks — they'll break the generated Rust code.58- **GUI editor crashes in VST3 hosts.** The web view editor (`gui { }` block) works in `muse preview` standalone mode but crashes when opened inside Ableton Live's VST3 host. Use `muse preview` to verify GUI appearance. Headless plugins (without `gui` block) work fine in all DAWs.59- **`muse preview` audio input is macOS-only.** The `--input mic` option requires microphone permission (macOS will prompt on first use). The `--input file:<path>` option accepts WAV files only — mono or stereo, any sample rate (resampling not applied; a rate mismatch warning is printed).60- **`muse preview` instruments ignore `--input`.** Only effect plugins use audio input routing. Instruments generate audio from MIDI — the `--input` flag is silently ignored for instrument plugins.61- **WAV only for samples and wavetables.** No MP3, OGG, FLAC support.62- **No sample rate conversion.** If WAV sample rate differs from host, playback speed varies.63- **External mode loads samples relative to current working directory at plugin load time.** The host's CWD determines where external samples are found.6465## CLI Quick Reference6667```68muse check <file> [--format json] # Parse + resolve only69muse compile <file> [--output-dir <dir>] [--format json] [--no-build] [--release]70muse test <file> [--format json] # Run test blocks71muse build <file> [--output-dir <dir>] [--format json] # Full build → CLAP + VST372muse preview <file> [--format json] [--midi-port <name|list>] [--input <source>]73 # Live audio preview with hot-reload (macOS)74```7576Exit codes: `0` success, `1` compile/check/test error, `2` build/I/O error.7778## Plugin Template (Copy This)7980```muse81plugin "My Effect" {82 vendor "Your Name"83 version "0.1.0"84 category effect8586 clap {87 id "com.yourname.my-effect"88 description "Short description"89 features [audio_effect, stereo]90 }9192 vst3 {93 id "YourMyEffect1"94 subcategories [Fx]95 }9697 input stereo98 output stereo99100 param amount: float = 0.5 in 0.0..1.0 {101 smoothing linear 10ms102 }103104 process {105 input -> gain(param.amount) -> output106 }107108 test "passes signal" {109 input sine 440Hz 1024 samples110 set param.amount = 1.0111 assert output.peak > 0.0112 }113114 test "silence in produces silence out" {115 input silence 512 samples116 assert output.rms < -120dB117 }118}119```120121</essential_principles>122123<intake>124125Before routing, determine what the user needs:126127**What do you want to do?**1281. **Create a new plugin** from a description → `workflows/create-plugin.md`1292. **Debug a compiler error** from muse check/compile/test output → `workflows/debug-errors.md`1303. **Extend an existing plugin** (add params, change DSP, add tests) → `workflows/extend-plugin.md`131132If the user's intent is clear from their message, skip the question and route directly.133134</intake>135136<routing>137138## Workflow Routing139140| User Intent | Workflow | Required Reading |141|---|---|---|142| Create new plugin from description | `workflows/create-plugin.md` | `references/language-reference.md`, `references/dsp-primitives.md`, `references/test-syntax.md`, `references/plugin-recipes.md` |143| Fix compiler/test errors | `workflows/debug-errors.md` | `references/error-codes.md`, `references/cli-commands.md` |144| Add features to existing plugin | `workflows/extend-plugin.md` | `references/language-reference.md`, `references/dsp-primitives.md`, `references/test-syntax.md` |145| Create plugin with custom GUI | `workflows/create-gui-plugin.md` | `references/language-reference.md`, `references/dsp-primitives.md`, `references/test-syntax.md`, `references/cli-commands.md`, `references/error-codes.md`, `references/plugin-recipes.md` |146147## Reference Files148149| File | Contents |150|---|---|151| `references/language-reference.md` | Complete syntax guide: plugin structure, params, process blocks, signal chains, routing, MIDI, GUI blocks, metadata, type system |152| `references/test-syntax.md` | Test block grammar, signal types, assertion properties, operators, JSON output format |153| `references/dsp-primitives.md` | All 37 DSP functions + 3 audio primitives (play, loop, wavetable_osc) by category with signatures and descriptions |154| `references/error-codes.md` | E001–E015 with causes and fix patterns (E015: duplicate sample/wavetable names; E003: unknown sample/wavetable in play/loop/wavetable_osc) |155| `references/cli-commands.md` | All 5 CLI commands with flags, exit codes, JSON output schemas |156| `references/plugin-recipes.md` | 21 annotated example patterns: gain, filter, synth, multiband, tremolo, distortion, chorus, dynamics, pulse synth, poly, MPE, unison, GUI (Tier 1), GUI (Tier 2), echo, EQ, gate, phaser, drum machine, wavetable synth, looping sampler |157158</routing>