Mackie Control Universal (MCU) プロトコル

コントロールサーフェス(フィジカルコントローラー)とDAWでやり取りするためのプロトコルです。

Human User Interface Protocol(HUI)が最初に作成され、後にMackie Control Universal (MCU) プロトコルの一部となっています。

 

HUIからMCUプロトコルまで作成された流れについて

Mackie社の製品が出た流れです。

 

Human User Interface(HUI)の誕生

Mackie Human User Interface

1998年、Mackie社は「Human User Interface」を発売しました。

コンピューターを使用したレコーディングシステムで業界標準となっている有名なものにDigidesign社(現Avid)の「Pro Tools」というものがあります。

このPro Toolsがまだバージョン4.0だった時代に、Mackie社はDigidesign社(現Avid)と共同プロジェクトを立ち上げHuman User Interface(HUI)というコントロールサーフェス(フィジカルコントローラー)を開発しました。

コンピューター上の操作を物理的に行えるようになる操作パネルの役割をしています。

この製品で使用されている通信プロトコルが通称HUIプロトコルと呼ばれるようになりました。

HUIプロトコルは様々なDAWでサポートされることになります。

Mackie BabyHUI

その後、小型のBaby HUIも発売。

 

Logic Controlの誕生

Emagic Logic Control

2002年、HUIに続き、Emagic社(現Apple社)のLogicに対応するLogic Control発売。

これは独自プロトコルでした。そのためLogic専用となっていました。

その後、Emagic社はApple社に買収されました。

 

Mackie Controlの誕生

Mackie Mackie Control

2002年、Mackie社はLogic Controlから外見はほぼそのままでファームウェアを変更したMackie Controlを発売。

 

Mackie Control Universal(MCU)の誕生

Mackie Mackie Control Universal

2003年になり、こちらも外見はほぼそのまま、アップデートを経てMackie Control Universalという製品になりました。

この際、今まで発売されたMackie Control、Logic Control、過去のHUIをすべて統合するMackie Control Universal (MCU) プロトコルが導入。

Mackie Control発売から割りとすぐにMackie Control Universalへと変更されたため、通信プロトコルとしては古くから使われるものが「HUI」、新しいプロトコルとしては「Mackie Control Universal (MCU) 」が使用されるようになったようです。

 

Mackie Control Universal Proの誕生

Mackie Mackie Control Universal Pro

2007年、Mackie Control Universal Pro発売。

今でも現行機種として販売されています。

Pro Toolsに対応するコントロールサーフェス(フィジカルコントローラー)用のプロトコルとして、Euphonix社のEUCONもあるようですがこのプロトコルを実装している製品はあまり見かけません。

Mackie Control Universal (MCU) プロトコルが使用できる製品は各社から販売されています。

マイコンに接続するなど各種工作に使用する上では、MIDIコネクタとして出ているほうがありがたいです。

USB-MIDIになってしまうとUSBホストの実装が必要になります。

 

PreSonus社のFaderPortシリーズや、Solid State Logic社のUF1、Waves Audio社のFIT ControllerやiCON Pro Audio社の製品ではUSB-MIDIしかないようです。

CM Labs Motormix & DashboardやDigidesign Command 8、M-Audio社のProjectMix I/O、Behringer社のBCF2000は生産終了。

そのため、2023年時点でMIDIコネクタが出ているものとしてはMackie社の「MCU Pro」シリーズかBehringer社の「X-TOUCH」シリーズの2択になってしまうようです。

 

オープンソースのプロジェクトであれば「MIDIbox LC」や「Control Surface」等が参考になるかもしれません。

 

プロトコルの詳細

インターネット上で発見した資料です。

 

Human User Interface Protocol(HUI)プロトコル

リバースエンジニアリングされた仕様書がネット上に存在しているようです。

theageman氏による解析結果です。

 

Logic Controlプロトコル

公式のマニュアル(105ページ~)にプロトコル仕様の説明があります。

Logic Proのマニュアル(239ページ~)にも同様の説明があります。

Mackie Controlとは若干の差異があるので参考程度に。

 

Mackie Control Universal (MCU) プロトコル

リバースエンジニアリングされた仕様書がネット上に存在しているようです。

Nicolas Jarnoux氏による解析結果です。

 

ArduinoからMCUプロトコルでBehringer X-TOUCHを制御

今回はBehringer社のX-TOUCHを用意しました。

MIDIコネクタを装備しています。

Arduinoを使って制御してみます。

 

X-TOUCH上のMIDIコネクタでMCUプロトコルを使用する設定

MCU X-TOUCH Arduino 001

X-TOUCHのチャンネル1のSELECTボタンを押しながら電源を入れることによってコンフィギュレーションメニューに入れます。

エンコーダーを回して、ModeをMC、IfcをMIDIにします。

これでMIDIコネクタ経由でMackie Control Universal (MCU) プロトコル使用する設定になりました。

SELECTボタンを再度押すと設定完了です。

 

X-TOUCHとArduinoの接続

MCU X-TOUCH Arduino 002 MCU X-TOUCH Arduino 003

使用したものは以下。

ピンヘッダのハンダ付けが必要です。

3.3V系のArduinoを使用したため、ピンヘッダでショートさせる必要がありました。(MIDI Unit for GROVEの説明をご覧ください)

MIDI Unit for GROVEにて信号のレベル変換を行い、5Vまたは3.3VのArduinoと接続します。

 

「SMPTE」「BEATS」「RUDE SOLO LIGHT」LEDを光らせる

Arduino側からMIDIメッセージを送り、LEDを制御する例です。

Arduino上で MIDI Library v5.0.2 を使用しました。

ディスプレイ部の右側に存在する「SMPTE」LEDと「BEATS」LEDを交互に光らせるサンプルコードです。

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

void setup()
{
    MIDI.begin(MIDI_CHANNEL_OMNI);
    delay(1000);
}

void loop()
{
  // SMPTE LED -> ON
  MIDI.sendNoteOn(113, 127, 1);
  MIDI.sendNoteOff(113, 0, 1);

  // BEATS LED -> OFF
  MIDI.sendNoteOn(114, 0, 1);
  MIDI.sendNoteOff(114, 0, 1);

  // Wait 1000ms (=1sec)
  delay(1000);
  
  // SMPTE LED -> OFF
  MIDI.sendNoteOn(113, 0, 1);
  MIDI.sendNoteOff(113, 0, 1);

  // BEATS LED -> ON
  MIDI.sendNoteOn(114, 127, 1);
  MIDI.sendNoteOff(114, 0, 1);

  // Wait 1000ms (=1sec)
  delay(1000);

  // MIDI Read
  MIDI.read();
}

MIDI Libraryのサンプルを見るとわかりやすいと思われます。

上記、Mackie Control Universal (MCU) プロトコルについてNicolas Jarnoux氏による解析結果を見ると、MIDI API負荷を下げるべく、ノートオンのあとすぐにノートオフを送ることが推奨されるようです。

簡単な例としてあげましたがMIDI.readは速いレートで繰り返し実行しないと受信バッファーが詰まる原因になるので、このようなコードは推奨されません。

0x71(0d113)がSMPTE LED、0x72(0d114)がBEATS LED、0x73(0d115)がRUDE SOLO LIGHT LEDです。

上記プログラムでは10進数(0d~)で指定していますが、16進数(0x~)での指定でも大丈夫です。

 

その他ボタンのLEDを光らせる

他のボタンやLEDなどを光らせるには以下のIDを使用します。

