デジタルノイズジェネレーターの仕組み

基盤:疑似乱数生成

WhiteNoise.top のノイズエンジン構築において、数学的ランダム性を説得力のあるオーディオに変換するパイプラインの最適化に数百時間を費やしてきました。すべてのデジタルノイズジェネレーターは同じ基本コンポーネントから始まります:疑似乱数生成器(PRNG)です。PRNGは、統計テストに基づいてランダムに見える決定論的な数列を生成するアルゴリズムです。ハードウェアエントロピー源からの真のランダム性はリアルタイムオーディオには遅すぎて予測不能であるため、PRNGがすべてのデジタルノイズ生成の実用的な基盤を提供します。

オーディオ作業に適した最も基本的なPRNGは線形合同生成器(LCG)で、前の値の線形関数として各値をモジュロ大定数で計算します。高速ですが、LCGには既知の弱点があります:連続するサンプル間の相関がノイズ信号で可聴アーティファクトを生じる可能性があります。初期のプロトタイプでは単純なLCGを使用し、高品質のヘッドフォンで聴くとかすかな周期的パターンが聞こえました。FFT分析で狭いスペクトルピークとして現れ、PRNGの統計的弱点がオーディオ領域に漏洩していることが確認されました。

製品品質のノイズ用にxorshift128+アルゴリズムに切り替えました。これはほとんどのJavaScriptエンジンがMath.random()で内部的に使用するPRNGです。2の128乗マイナス1の周期を持ち、優れた統計特性と無視できる計算コストを備えています。TestU01ランダム性テストバッテリーを実行すると、SmallCrushとCrushスイートのすべてに合格します。結果は可聴アーティファクトのないノイズ信号で、可聴範囲全体で0.3 dB以内のフラットスペクトルが検証されます。

乱数からオーディオサンプルへ

PRNGは数値を生成しますが、オーディオシステムには特定の振幅とサンプルレートでの波形サンプルが必要です。変換プロセスにはスケーリング、分布整形、バッファ管理が含まれます。私の実装ではPRNGが符号なし32ビット整数を出力し、それをマイナス1からプラス1の範囲の浮動小数点値に正規化します。これは Web Audio API やほとんどのオーディオフレームワークにおけるデジタルオーディオの標準振幅範囲です。

ランダム値の分布はノイズの特性に影響します。均一分布(範囲内のすべての値が等しく確率的)は、アナログ回路の熱ノイズを特徴づけるガウス分布とはやや異なる振幅分布のノイズを生成します。実際には違いは微妙で、均一ホワイトノイズのクレストファクターは約4.8 dBですが、ガウシアンホワイトノイズのクレストファクターは理論上無限大ですが、実際には典型的なバッファ長で約12 dBです。ほとんどの用途では均一分布で十分であり、計算上もより簡単です。

振幅統計が重要なアプリケーション向けにガウス分布ノイズが必要な場合は、Box-Muller変換を使用します。これは均一分布の乱数ペアをガウス分布の値ペアに変換します。計算オーバーヘッドは穏やかで、サンプルあたりのコストが約2倍になりますが、結果はアナログノイズ源の振幅統計により近いノイズ信号です。リスニングテストでは、均一とガウシアンホワイトノイズの違いはほぼ聞き取れませんが、ガウシアンバリアントは振幅統計が重要な特定の信号処理アプリケーションでより優れた性能を発揮します。

スペクトル成形:ホワイトをカラーに変換

ホワイトノイズは他のすべてのノイズカラーが作られる原材料です。変換はデジタルフィルタリング、つまりホワイトノイズスペクトルに周波数依存のゲインカーブを適用することで行われます。ノイズエンジンでは、IIR(無限インパルス応答)とFIR(有限インパルス応答)フィルターの両方を使用してスペクトル成形を実装しており、それぞれに独自の利点があります。

ピンクノイズ(オクターブあたりマイナス3デシベルの傾斜)には、主な方法としてVoss-McCartney アルゴリズムを使用しています。このアルゴリズムは異なるレートで更新される複数の独立した乱数生成器を維持します。出力を合計して理想的なピンクノイズの傾斜を近似する信号を生成します。実装では16のオクターブレイヤーを使用し、1 Hz以下から20 kHz以上まで正確なスペクトル成形を提供します。理想的な傾斜に対する誤差は可聴範囲全体で0.5 dB未満です。

