11

I can't seem to get the instrument to change. I switch the value of the instrument but get nothing different on the output. I can only get a piano instrument to play no matter what value I try. Here is the simple code below. Does anyone have any suggestions? Or am I missing a fundamental of the instrument object?

import javax.sound.midi.*;
//import javax.sound.*;

public class Drum {
    static int instrument = 45;
    static int note = 100;
    static int timbre = 0;
    static int force = 100;
    public static void main(String[] args) {        
        Synthesizer synth = null;
        try {
            synth = MidiSystem.getSynthesizer();
            synth.open();
        }
        catch (Exception e) {
            System.out.println(e);
        }
        Soundbank soundbank = synth.getDefaultSoundbank();
        Instrument[] instr = soundbank.getInstruments();
        synth.loadInstrument(instr[instrument]);    //Changing this int (instrument) does nothing
        MidiChannel[] mc = synth.getChannels();
        mc[4].noteOn(note, force);
        try { Thread.sleep(1000); } 
        catch(InterruptedException e) {}
        System.out.println(instr[instrument].getName());

        synth.close();

    }
} 
Matt
  • 111
  • 1
  • 1
  • 4
  • You can't just load an instrument, you must send a program change message as well. I am not a Java programmer, so I don't know how to do this, but that is what you must do. See http://download.oracle.com/javase/1.4.2/docs/api/javax/sound/midi/Synthesizer.html#loadInstrument(javax.sound.midi.Instrument) – Brad Feb 03 '11 at 00:36
  • https://stackoverflow.com/questions/30718831/midi-midimessage-program-change-with-instrument-from-different-bank – Martin Zeitler Aug 07 '18 at 19:37

3 Answers3

14

You need to tell the channel to use the instrument. I admit I've never used MIDI in Java, but something like mc.programChange(instr.getPatch().getProgram()) sounds promising.

Matti Virkkunen
  • 63,558
  • 9
  • 127
  • 159
  • That was correct. I needed the programChange command. So, for example, I used mc[4].programChange(0, instrument); I can now change instruments but it doesn't appear that percussion instruments are actually playing. I'll need to see what the deal is with that. I presume I have some setting off. Thanks guys! – Matt Feb 03 '11 at 00:58
5

To play the percussion instruments you have to use the channel 10, that channel is used only for percussion instruments. (http://en.wikipedia.org/wiki/General_MIDI)

For example:

int instrument = 36;

Sequence sequence = new Sequence(Sequence.PPQ, 1);

Track track = sequence.createTrack();


ShortMessage sm = new ShortMessage( );
sm.setMessage(ShortMessage.PROGRAM_CHANGE, 9, instrument, 0); //9 ==> is the channel 10.
track.add(new MidiEvent(sm, 0));

then every note you add it will sound with percussion.

jfp
  • 51
  • 1
  • 1
0

You need to send a program change event to the sequencer. How? Send a short message.

sound.setMessage(ShortMessage.PROGRAM_CHANGE, channel, instrument, channel);
            long timeStam1p = -1;
            Receiver rcv1r = MidiSystem.getReceiver();
            rcv1r.send(sound, timeStam1p);
            sound.setMessage(ShortMessage.NOTE_ON, channel, note, velocity);
            long timeStamp = -1;
            Receiver rcvr = MidiSystem.getReceiver();
            rcvr.send(sound, timeStamp);

Variables are channel (int) note (int), instrument (int), velocity (int). Also, I suggest to learn midi events. Events are how a midi plays notes, stops notes, change instruments, tempo change, control changes, etc. I spent 2 years using a midi program.