ID(0x) LED X-TOUCH LED COLOR
00 REC/RDY Ch. 1 RED
01 REC/RDY Ch. 2 RED
02 REC/RDY Ch. 3 RED
03 REC/RDY Ch. 4 RED
04 REC/RDY Ch. 5 RED
05 REC/RDY Ch. 6 RED
06 REC/RDY Ch. 7 RED
07 REC/RDY Ch. 8 RED
08 SOLO Ch. 1 ORANGE
09 SOLO Ch. 2 ORANGE
0A SOLO Ch. 3 ORANGE
0B SOLO Ch. 4 ORANGE
0C SOLO Ch. 5 ORANGE
0D SOLO Ch. 6 ORANGE
0E SOLO Ch. 7 ORANGE
0F SOLO Ch. 8 ORANGE
10 MUTE Ch. 1 RED
11 MUTE Ch. 2 RED
12 MUTE Ch. 3 RED
13 MUTE Ch. 4 RED
14 MUTE Ch. 5 RED
15 MUTE Ch. 6 RED
16 MUTE Ch. 7 RED
17 MUTE Ch. 8 RED
18 SELECT Ch. 1 GREEN
19 SELECT Ch. 2 GREEN
1A SELECT Ch. 3 GREEN
1B SELECT Ch. 4 GREEN
1C SELECT Ch. 5 GREEN
1D SELECT Ch. 6 GREEN
1E SELECT Ch. 7 GREEN
1F SELECT Ch. 8 GREEN
28 ASSIGNMENT: TRACK ORANGE
29 ASSIGNMENT: SEND ORANGE
2A ASSIGNMENT: PAN/SURROUND ORANGE
2B ASSIGNMENT: PLUG-IN ORANGE
2C ASSIGNMENT: EQ ORANGE
2D ASSIGNMENT: INSTRUMENT ORANGE
2E FADER BANK Left ORANGE
2F FADER BANK Right ORANGE
30 CHANNEL Left ORANGE
31 CHANNEL Right ORANGE
32 FLIP ORANGE
33 GLOBAL VIEW ORANGE
36 FUNCTION: F1 ORANGE
37 FUNCTION: F2 ORANGE
38 FUNCTION: F3 ORANGE
39 FUNCTION: F4 ORANGE
3A FUNCTION: F5 ORANGE
3B FUNCTION: F6 ORANGE
3C FUNCTION: F7 ORANGE
3D FUNCTION: F8 ORANGE
3E MIDI TRACKS ORANGE
3F INPUTS ORANGE
40 AUDIO TRACKS ORANGE
41 AUDIO INSTRUMENTS ORANGE
42 AUX ORANGE
43 BUSES ORANGE
44 OUTPUTS ORANGE
45 USER ORANGE
46 MODIFY: SHIFT ORANGE
47 MODIFY: OPTION ORANGE
48 MODIFY: CONTROL ORANGE
49 MODIFY: ALT ORANGE
4A AUTOMATION: READ/OFF GREEN
4B AUTOMATION: WRITE RED
4C AUTOMATION: TRIM ORANGE
4D AUTOMATION: TOUCH ORANGE
4E AUTOMATION: LATCH ORANGE
4F AUTOMATION: GROUP GREEN
50 UTILITIES: SAVE RED
51 UTILITIES: UNDO GREEN
52 UTILITIES: CANCEL ORANGE
53 UTILITIES: ENTER ORANGE
54 TRANSPORT: MARKER GREEN
55 TRANSPORT: NUDGE GREEN
56 TRANSPORT: CYCLE GREEN
57 TRANSPORT: DROP RED
58 TRANSPORT: REPLACE RED
59 TRANSPORT: CLICK GREEN
5A TRANSPORT: SOLO ORANGE
5B TRANSPORT: REWIND ORANGE
5C TRANSPORT: FAST FWD ORANGE
5D TRANSPORT: STOP ORANGE
5E TRANSPORT: PLAY GREEN
5F TRANSPORT: RECORD RED
60 Cursor Up ORANGE
61 Cursor Down ORANGE
62 Cursor Left ORANGE
63 Cursor Right ORANGE
64 Cursor Zoom BLUE
65 Scrub RED
71 DISPLAY: SMPTE LED RED
72 DISPLAY: BEATS LED RED
73 DISPLAY: RUDE SOLO LIGHT ORANGE

0x34にNAME/VALUE、0x35にSMPTE/BEATSがあるはずですが、X-TOUCHでは光らないボタンのようです。

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

void setup()
{
    MIDI.begin(MIDI_CHANNEL_OMNI);
    delay(1000);
}

void loop()
{
  // SOLO Ch. 1 LED -> ON
  MIDI.sendNoteOn(0x8, 0x7F, 1);
  MIDI.sendNoteOff(0x8, 0, 1);

  // SELECT Ch. 1 LED -> OFF
  MIDI.sendNoteOn(0x18, 0, 1);
  MIDI.sendNoteOff(0x18, 0, 1);

  // Wait 1000ms (=1sec)
  delay(1000);
  
  // SOLO Ch. 1 LED -> OFF
  MIDI.sendNoteOn(0x8, 0, 1);
  MIDI.sendNoteOff(0x8, 0, 1);

  // SELECT Ch. 1 LED -> ON
  MIDI.sendNoteOn(0x18, 0x7F, 1);
  MIDI.sendNoteOff(0x18, 0, 1);

  // Wait 1000ms (=1sec)
  delay(1000);

  // MIDI Read
  MIDI.read();
}

SOLO Ch. 1のLEDとSELECT Ch. 1のLEDを交互に光らせるサンプルコードです。

上記の表の通り、16進数で指定しています。

 

タイムコード7セグディスプレイを制御

7セグメントのディスプレイは左のASSIGNMENT部から右端のTICKSまで合計12桁並んでいます。

これらはコントロールチェンジメッセージにて桁ごとに制御が可能です。

解析資料を見ると16チャンネルのメッセージとして送るようですが、手元のFL Studioの通信内容をキャプチャすると1チャンネルのメッセージとして送られているようです。

どちらでも反応するようですが、要検証です。

ID(0x) Digit
4B ASSIGNMENT: 1/2 Digit
4A ASSIGNMENT: 2/2 Digit
49 BARS: 1/3 Digit
48 BARS: 2/3 Digit
47 BARS: 3/3 Digit
46 BEATS: 1/2 Digit
45 BEATS: 2/2 Digit
44 SUB DIVISION: 1/2 Digit
43 SUB DIVISION: 2/2 Digit
42 TICKS: 1/3 Digit
41 TICKS: 2/3 Digit
40 TICKS: 3/3 Digit

各桁に対するデータは以下のように指定します。

ビット 概要
7 [MSB] 未使用、常に0
6 ドット表示
5 未使用、常に1
4 桁 ON/OFF
3 表示値 [MSB]
2 表示値
1 表示値
0 [LSB] 表示値 [LSB]

表示値は0(0b0000)~9(0b1001)が表示可能です。

例えば、BARSの一番右の桁(0x47)に対して数字の1をドットなしで表示する場合、送るデータは 0b00110001(0x31) となります。

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

void setup()
{
    MIDI.begin(MIDI_CHANNEL_OMNI);
    delay(3000);
}

void loop()
{
  for (uint8_t i=0; i<10; i++) {
    MIDI.sendControlChange(0x47, 0x30 + i, 16);
    delay(1000);
  }
  MIDI.read();
}

このサンプルコードはBARSの一番右の桁(0x47)に対して0~9の数字を1秒間隔で繰り返し表示するコードです。

表示値がLSB側の4bitとなっているため、0x30の固定値にfor文で加算される変数iを足すことによって、0x30~0x39で値を変化させています。

チャンネルは16に送っていますが、1でも反応するみたいです。

 

エンコーダーノブ・V-Pot LEDを制御

ノブの円周に13個のLEDが配置されています。

MCUの解析資料によると、11個のLEDと、ノブ下部のLEDも存在します。

X-TOUCHでは13個のLEDがありますが、下部のLED2つがMCUで言うノブ下部のLEDに相当するようです。

コントロールチェンジでチャンネル1に対して送ることで制御が可能です。

コントロールナンバー0x30~0x37がチャンネル1~8に対応しています。

ビット 概要
7 [MSB] 未使用、常に0
6 V-Pot 下部LED ON/OFF
5 V-Potモード設定値 [MSB]
4 V-Potモード設定値 [LSB]
3 V-Pot表示値 [MSB]
2 V-Pot表示値
1 V-Pot表示値
0 [LSB] V-Pot表示値 [LSB]

解析情報からの表です。

「-」が消灯、「*」が点灯でノブ円周のLEDの表示例です。

データを送る際に、5,4ビット目でモードを指定します。

値(0x) Mode 00 (0x0) Mode 01 (0x1) Mode 10 (0x2) Mode 11 (0x3)
0 ----------- ----------- ----------- -----------
1 *---------- ******----- *---------- -----*-----
2 -*--------- -*****----- **--------- ----***----
3 --*-------- --****----- ***-------- ---*****---
4 ---*------- ---***----- ****------- --*******--
5 ----*------ ----**----- *****------ -*********-
6 -----*----- -----*----- ******----- ***********
7 ------*---- -----**---- *******---- ***********
8 -------*--- -----***--- ********--- ***********
9 --------*-- -----****-- *********-- ***********
A ---------*- -----*****- **********- ***********
B ----------* -----****** *********** ***********

X-TOUCHでは以下のようになり、モード0b11(0x3)での挙動が若干違うようです。

値(0x) Mode 00 (0x0) Mode 01 (0x1) Mode 10 (0x2) Mode 11 (0x3)
0 ----------- ----------- ----------- -----------
1 *---------- ******----- *---------- -----*-----
2 -*--------- -*****----- **--------- ----***----
3 --*-------- --****----- ***-------- ---*****---
4 ---*------- ---***----- ****------- --*******--
5 ----*------ ----**----- *****------ -*********-
6 -----*----- -----*----- ******----- ***********
7 ------*---- -----**---- *******---- -----------
8 -------*--- -----***--- ********--- -----------
9 --------*-- -----****-- *********-- -----------
A ---------*- -----*****- **********- -----------
B ----------* -----****** *********** -----------

