Bug 809271 - Implement DynamicsCompressorNode; r=bzbarsky
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 06 Nov 2012 20:01:11 -0500
changeset 112597 bc32dff943f6962ecf8c0b3e72677de5a2ef64c6
parent 112596 e1c05c15787c41bb54f923cb25d2959deef79e42
child 112598 c652c39732f8461406ad56965b1a0dd6daede27b
child 112602 2e6726f79a3b8de41d680715561c4db117df73cb
push id23830
push userryanvm@gmail.com
push dateThu, 08 Nov 2012 01:08:07 +0000
treeherdermozilla-central@c652c39732f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs809271
milestone19.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 809271 - Implement DynamicsCompressorNode; r=bzbarsky
content/media/webaudio/AudioContext.cpp
content/media/webaudio/AudioContext.h
content/media/webaudio/DynamicsCompressorNode.cpp
content/media/webaudio/DynamicsCompressorNode.h
content/media/webaudio/Makefile.in
content/media/webaudio/test/Makefile.in
content/media/webaudio/test/test_dynamicsCompressorNode.html
dom/bindings/Bindings.conf
dom/webidl/AudioContext.webidl
dom/webidl/DynamicsCompressorNode.webidl
dom/webidl/WebIDL.mk
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/dom/AudioContextBinding.h"
 #include "AudioDestinationNode.h"
 #include "AudioBufferSourceNode.h"
 #include "AudioBuffer.h"
 #include "GainNode.h"
 #include "DelayNode.h"
 #include "PannerNode.h"
 #include "AudioListener.h"
