SSブログ

音楽を演奏したい - tone編 [Arduino]

ard_tone.jpg

作った楽譜が再生できるかの確認です。
とりあえず、和音なし、Arduino標準のtone()関数を使った再生です。
tone関数は、周波数で音の高さを指定します。
基本の12音階(ド~シ)の周波数(Hz)をスケールとして配列で持っておき、1オクターブは上がると周波数は倍に、1オクターブ下がると周波数は半分になるので、シフト演算でいけます。16ビット符号なし整数型に収まる最大が第11オクターブになるので、ここから希望のオクターブまで右シフトすることで希望のオクターブの12音階(ド~シ)のそれぞれの周波数が得られるという仕組みにしました。
右ビットシフトは切り捨てになりますが、R_BITRSHIFT という四捨五入できるビットシフトマクロを作ってみましたが、それを聞き分けられるほどの耳ではないし、そもそもtone()関数の周波数は整数指定なので気にしなくてもよさそう。

#include "notes.h"              // 音符の定義データ(音階と音価(長さ))
#include "Gurenge.h"            // 曲データ
#define R_BITRSHIFT(X,S)  ((((X)>>((S)-1))+1)>>1)   // 四捨五入(ROUND)する右シフト(BITRSHIFT)マクロ
const uint16_t F_SCALE[] = { 33488, 35479, 37589, 39824, 42192, 44701, 47359, 50175, 53159, 56320, 59669, 63217 };
    // 基本の12音階(ド~シ:C11からB11まで)の周波数(Hz)(16ビット符号なし整数型に収まる最大が第11オクターブ)

void setup(){
  pinMode(  9, OUTPUT );              // tone()の中から呼び出されるのでなくていいが、明示的に
  pinMode( A1, INPUT_PULLUP );        // タクトスイッチ(PULLUPしてあり、押すとGND=LOWに)
}

void loop(){
  playTone( Gurenge );
  delay(1000);
  while( digitalRead(A1) );           // 演奏が終わったらスイッチが押される(LOWになる)まで待つ
  delay(1000);
}

void playTone(const uint16_t *d){
  uint16_t note, freq;                // PROGMEMから読み込んだ音符(音階+音価)情報(16bit), 周波数(Hz)
  uint32_t usExp, usDur, usRef;       // 音の切れる(expire)時刻, 音の持続時間(duration), 基準音符の長さ(usec)
  usRef = 1000000 * 60 * 4 / MIN_NOTE / pgm_read_word_near(d++);  // テンポから基準96,48分音符の長さ(usec)を計算
  usExp = micros();                   // 音の終了時刻の初期化
  do {                                // 曲データを読み込みながら再生
    if( micros() > usExp ) {                                      // 1音の出力時間を過ぎたら次の1音の準備
      if( !(note = pgm_read_word_near(++d)) ) continue;           // note = 0なら演奏終了
      usDur = (note & 0x00ff) * usRef;                            // 下位8ビットが音の長さ(基準音符の何倍の長さか)
      usExp += usDur;                                             // 音の切れる時間を更新
      if(note & 0xff00) {             // 休符でなければ、、
        freq = R_BITRSHIFT( F_SCALE[(note>>8)&0x0f], 11-(note>>12) ); // 上位4ビットがオクターブ、次の4ビットがピッチクラス(0-11)
        tone( 9, freq, usDur>>10 );                               // 10bitシフト=(1/1024):usからmsに変換し,やや音を短く
      }
    }
    if( !digitalRead(A1) ) break;     // タクトスイッチが押されたら演奏終了
  } while( note );
}

マクロ使わない場合。
        freq = F_SCALE[(note>>8)&0x0f] >> (11-(note>>12));        // 上位4ビットがオクターブ、次の4ビットがピッチクラス(0-11)


タグ:音楽 Tone 楽譜
nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。