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