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