File size: 1,353 Bytes
0abe23e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import subprocess
import sys
from pathlib import Path
from processor import _get_device


def _run_demucs(audio_path: Path) -> Path:
    """Run demucs in two-stems mode targeting vocals; return path to no_vocals stem."""
    out_root = audio_path.parent / "demucs_out"
    out_root.mkdir(parents=True, exist_ok=True)
    cmd = [
        sys.executable,
        "-m",
        "demucs",
        "--two-stems", "vocals",
        "-n", "htdemucs",
        "--device", _get_device(),
        "--mp3",
        "--mp3-bitrate", "192",
        "-o", str(out_root),
        str(audio_path),
    ]
    subprocess.run(cmd, check=True)
    # demucs writes to {out_root}/htdemucs/{audio_stem}/no_vocals.mp3
    candidate = out_root / "htdemucs" / audio_path.stem / "no_vocals.mp3"
    if not candidate.exists():
        raise RuntimeError(f"demucs did not produce {candidate}")
    return candidate


def _encode_mp3(wav_path: Path, mp3_path: Path) -> Path:
    """Re-encode (or copy) a stem file to the target mp3_path."""
    subprocess.run(
        ["ffmpeg", "-y", "-i", str(wav_path), "-b:a", "192k", str(mp3_path)],
        check=True, capture_output=True,
    )
    return mp3_path


def separate_vocals_to_mp3(audio_path: Path) -> Path:
    no_vocals_stem = _run_demucs(audio_path)
    return _encode_mp3(no_vocals_stem, audio_path.parent / "no_vocals.mp3")