Bug 1265405 - Use a dictionary to specify how PeriodicWave should be normalized (or not); r=padenot
authorDan Minor <dminor@mozilla.com>
Mon, 25 Apr 2016 11:37:20 -0400
changeset 295186 94189d37e581d108bf89064ded062831669a7be6
parent 295185 11de193d377770de40029cf9fbcc464fcdd1274d
child 295187 632811bf4b6e96b54709d125c298493d30576eb8
push id30220
push usercbook@mozilla.com
push dateThu, 28 Apr 2016 14:31:09 +0000
treeherdermozilla-central@4292da9df16b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1265405
milestone49.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 1265405 - Use a dictionary to specify how PeriodicWave should be normalized (or not); r=padenot MozReview-Commit-ID: IH7no48COML
dom/media/webaudio/AudioContext.cpp
dom/media/webaudio/OscillatorNode.cpp
dom/media/webaudio/PeriodicWave.cpp
dom/media/webaudio/PeriodicWave.h
dom/media/webaudio/blink/PeriodicWave.cpp
dom/media/webaudio/blink/PeriodicWave.h
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -537,17 +537,18 @@ AudioContext::CreatePeriodicWave(const F
   if (aRealData.Length() != aImagData.Length() ||
       aRealData.Length() == 0) {
     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return nullptr;
   }
 
   RefPtr<PeriodicWave> periodicWave =
     new PeriodicWave(this, aRealData.Data(), aImagData.Data(),
-                     aImagData.Length(), aRv);
+                     aImagData.Length(), aConstraints.mDisableNormalization,
+                     aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
   return periodicWave.forget();
 }
 
 AudioListener*
 AudioContext::Listener()
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -37,31 +37,33 @@ public:
     , mFrequency(440.f)
     , mDetune(0.f)
     , mType(OscillatorType::Sine)
     , mPhase(0.)
     , mFinalFrequency(0.)
     , mPhaseIncrement(0.)
     , mRecomputeParameters(true)
     , mCustomLength(0)
+    , mCustomDisableNormalization(false)
   {
     MOZ_ASSERT(NS_IsMainThread());
     mBasicWaveFormCache = aDestination->Context()->GetBasicWaveFormCache();
   }
 
   void SetSourceStream(AudioNodeStream* aSource)
   {
     mSource = aSource;
   }
 
   enum Parameters {
     FREQUENCY,
     DETUNE,
     TYPE,
-    PERIODICWAVE,
+    PERIODICWAVE_LENGTH,
+    DISABLE_NORMALIZATION,
     START,
     STOP,
   };
   void RecvTimelineEvent(uint32_t aIndex,
                          AudioTimelineEvent& aEvent) override
   {
     mRecomputeParameters = true;
 
@@ -99,16 +101,17 @@ public:
   {
     switch (aIndex) {
       case TYPE:
         // Set the new type.
         mType = static_cast<OscillatorType>(aParam);
         if (mType == OscillatorType::Sine) {
           // Forget any previous custom data.
           mCustomLength = 0;
+          mCustomDisableNormalization = false;
           mCustom = nullptr;
           mPeriodicWave = nullptr;
           mRecomputeParameters = true;
         }
         switch (mType) {
           case OscillatorType::Sine:
             mPhase = 0.0;
             break;
@@ -119,34 +122,41 @@ public:
             break;
           case OscillatorType::Custom:
             break;
           default:
             NS_ERROR("Bad OscillatorNodeEngine type parameter.");
         }
         // End type switch.
         break;
-      case PERIODICWAVE:
+      case PERIODICWAVE_LENGTH:
         MOZ_ASSERT(aParam >= 0, "negative custom array length");
         mCustomLength = static_cast<uint32_t>(aParam);
         break;
+      case DISABLE_NORMALIZATION:
+        MOZ_ASSERT(aParam >= 0, "negative custom array length");
+        mCustomDisableNormalization = static_cast<uint32_t>(aParam);
+        break;
       default:
         NS_ERROR("Bad OscillatorNodeEngine Int32Parameter.");
     }
     // End index switch.
   }
 
   void SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer) override
   {
     MOZ_ASSERT(mCustomLength, "Custom buffer sent before length");
     mCustom = aBuffer;
     MOZ_ASSERT(mCustom->GetChannels() == 2,
                "PeriodicWave should have sent two channels");
     mPeriodicWave = WebCore::PeriodicWave::create(mSource->SampleRate(),
-    mCustom->GetData(0), mCustom->GetData(1), mCustomLength);
+                                                  mCustom->GetData(0),
+                                                  mCustom->GetData(1),
+                                                  mCustomLength,
+                                                  mCustomDisableNormalization);
   }
 
   void IncrementPhase()
   {
     const float twoPiFloat = float(2 * M_PI);
     mPhase += mPhaseIncrement;
     if (mPhase > twoPiFloat) {
       mPhase -= twoPiFloat;
@@ -388,16 +398,17 @@ public:
   OscillatorType mType;
   float mPhase;
   float mFinalFrequency;
   float mPhaseIncrement;
   bool mRecomputeParameters;
   RefPtr<ThreadSharedFloatArrayBufferList> mCustom;
   RefPtr<BasicWaveFormCache> mBasicWaveFormCache;
   uint32_t mCustomLength;
+  bool mCustomDisableNormalization;
   RefPtr<WebCore::PeriodicWave> mPeriodicWave;
 };
 
 OscillatorNode::OscillatorNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Max,
               ChannelInterpretation::Speakers)
