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