b=815643 Use symmetry to halve the number of HRTF kernels calculated and cached r=ehsan
authorKarl Tomlinson <karlt+@karlt.net>
Thu, 08 Aug 2013 21:38:29 +1200
changeset 142357 c43863ae9218
parent 142356 214033794f62
child 142358 c56ecdd125ec
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 Use symmetry to halve the number of HRTF kernels calculated and cached r=ehsan
content/media/webaudio/blink/HRTFElevation.cpp
content/media/webaudio/blink/HRTFElevation.h
--- a/content/media/webaudio/blink/HRTFElevation.cpp
+++ b/content/media/webaudio/blink/HRTFElevation.cpp
@@ -47,18 +47,18 @@ namespace WebCore {
 const unsigned HRTFElevation::AzimuthSpacing = 15;
 const unsigned HRTFElevation::NumberOfRawAzimuths = 360 / AzimuthSpacing;
 const unsigned HRTFElevation::InterpolationFactor = 8;
 const unsigned HRTFElevation::NumberOfTotalAzimuths = NumberOfRawAzimuths * InterpolationFactor;
 
 // Number of frames in an individual impulse response.
 const size_t ResponseFrameSize = 256;
 
-bool HRTFElevation::calculateKernelsForAzimuthElevation(int azimuth, int elevation, float sampleRate, const String& subjectName,
-                                                        RefPtr<HRTFKernel>& kernelL, RefPtr<HRTFKernel>& kernelR)
+bool HRTFElevation::calculateKernelForAzimuthElevation(int azimuth, int elevation, float sampleRate, const String& subjectName,
+                                                       RefPtr<HRTFKernel>& kernelL)
 {
     // Valid values for azimuth are 0 -> 345 in 15 degree increments.
     // Valid values for elevation are -45 -> +90 in 15 degree increments.
 
     bool isAzimuthGood = azimuth >= 0 && azimuth <= 345 && (azimuth / 15) * 15 == azimuth;
     ASSERT(isAzimuthGood);
     if (!isAzimuthGood)
         return false;
@@ -87,26 +87,24 @@ bool HRTFElevation::calculateKernelsForA
 
     // Check number of channels and length.  For now these are fixed and known.
     bool isBusGood = responseLength == expectedLength && impulseResponse->numberOfChannels() == 2;
     ASSERT(isBusGood);
     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);
     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[] = {
@@ -141,75 +139,69 @@ static int maxElevations[] = {
 PassOwnPtr<HRTFElevation> HRTFElevation::createForSubject(const String& subjectName, int elevation, float sampleRate)
 {
     bool isElevationGood = elevation >= -45 && elevation <= 90 && (elevation / 15) * 15 == elevation;
     ASSERT(isElevationGood);
     if (!isElevationGood)
         return nullptr;
         
     OwnPtr<HRTFKernelList> kernelListL = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths));
-    OwnPtr<HRTFKernelList> kernelListR = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths));
 
     // Load convolution kernels from HRTF files.
     int interpolatedIndex = 0;
     for (unsigned rawIndex = 0; rawIndex < NumberOfRawAzimuths; ++rawIndex) {
         // Don't let elevation exceed maximum for this azimuth.
         int maxElevation = maxElevations[rawIndex];
         int actualElevation = min(elevation, maxElevation);
 
-        bool success = calculateKernelsForAzimuthElevation(rawIndex * AzimuthSpacing, actualElevation, sampleRate, subjectName, kernelListL->at(interpolatedIndex), kernelListR->at(interpolatedIndex));
+        bool success = calculateKernelForAzimuthElevation(rawIndex * AzimuthSpacing, actualElevation, sampleRate, subjectName, kernelListL->at(interpolatedIndex));
         if (!success)
             return nullptr;
             
         interpolatedIndex += InterpolationFactor;
     }
 
     // Now go back and interpolate intermediate azimuth values.
     for (unsigned i = 0; i < NumberOfTotalAzimuths; i += InterpolationFactor) {
         int j = (i + InterpolationFactor) % NumberOfTotalAzimuths;
 
         // Create the interpolated convolution kernels and delays.
         for (unsigned jj = 1; jj < InterpolationFactor; ++jj) {
             float x = float(jj) / float(InterpolationFactor); // interpolate from 0 -> 1
 
             (*kernelListL)[i + jj] = HRTFKernel::createInterpolatedKernel(kernelListL->at(i).get(), kernelListL->at(j).get(), x);
-            (*kernelListR)[i + jj] = HRTFKernel::createInterpolatedKernel(kernelListR->at(i).get(), kernelListR->at(j).get(), x);
         }
     }
     
