Java | MIDI Introduction

02 Jul, 2021
The Musical Instrument Digital Interface (MIDI) standard defines a communication protocol for electronic music devices, such as electronic keyboard instruments and personal computers. MIDI data can be transmitted over special cables during a live performance, and can also be stored in a standard type of file for later playback or editing.A midi file contains data that represents music in terms of events. Each event gives a description of the musical note to be played – duration, pitch, velocity, channel etc. The Package javax.sound.midi provides interfaces and classes for I/O, sequencing, and synthesis of MIDI data.MIDI is both a hardware specification and a software specification. The javax.sound.midi package is used to create and use midi events to produce a simple soundtrack in Java.  
Java Sound API’s Representation of MIDI Device
 
MidiDevice Interface : The MidiDevice interface includes an API for opening and closing a device. It also includes an inner class called MidiDevice.Info that provides textual descriptions of the device, including its name, vendor, and version.
Transmitters and Receivers : The way a device sends data is via one or more transmitter objects that it “owns.” Similarly, the way a device receives data is via one or more of its receiver objects. The transmitter objects implement the Transmitter interface, and the receivers implement the Receiver interface.Each transmitter can be connected to only one receiver at a time, and vice versa
 
Essential components of a Midi system
 
Synthesizer: This is the device that plays the midi soundtrack. It can either be a software synthesizer or a real midi compatible instrument.
Sequencer: A sequencer takes in Midi data(via a sequence) and commands different instruments to play the notes. It arranges events according to start time, duration and channel to be played on.
Channel: Midi supports upto 16 different channels. We can send off a midi event to any of those channels which are later synchronized by the sequencer.
Track: It is a sequence of Midi events.
Sequence: It is a data structure containing multiple tracks and timing information.The sequencer takes in a sequence and plays it.
 
Important classes and methods
 
MidiSystem: This class provides access to installed MIDI resources like sequencers, synthesizers, I/O ports. All methods are static and this class can’t be instantiated.
MidiSystem.getSequencer() – returns an instance of the sequencer interface which is connected to a synthesizer/receiver.
sequencer.open() – opens the sequencer so it can acquire system resources.
sequencer.setSequence(Sequence sequence) – Sets the current sequence on which the sequencer operates.
sequencer.setTempoInBPM(float bpm) – Sets the playback tempo in beats per minute.
sequencer.start() – Starts playback of the MIDI data in the currently loaded sequence.
sequencer.isRunning() – Indicates whether the Sequencer is currently running.
Sequence – The Sequence class instance holds a data structure representing one or more tracks and timing information.
Sequence.PPQ – Tempo based timing type, for which the resolution is expressed in pulses (ticks) per quarter note.
Sequence.createTrack() – Creates an empty track
Track – Class containing midi events arranged chronologically.
Track.add(MidiEvent event) – Adds a new event to the track.
MidiEvent(MidiMessage message, long tick) – A midi event object that contains a time stamped midi message.
ShortMessage() – A ShortMessage object with at most two data bytes (Extended from MidiMessage).
ShortMessage.setMessage(int command, int channel, int data1, int data2) – sets a ShortMessage object that has at most two data bytes (data1 and data2).
 
MIDI Commands
 
Below programs illustrate the usage of MIDI in Java: Program 1: Illustrating the implementation of a simple record. 
Java
// Java program showing the implementation of a simple recordimport 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)
Why is the number of notes limited to 31? Since data1 and data2 fields of ShortMessage are of byte type, while using setMessage(int command, int channel, int note, int velocity), note and velocity must not exceed 127.Program 2: Using command code 192 to change the instrument type  
Java
// Java program showing how to change the instrument typeimport 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
NOTE: The code won’t run on online IDE since the code requires a few seconds of runtime for playback which IDE won’t permit. 
akshaysingh98088
Java
Misc
Programming Language
Misc
Misc
Java
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Queue Interface In Java
Object Oriented Programming (OOPs) Concept in Java
Stack Class in Java
Interfaces in Java
ArrayList in Java
Overview of Data Structures | Set 1 (Linear Data Structures)
Top 10 algorithms in Interview Questions
vector::push_back() and vector::pop_back() in C++ STL
Program for nth Catalan Number
OOPs | Object Oriented Design