Arduino Uno:从 Cubase 捕获 MIDI 以在按下 PLAY、STOP、RECORD 时打开 RECORDING 标志

Posted

技术标签:

【中文标题】Arduino Uno:从 Cubase 捕获 MIDI 以在按下 PLAY、STOP、RECORD 时打开 RECORDING 标志【英文标题】:Arduino Uno: Capturing MIDI from Cubase to turn on RECORDING sign when PLAY, STOP, RECORD is pressed 【发布时间】:2021-01-20 13:45:55 【问题描述】:

我想要一个点亮的 RECORDING 标志,以根据我的录音软件的播放状态改变颜色。当我在音乐软件 Cubase 中按下 STOP、PLAY 或 RECORD 时,我编写了下面的 Arduino 代码来打开三个继电器(LED 灯)之一。按下时,Cubase 会传输这些 MIDI 字符串:

Cubase sends "B0 0C 0E   B0 2C 44" when it begins to PLAY
Cubase sends "B0 0C 0E   B0 2C 43" when it begins to STOP
Cubase sends "B0 0C 0E   B0 2C 45" when it begins to RECORD

我的代码找到了第一个字节,然后等待第二个字节。但那是不必要的。

例如,我只需要显示“B0 2C 44”(或十进制的 176-44-68),然后打开 PLAY(绿色)LED。

有效。

但是,并非总是如此。每隔四五次,它就感觉不到了。我将我正在使用的硬件放在注释中。

我已经进行了几天的研究,并且知道其他人遇到了同样的问题,但我似乎找不到解决方案。感谢您提供的任何建议。


/*RECORDING SIGN for Steinberg Cubase Pro 11
Copyright (c) 2021 by Tom Sylvester, Inc. A North Carolina Corp
Feel free to use this code in your own project.  Just credit me.
Monitoring MidiOX, I determined:
Cubase sends "B0 0C 0E   B0 2C 44" when it begins to PLAY
Cubase sends "B0 0C 0E   B0 2C 43" when it begins to STOP
Cubase sends "B0 0C 0E   B0 2C 45" when it begins to RECORD
Cubase sends "B0 0C 0E   B0 2C 42" when it begins to SCRUB FWD
Cubase sends "B0 0C 0E   B0 2C 41" when it begins to SCRUB REW
Cubase sends "B0 0C 0F   B0 2C 43" when LOOP is set to ON
Cubase sends "B0 0C 0F   B0 2C 03" when LOOP is set to OFF
The following code takes these strings and turns the LED Relays On/Off.
    
PARTS:
Arduino Uno R3 Microcontroller ($14)
UBld.it MIDI Breakout Board ($12)
HiLetgo 5V 4 Channel Relay Shield ($8)
5V LED Strip Light ($9)
Striveday 22 AWG 5 conductor wire ($18)
FORE MIDI to USB Interface MIDI Cable Adapter ($20)
Wolfwhoop PW-D Control Buck Converter 6-24V to 5V
1.5A Step-Down Regulator Module Power Inverter Volt Stabilizer ($2)
9V DC Adapter ($9)  
Radio Shack Project Enclosure (5x2x2.5) ($10)
SUBTOTAL: $93
Custom Etched Acrylic Logo (8.5x11x.25) approx $22
TOTAL: $115
*/
    
// VARIABLES
int dataStop = 67;
int dataPlay = 68;
int dataRecord = 69;
int dataFwd = 66;
int dataRev = 65;
int StayOnRecord = 0;
  
// MIDI 
byte status1;
byte data11;
byte data12;
    
// RELAYS
#define relay2Blue 6
#define relay3Green 5
#define relay4Red 4
    
void setup() 
  Serial.begin(31250);
  pinMode(relay2Blue, OUTPUT);
  pinMode(relay3Green, OUTPUT);
  pinMode(relay4Red, OUTPUT); 
  digitalWrite(relay2Blue, HIGH); // TURN ON BLUE RELAY (#2) INITIALLY

   