-    OwnPtr<HRTFElevation> hrtfElevation = adoptPtr(new HRTFElevation(kernelListL.release(), kernelListR.release(), elevation, sampleRate));
+    OwnPtr<HRTFElevation> hrtfElevation = adoptPtr(new HRTFElevation(kernelListL.release(), elevation, sampleRate));
     return hrtfElevation.release();
 }
 
 PassOwnPtr<HRTFElevation> HRTFElevation::createByInterpolatingSlices(HRTFElevation* hrtfElevation1, HRTFElevation* hrtfElevation2, float x, float sampleRate)
 {
     ASSERT(hrtfElevation1 && hrtfElevation2);
     if (!hrtfElevation1 || !hrtfElevation2)
         return nullptr;
         
     ASSERT(x >= 0.0 && x < 1.0);
     
     OwnPtr<HRTFKernelList> kernelListL = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths));
-    OwnPtr<HRTFKernelList> kernelListR = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths));
 
     HRTFKernelList* kernelListL1 = hrtfElevation1->kernelListL();
-    HRTFKernelList* kernelListR1 = hrtfElevation1->kernelListR();
     HRTFKernelList* kernelListL2 = hrtfElevation2->kernelListL();
-    HRTFKernelList* kernelListR2 = hrtfElevation2->kernelListR();
     
     // Interpolate kernels of corresponding azimuths of the two elevations.
     for (unsigned i = 0; i < NumberOfTotalAzimuths; ++i) {
         (*kernelListL)[i] = HRTFKernel::createInterpolatedKernel(kernelListL1->at(i).get(), kernelListL2->at(i).get(), x);
-        (*kernelListR)[i] = HRTFKernel::createInterpolatedKernel(kernelListR1->at(i).get(), kernelListR2->at(i).get(), x);
     }
 
     // Interpolate elevation angle.
     double angle = (1.0 - x) * hrtfElevation1->elevationAngle() + x * hrtfElevation2->elevationAngle();
     
-    OwnPtr<HRTFElevation> hrtfElevation = adoptPtr(new HRTFElevation(kernelListL.release(), kernelListR.release(), static_cast<int>(angle), sampleRate));
+    OwnPtr<HRTFElevation> hrtfElevation = adoptPtr(new HRTFElevation(kernelListL.release(), static_cast<int>(angle), sampleRate));
     return hrtfElevation.release();  
 }
 
 void HRTFElevation::getKernelsFromAzimuth(double azimuthBlend, unsigned azimuthIndex, HRTFKernel* &kernelL, HRTFKernel* &kernelR, double& frameDelayL, double& frameDelayR)
 {
     bool checkAzimuthBlend = azimuthBlend >= 0.0 && azimuthBlend < 1.0;
     ASSERT(checkAzimuthBlend);
     if (!checkAzimuthBlend)
@@ -220,34 +212,36 @@ void HRTFElevation::getKernelsFromAzimut
     bool isIndexGood = azimuthIndex < numKernels;
     ASSERT(isIndexGood);
     if (!isIndexGood) {
         kernelL = 0;
         kernelR = 0;
         return;
     }
     
-    // Return the left and right kernels.
+    // Return the left and right kernels,
+    // using symmetry to produce the right kernel.
     kernelL = m_kernelListL->at(azimuthIndex).get();
-    kernelR = m_kernelListR->at(azimuthIndex).get();
+    int azimuthIndexR = (numKernels - azimuthIndex) % numKernels;
+    kernelR = m_kernelListL->at(azimuthIndexR).get();
 
-    frameDelayL = m_kernelListL->at(azimuthIndex)->frameDelay();
-    frameDelayR = m_kernelListR->at(azimuthIndex)->frameDelay();
+    frameDelayL = kernelL->frameDelay();
+    frameDelayR = kernelR->frameDelay();
 
-    int azimuthIndex2 = (azimuthIndex + 1) % numKernels;
-    double frameDelay2L = m_kernelListL->at(azimuthIndex2)->frameDelay();
-    double frameDelay2R = m_kernelListR->at(azimuthIndex2)->frameDelay();
+    int azimuthIndex2L = (azimuthIndex + 1) % numKernels;
+    double frameDelay2L = m_kernelListL->at(azimuthIndex2L)->frameDelay();
+    int azimuthIndex2R = (numKernels - azimuthIndex2L) % numKernels;
+    double frameDelay2R = m_kernelListL->at(azimuthIndex2R)->frameDelay();
 
     // Linearly interpolate delays.
     frameDelayL = (1.0 - azimuthBlend) * frameDelayL + azimuthBlend * frameDelay2L;
     frameDelayR = (1.0 - azimuthBlend) * frameDelayR + azimuthBlend * frameDelay2R;
 }
 
 void HRTFElevation::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
 {
     MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::AudioSharedData);
     info.addMember(m_kernelListL, "kernelListL");
