Render MIDI on AI instruments (MIDI to audio)
doseedo_render_midiMIDI TO AUDIO, the virtual instrument for agents — THE tool for "I wrote the part, now play it": an AI instrument model (orchestral strings, brass, woodwinds, piano, guitar, bass, drums, World) performs your exact notes, in your key, at your bpm, and returns audio takes (doseedo_generate_music takes no notes or key). Input ONE of: notes[] ({pitch, start_beats, duration_beats, velocity} — beats from bar 1, the same rows as doseedo_edit_session set_midi_notes), midi_url (a .mid ≤2 MiB: a doseedo result link or a public https URL), or session_id + track_id (that track's notes, read from the session). Required: instrument (an entry's call from doseedo_instruments, no key — stay inside its range) and bpm. The notes are sent AS GIVEN — no pitch snapping, no quantizing. One voice per part: a chord part is rendered one voice per output with voice_split:true (result.voices maps each voice to its files and notes). Takes come back best-first (takes[0] = the scorer's winner). Async: job_id → doseedo_wait_task (~1–3 min). Result: takes[{url, rank, score}] (pre-signed: curl -OJ, no auth header, 24 h), seed, duration, voices?, refine?, chain. A take may miss or change a note — read takes[].check (measured against your notes) or listen; offer the takes, never promise note-perfection. Free harmony check first: doseedo_analyze_midi. DRUMS (GM notes): drum_engine:"oneshot" = a sampler kit made for drum_genre (default for "electronic"/"808"), every hit as written — use it on ANY kit when every hit must land; the drum model PERFORMS a kit and can drop hits (takes[].fit.missing). "synth" = a one-shot patch (synth_role, synth_genre); result.oneshots = the samples. SOUND: a preset (timbre_preset), a recording's tone (timbre_audio_url = timbre transfer), or YOUR OWN instrument (lora_id from doseedo_train_instrument; result.lora.applied). Cancel: a render that has not reached the GPU yet is stopped and its credits refunded; one already rendering finishes on the GPU (its credits are spent), the job ends as canceled and the output is discarded.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| bpm | No | REQUIRED (or tempo_map). Tempo of the notes (10–400). Written into the MIDI's tempo meta, so start_beats/duration_beats land at exactly this tempo. | |
| seed | No | Random seed (−1 or 0–4294967295). Reuse a result's seed to re-render close to the same take. | |
| tune | No | Light intonation (default true): a held, clearly pitched note the model rendered 15–85 cents off its written pitch is moved toward it, to a small natural residual — attack and vibrato as played, fast notes left. Winds, brass and strings. false = the take exactly as rendered. | |
| notes | No | The part, as note rows in beats from bar 1 (beat 0 = bar 1 beat 1, quarter-note beats at `bpm`). Monophonic for one voice; chords need voice_split:true. Up to 4096 notes. | |
| takes | No | How many takes to render, 1–4 (one GPU batch; no extra credits). Omit to let the server choose best-of-N for the part length. | |
| prompt | No | Optional caption override (default: the instrument id). Style words help a little; the notes are the control. | |
| refine | No | Opt-in post-render correction. "light": attacks re-timed onto the score, exposed wrong pitch classes re-pitched inside the played octave, misfires muted (winds/brass/strings). "shred": play exactly the written line, octave included, mute anything the score never wrote (any pitched mono part). The raw render stays downloadable (result.refine.raw_url). | |
| vaefix | No | VAE spectral corrector (default true): trims the low-mid fog the decoder adds under the instrument's register and removes mic hiss only when the take carries it. Winds, brass and strings. Receipt: vaefix. false = the decode exactly as rendered. | |
| lora_id | No | A CUSTOM INSTRUMENT: the lora_id doseedo_train_instrument returned (16 hex). The render is played by that trained instrument; pass the same instrument it was trained as. Owner-only. | |
| dynamics | No | One target dynamic for the whole part's tone: "pp", "p", "mp", "mf", "f", "ff", "fff", a 0–1 number, or a MIDI velocity as text. Omit it to let the notes' velocities shape the tone (dynamics_curve). | |
| midi_url | No | Alternative to notes: https URL of a Standard MIDI File (≤2 MiB) — a doseedo result link (a stem's MIDI) or a public URL. Its own tempo map is used by the model; bpm still tags the caption and sizes the default duration. | |
| track_id | No | With session_id: the t_… id of the MIDI/instrument track to render. | |
| tempo_map | No | Tempo CHANGES for the notes: [{beat, bpm}] — each point holds from its beat (beats from bar 1) until the next; the first point is beat 0 (or bpm covers the beats before it). Written into the MIDI, so a ritardando or a tempo that lands a cue on a film hit plays exactly. doseedo_tempo_map builds one from hit times. | |
| drum_genre | No | Electronic drums (instrument "electronic" or "808"): the genre whose one-shot kit plays the part — "house", "techno", "trap", "drill", "lo-fi", "dnb", "amapiano", "synthwave"… or free words. Default: the instrument. | |
| instrument | Yes | REQUIRED. The instrument from doseedo_instruments — its `call.instrument` (e.g. "violin", "tenor_sax", "electric_guitar", "piano"; a World name such as "koto" is resolved to its call). Keep the notes inside its range. An unknown name close to a catalog one is refused with did_you_mean before anything is spent. | |
| session_id | No | Alternative to notes: with track_id, render THAT session track's notes (read from doseedo_get_session's summary). | |
| synth_role | No | instrument "synth": the patch Stable Audio Open makes for the part — bass (an 808 where the genre's bass is one), 808, pad, lead, pluck. Default: from the notes (chords = pad, a low line = bass, else lead). | |
| drum_engine | No | Who plays a drum part: "oneshot" = a sampler kit made for drum_genre (the default for electronic / 808; congas and bongos are recordings of the skins) — every note lands exactly as written; use it on ANY kit when every hit must land. "model" = the drum model (the default for every other kit): a performance, which can drop or smear hits — read takes[].fit. | |
| synth_genre | No | instrument "synth": the genre the patch is made for — "house", "techno", "trap", "synthwave", "lo-fi", "dnb"… or free words. | |
| synth_words | No | instrument "synth": extra sound words for the patch ("reese", "warm analog", "acid"), ≤80 chars. | |
| voice_split | No | true = the notes hold chords: split them into the voices one player of this instrument can hold and render every voice (result.voices). Default false (a chord in a mono part is an error the model will fudge). | |
| synth_engine | No | Who plays a synth part: "oneshot" = a patch of one-shots made for it (the default for "synth"), "model" = the instrument model. | |
| lora_strength | No | With lora_id: how strongly the custom instrument applies, 0–2 (default 1.0, or a tuned per-adapter default; ~0.6 when a small training set overshoots). | |
| timbre_preset | No | A preset from doseedo_instruments — an entry's call.timbre_preset or presets[].call.timbre_preset (e.g. "violin:pizz", "sax:alto", "koto:preset1"). Omit for the instrument default. | |
| dynamics_curve | No | What colours the TONE over time: omitted/"auto" = the note velocities when they vary (soft notes darker, loud brighter — every instrument but drums, LoRAs included); "off" = one colour; "cc11"/"cc1" = that CC lane of a midi_url; or "pos:level,…" (pos and level 0–1, e.g. "0:0.1,1:0.9" = a crescendo). Receipt: result.dynamics. | |
| time_signature | No | Meter of the part, e.g. "4/4", "3/4", "6/8" (default 4/4). Written into the MIDI and the caption. | |
| idempotency_key | No | Optional. Any unique string for THIS request (e.g. a UUID). Re-sending the same call with the same key after a timeout returns the same job instead of starting a second one. | |
| revise_take_url | No | REVISE an earlier take instead of rendering a new one: the take's URL (as a render returned it). Only [revise_start_beats, revise_end_beats) is regenerated — steered by `notes` (send the whole part, with your corrections) — and spliced back with short crossfades; the rest of the take is kept as it was. | |
| duration_seconds | No | Length of the render in seconds (0.01–600). Default: the last note's end + 2 s of release. Each 30 s window costs 10 credits. | |
| revise_end_beats | No | With revise_take_url: end of the region to redo (exclusive), beats from bar 1. | |
| timbre_audio_url | No | TIMBRE TRANSFER: https URL of a short recording (≤24 MB; its first 30 s are used) whose SOUND the render should take on — a doseedo result link or a public URL. The notes stay yours; the tone comes from the recording. | |
| revise_start_beats | No | With revise_take_url: start of the region to redo, beats from bar 1. |