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