Spaces:
Running on Zero
Running on Zero
File size: 5,323 Bytes
6dea0da dc8400f 6dea0da dc8400f 6dea0da dc8400f 6dea0da dc8400f 6dea0da dc8400f 6dea0da dc8400f 6dea0da | 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 125 126 127 128 129 130 131 132 133 134 135 136 137 | import sys
sys.stdout.reconfigure(line_buffering=True)
try:
import spaces
except ImportError:
# keep @spaces.GPU usable as a no-op; ZeroGPU requires this exact name.
class spaces:
class GPU:
def __init__(self, func=None, duration=60):
self.func = func
def __call__(self, *args, **kwargs):
if self.func is not None:
return self.func(*args, **kwargs)
func = args[0]
return func
import tempfile
import gradio as gr
import soundfile as sf
import torch
import torchaudio
from huggingface_hub import hf_hub_download
from omegaconf import OmegaConf
from pyharp import ModelCard, build_endpoint
from model.config import CHECKPOINTS, CHECKPOINTS_REPO
from model.cqtdiff import Unet_CQT_oct_with_attention
from model.edm import EDM
from model.restoration import restore_audio
# one entry per architecture ("piano"/"singing"), holding everything that's
# lazily built/loaded once and reused across requests for that architecture
_state = {}
def get_arch_state(base_cfg, device):
"""Lazily builds (once per architecture) and caches the network and EDM diffusion parameters on `device`."""
key = base_cfg.architecture
if key not in _state:
net = Unet_CQT_oct_with_attention(base_cfg, device)
net.to(device)
net.eval()
_state[key] = {"network": net, "diff_params": EDM(base_cfg), "loaded_checkpoint": None, "ltas_ref": None}
return _state[key]
def load_checkpoint(label, device):
"""Downloads (if not already cached locally) and loads the checkpoint for the selected voice/instrument, reusing the shared network for its architecture."""
filename, base_cfg = CHECKPOINTS[label]
state = get_arch_state(base_cfg, device)
if state["loaded_checkpoint"] != filename:
ckpt_path = hf_hub_download(repo_id=CHECKPOINTS_REPO, filename=filename)
checkpoint = torch.load(ckpt_path, map_location="cpu", weights_only=False)
state["network"].load_state_dict(checkpoint["ema"])
state["ltas_ref"] = checkpoint["LTAS"]
state["loaded_checkpoint"] = filename
return state["network"], state["diff_params"], state["ltas_ref"], base_cfg
model_card = ModelCard(
name="BABE-2",
description="Restores degraded historical piano or singing-voice recordings with a diffusion-based generative equalizer.",
author="Eloi Moliner, Maija Turunen, Filip Elvander, Vesa Välimäki",
tags=["restoration", "equalizer", "diffusion", "historical recordings"],
)
@spaces.GPU(duration=180)
def process_fn(input_audio_path: str, checkpoint_label: str, steps: int, strength: float) -> str:
"""Restores the input recording using the selected voice/instrument model, diffusion step count, and restoration strength."""
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
net, diff_params, ltas_ref, base_cfg = load_checkpoint(checkpoint_label, device)
ltas_ref = ltas_ref.to(device)
cfg = OmegaConf.create(OmegaConf.to_container(base_cfg, resolve=True))
cfg.tester.T = int(steps)
cfg.tester.posterior_sampling.xi = float(strength)
audio, sr = sf.read(input_audio_path)
sig = torch.tensor(audio, dtype=torch.float32)
if sig.dim() > 1:
sig = sig.mean(dim=-1)
if sr != cfg.exp.sample_rate:
sig = torchaudio.functional.resample(sig, sr, cfg.exp.sample_rate)
def on_progress(fraction, desc):
print(f"[{fraction:.0%}] {desc}")
restored = restore_audio(sig, cfg, net, diff_params, ltas_ref, device, on_progress=on_progress)
out_path = tempfile.NamedTemporaryFile(suffix=".wav", delete=False).name
sf.write(out_path, restored.cpu().numpy(), cfg.exp.sample_rate)
return out_path
def update_strength_default(checkpoint_label):
"""Updates the Restoration Strength slider to the selected model's paper-recommended default."""
_, base_cfg = CHECKPOINTS[checkpoint_label]
return gr.update(value=float(base_cfg.tester.posterior_sampling.xi))
with gr.Blocks() as demo:
checkpoint_dropdown = gr.Dropdown(
choices=list(CHECKPOINTS.keys()),
value="Piano (MAESTRO)",
label="Voice / Instrument",
info="Singer-specific models give the most faithful restoration when your recording actually resembles that singer.",
)
input_components = [
gr.Audio(type="filepath", label="Input Audio").harp_required(True),
checkpoint_dropdown,
gr.Slider(minimum=10, maximum=100, step=1, value=51, label="Processing Steps",
info="More steps can improve quality at the cost of processing time."),
gr.Slider(minimum=0.0, maximum=2.0, step=0.05, value=1.0, label="Restoration Strength",
info="How strongly the output is guided to match the input recording."),
]
output_components = [
gr.Audio(type="filepath", label="Restored Audio").set_info("The restored recording."),
]
checkpoint_dropdown.change(fn=update_strength_default, inputs=checkpoint_dropdown, outputs=input_components[3])
build_endpoint(
model_card=model_card,
input_components=input_components,
output_components=output_components,
process_fn=process_fn,
)
demo.queue().launch(pwa=True)
|