11 points par GN⁺ 2024-05-01 | 2 commentaires | Partager sur WhatsApp
  • Pour les musiciens qui jouent en zoomant sur des PDF A4 sur de petits écrans mobiles, il faut un rendu de partitions fluide et responsive sur le web

Prototype Scribe

  • Par le passé, un prototype de moteur de rendu musical nommé Scribe, qui produit du SVG à partir de JSON, avait été développé
  • L’objectif initial était de créer un moteur de rendu musical responsive, mais les progrès étaient difficiles car il aurait fallu écrire un moteur de mise en page complexe à passages multiples
  • Plus tard, avec l’introduction de CSS Grid dans le projet, cela a semblé pouvoir apporter une réponse aux problèmes de mise en page traités dans Scribe

Classe .stave

  • Une portée ressemble à une grille. L’axe vertical correspond à la hauteur des notes, l’axe horizontal au temps
  • La classe .stave définit les lignes de grille de l’axe vertical
  • Des lignes de grille à taille fixe sont créées avec les noms de hauteurs standard, et une image d’arrière-plan est utilisée pour dessiner la portée
  • Exemple de mappage des lignes pour une portée en clé 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%;  
    }  
    
  • Chaque ligne de la portée et chaque espace reçoivent ainsi une ligne de grille nommée selon la hauteur correspondante

Placement des hauteurs sur la portée

  • Plusieurs hauteurs peuvent être placées sur chaque ligne de la portée
  • Pour positionner correctement les éléments du DOM sur la bonne ligne, on place le nom de la hauteur dans l’attribut data-pitch, puis on fait correspondre en CSS la valeur de data-pitch à la ligne de portée
    .stave > [data-pitch^="G"][data-pitch$="4"] { grid-row-start: G4; }  
    
  • Cette règle capture les hauteurs commençant par G et se terminant par 4, puis assigne G♭4, G4, G♯4, etc. à la ligne G4
  • Il faut faire cela pour toutes les lignes de la portée
  • On peut alors commencer à placer quelques symboles sur la portée

Classe .bar et temps

  • La gestion du rythme est un peu plus délicate
  • Il n’existe pas de subdivision rythmique minimale évidente qui prenne en charge tous les types de rythme
  • Une approche à 24 colonnes par temps constitue un bon point de départ, car elle permet de répartir uniformément croches, doubles croches, triples croches et triolets
  • Quatre temps sont définis comme 4 × 24 = 96 colonnes de grille, avec des colonnes ajoutées au début et à la fin :
    .bar {  
      column-gap: 0.03125em;  
      grid-template-columns:  
        [bar-begin]  
        max-content  
        repeat(96, minmax(max-content, auto))  
        max-content  
        [bar-end];  
    }  
    
  • Des barres de mesure sont ajoutées avec ::before et ::after, et la clé est centrée avec data-pitch="B4"

Placement des symboles dans le temps

  • Cette fois, on utilise l’attribut data-beat pour attribuer un temps aux éléments, puis des règles CSS pour faire correspondre ces temps aux colonnes de la grille
  • La table de correspondance CSS se compose d’une règle pour chaque 1/24 de temps
  • En utilisant le sélecteur de début d’attribut ^=, les règles deviennent tolérantes aux écarts
  • En l’utilisant avec la classe .stave, il suffit de définir data-beat sur une valeur entre 1 et 5 et data-pitch sur un nom de note pour placer les symboles selon le temps et la hauteur

Partitions fluides et responsives

  • En plaçant plusieurs de ces mesures dans un conteneur flexbox, on obtient une partition responsive
  • Il manque encore beaucoup de choses, mais cela constitue déjà une bonne base de départ
  • Les retours à la ligne sont déjà gérés de façon bien plus élégante que dans les moteurs de rendu musical en ligne existants