また、13個のLEDのうち、一番端の2個のLEDがノブ下部のLEDと同じ扱いですので、6ビット目を指定すると、下部LED2個は常に光ります。

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

void setup()
{
    MIDI.begin(MIDI_CHANNEL_OMNI);
    delay(3000);
}

void loop()
{
  for (uint8_t i=0; i<12; i++) {
    // V-Pot 1 (0x30), Under LED OFF, Mode 0b00
    MIDI.sendControlChange(0x30, i, 1);
    // V-Pot 2 (0x31), Under LED OFF, Mode 0b01
    MIDI.sendControlChange(0x31, (0b00010000 | i), 1);
    // V-Pot 3 (0x32), Under LED OFF, Mode 0b10
    MIDI.sendControlChange(0x32, (0b00100000 | i), 1);
    // V-Pot 4 (0x33), Under LED OFF, Mode 0b11
    MIDI.sendControlChange(0x33, (0b00110000 | i), 1);
    // V-Pot 5 (0x34), Under LED ON, Mode 0b00
    MIDI.sendControlChange(0x34, (1<<6 | 0<<4 | i), 1);
    // V-Pot 6 (0x35), Under LED ON, Mode 0b01
    MIDI.sendControlChange(0x35, (1<<6 | 1<<4 | i), 1);
    // V-Pot 7 (0x36), Under LED ON, Mode 0b10
    MIDI.sendControlChange(0x36, (1<<6 | 2<<4 | i), 1);
    // V-Pot 8 (0x37), Under LED ON, Mode 0b11
    MIDI.sendControlChange(0x37, (1<<6 | 0b11<<4 | i), 1);
    delay(1000);
  }
  MIDI.read();
}

チャンネル1~8のノブLEDを制御する例です。

4種類のモード、ノブ下部のLEDを点灯させた上での4種類のモードと、8つすべてのノブLEDを光らせるサンプルです。

 

VUメーターLEDを制御

アフタータッチでチャンネルプレッシャーを送れば光ります。

MCUの解析資料によると、VUメーターは12個のLEDがあり、以下のようにアサインされているようです。

Value Signal Leds
C >= 0dB Red (clip)
B >= -2dB Yellow
A >= -4dB Yellow
9 >= -6dB Yellow
8 >= -8dB Green
7 >= -10dB Green
6 >= -14dB Green
5 >= -20dB Green
4 >= -30dB Green
3 >= -40dB Green
2 >= -50dB Green
1 >= -60dB Green
0 < -60dB All leds off

しかしながら、X-TOUCHの場合、LEDは8個です。(上:赤LED4個・下:緑LED4個)

実際に試してみると、0~12の値では全部のLEDが点灯しませんでした。

X-TOUCHの場合は、0~14の値にアサインされているようです。

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

void setup()
{
    MIDI.begin(MIDI_CHANNEL_OMNI);
    delay(3000);
}

void loop()
{
  for (uint8_t i=0; i<15; i++) {
    // VU Channel 1
    MIDI.sendAfterTouch(i, 1);
    // VU Channel 2
    MIDI.sendAfterTouch((0b00010000 | i), 1);
    // VU Channel 7
    MIDI.sendAfterTouch((6<<4 | i), 1);
    // VU Channel 8
    MIDI.sendAfterTouch((7<<4 | i), 1);
    delay(1000);
  }
  MIDI.read();
}

0~14のアフタータッチ値をチャンネル1に送っています。

データの上位4ビットがVUメーターのチャンネル指定、下位4ビットが値の指定です。

ビット 概要
7 [MSB] 未使用、常に0
6 VUチャンネル値 [MSB]
5 VUチャンネル値
4 VUチャンネル値 [LSB]
3 VU表示値 [MSB]
2 VU表示値
1 VU表示値
0 [LSB] VU表示値 [LSB]

アフタータッチを送ると、VUメーターが指定値まで一気に上昇して光り、徐々に下がってくるような挙動をします。

値(0x) VU LED
F 光らず
E 下から8個全点灯 [CLIP]
D 下から7個点灯
C 下から7個点灯
B 下から6個点灯
A 下から5個点灯
9 下から5個点灯
8 下から4個点灯
7 下から4個点灯
6 下から3個点灯
5 下から3個点灯
4 下から2個点灯
3 下から2個点灯
2 下から1個点灯
1 下から1個点灯
0 光らず

X-TOUCHの場合は、このような挙動となりました。

なお、Logic Controlプロトコル仕様書では、0xEがオーバーロードのセット、0xFがオーバーロードのクリアとされていて、0x0~0xCでレベルメーターが0~100%で可変すると書かれています。

オーバーロードはクリアされないとも書かれているので、0xEを送ったあとにそのまま光り続けているのが本来の動作なのでしょうか?

 

LCDディスプレイの制御

MCUでは56文字の2行、合計112文字で構成され、DAWから送信されるシステムエクスクルーシブメッセージに反応するようです。

MIDIでの可変長メッセージとなり、0xF0で始まって0xF7で終わるメッセージとなります。

SysEXメッセージ内、メーカーIDは 0x00 0x00 0x66(Mackie社)、製品指定が0x14、LCD指定のIDが0x12、続けてカーソル(文字)位置を送ります。(0x00~0x6F)

カーソル(文字)位置は0x00で左上開始、0x37が右上の文字、0x38が左下の文字(2行目開始)、0x6Fが右下の文字位置となります。

指定した位置から送った文字を埋める動作になり、アスキーコードで文字を指定すればその通りに表示されます。

F0 00 00 66 14 12 38 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A F0

このようなメッセージを送れば、2行目の開始位置(0x38)より、アスタリスク(* : 0x2A)で10文字表示されます。

X-TOUCHの場合、小型のディスプレイが各チャンネルごとに8個並んでいる形ですが、MCUと同様に横長のLCDディスプレイとして扱えば良いです。

単純に7文字2行のLCDディスプレイに別れているというだけで、それが8個チャンネル数分並んでおり、合計56文字2行のLCDディスプレイとして制御可能です。

そのため、各チャンネルごとに表示内容を変えたい場合、7文字単位での文字送信が必要でしょう。

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

void setup()
{
    MIDI.begin(MIDI_CHANNEL_OMNI);
    delay(3000);
}

void loop()
{
  writeLCD(0, 0, 4, "hoge");
  delay(1000);
  writeLCD(0, 0, 4, "fuga");
  delay(1000);
  writeLCD(0, 0, 4, "piyo");
  delay(1000);
  
  MIDI.read();
}

void writeLCD(uint8_t setChannel, uint8_t setLine, uint8_t strLength, const char* strArray) {
  if (setChannel > 7) {setChannel = 7;}
  if (setLine > 1) {setLine = 1;}
  if (strLength > 7) {strLength = 7;}
  if (strLength > strlen(strArray)) {strLength = strlen(strArray);}
  uint8_t cmd[14] = {0x00, 0x00, 0x66, 0x14, 0x12, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00};
  cmd[5] = (setChannel * 7) + (setLine * 56);
  for (uint8_t i = 0; i < strLength; i++) {
    cmd[6 + i] = strArray[i];
  }
  MIDI.sendSysEx(13, cmd, false);
}

簡単に書いたサンプルコードです。

writeLCD関数の引数は、1個目が表示するチャンネル(0~7)指定、2個目が行指定(0~1)、表示する文字数、文字配列となっています。

 

LCDディスプレイのバックライト色制御

これはX-TOUCHに限定された制御についてです。

MCUでは横長の一体型LCDディスプレイを使用しているので不可能ですが、X-TOUCHの場合はチャンネル単位で小型のLCDを使用しているためバックライトの色が変更可能なようです。

以下のシステムエクスクルーシブメッセージを送れば即時バックライト色が変更されます。

F0 00 00 66 14 72 [Ch1] [Ch2] [Ch3] [Ch4] [Ch5] [Ch6] [Ch7] [Ch8] F7

8チャンネル分、一気に色指定をします。

Color(0x) LCD COLOR
00 BLANK (Backlit Off)
01 RED
02 GREEN
03 YELLOW
04 BLUE
05 PURPLE
06 CYAN
07 WHITE (Default)

初期状態(白色)に戻すには以下のシステムエクスクルーシブメッセージを送ります。

F0 00 00 66 14 72 07 07 07 07 07 07 07 07 F7
  uint8_t cmd[13] = {0x00, 0x00, 0x66, 0x14, 0x72, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07};
  MIDI.sendSysEx(13, cmd, false);

