おもちゃラボ

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

【Blender】ボーンヒートウエイトのエラーが出たときに試す5つの解決策

Blenderでキャラクタにリグを入れる場合、最後にボーンとキャラクタのメッシュを選んで「Ctrl+P」→「自動のウエイトで」を選択しますね。

nn-hokuson.hatenablog.com

Rigfyを使っていても、この手順は同じです。

nn-hokuson.hatenablog.com

このとき、キャラクタのメッシュが複雑だと「ボーンヒートウェイト:一つ以上のボーンで解決に失敗しました」というエラーが出ることが度々あります。英語版の場合は「Bone heat weighting: failed to find solution for one or more bones」とエラーが出ます。

f:id:nn_hokuson:20170830194353p:plain:w400

度々のエラーが頻繁にエラーに変わり、だんだん鬱陶しくなってきたので、解決策をちゃんと調べてみました。

重複頂点を削除

編集モードでキャラクタの頂点をすべて選択して、「Wキー/重複頂点を削除」を選択します。これで、メッシュ中で重複している頂点を削除できます。

f:id:nn_hokuson:20170830194409p:plain:w220

ボーンの拡縮を適用

オブジェクトモードでボーンを選択してから、画面下のメニュー「オブジェクト」→「適用」→「回転と拡縮」を選択してください。これを適用することでボーンの回転とスケールがリセットされます。(ただ、なぜこれでボーンヒートウエイトのエラーが直るのかはわかならい・・・・笑)

f:id:nn_hokuson:20170830194428p:plain:w400

メッシュのスムージング

編集モードでキャラクタの頂点をすべて選択して、画面下のメニューから「メッシュ」→「頂点」→「頂点スムーズ」を選択してください。うまくいくことが多いですが、スムージングするため、モデルの形が崩れてしまうのが玉に瑕です・・・

f:id:nn_hokuson:20170830194444p:plain:w400

法線の再計算

編集モードでキャラクタの頂点をすべて選択して、「Ctrl+N」を押してすべての面の法線方向を再計算してください。一度で法線の方向が揃わない場合は、何度か「Ctrl-N」を繰り返してみて下さい。

ちなみに、「Nキー」で表示されるプロパティパネルの「法線」の項目にチェックを入れることで、法線が表示されます。

f:id:nn_hokuson:20170830195441j:plain:w600

細分化曲面モディファイアを適用する

キャラクタのモデルを選択して右側のウインドウから「追加」→「細分化曲面モディファイア」を選択してください。この細分化曲面モディファイアも、ボーンヒートウエイトのエラーには有効なことが多いです。

f:id:nn_hokuson:20170830194537p:plain:w250

ただ、細分化するだけあって、頂点数がかなり増えてしまいます。そこで、増えた頂点は「ポリゴン数削減モディファイア」を使って減らしておきましょう。

【Unity】テクスチャ1枚で立体的な雲を作る

雲と言ってもゲームで使う雲には様々な種類の雲があります。地上から見上げるような雲や、コンバットゲームで使われるような平面上に描画される雲、360度どこからでも立体的に見える雲などがあります。

f:id:nn_hokuson:20170828185548j:plain

Unityでは雲の表現にはSKyboxがよく使われるようですが、ここでは360度どこから見ても立体的に見える雲(Volumetric Cloudを作ってみましょう。

立体的な雲(Volumetric Cloud)の作り方

ボリュメトリッククラウドって・・・名前だけは難しそうですが、作るのは全然簡単です(笑)まずは一枚雲のテクスチャを用意します。

見にくいので背景を黒色にしていますけど、実際は透明です。

f:id:nn_hokuson:20170828185607p:plain:w150

これを立体的な雲に仕立て上げるには・・・雲のテクスチャをパーティクルで放出するだけです。パーティクルは基本的にBillboardで表示されるので、どこからみても雲に見えるというわけです。

ビルボードの説明はこちらの記事を参照ください。

nn-hokuson.hatenablog.com

Particle Systemを使って雲を作る

ヒエラルキーウインドウからCreate -> Create Emptyを選択し、空のオブジェクトを作ります。そのオブジェクトにAdd Component -> Effects -> Particle Systemパーティクルコンポーネントをアタッチしてください。

f:id:nn_hokuson:20170828185640p:plain:w350

次にパーティクルの設定は次のように行いました。設定した項目だけ書いています

項目名 設定値
Start Lifetime 1000
Start Size 40, 80
Start Speed 0
Start Rotation -180, 180
Max Particles 100
Rate over Time 25
Shape Sphere
Sort Mode(Renderer) By Distance

雲のマテリアルを作る

プロジェクトウィンドウで右クリックし、Create → Material を選択します。作成したマテリアルのシェーダを「Particles/Alpha Blended」に変更してください。Particle Textureの欄に雲のテクスチャをドラッグ&ドロップします。

f:id:nn_hokuson:20170828190059p:plain:w350

作成した雲のマテリアルをParticye SystemのRenderer項目の中のMaterialの欄にドラッグ&ドロップして設定します。

f:id:nn_hokuson:20170828185713p:plain:w350

実行して雲の立体感を確かめる

UnityエディタでParticle EffectウインドウのSimulateを押して雲を発生させてください。

f:id:nn_hokuson:20170828185740g:plain:w400

画面をぐるぐると回すと、ちゃんと立体的な雲になっているのがわかりますね〜!

f:id:nn_hokuson:20170828185753g:plain:w400

雲の白さや透明感は、雲マテリアルの色設定から行えます。

f:id:nn_hokuson:20170828185729p:plain:w350

まとめ

ということで、雲のテクスチャ1枚とParticle SystemがあればUnityで立体的な雲を作れることがわかりました!これに環境マッピングを入れたら更にきれいな見た目になるはず・・・これは、また別の記事で〜

f:id:nn_hokuson:20170828191240j:plain