andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| 11 | // Modified from the Chromium original: |
| 12 | // src/media/base/sinc_resampler.cc |
| 13 | |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 14 | // Input buffer layout, dividing the total buffer into regions (r0_ - r5_): |
| 15 | // |
| 16 | // |----------------|-----------------------------------------|----------------| |
| 17 | // |
| 18 | // kBlockSize + kKernelSize / 2 |
| 19 | // <---------------------------------------------------------> |
| 20 | // r0_ |
| 21 | // |
| 22 | // kKernelSize / 2 kKernelSize / 2 kKernelSize / 2 kKernelSize / 2 |
| 23 | // <---------------> <---------------> <---------------> <---------------> |
| 24 | // r1_ r2_ r3_ r4_ |
| 25 | // |
| 26 | // kBlockSize |
| 27 | // <---------------------------------------> |
| 28 | // r5_ |
| 29 | // |
| 30 | // The algorithm: |
| 31 | // |
| 32 | // 1) Consume input frames into r0_ (r1_ is zero-initialized). |
| 33 | // 2) Position kernel centered at start of r0_ (r2_) and generate output frames |
| 34 | // until kernel is centered at start of r4_ or we've finished generating all |
| 35 | // the output frames. |
| 36 | // 3) Copy r3_ to r1_ and r4_ to r2_. |
| 37 | // 4) Consume input frames into r5_ (zero-pad if we run out of input). |
| 38 | // 5) Goto (2) until all of input is consumed. |
| 39 | // |
| 40 | // Note: we're glossing over how the sub-sample handling works with |
| 41 | // |virtual_source_idx_|, etc. |
| 42 | |
| 43 | // MSVC++ requires this to be set before any other includes to get M_PI. |
| 44 | #define _USE_MATH_DEFINES |
| 45 | |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 46 | #include "webrtc/common_audio/resampler/sinc_resampler.h" |
| 47 | #include "webrtc/system_wrappers/interface/compile_assert.h" |
| 48 | #include "webrtc/system_wrappers/interface/cpu_features_wrapper.h" |
| 49 | #include "webrtc/typedefs.h" |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 50 | |
| 51 | #include <cmath> |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 52 | #include <cstring> |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 53 | #include <limits> |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 54 | |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 55 | namespace webrtc { |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 56 | |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 57 | static double SincScaleFactor(double io_ratio) { |
| 58 | // |sinc_scale_factor| is basically the normalized cutoff frequency of the |
| 59 | // low-pass filter. |
| 60 | double sinc_scale_factor = io_ratio > 1.0 ? 1.0 / io_ratio : 1.0; |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 61 | |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 62 | // The sinc function is an idealized brick-wall filter, but since we're |
| 63 | // windowing it the transition from pass to stop does not happen right away. |
| 64 | // So we should adjust the low pass filter cutoff slightly downward to avoid |
| 65 | // some aliasing at the very high-end. |
| 66 | // TODO(crogers): this value is empirical and to be more exact should vary |
| 67 | // depending on kKernelSize. |
| 68 | sinc_scale_factor *= 0.9; |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 69 | |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 70 | return sinc_scale_factor; |
| 71 | } |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 72 | |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 73 | SincResampler::SincResampler(double io_sample_rate_ratio, |
| 74 | SincResamplerCallback* read_cb, |
| 75 | int block_size) |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 76 | : io_sample_rate_ratio_(io_sample_rate_ratio), |
| 77 | virtual_source_idx_(0), |
| 78 | buffer_primed_(false), |
| 79 | read_cb_(read_cb), |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 80 | block_size_(block_size), |
| 81 | buffer_size_(block_size_ + kKernelSize), |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 82 | // Create input buffers with a 16-byte alignment for SSE optimizations. |
| 83 | kernel_storage_(static_cast<float*>( |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 84 | AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))), |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 85 | kernel_pre_sinc_storage_(static_cast<float*>( |
| 86 | AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))), |
| 87 | kernel_window_storage_(static_cast<float*>( |
| 88 | AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))), |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 89 | input_buffer_(static_cast<float*>( |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 90 | AlignedMalloc(sizeof(float) * buffer_size_, 16))), |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 91 | #if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE__) |
| 92 | convolve_proc_(WebRtc_GetCPUInfo(kSSE2) ? Convolve_SSE : Convolve_C), |
| 93 | #elif defined(WEBRTC_ARCH_ARM_V7) && !defined(WEBRTC_ARCH_ARM_NEON) |
| 94 | convolve_proc_(WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON ? |
| 95 | Convolve_NEON : Convolve_C), |
| 96 | #endif |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 97 | // Setup various region pointers in the buffer (see diagram above). |
| 98 | r0_(input_buffer_.get() + kKernelSize / 2), |
| 99 | r1_(input_buffer_.get()), |
| 100 | r2_(r0_), |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 101 | r3_(r0_ + block_size_ - kKernelSize / 2), |
| 102 | r4_(r0_ + block_size_), |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 103 | r5_(r0_ + kKernelSize / 2) { |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 104 | Initialize(); |
| 105 | InitializeKernel(); |
| 106 | } |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 107 | |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 108 | SincResampler::SincResampler(double io_sample_rate_ratio, |
| 109 | SincResamplerCallback* read_cb) |
| 110 | : io_sample_rate_ratio_(io_sample_rate_ratio), |
| 111 | virtual_source_idx_(0), |
| 112 | buffer_primed_(false), |
| 113 | read_cb_(read_cb), |
| 114 | block_size_(kDefaultBlockSize), |
| 115 | buffer_size_(kDefaultBufferSize), |
| 116 | // Create input buffers with a 16-byte alignment for SSE optimizations. |
| 117 | kernel_storage_(static_cast<float*>( |
| 118 | AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))), |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 119 | kernel_pre_sinc_storage_(static_cast<float*>( |
| 120 | AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))), |
| 121 | kernel_window_storage_(static_cast<float*>( |
| 122 | AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))), |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 123 | input_buffer_(static_cast<float*>( |
| 124 | AlignedMalloc(sizeof(float) * buffer_size_, 16))), |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 125 | #if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE__) |
| 126 | convolve_proc_(WebRtc_GetCPUInfo(kSSE2) ? Convolve_SSE : Convolve_C), |
| 127 | #elif defined(WEBRTC_ARCH_ARM_V7) && !defined(WEBRTC_ARCH_ARM_NEON) |
| 128 | convolve_proc_(WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON ? |
| 129 | Convolve_NEON : Convolve_C), |
| 130 | #endif |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 131 | // Setup various region pointers in the buffer (see diagram above). |
| 132 | r0_(input_buffer_.get() + kKernelSize / 2), |
| 133 | r1_(input_buffer_.get()), |
| 134 | r2_(r0_), |
| 135 | r3_(r0_ + block_size_ - kKernelSize / 2), |
| 136 | r4_(r0_ + block_size_), |
| 137 | r5_(r0_ + kKernelSize / 2) { |
| 138 | Initialize(); |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 139 | InitializeKernel(); |
| 140 | } |
| 141 | |
| 142 | SincResampler::~SincResampler() {} |
| 143 | |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 144 | void SincResampler::Initialize() { |
| 145 | // Ensure kKernelSize is a multiple of 32 for easy SSE optimizations; causes |
| 146 | // r0_ and r5_ (used for input) to always be 16-byte aligned by virtue of |
| 147 | // input_buffer_ being 16-byte aligned. |
| 148 | COMPILE_ASSERT(kKernelSize % 32 == 0); |
| 149 | assert(block_size_ > kKernelSize); |
| 150 | // Basic sanity checks to ensure buffer regions are laid out correctly: |
| 151 | // r0_ and r2_ should always be the same position. |
| 152 | assert(r0_ == r2_); |
| 153 | // r1_ at the beginning of the buffer. |
| 154 | assert(r1_ == input_buffer_.get()); |
| 155 | // r1_ left of r2_, r2_ left of r5_ and r1_, r2_ size correct. |
| 156 | assert(r2_ - r1_ == r5_ - r2_); |
| 157 | // r3_ left of r4_, r5_ left of r0_ and r3_ size correct. |
| 158 | assert(r4_ - r3_ == r5_ - r0_); |
| 159 | // r3_, r4_ size correct and r4_ at the end of the buffer. |
| 160 | assert(r4_ + (r4_ - r3_) == r1_ + buffer_size_); |
| 161 | // r5_ size correct and at the end of the buffer. |
| 162 | assert(r5_ + block_size_ == r1_ + buffer_size_); |
| 163 | |
| 164 | memset(kernel_storage_.get(), 0, |
| 165 | sizeof(*kernel_storage_.get()) * kKernelStorageSize); |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 166 | memset(kernel_pre_sinc_storage_.get(), 0, |
| 167 | sizeof(*kernel_pre_sinc_storage_.get()) * kKernelStorageSize); |
| 168 | memset(kernel_window_storage_.get(), 0, |
| 169 | sizeof(*kernel_window_storage_.get()) * kKernelStorageSize); |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 170 | memset(input_buffer_.get(), 0, sizeof(*input_buffer_.get()) * buffer_size_); |
| 171 | } |
| 172 | |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 173 | void SincResampler::InitializeKernel() { |
| 174 | // Blackman window parameters. |
| 175 | static const double kAlpha = 0.16; |
| 176 | static const double kA0 = 0.5 * (1.0 - kAlpha); |
| 177 | static const double kA1 = 0.5; |
| 178 | static const double kA2 = 0.5 * kAlpha; |
| 179 | |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 180 | // Generates a set of windowed sinc() kernels. |
| 181 | // We generate a range of sub-sample offsets from 0.0 to 1.0. |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 182 | const double sinc_scale_factor = SincScaleFactor(io_sample_rate_ratio_); |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 183 | for (int offset_idx = 0; offset_idx <= kKernelOffsetCount; ++offset_idx) { |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 184 | const float subsample_offset = |
| 185 | static_cast<float>(offset_idx) / kKernelOffsetCount; |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 186 | |
| 187 | for (int i = 0; i < kKernelSize; ++i) { |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 188 | const int idx = i + offset_idx * kKernelSize; |
| 189 | const float pre_sinc = M_PI * (i - kKernelSize / 2 - subsample_offset); |
| 190 | kernel_pre_sinc_storage_.get()[idx] = pre_sinc; |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 191 | |
| 192 | // Compute Blackman window, matching the offset of the sinc(). |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 193 | const float x = (i - subsample_offset) / kKernelSize; |
| 194 | const float window = kA0 - kA1 * cos(2.0 * M_PI * x) + kA2 |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 195 | * cos(4.0 * M_PI * x); |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 196 | kernel_window_storage_.get()[idx] = window; |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 197 | |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 198 | // Compute the sinc with offset, then window the sinc() function and store |
| 199 | // at the correct offset. |
| 200 | if (pre_sinc == 0) { |
| 201 | kernel_storage_.get()[idx] = sinc_scale_factor * window; |
| 202 | } else { |
| 203 | kernel_storage_.get()[idx] = |
| 204 | window * sin(sinc_scale_factor * pre_sinc) / pre_sinc; |
| 205 | } |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 206 | } |
| 207 | } |
| 208 | } |
| 209 | |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 210 | void SincResampler::SetRatio(double io_sample_rate_ratio) { |
| 211 | if (fabs(io_sample_rate_ratio_ - io_sample_rate_ratio) < |
| 212 | std::numeric_limits<double>::epsilon()) { |
| 213 | return; |
| 214 | } |
| 215 | |
| 216 | io_sample_rate_ratio_ = io_sample_rate_ratio; |
| 217 | |
| 218 | // Optimize reinitialization by reusing values which are independent of |
| 219 | // |sinc_scale_factor|. Provides a 3x speedup. |
| 220 | const double sinc_scale_factor = SincScaleFactor(io_sample_rate_ratio_); |
| 221 | for (int offset_idx = 0; offset_idx <= kKernelOffsetCount; ++offset_idx) { |
| 222 | for (int i = 0; i < kKernelSize; ++i) { |
| 223 | const int idx = i + offset_idx * kKernelSize; |
| 224 | const float window = kernel_window_storage_.get()[idx]; |
| 225 | const float pre_sinc = kernel_pre_sinc_storage_.get()[idx]; |
| 226 | |
| 227 | if (pre_sinc == 0) { |
| 228 | kernel_storage_.get()[idx] = sinc_scale_factor * window; |
| 229 | } else { |
| 230 | kernel_storage_.get()[idx] = |
| 231 | window * sin(sinc_scale_factor * pre_sinc) / pre_sinc; |
| 232 | } |
| 233 | } |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | // If we know the minimum architecture avoid function hopping for CPU detection. |
| 238 | #if defined(WEBRTC_ARCH_X86_FAMILY) |
| 239 | #if defined(__SSE__) |
| 240 | #define CONVOLVE_FUNC Convolve_SSE |
| 241 | #else |
| 242 | // X86 CPU detection required. |convolve_proc_| will be set upon construction. |
| 243 | // TODO(dalecurtis): Once Chrome moves to a SSE baseline this can be removed. |
| 244 | #define CONVOLVE_FUNC convolve_proc_ |
| 245 | #endif |
| 246 | #elif defined(WEBRTC_ARCH_ARM_V7) |
| 247 | #if defined(WEBRTC_ARCH_ARM_NEON) |
| 248 | #define CONVOLVE_FUNC Convolve_NEON |
| 249 | #else |
| 250 | // NEON CPU detection required. |convolve_proc_| will be set upon construction. |
| 251 | #define CONVOLVE_FUNC convolve_proc_ |
| 252 | #endif |
| 253 | #else |
| 254 | // Unknown architecture. |
| 255 | #define CONVOLVE_FUNC Convolve_C |
| 256 | #endif |
| 257 | |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 258 | void SincResampler::Resample(float* destination, int frames) { |
| 259 | int remaining_frames = frames; |
| 260 | |
| 261 | // Step (1) -- Prime the input buffer at the start of the input stream. |
| 262 | if (!buffer_primed_) { |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 263 | read_cb_->Run(r0_, block_size_ + kKernelSize / 2); |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 264 | buffer_primed_ = true; |
| 265 | } |
| 266 | |
| 267 | // Step (2) -- Resample! |
| 268 | while (remaining_frames) { |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 269 | while (virtual_source_idx_ < block_size_) { |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 270 | // |virtual_source_idx_| lies in between two kernel offsets so figure out |
| 271 | // what they are. |
| 272 | int source_idx = static_cast<int>(virtual_source_idx_); |
| 273 | double subsample_remainder = virtual_source_idx_ - source_idx; |
| 274 | |
| 275 | double virtual_offset_idx = subsample_remainder * kKernelOffsetCount; |
| 276 | int offset_idx = static_cast<int>(virtual_offset_idx); |
| 277 | |
| 278 | // We'll compute "convolutions" for the two kernels which straddle |
| 279 | // |virtual_source_idx_|. |
| 280 | float* k1 = kernel_storage_.get() + offset_idx * kKernelSize; |
| 281 | float* k2 = k1 + kKernelSize; |
| 282 | |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 283 | // Ensure |k1|, |k2| are 16-byte aligned for SIMD usage. Should always be |
| 284 | // true so long as kKernelSize is a multiple of 16. |
| 285 | assert((reinterpret_cast<uintptr_t>(k1) & 0x0F) == 0u); |
| 286 | assert((reinterpret_cast<uintptr_t>(k2) & 0x0F) == 0u); |
| 287 | |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 288 | // Initialize input pointer based on quantized |virtual_source_idx_|. |
| 289 | float* input_ptr = r1_ + source_idx; |
| 290 | |
| 291 | // Figure out how much to weight each kernel's "convolution". |
| 292 | double kernel_interpolation_factor = virtual_offset_idx - offset_idx; |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 293 | *destination++ = CONVOLVE_FUNC( |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 294 | input_ptr, k1, k2, kernel_interpolation_factor); |
| 295 | |
| 296 | // Advance the virtual index. |
| 297 | virtual_source_idx_ += io_sample_rate_ratio_; |
| 298 | |
| 299 | if (!--remaining_frames) |
| 300 | return; |
| 301 | } |
| 302 | |
| 303 | // Wrap back around to the start. |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 304 | virtual_source_idx_ -= block_size_; |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 305 | |
| 306 | // Step (3) Copy r3_ to r1_ and r4_ to r2_. |
| 307 | // This wraps the last input frames back to the start of the buffer. |
| 308 | memcpy(r1_, r3_, sizeof(*input_buffer_.get()) * (kKernelSize / 2)); |
| 309 | memcpy(r2_, r4_, sizeof(*input_buffer_.get()) * (kKernelSize / 2)); |
| 310 | |
| 311 | // Step (4) |
| 312 | // Refresh the buffer with more input. |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 313 | read_cb_->Run(r5_, block_size_); |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 314 | } |
| 315 | } |
| 316 | |
andrew@webrtc.org | 5dea86a | 2013-05-08 20:35:43 +0000 | [diff] [blame] | 317 | #undef CONVOLVE_FUNC |
| 318 | |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 319 | int SincResampler::ChunkSize() { |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 320 | return block_size_ / io_sample_rate_ratio_; |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 321 | } |
| 322 | |
andrew@webrtc.org | dea537b | 2013-04-26 14:56:51 +0000 | [diff] [blame] | 323 | int SincResampler::BlockSize() { |
| 324 | return block_size_; |
| 325 | } |
| 326 | |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 327 | void SincResampler::Flush() { |
| 328 | virtual_source_idx_ = 0; |
| 329 | buffer_primed_ = false; |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 330 | memset(input_buffer_.get(), 0, sizeof(*input_buffer_.get()) * buffer_size_); |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 331 | } |
| 332 | |
andrew@webrtc.org | 13e46dc | 2013-02-13 23:00:49 +0000 | [diff] [blame] | 333 | float SincResampler::Convolve_C(const float* input_ptr, const float* k1, |
| 334 | const float* k2, |
| 335 | double kernel_interpolation_factor) { |
| 336 | float sum1 = 0; |
| 337 | float sum2 = 0; |
| 338 | |
| 339 | // Generate a single output sample. Unrolling this loop hurt performance in |
| 340 | // local testing. |
| 341 | int n = kKernelSize; |
| 342 | while (n--) { |
| 343 | sum1 += *input_ptr * *k1++; |
| 344 | sum2 += *input_ptr++ * *k2++; |
| 345 | } |
| 346 | |
| 347 | // Linearly interpolate the two "convolutions". |
| 348 | return (1.0 - kernel_interpolation_factor) * sum1 |
| 349 | + kernel_interpolation_factor * sum2; |
| 350 | } |
| 351 | |
andrew@webrtc.org | 4e91d4a | 2013-02-15 03:54:22 +0000 | [diff] [blame] | 352 | } // namespace webrtc |