b=815643 Reduce convolver fft size for low sample rates r=ehsan
authorKarl Tomlinson <karlt+@karlt.net>
Thu, 08 Aug 2013 21:38:30 +1200
changeset 142360 5a05c2215091
parent 142359 9b01d3f61a1b
child 142361 395fc5b9593c
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 Reduce convolver fft size for low sample rates r=ehsan
content/media/webaudio/blink/HRTFElevation.cpp
--- a/content/media/webaudio/blink/HRTFElevation.cpp
+++ b/content/media/webaudio/blink/HRTFElevation.cpp
@@ -58,21 +58,45 @@ const unsigned HRTFElevation::NumberOfTo
 
 const int rawSampleRate = irc_composite_c_r0195_sample_rate;
 
 // Number of frames in an individual impulse response.
 const size_t ResponseFrameSize = 256;
 
 size_t HRTFElevation::fftSizeForSampleRate(float sampleRate)
 {
-    // The HRTF impulse responses (loaded as audio resources) are 512 sample-frames @44.1KHz.
-    // Currently, we truncate the impulse responses to half this size, but an FFT-size of twice impulse response size is needed (for convolution).
-    // So for sample rates around 44.1KHz an FFT size of 512 is good. We double the FFT-size only for sample rates at least double this.
-    ASSERT(sampleRate >= 44100 && sampleRate <= 96000.0);
-    return (sampleRate < 88200.0) ? 512 : 1024;
+    // The IRCAM HRTF impulse responses were 512 sample-frames @44.1KHz,
+    // but these have been truncated to 256 samples.
+    // An FFT-size of twice impulse response size is used (for convolution).
+    // So for sample rates of 44.1KHz an FFT size of 512 is good.
+    // We double the FFT-size only for sample rates at least double this.
+    // If the FFT size is too large then the impulse response will be padded
+    // with zeros without the fade-out provided by HRTFKernel.
+    MOZ_ASSERT(sampleRate > 1.0 && sampleRate < 1048576.0);
+
+    // This is the size if we were to use all raw response samples.
+    unsigned resampledLength =
+        floorf(ResponseFrameSize * sampleRate / rawSampleRate);
+    // Keep things semi-sane, with max FFT size of 1024 and minimum of 4.
+    // "size |= 3" ensures a minimum of 4 (with the size++ below) and sets the
+    // 2 least significant bits for rounding up to the next power of 2 below.
+    unsigned size = min(resampledLength, 1023U);
+    size |= 3;
+    // Round up to the next power of 2, making the FFT size no more than twice
+    // the impulse response length.  This doubles size for values that are
+    // already powers of 2.  This works by filling in 7 bits to right of the
+    // most significant bit.  The most significant bit is no greater than
+    // 1 << 9, and the least significant 2 bits were already set above.
+    size |= (size >> 1);
+    size |= (size >> 2);
+    size |= (size >> 4);
+    size++;
+    MOZ_ASSERT((size & (size - 1)) == 0);
+
+    return size;
 }
 
 bool HRTFElevation::calculateKernelForAzimuthElevation(int azimuth, int elevation, SpeexResamplerState* resampler, float sampleRate,
                                                        RefPtr<HRTFKernel>& kernelL)
 {
     int elevationIndex = (elevation - firstElevation) / elevationSpacing;
     MOZ_ASSERT(elevationIndex >= 0 && elevationIndex <= numberOfElevations);
 
@@ -117,17 +141,17 @@ bool HRTFElevation::calculateKernelForAz
             nsAutoTArray<float, 256> zeros;
             zeros.SetLength(in_len);
             PodZero(zeros.Elements(), in_len);
             out_len = resampled.Length() - out_index;
             speex_resampler_process_float(resampler, 0,
                                           zeros.Elements(), &in_len,
                                           response + out_index, &out_len);
             out_index += out_len;
-            // There may be some uninitialized samples remaining for low
+            // There may be some uninitialized samples remaining for very low
             // sample rates.
             PodZero(response + out_index, resampled.Length() - out_index);
         }
 
         speex_resampler_reset_mem(resampler);
     }
 
     kernelL = HRTFKernel::create(response, responseLength, sampleRate);