まずはボタンから。
非力なRaspberry Pi 2Bでディスプレイも小さいですが、動作自体は問題なさそうです。
relativelayout.hatenablog.com
今回は、Mixxxを操作するハードウェアを作っていきます。
以前作ったデバイスを再利用
ハードウェアを作ると言っても、モノ自体は以前作ったデバイスを再利用していきます。
こんな感じで、5つのボタンをGNDとデジタルIOピンにつないだものです。
マイコン部分はArduino Leonardo互換機のSeeeduino Liteです。Atmega32U4が搭載されているのでUSBネイティブサポートも使えて、USBデバイスとしてエミュレーションも可能です。よって以て、USB接続できるMIDIデバイスとしてもエミュレーション可能なはず…。
いざプログラミング
ハードウェアは再利用するので、それを制御するロジックを書き換えていきます。コーディングはArduino IDEで。
久しぶりのダウンロード・起動だったので、UIがガラッと変わっていたのでびっくりしました。
www.arduino.cc
さて、プログラミング自体は下記のArduinoのドキュメントを参考にコーディングしていきます。
docs.arduino.cc
ポイントは…
- Native USB Port対応をしているボードを使う
- MIDIを扱うためにMIDIUSBライブラリを使う
こんな感じ。MIDI系のライブラリは複数あってカオスですが、今回はArduinoドキュメントに従っていきます。
コードは最後の方に貼っておきますが、MIDIのやり取りとしてはノートオン・ノートオフを使っていきます。
void noteOn(byte channel, byte pitch, byte velocity) {
Serial.println("noteOn");
midiEventPacket_t noteOn = { 0x09, 0x90 | channel, pitch, velocity };
MidiUSB.sendMIDI(noteOn);
}
void noteOff(byte channel, byte pitch, byte velocity) {
Serial.println("noteOff");
midiEventPacket_t noteOff = { 0x08, 0x80 | channel, pitch, velocity };
MidiUSB.sendMIDI(noteOff);
}
こんな感じで、ノート(鍵盤)を押す・離すという情報をプログラム的に送信します。鍵盤なので、どの音階をどのくらいの速さ(強さ)で押すか、などの情報も送ります。今回は中央のド(C3)からソ(G3)までを5つのボタンに割り当てて、ノートオン・ノートオフで送信します。チャネルと速度は固定のものを使いました。
ドレミファソをMixxxのコントロールに割り当てる
今回ド〜ソまでの5つの音階が表現できるMIDIデバイスが出来たので、それぞれDeck1/2のPlay・Cueに割り当てていきます。(5つのボタンのうち4つだけアサインしてみます)
理想としてはこんな割り当て。実際にMixxxでマッピングしていきます。
自作MIDIデバイスをRaspberry Piに接続してからMixxxを起動して、設定画面を開くとコントローラーというタブでデバイスが認識されているようです。
一応、プリセットという項目を覗いてみると、主要なDJコントローラーのマッピングには対応してそうですが、今回はプリセットは使わず、ラーニングウィザードを使って自力でマッピングしていきます。
ラーニングウィザードを開くと、Mixxx上の要素が一覧で並んでいて、それぞれに信号のアサインが出来ます。
とりあえず、Deck1/2のPlayとCueを探しては、実際にデバイスのボタンを押して、ボタンと制御の紐付けを行いました。
こんな感じ。
いざDJ
4ボタンだけなので、凝ったことは出来ませんが、ちゃんとボタンと演奏がリンクしていました。
雑感として
- 理論的にはボタンやスライダーを追加していけばDJコントローラーは自作できる
- ボタンがチャタるので、何かしらの制御が必要そう
- ハードウェアボタンを同時に押したり操作したりすると、処理が追いつくか(他の処理をブロッキングしないか)が心配
- ボタンが増えるとマッピングが面倒
こんな感じですねぇ。自作あるあるですが、やっぱり製品ってすげぇ…ってなりますね(笑)
とりあえず、横フェーダー・縦フェーダー、イコライザ、できればジョグあたりも追加してみたいところ・・・。
コードはこちら
#include <MIDIUSB.h>
#include <MIDIUSB_Defs.h>
#include <frequencyToNote.h>
#include <pitchToFrequency.h>
#include <pitchToNote.h>
#define BUTTON1 3
#define BUTTON2 5
#define BUTTON3 7
#define BUTTON4 8
#define BUTTON5 10
#define C3 48
#define D3 50
#define E3 52
#define F3 53
#define G3 55
#define DELAY 100
void setup() {
pinMode(BUTTON1, INPUT_PULLUP);
pinMode(BUTTON2, INPUT_PULLUP);
pinMode(BUTTON3, INPUT_PULLUP);
pinMode(BUTTON4, INPUT_PULLUP);
pinMode(BUTTON5, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
if (digitalRead(BUTTON1) == 0) {
Serial.println("BUTTON1");
noteOn(5, C3, 64);
MidiUSB.flush();
delay(DELAY);
noteOff(5, C3, 64);
MidiUSB.flush();
}
if (digitalRead(BUTTON2) == 0) {
Serial.println("BUTTON2");
noteOn(5, D3, 64);
MidiUSB.flush();
delay(DELAY);
noteOff(5, D3, 64);
MidiUSB.flush();
}
if (digitalRead(BUTTON3) == 0) {
Serial.println("BUTTON3");
noteOn(5, E3, 64);
MidiUSB.flush();
delay(DELAY);
noteOff(5, E3, 64);
MidiUSB.flush();
}
if (digitalRead(BUTTON4) == 0) {
Serial.println("BUTTON4");
noteOn(5, F3, 64);
MidiUSB.flush();
delay(DELAY);
noteOff(5, F3, 64);
MidiUSB.flush();
}
if (digitalRead(BUTTON5) == 0) {
Serial.println("BUTTON5");
noteOn(5, G3, 64);
MidiUSB.flush();
delay(DELAY);
noteOff(5, G3, 64);
MidiUSB.flush();
}
}
void noteOn(byte channel, byte pitch, byte velocity) {
Serial.println("noteOn");
midiEventPacket_t noteOn = { 0x09, 0x90 | channel, pitch, velocity };
MidiUSB.sendMIDI(noteOn);
}
void noteOff(byte channel, byte pitch, byte velocity) {
Serial.println("noteOff");
midiEventPacket_t noteOff = { 0x08, 0x80 | channel, pitch, velocity };
MidiUSB.sendMIDI(noteOff);
}
void controlChange(byte channel, byte control, byte value) {
Serial.println("controlChange");
midiEventPacket_t event = { 0x0B, 0xB0 | channel, control, value };
MidiUSB.sendMIDI(event);
}
最後に…
誰かPCDJを私に恵んでください…。
www.amazon.jp