The soundbank of the default synthesizer I’m using contains a variety of different instruments. For example, this code snippet…
Synthesizer synthesizer = MidiSystem.getSynthesizer(); synthesizer.open(); Instrument instruments = synthesizer.getDefaultSoundbank().getInstruments(); for (Instrument i : instruments) System.out.println(i);
… prints the following:
Instrument: Piano 1 bank #0 preset #0 Instrument: Piano 2 bank #0 preset #1 [...] Instrument: Applause bank #0 preset #126 Instrument: Gun Shot bank #0 preset #127 Instrument: SynthBass101 bank #128 preset #38 Instrument: Trombone 2 bank #128 preset #57 [...] Instrument: Machine Gun bank #128 preset #127 Instrument: Echo Pan bank #256 preset #102 Instrument: String Slap bank #256 preset #120 [...] Instrument: Lasergun bank #256 preset #127 [...] Instrument: Starship bank #1024 preset #125 Instrument: Carillon bank #1152 preset #14 [...] Instrument: Choir Aahs 2 bank #4096 preset #52
I can play an instrument from any of these banks through MidiChannel
, the programChange
method, and noteOn
, like so (this plays instrument 14 from bank 1152, “Carillon”):
MidiChannel channel = synthesizer.getChannels()[0]; if (channel != null) { channel.programChange(1152, 14); channel.noteOn(70, 100); }
I want to add a program change event to a sequence’s track so I can play the “Carillon” instrument in the sequence. I tried doing this with a ShortMessage
:
Sequence sequence = new Sequence(Sequence.PPQ, 2); Track track = sequence.createTrack(); ShortMessage pcMessage = new ShortMessage(ShortMessage.PROGRAM_CHANGE, 0, 14, 0); track.add(new MidiEvent(pcMessage, 0));
But this changes the instrument to instrument 14 in bank 0 (“Tubular-bell”) when I’m instead looking for instrument 14 in bank 1152. Attempting to change either of the last two arguments in the ShortMessage constructor to 1152 resulted in a javax.sound.midi.InvalidMidiDataException
for the data byte value being out of range. The other MidiMessage subclasses don’t seem to contain an option to load instruments from other banks, either.
How can I use an instrument from a different bank in the MidiEvent’s MidiMessage?
Advertisement
Answer
In the MIDI protocol itself, bank numbers are split into two 7-bit parts and transmitted as the value of two controllers, “Bank Select” and “Bank Select LSB”:
... = new ShortMessage(ShortMessage.CONTROL_CHANGE, 0, 0, 1152 >> 7); // = 9 ... = new ShortMessage(ShortMessage.CONTROL_CHANGE, 0, 32, 1152 & 0x7f); // = 0 ... = new ShortMessage(ShortMessage.PROGRAM_CHANGE, 0, 14, 0);
Please note that different standards (GS, XG, GM2) name the two parts of the bank select number differently. In this case, the Carillon is from the GS standard, which defines it as “variation number 9”, which is the MSB controller. But the controller name does not matter; you get the correct instrument as long as you set controller 0 to 9.