Chiptunes en tu escritorio: un reproductor de música de arcade con CircuitPython

Te acuerdas de los bleeps y bloops de las maquinitas de los 80? Esos sonidos no salían de un MP3: los generaba un chip dedicado, el famoso AY-3-8910, un generador de sonido programable de 3 voces que estaba adentro de un montón de arcades y computadores de la época. En este proyecto vas a revivir ese sonido armando un reproductor de chiptunes portátil que corre CircuitPython y emula ese chip por software con el módulo synthio.

La idea es simple pero entretenida: cargas archivos de música de videojuegos (formato .VGM / .VGZ) en una tarjeta microSD, los eliges desde una pantalla táctil y los escuchas por un DAC I2S de buena calidad conectado a unos parlantes. Al terminar vas a saber cómo emular hardware de sonido retro por software, cómo sacar audio digital I2S desde un microcontrolador y cómo montar una interfaz táctil de reproductor (play, pausa, siguiente, repetir) en pocas líneas.

Este tutorial está inspirado en la guía original de Adafruit (Liz Clark y los Ruiz Brothers), que usa un Feather RP2350 con una TFT FeatherWing. Acá lo reescribimos con enfoque chileno y te mostramos además cómo re portarlo a un ESP32-S3, que es mucho más fácil de conseguir en el país. El código CircuitPython lo dejamos fiel al original: lo que cambia es el hardware alrededor.

Módulo DAC I2S PCM5102 con salida de audio de nivel de línea

Cómo funciona: emular un chip de sonido de los 80

Los archivos VGM no son audio grabado, son un log de comandos: "escribe este valor en tal registro del chip de sonido en este instante". Para reproducirlos necesitas un chip AY-3-8910 real... o emularlo. Acá el microcontrolador ejecuta un emulador del AY8912 (adafruit_ay8912) que va leyendo esos comandos y sintetizando las 3 voces más el canal de ruido en tiempo real. Ese audio sintetizado se envía por el bus I2S a un DAC externo, y de ahí a los parlantes.

Por qué un DAC I2S separado y no el DAC interno del micro? Porque la calidad importa: el PCM5102 entrega 112 dB de relación señal ruido y una salida de nivel de línea limpia, muy superior a un PWM filtrado. Para música, la diferencia se nota.

Hardware y conexiones

En la versión original se usa un Feather RP2350 encajado sobre una TFT FeatherWing de 3.5" (que trae la pantalla táctil y el lector microSD integrados). El DAC PCM5102 se cablea a los pines del Feather que quedan duplicados en la FeatherWing.

Feather RP2350 usado como cerebro del reproductor

El cableado del DAC I2S es de solo 5 cables:

  • 3.3V de la placa -> VIN del DAC (cable rojo)
  • GND de la placa -> GND del DAC (cable negro)
  • A1 de la placa -> BCK del DAC (cable amarillo). reloj de bit
  • A2 de la placa -> WSEL del DAC (cable verde). word select (canal L/R)
  • A3 de la placa -> DIN del DAC (cable azul). datos de audio

Ese trío de señales (BCK, WSEL, DIN) es exactamente el protocolo I2S: un reloj de bit, una señal que indica el canal y la línea de datos serie. En el código, esos tres pines se declaran en una sola línea: audiobusio.I2SOut(board.A1, board.A2, board.A3).

Pantalla táctil TFT de 3.5 pulgadas con lector microSD integrado

La microSD entra en el socket de la FeatherWing y usa el mismo bus SPI que la pantalla, con su propio chip select (board.D5). Ahí copias tus archivos .vgm o .vgz.

Tarjeta microSD donde van los archivos VGM/VGZ

Instalar CircuitPython

Antes que nada, tienes que dejar la placa corriendo CircuitPython:

  1. Descarga el UF2 más reciente de tu placa desde circuitpython.org.
  2. Entra al bootloader: mantén apretado el botón BOOT/BOOTSEL y, sin soltarlo, presiona y suelta el botón de reset. Sigue apretando BOOTSEL hasta que aparezca la unidad RP2350 (en el ESP32-S3 el procedimiento equivalente es mantener BOOT y tocar reset).
  3. Arrastra el archivo .uf2 a esa unidad. La placa se reinicia y aparece la unidad CIRCUITPY.

Un consejo que ahorra rabias: usa un cable USB que sepas que transmite datos, no uno de solo carga. Es el error más común y frustrante al empezar.

El código del reproductor

Una vez con CircuitPython instalado, descarga el Project Bundle desde la página original (trae el code.py y todas las librerías necesarias en la carpeta lib). El programa completo arma dos vistas en la pantalla táctil. la de reproducción y el menú de selección de pistas. y maneja el emulador AY8912. Este es el código, fiel al original byte a byte:

El programa hace, en orden: monta la microSD (reintentando 3 veces por si falla la inicialización), lista los archivos VGM/VGZ, inicializa la pantalla HX8357 y el touch TSC2007, abre el bus I2S hacia el DAC, construye los botones táctiles de ambas vistas, arranca el emulador AY8912(sample_rate=22050, clock_rate=1773400) y define las funciones de reproducción (play_track, load_track, change_track) y el despachador de toques (dispatch).

