代码之家  ›  专栏  ›  技术社区  ›  jt bullitt

发送到同一频道的连续MIDI消息被篡改

  •  0
  • jt bullitt  · 技术社区  · 6 年前

    我正在编写一个简单的C++命令行实用程序,通过罗兰UM One Mk 2 USB接口将MIDI消息从我的Mac(MacOS 10.12)发送到贝林格Powerplay P16-m音频混音器。我正在使用 rtmidi realtime MIDI API

    当我向同一频道发送两条连续的MIDI消息时,这两条消息似乎被混音器弄乱了。当我向备用频道发送两条连续消息时,效果很好。

    例如,为了将通道1级别设置为midi 0(-51dB),将通道1 pan设置为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;
        }
    }
    
    1 回复  |  直到 6 年前
        1
  •  0
  •   jt bullitt    5 年前

    正如@Kurt Revis所言,问题出在混合器中。

    我所做的: 我用过 MIDI Monitor 验证我发送的消息是否正确。所以我的代码没问题。我将电缆连接到另一个MIDI设备(罗兰·朱诺合成器),并向它重复发送了一系列信息:没问题。我的结论是,Mac、我的代码、UM-ONE接口和电缆都可以。这就离开了搅拌机。我尝试了第二个Behringer Powerplay P16-M,得到了完全相同的结果。因此,搅拌机可能存在设计/制造问题。

    我的结论是: Behringer Powerplay P16-M混音器无法正确处理按顺序发送到同一频道的传入MIDI消息,除非它们都是相同的控制更改类型。

    解决方法: 经过大量实验,我得出以下结论:

    1. 向同一通道发送连续(但不同)控制更改消息时,请在消息之间插入至少500毫秒的延迟。例如,如果您向某个频道发送一组批量消息,然后再向该频道发送一组pan消息,则没有问题。如果要将一组交织的卷和pan消息发送到同一通道,则需要在每条消息之间插入延迟。

    2. 重置混音器时,通道0(“主”)需要特殊处理。发送到它的消息需要通过插入至少500毫秒的延迟与发送到其他通道的消息“隔离”。

    [编辑] 更好的解决方案: 不要插入延迟,而是向设备发送MIDI音调弯曲消息(例如,发送 0xE0 0x0 0x0 )。尽管P16-M没有任何关于俯仰弯曲消息的使用记录,但它显然足以让设备重新与消息流同步。不管怎样,对我来说很有用。

    推荐文章