Executando verificação de segurança...
-3

Como baixar e separar stems de músicas do SoundCloud com Python (2026)

O SoundCloud tem mais de 300 milhões de faixas. Se você quer separar vocais, instrumentais, bateria ou baixo de qualquer uma delas com Python, esse guia cobre o processo completo: download com yt-dlp e separação de stems via API.

O que você vai aprender

  • ✅ Como baixar áudio do SoundCloud com yt-dlp em um comando Python
  • ✅ Como enviar o arquivo para a API de separação de stems e obter job_id
  • ✅ Como implementar o loop de polling assíncrono até os stems ficarem prontos
  • ✅ Como baixar vocais, bateria, baixo e instrumental como arquivos WAV separados
  • ✅ Como montar um pipeline batch para processar várias faixas

Pré-requisitos

pip install yt-dlp requests python-dotenv

Você também precisa de uma chave de API do StemSplit (plano gratuito: 5 minutos de processamento, sem cartão de crédito): stemsplit.io/pt-BR/soundcloud-stem-splitter


Por que o SoundCloud para stems?

Resposta curta: porque é onde a maioria dos produtores independentes publica demos, remixes e acapellas — e muitas faixas não estão no Spotify ou no YouTube.

O caso de uso mais comum que eu vejo em comunidades BR de produção musical:

  • DJs querem separar o stem de bateria de uma faixa exclusiva do SoundCloud para remixtear
  • Cantores de cover precisam do instrumental limpo de uma versão demo
  • Produtores querem estudar o groove de baixo de uma faixa de outro produtor
  • Criadores de karaoke precisam remover vocais de músicas que só existem no SoundCloud

O yt-dlp suporta SoundCloud nativamente (incluindo faixas em playlists e reposts), então o pipeline fica bem direto.


Passo 1 — Baixar o áudio com yt-dlp

import subprocess
import os
from pathlib import Path

def download_soundcloud(url: str, output_dir: str = "downloads") -> Path:
    """
    Baixa uma faixa do SoundCloud como MP3 de alta qualidade.
    Retorna o caminho do arquivo baixado.
    """
    Path(output_dir).mkdir(exist_ok=True)

    # yt-dlp detecta o título automaticamente e usa como nome do arquivo
    result = subprocess.run(
        [
            "yt-dlp",
            "--extract-audio",
            "--audio-format", "mp3",
            "--audio-quality", "0",           # melhor qualidade disponível
            "--output", f"{output_dir}/%(title)s.%(ext)s",
            "--no-playlist",                   # só a faixa, não a playlist
            url,
        ],
        capture_output=True,
        text=True,
        check=True,
    )

    # Pega o nome do arquivo gerado da saída do yt-dlp
    for line in result.stdout.splitlines():
        if "[ExtractAudio] Destination:" in line:
            return Path(line.split("Destination:")[1].strip())

    # Fallback: pega o MP3 mais recente na pasta
    mp3_files = sorted(Path(output_dir).glob("*.mp3"), key=os.path.getmtime)
    if not mp3_files:
        raise FileNotFoundError("yt-dlp não criou nenhum arquivo MP3")
    return mp3_files[-1]


# Uso
audio_path = download_soundcloud("https://soundcloud.com/artista/nome-da-faixa")
print(f"Baixado: {audio_path}")

O yt-dlp também aceita URLs de playlists do SoundCloud — basta remover --no-playlist para baixar todas as faixas.


Passo 2 — Enviar para a API e obter o job_id

Resposta curta: a API aceita upload multipart e retorna um job_id imediatamente; o processamento acontece de forma assíncrona no servidor.

import requests
from pathlib import Path

API_BASE = "https://api.stemsplit.io/v1"
API_KEY = "sua_chave_aqui"  # ou use python-dotenv

def submit_job(audio_path: Path) -> str:
    """Envia o arquivo para a API e retorna o job_id."""
    with open(audio_path, "rb") as f:
        response = requests.post(
            f"{API_BASE}/jobs",
            headers={"Authorization": f"Bearer {API_KEY}"},
            files={"file": (audio_path.name, f, "audio/mpeg")},
            timeout=60,
        )
    response.raise_for_status()
    job_id = response.json()["job_id"]
    print(f"Job enviado: {job_id}")
    return job_id

O limite de tamanho de arquivo é 100 MB. Faixas do SoundCloud em MP3 de alta qualidade ficam em torno de 8–15 MB para uma faixa de 3–5 minutos — bem dentro do limite.


Passo 3 — Polling até o job completar

Resposta curta: poll a cada 5 segundos em GET /jobs/{job_id} até o status mudar para "done".

O HTDemucs (modelo que roda nos bastidores) leva em torno de 35–45 segundos para uma faixa de 3 minutos em GPU dedicada.

