Top

Web Audio API でピアノの音色に近づけたい

前回の記事でWeb Audio API をつかい、音程通りの音をピアノで出す実験をしてみました。今回は Web Audio API を使い、そのピアノの音をなんとかピアノの音色に近づけます。

前回の記事:Web Audio API でピアノを作ってみる

piano

ピアノデモ

押すと音が出ますので注意してください。音楽系の用語が全くわからないので、「ディストーション」とか「コンプレッサ」とかわかりません。

音程系のフィルタはそろっている様に見えます。また、歪みやいろいろなフィルターと思われるもの一式はあるようです。

参考:BiquadFilterNode | MDN
参考:Web Audio API オーディオエフェクター | MDN

ただ、前述のとおり全く知識がないので、本来であれば、このフィルター関係をバリバリ使うべきなのでしょうが、今回は音量調節と音程だけでピアノっぽく出来そうなのでしてみます。

JavaScript

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

    //音を出す関数
    function play(hz) {

        //2種類の音を作る
        var osciillator = audioCtx.createOscillator();
        var osciillator2 = audioCtx.createOscillator();

        //2種類目の音は1オクターブ上(Hzが2倍でオクターブ上)
        osciillator.frequency.value = hz;
        osciillator2.frequency.value = hz * 2;

        //音量(Gain)変更フィルター
        var gainNode = audioCtx.createGain();
        var gainNode2 = audioCtx.createGain();

        //音の出始める時刻を取得
        var currentTime = audioCtx.currentTime;

        //音を線形に音量変化させる
        gainNode.gain.linearRampToValueAtTime(1, currentTime);
        gainNode.gain.linearRampToValueAtTime(0, currentTime + 1.60);

        //2種類目の音は音量を小さく初めて少し長めに
        gainNode2.gain.linearRampToValueAtTime(0.2, currentTime);
        gainNode2.gain.linearRampToValueAtTime(0, currentTime + 2.0);

        //まず音量変更フィルタに作った音を通す
        osciillator.connect(gainNode);
        osciillator2.connect(gainNode2);
        var audioDestination = audioCtx.destination;

        //フィルタに通った音をスピーカーに接続
        gainNode.connect(audioDestination);
        gainNode2.connect(audioDestination);
        osciillator.start = osciillator.start || osciillator.noteOn;
        osciillator2.start = osciillator2.start || osciillator2.noteOn;
        osciillator.start();
        osciillator2.start();
    }

    var pianoKey = document.getElementsByClassName("pianokey");
    var pianoKeyL = pianoKey.length;
    for (i = 0; i < pianoKeyL; i++) {
        (function(i) {
        pianoKey[i].addEventListener("click", function() {
            var h = 442 * Math.pow(2, (1 / 12) * (i - 9));
            play(h);
            }, false)
        })(i)
    }
})()

1オクターブ上の音を少し小さめに同時に出して余韻を残すことによって、何となくピアノっぽく聞こえます。ハンドベルみたいな音ですが、ピアノということにします。

スポンサーリンク

audioCtx.createGain()

gainNode = audioCtx.createGain()

音量を変化させるためのフィルターを作る作業です。

audioCtx.currentTime

currentTime = audioCtx.currentTime

これで音を出す時刻を取得できます。音量を時間で変化させるために使います。

.gain.linearRampToValueAtTime

gainNode.gain.linearRampToValueAtTime(0.4, currentTime + 0.02);

gain プロパティの中にある linearRampToValueAtTime メソッドを使います。音量を指定時刻までに線形に(ものすごく簡単に言うと「直線的にだんだんと」)変化させます。

上の例で言えば「0.02秒後までに音量を0.4倍する」という意味です。音量は絶対値ではなく相対値で示すようです。

参考:AudioParam.linearRampToValueAtTime() | MDN

音を出す仕組み

osciillator.connect(gainNode);
gainNode.connect(audioDestination);

音を単純に出すだけであれば、前回の記事のように

osciillator.connect(audioDestination)

だけで構いませんが、今回はフィルターに通すので

osciillator ⇒ gainNode ⇒ audioDestination

と間にフィルターを挟みます。フィルターがある分だけ audioDestination につなげる前に接続する必要があります。

不具合関係

iPhone Safariでは音が出ない。
音が重なるとガジガジ汚かったりする。

直せそうなら直します。