アナライザーで波形データと周波数スペクトルをオシロスコープのように描画する [Web Audio API]
Web Audio APIのAnalyserNodeで音声を解析してオシロスコープのように「波形データ」と「周波数スペクトル」をCanvasに描画します。
クラシックな曲(砂嵐)とサイン波、三角波、矩形波、のこぎり波の合計5つの音声データの波形/スペクトルをブラウザで確認する事が出来ます。
音の選択 |
|
---|---|
TimeDomain 波形データ |
|
Frequency 周波数スペクトル |
波形データの縦軸は周波数、横軸は時間。周波数スペクトルの縦軸は強度、横軸は周波数です。お使いのコンピュータのサンプリング周波数が48,000の場合は周波数スペクトルの周波数は12,000Hzまで表示されます。
※砂嵐(曲)は甘茶の音楽工房さんが作成した曲を使用しています。
サイン波(正弦波)
三角波
矩形波
のこぎり波
ソースコード
波形データは信号の生データ。周波数スペクトルはAnalyserNode.getByteFrequencyData()が高速フーリエ変換(FFT)を行っています。
<!doctype html> <html> <head> <meta charset="UTF-8"> </head> <body> <video src="waveform_spectrum_sandstorm.mp3" style="display:none;"></video> <video src="waveform_spectrum_sine.mp3" style="display:none;"></video> <video src="waveform_spectrum_triangle.mp3"style="display:none;"></video> <video src="waveform_spectrum_square.mp3" style="display:none;"></video> <video src="waveform_spectrum_sawtooth.mp3" style="display:none;"></video> <p> <button onclick="play();">再生する</button> <button onclick="stop();">停止する</button> </p> <table> <tr> <th>音の選択</th> <td> <input type="radio" name="grp_option1" value="1" id="m1" checked="checked" onchange="play();"><label for="m1">砂嵐(曲)</label> <br> <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>TimeDomain<br />波形データ</th> <td><canvas id="canvas1" width="256" height="255" style="border:1px solid #ccc;"></canvas></td> </tr> <tr> <th>Frequency<br />周波数スペクトル</th> <td><canvas id="canvas2" width="256" height="255" style="border:1px solid #ccc;"></canvas></td> </tr> </table> <p>波形データの縦軸は周波数、横軸は時間。周波数スペクトルの縦軸は強度、横軸は周波数です。お使いのコンピュータのサンプリング周波数が48,000の場合は周波数スペクトルの周波数は12,000Hzまで表示されます。</p> <p>※砂嵐(曲)は<a href="http://amachamusic.chagasi.com/index.html">甘茶の音楽工房</a>さんが作成した曲を使用しています。</p> <script> var canvas1 = document.getElementById('canvas1'); var canvas2 = document.getElementById('canvas2'); var ctx1 = canvas1.getContext('2d') ; var ctx2 = canvas2.getContext('2d') ; ctx1.clearRect(0, 0, canvas1.width, canvas1.height); ctx2.clearRect(0, 0, canvas2.width, canvas2.height); ctx1.lineWidth = ctx2.lineWidth = 1; ctx1.strokeStyle = ctx2.strokeStyle = 'rgb(0, 0, 255)'; ctx1.fillStyle = ctx2.fillStyle = 'rgb(255, 255, 255)'; var audioCtx; var audioSourceNode; var analyserNode; var data1,data2; var audioEle; var firstflg = true; function play(){ try{ if(firstflg){ // AudioContextの生成 audioCtx = new AudioContext(); firstflg = false; } if(audioEle){ audioEle.pause(); } audioEle = new Audio(); if (document.getElementById("m1").checked) audioEle.src = 'waveform_spectrum_sandstorm.mp3'; if (document.getElementById("m2").checked) audioEle.src = 'waveform_spectrum_sine.mp3'; if (document.getElementById("m3").checked) audioEle.src = 'waveform_spectrum_triangle.mp3'; if (document.getElementById("m4").checked) audioEle.src = 'waveform_spectrum_square.mp3'; if (document.getElementById("m5").checked) audioEle.src = 'waveform_spectrum_sawtooth.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; data1 = new Uint8Array(analyserNode.fftSize); data2 = new Uint8Array(analyserNode.fftSize / 4); // オーディオノードの設定 audioSourceNode.connect(analyserNode); analyserNode.connect(audioCtx.destination); draw(); }catch(e){ alert(e); } } function draw() { requestAnimationFrame(draw); // TimeDomain(波形データ) 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 < data1.length; 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(); // Frequency(周波数スペクトル) analyserNode.getByteFrequencyData(data2); ctx2.fillRect(0, 0, canvas2.width, canvas2.height); // 周波数を簡易的に表示する ctx2.beginPath(); ctx2.moveTo(0, 255 - data2[0]); for(var i = 0; i < data2.length; i++) { ctx2.lineTo(i*4, 255 - data2[i]); } ctx2.stroke(); }; function stop(){ audioEle.pause(); } </script> </body> </html>
このコードはあくまでも簡易的ですので、各自で拡張してください。
また、周波数スペクトルの横幅の1単位の周波数は「周波数分解能」を用います。周波数分解能はaudioCtx.sampleRate / analyserNode.fftSizeで求められます。sampleRateが48,000でfftSizeが2048の場合は48000/2048 =23.4375Hzとなります。
追記:学習用にオープンソースで波形データ&周波数スペクトルを公開したのでご参考にして下さい。
参考サイト
AnalyserNode (MDN Web Docs)
AnalyserNode.getByteFrequencyData() (MDN Web Docs)
AnalyserNode.getByteTimeDomainData() (MDN Web Docs)