Implement .detune attribute for BiquadFilterNode
authorcrogers@google.com <crogers@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Nov 2012 01:46:16 +0000 (01:46 +0000)
committercrogers@google.com <crogers@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Nov 2012 01:46:16 +0000 (01:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=102737

Reviewed by Kenneth Russell.

Source/WebCore:

Similar to OscillatorNode, BiquadFilterNode must have a .detune attribute

Tests changed: webaudio/biquad-lowpass.html

* Modules/webaudio/BiquadDSPKernel.cpp:
(WebCore::BiquadDSPKernel::updateCoefficientsIfNecessary):
* Modules/webaudio/BiquadFilterNode.h:
(WebCore::BiquadFilterNode::detune):
* Modules/webaudio/BiquadFilterNode.idl:
* Modules/webaudio/BiquadProcessor.cpp:
(WebCore::BiquadProcessor::BiquadProcessor):
(WebCore::BiquadProcessor::checkForDirtyCoefficients):
* Modules/webaudio/BiquadProcessor.h:
(WebCore::BiquadProcessor::parameter4):
(BiquadProcessor):

LayoutTests:

* webaudio/biquad-lowpass.html:
* webaudio/resources/biquad-testing.js:
(createTestAndRun):
(generateReference):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@135218 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/webaudio/biquad-lowpass.html
LayoutTests/webaudio/resources/biquad-testing.js
Source/WebCore/ChangeLog
Source/WebCore/Modules/webaudio/BiquadDSPKernel.cpp
Source/WebCore/Modules/webaudio/BiquadFilterNode.h
Source/WebCore/Modules/webaudio/BiquadFilterNode.idl
Source/WebCore/Modules/webaudio/BiquadProcessor.cpp
Source/WebCore/Modules/webaudio/BiquadProcessor.h

index 44c20ba..7449da2 100644 (file)
@@ -1,3 +1,15 @@
+2012-11-19  Chris Rogers  <crogers@google.com>
+
+        Implement .detune attribute for BiquadFilterNode
+        https://bugs.webkit.org/show_bug.cgi?id=102737
+
+        Reviewed by Kenneth Russell.
+
+        * webaudio/biquad-lowpass.html:
+        * webaudio/resources/biquad-testing.js:
+        (createTestAndRun):
+        (generateReference):
+
 2012-11-19  Huang Dongsung  <luxtella@company100.net>
 
         Coordinated Graphics: Remove tiles of a layer when they are off the viewport.
index 1a9af8e..8d5e4a9 100644 (file)
@@ -34,6 +34,8 @@ function runTest() {
     var filterParameters = [{cutoff : 0,    q : 1, gain : 1 },
                             {cutoff : 1,    q : 1, gain : 1 },
                             {cutoff : 0.25, q : 1, gain : 1 },
+                            {cutoff : 0.25, q : 1, gain : 1, detune : 100 },
+                            {cutoff : 0.01, q : 1, gain : 1, detune : -200 },
                            ];
     createTestAndRun(context, f.LOWPASS, filterParameters);
 }
index 99a2e8d..97bc9e9 100644 (file)
@@ -434,6 +434,7 @@ function createTestAndRun(context, filterType, filterParameters) {
         filter[k] = context.createBiquadFilter();
         filter[k].type = filterType;
         filter[k].frequency.value = context.sampleRate / 2 * filterParameters[k].cutoff;
+        filter[k].detune.value = (filterParameters[k].detune === undefined) ? 0 : filterParameters[k].detune;
         filter[k].Q.value = filterParameters[k].q;
         filter[k].gain.value = filterParameters[k].gain;
 
@@ -467,8 +468,11 @@ function generateReference(filterType, filterParameters) {
     
     for (var k = 0; k < nFilters; ++k) {
         // Filter an impulse
+        var detune = (filterParameters[k].detune === undefined) ? 0 : filterParameters[k].detune;
+        var frequency = filterParameters[k].cutoff * Math.pow(2, detune / 1200); // Apply detune, converting from Cents.
+        
         var filterCoef = createFilter(filterType,
-                                      filterParameters[k].cutoff,
+                                      frequency,
                                       filterParameters[k].q,
                                       filterParameters[k].gain);
         var y = filterData(filterCoef, data, renderLengthSamples);
index c5b2eec..37c82f0 100644 (file)
@@ -1,3 +1,26 @@
+2012-11-19  Chris Rogers  <crogers@google.com>
+
+        Implement .detune attribute for BiquadFilterNode
+        https://bugs.webkit.org/show_bug.cgi?id=102737
+
+        Reviewed by Kenneth Russell.
+
+        Similar to OscillatorNode, BiquadFilterNode must have a .detune attribute
+
+        Tests changed: webaudio/biquad-lowpass.html
+
+        * Modules/webaudio/BiquadDSPKernel.cpp:
+        (WebCore::BiquadDSPKernel::updateCoefficientsIfNecessary):
+        * Modules/webaudio/BiquadFilterNode.h:
+        (WebCore::BiquadFilterNode::detune):
+        * Modules/webaudio/BiquadFilterNode.idl:
+        * Modules/webaudio/BiquadProcessor.cpp:
+        (WebCore::BiquadProcessor::BiquadProcessor):
+        (WebCore::BiquadProcessor::checkForDirtyCoefficients):
+        * Modules/webaudio/BiquadProcessor.h:
+        (WebCore::BiquadProcessor::parameter4):
+        (BiquadProcessor):
+
 2012-11-19  Patrick Gansterer  <paroga@webkit.org>
 
         [WIN] Add WebCore::getRegistryValue()
index a0611dc..37ef51e 100644 (file)
@@ -47,25 +47,33 @@ void BiquadDSPKernel::updateCoefficientsIfNecessary(bool useSmoothing, bool forc
         double value1;
         double value2;
         double gain;
+        double detune; // in Cents
 
         if (biquadProcessor()->hasSampleAccurateValues()) {
             value1 = biquadProcessor()->parameter1()->finalValue();
             value2 = biquadProcessor()->parameter2()->finalValue();
             gain = biquadProcessor()->parameter3()->finalValue();
+            detune = biquadProcessor()->parameter4()->finalValue();
         } else if (useSmoothing) {
             value1 = biquadProcessor()->parameter1()->smoothedValue();
             value2 = biquadProcessor()->parameter2()->smoothedValue();
             gain = biquadProcessor()->parameter3()->smoothedValue();
+            detune = biquadProcessor()->parameter4()->smoothedValue();
         } else {
             value1 = biquadProcessor()->parameter1()->value();
             value2 = biquadProcessor()->parameter2()->value();
             gain = biquadProcessor()->parameter3()->value();
+            detune = biquadProcessor()->parameter4()->value();
         }
 
         // Convert from Hertz to normalized frequency 0 -> 1.
         double nyquist = this->nyquist();
         double normalizedFrequency = value1 / nyquist;
 
+        // Offset frequency by detune.
+        if (detune)
+            normalizedFrequency *= pow(2, detune / 1200);
+
         // Configure the biquad with the new filter parameters for the appropriate type of filter.
         switch (biquadProcessor()->type()) {
         case BiquadProcessor::LowPass:
index ccd6cde..f6699af 100644 (file)
@@ -57,6 +57,7 @@ public:
     AudioParam* frequency() { return biquadProcessor()->parameter1(); }
     AudioParam* q() { return biquadProcessor()->parameter2(); }
     AudioParam* gain() { return biquadProcessor()->parameter3(); }
+    AudioParam* detune() { return biquadProcessor()->parameter4(); }
 
     // Get the magnitude and phase response of the filter at the given
     // set of frequencies (in Hz). The phase response is in radians.
index c976d05..af20d0b 100644 (file)
@@ -40,6 +40,7 @@
         setter raises(DOMException);
     
     readonly attribute AudioParam frequency; // in Hertz
+    readonly attribute AudioParam detune; // in Cents
     readonly attribute AudioParam Q; // Quality factor
     readonly attribute AudioParam gain; // in Decibels
 
index 6362a10..c44236b 100644 (file)
@@ -38,6 +38,7 @@ BiquadProcessor::BiquadProcessor(AudioContext* context, float sampleRate, size_t
     , m_parameter1(0)
     , m_parameter2(0)
     , m_parameter3(0)
+    , m_parameter4(0)
     , m_filterCoefficientsDirty(true)
     , m_hasSampleAccurateValues(false)
 {
@@ -47,6 +48,7 @@ BiquadProcessor::BiquadProcessor(AudioContext* context, float sampleRate, size_t
     m_parameter1 = AudioParam::create(context, "frequency", 350.0, 10.0, nyquist);
     m_parameter2 = AudioParam::create(context, "Q", 1, 0.0001, 1000.0);
     m_parameter3 = AudioParam::create(context, "gain", 0.0, -40, 40);
+    m_parameter4 = AudioParam::create(context, "detune", 0.0, -4800, 4800);
 
     if (autoInitialize)
         initialize();
@@ -71,7 +73,7 @@ void BiquadProcessor::checkForDirtyCoefficients()
     m_filterCoefficientsDirty = false;
     m_hasSampleAccurateValues = false;
     
-    if (m_parameter1->hasSampleAccurateValues() || m_parameter2->hasSampleAccurateValues() || m_parameter3->hasSampleAccurateValues()) {
+    if (m_parameter1->hasSampleAccurateValues() || m_parameter2->hasSampleAccurateValues() || m_parameter3->hasSampleAccurateValues() || m_parameter4->hasSampleAccurateValues()) {
         m_filterCoefficientsDirty = true;
         m_hasSampleAccurateValues = true;
     } else {
@@ -80,6 +82,7 @@ void BiquadProcessor::checkForDirtyCoefficients()
             m_parameter1->resetSmoothedValue();
             m_parameter2->resetSmoothedValue();
             m_parameter3->resetSmoothedValue();
+            m_parameter4->resetSmoothedValue();
             m_filterCoefficientsDirty = true;
             m_hasJustReset = false;
         } else {
@@ -87,7 +90,8 @@ void BiquadProcessor::checkForDirtyCoefficients()
             bool isStable1 = m_parameter1->smooth();
             bool isStable2 = m_parameter2->smooth();
             bool isStable3 = m_parameter3->smooth();
-            if (!(isStable1 && isStable2 && isStable3))
+            bool isStable4 = m_parameter4->smooth();
+            if (!(isStable1 && isStable2 && isStable3 && isStable4))
                 m_filterCoefficientsDirty = true;
         }
     }
index 9c3b968..0179e2e 100644 (file)
@@ -72,6 +72,7 @@ public:
     AudioParam* parameter1() { return m_parameter1.get(); }
     AudioParam* parameter2() { return m_parameter2.get(); }
     AudioParam* parameter3() { return m_parameter3.get(); }
+    AudioParam* parameter4() { return m_parameter4.get(); }
 
     FilterType type() const { return m_type; }
     void setType(FilterType);
@@ -82,6 +83,7 @@ private:
     RefPtr<AudioParam> m_parameter1;
     RefPtr<AudioParam> m_parameter2;
     RefPtr<AudioParam> m_parameter3;
+    RefPtr<AudioParam> m_parameter4;
 
     // so DSP kernels know when to re-compute coefficients
     bool m_filterCoefficientsDirty;