+#include "DynamicsCompressorNode.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(AudioContext)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(AudioContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWindow)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDestination)
@@ -110,16 +111,24 @@ AudioContext::CreateDelay(float aMaxDela
 
 already_AddRefed<PannerNode>
 AudioContext::CreatePanner()
 {
   nsRefPtr<PannerNode> pannerNode = new PannerNode(this);
   return pannerNode.forget();
 }
 
+already_AddRefed<DynamicsCompressorNode>
+AudioContext::CreateDynamicsCompressor()
+{
+  nsRefPtr<DynamicsCompressorNode> compressorNode =
+    new DynamicsCompressorNode(this);
+  return compressorNode.forget();
+}
+
 AudioListener*
 AudioContext::Listener()
 {
   if (!mListener) {
     mListener = new AudioListener(this);
   }
   return mListener;
 }
--- a/content/media/webaudio/AudioContext.h
+++ b/content/media/webaudio/AudioContext.h
@@ -23,16 +23,17 @@ class ErrorResult;
 
 namespace dom {
 
 class AudioBuffer;
 class AudioBufferSourceNode;
 class AudioDestinationNode;
 class AudioListener;
 class DelayNode;
+class DynamicsCompressorNode;
 class GainNode;
 class PannerNode;
 
 class AudioContext MOZ_FINAL : public nsWrapperCache,
                                public EnableWebAudioCheck
 {
   explicit AudioContext(nsIDOMWindow* aParentWindow);
 
@@ -71,16 +72,19 @@ public:
   CreateGain();
 
   already_AddRefed<DelayNode>
   CreateDelay(float aMaxDelayTime);
 
   already_AddRefed<PannerNode>
   CreatePanner();
 
+  already_AddRefed<DynamicsCompressorNode>
+  CreateDynamicsCompressor();
+
 private:
   nsCOMPtr<nsIDOMWindow> mWindow;
   nsRefPtr<AudioDestinationNode> mDestination;
   nsRefPtr<AudioListener> mListener;
 };
 
 }
 }
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/DynamicsCompressorNode.cpp
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DynamicsCompressorNode.h"
+#include "mozilla/dom/DynamicsCompressorNodeBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(DynamicsCompressorNode)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DynamicsCompressorNode, AudioNode)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mThreshold)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mKnee)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRatio)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReduction)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAttack)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRelease)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DynamicsCompressorNode, AudioNode)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mThreshold, AudioParam, "threshold value")
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mKnee, AudioParam, "knee value")
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mRatio, AudioParam, "ratio value")
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mReduction, AudioParam, "reduction value")
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mAttack, AudioParam, "attack value")
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mRelease, AudioParam, "release value")
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DynamicsCompressorNode)
+NS_INTERFACE_MAP_END_INHERITING(AudioNode)
+
+NS_IMPL_ADDREF_INHERITED(DynamicsCompressorNode, AudioNode)
+NS_IMPL_RELEASE_INHERITED(DynamicsCompressorNode, AudioNode)
+
+DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
+  : AudioNode(aContext)
+  , mThreshold(new AudioParam(aContext, -24.f, -100.f, 0.f))
+  , mKnee(new AudioParam(aContext, 30.f, 0.f, 40.f))
+  , mRatio(new AudioParam(aContext, 12.f, 1.f, 20.f))
+  , mReduction(new AudioParam(aContext, 0.f, -20.f, 0.f))
+  , mAttack(new AudioParam(aContext, 0.003f, 0.f, 1.f))
+  , mRelease(new AudioParam(aContext, 0.25f, 0.f, 1.f))
+{
+}
+
+JSObject*
+DynamicsCompressorNode::WrapObject(JSContext* aCx, JSObject* aScope,
+                                   bool* aTriedToWrap)
+{
+  return DynamicsCompressorNodeBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
+
+}
+}
+
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/DynamicsCompressorNode.h
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef DynamicsCompressorNode_h_
+#define DynamicsCompressorNode_h_
+
+#include "AudioNode.h"
+#include "AudioParam.h"
+
+namespace mozilla {
+namespace dom {
+
+class AudioContext;
+
+class DynamicsCompressorNode : public AudioNode
+{
+public:
+  explicit DynamicsCompressorNode(AudioContext* aContext);
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DynamicsCompressorNode, AudioNode)
+
+  virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
+                               bool* aTriedToWrap);
+
+  virtual uint32_t MaxNumberOfInputs() const MOZ_FINAL MOZ_OVERRIDE
+  {
+    return 1;
+  }
+  virtual uint32_t MaxNumberOfOutputs() const MOZ_FINAL MOZ_OVERRIDE
+  {
+    return 1;
+  }
+
+  AudioParam* Threshold() const
+  {
+    return mThreshold;
+  }
+
+  AudioParam* Knee() const
+  {
+    return mKnee;
+  }
+
+  AudioParam* Ratio() const
+  {
+    return mRatio;
+  }
+
+  AudioParam* Reduction() const
+  {
+    return mReduction;
+  }
+
+  AudioParam* Attack() const
+  {
+    return mAttack;
+  }
+
+  // Called GetRelease to prevent clashing with the nsISupports::Release name
+  AudioParam* GetRelease() const
+  {
+    return mRelease;
+  }
+
+private:
+  nsRefPtr<AudioParam> mThreshold;
+  nsRefPtr<AudioParam> mKnee;
+  nsRefPtr<AudioParam> mRatio;
+  nsRefPtr<AudioParam> mReduction;
+  nsRefPtr<AudioParam> mAttack;
+  nsRefPtr<AudioParam> mRelease;
+};
+
+}
+}
+
+#endif
+
--- a/content/media/webaudio/Makefile.in
+++ b/content/media/webaudio/Makefile.in
@@ -19,31 +19,33 @@ CPPSRCS := \
   AudioBufferSourceNode.cpp \
   AudioContext.cpp \
   AudioDestinationNode.cpp \
   AudioListener.cpp \
   AudioNode.cpp \
   AudioParam.cpp \
   AudioSourceNode.cpp \
   DelayNode.cpp \
+  DynamicsCompressorNode.cpp \
   EnableWebAudioCheck.cpp \
   GainNode.cpp \
   PannerNode.cpp \
   $(NULL)
 
 EXPORTS_NAMESPACES := mozilla/dom
 EXPORTS_mozilla/dom := \
   AudioBuffer.h \
   AudioBufferSourceNode.h \
   AudioDestinationNode.h \
   AudioListener.h \
   AudioNode.h \
   AudioParam.h \
   AudioSourceNode.h \
   DelayNode.h \
+  DynamicsCompressorNode.h \
   GainNode.h \
   PannerNode.h \
   $(NULL)
 
 PARALLEL_DIRS := test
 
 ifdef ENABLE_TESTS
 TOOL_DIRS += compiledtest
--- a/content/media/webaudio/test/Makefile.in
+++ b/content/media/webaudio/test/Makefile.in
@@ -12,14 +12,15 @@ include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_FILES := \
   test_bug808374.html \
   test_AudioBuffer.html \
   test_AudioContext.html \
   test_AudioListener.html \
   test_badConnect.html \
   test_delayNode.html \
