| /* |
| * Copyright (C) 2013 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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 "platform/audio/UpSampler.h" |
| #include "platform/wtf/MathExtras.h" |
| |
| namespace blink { |
| |
| UpSampler::UpSampler(size_t input_block_size) |
| : input_block_size_(input_block_size), |
| kernel_(kDefaultKernelSize), |
| convolver_(input_block_size), |
| temp_buffer_(input_block_size), |
| input_buffer_(input_block_size * 2) { |
| InitializeKernel(); |
| } |
| |
| void UpSampler::InitializeKernel() { |
| // Blackman window parameters. |
| double alpha = 0.16; |
| double a0 = 0.5 * (1.0 - alpha); |
| double a1 = 0.5; |
| double a2 = 0.5 * alpha; |
| |
| int n = kernel_.size(); |
| int half_size = n / 2; |
| double subsample_offset = -0.5; |
| |
| for (int i = 0; i < n; ++i) { |
| // Compute the sinc() with offset. |
| double s = piDouble * (i - half_size - subsample_offset); |
| double sinc = !s ? 1.0 : sin(s) / s; |
| |
| // Compute Blackman window, matching the offset of the sinc(). |
| double x = (i - subsample_offset) / n; |
| double window = |
| a0 - a1 * cos(twoPiDouble * x) + a2 * cos(twoPiDouble * 2.0 * x); |
| |
| // Window the sinc() function. |
| kernel_[i] = sinc * window; |
| } |
| } |
| |
| void UpSampler::Process(const float* source_p, |
| float* dest_p, |
| size_t source_frames_to_process) { |
| bool is_input_block_size_good = source_frames_to_process == input_block_size_; |
| DCHECK(is_input_block_size_good); |
| if (!is_input_block_size_good) |
| return; |
| |
| bool is_temp_buffer_good = source_frames_to_process == temp_buffer_.size(); |
| DCHECK(is_temp_buffer_good); |
| if (!is_temp_buffer_good) |
| return; |
| |
| bool is_kernel_good = kernel_.size() == kDefaultKernelSize; |
| DCHECK(is_kernel_good); |
| if (!is_kernel_good) |
| return; |
| |
| size_t half_size = kernel_.size() / 2; |
| |
| // Copy source samples to 2nd half of input buffer. |
| bool is_input_buffer_good = |
| input_buffer_.size() == source_frames_to_process * 2 && |
| half_size <= source_frames_to_process; |
| DCHECK(is_input_buffer_good); |
| if (!is_input_buffer_good) |
| return; |
| |
| float* input_p = input_buffer_.Data() + source_frames_to_process; |
| memcpy(input_p, source_p, sizeof(float) * source_frames_to_process); |
| |
| // Copy even sample-frames 0,2,4,6... (delayed by the linear phase delay) |
| // directly into destP. |
| for (unsigned i = 0; i < source_frames_to_process; ++i) |
| dest_p[i * 2] = *((input_p - half_size) + i); |
| |
| // Compute odd sample-frames 1,3,5,7... |
| float* odd_samples_p = temp_buffer_.Data(); |
| convolver_.Process(&kernel_, source_p, odd_samples_p, |
| source_frames_to_process); |
| |
| for (unsigned i = 0; i < source_frames_to_process; ++i) |
| dest_p[i * 2 + 1] = odd_samples_p[i]; |
| |
| // Copy 2nd half of input buffer to 1st half. |
| memcpy(input_buffer_.Data(), input_p, |
| sizeof(float) * source_frames_to_process); |
| } |
| |
| void UpSampler::Reset() { |
| convolver_.Reset(); |
| input_buffer_.Zero(); |
| } |
| |
| size_t UpSampler::LatencyFrames() const { |
| // Divide by two since this is a linear phase kernel and the delay is at the |
| // center of the kernel. |
| return kernel_.size() / 2; |
| } |
| |
| } // namespace blink |