11 puntos por GN⁺ 2024-05-01 | 2 comentarios | Compartir por WhatsApp
  • Para músicos que tocan ampliando PDFs A4 en pantallas móviles pequeñas, hace falta un renderizado de partituras fluido y responsivo en la web

Prototipo de Scribe

  • En el pasado se creó como prototipo un renderizador musical llamado Scribe que generaba SVG a partir de JSON
  • El objetivo original era crear un renderizador musical responsivo, pero era difícil avanzar porque había que escribir un complejo motor de maquetación multipaso
  • Más adelante, al introducir CSS Grid en el proyecto, pareció que podía ser la respuesta al problema de maquetación que Scribe estaba tratando

Clase .stave

  • El pentagrama es parecido a una cuadrícula. El eje vertical es la altura y el eje horizontal es el tiempo
  • En la clase .stave se definen las filas de la cuadrícula, que corresponden al eje vertical
  • Se crean filas de tamaño fijo con nombres estándar de alturas y se usa una imagen de fondo para dibujar el pentagrama
  • Ejemplo de mapa de filas para un pentagrama en clave de sol:
    .stave {  
      display: grid;  
      row-gap: 0;  
      grid-template-rows:   
        [A5] 0.25em [G5] 0.25em [F5] 0.25em [E5] 0.25em  
        [D5] 0.25em [C5] 0.25em [B4] 0.25em [A4] 0.25em  
        [G4] 0.25em [F4] 0.25em [E4] 0.25em [D4] 0.25em  
        [C4] 0.25em ;  
      background-image: url('/path/to/stave.svg');  
      background-repeat: no-repeat;  
      background-size: 100% 2.25em;  
      background-position: 0 50%;  
    }  
    
  • Cada línea del pentagrama y cada espacio obtiene una línea de cuadrícula con nombre de altura

Colocar alturas en el pentagrama

  • En cada fila del pentagrama pueden ubicarse varias alturas
  • Para colocar un elemento del DOM en la fila correcta, se pone el nombre de la altura en el atributo data-pitch y con CSS se mapea ese valor a la fila del pentagrama
    .stave > [data-pitch^="G"][data-pitch$="4"] { grid-row-start: G4; }  
    
  • Esta regla captura las alturas que empiezan con G y terminan con 4, y asigna G♭4, G4, G♯4, etc. a la fila G4
  • Hay que hacer esto para todas las filas del pentagrama
  • Ahora ya se pueden colocar algunos símbolos en el pentagrama

Clase .bar y compás

  • Manejar el ritmo es un poco más complicado
  • No existe una subdivisión rítmica mínima clara que soporte todos los tipos de ritmo
  • El enfoque de 24 columnas por pulso es un buen punto de partida porque permite distribuir de forma uniforme corcheas, semicorcheas, fusas y tresillos
  • Se definen 4 pulsos como 4 × 24 = 96 columnas de cuadrícula y se añaden columnas al inicio y al final:
    .bar {  
      column-gap: 0.03125em;  
      grid-template-columns:  
        [bar-begin]  
        max-content  
        repeat(96, minmax(max-content, auto))  
        max-content  
        [bar-end];  
    }  
    
  • Se agregan barras de compás con ::before y ::after, y la clave se coloca al centro con data-pitch="B4"

Colocar símbolos en el pulso

  • Esta vez se usa el atributo data-beat para asignar un pulso a cada elemento y reglas CSS para mapear el pulso a columnas de la cuadrícula
  • El mapa CSS está compuesto por una regla por cada 1/24 de pulso
  • Al usar el selector de atributo de inicio ^=, la regla tolera pequeñas imprecisiones
  • Al combinarlo con la clase .stave, se pueden colocar símbolos por pulso y por altura configurando data-beat con valores entre 1 y 5 y data-pitch con el nombre de la nota

