Tutorial · Python · ~10 min

How to Turn a Stereo Track into an Immersive Atmos Mix in Python

No matrix upmixing tricks. Separate the sources, mix them into space, render an object-based master — with two mlslabs APIs and one pipeline.

Source SeparationAI MixingSpatial Audio

Why this pipeline

Matrix upmixing is fake surround. This isn't.

Traditional stereo-to-surround tools use matrix upmixing: they spread the same two channels around the room and call it immersive. The AI route is different — you separate the actual sources (vocals, drums, bass, guitars), place each one independently in space, and render a 7.1.2 or object-based master. Sources stay where you put them; the mix is genuinely three-dimensional.

Step 1

Split the stereo mix into stems

Submit the stereo file to the Source Separation API. We return clean stems with independent control — the raw material for spatial placement.

Python
import requests

API = "https://api.mlslabs.io/v1"
KEY = "YOUR_API_KEY"

split = requests.post(
    API + "/source-separation/jobs",
    headers={"X-API-Key": KEY},
    json={
        "input": "s3://bucket/mix-stereo.wav",
        "output": "s3://bucket/stems/",
        "stems": ["vocals", "drums", "bass", "guitar"],
    },
).json()
split_id = split["job_id"]
print(split_id)

Postman: Source Separation → 4. Tutorials → stereo-to-atmos (01 Split stems)

Step 2

Wait for the stems

Jobs run asynchronously. Poll until status == "done" — or register a webhook and skip the loop entirely.

Python
import time

while True:
    job = requests.get(
        API + "/source-separation/jobs/" + split_id,
        headers={"X-API-Key": KEY},
    ).json()
    if job["status"] == "done":
        print(job["stems"])
        break
    if job["status"] == "failed":
        raise SystemExit("job failed (credits auto-refunded)")
    time.sleep(2)

Step 3

Mix the stems into space

Send the separated stems to the AI Mixing API with roles and priorities. The engine balances levels, resolves frequency masking, and renders an object-based spatial master.

Python
mix = requests.post(
    API + "/ai-mixing/jobs",
    headers={"X-API-Key": KEY},
    json={
        "stems": [
            {"url": job["stems"]["vocals"], "role": "vocals", "priority": 1},
            {"url": job["stems"]["drums"],  "role": "drums",  "priority": 2},
            {"url": job["stems"]["bass"],   "role": "bass",   "priority": 3},
            {"url": job["stems"]["guitar"], "role": "guitar", "priority": 4},
        ],
        "preset": "modern_pop",
        "output": {"format": "7.1.2", "objects": True},
    },
).json()
print(mix["job_id"])

Postman: AI Mixing → 4. Tutorials → stereo-to-atmos (02 Mix to spatial)

Step 4

Deliver & verify

Download the ADM BWF master and verify channels with ffprobe. Every stem has its own position; objects carry position metadata for Atmos-style rendering on playback.

Bash
# once the AI Mixing job reports "done":
curl -L -o atmos-master.adm <mix_output_url>

# verify channel layout
ffprobe -show_streams atmos-master.adm | grep channel_layout
# => 7.1.2, object-based metadata attached
Licensing note: ADM BWF is an open format and free to distribute. Atmos-branded encoded output (DD+JOC) requires a Dolby license — contact us before shipping that path.