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 "modules/webaudio/WaveShaperProcessor.h"
     32 #include "wtf/MainThread.h"
     33 #include "wtf/Threading.h"
     34 #include <algorithm>
     35 
     36 const unsigned RenderingQuantum = 128;
     37 
     38 using namespace std;
     39 
     40 namespace WebCore {
     41 
     42 WaveShaperDSPKernel::WaveShaperDSPKernel(WaveShaperProcessor* processor)
     43     : AudioDSPKernel(processor)
     44 {
     45     if (processor->oversample() != WaveShaperProcessor::OverSampleNone)
     46         lazyInitializeOversampling();
     47 }
     48 
     49 void WaveShaperDSPKernel::lazyInitializeOversampling()
     50 {
     51     if (!m_tempBuffer) {
     52         m_tempBuffer = adoptPtr(new AudioFloatArray(RenderingQuantum * 2));
     53         m_tempBuffer2 = adoptPtr(new AudioFloatArray(RenderingQuantum * 4));
     54         m_upSampler = adoptPtr(new UpSampler(RenderingQuantum));
     55         m_downSampler = adoptPtr(new DownSampler(RenderingQuantum * 2));
     56         m_upSampler2 = adoptPtr(new UpSampler(RenderingQuantum * 2));
     57         m_downSampler2 = adoptPtr(new DownSampler(RenderingQuantum * 4));
     58     }
     59 }
     60 
     61 void WaveShaperDSPKernel::process(const float* source, float* destination, size_t framesToProcess)
     62 {
     63     switch (waveShaperProcessor()->oversample()) {
     64     case WaveShaperProcessor::OverSampleNone:
     65         processCurve(source, destination, framesToProcess);
     66         break;
     67     case WaveShaperProcessor::OverSample2x:
     68         processCurve2x(source, destination, framesToProcess);
     69         break;
     70     case WaveShaperProcessor::OverSample4x:
     71         processCurve4x(source, destination, framesToProcess);
     72         break;
     73 
     74     default:
     75         ASSERT_NOT_REACHED();
     76     }
     77 }
     78 
     79 void WaveShaperDSPKernel::processCurve(const float* source, float* destination, size_t framesToProcess)
     80 {
     81     ASSERT(source && destination && waveShaperProcessor());
     82 
     83     Float32Array* curve = waveShaperProcessor()->curve();
     84     if (!curve) {
     85         // Act as "straight wire" pass-through if no curve is set.
     86         memcpy(destination, source, sizeof(float) * framesToProcess);
     87         return;
     88     }
     89 
     90     float* curveData = curve->data();
     91     int curveLength = curve->length();
     92 
     93     ASSERT(curveData);
     94 
     95     if (!curveData || !curveLength) {
     96         memcpy(destination, source, sizeof(float) * framesToProcess);
     97         return;
     98     }
     99 
    100     // Apply waveshaping curve.
    101     for (unsigned i = 0; i < framesToProcess; ++i) {
    102         const float input = source[i];
    103 
    104         // Calculate a virtual index based on input -1 -> +1 with 0 being at the center of the curve data.
    105         // Then linearly interpolate between the two points in the curve.
    106         double virtualIndex = 0.5 * (input + 1) * curveLength;
    107         int index1 = static_cast<int>(virtualIndex);
    108         int index2 = index1 + 1;
    109         double interpolationFactor = virtualIndex - index1;
    110 
    111         // Clip index to the input range of the curve.
    112         // This takes care of input outside of nominal range -1 -> +1
    113         index1 = max(index1, 0);
    114         index1 = min(index1, curveLength - 1);
    115         index2 = max(index2, 0);
    116         index2 = min(index2, curveLength - 1);
    117 
    118         double value1 = curveData[index1];
    119         double value2 = curveData[index2];
    120 
    121         double output = (1.0 - interpolationFactor) * value1 + interpolationFactor * value2;
    122         destination[i] = output;
    123     }
    124 }
    125 
    126 void WaveShaperDSPKernel::processCurve2x(const float* source, float* destination, size_t framesToProcess)
    127 {
    128     bool isSafe = framesToProcess == RenderingQuantum;
    129     ASSERT(isSafe);
    130     if (!isSafe)
    131         return;
    132 
    133     float* tempP = m_tempBuffer->data();
    134 
    135     m_upSampler->process(source, tempP, framesToProcess);
    136 
    137     // Process at 2x up-sampled rate.
    138     processCurve(tempP, tempP, framesToProcess * 2);
    139 
    140     m_downSampler->process(tempP, destination, framesToProcess * 2);
    141 }
    142 
    143 void WaveShaperDSPKernel::processCurve4x(const float* source, float* destination, size_t framesToProcess)
    144 {
    145     bool isSafe = framesToProcess == RenderingQuantum;
    146     ASSERT(isSafe);
    147     if (!isSafe)
    148         return;
    149 
    150     float* tempP = m_tempBuffer->data();
    151     float* tempP2 = m_tempBuffer2->data();
    152 
    153     m_upSampler->process(source, tempP, framesToProcess);
    154     m_upSampler2->process(tempP, tempP2, framesToProcess * 2);
    155 
    156     // Process at 4x up-sampled rate.
    157     processCurve(tempP2, tempP2, framesToProcess * 4);
    158 
    159     m_downSampler2->process(tempP2, tempP, framesToProcess * 4);
    160     m_downSampler->process(tempP, destination, framesToProcess * 2);
    161 }
    162 
    163 void WaveShaperDSPKernel::reset()
    164 {
    165     if (m_upSampler) {
    166         m_upSampler->reset();
    167         m_downSampler->reset();
    168         m_upSampler2->reset();
    169         m_downSampler2->reset();
    170     }
    171 }
    172 
    173 double WaveShaperDSPKernel::latencyTime() const
    174 {
    175     size_t latencyFrames = 0;
    176     WaveShaperDSPKernel* kernel = const_cast<WaveShaperDSPKernel*>(this);
    177 
    178     switch (kernel->waveShaperProcessor()->oversample()) {
    179     case WaveShaperProcessor::OverSampleNone:
    180         break;
    181     case WaveShaperProcessor::OverSample2x:
    182         latencyFrames += m_upSampler->latencyFrames();
    183         latencyFrames += m_downSampler->latencyFrames();
    184         break;
    185     case WaveShaperProcessor::OverSample4x:
    186         {
    187             // Account for first stage upsampling.
    188             latencyFrames += m_upSampler->latencyFrames();
    189             latencyFrames += m_downSampler->latencyFrames();
    190 
    191             // Account for second stage upsampling.
    192             // and divide by 2 to get back down to the regular sample-rate.
    193             size_t latencyFrames2 = (m_upSampler2->latencyFrames() + m_downSampler2->latencyFrames()) / 2;
    194             latencyFrames += latencyFrames2;
    195             break;
    196         }
    197     default:
    198         ASSERT_NOT_REACHED();
    199     }
    200 
    201     return static_cast<double>(latencyFrames) / sampleRate();
    202 }
    203 
    204 } // namespace WebCore
    205 
    206 #endif // ENABLE(WEB_AUDIO)
    207