Partitura fluida y responsiva

  • Si se colocan varios de estos compases dentro de un contenedor flexbox, se obtiene una partitura responsiva
  • Todavía faltan muchas cosas, pero es una buena base para empezar
  • Ya hace saltos de línea de una forma mucho más elegante que los renderizadores musicales en línea

Espacio entre notas

  • Las cabezas de nota que ocurren en momentos más cercanos entre sí se renderizan un poco más juntas
  • Es un efecto sutil e intencional creado por un column-gap pequeño, que actúa como una especie de "éter" temporal donde encajan los elementos simbólicos
  • Las columnas en sí tienen ancho 0 si no hay cabezas de nota, pero entre eventos más alejados en el pulso hay más espacios entre columnas (24 por pulso), así que aparece más distancia
  • Se puede ajustar el margen de los símbolos para controlar un espaciado constante

Claves y compases

  • La razón para usar clases separadas para el espaciado vertical y horizontal es que una puede sustituirse sin tocar la otra
  • Para mostrar la misma melodía en clave de fa, basta con sustituir la clase .stave por una clase bass-stave que mapee los mismos atributos data-pitch a las filas del pentagrama de bajo
  • Si con CSS se mapea data-duration="5" a las 120 columnas de la plantilla de cuadrícula de .bar, se puede dar al mismo pentagrama un compás de 5/4

Acordes y letra

  • Con CSS Grid también se pueden alinear otros símbolos dentro de la cuadrícula de la partitura
  • Se pueden alinear y extender acordes, letra, dinámicas, etc., con eventos ubicados en el tiempo

Plicas

  • Las plicas, los acordes y algunos silencios largos se hacen abarcar columnas mapeando el atributo data-duration a un valor de rango en grid-column-end

Escalado

  • Todo el sistema usa unidades em, así que se puede escalar solo cambiando font-size

Límites de Flex y Grid

  • No es un sistema perfecto. Tiene estas limitaciones:
    1. CSS no puede colocar automáticamente una nueva clave o armadura al hacer salto de línea
    2. No puede conectar ligaduras de corcheas con notas nuevas en la siguiente línea
    3. Las plicas inclinadas son difíciles de alinear porque su posición exacta solo se conoce después de que Grid hace la colocación
  • Para terminarlo por completo hace falta un poco de JavaScript de limpieza, pero como CSS se encarga de la mayor parte del trabajo de maquetación, en JavaScript queda mucho menos trabajo de layout

Elemento personalizado

  • Se escribió un intérprete alrededor de este nuevo sistema CSS y se envolvió en un elemento
  • Todavía no está listo para producción, pero ya puede renderizar lead sheets responsivas y notación de batería, así que resulta interesante y útil
  • Renderiza partituras a partir de los datos del contenido, de archivos obtenidos con el atributo src y de objetos de JS establecidos en la propiedad .data del elemento
  • La compilación de desarrollo actual puede importarse en una página web para probarla

Planes a futuro

  • Además de las mejoras de Scribe 0.3, estas son funciones que se quieren investigar a largo plazo:
    • Soporte para fuentes SMuFL: cambiar la fuente usada para los símbolos musicales
    • Soporte para secuencias anidadas: habilitar piezas de múltiples partes
    • Renderizado de pentagramas divididos: colocar varias partes en un solo pentagrama
    • Renderizado de múltiples pentagramas: colocar varias partes en varios pentagramas alineados

Opinión de GN⁺

  • Renderizar partituras de forma fluida y responsiva en la web parece algo muy útil tanto para músicos como para aficionados a la música. Podría resolver la incomodidad de ver partituras PDF haciendo zoom en pantallas pequeñas
  • El enfoque que aprovecha los layouts Grid y Flex de CSS resulta interesante. Es un buen ejemplo de cómo CSS por sí solo puede resolver bastante sin necesidad de un motor de maquetación complejo
  • Aun así, por la naturaleza de la partitura, hay partes donde CSS por sí solo tiene límites. En aspectos que requieren entender el contexto musical, como colocar automáticamente claves o armaduras al cambiar de línea, o conectar ligaduras de corcheas, hará falta ayuda de JavaScript
  • Ya se han implementado bastantes cosas, como el renderizado de partituras lead y el soporte para partituras de batería, así que parece posible que pronto mejore hasta un nivel bastante utilizable. Si se libera como código abierto y el desarrollo continúa, podría convertirse en una buena alternativa a editores de partituras existentes como MuseScore
  • Si se implementan funciones futuras como soporte para fuentes SMuFL y renderizado de múltiples partes y múltiples pentagramas, la calidad de representación de partituras podría subir mucho. Es un proyecto prometedor