Fíjate en un detalle elegante del manejo de memoria: antes de abrir cada archivo VGM se llama a gc.collect() y se apaga display.auto_refresh mientras se parsea el archivo. En un micro con RAM limitada, esos gestos evitan cuelgues al cambiar de pista.

Montaje del reproductor de chiptunes ensamblado

Cómo correrlo

  1. Copia tus archivos .vgm / .vgz a la raíz de la microSD. Puedes bajarlos de sitios de archivo de música de videojuegos o exportarlos desde software tracker; el Project Bundle incluye una pista de ejemplo para probar.
  2. Inserta la microSD, conecta los parlantes al DAC con un cable estéreo de 3.5 mm y alimenta la placa por USB.
  3. Copia code.py y la carpeta lib a CIRCUITPY. La placa recarga sola y aparece el reproductor.
  4. Toca MENU, elige una pista y vuelve a NOW PLAYING. Usa PLAY/PAUSE, << / >> para saltar y REPEAT para dejarla en loop.

Parlantes USB para escuchar la salida del reproductor

Variantes y mejoras

Ideas para llevar el proyecto más allá de la guía original:

  • Salida a un amplificador de tu equipo: en vez de parlantes USB, la salida de nivel de línea del PCM5102 se puede enchufar directo a la entrada AUX de un amplificador o parlante Bluetooth con entrada de 3.5 mm. Suena bastante mejor.
  • Control físico con botones: si prefieres botones reales en vez de la pantalla táctil, puedes mapear tres pulsadores (play, siguiente, anterior) a GPIO libres y llamar a las mismas funciones dispatch("play"), change_track(1) y change_track(-1). Ideal si armas una carcasa tipo arcade sin touch.
  • Visualizador de espectro: como ya tienes el emulador generando las 3 voces, puedes dibujar barras de nivel en la pantalla leyendo la actividad de cada canal y actualizándolas en el loop principal. Le da onda de ecualizador retro.
  • Playlist con autoavance: el código ya trae repeat_mode; una extensión natural es detectar el fin de la pista (cuando el progreso llega a 1.0) y llamar a change_track(1) automáticamente para que la microSD suene como un álbum continuo.

Personalización para Chile

Este proyecto usa hardware de la línea Feather de Adafruit, que no siempre se encuentra fácil en Chile. Acá va el BOM real y las equivalencias honestas para armarlo con lo que sí se consigue localmente. En MechatronicStore encuentras varios de estos componentes; te dejo las categorías, sin inventar SKUs ni precios:

  • Microcontrolador: el original usa un Adafruit Feather RP2350. Una alternativa muy conseguible es una placa ESP32-S3 con CircuitPython, que también tiene I2S por hardware y sobra de RAM/flash para el emulador. Ojo: los nombres de pines cambian, así que tendrás que ajustar board.D5, board.D9, board.D10, board.A1/A2/A3 por los GPIO reales de tu ESP32-S3. El código de audio y del emulador queda igual.
  • DAC I2S PCM5102: este sí está en catálogo (DAC I2S PCM5102) y es exactamente el mismo módulo del tutorial. Es la pieza central del sonido.
  • Tarjeta microSD: cualquier microSD de 512 MB en adelante formateada en FAT32 sirve. Si tu placa ESP32-S3 no trae lector, necesitas además un módulo lector microSD SPI.
  • Parlantes USB: los Parlantes USB del catálogo cumplen igual que los del original; o usa cualquier parlante con entrada de 3.5 mm.
  • Pantalla táctil: la TFT FeatherWing de 3.5" (HX8357 + touch TSC2007) es específica de Adafruit. Si la reemplazas por un display genérico distinto, tendrás que cambiar la librería (adafruit_hx8357) y el driver del touch por los de tu pantalla. Es la adaptación más grande respecto del original.
  • Cables y tornillería: jumpers macho macho de 20 cm para el DAC, un cable de audio estéreo 3.5 mm y la tornillería M2.5/M3 para la carcasa impresa en 3D.

Dos componentes (el Feather RP2350 y la TFT FeatherWing específica) pueden no tener equivalente exacto en tienda local; por eso mostramos la ruta ESP32-S3 + display genérico como camino realista para armarlo en Chile.

Recursos

  • Tutorial original: CircuitPython Chiptune Player de Liz Clark y los Ruiz Brothers (Adafruit Learn), en inglés. Este artículo está basado en esa guía.
  • Piezas 3D y Project Bundle: los archivos 3MF para imprimir, el código completo (code.py + librerías) y las fuentes CAD se descargan desde la página original enlazada arriba.
  • Modelos CAD de placas Adafruit: Adafruit CAD Parts (GitHub).
  • Documentación: módulos synthio y audiobusio de CircuitPython en docs.circuitpython.org.

Versión chilena con componentes en stock local en MechatronicStore.