@@ -467,18 +478,20 @@ OscillatorNode::SendTypeToStream()
 }
 
 void OscillatorNode::SendPeriodicWaveToStream()
 {
   NS_ASSERTION(mType == OscillatorType::Custom,
                "Sending custom waveform to engine thread with non-custom type");
   MOZ_ASSERT(mStream, "Missing node stream.");
   MOZ_ASSERT(mPeriodicWave, "Send called without PeriodicWave object.");
-  SendInt32ParameterToStream(OscillatorNodeEngine::PERIODICWAVE,
+  SendInt32ParameterToStream(OscillatorNodeEngine::PERIODICWAVE_LENGTH,
                              mPeriodicWave->DataLength());
+  SendInt32ParameterToStream(OscillatorNodeEngine::DISABLE_NORMALIZATION,
+                             mPeriodicWave->DisableNormalization());
   RefPtr<ThreadSharedFloatArrayBufferList> data =
     mPeriodicWave->GetThreadSharedBuffer();
   mStream->SetBuffer(data.forget());
 }
 
 void
 OscillatorNode::Start(double aWhen, ErrorResult& aRv)
 {
--- a/dom/media/webaudio/PeriodicWave.cpp
+++ b/dom/media/webaudio/PeriodicWave.cpp
@@ -15,18 +15,20 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Pe
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PeriodicWave, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PeriodicWave, Release)
 
 PeriodicWave::PeriodicWave(AudioContext* aContext,
                            const float* aRealData,
                            const float* aImagData,
                            const uint32_t aLength,
+                           const bool aDisableNormalization,
                            ErrorResult& aRv)
   : mContext(aContext)
+  , mDisableNormalization(aDisableNormalization)
 {
   MOZ_ASSERT(aContext);
 
   // Caller should have checked this and thrown.
   MOZ_ASSERT(aLength > 0);
   mLength = aLength;
 
   // Copy coefficient data. The two arrays share an allocation.
--- a/dom/media/webaudio/PeriodicWave.h
+++ b/dom/media/webaudio/PeriodicWave.h
@@ -19,16 +19,17 @@ namespace dom {
 
 class PeriodicWave final : public nsWrapperCache
 {
 public:
   PeriodicWave(AudioContext* aContext,
                const float* aRealData,
                const float* aImagData,
                const uint32_t aLength,
+               const bool aDisableNormalization,
                ErrorResult& aRv);
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PeriodicWave)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(PeriodicWave)
 
   AudioContext* GetParentObject() const
   {
     return mContext;
@@ -36,28 +37,34 @@ public:
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   uint32_t DataLength() const
   {
     return mLength;
   }
 
+  bool DisableNormalization() const
+  {
+    return mDisableNormalization;
+  }
+
   ThreadSharedFloatArrayBufferList* GetThreadSharedBuffer() const
   {
     return mCoefficients;
   }
 
   size_t SizeOfExcludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const;
   size_t SizeOfIncludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const;
 
 private:
   ~PeriodicWave() {}
 
   RefPtr<AudioContext> mContext;
   RefPtr<ThreadSharedFloatArrayBufferList> mCoefficients;
   uint32_t mLength;
+  bool mDisableNormalization;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/media/webaudio/blink/PeriodicWave.cpp
+++ b/dom/media/webaudio/blink/PeriodicWave.cpp
@@ -40,23 +40,25 @@ using namespace mozilla;
 using mozilla::dom::OscillatorType;
 
 namespace WebCore {
 
 already_AddRefed<PeriodicWave>
 PeriodicWave::create(float sampleRate,
                      const float* real,
                      const float* imag,
-                     size_t numberOfComponents)
+                     size_t numberOfComponents,
+                     bool disableNormalization)
 {
     bool isGood = real && imag && numberOfComponents > 0;
     MOZ_ASSERT(isGood);
     if (isGood) {
         RefPtr<PeriodicWave> periodicWave =
-            new PeriodicWave(sampleRate, numberOfComponents);
+            new PeriodicWave(sampleRate, numberOfComponents,
+                             disableNormalization);
 
         // Limit the number of components used to those for frequencies below the
         // Nyquist of the fixed length inverse FFT.
         size_t halfSize = periodicWave->m_periodicWaveSize / 2;
         numberOfComponents = std::min(numberOfComponents, halfSize);
         periodicWave->m_numberOfComponents = numberOfComponents;
         periodicWave->m_realComponents = new AudioFloatArray(numberOfComponents);
         periodicWave->m_imagComponents = new AudioFloatArray(numberOfComponents);
@@ -69,53 +71,54 @@ PeriodicWave::create(float sampleRate,
     }
     return nullptr;
 }
 
 already_AddRefed<PeriodicWave>
 PeriodicWave::createSine(float sampleRate)
 {
     RefPtr<PeriodicWave> periodicWave =
-        new PeriodicWave(sampleRate, MinPeriodicWaveSize);
+        new PeriodicWave(sampleRate, MinPeriodicWaveSize, false);
     periodicWave->generateBasicWaveform(OscillatorType::Sine);
     return periodicWave.forget();
 }
 
 already_AddRefed<PeriodicWave>
 PeriodicWave::createSquare(float sampleRate)
 {
     RefPtr<PeriodicWave> periodicWave =
-        new PeriodicWave(sampleRate, MinPeriodicWaveSize);
+        new PeriodicWave(sampleRate, MinPeriodicWaveSize, false);
     periodicWave->generateBasicWaveform(OscillatorType::Square);
     return periodicWave.forget();
 }
 
 already_AddRefed<PeriodicWave>
 PeriodicWave::createSawtooth(float sampleRate)
 {
     RefPtr<PeriodicWave> periodicWave =
-        new PeriodicWave(sampleRate, MinPeriodicWaveSize);
+        new PeriodicWave(sampleRate, MinPeriodicWaveSize, false);
     periodicWave->generateBasicWaveform(OscillatorType::Sawtooth);
     return periodicWave.forget();
 }
 
 already_AddRefed<PeriodicWave>
 PeriodicWave::createTriangle(float sampleRate)
 {
     RefPtr<PeriodicWave> periodicWave =
-        new PeriodicWave(sampleRate, MinPeriodicWaveSize);
+        new PeriodicWave(sampleRate, MinPeriodicWaveSize, false);
     periodicWave->generateBasicWaveform(OscillatorType::Triangle);
     return periodicWave.forget();
 }
 
-PeriodicWave::PeriodicWave(float sampleRate, size_t numberOfComponents)
+PeriodicWave::PeriodicWave(float sampleRate, size_t numberOfComponents, bool disableNormalization)
     : m_sampleRate(sampleRate)
     , m_centsPerRange(CentsPerRange)
     , m_maxPartialsInBandLimitedTable(0)
     , m_normalizationScale(1.0f)
+    , m_disableNormalization(disableNormalization)
 {
     float nyquist = 0.5 * m_sampleRate;
 
     if (numberOfComponents <= MinPeriodicWaveSize) {
         m_periodicWaveSize = MinPeriodicWaveSize;
     } else {
         unsigned npow2 = powf(2.0f, floorf(logf(numberOfComponents - 1.0)/logf(2.0f) + 1.0f));
         m_periodicWaveSize = std::min(MaxPeriodicWaveSize, npow2);
@@ -266,26 +269,28 @@ void PeriodicWave::createBandLimitedTabl
     m_bandLimitedTables[rangeIndex] = table;
 
     // Apply an inverse FFT to generate the time-domain table data.
     float* data = m_bandLimitedTables[rangeIndex]->Elements();
     frame.GetInverseWithoutScaling(data);
 
     // For the first range (which has the highest power), calculate
     // its peak value then compute normalization scale.
-    if (!rangeIndex) {
+    if (!m_disableNormalization && !rangeIndex) {
         float maxValue;
         maxValue = AudioBufferPeakValue(data, m_periodicWaveSize);
 
         if (maxValue)
             m_normalizationScale = 1.0f / maxValue;
     }
 
     // Apply normalization scale.
-    AudioBufferInPlaceScale(data, m_normalizationScale, m_periodicWaveSize);
+    if (!m_disableNormalization) {
+      AudioBufferInPlaceScale(data, m_normalizationScale, m_periodicWaveSize);
+    }
 }
 
 void PeriodicWave::generateBasicWaveform(OscillatorType shape)
 {
     const float piFloat = float(M_PI);
     unsigned fftSize = periodicWaveSize();
     unsigned halfSize = fftSize / 2;
 
--- a/dom/media/webaudio/blink/PeriodicWave.h
+++ b/dom/media/webaudio/blink/PeriodicWave.h
@@ -49,17 +49,18 @@ public:
     static already_AddRefed<PeriodicWave> createSawtooth(float sampleRate);
     static already_AddRefed<PeriodicWave> createTriangle(float sampleRate);
 
     // Creates an arbitrary periodic wave given the frequency components
     // (Fourier coefficients).
     static already_AddRefed<PeriodicWave> create(float sampleRate,
                                                  const float* real,
                                                  const float* imag,
-                                                 size_t numberOfComponents);
+                                                 size_t numberOfComponents,
+                                                 bool disableNormalization);
 
     // Returns pointers to the lower and higher wave data for the pitch range
     // containing the given fundamental frequency. These two tables are in
     // adjacent "pitch" ranges where the higher table will have the maximum
     // number of partials which won't alias when played back at this
     // fundamental frequency. The lower wave is the next range containing fewer
     // partials than the higher wave. Interpolation between these two tables
     // can be made according to tableInterpolationFactor. Where values
@@ -71,17 +72,17 @@ public:
     float rateScale() const { return m_rateScale; }
 
     unsigned periodicWaveSize() const { return m_periodicWaveSize; }
     float sampleRate() const { return m_sampleRate; }
 
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
 private:
-    explicit PeriodicWave(float sampleRate, size_t numberOfComponents);
+    explicit PeriodicWave(float sampleRate, size_t numberOfComponents, bool disableNormalization);
     ~PeriodicWave() {}
 
     void generateBasicWaveform(mozilla::dom::OscillatorType);
 
     float m_sampleRate;
     unsigned m_periodicWaveSize;
     unsigned m_numberOfRanges;
     float m_centsPerRange;
@@ -103,14 +104,15 @@ private:
     unsigned maxNumberOfPartials() const;
 
     unsigned numberOfPartialsForRange(unsigned rangeIndex) const;
 
     // Creates table for specified index based on fundamental frequency.
     void createBandLimitedTables(float fundamentalFrequency, unsigned rangeIndex);
     unsigned m_maxPartialsInBandLimitedTable;
     float m_normalizationScale;
+    bool m_disableNormalization;
     nsTArray<nsAutoPtr<AlignedAudioFloatArray> > m_bandLimitedTables;
 };
 
 } // namespace WebCore
 
 #endif // PeriodicWave_h