Espace entre les notes

  • Les têtes de note qui surviennent à des instants plus proches sont rendues légèrement plus rapprochées
  • C’est un effet subtil et intentionnel créé par un petit column-gap, qui joue une sorte d’« éther » temporel dans lequel viennent se loger les symboles
  • Les colonnes elles-mêmes ont une largeur nulle en l’absence de tête de note, mais entre des événements plus éloignés dans le temps, il y a davantage d’intervalles de colonnes — 24 par temps — ce qui crée plus de distance
  • On peut contrôler une partie de l’espacement constant en ajustant les marges des symboles

Clés et signatures rythmiques

  • La raison d’utiliser des classes séparées pour l’espacement vertical et horizontal est qu’on peut remplacer l’un sans toucher à l’autre
  • Pour afficher la même mélodie en clé de fa, il suffit de remplacer la classe .stave par une classe bass-stave qui mappe le même attribut data-pitch aux lignes d’une portée de basse
  • En CSS, on peut donner une mesure à 5/4 à la même portée en faisant correspondre data-duration="5" aux 120 colonnes du modèle de grille de .bar

Accords et paroles

  • Avec CSS Grid, il est aussi possible d’aligner d’autres symboles à l’intérieur de la grille de la partition
  • Accords, paroles, nuances, etc. peuvent être alignés et étendus avec des événements horodatés

Hampes de notes

  • Les hampes, les accords et certains silences longs peuvent s’étendre sur plusieurs colonnes en faisant correspondre l’attribut data-duration à une valeur de portée grid-column-end

Mise à l’échelle

  • Tout le système étant dimensionné en unités em, il peut être redimensionné simplement en changeant font-size

Limites de Flex et Grid

  • Ce n’est pas un système parfait. Ses limites :
    1. CSS ne peut pas placer automatiquement une nouvelle clé ou une nouvelle armure lors d’un retour à la ligne
    2. Il est impossible de relier automatiquement des crochets de ligature à une nouvelle note sur la ligne suivante
    3. Pour les hampes inclinées, l’alignement est difficile car leur position exacte n’est connue qu’après le placement par Grid
  • Pour finaliser complètement le tout, un peu de JavaScript de nettoyage sera nécessaire, mais comme CSS prend en charge l’essentiel du travail de mise en page, il reste beaucoup moins de logique de layout à gérer côté JavaScript

Élément personnalisé

  • Un interpréteur a été écrit autour de ce nouveau système CSS, puis encapsulé dans un élément
  • Ce n’est pas encore prêt pour la production, mais c’est déjà intéressant et utile pour rendre des lead sheets responsives et noter des parties de batterie
  • Les partitions sont rendues à partir des données du contenu, d’un fichier chargé via l’attribut src, ou d’un objet JS défini dans la propriété .data de l’élément
  • Le build de développement actuel peut être importé dans une page web pour être essayé

Suite du projet

  • En plus des améliorations de Scribe 0.3, voici les fonctionnalités à étudier à long terme :
    • prise en charge des polices SMuFL — changer la police utilisée pour les symboles musicaux
    • prise en charge des séquences imbriquées — activer les morceaux à plusieurs parties
    • rendu de portées partagées — placer plusieurs parties sur une seule portée
    • rendu multi-portées — placer plusieurs parties sur plusieurs portées alignées

Avis de GN⁺

  • Rendre les partitions de manière fluide et responsive sur le web semble pouvoir être très utile, tant pour les musiciens que pour les amateurs de musique. Cela pourrait éliminer l’inconfort lié au zoom et dézoom sur des partitions PDF sur de petits écrans
  • L’approche qui exploite les layouts Grid et Flex de CSS est intéressante. C’est un bon exemple montrant qu’on peut résoudre une grande partie du problème uniquement avec CSS, sans moteur de mise en page complexe
  • Mais, du fait de la nature même de la notation musicale, il existe aussi des limites à ce que CSS peut faire seul. Les aspects qui demandent de comprendre le contexte musical, comme le placement automatique des clés ou des armures lors des retours à la ligne, ou la connexion automatique des ligatures, auront besoin de l’aide de JavaScript
  • Comme le rendu de lead sheets et la prise en charge de la batterie sont déjà assez avancés, le projet semble pouvoir atteindre bientôt un niveau tout à fait utilisable. S’il devient open source et que le développement se poursuit, il pourrait constituer une bonne alternative aux éditeurs de partitions existants comme MuseScore
  • Si les fonctions prévues, comme la prise en charge des polices SMuFL, du multi-parties et du rendu multi-portées, sont implémentées, la qualité de représentation des partitions pourrait nettement progresser. Un projet prometteur

