b=815643 Add Blink's HRTFKernel to the build r=ehsan
authorKarl Tomlinson <karlt+@karlt.net>
Thu, 08 Aug 2013 21:38:29 +1200
changeset 142356 214033794f62
parent 142355 5fd2ef2d9947
child 142357 c43863ae9218
push id32374
push userktomlinson@mozilla.com
push dateTue, 13 Aug 2013 02:49:14 +0000
treeherdermozilla-inbound@62ad090a94a4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs815643
milestone26.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
b=815643 Add Blink's HRTFKernel to the build r=ehsan A functional difference is that HRTFKernel is not reference-counted.
content/media/webaudio/blink/HRTFElevation.cpp
content/media/webaudio/blink/HRTFKernel.cpp
content/media/webaudio/blink/HRTFKernel.h
content/media/webaudio/blink/moz.build
--- a/content/media/webaudio/blink/HRTFElevation.cpp
+++ b/content/media/webaudio/blink/HRTFElevation.cpp
@@ -91,18 +91,22 @@ bool HRTFElevation::calculateKernelsForA
     if (!isBusGood)
         return false;
     
     AudioChannel* leftEarImpulseResponse = impulseResponse->channelByType(AudioBus::ChannelLeft);
     AudioChannel* rightEarImpulseResponse = impulseResponse->channelByType(AudioBus::ChannelRight);
 
     // Note that depending on the fftSize returned by the panner, we may be truncating the impulse response we just loaded in.
     const size_t fftSize = HRTFPanner::fftSizeForSampleRate(sampleRate);
