Planetzebes

Suena ahora Main Menu International Superstar Soccer Deluxe 0 oyentes
Portada: Zebamp, el reproductor de los años 2000 ahora para MPD en Linux, con un reproductor de estilo retro dibujado

Zebamp: reviví Winamp para usarlo con MPD en Linux

Hay programas que se quedan pegados a una época. Para mí, Winamp es uno de ellos: las skins, el ecualizador, el espectro bailando en la esquina. Hoy mi música vive en MPD (Music Player Daemon), en Linux, y la manejo desde ncmpcpp o desde el móvil. Así que un día me pregunté: ¿se podrá tener aquel Winamp, con sus skins de verdad, pero funcionando con y para MPD?

Se lo pedí tal cual a Claude Code: «construye una aplicación que se parezca a Winamp… que trabaje con y para MPD, que use los skins clásicos y modernos, optimizada y con la menor cantidad de bugs posible». El resultado se llama Zebamp, es software libre (GPL-3.0) y ya tiene su primer candidato a versión, la 1.0.0rc1.

La idea: un mando a distancia con piel de los 2000

La decisión más importante fue la primera: Zebamp no reproduce audio. MPD ya lo hace muy bien y guarda todo el estado (cola, posición, volumen, biblioteca). Zebamp es un cliente: refleja ese estado y le manda órdenes. La interfaz nunca «supone» el resultado de un botón; espera a que MPD avise por su canal de eventos idle. Así, si cambio de canción desde el móvil, Zebamp se entera al instante.

Diagrama: Zebamp envía órdenes a MPD y recibe su estado; MPD suena por PipeWire con el filtro de ecualizador de Zebamp
Zebamp manda órdenes y MPD responde con su estado; el audio va por PipeWire.

Está escrito en Python con Qt 6 (PySide6), con una pieza pequeña en C++ para MilkDrop.

Skins clásicos: los .wsz de toda la vida

Un skin clásico es un ZIP lleno de bitmaps: botones, números, la barra de posición, las regiones que recortan la forma de la ventana, los cursores animados y la paleta del visualizador. Zebamp los lee todos y dibuja cada panel píxel a píxel. Para que no se vean diminutos en pantallas modernas, los amplía con Scale2x/Scale3x, un algoritmo pensado para pixel art que agranda sin difuminar ni pixelar.

También tiene un skin propio, «Zebamp», original y vectorial: se ve nítido a cualquier tamaño y lleva el nombre del programa en lugar del de otro.

Skins modernos: había que escribir una máquina virtual

Los skins de Winamp 3 y 5 (.wal, como Winamp Modern, Bento o Big Bento) son otra cosa: describen la interfaz en XML y la animan con scripts MAKI compilados a bytecode. Para soportarlos, Zebamp incluye un intérprete de MAKI escrito en Python, junto con los objetos gráficos que esos scripts esperan encontrar (botones, deslizadores, rejillas, textos desplazables, visualizadores…).

Aquí fue donde más se iteró: el volumen que funcionaba pero no llenaba la barrita azul, el título que no se desplazaba en el sitio correcto, franjas negras a los lados del ecualizador, la información junto a la carátula de Bento que no se veía bien, estrellas de valoración que solo llegaban a cuatro… Cada detalle se fue corrigiendo comparando con capturas, hasta que los skins modernos se sintieron como en el original.

Ventanas con imán… en Wayland

En Winamp, la ventana principal, el ecualizador y la lista se mueven por separado y se «pegan» con imán al acercarlas. El problema: en Wayland una aplicación no puede colocar sus propias ventanas; eso lo decide el compositor (en mi caso, sway).

La solución fue un lienzo: una ventana transparente del tamaño del monitor donde las ventanas del skin son hijas que Zebamp sí puede mover. Una máscara de entrada deja pasar los clics al escritorio por las zonas vacías. Encima de eso hubo que pulir mucho:

  • Recordar cómo quedaron acopladas las ventanas y abrir exactamente así la próxima vez.
  • Poder llevarlas al otro monitor arrastrando, pero que un simple clic nunca las cambie de pantalla ni haga parpadear nada.
  • Que el lienzo cubra solo el monitor donde están las ventanas, para que Zebamp no aparezca en todos los escritorios.

Visualización: compartir el audio sin pisarse con nadie

El espectro y el osciloscopio necesitan el audio. MPD puede escribirlo en un fifo, pero ncmpcpp ya leía el mío, y un fifo no se comparte bien. Zebamp ahora no se lo quita a nadie: si el fifo está ocupado, captura el audio de MPD directamente de PipeWire. Y para los nostálgicos de verdad, hay MilkDrop gracias a projectM, con miles de presets.

Más adelante, esos mismos fifos explicaron un misterio: un pequeño corte de audio al pausar y reanudar varias veces. Las salidas fifo retienen algo más de un segundo de audio; desactivándolas y dejando a MPD solo con PipeWire, el corte desapareció.

