Claude midi macro generation is the boring, useful side of LLM tooling — the part that doesn't trend on Twitter but quietly saves a producer an afternoon. Describe a DualSense macro set in a few sentences, paste the Universal Controller MIDI schema, and Claude returns a mapping file you can drop straight into the bridge. No GUI, no clicking, no naming faders by hand.
- What it is: using an LLM to author bridge mapping JSON.
- Why: mapping editors don't scale past 30 entries; words do.
- How: paste the schema + a clear spec, ask for valid JSON.
- Model: Claude Sonnet 4.6 or 4.7 is plenty.
- Not magic: validate the output, don't trust blindly.
What this actually solves
Universal Controller MIDI mappings live as JSON files. The bridge GUI is fine for the first ten entries — beyond that, you're scrolling, hunting, mis-clicking. A full DualSense macro set for a live show might have 60+ assignments: layered profiles, chord conditionals, CC range scaling per stick zone, separate behaviours for hold vs tap on the same button. Building that in a list editor is a chore. Describing it in English is fast.
The Anthropic structured-outputs documentation covers the mechanics of constraining model output to a schema. We're using the same trick informally: paste the schema, ask for conformance, validate downstream.
The schema (abbreviated)
Universal Controller MIDI mappings follow this shape. The full schema lives in schemas/mapping.schema.json inside the install bundle — open it once, copy it into a scratchpad, paste it into Claude as part of the system prompt.
{
"$schema": "https://controller-midi.aidxn.com/schemas/mapping.v1.json",
"name": "Live set — DualSense",
"controller": "dualsense",
"channels": [
{
"input": "cross",
"type": "note",
"note": 60,
"channel": 1,
"behaviour": "momentary"
},
{
"input": "left_stick_x",
"type": "cc",
"cc": 16,
"channel": 1,
"range": [0, 127],
"curve": "linear",
"deadzone": 0.06
}
]
} The prompt that works
Don't waste tokens on chat. Give Claude four things: the role, the schema, the spec, and the output constraint. Here's the prompt template we use:
You are generating a Universal Controller MIDI mapping file
for a DualSense controller.
SCHEMA:
<paste the full mapping.schema.json here>
SPEC (what the user wants):
- Cross = note 60, momentary, kick.
- Square = note 61, momentary, snare.
- Triangle = note 62, momentary, hat.
- Circle = note 63, latched, clap.
- Left stick X = CC 16, channel 1, deadzone 0.08.
- Left stick Y = CC 17, channel 1, deadzone 0.08, inverted.
- Right stick = MPE pitch + timbre (channel 2, MPE expression).
- L2 = CC 21, curve = exp, full 7-bit.
- R2 = CC 22, curve = exp, full 7-bit.
- Touchpad XY = CC 18 / CC 19, 14-bit.
- Touchpad click = note 70, momentary.
- Adaptive trigger feedback on L2 when channel 1 CC 71 > 100.
OUTPUT:
Return only valid JSON conforming to the schema.
No prose. No markdown code fences. What Claude returns
Sonnet 4.6 hands back a 60-line JSON file in two seconds. The first three entries look like this:
{
"$schema": "https://controller-midi.aidxn.com/schemas/mapping.v1.json",
"name": "DualSense live set",
"controller": "dualsense",
"channels": [
{ "input": "cross", "type": "note", "note": 60, "channel": 1, "behaviour": "momentary" },
{ "input": "square", "type": "note", "note": 61, "channel": 1, "behaviour": "momentary" },
{ "input": "triangle", "type": "note", "note": 62, "channel": 1, "behaviour": "momentary" }
]
}
Save it to ~/Library/Application Support/UniversalControllerMIDI/mappings/live-set.json on macOS or %APPDATA%/UniversalControllerMIDI/mappings/live-set.json on Windows, reload the bridge, and the profile appears in the dropdown.
Where the model is good, and where it isn't
| Task | LLM quality | Notes |
|---|---|---|
| Simple button → note mapping | Excellent | Repetitive structure, exact schema. Trivial. |
| Stick CC with curves + deadzones | Very good | Occasional curve-name typos. Validate. |
| MPE assignments | Good | Needs the MPE section of the schema spelled out clearly. |
| Conditional layers (hold-L1 modifier) | Mixed | Will invent field names if the schema is unclear. Always paste the conditional sub-schema. |
| Adaptive trigger feedback rules | Mixed | Model often forgets the bidirectional flag. Eyeball every row. |
| Musical reasoning (chord shapes, scales) | Surprisingly good | Ask for a Mixolydian b6 pad layout and it'll get the notes right. |
The validation step nobody skips
Pipe the output through ajv or any JSON Schema validator before loading. The bridge will refuse to load malformed JSON, but it won't always catch a structurally-valid mapping that uses a deprecated field name. Here's the one-liner we run in CI:
npm exec ajv validate \
-s schemas/mapping.schema.json \
-d mappings/live-set.json \
--strict=true A realistic workflow
We use this every time we set up a new live set. Rough order:
- Sketch the mapping on paper or in a notes doc.
- Open Claude, paste schema + spec, get JSON.
- Validate with ajv. Patch any errors via follow-up turn.
- Load in the bridge, test every input, log any wrong behaviour.
- Paste the bridge log back into Claude. Ask for corrections.
- Done in 15 minutes, not 90.
What it's not
Claude is not going to invent a new performance concept for you. Ask it for "a creative mapping" and it'll give you something generic — that's a content-generation task and the model is mediocre at it. The win is the boring part: turning a clear spec into clean JSON, fast. For musical decisions, see our mapping templates library for inspiration; for the schema reference, the bridge install ships it. The SysEx deep-dive covers the bidirectional side.
Universal Controller MIDI ships the schema file in every install. Open Claude, paste, ship.