Arduinoで2つのTone信号を同時に再生する


目的

Arduinoの標準Tone関数は同時に1音のみしかTone信号を再生する事ができません。
2音を同時再生したい場合はArduino Tone Libraryを使用するとよいです。
今回はArduino Tone Libraryを使った際のメモを記載します。

準備

Arduino Uno
Arduino Tone Library
100均のスピーカ 1〜3個

Tone Libraryはこちらのサイトからダウンロードして使います。
Tone Libraryを使用する際はDocument記載の下記点に注意が必要です。
特に後半2点はTone関数とTimerの同時使用に影響が出るものであり、
Tone関数を3つ使用した際に、PWM信号やdelay/milis等の待ち用関数の使用に影響が出るので注意です。

Hardware Connections/Requirements

Just connect the digital pin to a speaker (with a resistor - say 1K - in line), and the other side of the speaker to ground (GND).
You can use a potentiometer to control the volume. Use a 10K Ohm potentiometer (variable resistor) in line with the 1K Ohm resistor connected to the speaker.

Using this library will affect usage of the PWM outputs, so be aware.

Also, although it's the last timer to be allocated, timer 0 (which is used for millis() among other things) will be affected if used.

スピーカはDAISOなどで3極ミニプラグのものを使用すればOKです。
ミニプラグのL,R,GND,は下記サイトを参照すればOKです。
イヤホンの4極と3極の違いって?知っておきたいプラグの基本!
フォーンプラグ

配線図

PIN22,23,24とスピーカを接続します。

コード

1つのToneを再生する場合
こちらはサンプルtoneMelodyを参考に作成

toneMelody1
#include <MIDI.h>
#include <Tone.h>
#include "pitches.h"

// notes in the melody:
int melody[] = {
  0, 0, NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4, 0, 0
};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
  4, 4, 4, 8, 8, 4, 4, 4, 4, 4, 4, 4
};

Tone tone1;

#define PIN1 22

void setup() {

  tone1.begin(PIN1);

  for (int thisNote = 0; thisNote < 10; thisNote++) {

    int noteDuration = 1000 / noteDurations[thisNote];
    int data1=melody[thisNote];
    int data2=melody[thisNote + 2];
    if(data1 > 0) {
      tone1.play(data1);
    }
    else{
      tone1.stop();      
    }

    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    tone1.stop();
  }
}

void loop() {
  // no need to repeat the melody.
}

2つのToneを再生する場合

toneMelody2
#include <MIDI.h>
#include <Tone.h>
#include "pitches.h"

// notes in the melody:
int melody[] = {
  0, 0, NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4, 0, 0
};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
  4, 4, 4, 8, 8, 4, 4, 4, 4, 4, 4, 4
};

Tone tone1;
Tone tone2;

#define PIN1 22
#define PIN2 23

void setup() {

  tone1.begin(PIN1);
  tone2.begin(PIN2);

  for (int thisNote = 0; thisNote < 10; thisNote++) {

    int noteDuration = 1000 / noteDurations[thisNote];
    int data1=melody[thisNote];
    int data2=melody[thisNote + 2];
    if(data1 > 0) {
      tone1.play(data1);
    }
    else{
      tone1.stop();      
    }

    if(data2 > 0) {
      tone2.play(data2);
    }
    else{
      tone2.stop();      
    }

    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    tone1.stop();
    tone2.stop();
  }
}

void loop() {
  // no need to repeat the melody.
}

テスト

1つのToneを再生する場合

2つのToneを再生する場合

CodingError対策

3音鳴らすためにTone信号用のMIDIインスタンスを3つ宣言しつつ、
delay関数を使用した場合は、Tone再生を正しく行えなくなりました。
インスタンスを2つにするか、MIDIインスタンスを3つ宣言する場合はdelayやmilis関数を使わない実装をする必要がありそうです。

参考

ToneLibraryDocumentation
Arduino Tone Libraryでパワーコードを鳴らす
Arduino UNO+MIDIキーボードで3和音鳴らしてみる
イヤホンの4極と3極の違いって?知っておきたいプラグの基本!
フォーンプラグ