§ Guide · Session players for agents

MIDI to realistic instrument audio, for AI agents

Published October 2026

An agent can plan a part and write the notes. What it cannot do on its own is make those notes sound like a player. doseedo_render_midi is that step as a hosted tool: send the notes (in beats, at your tempo), name an instrument from the open catalog, and get back audio takes played by an instrument model trained on isolated instrument tracks from real recording sessions. There are 40+ instruments, from orchestral strings, brass and winds to guitars, basses, keys, drums and World instruments. Each part has one player and comes back as its own stem, measured against the notes you sent. The same render is one MCP call or one POST /api/jobs, and a whole arrangement goes in one call with doseedo_render_score.

The problem: General MIDI sounds like General MIDI

The usual way to hear an agent's MIDI is to play it through a General MIDI SoundFont with a software synth such as FluidSynth. That proves the notes are there, but it doesn't sound like a cello section or a trumpet player, so it can't ship in a film cue, a game or a demo. Rendering on a modelled instrument is a GPU job, and most agents have no GPU, SoundFont library or synth to run it on.

Doseedo moves that step to a hosted server. The agent keeps the parts it already writes and hands them over as note rows. The server plays them on the instrument you name and returns pre-signed links to the takes. Nothing runs locally except the call.

Connect

claude mcp add --transport http --scope user doseedo https://api.doseedo.com/mcp

That line is for Claude Code. The same URL installs in the Claude apps, ChatGPT, Cursor, Gemini CLI, Codex and VS Code (one page per client in the block below). Four tools answer before you sign in: doseedo_instruments, doseedo_quote, doseedo_recipes and doseedo_edit_ops_reference. The agent can pick an instrument and price a render before anyone authenticates. Headless clients send X-API-Key: dsk_live_… from Settings → API keys.

Pick the instrument: doseedo_instruments

The catalog is the source of truth for what can play. It needs no key and has 45 entries as of October 22, 2026. Each entry carries the exact call to pass to the render, the range in concert pitch (MIDI 60 = C4), whether one player can hold chords, the presets, and a public demo render. This is the trumpet entry as the live tool returns it:

{
  "id": "trumpet",
  "label": "Trumpet",
  "family": "brass",
  "call": { "instrument": "trumpet" },
  "range": "F#3–D6",
  "presets": [ "open", "muted" ],
  "demo": "https://doseedo.com/sources/renders/v3/melody/trumpet.m4a"
}

Search it the way an agent thinks: query:"warm low brass", pitches:[…] with the notes of the part (it returns instruments whose range holds them all), or id:"cello" for one entry in full, with every preset and its own range.

Render the notes: doseedo_render_midi

doseedo_render_midi {
  "instrument": "cello",
  "bpm": 72,
  "takes": 3,
  "notes": [
    { "pitch": 48, "start_beats": 0, "duration_beats": 2, "velocity": 80 },
    { "pitch": 55, "start_beats": 2, "duration_beats": 2, "velocity": 88 },
    { "pitch": 52, "start_beats": 4, "duration_beats": 1, "velocity": 84 },
    { "pitch": 53, "start_beats": 5, "duration_beats": 1, "velocity": 84 },
    { "pitch": 55, "start_beats": 6, "duration_beats": 2, "velocity": 92 }
  ]
}

Long jobs follow one shape everywhere: the submit tool returns a job_id, doseedo_wait_task polls it server-side (one call holds at most 50 seconds, so the agent calls again while it is still running), and the result arrives as pre-signed download links that work with a plain curl for 24 hours, with no key on the download. Those links are reusable as the input of the next tool, so a separated stem feeds the transcriber and a generated take lands on a session track without a round trip through your disk.

The same render over HTTP: the jobs API

Every MCP job is also a plain REST resource, which suits a pipeline without an MCP client. Submit with POST /api/jobs. An Idempotency-Key makes a retried submit return the same job instead of a second render:

curl -s -X POST https://api.doseedo.com/api/jobs \
  -H "X-API-Key: $DOO_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cue-1m1-cello-v1' \
  -d '{"kind":"render_midi","input":{"instrument":"cello","bpm":72,"takes":2,
       "notes":[{"pitch":48,"start_beats":0,"duration_beats":2,"velocity":80},
                {"pitch":55,"start_beats":2,"duration_beats":2,"velocity":88}]}}'

The reply is a job ("status":"queued", an estimate, eta_seconds, and urls.wait). Long-poll it. One call holds at most 50 seconds:

curl -s "https://api.doseedo.com/api/jobs/job_…?wait=50" -H "X-API-Key: $DOO_API_KEY"

This is the finished job from the capture behind this page (October 22, 2026), trimmed to its shape:

{
  "object": "job",
  "kind": "render_midi",
  "status": "succeeded",
  "output": {
    "takes": [
      { "url": "https://api.doseedo.com/api/files/…/stemphonic_468408271_n0.wav", "rank": 1 },
      { "url": "https://api.doseedo.com/api/files/…/stemphonic_468408271_n1.wav", "rank": 2 }
    ],
    "seed": 468408271,
    "duration": 8.67
  },
  "artifacts": [
    { "url": "…_n0.wav", "type": "audio", "expires_at": "2026-10-23T13:00:00.000Z" },
    { "url": "…_n1.wav", "type": "audio", "expires_at": "2026-10-23T13:00:00.000Z" }
  ]
}

