11 pontos por GN⁺ 2024-05-01 | 2 comentários | Compartilhar no WhatsApp
  • Para músicos que tocam ampliando PDFs A4 em telas pequenas de celular, é necessário um renderizador de partituras fluido e responsivo na web

Protótipo Scribe

  • No passado, foi criado como protótipo um renderizador musical chamado Scribe, que gerava SVG a partir de JSON
  • O objetivo original era criar um renderizador musical responsivo, mas o progresso foi difícil porque seria preciso escrever um mecanismo de layout complexo de múltiplas passagens
  • Depois, ao introduzir CSS Grid no projeto, pareceu que isso poderia ser a resposta para os problemas de layout tratados no Scribe

Classe .stave

  • A pauta é parecida com uma grade. O eixo vertical é a altura das notas, e o eixo horizontal é o tempo
  • Na classe .stave, são definidas as linhas da grade no eixo vertical
  • São criadas linhas de grade de tamanho fixo com nomes de notas padrão, usando uma imagem de fundo para desenhar a pauta
  • Exemplo de mapa de linhas para uma pauta em 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 linha e cada espaço da pauta passa a ter uma linha de grade com o nome de uma nota

Posicionando alturas na pauta

  • Várias alturas podem ser posicionadas em cada linha da pauta
  • Para colocar elementos do DOM na linha correta, o nome da nota é colocado no atributo data-pitch, e o CSS mapeia esse valor para a linha da pauta
    .stave > [data-pitch^="G"][data-pitch$="4"] { grid-row-start: G4; }  
    
  • Essa regra captura alturas que começam com G e terminam com 4, atribuindo G♭4, G4, G♯4 etc. à linha G4
  • Isso precisa ser feito para todas as linhas da pauta
  • A partir daí, já é possível posicionar alguns símbolos na pauta

Classe .bar e ritmo

  • Lidar com o ritmo é um pouco mais complicado
  • Não existe uma divisão rítmica mínima claramente definida que suporte todos os tipos de ritmo
  • A abordagem de 24 colunas por batida é um bom ponto de partida, pois permite posicionar colcheias, semicolcheias, fusas e tercinas de forma uniforme
  • Definindo 4 batidas como 4 × 24 = 96 colunas de grade e adicionando colunas no início e no fim:
    .bar {  
      column-gap: 0.03125em;  
      grid-template-columns:  
        [bar-begin]  
        max-content  
        repeat(96, minmax(max-content, auto))  
        max-content  
        [bar-end];  
    }  
    
  • Barras de compasso são adicionadas com ::before e ::after, e a clave é centralizada com data-pitch="B4"

Posicionando símbolos no tempo

  • Desta vez, o atributo data-beat é usado para atribuir uma batida aos elementos, e regras CSS mapeiam a batida para colunas da grade
  • O mapa em CSS consiste em uma regra para cada 1/24 de batida
  • O seletor de atributo de início ^= torna as regras tolerantes a imprecisões
  • Usando isso junto com a classe .stave, é possível posicionar símbolos por batida e por altura, definindo data-beat como uma batida entre 1 e 5 e data-pitch como o nome da nota

Partituras fluidas e responsivas

  • Colocando vários desses compassos dentro de um contêiner flexbox, é possível ter uma partitura responsiva
  • Ainda faltam muitas coisas, mas já é uma boa base para começar
  • A quebra de linha já funciona de forma muito mais elegante do que nos renderizadores musicais online existentes

Espaço entre as notas

  • As cabeças de nota que ocorrem em tempos mais próximos são renderizadas um pouco mais próximas entre si
  • Esse é um efeito sutil e intencional criado pelo pequeno column-gap, que funciona como uma espécie de "éter" temporal no qual os elementos simbólicos se encaixam
  • As próprias colunas têm largura 0 quando não há cabeça de nota, mas eventos mais distantes no tempo têm mais espaços entre colunas (24 por batida), o que gera maior distância
  • É possível controlar o espaçamento constante ajustando as margens dos símbolos

Claves e fórmulas de compasso

  • O motivo de usar classes separadas para espaçamento vertical e horizontal é que uma pode ser trocada sem mexer na outra
  • Para exibir a mesma melodia em clave de fá, basta trocar a classe .stave por uma classe bass-stave que mapeie os mesmos atributos data-pitch para as linhas da pauta de clave de fá
  • Mapeando data-duration="5" em CSS para 120 colunas no template de grade de .bar, a mesma pauta pode receber uma fórmula de compasso 5/4

Acordes e letras

  • Com CSS Grid, também é possível alinhar outros símbolos dentro da grade da partitura
  • Acordes, letras, dinâmicas etc. podem ser alinhados e expandidos junto com eventos temporizados

Hastes das notas

  • Hastes das notas, acordes e algumas pausas longas se estendem por colunas ao mapear o atributo data-duration para um valor de intervalo em grid-column-end

Escalonamento

  • Todo o sistema é dimensionado em unidades em, então é possível redimensioná-lo apenas alterando font-size

Limites de Flex e Grid

  • Não é um sistema perfeito. Limitações:
    1. O CSS não consegue posicionar automaticamente uma nova clave/armadura em uma quebra de linha
    2. Não consegue conectar barras de união a novas notas em uma nova linha
    3. Hastes inclinadas só têm sua posição exata conhecida depois que o Grid faz o posicionamento, o que dificulta o alinhamento
  • Para finalizar tudo por completo, será preciso um pouco de JavaScript de organização, mas como o CSS faz a maior parte do trabalho de layout, a quantidade de layout a ser feita em JavaScript fica muito menor

