MsTimer2をつかってMelodyのテンポを調整できるようにしてみた。

Arduino付属のサンプル"Melody"*1を改造してテンポ調整できるようにしました。

アナログ入力0番につながった可変抵抗の値によって曲のテンポが変化します。
発音中に可変抵抗の値が変化した場合にも滑らかにテンポが変わるようにタイマ割り込みを使って発音のタイミングを得ています。
Arduinoの標準のライブラリではタイマは使用できませんがContributed LibraryとしてMsTimer2*2があります。
これを利用することでシンプルにタイマ割り込み処理が実現できました。
以下ソース。

#include <MsTimer2.h>

int speakerPin = 9;
int length = 15; // the number of notes
char notes[] = "ccggaagffeeddc"; // a space represents a rest
int beats[] = { 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1 };

volatile int tempo = 127;
volatile int prevtempo = 0;
volatile int idx = 0;
volatile int cancel_note = 0;

void playTone(int tone, int duration) {
  for (long i = 0; i < duration * 1000L; i += tone * 2) {
    if (cancel_note == 1){ //発音をキャンセルしたときはインデックスを一個戻す
      cancel_note = 0;
      idx--;
      if (idx < 0){
        idx = 0;
      }
      break;
    }
    digitalWrite(speakerPin, HIGH);
    delayMicroseconds(tone);
    digitalWrite(speakerPin, LOW);
    delayMicroseconds(tone);
  }
}

void play() {
  if (notes[idx] == ' ') {
    delay(beats[idx] * tempo); // rest
  } else {
    playNote(notes[idx], beats[idx] * tempo);
  }
  idx++;
  if (idx > length) {
    idx = 0;
  }
}

void playNote(char note, int duration) {
  char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C', 'D' };
  int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956, 850 };

  // play the tone corresponding to the note name
  for (int i = 0; i < 9; i++) {
    if (names[i] == note) {
      playTone(tones[i]*4, duration);
    }
  }
}

void setup() {
  pinMode(speakerPin, OUTPUT);
  MsTimer2::set(10, play); // 10ms period
  MsTimer2::start();
}

void loop() {
  tempo = analogRead(0);
  if (abs(tempo - prevtempo) > 10){ //可変抵抗の値が変わったとき
    cancel_note = 1; //発音をキャンセル
  }
  prevtempo = tempo;
}

MsTimer2は「Arduinoをはじめよう」に収録されている言語リファレンスの中でも紹介されています。*3

Arduinoをはじめよう (Make:PROJECTS)

Arduinoをはじめよう (Make:PROJECTS)