Guía para principiantes de JFugue Parte III: Ritmos, lectura y escritura en MIDI

¡JFugue es una biblioteca de Java que crea música! Este es el tercer artículo de una serie de tutoriales de JFugue, y cubrimos ritmos y exportamos música a formato MIDI.

Introducción

En este tutorial, aprenderemos cómo crear ritmos usando la clase Rhythm, cómo usar el RhythmKit integrado de JFugue para crear ritmos convenientemente y cómo aplicar diferentes instrumentos de ritmo a nuestra canción. También cubriremos cómo guardar nuestra música en un archivo MIDI usando JFugue y cómo leer música desde un archivo MIDI usando la biblioteca de JFugue.

Esta es la tercera y última parte de la serie de guías de tres partes, en la que intentamos recrear la introducción de la versión jazz de [Domingo por la mañana de Maroon 5](https://www.youtube.com /reloj?v=lpt_Y5uLm6Q). Pero los pasos proporcionados en los artículos también son fácilmente aplicables a cualquier otro proceso de creación de canciones.

En la primera parte de la serie, cubrimos los fundamentos de la biblioteca JFugue, aprendiendo cómo usar notas, octavas, duraciones, tempo, instrumentos y patrones. Al final del primer artículo, creamos las voces de introducción sin ningún acorde. Al final de este tutorial, nuestra canción tendrá los acordes listos para tocar junto con las voces.

En la parte anterior de la serie, aprendimos cómo usar acordes y progresiones de acordes en la biblioteca JFugue. También cubrimos cómo usar los métodos setKey(), distribute() y allChordsAs() de la clase ChordProgression, cómo tocar diferentes patrones simultáneamente usando voces y cómo aplicar propiedades de ataque/caída a notas y/o acordes.

Aquí están los enlaces a las partes anteriores de nuestra serie de tutoriales JFugue:

Ritmos en JFugue

JFugue nos permite usar ritmos con la clase Rhythm incorporada. Esta clase proporciona una forma intuitiva de interactuar con las fichas de ritmo para crear el ritmo que queremos. Como se mencionó anteriormente, V9 es el canal de voz predefinido para toda la percusión. Por lo tanto, cualquier objeto que creemos a partir de esta clase se agregará a V9 de forma predeterminada.

Para usar la clase Rhythm, primero debemos importarla:

1
import org.jfugue.rhythm.Rhythm;

Luego lo instanciamos para agregar capas:

1
2
3
4
5
6
7
Rhythm rhythm = new Rhythm()
        .addLayer("O..oO...O..oOO..")
        .addLayer("..S...S...S...S.")
        .addLayer("````````````````")
        .addLayer("...............+");

player.play(rhythm.getPattern().repeat(2));

Ejecute el código para reproducir este genial ritmo que también está disponible en el sitio web oficial de JFugue.

La cadena que toma la clase Rhythm puede parecer un poco diferente a primera vista, pero tenga en cuenta que las convierte todas al Staccato en la parte posterior. Y al usar el método getPattern() podemos convertirlos en un objeto Pattern y usar métodos específicos del patrón, como repeat(). El método addLayer() funciona de manera similar a las voces. Puede pensar en cada capa como un equivalente de Voice, excepto que como ya estamos en una voz (V9), no podemos agregar ninguna, sino que agregamos capas hasta 16.

Para elaborar, cada uno de los caracteres que se pasan a la clase representan un instrumento o el Resto del RhythmKit predeterminado de JFugue. Aquí puede examinar cada instrumento que corresponde a los personajes del ejemplo anterior:

Carácter de duración


. Rhode Island O (mayúsculas) [BASS_DRUM]i o (minúsculas) Rs [BASS_DRUM]s S (mayúscula) [ACOUSTIC_SNARE]i s (minúsculas) Rs [ACOUSTIC_SNARE]s ^ (signo de intercalación) [PEDAL_HI_HAT]i ` (comilla grave) [PEDAL_HI_HAT]s Rs * (asterisco) [CRASH_CYMBAL_1]i + (más) [CRASH_CYMBAL_1]s Rs X (mayúsculas) [HAND_CLAP]i x (minúsculas) Rs [HAND_CLAP]s

Esta forma de producir ritmos puede parecer divertida y ordenada, pero es difícil componer un ritmo de jazz con ella. Para empezar, es mucho menos legible, además, las duraciones son fijas a menos que uses patrones para manipularlo (como hicimos con las progresiones de acordes).

Afortunadamente, JFugue también nos permite usar los tokens de ritmo con los viejos Patterns. Aquí, agregaremos ritmos a un patrón usando una cuerda Staccato:

1
Pattern introRhythm = new Pattern("T180 V9 [CLOSED_HI_HAT]x Rx [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt");

Es muy similar a lo que hemos hecho antes, excepto que esta vez no usamos el token I delante de cada instrumento, solo pasamos el nombre del instrumento de percusión. Cada nombre de instrumento va seguido de una ficha x que, como recordará, es la ficha de duración para la longitud Sesenta y cuatro de una nota completa. El resto debería parecer bastante familiar.

Toquemos esto con nuestros acordes anteriores y patrones de introducción:

1
2
3
4
5
6
7
8
Pattern mainChords = new Pattern("T180 V0 D4Min9hqit Ri G3Maj13hqi Ri C4Maj9wh Rh");
mainChords.add("D4Minhqit Ri G4Majhqi Ri C4Majwh Rht");

Pattern pianoTouch = new Pattern("T180 V1 Rw | Rw | Rhi | G4qi G3s A3is CMajis ri");
pianoTouch.add("Rw | Rw | Rhi | G4s C5wa100d0");
Pattern introOnce = new Pattern(mainChords, pianoTouch);

player.play(introOnce, introRhythm.repeat(8));

Esa es la primera parte de la introducción, ahora agregaremos un poco de BASS_DRUM para crear nuestro ritmo principal que debería sonar a lo largo de toda la canción (al menos en su mayor parte). Agregue esto después de reproducir la primera introducción:

1
2
Pattern mainRhythm = new Pattern("T180 V9 [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt  [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rtt [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rtt [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt "
);

Suena mejor de lo que parece. Hagamos un intento:

1
2
3
Pattern introSecondPart = new Pattern(mainChords, mainRhythm.repeat(2));

player.play(introSecondPart);

Consulte nuestro repositorio de GitHub para ver la lista completa de instrumentos de percusión

Agreguemos también un Bajo para finalizar nuestra música:

1
2
3
4
Pattern bassGuitar = new Pattern("T180 V3 I[SLAP_BASS_1] D3is D3s Rhq G3is G3s Rqis B2qi | C3is C3s Rhq D3is D3s Rq E3is E3s Rq | D3is D3s Rhq G2is G2s Rqis B2qi | C3is C3s Rhq G3is G3s Rq A3s Ri G3s E3q ");
bassGuitar.add("D3is D3s Rhq G2is G2s Rqis B2qi | C3is C3s Rhq D3is D3s Rq E3is E3s Rq D3is D3s Rhq G2is G2s Rqis B2qi C3is C3s Rhq G3i Ri A3q G3is F3s E3q ");

player.play(bassGuitar);

Antes de agregar el bajo a cualquier patrón, debemos decidir cuándo queremos que suene. No queremos que comience a reproducirse de inmediato, sino que sonaría mucho mejor si comenzara con introSecondPart.

Bueno, no podemos usar el mismo truco que usamos con pianoTouch, al menos no exactamente. Podemos agregar un patrón de silencio, lo suficientemente largo como para pasarlo a lo largo de introFirstPart y agregarle la línea de bajo, así:

1
2
3
Pattern bassGuitarSilence = new Pattern("T180 V3 Rw Rw Rw Rw | Rw Rw Rw Rw | Ri");
bassGuitarSilence.add(bassGuitar);
player.play(bassGuitarSilence.repeat(2), introSecondPart.repeat(8));

Pero entonces no podríamos reproducirlo en repetición porque haría que pasara la misma cantidad de silencio cada vez que se toca nuestro bajo. En su lugar, pasaremos bassGuitarSilence y bassGuitar por separado, sin utilizar el método add(), pero dejando ambos en el mismo canal de voz.

De esta forma, uno tendrá que esperar a que el otro termine de jugar:

1
player.play(bassGuitarSilence, bassGuitar.repeat(4), introSecondPart.repeat(8));

Eso es todo. Ahora todo lo que queda es combinar las voces y los acordes que hemos creado en las partes anteriores de nuestra serie de tutoriales, con nuestros ritmos para concluir la introducción de nuestra canción.

También hice algunos ajustes aquí y allá para sincronizar la música con el ritmo, así que aquí está la versión final:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import org.jfugue.player.Player;
import org.jfugue.pattern.Pattern;

public class MyMusic {
    public static void main(String[] args) {
        Player player = new Player();
        Pattern mainChords = new Pattern("T180 V0 D4Min9hqit Ri G3Majhqi Ri C4Maj9wh Rht ");
        mainChords.add("  D4Minhqit  Ri G4Majhqi   Ri C4Majwh Rht ");
        Pattern pianoTouch = new Pattern("T180 V1 Rw | Rw | Rhi | G4qi G3s A3is CMajis ri");
        pianoTouch.add(" Rw | Rw | Rhi | G4s C5wa100d0 Rw ");

        Pattern introOnce = new Pattern(mainChords, pianoTouch);

        Pattern introRhythm = new Pattern(
                "T180 V9 [CLOSED_HI_HAT]x Rx [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt ");

        Pattern introFirstPart = new Pattern(introOnce, introRhythm.repeat(8));

        Pattern mainRhythm = new Pattern(
                "T180 V9 [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt  [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rtt [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rtt [BASS_DRUM]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [ELECTRIC_SNARE]x [CLOSED_HI_HAT]x [MARACAS]x Rss [BASS_DRUM]x [MARACAS]x Rtt [CLOSED_HI_HAT]x [MARACAS]x Rss [CLOSED_HI_HAT]x [MARACAS]x Rtt ");

        Pattern vocalsSilence = new Pattern("T180 V4 Rw Rw Rw Rw | Rw Rw Rw Rw | Rq ");

        Pattern vocals = new Pattern("T180 V04 ");
        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 Rit");
        vocals.add("I[TROMBONE] C5s A3q C5i Rs | D5i Rs Eb5qs Rs | D5q Eb5i Rs D5is Eb5s D4q Rs | C5i A4q C5h Rw Rhi");

        Pattern introSecondPart = new Pattern(mainChords, mainRhythm.repeat(2));

        Pattern bassGuitarSilence = new Pattern("T180 V3 Rw Rw Rw Rw | Rw Rw Rw Rw | Rq ");
        Pattern bassGuitar = new Pattern(
                "T180 V3  I[SLAP_BASS_1] D3is D3s Rhq G3is G3s Rqis B2qi | C3is C3s Rhq D3is D3s Rq E3is E3s Rq | D3is D3s Rhq G2is G2s Rqis B2qi | C3is C3s Rhq G3is G3s Rq A3s Ri G3s E3q ");
        bassGuitar.add(
                "D3is D3s Rhq G2is G2s Rqis B2qi | C3is C3s Rhq D3is D3s Rq E3is E3s Rq D3is D3s Rhq G2is G2s Rqis B2qi C3is C3s Rhq G3i Ri A3q G3is F3s E3q ");

        Pattern introThirdPart = new Pattern(introFirstPart, bassGuitarSilence, bassGuitar.repeat(2), vocalsSilence,
                vocals.repeat(2), introSecondPart.repeat(4));
        player.play(introThirdPart);
    }
}

¡Siéntete libre de mejorarla o de continuar componiendo la canción completa ya que ahora sabes casi todo lo que necesitas saber!

Guardar música en un archivo MIDI usando JFugue

Con la cantidad adecuada de tiempo y esfuerzo, puede crear excelentes canciones MIDI con JFugue. La buena música es aún mejor cuando se comparte con amigos y seres queridos. Para compartir nuestra composición musical, usaremos el método savePatternToMidi() de JFugue para convertir nuestros patrones en un archivo MIDI.

Para guardar nuestra música en un MIDI, primero, necesitamos importar MidiFileManager y luego pasar la ruta del archivo junto con nuestro(s) patrón(es):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import org.jfugue.player.Player;
import org.jfugue.pattern.Pattern;

public class MyMusic {
    public static void main(String[] args) {
        // Our patterns…
        try {
            File filePath = new File("path/to/your/midi");
            MidiFileManager.savePatternToMidi(introThirdPart, filePath);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

Verifique la ruta del archivo para confirmar que su MIDI está listo para usar.

Leer música desde un archivo MIDI usando JFugue

Del mismo modo, también podemos leer un archivo MIDI y convertirlo en patrones. Usaremos el método loadPatternFromMidi() para pasar la ruta del archivo de un MIDI y leer el contenido.

Tenga en cuenta que también necesitaremos manejar la excepción IO:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import org.jfugue.midi.MidiFileManager;

public class MyMusic {
    public static void main(String[] args) throws IOException {
        Pattern loadedFile = new Pattern();
        try {
            File filePath = new File("C:\\Users\\Ruslan\\Desktop\\MySundayMorning.midi");
            loadedFile = MidiFileManager.loadPatternFromMidi(filePath);
        } catch (InvalidMidiDataException e) {
            e.printStackTrace();
        }
        System.out.println(loadedFile);
    }
}

Y esto concluye nuestra serie de tutoriales de tres partes de la biblioteca JFugue.

Conclusión

En este tutorial, cubrimos cómo crear y usar ritmos en JFugue usando la clase Rhythm y cómo usar el RhythmKit incorporado de JFugue para crear ritmos convenientemente. También aprendimos cómo crear ritmos usando Patterns con Cuerdas Staccato, y cómo aplicar diferentes instrumentos de ritmo a nuestra canción. Finalmente, cubrimos cómo guardar nuestra música en un archivo MIDI usando JFugue y cómo leer música desde un archivo MIDI usando JFugue.

You can check out the previous article to learn about the chords and chord progressions also to learn more about the voices, attack, and decay features: Guía para principiantes de JFugue Parte II: Acordes y progresiones de acordes.

Or if you need more details about the fundamentals of JFugue such as notes, octaves, durations, and patterns, you can check out the first article: Guía para principiantes de JFugue Parte I: notas, duraciones, patrones.