De la música de un bit - meowbit

El artículo anterior dedicado a la placa de entrenamiento de Meowbit y las implementaciones de Python terminó con una mención de la incapacidad de CircuitPython para reproducir música simultáneamente con el juego: CircuitPython no permite que los controladores de interrupciones se escriban en Python, y sin esto, un retraso para el redibujado de la pantalla (aproximadamente 0,15 s) "cuelga" el sonido ... Sin embargo, a menudo se necesita el sonido de fondo, y para la mayoría de las placas compatibles (100 de 189), CircuitPython incluye un módulo audioio



o audiopwmio



que implementa el sonido de fondo en formas nativas de la placa. Desafortunadamente, para Meowbit (y en general para placas basadas en STM32) ni uno ni el otro módulo están implementados; pero en un proyecto de código abierto, esto se puede arreglar. Encuentra el huevo de pascua en la foto Primero que nada: ¿por qué hay dos módulos diferentes para reproducir sonido con API completamente idénticas, y uno u otro es compatible con diferentes placas?













Así es como se ven ⅒ segundos de un archivo

WAV normal (16 bits) en un editor de audio (como Audacity) :





El valor cambia suavemente dentro del rango de aproximadamente -0,2 a +0,2 "unidades convencionales". Si el voltaje suministrado al altavoz electrodinámico se cambia de la misma manera , entonces la membrana oscilará con la misma suavidad, desde aproximadamente 0,2 de su desviación máxima posible en una dirección a 0,2 desviación en la otra dirección. El módulo audioio



implementa tal reproducción de sonido: a través del DAC cambia suavemente el voltaje en la salida conectada al altavoz.



Pero en Meowbit, en lugar de un altavoz, hay un tweeter piezoeléctrico barato, incapaz de desviar la membrana a posiciones intermedias: se mueve muy rápidamente de una posición extrema a otra extrema, y ​​permanece allí hasta la siguiente transición. Piense en ello como un sonido con una resolución de un bit por muestra:





De esta manera, es imposible transmitir el cambio en el volumen del sonido, pero teóricamente es posible transmitir todos los armónicos presentes en él, si, en paralelo con la reducción de 32768 veces en la resolución, la frecuencia de muestreo aumenta en la misma cantidad (es decir, hasta cientos de megahercios). Es poco probable que una membrana de tweeter piezoeléctrico pueda vibrar a esa frecuencia; pero esto se puede utilizar para su ventaja: si aprende a cambiar el voltaje del zumbador, cuando la membrana está a la mitad, puede producir sonidos de volumen intermedio. Una búsqueda de patentes confirma que la gente está explorando las posibilidades de usar el tweeter piezoeléctrico de esta manera. No nos adentraremos en esta jungla y dejaremos la frecuencia de muestreo WAV habitual de decenas de kilohercios. Para música donde los armónicos fundamentales están en la región de kilohercios, esto es suficiente; el habla, sin embargo, se convierte en un ruido apenas inteligible.Puede comparar cómo se percibe la muestra de sonido de ocho segundos que usé, reproducida en una sonda piezoeléctrica de un bit: primero la original, luego la versión de un bit, luego la grabación de Meowbit con un micrófono.





El módulo audiopwmio



implementa la reproducción de sonido a través de una salida digital usando PWM : una grabación de audio de un bit se convierte en una secuencia de retardos entre cambiar la

salida al valor opuesto.



Entonces, el plan de implementación general audiopwmio



para Meowbit es el siguiente:



  1. Traducimos la grabación de audio transmitida por el usuario al formato PWM (una lista de retrasos entre conmutadores);
  2. . pulseio



    , , – – Python .


No fue inmediatamente obvio que había otro aspecto de la implementación del que ocuparse: el almacenamiento en búfer de audio. Mi muestra de prueba de 8 segundos es 8 * 22050 * 2 ≈ 340 KB - tres veces el tamaño de toda la RAM de Meowbit; por lo tanto, tendrá que cargarse en la memoria pieza por pieza. La implementación estándar audiocore.WaveFile



carga el archivo WAV en fragmentos de 256 bytes, lo que corresponde a 128 muestras o 5,8 ms de tiempo de reproducción. Esto significa que, en promedio, cada 5,8 ms audiopwmio



tendrá que solicitar que se vuelva a llenar el búfer; no hay salida, excepto colocar esta llamada en el mismo controlador de interrupciones del temporizador; de lo contrario, volver a dibujar la pantalla puede retrasar el llenado del búfer en unos buenos cien milisegundos. Sin embargo, esto no resuelve completamente el problema: ¿qué sucede si se produce una interrupción del temporizador mientras se vuelve a dibujar la pantalla? La pantalla de Meowbit está conectada a través del bus SPI , la unidad flash está conectada a través de él, lo que significa que aún es imposible acceder al flash mientras se redibuja la pantalla.



El resultado es una implementación audiopwmio



capaz de reproducir grabaciones de audio desde la memoria (o generadas por procedimientos) con la mayor calidad posible en Meowbit; pero las grabaciones de audio de archivos se reproducen solo en ausencia de llamadas simultáneas a la pantalla y al flash. Esto es suficiente para la banda sonora de juegos simples. PR con mi implementación ha estado esperando una revisión durante más de una semana, y no audiopwmio



se sabe cuándo aparecerá Meowbit en la versión oficial de CircuitPython; pero eso no impide que alguien desee compilar CircuitPython para sí mismo con mi complemento.










All Articles