きゃべログ

Arduinoのtone関数を使わずに原始的な方法でスピーカから音を鳴らしてみた

Arduino電子工作

昨日故障していたディスプレイを解体して,スピーカが取り出せたので何か作ってみようと思い立ち,とりあえずメロディを奏でてみることにしました. 身近にあるArduinoを使って何かできるかなと思ってブレッドボードにパーツを刺してコーディングしていきました.

回路

ブレッドボードにぶっさした

回路というほど大したものは組んでいませんが,紹介しておきます. Arduinoの13番ピンを信号出力用のピンにして,抵抗をかませてスピーカを配置します. それだけです!

プログラム

#include
const int signal = 13;

void setup(){
  pinMode(signal, OUTPUT);
}

//noteNum: MIDIのノート番号
//length:length×0.5秒だけ音が鳴る
//ms: 周期の半分(μs)
//temp: 型変換のための一時変数
void se(double noteNum, int length){
  int ms;
  double f,temp;
  
  f = pow(2, ( (noteNum - 69)/12 )) * 440;  //MIDI Tuning Standardの式より周波数を計算
  temp = ( 1 / f * pow(10,6) / 2);
  ms = (int)temp;
  
  if(noteNum == 145){
 for(long i = 0; i < 500000 * length; i += ms*2){
  digitalWrite(signal,LOW);
        delayMicroseconds(ms);
        delayMicroseconds(ms);
    }
  }else{
    for(long i = 0; i < 500000 * length; i += ms*2){
        digitalWrite(signal,HIGH);
        delayMicroseconds(ms);
        digitalWrite(signal,LOW);
        delayMicroseconds(ms);
    }
  }
}
void loop(){
 //カエルの歌
 se(60,1);
 se(62,1);
 se(64,1);
 se(65,1);
 se(64,1);
 se(62,1);
 se(60,2);
 se(64,1);
 se(65,1);
 se(67,1);
 se(69,1);
 se(67,1);
 se(65,1);
 se(64,1);
 se(145,1);
 se(60,1);
 se(145,1);
 se(60,1);
 se(145,1);
 se(60,1);
 se(145,1);
 se(60,1);
 se(145,1);
 se(60,1);
 se(62,1);
 se(64,1);
 se(65,1);
 se(64,1);
 se(62,1);
 se(60,1);
 se(145,1);
}

※69行目のmath.hの閉じタグは無視してください,よくわからないのですが勝手に追加されました…

使い方

原理とかは置いといて,まずはこのプログラムの使い方を説明します. seという関数は,指定した音程・時間を鳴らすためのものです.第1引数にMIDIのノートナンバー,第2引数に0.5秒単位で音の長さを指定します. なお,第1引数を145とすることで休符になります. loop関数にひたすらse関数を並べていくだけで曲が演奏できます.簡単!

原理とか

タイムチャート

恥ずかしながら作り始めた当初,Arduinoに搭載されているtone関数を知らなかったので,高校の物理の授業で習う原始的な音程制御方法でプログラムを書きました. やっていることは単純で,MIDI Tuning Standardの計算式を基に周波数を計算して,そこから波形の周期を計算します. 図のように半周期ごとに波形をON・OFFしてやることで矩形波を作ることが可能です.この矩形波を指定時間以上で,指定時間に最も近くなるように繰り返すことで音の長さを制御しています.

演奏させてみた

見事に鳴ってくれました!感動!

まとめ

  • Arduinoで簡易シーケンサを作った!
  • 物理の理論が確認できた!
  • かえるの歌が演奏できた!

きゃべ (@cab_kyabe)
きゃべ (@cab_kyabe)
Software Engineer / Product Manager