IoTサービスを支えるエッジデバイスには、特定のイベントをトリガーとして音声データ(WAVやMP3など)を再生する、または周囲の音を収集し音声データとして保存する機能が度々求められます。旧来のシステムではエンコード(音声/オーディオ入力からデータへの変換)やデコード(データから音声/オーディオ出力への変換)専用に設計されたハードウェア・エンジンを搭載することにより、ハードウェア実装のメリットである高い性能を活かしてスムーズな再生/録音機能を実現していました。しかし、IoTサービスのエッジデバイスの場合、常に再生・録音を繰り返さない(特定の条件に合致した時のみ再生・録音する)ため、こうした専用ハードウェアの採用はコストの低減を阻害する、悩ましい課題です。
そこで、今回の初心者講座では、SPRESENSE SDKの提供しているソフトウェア・エンコーダ/デコーダにフォーカス。ソフトウェア・エンコーダ/デコーダの特徴、ASMPアーキテクチャとの高い親和性、使い方を紹介いたします。
目次
ソフトウェア・エンコーダ/デコーダの特徴
WAV形式やMP3形式の音声データを扱うためには、エンコード/デコード処理が必要となります。特に、MP3形式の場合は音声を圧縮して保存しているため、エンコードでは圧縮処理、デコードでは展開処理を高ビットレートのオーディオデータに対して適用しなければならないため、高い演算処理性能が不可欠です。そのため、システムの根幹を担うCPUがエンコードやデコードの処理を担当すると、他の処理を開始できず高いレスポンス性や優れたリアルタイム性の実現が難しくなります。
この課題を解決するため、旧来のシステムではエンコード/デコード処理をハードウェアで実装した「ハードウェア・エンコーダ/デコーダ」を搭載していました。ハードウェア実装のエンコーダ/デコーダは、システムの根幹を担うCPUの使用率を大きく低減することができます。なお、WAVやMP3を扱う処理は定型的なためブロック化し、切り出しやすい機能です(再利用しやすい開発資産です)。
一方、ハードウェア・エンコーダ/デコーダには、WAVやMP3を処理していない間はハードウェアが活用されないという課題があります(図1)。
これらの課題を解決するため、SPRESENSEは汎用CPU(サブコアであるCortex-M4)上でWAVやMP3を処理できる「ソフトウェア・エンコーダ/デコーダ」機能を提供しています。ソフトウェア・エンコーダ/デコーダをサブコア上で実行することにより、システムの根幹を担うメインコアに負荷をかけることなく音声処理を実現。また、サブコアは汎用CPUであるため、WAVやMP3を処理していない間には他のタスクを実行するリソースとして活用することができます(図2)。さらには、SPRESENSE SDKはWAVやMP3のエンコーダ/デコーダをコンパイル済みの実行ファイル形式(ELF形式)として提供しているため、ソフトウェア・エンコーダ/デコーダの開発工数を必要としません(図3)。
SPRESENSE SDK同梱の音声データのエンコーダ/デコーダ
ファイル名 | 提供する機能 | 形式 |
MP3DEC | MP3オーディオの再生処理 | ELF形式(実行ファイル形式) |
MP3ENC | MP3オーディオの録音処理 | ELF形式(実行ファイル形式) |
SRC | WAV、PCMオーディオの録音処理 | ELF形式(実行ファイル形式) |
WAVDEC | WAVオーディオの再生処理 | ELF形式(実行ファイル形式) |
マルチコアを活用し音声を再生・録音する
それでは早速、SPRESENSEのサブコアを使って、WAVやMP3のソフトウェア・エンコーダ/デコーダを実行してみましょう。内部処理は記事後半にて詳解いたします。
必要となる機材
本記事にて扱う音声の録音・再生には、SPRESENSE Main Boardに加えて、オーディオの入出力端子を備えたSPRESENSE Extension Board(図4)、SPRESENSE Extension Boardのマイク入力端子に4chのアナログマイク(WM-61A相当品)を簡単に接続できるAPS学習ボードが必要です。なお、音声はSPRESENSE Extension Boardのヘッドホンジャックから出力されます。
実行するサンプル・アプリケーションの準備
ソースコードの入手
今回はサンプル・アプリケーションとして「APS-Academy(Multicore) #7 Sample Code」を利用します。下記の手順に従ってソースコード一式をPCにダウンロードしてください。
【APS-WEB】初心者講座マルチコア編のWindows開発環境、設定手順のまとめ
# SPRESENSEのgitのリリースリストが表示されます $ git tag -l v1.0.0 v1.0.1 ... v1.4.0.is.4.0 # ソースコードから"1.4.0.is.4.0"という名前のブランチを生成します $ git checkout -b 1.4.0.is.4.0 refs/tags/v1.4.0.is.4.0 Switched to a new branch '1.4.0.is.4.0' # このように切り替わっています $ git branch * 1.4.0.is.4.0 master # 1.4.0.is.4.0の初期状態にリセットします $ git reset --hard HEAD
入手したソースコードのビルド方法
ソースコード入手後、「再生機能」を試す場合はソースコード中の「SPRESENSE」フォルダを右クリックし「SPRESENSE:SDKコンフィグ」-「新規作成」-「Examples」-「audio_player」を選択(図5)、SDKコンフィグを保存した後、「SPRESENSE:アプリケーションのビルド」-「SPRESENSE:ビルドと実行」を実行します。
「録音機能」はソースコード中の「SPRESENSE」フォルダを右クリックし「SPRESENSE:SDKコンフィグ」-「新規作成」-「Examples」-「audio_recorder」を選択(図6)、SDKコンフィグを保存した後、「SPRESENSE:アプリケーションのビルド」-「SPRESENSE:ビルドと実行」を実行します。
audio_playerとaudio_recorderを同時に選択した場合のビルドエラーについて
SDカードの準備
音声データ(再生音源、録音結果)はSPRESENSE Extension Boardに挿入したmicro-SDカードに保存されます。また、SDカードには、事前にソフトウェア・エンコーダ/デコーダの実行ファイルも格納する必要があります。
SDカードをフォーマットする
まず「FAT32形式のSDカード」をご用意ください。
2GB以下のSDカード、もしくは2GB以下のパーティションが作成されているSDカードの場合、FAT16形式でフォーマットされていることがあるため、注意が必要です。SDカードのフォーマットは、Windowsのスタートメニューを右クリック、「ディスクの管理」から確認することができます(Windows10の場合:図7)。
SDカード上にオーディオの再生・録音に必要なファイルを格納する
次に、SDカード上に「再生するオーディオデータ(MP3形式)」「再生リスト(csv形式)」「ソフトウェア・エンコーダ/デコーダの実行ファイル」を格納します。なお、録音するaudio_recorderサンプル・アプリケーションを実行すると「録音したデータ(WAV形式)」がSDカード上に生成されます。以下のリンクから必要なファイル一式を入手し、SDカードに格納してください(格納後、図8のフォルダ構成となるようにしてください)。
- AUDIOフォルダに入れる内容
- PLAYLISTフォルダに入れる内容
- BINフォルダに入れる内容
- RECフォルダは空でも問題ありません(録音データ格納先のため)
JTAG-ICEデバッガの接続(オプション)
JTAG-ICEデバッガとVisual Studio Codeを組み合わせ、実行中のプログラムを追いかけることで、本記事やサンプル・アプリケーションをより深く理解することができます。JTAG-ICEデバッガを利用するには、SPRESENSE Extension BoardのCN1に、JTAG-ICEデバッガ(LPC-Link2)を接続してください。詳細は「SPRESENSEハードウェアドキュメント」をご参照ください。
SPRESENSEハードウェアドキュメント|JTAGデバッガの使用方法
録音データの確認(audio_recorder)
audio_recorderアプリケーションをnshから実行すると、録音が開始され、10秒間録音した後にSDカード上に音声ファイルが保存されます(図10)。
録音されたデータ(WAVファイル)の構造
audio_recorderは、10秒間マイクからステレオ音声(左(L)ch、右(R)ch)を収集、WAV形式の音声データをSDカードのRECフォルダ内に保存するサンプル・アプリケーションです。WAV形式のファイルは、ヘッダ情報が先頭に格納され、その後ろにL(左マイクからの録音データ)とR(右マイクからの録音データ)がペアで記録されている扱いやすいデータ構造となっています(図11)。
ヘッダには下記の情報が保存されています。すべてのフィールドはリトル・エンディアン形式(マルチバイトデータを最下位バイトが先頭として記録する形式)で記録されています。
フィールド番号 | 意味 | 値 |
1 | 固定文字列 | “RIFF” |
2 | 本フィールド以降のサイズ | 0x001C2024 |
3 | 固定文字列 | “WAVE” | 4 | 固定文字列 | “fmt” |
5 | フォーマットのチャンク数 | 0x10(リニアPCM) |
6 | データフォーマット | 0x01(PCM) |
7 | チャンネル数 | 0x02(L+R) |
8 | サンプリング周波数 | 0xDD80 |
9 | Byte/s | 0x02EE00(192kB/s) |
10 | 全チャネルの合計バイト数 | 0x0004(4Byte) |
11 | 1chのビット数 | 0x0010(16bit) |
12 | 固定文字列 | “data” |
13 | 音声データのサイズ | 0x001C2000 |
以降、データ | L(16bit)+R(16bit) | – |
録音データの活用方法
WAV形式のファイルは圧縮されていない単純な構造となっているため、簡単に録音データを加工・解析することができます。もちろん、SPRESENSEのマルチコア構成を活かし、データの加工/解析処理を別のサブコアに担当させることも可能です。
例えば、SPRESENSEに内蔵された高品質なオーディオ入力機能を活用し、微弱な音を録音。LチャンネルとRチャンネル間の相関を解析することにより、音源方向の推定などが可能です。
なお、LチャンネルとRチャンネルのデータそれぞれを別々のサブコア上で解析したい場合、ステレオ形式のデータはLとRのデータが近接しているため、サブコアからのメモリアクセスが衝突し、バスアービトレーション(データ通信バスの調停処理)が発生。期待する性能を得られないことがあります。そのため、スムーズな処理を実現するためには、2個のマイクのデータをモノラル形式として別々のメモリタイルに記録するといった工夫が必要です(図12)。
audio_player|メインコアからサブコア上のデコーダを制御する仕組みを理解する
続いて、サブコア用の実行ファイルがどのように制御され音声処理機能を提供しているのかを、JTAGデバッガのステップ実行を利用し、紹介いたします。
アプリケーションを開始する
audio_playerでは、下記ソースコードによりパラメータを設定しています。実行環境にあわせて調整してください。なお “/mnt/sd0” SPRESENSE Extension Boardに挿入されているmicro-SDカードとなります(非対応SDカードの場合、sd0はSPRESENSE上で非表示となります)。
アプリケーションをビルドしデバッグを開始すると、RTOS(NuttX)のエントリポイントでプログラムが一時停止します(図13)。プログラムを再開し、ターミナルに「audio_player
」を入力し、Enterキーを押すことにより、サンプル・アプリケーションを実行できます。
サブコア上にソフトウェア・デコーダを展開・起動する
プログラム開始後、まず、メインコア側の準備処理(app_init_libraries)により、サブコアと通信するためのメッセージキューやオーディオ処理用のメモリプールなどのリソースを初期化。続いて、サブコア上にて実行するソフトウェア・デコーダの起動処理(app_create_audio_sub_system)によりサブコア上でタスクが開始されます。
app_create_audio_sub_systemにブレークポイントを設定し、ステップイン実行することにより、audio_playerからSDKの提供する機能「AS_CreateAudioManager」が実行されタスクが生成されている様子を見ることができます。
サブコア上のMP3ソフトウェア・デコーダを制御する
上記の処理により、メインコアおよび、サブコア上のMP3データのソフトウェア・デコーダが利用可能な状態となっています。メインコアからサブコアへ再生、停止、音量調整等の処理の依頼はメッセージキューを介して行われます。メインコアからサブコアへのメッセージ送出は、SDKの提供する機能「AS_SendAudioCommand」により解決されます。
SPRESENSE SDK Library | AS_SendAudioCommand
メインコアからサブコアへと制御を依頼できるAPIを下記に示します。これらのAPIの組み合わせによって、WAVやMP3のファイルフォーマットに初めて触れるユーザーでも、短い工数で再生機能や録音機能を備えたIoTエッジデバイスを開発することができます。
static bool app_power_off(void) { AudioCommand command; command.header.packet_length = LENGTH_SET_POWEROFF_STATUS; command.header.command_code = AUDCMD_SETPOWEROFFSTATUS; command.header.sub_code = 0x00; AS_SendAudioCommand(&command); ... static bool app_set_ready(void); static bool app_get_status(void); static bool app_init_output_select(void); static bool app_set_volume(int master_db); static bool app_set_player_status(void); static int app_init_player(uint8_t codec_type, uint32_t sampling_rate, uint8_t channel_number, uint8_t bit_length); static int app_play_player(void); static bool app_stop_player(int mode); static bool app_set_clkmode(int clk_mode);
まとめ
SPRESENSEのサブコアを活用することにより、これまでハードウェア実装が必要とされていた様々な機能をサブコア上で実現。機能が利用されていない間は、別の機能を実行させる、またハードウェアリソースを余らせることなく使い切る「省ハードウェアリソース」のIoTシステムを構築できます。
なお、本記事にて紹介したSonyから提供されているWAVやMP3のエンコーダ/デコーダだけでなく、3rd-Party製の暗号化機能や復号機能、正統性の検証機能といったセキュリティに関する実行ファイルも登場しています。是非ご活用ください。
補足
複数のサンプルアプリケーションを同時にビルドする際の注意点
SPRESENSE SDK開発環境では、ビルドスクリプトにより、メインコア用の実行ファイル(nuttx.spk)は、RTOS(NuttX)も含めて1個のバイナリデータとして生成されます。そのため、SDKコンフィグにて「examples/audio_player」と「examples/audio_recorder」を同時に選択すると、同じ名前のオブジェクト(pool_numなど)が同じ名前空間(MemMgrLite::〜)に2個定義されるため、関数やオブジェクトを一意に特定できずビルドエラーが発生します(図16)。
実際の開発では、関数・クラス・オブジェクト等が同名である必要はないため、録音機能と再生機能を両方含むアプリケーションも実現可能です(図17)。
SONY SPRESENSE
SPRESENSEは、Arm Cortex-M4コア(FPU機能搭載)を6コア搭載したシングルボードコンピュータです。マルチコアによる豊富な演算能力をはじめ、魅力的なペリフェラルを多数搭載しながら、電池のみでも駆動できる超低消費電力な製品です。本格的なエッジコンピューティングを是非ご体験ください。システムの試作はもちろん、PoC、製品化にもご活用いただけます。
開発者向けサイトを見る Switch-Scienceで購入する
APS学習ボード(SPRESENSE™ Extension Board用)
APS学習ボード(SPRESENSE™ Extension Board用)は、初心者講座の内容をはじめ、SPRESENSE SDKの提供するオーディオ入力機能やLCDドライバをはじめとする各種機能を、回路設計をすることなく簡単にお試しいただけるよう開発したAPSオリジナルの評価基板です。Web記事と併せてお楽しみください。
取扱説明書|APS学習ボード Switch-Scienceで購入する(ボード単体) Switch-Scienceで購入する(部品キット)
こちらも是非
“もっと見る” マルチコア|SPRESENSE編
SPRESENSE×Neural Network Console:第4回|推論モデルを最適化し、エッジAIによるオリジナルの音声識別システムを構築する
今回の初心者講座では、SPRESENSEの「ハイレゾオーディオ入力」と「DNNRT機能」により「Neural Network Console」で生成したディープニューラルネットワーク(DNN)の推論モデルを統合。エッジ単体で完結するオリジナルの音声識別システムを構築する技法を解説いたします。
SPRESENSE×Neural Network Console:第3回|オーディオ解析に必要な学習用データを採取し、PC上で学習・推論を実行する
今回の初心者講座では、SPRESENSEに搭載されたハイレゾオーディオ入力を活用し、環境音を録音し、ディープニューラルネットワークによる音声分類に不可欠な学習用データと検証用データを生成する方法について解説します。また、PC上で動作するNeural Network Consoleによって生成した推論モデルをエッジ・デバイスへ統合するために解決すべき課題を紹介します。
SPRESENSE×Neural Network Console:第2回|異常検知に活用できるニューラルネットワークで波形の扱い方を学ぶ
SPRESENSEのDNNRT機能が扱うことのできるデータは画像だけでなく、産業分野を中心に人気が高まっている「異常検知・故障予知」に活用できる加速度センサーや大気圧センサーなどから収集した波形データも解析することができます。さらにSPRESENSEに内蔵されたハイレゾオーディオ録音機能も周辺環境を可聴域の波形データとして記録することができる優れたセンサーとして利用可能です。そこで、今回の初心者講座では、まず簡単な波形データの解析方法を例に、DNNRT機能から波形データを扱うシステムの構築方法について解説。DNNRT機能を活用した製品開発に必要となる技術を紹介いたします。