このようなコードで初期状態に戻ります。

 

フェーダー位置の制御

MCUで特徴的なのは電動で動くモーターフェーダーです。

MCUからDAWへの通知では、ピッチベンドメッセージとノートONメッセージを使用します。

DAWからMCUでのフェーダー制御では、ピッチベンドメッセージを使用します。

フェーダー位置に関してはピッチベンド値で表現され、14bitの値で制御します。

DAWのMIDI API実装によって異なりますが、 -8192~8191 または 0~16383 の値としてフェーダー位置を制御できるということです。

MCUからの通知では、以下のような順序で通知されます。

  1. 指がフィーダーに触れる(ノートONで移動し始め通知)
  2. フィーダーが動く(ピッチベンドで値が送信)
  3. フィーダーが動く(ピッチベンドで値が送信)
  4. ・・・・・
  5. フィーダーが動く(ピッチベンドで値が送信)
  6. 指がフィーダーから離れる(ノートOFFで移動し終わり通知)
#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

void setup()
{
    MIDI.begin(MIDI_CHANNEL_OMNI);
    delay(3000);
}

void loop()
{
  MIDI.sendPitchBend(-8192, 1);
  delay(2000);
  MIDI.sendPitchBend(0, 1);
  delay(2000);
  MIDI.sendPitchBend(8191, 1);
  delay(2000);
  
  MIDI.read();
}

フェーダーを動かすサンプルです。

ArduinoのMIDIライブラリでは、中央が0での値指定ができるようです。

つまり、-8192~8191の14bitで値を指定することになります。

 

値の読み込み

Arduino側での値の読み込みは、ノートオン、ノートオフ、コントロールチェンジ、ピッチベンドの各イベントを拾えばOKです。

以下に例を示します。

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();


// Mackie Control Universal ID List
// === START ===
  char *mcuIDs[] = {
    "REC/RDY Ch. 1",            // 0x00
    "REC/RDY Ch. 2",            // 0x01
    "REC/RDY Ch. 3",            // 0x02
    "REC/RDY Ch. 4",            // 0x03
    "REC/RDY Ch. 5",            // 0x04
    "REC/RDY Ch. 6",            // 0x05
    "REC/RDY Ch. 7",            // 0x06
    "REC/RDY Ch. 8",            // 0x07
    "SOLO Ch. 1",               // 0x08
    "SOLO Ch. 2",               // 0x09
    "SOLO Ch. 3",               // 0x0A
    "SOLO Ch. 4",               // 0x0B
    "SOLO Ch. 5",               // 0x0C
    "SOLO Ch. 6",               // 0x0D
    "SOLO Ch. 7",               // 0x0E
    "SOLO Ch. 8",               // 0x0F
    "MUTE Ch. 1",               // 0x10
    "MUTE Ch. 2",               // 0x11
    "MUTE Ch. 3",               // 0x12
    "MUTE Ch. 4",               // 0x13
    "MUTE Ch. 5",               // 0x14
    "MUTE Ch. 6",               // 0x15
    "MUTE Ch. 7",               // 0x16
    "MUTE Ch. 8",               // 0x17
    "SELECT Ch. 1",             // 0x18
    "SELECT Ch. 2",             // 0x19
    "SELECT Ch. 3",             // 0x1A
    "SELECT Ch. 4",             // 0x1B
    "SELECT Ch. 5",             // 0x1C
    "SELECT Ch. 6",             // 0x1D
    "SELECT Ch. 7",             // 0x1E
    "SELECT Ch. 8",             // 0x1F
    "V-Pot Knob Ch. 1",         // 0x20
    "V-Pot Knob Ch. 2",         // 0x21
    "V-Pot Knob Ch. 3",         // 0x22
    "V-Pot Knob Ch. 4",         // 0x23
    "V-Pot Knob Ch. 5",         // 0x24
    "V-Pot Knob Ch. 6",         // 0x25
    "V-Pot Knob Ch. 7",         // 0x26
    "V-Pot Knob Ch. 8",         // 0x27
    "ASSIGNMENT: TRACK",        // 0x28
    "ASSIGNMENT: SEND",         // 0x29
    "ASSIGNMENT: PAN/SURROUND", // 0x2A
    "ASSIGNMENT: PLUG-IN",      // 0x2B
    "ASSIGNMENT: EQ",           // 0x2C
    "ASSIGNMENT: INSTRUMENT",   // 0x2D
    "FADER BANK Left",          // 0x2E
    "FADER BANK Right",         // 0x2F
    "CHANNEL Left",             // 0x30
    "CHANNEL Right",            // 0x31
    "FLIP",                     // 0x32
    "GLOBAL VIEW",              // 0x33
    "DISPLAY: NAME/VALUE",      // 0x34
    "DISPLAY: SMPTE BEATS",     // 0x35
    "FUNCTION: F1",             // 0x36
    "FUNCTION: F2",             // 0x37
    "FUNCTION: F3",             // 0x38
    "FUNCTION: F4",             // 0x39
    "FUNCTION: F5",             // 0x3A
    "FUNCTION: F6",             // 0x3B
    "FUNCTION: F7",             // 0x3C
    "FUNCTION: F8",             // 0x3D
    "MIDI TRACKS",              // 0x3E
    "INPUTS",                   // 0x3F
    "AUDIO TRACKS",             // 0x40
    "AUDIO INSTRUMENTS",        // 0x41
    "AUX",                      // 0x42
    "BUSES",                    // 0x43
    "OUTPUTS",                  // 0x44
    "USER",                     // 0x45
    "MODIFY: SHIFT",            // 0x46
    "MODIFY: OPTION",           // 0x47
    "MODIFY: CONTROL",          // 0x48
    "MODIFY: ALT",              // 0x49
    "AUTOMATION: READ/OFF",     // 0x4A
    "AUTOMATION: WRITE",        // 0x4B
    "AUTOMATION: TRIM",         // 0x4C
    "AUTOMATION: TOUCH",        // 0x4D
    "AUTOMATION: LATCH",        // 0x4E
    "AUTOMATION: GROUP",        // 0x4F
    "UTILITIES: SAVE",          // 0x50
    "UTILITIES: UNDO",          // 0x51
    "UTILITIES: CANCEL",        // 0x52
    "UTILITIES: ENTER",         // 0x53
    "TRANSPORT: MARKER",        // 0x54
    "TRANSPORT: NUDGE",         // 0x55
    "TRANSPORT: CYCLE",         // 0x56
    "TRANSPORT: DROP",          // 0x57
    "TRANSPORT: REPLACE",       // 0x58
    "TRANSPORT: CLICK",         // 0x59
    "TRANSPORT: SOLO",          // 0x5A
    "TRANSPORT: REWIND",        // 0x5B
    "TRANSPORT: FAST FWD",      // 0x5C
    "TRANSPORT: STOP",          // 0x5D
    "TRANSPORT: PLAY",          // 0x5E
    "TRANSPORT: RECORD",        // 0x5F
    "Cursor Up",                // 0x60
    "Cursor Down",              // 0x61
    "Cursor Left",              // 0x62
    "Cursor Right",             // 0x63
    "Cursor Zoom",              // 0x64
    "Scrub",                    // 0x65
    "=====",                    // 0x66
    "=====",                    // 0x67
    "Fader Ch. 1",              // 0x68
    "Fader Ch. 2",              // 0x69
    "Fader Ch. 3",              // 0x6A
    "Fader Ch. 4",              // 0x6B
    "Fader Ch. 5",              // 0x6C
    "Fader Ch. 6",              // 0x6D
    "Fader Ch. 7",              // 0x6E
    "Fader Ch. 8",              // 0x6F
    "Fader Ch. MAIN",           // 0x70
    "DISPLAY: SMPTE LED",       // 0x71
    "DISPLAY: BEATS LED",       // 0x72
    "DISPLAY: RUDE SOLO LIGHT", // 0x73
    "=====",                    // 0x74
    "=====",                    // 0x75
    "=====",                    // 0x76
    "=====",                    // 0x77
    "=====",                    // 0x78
    "=====",                    // 0x79
    "=====",                    // 0x7A
    "=====",                    // 0x7B
    "=====",                    // 0x7C
    "=====",                    // 0x7D
    "=====",                    // 0x7E
    "=====",                    // 0x7F
  };
// === END ===
// Mackie Control Universal ID List


// Mackie Control Universal LED List
// === START ===
  bool mcuLEDs[] = {
    true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,               //0x0*
    true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,               //0x1*
    false, false, false, false, false, false, false, false, true, true, true, true, true, true, true, true,       //0x2*
    true, true, true, true, false, false, true, true, true, true, true, true, true, true, true, true,             //0x3*
    true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,               //0x4*
    true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,               //0x5*
    true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false,     //0x6*
    false, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false,  //0x7*
  };
