La fuente se elige en pantalla: el micrófono o el bucle de captura del sistema, es decir, lo que el PC está reproduciendo. El audio entra a dieciséis mil hercios, se lee en cuadros de doscientos milisegundos, se mezcla a mono y se acumula hasta el tamaño del fragmento. Cuatro segundos es un compromiso medido, no un número redondo: con dos segundos hay menos retraso pero el modelo pierde el contexto y traduce peor la frase larga; con seis u ocho gana contexto a costa de latencia. Cuatro es el punto donde se puede seguir una conversación.
La cola tiene capacidad máxima de dos fragmentos. Cuando se llena, se descarta el más viejo y entra el nuevo. Es la decisión que más me gusta del proyecto: si el modelo va lento, el subtítulo no se acumula ni se retrasa un minuto entero, simplemente muestra el presente. Un subtítulo de hace cuarenta segundos no sirve para nada.
El reconocimiento corre con faster-whisper sobre CTranslate2 y tres parámetros que valen más que el código entero: detección de voz activa con trescientos milisegundos de silencio mínimo, haz de cinco, y memoria del texto anterior desactivada. Esa última es la que evita el fallo clásico de Whisper, que se pone a repetir y a inventar agarrándose a lo que dijo en el corte previo. El modelo se carga en el hilo de trabajo, nunca en el de interfaz, así que la ventana responde mientras el modelo despierta.
Encima de la ventana: rectángulo redondeado dibujado a mano con QPainter, arrastre para colocarla donde no tape, y modo «ignorar clics» que deja pasar el ratón a lo que hay debajo. Sin eso, una app así estorba en dos minutos.
micrófono · bucle de audio del sistema
→ lectura 200 ms @ 16 kHz · mezcla a mono
→ fragmento de 4 s → cola (máx. 2, se descarta el viejo)
→ Whisper Small · INT8 · CPU · ja → en · haz 5 · VAD 300 ms
→ [si se pide español] traductor neuronal en → es · haz 4
→ ventana flotante sin borde, siempre encima, clics atravesables