音の鳴るブログ

鳴らないこともある

AudioParam Viewer

Web Audio API の AudioParam の値を可視化できるやつを作った。

AudioParam Viewer

f:id:mohayonao:20141020195228p:plain

コードを書いて実行(eval)すると30秒分の値の遷移を記録してグラフ表示します。param というのが操作する AudioParam のインスタンスで、Ctrl+OCtrl+Space で操作関数を補完できます。

仕組み

Web Audio API はリアルタイムでオーディオ処理をするためのAPIだと思われがちだけど、OfflineAudioContext というのを使えば静的なオーディオ処理もできます。以下は簡単な使い方。レンダリング用のインターフェースがあるだけで基本的には AudioContext と同じように使えます。これを使うと30秒の処理を一瞬で行うことができるので、それを使って常に 1 を出力する AudioBufferSource とパラメータ操作用の GainNode を接続し、レンダリング結果をグラフ化しています。

// (1) OfflineAudioContext を作る
var context = new OfflineAudioContext(numOfChannels, length, sampleRate);

context.oncomplete = function(e) {
  // (4) 処理の結果
  e.renderedBuffer; // AudioBuffer
};

// (2) ここで処理をする(同期処理)
audioProcessing(context);

// (3) レンダリング開始
context.startRendering();

AudioContext と OfflineAudioContext の違い

AudioContext と OfflineAudioContext の大きな違いは処理を行うタイミングにあります。良くある AudioContext のアプリケーションでは setInterval 等を使って数ミリ秒単位で少しずつ行いますが、OfflineAudioContext の場合は一気に処理を行う必要があります。また、複数トラックを扱うようなアプリケーションを書くときに AudioContext の場合はすべてのトラックをリアルタイムに並列で処理する必要がありますが、OfflineAudioContext の場合はリアルタイムでないので各トラックずつ順番にといったように直列に処理することができます。そして、AudioContext ではボタンクリック等のイベントを介して今すぐ音を鳴らすというような書き方ができるのに対して、OfflineAudioContext はイベントを介した操作はまずできなくて、いつ音を出して、いつ音を止めるか、いつパラメーターをどう変化させるかを厳密に指定する必要があります。

お前それ OfflineAudioContext でも同じこと言えんの?

上記のように時間にシビアな OfflineAudioContext では osc.start(0) で今すぐ音を出すみたいな書き方や、一定時間経過後にオシレーターの周波数を変えたいので、それっぽいタイミングで osc.frequency.value = newValue をするというような使い方はできません。シンセサイザーアプリのようにユーザーイベントがきっかけになるような場合は仕方がないケースもありますが、それでもきっちりと時間を指定して osc.start(context.currentTime)osc.frequency.setValueAtTime(newValue, startTime) のように書いておいた方が後々に機能の追加や、コードの流用などの点で有利になります*1。OfflineAudioContext を制するものは Web Audio API を制するといっても過言ではないのです。

ということで練習です

AudioParam Viewer は OfflineAudioContext を使っているので厳密に時間を指定する方法で書く必要がありますが、逆にこれを使いこなして思い通りのグラフが書けるようになると AudioContext でもかっちりしたコードが書けるようになります。以下、適当に練習問題を考えてみましたので、どうぞお試しください。

f:id:mohayonao:20141020212338p:plain

答え

f:id:mohayonao:20141020212711p:plain

答え

f:id:mohayonao:20141020213021p:plain

ヒント: timeConstant = 0.1
答え

f:id:mohayonao:20141021072928p:plain

ヒント: var a = 0.2, d = 0.1, s = 0.4, r = 0.2, keyOff = 0.8;
答え

f:id:mohayonao:20141021073346p:plain

keyOff = 0.1 とかしても適切なカーブを描かせる
答え

*1:例外として変化しないパラメーターは param.value で直接代入したほうが良いです