import time

POLL_INTERVAL = 5   # segundos entre cada verificação
POLL_TIMEOUT = 300  # 5 minutos máximo

def poll_job(job_id: str) -> dict:
    """Aguarda o job completar e retorna o dict de stems."""
    deadline = time.time() + POLL_TIMEOUT
    headers = {"Authorization": f"Bearer {API_KEY}"}

    while time.time() < deadline:
        resp = requests.get(
            f"{API_BASE}/jobs/{job_id}",
            headers=headers,
            timeout=15,
        )
        resp.raise_for_status()
        data = resp.json()

        status = data.get("status")
        print(f"  Status: {status}")

        if status == "done":
            return data["stems"]
        if status == "failed":
            raise RuntimeError(f"Job falhou: {data.get('error')}")

        time.sleep(POLL_INTERVAL)

    raise TimeoutError("Job excedeu o tempo limite de 5 minutos")

Passo 4 — Baixar os stems

def download_stems(stems: dict, output_dir: str = "stems") -> dict[str, Path]:
    """
    Baixa cada stem como arquivo WAV.
    Retorna dict {nome_do_stem: caminho_do_arquivo}.
    """
    Path(output_dir).mkdir(exist_ok=True)
    downloaded = {}

    for stem_name, url in stems.items():
        dest = Path(output_dir) / f"{stem_name}.wav"
        print(f"  Baixando {stem_name}…")

        resp = requests.get(url, timeout=60, stream=True)
        resp.raise_for_status()

        with open(dest, "wb") as f:
            for chunk in resp.iter_content(chunk_size=8192):
                f.write(chunk)

        downloaded[stem_name] = dest

    return downloaded

Os stems disponíveis são: vocals, drums, bass, other (outros instrumentos).


Pipeline completo

from pathlib import Path
from dotenv import load_dotenv
import os

load_dotenv()
API_KEY = os.environ["STEMSPLIT_API_KEY"]

def process_soundcloud_track(url: str, track_name: str) -> dict[str, Path]:
    """Pipeline completo: download → separação → stems."""
    print(f"\n[{track_name}]")

    print("→ Baixando do SoundCloud…")
    audio_path = download_soundcloud(url)

    print("→ Enviando para a API…")
    job_id = submit_job(audio_path)

    print("→ Aguardando processamento…")
    stems_urls = poll_job(job_id)

    print("→ Baixando stems…")
    stem_paths = download_stems(stems_urls, output_dir=f"stems/{track_name}")

    print(f"✓ Pronto! {len(stem_paths)} stems salvos em stems/{track_name}/")
    return stem_paths


# Exemplo de uso
if __name__ == "__main__":
    tracks = [
        ("https://soundcloud.com/artista/faixa-1", "faixa-1"),
        ("https://soundcloud.com/artista/faixa-2", "faixa-2"),
    ]

    for url, name in tracks:
        try:
            stems = process_soundcloud_track(url, name)
            for stem, path in stems.items():
                print(f"  {stem}: {path}")
        except Exception as e:
            print(f"  Erro em {name}: {e}")

Casos de uso práticos

Karaoke a partir de faixas exclusivas do SoundCloud

Muitos cantores publicam versões demo no SoundCloud antes de lançar no Spotify. Com esse pipeline você extrai o instrumental limpo em segundos — sem depender de nenhuma ferramenta online com limite de arquivo.

Estudo de produção

Isolar o stem de bateria ou baixo de uma faixa de referência é a forma mais rápida de entender o groove. Com Python você pode automatizar isso para uma lista inteira de referências de uma vez.

Criação de conteúdo

Se você cria conteúdos com a música de um produtor independente do SoundCloud, ter o stem de vocais e o instrumental separadamente facilita muito a edição — especialmente para Reels e TikTok.


Considerações sobre direitos autorais

Usar esse pipeline em faixas protegidas por direitos autorais sem autorização viola os Termos de Serviço do SoundCloud. Use apenas em:

  • Faixas com licença Creative Commons
  • Faixas de sua própria autoria
  • Com permissão explícita do artista

Conclusão

O pipeline inteiro tem menos de 100 linhas de Python: yt-dlp resolve o download, a API cuida do processamento pesado com HTDemucs, e você só precisa implementar o polling e o download dos stems.

Para processar faixas sem escrever nenhuma linha de código — direto pelo navegador — o separador de stems do SoundCloud do StemSplit faz exatamente isso com a mesma qualidade de separação.

Se você quiser ir mais fundo, nosso primeiro artigo aqui no TabNews cobre como separar stems com Demucs localmente e via API — incluindo benchmarks de SDR e comparação Demucs vs Spleeter.

Dúvidas ou sugestões? Deixe nos comentários.

Carregando publicação patrocinada...