aboutsummaryrefslogtreecommitdiff
path: root/lib/src/producer/engines/denoise_dfn.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/src/producer/engines/denoise_dfn.py')
-rw-r--r--lib/src/producer/engines/denoise_dfn.py98
1 files changed, 98 insertions, 0 deletions
diff --git a/lib/src/producer/engines/denoise_dfn.py b/lib/src/producer/engines/denoise_dfn.py
new file mode 100644
index 0000000..66a8cf6
--- /dev/null
+++ b/lib/src/producer/engines/denoise_dfn.py
@@ -0,0 +1,98 @@
+from __future__ import annotations
+
+import sys
+import types
+import urllib.request
+import zipfile
+from pathlib import Path
+
+import numpy as np
+
+from .. import dsp, lazy
+from .base import blend, device_name, pick_device
+
+MODELS_DIR = lazy.DATA_DIR / "models"
+TAG = "v0.5.6"
+MODEL_ZIPS = {
+ "DeepFilterNet3": "models/DeepFilterNet3.zip",
+ "DeepFilterNet2": "models/DeepFilterNet2.zip",
+}
+BASE_URL = f"https://raw.githubusercontent.com/Rikorose/DeepFilterNet/{TAG}"
+
+
+def _shim_torchaudio_backend() -> None:
+ try:
+ import torchaudio.backend # noqa: F401
+ except Exception:
+ pkg = sys.modules.get("torchaudio")
+ if pkg is not None and "torchaudio.backend" not in sys.modules:
+ stub = types.ModuleType("torchaudio.backend")
+ stub.__path__ = []
+ sys.modules["torchaudio.backend"] = stub
+ pkg.backend = stub
+
+
+def ensure_model(model: str) -> Path:
+ target = MODELS_DIR / model
+ if (target / "config.ini").is_file():
+ return target
+ url = f"{BASE_URL}/{MODEL_ZIPS[model]}"
+ MODELS_DIR.mkdir(parents=True, exist_ok=True)
+ zpath = MODELS_DIR / f"{model}.zip"
+ print(f"[producer] downloading {model} weights...", flush=True)
+ urllib.request.urlretrieve(url, zpath)
+ with zipfile.ZipFile(zpath) as z:
+ z.extractall(target)
+ zpath.unlink(missing_ok=True)
+ if not (target / "config.ini").is_file():
+ inner = list(target.glob(f"**/{model}/config.ini"))
+ if inner:
+ src = inner[0].parent
+ for f in src.iterdir():
+ f.rename(target / f.name)
+ if not (target / "config.ini").is_file():
+ raise RuntimeError(f"{model} weights download failed")
+ return target
+
+
+def denoise(
+ x: np.ndarray, sr: int, strength: float, device_pref: str = "auto"
+) -> tuple[np.ndarray, str, str]:
+ lazy.ensure(["deepfilternet==0.5.6"], purpose="DeepFilterNet")
+ lazy.ensure_torch()
+ _shim_torchaudio_backend()
+ model_name = "DeepFilterNet3"
+ try:
+ model_dir = ensure_model(model_name)
+ except Exception:
+ model_name = "DeepFilterNet2"
+ model_dir = ensure_model(model_name)
+ from df.enhance import enhance as df_enhance
+ from df.enhance import init_df
+
+ device = pick_device(device_pref)
+ model, df_state, _ = init_df(
+ model_base_dir=str(model_dir),
+ post_filter=strength >= 0.95,
+ log_level="error",
+ log_file=None,
+ )
+ try:
+ model = model.to(device)
+ dev = device
+ except Exception:
+ dev = "cpu"
+ sr_df = int(df_state.sr())
+ xin = dsp.resample(x, sr, sr_df)
+ import torch
+
+ xin_t = torch.from_numpy(xin.astype(np.float32)).unsqueeze(0)
+ y = df_enhance(model, df_state, xin_t)
+ if isinstance(y, torch.Tensor):
+ y = y.detach().cpu().numpy()
+ y = np.asarray(y, dtype=np.float32)
+ if y.ndim > 1:
+ y = y.reshape(-1)
+ y = dsp.resample(y, sr_df, sr)
+ y = blend(x, y, strength)
+ return y, f"dfn ({model_name})", f"{device_name(dev)} ({dev})"