File size: 3,887 Bytes
1220b6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
from __future__ import annotations

import gradio as gr
try:
    import spaces
except ImportError:  # 'spaces' is only provided by Hugging Face Spaces
    import types as _types

    def _gpu(*args, **kwargs):
        if len(args) == 1 and callable(args[0]) and not kwargs:
            return args[0]

        def _decorator(func):
            return func

        return _decorator

    spaces = _types.SimpleNamespace(GPU=_gpu)

from pyharp import *


try:  # torch>=2.6 flipped torch.load(weights_only) to True; legacy ckpts need False
    import torch as _torch

    if getattr(_torch.load, "__harp_compat__", False) is False:
        _torch_load_orig = _torch.load

        def _torch_load_compat(*args, **kwargs):
            kwargs.setdefault("weights_only", False)
            return _torch_load_orig(*args, **kwargs)

        _torch_load_compat.__harp_compat__ = True
        _torch.load = _torch_load_compat
except Exception:  # torch not installed / unexpected API -- nothing to patch
    pass


import tempfile
import torch
import torchaudio
from openunmix import utils, predict

DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
_separators = {}

def get_separator(model_name, niter, wiener_win_len):
    key = (model_name, niter, wiener_win_len)
    if key not in _separators:
        sep = utils.load_separator(
            model_str_or_path=model_name,
            niter=niter,
            wiener_win_len=wiener_win_len,
            device=DEVICE,
            pretrained=True,
        )
        sep.freeze()
        sep.to(DEVICE)
        _separators[key] = sep
    return _separators[key]


model_card = ModelCard(
    name="Open-Unmix",
    description="Music source separation into vocals, drums, bass, and other instruments using deep neural networks.",
    author="sigsep",
    tags=["audio-to-audio", "source-separation", "stems"],
)


@spaces.GPU
def process_fn(input_audio, model_name, niter, wiener_win_len):
    audio, rate = torchaudio.load(input_audio)
    if audio.shape[0] == 1:
        audio = audio.repeat(2, 1)

    separator = get_separator(model_name, int(niter), int(wiener_win_len))

    estimates = predict.separate(
        audio=audio,
        rate=rate,
        model_str_or_path=model_name,
        separator=separator,
        device=DEVICE
    )

    output_files = {}
    for target in ["vocals", "drums", "bass", "other"]:
        target_tensor = estimates[target][0].cpu()
        out_file = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)
        out_file.close()
        torchaudio.save(out_file.name, target_tensor, int(separator.sample_rate))
        output_files[target] = out_file.name

    return (
        output_files["vocals"],
        output_files["drums"],
        output_files["bass"],
        output_files["other"]
    )


with gr.Blocks() as demo:
    input_components = [
        gr.Audio(type="filepath", label="Input Audio").harp_required(True),
        gr.Dropdown(choices=["umxl", "umxhq", "umx"], value="umxl", label="Model", info="umxl is the largest and best performing model, trained on extra data."),
        gr.Slider(minimum=0, maximum=5, step=1, value=1, label="Wiener Filter Iterations", info="Number of iterations for Wiener filtering. 0 means softmask."),
        gr.Slider(minimum=100, maximum=500, step=50, value=300, label="Wiener Window Length", info="Number of frames on which to apply filtering independently."),
    ]
    output_components = [
        gr.Audio(type="filepath", label="Vocals"),
        gr.Audio(type="filepath", label="Drums"),
        gr.Audio(type="filepath", label="Bass"),
        gr.Audio(type="filepath", label="Other"),
    ]
    build_endpoint(
        model_card=model_card,
        input_components=input_components,
        output_components=output_components,
        process_fn=process_fn,
    )

demo.queue().launch(share=True, show_error=False, pwa=True)