Introduction: Editor De Pentagramas
En este proyecto se aborda el diseño y la implementación de una aplicación web que nos permite editar partituras. El objetivo principal ha sido desarrollar una herramienta sencilla que nos permita componer, editar y exportar partituras directamente desde un navegador, sin la necesidad de instalar programas especializados.
Para ello, se emplean HTML y CSS para la interfaz de usuario, y JavaScript para la lógica de la aplicación, apoyándose sobre todo en la librería VexFlow para el dibujo de los pentagramas y las notas en formato SVG.
Supplies
Para realizar la aplicación hemos utilizado los siguientes elementos:
Software y entorno de trabajo
- Navegador web: nos permite interpretar el código y mostrar la aplicación web. En nuestro caso hemos utilizado Google Chrome pero también es compatible con otros navegadores como Opera o Edge.
- Editor de código fuente: la escritura del código se ha implementado en VsCode. aunque se pueden utilizar otros editores.
Tecnologías web: hemos usado los 3 lenguajes estándar para construir la web:
- HTML: la estructura de la página, donde se definen los elementos de la web con los que interactúa el usuario (botones, seleccionables, etc.)
- CSS: el diseño de la página, que nos permite manejar la apariencia de la página.
- JavaScript: el cerebro de la aplicación, contiene las funciones que nos permiten editar la partitura.
Librerías externas:
- VexFlow: la librería de la notación musical, nos permite transformar los elementos musicales en elementos visuales, dibujando el pentagrama y las figuras musicales en la pantalla.
- jsPDF: nos permite generar un documento pdf con nuestra partitura
Step 1: Estructura Básica Del Proyecto (HTML)
En pentagrama.html encontramos la estructura básica del proyecto, el esqueleto. En este archivo organizaremos el navegador en zonas y cargaremos las herramientas necesarias. Esta dividido en 2 secciones principales:
- Cabecera y librerías: en el head, nos encargamos de cargar las librerías externas al empezar (VexFlow y jsPDF). Además de vincular nuestra hoja de estilos (styles.css).
- Body: se definen las 3 zonas visibles de la aplicación:
- Topbar: esta sección actúa como el panel de configuración global de la partitura, en él hemos colocado los siguientes elementos para que el usuario pueda configurarlos a lo largo de la partitura: compás, clave, armadura y tempo. Además de los botones que nos permite cargar, guardar y descargar la partitura.
- Leftbar: contiene los símbolos musicales, botones que nos permiten insertar notas, silencios, modificadores, articulaciones, dinámicas y barras.
- Output: un contendor vacío que va albergar el dibujo de la partitura con todos sus elementos.
Antes de finalizar la etiqueta del body, insertaremos nuestro script.js para que cuando empecemos a interaccionar con la página web los elementos (botones, selectores) ya se estén creados.
Step 2: Diseño De La Interfaz (CSS)
El archivo styles.css es el encargado de configurar el diseño de nuestra página.
Puntos clave :
- Se usa un layout de pantalla completa con flexbox:
- La barra superior ocupa toda la anchura en la parte de arriba.
- Debajo, el espacio se divide entre la barra lateral y el área del pentagrama.
- La barra lateral agrupa los controles en paneles con título: “Notas”, “Silencios”, "Ritmo", “Alteraciones”, “Articulación”, “Dinámicas” y “Barras”.
- Los iconos se organizan en una cuadrícula (panel-grid) para que sea fácil localizar cada símbolo:
- Todos los botones de nota, modificador, articulación, etc. , comparten el mismo estilo base para mantener una estética uniforme.
- Se definen estados visuales:
- “Hover” (al pasar el ratón) para dar sensación de respuesta.
- “Activo/seleccionado” para indicar qué nota o modificador está preparado para insertarse.
- El contenedor del pentagrama:
- Tiene fondo claro, borde y esquinas redondeadas.
- El SVG se adapta al ancho disponible para mostrar varios sistemas si la partitura es larga.
Este diseño está pensado para que cualquier usuario reconozca rápidamente qué está seleccionando y tenga una experiencia fluida al editar.
Step 3: Clase Partitura (Primera Parte JavaScript)
El archivo script.js contiene el núcleo funcional de la aplicación. En él se define cómo interactúan los elementos de la interfaz con el motor de renderizado VexFlow y cómo se gestionan las reglas de la teoría musical.
El código está estructurado en base a la programación orientada a objetos, dividiendo la responsabilidad en dos clases principales. En este paso, vamos a hablar de la primera de ellas, la clase partitura.
La clase Partitura, definida en script.js, es la encargada de almacenar y gestionar los datos musicales. Funciona como el "Modelo" de nuestra aplicación: no interactúa con el HTML (DOM) ni dibuja nada, solo aplica reglas lógicas y matemáticas para asegurar que la música sea coherente.
Su funcionamiento se basa en 4 pilares fundamentales:
- Estructura: la clase contiene una lista principal llamada "compases", donde cada elemento guarda su propia configuración (clave, compás, armadura) y su lista de notas. En este apartado, podemos incluir estas funciones principales, que nos ayudan a crear nuestra estructura:
- iniciar(): es la función de arranque. Usada sólo para una vez al iniciar la aplicación.
- crearCompas(): genera un nuevo elemento en la lista de "compases", con los siguientes elementos : numerador, denominador, clave y armadura.
- cambiarConfiguracion(): cuando el usuario cambia la clave, el compás o la armadura se actualiza en el compás actual si está vacío o crea uno nuevo con las modificaciones si no lo está.
- estaFinalizada(): verifica si el último compás tiene una barra de fin, si devuelve true, bloquea la edición para evitar que se pueda escribir en una partitura ya finalizada.
- getUltimoCompas(): lo usamos para ubicarnos en el último compás.
- calcularOcupacion(compas): comprueba si la nota a insertar entra en el compás actual y sino invoca automáticamente a crearCompas() y coloca la nota en el nuevo espacio.
- Lógica de inserción de la nota: la función agregarNota() es la encargada de construir el objeto "Nota" antes de guardarlo. Este objeto contiene:
- Keys: la altura exacta (el pitch) formateada para VexFlow (ej. c/4).
- Duration: la figura rítmica (redonda w, negra q, corchea 8, etc.).
- Modificadores: variables que indican si es silencio, si lleva puntillo, alteraciones forzadas (#, b,...) o articulaciones (staccato, tenuto,...).
- Contexto: variables para gestionar ligaduras (inicio/fin) y dinámicas (piano, forte,...).
- Herramientas de edición:
- limpiarTodo(): pone los modificadores temporales (puntillo, alteraciones, etc.) después de guardar una nota a null.
- eliminarUltimaNota(): permite borra la última nota del último compás. Si el compás se queda vacío, esta función también elimina el compás entero para mantener la partitura limpia.
- Traducción de Datos: el ordenador entiende números (MIDI), pero VexFlow necesita texto ("c/4").
- midiToKey(midi):Transforma un 60 en un c/4 (Do central). Además, consulta MAPAS.notasBemoles o MAPAS.notasSostenidos dependiendo de la armadura que hayas elegido, para escribir la nota correctamente.
- asignarTempo(figura, bpm): permite guardar la velocidad (BPM) en el compás, gestionando si la figura base tiene puntillo o no.
Step 4: Clase Renderizador (Segunda Parte JavaScript)
La segunda clase principal, ubicada en script.js, se llama Renderizador. Su función es traducir los datos de la clase Partitura (compases, notas, clave, compás) y transformarlos en elementos gráficos SVG en pantalla, a través de la librería VexFlow.
Lo primero es ejecutar el constructor, que inicia el motor de VexFlow (VF.Renderer) y lo vincula al contenedor de HTML llamado output.
La función principal es dibujar(partitura) , que orquesta todo el proceso visual en tres fases lógicas:
- Cálculo de Espacio y "Sistemas": antes de dibujar, el código necesita saber el espacio que va a ocupar cada compás y cada sistema(que será cada línea de pentagrama vertical).
- Calcular anchos: el código itera sobre cada compás y calcula cuánto espacio necesita según el número de notas y reserva espacio para la clave y la indicación de compás al principio de cada pentagrama/sistema o cuando hay un cambio gracias a las variables como cambioClave o cambioTiempo.
- Agrupación en Sistemas: el código va sumando el ancho de los compases, si supera el anchoContenedor, el código crea un nuevo sistema debajo.
- Dibujado del pentagrama (Stave): una vez organizados los sistemas, iteramos sobre ellos. Para cada compás se crea un objeto VF.Stave. El código solo dibuja la clave (addClef), el compás (addTimeSignature) o la armadura (addKeySignature) al principio de la línea o si ha habido un cambio respecto al compás anterior. También gestiona las barras divisorias (setEndBarType), dibujando barras de repetición o la barra final si la partitura ha terminado.
- Dibujado de notas y elementos (dibujarNotas): finalmente la función dibujarNotas() transforma los datos abstractos en notas visuales (VF.StaveNote). Aquí se gestionan cuatro aspectos clave:
- Modificadores: se añaden automáticamente puntillos (VF.Dot), alteraciones (VF.Accidental), articulaciones (VF.Articulation) y dinámicas (VF.Annotation) según lo que hayamos guardado en el objeto nota.
- Gestión de Beams (Barras): usamos VF.Beam.generateBeams para unir automáticamente los corchetes de las corcheas, semicorcheas, fusas y semifusas según el compás.
- Ligaduras: guardamos en que nota inicia y termina una ligadura y las unimos haciendo uso de VF.Curve.
- Previsualización de la nota: si el usuario tiene una nota seleccionada pero aún no la ha guardado, dibujamos una nota temporal en color gris para que sepa exactamente dónde caerá y si cabe en el compás.
Step 5: Interacción Con El Usuario
Definida la lógica y los gráficos musicales, procederemos a crear un puente de comunicación entre el HTML y el JavaScript. Para ello, usaremos la función asignarEventos() que se encuentra en el archivo script.js.
Para facilitar esa comunicación, hacemos uso de los siguientes elementos:
- Clicks en el DOM: se realizan eventos de click y cambio (change), el código gestiona 3 grupos de controles:
- Leftbar: se asignan listeners a los botones de la barra lateral, lo que nos permite introducir notas, silencios, modificadores, articulaciones, dinámicas y barras, al activarlos el estado app.notaSeleccionada se actualiza, y visualmente pasa a ser .seleccionado.
- Topbar: nos permite cambiar la clave, compás, armadura y tempo, a través de selects y numbers que al modificarlos invocan la función app.cambiarConfiguracion(). También podremos utilizar el boton Atrás que nos permite deshacer la última nota de nuestro último compás.
- Gestión de archivos: nos permite al clicar los botones guardar la partitura en formato JSON, cargar una partitura en el ese formato o descargarla en formato jpg o pdf.
- Atajos del teclado: para agilizar la escritura musical hay un par de atajos presentes en el teclado:
- Teclas numéricas del 1 al 9: nos permite seleccionar la altura(pitch) conforme a la clave actual.
- Flechas: las teclas ArrowUp y ArrowDown nos permite también cambiar la altura.
- Enter: llama a la función app.agregarNota(), guardan la nota y dibujándolo definitivamente en el pentagrama.
- Delete o Backspace: llaman a app.eliminarUltimaNota(), que nos permite deshacer nuestra última acción.
- Ratón: además de la función estándar del click izquierda para la selección de los elementos de la interfaz, hemos añadido 2 funcionalidades para agilizar el funcionamiento de la aplicación:
- Click derecho: tiene la misma función que la tecla Enter.
- Rueda de desplazamiento: al girar la rueda, aumenta o disminuye la altura de la nota. Es importante destacar que el código utiliza e.preventDefault() para bloquear el scroll nativo de la página, evitando que la web se mueva mientras el usuario ajusta la nota.
Step 6: Guardar, Cargar Y Descargar La Partitura
En este último paso, abordamos la lógica implementada en script.js para gestionar el ciclo de vida de los datos mediante tres procesos clave: guardado, carga y descarga.
Cargar datos:
- Al pulsar el botón de cargar, se abre un selector de archivos.
- Si se elige un JSON válido generado por la aplicación:
- Se reconstruye la estructura interna con compases y notas.
- Se actualizan los selectores de compás y clave.
- Se redibuja la partitura en pantalla.
Guardar datos (JSON):
- Al pulsar el botón de guardar, se genera un objeto que contiene:
- La configuración de la partitura (compás, clave).
- Todos los compases con sus notas y propiedades.
- Este objeto se convierte en un archivo JSON descargable, que el usuario puede guardar en su ordenador.
Descargar imagen o PDF:
- La partitura se dibuja inicialmente como SVG.
- Para exportar:
- Se convierte el SVG a un canvas.
- Desde el canvas se genera:
- Una imagen JPG.
- O un PDF, usando jsPDF, adaptando la partitura al tamaño de la página.
- El usuario puede elegir formato y descargar su partitura final ya maquetada.
Step 7: Ejecución Del Proyecto
Para terminar, el funcionamiento de este editor de partituras solo requiere descargar la carpeta en el siguiente enlace. Allí se encontrará el código fuente (pentagrama.html, styles.css, script.js) y el directorio de recursos gráficos necesarios (la carpeta images) para la interfaz. Para iniciar la herramienta, basta con descargar el paquete, descomprimirlo y ejecutar el archivo pentagram.html directamente en cualquier navegador web moderno.

