BONXを支える音声信号処理開発のウラガワ
皆様はじめまして、BONXで技術顧問をやっている粟飯原と言います。BONXでは、開発領域では音声信号処理アルゴリズム開発とVoIPシステムに関するソフトウェアレベルでの音声通話品質向上だったりが主ですが、他いろいろやってます。技術顧問という肩書を頂いては居ますが、VoIPサーバをgolangで書いたり、組み込み向けの音声処理ライブラリをC++で実際に書いてます。
BONXは、御存知の通りアウトドアにかぎらず複数人で行う様々なアクティビティをより楽しくするためのコミュニケーションツールとして、ウェアラブルトランシーバとそれに付随するアプリケーションの開発を行っています。今回は、その中でもBONXを支える技術の一つである、音声信号処理アルゴリズムの開発過程をまとめさせて頂きます。
BONXと音声信号処理
BONXは、アウトドアスポーツ等を行っている間に利用するトランシーバーであるので、通常のトランシーバーと異なり、ボタンを押してから話し始めると言うのではなく、人の発話を自動的に検知して手による操作をなしに会話が出来る(自動発話検知)ということがkey featureの一つとなっています。(接客等の周囲の人間と会話しつつ、離れた人とも会話したいというユースケース向けに、ボタンを押して音声送信を始めるPush-to-talkモードでも利用可能です。)
BONXのユースケースは、メインとなるアクティビティの補助であるので、電話と異なって常に会話を行うというものでもありませんし、利用シーンとして周辺環境の騒音が大きい場所で利用することになります。一般的な電話機なんかでも発話検出やノイズ除去の機能を持ったチップは乗っていたりするのですが、もともと想定されているユースケースが異なるのでそのまま使えるわけではありません。
BONXを利用している間、会話自体はまれにしかしないのに常に音声を送信し続けてしまうと非常に耳障りなだけではなく、電話代・パケット代が大変なことになってしまいますので、UXだけではなくコスト的にも非常に重要な機能となっています。
また自動発話検知を実現するために、アプリケーションレベルの様々なアルゴリズムの適用だけではなく、ハードウェアレベルの音質向上の取り組みや、ファームウェアレベルの音響調整と音質向上のためのセッティングなども同時に進める事になります。
発話区間検出
BONXにおける音声信号処理アルゴリズム開発
BONXでの音声信号処理アルゴルズム開発以下のような流れで今に至っています。
- 標準的なセッティング
- 実地テスト・ユーザからの要望が上がる
- アクティビティ中の生音の収集
- 集めた生音でPython + Jupyter Notebookによるアルゴリズム検討
- モバイル向け実装の開発
- ファームウェアの最終チューニング
- 実地テストという名の社内アウトドアイベント
- 2に戻る
基本的には、一般的なWebサービス等のプロダクトにおけるUI/UX改善のデータ分析業務と同じようなものだと思っていますが、体験が音声会話であり、扱うデータが音声であること
という部分に特殊性があると思います。
標準的なセッティングの実施
BONXは、Bluetoothヘッドセットデバイスと、スマートフォンアプリを連携させて初めて真価を生むプロダクトです。音声信号処理についても、まずハードウェアレベルでの前処理が上手く動いているお陰で、アプリケーション側だけでは実現不可能なノイズ除去や発話検出を実現しています。
ハードウェアチップには標準音響処理エンジンが入っているのでマイクの配置の調整と、ビームフォーミングによる口元の音声の強調や、定常ノイズの除去とイコライジング等のセッティングを実施します。それの設定によって音の質(スペクトルの分布や波形の歪み)が変わってきますので、その音声に合わせて、パラメータを調整した発話検出のための標準的なアルゴリズムを実装して、まず(社内)リリースを行いました。
実地テスト・ユーザからの要望が上がる
しかし、いざ(社内)リリースしてみると、ランニング中の息遣いが荒い時うるさいからなんとかしてほしい
であったり、スケボーでオーリーした時の衝撃音を無視したい
、特定の音が耳に刺さる
等のいろんな要望が上がってきます。
音響的なものについては、社内にいるプロのオーディオエンジニア
の方にハード・ソフト両面に色々処理を追加してもらうのですが、デザイン性もプロダクトの価値として非常に重要であるので、S/N比を稼ぐためにマイクを口元に持ってこれない以上、音声信号処理のレイヤーで頑張るしか無いので、やることはとにかくなんでも試す必要がありました。
アクティビティ中の会話の生音を集める
定性的な感想から、実際にその環境を再現して音データを見ないと行けないわけですが、再現するとなると実際にアクティビティをやって音を集めてこなければなりません。マイク(ハードウェア特性)、空間特性、環境音、声によって音は変わってくるのでとにかく体当たりで集めに行くのが一番はやいです。
自分自身も、オフィスの近くの駒沢公園をランニングしながら、自分のブレス音と環境音を録音してみたり、やったことのないスケボーを自分でも初めて、スケートパーク内でスケートしながらボードが立てる騒音を録音してみたりしています。もちろん、他の社員も日常的に山に行ったり釣りに行ったりするので、録音アプリを持たせて直してほしかったら音取ってこいやととにかくいろんな環境音を集めています。
Python + Jupyter Notebookによるアルゴリズム検討
検証用の音声が集まったあとは、普通のデータ分析仕事と同様、Python + Jupyter Notebookを用いてインタラクティブにアルゴリズム検証を行います。Pythonには、numpy、scipyといった基本的な数値計算のためのものから、音楽分析と可視化用のlibrosaや、音声分析のためのpysptk,等音声信号処理アルゴリズムの検証を低コストで回す環境は一通り揃っています。音声データをスペクトルの可視化等をしながら検証出来るのはとても効率的です。
また、個人的にも、これまでの数年間の中で、音声信号処理に関する研究開発の仕事もやってきていますので、そのための検証や、ノイズ除去アルゴリズム等の基本的な実装をまとめています。
直接BONXの製品に入っているアルゴリズムが入っているわけではないのと実装的に動かないものもあるのであくまでご参考まで。
モバイル向け実装の開発
アルゴリズムが固まったら、スマートフォン上で実行出来るようにC++で再実装します。この部分は特に話すことは無いのですが、iOS/Android両方で利用出来るように、C++による共通実装をライブラリ化して開発しています。
リアルタイム性が求められるアプリケーションであり、計算遅延の発生は許されないため、メモリアロケーションを最小限にすると言った基本的な高速化から、ARMのSIMD拡張であるNEONを利用するなどの効率的な実装が求められます。iOSだけであればAccelerate Framework(vDSP)があるので、そこまで頑張らなくても十分早くなったりするのですが共通化を目指すと組み込み系素人にはなかなかにハードルの高い取り組みでした。
実地テストという名の社内アウトドアイベント
ある程度機能が固まり、録音音声での検証が済むと、最後は実地検証として実際にBONXを試す会を実施します。業務
なのでスノボや釣り等のアウトドアアクティビティへ繰り出すしかないのです。
この写真は、深夜にまったく明かりが無い、坊岬の沖合2kmぐらいで腰まで海に浸かってウェーディングをしたときの様子です。初めてのウェーディングという環境で、同僚と二人で数百メートル離れて釣りをしていたのですが、風速15mぐらいの風が吹いていても手を使わずに話した分だけ音声が届いて、初心者でも同行者の手をあまり煩わせずウェーディングを楽しむことが出来ました。。このシチュエーションはハンズフリーで長時間会話出来るソリューションが無いとかなり不安になるような環境だったので、そこで安定して動作をしたの確認できて非常に安心したというリリース前ギリギリの話でした。
大体は、こんな音絶対非発話として判定できねーよ
となって打ちひしがれることが多いので、上手く行ったときの喜びは一入であります。
おわりに
BONXにおける音声信号処理アルゴリズムの開発プロセスについてまとめさせていただきました。まだまだ問題は出ているプロダクトでありますが、Dogfoodingを厭わないチームとして動いています。End-to-Endでのアルゴリズム開発からアプリへの適用、そしてそれをリリースしたプロダクトで自分たちを含めたアウトドアスポーツを楽しむ人達の趣味がより楽しくなるという素晴らしい環境であると思うので、音声信号処理の仕事としては非常に楽しいプロダクトだと思います。
golangでVoIPシステムを書いたり音声信号処理の基盤ライブラリを書いたりする仲間はいつでも探してますのでよろしくお願いいたします(そもそも音声信号処理の組み込みライブラリをベンチャーで書いてる人がいればいろいろ話聞きたいのでそれはそれで仲良くしてください)。