MIDI - 使用来自不同银行的乐器更改 MidiMessage 程序
Posted
技术标签:
【中文标题】MIDI - 使用来自不同银行的乐器更改 MidiMessage 程序【英文标题】:MIDI - MidiMessage Program Change with Instrument From Different Bank 【发布时间】:2015-06-08 20:49:31 【问题描述】:我使用的默认合成器的音库包含各种不同的乐器。比如这段代码sn -p...
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
演奏这些库中的任何一种乐器,就像这样(演奏来自 1152 库的乐器 14,“Carillon”):
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));
但是,当我在银行 1152 中寻找工具 14 时,这会将工具更改为银行 0(“Tubular-bell”)中的工具 14。尝试将 ShortMessage 构造函数中的最后两个参数中的任何一个更改为 1152 导致在 javax.sound.midi.InvalidMidiDataException
中表示数据字节值超出范围。其他 MidiMessage 子类似乎也不包含从其他银行加载工具的选项。
如何在 MidiEvent 的 MidiMessage 中使用来自不同银行的乐器?
【问题讨论】:
可能取决于您发送 MIDI 库选择消息的时间和方式。 sn-ps 不显示任何库选择操作。如果您只是忘记它,请先尝试一下。如果你这样做了,我可能会有一个答案,告诉更多关于 MIDI Bank Select 可能存在的问题。 @Hibou57 据我所知,银行选择命令用于 MidiChannels(除非我弄错了,否则我的格式为channel.programChange(1152, 14)
)。 MidiMessage 是否有等价物?
好吧...我不知道 Java MIDI API,所以我没有注意到。银行号码大得惊人(这对我来说并不常见)。问题可能在于 Bank Select 消息(此处必须是隐含的)存在三种可能的形式:GM2 或 GS 或 XG。但是如果 API 不允许直接处理 Bank Select 消息,那么了解它也无济于事。
另外,ShortMessage(ShortMessage.PROGRAM_CHANGE, 0, 14, 0)
在我看来很可疑。你检查过这个吗?应该有两个参数(频道和节目号),但这里有三个。您是否尝试过将零之一变成其他东西?看起来其中一个参数可能是此 API 的银行号码。
@Hibou57 ShortMessage
构造函数的四参数形式从单独的命令和通道值创建 MIDI 状态字节。
【参考方案1】:
在 MIDI 协议本身中,库编号被分成两个 7 位部分,并作为两个 controllers 的值传输,“Bank Select”和“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);
请注意,不同的标准(GS、XG、GM2)以不同的方式命名银行选择编号的两个部分。 在这种情况下,Carillon 来自 GS 标准,该标准将其定义为“变体编号 9”,即 MSB 控制器。但控制器名称无关紧要;只要将控制器 0 设置为 9,就可以获得正确的仪器。
【讨论】:
正是我想要的。感谢您的帮助和信息。以上是关于MIDI - 使用来自不同银行的乐器更改 MidiMessage 程序的主要内容,如果未能解决你的问题,请参考以下文章
Java MIDI - ControllerEventListener(如何更改乐器)
无法在 Java MIDI 程序中更改乐器,InvalidMidiDataException:channel out of range