音楽理論とかぜんぜんわからないんですが、この動画で和音の話してて、うちにある唯一のポリフォニックシンセ・MIDI野郎用に和音を鳴らせるMIDIシーケンサーをつくってみるか、と思い立ってつくったやつのメモ。
完成(?)品
謎の配置になってるんですが、それぞれこういう役割です。3ステップシーケンサーで、音の高さ(tone
)・長さ(length
)・音数(chord
)が各ステップごとに指定できます。音数のツマミが小さいと単音、多いと和音になります。length
が3ステップ目にないのはなぜかは後述。
回路図的なもの(雰囲気)
(慣れてないので、記号とか変だったらすみません...)
TC4051BP
8つの入力(上の図のA0
〜A7
)の中から1つを選択して出力(COM
)に流すIC。どれを選ぶかはS0
〜S2
のhigh/lowで切り替えられます。
要は0〜7までの整数を3bitで表現すればよく、上の図のようにつながっている状態だと以下のコードになります(D2
からなので2桁シフトする)。PORTD
はport registerというやつです。
PORTD = i << 2;
ただ、今回のはTX(D1
にあたるもの)をMIDIの送信に使っていて、そこの状態は保ちたいのでPORTD & B00000010
とのORを取ることになります。
PORTD = (PORTD & B00000010) | (i << 2);
こんな感じで、一定間隔ごとに読み取るチャンネルを切り替えていくとシーケンサーができあがります。
MIDI Library
MIDI関連の操作は、Arduino MIDI Libraryを使います。あんまりドキュメントちゃんと読んでませんが、MIDI送信側で使うときは何も考えずに使える感じでした(受信側はちょっとややこしそうかも)。
メジャーコード、マイナーコード
↑の動画いわく、メジャーコードは4 tone上の音とそこからさらに3 tone上の音を足せばいける、ということで、
MIDI.sendNoteOn(baseTone, 127, 1); MIDI.sendNoteOn(baseTone + 4, 127, 1); MIDI.sendNoteOn(baseTone + 7, 127, 1);
とかやるとメジャーコードになるみたいです。マイナーコードは、3 note上→4 note上、なので
MIDI.sendNoteOn(baseTone, 127, 1); MIDI.sendNoteOn(baseTone + 3, 127, 1); MIDI.sendNoteOn(baseTone + 7, 127, 1);
です。どっちも鳴らせるようにしたいので、デフォルトはマイナーの方にしておいてメジャーなら偶数のときは1 tone足す、という感じにしました。
int chord[5] = { 0, 3, 7, 10, }; // toneは0〜127の128段階だが、下位1bitをメジャー・マイナーの区別に使いたいので256段階の値を読み取る sensorValue = map(analogRead(pin), 0, 1023, 0, 255); major = sensorValue & 1; // major or minor baseTone = sensorValue >> 1; for (int n = 0; n < notes; n++) { MIDI.sendNoteOn(baseTone + chord[n] + n % 2 * major, velocity, 1); }
3ステップ目のlength
TC4051BPは8チャンネルしかないので、3ステップに3つのパラメーターを指定しようと思うと3x3=9で1チャンネル足りません。なんですが、1シーケンスのステップ数が一定だとすると、
3ステップ目の長さ = (シーケンス全体の長さ) - (1ステップ目の長さ) - (2ステップ目の長さ)
で計算できるので、まあ別になくてもいいかということでこうなっています。
その他
あと、音に変化を付けるため、
- 1/10くらいは別の音色で鳴らす
- 音数は毎回同じではなく、ランダムに飛ばしたりする
toneOn
だけでなくtoneOff
もランダムに飛ばして、たまに長く鳴る音が出るようにする
みたいなこともしています。気になる方はコードを見てください(注:音の長さの計算あたりはたぶん間違えてます。直す気力がない...)
感想
シーケンサー、こんなに可変抵抗ついてて尊い...という気持ちになりました。
あとMIDI野郎は便利。一家に一台ぜひ。