画像や音声データなどのオブジェクトを組み込んで、画像表示させたり、音声を再生したりさせたい!なんて時が、たまにあったりしますよね?
でも、なかなかすんなり動作してくれなくて、いつもドはまりしていました。
ネットで調べてもあまり情報がなく、どうしたらいいんだーと嘆いていました。色々と試行錯誤して辿り着いた方法ですが、もっと効果的でスマートな方法はあるとは思いますが、そんな時のためにここで紹介するバイナリーオブジェクトの組込み方法を参照してください。
やはり、NXPファンなもんで、Kinetisマイコンで確認していきますね。
やりたいこと
音声データのバイナリを組み込みたい。最終的には、I2SにPCMデータとして外部デバイスに音声出力したい。
今回は、オーディオデータを作成し、ARMバイナリイメージに変換し、プロジェクトに組み込むところまでを目指します。
ワークフロー
- 音声は、デモとしてサイン波を作成(フリーツールAudacityを使用)
- 作成したサイン波のバイナリーオブジェクトをARMバイナリーイメージに変換
- Cソースに組込む
要点
- 音声の作成は、フリーソフトのAudacityで簡単に作成できる
- 音声ファイルフォーマットはPCMが必要
- 作成した音声ファイルをARM用バイナリーに変換が必要
- 変換には、object copyを使う
- 変換したバイナリーファイルのセクションの変更が必要
- Cソースへの組込みには、配列として宣言し先頭アドレスへアクセスする
では、行ってみましょう!
音声データ作成
まず、何はともあれ、音声データが無いと始まりません。既に、使用するオブジェクトファイルがある場合は、この項目はスキップしてください。
音声データ作成には、私はフリーで使用できるAudacityを使っています。
音声の取り込みなどは、録音ボタン等で直感的に録音等が可能です。今回は、最終的には正しくI2Sに音声データが転送されるか確認したい(次回以降の記事で紹介)ので、サイン波を作成していきます。
Audacityのダウンロード
Audacityのダウンロードはこちらから↓
Audasityの起動する
起動直後は、トラックが無い状態です。まずは、トラックを作成して音声を生成していきます。
トラックの作成
トラックの分離
サイン波を生成する前に、作成したステレオトラックを一旦分離しておきます。分離すると右、左のチャンネルにそれぞれ異なる周波数のサイン波を作成することができます。
今後、右と左のチャンネルでそれぞれ正しく音声が出力、入力できているか確認する時に、それぞれ異なる周波数にしておくと便利です。
トラックボタン▼をクリックして、続いて”ステレオトラックを分離”をクリック。
トラック分離後はこんな感じです。↓
トーン(サイン波)の生成
いよいよサイン波を生成します。ツールバーのジェネレータからトーンをクリックしてサイン波を選びます。440Hzで残りはままでOKをクリックします。440Hzは、音楽ではラの音ですね。
両方のチャンネルに440Hzが設定されるので、今度は、右チャンネル側をクリックして選択しておき、同様にトーンをクリックして、異なる周波数に設定します。今回は、900Hzに設定します。
サンプリング周波数の設定
サンプリング周波数を設定します。通常44.1kHzで良いでしょう。
ステレオトラックの統合
ステレオのトラックを統合して、ステレオトラックを作成します。
フォーマット設定
PCMフォーマットを設定しておきます。今回は24ビットPCMを選択します。
オーディオの書き出し
オーディオの書き出しは、ファイルのヘッダに色々情報が書き込まれるので、RAWデータを選択して書き出します。ファイル名の拡張子は、そのままでも問題ありません。出力後、.rawに自動的に保存されます。
後は、そのままOKをクリックして終了です。
ARMバイナリーフォーマットへ変換
ARMのバイナリーフォーマットは、32bitリトルエンディアンです。そのため、音声ファイルもこのバイナリーに変換してあげる必要があります。
その変換ツールは、open sourceのobjectcopyが使えます。MCUXpresso IDEをインストールしている場合は、既にobjectcopyがインストールされています。
このobjectcopyは、様々なフォーマット間の変換をしてくれます。
例:
WAV file ⇄ bin
ELF32 ⇄ bin
など
コマンド
objectcopy -I binary -B arm -O elf32-littlearm foo.bin foo.o
-I binary: | –input-target 入力とするファイルのフォーマット(bfdname)を指定します。今回は、binaryと指定します。 |
-B arm: | バイナリーのアーキテクチャを指定します。今回は、armと指定します。 |
-O elf32-littlearm : | 出力ファイルのフォーマットを指定します。ARM Cortex-M向けには、elf32-littlearmが用意されています。 |
セクションの変更
Cソースのプロジェクトに変換したバイナリを組み込むとデフォルトでは.dataセクションに配置されてしまいます。
.rodata(定数領域)にセクションを変更すると良いです。
オプション指定
–rename-section .data=.rodata,alloc,load,readonly,data,contents foo.bin foo.o
foo.binとfoo.oには任意のファイル名で指定します。
今回は、
foo.binに、sine-wave.aiff
foo.oに、sine-wave.o
と指定します。
objcopy実行
出力されたオブジェクトファイルの確認
出力されたオブジェクトの中身を見てみると、、、
readelfを使って出力されたオブジェクトファイルを確認できます。
readelfコマンド
readelf foo.o -h -S
ヘッダ情報とセクション情報を表示します。
objdumpでシンボルテーブルを確認
シンボルテーブルを見ると、.rodataセクションは_binary_sine_wave_raw_start[]でアクセスできることが分かります。
Cソースでは、
extern char _binary_sine_wave_raw_start[];
extern char _binary_sine_wave_raw_size[];
const char *sine-wave = _binary_sine_wave_raw_start;
size_t sine-wave_size = _binary_sine_wave_raw_size;
でアクセスできます。配列の先頭アドレスやサイズでこのオブジェクトにアクセスできるところが重要です。
まとめ
サイン波を生成するには、Audacityが便利です。私は、何かと評価用の音源ソースを生成する時にはよく使用します。
バイナリイメージを変換するには、GNUのフリーツールが使用でき、MCUXpresso IDEをインストールすると付属してくるobjcopyが使用できます。
変換後は、セクション先頭アドレスに配列名でアクセスできます。
たまにバイナリーイメージを組み込みたい時は、参考にしてください。