2 commentaires

 
roxie 2024-05-06

Vous devez bien avoir une raison de faire ça.

 
GN⁺ 2024-05-01
Avis sur Hacker News
  • Éloge de la méthode de rendu de partitions utilisant CSS Grid, de la part d’un développeur de logiciels de notation musicale
    • Il développe depuis plus de 10 ans Soundslice, un service web de rendu de partitions, et a implémenté dès 2014 le premier rendu de partitions web « responsive »
    • Pour les détails techniques, voir la vidéo de présentation : https://www.youtube.com/watch?v=XH5EtQge_Bg
    • Exemple de partition responsive de Soundslice : https://www.soundslice.com/slices/zzNlc/
    • Le service propose aussi divers outils, comme un éditeur web, des fonctions d’entraînement, et un scan permettant d’extraire des données de partition depuis des photos/PDF
    • L’approche CSS Grid peut être utile pour des projets légers, mais il sera sans doute difficile d’implémenter toute la complexité et les nuances d’une partition complète
  • Cela vaudrait peut-être le coup de faire une proposition à la communauté CSS pour permettre une implémentation en CSS seul, sans JavaScript
    • Par exemple, la répétition de la clé au retour à la ligne ressemble à un sticky table header, ce qui pourrait aussi servir en dehors de la notation musicale
  • La syntaxe des attribute selectors ([...]) en CSS était impressionnante. Exemple : .stave > [data-pitch^="A"][data-pitch$="5"] { grid-row-start: A5; }
  • Du point de vue d’un graveur musical, cela semble encore nécessiter beaucoup d’améliorations visuelles. Avec le CSS seul, les limites de précision risquent d’être bloquantes
    • Il y a des problèmes dans le rendu des hampes, ligatures, liaisons, etc.
    • La plupart des partitions dans le navigateur utilisent un rendu vectoriel en SVG ou Canvas pour obtenir une précision extrême
    • En dehors du CSS, il existe déjà d’autres outils capables d’afficher des partitions scalables dans le navigateur, comme Soundslice ou Sibelius Cloud Publishing
  • Au départ, cela ne semblait pas très prometteur pour représenter des partitions en CSS, mais la qualité typographique est impressionnante pour une approche simple. Bravo à l’auteur
    • En revanche, on peut s’inquiéter du comportement dans des cas particuliers comme les accords, l’espacement des croches/double-croches, ou l’alignement entre parties. Lilypond a déjà prouvé sa souplesse sur ce type de complexité
  • CSS Grid est intéressant. J’avais autrefois réalisé un configurateur de meubles en pur frontend JS en m’appuyant sur CSS Grid : https://alnvdl.github.io/2023/01/07/designing-furniture-using-the-css-grid.html
  • Le custom element <scribe-music> est aussi prometteur
  • C’est une bonne chose de voir apparaître une alternative à Lilypond (lilypond.org), mais la notation est si complexe que l’avantage de concision risque de ne pas durer longtemps
    • Pour les fans d’Asciidoc, Lilypond s’intègre facilement dans une toolchain Asciidoc. Je l’utilise dans une pipeline PDF DocBook, et le rendu est plutôt bon. C’est comparable à TeX
  • Cela rappelle https://www.musicxml.com et https://opensheetmusicdisplay.org, qui sont des solutions complètes, mais bien plus coûteuses
  • Je me demande si cela pourrait remplacer les fonctionnalités de partition assez rudimentaires d’Impro-Visor (https://github.com/Impro-Visor/Impro-Visor)
  • Ça fait un peu penser à un benchmark CSS