双2次フィルタで音声の特定周波数をカット、増幅、減衰する [Web Audio API]
Web Audio APIの「双2次フィルタ」(BiquadFilterNode)を使用して音声の特定周波数をカット、増幅、減衰を行います。この双2次フィルタはマイクなどのハウリング対策にも活用可能です。
テスト用の音声は「ドレミファと伴奏」に「130Hzのサイン波」を加えてます。双2次フィルタの使用によってこの音がどうなるかを確認します。
選択 |
(MP3ダウンロード) |
---|---|
波形データ |
フィルタ | 内容 |
---|---|
ローパスフィルタ | 特定周波数より下を通す。それ以上は減衰する。 この例では130Hzとしています。 |
ハイパスフィルタ | 特定周波数より上を通す。それ以下は減衰する。 この例では260Hzとしています。 |
バンドパスフィルタ | 特定周波数の「範囲」を通す。それ以外は減衰。 (未使用) |
ローシェルフフィルタ | 特定周波数より下を増幅または減衰させる。 この例では130Hzでゲインは-40としています。 |
ハイシェルフフィルタ | 特定周波数より上を増幅または減衰させる。 (未使用) |
ピーキングフィルタ | 特定周波数の「範囲」を増幅、減衰させる。 (未使用) |
ノッチフィルタ | 特定周波数の「範囲」を減衰させる。 この例では130Hzとしています。 |
オールパスフィルタ | 全ての周波数を通して位相関係を変える。 (未使用) |
- | |
ローパスフィルタ + ハイパスフィルタ | この例では500-800Hzを通して、それ以外は減衰しています。 |
※ゲインがマイナスは減衰。プラスは増幅です。
※このフィルタの使い方はBiquadFilterNode (MDN web docs)を参照。
ソースコード
<!doctype html> <html> <head> <meta charset="UTF-8"> </head> <body> <video src="biquadfilter.mp3" style="display:none;"></video> <p> <button onclick="play();">再生する</button> <button onclick="stop();">停止する</button> </p> <p style="color:green;;">テスト用の音声は「ドレミファと伴奏」に「130Hzのサイン波」を加えてます。双2次フィルタの使用によってこの音がどうなるかを確認します。</p> <table> <tr> <th>選択</th> <td> <input type="radio" name="grp_option1" value="0" id="m0" checked="checked" onchange="play();"><label for="m0">テスト用の音声</label><br> <input type="radio" name="grp_option1" value="1" id="m1" onchange="play();"><label for="m1">ローパスフィルタ</label> <input type="radio" name="grp_option1" value="2" id="m2" onchange="play();"><label for="m2">ハイパスフィルタ</label> <input type="radio" name="grp_option1" value="3" id="m3" onchange="play();"><label for="m3">ローシェルフフィルタ</label><br> <input type="radio" name="grp_option1" value="4" id="m4" onchange="play();"><label for="m4">ノッチフィルタ</label> <input type="radio" name="grp_option1" value="5" id="m5" onchange="play();"><label for="m5">ローパスフィルタ + ハイパスフィルタ</label> </td> </tr> <tr> <th>波形データ</th> <td><canvas id="canvas1" width="256" height="255" style="border:1px solid #ccc;"></canvas></td> </tr> </table> <script> var canvas1 = document.getElementById('canvas1'); var ctx1 = canvas1.getContext('2d') ; ctx1.clearRect(0, 0, canvas1.width, canvas1.height); ctx1.lineWidth = 1; ctx1.strokeStyle ='rgb(0, 0, 255)'; ctx1.fillStyle = 'rgb(255, 255, 255)'; var audioCtx; var audioSourceNode; var analyserNode; var filter1,filter2; var data1; var bufferLength; var audioEle; var firstflg = true; function play(){ try{ if(firstflg){ // AudioContextの生成 audioCtx = new AudioContext(); firstflg = false; } stop(); audioEle = new Audio(); audioEle.src = 'biquadfilter.mp3'; audioEle.autoplay = true; audioEle.preload = 'auto'; // MediaElementAudioSourceNodeの生成 if(audioSourceNode){ audioSourceNode.disconnect(); } audioSourceNode = audioCtx.createMediaElementSource(audioEle); // AnalyserNodeの生成 // ※音声の時間と周波数を解析する if(analyserNode){ analyserNode.disconnect(); } analyserNode = audioCtx.createAnalyser(); // FFT(高速フーリエ変換)においての周波数領域 analyserNode.fftSize = 256; // fftSize bufferLength = analyserNode.fftSize; data1 = new Uint8Array(bufferLength); if(filter1){ filter1.disconnect(); filter1 = null; } if(filter2){ filter2.disconnect(); filter2 = null; } // ローパスフィルタ if (document.getElementById("m1").checked){ filter1 = audioCtx.createBiquadFilter(); filter1.type='lowpass'; filter1.frequency.value = 130; // 周波数 } // ハイパスフィルタ if (document.getElementById("m2").checked){ filter1 = audioCtx.createBiquadFilter(); filter1.type='highpass'; filter1.frequency.value = 260; } // ローシェルフフィルタ if (document.getElementById("m3").checked){ filter1 = audioCtx.createBiquadFilter(); filter1.type='lowshelf'; filter1.gain.value = -40; filter1.frequency.value = 130; } // ノッチフィルタ if (document.getElementById("m4").checked){ filter1 = audioCtx.createBiquadFilter(); filter1.type='notch'; filter1.frequency.value = 130; } // ローパスフィルタ + ハイパスフィルタ if (document.getElementById("m5").checked){ filter1 = audioCtx.createBiquadFilter(); filter1.type='lowpass'; filter1.frequency.value = 800; filter2 = audioCtx.createBiquadFilter(); filter2.type='highpass'; filter2.frequency.value = 500; // オーディオノードの設定 audioSourceNode.connect(filter1); filter1.connect(filter2); filter2.connect(analyserNode); analyserNode.connect(audioCtx.destination); }else{ // m0 if (document.getElementById("m0").checked){ audioSourceNode.connect(analyserNode); analyserNode.connect(audioCtx.destination); // m1,2,3,4 }else{ audioSourceNode.connect(filter1); filter1.connect(analyserNode); analyserNode.connect(audioCtx.destination); } } draw(); }catch(e){ alert(e); } } function draw() { requestAnimationFrame(draw); // 波形データ analyserNode.getByteTimeDomainData(data1); ctx1.fillRect(0, 0, canvas1.width, canvas1.height); ctx1.strokeStyle = 'rgb(0, 0, 255)'; ctx1.beginPath(); ctx1.moveTo(0, data1[0]); for(var i = 0; i < bufferLength; i++) { ctx1.lineTo(i, data1[i]); } ctx1.stroke(); ctx1.strokeStyle = 'rgb(255, 0, 0)'; ctx1.beginPath(); ctx1.moveTo(0, 127); ctx1.lineTo(256, 127); ctx1.stroke(); }; function stop(){ if(audioEle){ audioEle.pause(); } } </script> </body> </html>
Webアプリ
スポンサーリンク
関連記事
公開日:2019年02月07日 最終更新日:2019年02月16日
記事NO:02727