Guía para principiantes de JFugue Parte I: notas, duraciones, patrones

JFugue es una biblioteca de Java utilizada para crear música inmersiva. En esta guía, veremos cómo usar notas, duraciones y patrones para la generación de música básica.

Introducción

JFugue es una biblioteca de música de código abierto que le permite reproducir y componer música MIDI utilizando el lenguaje de programación Java. Utiliza su formato "Staccato" para analizar cadenas de instrucciones musicales. Al usar JFugue, puede convertir las cadenas Staccato en un archivo MIDI, así como importar un archivo MIDI y convertir el contenido en cadenas legibles por humanos.

Esta va a ser la primera parte de la serie de tres partes. En esta guía, nos centraremos en las partes más fundamentales de la biblioteca de JFugue aprendiendo sobre las notas, las octavas, las duraciones, el tempo, los instrumentos y los patrones. Haciéndolo podremos recrear una pequeña parte de las voces de la versión jazz de Domingo por la mañana de Maroon 5.

En la segunda parte de la serie, exploraremos cómo crear y manipular acordes y progresiones de acordes en Jfugue. Aprenderemos a usar los métodos setKey(), distribute() y allChordsAs() de la clase ChordProgression.

En la tercera y última parte de la serie, aprenderemos sobre los ritmos en JFugue. Usando nuestro conocimiento previo, podremos finalizar la introducción de nuestra canción. En la parte final, también veremos cómo guardar nuestra música en un archivo MIDI usando JFugue, así como leer música de un archivo MIDI usando la biblioteca JFugue:

Comencemos por preparar nuestro entorno de desarrollo.

Requisitos previos

Como vamos a trabajar con MIDI, será necesario un dispositivo de salida de audio (altavoces o auriculares) para observar los resultados.

Si bien no es un requisito estricto, los conocimientos musicales básicos te ayudarán a comprender más rápidamente algunos de los conceptos musicales a los que se hace referencia en el artículo.

Instalación

Descarga la Biblioteca JFugue oficial (la versión actual es la 5.0.9) y agrega el archivo JAR a tu proyecto java como una biblioteca externa.

Alternativamente, si está utilizando Maven, puede descargar la dependencia a través de su archivo pom.xml. Sin embargo, también tendrás que agregar el repositorio JitPack:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

<dependency>
    <groupId>jfugue</groupId>
    <artifactId>jfugue</artifactId>
    <version>5.0.9</version>
</dependency>

O, si estás usando Gradle:

1
2
3
4
5
6
7
8
allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

implementation group: 'jfugue', name: 'jfugue', version: '5.0.9'

La API principal de la biblioteca JFugue es la clase Player. Vamos a instanciarlo:

1
2
3
4
5
6
7
import org.jfugue.player.Player;

public class MyMusic {
    public static void main(String[] args) {
        Player player = new Player();
    }
}

Usaremos esta clase para interpretar y reproducir los sonidos que nos gustaría realizar.

Notas, octavas y duraciones en JFugue

Como mencionamos anteriormente, Staccato representa todas las características musicales con un formato fácil de leer y escribir. La guía oficial de JFugue se refiere a Staccato como “Formato legible por humanos y analizable por máquina”. Es bastante flexible, no distingue entre mayúsculas y minúsculas ni tiene en cuenta múltiples espacios en blanco (siempre que haya al menos un espacio).

Así es como se ve una cadena Staccato:

1
player.play("C D E F G A B");

Ejecute el código y prepare sus parlantes para escuchar el sonido mágico del MIDI.

Nota: encontrará muchos métodos player.play() junto con este tutorial. Para evitar complicaciones, puede mantener un método player.play() al final de su código y reemplazarlo cada vez que vea uno nuevo.

Esta cadena es bastante legible por humanos. Pero es posible que haya notado que no especificamos ninguna octava ni la duración de ninguna de las notas. Cuando no se proporciona información de octava, las notas se reproducirán con la octava predeterminada, que es 5. Esto significa que la cadena de música anterior es igual a la siguiente:

1
player.play("C5 D5 E5 F5 G5 A5 B5");

Podemos indicar el número de octava entre 1 y 10, donde 1 es la octava más baja y 10 la octava más alta. El número de octava debe seguir justo después de la nota o acorde (más sobre acordes más adelante en el artículo):

1
player.play("G4 G3 A3 B2");

Fíjate que tocamos la misma nota G dos veces pero una con la 4ta octava y la segunda es la 3ra, las cuales producen un sonido diferente.

Por supuesto, por el momento nuestra cuerda de música no suena muy interesante, porque todas las notas tienen la misma duración. Similar a las octavas, cuando no se especifica ninguna, se utilizará la duración predeterminada de "q".

"Q" representa la "negra". Algunas de las duraciones más comunes son "entero", "mitad", "cuarto", "octavo". Cada duración es la mitad de tiempo más rápida o más corta que la anterior y dos veces más lenta o más larga que la siguiente. La duración de la nota "negra" (¼), por ejemplo, es más corta que la "media" (½) y dos veces más larga que la "corchea" (⅛) Nota. JFugue te permite ser tan preciso como quieras, con duraciones de hasta 1/128.

