Music & audio for AI agents: 50+ AI instruments play your MIDI, stems, audio to MIDI, Logic/Ableton
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.
Tool list last changed Oct 25, 2026.
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
}Add an audio file to a session — from a public URL (a doseedo-generated song, a separated stem, any https audio) OR from a LOCAL file you uploaded (doseedo_get_upload_url → PUT the bytes → pass the returned audio_key here). Ingested server-side and returned as a sha256 you then use: place it on a track with attach_audio, or load it into a Quick Sampler with load_quick_sampler_sample {track_id, sample_path: "<the sha>"} (bakes into the exported .logicx, no desktop needed — the drum-pack/sample-swap path). Give audio_url OR audio_key.
| Argument | Type | Description |
|---|---|---|
| filename | string | Optional name for the asset. |
| audio_key | string | audio_key from doseedo_get_upload_url after you PUT a local file to its upload_url (a file from the user's disk, e.g. a drum-pack WAV). |
| audio_url | string | https URL of the audio — any public URL, or a doseedo result URL from a job (pre-signed links work as-is; no key needed). |
| session_id* | string |
{
"type": "object",
"required": [
"session_id"
],
"properties": {
"filename": {
"type": "string",
"description": "Optional name for the asset."
},
"audio_key": {
"type": "string",
"description": "audio_key from doseedo_get_upload_url after you PUT a local file to its upload_url (a file from the user's disk, e.g. a drum-pack WAV)."
},
"audio_url": {
"type": "string",
"description": "https URL of the audio — any public URL, or a doseedo result URL from a job (pre-signed links work as-is; no key needed)."
},
"session_id": {
"type": "string"
}
},
"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). |
Key detection, BPM/tempo detection, song structure and chords — musical analysis of a recording in one call: key (e.g. "D minor"), bpm + per-beat tempo_map, meter / beats_per_bar, downbeats (seconds), sections (intro/verse/chorus… with times), chords (a progression on the beat grid), dynamics. USE THIS to learn the key and tempo of a reference before writing a part — never guess or ask the user for what the audio already says. Pass audio_key (an upload) or audio_url (a result URL from another job as returned, or any public https URL). Up to 10 minutes of audio is analyzed. Synchronous (~5–20 s): the result is in this response. No separation, so a dense mix's chords are a draft — for a chord chart from stems use doseedo_detect_chords on the separated stems. Cancel: not applicable — the result is returned in the submit response; the job is already finished.
| Argument | Type | Description |
|---|---|---|
| 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/"). Provide this or audio_url. |
| audio_url | string | https URL of the audio (a doseedo result URL as returned, or any public URL). Alternative to audio_key. |
| 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": {
"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/\"). Provide this or audio_url."
},
"audio_url": {
"type": "string",
"description": "https URL of the audio (a doseedo result URL as returned, or any public URL). Alternative to audio_key."
},
"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
}Turn an uploaded full mix into a complete multitrack DAW session (separated stems as tracks, tempo map, optional per-stem MIDI and chord guide). The result is a downloadable session zip for Logic Pro or Ableton. Async: returns a job_id — poll with doseedo_wait_task (~4 minutes). Cancel: cooperative — the build stops at its next stage boundary and the build's sound-tool unit is refunded (a GPU separation already run stays charged).
| Argument | Type | Description |
|---|---|---|
| key | boolean | Detect the key and write it into the project (default true in the full build, false with simple). |
| name | string | Project name for the session file. |
| loops | boolean | Detect repeated clips and lay them as loops (default false). |
| chords | boolean | Add a detected-chords guide track (default false). |
| retune | boolean | Default true: a mix sitting >35 cents off A440 is pitch-corrected onto the 12-TET grid before separation (every transcriber coin-flips otherwise). false = leave the tuning as recorded. |
| simple | boolean | Faster minimal build: meter + tempo + stems only, no MIDI (default false). Required for stem_mode orchestra/detect. |
| target | string | DAW target (default logic). |
| markers |
Beat detection / beat tracking: bpm, beats[] (seconds), downbeats[] (seconds), beats_per_bar, downbeat_offset, beat_map[{t, pos}], duration — the grid to place a part against a recording (beat n is at beats[n] seconds). Pass audio_key (an upload) or audio_url (a result URL from another job as returned, or any public https URL). Up to 10 minutes of audio is analyzed. Synchronous (~3–15 s). For key + sections + chords as well use doseedo_analyze_song. Cancel: not applicable — the result is returned in the submit response; the job is already finished.
| Argument | Type | Description |
|---|---|---|
| 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/"). Provide this or audio_url. |
| audio_url | string | https URL of the audio (a doseedo result URL as returned, or any public URL). Alternative to audio_key. |
| 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": {
"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/\"). Provide this or audio_url."
},
"audio_url": {
"type": "string",
"description": "https URL of the audio (a doseedo result URL as returned, or any public URL). Alternative to audio_key."
},
"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
}Bounce a session (or specific tracks) to audio through their REAL plugin chains, offline — Dø Desktop renders them in the background WITHOUT the user opening the DAW (live via Logic if it's open, headless if it isn't; this is the thing stock DAWs can't do). Headless renders AUDIO tracks only — an instrument/MIDI track needs the project open in Logic. A track that could not render is named in the error with its reason. Async: returns a job_id — poll with doseedo_wait_task. The result is downloadable stem URLs. Needs Dø Desktop to run at some point to pick up the job; until then it stays queued. No credits (rendered on the user's machine). Cancel: a bounce still queued never renders (its budget is refunded); one mid-render has its result dropped on arrival.
| Argument | Type | Description |
|---|---|---|
| stems | boolean | true (default) = one file per track; false = a single mixdown. |
| format | string | Output format (default wav). |
| track_ids | array | Tracks to bounce (t_… ids from doseedo_get_session). Omit to bounce the whole session. |
| session_id* | string | |
| tail_seconds | number | Extra seconds for reverb/delay to ring out (default 2). |
| 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. |
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.
| 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, 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, 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. |
{
"type": "object",
"properties": {
"kind": {
"enum": [
"generate_music",
"generate_sound",
"cover_stem",
"fill_gap",
"render_midi",
"train_instrument",
"render_score",
"mix",
"session_from_stems",
"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",
"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, 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, 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."
}
},
"additionalProperties": false
}Finish a MULTIPART project upload started by doseedo_get_project_upload_url: pass every uploaded part's number and ETag (from the PUT response header; quotes optional). Returns the project_key to pass to doseedo_convert_project / doseedo_import_project. All parts except the last must be the same size (what `split -b` produces). abort:true discards the upload instead.
| Argument | Type | Description |
|---|---|---|
| abort | boolean | true = abandon the upload and free its parts (no project_key results). |
| parts | array | [{part_number, etag}] for EVERY part, in order. |
| upload_id* | string | |
| project_key* | string |
{
"type": "object",
"required": [
"project_key",
"upload_id"
],
"properties": {
"abort": {
"type": "boolean",
"description": "true = abandon the upload and free its parts (no project_key results)."
},
"parts": {
"type": "array",
"items": {
"type": "object",
"required": [
"part_number",
"etag"
],
"properties": {
"etag": {
"type": "string"
},
"part_number": {
"type": "number"
}
},
"additionalProperties": false
},
"description": "[{part_number, etag}] for EVERY part, in order."
},
"upload_id": {
"type": "string"
},
"project_key": {
"type": "string"
}
},
"additionalProperties": false
}DAW CONVERTER: a project rebuilt natively in the target: tracks, MIDI, audio clips, tempo and markers arrive editable (Logic/Ableton/Pro Tools/REAPER pairs also automation, buses/sends, plugin state; into FL 3rd-party plugins only). Sources: Logic .logicx, Ableton .als, FL Studio .flp, Pro Tools .ptx, REAPER .rpp, Cubase .cpr, Dorico .dorico/.musicxml, Studio One .song, GarageBand .band (SOURCE only — zip the .band package like a .logicx; a GarageBand 6 project must be re-saved in GarageBand 10), Bitwig = any .dawproject (Bitwig/Studio One/Cubase export it; a native .bwproject is refused — File > Export… > DAWproject in Bitwig). The enum lists the exact pairs. ★ ASYMMETRIC TARGETS (an undocumented native file is never written): TO Cubase, Studio One or Bitwig = ONE .dawproject the app imports, not a .cpr/.song/.bwproject; TO Dorico = MusicXML (.mxl, Dorico's own notation import), not a .dorico. FROM Cubase the .cpr carries tracks, tempo and MIDI parts but not the audio pool (audio tracks arrive empty). FROM Dorico a .dorico carries players and flows but NOT its notes: convert its MusicXML export instead (.musicxml/.mxl accepted under dorico2*). Every result carries a transfer REPORT: `report`, `lossy`, `summary[]` (what changed), `warnings[]` (read before opening) — relay them; silence is never "lossless". Upload first: doseedo_get_project_upload_url + PUT (zip a project FOLDER so its audio travels; a bare project file works too; multipart past ~4 GB). Directions: "<source>2<target>"; "auto2<target>" detects the source; "<daw>2<daw>" rebuilds Logic/Ableton/FL/REAPER/Pro Tools in place (e.g. options.third_party_plugins:"disable"). To EDIT a project use doseedo_import_project; to convert a session the tools built: doseedo_download_session → upload that zip → logic2<target> (not a session_id). Async: job_id → doseedo_wait_task (15 s–2 min; `stage`); `file` is a direct storage link. Cancel: no stop — it completes, the job ends canceled, output discarded; the credit is refunded only when the conversion itself fails.
| Argument | Type | Description |
|---|---|---|
| options | object | Conversion options (all optional). third_party_plugins:"disable" drops third-party AU/VST devices so the export opens clean on a machine without them; stock_plugins:"disable" leaves stock devices unmapped instead of mapping to the nearest target-DAW device; carry_plugin_presets:false strips plugin patches; lossless:true (→Logic) pins the project to the MAX clip sample rate so no clip is downsampled; project_rate (→Logic) pins an exact rate in Hz; silence_empty_sampler:false (→Logic) keeps Logic's audible default Quick Sampler on tracks whose sampler had no sample; source_name = the project's display name for the output file. |
AI COVER / style transfer of a whole song: re-render an uploaded song as a cover, keeping its structure/melody while changing timbre, instruments, or lyrics. INSTRUMENT SWAP: instruments {"piano": "electric_guitar"} separates the song, transcribes the swapped stem and re-plays THOSE transcribed notes on the target instrument; by default only the swapped stem(s) are regenerated and every other stem passes through as the original separated audio (regen changes that). Because the swap replays a transcription, small note differences from the source are expected — verify from result.cover.instrument_swaps (applied or why not), and offer the user the result/takes to judge rather than promising a note-perfect copy. Target ids: GET https://api.doseedo.com/api/instruments (open). Optionally export a DAW session too. Async: returns a job_id — poll with doseedo_wait_task (several minutes for full songs). Result files are pre-signed links: 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 |
|---|---|---|
| seed | number | Optional random seed for reproducibility. |
| genre | string | Optional GENRE style transfer: free text naming the target genre (e.g. "bossa nova", "80s synth-pop"); every regenerated stem is captioned with it. Outcome in result.cover.genre. |
| regen | string | Optional: which stems to regenerate. Default with a swap = only the swapped stems (the rest are the original separated audio). "all" = cover every stem; or a comma list of stems/instruments, e.g. "piano,other" (a swapped stem is always regenerated). |
| export | string |
TIMBRE TRANSFER (an instrument swap) from a recording: hum or whistle a melody, play it on a kazoo, take a guitar line — and get it back played by a cello, a trumpet, a koto (any doseedo_instruments call). Re-play ONE recorded part — a separated stem, a solo, a region of the user's session — on another instrument, straight from the audio: the recording's FSQ codes carry its structure into a take generated from noise, and the sound is the instrument's (caption + timbre_preset) — the FSQ + timbre combination the cond5 model was trained on (served on its turbo graft). No MIDI by default (midi:true adds the server's own pitch roll of the recording); `fidelity` > 0 also keeps that much of the recording's own latents (closer, but its sound leaks back in). For the exact notes, transcribe and doseedo_render_midi; a whole mix → doseedo_cover_song. result.recipe says what reached the model (fsq, timbre, cns). Async: job_id → doseedo_wait_task (~30–90 s) → takes[{url}] (pre-signed: curl -OJ, no auth header, 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 | The recording's tempo (a hint; default 120). |
| midi | boolean | true = the server also transcribes the recording's notes into a roll that drives the MIDI hooks beside the FSQ codes — closer notes, a little slower (LatentPitch on audio; vaescriptor on a latent_key; a drum part — either route — gets its hits from vaescriptor_drums). recipe.midi_source names it. Default false: the codes alone. |
| seed | number | Optional random seed for reproducibility. |
| takes | number | How many takes, 1–4 (default: the server's best-of-N). |
Create a new, empty DAW session in the account (a blank project you can then populate with doseedo_edit_session, or target with doseedo_audio_to_session). Returns its session_id.
| Argument | Type | Description |
|---|---|---|
| daw | string | Bound DAW (default logic). |
| name* | string | Session name. |
{
"type": "object",
"required": [
"name"
],
"properties": {
"daw": {
"enum": [
"logic",
"ableton"
],
"type": "string",
"description": "Bound DAW (default logic)."
},
"name": {
"type": "string",
"description": "Session name."
}
},
"additionalProperties": false
}Delete DAW sessions in bulk — a SOFT delete (the sessions disappear from the account and every listing; nothing on the user's disk is touched). Select by ids, or by filters (daw_kind, created_before / created_after, name_contains); filters combine with AND. SAFE BY DEFAULT: without confirm:true this is a DRY RUN that deletes nothing and returns {matched, ids}. Always run the dry run first, show the user the count (and names if few), and call again with confirm:true only after they agree. Never delete sessions the user did not ask to remove.
| Argument | Type | Description |
|---|---|---|
| ids | array | Session ids to delete (up to 500), from doseedo_list_sessions. |
| limit | number | Cap on how many sessions one call may match (default and max 1000). |
| confirm | boolean | false/omitted = dry run (nothing deleted). true = actually delete — only after the user saw the dry-run count and agreed. |
| daw_kind | string | Only sessions bound to this DAW, e.g. "logic", "ableton". |
| created_after | string | ISO-8601 date/time: only sessions created after this. |
| name_contains | string | Only sessions whose name contains this text (case-insensitive). |
| created_before |
Is Dø Desktop running on the user's Mac, and can it put edits into their Logic project? Reports which sessions it holds, how it applies edits (apply_mode "reopen" = save, back up, close, apply, reopen), whether macOS lets it (logic_control), each session's last apply (reopen_results) and its applied cursor. Use it to know whether an edit will reach the project now or wait for the next session open. When it is NOT connected the result says how the user gets and pairs the app, and what still works without it. Read-only.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}Chord detection on audio (a chord chart on the beat grid): chord_spans[{chord, start, end, start_beat, end_beat, confidence}], chords{"<beat>": "Am7"}, bpm, beats_per_bar, beat_map. Default = the deep ACE detector (GPU-backed, a CPU chroma detector is the automatic fallback); deep:false forces the fast CPU detector. Pass audio_key (an upload) or audio_url (a result URL from another job as returned, or any public https URL). Up to 10 minutes of audio is analyzed. Works best on a harmonic stem (piano/guitar/bass) or a clean mix. Synchronous (~5–30 s). Cancel: not applicable — the result is returned in the submit response; the job is already finished.
| Argument | Type | Description |
|---|---|---|
| deep | boolean | true (default) = deep ACE detector; false = fast CPU chroma detector. |
| 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/"). Provide this or audio_url. |
| audio_url | string | https URL of the audio (a doseedo result URL as returned, or any public URL). Alternative to audio_key. |
| 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": {
"deep": {
"type": "boolean",
"description": "true (default) = deep ACE detector; false = fast CPU chroma detector."
},
"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/\"). Provide this or audio_url."
},
"audio_url": {
"type": "string",
"description": "https URL of the audio (a doseedo result URL as returned, or any public URL). Alternative to audio_key."
},
"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
}Save a session as a native Logic project (.logicx.zip), rebuilt server-side from the session state — no desktop needed. Returns a short-lived NO-AUTH download_url (plain `curl -o ~/Downloads/…`, no header) plus `replay` = what the build put in the file (per track: kind, Quick Sampler sample + sampler {mode, sample_seconds, start/end, plays_beats}, MIDI note count, audio region count; bundled media; deferred ops the offline build could not synthesize) and `warnings` (e.g. a classic-mode sampler whose notes end before its sample; an unknown sample length). Verify from replay/warnings, never by unzipping ProjectData. `place_local_files` (when present) is ACTION-REQUIRED after unzipping — for Quick Sampler samples AND audio regions from local paths: a replay track with audio_source:"place_local_files" or a "NOT bundled" warning means that file is not in the zip until you run those cp commands; then tell the user the project is complete.
| Argument | Type | Description |
|---|---|---|
| daw | string | Target DAW (default logic; only logic is a one-shot native download — for others use doseedo_convert_project). |
| session_id* | string |
{
"type": "object",
"required": [
"session_id"
],
"properties": {
"daw": {
"enum": [
"logic",
"ableton",
"fl",
"reaper"
],
"type": "string",
"description": "Target DAW (default logic; only logic is a one-shot native download — for others use doseedo_convert_project)."
},
"session_id": {
"type": "string"
}
},
"additionalProperties": false
}The catalog of session edit ops doseedo_edit_session accepts, served in views that each fit one answer (never cut mid-JSON). DEFAULT (no args): units, ids, applies, groups, batching/policy, the recipe NAMES and every op as {op, group, applies, summary} — read it ONCE before a build. Then fetch what you need: op:"load_quick_sampler_sample" (or ops:[…]) → those ops in full (args, units, doc; an unknown name gets did_you_mean); section:"recipes" → the full recipes (drum kit from local samples, fix note lengths, one-shots on an audio track, remote sample, submix bus, verify) — copy one instead of discovering op order; section:"ops" → every op in full; "units" / "ids" / "summary" (the get_session field map + workflow + policy + batching) / "all" (fitted, may shorten). Each op says where it lands (applies: live in the open project | next_open | state). Read-only, no key needed.
| Argument | Type | Description |
|---|---|---|
| op | string | One op name, e.g. "set_midi_notes" — returns that op in full. |
| ops | array | Several op names — returns each in full. |
| section | string | Which part of the catalog. Omit for the default overview. |
{
"type": "object",
"properties": {
"op": {
"type": "string",
"description": "One op name, e.g. \"set_midi_notes\" — returns that op in full."
},
"ops": {
"type": "array",
"items": {
"type": "string"
},
"description": "Several op names — returns each in full."
},
"section": {
"enum": [
"summary",
"ops",
"recipes",
"units",
"ids",
"all"
],
"type": "string",
"description": "Which part of the catalog. Omit for the default overview."
}
},
"additionalProperties": false
}Edit a DAW session with a list of ops (regions, MIDI notes, sampler samples, tracks, mixer faders/pans/mutes, plugins, tempo, markers, key, …): ids and current values from doseedo_get_session, op arguments from doseedo_edit_ops_reference. When sync.live_edits is true Dø Desktop puts it into the user's Logic project (it saves, backs up, closes and reopens the project, ~10–20 s — tell the user); otherwise stored and applied at next open. CONTRACT: every op is validated before anything is stored; a rejection carries a code — unknown_op / unknown_plugin (with did_you_mean), unknown_id (with the valid ids), duplicate_id, forbidden_group, read_only_key — and a reason. atomic (default true): one rejection → NOTHING stored, all rejections listed; atomic:false stores the good ops. RETRY: re-send a timed-out call with the SAME batch_key and it dedups (deduped:true); without batch_key a retry duplicates. Ops apply on the desktop one at a time in order, no per-batch undo — verify with doseedo_download_session (replay).
| Argument | Type | Description |
|---|---|---|
| ops* | array | The edits, e.g. [{"op":"set_track_crop","args":{"track_id":"t_…","start_beats":4,"end_beats":124,"prev_start_beats":24}}, {"op":"set_channel_volume","args":{"channel_id":"ch_…","value":0.6}}]. See doseedo_edit_ops_reference. |
| atomic | boolean | Default true: any rejected op means nothing is stored. Set false to store the valid ops and receive the rest as `rejected`. |
| batch_key | string | A stable id for THIS batch (e.g. "drumkit-build-1"). Same batch_key + same ops on a retry = the same client_op_ids = no duplicates. Always pass one for a build you might have to retry. |
| session_id* | string |
INPAINT (repair) a part: send ONE recorded part (a stem, a DAW track's audio) with a gap in it — the silence between two clips, a bar to redo, a dropout — and get it back with the gap PLAYED: the take before and after the gap is kept bit-exact (spliced back), and the gap is generated against both, so it continues out of what comes before and leads into what follows. What fills it is planned first (the DSP plane's extend planner, which hears the part): the take's own LOOP when it has one — the gap is seeded from its own passes at the matching bar phase, so a groove keeps turning — else a part written in its key and over its chords, performed in the take's own sound. Pass the session's bpm and bar grid (bar_offset_seconds: where a bar line falls in the audio you send); the gap is in seconds of that audio. Send the part with some of the take on each side of the gap (8 bars or more before it is best). Async: job_id → doseedo_wait_task (~40–150 s) → takes[{url}]: WAVs as long as the audio you sent, the gap filled — cut out the gap (or the span you need) to drop it into the DAW. output.plan says what filled it (loop bars, or the writer and the changes). 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. The session's tempo — the gap is filled on its bar grid. |
| fill | string | What fills the gap: "context" = the span played AGAIN from the take around it — no plan, no notes: a variation of what is there, in its own sound and level (INPAINTING a span that has audio — the right default there); "loop" = the take's own passes (a groove that keeps turning), "written" = a part written in its key and chords, "auto" (default) = the loop when the part has one, else written. |
| keep | number |
TEXT TO MUSIC: generate an original AI music track — a song or an instrumental, background music for a video — from a text PROMPT (optionally with lyrics). The prompt sets style/instrumentation; bpm and time_signature only tag the caption (a loose hint, NOT an enforced tempo or grid); there is no key control (a key named in the prompt is not honoured) and no MIDI input. Wrong tool for "a part in D minor at the session tempo" — for that YOU write the notes and render them with doseedo_render_midi (the instrument model plays your exact MIDI); key/tempo of a reference: doseedo_analyze_song; session tempo: doseedo_get_session; the exact calls: doseedo_recipes name="compose-part". Async: job_id → doseedo_wait_task (typically 1–3 min) → audio URLs (pre-signed: curl -OJ <url>, no auth header, valid 24 h — see expires_at). Several files = several takes, and a take may miss or change notes — hand the user the takes or pick by listening/transcribing; never promise exact notes. 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 | Optional tempo HINT in BPM, written into the caption (default 120). Not enforced — the output tempo can drift from it. |
| seed | number | Optional random seed for reproducibility. |
| lyrics | string | Optional lyrics to sing. Omit for instrumental. |
| prompt* | string | Style/mood/instrumentation prompt, e.g. "warm jazz trio, brushed drums, late-night ballad". |
| time_signature |
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 whole song (doseedo_generate_music). 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 a DAW PROJECT file (for doseedo_convert_project / doseedo_import_project). Zip a project FOLDER so its audio travels with it — and a .logicx or GarageBand .band, which are folders (macOS packages). SIZE LIMITS: a single PUT takes up to 5 GB; guest and free accounts convert projects up to 2 GB, paid plans up to 12 GB (a larger one is refused as project_too_large with the cap and an upgrade link). Pass size_bytes: past 4 GB (or with multipart:true) you get a MULTIPART upload instead — a part_size, one presigned part_url per part, and the complete step (doseedo_complete_project_upload); each part is retried on its own, so a dropped connection costs one part, not the upload. Single PUT: `curl -sS -X PUT -H "Content-Type: application/zip" --data-binary @project.zip "<upload_url>"`, then pass project_key on. Multipart: `split -b <part_size_bytes> project.zip part.` then for each piece in order `curl -sS -X PUT --data-binary @part.aa "<part_url>" -D - -o /dev/null | grep -i etag` (keep each ETag), then doseedo_complete_project_upload {project_key, upload_id, parts}. Need more part URLs than one answer holds? Call this again with project_key + upload_id + part_numbers.
| Argument | Type | Description |
|---|---|---|
| filename | string | File name including extension, e.g. "Song Project.zip", "My Song.band.zip", "beat.flp", "song.cpr", "Mix.song", "set.dawproject" or "score.mxl". |
| multipart | boolean | Force a multipart upload regardless of size (resumable per part). |
| upload_id | string | CONTINUATION: the upload_id the first call returned. |
| size_bytes | number | The file's size in bytes (stat it). Decides single PUT vs multipart and sizes the parts. |
Read a DAW session as the arrangement an agent edits against: every track with its wire ids (track_id t_…, mixer strip channel_id ch_…), regions in BOTH beats and seconds with their MIDI notes (i, pitch, velocity, start_beats, duration_beats — i is what edit_midi_notes selects by), mixer (volume with dB, pan, mute), plugins with params[{param_id, name, value}] (set_device_param needs param_id) and sampler {mode, sample_seconds, plays_beats, …}, sends/output as ch_b_… ids, buses, tempo_bpm + tempo_map, time_signature + meter_map, key_signature when known, markers (marker_id, beat ABSOLUTE from bar 1), automation lanes, instrument, counts, length — and `sync` with live_edits:true|false + live_edits_reason (will an edit reach Logic now?). Field-by-field map: doseedo_edit_ops_reference {section:"summary"}. BUDGET (never cut mid-JSON): notes come inline when the selected tracks hold ≤200 notes, else regions carry note_count + notes_omitted:true — pass include_notes:true with tracks:[ids] for a track's notes; include_params:false / include_automation:false drop params / points; a result still too big is paginated by track with `truncated` + `next` (the exact args for the rest). Read-only. Pass the ids straight to doseedo_edit_session, or a track_id to doseedo_render_midi {session_id, track_id}.
| Argument | Type | Description |
|---|---|---|
| tracks | array | Only these tracks (track_id t_… or channel_id ch_…; a track name matches too). The rest of the session (tempo, markers, buses, sync) is always included. |
| session_id* | string | From doseedo_list_sessions. |
| include_notes | boolean | Include MIDI notes. Default: true when the selected tracks hold ≤200 notes in all, else false (regions then carry note_count + notes_omitted:true). |
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. 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). 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). Required for any other extension."
}
},
"additionalProperties": false
}Open an uploaded DAW project (Logic .logicx.zip, Ableton .als or project zip, FL .flp, REAPER .rpp, Pro Tools .ptx — zip the folder) as an EDITABLE doseedo session: returns a session_id the session tools then work on (doseedo_get_session → doseedo_edit_session → doseedo_download_session as a native Logic project, or convert that download to another DAW with doseedo_convert_project). The session gets the project's tempo (+ tempo map), meter, markers, and every track with its name, mixer level/pan, color and MIDI notes. AUDIO IS NOT CARRIED: the import reads the project, not its media — audio tracks arrive named and positioned (audio.placements lists each clip's file and beats) and audio.next says how to supply the files. Plugins and summing buses are reported, not recreated. Upload first with doseedo_get_project_upload_url; this call parses the project (seconds to minutes for a big one) — if it answers status:"running", call it again with the returned task_id until it hands back session_id.
| Argument | Type | Description |
|---|---|---|
| daw | string | The source DAW, when the filename does not say (optional; detected otherwise). |
| name | string | Session name (default: the project's own name). |
| task_id | string | CONTINUATION: the task_id a previous call returned while the parse was still running. |
| project_key | string | R2 key of the uploaded project (from doseedo_get_project_upload_url; starts with "uploads/"). |
{
"type": "object",
"properties": {
"daw": {
"enum": [
"logic",
"ableton",
"fl",
"reaper",
"protools"
],
"type": "string",
"description": "The source DAW, when the filename does not say (optional; detected otherwise)."
},
"name": {
"type": "string",
"description": "Session name (default: the project's own name)."
},
"task_id": {
"type": "string",
"description": "CONTINUATION: the task_id a previous call returned while the parse was still running."
},
"project_key": {
"type": "string",
"description": "R2 key of the uploaded project (from doseedo_get_project_upload_url; starts with \"uploads/\")."
}
},
"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, 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, 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). |
{
"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, 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, 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
}List the plugins you can insert on a strip with doseedo_edit_session's add_device op. Returns the stock Logic catalog (instruments + effects, always available) and — when Dø Desktop is connected — the actual plugins installed on the user's Mac (stock + third-party). Insert any of them BY NAME: add_device {channel_id, device: {name: "…"}}.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}List the connected account's DAW sessions (most recently updated first) — their ids, names, DAW, and update time. Pages with limit + offset (the response carries total and next_offset); name_contains filters by name. Use a session id with doseedo_get_session and doseedo_edit_session; clean up old ones with doseedo_delete_sessions.
| Argument | Type | Description |
|---|---|---|
| limit | number | How many to return (default 25, max 200). |
| offset | number | How many to skip (default 0) — pass the previous response's next_offset to get the next page. |
| name_contains | string | Only sessions whose name contains this text (case-insensitive). |
{
"type": "object",
"properties": {
"limit": {
"type": "number",
"description": "How many to return (default 25, max 200)."
},
"offset": {
"type": "number",
"description": "How many to skip (default 0) — pass the previous response's next_offset to get the next page."
},
"name_contains": {
"type": "string",
"description": "Only sessions whose name contains this text (case-insensitive)."
}
},
"additionalProperties": false
}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: rendered as written (safety rails still apply and are 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, 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 or duration_seconds, voice_split / voices, takes — takes are free, voices cost one batch per ~6). 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",
"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 (1–4) fixes the number of takes; omitted, the server picks best-of-N for the part length and returns them 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 (pass it back to re-render close to the same take), duration, voices?, refine?, chain. A take may miss or change a note — verify by listening or by doseedo_transcribe on a take (then compare pitches/onsets to what you sent); offer the takes rather than promising note-perfection. Free harmony check first: doseedo_analyze_midi. Electronic drums ("electronic"/"808", GM notes) play a one-shot kit made for drum_genre, "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 and orchestral arrangement: 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 (dynamics, hairpins, staccato/accents, pizz./arco, con sord. are performed; concert pitch). 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 recording and 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 (≤ 96 players), plain, sampled and World / LoRA instruments together (played in groups, ~1 min each). No synth / electronic parts (doseedo_render_midi), ≤ 600 s. 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), 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; overrides a file's own tempo. |
| mix | boolean |
STEM SEPARATION and VOCAL REMOVER: split an uploaded mix into stems (vocals, drums, bass, guitar, piano, other — or orchestral/auto-detected instruments) to isolate vocals (the vocals stem is the acapella; the other stems are the karaoke backing), with optional per-stem MIDI transcription and DAW-session export. Async: returns a job_id — poll with doseedo_wait_task (~2 minutes). Result: stems{name: url}, midi{name: url}, drum_substems{kick, snare, …} (drum_split), vocals_lyrics / vocals_notes, session_tracks + session_tempo_bpm when session_id was given, models_effective (what the auto family gate actually ran), other_classification (what the "other" stem was heard as), guitar_split (outcome). Cancel: the plane has no stop for a running separation — 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 |
|---|---|---|
| export | string | Optionally also build a DAW session from the stems. |
| models | string | Separation model set. Default 6stem (vocals/drums/bass/guitar/piano/other); auto/orchestra/detect for wider instrument sets. |
| 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/"). Provide this or audio_url. |
| audio_url | string | https URL of the audio, as an alternative to audio_key: a doseedo result URL exactly as a job returned it (a stem, a take, a bounce), or any public URL. The gateway fetches it (≤256 MB) into your account's ingest storage before the job starts. Pass audio_key OR audio_url. |
| drum_split |
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). |
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), 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 | string | Land hits on bar lines (default) or on any beat. |
| start_s | number | Alternative: the cue start in seconds of film time (informational when hits are time_s). |
| bpm_range | array | Allowed tempo range [min, max] (default ±12 % of bpm). |
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 |
AUDIO TO MIDI transcription: a melody, a bass line or a part as notes (pitch, onset/offset seconds, velocity, confidence as JSON — not a MIDI file; for .mid files per stem use doseedo_separate_stems with transcription or doseedo_audio_to_session). Works from an uploaded audio_key or an audio_url — any public https URL, including a result URL from another doseedo job (a generate take, a stem) as it was returned. Async: returns a job_id — poll with doseedo_wait_task (usually ~15–60s). For the KEY / tempo / chords of a whole mix use doseedo_analyze_song instead. Cancel: the plane has no stop for a running transcription — 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 |
|---|---|---|
| want | string | What to return: "notes" (default), "f0" (the continuous pitch contour — frame-rate Hz values, for glides/vibrato/intonation), or both. |
| chairs | string | polyphony="section": register codes per chair, as an alternative to roster. |
| family | string | Optional instrument family (e.g. "brass", "reeds", "strings") when the exact instrument is unknown. |
| roster | string | polyphony="section": the chairs on the stem, e.g. "trumpet,trumpet,trombone,tenor_sax". Omit for the family default. |
| backend | string | Advanced: force a transcription backend. Omit — the server routes by instrument. |
| strikes | boolean |
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, 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, 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. |
{
"type": "object",
"properties": {
"kind": {
"enum": [
"generate_music",
"generate_sound",
"cover_stem",
"fill_gap",
"render_midi",
"train_instrument",
"render_score",
"mix",
"session_from_stems",
"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",
"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, 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, 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
}| 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
}| boolean |
| Add section markers (intro/verse/chorus…) (default true in the full build, false with simple). |
| dereverb | boolean | Opt-in: lay DRY stems and recreate the room with a reverb plugin on each track (default false). |
| separate | boolean | false = no separation: the mix lands as ONE audio track (default true). |
| 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/"). Provide this or audio_url. |
| audio_url | string | https URL of the audio, as an alternative to audio_key: a doseedo result URL exactly as a job returned it (a stem, a take, a bounce), or any public URL. The gateway fetches it (≤256 MB) into your account's ingest storage before the job starts. Pass audio_key OR audio_url. |
| stem_mode | string | Separation family. auto (DEFAULT): the 6 stems plus a residual cascade that peels detected orchestral sections out of "other" (no orchestral content → identical to 6stem). 6stem: vocals/drums/bass/guitar/piano/other. drumsep: the drum stem replaced by isolated kick/snare/hh/… tracks on a Drums bus. sections: the 6 stems with "other" split by the joint section model (trumpet/trombone/sax/violin/viola/cello), each transcribed per chair. orchestra / detect: the 53-instrument bank on the MIX (needs simple:true; detect auto-picks, orchestra takes `instruments`). |
| tempo_map | boolean | false = one constant tempo instead of a tempo map (default true). |
| midi_stems | string | Optional comma-separated stems to also add as MIDI tracks, e.g. "piano,bass" (include "drums" for a GM drum roll). |
| instruments | string | stem_mode orchestra/detect: optional comma list restricting the orchestral set, e.g. "violin,cello,flute". |
| crop_silence | boolean | Punch regions in where each stem plays instead of whole-length stems (default false). |
| drum_sampler | boolean | Sampled kits → a one-shot sampler track + MIDI (default false). |
| guitar_split | string | Split the guitar stem into N players, each its own track + MIDI lane on a Guitar Section bus: "0" (off), "auto" (DEFAULT — a one-vs-two probe decides), "2"–"4". |
| drum_substems | boolean | Lay each drum piece as its own audio track on a Drums bus (default false; implied by stem_mode drumsep). |
| quantize_midi | string | Snap every pitched MIDI lane: "grid" = to the grid its own onsets support (straight/swing 8ths, 16ths, triplets, detected per lane); "score" = notation positions (straight 8ths). Default off (played timing). |
| drum_midi_split | boolean | With "drums" in midi_stems: one Quick Sampler track PER kit piece, each loaded with a synthesized one-shot (default false = one GM drum-roll track). |
| 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. |
| keep_stem_audio | boolean | With midi_stems: keep the audio stem next to its MIDI track (default true); false = the MIDI track REPLACES the audio. |
{
"type": "object",
"properties": {
"key": {
"type": "boolean",
"description": "Detect the key and write it into the project (default true in the full build, false with simple)."
},
"name": {
"type": "string",
"description": "Project name for the session file."
},
"loops": {
"type": "boolean",
"description": "Detect repeated clips and lay them as loops (default false)."
},
"chords": {
"type": "boolean",
"description": "Add a detected-chords guide track (default false)."
},
"retune": {
"type": "boolean",
"description": "Default true: a mix sitting >35 cents off A440 is pitch-corrected onto the 12-TET grid before separation (every transcriber coin-flips otherwise). false = leave the tuning as recorded."
},
"simple": {
"type": "boolean",
"description": "Faster minimal build: meter + tempo + stems only, no MIDI (default false). Required for stem_mode orchestra/detect."
},
"target": {
"enum": [
"logic",
"ableton"
],
"type": "string",
"description": "DAW target (default logic)."
},
"markers": {
"type": "boolean",
"description": "Add section markers (intro/verse/chorus…) (default true in the full build, false with simple)."
},
"dereverb": {
"type": "boolean",
"description": "Opt-in: lay DRY stems and recreate the room with a reverb plugin on each track (default false)."
},
"separate": {
"type": "boolean",
"description": "false = no separation: the mix lands as ONE audio track (default true)."
},
"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/\"). Provide this or audio_url."
},
"audio_url": {
"type": "string",
"description": "https URL of the audio, as an alternative to audio_key: a doseedo result URL exactly as a job returned it (a stem, a take, a bounce), or any public URL. The gateway fetches it (≤256 MB) into your account's ingest storage before the job starts. Pass audio_key OR audio_url."
},
"stem_mode": {
"enum": [
"auto",
"6stem",
"drumsep",
"sections",
"orchestra",
"detect"
],
"type": "string",
"description": "Separation family. auto (DEFAULT): the 6 stems plus a residual cascade that peels detected orchestral sections out of \"other\" (no orchestral content → identical to 6stem). 6stem: vocals/drums/bass/guitar/piano/other. drumsep: the drum stem replaced by isolated kick/snare/hh/… tracks on a Drums bus. sections: the 6 stems with \"other\" split by the joint section model (trumpet/trombone/sax/violin/viola/cello), each transcribed per chair. orchestra / detect: the 53-instrument bank on the MIX (needs simple:true; detect auto-picks, orchestra takes `instruments`)."
},
"tempo_map": {
"type": "boolean",
"description": "false = one constant tempo instead of a tempo map (default true)."
},
"midi_stems": {
"type": "string",
"description": "Optional comma-separated stems to also add as MIDI tracks, e.g. \"piano,bass\" (include \"drums\" for a GM drum roll)."
},
"instruments": {
"type": "string",
"description": "stem_mode orchestra/detect: optional comma list restricting the orchestral set, e.g. \"violin,cello,flute\"."
},
"crop_silence": {
"type": "boolean",
"description": "Punch regions in where each stem plays instead of whole-length stems (default false)."
},
"drum_sampler": {
"type": "boolean",
"description": "Sampled kits → a one-shot sampler track + MIDI (default false)."
},
"guitar_split": {
"type": "string",
"description": "Split the guitar stem into N players, each its own track + MIDI lane on a Guitar Section bus: \"0\" (off), \"auto\" (DEFAULT — a one-vs-two probe decides), \"2\"–\"4\"."
},
"drum_substems": {
"type": "boolean",
"description": "Lay each drum piece as its own audio track on a Drums bus (default false; implied by stem_mode drumsep)."
},
"quantize_midi": {
"enum": [
"grid",
"score"
],
"type": "string",
"description": "Snap every pitched MIDI lane: \"grid\" = to the grid its own onsets support (straight/swing 8ths, 16ths, triplets, detected per lane); \"score\" = notation positions (straight 8ths). Default off (played timing)."
},
"drum_midi_split": {
"type": "boolean",
"description": "With \"drums\" in midi_stems: one Quick Sampler track PER kit piece, each loaded with a synthesized one-shot (default false = one GM drum-roll track)."
},
"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."
},
"keep_stem_audio": {
"type": "boolean",
"description": "With midi_stems: keep the audio stem next to its MIDI track (default true); false = the MIDI track REPLACES the audio."
}
},
"additionalProperties": false
}{
"type": "object",
"required": [
"session_id"
],
"properties": {
"stems": {
"type": "boolean",
"description": "true (default) = one file per track; false = a single mixdown."
},
"format": {
"enum": [
"wav",
"aiff"
],
"type": "string",
"description": "Output format (default wav)."
},
"track_ids": {
"type": "array",
"items": {
"type": "string"
},
"description": "Tracks to bounce (t_… ids from doseedo_get_session). Omit to bounce the whole session."
},
"session_id": {
"type": "string"
},
"tail_seconds": {
"type": "number",
"description": "Extra seconds for reverb/delay to ring out (default 2)."
},
"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
}| 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
}| direction* | string | Source and target as "<source>2<target>" (logic | ableton | fl | protools | reaper | cubase | dorico | studioone | bitwig | garageband), "auto2<target>" to let the server detect the source, or "<daw>2<daw>" to rebuild in the same format (Logic/Ableton/FL/REAPER/Pro Tools only). cubase2* reads a .cpr and *2cubase writes a .dawproject (Cubase 14+/Nuendo open it natively). dorico2* reads a .dorico, .musicxml or .mxl and *2dorico writes MusicXML (.mxl). studioone2* reads a .song and *2studioone writes a .dawproject (Studio One 6.5+ imports it). bitwig2* reads any .dawproject and *2bitwig writes a .dawproject (Bitwig 5+ imports it). garageband2* reads a zipped .band package (source only — no *2garageband). |
| project_key* | string | R2 key of the uploaded project (from doseedo_get_project_upload_url / POST /api/upload/r2/signed-url; starts with "uploads/"). |
| 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": [
"project_key",
"direction"
],
"properties": {
"options": {
"type": "object",
"properties": {
"lossless": {
"type": "boolean"
},
"source_name": {
"type": "string",
"description": "Display name of the source project, e.g. \"My Song.als\" — names the output."
},
"project_rate": {
"type": "number",
"description": "Hz, ≥ 8000 (ableton2logic only; overrides lossless)."
},
"stock_plugins": {
"enum": [
"map",
"disable"
],
"type": "string"
},
"third_party_plugins": {
"enum": [
"keep",
"disable"
],
"type": "string"
},
"carry_plugin_presets": {
"type": "boolean"
},
"silence_empty_sampler": {
"type": "boolean"
}
},
"description": "Conversion options (all optional). third_party_plugins:\"disable\" drops third-party AU/VST devices so the export opens clean on a machine without them; stock_plugins:\"disable\" leaves stock devices unmapped instead of mapping to the nearest target-DAW device; carry_plugin_presets:false strips plugin patches; lossless:true (→Logic) pins the project to the MAX clip sample rate so no clip is downsampled; project_rate (→Logic) pins an exact rate in Hz; silence_empty_sampler:false (→Logic) keeps Logic's audible default Quick Sampler on tracks whose sampler had no sample; source_name = the project's display name for the output file.",
"additionalProperties": false
},
"direction": {
"enum": [
"logic2ableton",
"ableton2logic",
"fl2logic",
"fl2ableton",
"ableton2fl",
"logic2fl",
"reaper2logic",
"reaper2ableton",
"reaper2fl",
"logic2reaper",
"ableton2reaper",
"fl2reaper",
"protools2logic",
"protools2ableton",
"protools2fl",
"protools2reaper",
"logic2protools",
"ableton2protools",
"fl2protools",
"reaper2protools",
"cubase2logic",
"cubase2ableton",
"cubase2fl",
"cubase2reaper",
"cubase2protools",
"cubase2dorico",
"logic2cubase",
"ableton2cubase",
"fl2cubase",
"reaper2cubase",
"protools2cubase",
"dorico2logic",
"dorico2ableton",
"dorico2fl",
"dorico2reaper",
"dorico2protools",
"dorico2cubase",
"logic2dorico",
"ableton2dorico",
"fl2dorico",
"reaper2dorico",
"protools2dorico",
"garageband2logic",
"garageband2ableton",
"garageband2fl",
"garageband2reaper",
"garageband2protools",
"garageband2cubase",
"garageband2dorico",
"bitwig2logic",
"bitwig2ableton",
"bitwig2fl",
"bitwig2reaper",
"bitwig2protools",
"bitwig2cubase",
"bitwig2dorico",
"logic2bitwig",
"ableton2bitwig",
"fl2bitwig",
"reaper2bitwig",
"protools2bitwig",
"cubase2bitwig",
"dorico2bitwig",
"studioone2logic",
"studioone2ableton",
"studioone2fl",
"studioone2reaper",
"studioone2protools",
"studioone2cubase",
"logic2studioone",
"ableton2studioone",
"fl2studioone",
"reaper2studioone",
"protools2studioone",
"cubase2studioone",
"logic2logic",
"ableton2ableton",
"fl2fl",
"reaper2reaper",
"protools2protools",
"auto2logic",
"auto2ableton",
"auto2fl",
"auto2reaper",
"auto2protools",
"auto2cubase",
"auto2dorico",
"auto2bitwig",
"auto2studioone"
],
"type": "string",
"description": "Source and target as \"<source>2<target>\" (logic | ableton | fl | protools | reaper | cubase | dorico | studioone | bitwig | garageband), \"auto2<target>\" to let the server detect the source, or \"<daw>2<daw>\" to rebuild in the same format (Logic/Ableton/FL/REAPER/Pro Tools only). cubase2* reads a .cpr and *2cubase writes a .dawproject (Cubase 14+/Nuendo open it natively). dorico2* reads a .dorico, .musicxml or .mxl and *2dorico writes MusicXML (.mxl). studioone2* reads a .song and *2studioone writes a .dawproject (Studio One 6.5+ imports it). bitwig2* reads any .dawproject and *2bitwig writes a .dawproject (Bitwig 5+ imports it). garageband2* reads a zipped .band package (source only — no *2garageband)."
},
"project_key": {
"type": "string",
"description": "R2 key of the uploaded project (from doseedo_get_project_upload_url / POST /api/upload/r2/signed-url; starts with \"uploads/\")."
},
"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
}| Optionally also build a DAW session for this target. |
| labels | object | Optional identity CORRECTIONS {source: instrument}, same shape as instruments, e.g. {"other": "trumpet"} when the separation mislabels a stem. Only fixes what the stem is called (caption/timbre); nothing is re-played. Outcome in result.cover.stem_labels. |
| lyrics | string | Optional replacement lyrics. |
| swap_cns | number | Optional 0–1, only with instruments: how far the SWAPPED stems may depart from their source (overrides cover_noise_strength for them; server default 0.35). Lower = closer to the original timing/feel. |
| 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/"). Provide this or audio_url. |
| audio_url | string | https URL of the audio, as an alternative to audio_key: a doseedo result URL exactly as a job returned it (a stem, a take, a bounce), or any public URL. The gateway fetches it (≤256 MB) into your account's ingest storage before the job starts. Pass audio_key OR audio_url. |
| midi_only | boolean | Optional: re-perform every regenerated stem from its transcribed MIDI with NO timbre from the recording (the stem's own sound is dropped). Stems with nothing to render are skipped (result.cover.midi_only.skipped). |
| style_key | string | Optional ingest key (upload it first) of a reference MIX whose TIMBRE the regenerated stems take on (style transfer). |
| drum_split | boolean | true = explode the covered drums into isolated kick/snare/hh/… stems, each generated from its own slice of the drum roll (result.drum_stems). |
| instruments | object | Optional per-stem instrument SWAP map {source: target}, e.g. {"piano": "electric_guitar", "sax": "violin"}. Source = a stem (drums, bass, vocals, guitar, piano, other) or a detected instrument (sax, trumpet…); target = an instrument id from /api/instruments (an unknown target is refused up front). |
| guitar_split | string | Deal the guitar bucket into N players, each its own row/swap: "2"–"4", or "auto" (a one-vs-two probe decides). Outcome in result.cover.guitar_split. |
| structure_key | string | Optional ingest key of audio whose STRUCTURE codes replace the source's (the Cover page's "Structure: custom"). |
| timbre_preset | string | Optional named timbre preset — the fallback rung of the timbre ladder (stem latent > this > stock bank). |
| 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. |
| cover_noise_strength | number | Optional 0–1 fidelity dial: higher departs further from the source. |
{
"type": "object",
"properties": {
"seed": {
"type": "number",
"description": "Optional random seed for reproducibility."
},
"genre": {
"type": "string",
"description": "Optional GENRE style transfer: free text naming the target genre (e.g. \"bossa nova\", \"80s synth-pop\"); every regenerated stem is captioned with it. Outcome in result.cover.genre."
},
"regen": {
"type": "string",
"description": "Optional: which stems to regenerate. Default with a swap = only the swapped stems (the rest are the original separated audio). \"all\" = cover every stem; or a comma list of stems/instruments, e.g. \"piano,other\" (a swapped stem is always regenerated)."
},
"export": {
"enum": [
"logic",
"ableton"
],
"type": "string",
"description": "Optionally also build a DAW session for this target."
},
"labels": {
"type": "object",
"description": "Optional identity CORRECTIONS {source: instrument}, same shape as instruments, e.g. {\"other\": \"trumpet\"} when the separation mislabels a stem. Only fixes what the stem is called (caption/timbre); nothing is re-played. Outcome in result.cover.stem_labels.",
"additionalProperties": {
"type": "string"
}
},
"lyrics": {
"type": "string",
"description": "Optional replacement lyrics."
},
"swap_cns": {
"type": "number",
"description": "Optional 0–1, only with instruments: how far the SWAPPED stems may depart from their source (overrides cover_noise_strength for them; server default 0.35). Lower = closer to the original timing/feel."
},
"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/\"). Provide this or audio_url."
},
"audio_url": {
"type": "string",
"description": "https URL of the audio, as an alternative to audio_key: a doseedo result URL exactly as a job returned it (a stem, a take, a bounce), or any public URL. The gateway fetches it (≤256 MB) into your account's ingest storage before the job starts. Pass audio_key OR audio_url."
},
"midi_only": {
"type": "boolean",
"description": "Optional: re-perform every regenerated stem from its transcribed MIDI with NO timbre from the recording (the stem's own sound is dropped). Stems with nothing to render are skipped (result.cover.midi_only.skipped)."
},
"style_key": {
"type": "string",
"description": "Optional ingest key (upload it first) of a reference MIX whose TIMBRE the regenerated stems take on (style transfer)."
},
"drum_split": {
"type": "boolean",
"description": "true = explode the covered drums into isolated kick/snare/hh/… stems, each generated from its own slice of the drum roll (result.drum_stems)."
},
"instruments": {
"type": "object",
"description": "Optional per-stem instrument SWAP map {source: target}, e.g. {\"piano\": \"electric_guitar\", \"sax\": \"violin\"}. Source = a stem (drums, bass, vocals, guitar, piano, other) or a detected instrument (sax, trumpet…); target = an instrument id from /api/instruments (an unknown target is refused up front).",
"additionalProperties": {
"type": "string"
}
},
"guitar_split": {
"type": "string",
"description": "Deal the guitar bucket into N players, each its own row/swap: \"2\"–\"4\", or \"auto\" (a one-vs-two probe decides). Outcome in result.cover.guitar_split."
},
"structure_key": {
"type": "string",
"description": "Optional ingest key of audio whose STRUCTURE codes replace the source's (the Cover page's \"Structure: custom\")."
},
"timbre_preset": {
"type": "string",
"description": "Optional named timbre preset — the fallback rung of the timbre ladder (stem latent > this > stock bank)."
},
"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."
},
"cover_noise_strength": {
"type": "number",
"description": "Optional 0–1 fidelity dial: higher departs further from the source."
}
},
"additionalProperties": false
}| fidelity | number | How much of the recording's own latents the take keeps, 0–0.6 (cover noise strength over the source). Default 0: structure from its FSQ codes only, the sound all the instrument's. |
| 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/"). Provide this, audio_url, or latent_key. |
| audio_url | string | https URL of the audio, as an alternative to audio_key: a doseedo result URL exactly as a job returned it (a stem, a take, a bounce), or any public URL. The gateway fetches it (≤256 MB) into your account's ingest storage before the job starts. Pass audio_key OR audio_url. |
| instrument* | string | REQUIRED. The instrument that plays it — call.instrument from doseedo_instruments (with its call.timbre_preset where it has one). |
| latent_key | string | Instead of the audio: the recording already VAE-encoded (ACE-Step 1.5 VAE, 48 kHz stereo → [T, 64] at 25 Hz, the latent mean) as a 64-channel 25 Hz float WAV `*.latent.wav`, uploaded like audio (POST /api/jobs/uploads). The server skips its encode. Dø Desktop sends this when encoding on the Mac lands sooner than uploading the audio. |
| timbre_preset | string | A named timbre preset (the catalog's preset ids, e.g. "cello:preset1"). Omit for the instrument 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. |
| duration_seconds* | number | REQUIRED. The recording's length in seconds (0.5–600): the take is this long. |
{
"type": "object",
"required": [
"instrument",
"duration_seconds"
],
"properties": {
"bpm": {
"type": "number",
"description": "The recording's tempo (a hint; default 120)."
},
"midi": {
"type": "boolean",
"description": "true = the server also transcribes the recording's notes into a roll that drives the MIDI hooks beside the FSQ codes — closer notes, a little slower (LatentPitch on audio; vaescriptor on a latent_key; a drum part — either route — gets its hits from vaescriptor_drums). recipe.midi_source names it. Default false: the codes alone."
},
"seed": {
"type": "number",
"description": "Optional random seed for reproducibility."
},
"takes": {
"type": "number",
"description": "How many takes, 1–4 (default: the server's best-of-N)."
},
"fidelity": {
"type": "number",
"description": "How much of the recording's own latents the take keeps, 0–0.6 (cover noise strength over the source). Default 0: structure from its FSQ codes only, the sound all the instrument's."
},
"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/\"). Provide this, audio_url, or latent_key."
},
"audio_url": {
"type": "string",
"description": "https URL of the audio, as an alternative to audio_key: a doseedo result URL exactly as a job returned it (a stem, a take, a bounce), or any public URL. The gateway fetches it (≤256 MB) into your account's ingest storage before the job starts. Pass audio_key OR audio_url."
},
"instrument": {
"type": "string",
"description": "REQUIRED. The instrument that plays it — call.instrument from doseedo_instruments (with its call.timbre_preset where it has one)."
},
"latent_key": {
"type": "string",
"description": "Instead of the audio: the recording already VAE-encoded (ACE-Step 1.5 VAE, 48 kHz stereo → [T, 64] at 25 Hz, the latent mean) as a 64-channel 25 Hz float WAV `*.latent.wav`, uploaded like audio (POST /api/jobs/uploads). The server skips its encode. Dø Desktop sends this when encoding on the Mac lands sooner than uploading the audio."
},
"timbre_preset": {
"type": "string",
"description": "A named timbre preset (the catalog's preset ids, e.g. \"cello:preset1\"). Omit for the instrument 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": "REQUIRED. The recording's length in seconds (0.5–600): the take is this long."
}
},
"additionalProperties": false
}| string |
| ISO-8601 date/time: only sessions created before this. |
{
"type": "object",
"properties": {
"ids": {
"type": "array",
"items": {
"type": "string"
},
"description": "Session ids to delete (up to 500), from doseedo_list_sessions."
},
"limit": {
"type": "number",
"description": "Cap on how many sessions one call may match (default and max 1000)."
},
"confirm": {
"type": "boolean",
"description": "false/omitted = dry run (nothing deleted). true = actually delete — only after the user saw the dry-run count and agreed."
},
"daw_kind": {
"type": "string",
"description": "Only sessions bound to this DAW, e.g. \"logic\", \"ableton\"."
},
"created_after": {
"type": "string",
"description": "ISO-8601 date/time: only sessions created after this."
},
"name_contains": {
"type": "string",
"description": "Only sessions whose name contains this text (case-insensitive)."
},
"created_before": {
"type": "string",
"description": "ISO-8601 date/time: only sessions created before this."
}
},
"additionalProperties": false
}{
"type": "object",
"required": [
"session_id",
"ops"
],
"properties": {
"ops": {
"type": "array",
"items": {
"type": "object",
"required": [
"op",
"args"
],
"properties": {
"op": {
"type": "string",
"description": "The op name, e.g. \"set_track_crop\"."
},
"args": {
"type": "object",
"description": "The op arguments (see the ops reference)."
}
},
"additionalProperties": false
},
"description": "The edits, e.g. [{\"op\":\"set_track_crop\",\"args\":{\"track_id\":\"t_…\",\"start_beats\":4,\"end_beats\":124,\"prev_start_beats\":24}}, {\"op\":\"set_channel_volume\",\"args\":{\"channel_id\":\"ch_…\",\"value\":0.6}}]. See doseedo_edit_ops_reference."
},
"atomic": {
"type": "boolean",
"description": "Default true: any rejected op means nothing is stored. Set false to store the valid ops and receive the rest as `rejected`."
},
"batch_key": {
"type": "string",
"description": "A stable id for THIS batch (e.g. \"drumkit-build-1\"). Same batch_key + same ops on a retry = the same client_op_ids = no duplicates. Always pass one for a build you might have to retry."
},
"session_id": {
"type": "string"
}
},
"additionalProperties": false
}| fill "context": how much of what is in the span its regeneration keeps, 0.01–0.9 (default 0.05: a variation; 0.45 ≈ the same playing again). |
| role | string | The part's role, when you know it (the planner hears it otherwise). |
| seed | number | Optional random seed (the same seed plans and renders the same). |
| takes | number | How many takes, 1–4 (default: the server's best-of-N). |
| 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/"). The part, with the gap in it. Provide this or audio_url. |
| audio_url | string | https URL of the audio, as an alternative to audio_key: a doseedo result URL exactly as a job returned it (a stem, a take, a bounce), or any public URL. The gateway fetches it (≤256 MB) into your account's ingest storage before the job starts. Pass audio_key OR audio_url. |
| exact_grid | boolean | true = the audio is cut from a DAW session, so bpm and bar_offset_seconds are its EXACT grid: the fill keeps it (default false: the planner fine-tunes the grid to the audio's own onsets — right for a stem whose tempo you only know roughly). |
| instrument | string | What plays the part (an id from doseedo_instruments). Optional — the take's own sound is kept either way; a written fill is played by it. |
| track_name | string | The part's track name in the DAW ("Drums", "Bass", "Strings") — the planner hears a role from the name first, then from the sound. |
| time_signature | string | The session's meter, e.g. "4/4" (default) or "3/4". |
| gap_end_seconds* | number | REQUIRED. Where the gap ends (and the take resumes), in seconds of the audio. |
| 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 | REQUIRED. The audio's length in seconds (1–600). |
| gap_start_seconds* | number | REQUIRED. Where the gap starts, in seconds of the audio. |
| bar_offset_seconds | number | Where a bar line falls in the audio (seconds; default 0 = the audio starts on a downbeat). Sending a span of a DAW track that starts mid-bar? Give the first downbeat's time in it. |
{
"type": "object",
"required": [
"duration_seconds",
"gap_start_seconds",
"gap_end_seconds",
"bpm"
],
"properties": {
"bpm": {
"type": "number",
"description": "REQUIRED. The session's tempo — the gap is filled on its bar grid."
},
"fill": {
"enum": [
"auto",
"context",
"loop",
"written"
],
"type": "string",
"description": "What fills the gap: \"context\" = the span played AGAIN from the take around it — no plan, no notes: a variation of what is there, in its own sound and level (INPAINTING a span that has audio — the right default there); \"loop\" = the take's own passes (a groove that keeps turning), \"written\" = a part written in its key and chords, \"auto\" (default) = the loop when the part has one, else written."
},
"keep": {
"type": "number",
"description": "fill \"context\": how much of what is in the span its regeneration keeps, 0.01–0.9 (default 0.05: a variation; 0.45 ≈ the same playing again)."
},
"role": {
"enum": [
"drums",
"perc",
"bass",
"harmony",
"melody"
],
"type": "string",
"description": "The part's role, when you know it (the planner hears it otherwise)."
},
"seed": {
"type": "number",
"description": "Optional random seed (the same seed plans and renders the same)."
},
"takes": {
"type": "number",
"description": "How many takes, 1–4 (default: the server's best-of-N)."
},
"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/\"). The part, with the gap in it. Provide this or audio_url."
},
"audio_url": {
"type": "string",
"description": "https URL of the audio, as an alternative to audio_key: a doseedo result URL exactly as a job returned it (a stem, a take, a bounce), or any public URL. The gateway fetches it (≤256 MB) into your account's ingest storage before the job starts. Pass audio_key OR audio_url."
},
"exact_grid": {
"type": "boolean",
"description": "true = the audio is cut from a DAW session, so bpm and bar_offset_seconds are its EXACT grid: the fill keeps it (default false: the planner fine-tunes the grid to the audio's own onsets — right for a stem whose tempo you only know roughly)."
},
"instrument": {
"type": "string",
"description": "What plays the part (an id from doseedo_instruments). Optional — the take's own sound is kept either way; a written fill is played by it."
},
"track_name": {
"type": "string",
"description": "The part's track name in the DAW (\"Drums\", \"Bass\", \"Strings\") — the planner hears a role from the name first, then from the sound."
},
"time_signature": {
"type": "string",
"description": "The session's meter, e.g. \"4/4\" (default) or \"3/4\"."
},
"gap_end_seconds": {
"type": "number",
"description": "REQUIRED. Where the gap ends (and the take resumes), in seconds of the audio."
},
"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": "REQUIRED. The audio's length in seconds (1–600)."
},
"gap_start_seconds": {
"type": "number",
"description": "REQUIRED. Where the gap starts, in seconds of the audio."
},
"bar_offset_seconds": {
"type": "number",
"description": "Where a bar line falls in the audio (seconds; default 0 = the audio starts on a downbeat). Sending a span of a DAW track that starts mid-bar? Give the first downbeat's time in it."
}
},
"additionalProperties": false
}| string |
| Optional meter HINT written into the caption, e.g. "4/4", "3/4". Not enforced. |
| 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 | Target length in seconds (e.g. 30–120). Omit for the model default. |
{
"type": "object",
"required": [
"prompt"
],
"properties": {
"bpm": {
"type": "number",
"description": "Optional tempo HINT in BPM, written into the caption (default 120). Not enforced — the output tempo can drift from it."
},
"seed": {
"type": "number",
"description": "Optional random seed for reproducibility."
},
"lyrics": {
"type": "string",
"description": "Optional lyrics to sing. Omit for instrumental."
},
"prompt": {
"type": "string",
"description": "Style/mood/instrumentation prompt, e.g. \"warm jazz trio, brushed drums, late-night ballad\"."
},
"time_signature": {
"type": "string",
"description": "Optional meter HINT written into the caption, e.g. \"4/4\", \"3/4\". Not enforced."
},
"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": "Target length in seconds (e.g. 30–120). Omit for the model default."
}
},
"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
}| project_key |
| string |
| CONTINUATION of a multipart upload: the key the first call returned. |
| content_type | string | MIME type: application/zip for zips (default), application/octet-stream for bare project files. |
| part_numbers | array | CONTINUATION: which part numbers (1-based) to sign now, ≤ 24 per call. |
{
"type": "object",
"properties": {
"filename": {
"type": "string",
"description": "File name including extension, e.g. \"Song Project.zip\", \"My Song.band.zip\", \"beat.flp\", \"song.cpr\", \"Mix.song\", \"set.dawproject\" or \"score.mxl\"."
},
"multipart": {
"type": "boolean",
"description": "Force a multipart upload regardless of size (resumable per part)."
},
"upload_id": {
"type": "string",
"description": "CONTINUATION: the upload_id the first call returned."
},
"size_bytes": {
"type": "number",
"description": "The file's size in bytes (stat it). Decides single PUT vs multipart and sizes the parts."
},
"project_key": {
"type": "string",
"description": "CONTINUATION of a multipart upload: the key the first call returned."
},
"content_type": {
"type": "string",
"description": "MIME type: application/zip for zips (default), application/octet-stream for bare project files."
},
"part_numbers": {
"type": "array",
"items": {
"type": "number"
},
"description": "CONTINUATION: which part numbers (1-based) to sign now, ≤ 24 per call."
}
},
"additionalProperties": false
}| include_params | boolean | Include plugin params (default true). false keeps param_count only. |
| include_automation | boolean | Include automation lanes with points (default true). false keeps a lane count per track. |
{
"type": "object",
"required": [
"session_id"
],
"properties": {
"tracks": {
"type": "array",
"items": {
"type": "string"
},
"description": "Only these tracks (track_id t_… or channel_id ch_…; a track name matches too). The rest of the session (tempo, markers, buses, sync) is always included."
},
"session_id": {
"type": "string",
"description": "From doseedo_list_sessions."
},
"include_notes": {
"type": "boolean",
"description": "Include MIDI notes. Default: true when the selected tracks hold ≤200 notes in all, else false (regions then carry note_count + notes_omitted:true)."
},
"include_params": {
"type": "boolean",
"description": "Include plugin params (default true). false keeps param_count only."
},
"include_automation": {
"type": "boolean",
"description": "Include automation lanes with points (default true). false keeps a lane count per track."
}
},
"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
}| 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). |
| 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). 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). |
| 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. |
| 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": {
"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"
}
},
"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). 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)."
},
"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."
},
"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
}| 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 kit of one-shots generated for drum_genre (the default for electronic / 808), "model" = the drum model (the default for every other kit). |
| 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 kit of one-shots generated for drum_genre (the default for electronic / 808), \"model\" = the drum model (the default for every other kit)."
},
"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
}| 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?}]}] — 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. |
| 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; overrides a file's own tempo."
},
"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."
},
"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 note velocities when they vary — soft notes darker, loud notes brighter, on every instrument but drums; off = one colour throughout; 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?}]}] — 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."
},
"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
}| boolean |
| true = also split the drum stem into isolated kick / snare / hi-hat / toms / ride / crash (+ perc) sub-stems (result.drum_substems). |
| session_id | string | Register the stems INTO this doseedo session (from doseedo_list_sessions) as audio tracks — result.session_tracks lists them. Needs parent_track_id. |
| stems_only | boolean | true = the stems and NOTHING derived from them (no MIDI, no lyrics, no latents) — the fastest, cheapest separation. Implies include_midi:false. |
| instruments | string | models=orchestra only: comma-separated extractor targets, e.g. "saxophone,trumpet,trombone". Available: drums, percussion, bass, double_bass, guitar, electric_guitar, acoustic_guitar, piano, organ, harp, brass, trumpet, trombone, french_horn, tuba, saxophone, clarinet, oboe, bassoon, flute, woodwind, strings, violin, viola, cello. Omit for the curated default set. |
| guitar_split | string | Deal the guitar stem into N players (same-instrument separation): "2"–"4", or "auto" (a one-vs-two probe decides; no split when it hears one). Outcome in result.guitar_split. |
| include_midi | boolean | Also transcribe each stem to MIDI (default true). |
| 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. |
| parent_track_id | string | With session_id: the t_… track the mix sits on; the stems are added as its children. |
{
"type": "object",
"properties": {
"export": {
"enum": [
"logic",
"ableton"
],
"type": "string",
"description": "Optionally also build a DAW session from the stems."
},
"models": {
"enum": [
"6stem",
"auto",
"orchestra",
"detect"
],
"type": "string",
"description": "Separation model set. Default 6stem (vocals/drums/bass/guitar/piano/other); auto/orchestra/detect for wider instrument sets."
},
"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/\"). Provide this or audio_url."
},
"audio_url": {
"type": "string",
"description": "https URL of the audio, as an alternative to audio_key: a doseedo result URL exactly as a job returned it (a stem, a take, a bounce), or any public URL. The gateway fetches it (≤256 MB) into your account's ingest storage before the job starts. Pass audio_key OR audio_url."
},
"drum_split": {
"type": "boolean",
"description": "true = also split the drum stem into isolated kick / snare / hi-hat / toms / ride / crash (+ perc) sub-stems (result.drum_substems)."
},
"session_id": {
"type": "string",
"description": "Register the stems INTO this doseedo session (from doseedo_list_sessions) as audio tracks — result.session_tracks lists them. Needs parent_track_id."
},
"stems_only": {
"type": "boolean",
"description": "true = the stems and NOTHING derived from them (no MIDI, no lyrics, no latents) — the fastest, cheapest separation. Implies include_midi:false."
},
"instruments": {
"type": "string",
"description": "models=orchestra only: comma-separated extractor targets, e.g. \"saxophone,trumpet,trombone\". Available: drums, percussion, bass, double_bass, guitar, electric_guitar, acoustic_guitar, piano, organ, harp, brass, trumpet, trombone, french_horn, tuba, saxophone, clarinet, oboe, bassoon, flute, woodwind, strings, violin, viola, cello. Omit for the curated default set."
},
"guitar_split": {
"type": "string",
"description": "Deal the guitar stem into N players (same-instrument separation): \"2\"–\"4\", or \"auto\" (a one-vs-two probe decides; no split when it hears one). Outcome in result.guitar_split."
},
"include_midi": {
"type": "boolean",
"description": "Also transcribe each stem to MIDI (default true)."
},
"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."
},
"parent_track_id": {
"type": "string",
"description": "With session_id: the t_… track the mix sits on; the stems are added as its children."
}
},
"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
}| 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": {
"type": "object",
"properties": {
"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": {
"enum": [
"downbeat",
"beat"
],
"type": "string",
"description": "Land hits on bar lines (default) or on any beat."
},
"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
}| With tempo_bpm: also return the harmony_strikes attack grid. |
| register | string | Optional register hint for the instrument (e.g. "soprano", "tenor", "bass"). |
| 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/"). Provide this or audio_url. |
| audio_url | string | https URL of the audio to transcribe (alternative to audio_key): any public URL, or a doseedo result URL exactly as a job returned it — no key needed. |
| polyphony | string | Optional: "solo" (monophonic line), "poly", or "section" (a horn section — see roster/chairs). |
| tempo_bpm | number | Optional known tempo — enables beat-aligned note times. |
| instrument | string | Optional instrument hint, e.g. "piano", "sax", "vocals", "bass". |
| beats_per_bar | number | With tempo_bpm: beats per bar for the beat-domain times (default 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": {
"want": {
"enum": [
"notes",
"f0",
"notes,f0"
],
"type": "string",
"description": "What to return: \"notes\" (default), \"f0\" (the continuous pitch contour — frame-rate Hz values, for glides/vibrato/intonation), or both."
},
"chairs": {
"type": "string",
"description": "polyphony=\"section\": register codes per chair, as an alternative to roster."
},
"family": {
"type": "string",
"description": "Optional instrument family (e.g. \"brass\", \"reeds\", \"strings\") when the exact instrument is unknown."
},
"roster": {
"type": "string",
"description": "polyphony=\"section\": the chairs on the stem, e.g. \"trumpet,trumpet,trombone,tenor_sax\". Omit for the family default."
},
"backend": {
"type": "string",
"description": "Advanced: force a transcription backend. Omit — the server routes by instrument."
},
"strikes": {
"type": "boolean",
"description": "With tempo_bpm: also return the harmony_strikes attack grid."
},
"register": {
"type": "string",
"description": "Optional register hint for the instrument (e.g. \"soprano\", \"tenor\", \"bass\")."
},
"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/\"). Provide this or audio_url."
},
"audio_url": {
"type": "string",
"description": "https URL of the audio to transcribe (alternative to audio_key): any public URL, or a doseedo result URL exactly as a job returned it — no key needed."
},
"polyphony": {
"type": "string",
"description": "Optional: \"solo\" (monophonic line), \"poly\", or \"section\" (a horn section — see roster/chairs)."
},
"tempo_bpm": {
"type": "number",
"description": "Optional known tempo — enables beat-aligned note times."
},
"instrument": {
"type": "string",
"description": "Optional instrument hint, e.g. \"piano\", \"sax\", \"vocals\", \"bass\"."
},
"beats_per_bar": {
"type": "number",
"description": "With tempo_bpm: beats per bar for the beat-domain times (default 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
}