畳み込み演算 =============== ## はじめに WebAudioAPIは,標準で畳み込み演算の機能を持っており,コンボルバーノードと呼ばれています.インパルス応答は,外部ファイルを読み込むことも,プログラム中で配列に数値を入れることでも実現できます.このページのプログラムでは,配列に数値を入れています.まずは以下を実行してください. ```javascript once editable // はじめに1回だけ実行してください window.AudioContext = window.webkitAudioContext || window.AudioContext; var audioCtx = new AudioContext(); ``` その後,以下の枠を順に実行してください.なお,上から順に実行すれば,何回でも実行可能です.
```javascript runnable editable // 畳み込み演算の例 // LFO関係(注:FM音源ではModulatorと呼ばれている) var lfo = audioCtx.createOscillator(); lfo.frequency.value = 223; var gainLfo = audioCtx.createGain(); gainLfo.gain.value = 0.8; // Feedback関係 var gainFb = audioCtx.createGain(); gainFb.gain.value = 200; // VCO1関係(注:FM音源ではCarrierと呼ばれている) var vco1 = audioCtx.createOscillator(); vco1.frequency.value = 220; vco1.type="sine"; var gainVco1 = audioCtx.createGain(); gainVco1.gain.value = 0.8; // エンベロープ関連 var gainVcf = audioCtx.createGain(); gainVcf.gain.value = 1; ``` 以下の部分が,インパルス応答を定義する部分です.左右のチャンネル(chanLとchanR)に分かれており,独立した数値を入れることも可能です.なお,```audioCtx.sampleRate```には,WebAudioAPIが内部的に使用するサンプリング周波数が入っています. プログラム中の```audioCtx.createBuffer```のパラメータは以下のとおりです. * チャンネル数 * インパルス応答の要素数(サンプリング周波数☓秒数を与える) * サンプリング周波数 その下にある配列への代入によって,インパルス応答を作成しています.代入できる値は-1〜+1です.タイミングや音量を調整することで,様々な空間を再現することが可能です. ```javascript runnable editable // バッファ作成 var arr = audioCtx.createBuffer( 2, audioCtx.sampleRate * 1.0, audioCtx.sampleRate ); var chanL = arr.getChannelData( 0 ); var chanR = arr.getChannelData( 1 ); chanL[0] = chanR[0] = 1.0; chanL[44100/4+44100/8] = chanR[44100/4+44100/8] = 0.8; chanL[44100/2] = chanR[44100/2] = 0.6; ``` 以下の部分で,実際に音を出しています.音はベースのような音です.Node同士の接続は以下の通りとなります. ```mermaid graph LR lfo -- connect --> gainLfo lfo -- connect --> gainFb gainFb -- frequency --> lfo gainLfo -- connect --> gainVcf vco1 -- connect --> gainVco1 gainVco1 -- connect --> gainVcf gainVcf -- connect --> convNode convNode -- connect --> destination ``` ```javascript runnable editable console.log( arr ); // 畳み込み関連 var convNode = audioCtx.createConvolver(); convNode.buffer = arr // 接続 lfo.connect( gainLfo ); lfo.connect( gainFb ); gainFb.connect( lfo.frequency ); gainLfo.connect( gainVcf ); vco1.connect( gainVco1 ); gainVco1.connect( gainVcf ); gainVcf.connect( convNode ); convNode.connect( audioCtx.destination ); // 音を出す lfo.start(); vco1.start(); // エンベロープ設定 var now = audioCtx.currentTime; var volume = 1; var attack = 0.0 // attackに要する時間 [sec] var decay = 0.2; // decayする時間 [sec] var sustain = 0.8; // sustainレベル var release = 0.5; // キーオフしてからの時間 [sec] gainVcf.gain.cancelScheduledValues( 0 ); gainVcf.gain.setValueAtTime( 0.0, now ); gainVcf.gain.linearRampToValueAtTime( volume, now + attack ); gainVcf.gain.linearRampToValueAtTime( sustain * volume, now + attack + decay ); gainVcf.gain.linearRampToValueAtTime( 0.0, now + attack + decay + release ); // 音を止める setTimeout( () => { lfo.stop(); vco1.stop(); }, 3000 ); ```