audio-denoise / README.md
Azuredraco's picture
Despliegue desde GitHub
c6a2c55 verified
|
Raw History Blame Contribute Delete
11.8 kB
---
title: Audio Denoise
emoji: 🎙️
colorFrom: blue
colorTo: green
sdk: gradio
sdk_version: "6.9.0"
python_version: "3.12"
app_file: app.py
pinned: false
short_description: Limpieza de voz y control de entregas de audio
---
# 🎙️ Limpieza y control de voz — documentación técnica
> **¿Vas a usar la app?** Todo lo que necesitas está en la pestaña **❓ Ayuda** de la propia app.
> Este documento es para mantenerla: cómo está hecha, cómo crear proyectos nuevos y cómo publicarla.
La app reduce el ruido de grabaciones de voz sin perder naturalidad y comprueba que cada audio cumple la especificación técnica de un cliente (un *perfil*). Si no cumple, genera la versión corregida y un informe en Excel. Funciona en Hugging Face con **ZeroGPU**; si no hay cuota de GPU, sigue en CPU automáticamente.
---
## 1. Publicar cambios en Hugging Face
El código vive en GitHub y el Space es una copia que se actualiza con un botón.
1. Los cambios tienen que estar en la rama `main` de GitHub. Si vienen en otra rama, primero hay que fusionar el *pull request* con **Merge pull request**.
2. En GitHub: **Actions** → **Desplegar en Hugging Face** → **Run workflow** → **Run workflow**.
3. Al cabo de un minuto aparece ✅. El Space se reconstruye solo: con cambios en `requirements.txt` o `packages.txt` tarda 5–10 minutos; si no, menos de uno.
Configuración, una sola vez (ya hecha):
| Dónde | Qué |
|---|---|
| GitHub → Settings → Secrets and variables → Actions → **Secrets** | `HF_TOKEN`: token de Hugging Face de tipo **Write** |
| GitHub → … → **Variables** (opcional) | `HF_SPACE`: si no existe, se usa `Azuredraco/audio-denoise` |
Alternativa desde el PC: `python scripts/deploy_hf.py --space Azuredraco/audio-denoise`. Usa el token de `hf auth login` o el de la variable de entorno `HF_TOKEN`.
El Space queda como copia exacta del repositorio, sin `tests/`, `scripts/` ni `.github/`.
### Versión para Windows
Cada vez que entra un cambio en `main`, GitHub construye **solo** la versión de escritorio (workflow *Versión para Windows*). La prueba en un Windows real y la publica en **https://huggingface.co/Azuredraco/limpieza-de-voz-windows**. El Space tiene un enlace a esa página. Tarda unos 15–20 minutos. También se puede lanzar a mano desde **Actions → Versión para Windows → Run workflow**.
- **Instalador** `Instalar-Limpieza-de-voz.exe`: no pide permisos de administrador. Crea accesos directos en el escritorio y en el menú Inicio, y al ejecutar uno nuevo actualiza encima.
- **Portable** `Limpieza-de-voz-portable.zip`: se descomprime y se abre con `Iniciar.bat`.
- Lleva dentro su propio Python 3.11, las dependencias (PyTorch CPU) y los modelos: **funciona sin internet**. Ocupa ~1 GB instalado.
- Por dentro es la misma app (`app.py`) en `127.0.0.1`. `desktop/iniciar.py` la arranca y abre el navegador; la ventana negra es el servidor.
- Ficheros: `desktop/` (lanzador, prueba de humo, icono, script de Inno Setup y publicación) y `requirements-desktop.txt`.
El repositorio de GitHub es privado, por eso el instalador se publica en Hugging Face: así se descarga sin necesidad de cuenta.
---
## 2. Perfiles de proyecto (`perfiles/*.yaml`)
Cada proyecto o cliente es un fichero YAML. Al crear uno nuevo, aparece solo en el desplegable «Proyecto».
| Fichero | Nombre en la app | Uso |
|---|---|---|
| `multiling_es-es_01.yaml` | MultiLing · voz femenina es-ES (40 min) | Encargo MultiLing: WAV PCM, 48 kHz, ≥ 24 bits, SNR ≥ 50 dB. Sin recortes ni cambios de volumen (el cliente quiere la toma entera). Controla los 6 entregables y el objetivo de 40 min. |
| `analizador_v4.yaml` | Proyecto 12 h 30 min · mismas reglas que el analizador v4 | Las mismas reglas que el *Analizador de audio v4* en HTML: WAV PCM 24 bits, 48 kHz, mono, pico ≤ −3 dBFS, RMS de voz −30…−20 dBFS, ruido ≤ −40 dB y silencios de 0,5–0,7 s. |
| `asr_dialogo_dos_pistas.yaml` | ASR · diálogo a dos pistas | Encargo ASR Dual-Track: WAV PCM 16 bits, 48 kHz, mono, espectro > 22 kHz, ruido de fondo ≤ −50 dBFS, voz > 5000 (escala 16 bits), sin saturación. Arranca en nivel «Solo formato» (el PDF pide sin procesado). Comprueba parejas de pistas (misma duración, sin voz cruzada). |
| `libre.yaml` | Solo limpiar ruido · sin reglas de cliente | Solo limpieza; conserva formato, frecuencia y canales. |
### Crear un perfil nuevo
Copia el que más se parezca, cámbiale el nombre al fichero y edita los valores. Todas las secciones son opcionales: lo que no pongas no se comprueba.
```yaml
nombre: "Cliente X · audiolibro (10 h)" # lo que se ve en el desplegable
descripcion: "WAV 24 bits · 44,1 kHz · …" # resumen técnico de una línea
explicacion: | # lo que ve el usuario bajo el desplegable (Markdown)
- **Qué pide el cliente:** …
- **Qué hace la corrección:** …
orden: 3 # posición en el desplegable
procesar_siempre: false # true = limpiar aunque ya cumpla
formato:
contenedor: WAV # WAV | FLAC | AIFF
pcm_entero: true # exige PCM entero (no coma flotante)
bits: 24 # exactamente 24… (o bien) bits_min: 24 → 24 o más
frecuencia: 48000 # Hz; la corrección remuestrea
ancho_banda_min_hz: 22000 # el espectro debe llegar más allá (detecta audio filtrado, comprimido o de 44,1 kHz)
canales: 1 # 1 = exige mono (la casilla «Convertir a mono» sale marcada); null = sin requisito
niveles:
pico_max_dbfs: -3.0 # techo de picos (se aplica limitador)
rms_voz: {min: -30, max: -20, objetivo: -25} # volumen medio de la voz; corrige al objetivo
amplitud_voz_min: 5000 # muestra más alta de la voz en escala de 16 bits (0–32767)
ruido:
snr_min_db: 50 # voz activa frente a ruido de las pausas
ruido_relativo_max_db: -40 # primeros/últimos 0,4 s frente a la voz (criterio del analizador v4)
ruido_fondo_max_dbfs: -50 # nivel absoluto del ruido de las pausas
silencios: # null = no tocar inicio ni final
min_s: 0.5
max_s: 0.7
objetivo_s: 0.6
relleno: tono_sala # tono_sala (ruido ambiente real, recomendado) | digital (ceros)
saturacion_max_muestras: 0
pistas_pareadas: false # true = diálogo a dos pistas: comprueba duraciones idénticas y voz cruzada
procesado: # valores por defecto de «Opciones avanzadas»
reduccion_db: 24 # 12 Suave · 24 Natural · 36 Fuerte · null Máximo
paso_alto_hz: 70 # null = sin filtro
conservar_ultrasonidos: true
salida: {contenedor: WAV, subtipo: PCM_24} # null = como el original
modo_defecto: ninja # nivel de procesado inicial: formato | permitido | ninja (el usuario lo cambia en la app)
entregables: # opcional: control de ficheros y duración total
objetivo_total_s: 2400
ficheros:
- {nombre: "nonverbal_laughter", duracion_min_s: 30}
- {nombre: "full recording_part 1", duracion_aprox_s: 760}
```
Los nombres de los entregables se comparan sin distinguir mayúsculas, extensión, espacios ni guiones bajos.
---
## 3. Cómo funciona
### Cadena de corrección (`pipeline.py`)
1. **Canales:** se conservan, salvo que se marque «Convertir a mono».
2. **Paso alto** Butterworth de fase cero, a 70 Hz por defecto. Quita retumbes, golpes graves y DC.
3. **Remuestreo** con SoX VHQ (fase lineal, sin desfase) a la frecuencia exigida.
4. **DeepFilterNet3** a 48 kHz, por bloques de 60 s con 5 s de contexto y fundido cruzado. Así los ficheros de 30 min o más tienen memoria acotada y llamadas a GPU cortas.
- Si no se alcanza el ruido exigido, se escala la reducción: 24 → 36 dB → sin límite.
- Como último recurso, un expansor de −15 dB solo en las pausas, con 100 ms de margen antes de la voz y 200 ms después.
5. **Más de 48 kHz:** la banda > 20 kHz no pasa por el modelo. Se conserva del original mediante un cruce FIR complementario, con una ganancia que sigue la reducción aplicada en 12–20 kHz.
6. **Silencios inicial/final:** recorte, o relleno con tono de sala (el tramo sin voz más silencioso de la propia toma, con fundidos de potencia constante).
7. **Nivel:** ganancia hasta el RMS objetivo y limitador de picos con anticipación. El limitador es un mínimo deslizante suavizado, sin sobreoscilación garantizada.
8. **Escritura** (dither TPDF si se baja a 16 bits) y **nueva medición del fichero escrito**: la columna «Después» es real.
### Métricas (`metrics.py`, `dnsmos.py`)
- **Pico** (dBFS) y **pico real** (dBTP, sobremuestreo ×4, por bloques).
- **RMS de voz** entre la primera y la última voz, como el analizador v4.
- **Ruido relativo** de los primeros/últimos 0,4 s frente a la voz.
- **SNR**: voz activa frente a ruido de pausas.
- **Silencios**: la detección de voz ignora clics y golpes de menos de 120 ms.
- **Saturación** y **LUFS** (BS.1770-4; coeficientes verificados con la tabla ITU).
- **DNSMOS** P.835 de Microsoft: SIG (voz), BAK (fondo) y OVRL (global), de 1 a 5. Usa como mucho 10 ventanas de 9 s repartidas por el audio. Es opcional («⭐ Poner nota de calidad al corregir», desmarcada por defecto) porque en CPUs modestas triplica el tiempo.
### ZeroGPU
- `denoise_core.py` coloca el modelo en `cuda` a nivel de módulo (patrón oficial de ZeroGPU) y decora la inferencia con `@spaces.GPU` y duración dinámica. Cada llamada cubre hasta 5 min de audio.
- **La GPU solo se usa con audios de 90 s o más.** Para audios cortos, la espera de ZeroGPU (cola, asignación, comprobación de cuota) cuesta más que procesar en CPU.
- Si una llamada falla (cuota, cola, timeout), el resto del fichero va por CPU con el mismo resultado. Durante 15 minutos no se vuelve a intentar con GPU, para no repetir la espera.
- Si el original tiene mucho más ruido del permitido, la corrección empieza directamente por el escalón de reducción necesario. Así no se pasa el modelo varias veces.
- Cuota diaria según la documentación de HF: 2 min sin sesión, 5 min con cuenta gratuita, 40 min con PRO.
### Ficheros
| Fichero | Contenido |
|---|---|
| `app.py` | Interfaz Gradio y textos de ayuda para el usuario |
| `ui_html.py` | Tarjetas de resultados, CSS (móvil, modo claro/oscuro) |
| `pipeline.py` | Analizar y corregir según un perfil |
| `denoise_core.py` | DeepFilterNet3 + ZeroGPU + respaldo en CPU |
| `dsp.py` | Remuestreo, filtros, detección de voz, silencios, limitador, expansor |
| `metrics.py` · `dnsmos.py` | Mediciones |
| `profiles.py` · `perfiles/` | Carga de perfiles y comprobaciones |
| `vad.py` | Detector de voz neuronal (Silero VAD) para los ruidos sueltos |
| `pairs.py` | Parejas de pistas: misma duración y voz cruzada |
| `report.py` | Informe Excel y CSV |
| `audio_io.py` | Lectura (soundfile o ffmpeg) y escritura |
| `models.py` | Descarga de modelos (DeepFilterNet3, DNSMOS, Silero VAD) verificada por SHA-256 |
---
## 4. Trabajo en local (Windows / PyCharm)
```bash
python -m venv .venv
.venv\Scripts\activate # Linux/Mac: source .venv/bin/activate
pip install -r requirements-dev.txt
python app.py # http://localhost:7860
python -m pytest -q tests
```
`deepfilternet` 0.5.6 compila una parte en Rust si no hay paquete precompilado para tu sistema; en Windows hay que instalar [Rust](https://rustup.rs) la primera vez. Las versiones están fijadas en `requirements.txt`: `deepfilternet` exige `numpy < 2` y ZeroGPU exige `torch ≥ 2.8`. Los modelos se descargan la primera vez en `~/.cache/audio-denoise`.
## Créditos
- [DeepFilterNet](https://github.com/Rikorose/DeepFilterNet) (H. Schröter et al.), reducción de ruido.
- [DNSMOS](https://github.com/microsoft/DNS-Challenge/tree/master/DNSMOS) (Microsoft), calidad percibida.