我正在编写一个简单的C ++命令行工具,通过Roland UM-One Mk 2 USB接口将来自Mac(MacOS 10.12)的MIDI信息发送到Behringer Powerplay P16-M音频混音器。我正在使用rtmidi
realtime MIDI API。
当我将两个连续的MIDI信息发送到同一个频道时,这两个信息似乎被混音器弄乱了。当我向备用频道发送两条连续的消息时,它可以正常工作。
例如,为了将通道1电平设置为midi 0(-51dB)和通道1平移到midi 64(居中),我理解我应该发送以下两条消息:
0xB0 0x07 0x0
和0xB0 0x0A 0x40
。当我一个接一个地发送这些消息时,混音器上的LED意外地指示通道1级别大约为64并且平移没有改变 - 就像我发送了单个消息0xB0 0x07 0x40
一样。相反,如果我用另一个频道的消息散布这两个消息,或者用一个可笑的长睡眠(任何超过900毫秒的时间),LED指示预期的设置:水平为零,平移中心。
我做错了什么?为什么我不能将两个连续的消息发送到同一个频道?我发送的邮件太快了吗?这是rtmidi
问题吗?这是调音台的问题吗?
这是一个演示问题的最小但完整的工作示例。 (我在XCode中针对CoreMIDI,CoreAudio和CoreFoundation框架进行编译。)
#include <iostream>
#include <vector>
#include <unistd.h> // (for usleep)
#include "RtMidi.h"
// define some midi messages
static std::vector<unsigned char> ch1vol {0xB0 , 0x07 , 0x0}; // set ch 1 volume to midi 0 (-51dB)
static std::vector<unsigned char> ch1pan {0xB0 , 0x0A , 0x40}; // set ch 1 pan to 64
static std::vector<unsigned char> ch2vol {0xB1 , 0x07 , 0x0}; // set ch 2 volume to midi 0 (-51dB)
static std::vector<unsigned char> ch2pan {0xB1 , 0x0A , 0x40}; // set ch 2 pan to 64
#define SLEEPMSEC( milliseconds ) usleep( (unsigned long) (milliseconds * 1000.0) )
int main(int argc, const char * argv[]) {
RtMidiOut * midiOut = new RtMidiOut(); // create an RtMidiOut
// are there any midi ports available?
if (!midiOut->getPortCount()) {
std::cout << "*** No midi ports found. Goodbye." << std::endl;
exit(1);
}
// open the desired midi device
std::string portName = midiOut->getPortName(0);
if (portName != "Powerplay 16") {
std::cout << "*** Can't find requested midi device. Goodbye." << std::endl;
exit(1);
}
midiOut->openPort(0); // open the midi device to receive output
switch(argc) {
case 2:
// This works as expected
// Result: channels 1 and 2 volumes are set to 0; the panning in both channels is centered)
midiOut->sendMessage( &ch1vol ); // set ch 1 volume to 0
midiOut->sendMessage( &ch2vol ); // set ch 2 volume to 0
midiOut->sendMessage( &ch1pan ); // set ch 1 pan to center
midiOut->sendMessage( &ch2pan ); // set ch 2 pan to center
break;
case 3:
// This does NOT work as expected
// Result: channels 1 and 2 volumes are set to 64; the panning in both channels is unchanged
midiOut->sendMessage( &ch1vol ); // set ch 1 volume to 0
midiOut->sendMessage( &ch1pan ); // set ch 1 pan to center
midiOut->sendMessage( &ch2vol ); // set ch 2 volume to 0
midiOut->sendMessage( &ch2pan ); // set ch 2 pan to center
break;
case 4:
// Introduce a sleep in between same-channel calls.
// This DOES work as expected (but with an unacceptable delay)
midiOut->sendMessage( &ch1vol ); // set ch 1 volume to 0
SLEEPMSEC(900);
midiOut->sendMessage( &ch1pan ); // set ch 1 pan to center
midiOut->sendMessage( &ch2vol ); // set ch 2 volume to 0
SLEEPMSEC(900);
midiOut->sendMessage( &ch2pan ); // set ch 2 pan to center
break;
default:
std::cout << "Usage: testmidi ARG [ARG [ARG]]" << std::endl;
std::cout << "Perform a midi test according to the number of arguments." << std::endl;
std::cout << "Be sure to reset the device manually after each run." << std::endl;
break;
}
}
答案 0 :(得分:0)
正如@Kurt Revis所说,问题在于调音台。
我做了什么: 我使用MIDI Monitor来验证我的外发邮件是否正确。所以我的代码没问题。我将我的电缆连接到另一个MIDI设备(一个Roland Juno合成器)并发送了一堆重复的消息:没问题。我得出结论,Mac,我的代码,UM-ONE接口和电缆都可以。离开调音台。我尝试了第二个Behringer Powerplay P16-M,并得到了完全相同的结果。因此,混合器似乎可能是设计/制造问题。
我的结论是: Behringer Powerplay P16-M调音台无法正确处理按顺序发送到同一频道的MIDI信息,除非它们都是相同的控制变化类型。
解决方法: 经过大量的实验,这就是我所提出的:
将连续(但不同)控制更改消息发送到同一通道时,在消息之间插入至少500毫秒的延迟。例如,如果您向一个频道发送一堆音量消息,然后向该频道发送一堆平移消息,则没有问题。如果要将一堆交错的卷和平移消息发送到同一个通道,则需要在每条消息之间插入延迟。
重置调音台时,通道0(&#34; main&#34;)需要特殊处理。发送给它的消息需要被隔离&#34;通过插入至少500毫秒的延迟发送到其他频道的消息。
<强> [编辑] 强>
更好的解决方案:
而不是插入延迟,而是向设备发送MIDI音调弯曲消息(例如,发送0xE0 0x0 0x0
)。尽管P16-M没有任何记录用于弯音信息的用途,但它显然足以震动并使设备恢复与消息流同步。无论如何,对我有用。