# Separación Demucs

Separa la música en stems (voces, batería, bajo, otros) con Demucs.

{% hint style="success" %}
Todos los ejemplos se pueden ejecutar en servidores GPU alquilados a través de [CLORE.AI Marketplace](https://clore.ai/marketplace).
{% endhint %}

## Alquilar en CLORE.AI

1. Visita [CLORE.AI Marketplace](https://clore.ai/marketplace)
2. Filtrar por tipo de GPU, VRAM y precio
3. Elegir **Bajo demanda** (tarifa fija) o **Spot** (precio de puja)
4. Configura tu pedido:
   * Selecciona imagen Docker
   * Establece puertos (TCP para SSH, HTTP para interfaces web)
   * Agrega variables de entorno si es necesario
   * Introduce el comando de inicio
5. Selecciona pago: **CLORE**, **BTC**, o **USDT/USDC**
6. Crea el pedido y espera el despliegue

### Accede a tu servidor

* Encuentra los detalles de conexión en **Mis Pedidos**
* Interfaces web: Usa la URL del puerto HTTP
* SSH: `ssh -p <port> root@<proxy-address>`

## ¿Qué es Demucs?

Demucs de Meta AI puede:

* Separar las voces de la música
* Extraer batería, bajo y otros instrumentos
* Procesar cualquier formato de audio
* Extracción de stems de alta calidad

## Despliegue rápido

**Imagen Docker:**

```
pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime
```

**Puertos:**

```
22/tcp
7860/http
```

**Comando:**

```bash
pip install demucs gradio && \
python -c "
import gradio as gr
from demucs.pretrained import get_model
from demucs.apply import apply_model
import torch
import torchaudio
import tempfile
import os

model = get_model('htdemucs')
model.cuda()

def separate(audio_path, stem):
    wav, sr = torchaudio.load(audio_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    stems = {'drums': 0, 'bass': 1, 'other': 2, 'vocals': 3}
    output = sources[stems[stem]].cpu()

    with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as f:
        torchaudio.save(f.name, output, sr)
        return f.name

demo = gr.Interface(
    fn=separate,
    inputs=[gr.Audio(type='filepath'), gr.Dropdown(['vocals', 'drums', 'bass', 'other'])],
    outputs=gr.Audio(),
    title='Demucs Audio Separator'
)
demo.launch(server_name='0.0.0.0', server_port=7860)
"
```

## Accediendo a tu servicio

Después del despliegue, encuentra tu `http_pub` URL en **Mis Pedidos**:

1. Ir a **Mis Pedidos** página
2. Haz clic en tu pedido
3. Encuentra la `http_pub` URL (por ejemplo, `abc123.clorecloud.net`)

Usa `https://TU_HTTP_PUB_URL` en lugar de `localhost` en los ejemplos abajo.

## Instalación

```bash
pip install demucs

# o
pip install -e git+https://github.com/facebookresearch/demucs#egg=demucs
```

## Uso desde la línea de comandos

### Separación básica

```bash

# Separar en 4 stems
demucs song.mp3

# Salida: separated/htdemucs/song/{drums,bass,other,vocals}.wav
```

### Opciones

```bash
demucs \
    --two-stems vocals \     # Solo voces + instrumental
    -n htdemucs \            # Nombre del modelo
    -d cuda \                # Usar GPU
    -o ./output \            # Directorio de salida
    --mp3 \                  # Salida en MP3
    song.mp3
```

### Procesar carpeta

```bash
demucs --two-stems vocals -d cuda ./songs/*.mp3
```

## API de Python

### Separación básica

```python
from demucs.pretrained import get_model
from demucs.apply import apply_model
import torchaudio
import torch

# Cargar modelo
model = get_model('htdemucs')
model.cuda()
model.eval()

# Cargar audio
wav, sr = torchaudio.load("song.mp3")
wav = wav.cuda()

# Separar
with torch.no_grad():
    sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

# forma de sources: [4, canales, muestras]

# 0: batería, 1: bajo, 2: otros, 3: voces

# Guardar stems
stems = ['drums', 'bass', 'other', 'vocals']
for i, stem in enumerate(stems):
    torchaudio.save(f"{stem}.wav", sources[i].cpu(), sr)
```

### Obtener solo las voces

```python
def extract_vocals(audio_path):
    wav, sr = torchaudio.load(audio_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    vocals = sources[3].cpu()  # Índice 3 = voces
    return vocals, sr

vocals, sr = extract_vocals("song.mp3")
torchaudio.save("vocals.wav", vocals, sr)
```

### Obtener instrumental (sin voces)

```python
def extract_instrumental(audio_path):
    wav, sr = torchaudio.load(audio_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    # Sumar batería + bajo + otros
    instrumental = sources[0] + sources[1] + sources[2]
    return instrumental.cpu(), sr

instrumental, sr = extract_instrumental("song.mp3")
torchaudio.save("instrumental.wav", instrumental, sr)
```

## Variantes de modelo

| Modelo       | Stems | Calidad | Velocidad |
| ------------ | ----- | ------- | --------- |
| htdemucs     | 4     | Mejor   | Medio     |
| htdemucs\_ft | 4     | Best+   | Lento     |
| htdemucs\_6s | 6     | Genial  | Medio     |
| mdx\_extra   | 4     | Genial  | Rápido    |

### Modelo de 6 stems

```python
model = get_model('htdemucs_6s')

# Stems: batería, bajo, otros, voces, guitarra, piano
```

### Modelo afinado

```python
model = get_model('htdemucs_ft')

# Mayor calidad pero más lento
```

## Procesamiento por lotes

```python
import os
from demucs.pretrained import get_model
from demucs.apply import apply_model
import torchaudio
import torch

model = get_model('htdemucs')
model.cuda()
model.eval()

input_dir = "./songs"
output_dir = "./separated"

for filename in os.listdir(input_dir):
    if filename.endswith(('.mp3', '.wav', '.flac')):
        input_path = os.path.join(input_dir, filename)
        song_output_dir = os.path.join(output_dir, filename.rsplit('.', 1)[0])
        os.makedirs(song_output_dir, exist_ok=True)

        print(f"Procesando: {filename}")

        wav, sr = torchaudio.load(input_path)
        wav = wav.cuda()

        with torch.no_grad():
            sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

        stems = ['drums', 'bass', 'other', 'vocals']
        for i, stem in enumerate(stems):
            torchaudio.save(
                os.path.join(song_output_dir, f"{stem}.wav"),
                sources[i].cpu(),
                sr
            )

        print(f"Guardado: {song_output_dir}")
```

## Servidor API

```python
from fastapi import FastAPI, UploadFile
from fastapi.responses import FileResponse
from demucs.pretrained import get_model
from demucs.apply import apply_model
import torchaudio
import torch
import tempfile
import os

app = FastAPI()

model = get_model('htdemucs')
model.cuda()
model.eval()

@app.post("/separate")
async def separate(file: UploadFile, stem: str = "vocals"):
    # Guardar archivo subido
    with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
        content = await file.read()
        tmp.write(content)
        tmp_path = tmp.name

    # Cargar y separar
    wav, sr = torchaudio.load(tmp_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    stems = {'drums': 0, 'bass': 1, 'other': 2, 'vocals': 3}
    output = sources[stems[stem]].cpu()

    # Guardar salida
    with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as out:
        torchaudio.save(out.name, output, sr)
        return FileResponse(out.name, media_type="audio/wav")

@app.post("/instrumental")
async def get_instrumental(file: UploadFile):
    with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
        content = await file.read()
        tmp.write(content)
        tmp_path = tmp.name

    wav, sr = torchaudio.load(tmp_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    # Combinar stems que no son vocales
    instrumental = sources[0] + sources[1] + sources[2]

    with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as out:
        torchaudio.save(out.name, instrumental.cpu(), sr)
        return FileResponse(out.name, media_type="audio/wav")

# Ejecutar: uvicorn server:app --host 0.0.0.0 --port 8000
```

## Optimización de memoria

### Para audio largo

```python
from demucs.apply import apply_model

# Usar división para audio largo
sources = apply_model(
    model,
    wav.unsqueeze(0),
    split=True,         # Dividir en fragmentos
    overlap=0.25,       # Solapamiento entre fragmentos
    progress=True
)[0]
```

### Para VRAM limitada

```python

# Usar CPU para algunas operaciones
model.cpu()
wav = wav.cpu()

# O usar procesamiento por segmentos
sources = apply_model(
    model,
    wav.unsqueeze(0),
    split=True,
    segment=10  # segmentos de 10 segundos
)[0]
```

## Casos de uso

### Pista karaoke

```python
def create_karaoke(song_path):
    wav, sr = torchaudio.load(song_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    # Todo excepto las voces
    karaoke = sources[0] + sources[1] + sources[2]
    return karaoke.cpu(), sr
```

### Preparación para remix

```python
def extract_all_stems(song_path, output_dir):
    wav, sr = torchaudio.load(song_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    stems = ['drums', 'bass', 'other', 'vocals']
    paths = {}

    for i, stem in enumerate(stems):
        path = os.path.join(output_dir, f"{stem}.wav")
        torchaudio.save(path, sources[i].cpu(), sr)
        paths[stem] = path

    return paths
```

### Extracción de acapella

```python
def extract_acapella(song_path):
    wav, sr = torchaudio.load(song_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    vocals = sources[3]
    return vocals.cpu(), sr
```

## Consejos de calidad

### Para mejores resultados

* Usar entrada sin pérdida (WAV, FLAC)
* Mayor frecuencia de muestreo = mejor calidad
* Usa `htdemucs_ft` para trabajos críticos

### Postprocesamiento

```python
from pydub import AudioSegment
from pydub.effects import normalize, high_pass_filter

# Cargar vocal separada
vocals = AudioSegment.from_wav("vocals.wav")

# Eliminar rumor bajo
vocals = high_pass_filter(vocals, 80)

# Normalizar
vocals = normalize(vocals)

vocals.export("vocals_clean.wav", format="wav")
```

## Rendimiento

| Duración del audio | GPU      | Tiempo  |
| ------------------ | -------- | ------- |
| canción de 3 min   | RTX 3090 | \~15s   |
| canción de 3 min   | RTX 4090 | \~10s   |
| canción de 3 min   | A100     | \~8s    |
| álbum de 1 hora    | RTX 3090 | \~5 min |

## Solución de problemas

### Memoria insuficiente

```bash

# Usar segmentos más pequeños
demucs --segment 10 song.mp3
```

### Separación deficiente

* Usar el modelo htdemucs\_ft
* Comprobar la calidad de entrada
* Evitar MP3s muy comprimidos

### Artefactos

* Aumentar el solapamiento
* Usar un modelo de mayor calidad
* Comprobar si hay recorte (clipping) en la entrada

## Estimación de costos

Tarifas típicas del marketplace de CLORE.AI (a fecha de 2024):

| GPU       | Tarifa por hora | Tarifa diaria | Sesión de 4 horas |
| --------- | --------------- | ------------- | ----------------- |
| RTX 3060  | \~$0.03         | \~$0.70       | \~$0.12           |
| RTX 3090  | \~$0.06         | \~$1.50       | \~$0.25           |
| RTX 4090  | \~$0.10         | \~$2.30       | \~$0.40           |
| A100 40GB | \~$0.17         | \~$4.00       | \~$0.70           |
| A100 80GB | \~$0.25         | \~$6.00       | \~$1.00           |

*Los precios varían según el proveedor y la demanda. Consulta* [*CLORE.AI Marketplace*](https://clore.ai/marketplace) *para las tarifas actuales.*

**Ahorra dinero:**

* Usa **Spot** market para cargas de trabajo flexibles (a menudo 30-50% más barato)
* Paga con **CLORE** tokens
* Compara precios entre diferentes proveedores

## Próximos pasos

* [Clon de voz RVC](https://docs.clore.ai/guides/guides_v2-es/audio-y-voz/rvc-voice-clone) - Procesar las voces extraídas
* [AudioCraft Music](https://docs.clore.ai/guides/guides_v2-es/audio-y-voz/audiocraft-music) - Generar nueva música
* [Whisper Transcription](https://docs.clore.ai/guides/guides_v2-es/audio-y-voz/whisper-transcription) - Transcribir las voces
