1 /*
2 * Copyright (C) 2012, 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/OscillatorNode.h"
30
31 #include "platform/audio/AudioUtilities.h"
32 #include "platform/audio/VectorMath.h"
33 #include "modules/webaudio/AudioContext.h"
34 #include "modules/webaudio/AudioNodeOutput.h"
35 #include "modules/webaudio/PeriodicWave.h"
36 #include "wtf/MathExtras.h"
37 #include "wtf/StdLibExtras.h"
38 #include <algorithm>
39
40 using namespace std;
41
42 namespace WebCore {
43
44 using namespace VectorMath;
45
create(AudioContext * context,float sampleRate)46 PassRefPtrWillBeRawPtr<OscillatorNode> OscillatorNode::create(AudioContext* context, float sampleRate)
47 {
48 return adoptRefWillBeNoop(new OscillatorNode(context, sampleRate));
49 }
50
OscillatorNode(AudioContext * context,float sampleRate)51 OscillatorNode::OscillatorNode(AudioContext* context, float sampleRate)
52 : AudioScheduledSourceNode(context, sampleRate)
53 , m_type(SINE)
54 , m_firstRender(true)
55 , m_virtualReadIndex(0)
56 , m_phaseIncrements(AudioNode::ProcessingSizeInFrames)
57 , m_detuneValues(AudioNode::ProcessingSizeInFrames)
58 {
59 ScriptWrappable::init(this);
60 setNodeType(NodeTypeOscillator);
61
62 // Use musical pitch standard A440 as a default.
63 m_frequency = AudioParam::create(context, "frequency", 440, 0, 100000);
64 // Default to no detuning.
65 m_detune = AudioParam::create(context, "detune", 0, -4800, 4800);
66
67 // Sets up default wavetable.
68 setType(m_type);
69
70 // An oscillator is always mono.
71 addOutput(adoptPtr(new AudioNodeOutput(this, 1)));
72
73 initialize();
74 }
75
~OscillatorNode()76 OscillatorNode::~OscillatorNode()
77 {
78 uninitialize();
79 }
80
type() const81 String OscillatorNode::type() const
82 {
83 switch (m_type) {
84 case SINE:
85 return "sine";
86 case SQUARE:
87 return "square";
88 case SAWTOOTH:
89 return "sawtooth";
90 case TRIANGLE:
91 return "triangle";
92 case CUSTOM:
93 return "custom";
94 default:
95 ASSERT_NOT_REACHED();
96 return "custom";
97 }
98 }
99
setType(const String & type)100 void OscillatorNode::setType(const String& type)
101 {
102 if (type == "sine")
103 setType(SINE);
104 else if (type == "square")
105 setType(SQUARE);
106 else if (type == "sawtooth")
107 setType(SAWTOOTH);
108 else if (type == "triangle")
109 setType(TRIANGLE);
110 }
111
setType(unsigned type)112 bool OscillatorNode::setType(unsigned type)
113 {
114 PeriodicWave* periodicWave = 0;
115 float sampleRate = this->sampleRate();
116
117 switch (type) {
118 case SINE: {
119 DEFINE_STATIC_REF_WILL_BE_PERSISTENT(PeriodicWave, periodicWaveSine, (PeriodicWave::createSine(sampleRate)));
120 periodicWave = periodicWaveSine;
121 break;
122 }
123 case SQUARE: {
124 DEFINE_STATIC_REF_WILL_BE_PERSISTENT(PeriodicWave, periodicWaveSquare, (PeriodicWave::createSquare(sampleRate)));
125 periodicWave = periodicWaveSquare;
126 break;
127 }
128 case SAWTOOTH: {
129 DEFINE_STATIC_REF_WILL_BE_PERSISTENT(PeriodicWave, periodicWaveSawtooth, (PeriodicWave::createSawtooth(sampleRate)));
130 periodicWave = periodicWaveSawtooth;
131 break;
132 }
133 case TRIANGLE: {
134 DEFINE_STATIC_REF_WILL_BE_PERSISTENT(PeriodicWave, periodicWaveTriangle, (PeriodicWave::createTriangle(sampleRate)));
135 periodicWave = periodicWaveTriangle;
136 break;
137 }
138 case CUSTOM:
139 default:
140 // Return error for invalid types, including CUSTOM since setPeriodicWave() method must be
141 // called explicitly.
142 return false;
143 }
144
145 setPeriodicWave(periodicWave);
146 m_type = type;
147 return true;
148 }
149
calculateSampleAccuratePhaseIncrements(size_t framesToProcess)150 bool OscillatorNode::calculateSampleAccuratePhaseIncrements(size_t framesToProcess)
151 {
152 bool isGood = framesToProcess <= m_phaseIncrements.size() && framesToProcess <= m_detuneValues.size();
153 ASSERT(isGood);
154 if (!isGood)
155 return false;
156
157 if (m_firstRender) {
158 m_firstRender = false;
159 m_frequency->resetSmoothedValue();
160 m_detune->resetSmoothedValue();
161 }
162
163 bool hasSampleAccurateValues = false;
164 bool hasFrequencyChanges = false;
165 float* phaseIncrements = m_phaseIncrements.data();
166
167 float finalScale = m_periodicWave->rateScale();
168
169 if (m_frequency->hasSampleAccurateValues()) {
170 hasSampleAccurateValues = true;
171 hasFrequencyChanges = true;
172
173 // Get the sample-accurate frequency values and convert to phase increments.
174 // They will be converted to phase increments below.
175 m_frequency->calculateSampleAccurateValues(phaseIncrements, framesToProcess);
176 } else {
177 // Handle ordinary parameter smoothing/de-zippering if there are no scheduled changes.
178 m_frequency->smooth();
179 float frequency = m_frequency->smoothedValue();
180 finalScale *= frequency;
181 }
182
183 if (m_detune->hasSampleAccurateValues()) {
184 hasSampleAccurateValues = true;
185
186 // Get the sample-accurate detune values.
187 float* detuneValues = hasFrequencyChanges ? m_detuneValues.data() : phaseIncrements;
188 m_detune->calculateSampleAccurateValues(detuneValues, framesToProcess);
189
190 // Convert from cents to rate scalar.
191 float k = 1.0 / 1200;
192 vsmul(detuneValues, 1, &k, detuneValues, 1, framesToProcess);
193 for (unsigned i = 0; i < framesToProcess; ++i)
194 detuneValues[i] = powf(2, detuneValues[i]); // FIXME: converting to expf() will be faster.
195
196 if (hasFrequencyChanges) {
197 // Multiply frequencies by detune scalings.
198 vmul(detuneValues, 1, phaseIncrements, 1, phaseIncrements, 1, framesToProcess);
199 }
200 } else {
201 // Handle ordinary parameter smoothing/de-zippering if there are no scheduled changes.
202 m_detune->smooth();
203 float detune = m_detune->smoothedValue();
204 float detuneScale = powf(2, detune / 1200);
205 finalScale *= detuneScale;
206 }
207
208 if (hasSampleAccurateValues) {
209 // Convert from frequency to wavetable increment.
210 vsmul(phaseIncrements, 1, &finalScale, phaseIncrements, 1, framesToProcess);
211 }
212
213 return hasSampleAccurateValues;
214 }
215
process(size_t framesToProcess)216 void OscillatorNode::process(size_t framesToProcess)
217 {
218 AudioBus* outputBus = output(0)->bus();
219
220 if (!isInitialized() || !outputBus->numberOfChannels()) {
221 outputBus->zero();
222 return;
223 }
224
225 ASSERT(framesToProcess <= m_phaseIncrements.size());
226 if (framesToProcess > m_phaseIncrements.size())
227 return;
228
229 // The audio thread can't block on this lock, so we call tryLock() instead.
230 MutexTryLocker tryLocker(m_processLock);
231 if (!tryLocker.locked()) {
232 // Too bad - the tryLock() failed. We must be in the middle of changing wave-tables.
233 outputBus->zero();
234 return;
235 }
236
237 // We must access m_periodicWave only inside the lock.
238 if (!m_periodicWave.get()) {
239 outputBus->zero();
240 return;
241 }
242
243 size_t quantumFrameOffset;
244 size_t nonSilentFramesToProcess;
245
246 updateSchedulingInfo(framesToProcess, outputBus, quantumFrameOffset, nonSilentFramesToProcess);
247
248 if (!nonSilentFramesToProcess) {
249 outputBus->zero();
250 return;
251 }
252
253 unsigned periodicWaveSize = m_periodicWave->periodicWaveSize();
254 double invPeriodicWaveSize = 1.0 / periodicWaveSize;
255
256 float* destP = outputBus->channel(0)->mutableData();
257
258 ASSERT(quantumFrameOffset <= framesToProcess);
259
260 // We keep virtualReadIndex double-precision since we're accumulating values.
261 double virtualReadIndex = m_virtualReadIndex;
262
263 float rateScale = m_periodicWave->rateScale();
264 float invRateScale = 1 / rateScale;
265 bool hasSampleAccurateValues = calculateSampleAccuratePhaseIncrements(framesToProcess);
266
267 float frequency = 0;
268 float* higherWaveData = 0;
269 float* lowerWaveData = 0;
270 float tableInterpolationFactor;
271
272 if (!hasSampleAccurateValues) {
273 frequency = m_frequency->smoothedValue();
274 float detune = m_detune->smoothedValue();
275 float detuneScale = powf(2, detune / 1200);
276 frequency *= detuneScale;
277 m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWaveData, higherWaveData, tableInterpolationFactor);
278 }
279
280 float incr = frequency * rateScale;
281 float* phaseIncrements = m_phaseIncrements.data();
282
283 unsigned readIndexMask = periodicWaveSize - 1;
284
285 // Start rendering at the correct offset.
286 destP += quantumFrameOffset;
287 int n = nonSilentFramesToProcess;
288
289 while (n--) {
290 unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
291 unsigned readIndex2 = readIndex + 1;
292
293 // Contain within valid range.
294 readIndex = readIndex & readIndexMask;
295 readIndex2 = readIndex2 & readIndexMask;
296
297 if (hasSampleAccurateValues) {
298 incr = *phaseIncrements++;
299
300 frequency = invRateScale * incr;
301 m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWaveData, higherWaveData, tableInterpolationFactor);
302 }
303
304 float sample1Lower = lowerWaveData[readIndex];
305 float sample2Lower = lowerWaveData[readIndex2];
306 float sample1Higher = higherWaveData[readIndex];
307 float sample2Higher = higherWaveData[readIndex2];
308
309 // Linearly interpolate within each table (lower and higher).
310 float interpolationFactor = static_cast<float>(virtualReadIndex) - readIndex;
311 float sampleHigher = (1 - interpolationFactor) * sample1Higher + interpolationFactor * sample2Higher;
312 float sampleLower = (1 - interpolationFactor) * sample1Lower + interpolationFactor * sample2Lower;
313
314 // Then interpolate between the two tables.
315 float sample = (1 - tableInterpolationFactor) * sampleHigher + tableInterpolationFactor * sampleLower;
316
317 *destP++ = sample;
318
319 // Increment virtual read index and wrap virtualReadIndex into the range 0 -> periodicWaveSize.
320 virtualReadIndex += incr;
321 virtualReadIndex -= floor(virtualReadIndex * invPeriodicWaveSize) * periodicWaveSize;
322 }
323
324 m_virtualReadIndex = virtualReadIndex;
325
326 outputBus->clearSilentFlag();
327 }
328
setPeriodicWave(PeriodicWave * periodicWave)329 void OscillatorNode::setPeriodicWave(PeriodicWave* periodicWave)
330 {
331 ASSERT(isMainThread());
332
333 // This synchronizes with process().
334 MutexLocker processLocker(m_processLock);
335 m_periodicWave = periodicWave;
336 m_type = CUSTOM;
337 }
338
propagatesSilence() const339 bool OscillatorNode::propagatesSilence() const
340 {
341 return !isPlayingOrScheduled() || hasFinished() || !m_periodicWave.get();
342 }
343
trace(Visitor * visitor)344 void OscillatorNode::trace(Visitor* visitor)
345 {
346 visitor->trace(m_frequency);
347 visitor->trace(m_detune);
348 visitor->trace(m_periodicWave);
349 AudioScheduledSourceNode::trace(visitor);
350 }
351
352 } // namespace WebCore
353
354 #endif // ENABLE(WEB_AUDIO)
355