Home | History | Annotate | Download | only in webaudio
      1 /*
      2  * Copyright (C) 2011, 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
      6  * are met:
      7  * 1.  Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2.  Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 #include "config.h"
     26 
     27 #if ENABLE(WEB_AUDIO)
     28 
     29 #include "modules/webaudio/WaveShaperDSPKernel.h"
     30 
     31 #include "wtf/MainThread.h"
     32 #include "wtf/Threading.h"
     33 #include <algorithm>
     34 
     35 const unsigned RenderingQuantum = 128;
     36 
     37 using namespace std;
     38 
     39 namespace WebCore {
     40 
     41 WaveShaperDSPKernel::WaveShaperDSPKernel(WaveShaperProcessor* processor)
     42     : AudioDSPKernel(processor)
     43 {
     44     if (processor->oversample() != WaveShaperProcessor::OverSampleNone)
     45         lazyInitializeOversampling();
     46 }
     47 
     48 void WaveShaperDSPKernel::lazyInitializeOversampling()
     49 {
     50     if (!m_tempBuffer) {
     51         m_tempBuffer = adoptPtr(new AudioFloatArray(RenderingQuantum * 2));
     52         m_tempBuffer2 = adoptPtr(new AudioFloatArray(RenderingQuantum * 4));
     53         m_upSampler = adoptPtr(new UpSampler(RenderingQuantum));
     54         m_downSampler = adoptPtr(new DownSampler(RenderingQuantum * 2));
     55         m_upSampler2 = adoptPtr(new UpSampler(RenderingQuantum * 2));
     56         m_downSampler2 = adoptPtr(new DownSampler(RenderingQuantum * 4));
     57     }
     58 }
     59 
     60 void WaveShaperDSPKernel::process(const float* source, float* destination, size_t framesToProcess)
     61 {
     62     switch (waveShaperProcessor()->oversample()) {
     63     case WaveShaperProcessor::OverSampleNone:
     64         processCurve(source, destination, framesToProcess);
     65         break;
     66     case WaveShaperProcessor::OverSample2x:
     67         processCurve2x(source, destination, framesToProcess);
     68         break;
     69     case WaveShaperProcessor::OverSample4x:
     70         processCurve4x(source, destination, framesToProcess);
     71         break;
     72 
     73     default:
     74         ASSERT_NOT_REACHED();
     75     }
     76 }
     77 
     78 void WaveShaperDSPKernel::processCurve(const float* source, float* destination, size_t framesToProcess)
     79 {
     80     ASSERT(source && destination && waveShaperProcessor());
     81 
     82     Float32Array* curve = waveShaperProcessor()->curve();
     83     if (!curve) {
     84         // Act as "straight wire" pass-through if no curve is set.
     85         memcpy(destination, source, sizeof(float) * framesToProcess);
     86         return;
     87     }
     88 
     89     float* curveData = curve->data();
     90     int curveLength = curve->length();
     91 
     92     ASSERT(curveData);
     93 
     94     if (!curveData || !curveLength) {
     95         memcpy(destination, source, sizeof(float) * framesToProcess);
     96         return;
     97     }
     98 
     99     // Apply waveshaping curve.
    100     for (unsigned i = 0; i < framesToProcess; ++i) {
    101         const float input = source[i];
    102 
    103         // Calculate a virtual index based on input -1 -> +1 with -1 being curve[0], +1 being
    104         // curve[curveLength - 1], and 0 being at the center of the curve data. Then linearly
    105         // interpolate between the two points in the curve.
    106         double virtualIndex = 0.5 * (input + 1) * (curveLength - 1);
    107         double output;
    108 
    109         if (virtualIndex < 0) {
    110             // input < -1, so use curve[0]
    111             output = curveData[0];
    112         } else if (virtualIndex >= curveLength - 1) {
    113             // input >= 1, so use last curve value
    114             output = curveData[curveLength - 1];
    115         } else {
    116             // The general case where -1 <= input < 1, where 0 <= virtualIndex < curveLength - 1,
    117             // so interpolate between the nearest samples on the curve.
    118             unsigned index1 = static_cast<unsigned>(virtualIndex);
    119             unsigned index2 = index1 + 1;
    120             double interpolationFactor = virtualIndex - index1;
    121 
    122             double value1 = curveData[index1];
    123             double value2 = curveData[index2];
    124 
    125             output = (1.0 - interpolationFactor) * value1 + interpolationFactor * value2;
    126         }
    127         destination[i] = output;
    128     }
    129 }
    130 
    131 void WaveShaperDSPKernel::processCurve2x(const float* source, float* destination, size_t framesToProcess)
    132 {
    133     bool isSafe = framesToProcess == RenderingQuantum;
    134     ASSERT(isSafe);
    135     if (!isSafe)
    136         return;
    137 
    138     float* tempP = m_tempBuffer->data();
    139 
    140     m_upSampler->process(source, tempP, framesToProcess);
    141 
    142     // Process at 2x up-sampled rate.
    143     processCurve(tempP, tempP, framesToProcess * 2);
    144 
    145     m_downSampler->process(tempP, destination, framesToProcess * 2);
    146 }
    147 
    148 void WaveShaperDSPKernel::processCurve4x(const float* source, float* destination, size_t framesToProcess)
    149 {
    150     bool isSafe = framesToProcess == RenderingQuantum;
    151     ASSERT(isSafe);
    152     if (!isSafe)
    153         return;
    154 
    155     float* tempP = m_tempBuffer->data();
    156     float* tempP2 = m_tempBuffer2->data();
    157 
    158     m_upSampler->process(source, tempP, framesToProcess);
    159     m_upSampler2->process(tempP, tempP2, framesToProcess * 2);
    160 
    161     // Process at 4x up-sampled rate.
    162     processCurve(tempP2, tempP2, framesToProcess * 4);
    163 
    164     m_downSampler2->process(tempP2, tempP, framesToProcess * 4);
    165     m_downSampler->process(tempP, destination, framesToProcess * 2);
    166 }
    167 
    168 void WaveShaperDSPKernel::reset()
    169 {
    170     if (m_upSampler) {
    171         m_upSampler->reset();
    172         m_downSampler->reset();
    173         m_upSampler2->reset();
    174         m_downSampler2->reset();
    175     }
    176 }
    177 
    178 double WaveShaperDSPKernel::latencyTime() const
    179 {
    180     size_t latencyFrames = 0;
    181     WaveShaperDSPKernel* kernel = const_cast<WaveShaperDSPKernel*>(this);
    182 
    183     switch (kernel->waveShaperProcessor()->oversample()) {
    184     case WaveShaperProcessor::OverSampleNone:
    185         break;
    186     case WaveShaperProcessor::OverSample2x:
    187         latencyFrames += m_upSampler->latencyFrames();
    188         latencyFrames += m_downSampler->latencyFrames();
    189         break;
    190     case WaveShaperProcessor::OverSample4x:
    191         {
    192             // Account for first stage upsampling.
    193             latencyFrames += m_upSampler->latencyFrames();
    194             latencyFrames += m_downSampler->latencyFrames();
    195 
    196             // Account for second stage upsampling.
    197             // and divide by 2 to get back down to the regular sample-rate.
    198             size_t latencyFrames2 = (m_upSampler2->latencyFrames() + m_downSampler2->latencyFrames()) / 2;
    199             latencyFrames += latencyFrames2;
    200             break;
    201         }
    202     default:
    203         ASSERT_NOT_REACHED();
    204     }
    205 
    206     return static_cast<double>(latencyFrames) / sampleRate();
    207 }
    208 
    209 } // namespace WebCore
    210 
    211 #endif // ENABLE(WEB_AUDIO)
    212