1 /* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 33 #if ENABLE(WEB_AUDIO) 34 35 #include "core/platform/audio/UpSampler.h" 36 37 #include "wtf/MathExtras.h" 38 39 namespace WebCore { 40 41 UpSampler::UpSampler(size_t inputBlockSize) 42 : m_inputBlockSize(inputBlockSize) 43 , m_kernel(DefaultKernelSize) 44 , m_tempBuffer(inputBlockSize) 45 , m_inputBuffer(inputBlockSize * 2) 46 , m_convolver(inputBlockSize) 47 { 48 initializeKernel(); 49 } 50 51 void UpSampler::initializeKernel() 52 { 53 // Blackman window parameters. 54 double alpha = 0.16; 55 double a0 = 0.5 * (1.0 - alpha); 56 double a1 = 0.5; 57 double a2 = 0.5 * alpha; 58 59 int n = m_kernel.size(); 60 int halfSize = n / 2; 61 double subsampleOffset = -0.5; 62 63 for (int i = 0; i < n; ++i) { 64 // Compute the sinc() with offset. 65 double s = piDouble * (i - halfSize - subsampleOffset); 66 double sinc = !s ? 1.0 : sin(s) / s; 67 68 // Compute Blackman window, matching the offset of the sinc(). 69 double x = (i - subsampleOffset) / n; 70 double window = a0 - a1 * cos(2.0 * piDouble * x) + a2 * cos(4.0 * piDouble * x); 71 72 // Window the sinc() function. 73 m_kernel[i] = sinc * window; 74 } 75 } 76 77 void UpSampler::process(const float* sourceP, float* destP, size_t sourceFramesToProcess) 78 { 79 bool isInputBlockSizeGood = sourceFramesToProcess == m_inputBlockSize; 80 ASSERT(isInputBlockSizeGood); 81 if (!isInputBlockSizeGood) 82 return; 83 84 bool isTempBufferGood = sourceFramesToProcess == m_tempBuffer.size(); 85 ASSERT(isTempBufferGood); 86 if (!isTempBufferGood) 87 return; 88 89 bool isKernelGood = m_kernel.size() == DefaultKernelSize; 90 ASSERT(isKernelGood); 91 if (!isKernelGood) 92 return; 93 94 size_t halfSize = m_kernel.size() / 2; 95 96 // Copy source samples to 2nd half of input buffer. 97 bool isInputBufferGood = m_inputBuffer.size() == sourceFramesToProcess * 2 && halfSize <= sourceFramesToProcess; 98 ASSERT(isInputBufferGood); 99 if (!isInputBufferGood) 100 return; 101 102 float* inputP = m_inputBuffer.data() + sourceFramesToProcess; 103 memcpy(inputP, sourceP, sizeof(float) * sourceFramesToProcess); 104 105 // Copy even sample-frames 0,2,4,6... (delayed by the linear phase delay) directly into destP. 106 for (unsigned i = 0; i < sourceFramesToProcess; ++i) 107 destP[i * 2] = *((inputP - halfSize) + i); 108 109 // Compute odd sample-frames 1,3,5,7... 110 float* oddSamplesP = m_tempBuffer.data(); 111 m_convolver.process(&m_kernel, sourceP, oddSamplesP, sourceFramesToProcess); 112 113 for (unsigned i = 0; i < sourceFramesToProcess; ++i) 114 destP[i * 2 + 1] = oddSamplesP[i]; 115 116 // Copy 2nd half of input buffer to 1st half. 117 memcpy(m_inputBuffer.data(), inputP, sizeof(float) * sourceFramesToProcess); 118 } 119 120 void UpSampler::reset() 121 { 122 m_convolver.reset(); 123 m_inputBuffer.zero(); 124 } 125 126 size_t UpSampler::latencyFrames() const 127 { 128 // Divide by two since this is a linear phase kernel and the delay is at the center of the kernel. 129 return m_kernel.size() / 2; 130 } 131 132 } // namespace WebCore 133 134 #endif // ENABLE(WEB_AUDIO) 135