Aquí está la tabla completa de duraciones con los valores decimales de la Guía oficial de JFugue:

Duración Carácter Valor decimal


Todo W 1.0 Mitad H 0.5 Trimestre Q 0.25 Octava I 0.125 Decimosexto S 0.0625 Treinta y dos T 0.03125 Sesenta y cuatro X 0.015625 Uno-veintiocho O 0.0078125

Ahora que sabemos cómo funcionan las duraciones en JFugue, podemos ponerlo a trabajar en nuestra cadena de música (también conocida como Staccato):

1
player.play("G4qi G3s A3is B2is");

Tenga en cuenta que usamos dos notaciones de duración juntas para G4qi. Con JFugue, puede combinar tantas o tan pocas notaciones de duración como desee para crear el sonido y la sensación que desea. El orden de las anotaciones de duración no importa, pero para una mejor legibilidad, se recomienda utilizarlas en orden ascendente. Es decir, comience con una mayor duración seguida de una menor duración.

Otro concepto musical esencial es Descanso. Para decirlo en el sentido más simple, el descanso es una pausa, un silencio, una ausencia de música. En JFugue, el descanso se representa con la letra 'R' o 'r'. Al igual que las notas, el descanso también puede tener una duración y el valor de duración predeterminado es el mismo que los demás: cuarto.

Intentemos recrear un fragmento de la voz del Sunday Morning usando todo lo que hemos aprendido hasta ahora:

1
player.play("G5is E5i Ri | G5s Ris E5q Rs | G5q E5i Rs D5q rs C5h Rs");

Puede eliminar todos los tokens 'R' y comparar dos versiones para comprender el efecto del resto.

Es posible que haya notado que también hay un carácter "|" (tubería) que aún no hemos mencionado. La tubería en JFugue es simplemente para una mejor legibilidad y no afecta el audio. Puede dividir su Staccato utilizando tantos tubos como desee y no cambiará la salida musical. Parece una 'línea de compás' en las partituras pero, a diferencia de la línea de compás, un tubo no especifica el número de tiempos.

Dado que nuestro Staccato es una cadena, podemos usar la concatenación de cadenas con el operador + para combinar varias cadenas.

Supongamos que tenemos cuerdas separadas para las voces, podemos combinarlas fácilmente para formar una cuerda continua y tocar:

1
2
3
4
String vocals = "Rh G5is E5i Ri | G5s Ris E5q Rs | G5q E5i Rs D5q rs C5h Rs "
                + "C4i A5q G5isa50d0 Rs A5s E5i D5is Rs C5qis "
                + "Rqi A4s G5i E5i Rs | G5is Rs E5q | D5is C5i Rs C5q G4q Ri";
player.play(vocals);

Observe el espacio en blanco al final de la primera y segunda cadena. Como estamos concatenando, queremos evitar unir el final de una cadena con el comienzo de otra cadena como "RsC4i".

Esto no generará ningún error, pero JFugue simplemente omitirá la reproducción de esa(s) nota(s) ya que es irreconocible. Afortunadamente, JFugue ofrece una mejor manera de combinar múltiples Staccatos, sin tener que lidiar con asuntos triviales como espacios en blanco al final de cada cadena. En la siguiente sección, aprenderemos sobre Patrones y cómo usar los instrumentos.

Usando patrones e instrumentos en JFugue

Cada elemento musical en una cuerda Staccato es un token. Cada nota, silencio y duración, y todo lo demás que descubriremos más adelante en el artículo son tokens. Un patrón envuelve una cadena Staccato hecha de tokens y nos permite manipularla de manera conveniente.

La clase Pattern proporciona algunos métodos eficientes, como setTempo(), setInstrument(), setVoice() y más. También podemos encadenar estos métodos. Usando el método add(), podemos agregar múltiples patrones o múltiples Staccatos juntos.

Importemos y creemos un objeto Pattern para envolver nuestra cadena Staccato y combinar varias cadenas sin tener que preocuparnos por los espacios en blanco al final:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import org.jfugue.pattern.Pattern;

Pattern vocals = new Pattern();
vocals.add("Rh G5is E5i Ri | G5s Ris E5q Rs | G5q E5i Rs D5q rs C5h Rs");
vocals.add("C4i A5q G5isa50d0 Rs A5s E5i D5is Rs C5qis");
vocals.add("Rqi A4s G5i E5i Rs | G5is Rs E5q | D5is C5i Rs C5q G4q Ri");
vocals.add("G3is A3s C4is D4s C4is D4s G4is A4s G4is A4s | E4q rs F4h");
vocals.add("G5is E5i Ri | G5s Ris E5q Rs | G5q E5i Rs A5is rs G5q A5s E5i D5i ri C5h Ri");
vocals.add("C5s A3q C5i Rs | D5i Rs Eb5qs Rs | D5q Eb5i Rs D5is Eb5s D4q Rs | C5i A4q C5h");

player.play(vocals);

Agregar cadenas juntas de esta manera, no solo evita errores de espacios en blanco, sino que también nos brinda más funcionalidades.