ブラウンノイズ(オクターブあたりマイナス6デシベルの傾斜)には、単純な積分を使用します。各出力サンプルは前の出力と新しいホワイトノイズサンプルの合計にスケール係数を乗じたものです。数学的にはこれは1に非常に近いポールを持つ1次IIRローパスフィルターです。このアプローチの課題はDCドリフトです。累積和は時間とともにゼロから大きく離れ、最終的にクリッピングしきい値を超える可能性があります。5 Hzの非常に穏やかな1次ハイパスフィルターを追加してドリフトを制約し、20 Hz以上のスペクトルに可聴的な影響を与えることなく解決しています。

上級ユーザーが要求するカスタムスペクトル形状には、カスケード接続された2次バイクワッドフィルターセクションで構築されたパラメトリックイコライザーを使用します。各セクションはユーザー調整可能な周波数、ゲイン、帯域幅パラメーターを持つ標準フィルタータイプ(ピーク、ローシェルフ、ハイシェルフ、ノッチ)を実装します。4~6セクションを連結することで、穏やかな傾斜から複雑なマルチバンドの輪郭まで、ユーザーが望むほぼすべての滑らかなスペクトル形状を近似できます。

Web Audio API によるリアルタイム生成

すべての最新ブラウザで利用可能な Web Audio API は、サーバーサイド処理なしでリアルタイムにノイズを生成し再生するためのインフラストラクチャを提供します。WhiteNoise.top の実装では、AudioContext、ScriptProcessorNode(またはその後継であるAudioWorkletNode)、BiquadFilterNodeの3つの主要な Web Audio API コンポーネントを使用しています。

AudioWorkletNodeがコア生成の場所です。ブラウザのメインスレッドとは別のスレッドで動作するカスタムAudioWorkletProcessorを登録し、UIインタラクションがオーディオグリッチを引き起こさないようにしています。プロセッサのprocess()メソッドは出力バッファとともに繰り返し呼び出されます(通常44.1 kHzで128サンプルごと)。このメソッド内でPRNGを使用してホワイトノイズサンプルを生成し、スペクトル成形を適用し、結果を出力バッファに書き込みます。パイプライン全体は最新のハードウェアでバッファあたり約0.01ミリ秒で実行され、グリッチのない再生のための約3ミリ秒の期限を十分に下回ります。

バッファ管理は可聴アーティファクトの回避に不可欠です。プロセッサがバッファを時間内に埋められない場合、オーディオ出力がアンダーランし、クリックやポップが発生します。ストレステストでは、メインスレッドに計算負荷(大規模なDOM操作や大きなJSONの解析など)を追加し、オーディオワークレットスレッドがバッファの配信を時間内に続けることを検証します。AudioWorklet APIが提供するスレッド分離はこの堅牢性に不可欠です。古いScriptProcessorNodeはメインスレッドで動作し、重いJavaScript実行中にグリッチが発生しやすかったのです。

Web Audio API の組み込みBiquadFilterNodeを使用して標準タイプのフィルターでスペクトル成形も行います。これらのノードは最適化されたネイティブコードで実装されており、同等のJavaScript実装よりも大幅に高速です。よりシンプルな構成でのピンクノイズ生成には、慎重に選択された周波数とQファクターを持つローパスフィルターとして構成された複数のBiquadFilterNodeをカスケード接続し、理想的なオクターブあたりマイナス3デシベルの傾斜を近似します。

最適化と実用上の考慮事項

パフォーマンス最適化はリアルタイムオーディオ生成において継続的な課題です。品質を犠牲にすることなく効率を最大化するため、いくつかの技法を実装しています。最初は事前計算です。動的に変化しないノイズカラーについては、初期化中に大きなバッファ(通常44.1 kHzで10秒、441,000サンプル)を生成し、再生中にループします。ループが聞こえないようにするため、ループ境界でクロスフェードを使用し、レイズドコサイン窓を使用してバッファの最後の4,096サンプルと最初の4,096サンプルをブレンドします。結果のループは知覚的にシームレスです。

2番目の最適化はJavaScript内でのSIMDスタイル処理です。AudioWorkletコンテキストではJavaScriptが明示的なSIMD命令を提供しませんが、内部ループを4サンプルずつのグループで処理するように構成し、JavaScriptエンジンのJITコンパイラが自動ベクトル化を適用できるようにしています。ベンチマークでは、ブラウザエンジンに応じて1サンプルずつの処理と比較して15~25%の速度向上が得られます。

