Arduinoで電子オルガンを作る
周波数の計算方法について簡単に説明しておきます。音が高くなるほど周波数も高くなりますが、音階が1オクターブ上がるごとに周波数が2倍になるという規則がある事が知られています。1オクターブは12半音ですので、半音上がるごとに周波数が一定の比率で上昇するとして計算すると、音階が半音あがれば周波数は 12 2 ≒1.059463倍になります。(ここではピアノの調律などに使われる平均律 の話をしています。他にも、音の響きを重視した純正律 などの調律法があります)
ピアノの中央ド音(C4)の上のラ音(A4)は、440Hzに調律するのが基準とされている ので、この音を基準に、半音あがるごとに周波数を 12 √2倍していけば、全ての音階の周波数が計算できます。これをExcelで計算した結果をまとめたのが次の表です。
表1 、平均律における、音階と周波数 音階 周波数[Hz] 備考 C4 261.626 ピアノの中央のド音 C#4 277.183 D4 293.655 D#4 311.127 E4 329.628 F4 349.228 F#4 369.994 G4 391.995 G#4 415.305 A4 440.000 調律の基準音 A#4 466.164 B4 493.883 音階 周波数[Hz] 備考 C5 523.251 中央から1オクターブ上のド音 C#5 554.365 D5 587.330 D#5 622.254 E5 659.255 F5 698.456 F#5 739.989 G5 783.991 G#5 830.609 A5 880.000 A#5 932.328 B5 987.767 音階 周波数[Hz] 備考 C6 1046.502 今回使う最低音 C#6 1108.731 D6 1174.659 D#6 1244.508 E6 1318.510 F6 1396.913 F#6 1479.978 G6 1567.982 G#6 1661.219 A6 1760.000 A#6 1864.655 B6 1975.533 音階 周波数[Hz] 備考 C7 2093.005 今回使う最高音 C#7 2217.461 D7 2349.318 D#7 2489.016 E7 2637.020 F7 2793.826 F#7 2959.955 G7 3135.963 G#7 3322.438 A7 3520.000 A#7 3729.310 B7 3951.066以上のことを踏まえて電子オルガンのスケッチを作ると、次のようになります。Arduino Uno/Mega 2560/Leonardoのどれでもこのスケッチが使えます。動作確認はArduino IDE 1.0.5で行いました。
const int KeyNum = 13; // キーの数 const int threshold[KeyNum] = < 35, 115, 196, 277, 357, 433, 510, 588, 670, 751, 831, 908, 987>; // AD変換値の閾値 const int frequency[KeyNum] = < 1047,1109,1175,1245,1319,1397,1480,1568,1661,1760,1865,1976,2093>; // 各キーの周波数 // キーデコード関数 // 引数をA/D変換結果(0~1023)にして呼ぶと、押したキーの番号(0~KeyNum-1)を返す。 // 何もキーを押していない時は、-1を返す。 int KeyDecode(int n) < int i=0; while(ithreshold[i]) i++; if(i>=KeyNum) return -1; return i; > // KeyDecode void setup() < >// setup void loop() < int LastResult=-2; // 前回のキーデコード結果 int result; // 今回のキーデコード結果 int cnt=0; // デコード結果が一致した回数 static int LastDisplayed=-2; // 前回loop関数が呼ばれたと時に表示したキー // 複数回のloop関数の呼び出しにわたって値を保持するために、static変数にしている // キーを読み取る // チャタリングの除去などのため、A/D変換の値が落ち着くまで待つ // 1ms間隔でキーを読み取り、10回連続で同じキーが押されていたら、落ち着いたと判断する do < result=KeyDecode(analogRead(A0)); if(result==LastResult) < cnt++; >else < LastResult=result; cnt=0; >// if delay(1); > while(cnt // if > // if LastDisplayed=result; > // loopこのページで使われている用語の解説
関連ページ
- I/Oピン一つで読み取れるキーパッドの製作アナログ入力ピン一つで読み取れる16キーのキーパッドの製作。
- 抵抗分圧器を使った、多くのスイッチのセンシング(1)1つのアナログ入力ピンで多くのスイッチをセンシングするキーパッドの設計法を解説。
- 抵抗の値はなぜ中途半端なの?(E系列の話)(1)