diff options
Diffstat (limited to 'crates/asist-audio/src/lib.rs')
| -rw-r--r-- | crates/asist-audio/src/lib.rs | 58 |
1 files changed, 29 insertions, 29 deletions
diff --git a/crates/asist-audio/src/lib.rs b/crates/asist-audio/src/lib.rs index de3f002..a339d16 100644 --- a/crates/asist-audio/src/lib.rs +++ b/crates/asist-audio/src/lib.rs @@ -1,35 +1,35 @@ -//! Entrada y salida de audio, y el detector de voz que las separa en turnos. +//! Audio input and output, and the voice detector that splits them into turns. //! -//! La regla que gobierna este crate: **la retrollamada de audio no bloquea -//! nunca**. cpal la ejecuta en un hilo de tiempo real y cualquier espera ahí -//! se oye como un chasquido, así que se limita a copiar muestras a un canal -//! (entrada) o a vaciar un anillo ya rellenado (salida). Todo el trabajo real -//! —remuestreo, VAD, HTTP— ocurre en hilos normales al otro lado. +//! The rule that governs this crate: **the audio callback never blocks**. cpal +//! runs it on a real-time thread and any wait there is heard as a click, so it +//! only copies samples to a channel (input) or drains an already filled ring +//! (output). All the real work (resampling, VAD, HTTP) happens on regular +//! threads on the other side. pub mod capture; pub mod playback; pub mod vad; -/// Se reexporta para que el binario pueda listar dispositivos sin volver a -/// declarar cpal y arriesgarse a resolver otra versión. +/// Re-exported so the binary can list devices without declaring cpal +/// again and risking resolving another version. pub use cpal; pub use capture::{Capture, CaptureBlock, InputFormat}; pub use playback::{detached_handle, Playback, PlaybackHandle}; pub use vad::{Gate, Segmenter, Utterance, VoiceEvent}; -/// Frecuencia a la que trabaja Canary. La captura se abre directamente aquí -/// cuando el dispositivo lo permite, lo que quita el remuestreo del camino. +/// Rate Canary works at. Capture is opened directly at this rate when the +/// device allows it, which takes resampling off the path. pub const ASR_SAMPLE_RATE: u32 = 16_000; -/// Frecuencia a la que sintetiza qwentts. +/// Rate qwentts synthesizes at. pub const TTS_SAMPLE_RATE: u32 = 24_000; -/// Nombre legible de un dispositivo. +/// Human-readable device name. /// -/// `DeviceTrait::name` está obsoleto en cpal 0.17 a favor de `description`, -/// que devuelve una ficha entera; aquí sólo interesa el nombre, y tener un -/// único sitio donde extraerlo evita repetir el desempaquetado. +/// `DeviceTrait::name` is deprecated in cpal 0.17 in favour of `description`, +/// which returns a whole record; only the name matters here, and having a +/// single place to extract it avoids repeating the unwrapping. pub fn describe(device: &impl cpal::traits::DeviceTrait) -> String { device .description() @@ -37,7 +37,7 @@ pub fn describe(device: &impl cpal::traits::DeviceTrait) -> String { .unwrap_or_else(|_| "desconocido".into()) } -/// Nivel RMS de un bloque, la medida con la que el VAD decide. +/// RMS level of a block, the measure the VAD decides on. pub fn rms(samples: &[f32]) -> f32 { if samples.is_empty() { return 0.0; @@ -46,11 +46,11 @@ pub fn rms(samples: &[f32]) -> f32 { (sum / samples.len() as f32).sqrt() } -/// Mezcla a mono y remuestrea linealmente a `target`. +/// Mixes down to mono and resamples linearly to `target`. /// -/// La interpolación lineal basta: el dispositivo ya entrega la señal limitada -/// en banda, y un remuestreador decente costaría más que la decodificación a -/// la que alimenta. +/// Linear interpolation is enough: the device already delivers a +/// band-limited signal, and a decent resampler would cost more than the +/// decoding it feeds. pub fn to_mono_at(samples: &[f32], format: InputFormat, target: u32) -> Vec<f32> { let mono: Vec<f32> = if format.channels > 1 { samples @@ -78,7 +78,7 @@ pub fn to_mono_at(samples: &[f32], format: InputFormat, target: u32) -> Vec<f32> .collect() } -/// Convierte s16le a f32 en [-1, 1]. Es el formato en el que el TTS entrega. +/// Converts s16le to f32 in [-1, 1]. It is the format the TTS delivers. pub fn s16le_to_f32(bytes: &[u8], out: &mut Vec<f32>) { for pair in bytes.chunks_exact(2) { let sample = i16::from_le_bytes([pair[0], pair[1]]); @@ -91,13 +91,13 @@ mod tests { use super::*; #[test] - fn el_rms_de_una_senal_constante_es_su_amplitud() { + fn rms_of_a_constant_signal_is_its_amplitude() { assert!((rms(&[0.5; 100]) - 0.5).abs() < 1e-6); assert_eq!(rms(&[]), 0.0); } #[test] - fn el_estereo_se_mezcla_a_mono_promediando() { + fn stereo_is_mixed_to_mono_by_averaging() { let format = InputFormat { sample_rate: 16_000, channels: 2, @@ -107,17 +107,17 @@ mod tests { } #[test] - fn el_remuestreo_ajusta_la_duracion() { + fn resampling_adjusts_the_duration() { let format = InputFormat { sample_rate: 48_000, channels: 1, }; let out = to_mono_at(&vec![0.0; 4800], format, 16_000); - assert_eq!(out.len(), 1600, "48 kHz -> 16 kHz debe dividir por tres"); + assert_eq!(out.len(), 1600, "48 kHz -> 16 kHz must divide by three"); } #[test] - fn a_la_misma_frecuencia_el_remuestreo_no_toca_nada() { + fn resampling_at_the_same_rate_changes_nothing() { let format = InputFormat { sample_rate: 16_000, channels: 1, @@ -127,7 +127,7 @@ mod tests { } #[test] - fn s16le_recorre_el_rango_completo() { + fn s16le_covers_the_full_range() { let mut out = Vec::new(); s16le_to_f32(&[0x00, 0x00, 0xff, 0x7f, 0x00, 0x80], &mut out); assert_eq!(out[0], 0.0); @@ -136,13 +136,13 @@ mod tests { } #[test] - fn un_byte_suelto_no_produce_una_muestra_a_medias() { + fn stray_byte_does_not_produce_a_partial_sample() { let mut out = Vec::new(); s16le_to_f32(&[0x00, 0x00, 0x11], &mut out); assert_eq!( out.len(), 1, - "el byte impar se ignora en vez de corromper la muestra" + "the odd byte is ignored instead of corrupting the sample" ); } } |