オーディオ

Emscriptenには、Web Audio APIをバックエンドとして使用する、独自のOpenAL 1.1 API実装が付属しています。

移植されたOpenALアプリケーションは、追加の作業なしで「そのまま動作する」と期待できます。 `-lopenal`リンカーフラグとリンクするだけです。

実装固有の側面がいくつかあり、考慮に値するため、ここに記載します。

警告

以前は、OpenALを使用するためにコンパイラに渡す追加のフラグはありませんでした。ただし、上記のように`-lopenal`を指定することは必須と見なされるべきです(将来的には**必須**になります!)。

サポートされているOpenAL拡張機能

EmscriptenのOpenAL実装では、以下の拡張機能がサポートされています。

  • ALC_SOFT_pause_device;

  • ALC_SOFT_HRTF;

  • AL_EXT_float32;

  • AL_SOFT_loop_points;

  • AL_SOFT_source_length;

  • AL_EXT_source_distance_model;

  • AL_SOFT_source_spatialize;

警告

これは、これらの存在を当然のことと考えるべきという意味ではありません! 正確性を期すために、優れたアプリケーションと同様に、拡張機能を使用する前に**常に**サポートされているかどうかを確認する必要があります。

Emscriptenでのオーディオのガイドライン

オーディオ処理を実行するには、アプリケーションがJavascriptメインループに制御を渡す必要があることに注意してください(ブラウザメインループを参照)。簡単に言うと、この種のコードは無期限にブロックされます

while(nframes < THE_NUMBER_OF_FRAMES_WE_WANT)
    alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, 1, &nframes);

上記のコードスニペットは、ほとんどのOpenAL実装が1つ以上の個別のスレッドを所有および管理しているため、通常はネイティブアプリケーションで機能します。Emscriptenでは**そうではありませ**ん。代わりに、このようなクエリを「メインループの反復」(つまり、emscripten_set_main_loop()またはemscripten_set_main_loop_arg()を介して提供するコールバック)ごとに1回だけ実行する必要があります。

発生する可能性のあるもう1つの問題は、ブラウザがユーザー入力の前にオーディオの再生を許可しないことです。これにより、ページがメディアを自動再生することを防ぎます。これは、意図しない場合に煩わしい場合があります。EmscriptenのOpenAL実装(およびSDL1)は、ドキュメントとキャンバスでのユーザークリックまたはキー押下を自動的にリッスンし、オーディオを再開します。つまり、ユーザーがページ上で何かを実行すると、オーディオの再生が開始されます。(内部的な動作については、`autoResumeAudioContext()`を参照してください。)

Emscripten固有のキャプチャ動作

ユーザーのオーディオキャプチャデバイスへの入力ストリームを開こうとすると、ユーザーの許可を求める小さなブラウザ固有のダイアログが非同期で表示され、一部のブラウザでは、選択するキャプチャデバイスが表示されます。

これを念頭に置いて、有効でサポートされているパラメータを使用して`alcCaptureOpenDevice()`が呼び出されると、「プロキシ」デバイスが返されます。ユーザーが上記のダイアログで「許可」をクリックするまで、サンプルは正常にキャプチャされません。

つまり、`alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, 1, &nframes)`を呼び出すと、ユーザーが「許可」をクリックするまで、`nframes`はゼロに設定されたままになります。 アプリケーションがこの特定の動作を処理するようにする必要がある場合があります。

ユーザーが「拒否」をクリックすると、デバイスは無効化されます(これは物理デバイスを取り外すのと似ているため)、そのデバイスで`alcCapture*`関数を呼び出すと、`ALC_INVALID_DEVICE`で一貫して失敗します。 アプリケーションはこの問題を適切に処理できるように準備する必要があります。

注記

一部のブラウザはこの選択を「記憶」し、再度質問されるたびに自動的に適用します。実装がこの動作を検出する方法はありません。

OpenALキャプチャの実装に関する役立つ詳細

内部的には、Web Audioのキャプチャデータは常にJavascriptの`Float32Array`によって裏付けられています。したがって、`AL_FORMAT_MONO_FLOAT32`と`AL_FORMAT_STEREO_FLOAT32`は、取得したサンプルを初期タイプから別のタイプに変換する必要がない唯一の形式です。

また、デバイスからサンプルが取得される実際のサンプルレートは、現在、ユーザーコードではなく、ブラウザとハードウェアによって決定されます。このサンプルレートがアプリで要求したものと一致しない場合、実装はユーザーに代わってリサンプリングを実行する必要があります。

そのサンプルレートは`audioCtx.sampleRate`によって与えられます。ここで、`audioCtx`は関連するキャプチャ`ALCdevice`によって内部的に使用される`AudioContext`オブジェクトです。現在、Emscriptenはアプリケーションがこの値に直接アクセスする方法を提供していませんが、これはEmscripten固有のOpenAL拡張機能を通じて提供される可能性があります(まだ登録が必要なため、ここでは提供されていません)。

ただし、現時点では、これを行うための迅速かつ*事実上*信頼できる方法があります(Cの例)

#ifdef __EMSCRIPTEN__

#include <emscripten.h>

// Avoid calling this more than once! Caching the value is up to you.
unsigned query_sample_rate_of_audiocontexts() {
    return EM_ASM_INT({
        var AudioContext = window.AudioContext || window.webkitAudioContext;
        var ctx = new AudioContext();
        var sr = ctx.sampleRate;
        ctx.close();
        return sr;
    });
}
#endif

このサンプルレートは44100Hzまたは48000Hzのいずれかであると予想されます。興味がある場合は、javascriptの部分をブラウザのコンソールにコピーして、すぐにテストできます。

実装の改善と拡張

現在、OpenALキャプチャ実装は、単純であり、品質のわずかな低下は許容できると見なされたため、単純な線形リサンプリングを実行します。

ただし、ご希望であれば、貢献してこれを改善していただければ幸いです!たとえば、この問題を参照してください。

同様に、特定の拡張機能(登録されているかどうかにかかわらず)を実装したい場合は、問題を報告する(この問題に関連する以前の問題が存在しない場合)か、貢献するのが最善の方法です!ガイドラインについては、貢献を参照してください。