2 comentarios

 
roxie 2024-05-06

Debe haber una razón para que haga esto.

 
GN⁺ 2024-05-01
Opiniones en Hacker News
  • Un desarrollador de software de partituras elogia el enfoque de renderizar partituras usando CSS Grid
    • Lleva más de 10 años desarrollando Soundslice, un servicio web de renderizado de partituras, y en 2014 implementó por primera vez un renderizado de partituras web "responsivo"
    • Para los detalles técnicos relacionados, ver el enlace al video de la charla: https://www.youtube.com/watch?v=XH5EtQge_Bg
    • Enlace a un ejemplo de partitura responsiva de Soundslice: https://www.soundslice.com/slices/zzNlc/
    • Ofrece varias herramientas, como editor web, funciones de práctica y una función de escaneo que extrae datos de partituras desde fotos/PDF
    • El enfoque con CSS Grid puede ser útil para proyectos ligeros, pero sería difícil implementar toda la complejidad y los matices de una partitura completa
  • También podría ser buena idea proponerlo a la comunidad de CSS para que pueda implementarse solo con CSS, sin JavaScript
    • Por ejemplo, repetir la clave al hacer salto de línea es parecido a un sticky table header, y podría usarse también fuera de la notación musical
  • La sintaxis del attribute selector([...]) de CSS resultó impresionante. Ejemplo: .stave > [data-pitch^="A"][data-pitch$="5"] { grid-row-start: A5; }
  • Desde la perspectiva de un grabador musical, parece que todavía necesita mucha mejora visual. Solo con CSS sería difícil por sus límites de precisión
    • Hay problemas al representar plicas, ligaduras y ties
    • La mayoría de las partituras en navegador usan renderizado vectorial con SVG o Canvas para lograr precisión milimétrica
    • Además de CSS, ya existen otras herramientas para implementar partituras escalables en el navegador, como Soundslice y Sibelius Cloud Publishing
  • Al principio parecía que expresar partituras con CSS no iba a funcionar bien, pero impresiona la calidad tipográfica lograda con un enfoque simple. Mis respetos para el autor
    • Aun así, preocupa si funcionará bien en casos especiales como acordes, espaciado de corcheas/semicorcheas y alineación entre partes. Lilypond ha demostrado flexibilidad en estas expresiones complejas
  • CSS Grid es interesante. Hace tiempo alguien implementó un diseñador de muebles usando CSS Grid con pure frontend JS: https://alnvdl.github.io/2023/01/07/designing-furniture-using-the-css-grid.html
  • También genera expectativas el custom element <scribe-music>
  • Está bien que haya aparecido una alternativa a Lilypond(lilypond.org), pero la notación es tan compleja que la ventaja de la simplicidad probablemente no durará mucho
    • Para fans de Asciidoc, es fácil integrar Lilypond en la toolchain de Asciidoc. Se usa en un pipeline de PDF con DocBook y el resultado es bastante bueno. Se parece a TeX
  • Hace recordar a https://www.musicxml.com y https://opensheetmusicdisplay.org. Cuesta mucho más, pero es una solución completa
  • Me pregunto si se podría reemplazar con esto la rudimentaria función de partituras de Impro-Visor(https://github.com/Impro-Visor/Impro-Visor)
  • Se siente como una especie de benchmark de CSS