summaryrefslogtreecommitdiff
path: root/media/base/sinc_resampler.cc
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-05-09 18:35:53 +0100
committerTorne (Richard Coles) <torne@google.com>2013-05-13 13:57:14 +0100
commitc2e0dbddbe15c98d52c4786dac06cb8952a8ae6d (patch)
tree1dbdbb0624cc869ab25ee7f46971984c6fee3e7a /media/base/sinc_resampler.cc
parent2d519ce2457219605d4f472da8d2ffd469796035 (diff)
downloadchromium_org-c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d.tar.gz
Merge from Chromium at DEPS revision r198571
This commit was generated by merge_to_master.py. Change-Id: I951118a03836157090561764dd2627f0add8118f
Diffstat (limited to 'media/base/sinc_resampler.cc')
-rw-r--r--media/base/sinc_resampler.cc92
1 files changed, 69 insertions, 23 deletions
diff --git a/media/base/sinc_resampler.cc b/media/base/sinc_resampler.cc
index 00f9314c61..6bce67a3e7 100644
--- a/media/base/sinc_resampler.cc
+++ b/media/base/sinc_resampler.cc
@@ -37,6 +37,7 @@
#include "media/base/sinc_resampler.h"
#include <cmath>
+#include <limits>
#include "base/cpu.h"
#include "base/logging.h"
@@ -47,6 +48,22 @@
namespace media {
+static double SincScaleFactor(double io_ratio) {
+ // |sinc_scale_factor| is basically the normalized cutoff frequency of the
+ // low-pass filter.
+ double sinc_scale_factor = io_ratio > 1.0 ? 1.0 / io_ratio : 1.0;
+
+ // The sinc function is an idealized brick-wall filter, but since we're
+ // windowing it the transition from pass to stop does not happen right away.
+ // So we should adjust the low pass filter cutoff slightly downward to avoid
+ // some aliasing at the very high-end.
+ // TODO(crogers): this value is empirical and to be more exact should vary
+ // depending on kKernelSize.
+ sinc_scale_factor *= 0.9;
+
+ return sinc_scale_factor;
+}
+
SincResampler::SincResampler(double io_sample_rate_ratio, const ReadCB& read_cb)
: io_sample_rate_ratio_(io_sample_rate_ratio),
virtual_source_idx_(0),
@@ -55,6 +72,10 @@ SincResampler::SincResampler(double io_sample_rate_ratio, const ReadCB& read_cb)
// Create input buffers with a 16-byte alignment for SSE optimizations.
kernel_storage_(static_cast<float*>(
base::AlignedAlloc(sizeof(float) * kKernelStorageSize, 16))),
+ kernel_pre_sinc_storage_(static_cast<float*>(
+ base::AlignedAlloc(sizeof(float) * kKernelStorageSize, 16))),
+ kernel_window_storage_(static_cast<float*>(
+ base::AlignedAlloc(sizeof(float) * kKernelStorageSize, 16))),
input_buffer_(static_cast<float*>(
base::AlignedAlloc(sizeof(float) * kBufferSize, 16))),
#if defined(ARCH_CPU_X86_FAMILY) && !defined(__SSE__)
@@ -89,6 +110,10 @@ SincResampler::SincResampler(double io_sample_rate_ratio, const ReadCB& read_cb)
memset(kernel_storage_.get(), 0,
sizeof(*kernel_storage_.get()) * kKernelStorageSize);
+ memset(kernel_pre_sinc_storage_.get(), 0,
+ sizeof(*kernel_pre_sinc_storage_.get()) * kKernelStorageSize);
+ memset(kernel_window_storage_.get(), 0,
+ sizeof(*kernel_window_storage_.get()) * kKernelStorageSize);
memset(input_buffer_.get(), 0, sizeof(*input_buffer_.get()) * kBufferSize);
InitializeKernel();
@@ -103,38 +128,59 @@ void SincResampler::InitializeKernel() {
static const double kA1 = 0.5;
static const double kA2 = 0.5 * kAlpha;
- // |sinc_scale_factor| is basically the normalized cutoff frequency of the
- // low-pass filter.
- double sinc_scale_factor =
- io_sample_rate_ratio_ > 1.0 ? 1.0 / io_sample_rate_ratio_ : 1.0;
-
- // The sinc function is an idealized brick-wall filter, but since we're
- // windowing it the transition from pass to stop does not happen right away.
- // So we should adjust the low pass filter cutoff slightly downward to avoid
- // some aliasing at the very high-end.
- // TODO(crogers): this value is empirical and to be more exact should vary
- // depending on kKernelSize.
- sinc_scale_factor *= 0.9;
-
// Generates a set of windowed sinc() kernels.
// We generate a range of sub-sample offsets from 0.0 to 1.0.
+ const double sinc_scale_factor = SincScaleFactor(io_sample_rate_ratio_);
for (int offset_idx = 0; offset_idx <= kKernelOffsetCount; ++offset_idx) {
- double subsample_offset =
- static_cast<double>(offset_idx) / kKernelOffsetCount;
+ const float subsample_offset =
+ static_cast<float>(offset_idx) / kKernelOffsetCount;
for (int i = 0; i < kKernelSize; ++i) {
- // Compute the sinc with offset.
- double s =
- sinc_scale_factor * M_PI * (i - kKernelSize / 2 - subsample_offset);
- double sinc = (!s ? 1.0 : sin(s) / s) * sinc_scale_factor;
+ const int idx = i + offset_idx * kKernelSize;
+ const float pre_sinc = M_PI * (i - kKernelSize / 2 - subsample_offset);
+ kernel_pre_sinc_storage_[idx] = pre_sinc;
// Compute Blackman window, matching the offset of the sinc().
- double x = (i - subsample_offset) / kKernelSize;
- double window = kA0 - kA1 * cos(2.0 * M_PI * x) + kA2
+ const float x = (i - subsample_offset) / kKernelSize;
+ const float window = kA0 - kA1 * cos(2.0 * M_PI * x) + kA2
* cos(4.0 * M_PI * x);
+ kernel_window_storage_[idx] = window;
+
+ // Compute the sinc with offset, then window the sinc() function and store
+ // at the correct offset.
+ if (pre_sinc == 0) {
+ kernel_storage_[idx] = sinc_scale_factor * window;
+ } else {
+ kernel_storage_[idx] =
+ window * sin(sinc_scale_factor * pre_sinc) / pre_sinc;
+ }
+ }
+ }
+}
+
+void SincResampler::SetRatio(double io_sample_rate_ratio) {
+ if (fabs(io_sample_rate_ratio_ - io_sample_rate_ratio) <
+ std::numeric_limits<double>::epsilon()) {
+ return;
+ }
+
+ io_sample_rate_ratio_ = io_sample_rate_ratio;
- // Window the sinc() function and store at the correct offset.
- kernel_storage_.get()[i + offset_idx * kKernelSize] = sinc * window;
+ // Optimize reinitialization by reusing values which are independent of
+ // |sinc_scale_factor|. Provides a 3x speedup.
+ const double sinc_scale_factor = SincScaleFactor(io_sample_rate_ratio_);
+ for (int offset_idx = 0; offset_idx <= kKernelOffsetCount; ++offset_idx) {
+ for (int i = 0; i < kKernelSize; ++i) {
+ const int idx = i + offset_idx * kKernelSize;
+ const float window = kernel_window_storage_[idx];
+ const float pre_sinc = kernel_pre_sinc_storage_[idx];
+
+ if (pre_sinc == 0) {
+ kernel_storage_[idx] = sinc_scale_factor * window;
+ } else {
+ kernel_storage_[idx] =
+ window * sin(sinc_scale_factor * pre_sinc) / pre_sinc;
+ }
}
}
}