Todo lo demás que tenía Winamp (y algo más)

  • Ecualizador de 10 bandas como filtro de PipeWire; cerrar Zebamp no corta la música.
  • Teclas multimedia vía MPRIS (también funcionan playerctl y waybar), icono en la bandeja y notificaciones con carátula.
  • Búsqueda instantánea en toda la biblioteca (probada con 107 000 canciones), con un atajo global del gestor de ventanas.
  • Biblioteca con vistas de más escuchadas, mejor valoradas y recientes; las estrellas y las veces escuchada se guardan en los stickers de MPD.
  • Radio por Internet, marcadores, editor de etiquetas y una ayuda completa integrada: F1 en cada ventana abre su sección.

«A continuación», incluso en aleatorio

Un detalle que parece sencillo: «reproducir esta canción a continuación». Moverla justo después de la actual funciona… hasta que activas el aleatorio, porque entonces MPD ignora el orden de la cola. El truco fue usar las prioridades de MPD: una canción con prioridad alta es la siguiente elegida aunque esté en aleatorio.

# "+0" = justo después de la canción actual (posiciones relativas, MPD >= 0.23)
for sid in reversed(ids):
    cmds.append(("moveid", sid, "+0"))
if random_on:
    # en aleatorio MPD ignora el orden: la prioridad manda
    for i, sid in enumerate(ids):
        cmds.append(("prioid", max(1, 255 - i), sid))

Letras que se sincronizan solas

Las letras salen, por este orden, de un .lrc junto a la canción, de las etiquetas del archivo o de LRCLIB, eligiendo la versión cuya duración más se parezca. Como tengo canciones aceleradas o con introducciones más largas, Zebamp ajusta la velocidad solo, y con Mayús+clic en una línea en el momento justo se sincroniza a mano (y lo recuerda para esa canción). Si no hay letra, lo dice claro: «no se encontró la letra», y no «nada sonando».

Buenas prácticas: el «BCP38» del código

En redes, BCP38 es una buena práctica que todos deberían aplicar. Le pedí lo equivalente para este proyecto: código que cualquiera pueda leer, que funcione y que no gaste recursos. De ahí salieron unas «reglas de la casa» documentadas y medidas:

  • Nada se despierta sin motivo: los temporizadores solo corren cuando hacen falta, y la visualización se detiene con Zebamp oculto.
  • Repintar solo lo que cambia. Con eso y un índice de objetos por tipo, Big Bento pasó de un 28 % a un 8,5 % de CPU.
  • Nada bloqueante en la interfaz: red, disco y consultas largas van en hilos aparte.
  • Los datos de fuera no se dan por buenos (Internet, etiquetas, archivos): si algo no encaja, es «no encontrado», nunca un cierre.
  • La configuración del usuario es sagrada. Lo aprendimos a las malas: una prueba llegó a escribir en la configuración real. Desde entonces, las 70 pruebas usan su propio MPD privado y una configuración temporal.
Cifras de Zebamp: 35 commits, unas 20 mil líneas de Python, 70 pruebas, búsqueda en 107 mil canciones y consumo de CPU
Las cifras de la 1.0.0rc1, medidas en la misma máquina.

Además, normas de estilo comprobadas con ruff, una guía de arquitectura para quien quiera leer el código y pruebas de estrés con miles de acciones aleatorias, incluyendo reinicios de MPD en medio.

Pruébalo

El código está en GitHub: github.com/1985a/zebamp. En Arch Linux necesitas python, pyside6, python-mpd2, python-numpy y, claro, mpd (opcionales: python-mutagen, python-dbus, pipewire y projectm).

git clone https://github.com/1985a/zebamp.git ~/proyectos/zebamp
cd ~/proyectos/zebamp
install -Dm755 packaging/zebamp.sh ~/.local/bin/zebamp
install -Dm644 packaging/zebamp.desktop ~/.local/share/applications/zebamp.desktop
zebamp                  # abre con el último skin
zebamp --skin mi.wsz    # o con uno concreto

Si usas sway, estas dos líneas lo dejan flotando y con búsqueda global:

for_window [app_id="zebamp"] floating enable, border none
bindsym $mod+Shift+s exec zebamp --buscar

Lo que falta, siendo honestos: los skins modernos que dependen de piezas internas de Winamp (vídeo, AVS, el navegador) funcionan solo en parte, y «siempre visible» no tiene efecto en Wayland. Y lo siguiente en la lista es llevar la experiencia a la pantalla Android del carro.

Zebamp es un proyecto independiente y no está afiliado a Winamp ni a sus propietarios; Winamp es una marca de sus respectivos dueños. Los skins pertenecen a sus autores. Algunos datos (los preajustes del ecualizador y la descripción de los objetos MAKI) provienen de Webamp, con licencia MIT, como se detalla en el repositorio.


Posted

in

by

Comments

Deja una respuesta

WordPress Appliance - Powered by TurnKey Linux