前回のJavaScriptのAnalyzerNodeで拾った音の周波数を可視化してみる1で、

数学が弱い生物系出身の自分が無謀ながらコンピュータにおける高速フーリエ変換に触れてしまった。


フーリエ変換と言えば、

世の中を劇的に変えたであろう偉大な数式を挙げろと言われたら必ず出てくるようなもので、


身近でフーリエ変換によって出来たものと言えば、

真っ先に挙がるのが音声データが保存されたCDだろう。


オーケストラのCDをイメージしてみたらしい。


円盤がくるくると周り、

下から光を当てるだけであんなにも美しい音をスピーカを介して発生させることが出来るなんて、

1000年ぐらい前の貴族たちからしたら神の所業であると感じるに違いない。


フーリエ変換にはそれ程のインパクトがある。


もちろん、

周波数データを元にアナログの波に変換して、

その波をスピーカに渡すためのアンプも偉大である。

アンプ (音響機器) - Wikipedia


このような過去の偉業の賞賛はここまでにしておいて、

今回はWeb Audio APIでFFT(高速フーリエ変換)をしてみる。


Web Audio APIでFFTを行うために、

Web Audio APIではAnalyzerNodeインターフェースが用意されている。

AnalyserNode - Web API インターフェイス | MDN


AnalyzerNodeはFFTでマイクから取得した音波から周波数データを取得するという説明に留めておいて、

早速コードを書いてみる。


<canvas id="canvas" width="500" height="200" style="border:1px solid #000000;"></canvas>
<script>
    var canvas = document.querySelector("#canvas");
    var ctx = canvas.getContext("2d");

    //様々なブラウザでマイクへのアクセス権を取得する
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;

    //audioのみtrue
    navigator.getUserMedia({
        audio: true,
        video: false
    }, successFunc, errorFunc);

    var audioCtx = new(window.AudioContext || window.webkitAudioContext)();

    //FFT
    var analyser = audioCtx.createAnalyser();
    analyser.fftSize = 2048;    //取得するデータのサイズ(配列の大きさ)を決める

    function successFunc(stream) {
        //マイクから集音した音をFFTに入れる
        var src = audioCtx.createMediaStreamSource(stream);
        src.connect(analyser);
        analyser.connect(audioCtx.destination);

        setInterval(draw, 500);
        draw();
    }

    //取得した周波数データを描写する
    function draw() {
        var bufLen = analyser.frequencyBinCount;
        var data = new Uint8Array(bufLen);
        analyser.getByteFrequencyData(data);

        /** 描写 **/
        ctx.fillStyle = 'rgb(200, 200, 200)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        ctx.lineWidth = 2;
        ctx.strokeStyle = 'rgb(0, 0, 0)';

        ctx.beginPath();

        var sliceWidth = canvas.width * 1.0 / bufLen;
        var x = 0;

        for (var i = 0; i < bufLen; i++) {

            var v = data[i] / 128.0;
            var y = v * canvas.height / 2;

            if (i === 0) {
                ctx.moveTo(x, y);
            } else {
                ctx.lineTo(x, y);
            }

            x += sliceWidth;
        }

        ctx.lineTo(canvas.width, canvas.height / 2);
        ctx.stroke();
    }

    // Web Audio APIが使えなかった時
    function errorFunc(error) {
        alert("error");
    }

</script>

周波数データの取得と、取得したデータの描写はAnalyserNode - Web API インターフェイス | MDNを元に作成してみた。


前回のコードとの変更点は太字と

太字ではないがdraw関数を作成して周波数の描写を行ってみた。


このコードを実行してみて、

パソコンのマイクに向かって何らかの言葉を発声してみると、


fft_res2


こんな感じのグラフが描写された。

描写周りはサンプルコードそのままなので描写はおそらく正しいのだろう。


何度か音を発していると、

ファンファンファンのようなハウリングがすぐに発生する。

ハウリング - Wikipedia


これに対してはフィルターでどうにかするらしいけれども、

今回はここまでにしておく。