Music Room
codai Studio Music Room — a team of role agents writes, plays, sings and mixes a song that sounds played by people, with three approval gates, a monthly plan quota and an editable audio creative.
The Music Room is a team of role agents that produces one song together: a producer plans it, a composer and a lyricist write it, an arranger builds the form, session players write their parts on real sampled instruments, a vocal producer adds the vocals, mix and mastering engineers finish it, a critic listens, and a rights check compares the melody against a reference corpus. The result is a normal audio creative: every note any agent wrote is an editable op with undo, and you can take over in the multitrack editor at any time.
| Method | Path | Result |
|---|---|---|
POST | /v1/studio/music-room | Start a song (202, Idempotency-Key honoured) |
GET | /v1/studio/music-room | Your songs, newest first (?limit 1–100, ?before ISO date) |
GET | /v1/studio/music-room/quota | { plan, included, used, remaining, period_end } |
GET | /v1/studio/music-room/{id} | The song; reading it advances the workflow |
POST | /v1/studio/music-room/{id}/choose | Answer the open gate |
POST | /v1/studio/music-room/{id}/direct | Talk to one player (202, Idempotency-Key honoured) |
How a song is made
brief ─► plan ─► [gate 1: choose a plan variant] ─► compose ─► lyrics ─► arrange ─► parts
─► humanise ─► demo render ─► [gate 2: approve the demo or direct a player]
─► vocals ─► mix ─► master ─► critique (at most 2 rounds of fixes) ─► [gate 3: approve the final mix] ─► readyAgents never write audio directly. They write symbolic parts on a beat grid; deterministic code humanises timing and dynamics per player; codai-studio-media renders the stems with sampled instruments; ACE-Step sings the vocals over a rendered guide, checked by speech recognition and repaired syllable by syllable. The critic scores groove, harmony, melody, arrangement, mix, humanness and genre fit and sends targeted fixes back to the players at most twice. robot_score (0 human … 1 robotic) is a symbolic measure of the usual "AI tells", and copy_risk reports melody similarity to known tunes.
Starting a song
curl https://ai.codai.ro/v1/studio/music-room \
-H "Authorization: Bearer $CODAI_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: song-42" \
-d '{
"brief": "a cheerful wedding song about two friends who finally meet again",
"language": "ro",
"genre": "hora",
"duration_seconds": 150,
"vocals": true
}'| Field | Default | Notes |
|---|---|---|
brief | required | 10–2000 characters: occasion, mood, story, audience; no artist names |
language | ro | ro or en — the language of the lyrics |
genre | the producer picks | A genre pack id: pop, jingle, rock, indie, hiphop, trap, cinematic, lofi, ballad, hora, sarba, doina, colind, lautareasca, manele, pop_folk_ro, fanfara, cocek, kolo… |
duration_seconds | — | 6–240 (four minutes at most) |
vocals | true | false for an instrumental |
timbre | chosen for the genre | A vocal timbre id |
voice_passport_id | — | Sing with your own voice (beta): one of your custom voices with an active singing consent. See Voice passport |
instruments | — | Instrument ids the band must use (drums.kit_rock, balkan.accordion…) |
auto | false | Skip the three gates (plan variant 0, demo and final approved) |
budget_micro_usd | 10000000 | Cap for one song beyond the quota, at most 20000000 ($20) |
title | — | Up to 200 characters |
The answer is 202 with the song (object: "studio.music_room"). Poll GET /v1/studio/music-room/{id} every 20–60 seconds; the background sweeper also moves the song forward when nobody polls.
Voice passport (beta)
Your own custom voice can sing your songs once you give a separate, revocable singing consent for it: in the hub voice card "Singing (beta)" you read the singing statement aloud and record a short sung sample (the same in-app liveness check as when the voice was created), which calls POST /v1/studio/voices/{id}/singing-consent. DELETE /v1/studio/voices/{id}/singing-consent revokes only the singing purpose; deleting the voice revokes everything. The vocal producer passes your sung sample to ACE-Step as a timbre reference, so the result approximates your timbre; it is not a faithful clone. Available only where voice cloning is enabled for your account.
warnings tells you what happened: voice_passport_beta (sung with your voice), voice_passport_needs_singing_consent (no active singing consent, or revoked during the song), voice_passport_not_found (not one of your active voices), voice_passport_unavailable (voice cloning not enabled for your account, or the voice is paused), voice_passport_lyrics_refused (the lyrics failed the voice-safety check). In every case except the first the song is still made with timbre.
The three gates
When the song reaches a gate it answers status: "waiting" with gate.kind set, and nothing runs until you answer:
| Gate | What you see | Answer |
|---|---|---|
plan | Up to 3 plan variants in gate.variants: title, genre, BPM, meter, mode, sections and instrumentation, each with the producer's rationale | {"gate": "plan", "variant": 0} (0–2) |
demo | The arranged demo in demo_asset_id and the team with each player's rationale | {"gate": "demo", "approve": true} |
final | The final mix in final_asset_id, stems in stems_asset_ids, the critic's last review | {"gate": "final", "approve": true} |
curl https://ai.codai.ro/v1/studio/music-room/$ID/choose \
-H "Authorization: Bearer $CODAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"gate": "plan", "variant": 1}'At the demo or final gate you can also direct one player, like a producer in the studio. The player re-plays its part (one section or the whole song) and the demo is re-rendered:
curl https://ai.codai.ro/v1/studio/music-room/$ID/direct \
-H "Authorization: Bearer $CODAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"role": "drums", "section_id": "chorus1", "direction": "lay back on the chorus, fewer fills, more ghost notes"}'role is one of producer, composer, lyricist, arranger, drums, bass, guitar, keys, strings, brass, winds, balkan_lead, balkan_rhythm, percussion, synth, vocal_producer, sound_designer, mix_engineer, mastering_engineer, critic, rights; direction is at most 500 characters. A gate left unanswered for 7 days fails the song (error: "gate_expired") and releases any hold.
Quota and budget
Songs are counted per calendar month (UTC): every Music Room song that reached ready or is still running.
| Plan | Songs included per month |
|---|---|
| Pro | 4 |
| Builder | 12 |
| Max | 30 |
| Team | 10 per seat |
| Free, Lite, Student, BYOK | 1 |
Within the quota a song is free for you (quota.within: true). Beyond it every step is quoted, held on your wallet and settled with the real cost — 402 insufficient_funds when the wallet is short. budget_micro_usd caps one song either way; spent_micro_usd shows what it cost so far. Agent turns are token-metered under the public model codai (usage model codai::music-<role>, prompt caching on). Check what is left with GET /v1/studio/music-room/quota.
Errors
| Status | Code | When |
|---|---|---|
400 | invalid_request | The body does not match the schema |
402 | insufficient_funds | Beyond the quota and the wallet cannot cover the next step |
404 | not_found | Unknown id, or another account's song |
409 | not_at_gate | choose or direct while the song is not waiting at that gate |
429 | too_many_music_rooms | Two songs are already running for you |
503 | media_ops_unavailable | The music renderer is not configured on this gateway |
Credits
credits lists the lines to publish with the song: CC-BY sample libraries used by the players and "Built with Llama" when a symbolic helper ran. Every output carries AI marking like the rest of codai Studio.
SDKs
const room = await codai.studio.musicRoom.create(
{ brief: 'a cheerful wedding song about two old friends', language: 'ro', genre: 'hora' },
{ idempotencyKey: 'song-42' },
);
let r = await codai.studio.musicRoom.wait(room.id, { untilGate: true });
if (r.gate?.kind === 'plan') r = await codai.studio.musicRoom.choose(r.id, { gate: 'plan', variant: 0 });
await codai.studio.musicRoom.direct(r.id, { role: 'drums', direction: 'fewer fills' });
const { remaining } = await codai.studio.musicRoom.quota();room = client.studio.music_room.create("a cheerful wedding song about two old friends", language="ro", genre="hora")
r = client.studio.music_room.wait(room["id"], until_gate=True)
if r["gate"] and r["gate"]["kind"] == "plan":
r = client.studio.music_room.choose(r["id"], "plan", variant=0)
print(client.studio.music_room.quota()["remaining"])TypeScript: studio.musicRoom.create / get / list / choose / direct / quota / wait (wait(id, { untilGate, intervalMs, timeoutMs, signal })). Python: studio.music_room.create / get / list / choose / direct / quota / wait (wait(id, until_gate=, interval=, timeout=)).
Agent tools
The codai desktop, phone and VS Code agents and the MCP Studio toolset use the same workflow through four tools: music_room_create (start a song; auto only when you asked to just make it), music_room_status (read and advance it), music_room_choose (answer a gate with your decision) and music_room_direct (talk to one player).
Lyrics and live jam
codai Studio songwriting tools — write lyrics with syllable and rhyme checks, align them to a vocal clip for karaoke timing and LRC, and jam live with generated music over a WebSocket.
Batches
Fill a template or a creative from a CSV file or a sheet — one creative per row, with optional per-row language and render, status export and a ZIP of the videos.