HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Playing MIDI instruments in Java

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
playingmidiinstrumentsjava

Problem

This program offers 8 notes C, D, ..., A, B, C on keyboard keys 1, 2, ..., 8. Also, by typing Left or Right, you can cycle over MIDI instruments.

KeyboardPiano.java:

```
package net.coderodde.music;

import java.awt.Canvas;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.sound.midi.Instrument;
import javax.sound.midi.MidiChannel;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Soundbank;
import javax.sound.midi.Synthesizer;
import javax.swing.JFrame;

public class KeyboardPiano {

private static final String APP_TITLE = "Keyboard Piano";

private final JFrame frame = new JFrame(APP_TITLE);
private final Canvas canvas = new Canvas();
private Synthesizer synthesizer;
private final MidiChannel[] midiChannels;
private final Instrument[] instruments;
private int instrumentIndex = 0;

KeyboardPiano() {
try {
synthesizer = MidiSystem.getSynthesizer();
synthesizer.open();
} catch (MidiUnavailableException ex) {
ex.printStackTrace();
System.exit(1);
}

this.midiChannels = synthesizer.getChannels();

Soundbank bank = synthesizer.getDefaultSoundbank();

synthesizer.loadAllInstruments(bank);

this.instruments = synthesizer.getAvailableInstruments();
synthesizer.loadAllInstruments(synthesizer.getDefaultSoundbank());
synthesizer.getChannels()[0].programChange(instrumentIndex);

System.out.println("[STATE] MIDI channels: " + midiChannels.length);
System.out.println("[STATE] Instruments: " + instruments.length);
}

private void init() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(canvas);
frame.setSize(100, 100);
frame.setResizable(false);
canvas.addKeyListener(new KeyboardPianoListener());
canvas.setFocusable(true);

Solution

Repetition, specially when it occurs with switch cases is both bad for you and for your code. The switch (keyCode) is present two times in your code and all it does (almost) is just to map an integer. And I bolded map because that if that is what you want to do then we can use the HashMap to specify the note number that a key matches to.

private HashMap mapNotes = new HashMap();

KeyboardPiano() {
    try {
        synthesizer = MidiSystem.getSynthesizer();
        synthesizer.open();
    } catch (MidiUnavailableException ex) {
        ex.printStackTrace();
        System.exit(1);
    }   

    mapNotes.put(KeyEvent.VK_1, 60);
    mapNotes.put(KeyEvent.VK_2, 62);
    mapNotes.put(KeyEvent.VK_3, 64);
    mapNotes.put(KeyEvent.VK_4, 65);
    mapNotes.put(KeyEvent.VK_5, 67);
    mapNotes.put(KeyEvent.VK_6, 69);
    mapNotes.put(KeyEvent.VK_7, 71);
    mapNotes.put(KeyEvent.VK_8, 72);
    //...
}


And then use this same map

public void keyPressed(KeyEvent e) {
    int keyCode = e.getExtendedKeyCode();
    int noteNumber = -1;

    if(mapNotes.containsKey(keyCode)){
        noteNumber = mapNotes.get(keyCode);
    }
    //...
 }


The switch statment in keyPressed can also be simplified because there is common code. The following code is executed in both left and right key press.

synthesizer.getChannels()[0].programChange(instrumentIndex);
System.out.println("Switched to " + 
                 instruments[instrumentIndex].getName());


With everything put togheter the keyPressedbecomes the following:

public void keyPressed(KeyEvent e) {
    int keyCode = e.getExtendedKeyCode();
    int noteNumber = -1;

    if(mapNotes.containsKey(keyCode)){
        noteNumber = mapNotes.get(keyCode);
    }else{
        switch (keyCode) {
            case KeyEvent.VK_LEFT: {
                if (instrumentIndex == 0) {
                    instrumentIndex = instruments.length - 1;
                } else {
                    instrumentIndex--;
                }
                break;
            }
            case KeyEvent.VK_RIGHT: {
                if (instrumentIndex == instruments.length - 1) {
                    instrumentIndex = 0;
                } else {
                    instrumentIndex++;
                }
                break;
            }
        }
        synthesizer.getChannels()[0].programChange(instrumentIndex);
        System.out.println("Switched to " + 
                           instruments[instrumentIndex].getName());
    }

    if (noteNumber != -1) {
        midiChannels[0].noteOn(noteNumber, 600);
    }
}

Code Snippets

private HashMap<Integer, Integer> mapNotes = new HashMap<Integer, Integer>();

KeyboardPiano() {
    try {
        synthesizer = MidiSystem.getSynthesizer();
        synthesizer.open();
    } catch (MidiUnavailableException ex) {
        ex.printStackTrace();
        System.exit(1);
    }   

    mapNotes.put(KeyEvent.VK_1, 60);
    mapNotes.put(KeyEvent.VK_2, 62);
    mapNotes.put(KeyEvent.VK_3, 64);
    mapNotes.put(KeyEvent.VK_4, 65);
    mapNotes.put(KeyEvent.VK_5, 67);
    mapNotes.put(KeyEvent.VK_6, 69);
    mapNotes.put(KeyEvent.VK_7, 71);
    mapNotes.put(KeyEvent.VK_8, 72);
    //...
}
public void keyPressed(KeyEvent e) {
    int keyCode = e.getExtendedKeyCode();
    int noteNumber = -1;

    if(mapNotes.containsKey(keyCode)){
        noteNumber = mapNotes.get(keyCode);
    }
    //...
 }
synthesizer.getChannels()[0].programChange(instrumentIndex);
System.out.println("Switched to " + 
                 instruments[instrumentIndex].getName());
public void keyPressed(KeyEvent e) {
    int keyCode = e.getExtendedKeyCode();
    int noteNumber = -1;

    if(mapNotes.containsKey(keyCode)){
        noteNumber = mapNotes.get(keyCode);
    }else{
        switch (keyCode) {
            case KeyEvent.VK_LEFT: {
                if (instrumentIndex == 0) {
                    instrumentIndex = instruments.length - 1;
                } else {
                    instrumentIndex--;
                }
                break;
            }
            case KeyEvent.VK_RIGHT: {
                if (instrumentIndex == instruments.length - 1) {
                    instrumentIndex = 0;
                } else {
                    instrumentIndex++;
                }
                break;
            }
        }
        synthesizer.getChannels()[0].programChange(instrumentIndex);
        System.out.println("Switched to " + 
                           instruments[instrumentIndex].getName());
    }

    if (noteNumber != -1) {
        midiChannels[0].noteOn(noteNumber, 600);
    }
}

Context

StackExchange Code Review Q#115559, answer score: 6

Revisions (0)

No revisions yet.