# Beatra Skill + MCP — Audio processing, voice isolation & stems

> Isolate clean vocals from noise and music, separate songs into stems, or trim, loop, fade, normalize loudness, and convert audio.
> Self-contained workflow guide for AI agents.
> Human-readable page: https://docs.beatra.ai/en/docs/capabilities/speech/audio-processing

- Primary surface: the Universal Beatra Skill with authenticated MCP.
- Install or reconnect: https://beatra.ai/install.md
- MCP endpoint: `https://mcp.beatra.ai/mcp`
- Billable action: `beatra.audio.process`
- Dynamic model facts: call `beatra.models.list` with `capability: "audio_process"` only when model constraints, controls, or prices matter.
- Interaction model: create one opaque `client_request_id`, submit the finalized arguments exactly once, then poll the returned `task_id` with `beatra.tasks.get` until terminal.
- Local media: call `beatra.assets.upload`, perform the returned HTTPS PUT exactly, and use the artifact ID from the PUT response.

REST/OpenAPI is the fallback protocol path, not the primary agent packaging.

---

Isolate clean speech or singing vocals from noisy recordings, split songs into
stems, or apply deterministic audio utilities — trimming, seamless looping,
fades, EBU R128 loudness normalization, and format conversion.

## Primary agent path

Use the Universal Skill with the MCP tool `beatra.audio.process`. One tool
covers all three capability families via the `operation` discriminator, and
every call returns an asynchronous billable task:

| `operation` | Capability | Model | Symmetrical REST endpoint |
| --- | --- | --- | --- |
| `isolate_voice` | `audio_voice_isolation` | `elevenlabs-audio-isolation` | `POST /v1/audio/isolation` |
| `separate_stems` | `audio_stem_separation` | `beatra-stems-v1` | `POST /v1/audio/stems` |
| `trim`, `loop`, `fade`, `normalize_loudness`, `convert_format` | `audio_process` | `beatra-audio-v1` | `POST /v1/audio/process` |

1. Upload local audio with `beatra.assets.upload` and pass its `artifact_id` as
   `source` (or `audio`, accepted interchangeably across MCP `beatra.audio.process`
   and REST; an `https_url` is also accepted). Tokens authorized with either
   `speech:generate` or `music:generate` can invoke `beatra.audio.process`.
2. Call `beatra.models.list` with the matching `capability` when limits,
   formats, or live prices matter.
3. Create one opaque `client_request_id`, submit once, and poll
   `beatra.tasks.get` until terminal.

## Voice isolation

`operation: "isolate_voice"` (`elevenlabs-audio-isolation`, REST
`POST /v1/audio/isolation`) extracts clean speech or singing vocals while
removing background music, room reverb, wind, traffic, and crowd noise. Use it
to clean noisy field recordings before
[voice clone](https://docs.beatra.ai/en/docs/capabilities/speech/voice-clone),
[speech to text](https://docs.beatra.ai/en/docs/capabilities/speech/speech-to-text), or
[speech to speech](https://docs.beatra.ai/en/docs/capabilities/speech/speech-to-speech).

```json
{
  "operation": "isolate_voice",
  "source": { "type": "artifact", "artifact_id": "artifact_01JX..." },
  "format": "wav",
  "client_request_id": "isolate-opaque-1"
}
```

- **Input limits**: duration must be **`4.6` seconds to `300.0` seconds (`5 minutes`)**,
  and file size at most `100 MB`. Clips shorter than `4.6` seconds or longer than
  `300.0` seconds are rejected before billing with `422 invalid_request`
  (`details.reason: "audio_too_short"` or `"audio_too_long"`, zero credit charge).
  Both MCP `beatra.audio.process` and REST `POST /v1/audio/isolation` accept either
  `source` or `audio` for the input media reference (and normalize the legacy model
  alias `"beatra-voice-isolate-v1"` to `"elevenlabs-audio-isolation"`).
- **Optional output formatting**: `isolate_voice` accepts only `format` (`"wav"`
  default, `"mp3"`, `"ogg"`, `"flac"`, `"m4a"`, or `"ulaw_8k_wav"`), `sample_rate`
  (`8000`, `16000`, `22050`, `24000`, `32000`, `44100`, `48000` Hz),
  `bitrate_kbps` (`64`, `128`, `192`, `256`, `320` for lossy `"mp3"`, `"ogg"`,
  `"m4a"`, with `"m4a"` up to `256`), and `channels` (`1` or `2`). Do not pass
  `fade_in_ms`, `fade_out_ms`, `loudness_lufs`, or `true_peak_db` on
  `isolate_voice` — apply those afterward with the deterministic audio utilities
  below.
- **Cost & output**: prepaid by **started input minute** at `721 credits` per
  started minute (`<= 60s` = `721 credits`, `5 min` = `3,605 credits`). Returns
  `outputs: [{"role": "voice", ...}]` containing pure isolated vocals without
  accompaniment stems.

## Stem separation

`operation: "separate_stems"` (`beatra-stems-v1`, REST `POST /v1/audio/stems`)
splits a mixed music track (up to `600` seconds / `10 minutes`, `<= 100 MB`)
into individual instrument and vocal stems.

```json
{
  "operation": "separate_stems",
  "source": { "type": "artifact", "artifact_id": "artifact_01JX..." },
  "mode": "two_stem",
  "client_request_id": "stems-opaque-1"
}
```

- `mode: "two_stem"` (default, `180 credits` per task): returns `vocals` and
  `instrumental` (`outputs[].role`: `"vocals"`, `"instrumental"`).
- `mode: "multi_stem"` (`360 credits` per task): splits into 6 stems (`vocals`,
  `drums`, `bass`, `guitar`, `piano`, `other`, returned as `outputs[].role`:
  `"stem:vocals"`, `"stem:drums"`, `"stem:bass"`, `"stem:guitar"`, `"stem:piano"`,
  `"stem:other"`).
- Output format is determined by the stem separation model; `separate_stems` does
  not accept `format` or local finishing parameters.

## Deterministic audio utilities

`beatra-audio-v1` (REST `POST /v1/audio/process`) performs deterministic audio
post-processing on inputs up to `3,600` seconds (`60 minutes`, `<= 300 MB`) at
a flat **`60 credits` per task**:

- `trim`: cut a segment using `start_ms` (`>= 0`, default `0`) plus **exactly
  one** of `end_ms` (`> start_ms`) or `target_duration_ms`.
- `loop`: repeat the clip or a sub-range (`loop_start_ms` default `0`,
  `loop_end_ms`; loop window at least `4,000` ms) using **exactly one** of
  `target_duration_ms` (`1,000`–`3,600,000` ms) or `loop_count` (`2`–`100`),
  with `crossfade_ms` (`50`–`3,000` ms, default `500` ms) and `end_with_fade`
  (boolean, default `true`).
- `fade`: apply `fade_in_ms` and/or `fade_out_ms` (`0`–`30,000` ms, at least one
  provided) using `fade_curve` (`"tri"` default, `"exp"`, `"log"`, or `"qsin"`).
- `normalize_loudness`: two-pass EBU R128 loudness normalization to
  `loudness_lufs` (`-30.0` to `-9.0` LUFS, default `-14.0`) and `true_peak_db`
  (`-9.0` to `0.0` dBTP, default `-1.0`).
- `convert_format`: transcode or resample to `format` (required: `"mp3"`,
  `"wav"`, `"ogg"`, `"flac"`, `"m4a"`, or `"ulaw_8k_wav"` for 8 kHz mono
  telephony), with optional `sample_rate`, `bitrate_kbps`, and `channels` (`1`
  or `2`).
- Every deterministic operation above can also include optional finishing fields
  (`fade_in_ms`, `fade_out_ms`, `fade_curve`, `loudness_lufs`, `true_peak_db`,
  `format`, `sample_rate`, `bitrate_kbps`, `channels`) in the same task.

## Result

Every operation returns `"type": "audio_process"`, `"operation"`, and
`"outputs"` (`separate_stems` adds `"mode"`, and deterministic utilities add
`"metrics"` and `"steps"`). Each `outputs[]` item carries `role` (`"voice"` for
`isolate_voice`, `"vocals"` / `"instrumental"` for `two_stem`, `"stem:<kind>"`
for `multi_stem`, and `"main"` for deterministic utilities), `artifact_id`, CDN
`url`, `mime_type`, and `duration_seconds`; `"role": "main"` also includes
measured `loudness_lufs` and `true_peak_db`:

```json
{
  "type": "audio_process",
  "operation": "isolate_voice",
  "outputs": [
    {
      "role": "voice",
      "artifact_id": "artifact_01JZ...",
      "url": "https://cdn.beatra.ai/tenants/.../voice.wav",
      "mime_type": "audio/wav",
      "duration_seconds": 18.4
    }
  ]
}
```

## Task status and recovery

`queued` and `running` are not failures. Keep polling the same `task_id`; never
submit a replacement because work is still running. On a lost create response,
retry the identical arguments with the same `client_request_id`. If any input
changes, use a new ID. Failed tasks automatically refund the reserved credits.
Artifact URLs are CDN addresses — copy them to your own storage promptly.

## REST API

Direct protocol integrations may call `POST /v1/audio/isolation`,
`POST /v1/audio/stems`, or `POST /v1/audio/process` with a stable
`Idempotency-Key` header, plus the shared task endpoints. Follow the generated
[API reference](https://docs.beatra.ai/en/docs/api-reference). Skill + MCP is the recommended
integration; use REST for custom, non-agent applications.

---

## Appendix: shared Skill + MCP contract

### Retry identity

One logical generation has one `client_request_id`. If the create response is
lost, retry the exact same arguments with that ID. If any prompt, media, model,
or output control changes, use a new ID. Never create another paid task merely
because the first task is `queued` or `running`.

### Polling and billing truth

Poll with `beatra.tasks.get` using bounded backoff. Stop at `succeeded`,
`failed`, or `canceled`. Only the task response is authoritative for the
resolved model, artifacts, charged credits, and refunded credits.

### Recovery

Preserve structured Beatra error codes. Reconnect on authentication failure;
stop and request a balance action on insufficient balance; refresh current
constraints with `beatra.models.list` after model validation; request a new
upload grant after expiration or MIME/length mismatch. Changed generation
arguments always require a new `client_request_id`.
