Descargo de responsabilidad: no considero ningún algoritmo ni API para trabajar con el reconocimiento de sonido y voz. Este artículo trata sobre problemas de audio y cómo resolverlos con Go.

phono
es un marco de aplicación para trabajar con sonido. Su función principal es crear un transportador a partir de diversas tecnologías que procesará el sonido. para ti en la forma que necesitas.
¿Qué tiene que ver el transportador con él, además de las diferentes tecnologías, y por qué otro marco? Ahora vamos a resolverlo.
¿De dónde viene el sonido?
Para 2018, el sonido se ha convertido en la forma estándar en que los humanos interactúan con la tecnología. La mayoría de los gigantes de TI han creado su propio asistente de voz o lo están haciendo ahora mismo. El control por voz ya está en la mayoría de los sistemas operativos, y la mensajería de voz es una característica típica de cualquier mensajero. En el mundo, alrededor de mil nuevas empresas están trabajando en el procesamiento del lenguaje natural y alrededor de doscientas en el reconocimiento de voz.
Con música, una historia similar. Se reproduce desde cualquier dispositivo y la grabación de sonido está disponible para todos los que tengan una computadora. El software musical es desarrollado por cientos de empresas y miles de entusiastas de todo el mundo.
Si tuvo que trabajar con sonido, entonces las siguientes condiciones deberían sonarle familiares:
- El audio debe obtenerse de un archivo, dispositivo, red, etc.
- El audio debe ser procesado : agregar efectos, transcodificar, analizar, etc.
- El audio debe transferirse a un archivo, dispositivo, red, etc.
- Los datos se transmiten en pequeños buffers.
Resulta una tubería regular: hay un flujo de datos que pasa por varias etapas de procesamiento.
Soluciones
Para mayor claridad, tomemos una tarea de la vida real. Por ejemplo, necesita convertir una voz a texto:
- Grabamos audio del dispositivo
- Eliminar el ruido
- Igualar
- Pase la señal a la API de reconocimiento de voz
Como cualquier otra tarea, esta tiene varias soluciones.
Frente
Solo hardcore ciclistas programadores Grabamos el sonido directamente a través del controlador de la tarjeta de sonido, escribimos reducción de ruido inteligente y ecualizador multibanda. Esto es muy interesante, pero puede olvidarse de su tarea original durante varios meses.
Largo y muy difícil.
Normal
Una alternativa es utilizar las API existentes. Puede grabar audio usando ASIO, CoreAudio, PortAudio, ALSA y otros. También hay varios tipos de complementos para el procesamiento: AAX, VST2, VST3, AU.
Una amplia elección no significa que puede usar todo a la vez. Por lo general, se aplican las siguientes restricciones:
- Sistema operativo No todas las API están disponibles en todos los sistemas operativos. Por ejemplo, AU es tecnología nativa de OS X y solo está disponible allí.
- Lenguaje de programación La mayoría de las bibliotecas de audio están escritas en C o C ++. En 1996, Steinberg lanzó la primera versión del VST SDK, que sigue siendo el estándar de plugin más popular. Después de 20 años, ya no es necesario escribir en C / C ++: para VST hay contenedores en Java, Python, C #, Rust y quién sabe qué más. Aunque el idioma sigue siendo una limitación, ahora incluso el sonido se procesa en JavaScript.
- Funcional Si la tarea es simple y directa, no es necesario escribir una nueva aplicación. El mismo FFmpeg puede hacer mucho.
En esta situación, la complejidad depende de su elección. En el peor de los casos, debe lidiar con varias bibliotecas. Y si no tienes suerte, con abstracciones complejas e interfaces completamente diferentes.
Cual es el resultado?
Tienes que elegir entre muy complejo y complejo :
- ya sea con varias API de bajo nivel para escribir sus bicicletas
- lidiar con múltiples API e intentar hacer amigos con ellas
No importa qué método se seleccione, la tarea siempre se reduce al transportador. Las tecnologías utilizadas pueden variar, pero la esencia es la misma. El problema es que nuevamente, en lugar de resolver un problema real, tienes que escribir la bici cinta transportadora
Pero hay una salida.
phono

phono
creado para resolver problemas comunes: para " recibir, procesar y transmitir " sonido. Para hacer esto, usa la tubería como la abstracción más natural. Hay un artículo en el blog oficial de Go que describe el patrón de canalización. La idea principal de la tubería es que hay varias etapas de procesamiento de datos que funcionan independientemente entre sí e intercambian datos a través de canales. Lo que necesitas
Por qué ir
Primero, la mayoría de los programas de audio y bibliotecas están escritos en C, y Go a menudo se conoce como su sucesor. Además, hay cgo y bastantes carpetas para las bibliotecas de audio existentes. Puedes tomar y usar.
En segundo lugar, en mi opinión personal, Go es un buen idioma. No profundizaré, pero notaré su multihilo . Los canales y las gorutinas simplifican enormemente la implementación del transportador.
Abstracción
El corazón de phono
es el tipo de pipe.Pipe
. Es él quien implementa la tubería. Como en la muestra del blog , hay tres tipos de etapas:
pipe.Pump
(bomba inglesa): recepción de sonido, solo canales de salidapipe.Processor
(procesador en inglés) - procesamiento de sonido, canales de entrada y salidapipe.Sink
(sumidero inglés) - transmisión de sonido, solo canales de entrada
Inside pipe.Pipe
datos se pasan en buffers. Reglas por las cuales construir una tubería:

