Bug 916285 - Make OscillatorNode handle negative frequencies. r=karlt
authorPaul Adenot <paul@paul.cx>
Mon, 01 Dec 2014 16:10:54 -0800
changeset 222757 186c02fdb2218b2d15d583dca7c8f5e6fd7c2088
parent 222756 894be64b069b8223f41af5154621fa8f0762c04e
child 222758 b8d51d20fd97aca487d04b7bf0f57cf31c954e4e
push id28073
push userkwierso@gmail.com
push dateFri, 09 Jan 2015 01:08:23 +0000
treeherdermozilla-central@b3f84cf78dc2 [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>