Home | History | Annotate | Download | only in audio
      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