おもちゃラボ

Unityで遊びを作ってます

【Arduino】WAVまたはMP3ファイルを再生する

PCなどと接続せず、Arduino単体で音を鳴らしたい場合、WAVやMP3の音源ファイルをSDカードにもつか、またはArduinoのフラッシュにおさめておく必要があります。

f:id:nn_hokuson:20170901092737j:plain

ここでは、小さな効果音などの比較的小さな音声ファイルを使うことを想定して、SDカードを使わずArduino単体で完結する音の鳴らし方を紹介します。

音声ファイルをテキストデータに変換する

「WAVまたはMP3ファイルを再生する方法」と書いておきながら、いきなりフォーマットを変換しちゃいます(笑)最近流行りのMP3ファイル鳴らす鳴らす詐欺と言われても仕方がない・・・

フォーマット変換にはAudacityとコマンドラインを使います。Audacityは高機能なフリーの波形編集ソフトです。こちらからダウンロードしてください。

audacity.softonic.jp

このAudacity、非常に高機能なんですが、今回はほぼファイルフォーマットの変換のみに使います。ピッチャー登場、ただしピッチングマシーン使用、みたいな。

使用したいWAVファイルまたはMP3ファイルをAudacityで開いたら、メニューバーから「トラック」→「ステレオからモノラルへ」を選択し1chのオーディオファイルに変換します。

f:id:nn_hokuson:20170901075236j:plain

現在、サンプリング周波数が44100Hzになっていると思います。これではファイルサイズが大きすぎるので、サンプリング周波数を8000Hzに変更してください。

f:id:nn_hokuson:20170901075325j:plain:w400

最後にフォーマットを指定してファイルを書き出します。メニューバーから「ファイル」→「オーディオの書き出し」を選択し、ファイルタイプなどを次のように設定してください。

項目 設定値
ファイルタイプ その他の非圧縮ファイル
ヘッダ RAW(header-less)
エンコーディング Unsigned 8-bit PCM

設定後の画面は次のようになりました。

f:id:nn_hokuson:20170901075429p:plain:w300

音声ファイルをテキストに変換する

Audacityで書き出したRAW形式の音声ファイルを、テキストデータに変換します。音声ファイルはバイナリ形式のため、xxdコマンドで出力します。

 xxd -i sample.raw

xxdコマンドは「-i」オプションを付けることでC言語の配列形式でデータを出力してくれます。超便利ですね〜!

出力結果は次のようになりました。

const unsigned char sample_raw[] = {
  0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80,
  0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80,
  0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f,
  0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80,

・・・・・・

  0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
  0x80, 0x80, 0x7f
};
unsigned int sample_raw_len = 1200;

Arduinoに音声でデータを書き込む

最後に、いま作成した音声データをArduinoに書き込み、再生するプログラムを作ります。Arduinoのプロジェクトを作成し、次のプログラムを入力してください。

const unsigned char sample_raw[] PROGMEM = {
  0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80,
・・・・・・
  0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
  0x80, 0x80, 0x7f
};
unsigned int sample_raw_len = 1200;

void setup() 
{
  pinMode(3, OUTPUT);
  TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  TCCR2B = _BV(CS20);
  
  play();
}

void play() {
  for (int i = 0; i < sample_raw_len; i++) {
    OCR2B = pgm_read_byte_near(&sample_raw[i]);
    delayMicroseconds(125);
  }
} 

void loop() {
}

ここでは、音声データの配列をコピペしてグローバル変数として宣言しています。配列を宣言するときに、配列の先頭に「PROGMEM」とつけるのを忘れないようにしてください。

この「PROGMEM」はデータをSRAMではなくフラッシュメモリに置くための指定子です。

音声データは比較的データサイズが大きいため、SRAMには入り切らないことが考えられます。そこで容量的に余裕のあるフラッシュメモリに音声データを置くようにします。

Arduinoでは、フラッシュメモリであれば32KB程度あるので、効果音程度なら5個くらい置くことが出来ます。

d.hatena.ne.jp

setup関数内では出力ピン及びPWMの設定を行い、play関数では音声データを1つづつ読み出し出力しています。8000Hzでサンプリングしているので、サンプリング間隔は1秒/8000=125usになります。そこで、1データぶん再生する毎に、delayMicroseconds関数を使って125usの間スリープしています。

ハードウエアを作る

今回、ハードウエアの構成は非常に簡単で(そりゃ、部品がスピーカしかないからな)、スピーカをArduinoの3番ピンとGNDに接続するだけです。

f:id:nn_hokuson:20170901091713p:plain

接続できたら、Arduinoにプログラムを転送してください。転送後リセットボタンを押して、音がなれば成功です!

f:id:nn_hokuson:20170901092728j:plain

まとめ&参考

この記事ではArduinoを使ってWAVファイルまたはMP3ファイルを再生する方法を紹介しました。長い楽曲ファイルには使えない方法ですが、効果音など短いサウンドはArduinoだけで完結する方法なので、結構便利ですよ!

qiita.com