Score video as an agent: cue sheet from the cut, 50+ AI instruments play your MIDI, mixed to picture
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Check the connected doseedo account: plan tier, the monthly credit pool (generation AND DAW conversions draw it), purchased extra-usage credits, and storage. Read-only — consumes nothing. Use it before starting expensive work to confirm there is budget.
This tool takes no arguments.
Check the connected doseedo account: plan tier, the monthly credit pool (generation AND DAW conversions draw it), purchased extra-usage credits, and storage. Read-only — consumes nothing. Use it before starting expensive work to confirm there is budget.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}Check the HARMONY of notes before rendering or placing them: factor a MIDI progression into its sonorities (mode "midi", default — chord-detection-free: each segment of simultaneously sounding pitches reduced to an anchor pitch class + register-exact shape, covered with recurring shape cells) or into chord symbols (mode "chord": one estimated chord per ~2 beats + a corpus-grammar cell cover with a schedule). Input: notes[] (the rows you would give doseedo_render_midi / set_midi_notes) with bpm, or midi_url (a .mid ≤2 MiB: a doseedo result link such as a stem's MIDI, or a public URL). Synchronous (~2–10 s), CPU, no credits. Returns sonorities[] or chords[], cover, cells, compression — read chords[].chord / sonorities[].anchor to confirm the key and progression you intended. Cancel: not applicable — the result is returned in the submit response; the job is already finished.
| Argument | Type | Description |
|---|---|---|
| bpm | number | Tempo of the notes (needed with notes; default 120). |
| mode | string | "midi" (default): sonority / shape factoring. "chord": chord symbols per segment + cell cover. |
| notes | array | The notes to analyze, in beats from bar 1 (same rows as doseedo_render_midi). Needs bpm. |
| midi_url | string | Alternative to notes: https URL of a Standard MIDI File (≤2 MiB). |
| min_seg_beats | number | mode midi: shortest sonority segment in beats (default 0.25). |
| time_signature | string | Meter of the notes, e.g. "4/4" (default). |
| idempotency_key | string | 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. |
| beats_per_segment | number | mode chord: segment length in beats (0.25–8, default 2). |
{
"type": "object",
"properties": {
"bpm": {
"type": "number",
"description": "Tempo of the notes (needed with notes; default 120)."
},
"mode": {
"enum": [
"midi",
"chord"
],
"type": "string",
"description": "\"midi\" (default): sonority / shape factoring. \"chord\": chord symbols per segment + cell cover."
},
"notes": {
"type": "array",
"items": {
"type": "object",
"required": [
"pitch",
"start_beats",
"duration_beats"
],
"properties": {
"pitch": {
"type": "number"
},
"velocity": {
"type": "number"
},
"start_beats": {
"type": "number"
},
"duration_beats": {
"type": "number"
}
},
"additionalProperties": false
},
"description": "The notes to analyze, in beats from bar 1 (same rows as doseedo_render_midi). Needs bpm."
},
"midi_url": {
"type": "string",
"description": "Alternative to notes: https URL of a Standard MIDI File (≤2 MiB)."
},
"min_seg_beats": {
"type": "number",
"description": "mode midi: shortest sonority segment in beats (default 0.25)."
},
"time_signature": {
"type": "string",
"description": "Meter of the notes, e.g. \"4/4\" (default)."
},
"idempotency_key": {
"type": "string",
"description": "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."
},
"beats_per_segment": {
"type": "number",
"description": "mode chord: segment length in beats (0.25–8, default 2)."
}
},
"additionalProperties": false
}Cancel a queued or running job. What that stops and refunds depends on the kind — generate_music / render_midi / cover_song: a render not yet on the GPU is stopped and its credits refunded; one already rendering finishes (credits spent), the job ends as canceled, output discarded. audio_to_session: cooperative — stops at the next stage boundary and refunds the build's sound-tool unit (a separation already run stays charged). bounce_session: a bounce still queued never renders (budget refunded); one mid-render has its result dropped. separate_stems / transcribe / convert_project: no plane-side stop — the work completes (credits spent), the job ends as canceled and its output is discarded. The synchronous analyses are already finished (409 already_terminal).
| Argument | Type | Description |
|---|---|---|
| job_id* | string | The job_id from a submit tool or doseedo_list_jobs. |
{
"type": "object",
"required": [
"job_id"
],
"properties": {
"job_id": {
"type": "string",
"description": "The job_id from a submit tool or doseedo_list_jobs."
}
},
"additionalProperties": false
}MEASURE a take instead of guessing: give the audio (a render_midi take URL, any recording) and the notes it should play — notes[] + bpm (and tempo_map) or a midi_url — and get back how many written notes were heard at the right pitch and time (recall / precision / f1, octave errors, the first missed notes with their beats), the timing error in ms, loudness (integrated LUFS, peak dBFS, clipped share), any stretch where a note was written but nothing sounds, and a verdict (good / check / bad) with reasons in plain words. doseedo_render_midi results already carry this per take (takes[].check) when the part was given as notes. Method: an independent note transcriber (basic-pitch) — dense chords and very fast runs read less reliably; use it as a screen, and listen to anything marked check. Synchronous (~3–15 s), CPU, no credits. Cancel: not applicable — the result is returned in the submit response; the job is already finished.
| Argument | Type | Description |
|---|---|---|
| bpm | number | Tempo of the notes (or tempo_map). |
| notes | array | The notes the take should play, in beats from bar 1 (the rows you sent doseedo_render_midi). |
| midi_url | string | Alternative to notes: the part as a Standard MIDI File (≤ 2 MiB). |
| audio_key | string | R2 ingest key of an uploaded audio file (from doseedo_get_upload_url / POST /api/upload/r2/ingest-url; starts with "ingest/"). Alternative to audio_url. |
| audio_url | string | The take: a doseedo result URL as returned, or any public https URL. |
| tempo_map |
Check an async doseedo task once. Returns current status, and the result (file URLs / notes) when finished. A big result comes back as a brief (each row cut to its deciding fields): parts: ["<name>" or index, …] returns those rows of the job record IN FULL — a render_score part's every receipt, a mix part's strip, rides (every point) and loudness.
| Argument | Type | Description |
|---|---|---|
| kind | string | Which job kind created the task — the registry name the submit reply carried (generate_music, generate_sound, cover_stem, fill_gap, render_midi, train_instrument, render_score, mix, session_from_stems, spot_video, score_to_picture, cover_song, separate_stems, transcribe, audio_to_session, convert_project, bounce_session, analyze_song, detect_chords, beat_grid, check_take, analyze_midi); the short codes (generate, sound, coverstem, fillgap, render, train, score, stemsess, spot, picture, cover, separate, session, convert, bounce, analyze, chords, beats, check, harmony) are accepted aliases. |
| parts | array | Optional, on a finished job: the parts to return in full, by name (as the result names them) or index — e.g. ["Oboes", "Timpani"]. |
| job_id | string | Alternatively the job_id (job_…) from a submit tool or the jobs API — replaces task_id + kind. |
| task_id | string | The task_id returned by a submit tool. |
{
"type": "object",
"properties": {
"kind": {
"enum": [
"generate_music",
"generate_sound",
"cover_stem",
"fill_gap",
"render_midi",
"train_instrument",
"render_score",
"mix",
"session_from_stems",
"spot_video",
"score_to_picture",
"cover_song",
"separate_stems",
"transcribe",
"audio_to_session",
"convert_project",
"bounce_session",
"analyze_song",
"detect_chords",
"beat_grid",
"check_take",
"analyze_midi",
"generate",
"sound",
"coverstem",
"fillgap",
"render",
"train",
"score",
"stemsess",
"spot",
"picture",
"cover",
"separate",
"session",
"convert",
"bounce",
"analyze",
"chords",
"beats",
"check",
"harmony"
],
"type": "string",
"description": "Which job kind created the task — the registry name the submit reply carried (generate_music, generate_sound, cover_stem, fill_gap, render_midi, train_instrument, render_score, mix, session_from_stems, spot_video, score_to_picture, cover_song, separate_stems, transcribe, audio_to_session, convert_project, bounce_session, analyze_song, detect_chords, beat_grid, check_take, analyze_midi); the short codes (generate, sound, coverstem, fillgap, render, train, score, stemsess, spot, picture, cover, separate, session, convert, bounce, analyze, chords, beats, check, harmony) are accepted aliases."
},
"parts": {
"type": "array",
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "Optional, on a finished job: the parts to return in full, by name (as the result names them) or index — e.g. [\"Oboes\", \"Timpani\"]."
},
"job_id": {
"type": "string",
"description": "Alternatively the job_id (job_…) from a submit tool or the jobs API — replaces task_id + kind."
},
"task_id": {
"type": "string",
"description": "The task_id returned by a submit tool."
}
},
"additionalProperties": false
}SOUND EFFECTS (SFX) from words with Stable Audio Open — SOUND DESIGN and FOLEY for game audio, apps and video: impacts, whooshes, door slams, footsteps, UI blips, creature and sci-fi sounds, ambiences ("rain on a tin roof", "busy café"), risers, drum one-shots. A one-shot hit ("punchy house kick", "snare with a short room", "a riser into the drop"), a loop on the tempo grid ("glitchy percussion"), or a texture ("vinyl crackle", "rain"). kind picks which (hit | loop | texture); omitted, the server reads it off the words. Don't put a tempo in a hit's prompt — tempo words make it write a loop. Wrong tool for a part with notes (doseedo_render_midi) or a piece of music (you write it; doseedo_render_score plays it). Async: job_id → doseedo_wait_task (typically 15–40 s) → audio URLs (pre-signed: curl -OJ <url>, no auth header, valid 24 h). 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.
| Argument | Type | Description |
|---|---|---|
| bpm | number | Tempo a loop is cut to (default 120). |
| kind | string | hit = one sound (0.5–10 s), loop = 1–4 bars tiled at bpm, texture = a bed. Default: read off the prompt. |
| seed | number | Optional random seed for reproducibility. |
| prompt* | string | What it sounds like, e.g. "punchy house kick drum, single hit" or "dusty vinyl crackle". ≤ 300 characters. |
| time_signature | string | Meter a loop is cut to, e.g. "4/4" (default). |
Get a presigned upload for your own audio file. Returns an upload_url (PUT the raw file bytes there, e.g. `curl -X PUT -H "Content-Type: <content_type>" --data-binary @song.wav "<upload_url>"`) and an audio_key to pass to doseedo_separate_stems / doseedo_transcribe / doseedo_cover_song / doseedo_audio_to_session, or to doseedo_add_audio_to_session. A FILM (mp4, mov, m4v, webm, mkv; ≤ 2 GB) uploads the same way: pass the key as video_key to doseedo_spot_video / doseedo_score_to_picture. Formats: WAV, AIFF, FLAC, MP3, M4A/AAC, Ogg/Opus, WebM — all accepted for processing on every plan. Storing audio IN A SESSION (doseedo_add_audio_to_session) keeps WAV/AIFF/FLAC lossless only on Pro+; below Pro+ lossless is not kept there, so send Opus (audio/ogg). Samples/regions for a session that are on this machine need NO upload: use load_quick_sampler_sample sample_path / attach_audio local_path / set_track_clips audio_ref.local_path and run place_local_files after the download.
| Argument | Type | Description |
|---|---|---|
| filename* | string | File name including extension, e.g. "song.wav". |
| content_type | string | MIME type; inferred from the extension when omitted (wav, aif/aiff, flac, mp3, m4a/aac, ogg/opus, webm; a film: mp4, mov, m4v, mkv). Required for any other extension. |
{
"type": "object",
"required": [
"filename"
],
"properties": {
"filename": {
"type": "string",
"description": "File name including extension, e.g. \"song.wav\"."
},
"content_type": {
"type": "string",
"description": "MIME type; inferred from the extension when omitted (wav, aif/aiff, flac, mp3, m4a/aac, ogg/opus, webm; a film: mp4, mov, m4v, mkv). Required for any other extension."
}
},
"additionalProperties": false
}The instrument list — the sound palette: every instrument doseedo can PLAY YOUR NOTES on (doseedo_render_midi) — orchestral strings, brass and winds, guitars, basses, keys, drums and percussion, and World instruments (koto, sitar, banjo, pedal steel, tabla, congas…). Each entry gives the EXACT render call (`call`: instrument, plus timbre_preset where one is needed — a koto is the acoustic_guitar model with the koto timbre), its playable range in concert MIDI pitch, whether it plays chords, its presets (pizz, muted, sax registers…) and a demo render. No args → the whole catalog; query:"warm low brass" / family / pitches:[…] (instruments whose range holds them) / chords:true narrow it; id:"cello" → one instrument in full. Read-only, free, no key needed — read it before writing a part.
| Argument | Type | Description |
|---|---|---|
| id | string | One instrument (id, alias or label, e.g. "cello", "upright bass", "koto") → its full entry: every preset with its own call and range, transposition, aliases, demo, page. |
| query | string | What the part needs, in words: an instrument ("trumpet"), a family ("woodwinds"), a technique ("pizzicato", "muted") or a register ("low", "bright"). Ranked best-first. |
| chords | boolean | true = only instruments one player can play chords on. |
| family | string | Only this family. |
| pitches | array | MIDI pitches the part uses (concert, 60 = C4) — only instruments whose range holds every one. |
List the jobs this account submitted (generate / render_midi / cover / stems / transcribe / session / convert / bounce / the analyses), newest first — to find an earlier result, check what is still running, or resume after a lost connection. Each row names its artifacts (e.g. ["vocals", "drums", "midi_piano"]); doseedo_check_task {job_id} returns the full result with fresh links. Read-only.
| Argument | Type | Description |
|---|---|---|
| kind | string | Only this job kind (registry name): generate_music, generate_sound, cover_stem, fill_gap, render_midi, train_instrument, render_score, mix, session_from_stems, spot_video, score_to_picture, cover_song, separate_stems, transcribe, audio_to_session, convert_project, bounce_session, analyze_song, detect_chords, beat_grid, check_take, analyze_midi. Short codes (generate, sound, coverstem, fillgap, render, train, score, stemsess, spot, picture, cover, separate, session, convert, bounce, analyze, chords, beats, check, harmony) are accepted aliases. |
| limit | number | How many (1–100, default 20). |
| before | string | Page cursor: the next_cursor of a previous call. |
| status | string | |
| session_id | string | Only jobs whose input names this session — a bounce, stems registered into it, a render of one of its tracks (filtered within the fetched page). |
MIXING and MASTERING: mix the stems instead of summing them: each part levelled for how loud it plays, panned, high-passed, given its depth on a shared reverb, and mastered to a loudness target — returned as a WAV AND as `mixgraph`, the mix as a document you edit. After doseedo_render_score pass from_job (its parts and the instruments they play are the stems); or stems: [{name, audio_url, instrument?}] (result links work as-is). An orchestra (strings / winds / brass / timpani / harp…) is SEATED by default (film-orchestral: violins left, low strings right, winds centre, brass behind, each seat with its own depth in a 2.3 s hall, written dynamics riding the faders; room / dynamics_ride change that); other stems get the blind default. style: film-orchestral, film-scoring-stage, concert-hall, film-epic-hybrid, cathedral-choral, classical-chamber, cartoon-studio, golden-age-cartoon, jazz-combo, ambient, country-pop, metal-modern, 1950s-mono, 1960s-lcr-pop, 1970s-analog-rock, 1970s-dub, 1980s-pop-gated, 1990s-rock-dry, 1990s-hiphop, 2000s-loudness-rock, 2010s-edm, 2010s-trap, 2020s-pop, 2020s-hyperpop — an id or words ("dry 90s rock"). balance {part: dB} moves parts on top of the levelling (+3 brings a melody forward). Change the mix: edit the returned mixgraph — strips[] {stem, gain_db, pan, seat, chain, sends}, buses[] (verb = the hall), master.chain, automation [{target: "strips.<stem>.gain_db", points: [[seconds, dB]…]}] for rides — and call again with mixgraph + the same from_job / stems — or mix_job (this job_id) + only your edits: rendered as written (safety rails apply, reported), no credits. report.strips.<part>.active_lufs = how loud each part plays in the mix. Then doseedo_session_from_stems {from_job, mix_job: <this job_id>} → the DAW project at this mix's levels and pans. Async: job_id → doseedo_wait_task (~15–90 s). Cancel: the plane has no stop for a running mix — it runs to completion (credits spent), the job ends as canceled and its output is discarded. Only a job still queued at the plane is refunded by the plane's own failure refund.
| Argument | Type | Description |
|---|---|---|
| room | any | An orchestra's room: "studio" (intimate scoring stage, ~1.2 s, close), "stage" (~1.8 s), "hall" (the default scoring hall, ~2.3 s), "cathedral" (~4 s, wet) — or 0..1 between them. Sets the decay, size and how wet every seat sits. |
Estimate what a job will cost in credits BEFORE submitting it, and whether the connected account can afford it right now. Spends nothing. Pass the job (generate_music, generate_sound, cover_stem, fill_gap, render_midi, train_instrument, cover_song, separate_stems, transcribe, audio_to_session, convert_project, bounce_session, spot_video, score_to_picture, analyze_song, detect_chords, beat_grid, analyze_midi, render_score, mix, session_from_stems, check_take) and the same args you would give the job tool (duration_seconds, models, instruments; for render_midi: notes + bpm / tempo_map or duration_seconds, voice_split / voices, takes — takes are free, voices cost one batch per ~6; for render_score: parts + bpm / tempo_map — planned exactly as the job plans it (lines, player rows, length), and `refused` says when the job would refuse it). The estimate follows the planes' own price table; the gate is authoritative and a refusal names the exact price.
| Argument | Type | Description |
|---|---|---|
| job* | string | Which job to price (a doseedo_ tool name or recipe verb is accepted too). |
| args | object | The arguments you intend to pass to the job tool; only the price-relevant ones matter. |
{
"type": "object",
"required": [
"job"
],
"properties": {
"job": {
"enum": [
"generate_music",
"generate_sound",
"cover_stem",
"fill_gap",
"render_midi",
"train_instrument",
"cover_song",
"separate_stems",
"transcribe",
"audio_to_session",
"convert_project",
"bounce_session",
"spot_video",
"score_to_picture",
"analyze_song",
"detect_chords",
"beat_grid",
"analyze_midi",
"render_score",
"mix",
"session_from_stems",
"check_take"
],
"type": "string",
"description": "Which job to price (a doseedo_ tool name or recipe verb is accepted too)."
},
"args": {
"type": "object",
"description": "The arguments you intend to pass to the job tool; only the price-relevant ones matter.",
"additionalProperties": true
}
},
"additionalProperties": false
}The named pipelines people actually ask for — stems, session (mix → DAW project), cover, transcribe, generate, render-midi (your notes played by an instrument model), custom-instrument (train your own from a recording), timbre-transfer (your notes, a recording's tone), sound-design (SFX / foley / one-shots), analyze-song (key/tempo/sections/chords), convert, bounce, and the compose-part guide (a part in the session's key at its tempo: analyze → you write the MIDI → place or render it) — each with its inputs, the tool calls in order, outputs, a credit/time estimate and how to VERIFY success from the response. Call with no name for the index (pick by use_when), or with a name for the full recipe. Read-only.
| Argument | Type | Description |
|---|---|---|
| name | string | A recipe name or alias, e.g. "session" / "stems-to-session". Omit to list all. |
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "A recipe name or alias, e.g. \"session\" / \"stems-to-session\". Omit to list all."
}
},
"additionalProperties": false
}MIDI 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.
| Argument | Type | Description |
|---|---|---|
| bpm | number | 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. |
FILM SCORING, orchestral arrangement, background music, a song or an instrumental YOU wrote: a WHOLE ARRANGEMENT in one call (a film cue, a string quartet, a big-band chart): every part played by its doseedo instrument, one stem per part from bar 1 at your tempo, plus a summed mix. Input ONE of: parts[] ({name, instrument, timbre_preset?, lora_id?, players?, notes[]} — doseedo_instruments calls), midi_url (multi-track SMF), or musicxml_url (notation played as marked, at concert pitch; what isn't: prepared.score.warnings). A file's parts are matched by name, then GM program; name any part with instruments {"<part name or index>": {instrument, timbre_preset?, players?}}. A chord on a one-line instrument is split into voices (one stem each). ★ SECTIONS: an instrument is ONE player; give a part players: N (2–8) and its line is played by N different players (each its own performance), summed into ONE section stem — that is how you write an orchestra: violins I / violins II / violas / cellos / basses as five parts with players 6 / 6 / 4 / 4 / 3, horns 2–4 in unison, a woodwind or brass line doubled; leave players out for a solo. The WHOLE orchestra in one call: ≤ 32 lines and ≤ 96 player rows (players: N = N rows), plain, sampled and World / LoRA instruments together (~1 min groups), ≤ 600 s. Synth / electronic parts and drums where every hit must land (drum_engine:"oneshot"): doseedo_render_midi. Timing: bpm and/or tempo_map ([{beat, bpm}]; doseedo_tempo_map lands film hits on downbeats). Result: parts[{name, instrument, url, fit, timbre, lora, players}] — fit.verdict / coverage = did it PLAY its notes (a failed part is re-rolled once; fit.rolls.missed = a roll not played as one), lora.applied = its adapter played — plus mix_url. Next: doseedo_mix {from_job}, then doseedo_session_from_stems {from_job, mix_job}. Async: job_id → doseedo_wait_task (~1–4 min). 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.
| Argument | Type | Description |
|---|---|---|
| bpm | number | Tempo of the parts (10–400). Required with parts[] unless tempo_map is given; on a file it sets the speed and keeps the score's fermatas / rit. / tempo changes. |
SCORE TO PICTURE: the last step of scoring a film. Lays each mixed cue (and any sound effect) on the video at its SMPTE timecode, with dialogue ducking (the lines found on the video's own soundtrack by VAD, or the spans you pass; the music dips ahead of each line and comes back after it), normalises the program to a delivery loudness (web −16, streaming −14, broadcast/ebu −23, atsc −24 LUFS, or a number; true peak under the ceiling) and muxes it onto the picture untouched (no re-encode). Returns the scored video, the printmaster WAV and the music-and-effects stem, plus a report of what it MEASURED: where each track landed (and what was cut at the film's edges), how far the music sits under the lines, and the final loudness and true peak. CPU, no credits. tracks: [{audio_url (a doseedo_mix mix_url as returned, or any public https URL) | audio_key, start_timecode (in the film's timecode) | start_s, gain_db?, role?: music|sfx, name?}], ≤ 64. Keep the production audio (default) or drop it (production_audio:"drop" — e.g. a temp score you are replacing; then pass dialogue spans to duck under). Up to 25 minutes of film per call (a reel). Async: job_id → doseedo_wait_task. Cancel: the plane has no stop for a running delivery — it runs to completion (credits spent), the job ends as canceled and its output is discarded. Only a job still queued at the plane is refunded by the plane's own failure refund.
| Argument | Type | Description |
|---|---|---|
| duck | object | Dialogue ducking (on by default): depth_db (default 10), attack_ms (250: how early before a line the music is down), release_ms (700), sfx (false: duck effects too), enabled. |
| tracks* | array | What to lay on the film, in any order. |
| dialogue | array | Dialogue spans [{start_s, end_s}] to duck under, instead of detecting them (use the cue sheet's dialogue, or your own). |
Build a native DAW PROJECT from stems: each stem on its own audio track from bar 1, optional MIDI tracks (the written parts) beside them, on your tempo (bpm or tempo_map) — Logic Pro (.logicx) or Ableton Live (.als), zipped. The deliverable after doseedo_render_score (pass from_job: its job_id and the stems, MIDI and tempo come from that job) or after any renders / separations you made (stems: [{name, audio_url}] — result links work as-is). After doseedo_mix add mix_job: each track at that mix's level and pan, the mix as a muted reference track. Async: job_id → doseedo_wait_task (~30–90 s) → file (pre-signed zip, curl -o session.zip <url>, 24 h). Cancel: the plane has no stop for a running session build — it runs to completion (credits spent), the job ends as canceled and its output is discarded. Only a job still queued at the plane is refunded by the plane's own failure refund.
| Argument | Type | Description |
|---|---|---|
| bpm | number | Project tempo (default 120). |
| name | string | Project name. |
| stems | array | [{name, audio_url | audio_key, gain_db?, pan?, mute?, position_beats?}] — the audio tracks, in order. |
| target | string | Which DAW (default logic). |
| mix_job | string | MCP: a doseedo_mix job_id — every track takes that mix's level and pan, and the mix itself rides along as a muted reference track "Mix (doseedo)". |
| from_job | string | MCP: a doseedo_render_score job_id — its stems, parts' MIDI and tempo are used (no other input needed). |
SPOT A FILM: a video in, the music editor's cue sheet out — the first step of scoring to picture. Scene detection on EVERY frame, and it listens to the soundtrack (CPU, no credits): hard cuts frame-exact (dark, low-contrast footage included), fades, flashes and visual impacts; each shot's brightness, colour, warmth, contrast, motion and mood, with a keyframe JPEG per shot so you can SEE what it shows; where dialogue is (Silero VAD) and loud audio hits; then cues placed where the picture wants music and the dialogue lets it (1M1, 1M2 …: start/end SMPTE timecode, emotion, energy, tension arc, hit points ranked by strength, a suggested bpm that lands them, and tempo_map_input — pass it to doseedo_tempo_map as is). It sees light, movement and editing, not meaning: read the keyframes for what each scene is about. Input: video_key (doseedo_get_upload_url accepts mp4/mov/m4v/webm/mkv) or video_url (public https), ≤ 2 GB and ≤ 3 h. Optional start_timecode (the first frame's, e.g. 01:00:00:00; default the file's own), coverage (0.05–0.98, default 0.55: how much of the film gets music), reel (cue ids <reel>M<n>), keyframes (0–60). Async: job_id → doseedo_wait_task (~1 min for a 10-min 1080p reel). Next: doseedo_tempo_map per cue → write the notes → doseedo_render_score → doseedo_mix → doseedo_score_to_picture. Cancel: the plane has no stop for a running spotting pass — it runs to completion (credits spent), the job ends as canceled and its output is discarded. Only a job still queued at the plane is refunded by the plane's own failure refund.
| Argument | Type | Description |
|---|---|---|
| reel | integer | Reel number for the cue ids (default 1 → 1M1, 1M2 …). |
| coverage | number | How much of the film gets music (default 0.55). Raise it for wall-to-wall scoring (a trailer, an animation), lower it for a dialogue drama. |
| keyframes | integer | How many shots get a keyframe JPEG (default 24; the longest shots first). |
Scoring to picture: turn HIT POINTS (a cut, an impact, the title card — as seconds from the cue start or SMPTE timecodes) into a TEMPO MAP that lands each hit exactly on a downbeat (or a beat — per hit with hits[].land), staying near your tempo and inside bpm_range. Returns tempo_map [{beat, bpm}] to pass unchanged to doseedo_render_midi / doseedo_render_score / doseedo_session_from_stems, and hits[] with the beat, bar and beat-in-bar each hit lands on — write the accent, stinger or change there. Handles 23.976 / 24 / 25 / 29.97 (";" = drop-frame) / 30 / 50 / 59.94 / 60 fps timecode. Pure math: free, instant, no key needed.
| Argument | Type | Description |
|---|---|---|
| bpm* | number | The cue's tempo (20–300) — the map stays as close to it as the hits allow. |
| fps | number | Frame rate of the timecodes: 23.976, 24, 25, 29.97, 30, 50, 59.94, 60. |
| hits* | array | The moments the music must land on: [{time_s} (seconds from the cue start) or {timecode: "01:00:12:08"} (film timecode, with fps and start_timecode), label?, land?}] — land = THIS hit's landing ("downbeat" or "beat"; default: the request's land), e.g. the big cuts on bar lines and a quick accent on a beat. A bare number = {time_s}. |
| land | string | Land hits on bar lines (default) or on any beat — the default for every hit without its own land. |
| start_s | number | Alternative: the cue start in seconds of film time (informational when hits are time_s). |
Make a CUSTOM INSTRUMENT in your own sound: upload 30 s–3 min of ONE instrument playing (your own player, a rare or folk instrument, a prepared/invented instrument, a vintage synth) and doseedo trains a private adapter (LoRA) on its serving instrument model in about 1–2 minutes. After that, doseedo_render_midi {instrument: <the same instrument>, lora_id} plays ANY notes you write in that sound. Several takes help (up to 8 files; the first 3 min are used, ≥8 s required); a clean, solo, dry recording works best. instrument = the closest catalog instrument — it picks the model voice the adapter trains on (a shamisen trains as acoustic_guitar, a whistle as flute: doseedo_instruments lists each one's call.instrument). The notes are transcribed for you (pass notes to skip that). 20 credits. Result: lora_id, name, the windows it trained on, loss first→last, and `use` (the render args). Earlier ones: doseedo_list_jobs {kind:"train_instrument"}. Owner-only: no one else can render with it. Async: job_id → doseedo_wait_task (~1–2 min). Cancel: the plane has no stop for a running training — it runs to completion (credits spent), the job ends as canceled and its output is discarded. Only a job still queued at the plane is refunded by the plane's own failure refund.
| Argument | Type | Description |
|---|---|---|
| bpm | number | Optional tempo of the recording (30–300). |
| name | string | A name for it, e.g. "Grandpa's banjo" (≤80 chars). |
| seed | number | Random seed. |
| notes | array | Optional: the notes played, one list per file — [[{pitch, start, end, velocity?}…]] in SECONDS. Omitted, they are transcribed. |
| steps | number |
Wait for an async doseedo job to finish: polls server-side for up to timeout_seconds (5–50; one call can never hold longer than 50 s), then returns the result or the latest status. If it returns still_running:true, call it again — a submit reply's eta_seconds says how long the whole job usually takes (transcribe ~15 s, a render 1–3 min, audio_to_session ~4 min), so a 3-minute job is three or four calls, not one. A finished job answers with its output, artifacts (pre-signed links) and note.
| Argument | Type | Description |
|---|---|---|
| kind | string | Which job kind created the task — the registry name the submit reply carried (generate_music, generate_sound, cover_stem, fill_gap, render_midi, train_instrument, render_score, mix, session_from_stems, spot_video, score_to_picture, cover_song, separate_stems, transcribe, audio_to_session, convert_project, bounce_session, analyze_song, detect_chords, beat_grid, check_take, analyze_midi); the short codes (generate, sound, coverstem, fillgap, render, train, score, stemsess, spot, picture, cover, separate, session, convert, bounce, analyze, chords, beats, check, harmony) are accepted aliases. |
| job_id | string | Alternatively the job_id (job_…) from a submit tool or the jobs API — replaces task_id + kind. |
| task_id | string | The task_id returned by a submit tool. |
| timeout_seconds | number | Max seconds to wait in this call (5–50, default 45). Start with the submit reply's suggested_next_wait. |
| array |
| Tempo changes [{beat, bpm}]. |
| instrument | string | The instrument (a drum/percussion name switches to onset-only matching). |
| time_signature | string | Meter (default 4/4). |
| idempotency_key | string | 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. |
| onset_tolerance_ms | number | How far a heard onset may be from the written one and still count (default 50). |
{
"type": "object",
"properties": {
"bpm": {
"type": "number",
"description": "Tempo of the notes (or tempo_map)."
},
"notes": {
"type": "array",
"items": {
"type": "object",
"required": [
"pitch",
"start_beats",
"duration_beats"
],
"properties": {
"pitch": {
"type": "number"
},
"velocity": {
"type": "number"
},
"start_beats": {
"type": "number"
},
"duration_beats": {
"type": "number"
}
},
"additionalProperties": false
},
"description": "The notes the take should play, in beats from bar 1 (the rows you sent doseedo_render_midi)."
},
"midi_url": {
"type": "string",
"description": "Alternative to notes: the part as a Standard MIDI File (≤ 2 MiB)."
},
"audio_key": {
"type": "string",
"description": "R2 ingest key of an uploaded audio file (from doseedo_get_upload_url / POST /api/upload/r2/ingest-url; starts with \"ingest/\"). Alternative to audio_url."
},
"audio_url": {
"type": "string",
"description": "The take: a doseedo result URL as returned, or any public https URL."
},
"tempo_map": {
"type": "array",
"items": {
"type": "object",
"required": [
"beat",
"bpm"
],
"properties": {
"bpm": {
"type": "number"
},
"beat": {
"type": "number"
}
},
"additionalProperties": false
},
"description": "Tempo changes [{beat, bpm}]."
},
"instrument": {
"type": "string",
"description": "The instrument (a drum/percussion name switches to onset-only matching)."
},
"time_signature": {
"type": "string",
"description": "Meter (default 4/4)."
},
"idempotency_key": {
"type": "string",
"description": "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."
},
"onset_tolerance_ms": {
"type": "number",
"description": "How far a heard onset may be from the written one and still count (default 50)."
}
},
"additionalProperties": false
}| idempotency_key |
| string |
| 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. |
| duration_seconds | number | Length in seconds. Default: 2 s for a hit, 4 bars at bpm for a loop, 8 s for a texture. |
{
"type": "object",
"required": [
"prompt"
],
"properties": {
"bpm": {
"type": "number",
"description": "Tempo a loop is cut to (default 120)."
},
"kind": {
"enum": [
"hit",
"loop",
"texture"
],
"type": "string",
"description": "hit = one sound (0.5–10 s), loop = 1–4 bars tiled at bpm, texture = a bed. Default: read off the prompt."
},
"seed": {
"type": "number",
"description": "Optional random seed for reproducibility."
},
"prompt": {
"type": "string",
"description": "What it sounds like, e.g. \"punchy house kick drum, single hit\" or \"dusty vinyl crackle\". ≤ 300 characters."
},
"time_signature": {
"type": "string",
"description": "Meter a loop is cut to, e.g. \"4/4\" (default)."
},
"idempotency_key": {
"type": "string",
"description": "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."
},
"duration_seconds": {
"type": "number",
"description": "Length in seconds. Default: 2 s for a hit, 4 bars at bpm for a loop, 8 s for a texture."
}
},
"additionalProperties": false
}{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "One instrument (id, alias or label, e.g. \"cello\", \"upright bass\", \"koto\") → its full entry: every preset with its own call and range, transposition, aliases, demo, page."
},
"query": {
"type": "string",
"description": "What the part needs, in words: an instrument (\"trumpet\"), a family (\"woodwinds\"), a technique (\"pizzicato\", \"muted\") or a register (\"low\", \"bright\"). Ranked best-first."
},
"chords": {
"type": "boolean",
"description": "true = only instruments one player can play chords on."
},
"family": {
"enum": [
"strings",
"brass",
"winds",
"piano",
"guitar",
"bass",
"drums",
"world",
"pitched_percussion",
"unpitched_percussion",
"synth"
],
"type": "string",
"description": "Only this family."
},
"pitches": {
"type": "array",
"items": {
"type": "number"
},
"description": "MIDI pitches the part uses (concert, 60 = C4) — only instruments whose range holds every one."
}
},
"additionalProperties": false
}{
"type": "object",
"properties": {
"kind": {
"type": "string",
"description": "Only this job kind (registry name): generate_music, generate_sound, cover_stem, fill_gap, render_midi, train_instrument, render_score, mix, session_from_stems, spot_video, score_to_picture, cover_song, separate_stems, transcribe, audio_to_session, convert_project, bounce_session, analyze_song, detect_chords, beat_grid, check_take, analyze_midi. Short codes (generate, sound, coverstem, fillgap, render, train, score, stemsess, spot, picture, cover, separate, session, convert, bounce, analyze, chords, beats, check, harmony) are accepted aliases."
},
"limit": {
"type": "number",
"description": "How many (1–100, default 20)."
},
"before": {
"type": "string",
"description": "Page cursor: the next_cursor of a previous call."
},
"status": {
"enum": [
"queued",
"running",
"succeeded",
"failed",
"canceled"
],
"type": "string"
},
"session_id": {
"type": "string",
"description": "Only jobs whose input names this session — a bounce, stems registered into it, a render of one of its tracks (filtered within the fetched page)."
}
},
"additionalProperties": false
}| stems | array | [{name, audio_url, instrument?}] — the stems (≤ 32). instrument = the sound it plays (a doseedo_instruments id: "violin", "timpani", "harp"), which decides how it is mixed; without it the name decides. |
| style | string | A mix style: an id or words ("dry 90s rock"). Pick it for the picture — the default (film-orchestral, a 2.3 s scoring hall) suits film drama, not every orchestra: cartoon-studio = a cartoon / animation orchestra (a close, dry, wide scoring stage, punchy rides); golden-age-cartoon = a 1940s–50s cartoon (mono, small studio, tape); film-scoring-stage = intimate TV / documentary; concert-hall; film-epic-hybrid = trailer / action; cathedral-choral; classical-chamber; or jazz-combo, ambient, 1970s-analog-rock, 2020s-pop … |
| balance | object | {part name: dB in -12..12} — your balance on top of the levelling (and of the written dynamics a from_job reads). |
| mix_job | string | MCP: a doseedo_mix job_id to edit — its whole stored mix (every ride) is the base, mixgraph is applied on top, and its stems are reused when you pass no from_job / stems. |
| vintage | string | A period medium over any style, after the mix: "tape" = 7.5 ips tape (saturation, wow and flutter, a low hiss); "shellac" = a 78 played back (mono, ~90 Hz–5.5 kHz with the reproducer's presence, a 1.3 Hz wow, surface noise that swishes once a turn, crackle). "none" takes a style's own medium off (golden-age-cartoon carries tape). Its node (master.chain type vintage: noise_db, crackle, hi_hz …) is editable in the returned mixgraph. |
| dynamics | object | Fader rides from written dynamics: {part name: [[onset_seconds, velocity 0-127], …]}. from_job fills it from the score (pp to ff ≈ 17 dB); pass {} for no rides. |
| from_job | string | MCP: a doseedo_render_score job_id — its parts are the stems, each with the instrument it plays, and each part's written dynamics (its mean velocity) set its balance. |
| mixgraph | object | An edited mix — the mixgraph a doseedo_mix returned, changed — rendered against the same stems (from_job or stems). With mix_job: ONLY what you change (strips[] by stem, automation[] rides by target — points: [] removes one, buses[] by id, master) — the rest is that mix as stored. A mixgraph marked `partial` (its rides summarized) is refused without mix_job. Omit for a fresh mix. |
| target_lufs | number | Master loudness, -24..-6 LUFS (default: the style's — -18 for film-orchestral, -14 for the blind default). |
| tonal_match | boolean | Nudge the master toward professionally mixed orchestral references (default on for the orchestral styles). Its presence and air are judged only where the score is written loud (written_level), so a pp passage keeps its darkness. |
| dynamics_ride | number | How hard the written dynamics move the faders: 1 = default (pp to ff ≈ 17 dB), 0 = no rides, up to 1.5. |
| written_level | array | [[seconds, velocity], …] — the whole score's written level, the loudest part sounding, held until the next row (0 = nothing plays). The tonal match reads only the passages it writes loud (f and louder), so a pp passage keeps its darkness. from_job fills it. |
| idempotency_key | string | 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. |
| dynamics_carried | object | {part name: top velocity} — parts whose stems already play their written level (a render part's dynamics_level receipt, up to its top_vel). Their rides count it: no doubled swing. from_job fills it. |
{
"type": "object",
"properties": {
"room": {
"anyOf": [
{
"enum": [
"studio",
"stage",
"hall",
"cathedral"
],
"type": "string"
},
{
"type": "number",
"maximum": 1,
"minimum": 0
}
],
"description": "An orchestra's room: \"studio\" (intimate scoring stage, ~1.2 s, close), \"stage\" (~1.8 s), \"hall\" (the default scoring hall, ~2.3 s), \"cathedral\" (~4 s, wet) — or 0..1 between them. Sets the decay, size and how wet every seat sits."
},
"stems": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"audio_url"
],
"properties": {
"name": {
"type": "string"
},
"audio_url": {
"type": "string"
},
"instrument": {
"type": "string"
}
},
"additionalProperties": false
},
"description": "[{name, audio_url, instrument?}] — the stems (≤ 32). instrument = the sound it plays (a doseedo_instruments id: \"violin\", \"timpani\", \"harp\"), which decides how it is mixed; without it the name decides."
},
"style": {
"type": "string",
"description": "A mix style: an id or words (\"dry 90s rock\"). Pick it for the picture — the default (film-orchestral, a 2.3 s scoring hall) suits film drama, not every orchestra: cartoon-studio = a cartoon / animation orchestra (a close, dry, wide scoring stage, punchy rides); golden-age-cartoon = a 1940s–50s cartoon (mono, small studio, tape); film-scoring-stage = intimate TV / documentary; concert-hall; film-epic-hybrid = trailer / action; cathedral-choral; classical-chamber; or jazz-combo, ambient, 1970s-analog-rock, 2020s-pop …"
},
"balance": {
"type": "object",
"description": "{part name: dB in -12..12} — your balance on top of the levelling (and of the written dynamics a from_job reads).",
"additionalProperties": {
"type": "number"
}
},
"mix_job": {
"type": "string",
"description": "MCP: a doseedo_mix job_id to edit — its whole stored mix (every ride) is the base, mixgraph is applied on top, and its stems are reused when you pass no from_job / stems."
},
"vintage": {
"enum": [
"tape",
"shellac",
"none"
],
"type": "string",
"description": "A period medium over any style, after the mix: \"tape\" = 7.5 ips tape (saturation, wow and flutter, a low hiss); \"shellac\" = a 78 played back (mono, ~90 Hz–5.5 kHz with the reproducer's presence, a 1.3 Hz wow, surface noise that swishes once a turn, crackle). \"none\" takes a style's own medium off (golden-age-cartoon carries tape). Its node (master.chain type vintage: noise_db, crackle, hi_hz …) is editable in the returned mixgraph."
},
"dynamics": {
"type": "object",
"description": "Fader rides from written dynamics: {part name: [[onset_seconds, velocity 0-127], …]}. from_job fills it from the score (pp to ff ≈ 17 dB); pass {} for no rides.",
"additionalProperties": {
"type": "array"
}
},
"from_job": {
"type": "string",
"description": "MCP: a doseedo_render_score job_id — its parts are the stems, each with the instrument it plays, and each part's written dynamics (its mean velocity) set its balance."
},
"mixgraph": {
"type": "object",
"description": "An edited mix — the mixgraph a doseedo_mix returned, changed — rendered against the same stems (from_job or stems). With mix_job: ONLY what you change (strips[] by stem, automation[] rides by target — points: [] removes one, buses[] by id, master) — the rest is that mix as stored. A mixgraph marked `partial` (its rides summarized) is refused without mix_job. Omit for a fresh mix."
},
"target_lufs": {
"type": "number",
"description": "Master loudness, -24..-6 LUFS (default: the style's — -18 for film-orchestral, -14 for the blind default)."
},
"tonal_match": {
"type": "boolean",
"description": "Nudge the master toward professionally mixed orchestral references (default on for the orchestral styles). Its presence and air are judged only where the score is written loud (written_level), so a pp passage keeps its darkness."
},
"dynamics_ride": {
"type": "number",
"description": "How hard the written dynamics move the faders: 1 = default (pp to ff ≈ 17 dB), 0 = no rides, up to 1.5."
},
"written_level": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "number"
},
"maxItems": 2,
"minItems": 2
},
"maxItems": 4096,
"description": "[[seconds, velocity], …] — the whole score's written level, the loudest part sounding, held until the next row (0 = nothing plays). The tonal match reads only the passages it writes loud (f and louder), so a pp passage keeps its darkness. from_job fills it."
},
"idempotency_key": {
"type": "string",
"description": "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."
},
"dynamics_carried": {
"type": "object",
"description": "{part name: top velocity} — parts whose stems already play their written level (a render part's dynamics_level receipt, up to its top_vel). Their rides count it: no doubled swing. from_job fills it.",
"additionalProperties": {
"type": "number"
}
}
},
"additionalProperties": false
}| seed | number | Random seed (−1 or 0–4294967295). Reuse a result's seed to re-render close to the same take. |
| tune | boolean | 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 | array | 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 | number | 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 | string | Optional caption override (default: the instrument id). Style words help a little; the notes are the control. |
| refine | string | 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 | boolean | 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 | string | 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 | string | 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 | string | 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 | string | With session_id: the t_… id of the MIDI/instrument track to render. |
| tempo_map | array | 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 | string | 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* | string | 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 | string | Alternative to notes: with track_id, render THAT session track's notes (read from doseedo_get_session's summary). |
| synth_role | string | 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 | string | 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 | string | instrument "synth": the genre the patch is made for — "house", "techno", "trap", "synthwave", "lo-fi", "dnb"… or free words. |
| synth_words | string | instrument "synth": extra sound words for the patch ("reese", "warm analog", "acid"), ≤80 chars. |
| voice_split | boolean | 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 | string | Who plays a synth part: "oneshot" = a patch of one-shots made for it (the default for "synth"), "model" = the instrument model. |
| lora_strength | number | 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 | string | 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 | string | 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 | string | Meter of the part, e.g. "4/4", "3/4", "6/8" (default 4/4). Written into the MIDI and the caption. |
| idempotency_key | string | 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 | string | 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 | number | 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 | number | With revise_take_url: end of the region to redo (exclusive), beats from bar 1. |
| timbre_audio_url | string | 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 | number | With revise_take_url: start of the region to redo, beats from bar 1. |
{
"type": "object",
"required": [
"instrument"
],
"properties": {
"bpm": {
"type": "number",
"description": "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": {
"type": "number",
"description": "Random seed (−1 or 0–4294967295). Reuse a result's seed to re-render close to the same take."
},
"tune": {
"type": "boolean",
"description": "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": {
"type": "array",
"items": {
"type": "object",
"required": [
"pitch",
"start_beats",
"duration_beats"
],
"properties": {
"pitch": {
"type": "number",
"description": "MIDI note number 0–127 (60 = middle C)."
},
"velocity": {
"type": "number",
"description": "1–127 (default 96)."
},
"start_beats": {
"type": "number",
"description": "Onset in beats from bar 1."
},
"duration_beats": {
"type": "number",
"description": "Length in beats (> 0)."
}
},
"additionalProperties": false
},
"description": "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": {
"type": "number",
"description": "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": {
"type": "string",
"description": "Optional caption override (default: the instrument id). Style words help a little; the notes are the control."
},
"refine": {
"enum": [
"light",
"shred"
],
"type": "string",
"description": "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": {
"type": "boolean",
"description": "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": {
"type": "string",
"description": "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": {
"type": "string",
"description": "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": {
"type": "string",
"description": "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": {
"type": "string",
"description": "With session_id: the t_… id of the MIDI/instrument track to render."
},
"tempo_map": {
"type": "array",
"items": {
"type": "object",
"required": [
"beat",
"bpm"
],
"properties": {
"bpm": {
"type": "number"
},
"beat": {
"type": "number"
}
},
"additionalProperties": false
},
"description": "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": {
"type": "string",
"description": "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": {
"type": "string",
"description": "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": {
"type": "string",
"description": "Alternative to notes: with track_id, render THAT session track's notes (read from doseedo_get_session's summary)."
},
"synth_role": {
"enum": [
"bass",
"808",
"pad",
"lead",
"pluck"
],
"type": "string",
"description": "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": {
"enum": [
"oneshot",
"model"
],
"type": "string",
"description": "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": {
"type": "string",
"description": "instrument \"synth\": the genre the patch is made for — \"house\", \"techno\", \"trap\", \"synthwave\", \"lo-fi\", \"dnb\"… or free words."
},
"synth_words": {
"type": "string",
"description": "instrument \"synth\": extra sound words for the patch (\"reese\", \"warm analog\", \"acid\"), ≤80 chars."
},
"voice_split": {
"type": "boolean",
"description": "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": {
"enum": [
"oneshot",
"model"
],
"type": "string",
"description": "Who plays a synth part: \"oneshot\" = a patch of one-shots made for it (the default for \"synth\"), \"model\" = the instrument model."
},
"lora_strength": {
"type": "number",
"description": "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": {
"type": "string",
"description": "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": {
"type": "string",
"description": "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": {
"type": "string",
"description": "Meter of the part, e.g. \"4/4\", \"3/4\", \"6/8\" (default 4/4). Written into the MIDI and the caption."
},
"idempotency_key": {
"type": "string",
"description": "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": {
"type": "string",
"description": "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": {
"type": "number",
"description": "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": {
"type": "number",
"description": "With revise_take_url: end of the region to redo (exclusive), beats from bar 1."
},
"timbre_audio_url": {
"type": "string",
"description": "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": {
"type": "number",
"description": "With revise_take_url: start of the region to redo, beats from bar 1."
}
},
"additionalProperties": false
}| mix | boolean | Also bounce a summed mix of the stems (default true). |
| seed | number | Random seed (reuse to re-render close to the same performance). |
| tune | boolean | Light intonation on every winds / brass / strings part (default true): held, clearly pitched notes the model rendered 15–85 cents off are moved toward their written pitch, to a small natural residual — attacks, vibrato and fast notes as played. Receipt: parts[].tune. false = every part as rendered (or parts[].tune false for one). |
| parts | array | The parts you wrote: [{name?, instrument, timbre_preset?, lora_id?, players?, notes:[{pitch, start_beats, duration_beats, velocity?}], dynamics?}] — beats from bar 1, concert pitch. instrument/timbre_preset = a doseedo_instruments call. players = how many play the line: 1 (default) a soloist, 2–8 a SECTION (e.g. Violins I players 6). |
| vaefix | boolean | VAE spectral corrector on every winds / brass / strings part (default true): the decoder's low-mid fog under each instrument's register is trimmed, mic hiss removed only where present. Receipt: parts[].vaefix. false = every decode as rendered (or parts[].vaefix false for one). |
| midi_url | string | Alternative to parts: a multi-track Standard MIDI File (≤ 2 MiB) — a doseedo result link or a public https URL. Channel 10 = drums: the kit, or the one percussion instrument a part is named for (Bass Drum, Cymbals, Bass Drum & Cymbals, Triangle…). |
| score_url | string | Alternative to parts: a score file URL — MIDI or MusicXML, told apart by its content. |
| tempo_map | array | Tempo changes [{beat, bpm}] (first point at beat 0). Overrides a file's own tempo. |
| instruments | object | Name the instrument for any part: {"Violin I": {"instrument": "violin", "players": 6}, "2": {"instrument": "acoustic_guitar", "timbre_preset": "koto:preset1"}} — key = the part name or its 0-based index; players makes a MIDI / MusicXML part a section. Wins over the name/program match. |
| musicxml_url | string | Alternative to parts: a MusicXML score (.musicxml / .xml / .mxl, ≤ 8 MiB) exported from Dorico, Sibelius, Finale, MuseScore, or written by you. |
| time_signature | string | Meter, e.g. "4/4" (default, or the file's). |
| idempotency_key | string | 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. |
| duration_seconds | number | Render length (default: the last note + 2 s; ≤ 600). |
{
"type": "object",
"properties": {
"bpm": {
"type": "number",
"description": "Tempo of the parts (10–400). Required with parts[] unless tempo_map is given; on a file it sets the speed and keeps the score's fermatas / rit. / tempo changes."
},
"mix": {
"type": "boolean",
"description": "Also bounce a summed mix of the stems (default true)."
},
"seed": {
"type": "number",
"description": "Random seed (reuse to re-render close to the same performance)."
},
"tune": {
"type": "boolean",
"description": "Light intonation on every winds / brass / strings part (default true): held, clearly pitched notes the model rendered 15–85 cents off are moved toward their written pitch, to a small natural residual — attacks, vibrato and fast notes as played. Receipt: parts[].tune. false = every part as rendered (or parts[].tune false for one)."
},
"parts": {
"type": "array",
"items": {
"type": "object",
"required": [
"notes"
],
"properties": {
"name": {
"type": "string"
},
"tune": {
"type": "boolean",
"description": "false = this part exactly as rendered (no light intonation pass; default true)."
},
"notes": {
"type": "array",
"items": {
"type": "object",
"required": [
"pitch",
"start_beats",
"duration_beats"
],
"properties": {
"pitch": {
"type": "number"
},
"velocity": {
"type": "number"
},
"start_beats": {
"type": "number"
},
"duration_beats": {
"type": "number"
}
},
"additionalProperties": false
}
},
"vaefix": {
"type": "boolean",
"description": "false = this part's decode exactly as rendered (no VAE spectral corrector; default true)."
},
"lora_id": {
"type": "string"
},
"players": {
"type": "number",
"description": "How many players play this line: 1 (default) = a soloist; 2–8 = a SECTION — the line played by that many different players (each its own recording and performance), summed into ONE section stem. A string section = violins I, violins II, violas, cellos, basses with players 4–8 each. Each player renders (and costs) like a part."
},
"dynamics": {
"type": "array",
"items": {
"type": "object",
"required": [
"beat",
"velocity"
],
"properties": {
"beat": {
"type": "number"
},
"velocity": {
"type": "number"
}
},
"additionalProperties": false
},
"description": "The part's written LEVEL over time, as a DAW automation lane: [{beat, velocity 1–127}] in beat order, linear between points, a step = two points on one beat, held after the last (p 52, mf 80, f 96, ff 112). A velocity says how a note STARTS; this says how it goes on — a crescendo on a held note: [{beat: 0, velocity: 52}, {beat: 8, velocity: 96}]. Its tone follows it, through a held note too, and doseedo_mix {from_job} rides the level to it. A MusicXML score's dynamics + hairpins arrive as this lane on their own."
},
"instrument": {
"type": "string"
},
"timbre_preset": {
"type": "string"
},
"dynamics_curve": {
"enum": [
"auto",
"off",
"velocity",
"cc11",
"cc1"
],
"type": "string",
"description": "What colours this part's TONE over time: auto (default) = its dynamics lane when that moves, else its note velocities when they vary — soft darker, loud brighter, on every instrument but drums; off = one colour throughout; velocity = the velocities even with a lane; cc11/cc1 = that MIDI CC lane (a midi_url part). Receipt: parts[].dynamics."
}
},
"additionalProperties": false
},
"description": "The parts you wrote: [{name?, instrument, timbre_preset?, lora_id?, players?, notes:[{pitch, start_beats, duration_beats, velocity?}], dynamics?}] — beats from bar 1, concert pitch. instrument/timbre_preset = a doseedo_instruments call. players = how many play the line: 1 (default) a soloist, 2–8 a SECTION (e.g. Violins I players 6)."
},
"vaefix": {
"type": "boolean",
"description": "VAE spectral corrector on every winds / brass / strings part (default true): the decoder's low-mid fog under each instrument's register is trimmed, mic hiss removed only where present. Receipt: parts[].vaefix. false = every decode as rendered (or parts[].vaefix false for one)."
},
"midi_url": {
"type": "string",
"description": "Alternative to parts: a multi-track Standard MIDI File (≤ 2 MiB) — a doseedo result link or a public https URL. Channel 10 = drums: the kit, or the one percussion instrument a part is named for (Bass Drum, Cymbals, Bass Drum & Cymbals, Triangle…)."
},
"score_url": {
"type": "string",
"description": "Alternative to parts: a score file URL — MIDI or MusicXML, told apart by its content."
},
"tempo_map": {
"type": "array",
"items": {
"type": "object",
"required": [
"beat",
"bpm"
],
"properties": {
"bpm": {
"type": "number"
},
"beat": {
"type": "number"
}
},
"additionalProperties": false
},
"description": "Tempo changes [{beat, bpm}] (first point at beat 0). Overrides a file's own tempo."
},
"instruments": {
"type": "object",
"description": "Name the instrument for any part: {\"Violin I\": {\"instrument\": \"violin\", \"players\": 6}, \"2\": {\"instrument\": \"acoustic_guitar\", \"timbre_preset\": \"koto:preset1\"}} — key = the part name or its 0-based index; players makes a MIDI / MusicXML part a section. Wins over the name/program match."
},
"musicxml_url": {
"type": "string",
"description": "Alternative to parts: a MusicXML score (.musicxml / .xml / .mxl, ≤ 8 MiB) exported from Dorico, Sibelius, Finale, MuseScore, or written by you."
},
"time_signature": {
"type": "string",
"description": "Meter, e.g. \"4/4\" (default, or the file's)."
},
"idempotency_key": {
"type": "string",
"description": "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."
},
"duration_seconds": {
"type": "number",
"description": "Render length (default: the last note + 2 s; ≤ 600)."
}
},
"additionalProperties": false
}| loudness |
| any |
| Delivery loudness: "web" (−16 LUFS, default), "streaming" (−14), "broadcast" / "ebu" (−23), "atsc" (−24), or a LUFS number (−36…−8). |
| video_key | string | R2 ingest key of the video (the same upload doseedo_spot_video used). |
| video_url | string | https URL of the video, as an alternative to video_key. |
| start_timecode | string | SMPTE timecode of the film's first frame (default: the file's own, else 00:00:00:00) — the clock the tracks' start_timecode is read on. |
| idempotency_key | string | 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. |
| production_audio | string | keep (default) mixes the video's own soundtrack under the score; drop replaces it. |
| production_gain_db | number | Trim on the production audio when kept (default 0). |
{
"type": "object",
"required": [
"tracks"
],
"properties": {
"duck": {
"type": "object",
"properties": {
"sfx": {
"type": "boolean"
},
"enabled": {
"type": "boolean"
},
"depth_db": {
"type": "number",
"maximum": 40,
"minimum": 0
},
"attack_ms": {
"type": "number",
"maximum": 3000,
"minimum": 0
},
"release_ms": {
"type": "number",
"maximum": 5000,
"minimum": 0
}
},
"description": "Dialogue ducking (on by default): depth_db (default 10), attack_ms (250: how early before a line the music is down), release_ms (700), sfx (false: duck effects too), enabled.",
"additionalProperties": false
},
"tracks": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "A label for the report, e.g. 1M3."
},
"role": {
"enum": [
"music",
"sfx"
],
"type": "string",
"description": "music (default; ducked under dialogue) or sfx (not ducked unless duck.sfx)."
},
"gain_db": {
"type": "number",
"maximum": 24,
"minimum": -60,
"description": "Level trim (default 0)."
},
"start_s": {
"type": "number",
"description": "Or where it starts in seconds from the first frame."
},
"audio_key": {
"type": "string",
"description": "An ingest key instead of audio_url."
},
"audio_url": {
"type": "string",
"description": "The cue's mixed audio (doseedo_mix mix_url as returned) or any public https URL."
},
"start_timecode": {
"type": "string",
"description": "Where it starts, in the film's timecode (HH:MM:SS:FF) — the cue sheet's start_timecode."
}
},
"additionalProperties": false
},
"maxItems": 64,
"minItems": 1,
"description": "What to lay on the film, in any order."
},
"dialogue": {
"type": "array",
"items": {
"type": "object",
"required": [
"start_s",
"end_s"
],
"properties": {
"end_s": {
"type": "number"
},
"start_s": {
"type": "number"
}
},
"additionalProperties": false
},
"description": "Dialogue spans [{start_s, end_s}] to duck under, instead of detecting them (use the cue sheet's dialogue, or your own)."
},
"loudness": {
"anyOf": [
{
"enum": [
"web",
"streaming",
"broadcast",
"ebu",
"atsc"
],
"type": "string"
},
{
"type": "number"
}
],
"description": "Delivery loudness: \"web\" (−16 LUFS, default), \"streaming\" (−14), \"broadcast\" / \"ebu\" (−23), \"atsc\" (−24), or a LUFS number (−36…−8)."
},
"video_key": {
"type": "string",
"description": "R2 ingest key of the video (the same upload doseedo_spot_video used)."
},
"video_url": {
"type": "string",
"description": "https URL of the video, as an alternative to video_key."
},
"start_timecode": {
"type": "string",
"description": "SMPTE timecode of the film's first frame (default: the file's own, else 00:00:00:00) — the clock the tracks' start_timecode is read on."
},
"idempotency_key": {
"type": "string",
"description": "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."
},
"production_audio": {
"enum": [
"keep",
"drop"
],
"type": "string",
"description": "keep (default) mixes the video's own soundtrack under the score; drop replaces it."
},
"production_gain_db": {
"type": "number",
"maximum": 12,
"minimum": -60,
"description": "Trim on the production audio when kept (default 0)."
}
},
"additionalProperties": false
}| mixgraph | object | A mix document (doseedo_mix → mixgraph): each stem named in it takes its strip's gain_db and pan. The EQ, compression, reverb and rides are not written into the project. |
| tempo_map | array | Tempo changes [{beat, bpm}] for the project. |
| midi_tracks | array | Optional MIDI tracks: [{name, notes:[{pitch, start_beats, duration_beats, velocity?}]}]. |
| time_signature | string | Meter (default 4/4). |
| idempotency_key | string | 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. |
{
"type": "object",
"properties": {
"bpm": {
"type": "number",
"description": "Project tempo (default 120)."
},
"name": {
"type": "string",
"description": "Project name."
},
"stems": {
"type": "array",
"items": {
"type": "object",
"properties": {
"pan": {
"type": "number"
},
"mute": {
"type": "boolean"
},
"name": {
"type": "string"
},
"gain_db": {
"type": "number"
},
"audio_key": {
"type": "string"
},
"audio_url": {
"type": "string"
},
"position_beats": {
"type": "number"
}
},
"additionalProperties": false
},
"description": "[{name, audio_url | audio_key, gain_db?, pan?, mute?, position_beats?}] — the audio tracks, in order."
},
"target": {
"enum": [
"logic",
"ableton"
],
"type": "string",
"description": "Which DAW (default logic)."
},
"mix_job": {
"type": "string",
"description": "MCP: a doseedo_mix job_id — every track takes that mix's level and pan, and the mix itself rides along as a muted reference track \"Mix (doseedo)\"."
},
"from_job": {
"type": "string",
"description": "MCP: a doseedo_render_score job_id — its stems, parts' MIDI and tempo are used (no other input needed)."
},
"mixgraph": {
"type": "object",
"description": "A mix document (doseedo_mix → mixgraph): each stem named in it takes its strip's gain_db and pan. The EQ, compression, reverb and rides are not written into the project."
},
"tempo_map": {
"type": "array",
"items": {
"type": "object",
"required": [
"beat",
"bpm"
],
"properties": {
"bpm": {
"type": "number"
},
"beat": {
"type": "number"
}
},
"additionalProperties": false
},
"description": "Tempo changes [{beat, bpm}] for the project."
},
"midi_tracks": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"notes": {
"type": "array",
"items": {
"type": "object"
}
}
},
"additionalProperties": false
},
"description": "Optional MIDI tracks: [{name, notes:[{pitch, start_beats, duration_beats, velocity?}]}]."
},
"time_signature": {
"type": "string",
"description": "Meter (default 4/4)."
},
"idempotency_key": {
"type": "string",
"description": "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."
}
},
"additionalProperties": false
}| video_key | string | R2 ingest key of the uploaded video (doseedo_get_upload_url with the file name, e.g. reel1.mp4; starts with "ingest/"). |
| video_url | string | https URL of the video, as an alternative to video_key (a public file URL, fetched directly; ≤ 2 GB). |
| cut_threshold | number | Scene-change threshold at full contrast (default 0.3). Lower finds softer cuts, higher only the hardest. |
| start_timecode | string | SMPTE timecode of the first frame, HH:MM:SS:FF (";" before the frames = drop-frame at 29.97/59.94). Default: the file's embedded timecode, else 00:00:00:00. |
| idempotency_key | string | 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. |
{
"type": "object",
"properties": {
"reel": {
"type": "integer",
"maximum": 99,
"minimum": 1,
"description": "Reel number for the cue ids (default 1 → 1M1, 1M2 …)."
},
"coverage": {
"type": "number",
"maximum": 0.98,
"minimum": 0.05,
"description": "How much of the film gets music (default 0.55). Raise it for wall-to-wall scoring (a trailer, an animation), lower it for a dialogue drama."
},
"keyframes": {
"type": "integer",
"maximum": 60,
"minimum": 0,
"description": "How many shots get a keyframe JPEG (default 24; the longest shots first)."
},
"video_key": {
"type": "string",
"description": "R2 ingest key of the uploaded video (doseedo_get_upload_url with the file name, e.g. reel1.mp4; starts with \"ingest/\")."
},
"video_url": {
"type": "string",
"description": "https URL of the video, as an alternative to video_key (a public file URL, fetched directly; ≤ 2 GB)."
},
"cut_threshold": {
"type": "number",
"maximum": 0.9,
"minimum": 0.05,
"description": "Scene-change threshold at full contrast (default 0.3). Lower finds softer cuts, higher only the hardest."
},
"start_timecode": {
"type": "string",
"description": "SMPTE timecode of the first frame, HH:MM:SS:FF (\";\" before the frames = drop-frame at 29.97/59.94). Default: the file's embedded timecode, else 00:00:00:00."
},
"idempotency_key": {
"type": "string",
"description": "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."
}
},
"additionalProperties": false
}| bpm_range | array | Allowed tempo range [min, max] (default ±12 % of bpm). |
| start_timecode | string | Film timecode of the cue's first downbeat (bar 1); hit timecodes are measured from it. |
| time_signature | string | Meter (default 4/4). |
{
"type": "object",
"required": [
"hits",
"bpm"
],
"properties": {
"bpm": {
"type": "number",
"description": "The cue's tempo (20–300) — the map stays as close to it as the hits allow."
},
"fps": {
"type": "number",
"description": "Frame rate of the timecodes: 23.976, 24, 25, 29.97, 30, 50, 59.94, 60."
},
"hits": {
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"type": "object",
"properties": {
"land": {
"enum": [
"downbeat",
"beat"
],
"type": "string"
},
"label": {
"type": "string"
},
"time_s": {
"type": "number"
},
"timecode": {
"type": "string"
}
},
"additionalProperties": false
}
]
},
"description": "The moments the music must land on: [{time_s} (seconds from the cue start) or {timecode: \"01:00:12:08\"} (film timecode, with fps and start_timecode), label?, land?}] — land = THIS hit's landing (\"downbeat\" or \"beat\"; default: the request's land), e.g. the big cuts on bar lines and a quick accent on a beat. A bare number = {time_s}."
},
"land": {
"enum": [
"downbeat",
"beat"
],
"type": "string",
"description": "Land hits on bar lines (default) or on any beat — the default for every hit without its own land."
},
"start_s": {
"type": "number",
"description": "Alternative: the cue start in seconds of film time (informational when hits are time_s)."
},
"bpm_range": {
"type": "array",
"items": {
"type": "number"
},
"description": "Allowed tempo range [min, max] (default ±12 % of bpm)."
},
"start_timecode": {
"type": "string",
"description": "Film timecode of the cue's first downbeat (bar 1); hit timecodes are measured from it."
},
"time_signature": {
"type": "string",
"description": "Meter (default 4/4)."
}
},
"additionalProperties": false
}| Training steps 50–800. Default 300 for ≤60 s of audio, 400 above. |
| audio_key | string | R2 ingest key of an uploaded audio file (from doseedo_get_upload_url / POST /api/upload/r2/ingest-url; starts with "ingest/"). One recording; or audio_keys for several. |
| audio_url | string | https URL of a recording (a doseedo result link — a separated stem works — or any public URL). Alternative to audio_key. |
| drum_mode | boolean | true for an unpitched percussion recording. |
| audio_keys | array | Several uploaded takes of the SAME instrument (≤8). |
| audio_urls | array | Several recording URLs of the same instrument (≤8). |
| instrument* | string | REQUIRED. The catalog instrument it is closest to (call.instrument from doseedo_instruments, e.g. "violin", "acoustic_guitar", "flute", "percussion"). |
| idempotency_key | string | 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. |
{
"type": "object",
"required": [
"instrument"
],
"properties": {
"bpm": {
"type": "number",
"description": "Optional tempo of the recording (30–300)."
},
"name": {
"type": "string",
"description": "A name for it, e.g. \"Grandpa's banjo\" (≤80 chars)."
},
"seed": {
"type": "number",
"description": "Random seed."
},
"notes": {
"type": "array",
"description": "Optional: the notes played, one list per file — [[{pitch, start, end, velocity?}…]] in SECONDS. Omitted, they are transcribed."
},
"steps": {
"type": "number",
"description": "Training steps 50–800. Default 300 for ≤60 s of audio, 400 above."
},
"audio_key": {
"type": "string",
"description": "R2 ingest key of an uploaded audio file (from doseedo_get_upload_url / POST /api/upload/r2/ingest-url; starts with \"ingest/\"). One recording; or audio_keys for several."
},
"audio_url": {
"type": "string",
"description": "https URL of a recording (a doseedo result link — a separated stem works — or any public URL). Alternative to audio_key."
},
"drum_mode": {
"type": "boolean",
"description": "true for an unpitched percussion recording."
},
"audio_keys": {
"type": "array",
"items": {
"type": "string"
},
"description": "Several uploaded takes of the SAME instrument (≤8)."
},
"audio_urls": {
"type": "array",
"items": {
"type": "string"
},
"description": "Several recording URLs of the same instrument (≤8)."
},
"instrument": {
"type": "string",
"description": "REQUIRED. The catalog instrument it is closest to (call.instrument from doseedo_instruments, e.g. \"violin\", \"acoustic_guitar\", \"flute\", \"percussion\")."
},
"idempotency_key": {
"type": "string",
"description": "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."
}
},
"additionalProperties": false
}{
"type": "object",
"properties": {
"kind": {
"enum": [
"generate_music",
"generate_sound",
"cover_stem",
"fill_gap",
"render_midi",
"train_instrument",
"render_score",
"mix",
"session_from_stems",
"spot_video",
"score_to_picture",
"cover_song",
"separate_stems",
"transcribe",
"audio_to_session",
"convert_project",
"bounce_session",
"analyze_song",
"detect_chords",
"beat_grid",
"check_take",
"analyze_midi",
"generate",
"sound",
"coverstem",
"fillgap",
"render",
"train",
"score",
"stemsess",
"spot",
"picture",
"cover",
"separate",
"session",
"convert",
"bounce",
"analyze",
"chords",
"beats",
"check",
"harmony"
],
"type": "string",
"description": "Which job kind created the task — the registry name the submit reply carried (generate_music, generate_sound, cover_stem, fill_gap, render_midi, train_instrument, render_score, mix, session_from_stems, spot_video, score_to_picture, cover_song, separate_stems, transcribe, audio_to_session, convert_project, bounce_session, analyze_song, detect_chords, beat_grid, check_take, analyze_midi); the short codes (generate, sound, coverstem, fillgap, render, train, score, stemsess, spot, picture, cover, separate, session, convert, bounce, analyze, chords, beats, check, harmony) are accepted aliases."
},
"job_id": {
"type": "string",
"description": "Alternatively the job_id (job_…) from a submit tool or the jobs API — replaces task_id + kind."
},
"task_id": {
"type": "string",
"description": "The task_id returned by a submit tool."
},
"timeout_seconds": {
"type": "number",
"description": "Max seconds to wait in this call (5–50, default 45). Start with the submit reply's suggested_next_wait."
}
},
"additionalProperties": false
}