// === END ===
// Mackie Control Universal LED List


// MCU Button LED State
bool mcuState[128];


void setup()
{
    MIDI.begin(MIDI_CHANNEL_OMNI);
    SerialUSB.begin(9600);
    delay(3000);
    SerialUSB.println("Start");
}


void loop()
{
  if (MIDI.read())
  {
    switch(MIDI.getType())
    {
      case midi::NoteOn:
        handleNoteOn(MIDI.getChannel(), MIDI.getData1(), MIDI.getData2());
        break;
      case midi::NoteOff:
        handleNoteOff(MIDI.getChannel(), MIDI.getData1(), MIDI.getData2());
        break;
      case midi::ControlChange:
        handleControlChange(MIDI.getChannel(), MIDI.getData1(), MIDI.getData2());
        break;
      case midi::PitchBend: // -8192 - 8191 (X-TOUCH: 0d8188 [0b11111111111100] Max?)
        handlePitchBend(MIDI.getChannel(), ((uint16_t)MIDI.getData2()<<7 | (MIDI.getData1() & 0b01111111)) - 8192);
        break;
      default:
        break;
    }
  }
}


void handleNoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
{
  if (channel == 1 && velocity == 127)
  {
    SerialUSB.print("Push: ");
    SerialUSB.print(mcuIDs[note]);
    // Fader is Non-State
    if (note < 0x68 || 0x70 < note)
    {
      SerialUSB.print(" @ State: ");
      if (mcuState[note])
      {
        mcuState[note] = false;
        SerialUSB.println("Off");
        if (mcuLEDs[note])
        {
          sendLedOff(note);
        }
      } else {
        mcuState[note] = true;
        SerialUSB.println("On");
      }
    } else {
      SerialUSB.println();
    }
  }
}


void handleNoteOff(uint8_t channel, uint8_t note, uint8_t velocity)
{
  if (channel == 1 && velocity == 0)
  {
    SerialUSB.print("Release: ");
    SerialUSB.print(mcuIDs[note]);
    SerialUSB.println();
  }
}


void handleControlChange(uint8_t channel, uint8_t number, uint8_t value)
{
  if (channel == 1)
  {
    if (number == 0x3C)
    {
      SerialUSB.print("Jog");
    } else if (0x10 <= number && number  <= 0x17)
    {
      SerialUSB.print("V-Pot Knob Ch. ");
      SerialUSB.print(number - 0x0F);
    }
    if ((value>>6 & 0b1) == 1) {
      SerialUSB.print(" Left @ Speed: ");
      SerialUSB.println(value & 0b00111111);
    } else {
      SerialUSB.print(" Right @ Speed: ");
      SerialUSB.println(value & 0b00111111);
    }
  }
}


void handlePitchBend(uint8_t channel, int16_t bend)
{
  SerialUSB.print("Fader Ch. ");
  SerialUSB.print(channel);
  SerialUSB.print(" : ");
  SerialUSB.print(bend);
  SerialUSB.println();
}


void sendLedOff(uint8_t id)
{
  MIDI.sendNoteOn(id, 0, 1);
  MIDI.sendNoteOff(id, 0, 1);
}

(※Arduino M0以外だと、コード中のSerialUSBをSerialに書き換える必要があります。)

受信した内容をUSB経由でArduino IDEのシリアルモニタに表示するサンプルコードです。

これは、ArduinoのD0/D1ピンがUSBに割り当てられていないArduino M0を使用しているため、MIDIのシリアル通信を送受信しながらコンピューターにもUSB経由で送ることができるのです。

Arduino Uno R3等であると共用となっているので、別途ソフトウェアシリアルでの通信の必要性が出てくると思います。

Arduino UNO R4 Minima, Micro, Zero, Leonardo, MKR ZERO, Due, Nano Everyであるとシリアル通信でのUSBとハードウェアピンが別になっているため便利です。

 

ボタンやV-Potのノブを押した際、また、フェーダーに触れた際にノートオンが送られてきます。

その後、ボタンを離したタイミングでノートオフが送られてきます。

 

X-TOUCHは各種ボタンを押した際に勝手にボタンのLEDが点灯します。

よって、ボタンを使用する上では逆に消灯させる必要が出てきます。

上記サンプルコードでは、配列でボタンのステートを保持し、押すたびにLEDの点灯・消灯が切り替わります。

消灯する場合は、ノートオフコマンドを送っています。(sendLedOff関数)

最初から点灯させたくない場合はノートオンを受信した際に、瞬時にノートオフで消灯コマンドを送ることで実質点灯しない状態となります。

ちなみに、ジョグダイヤルとV-Potのノブはコントロールチェンジで回転方向のイベントが発生します。

6bit値で回転スピードも取れるようですが、ジョグダイヤルはスピードが1固定のようです。

V-Potのノブはゆっくり回すと1~2、速く回すと7前後の数値でスピードが通知されるようです。

頑張って速く回してみても10が限界でした。

6bitであれば最大63で値が取れそうですが、10程度まででとどまるようです。

 

X-TOUCHのフェーダーは、ピッチベンドで通知されるのですが、下位2bitは0固定のようです。

実際に試すと最大値が0d8188(0b11111111111100)として通知されてきます。

12bitの値として通知されますが、実際に12bitの解像度があるのかは不明です。

一応、通知される値から統計を取ると約900種の値が通知されているようなので、現実的には10bit程度の値として扱えそうです。

なお、変化量の統計では、ログ取り時に16が72%、20が15%、32が5%、36が4%他、48、52、64、24と値が続きます。

フェーダーの動かし方によって変わると思いますので参考までに。

実際の値としては、0→16→32→48→64→80→・・・・・→16356→16380のような感じになります。

下位2bit以外の変化があるため、ビットシフトではなく、出てきた値÷16として10bitとしての値を取り出すのが良いかとは思います。

実際、この方法で値の統計を取ると、1もしくは2の値の変化で、900種以上の値が取れているので、実質10bitで扱えると思います。

 

その他コマンド(ファームウェアバージョンリクエスト)

ファームウェアのバージョン情報を要求することができます。

システムエクスクルーシブメッセージでのやり取りが必要です。

※Logic Controlプロトコル仕様書参照

(ヘッダのみ解析情報を使用して書き換えてあります。X-TOUCHでのみ動作確認済み。)

F0 00 00 66 14 13 00 F7

を送ることによって、対する応答もシステムエクスクルーシブメッセージで帰ってきます。

X-TOUCHでは以下の12バイトでの返答になるようです。

F0 00 00 66 14 14 56 31 2E 32 32 F7

データ部分のペイロード、5バイトのデータ(0x56~0x32まで)です。

つまり「V1.22」という文字列のアスキーコード5桁の返答になり、このバージョン情報は、X-TOUCH起動時にも本体のHOURS/BARSディスプレイ部に表示されます。

以下、Arduinoで動かすためのサンプルコードです。

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

void setup()
{
    MIDI.begin(MIDI_CHANNEL_OMNI);
    SerialUSB.begin(9600);
    delay(3000);
    SerialUSB.println("Start");
}

void loop()
{
  if (SerialUSB.available() > 0)
  {
    while(SerialUSB.read() > 0);
    SerialUSB.println("Read!");
    uint8_t cmd[6] = {0x00, 0x00, 0x66, 0x14, 0x13, 0x00};
    MIDI.sendSysEx(6, cmd, false);
  }
  if (MIDI.read())
  {
    uint8_t length;
    uint8_t data[128];
    length = MIDI.getSysExArrayLength();
    memcpy(data, MIDI.getSysExArray(), length);
    SerialUSB.print("DataLength: ");
    SerialUSB.println(length);
    SerialUSB.print("Data: ");
    for (uint8_t i=0; i<length; i++)
    {
      if (data[i] < 0x10) SerialUSB.print("0");
      SerialUSB.print(data[i], HEX);
      SerialUSB.print(" ");
    }
    SerialUSB.println();
  }
}

(※Arduino M0以外だと、コード中のSerialUSBをSerialに書き換える必要があります。)

ファームウェアバージョンをUSB経由でArduino IDEのシリアルモニタに表示するサンプルコードです。

シリアルモニタ上でなにか適当な文字列(改行だけでも可)を送ると以下のような応答があります。

Read!
DataLength: 12
Data: F0 00 00 66 14 14 56 31 2E 32 32 F7

 

その他コマンド(リセットメッセージ)

※Logic Controlプロトコル仕様書参照

リセット関係のコマンドですがMCUプロトコル中には定義がないのか動作しませんでした。

 

