• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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