Open In App

Java | MIDI Introduction

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

Introduction:

Java MIDI is a set of Java APIs for handling musical data and MIDI (Musical Instrument Digital Interface) devices. These APIs allow Java programs to access and manipulate MIDI data, and can be used to create applications such as music players, synthesizers, and more. The Java Sound API, which includes the MIDI package, provides a low-level, platform-independent interface to audio devices and MIDI devices.

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

 

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.
 

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)

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 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

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.

Advantages Or Disadvantages:
 Advantages of Java MIDI:

  1. Cross-platform compatibility: Java MIDI works on any platform that has a Java Virtual Machine, making it a portable solution.
  2. High-level API: Java MIDI provides a high-level API, which makes it easier to work with MIDI data compared to the low-level MIDI API.
  3. Large developer community: Java has a large developer community, which makes it easier to find support and resources when working with Java MIDI.

Disadvantages of Java MIDI:

  1. Performance: Java MIDI may not perform as well as native MIDI implementations, particularly when it comes to real-time performance.
  2. Limited device support: Java MIDI may not support all the features of a particular MIDI device, as the API is designed to be platform-independent.
  3. Complexity: Java MIDI can be complex to work with, especially for developers who are not familiar with the Java Sound API.


Last Updated : 05 Feb, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads