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