El estándar de interfaz digital de instrumentos musicales (MIDI) define un protocolo de comunicación para dispositivos de música electrónica, como instrumentos de teclado electrónico y computadoras personales. Los datos MIDI se pueden transmitir a través de cables especiales durante una actuación en vivo y también se pueden almacenar en un tipo de archivo estándar para su posterior reproducción o edición.
Un archivo midi contiene datos que representan la música en términos de eventos. Cada evento proporciona una descripción de la nota musical que se reproducirá: duración, tono, velocidad, canal, etc. El paquete javax.sound.midi proporciona interfaces y clases para E/S, secuenciación y síntesis de datos MIDI.
MIDI es tanto una especificación de hardware como una especificación de software.
El javax.sonido.midiEl paquete se usa para crear y usar eventos midi para producir una banda sonora simple en Java.
Representación de dispositivo MIDI de Java Sound API
- Interfaz MidiDevice: La interfaz MidiDevice incluye una API para abrir y cerrar un dispositivo. También incluye una clase interna llamada MidiDevice.Info que proporciona descripciones textuales del dispositivo, incluido su nombre, proveedor y versión.
- Transmisores y receptores: la forma en que un dispositivo envía datos es a través de uno o más objetos transmisores que «posee». De manera similar, la forma en que un dispositivo recibe datos es a través de uno o más de sus objetos receptores. Los objetos transmisores implementan la interfaz Transmisor y los receptores implementan la interfaz Receptor.
Cada transmisor se puede conectar a un solo receptor a la vez, y viceversa
Componentes esenciales de un sistema Midi
- Sintetizador: Este es el dispositivo que reproduce la banda sonora midi. Puede ser un sintetizador de software o un instrumento real compatible con midi.
- Secuenciador: un secuenciador toma datos Midi (a través de una secuencia) y ordena diferentes instrumentos para tocar las notas. Organiza los eventos según la hora de inicio, la duración y el canal en el que se reproducirá.
- Canal: Midi admite hasta 16 canales diferentes. Podemos enviar un evento midi a cualquiera de esos canales que luego son sincronizados por el secuenciador.
- Pista: Es una secuencia de eventos Midi.
- Secuencia: es una estructura de datos que contiene múltiples pistas e información de tiempo. El secuenciador toma una secuencia y la reproduce.
Clases y métodos importantes
- MidiSystem : esta clase proporciona acceso a recursos MIDI instalados como secuenciadores, sintetizadores, puertos de E/S. Todos los métodos son estáticos y esta clase no se puede instanciar.
- MidiSystem.getSequencer() : devuelve una instancia de la interfaz del secuenciador que está conectada a un sintetizador/receptor.
- secuenciar.open() : abre el secuenciador para que pueda adquirir recursos del sistema.
- secuenciador.setSequence(secuencia de secuencia) – Establece la secuencia actual en la que opera el secuenciador.
- secuenciar.setTempoInBPM(float bpm) – Establece el tempo de reproducción en pulsaciones por minuto.
- secuenciar.start() : inicia la reproducción de los datos MIDI en la secuencia cargada actualmente.
- secuenciar.isRunning() : indica si el secuenciador se está ejecutando actualmente.
- Secuencia : la instancia de la clase Secuencia contiene una estructura de datos que representa una o más pistas e información de tiempo.
- Sequence.PPQ : tipo de temporización basado en tempo, para el cual la resolución se expresa en pulsos (ticks) por negra.
- Sequence.createTrack() – Crea una pista vacía
- Pista : clase que contiene eventos midi ordenados cronológicamente.
- Track.add (evento MidiEvent) : agrega un nuevo evento a la pista.
- MidiEvent (mensaje MidiMessage, marca larga) : un objeto de evento midi que contiene un mensaje midi con marca de tiempo.
- ShortMessage() : un objeto ShortMessage con dos bytes de datos como máximo (extendido de MidiMessage).
- ShortMessage.setMessage(int command, int channel, int data1, int data2) : establece un objeto ShortMessage que tiene como máximo dos bytes de datos (data1 y data2).
Comandos MIDI
Código | Dominio |
---|---|
144 | Nota sobre el evento |
128 | Evento de nota desactivada |
192 | Cambio de programa para cambiar el instrumento predeterminado, etc. |
176 | Cambio de control para el envío de eventos |
224 | Inflexión de tono |
Los siguientes programas ilustran el uso de MIDI en Java:
Programa 1: Ilustra la implementación de un registro simple.
Java
// Java program showing the implementation of a simple record import javax.sound.midi.*; import java.util.*; public class MyMidiPlayer { public static void main(String[] args) { System.out.println("Enter the number of notes to be played: "); Scanner in = new Scanner(System.in); int numOfNotes = in.nextInt(); MyMidiPlayer player = new MyMidiPlayer(); player.setUpPlayer(numOfNotes); } public void setUpPlayer(int numOfNotes) { try { // A static method of MidiSystem that returns // a sequencer instance. Sequencer sequencer = MidiSystem.getSequencer(); sequencer.open(); // Creating a sequence. Sequence sequence = new Sequence(Sequence.PPQ, 4); // PPQ(Pulse per ticks) is used to specify timing // type and 4 is the timing resolution. // Creating a track on our sequence upon which // MIDI events would be placed Track track = sequence.createTrack(); . // Adding some events to the track for (int i = 5; i < (4 * numOfNotes) + 5; i += 4) { // Add Note On event track.add(makeEvent(144, 1, i, 100, i)); // Add Note Off event track.add(makeEvent(128, 1, i, 100, i + 2)); } // Setting our sequence so that the sequencer can // run it on synthesizer sequencer.setSequence(sequence); // Specifies the beat rate in beats per minute. sequencer.setTempoInBPM(220); // Sequencer starts to play notes sequencer.start(); while (true) { // Exit the program when sequencer has stopped playing. if (!sequencer.isRunning()) { sequencer.close(); System.exit(1); } } } catch (Exception ex) { ex.printStackTrace(); } } public MidiEvent makeEvent(int command, int channel, int note, int velocity, int tick) { MidiEvent event = null; try { // ShortMessage stores a note as command type, channel, // instrument it has to be played on and its speed. ShortMessage a = new ShortMessage(); a.setMessage(command, channel, note, velocity); // A midi event is comprised of a short message(representing // a note) and the tick at which that note has to be played event = new MidiEvent(a, tick); } catch (Exception ex) { ex.printStackTrace(); } return event; } }
Input: Enter the number of notes to be played: 15 Output: 15 sound notes with increasing pitch are played Input: Enter the number of notes to be played: 25 Output: 25 sound notes with increasing pitch are played (Note: Number of notes should not exceed 31 for reasons cited later)
¿Por qué el número de billetes está limitado a 31?
Dado que los campos data1 y data2 de ShortMessage son de tipo byte, al usar setMessage(int command, int channel, int note, int speed), la nota y la velocidad no deben exceder 127.
Programa 2: Usar el código de comando 192 para cambiar el tipo de instrumento
Java
// Java program showing how to change the instrument type import javax.sound.midi.*; import java.util.*; public class MyMidiPlayer1 { public static void main(String[] args) { MyMidiPlayer1 player = new MyMidiPlayer1(); Scanner in = new Scanner(System.in); System.out.println("Enter the instrument to be played"); int instrument = in.nextInt(); System.out.println("Enter the note to be played"); int note = in.nextInt(); player.setUpPlayer(instrument, note); } public void setUpPlayer(int instrument, int note) { try { Sequencer sequencer = MidiSystem.getSequencer(); sequencer.open(); Sequence sequence = new Sequence(Sequence.PPQ, 4); Track track = sequence.createTrack(); // Set the instrument type track.add(makeEvent(192, 1, instrument, 0, 1)); // Add a note on event with specified note track.add(makeEvent(144, 1, note, 100, 1)); // Add a note off event with specified note track.add(makeEvent(128, 1, note, 100, 4)); sequencer.setSequence(sequence); sequencer.start(); while (true) { if (!sequencer.isRunning()) { sequencer.close(); System.exit(1); } } } catch (Exception ex) { ex.printStackTrace(); } } public MidiEvent makeEvent(int command, int channel, int note, int velocity, int tick) { MidiEvent event = null; try { ShortMessage a = new ShortMessage(); a.setMessage(command, channel, note, velocity); event = new MidiEvent(a, tick); } catch (Exception ex) { ex.printStackTrace(); } return event; } }
Input : Enter the instrument to be played 102 Enter the note to be played 110 Output : Sound note is played Input : Enter the instrument to be played 40 Enter the note to be played 100 Output : Sound note is played
NOTA: El código no se ejecutará en el IDE en línea, ya que el código requiere unos segundos de tiempo de ejecución para la reproducción que el IDE no permite.