Arduino Tone Libraryを使うと、Arduino本体のみで複数の音が鳴らせるということなので使ってみました。
参考サイト
ArduinoでMIDI音源を作ってみた | メモとか倉庫とか(仮)
2012-03-07 – 熊工房 ohgumaの腹凹ませたい日記
↑こちらのサイトによると、Aruidno IDE 1.0以降ではTone.cppの
#include <wiring.h>
を
#include <wiring_private.h>
と書き換える必要があります。
しかし、Arduino UNOで3音同時に鳴らす場合、Timer0を使ってしまうため、お手軽にdelay()関数やmillis()関数で音を鳴らす、ということができなくなります。
毎度おなじみMetro Libraryも、内部でmillis()関数を呼んでいるのでやっぱり使えません。
(ちなみに、普通のtone()関数とか、MsTimer2 Libraryで使われているのがTimer2です
Timer1を使ったライブラリもあるようですが、これは使ったことないです)
ここで、「外部からのMIDI入力に対応しよう」ではなく、「だったら2音でいいや」に妥協するのが私です。
2音と言えばパワーコード。
ラモーンズやピストルズなどのパンク・ロックで使われている、元になる音と5度の音(半音7つ分上)だけで構成されるコードです。
アナログ入力(A0-A3)に半固定抵抗4つ付けて各種パラメータに使います。
D8とD9はTone2音の出力。ここではそれぞれ1kΩの抵抗を挟んでミックスしてますが、別々で音を出すならステレオ出力っぽいことも出来ますね。
回路図作る必要も無い気がしますが、こんな感じ。
スケッチはこちら。
#include <Tone.h>
const byte AIN_TEMPO = 1;
const byte AIN_LENGTH = 0;
const byte AIN_ROOT = 2;
const byte AIN_CHORD = 3;
const byte ch_count = 2;
const byte SND_PIN[ch_count] = {8,9};
Tone t[ch_count];
int tone_interval[ch_count];
const byte LED_PIN = 3;
int Freqs[] = {
262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494,
523, 554, 587, 622, 659, 699, 740, 784, 831, 880, 932, 988,
};
void setup()
{
for (int i = 0; i < ch_count; i++){
pinMode(SND_PIN[i], OUTPUT);
t[i].begin(SND_PIN[i]);
}
pinMode(LED_PIN, OUTPUT);
}
int note_root = 0;
int note_chord = 3;
int note_length = 48;
int note_gate = note_length / 4;
void loop()
{
set_note();
snd_play(note_root, note_chord, note_gate);
snd_stop(note_length - note_gate);
}
void snd_play(int note_number, int chord, int ms)
{
digitalWrite(LED_PIN, HIGH);
t[0].play(Freqs[note_number]);
t[1].play(Freqs[note_number + chord]);
delay(ms);
digitalWrite(LED_PIN, LOW);
}
void snd_stop(int ms)
{
t[0].stop();
t[1].stop();
delay(ms);
}
void set_note()
{
int tmp;
if (note_root != (tmp = map(analogRead(AIN_ROOT),0,1023, 0,11))){
note_root = tmp;
}
if (note_chord != (tmp = map(analogRead(AIN_CHORD),0,1023, 1, 12))){
note_chord = tmp;
}
if (note_length != (tmp = analogRead(AIN_TEMPO) + 1)){
note_length = tmp;
}
if (note_gate != (tmp = map(analogRead(AIN_LENGTH), 0, 1023, 1, note_length))){
note_gate = tmp;
}
}
基本的にはArduinoでYMOクリックもどきとかArduinoで雷電風リズムマシンのスケッチと同じです。
キモになってくるのが、アナログ入力からパラメータを設定しているset_note()関数。
まず、ルート音をAIN_ROOT(A2)から取ってます。前はシフト演算子とか使ってましたが、そんなに速度が必要なわけでもないし、何よりmap()関数便利すぎなので。
ここではアナログ入力の0~1023を0~11に丸めています。0~11はそれぞれド~シ(C,C#,D,D#,E,F,F#,G,G#,A,A#,B)の音程になります(Freqs配列の中身は2オクターブ分の周波数です)。
次のAIN_CHORD(A3)はルート音から半音いくつ分離れた音を一緒に鳴らすか。
取る値は1~12。パワーコードに限定するなら「7」固定でいいんですが、まあせっかくなので、隣のフレット(鍵盤)を同時にならした場合から、1オクターブ上の音まで設定できるようにしました。
AIN_TEMPO(A1)から取ってるのは、そのまんま1音1音を何ミリ秒鳴らすか。+1してるのは、0にした時にフリーズしちゃうので。
AIN_LENGTH(A0)は、↑の1音の長さの内、実際に音を鳴らしている時間の割合です。MIDIで言うGate Time、MMLで言うQコマンドです。
で、実行してみると、かように珍妙な音が鳴ります。
……おかしいな、ラモーンズを目指していたはずなのに。