Download each take with a plain curl -OJ <url> (no header). Instead of polling, you can stream state changes from GET /api/jobs/{id}/events (Server-Sent Events) or pass "webhook":{"url":"https://…"} on the submit. The per-take check is added by the MCP tools. Over HTTP, measure a take with {"kind":"check_take","input":{"audio_url":…,"notes":…,"bpm":72}}, which answers in the submit response. The full schema of every kind is open at GET https://api.doseedo.com/api/jobs/kinds/render_midi, and /api/jobs/openapi.json has the whole API as OpenAPI 3.1.

Every take comes back measured

A render is a performance, not a playback, and a take can miss or change a note. So the server measures each one before the agent hands it on. When the part was sent as notes, the finished result that doseedo_wait_task returns carries a check on every take, from an independent note transcriber (basic-pitch) matched against your notes: same pitch, onset within ±50 ms.

"takes": [
  { "url": "…_n0.wav", "rank": 1,
    "check": {
      "verdict": "good" | "check" | "bad",
      "reasons": [ "…plain words, only when it is not good…" ],
      "notes_heard": "<matched>/<sent>",
      "recall": …, "precision": …, "octave_errors": …,
      "onset_error_ms": { "median": …, "p90": …, "max": … },
      "first_missed": [ { "pitch": …, "start_beats": …, "start_s": … } ],
      "lufs": …, "peak_dbfs": …
    } },
  …
],
"take_check": "<n>/<m> take(s) measured good against your notes …"

What it costs

Ten credits per 30-second window of rendered audio, from the account's one credit pool. Takes are free, and a chord part split into voices costs one batch per few voices. doseedo_quote prices a call before it runs, spends nothing and needs no sign-in. This is its reply for the five-note cello part above, captured October 22, 2026:

{
  "kind": "render_midi",
  "estimate": { "generation": 10 },
  "basis": "10 credits per 30 s window (8.67 s → 1 window) → 10 credits",
  "assumptions": [
    "takes (3) render in one GPU batch and cost nothing extra",
    "a chord part split into voices (voice_split) costs one batch per ~6 voices — pass voices to price it",
    "estimate only — the plane gate is authoritative and a refusal names the exact price",
    "failed jobs are refunded; free accounts also have a monthly ceiling"
  ]
}

A render runs to the last note plus 2 seconds of release unless you set duration_seconds. Windows overlap by two seconds, so a 62-second part is three windows (30 credits). Checking a take with doseedo_check_take costs no credits. The free tier covers the first renders, and pricing has the plans.

Honest limits

Render one part from your agent

Connect the server, ask the agent to look up an instrument in doseedo_instruments, write eight bars and render three takes.

The Doseedo MCP server →

FAQ

Is there an API that turns MIDI into realistic instrument audio?

Yes. Doseedo's doseedo_render_midi (an MCP tool, and kind "render_midi" on the jobs API at api.doseedo.com/api/jobs) plays notes you send, or a .mid file, on 40+ AI instruments. It returns audio takes as pre-signed links. It is hosted, so the caller needs no synth, SoundFont or GPU.

Does it play my exact notes?

The notes are sent exactly as written, at your bpm or tempo map, with no snapping or quantizing. The render is a performance by an instrument model, so a take can miss or change a note. Each take comes back with a check (notes heard at the right pitch and time, timing in milliseconds, loudness, a good / check / bad verdict), and doseedo_check_take measures any take on demand.

Can it follow tempo changes?

Yes. Pass tempo_map as [{beat, bpm}] points and the MIDI is written with those changes, so a ritardando or a cue stretched to land on a film hit plays as written. doseedo_tempo_map builds a tempo map from hit points or SMPTE timecodes, for free.

Can it render a whole score at once?

Use doseedo_render_score: parts you wrote, a multi-track MIDI file or a MusicXML export, every part played by its instrument in one batch, one stem per part plus a mix, up to 8 stems a call. doseedo_session_from_stems then builds a Logic Pro or Ableton Live project from the result.

Which instruments can it play?

The open catalog, doseedo_instruments, lists them with the exact call for each: orchestral strings, brass and winds, guitars, basses, keys, drums and percussion, and World instruments such as koto, sitar, banjo, shamisen and pedal steel. It had 45 entries on October 22, 2026, and needs no key.

Can it play chords?

Instruments marked plays_chords in the catalog can. Pass voice_split: true and the chords are split into the voices one player of that instrument can hold, each rendered as its own output, with result.voices mapping voices to files.

What does a render cost?

Ten credits per 30-second window of audio, with up to four takes in the same call at no extra cost. doseedo_quote prices a call first without spending anything, and a free tier covers the first renders.

Can it use my own sound?

Yes, in two ways. Pass a short recording as timbre_audio_url and the render takes on its tone, or train a private custom instrument from 30 seconds to 3 minutes of a recording with doseedo_train_instrument and pass its lora_id.

How is this different from rendering with FluidSynth and a General MIDI SoundFont?

A SoundFont plays a stored sample for each note. Doseedo renders the part with an instrument model trained on isolated instrument tracks from real recording sessions, on its GPUs, and returns several takes to choose from.

The Doseedo MCP server · one URL, every client

By DAW
By AI client
By capability

Related