フェーダーを最小にするコマンド

F0 00 00 66 14 61 F7

LEDをすべてオフにするコマンド

F0 00 00 66 14 62 F7

リセットコマンド

F0 00 00 66 14 63 F7

すべて、X-TOUCHでは動作しませんでした。

よってArduinoサンプルも無しです。

 

その他コマンド(コンフィギュレーションメッセージ)

※Logic Controlプロトコル仕様書参照

 

トランスポートボタンクリック(0x0A)

7バイト目で挙動が変わるようです。

F0 00 00 66 14 0A 00 F7 // no trasnport button click
F0 00 00 66 14 0A 01 F7 // transport button click (default)

FL Studioではデフォルト値が送信されるようですが、特に挙動が変わらないように見えます。

 

LCDバックライトセーバー(0x0B)

7バイト目で挙動が変わるようです。

F0 00 00 66 14 0B 00 F7 // LCD back light off
F0 00 00 66 14 0B 0F F7 // LCD back light on, with time out in minutes (default: 0F = 15minutes)

送信してもX-TOUCHではLCDバックライトをオフにできませんでした。

FL Studioではデフォルト値が送信されるようです。

 

タッチレスムーバブルフェーダー(0x0C)

F0 00 00 66 14 0C 00 F7 // fader movements are only transmitted if the fader has been recognized as touched
F0 00 00 66 14 0C 01 F7 // fader movements are also transmitted if the fader has not been recognized as touched (e. g. with fingernail or pen)

フェーダーはモーターフェーダーの都合があり、タッチセンサーが入っています。

そのため、タッチを検出しなかった場合(指以外で動かした場合)に、動きを通知するかという設定です。

FL Studioでは設定値として01が送信されているようで、指以外で動かした場合も通知されるようになっています。

 

フェーダー感度(0x0E)

F0 00 00 66 14 0E 00 03 F7 // 0 Chan Fader touch sensitivity (00 to 05; default:03)
F0 00 00 66 14 0E 07 03 F7 // 7 Chan Fader touch sensitivity (00 to 05; default:03)
F0 00 00 66 14 0E 08 03 F7 // Master Fader touch sensitivity (00 to 05; default:03)

このコマンドの使用はFL Studio上では確認できませんでした。

 

その他コマンド(メーター)

※Logic Controlプロトコル仕様書参照

 

チャンネルメーターモード

F0 00 00 66 14 20 ii mm F7
ii = Channel ID (0 to 7)
mm = mode bit map in the form of (0 0 0 0 0 l p s):
    l Enable level meter on LCD
    p Enable peak hold display (horizontal only)
    s Enable Signal LED

FL Studioでは接続時に各チャンネルに対してモードを0x0として送信し、グローバルLCDメーターモード設定直後に、各チャンネルに対してモードを0x3として設定を送っているようです。

0x3では、0b00000011となるため、ピークホールドディスプレイとシグナルLEDを有効にしている設定のようです。

切断時には各チャンネルを0x0で設定しているようです。

 

グローバルLCDメーターモード

F0 00 00 66 14 21 00 F7 // Global LCD meter mode: horizontal
F0 00 00 66 14 21 01 F7 // Global LCD meter mode: vertical

FL Studioでは、0x00が設定されるようです。

 

レベルメーターはチャンネルごとに1つだけあります。

ステレオトラックの場合は左右のレベルの最大値を使用します。

ピークレベルのみ送信を行えば良く、時間の経過と共にレベルメーターのバーを自動的に減らし、LEDをオフにします。

そのためMIDIの帯域幅を圧迫しません。

レベルメーターの減衰率は1目盛りあたり300msで、100%から0%に低下するのに1.8秒かかります。

LCDを水平、垂直でモード切替を行う場合、切り替わる間はLCDメッセージは無視されます。

モード変更後はLCDメッセージを送るまでに最低でも600ms待機する必要があります。

 

FL Studioで実際にやり取りされる内容(接続時)

接続時の通信内容をモニターした結果が以下の通りです。

すべて、DAWからMCU(X-TOUCH)側への通信です。

