Spaces:
Running on Zero
Running on Zero
File size: 3,998 Bytes
85ea235 5fc96bf 85ea235 36dbf9f 85ea235 36dbf9f 0fd0c69 85ea235 0fd0c69 85ea235 0fd0c69 | 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 | from __future__ import annotations
import json
import uuid
from pathlib import Path
from tempfile import gettempdir
import gradio as gr
import soundfile as sf
try:
import spaces
except ImportError:
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)
return args[0]
from pyharp import ModelCard, build_endpoint
from pyharp.tags import Subcategory
from deepafx_st_runtime import style_transfer
MIN_AUDIO_SECONDS = 1
MAX_AUDIO_SECONDS = 30
OUTPUT_ROOT = Path(gettempdir()) / "deepafx_st_outputs"
model_card = ModelCard(
name="DeepAFx-ST",
description=(
(
"Transfer the production style (EQ, compression) of a reference recording "
"onto your audio. Repository: "
"https://github.com/adobe-research/DeepAFx-ST Paper: "
"https://arxiv.org/abs/2207.08759"
)
),
author="Christian J. Steinmetz, Nicholas J. Bryan, Joshua D. Reiss",
tags=[Subcategory.MIXING_STYLE_TRANSFER, 'audio-effects', 'style-transfer', 'mixing', 'mastering', 'production'],
)
def _validate_audio(path: str | None, label: str) -> str:
if not path:
raise gr.Error(f"Please upload {label}.")
try:
duration = sf.info(path).duration
except Exception as exc:
raise gr.Error(f"Could not read {label}: {exc}") from exc
if duration < MIN_AUDIO_SECONDS:
raise gr.Error(
f"{label} must be at least {MIN_AUDIO_SECONDS} second long."
)
if duration > MAX_AUDIO_SECONDS:
raise gr.Error(
f"{label} must be no longer than {MAX_AUDIO_SECONDS} seconds. "
f"Received {duration:.1f} seconds."
)
return path
@spaces.GPU(duration=120)
def process_fn(
input_path: str | None,
reference_path: str | None,
) -> tuple[str, str]:
input_path = _validate_audio(input_path, "input audio")
reference_path = _validate_audio(reference_path, "reference audio")
try:
audio, sample_rate, params = style_transfer(input_path, reference_path)
except Exception as exc:
raise gr.Error(f"DeepAFx-ST inference failed: {exc}") from exc
output_dir = OUTPUT_ROOT / uuid.uuid4().hex
output_dir.mkdir(parents=True, exist_ok=True)
audio_path = output_dir / "styled_output.wav"
sf.write(str(audio_path), audio.numpy(), sample_rate)
params_path = output_dir / "dsp_parameters.json"
params_path.write_text(
json.dumps(
{"model": "DeepAFx-ST", "variant": "autodiff", **params},
indent=2,
)
+ "\n",
encoding="utf-8",
)
return str(audio_path), str(params_path)
if __name__ == "__main__":
with gr.Blocks(title="DeepAFx-ST") as demo:
input_components = [
gr.Audio(type="filepath", label="Input Audio")
.harp_required(True)
.set_info("Audio to process, 1 to 30 seconds."),
gr.Audio(type="filepath", label="Reference Audio")
.harp_required(True)
.set_info("Target style — your input will be EQ'd and compressed to match this recording."),
]
output_components = [
gr.Audio(type="filepath", label="Styled Output")
.set_info("Processed audio with the reference's production style."),
gr.File(
type="filepath",
file_types=[".json"],
label="DSP Parameters",
).set_info("Predicted EQ and compressor parameters."),
]
build_endpoint(
model_card=model_card,
input_components=input_components,
output_components=output_components,
process_fn=process_fn,
)
demo.queue(default_concurrency_limit=1).launch(share=True, show_error=True, pwa=True)
|