今回はアラーム音をメロディに変更します。
アラーム音をメロディに変えよう
ここまでのプログラミングで、キッチンタイマーとしての動作はある程度完成しました。
ただ、せっかく音程を出すことができるスピーカーがあるのに、時間がきたら単調なアラーム音が鳴るだけではちょっと寂しいですよね。
そこで、今の単調なアラーム音をメロディーに変更しようと思います。
音程の周波数を#defineで定義
Arduino言語には、指定した周波数の信号を発生してくれるtone
があります。
例えば、A0端子に接続しているスピーカーで262Hz(ドの音程)を出したい場合、次のようにスケッチに書きます。
tone(A5, 262);
この指示を実行すると音を出したままになりますので、止める場合はスケッチに次のように書きます。
noTone(A5);
メロディーを出したい場合、その音程の周波数を指定すれば良いですが、いちいち数字を書いて周波数を指定するのはわかりづらいですよね。
そこで、スケッチの先頭部分で音階の名前と周波数を#define
で定義しておきたいと思います。
#define
で定義する音階名ですが、お馴染みの「ドレミファソラシ」を使おうと思います。
音階は低い「ド」から高い「ド」まで、いくつも同じ「ド」の音がありますので、オクターブ番号が付けられています。
普通のドは第4オクターブです。1オクターブ低いドは第3オクターブ、1オクターブ高いドは第5オクターブです。
またピアノの黒い鍵盤は隣の音と半音違いになり、左隣の音階名に「#」(シャープ)をつけます。
音階名をまとめると次のようになります。
そこで、#defineで定義する音階名は、オクターブ番号も付加することにします。例えば第4オクターブのドの周波数は262Hzですので、次のように定義することにします。
#define DO_4 262 // ド(第4オクターブ)
定義する範囲は、第4オクターブを中心に3オクターブ分ぐらいあればある程度の曲は作れると思います。
そこで、次のように3オクターブ分の音程を定義してみました。半音の「#」など、記号はC++言語では特別な意味を持つ文字として扱われることがありますので、音階名に「S」(Sharpの意味)をつけて使うことにします。
// 音の周波数
#define DO_3 131
#define DOS_3 139
#define RE_3 147
#define RES_3 156
#define MI_3 165
#define FA_3 175
#define FAS_3 185
#define SO_3 196
#define SOS_3 208
#define RA_3 220
#define RAS_3 233
#define SI_3 247
#define DO_4 262
#define DOS_4 277
#define RE_4 294
#define RES_4 311
#define MI_4 330
#define FA_4 349
#define FAS_4 370
#define SO_4 392
#define SOS_4 415
#define RA_4 440
#define RAS_4 466
#define SI_4 494
#define DO_5 523
#define DOS_5 554
#define RE_5 587
#define RES_5 622
#define MI_5 659
#define FA_5 698
#define FAS_5 740
#define SO_5 784
#define SOS_5 831
#define RA_5 880
#define RAS_5 932
#define SI_5 988
音の鳴らし方
それぞれの音程の周波数は定義できましたので、この定義名を使って音を鳴らすことにします。
A5端子に接続しているスピーカーで、普通のドの音を出すには次のように書けばOKです。
tone(A5, DO_4);
Arduinoボードはこの指示を処理すると、ずっとドの音を出し続けます。
ドの音が出ているときに、違う音、例えばレの音に変更したい場合は次のように書けばOKです。
tone(A5, RE_4);
音を止めるときはnoTone
を使います。
noTone(A5);
それでは適当な?メロディーを作ってアラーム音をメロディー音に変更してみましょう。
メロディー音を作る
メロディーはお馴染みの曲を使うと著作権の問題が出てくることもありますので、この記事では適当にメロディーを作ってみました。(個人で楽しむ分にはお馴染みのメロディーで大丈夫です)
それぞれの音の長さは200msで、次のメロディーにしてみます。
ドミソミドミソミドミソシド
なんともセンスがないメロディーですが、スケッチはこのメロディーを実装します。
それぞれの音は200msの長さで鳴らしますので、以下のようにスケッチに書けばOKです。
// ド
tone(SPEAKER, DO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ソ
tone(SPEAKER, SO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ド
tone(SPEAKER, DO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ソ
tone(SPEAKER, SO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ド
tone(SPEAKER, DO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ソ
tone(SPEAKER, SO_4);
delay(200);
// シ
tone(SPEAKER, SI_4);
delay(200);
// 1オクターブ高いド
tone(SPEAKER, DO_5);
delay(200);
// 音を消す
noTone(SPEAKER);
キッチンタイマーの時間が来たら、このメロディーを3回鳴らすようにしたいと思います。
前回までに作成したスケッチでは、アラーム音を3回鳴らすようにしてありますので、そのアラーム音の部分をメロディーに置き換えればOKです。
スケッチを作る
それではスケッチをメロディーを鳴らすように変更してみましょう。
スケッチ先頭部分に音階と周波数の定義を追加しました。また、アラーム音の部分はメロディーに置き換えました。
/*
キッチンタイマー
内容: スイッチ、LED、スピーカーを使ったキッチンタイマー
変更履歴:
2024.11.25: 新規作成
2024.12.01: スイッチが押されたらLED点滅開始
2024.12.02: スイッチ関連の#define追加
2024.12.05: 点滅回数カウント追加
2024.12.06: 繰り返し処理をforに変更
2024.12.13: アラーム音追加・動作開始時とタイマー時間の時に青色LEDを点灯
2024.12.15: 残り時間のLED制御を追加
2024.12.17: 残り時間が少なくなったら音も鳴らす制御を追加
2024.12.17: アラーム音をメロディーに変更
*/
// 秒を表現するLED関連の定義
#define BYOU_LED 12 // 秒を表現するLEDの接続端子
#define BYOU_ON 50 // 秒を表現するLEDを点灯している時間(単位:ミリ秒)
#define BYOU_OFF (1000 - BYOU_ON) // 秒を表現するLEDを消している時間(単位:ミリ秒)
// 残り時間を表現するLED関連(緑色、黄色、赤色LED)
#define LED_MIDORI 8 // 緑色LEDの端子番号
#define LED_KIIRO 6 // 黄色LEDの端子番号
#define LED_AKA 4 // 赤色LEDの端子番号
// タイマースタートスイッチ関連の定義
#define SWITCH A5 // スイッチを接続している端子名
#define SWITCH_OFF 1 // スイッチOFFの時のdigitalReadの値
#define SWITCH_ON 0 // スイッチONの時のdigitalReadの値
// タイマー時間設定(LEDの点滅回数)
#define TIMER_JIKAN 30
// 残り時間を表現するLEDの制御時間
#define KIIRO_JIKAN 10 // 残り時間3分の2
#define AKA_JIKAN 20 // 残り時間3分の1
// アラーム音関連
#define SPEAKER A0 // スピーカーの端子番号
#define ALARM 880 // アラーム音の音程
// メロディー演奏用の音の周波数
#define DO_3 131
#define DOS_3 139
#define RE_3 147
#define RES_3 156
#define MI_3 165
#define FA_3 175
#define FAS_3 185
#define SO_3 196
#define SOS_3 208
#define RA_3 220
#define RAS_3 233
#define SI_3 247
#define DO_4 262
#define DOS_4 277
#define RE_4 294
#define RES_4 311
#define MI_4 330
#define FA_4 349
#define FAS_4 370
#define SO_4 392
#define SOS_4 415
#define RA_4 440
#define RAS_4 466
#define SI_4 494
#define DO_5 523
#define DOS_5 554
#define RE_5 587
#define RES_5 622
#define MI_5 659
#define FA_5 698
#define FAS_5 740
#define SO_5 784
#define SOS_5 831
#define RA_5 880
#define RAS_5 932
#define SI_5 988
void setup() {
// 端子の設定
// スピーカー接続端子はtoneの指示で自動的に出力設定になるので設定していません
pinMode(BYOU_LED, OUTPUT); // 秒表現のLED接続端子の出力設定
pinMode(SWITCH, INPUT_PULLUP); // スイッチ接続端子をプルアップ設定
pinMode(LED_MIDORI, OUTPUT); // 緑色LED接続端子設定
pinMode(LED_KIIRO, OUTPUT); // 緑色LED接続端子設定
pinMode(LED_AKA, OUTPUT); // 緑色LED接続端子設定
// 秒のLED(青色LED)を点灯する
digitalWrite(BYOU_LED, HIGH);
// スイッチが押されるまで何もしないで待つ
while( digitalRead(SWITCH) == SWITCH_OFF ) {
}
// タイマー開始時に緑色LEDを点灯
digitalWrite(LED_MIDORI, HIGH);
}
void loop() {
// TIMER_JIKAN分の回数を数える
for(uint8_t count=0; count<TIMER_JIKAN; count++) {
// 残り時間が3分の2のとき、緑色をOFF、黄色をONにする
if( count == KIIRO_JIKAN ) {
digitalWrite(LED_MIDORI, LOW);
digitalWrite(LED_KIIRO, HIGH);
}
// 残り時間が3分の1のとき、黄色をOFF、赤色をONにする
if( count == AKA_JIKAN ){
digitalWrite(LED_KIIRO, LOW);
digitalWrite(LED_AKA, HIGH);
}
// 残り時間が5秒以下かそうでないかで処理を変える
if( (TIMER_JIKAN-count) <= 5 ) {
// 残り時間が5秒以下のときは、1秒に1回青色LEDを点滅すると同時に音を鳴らす
digitalWrite(BYOU_LED, HIGH);
tone(SPEAKER, ALARM);
delay(BYOU_ON);
digitalWrite(BYOU_LED, LOW);
noTone(SPEAKER);
delay(BYOU_OFF);
} else {
// そうでなければ、1秒に1回青色LEDを点滅する(音は鳴らさない)
digitalWrite(BYOU_LED, HIGH);
delay(BYOU_ON);
digitalWrite(BYOU_LED, LOW);
delay(BYOU_OFF);
}
}
// 時間になったので秒のLED(青色LED)を点灯する
digitalWrite(BYOU_LED, HIGH);
// メロディーを3回演奏する
for(uint8_t count=0; count<3; count++) {
// ド
tone(SPEAKER, DO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ソ
tone(SPEAKER, SO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ド
tone(SPEAKER, DO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ソ
tone(SPEAKER, SO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ド
tone(SPEAKER, DO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ソ
tone(SPEAKER, SO_4);
delay(200);
// シ
tone(SPEAKER, SI_4);
delay(200);
// 1オクターブ高いド
tone(SPEAKER, DO_5);
delay(200);
// 音を消す
noTone(SPEAKER);
}
// 何もしないで待つ
while( true ) {
}
}
ミニチャレンジ課題
上のスケッチを動作させると、すぐに気付くことがあると思います。
「ドミソミドミソミドミソシド」というメロディーがつながってしまって、「ドミソミドミソミドミソシドドミソミドミソミドミソシドドミソミドミソミドミソシド」という1つのメロディーになってしまっています。
そこで、「ドミソミドミソミドミソシド」を3回繰り返しとして聞こえるように、「ドミソミドミソミドミソシド」のメロディーが終わったら少し時間をおいて次の「ドミソミドミソミドミソシド」が鳴るようにスケッチを変更してみてください。
スケッチが長いですよね
ところで!
キッチンタイマーのアラーム音をメロディーに変更したら、ずいぶんとスケッチが長くなってしまいましたよね。
これって何かいい解決策はないのでしょうか…
ミニチャレンジ課題解答例
「ドミソミドミソミドミソシド」のあとに時間待ちを入れればメロディーを区切ることができますので、次のようにnoToneで音を止めた後、0.5秒待つようにしてみました。
スケッチはメロディー演奏部分のみ掲載しています。
// メロディーを3回演奏する
for(uint8_t count=0; count<3; count++) {
// ド
tone(SPEAKER, DO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ソ
tone(SPEAKER, SO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ド
tone(SPEAKER, DO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ソ
tone(SPEAKER, SO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ド
tone(SPEAKER, DO_4);
delay(200);
// ミ
tone(SPEAKER, MI_4);
delay(200);
// ソ
tone(SPEAKER, SO_4);
delay(200);
// シ
tone(SPEAKER, SI_4);
delay(200);
// 1オクターブ高いド
tone(SPEAKER, DO_5);
delay(200);
// 音を消す
noTone(SPEAKER);
// メロディーを区切るために少し時間待ちをする
delay(500);
}
更新履歴
日付 | 内容 |
---|---|
2019.11.4 | 新規投稿 |
2021.8.27 | 新サイトデザイン対応 |
2022.2.17 | 誤字訂正 |
2024.12.17 | スケッチ一部変更(端子指定など) ミニチャレンジ課題解答例追加 |
単なる誤植だと思いますが、
「普通のド(第4オクターブのド)は440Hz」ではなく
(正)262Hz ではないでしょうか。
いつも分かりやすく、70歳を超えていてもよく理解できます。
ありがとうございます。
otaさま、
ご指摘いただきどうもありがとうございました!
おっしゃる通り、ドは262Hzです。早速修正させていただきました。
自分ではなかなか気づかないのでご指摘いただき大変助かります。
440Hzはラの音ですので全然違いますね…
ところでラの音は440Hzとなっていますが、モーツァルトの時代は432Hzだったという話を聞いたことがあります。ラを432Hzにして昔風のアラームを作ってみるのも面白いかもしれませんね。
コメントいただきどうもありがとうございました。