void checkMIDI() 
  do 
    if (Serial.available()) 
      status1 = Serial.read(); // read first byte
      data11 = Serial.read();  // read next byte
      data12 = Serial.read();  // read final byte

      // STOP
      if ((status1 == 176) && (data11 == 44) && (data12 == dataStop)) 
        StayOnRecord = 0;
        digitalWrite(relay2Blue, HIGH);
        digitalWrite(relay3Green, LOW);
        digitalWrite(relay4Red, LOW);
      
    
      // RECORD
      if ((status1 == 176) && (data11 == 44) && (data12 == dataRecord)) 
        StayOnRecord = 1;
        digitalWrite(relay2Blue, LOW);    
        digitalWrite(relay3Green, LOW);
        digitalWrite(relay4Red, HIGH);
      
                          
      // PLAY
      if ((status1 == 176) && (data11 == 44) && (data12 == dataPlay)) 
        if (StayOnRecord == 0)  // Cubase sends a PLAY command after RECORD, so this keeps PLAY (GREEN) from lighting up during RECORD (RED)
          digitalWrite(relay2Blue, LOW);    
          digitalWrite(relay3Green, HIGH);
          digitalWrite(relay4Red, LOW);
        
        StayOnRecord = 0; // ...then RESETs it.
      
    
      // FAST FORWARD
      if ((status1 == 176) && (data11 == 44) && (data12 == 66)) 
        for (int i=1; i<=6 ; i++)  
          digitalWrite(relay2Blue, HIGH);
          digitalWrite(relay4Red, LOW); 
          digitalWrite(relay3Green, HIGH); // TURN ON ALL RELAYS
          delay(20);
          digitalWrite(relay2Blue, LOW);
          digitalWrite(relay4Red, LOW); 
          digitalWrite(relay3Green, LOW);  // TURN OFF ALL RELAYS
          delay(20);
        
        digitalWrite(relay3Green, LOW);
        digitalWrite(relay4Red, LOW);
        digitalWrite(relay2Blue, HIGH);    // TURN ON BLUE RELAY (#2)
        StayOnRecord = 0;
        delay(10);
      
    
      // FAST REVERSE
      if ((status1 == 176) && (data11 == 44) && (data12 == 65)) 
        for (int i=1; i<=6 ; i++)  
          digitalWrite(relay2Blue, HIGH);
          digitalWrite(relay4Red, LOW); 
          digitalWrite(relay3Green, HIGH); // TURN ON ALL RELAYS
          delay(20);
          digitalWrite(relay2Blue, LOW);
          digitalWrite(relay4Red, LOW); 
          digitalWrite(relay3Green, LOW);  //TURN OFF ALL RELAYS
          delay(20);
        
        digitalWrite(relay3Green, LOW);
        digitalWrite(relay4Red, LOW);
        digitalWrite(relay2Blue, HIGH);    //TURN ON BLUE RELAY (#2)
        StayOnRecord = 0;
        delay(10);
      
    
  
  while (Serial.available() > 2); // when at least three bytes available   

    
void loop()
  checkMIDI();
  delay(10);

Arduino,带有 Relay Shield:

工作记录标志:

【问题讨论】:

【参考方案1】:

酷项目!

每次通过loop() 调用checkMIDI(),它会测试一个字符是否可用,然后尝试读取三个 值。将 do while 更改为 while (Serial.available() &gt;= 3) ... 可能会修复它,这可能就足够了。

一个选项 - 使用 MIDI 库,让它为您收集和解析。您将定义一个回调来获取 CC 命令,并决定如何处理它们。 https://github.com/FortySevenEffects/arduino_midi_library

另一种选择,重新扫描以设置一些标志,并使用loop()。这是一个粗略的骨架:

const byte IDLE = 0, NEEDCC = 1, NEEDNUM = 2;

byte midiscanstate = IDLE;

// this is inside loop()
if serial available
    b = serial read
    switch midiscanstate
    case IDLE
        if b == B0
            midiscanstate = NEEDCC
    case NEEDCC
        if b == 0x2C
            midiscanstate = NEEDNUM
        else
            midiscanstate = IDLE
    case NEEDNUM
        doaction(b)
        midiscanstate = IDLE
    default
        midiscanstate = IDLE

画出状态和改变状态的字节,以确保我做对了。我认为这会奏效。 (如果它们妨碍了,可能应该忽略 MIDI 实时消息)。 !玩得开心!

【讨论】:

非常感谢。我越来越近了。我使用了您推荐的 CallBack,它正确地进入了程序。但是我看不到status1、data11、data12的内容。我认为它期待十六进制。我可以让它在程序中打开灯。但是如果没有 IF..THEN 或 CASE 来确定变量,我就被卡住了。也许你可以告诉我如何让串行监视器在 9600 以外的地方工作,这样我就可以看到 status1、data11 和 data12 是什么。非常感谢您的帮助。【参考方案2】:

@aMike,感谢您的想法。您的回调建议几乎有效。它将转到下面的 doCC 回调(我用 != 0 对其进行了测试,并且还通过简单地在过程中打开继电器)。但是为了做 IF..THENCASE,我需要知道 status1data11、而 data12 又回来了。唉,没有可用的串行监视器(9600 波特),我在一个熄灯的房间里。它应该发送“B0 2C 44”,但显然不是。你一直很有帮助——几乎就在那里!

#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
void handleControlChange(byte status1, byte data11, byte data12);

// VARIABLES
byte dataStop = 0x43;
byte dataPlay = 0x44;
byte dataRecord = 0x45;
int StayOnRecord = 0;
  
// RELAYS
#define relay2Blue 6
#define relay3Green 5
#define relay4Red 4
    