3番目の考慮事項はメモリ管理です。オーディオ処理中のメモリ確保と解放はガベージコレクション一時停止を引き起こす可能性があり、可聴グリッチの原因となります。初期化中にすべてのバッファを事前確保し、セッション全体で再利用します。process()メソッド内ではオブジェクトを作成せず、すべての中間値は事前確保された型付き配列に格納されます。この規律によりGC関連のオーディオアーティファクトが完全に排除されます。

消費電力も、特にモバイルデバイスにとって実用的な懸念事項です。スマートフォンでのテストでは、単純なノイズジェネレーターのCPU負荷は通常1%未満で無視できることがわかりました。しかし、オーディオ出力をアクティブに保つとデバイスがディープスリープ状態に入るのを防ぎ、長時間のセッションでバッテリーを消耗する可能性があります。ユーザー指定の時間後にジェネレーターを停止するタイマー機能を提供し、ブラウザタブがフォアグラウンドにないときにPage Visibility APIを使用して生成を一時停止することで軽減しています。

ジェネレーター出力品質の検証

ノイズジェネレーターの価値はその出力品質にかかっており、品質は客観的な測定で検証されなければなりません。品質保証プロセスでは、ユーザーにリリースする前にすべてのジェネレーター構成を自動テストスイートで実行しています。最初のテストはスペクトル平坦性です。60秒間のホワイトノイズサンプルをキャプチャし、平均FFTマグニチュードを計算し、いかなる周波数ビンも平均から1 dB以上逸脱していないことを確認します。成形ノイズについては、測定されたスペクトルをターゲットカーブと比較し、偏差が0.5 dB未満であることを検証します。

2番目のテストは振幅分布です。サンプル値のヒストグラムを計算し、Kolmogorov-Smirnovテストを使用して期待される分布(均一またはガウシアン)と比較します。0.05を超えるp値は、分布が95%信頼レベルで期待される形状と一致していることを示します。

3番目のテストは周期性の検出です。10秒間のサンプルの自己相関関数を計算し、いかなる非ゼロラグもその長さのランダムプロセスの理論的最大値を超える相関係数を持たないことを確認します。PRNGの周期的パターンは、たとえ可聴でなくても自己相関関数のピークとして現れ、信号処理アプリケーションで問題を引き起こす可能性のあるジェネレーターの欠陥を示します。

最後に、ヘッドフォンを使用した主観的リスニングテストを実施し、クリック、ポップ、トーナルアーティファクト、長時間再生中のレベルや音色の変動をチェックします。自動テストでほとんどの問題を検出できますが、人間の耳がオーディオ品質の究極の審判であり続けます。プラットフォームで公開する前にすべてのジェネレーターバリエーションを個人的に聴くことを徹底しています。

参考文献

よくある質問

デジタルノイズジェネレーターは本当にランダムな出力を生成できますか?

いいえ。デジタルノイズジェネレーターは決定論的な数列を生成する疑似乱数生成器(PRNG)を使用します。しかし、適切に設計されたPRNGは、すべての実用的なオーディオアプリケーションにおいて真のランダム性と統計的に区別できない出力を生成します。

Web Audio API が ScriptProcessorNode ではなく AudioWorklet を使用するのはなぜですか?

AudioWorkletはブラウザのメインスレッドとは別のスレッドで動作し、UI操作がオーディオグリッチを引き起こすのを防ぎます。ScriptProcessorNodeはメインスレッドで動作し、重いJavaScript実行中にドロップアウトが発生しやすかったのです。ScriptProcessorNodeは現在非推奨です。

ノイズジェネレーターのクリックやポップの原因は?

クリックやポップは通常、ジェネレーターが出力バッファを時間内に埋められないバッファアンダーランや、JavaScriptのガベージコレクション一時停止によって引き起こされます。適切なバッファ管理とメモリの事前確保でこれらのアーティファクトを排除できます。

ノイズジェネレーターはどのくらいのCPUを使用しますか?

単純なノイズジェネレーターは通常、最新のハードウェアでCPUの1%未満を使用します。主なパフォーマンス上の懸念は、オーディオグリッチを防ぐための一貫したタイミングの維持であり、全体的なCPU負荷ではありません。

リアルタイム生成の代わりにノイズサンプルをループできますか?

はい。ただし、可聴クリックを防ぐためにループ境界にクロスフェードを適用する必要があります。44.1 kHzで約4,096サンプルのレイズドコサインクロスフェードにより、知覚的にシームレスなループが作成できます。

Leo Chen

Leo Chenはツール開発者でありオーディオ愛好家です。実用的なオンラインサウンドツールや生産性向上ツールの開発に取り組んでいます。