Si intenta reproducir el patrón de “voces” anterior, notará que suena demasiado lento. La razón, como ya habrás adivinado, tiene que ver con duraciones. Sin embargo, no queremos acortar las duraciones, de verdad. Queremos ampliar el tempo.

Podemos establecer un nuevo tempo sin problemas usando el método setTempo(int) de la instancia Pattern:

1
vocals.setTempo(180);

Ahora notaremos la diferencia si lo jugamos:

1
player.play(vocals);

Hasta ahora solo hemos usado el instrumento predeterminado, que es Piano. Si bien es uno de los instrumentos más versátiles, desafortunadamente, no es el mejor ajuste para cada situación. Hagamos esto más 'Jazzy' agregando algunos instrumentos:

Podemos encadenar varios métodos en la instancia Pattern, cambiando la configuración con varios ajustes:

1
vocals.setTempo(180).setInstrument("TROMBONE");

Hay 128 instrumentos, incluidos, bueno, no instrumentos como "SEASHORE", "BIRDTWEET" e incluso "HELICOPTER".

Puede dejar las otras líneas como están y ejecutar el código para escuchar la diferencia. Al encadenar el método setInstrument() hasta el final, configuramos el “TROMBONE” para todas las cadenas Staccato arriba de esa llamada.

Por supuesto, podemos configurar diferentes instrumentos para cualquier línea individual incrustando la información del instrumento en el propio Staccato:

1
2
3
4
5
6
7
8
Pattern vocals = new Pattern();
vocals.add("I[TROMBONE] Rh G5is E5i Ri | G5s Ris E5q Rs | G5q E5i Rs D5q rs C5h Rs");
vocals.add("I[ALTO_SAX] C4i A5q G5isa50d0 Rs A5s E5i D5is Rs C5qis");
vocals.add("I[TROMBONE] Rqi A4s G5i E5i Rs | G5is Rs E5q | D5is C5i Rs C5q G4q Ri");
vocals.add("I[TRUMPET] G3is A3s C4is D4s C4is D4s G4is A4s G4is A4s | E4q rs F4h");
vocals.add("I[TROMBONE] G5is E5i Ri | G5s Ris E5q Rs | G5q E5i Rs A5is rs G5q A5s E5i D5i ri C5h Ri");
vocals.add("C5s A3q C5i Rs | D5i Rs Eb5qs Rs | D5q Eb5i Rs D5is Eb5s D4q Rs | C5i A4q C5h");
vocals.setTempo(180);

Observe que no hay información del instrumento en la última línea. JFugue continuará con la última selección de instrumento hasta que se realice cualquier otra selección. Pero, por supuesto, para una mejor legibilidad, es mejor proporcionar información del instrumento siempre que sea posible.

Nuevamente, JFugue viene con 128 instrumentos predefinidos. Por si quieres descubrir tus otras opciones sobre los instrumentos, [aquí está la lista completa](https://github.com/wikihtp/Java-Music-Programming-with-JFugue/blob/main/README.md#jfugue -instrumentos).

Similar a los instrumentos, podemos establecer el valor de tempo dentro del mismo Staccato, pasando el valor de tempo a nuestro constructor Pattern cuando lo instanciamos en la primera línea.

El resultado final del patrón vocals debería verse así:

1
2
3
4
5
6
7
Pattern vocals = new Pattern("T180");
vocals.add("I[TROMBONE] Rh G5is E5i Ri | G5s Ris E5q Rs | G5q E5i Rs D5q rs C5h Rs");
vocals.add("I[ALTO_SAX] C4i A5q G5isa50d0 Rs A5s E5i D5is Rs C5qis");
vocals.add("I[TROMBONE] Rqi A4s G5i E5i Rs | G5is Rs E5q | D5is C5i Rs C5q G4q Ri");
vocals.add("I[TRUMPET] G3is A3s C4is D4s C4is D4s G4is A4s G4is A4s | E4q rs F4h");
vocals.add("I[TROMBONE] G5is E5i Ri | G5s Ris E5q Rs | G5q E5i Rs A5is rs G5q A5s E5i D5i ri C5h Ri");
vocals.add("I[TROMBONE] C5s A3q C5i Rs | D5i Rs Eb5qs Rs | D5q Eb5i Rs D5is Eb5s D4q Rs | C5i A4q C5h");

Eliminamos vocals.setTempo(180); ya que establecer el tempo al principio tiene el mismo efecto.

Y eso concluye la parte vocal de nuestra canción, así como la primera parte de nuestra serie de tutoriales.

Conclusión

En este tutorial, cubrimos las partes más fundamentales de la biblioteca de música Java de código abierto de JFugue. Aprendimos a usar notas, duraciones, tempo y patrones.

Si bien estos eran los elementos esenciales de JFugue, fue solo un paso hacia las muchas posibilidades que JFugue tiene para ofrecer. En las siguientes partes, exploraremos cómo manipular acordes y progresiones de acordes, los conceptos básicos del ritmo y cómo importar y exportar archivos MIDI usando JFugue.

Continue to read the second part of the guide series: Guía para principiantes de JFugue Parte II: Acordes y progresiones de acordes.