コマンド データ 概要
SystemExclusive F0 00 00 66 14 0C 01 F7 タッチレスムーバブルフェーダー設定
SystemExclusive F0 00 00 66 14 0B 02 F7 LCDバックライトセーバー設定
SystemExclusive F0 00 00 66 14 0A 01 F7 トランスポートボタンクリック設定
ChannelPressure D0 0F VUメーター1:最大値0xF(X-TOUCHでは光らず)
ChannelPressure D0 1F VUメーター2:最大値0xF(X-TOUCHでは光らず)
ChannelPressure D0 2F VUメーター3:最大値0xF(X-TOUCHでは光らず)
ChannelPressure D0 3F VUメーター4:最大値0xF(X-TOUCHでは光らず)
ChannelPressure D0 4F VUメーター5:最大値0xF(X-TOUCHでは光らず)
ChannelPressure D0 5F VUメーター6:最大値0xF(X-TOUCHでは光らず)
ChannelPressure D0 6F VUメーター7:最大値0xF(X-TOUCHでは光らず)
ChannelPressure D0 7F VUメーター8:最大値0xF(X-TOUCHでは光らず)
SystemExclusive F0 00 00 66 14 20 00 00 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 01 00 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 02 00 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 03 00 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 04 00 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 05 00 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 06 00 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 07 00 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 12 38 20 20
20 20 20 20 2E 20 20 20 20
20 20 2E 20 20 20 20 20 20
2E 20 20 20 20 20 20 2E 20
20 20 20 20 20 2E 20 20 20
20 20 20 2E 20 20 20 20 20
20 2E 20 20 20 20 20 20 F7
LCD2行目書き換え
" ."
の繰り返し表示
SystemExclusive F0 00 00 66 14 21 00 F7 グローバルLCDメーターモード設定
SystemExclusive F0 00 00 66 14 20 00 03 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 01 03 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 02 03 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 03 03 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 04 03 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 05 03 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 06 03 F7 チャンネルメーターモード設定
SystemExclusive F0 00 00 66 14 20 07 03 F7 チャンネルメーターモード設定
ControlChange B0 30 16 V-Pot LED設定 Ch 1, モード01 / 値6(中央)
NoteOff 90 00 00 ボタン REC/RDY Ch. 1 消灯
NoteOff 90 08 00 ボタン SOLO Ch. 1 消灯
NoteOff 90 10 00 ボタン MUTE Ch. 1 消灯
PitchBend E0 10 66 フェーダー Ch. 1 設定 4880 (0dB)
ControlChange B0 31 16 V-Pot LED設定 Ch 2, モード01 / 値6(中央)
NoteOff 90 01 00 ボタン REC/RDY Ch. 2 消灯
NoteOff 90 09 00 ボタン SOLO Ch. 2 消灯
NoteOff 90 11 00 ボタン MUTE Ch. 2 消灯
PitchBend E1 10 66 フェーダー Ch. 2 設定 4880 (0dB)
ControlChange B0 32 16 V-Pot LED設定 Ch 3, モード01 / 値6(中央)
NoteOff 90 02 00 ボタン REC/RDY Ch. 3 消灯
NoteOff 90 0A 00 ボタン SOLO Ch. 3 消灯
NoteOff 90 12 00 ボタン MUTE Ch. 3 消灯
PitchBend E2 10 66 フェーダー Ch. 3 設定 4880 (0dB)
ControlChange B0 33 16 V-Pot LED設定 Ch 4, モード01 / 値6(中央)
NoteOff 90 03 00 ボタン REC/RDY Ch. 4 消灯
NoteOff 90 0B 00 ボタン SOLO Ch. 4 消灯
NoteOff 90 13 00 ボタン MUTE Ch. 4 消灯
PitchBend E3 10 66 フェーダー Ch. 4 設定 4880 (0dB)
ControlChange B0 34 16 V-Pot LED設定 Ch 5, モード01 / 値6(中央)
NoteOff 90 04 00 ボタン REC/RDY Ch. 5 消灯
NoteOff 90 0C 00 ボタン SOLO Ch. 5 消灯
NoteOff 90 14 00 ボタン MUTE Ch. 5 消灯
PitchBend E4 10 66 フェーダー Ch. 5 設定 4880 (0dB)
ControlChange B0 35 16 V-Pot LED設定 Ch 6, モード01 / 値6(中央)
NoteOff 90 05 00 ボタン REC/RDY Ch. 6 消灯
NoteOff 90 0D 00 ボタン SOLO Ch. 6 消灯
NoteOff 90 15 00 ボタン MUTE Ch. 6 消灯
PitchBend E5 10 66 フェーダー Ch. 6 設定 4880 (0dB)
ControlChange B0 36 16 V-Pot LED設定 Ch 7, モード01 / 値6(中央)
NoteOff 90 06 00 ボタン REC/RDY Ch. 7 消灯
NoteOff 90 0E 00 ボタン SOLO Ch. 7 消灯
NoteOff 90 16 00 ボタン MUTE Ch. 7 消灯
PitchBend E6 10 66 フェーダー Ch. 7 設定 4880 (0dB)
ControlChange B0 37 16 V-Pot LED設定 Ch 8, モード01 / 値6(中央)
NoteOff 90 07 00 ボタン REC/RDY Ch. 8 消灯
NoteOff 90 0F 00 ボタン SOLO Ch. 8 消灯
NoteOff 90 17 00 ボタン MUTE Ch. 8 消灯
PitchBend E7 10 66 フェーダー Ch. 8 設定 4880 (0dB)
PitchBend E8 10 66 フェーダー Ch. MAIN 設定 4880 (0dB)
ControlChange B0 4B 20 7セグ書き換え ASSIGNMENT: 1/2 Digit 表示なし
ControlChange B0 4A 31 7セグ書き換え ASSIGNMENT: 2/2 Digit 値 1 表示 ドット無し
NoteOn 90 5D 7F ボタン TRANSPORT: STOP 点灯
NoteOn 90 5A 7F ボタン TRANSPORT: SOLO 点灯
NoteOff 90 5F 00 ボタン TRANSPORT: RECORD 消灯
NoteOff 90 71 00 ボタン DISPLAY: SMPTE LED 消灯
NoteOn 90 72 7F ボタン DISPLAY: BEATS LED 点灯
NoteOn 90 28 7F ボタン ASSIGNMENT: TRACK 点灯
NoteOff 90 29 00 ボタン ASSIGNMENT: SEND 消灯
NoteOff 90 2A 00 ボタン ASSIGNMENT: PAN/SURROUND 消灯
NoteOff 90 2B 00 ボタン ASSIGNMENT: PLUG-IN 消灯
NoteOff 90 2C 00 ボタン ASSIGNMENT: EQ 消灯
NoteOff 90 2D 00 ボタン ASSIGNMENT: INSTRUMENT 消灯
NoteOn 90 50 7F ボタン UTILITIES: SAVE 点灯
NoteOff 90 57 00 ボタン TRANSPORT: DROP 消灯
NoteOff 90 58 00 ボタン TRANSPORT: REPLACE 消灯
NoteOff 90 65 00 ボタン Scrub 消灯
NoteOff 90 73 00 ボタン DISPLAY: RUDE SOLO LIGHT 消灯
NoteOn 90 33 7F ボタン GLOBAL VIEW 点灯
NoteOff 90 32 00 ボタン FLIP 消灯
NoteOn 90 56 7F ボタン TRANSPORT: CYCLE 点灯
NoteOff 90 4A 00 ボタン AUTOMATION: READ/OFF 消灯
NoteOff 90 4B 00 ボタン AUTOMATION: WRITE 消灯
NoteOff 90 18 00 ボタン SELECT Ch. 1 消灯
NoteOff 90 19 00 ボタン SELECT Ch. 2 消灯
NoteOff 90 1A 00 ボタン SELECT Ch. 3 消灯
NoteOff 90 1B 00 ボタン SELECT Ch. 4 消灯
NoteOff 90 1C 00 ボタン SELECT Ch. 5 消灯
NoteOff 90 1D 00 ボタン SELECT Ch. 6 消灯
NoteOff 90 1E 00 ボタン SELECT Ch. 7 消灯
NoteOff 90 1F 00 ボタン SELECT Ch. 8 消灯
NoteOff 90 50 00 ボタン UTILITIES: SAVE 消灯
NoteOn 90 4B 7F ボタン AUTOMATION: WRITE 点灯
ChannelPressure D0 00 VUメーター1:最小値0x0
ChannelPressure D0 10 VUメーター2:最小値0x0
ChannelPressure D0 20 VUメーター3:最小値0x0
ChannelPressure D0 30 VUメーター4:最小値0x0
ChannelPressure D0 40 VUメーター5:最小値0x0
ChannelPressure D0 50 VUメーター6:最小値0x0
ChannelPressure D0 60 VUメーター7:最小値0x0
ChannelPressure D0 70 VUメーター8:最小値0x0
ControlChange B0 49 20 7セグ書き換え BARS: 1/3 Digit 表示なし
ControlChange B0 48 20 7セグ書き換え BARS: 2/3 Digit 表示なし
ControlChange B0 47 31 7セグ書き換え BARS: 3/3 Digit 値 1 表示 ドット無し
ControlChange B0 46 30 7セグ書き換え BEATS: 1/2 Digit 値 0 表示 ドット無し
ControlChange B0 45 31 7セグ書き換え BEATS: 2/2 Digit 値 1 表示 ドット無し
ControlChange B0 44 20 7セグ書き換え SUB DIVISION: 1/2 Digit 表示なし
ControlChange B0 43 20 7セグ書き換え SUB DIVISION: 2/2 Digit 表示なし
ControlChange B0 42 30 7セグ書き換え TICKS: 1/3 Digit 値 0 表示 ドット無し
ControlChange B0 41 30 7セグ書き換え TICKS: 2/3 Digit 値 0 表示 ドット無し
ControlChange B0 40 30 7セグ書き換え TICKS: 3/3 Digit 値 0 表示 ドット無し
SystemExclusive F0 00 00 66 14 12 00 4C 69
6E 6B 65 64 20 74 6F 20 46
4C 20 53 74 75 64 69 6F 20
31 31 20 28 50 72 6F 64 75
63 65 72 20 45 64 69 74 69
6F 6E 20 76 31 31 2E 31 2E
31 29 20 20 20 20 20 20 F7
LCD1行目書き換え
"Linked to FL Studio 11 (Producer Edition v11.1.1) "
の表示
SystemExclusive F0 00 00 66 14 12 00 49 4E
53 20 31 20 20 49 4E 53 20
32 20 20 49 4E 53 20 33 20
20 49 4E 53 20 34 20 20 49
4E 53 20 35 20 20 49 4E 53
20 36 20 20 49 4E 53 20 37
20 20 49 4E 53 20 38 F7
LCD1行目書き換え
"INS 1 INS 2 INS 3 INS 4 INS 5 INS 6 INS 7 INS 8"
の表示

初期化処理は特にないようで、いくつかのボタンを光りっぱなしにしたあとに接続しても、そのボタンは光りっぱなしになってしまうようです。

フェーダー位置は、 0x66, 0x10 から 0b01100110, 0x00010000 となり、7bitで結合すると 0b11001100010000 = 0d13072 (0~16383中)となり、Arduino MIDI Libraryに -8192~8191 で渡すため 13072-8192 を計算すると 4880 となります。

MIDI.sendPitchBend(4880, 1);

とするのがフェーダーの0dB位置で初期化されるようです。

 

FL Studioで実際にやり取りされる内容(切断時)

切断時の通信内容をモニターした結果が以下の通りです。

X-TOUCHを起動したまま、FL Studioを終了したときの内容です。

コマンド データ 概要
SystemExclusive F0 00 00 66 14 20 00 00 F7 チャンネルメーターモード
SystemExclusive F0 00 00 66 14 20 01 00 F7 チャンネルメーターモード
SystemExclusive F0 00 00 66 14 20 02 00 F7 チャンネルメーターモード
SystemExclusive F0 00 00 66 14 20 03 00 F7 チャンネルメーターモード
SystemExclusive F0 00 00 66 14 20 04 00 F7 チャンネルメーターモード
SystemExclusive F0 00 00 66 14 20 05 00 F7 チャンネルメーターモード
SystemExclusive F0 00 00 66 14 20 06 00 F7 チャンネルメーターモード
SystemExclusive F0 00 00 66 14 20 07 00 F7 チャンネルメーターモード
SystemExclusive F0 00 00 66 14 12 00 46 4C
20 53 74 75 64 69 6F 20 31
31 20 73 65 73 73 69 6F 6E
20 63 6C 6F 73 65 64 20 61
74 20 32 3A 32 32 3A 30 32
20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 F7
LCD1行目書き換え
"FL Studio 11 session closed a 2:22:02 "
の表示
SystemExclusive F0 00 00 66 14 12 3E 20 20
20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20
20 20 20 20 20 F7
LCD2行目書き換え
" "
の表示
ControlChange B0 47 20 7セグ書き換え BARS: 3/3 Digit 表示なし
ControlChange B0 46 20 7セグ書き換え BEATS: 1/2 Digit 表示なし
ControlChange B0 45 20 7セグ書き換え BEATS: 2/2 Digit 表示なし
ControlChange B0 42 20 7セグ書き換え TICKS: 1/3 Digit 表示なし
ControlChange B0 41 20 7セグ書き換え TICKS: 2/3 Digit 表示なし
ControlChange B0 40 20 7セグ書き換え TICKS: 3/3 Digit 表示なし
ControlChange B0 4B 20 7セグ書き換え ASSIGNMENT: 1/2 Digit 表示なし
ControlChange B0 4A 20 7セグ書き換え ASSIGNMENT: 2/2 Digit 表示なし

 

