第36回 アラーム音をメロディーに変更する

今回はアラーム音をメロディに変更します。

目次

アラーム音をメロディに変えよう

ここまでのプログラミングで、キッチンタイマーとしての動作はある程度完成しました。

ただ、せっかく音程を出すことができるスピーカーがあるのに、時間がきたら単調なアラーム音が鳴るだけではちょっと寂しいですよね。

そこで、今の単調なアラーム音をメロディーに変更しようと思います。

音程の周波数を#defineで定義

Arduino言語には、指定した周波数の信号を発生してくれるtoneがあります。

例えば、A0端子に接続しているスピーカーで262Hz(ドの音程)を出したい場合、次のようにスケッチに書きます。

tone(A5, 262);

この指示を実行すると音を出したままになりますので、止める場合はスケッチに次のように書きます。

noTone(A5);

メロディーを出したい場合、その音程の周波数を指定すれば良いですが、いちいち数字を書いて周波数を指定するのはわかりづらいですよね。

そこで、スケッチの先頭部分で音階の名前と周波数を#defineで定義しておきたいと思います。

#defineで定義する音階名ですが、お馴染みの「ドレミファソラシ」を使おうと思います。

「ドレミファソラシ」はイタリア語表記です。日本語表記は「ハニホヘトイロ」になります。また英語表記では「CDEFGAB」になります。やはり「ドレミ」が一番馴染み深いですよね。

音階は低い「ド」から高い「ド」まで、いくつも同じ「ド」の音がありますので、オクターブ番号が付けられています

普通のドは第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スケッチ一部変更(端子指定など)
ミニチャレンジ課題解答例追加
通知の設定
通知タイミング
guest
2 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
ota
ota
1 年 前

単なる誤植だと思いますが、
「普通のド(第4オクターブのド)は440Hz」ではなく
(正)262Hz ではないでしょうか。

いつも分かりやすく、70歳を超えていてもよく理解できます。
ありがとうございます。

目次