Elemento personalizado

  • Foi escrito um interpretador em torno desse novo sistema em CSS e encapsulado em um elemento
  • Ainda não está pronto para produção, mas já consegue renderizar lead sheets responsivos e notação de bateria, o que o torna interessante e útil
  • A partitura é renderizada a partir de dados do conteúdo, de arquivos carregados via atributo src e de objetos JS definidos na propriedade .data do elemento
  • No momento, o build de desenvolvimento pode ser importado em uma página web para testes

Planos futuros

  • Além das melhorias do Scribe 0.3, há recursos que se pretende investigar no longo prazo:
    • Suporte a fontes SMuFL - trocar a fonte usada para símbolos musicais
    • Suporte a sequências aninhadas - viabilizar músicas com múltiplas partes
    • Renderização de pauta dividida - posicionar várias partes em uma única pauta
    • Renderização de múltiplas pautas - posicionar várias partes em várias pautas alinhadas

Opinião do GN⁺

  • Renderizar partituras de forma fluida e responsiva na web parece ser algo muito útil tanto para músicos quanto para amantes da música. Isso pode resolver o incômodo de ficar ampliando e reduzindo partituras em PDF em telas pequenas
  • A abordagem usando layouts Grid e Flex do CSS é interessante. É um bom exemplo de como o CSS sozinho já consegue resolver bastante coisa sem um mecanismo de layout complexo
  • Mas, pelas características da notação musical, há pontos em que o CSS sozinho tem limitações. Partes que exigem compreensão do contexto musical, como posicionar automaticamente claves ou armaduras em quebras de linha, ou conectar barras de união automaticamente, vão precisar da ajuda do JavaScript
  • Como já foram implementadas várias partes, como renderização de lead sheets e suporte a partitura de bateria, parece possível que isso evolua em breve para um nível bastante utilizável. Se virar open source e o desenvolvimento continuar, pode se tornar uma boa alternativa a editores de partitura existentes como o MuseScore
  • Se forem implementados recursos planejados como suporte a fontes SMuFL, múltiplas partes e renderização de múltiplas pautas, a qualidade da representação musical deve aumentar bastante. É um projeto promissor

2 comentários

 
roxie 2024-05-06

Deve haver um motivo para você estar fazendo isso, né?

 
GN⁺ 2024-05-01
Comentários no Hacker News
  • Houve elogios de um desenvolvedor de software de partituras ao método de renderização de partituras usando CSS Grid
    • Ele desenvolve há mais de 10 anos o Soundslice, um serviço web de renderização de partituras, e implementou pela primeira vez em 2014 uma renderização de partituras web "responsiva"
    • Para detalhes técnicos relacionados, veja o link do vídeo da apresentação: https://www.youtube.com/watch?v=XH5EtQge_Bg
    • Link de exemplo da partitura responsiva do Soundslice: https://www.soundslice.com/slices/zzNlc/
    • Ele oferece várias ferramentas, como editor web, recursos de prática e função de escaneamento que extrai dados de partitura de fotos/PDF
    • A abordagem com CSS Grid pode ser útil para projetos leves, mas provavelmente será difícil implementar toda a complexidade e nuances de uma partitura completa
  • Talvez fosse interessante propor isso à comunidade CSS para que possa ser implementado apenas com CSS, sem JavaScript
    • Por exemplo, a repetição da clave na quebra de linha é semelhante a um sticky table header, e pode ser útil também fora do contexto de partituras
  • A sintaxe de attribute selector([...]) do CSS pareceu impressionante. Ex.: .stave > [data-pitch^="A"][data-pitch$="5"] { grid-row-start: A5; }
  • Do ponto de vista de um gravador musical, ainda parece precisar de muitas melhorias visuais. Só com CSS, isso deve ser difícil por causa dos limites de precisão
    • Há problemas na representação de hastes de notas, ligaduras de arco e ties
    • A maioria das partituras no navegador usa SVG ou Canvas para renderização vetorial e assim obter precisão exata
    • Além do CSS, já existem outras ferramentas que implementam partituras escaláveis no navegador, como Soundslice e Sibelius Cloud Publishing
  • No começo parecia que expressar partituras com CSS não funcionaria bem, mas a qualidade tipográfica impressiona pela simplicidade da abordagem. Elogios ao autor
    • Ainda assim, há preocupação se funcionará bem em casos especiais, como acordes, espaçamento entre colcheias/semicolcheias e alinhamento entre partes. O Lilypond já provou sua flexibilidade nessas representações complexas
  • CSS Grid é interessante. No passado, alguém implementou um designer de móveis com pure frontend JS usando CSS Grid: https://alnvdl.github.io/2023/01/07/designing-furniture-using-the-css-grid.html
  • O custom element <scribe-music> também gera expectativa
  • É bom ver surgir uma alternativa ao Lilypond(lilypond.org), mas a notação é tão complexa que a vantagem da concisão provavelmente não durará muito
    • Para fãs de Asciidoc, é fácil integrar o Lilypond ao toolchain do Asciidoc. Ele está sendo usado em um pipeline DocBook PDF, e a saída fica muito boa. É semelhante ao TeX
  • Isso lembra https://www.musicxml.com e https://opensheetmusicdisplay.org, que são soluções completas, embora muito mais custosas
  • Fica a curiosidade se seria possível substituir por isso o recurso meio improvisado de partituras do Impro-Visor(https://github.com/Impro-Visor/Impro-Visor)
  • Passa uma sensação de benchmark de CSS