+  test_dynamicsCompressorNode.html \
   test_gainNode.html \
   test_pannerNode.html \
   test_singleSourceDest.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_dynamicsCompressorNode.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test DynamicsCompressorNode</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function near(a, b, msg) {
+  ok(Math.abs(a - b) < 1e-4, msg);
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+
+  var context = new mozAudioContext();
+  var buffer = context.createBuffer(1, 2048, 44100);
+  for (var i = 0; i < 2048; ++i) {
+    buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / 44100);
+  }
+
+  var destination = context.destination;
+
+  var source = context.createBufferSource();
+
+  var compressor = context.createDynamicsCompressor();
+
+  source.buffer = buffer;
+
+  source.connect(compressor);
+  compressor.connect(destination);
+
+  // Verify default values
+  with (compressor) {
+    near(threshold.defaultValue, -24, "Correct default value for threshold");
+    near(knee.defaultValue, 30, "Correct default value for knee");
+    near(ratio.defaultValue, 12, "Correct default value for ratio");
+    near(reduction.defaultValue, 0, "Correct default value for reduction");
+    near(attack.defaultValue, 0.003, "Correct default value for attack");
+    near(release.defaultValue, 0.25, "Correct default value for release");
+  }
+
+  // Verify min/max values
+  with (compressor) {
+    near(threshold.minValue, -100, "Correct min value for threshold");
+    near(knee.minValue, 0, "Correct min value for knee");
+    near(ratio.minValue, 1, "Correct min value for ratio");
+    near(reduction.minValue, -20, "Correct min value for reduction");
+    near(attack.minValue, 0, "Correct min value for attack");
+    near(release.minValue, 0, "Correct min value for release");
+    near(threshold.maxValue, 0, "Correct max value for threshold");
+    near(knee.maxValue, 40, "Correct max value for knee");
+    near(ratio.maxValue, 20, "Correct max value for ratio");
+    near(reduction.maxValue, 0, "Correct max value for reduction");
+    near(attack.maxValue, 1, "Correct max value for attack");
+    near(release.maxValue, 1, "Correct max value for release");
+  }
+
+  source.start(0);
+  SimpleTest.executeSoon(function() {
+    source.stop(0);
+    source.disconnect();
+    compressor.disconnect();
+
+    SpecialPowers.clearUserPref("media.webaudio.enabled");
+    SimpleTest.finish();
+  });
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -176,16 +176,25 @@ DOMInterfaces = {
 
 'DOMTokenList': {
     'nativeType': 'nsDOMTokenList',
     'binaryNames': {
         '__stringifier': 'Stringify'
     }
 },
 
+'DynamicsCompressorNode': [
+{
+    'resultNotAddRefed': [ 'threshold', 'knee', 'ratio',
+                           'reduction', 'attack', 'release' ],
+    'binaryNames': {
+        'release': 'getRelease'
+    }
+}],
+
 'Event': [
 {
     'workers': True,
 }],
 
 'EventListener': [
 {
     'workers': True,
--- a/dom/webidl/AudioContext.webidl
+++ b/dom/webidl/AudioContext.webidl
@@ -28,12 +28,15 @@ interface mozAudioContext {
 
     [Creator]
     GainNode createGain();
     [Creator]
     DelayNode createDelay(optional float maxDelayTime = 1);
     [Creator]
     PannerNode createPanner();
 
+    [Creator]
+    DynamicsCompressorNode createDynamicsCompressor();
+
 };
 
 typedef mozAudioContext AudioContext;
 
new file mode 100644
--- /dev/null
+++ b/dom/webidl/DynamicsCompressorNode.webidl
@@ -0,0 +1,24 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[PrefControlled]
+interface DynamicsCompressorNode : AudioNode {
+
+    readonly attribute AudioParam threshold; // in Decibels
+    readonly attribute AudioParam knee; // in Decibels
+    readonly attribute AudioParam ratio; // unit-less
+    readonly attribute AudioParam reduction; // in Decibels
+    readonly attribute AudioParam attack; // in Seconds
+    readonly attribute AudioParam release; // in Seconds
+
+};
+
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -21,16 +21,17 @@ webidl_files = \
   CanvasRenderingContext2D.webidl \
   ClientRectList.webidl \
   CSSStyleDeclaration.webidl \
   DelayNode.webidl \
   DOMImplementation.webidl \
   DOMTokenList.webidl \
   DOMSettableTokenList.webidl \
   DOMStringMap.webidl \
+  DynamicsCompressorNode.webidl \
   Function.webidl \
   EventHandler.webidl \
   EventListener.webidl \
   EventTarget.webidl \
   FileList.webidl \
   FileReaderSync.webidl \
   GainNode.webidl \
   HTMLCollection.webidl \