Arei's blog

図解 Web(JavaScript)で音声処理 in 2023 


これは何?

音声処理をするWebアプリを作る上で、欲しくなる情報をまとめた。

何がしたいの?

音声をマイクで録音したり、ファイルを読み込んだりした音声データを、何らかの音声処理(フィルター)を適用して、その出力をファイルにしてダウンロードできるWebアプリを作りたい。

誰のため?

ざっくりとweb上での音声処理の流れを知りたい人。詳細な使い方は各ドキュメントを参照のこと。

今回の主役

Web Audio API: 音声を読み込み、フィルターを適用し、スピーカーに出力することを司るAPI(https://developer.mozilla.org/ja/docs/Web/API/Web_Audio_API

Media Capture and Streams API: ウェブカメラやマイクといったブラウザの外側に近いメディアを司るAPI。マイク入力と音声ファイル作成に使う(https://developer.mozilla.org/ja/docs/Web/API/Media_Capture_and_Streams_API

図解

凡例

  • → オブジェクトの流れ
  • ⇒ AudioContext内の接続(connect)

補足

動作環境について

fetch()などのファイルを扱う処理はローカル環境だとセキュリティの関係で動作しない。pythonなどでサーバーを立てよう。 

参考 https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

単純なサーバーの立て方

python3 -m http.server

getUserMediaは、セキュリティの都合上、HTTPS環境でないと使えない。ローカルで試したいときはオレオレ証明書+python HTTPSサーバーを使おう

参考 https://www.lifewithpython.com/2021/03/python-https-server.html

Web Audio APIについて

フィルターとフィルターをモジュラーケーブルでつないで音を作るアナログシンセサイザーをイメージするとわかりやすい。

AudioContextというシンセサイザーの中で、入力(AudioSourceNode)からいくつかのフィルターのためのノード(ConvolverNodeなど)を経由して、出力(AudioDestinationNode)へと繋ぐ(connect)ことで、音が流れる

ConvolverNodeのバッファーも音声ファイルと同様な形で読み込む。ここで読み込む音声ファイルとは、有限インパルス応答フィルタのデータのことで、平たく言えば、コンサートホールで手を1回打ったときの反響音を録音したもの。これを入力音声とたたみ込み(と言う名前の積分)することで音声に様々なフィルタをかけることができる。私の場合は、SOFAファイルから得られた頭部伝達関数になるんだけど、この話はまたいつか。

Media Capture and Streams API について

MediaStreamの管轄するオブジェクトはEventTargetを継承している。そのため、stopやdataavailableなどといったイベントを持っている。これらを使って動作を制御できる。

同期・非同期処理について

fetch()などの処理は、時間がかかる。

JavaScriptの環境では、時間がかかる処理を行う関数はPromiseという”約束手形”を返すようになっている。

var file = fetch(url);
console.log(file);  // Promise{..}

そのため、受け取ったはずの現金(実は約束手形)をすぐに使おうとすると型エラーが出る。

var file = fetch(url);
file.arrayBuffer();  // Uncaught TypeError: file.arrayBuffer is not a function

解決方法は単純に、金が用意されるまで、ドアを叩いて待っていればいい。

呼び出す元の関数にはasync(非同期)、呼び出す関数にはawait(待つ)だ。

async function getArrayBuf(url) {  // awaitを使う関数ではasyncを使う
  var file = await detch(url);
  return file.arrayBuffer();  // 今度はエラーは出ない。
  }
  
var buf = awaitgetArrayBuf(Url);  // 関数を呼び出すときもawaitをつける

欠点は、ドアの前で張り付きになってしまうことで、この間JavaScriptインタプリタは他のことができない。そのため、ページの描画やUIの反応を止めてしまうことだ。

そこでPromiseにはthenやらresolveなど、現金が用意できたときの処理を書いて置くための仕組みが存在する。しかし、私はいまいち使いこなせないため、説明しない。


投稿日

カテゴリー:

投稿者:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です