Bug 916285 - Make OscillatorNode handle negative frequencies. r=karlt
☠☠ backed out by 72d7ae169b09 ☠ ☠
authorPaul Adenot <paul@paul.cx>
Mon, 01 Dec 2014 16:10:54 -0800
changeset 247871 011c2f2f58992100ebe4c6ca4433d58117de7cf4
parent 247870 b7303f56216b6f000055f434437d86df496b169f
child 247872 43e2d930ba6f044213d2446bbfcbb1c256a50660
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs916285
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 916285 - Make OscillatorNode handle negative frequencies. r=karlt
dom/media/webaudio/OscillatorNode.cpp
dom/media/webaudio/test/mochitest.ini
dom/media/webaudio/test/test_oscillatorNodeNegativeFrequency.html
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -137,18 +137,20 @@ public:
                "PeriodicWave should have sent two channels");
     mPeriodicWave = WebCore::PeriodicWave::create(mSource->SampleRate(),
     mCustom->GetData(0), mCustom->GetData(1), mCustomLength);
   }
 
   void IncrementPhase()
   {
     mPhase += mPhaseIncrement;
-    if (mPhase > mPhaseWrap) {
-      mPhase -= mPhaseWrap;
+    if (mPhase > 2 * M_PI) {
+      mPhase -= 2 * M_PI;
+    } else if (mPhase < -2 * M_PI) {
+      mPhase += 2 * M_PI;
     }
   }
 
   void UpdateParametersIfNeeded(StreamTime ticks, size_t count)
   {
     double frequency, detune;
 
     // Shortcut if frequency-related AudioParam are not automated, and we
@@ -166,21 +168,20 @@ public:
       frequency = mFrequency.GetValueAtTime(ticks, count);
     }
     if (simpleDetune) {
       detune = mDetune.GetValue();
     } else {
       detune = mDetune.GetValueAtTime(ticks, count);
     }
 
+    mFinalFrequency = frequency * pow(2., detune / 1200.);
     float signalPeriod = mSource->SampleRate() / mFinalFrequency;
-    mFinalFrequency = frequency * pow(2., detune / 1200.);
     mRecomputeParameters = false;
 
-    mPhaseWrap = 2 * M_PI;
     mPhaseIncrement = 2 * M_PI / signalPeriod;
   }
 
   void FillBounds(float* output, StreamTime ticks,
                   uint32_t& start, uint32_t& end)
   {
     MOZ_ASSERT(output);
     static_assert(StreamTime(WEBAUDIO_BLOCK_SIZE) < UINT_MAX,
@@ -362,17 +363,16 @@ public:
   StreamTime mStart;
   StreamTime mStop;
   AudioParamTimeline mFrequency;
   AudioParamTimeline mDetune;
   OscillatorType mType;
   float mPhase;
   float mFinalFrequency;
   float mPhaseIncrement;
-  float mPhaseWrap;
   bool mRecomputeParameters;
   nsRefPtr<ThreadSharedFloatArrayBufferList> mCustom;
   uint32_t mCustomLength;
   nsAutoPtr<WebCore::PeriodicWave> mPeriodicWave;
 };
 
 OscillatorNode::OscillatorNode(AudioContext* aContext)
   : AudioNode(aContext,
--- a/dom/media/webaudio/test/mochitest.ini
+++ b/dom/media/webaudio/test/mochitest.ini
@@ -121,16 +121,17 @@ skip-if = android_version == '10' # bug 
 [test_mozaudiochannel.html]
 skip-if = (toolkit == 'gonk' && !debug)
 [test_nodeToParamConnection.html]
 [test_OfflineAudioContext.html]
 [test_offlineDestinationChannelCountLess.html]
 [test_offlineDestinationChannelCountMore.html]
 [test_oscillatorNode.html]
 [test_oscillatorNode2.html]
+[test_oscillatorNodeNegativeFrequency.html]
 [test_oscillatorNodePassThrough.html]
 [test_oscillatorNodeStart.html]
 [test_oscillatorTypeChange.html]
 [test_pannerNode.html]
 [test_pannerNode_equalPower.html]
 [test_pannerNodeAbove.html]
 [test_pannerNodeChannelCount.html]
 [test_pannerNodeHRTFSymmetry.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/test/test_oscillatorNodeNegativeFrequency.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test the OscillatorNode when the frequency is negative</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+
+  var types = ["sine",
+               "square",
+               "sawtooth",
+               "triangle"];
+
+  var finished = 0;
+  function finish() {
+    if (++finished == types.length) {
+      SimpleTest.finish();
+    }
+  }
+
+  types.forEach(function(t) {
+    var context = new OfflineAudioContext(1, 256, 44100);
+    var osc = context.createOscillator();
+
+    osc.frequency.value = -440;
+    osc.type = t;
+
+    osc.connect(context.destination);
+    osc.start();
+    context.startRendering().then(function(buffer) {
+      var samples = buffer.getChannelData(0);
+      // This samples the wave form in the middle of the first period, the value
+      // should be negative.
+      ok(samples[Math.floor(44100 / 440 / 4)] < 0., "Phase should be inverted when using a " + t + " waveform");
+      finish();
+    });
+  });
+});
+
+</script>
+</pre>
+</body>
+</html>