Dave Nelson

REAPER + AI: Notes on a Data Problem

August 2026 — Labs & Notebooks

There's a gap in the standard AI-assisted composition workflow that doesn't get named clearly: the AI is responding to your description of the music, not the music. You paste a screenshot of a piano roll. You type out a chord progression. You explain what you're hearing. The model works from that — and it's useful, but it's one layer removed.

The question worth testing: can an AI read MIDI data directly and reason about it as music? Yes. But format matters more than you'd expect.

What the Test Showed

The same two-measure phrase — a bass line moving from an implied C major cluster to a D major chord — fed to a model three ways: notation screenshot, full MusicXML export, and a compact custom text format derived directly from REAPER's MIDI API. The screenshot produced inconsistent results. The structured data formats produced accurate pitch, rhythm, and voice-leading analysis every time.

Screenshots require visual reasoning — the model has to parse rendered pixels back into musical meaning. Structured text is pattern-matching on note names, durations, and intervals, which is what these models actually do well. Handing a model a notation image and asking for voice-leading feedback is roughly equivalent to describing a film score over the phone and asking someone to notate it.

The Efficiency Problem

MusicXML is the obvious structured format, but it carries significant overhead. A four-measure phrase with two active measures exports at roughly 6,200 characters — mostly layout and positioning tags the model never uses. The same musical information in a purpose-built shorthand runs about 110 characters. API calls are billed by token count. That ratio matters in a working session with frequent data exchanges.

REAPER's ReaScript API can read MIDI note data directly from memory — pitch, velocity, duration, position — without writing any file to disk. A Lua script can extract that data, convert it to a compact readable format, and send it to an AI endpoint in one step, mid-session. No export, no round-trip, no leaving the DAW.

Where This Is Going

The working project name is reaper-ai-bridge — kept platform-agnostic, since the architecture doesn't depend on any specific AI provider. Near-term scope is modest: a dockable panel in REAPER that reads a selected MIDI item, formats it as compact text, and opens a conversation about it. Routing logic handles model selection — a lightweight search model for quick questions, a heavier reasoning model for analysis or code generation.

The technical spec is on GitHub. This post is a working note, not a release. The interesting finding isn't the tooling — it's the framing shift. Describing music to an AI is a workaround. The actual interface is the data.

Technical & Functional Specification — reaper-ai-bridge (Draft, August 2026)

# reaper-ai-bridge ## Technical & Functional Specification Status: Ideation — not yet scoped for development --- 1. CORE INSIGHT Screenshots require visual reasoning; LLMs perform this inconsistently. Structured MIDI/text data is parsed reliably. Feeding data instead of images converts an unreliable capability into a reliable one. Validated: side-by-side test of notation screenshot, MusicXML export, and raw REAPER XML dump — structured formats produced correct analysis every time. --- 2. PROPOSED SYSTEM Lightweight bridge: REAPER (ReaScript/Lua) → AI API Mode A: Conversational — composition discussion, theory questions, arrangement feedback against live project data Mode B: Code generation — one-off Lua scripts, executed once Not a full bidirectional control system (see reaper-mcp-server for that). This is chat + data-read, with room to grow. --- 3. KEY FUNCTIONAL REQUIREMENTS 3.1 Chat Interface - Dockable panel via ReaImGui (Dear ImGui Lua binding) - Client-side conversation history (API is stateless) 3.2 MIDI Data Extraction (local, no file export required) - MIDI_GetNote() / MIDI_GetAllEvts() from in-memory project state - Pre-process to compact text before sending: m1: bass C3 E3 G3 A#3 (quarters); treble rest m2: treble C4. (dotted half); bass D3-F#3-A3 chord tied to D3 Full MusicXML: ~1,560 tokens / ~$0.0047 per request (Sonnet) Compact text: ~24 tokens / ~$0.00007 per request (Sonnet) Reduction: ~98% 3.3 Model Routing - Default: Sonar/Sonar Pro — quick questions, low cost - Escalate: Claude Sonnet — analysis, code generation - Future: Claude Opus — heaviest reasoning tasks 3.4 Code Generation - Route to Sonnet tier on request - Present with "Save & Run" action - Execute via reaper.dofile(), single-use --- 4. OUT OF SCOPE (for now) - Full bidirectional DAW control - Subscription credit-based agentic workflows --- 5. NEXT STEPS 1. Prototype MIDI-to-compact-text Lua function (no networking) 2. Prototype HTTP call from ReaScript to Sonar endpoint 3. Build minimal ReaImGui chat window 4. Add model-routing logic 5. Evaluate before adding Save & Run or MCP expansion

Full spec and version history on GitHub