MIDI - Смена программы MidiMessage с помощью инструмента из другого банка

Звуковой банк синтезатора по умолчанию, который я использую, содержит множество различных инструментов. Например, этот фрагмент кода...

Synthesizer synthesizer = MidiSystem.getSynthesizer();
synthesizer.open();
Instrument instruments = synthesizer.getDefaultSoundbank().getInstruments();
for (Instrument i : instruments)
    System.out.println(i);

... печатает следующее:

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

Я могу играть на инструменте из любого из этих банков через MidiChannel, programChange метод и noteOnПримерно так (это играет инструмент 14 из банка 1152, "Карильон"):

MidiChannel channel = synthesizer.getChannels()[0];
if (channel != null) {
    channel.programChange(1152, 14);
    channel.noteOn(70, 100);
}

Я хочу добавить событие изменения программы в дорожку последовательности, чтобы я мог играть на инструменте "Карильон" в последовательности. Я пытался сделать это с 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));

Но это меняет инструмент на инструмент 14 в банке 0 ("трубчатый колокол"), когда я вместо этого ищу инструмент 14 в банке 1152. Попытка изменить один из двух последних аргументов в конструкторе ShortMessage на 1152 привела к javax.sound.midi.InvalidMidiDataException для значения байта данных вне диапазона. Другие подклассы MidiMessage, по-видимому, также не содержат возможности загрузки инструментов из других банков.

Как я могу использовать инструмент из другого банка в MidiMventage MidiEvent?

1 ответ

Решение

В самом протоколе MIDI номера банков разделены на две 7-битные части и передаются как значения двух контроллеров: "Выбор банка" и "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);

Обратите внимание, что в разных стандартах (GS, XG, GM2) две части номера выбора банка называются по-разному. В этом случае Carillon взят из стандарта GS, который определяет его как "вариант № 9", который является контроллером MSB. Но имя контроллера не имеет значения; вы получаете правильный инструмент, если вы установите контроллер от 0 до 9.

Другие вопросы по тегам