-    info.addMember(m_kernelListR, "kernelListR");
 }
 
 } // namespace WebCore
 
 #endif // ENABLE(WEB_AUDIO)
--- a/content/media/webaudio/blink/HRTFElevation.h
+++ b/content/media/webaudio/blink/HRTFElevation.h
@@ -50,20 +50,16 @@ public:
     // Normally, there will only be a single HRTF database set, but this API supports the possibility of multiple ones with different names.
     // Interpolated azimuths will be generated based on InterpolationFactor.
     // Valid values for elevation are -45 -> +90 in 15 degree increments.
     static PassOwnPtr<HRTFElevation> createForSubject(const String& subjectName, int elevation, float sampleRate);
 
     // Given two HRTFElevations, and an interpolation factor x: 0 -> 1, returns an interpolated HRTFElevation.
     static PassOwnPtr<HRTFElevation> createByInterpolatingSlices(HRTFElevation* hrtfElevation1, HRTFElevation* hrtfElevation2, float x, float sampleRate);
 
-    // Returns the list of left or right ear HRTFKernels for all the azimuths going from 0 to 360 degrees.
-    HRTFKernelList* kernelListL() { return m_kernelListL.get(); }
-    HRTFKernelList* kernelListR() { return m_kernelListR.get(); }
-
     double elevationAngle() const { return m_elevationAngle; }
     unsigned numberOfAzimuths() const { return NumberOfTotalAzimuths; }
     float sampleRate() const { return m_sampleRate; }
     
     // Returns the left and right kernels for the given azimuth index.
     // The interpolated delays based on azimuthBlend: 0 -> 1 are returned in frameDelayL and frameDelayR.
     void getKernelsFromAzimuth(double azimuthBlend, unsigned azimuthIndex, HRTFKernel* &kernelL, HRTFKernel* &kernelR, double& frameDelayL, double& frameDelayR);
     
@@ -74,35 +70,36 @@ public:
     static const unsigned NumberOfRawAzimuths;
 
     // Interpolates by this factor to get the total number of azimuths from every azimuth loaded from resource.
     static const unsigned InterpolationFactor;
     
     // Total number of azimuths after interpolation.
     static const unsigned NumberOfTotalAzimuths;
 
-    // Given a specific azimuth and elevation angle, returns the left and right HRTFKernel.
-    // Valid values for azimuth are 0 -> 345 in 15 degree increments.
-    // Valid values for elevation are -45 -> +90 in 15 degree increments.
-    // Returns true on success.
-    static bool calculateKernelsForAzimuthElevation(int azimuth, int elevation, float sampleRate, const String& subjectName,
-                                                    RefPtr<HRTFKernel>& kernelL, RefPtr<HRTFKernel>& kernelR);
-
     void reportMemoryUsage(MemoryObjectInfo*) const;
 
 private:
-    HRTFElevation(PassOwnPtr<HRTFKernelList> kernelListL, PassOwnPtr<HRTFKernelList> kernelListR, int elevation, float sampleRate)
+    HRTFElevation(PassOwnPtr<HRTFKernelList> kernelListL, int elevation, float sampleRate)
         : m_kernelListL(kernelListL)
-        , m_kernelListR(kernelListR)
         , m_elevationAngle(elevation)
         , m_sampleRate(sampleRate)
     {
     }
 
+    // Returns the list of left ear HRTFKernels for all the azimuths going from 0 to 360 degrees.
+    HRTFKernelList* kernelListL() { return m_kernelListL.get(); }
+
+    // Given a specific azimuth and elevation angle, returns the left HRTFKernel.
+    // Valid values for azimuth are 0 -> 345 in 15 degree increments.
+    // Valid values for elevation are -45 -> +90 in 15 degree increments.
+    // Returns true on success.
+    static bool calculateKernelForAzimuthElevation(int azimuth, int elevation, float sampleRate, const String& subjectName,
+                                                   RefPtr<HRTFKernel>& kernelL);
+
     OwnPtr<HRTFKernelList> m_kernelListL;
-    OwnPtr<HRTFKernelList> m_kernelListR;
     double m_elevationAngle;
     float m_sampleRate;
 };
 
 } // namespace WebCore
 
 #endif // HRTFElevation_h