Web Audio API Biquad Filter 編
清水智公
chikoski@gmail.com / @chikoski
Firefox OS コードリーディング
@chikoski
• 関数プログラミングわなびー
• プログラミング言語論
• Emacs
• 機械学習
• ニューラルネットワーク
• Bayesian
• TaPL / PRMLを読みたい!
音を扱うアプリを作りたい!
Audio 要素
• 音声コンテンツを表すHTML要素
• src属性で埋め込む音声リソースを指定
• コントロール、ロード方法なども属性で指定
<audio src="foo.mp3" autoplay control loop></audio>
Web Audio API
• 音声の処理を行うためのAPI
• できること
• 音声データのデコード
• 変調、FFT、ミキシング、パンニング
• オシレーション
• オーディオグラフ
オーディオグラフ
• 音声データの処理の流れ
• オーディオノードをつないで作成
• ノードはオーディオコンテキストから作成
簡単なオーディオグラフの作成例
• AudioContextオブジェクトのファクトリメソッドを利
用してオーディオノードを作成
• connectメソッドでノードを接続
• context.destination がスピーカー
var elm = document.querySelector("audio");
var context = new AudioContext();
var source = context.createMediaElementSource(elm);
source.connect(context.destination);
簡単なオーディオグラフの作成例
var elm = document.querySelector("audio");
var context = new AudioContext();
var source = context.createMediaElementSource(elm);
source.connect(context.destination);
source context.destination
ディレイを行うグラフ
var elm = document.querySelector("audio");
var context = new AudioContext();
var source = context.createMediaElementSource(elm);
var delay = context.createDelay();
var wet = context.createGain();
var dry = context.createGain();
var feedback = context.createGain();
source.connect(dry);
dry.connect(context.destination);
source.connect(delay);
delay.connect(wet);
wet.connect(context.destination);
delay.connect(feedback);
feedback.connect(delay);
ディレイを行うグラフ
source
context.destination
delayfeedback dry
wet
Web Audio エディタ
BiquadFilter Node
BiquadFilter:周波数によるフィルタ
種類 効果
lowpass 指定された周波数より低い音のみ通過させる
highpass 指定された周波数より高い音のみ通過させる
bandpass 指定された範囲の周波数の音のみ通過させる
lowshelf 指定された値よりより低い周波数の音を増幅する
highshelf 指定された値よりより高い周波数の音を増幅する
peaking 指定された範囲の周波数の音を増幅する
notch 指定された範囲以外の周波数の音をのみを通過させる
allpass 全ての音を通過させる
ローパスフィルタ
var elm = document.querySelector("audio");
var context = new AudioContext();
var source = context.createMediaElementSource(elm);
var lowpass = context.createBiquadFilter();
lowpass.type = "lowpass";
source.connect(lowpass);
lowpass.connect(context.destination);
source context.destinationlowpass
BiquadFilterの使い方
• フィルタの種類はtype属性に名前を代入して指定
• frequency, Q, gain のパラメータを持つ
• パラメータの役割はMDNを参照してください

https://developer.mozilla.org/ja/docs/Web/API/BiquadFilterNode
var context = new AudioContext();
var lowpass = context.createBiquadFilter();
lowpass.type = "lowpass";
lowpass.frequency.value = 2000;
lowpass.Q.value = 30;
AudioParamオブジェクト
• パラメータを表すオブジェクト

https://developer.mozilla.org/docs/Web/API/AudioParam
• 例:BiquadFilterNodeオブジェクトのfrequency属性
• value と defaultValue の2つの属性を持つ
• タイミングにあわせた値設定なども可能
var context = new AudioContext();
var lowpass = context.createBiquadFilter();
lowpass.frequency.value = 2000;
フィルタ種類の変更をしたい
source destinationBiquadFilter
destination
BiquadFilterGain
BiquadFilterGain
BiquadFilterGain
BiquadFilterGain
source
コードを読んでみる
ソースコードを取ってくる
• しばらく時間がかかります
• お風呂に入ったりすると良いかも
% git clone https://github.com/mozilla-b2g/B2G
% cd B2G
% ./config.sh flame-kk
gecko/dom/webidl
gecko/dom/media/webaudio
BiquadFilterNode.cpp
BiquadFilterNode::BiquadFilterNode(AudioContext* aContext)
: AudioNode(aContext,
2,
ChannelCountMode::Max,
ChannelInterpretation::Speakers)
, mType(BiquadFilterType::Lowpass)
, mFrequency(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
SendFrequencyToStream, 350.f))
, mDetune(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
SendDetuneToStream, 0.f))
, mQ(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
SendQToStream, 1.f))
, mGain(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
SendGainToStream, 0.f))
void
BiquadFilterNode::SetType(BiquadFilterType aType)
{
mType = aType;
SendInt32ParameterToStream(BiquadFilterNodeEngine::TYPE,
static_cast<int32_t>(aType));
}
AudioNode.cpp
AudioNode::SendInt32ParameterToStream(uint32_t aIndex,
int32_t aValue)
{
AudioNodeStream* ns =
static_cast<AudioNodeStream*>(mStream.get());
MOZ_ASSERT(ns, "How come we don't have a stream here?");
ns->SetInt32Parameter(aIndex, aValue);
}
AudioNodeStream::SetInt32Parameter(uint32_t aIndex, int32_t aValue)
{
class Message : public ControlMessage {
public:
Message(AudioNodeStream* aStream, uint32_t aIndex, int32_t aValue)
: ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {}
virtual void Run()
{
static_cast<AudioNodeStream*>(mStream)->Engine()->
SetInt32Parameter(mIndex, mValue);
}
int32_t mValue;
uint32_t mIndex;
};
MOZ_ASSERT(this);
GraphImpl()->AppendMessage(new Message(this, aIndex, aValue));
}
BiquadFilterNodeEngine
ProcessBlock
SetParamsOnBiquad
gecko/dom/media/webaudio/blink
Biquad.cpp
setNormalizedCoefficients
void Biquad::setNormalizedCoefficients(double b0, double b1, double
b2, double a0, double a1, double a2)
{
double a0Inverse = 1 / a0;
m_b0 = b0 * a0Inverse;
m_b1 = b1 * a0Inverse;
m_b2 = b2 * a0Inverse;
m_a1 = a1 * a0Inverse;
m_a2 = a2 * a0Inverse;
}
まとめ
Digital Biquad Filter
http://en.wikipedia.org/wiki/Digital_biquad_filter
http://en.wikipedia.org/wiki/Digital_biquad_filter
AudioNode
BiquadFilterNode BiquadFilterNodeEngine
WebCore::Biquad
AudioNodeEngine
source destinationBiquadFilter

20141115 fx os-codereading