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