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 0 being at the center of the curve data.
    104         // Then linearly interpolate between the two points in the curve.
    105         double virtualIndex = 0.5 * (input + 1) * curveLength;
    106         int index1 = static_cast<int>(virtualIndex);
    107         int index2 = index1 + 1;
    108         double interpolationFactor = virtualIndex - index1;
    109 
    110         // Clip index to the input range of the curve.
    111         // This takes care of input outside of nominal range -1 -> +1
    112         index1 = max(index1, 0);
    113         index1 = min(index1, curveLength - 1);
    114         index2 = max(index2, 0);
    115         index2 = min(index2, curveLength - 1);
    116 
    117         double value1 = curveData[index1];
    118         double value2 = curveData[index2];
    119 
    120         double output = (1.0 - interpolationFactor) * value1 + interpolationFactor * value2;
    121         destination[i] = output;
    122     }
    123 }
    124 
    125 void WaveShaperDSPKernel::processCurve2x(const float* source, float* destination, size_t framesToProcess)
    126 {
    127     bool isSafe = framesToProcess == RenderingQuantum;
    128     ASSERT(isSafe);
    129     if (!isSafe)
    130         return;
    131 
    132     float* tempP = m_tempBuffer->data();
    133 
    134     m_upSampler->process(source, tempP, framesToProcess);
    135 
    136     // Process at 2x up-sampled rate.
    137     processCurve(tempP, tempP, framesToProcess * 2);
    138 
    139     m_downSampler->process(tempP, destination, framesToProcess * 2);
    140 }
    141 
    142 void WaveShaperDSPKernel::processCurve4x(const float* source, float* destination, size_t framesToProcess)
    143 {
    144     bool isSafe = framesToProcess == RenderingQuantum;
    145     ASSERT(isSafe);
    146     if (!isSafe)
    147         return;
    148 
    149     float* tempP = m_tempBuffer->data();
    150     float* tempP2 = m_tempBuffer2->data();
    151 
    152     m_upSampler->process(source, tempP, framesToProcess);
    153     m_upSampler2->process(tempP, tempP2, framesToProcess * 2);
    154 
    155     // Process at 4x up-sampled rate.
    156     processCurve(tempP2, tempP2, framesToProcess * 4);
    157 
    158     m_downSampler2->process(tempP2, tempP, framesToProcess * 4);
    159     m_downSampler->process(tempP, destination, framesToProcess * 2);
    160 }
    161 
    162 void WaveShaperDSPKernel::reset()
    163 {
    164     if (m_upSampler) {
    165         m_upSampler->reset();
    166         m_downSampler->reset();
    167         m_upSampler2->reset();
    168         m_downSampler2->reset();
    169     }
    170 }
    171 
    172 double WaveShaperDSPKernel::latencyTime() const
    173 {
    174     size_t latencyFrames = 0;
    175     WaveShaperDSPKernel* kernel = const_cast<WaveShaperDSPKernel*>(this);
    176 
    177     switch (kernel->waveShaperProcessor()->oversample()) {
    178     case WaveShaperProcessor::OverSampleNone:
    179         break;
    180     case WaveShaperProcessor::OverSample2x:
    181         latencyFrames += m_upSampler->latencyFrames();
    182         latencyFrames += m_downSampler->latencyFrames();
    183         break;
    184     case WaveShaperProcessor::OverSample4x:
    185         {
    186             // Account for first stage upsampling.
    187             latencyFrames += m_upSampler->latencyFrames();
    188             latencyFrames += m_downSampler->latencyFrames();
    189 
    190             // Account for second stage upsampling.
    191             // and divide by 2 to get back down to the regular sample-rate.
    192             size_t latencyFrames2 = (m_upSampler2->latencyFrames() + m_downSampler2->latencyFrames()) / 2;
    193             latencyFrames += latencyFrames2;
    194             break;
    195         }
    196     default:
    197         ASSERT_NOT_REACHED();
    198     }
    199 
    200     return static_cast<double>(latencyFrames) / sampleRate();
    201 }
    202 
    203 } // namespace WebCore
    204 
    205 #endif // ENABLE(WEB_AUDIO)
    206