Media operations
codai Studio media operations — remove backgrounds, upscale, inpaint, separate stems, denoise, master, convert audio to MIDI and generate music or sound effects from your assets.
Media operations turn one Studio asset into new ones: cut out a subject, upscale a still, repaint a masked area, split a song into stems, clean up a voice, master a mix, convert a melody to MIDI or generate a song or a sound effect. Every op takes asset ids and strict per-op parameters, and every output is stored as a new asset in your library. The public model id is codai-studio-media.
| Method | Path | Result |
|---|---|---|
GET | /v1/studio/media-ops | The op catalogue: engine, mode, inputs, available, a list quote (free) |
POST | /v1/studio/media-ops/{op}/quote | The exact price of a request; nothing is held or billed |
POST | /v1/studio/media-ops/{op} | 200 with the outputs (sync ops) or 202 with a job (async ops) |
GET | /v1/studio/media-ops/jobs/{id} | An async job; a finished one is settled when you read it |
{op} is the dotted op id, for example image.remove_background or audio.separate_stems.
The ops
| Op | Inputs | Output | Mode | Engine |
|---|---|---|---|---|
image.remove_background | 1 image | Cut-out PNG / WebP with transparency | sync | BiRefNet |
image.upscale | 1 image | Image ×2 or ×4 (at most 64 MP) | sync | Real-ESRGAN x4plus |
image.inpaint | image + PNG mask | The image with the white mask area repainted from prompt | sync | Gemini image edit |
image.erase | image + PNG mask | The image with the masked object removed | sync | Gemini image edit |
image.outpaint | 1 image | The scene extended to a new aspect_ratio | sync | Gemini image edit |
audio.separate_stems | 1 audio | 4 stems (vocals, drums, bass, other) or 2 (vocals, accompaniment) | async | Demucs (htdemucs) |
audio.denoise | 1 audio | The same audio with background noise removed | async | DeepFilterNet 3 |
audio.to_midi | 1 audio | A Standard MIDI File (kind: "midi") | async | Basic Pitch |
audio.master | 1 audio | A loudness-normalised master (WAV or MP3) | async | ffmpeg loudnorm, 2 passes + limiter |
audio.analyze | 1 audio | JSON only: BPM, key, loudness, peak | sync | librosa + pyloudnorm |
music.generate_ace | 0–1 audio | A song from a style prompt and optional lyrics | async | ACE-Step 1.5 |
music.repaint | 1 audio | The song with one section replaced | async | ACE-Step 1.5 |
music.extend | 1 audio | The song continued by extend_seconds | async | ACE-Step 1.5 |
music.cover | 1 audio | Your own song restyled | async | ACE-Step 1.5 |
sfx.generate | none | A sound effect from a prompt | async | ACE-Step 1.5 |
Image ops accept image, upload and frame assets (PNG, JPEG or WebP); audio ops accept music, speech, sfx and upload assets. For image.inpaint and image.erase the second asset is a black-and-white PNG mask of the first: white is edited, black is kept. The mask is sent to the model as a reference image, so edits follow it closely but not pixel-exactly (the catalogue entry carries a note saying so).
Parameters
Parameters are validated strictly per op — an unknown key is a 400.
| Op | Params (defaults) |
|---|---|
image.remove_background | format: png | webp (png) |
image.upscale | scale: 2 | 4 (4) |
image.inpaint | prompt (required), model, image_size: 1K | 2K | 4K |
image.erase | prompt (optional hint), model, image_size |
image.outpaint | aspect_ratio (required: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9, 9:21), prompt, model, image_size |
audio.separate_stems | stems: 2 | 4 (4) |
audio.denoise | strength: 0–1 (1) |
audio.to_midi | onset_threshold: 0.05–0.95 (0.5), min_note_ms: 10–1000 (58) |
audio.master | target_lufs: -14 | -16 | -23 (-14), true_peak_db: −3…−0.1 (-1), format: wav | mp3 (wav) |
audio.analyze | none |
music.generate_ace | prompt (required, ≤ 1000 chars), lyrics (≤ 4000), duration_seconds: 10–240 (60), bpm: 40–220, key, language (en, ro, es, fr, de, it, pt, ja, ko, zh), seed |
music.repaint | prompt, lyrics, start_seconds, end_seconds (after the start, inside the song), seed |
music.extend | prompt, lyrics, extend_seconds: 5–120, seed |
music.cover | prompt, lyrics, strength: 0–1 (0.8), seed |
sfx.generate | prompt (required), duration_seconds: 1–30 (5), seed |
Running an op
curl https://ai.codai.ro/v1/studio/media-ops/image.remove_background \
-H "Authorization: Bearer $CODAI_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: cutout-42" \
-d '{ "asset_ids": ["3f2b8c1e-0000-4000-8000-000000000001"], "params": { "format": "png" } }'A sync op answers 200:
{
"object": "media_op.result",
"op": "image.remove_background",
"status": "ready",
"outputs": [{ "asset_id": "…", "kind": "image", "mime_type": "image/png", "url": "https://…" }],
"analysis": null,
"cost_micro_usd": 2640
}audio.analyze stores nothing and returns analysis: { duration_seconds, bpm, key, key_confidence, integrated_lufs, sample_peak_dbfs }.
Async jobs
Stems, denoise, MIDI, mastering and every music or sound-effect op run as jobs. The run answers 202 with { "object": "media_op.job", "id", "status": "pending", … }. Poll GET /v1/studio/media-ops/jobs/{id} until status is ready (with outputs, one asset per stem for separation) or failed (with error: timeout, input_refused, dispatch_failed, store_failed or an engine message). A job that has not produced a result after 20 minutes fails with timeout. Reading a finished job stores its outputs and bills it once; the background sweeper does the same when nobody polls. At most 3 async jobs run per account at once — a fourth answers 429 with Retry-After.
Pricing
Every op has a quote — the price ceiling — that is held on your wallet before anything runs; when the wallet cannot cover it the answer is 402 insufficient_funds and nothing starts. After the op the measured cost is billed once and the rest of the hold is released; a failed op releases the whole hold.
- GPU / CPU ops (everything except the Gemini image edits) are priced by instance time on the codai Studio media service: $0.95 per hour, at least 5 seconds per op, estimated from the input length (for example
audio.separate_stems≈ 15 s + 0.5 s per input second). You pay the seconds the engine reports, never more than the quote. image.inpaint/erase/outpaintare billed like an image edit of the chosenmodelandimage_size.
GET /v1/studio/media-ops lists a reference quote per op (default params, 60 s of audio or a 1024×1024 image) as quote_micro_usd and the wallet amount as quote_micro_eur; POST …/{op}/quote prices your real request with the same validation as the run.
Errors
| Status | When |
|---|---|
400 | Bad body or params, the wrong number or kind of assets, a mask that is not PNG, an upscale over 64 MP, end_seconds before start_seconds |
402 insufficient_funds | The quote does not fit in your wallet |
404 | Unknown op id, or an asset that does not exist, is not ready or is not yours |
429 | Three async jobs already running, or your key's rate limit |
502 | The engine failed |
503 media_ops_unavailable | The op's lane is not configured on this gateway (available: false in the catalogue); nothing is held or billed |
503 assets_unavailable | Asset storage is not configured |
AI marking and lineage
Every output is marked as AI-generated before it is stored: C2PA / XMP on images, RIFF INFO or ID3 tags on audio, plus the ai-generated object metadata. Each output also records where it came from — parent_asset_id (the first input), op and op_inputs (asset_ids + the validated params) — so you can always trace a stem, a master or a cut-out back to its source. Generate covers only from music you own or have the rights to.
SDKs
const job = await codai.mediaOps.run('audio.separate_stems', { assetIds: [songId], params: { stems: 4 } });
const done = await codai.mediaOps.wait(job.id); // or mediaOps.runAndWait(...)done = client.media_ops.run_and_wait("audio.master", [mix_id], {"target_lufs": -14})TypeScript: mediaOps.list / quote / run / job / wait / runAndWait. Python: media_ops.list / quote / run / job / wait / run_and_wait. Songs and podcasts built from these outputs are edited as audio creatives and rendered to a mastered mix with creatives.renderAudio; lyrics come from the lyrics writer.
Audio creatives
Songs and podcasts as editable codai Studio creatives — a multitrack timeline with sections, tracks, clips, MIDI, effects, a master bus and timed lyrics, edited with small ops.
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.