2 * Copyright (C) 2011, Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "modules/webaudio/WaveShaperDSPKernel.h"
31 #include "wtf/MainThread.h"
32 #include "wtf/Threading.h"
35 const unsigned RenderingQuantum = 128;
39 WaveShaperDSPKernel::WaveShaperDSPKernel(WaveShaperProcessor* processor)
40 : AudioDSPKernel(processor)
42 if (processor->oversample() != WaveShaperProcessor::OverSampleNone)
43 lazyInitializeOversampling();
46 void WaveShaperDSPKernel::lazyInitializeOversampling()
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));
58 void WaveShaperDSPKernel::process(const float* source, float* destination, size_t framesToProcess)
60 switch (waveShaperProcessor()->oversample()) {
61 case WaveShaperProcessor::OverSampleNone:
62 processCurve(source, destination, framesToProcess);
64 case WaveShaperProcessor::OverSample2x:
65 processCurve2x(source, destination, framesToProcess);
67 case WaveShaperProcessor::OverSample4x:
68 processCurve4x(source, destination, framesToProcess);
76 void WaveShaperDSPKernel::processCurve(const float* source, float* destination, size_t framesToProcess)
78 ASSERT(source && destination && waveShaperProcessor());
80 DOMFloat32Array* curve = waveShaperProcessor()->curve();
82 // Act as "straight wire" pass-through if no curve is set.
83 memcpy(destination, source, sizeof(float) * framesToProcess);
87 float* curveData = curve->data();
88 int curveLength = curve->length();
92 if (!curveData || !curveLength) {
93 memcpy(destination, source, sizeof(float) * framesToProcess);
97 // Apply waveshaping curve.
98 for (unsigned i = 0; i < framesToProcess; ++i) {
99 const float input = source[i];
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);
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];
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;
120 double value1 = curveData[index1];
121 double value2 = curveData[index2];
123 output = (1.0 - interpolationFactor) * value1 + interpolationFactor * value2;
125 destination[i] = output;
129 void WaveShaperDSPKernel::processCurve2x(const float* source, float* destination, size_t framesToProcess)
131 bool isSafe = framesToProcess == RenderingQuantum;
136 float* tempP = m_tempBuffer->data();
138 m_upSampler->process(source, tempP, framesToProcess);
140 // Process at 2x up-sampled rate.
141 processCurve(tempP, tempP, framesToProcess * 2);
143 m_downSampler->process(tempP, destination, framesToProcess * 2);
146 void WaveShaperDSPKernel::processCurve4x(const float* source, float* destination, size_t framesToProcess)
148 bool isSafe = framesToProcess == RenderingQuantum;
153 float* tempP = m_tempBuffer->data();
154 float* tempP2 = m_tempBuffer2->data();
156 m_upSampler->process(source, tempP, framesToProcess);
157 m_upSampler2->process(tempP, tempP2, framesToProcess * 2);
159 // Process at 4x up-sampled rate.
160 processCurve(tempP2, tempP2, framesToProcess * 4);
162 m_downSampler2->process(tempP2, tempP, framesToProcess * 4);
163 m_downSampler->process(tempP, destination, framesToProcess * 2);
166 void WaveShaperDSPKernel::reset()
169 m_upSampler->reset();
170 m_downSampler->reset();
171 m_upSampler2->reset();
172 m_downSampler2->reset();
176 double WaveShaperDSPKernel::latencyTime() const
178 size_t latencyFrames = 0;
179 WaveShaperDSPKernel* kernel = const_cast<WaveShaperDSPKernel*>(this);
181 switch (kernel->waveShaperProcessor()->oversample()) {
182 case WaveShaperProcessor::OverSampleNone:
184 case WaveShaperProcessor::OverSample2x:
185 latencyFrames += m_upSampler->latencyFrames();
186 latencyFrames += m_downSampler->latencyFrames();
188 case WaveShaperProcessor::OverSample4x:
190 // Account for first stage upsampling.
191 latencyFrames += m_upSampler->latencyFrames();
192 latencyFrames += m_downSampler->latencyFrames();
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;
201 ASSERT_NOT_REACHED();
204 return static_cast<double>(latencyFrames) / sampleRate();
209 #endif // ENABLE(WEB_AUDIO)