今回はスピーカーを使って「音」をテーマにArduinoを触っていきたいと思います。Arduinoでは比較的手軽に音を扱うことができるtone関数などが標準で用意されていますが、今回は、そのtone関数をはじめとして詳しい「音」の話や、Arduinoを使ってできるシンプル楽器ガジェットを作成してみます。
今回の電子工作レシピ
完成までの時間目安:90分
必要なパーツ
- Arduino本体(Arduino Uno R3 /Arduino Pro Mini)
http://www.switch-science.com/catalog/789/
http://www.switch-science.com/catalog/946/ - ブレッドボード http://www.switch-science.com/catalog/313/
- 圧電スピーカー http://akizukidenshi.com/catalog/g/gP-04228/
- タクトスイッチ http://akizukidenshi.com/catalog/g/gP-03648/
スピーカーについて知る
今回スピーカーを使うわけですが、スピーカーとはそもそも”電子工作的”にどのようなパーツなのでしょうか、なんとなく電気を流すとスピーカーが震えて音が鳴る、というような印象は皆さん持っていると思いますが、実際にどのような仕組みで音がなるのか調べてみます。
スピーカーの種類
スピーカーの種類を分ける際に、形で分けるといろいろな種類がありますが、電気信号を振動に変換する、という目線で分類してみると、動電型(ダイナミック型)、静電型(コンデンサ型)、圧電型、放電型(イオン型)、マグネティック型、リボン型などさまざまな方式があります。
今回利用する圧電型のしくみは図1になります。
また、一般的によく見る動電型(ダイナミック)スピーカーのしくみは図2になります。いずれにしても、出力したい音の信号に従って電流を流すことで、スピーカーが振動して空気を震わせて音になります。
スピーカーとマイクの関係について
今回スピーカーを扱いますが、ちょっと寄り道をして、「マイク」はどのような原理で動くでしょうか?マイクも乱暴な言い方をしてしまえば、一種のスピーカーなのです。スピーカーは電気を流すことで空気を震わせ音に変えますが、マイクは空気の振動を電気に変えて音声信号として利用する仕組みになっています。
ここでちょっと面白い実験をしてみます。今回利用する圧電スピーカーは電流を流すことでスピーカーの圧電素子をちぢめて金属板を震わせ音を出しますが、LEDをスピーカーに接続した状態で、手で圧電スピーカーをくいっくいっとまげて見ます。ちなみにスピーカーは+-の向きはありません。
すると、どうでしょうか、一瞬ですがLEDが光りますね。これはマイクと同じ仕組みで、圧電スピーカーを曲げる(マイクの場合は空気の振動を受ける)ことで、電流が発生している証拠です。圧電スピーカーを曲げることで発生する電流はとても短く小さな出力なのでこれを何かに応用する、というのはなかなか難しいですが、素直に面白いですよね。
Arduinoで圧電スピーカーを鳴らしてみる
では、さっそくArduinoでスピーカーを鳴らしてみましょう。Arduinoでは手軽にスピーカーで音を鳴らすためにtone関数というものが用意されています。
tone関数
tone(出力ピン番号, 出力する周波数, 長さ);
Arduinoにスピーカーをそのまま接続してプログラムを本体にアップロードしてみます。
//***************************************/ // tone関数で音を鳴らすプログラムその1 //***************************************/ #define BEATTIME 200 //音を出している時間(msec) #define SPEAKER 12 //スピーカーの出力ピン番号 void setup() { } void loop() { tone(SPEAKER,262,BEATTIME) ; // ド delay(BEATTIME) ; tone(SPEAKER,294,BEATTIME) ; // レ delay(BEATTIME) ; tone(SPEAKER,330,BEATTIME) ; // ミ delay(BEATTIME) ; tone(SPEAKER,349,BEATTIME) ; // ファ delay(BEATTIME) ; tone(SPEAKER,392,BEATTIME) ; // ソ delay(BEATTIME) ; tone(SPEAKER,440,BEATTIME) ; // ラ delay(BEATTIME) ; tone(SPEAKER,494,BEATTIME) ; // シ delay(BEATTIME) ; tone(SPEAKER,523,BEATTIME) ; // ド delay(BEATTIME) ; }
ドレミファソラシドの繰り返しが鳴りましたね。では、次に下記のプログラムを試してみてください。「ド」と「ミ」を一緒に鳴らしてみたいと思います。
//***************************************/ // tone関数で音を鳴らすプログラムその2 //***************************************/ #define BEATTIME 100 //音を出している時間(msec) #define SPEAKER 12 //スピーカーの出力ピン番号 void setup() { } void loop() { tone(SPEAKER,262,BEATTIME) ; // ド tone(SPEAKER,330,BEATTIME) ; // ミ delay(BEATTIME) ; }
どうなったでしょうか?思った通りに動きませんね。Tone関数では、プログラムの処理の流れとして「ド」を鳴らしたすぐあとコンマ何秒単位で「ミ」を鳴らそうとするため、物理的にスピーカーの振動が重なってしまうため、ノイズとなり意図した結果になりません。Arduinoのtone関数は同時に1音しか鳴らすことができないのです。
では、どうしたら和音を鳴らせるでしょうか?音の仕組みを少し勉強してみます。
音って?和音って?
音は空気の振動=波になっています。単一の周波数の場合、例えば楽器の音を合わせる(チューニング)するときや音叉(おんさ)が鳴らしている「ラ」の音は440Hz(ヘルツ)です。これは簡単に言ってしまえば1秒間に440回空気が振動している(波ができている)ということです。図にすると下記のようになります。
では、次にこのラの音がなっているところに別の音が鳴るとどのようになるでしょうか?
グラフの赤い線が新たに追加された音です。スピーカーが2つの場合はそれぞれの音を鳴らせば良いですが、スピーカーが1つの場合、この2つの音の波を合成して鳴らす必要があります。その合成した結果が下の図です。
このグラフの緑の線が実際に2つの音を合成して鳴らしたい場合の音の波になります。1つのスピーカーの場合は、このように音と音を合成して鳴らす必要があります。
プログラムで、音の周波数を実際に計算し作成することはできますが、何かを作成する際に毎回計算式を元に音を作成していくのはちょっとハードルが高くなってしまいますね。
実際にtone関数を使わずプログラム上で音の波を計算している例もあるので、興味がある方は試してみてください。
シンプルな楽器ガジェットを作成する
ある程度Arduinoで音の扱いがわかってきましたので、シンプルな楽器ガジェットを作ってみます。tone関数とタクトスイッチを利用して、簡単な電子オルガンをつくってみました。鍵盤の数は7個でそれを一つ一つ全てAnalogピンに割り当てるのはあまり美しくないので、今回は鍵盤の音が上がるたびに抵抗値を大きく(10K,12K,15K,18K,20K,22K,25K)することで、プログラム側でif文の条件でAnalogInputの値を判定して音階を決めるようにしました。
これで、AnalogInputは1つのピンだけで制御できますね。
//***************************************/ // シンプル楽器ガジェットプログラム //***************************************/ int s = 0; int speaker = 12; int sounds[] = {262,294,330,349,392,440,494}; int BEATTIME = 100; void setup() { Serial.begin(9600); pinMode(0,INPUT); pinMode(1,INPUT); } void loop() { s = analogRead(0); int p = analogRead(1); //一度音をリセット noTone(12); if(550 < s){ tone(speaker,sounds[0],BEATTIME); } else if(530 < s){ tone(speaker,sounds[1],BEATTIME); } else if(510 < s){ tone(speaker,sounds[2],BEATTIME); } else if(490 < s){ tone(speaker,sounds[3],BEATTIME); } else if(470 < s){ tone(speaker,sounds[4],BEATTIME); } else if(450 < s){ tone(speaker,sounds[5],BEATTIME); } else if(430 < s){ tone(speaker,sounds[6],BEATTIME); } else if(200 < s){ tone(speaker,sounds[7],BEATTIME); } delay(100); Serial.println(s); Serial.println(p); }
少しだけ工夫をしてみる
うまく動きましたね。もう少し工夫をしてみます。以前使ったフォトリフレクタを利用して、指を近づけると少し音程が変わるようにしてみます。ギターでいうとチョーキングという奏法に近いですね。フォトリフレクタからの入力値を音程に少し加えることで音程に変化をつけます。
//***************************************/ // シンプル楽器ガジェットプログラム改良版 //***************************************/ int s = 0; int speaker = 12; int sounds[] = {262,294,330,349,392,440,494}; int BEATTIME = 200; void setup() { Serial.begin(9600); pinMode(0,INPUT); pinMode(1,INPUT); } void loop() { s = analogRead(0); int p = 1023 - analogRead(1); //ピッチ p = p * 2; //一度音をリセット noTone(12); if(550 < s){ tone(speaker,sounds[0]+p,BEATTIME); } else if(530 < s){ tone(speaker,sounds[1]+p,BEATTIME); } else if(510 < s){ tone(speaker,sounds[2]+p,BEATTIME); } else if(490 < s){ tone(speaker,sounds[3]+p,BEATTIME); } else if(470 < s){ tone(speaker,sounds[4]+p,BEATTIME); } else if(450 < s){ tone(speaker,sounds[5]+p,BEATTIME); } else if(430 < s){ tone(speaker,sounds[6]+p,BEATTIME); } else if(200 < s){ tone(speaker,sounds[7]+p,BEATTIME); } delay(50); Serial.println(p); }
まとめ
次回はさらにもう一歩踏み込んでステレオジャックを経由してArduinoから市販のスピーカーで音を出したり、tone関数のようなビープ音だけではなく、シンセサイザーなどのようなもっと豊かな音色をシールドなしでArduinoだけで鳴らすことができるMozziというオープンソースのライブラリを利用してみたいと思います。