Bug 1265405 - Use a dictionary to specify how PeriodicWave should be normalized (or not); r?padenot draft
authorDan Minor <dminor@mozilla.com>
Wed, 20 Apr 2016 15:20:38 -0400
changeset 355383 855b5072a2b493931c1d4639ead00a3f0c98cc92
parent 355382 658bfb54810c850d6313ef101c0b0bbfb9c8bef1
child 355384 532c6cfa3cae75d1952ca3fe7cee188cf7ea02d6
push id16273
push userdminor@mozilla.com
push dateFri, 22 Apr 2016 13:53:55 +0000
reviewerspadenot
bugs1265405
milestone48.0a1
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,51 +71,52 @@ 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_disableNormalization(disableNormalization)
     , m_maxPartialsInBandLimitedTable(0)
     , m_normalizationScale(1.0f)
 {
     float nyquist = 0.5 * m_sampleRate;
 
     if (numberOfComponents <= MinPeriodicWaveSize) {
         m_periodicWaveSize = MinPeriodicWaveSize;
     } else {
@@ -262,26 +265,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