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

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

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

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

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

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

 

音階を#define定義する

第31回の記事で説明したように、Arduinoではtone()/noTone()命令で指定した周波数の音程を鳴らすことができます。

tone命令でいちいち数字を書いて周波数を指定するのはわかりづらいので、まずは音階の名前と周波数を#defineで定義しておきましょう。

#defineで音階名を定義する場合、日本人が慣れている「ドレミファソラシ」で名前を定義しようと思います。「ドレミファソラシ」はイタリア語表記何ですよね。日本語表記は「ハニホヘトイロ」になります。また英語表記では「CDEFGAB」になります。

考えてみると日本ではいろいろな表記が混在して使われていますよね。音程は普通「ドレミファ」を使いますが、曲調を表現する場合は「ハ長調」など「ハニホヘト」の日本語表記を使っています。またMacintoshでは無償の音楽作成アプリGarageBandが有名ですが、このようなDTMアプリ(音楽作成アプリ)では音階の指定に「CDEFG」が使われています。

音階はオクターブごとに番号が振られていて、普通のドは第4オクターブになっています。1オクターブ低いドは第3オクターブ、1オクターブ高いドは第5オクターブです。

またピアノの黒い鍵盤は隣の音と半音違いになり、左隣の音階名に「#」(シャープ)をつけます。

以上をまとめると以下のように音階名が決められています。

音階まとめ

ということで、音階と周波数の定義は、音階名とオクターブ番号を使って#define定義しようと思います。例えば普通のド(第4オクターブのド)は440Hzですので以下のように定義しようと思います。

#define DO_4 440 // ド(第4オクターブ)

第4オクターブを中心に、3オクターブ分あればある程度の曲は作れると思いますので、以下のように3オクターブ分定義してみました。なお、半音の「#」など、記号はC/C++言語では特殊文字として扱われることがあるので、実際の#defineでは音階名に「S」をつけて使うことにします。

// 音の周波数
#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

 

音の鳴らし方

音階の#define定義はできましたので、この定義名を使って音を鳴らすことにします。tone命令で音を鳴らすことができますので、例えば普通のドを鳴らしたい場合は、

tone(SPEAKER, DO_4);

で鳴らすことができます。SPEAKERはスピーカーが接続されているArduioボードの端子番号で、#defineで定義しています。

違う音を鳴らしたい場合は、noTone()命令で音を止めなくても、先ほどの普通のドがなっている状態の時に

tone(SPEAKER, RE_4);

と書けばレの音を鳴らすことができます。

また音を止めるときはnoTone()命令を書けばOKです。

ということで適当なメロディーを作ってアラーム音をメロディー音に変更してみましょう。

 

メロディー音を作る

メロディーは最近の曲を使うと著作権の問題が出てきますので、適当にメロディーを作ってみました。それぞれの音の長さは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回鳴らすのは簡単ですよね。今のスケッチがアラーム音を3回鳴らすようにしてありますので、その部分をメロディーに置き換えればOKです。

 

スケッチを作る

それではスケッチをメロディーを鳴らすように変更してみましょう。

スケッチのsetup()部分の前に音階の定義を書きます。また、アラーム音の部分をメロディーに置き換えればOKです。このように変更したスケッチを以下に示します。今回のスケッチの変更は入力すると面倒ですので、コピペしてしまいましょう。スケッチができたらArduino Microにスケッチを送って動作を確認してみましょう。

/*
 * キッチンタイマー
 * 
 * 内容: スイッチ、LED、スピーカーを使ったキッチンタイマー
 * 変更履歴:
 *   2019. 8.11: 新規作成
 *   2019. 8.15: スタートスイッチ処理を追加
 *   2019. 8.17: スイッチ関連の#define追加
 *   2019. 9. 8: 点滅回数カウント追加
 *               最終的に繰り返し処理をfor文で作成
 *   2019. 9.16: スケッチ動作開始時にLEDを点滅
 *   2019.10. 5: アラーム音追加
 *               動作開始時とタイマー時間の時に青色LEDを点灯するように変更
 *   2019.10.13: 残り時間LED制御追加
 *   2019.10.14: 残り時間が5秒以下になったらスピーカーを鳴らす動作を追加
 *   2019.11. 4: アラーム音をメロディーに変更
 */

// 秒を表現するLED関連(青色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 23    // スイッチを接続している端子番号
#define SWITCH_OFF 1 // スイッチOFFの時のdigitalReadの値
#define SWITCH_ON  0 // スイッチONの時のdigitalReadの値

// タイマー時間設定(単位:秒)
#define TIMER_JIKAN 10

// 残り時間を表現するLEDの制御時間
#define KIIRO_JIKAN TIMER_JIKAN / 3
#define AKA_JIKAN   TIMER_JIKAN / 3 * 2

// アラーム音関連
#define SPEAKER 18  // スピーカーの端子番号
#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() {
  // 端子の設定
  pinMode(BYOU_LED,   OUTPUT);   // 青色LED接続端子設定
  pinMode(LED_MIDORI, OUTPUT);   // 緑色LED接続端子設定
  pinMode(LED_KIIRO,  OUTPUT);   // 緑色LED接続端子設定
  pinMode(LED_AKA,    OUTPUT);   // 緑色LED接続端子設定
  pinMode(SWITCH, INPUT_PULLUP); // スイッチ接続端子の設定

  // 秒のLED(青色LED)を点灯する
  digitalWrite(BYOU_LED, HIGH);

  // スイッチが押されるまで待つ
  while(digitalRead(SWITCH) == SWITCH_OFF) {
  }

  // タイマー開始時に緑色LEDを点灯
  digitalWrite(LED_MIDORI, HIGH);

}


void loop() {
  // for文で回数を数えるために使用する変数
  uint8_t count;

  // TIMER_JIKAN分の回数を数える
  for( count=0; count<TIMER_JIKAN; count++) {

    // 残り時間表現用LEDの制御
    if( count == KIIRO_JIKAN ) {
      digitalWrite(LED_MIDORI, LOW);
      digitalWrite(LED_KIIRO,  HIGH);
    }

    if( count == AKA_JIKAN ){
      digitalWrite(LED_KIIRO, LOW);
      digitalWrite(LED_AKA, HIGH);
    }

    // 残り時間に応じて処理を変える
    if( count >= (TIMER_JIKAN - 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( 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回繰り返しとして聞こえるように、「ドミソミドミソミドミソシド」のメロディーが終わったら少し時間をおいて次の「ドミソミドミソミドミソシド」が鳴るようにスケッチを変更してください。

 

スケッチが長いですよね

キッチンタイマーのアラームをメロディーに変更したら、ずいぶんとスケッチが長くなってしまいました。

これって何かいい解決策はないのでしょうか…

 

 

更新履歴

日付 内容
2019.11.4 新規投稿