Stable-Audio-3 / stable_audio_runtime.py
LING
Use Stable Audio 3 compatible runtime
23df7cf
Raw
History Blame Contribute Delete
4.89 kB
from __future__ import annotations
import subprocess
import sys
import tempfile
import threading
from pathlib import Path
MODEL_REPO = "stabilityai/stable-audio-3-small-music"
MODEL_REVISION = "0fef1392cd842149a2b6d445e181c97608faac06"
STABLE_AUDIO_TOOLS_REVISION = "3241adba4fc2a85cf5b29d9eb68d42f40a28e820"
OUTPUT_ROOT = Path(tempfile.gettempdir()) / "stable_audio_3_outputs"
_MODEL = None
_MODEL_CONFIG = None
_MODEL_LOCK = threading.Lock()
def _ensure_stable_audio_tools() -> None:
try:
import stable_audio_tools # noqa: F401
return
except ImportError:
pass
subprocess.check_call(
[
sys.executable,
"-m",
"pip",
"install",
"--quiet",
"--no-deps",
(
"git+https://github.com/Stability-AI/stable-audio-tools.git@"
f"{STABLE_AUDIO_TOOLS_REVISION}"
),
]
)
_ensure_stable_audio_tools()
def _load_model():
global _MODEL, _MODEL_CONFIG
if _MODEL is not None:
return _MODEL, _MODEL_CONFIG
with _MODEL_LOCK:
if _MODEL is not None:
return _MODEL, _MODEL_CONFIG
import torch
from stable_audio_tools.models import pretrained
original_download = pretrained.hf_hub_download
def pinned_download(repo_id, *args, **kwargs):
if repo_id == MODEL_REPO:
kwargs.setdefault("revision", MODEL_REVISION)
return original_download(repo_id, *args, **kwargs)
pretrained.hf_hub_download = pinned_download
try:
model, config = pretrained.get_pretrained_model(MODEL_REPO)
finally:
pretrained.hf_hub_download = original_download
model = model.to("cuda").to(torch.float16)
model.eval().requires_grad_(False)
_MODEL = model
_MODEL_CONFIG = config
return _MODEL, _MODEL_CONFIG
def _load_audio(path: str):
import torch
import torchaudio
audio, sample_rate = torchaudio.load(path)
if audio.shape[0] > 2:
audio = audio[:2]
return int(sample_rate), audio.to(torch.float32)
def _save_audio(output, sample_rate: int) -> str:
import soundfile as sf
import torch
output = output.permute(1, 0, 2).reshape(output.shape[1], -1)
output = output.to(torch.float32)
peak = output.abs().max().clamp(min=1e-9)
output = output.div(peak).clamp(-1, 1).cpu().numpy().T
OUTPUT_ROOT.mkdir(parents=True, exist_ok=True)
output_dir = Path(tempfile.mkdtemp(dir=OUTPUT_ROOT))
output_path = output_dir / "stable_audio_3_edit.wav"
sf.write(output_path, output, sample_rate, subtype="PCM_16")
return str(output_path)
def edit_audio(
audio_path: str,
prompt: str,
mode: str,
edit_start: float,
edit_end: float,
continuation_length: float,
strength: float,
seed: int,
) -> str:
import torch
import torchaudio
model, config = _load_model()
from stable_audio_tools.inference.generation import (
generate_diffusion_cond_inpaint,
)
sample_rate = int(config["sample_rate"])
sample_size = int(config["sample_size"])
source_rate, source = _load_audio(audio_path)
source_duration = source.shape[-1] / source_rate
if source_rate != sample_rate:
source = torchaudio.functional.resample(source, source_rate, sample_rate)
model_dtype = next(model.parameters()).dtype
source_tuple = (sample_rate, source.to(model_dtype))
if mode == "Continue":
output_duration = source_duration + continuation_length
else:
output_duration = source_duration
conditioning = [{"prompt": prompt, "seconds_total": output_duration}]
kwargs = {
"steps": 8,
"cfg_scale": 1.0,
"conditioning": conditioning,
"sample_size": sample_size,
"sampler_type": "pingpong",
"seed": int(seed) if seed > 0 else -1,
"device": "cuda",
"sigma_max": 1.0,
"apg_scale": 1.0,
"duration_padding_sec": 6.0,
}
if mode == "Restyle":
kwargs["init_audio"] = source_tuple
kwargs["init_noise_level"] = float(strength)
elif mode == "Inpaint":
kwargs["inpaint_audio"] = source_tuple
kwargs["inpaint_mask_start_seconds"] = float(edit_start)
kwargs["inpaint_mask_end_seconds"] = float(edit_end)
elif mode == "Continue":
kwargs["inpaint_audio"] = source_tuple
kwargs["inpaint_mask_start_seconds"] = float(source_duration)
kwargs["inpaint_mask_end_seconds"] = float(output_duration)
else:
raise ValueError(f"Unknown edit mode: {mode}")
with torch.inference_mode():
output = generate_diffusion_cond_inpaint(model, **kwargs)
output = output[..., : int(output_duration * sample_rate)]
return _save_audio(output, sample_rate)