-    kernelL = HRTFKernel::create(leftEarImpulseResponse, fftSize, sampleRate);
-    kernelR = HRTFKernel::create(rightEarImpulseResponse, fftSize, sampleRate);
+    MOZ_ASSERT(responseLength >= fftSize / 2);
+    if (responseLength < fftSize / 2)
+        return false;
+
+    kernelL = HRTFKernel::create(leftEarImpulseResponse, fftSize / 2, sampleRate);
+    kernelR = HRTFKernel::create(rightEarImpulseResponse, fftSize / 2, sampleRate);
     
     return true;
 }
 
 // The range of elevations for the IRCAM impulse responses varies depending on azimuth, but the minimum elevation appears to always be -45.
 //
 // Here's how it goes:
 static int maxElevations[] = {
--- a/content/media/webaudio/blink/HRTFKernel.cpp
+++ b/content/media/webaudio/blink/HRTFKernel.cpp
@@ -21,111 +21,79 @@
  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "config.h"
-
-#if ENABLE(WEB_AUDIO)
-
-#include "core/platform/audio/HRTFKernel.h"
-
-#include "core/platform/FloatConversion.h"
-#include "core/platform/PlatformMemoryInstrumentation.h"
-#include "core/platform/audio/AudioChannel.h"
-#include "core/platform/audio/FFTFrame.h"
-#include <wtf/MathExtras.h>
-
-using namespace std;
-
+#include "HRTFKernel.h"
 namespace WebCore {
 
-// Takes the input AudioChannel as an input impulse response and calculates the average group delay.
+// Takes the input audio channel |impulseP| as an input impulse response and calculates the average group delay.
 // This represents the initial delay before the most energetic part of the impulse response.
-// The sample-frame delay is removed from the impulseP impulse response, and this value  is returned.
-// the length of the passed in AudioChannel must be a power of 2.
-static float extractAverageGroupDelay(AudioChannel* channel, size_t analysisFFTSize)
+// The sample-frame delay is removed from the |impulseP| impulse response, and this value  is returned.
+// The |length| of the passed in |impulseP| must be must be a power of 2.
+static float extractAverageGroupDelay(float* impulseP, size_t length)
 {
-    ASSERT(channel);
-        
-    float* impulseP = channel->mutableData();
-    
-    bool isSizeGood = channel->length() >= analysisFFTSize;
-    ASSERT(isSizeGood);
-    if (!isSizeGood)
-        return 0;
-    
     // Check for power-of-2.
-    ASSERT(1UL << static_cast<unsigned>(log2(analysisFFTSize)) == analysisFFTSize);
+    MOZ_ASSERT(length && (length & (length - 1)) == 0);
 
-    FFTFrame estimationFrame(analysisFFTSize);
-    estimationFrame.doFFT(impulseP);
+    FFTBlock estimationFrame(length);
+    estimationFrame.PerformFFT(impulseP);
 
-    float frameDelay = narrowPrecisionToFloat(estimationFrame.extractAverageGroupDelay());
-    estimationFrame.doInverseFFT(impulseP);
+    float frameDelay = static_cast<float>(estimationFrame.ExtractAverageGroupDelay());
+    estimationFrame.PerformInverseFFT(impulseP);
 
     return frameDelay;
 }
 
-HRTFKernel::HRTFKernel(AudioChannel* channel, size_t fftSize, float sampleRate)
+HRTFKernel::HRTFKernel(float* impulseResponse, size_t length, float sampleRate)
     : m_frameDelay(0)
     , m_sampleRate(sampleRate)
 {
-    ASSERT(channel);
-
     // Determine the leading delay (average group delay) for the response.
-    m_frameDelay = extractAverageGroupDelay(channel, fftSize / 2);
+    m_frameDelay = extractAverageGroupDelay(impulseResponse, length);
 
-    float* impulseResponse = channel->mutableData();
-    size_t responseLength = channel->length();
-
-    // We need to truncate to fit into 1/2 the FFT size (with zero padding) in order to do proper convolution.
-    size_t truncatedResponseLength = min(responseLength, fftSize / 2); // truncate if necessary to max impulse response length allowed by FFT
+    // The FFT size (with zero padding) needs to be twice the response length
+    // in order to do proper convolution.
+    unsigned fftSize = 2 * length;
 
     // Quick fade-out (apply window) at truncation point
+    // because the impulse response has been truncated.
     unsigned numberOfFadeOutFrames = static_cast<unsigned>(sampleRate / 4410); // 10 sample-frames @44.1KHz sample-rate
-    ASSERT(numberOfFadeOutFrames < truncatedResponseLength);
-    if (numberOfFadeOutFrames < truncatedResponseLength) {
-        for (unsigned i = truncatedResponseLength - numberOfFadeOutFrames; i < truncatedResponseLength; ++i) {
-            float x = 1.0f - static_cast<float>(i - (truncatedResponseLength - numberOfFadeOutFrames)) / numberOfFadeOutFrames;
+    MOZ_ASSERT(numberOfFadeOutFrames < length);
+    if (numberOfFadeOutFrames < length) {
+        for (unsigned i = length - numberOfFadeOutFrames; i < length; ++i) {
+            float x = 1.0f - static_cast<float>(i - (length - numberOfFadeOutFrames)) / numberOfFadeOutFrames;
             impulseResponse[i] *= x;
         }
     }
 
-    m_fftFrame = adoptPtr(new FFTFrame(fftSize));
-    m_fftFrame->doPaddedFFT(impulseResponse, truncatedResponseLength);
+    m_fftFrame = new FFTBlock(fftSize);
+    m_fftFrame->PerformPaddedFFT(impulseResponse, length);
 }
 
 // Interpolates two kernels with x: 0 -> 1 and returns the result.
-PassRefPtr<HRTFKernel> HRTFKernel::createInterpolatedKernel(HRTFKernel* kernel1, HRTFKernel* kernel2, float x)
+nsReturnRef<HRTFKernel> HRTFKernel::createInterpolatedKernel(HRTFKernel* kernel1, HRTFKernel* kernel2, float x)
 {
-    ASSERT(kernel1 && kernel2);
+    MOZ_ASSERT(kernel1 && kernel2);
     if (!kernel1 || !kernel2)
-        return 0;
+        return nsReturnRef<HRTFKernel>();
  
-    ASSERT(x >= 0.0 && x < 1.0);
-    x = min(1.0f, max(0.0f, x));
+    MOZ_ASSERT(x >= 0.0 && x < 1.0);
+    x = mozilla::clamped(x, 0.0f, 1.0f);
     
     float sampleRate1 = kernel1->sampleRate();
     float sampleRate2 = kernel2->sampleRate();
-    ASSERT(sampleRate1 == sampleRate2);
+    MOZ_ASSERT(sampleRate1 == sampleRate2);
     if (sampleRate1 != sampleRate2)
-        return 0;
+        return nsReturnRef<HRTFKernel>();
     
     float frameDelay = (1 - x) * kernel1->frameDelay() + x * kernel2->frameDelay();
     
-    OwnPtr<FFTFrame> interpolatedFrame = FFTFrame::createInterpolatedFrame(*kernel1->fftFrame(), *kernel2->fftFrame(), x);
-    return HRTFKernel::create(interpolatedFrame.release(), frameDelay, sampleRate1);
-}
-
-void HRTFKernel::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
-{
-    MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::AudioSharedData);
-    info.addMember(m_fftFrame, "fftFrame");
+    nsAutoPtr<FFTBlock> interpolatedFrame(
+        FFTBlock::CreateInterpolatedBlock(*kernel1->fftFrame(), *kernel2->fftFrame(), x));
+    return HRTFKernel::create(interpolatedFrame, frameDelay, sampleRate1);
 }
 
 } // namespace WebCore
-
-#endif // ENABLE(WEB_AUDIO)
--- a/content/media/webaudio/blink/HRTFKernel.h
+++ b/content/media/webaudio/blink/HRTFKernel.h
@@ -24,74 +24,87 @@
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef HRTFKernel_h
 #define HRTFKernel_h
 
-#include "core/platform/audio/FFTFrame.h"
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
-#include <wtf/Vector.h>
+#include "nsAutoPtr.h"
+#include "nsAutoRef.h"
+#include "nsTArray.h"
+#include "mozilla/FFTBlock.h"
 
 namespace WebCore {
 
-class AudioChannel;
-    
+using mozilla::FFTBlock;
+
 // HRTF stands for Head-Related Transfer Function.
 // HRTFKernel is a frequency-domain representation of an impulse-response used as part of the spatialized panning system.
 // For a given azimuth / elevation angle there will be one HRTFKernel for the left ear transfer function, and one for the right ear.
 // The leading delay (average group delay) for each impulse response is extracted:
 //      m_fftFrame is the frequency-domain representation of the impulse response with the delay removed
 //      m_frameDelay is the leading delay of the original impulse response.
-class HRTFKernel : public RefCounted<HRTFKernel> {
+class HRTFKernel {
 public:
-    // Note: this is destructive on the passed in AudioChannel.
-    // The length of channel must be a power of two.
-    static PassRefPtr<HRTFKernel> create(AudioChannel* channel, size_t fftSize, float sampleRate)
-    {
-        return adoptRef(new HRTFKernel(channel, fftSize, sampleRate));
-    }
+    // Note: this is destructive on the passed in |impulseResponse|.
+    // The |length| of |impulseResponse| must be a power of two.
+    // The size of the DFT will be |2 * length|.
+    static nsReturnRef<HRTFKernel> create(float* impulseResponse, size_t length, float sampleRate);
 
-    static PassRefPtr<HRTFKernel> create(PassOwnPtr<FFTFrame> fftFrame, float frameDelay, float sampleRate)
-    {
-        return adoptRef(new HRTFKernel(fftFrame, frameDelay, sampleRate));
-    }
+    static nsReturnRef<HRTFKernel> create(nsAutoPtr<FFTBlock> fftFrame, float frameDelay, float sampleRate);
 
     // Given two HRTFKernels, and an interpolation factor x: 0 -> 1, returns an interpolated HRTFKernel.
-    static PassRefPtr<HRTFKernel> createInterpolatedKernel(HRTFKernel* kernel1, HRTFKernel* kernel2, float x);
+    static nsReturnRef<HRTFKernel> createInterpolatedKernel(HRTFKernel* kernel1, HRTFKernel* kernel2, float x);
   
-    FFTFrame* fftFrame() { return m_fftFrame.get(); }
+    FFTBlock* fftFrame() { return m_fftFrame.get(); }
     
-    size_t fftSize() const { return m_fftFrame->fftSize(); }
+    size_t fftSize() const { return m_fftFrame->FFTSize(); }
     float frameDelay() const { return m_frameDelay; }
 
     float sampleRate() const { return m_sampleRate; }
     double nyquist() const { return 0.5 * sampleRate(); }
 
-    void reportMemoryUsage(MemoryObjectInfo*) const;
+private:
+    HRTFKernel(const HRTFKernel& other) MOZ_DELETE;
+    void operator=(const HRTFKernel& other) MOZ_DELETE;
 
-private:
-    // Note: this is destructive on the passed in AudioChannel.
-    HRTFKernel(AudioChannel*, size_t fftSize, float sampleRate);
+    // Note: this is destructive on the passed in |impulseResponse|.
+    HRTFKernel(float* impulseResponse, size_t fftSize, float sampleRate);
     
-    HRTFKernel(PassOwnPtr<FFTFrame> fftFrame, float frameDelay, float sampleRate)
+    HRTFKernel(nsAutoPtr<FFTBlock> fftFrame, float frameDelay, float sampleRate)
         : m_fftFrame(fftFrame)
         , m_frameDelay(frameDelay)
         , m_sampleRate(sampleRate)
     {
     }
     
-    OwnPtr<FFTFrame> m_fftFrame;
+    nsAutoPtr<FFTBlock> m_fftFrame;
     float m_frameDelay;
     float m_sampleRate;
 };
 
-typedef Vector<RefPtr<HRTFKernel> > HRTFKernelList;
+typedef nsTArray<nsAutoRef<HRTFKernel> > HRTFKernelList;
 
 } // namespace WebCore
 
+template <>
+class nsAutoRefTraits<WebCore::HRTFKernel> :
+    public nsPointerRefTraits<WebCore::HRTFKernel> {
+public:
+    static void Release(WebCore::HRTFKernel* ptr) { delete(ptr); }
+};
+
+namespace WebCore {
+
+inline nsReturnRef<HRTFKernel> HRTFKernel::create(float* impulseResponse, size_t length, float sampleRate)
+{
+    return nsReturnRef<HRTFKernel>(new HRTFKernel(impulseResponse, length, sampleRate));
+}
+
+inline nsReturnRef<HRTFKernel> HRTFKernel::create(nsAutoPtr<FFTBlock> fftFrame, float frameDelay, float sampleRate)
+{
+    return nsReturnRef<HRTFKernel>(new HRTFKernel(fftFrame, frameDelay, sampleRate));
+}
+
+} // namespace WebCore
 #endif // HRTFKernel_h
--- a/content/media/webaudio/blink/moz.build
+++ b/content/media/webaudio/blink/moz.build
@@ -7,16 +7,17 @@
 MODULE = 'content'
 
 CPP_SOURCES += [
     'Biquad.cpp',
     'DirectConvolver.cpp',
     'DynamicsCompressor.cpp',
     'DynamicsCompressorKernel.cpp',
     'FFTConvolver.cpp',
+    'HRTFKernel.cpp',
     'Reverb.cpp',
     'ReverbAccumulationBuffer.cpp',
     'ReverbConvolver.cpp',
     'ReverbConvolverStage.cpp',
     'ReverbInputBuffer.cpp',
     'ZeroPole.cpp',
 ]