-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathonly_guitar.py
More file actions
86 lines (68 loc) · 2.26 KB
/
only_guitar.py
File metadata and controls
86 lines (68 loc) · 2.26 KB
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/env python3
import argparse
import shutil
import subprocess
from pathlib import Path
def run(cmd: list[str]) -> None:
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(
"Command failed:\n"
+ " ".join(cmd)
+ "\n\nSTDOUT:\n"
+ result.stdout
+ "\n\nSTDERR:\n"
+ result.stderr
)
def output_codec_args(output_path: Path) -> list[str]:
ext = output_path.suffix.lower()
if ext == ".mp3":
return ["-c:a", "libmp3lame", "-q:a", "2"]
if ext in {".m4a", ".mp4"}:
return ["-c:a", "aac", "-b:a", "192k"]
return ["-c:a", "pcm_s16le"]
def only_guitar(input_path: Path, output_path: Path, model: str) -> None:
if not input_path.exists():
raise FileNotFoundError(str(input_path))
work_dir = output_path.parent
work_dir.mkdir(parents=True, exist_ok=True)
# Verify demucs/ffmpeg are available.
run(["demucs", "-h"])
run(["ffmpeg", "-version"])
# Run demucs to split stems.
run(
[
"demucs",
"-n",
model,
"--out",
str(work_dir),
str(input_path),
]
)
# Demucs output path: <out>/<model>/<trackname>/
track_dir = work_dir / model / input_path.stem
other = track_dir / "other.wav"
if not other.exists():
raise RuntimeError(f"Missing expected stem {other}")
ffmpeg_cmd = ["ffmpeg", "-y", "-i", str(other)]
ffmpeg_cmd += output_codec_args(output_path)
ffmpeg_cmd.append(str(output_path))
run(ffmpeg_cmd)
# Cleanup demucs stems to keep the workspace tidy.
shutil.rmtree(work_dir / model, ignore_errors=True)
def main() -> None:
parser = argparse.ArgumentParser(
description="Extract the 'other' stem (approx guitar) from Demucs."
)
parser.add_argument("input", help="Path to input audio file")
parser.add_argument("output", help="Path to output audio file")
parser.add_argument(
"--model",
default="htdemucs",
help="Demucs model name (default: htdemucs)",
)
args = parser.parse_args()
only_guitar(Path(args.input), Path(args.output), args.model)
if __name__ == "__main__":
main()