Usar Spleeter para separación y corregir flujo
Browse files- app.py +12 -12
- audio_pipeline.py +16 -32
app.py
CHANGED
|
@@ -3,36 +3,36 @@
|
|
| 3 |
import os
|
| 4 |
import gradio as gr
|
| 5 |
from audio_pipeline import (
|
| 6 |
-
|
| 7 |
limpiar_stems,
|
| 8 |
combinar_stems_sin_vocales,
|
| 9 |
reducir_ruido
|
| 10 |
)
|
| 11 |
|
| 12 |
def procesar_wav(input_wav_path):
|
| 13 |
-
# 1) Separar con
|
| 14 |
-
stems_dir =
|
| 15 |
|
| 16 |
# 2) Limpiar stems (_cleaned.wav)
|
| 17 |
limpiar_stems(stems_dir)
|
| 18 |
|
| 19 |
-
# 3) Combinar stems sin vocales
|
| 20 |
combinar_stems_sin_vocales(stems_dir)
|
| 21 |
|
| 22 |
-
# 4) Reducir ruido
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
reducir_ruido(
|
| 26 |
|
| 27 |
-
# 5) Devolver
|
| 28 |
-
return
|
| 29 |
|
| 30 |
demo = gr.Interface(
|
| 31 |
fn=procesar_wav,
|
| 32 |
inputs=gr.Audio(label="Sube un archivo .wav", type="filepath"),
|
| 33 |
outputs=gr.Audio(label="Base instrumental limpia", type="filepath"),
|
| 34 |
-
title="Procesador de WAV a Base Instrumental",
|
| 35 |
-
description="Sube tu WAV y obtén
|
| 36 |
)
|
| 37 |
|
| 38 |
if __name__ == "__main__":
|
|
|
|
| 3 |
import os
|
| 4 |
import gradio as gr
|
| 5 |
from audio_pipeline import (
|
| 6 |
+
separar_audio_spleeter,
|
| 7 |
limpiar_stems,
|
| 8 |
combinar_stems_sin_vocales,
|
| 9 |
reducir_ruido
|
| 10 |
)
|
| 11 |
|
| 12 |
def procesar_wav(input_wav_path):
|
| 13 |
+
# 1) Separar con Spleeter
|
| 14 |
+
stems_dir = separar_audio_spleeter(input_wav_path)
|
| 15 |
|
| 16 |
# 2) Limpiar stems (_cleaned.wav)
|
| 17 |
limpiar_stems(stems_dir)
|
| 18 |
|
| 19 |
+
# 3) Combinar stems sin vocales => base_instrumental.wav
|
| 20 |
combinar_stems_sin_vocales(stems_dir)
|
| 21 |
|
| 22 |
+
# 4) Reducir ruido en la base
|
| 23 |
+
base = os.path.join(stems_dir, "base_instrumental.wav")
|
| 24 |
+
clean = os.path.join(stems_dir, "base_instrumental_clean.wav")
|
| 25 |
+
reducir_ruido(base, clean)
|
| 26 |
|
| 27 |
+
# 5) Devolver ruta al WAV final
|
| 28 |
+
return clean
|
| 29 |
|
| 30 |
demo = gr.Interface(
|
| 31 |
fn=procesar_wav,
|
| 32 |
inputs=gr.Audio(label="Sube un archivo .wav", type="filepath"),
|
| 33 |
outputs=gr.Audio(label="Base instrumental limpia", type="filepath"),
|
| 34 |
+
title="Procesador de WAV a Base Instrumental con Spleeter",
|
| 35 |
+
description="Sube tu WAV y obtén la base sin vocales usando Spleeter."
|
| 36 |
)
|
| 37 |
|
| 38 |
if __name__ == "__main__":
|
audio_pipeline.py
CHANGED
|
@@ -1,47 +1,33 @@
|
|
| 1 |
# audio_pipeline.py
|
| 2 |
|
| 3 |
import os
|
| 4 |
-
import subprocess
|
| 5 |
-
import sys
|
| 6 |
-
import torch
|
| 7 |
import librosa
|
| 8 |
import numpy as np
|
| 9 |
import soundfile as sf
|
| 10 |
import noisereduce as nr
|
|
|
|
| 11 |
|
| 12 |
# Directorio base donde guardaremos todos los stems
|
| 13 |
BASE_STEMS_DIR = "data/stems"
|
| 14 |
|
| 15 |
-
def
|
| 16 |
-
"""Aplica un filtro Butterworth de paso alto al audio."""
|
| 17 |
-
sos = signal.butter(order, cutoff, btype='highpass', fs=sr, output='sos')
|
| 18 |
-
return signal.sosfilt(sos, audio)
|
| 19 |
-
|
| 20 |
-
def separar_audio_demucs(input_file, model="htdemucs"):
|
| 21 |
"""
|
| 22 |
-
Separa stems usando
|
| 23 |
-
|
| 24 |
-
y devuelve la ruta al folder con los stems.
|
| 25 |
"""
|
| 26 |
-
|
| 27 |
-
|
|
|
|
| 28 |
os.makedirs(out_root, exist_ok=True)
|
| 29 |
|
| 30 |
-
#
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
sys.executable, "-m", "demucs",
|
| 34 |
-
input_file,
|
| 35 |
-
"--out", out_root,
|
| 36 |
-
"--device", device
|
| 37 |
-
]
|
| 38 |
-
subprocess.run(cmd, check=True)
|
| 39 |
|
| 40 |
-
#
|
| 41 |
-
base = os.path.splitext(os.path.basename(input_file))[0]
|
| 42 |
stems_dir = os.path.join(out_root, base)
|
| 43 |
if not os.path.isdir(stems_dir):
|
| 44 |
-
raise FileNotFoundError(f"No
|
| 45 |
return stems_dir
|
| 46 |
|
| 47 |
def limpiar_stems(stems_dir):
|
|
@@ -55,18 +41,16 @@ def limpiar_stems(stems_dir):
|
|
| 55 |
|
| 56 |
def combinar_stems_sin_vocales(stems_dir):
|
| 57 |
"""Mezcla todos los stems (limpios) excepto los de vocales."""
|
| 58 |
-
#
|
| 59 |
wavs = [
|
| 60 |
f for f in os.listdir(stems_dir)
|
| 61 |
-
if f.endswith(".wav") and
|
| 62 |
-
"cleaned" in f.lower() and
|
| 63 |
-
"vocal" not in f.lower()
|
| 64 |
]
|
| 65 |
-
# Si no hay cleaned, fallback a
|
| 66 |
if not wavs:
|
| 67 |
wavs = [
|
| 68 |
f for f in os.listdir(stems_dir)
|
| 69 |
-
if f.endswith(".wav") and "
|
| 70 |
]
|
| 71 |
|
| 72 |
signals = []
|
|
|
|
| 1 |
# audio_pipeline.py
|
| 2 |
|
| 3 |
import os
|
|
|
|
|
|
|
|
|
|
| 4 |
import librosa
|
| 5 |
import numpy as np
|
| 6 |
import soundfile as sf
|
| 7 |
import noisereduce as nr
|
| 8 |
+
from spleeter.separator import Separator
|
| 9 |
|
| 10 |
# Directorio base donde guardaremos todos los stems
|
| 11 |
BASE_STEMS_DIR = "data/stems"
|
| 12 |
|
| 13 |
+
def separar_audio_spleeter(input_file, model="spleeter:4stems"):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
"""
|
| 15 |
+
Separa stems usando Spleeter (4 stems: vocals, drums, bass, other),
|
| 16 |
+
los deja en data/stems/4stems/<nombre_base>/ y devuelve esa ruta.
|
|
|
|
| 17 |
"""
|
| 18 |
+
base = os.path.splitext(os.path.basename(input_file))[0]
|
| 19 |
+
model_name = model.split(":")[1] # "4stems"
|
| 20 |
+
out_root = os.path.join(BASE_STEMS_DIR, model_name)
|
| 21 |
os.makedirs(out_root, exist_ok=True)
|
| 22 |
|
| 23 |
+
# Ejecuta la separación
|
| 24 |
+
sep = Separator(model)
|
| 25 |
+
sep.separate_to_file(input_file, out_root)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
+
# La salida es out_root/<base>/*.wav
|
|
|
|
| 28 |
stems_dir = os.path.join(out_root, base)
|
| 29 |
if not os.path.isdir(stems_dir):
|
| 30 |
+
raise FileNotFoundError(f"No se encontró el folder de stems en {stems_dir}")
|
| 31 |
return stems_dir
|
| 32 |
|
| 33 |
def limpiar_stems(stems_dir):
|
|
|
|
| 41 |
|
| 42 |
def combinar_stems_sin_vocales(stems_dir):
|
| 43 |
"""Mezcla todos los stems (limpios) excepto los de vocales."""
|
| 44 |
+
# Busca "*_cleaned.wav" que no contengan "vocals"
|
| 45 |
wavs = [
|
| 46 |
f for f in os.listdir(stems_dir)
|
| 47 |
+
if f.endswith("_cleaned.wav") and "vocals" not in f.lower()
|
|
|
|
|
|
|
| 48 |
]
|
| 49 |
+
# Si no hay cleaned, fallback a originales sin "vocals"
|
| 50 |
if not wavs:
|
| 51 |
wavs = [
|
| 52 |
f for f in os.listdir(stems_dir)
|
| 53 |
+
if f.endswith(".wav") and "vocals" not in f.lower()
|
| 54 |
]
|
| 55 |
|
| 56 |
signals = []
|