ArduinoからMCUプロトコルでMackie Control C4を制御

Mackie Control C4

Mackie Control C4を入手したのでこちらも動作テストしてみます。

ファームウェアは最終版のv1.02です。

 

ボタン一覧

ボタンはMackie Controlと同様にノートオン、ノートオフでボタンを押した瞬間と離した瞬間が通知されるようです。

ID(0x) BUTTON LED COLOR
00 FUNCTION: SPLIT YELLOW(1/3 LED)
01 --- YELLOW(2/2 LED)
02 --- YELLOW(3/1 LED)
03 FUNCTION: LOCK YELLOW
04 FUNCTION: SPOT ERASE RED
05 ASSIGNMENT: MARKER YELLOW
06 ASSIGNMENT: TRACK YELLOW
07 ASSIGNMENT: CHAN STRIP YELLOW
08 ASSIGNMENT: FUNCTION YELLOW
09 PARAMETER: BANK Left ---
0A PARAMETER: BANK Right ---
0B PARAMETER: SINGLE Left ---
0C PARAMETER: SINGLE Right ---
0D MODIFIERS: SHIFT ---
0E MODIFIERS: OPTION ---
0F MODIFIERS: CONTROL ---
10 MODIFIERS: ALT ---
11 SLOT UP ---
12 SLOT DOWN ---
13 TRACK L ---
14 TRACK R ---
--- --- ---
20 V-Pot Knob (Row 1) Ch. 1 ---
21 V-Pot Knob (Row 1) Ch. 2 ---
22 V-Pot Knob (Row 1) Ch. 3 ---
23 V-Pot Knob (Row 1) Ch. 4 ---
24 V-Pot Knob (Row 1) Ch. 5 ---
25 V-Pot Knob (Row 1) Ch. 6 ---
26 V-Pot Knob (Row 1) Ch. 7 ---
27 V-Pot Knob (Row 1) Ch. 8 ---
28 V-Pot Knob (Row 2) Ch. 1 ---
29 V-Pot Knob (Row 2) Ch. 2 ---
2A V-Pot Knob (Row 2) Ch. 3 ---
2B V-Pot Knob (Row 2) Ch. 4 ---
2C V-Pot Knob (Row 2) Ch. 5 ---
2D V-Pot Knob (Row 2) Ch. 6 ---
2E V-Pot Knob (Row 2) Ch. 7 ---
2F V-Pot Knob (Row 2) Ch. 8 ---
30 V-Pot Knob (Row 3) Ch. 1 ---
31 V-Pot Knob (Row 3) Ch. 2 ---
32 V-Pot Knob (Row 3) Ch. 3 ---
33 V-Pot Knob (Row 3) Ch. 4 ---
34 V-Pot Knob (Row 3) Ch. 5 ---
35 V-Pot Knob (Row 3) Ch. 6 ---
36 V-Pot Knob (Row 3) Ch. 7 ---
37 V-Pot Knob (Row 3) Ch. 8 ---
38 V-Pot Knob (Row 4) Ch. 1 ---
39 V-Pot Knob (Row 4) Ch. 2 ---
3A V-Pot Knob (Row 4) Ch. 3 ---
3B V-Pot Knob (Row 4) Ch. 4 ---
3C V-Pot Knob (Row 4) Ch. 5 ---
3D V-Pot Knob (Row 4) Ch. 6 ---
3E V-Pot Knob (Row 4) Ch. 7 ---
3F V-Pot Knob (Row 4) Ch. 8 ---

0x01と0x02はLEDだけしか存在しません。

ボタンは0x00のSPLITだけです。

切り替え表示のための実装のようです。

 

V-Potのノブの位置に対するノート番号の一覧表。

Ch. 1 Ch. 2 Ch. 3 Ch. 4 Ch. 5 Ch. 6 Ch. 7 Ch. 8
1行目(一番上) 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27
2行目 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F
3行目 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37
4行目(一番下) 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F

V-Potのノブも押し込んだ際にボタンと同様の動作をします。

 

エンコーダーノブ・V-Potの読み込み

基本的には前述の通りで読み込み方法は変わりません。

V-Potのノブはコントロールチェンジで回転方向のイベントが発生します。

コントロールチェンジを読めばOKです。

チャンネルは1に対して、コントロール番号が0x00~0x1Fで割り当てられているようです。

6bit値で取れる回転スピードについては、X-TOUCHと異なりかなりリニアに変化するようです。

しかしビット数は低いようです。

具体的には、ゆっくり回すと1ですが、その後、4、8、12、15と変わっていきます。

合計5パターンでの値の出力です。

15が値として最大のようです。どれだけ速く回してみてもそれ以上の数値は見られませんでした。

 

V-Potのノブの位置に対するコントロール番号の一覧表。

Ch. 1 Ch. 2 Ch. 3 Ch. 4 Ch. 5 Ch. 6 Ch. 7 Ch. 8
1行目(一番上) 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
2行目 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F
3行目 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17
4行目(一番下) 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F

 

エンコーダーノブ・V-Pot LEDを制御

基本的には前述の通りで読み込み方法は変わりません。

コントロールチェンジを送ればそれに対応して光ります。

LEDの色は赤色なので明るいところだと見づらいです。

 

V-PotのLEDの位置に対するコントロール番号の一覧表。

Ch. 1 Ch. 2 Ch. 3 Ch. 4 Ch. 5 Ch. 6 Ch. 7 Ch. 8
1行目(一番上) 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27
2行目 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F
3行目 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37
4行目(一番下) 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F

 

LCDディスプレイの制御

基本的には前述の通りで表示方法は変わりませんが、システムエクスクルーシブメッセージのヘッダーが若干変わります。

Mackie Control C4の場合、製品指定が0x14ではなく、0x17を使用するようです。

現在わかっている範囲では以下のようになります。

ID 機種
0x10 Logic Control
0x11 Logic Control XT
0x14 Mackie Control
0x15 Mackie Control XT
0x17 Mackie Control C4

 

また、LCD指定のIDについては以下のようになります。

ID
1行目(一番上) 0x12
2行目 0x31
3行目 0x32
4行目(一番下) 0x33

 

したがって、一番上のLCDに表示するならば、以下のようなシステムエクスクルーシブメッセージ。

F0 00 00 66 17 12 [位置] [内容] F0

 

一番下のLCDに表示するならば、以下のようなシステムエクスクルーシブメッセージ。

F0 00 00 66 17 33 [位置] [内容] F0

 

なお、一番上のLCDには起動時にバージョン情報含めて表示が行われるために、任意の文字を表示する前にスペースで埋めて消す処理を行ったほうが良いと思われます。

 

その他コマンド(ファームウェアバージョンリクエスト)

基本的には前述の通りで取得方法は変わりませんが、LCDと同様に製品指定のIDだけ0x17に変化します。

F0 00 00 66 17 13 00 F7

以上のシステムエクスクルーシブメッセージを送ると以下の様な返答があります。

F0 00 00 66 17 14 56 31 2E 30 32 F7

データ部分のペイロード、5バイトのデータ(0x56~0x32まで)です。

つまり「V1.02」という文字列のアスキーコード5桁の返答になり、このバージョン情報はLCDディスプレイ部に表示されています。

製品指定のIDが異なると反応しないため、繋がっている機器の判定ができると思われます。

 

その他コマンド(リセットメッセージ)

基本的には前述の通りです。

製品指定のIDだけ0x17に変化します。

 

LEDをすべてオフにするコマンド

F0 00 00 66 17 62 F7

ボタンとV-PotのLEDが消灯しました。

 

リセットコマンド

F0 00 00 66 17 63 F7

リセットがかかり、LCD表示内容も初期化されました。

 

その他コマンド(コンフィギュレーションメッセージ)

基本的には前述の通りです。

製品指定のIDだけ0x17に変化します。

 

LCDバックライトセーバー(0x0B)

7バイト目で挙動が変わるようです。

F0 00 00 66 17 0B 00 F7 // LCD back light off
F0 00 00 66 17 0B 0F F7 // LCD back light on, with time out in minutes (default: 0F = 15minutes)

バックライトの制御が可能でした。

15分経過するとバックライトが消えます。(ボタン等に触れるとバックライトが点灯します)