Describe a sound.
Get a real synth preset.

A text prompt in, a loadable preset file out — for Surge XT, Dexed and Vital. Bring your own Claude or Gemini API key. No server, no account, no telemetry.

GPL-3.0 open source Rust · egui native app + CLI BYO-key: Claude / Gemini

Try it in your browser → No key, no install — selectable on-device models, multilingual prompts, optional WebGPU LLM.

# one prompt → one preset
$ deepsynth-preset "dark hypnotic warehouse techno bass, grinding and analog" \
    --synth surge --provider gemini -o warehouse_bass.fxp
Generating surge preset via gemini (gemini-3.5-flash)...
Wrote warehouse_bass.fxp (29 KB, 64 parameters)

# drop it into Surge XT — it just loads

The desktop app

Type a prompt, pick a synth and a provider, hit Generate. Every parameter the model chose is shown before you save the file. API keys live in your OS keychain.

DeepSynth Preset app right after generating a Surge XT patch with Gemini

Live generation with Gemini 3.5 Flash — the model picked a ladder filter with drive and a tight envelope for “grinding and analog”.

Or generate one right here, in your browser

No API key and no install. A tiny embedding model (all-MiniLM-L6-v2, ~23 MB) runs on your own machine and matches your words to a hand-authored sound-design bank; the same Rust preset writers — compiled to WebAssembly — produce the real, loadable file. Runs entirely client-side; nothing is uploaded anywhere.

Open the in-browser generator →

Supported synths

SynthFormatWhat actually lands in the file
Surge XT .fxp Native FPCh/cjs3 patch chunk with Surge’s real XML document 64 parameters across oscillators, mixer, filters, envelopes, LFOs and global — plus real modulation routings (LFO→cutoff, env→pitch, velocity→cutoff), written in Surge’s internal units and verified to load in Surge XT 1.3.4.
Dexed / DX7 .syx 155-byte DX7 voice SysEx The full 6-operator FM voice — 164 parameters, byte-identical to the reference implementation, checksum verified.
Vital .vital Vital JSON preset 56 parameters: 3 oscillators, 2 filters, envelopes, LFOs and the core effects.

Why the files actually load

Most “AI preset generators” write a file that looks like a preset. This project obsesses over the part after the model answers.

01Real formats, from the source

The Surge XT writer implements Surge’s actual patch container — reverse-engineered from the GPL source, not guessed. Parameters are stored in Surge’s internal units: cutoff as semitones from 440 Hz, envelope times as log2(seconds), pitch decomposed into octave + semitone.

02Schema-constrained generation

Each synth’s parameter table generates a JSON Schema, and the LLM is forced to answer inside it (structured outputs). Out-of-range values are clamped, missing ones fall back to sane defaults — the output is always a valid parameter set.

03Tested against the real thing

Every encoding has a unit test citing the Surge source line it was derived from. Generated patches are load-tested headlessly with surge-xt-cli, and the DX7 writer is byte-parity-tested against the original implementation.

A war story: the legacy version of this code embedded a JSON blob inside the FXP wrapper. Files were produced, extensions matched, everyone was happy — except Surge XT, which can’t read them at all. And once the real format was implemented, a patch that asked for an octave-down bass was silently playing a fifth down instead: Surge stores oscillator pitch in a ±7 semitone field.

Both bugs were only found by loading generated files into the real synth. That’s why verification against the actual instrument is a design principle here, not an afterthought.

Quick start

Build from source

git clone https://github.com/backpropagated-ai/vst-preset-generator
cd vst-preset-generator
cargo build --release

# CLI
./target/release/deepsynth-preset --help
# Desktop app
./target/release/deepsynth-preset-app

Bring your own key

# either provider works
export ANTHROPIC_API_KEY=sk-ant-…
export GEMINI_API_KEY=…

deepsynth-preset "ethereal evolving pad" \
  --synth vital -o pad.vital

# offline mode (no API): write a preset
# from a params JSON, or dump the schema
deepsynth-preset --defaults --synth surge -o init.fxp
deepsynth-preset --schema surge