void doCC(byte status1, byte data11, byte data12)

      // STOP
      if ((status1 == 0xB0) && (data11 == 0x2C) && (data12 == 0x43)) 
        StayOnRecord = 0;
        digitalWrite(relay2Blue, HIGH);
        digitalWrite(relay3Green, LOW);
        digitalWrite(relay4Red, LOW);
      
    
      // RECORD
      if ((status1 == 0xB0) && (data11 == 0x2C) && (data12 == 0x45)) 
        StayOnRecord = 1;
        digitalWrite(relay2Blue, LOW);    
        digitalWrite(relay3Green, LOW);
        digitalWrite(relay4Red, HIGH);
      
                          
      // PLAY
      if ((status1 == 0xB0) && (data11 == 0x2C) && (data12 == 0x44)) 
        if (StayOnRecord == 0)                   // Cubase sends a PLAY command after RECORD, so this keeps PLAY (GREEN) from lighting up during RECORD (RED)
          digitalWrite(relay2Blue, LOW);    
          digitalWrite(relay3Green, HIGH);
          digitalWrite(relay4Red, LOW);
        
        StayOnRecord = 0;                         // ...then RESETs it.
      



void setup() 
  pinMode(relay2Blue, OUTPUT);
  pinMode(relay3Green, OUTPUT);
  pinMode(relay4Red, OUTPUT); 
  digitalWrite(relay2Blue, HIGH);               // TURN ON the BLUE LED Relay (#2) INITIALLY

    MIDI.begin(MIDI_CHANNEL_OMNI);             // Listen on all channels
//    MIDI.turnThruOff();          
    MIDI.setHandleControlChange(doCC);    



void loop()

  MIDI.read();

【讨论】:

我们快到了! MIDI 库正在为您进行大量处理和解码。您的回调获取通道号,而不是整个状态字节。我可能会尽快完成测试和return;它将简化您的 if 语句:if (chan != 0) return; if (ccnum != 0x2C) return; // now switch on the CC value ... 非常重要 - 您的回调不应使用 delay 或做任何需要时间的事情。另外,Uno 只有一个串口,供 MIDI 使用,所以我们无法打印到串口监视器。 非常感谢@aMike!你很准。我不知道该怎么感谢你才足够!代码现在完美运行,绝对完美——没有丢失!【参考方案3】:

非常感谢@aMike。你的想法是正确的。现在,此代码完美运行,零退出:

#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
void handleControlChange(byte status1, byte data11, byte data12);

// VARIABLES
byte dataStop = 0x43;
byte dataPlay = 0x44;
byte dataRecord = 0x45;
byte dataFFWD = 0x42;
byte dataFREV = 0x41;
int StayOnRecord = 0;
  
// RELAYS
#define relay2Blue 6
#define relay3Green 5
#define relay4Red 4
    
void doCC(byte status1, byte data11, byte data12)
     // get note value
      status1 = MIDI.getChannel();
      data11 = MIDI.getData1();
      data12 = MIDI.getData2();

      // STOP
      if (data12 == dataStop) 
        StayOnRecord = 0;
        digitalWrite(relay2Blue, HIGH);
        digitalWrite(relay3Green, LOW);
        digitalWrite(relay4Red, LOW);
      
    
      // RECORD
      if (data12 == dataRecord) 
        StayOnRecord = 1;
        digitalWrite(relay2Blue, LOW);    
        digitalWrite(relay3Green, LOW);
        digitalWrite(relay4Red, HIGH);
      
                          
      // PLAY
      if (data12 == dataPlay) 
        if (StayOnRecord == 0)                   // Cubase sends a PLAY command after RECORD, so this keeps PLAY (GREEN) from lighting up during RECORD (RED)
          digitalWrite(relay2Blue, LOW);    
          digitalWrite(relay3Green, HIGH);
          digitalWrite(relay4Red, LOW);
        
        StayOnRecord = 0;                         // ...then RESETs it.
      

      // Fast FWD
      if (data12 == dataFFWD) 
        StayOnRecord = 0;
        digitalWrite(relay2Blue, HIGH);
        digitalWrite(relay3Green, HIGH);
        digitalWrite(relay4Red, LOW);
      

      // Fast REV
      if (data12 == dataFREV) 
        StayOnRecord = 0;
        digitalWrite(relay2Blue, LOW);
        digitalWrite(relay3Green, HIGH);
        digitalWrite(relay4Red, HIGH);
      





void setup() 
  pinMode(relay2Blue, OUTPUT);
  pinMode(relay3Green, OUTPUT);
  pinMode(relay4Red, OUTPUT); 
  digitalWrite(relay2Blue, HIGH);               // TURN ON the BLUE LED Relay (#2) INITIALLY
  MIDI.begin(MIDI_CHANNEL_OMNI);               // Listen on all channels
  MIDI.turnThruOff();          
  MIDI.setHandleControlChange(doCC);    



void loop()

  MIDI.read();

【讨论】:

以上是关于Arduino Uno:从 Cubase 捕获 MIDI 以在按下 PLAY、STOP、RECORD 时打开 RECORDING 标志的主要内容,如果未能解决你的问题,请参考以下文章

arduino uno r3 上的这么多针脚都有啥用

arduino uno r3 上的这么多针脚都有啥用?

如何用Arduino uno r3给另一块板子烧录Bootloader

Arduino uno板上连接一个HC-05,设置后能与手机配对成功,但是无法连接?

arduino uno +sim900+手机接收短信

为啥arduino uno只能保留两位小数