- Una
pipe.Pump
- Varios
pipe.Processor
colocado secuencialmente uno tras otro - Uno o más
pipe.Sink
colocado en paralelo - Todas las
pipe.Pipe
componentes de la pipe.Pipe
deben tener lo mismo:
- Tamaño del búfer (mensajes)
- Tasa de muestreo
- Numero de canales
La configuración mínima es Bomba y un fregadero, el resto es opcional.
Veamos algunos ejemplos.
Simple
Tarea: reproducir el archivo wav.
Llevémoslo al formulario " recibir, procesar, transferir ":
- Obtener audio de un archivo wav
- Transfiere audio a un dispositivo portaudio

El audio se lee y se reproduce de inmediato.
Código package example import ( "github.com/dudk/phono" "github.com/dudk/phono/pipe" "github.com/dudk/phono/portaudio" "github.com/dudk/phono/wav" )
Primero, creamos los elementos de la tubería futura: wav.Pump
y portaudio.Sink
y los pasamos a la pipe.New
constructor. La función de p.Do(pipe.actionFn) error
inicia la canalización y espera a que termine.
Mas duro
Tarea: dividir el archivo wav en muestras, componer una pista a partir de ellos, guardar el resultado y reproducirlo simultáneamente.
Una pista es una secuencia de muestras, y una muestra es un pequeño segmento de audio. Para cortar el audio, primero debe cargarlo en la memoria. Para hacer esto, use el asset.Asset
Tipo de phono/asset
paquete phono/asset
. Dividimos la tarea en pasos estándar:
- Obtener audio de un archivo wav
- Transfiere audio a la memoria
Ahora hacemos muestras con nuestras manos, las agregamos a la pista y finalizamos la tarea:
- Obtén audio de una pista
- Transferir audio a
- archivo wav
- dispositivo portaudio

De nuevo, sin una etapa de procesamiento, ¡pero dos tuberías!
Código package example import ( "github.com/dudk/phono" "github.com/dudk/phono/asset" "github.com/dudk/phono/pipe" "github.com/dudk/phono/portaudio" "github.com/dudk/phono/track" "github.com/dudk/phono/wav" )
En comparación con el ejemplo anterior, hay dos pipe.Pipe
. El primero transfiere datos a la memoria para que pueda cortar las muestras. El segundo tiene dos destinatarios al final: wav.Sink
y portaudio.Sink
. Con este esquema, el sonido se graba simultáneamente en un archivo wav y se reproduce.
Mas duro
Tarea: lea dos archivos wav, mezcle, procese el complemento vst2 y guárdelo en un nuevo archivo wav.
Hay un mixer.Mixer
simple. mixer.Mixer
en el mixer.Mixer
phono/mixer
. Puede transmitir señales de varias fuentes y obtener una mezcla. Para hacer esto, implementa simultáneamente pipe.Pump
y pipe.Sink
.
Nuevamente, la tarea consta de dos subtareas. El primero se ve así:
- Obtenga el archivo de audio wav
- Transfiere audio al mezclador
Segundo:
- Obtenga audio del mezclador.
- Procesando complemento de audio
- Transferir audio a archivo wav

Código package example import ( "github.com/dudk/phono" "github.com/dudk/phono/mixer" "github.com/dudk/phono/pipe" "github.com/dudk/phono/vst2" "github.com/dudk/phono/wav" vst2sdk "github.com/dudk/vst2" )
Ya hay tres pipe.Pipe
. pipe.Pipe
, todos interconectados a través de un mezclador. Para comenzar, use la función p.Begin(pipe.actionFn) (pipe.State, error)
. A diferencia del p.Do(pipe.actionFn) error
, no bloquea la llamada, sino que simplemente devuelve un estado que luego se puede esperar con el p.Wait(pipe.State) error
.
Que sigue
Quiero que phono
convierta en el marco de aplicación más conveniente. Si tiene un problema con el sonido, no necesita comprender API complejas y pasar tiempo estudiando estándares. Todo lo que se necesita es construir un transportador a partir de elementos adecuados y ejecutarlo.
Durante medio año, se filmaron los siguientes paquetes:
phono/wav
- lee / escribe archivos wavphono/vst2
: enlaces incompletos del SDK de VST2, mientras que solo puede abrir el complemento y llamar a sus métodos, pero no todas las estructurasphono/mixer
- mezclador, agrega señales N, sin balance y volumenphono/asset
- muestreo de búferphono/track
- lectura secuencial de muestras (estratificación rota)phono/portaudio
- reproducción de señal durante experimentos
Además de esta lista, hay una acumulación constante de nuevas ideas e ideas, que incluyen:
- Cuenta regresiva
- Variable en la tubería de vuelo
- Bomba HTTP / sumidero
- Automatización de parámetros
- Procesador de remuestreo
- Mezclador balance y volumen
- Bomba en tiempo real
- Bomba sincronizada para múltiples pistas.
- Vst2 completo
En los siguientes artículos analizaré:
pipe.Pipe
vida de la pipe.Pipe
: debido a la estructura compleja, su estado está controlado por el átomo final- cómo escribir las etapas de tu tubería
Este es mi primer proyecto de código abierto, por lo que agradeceré cualquier ayuda y recomendaciones. De nada.
Referencias