Java | MIDI Introduction

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.
  • Seqeunce.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

Code Command
144 Note On Event
128 Note Off Event
192 Program Change for changing default instrument etc
176 Control change for sending events
224 Pitch Bend

Below programs illustrate the usage of MIDI in Java:
Program 1: Illustrating the implementation of a simple record.

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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;
    }
}

chevron_right


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

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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;
    }
}

chevron_right


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.



My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.




Article Tags :
Practice Tags :


Be the First to upvote.


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.