2 * Copyright (C) 2012, 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/OscillatorNode.h"
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"
42 using namespace VectorMath;
44 PassRefPtrWillBeRawPtr<OscillatorNode> OscillatorNode::create(AudioContext* context, float sampleRate)
46 return adoptRefWillBeNoop(new OscillatorNode(context, sampleRate));
49 OscillatorNode::OscillatorNode(AudioContext* context, float sampleRate)
50 : AudioScheduledSourceNode(context, sampleRate)
53 , m_virtualReadIndex(0)
54 , m_phaseIncrements(AudioNode::ProcessingSizeInFrames)
55 , m_detuneValues(AudioNode::ProcessingSizeInFrames)
57 ScriptWrappable::init(this);
58 setNodeType(NodeTypeOscillator);
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);
65 // Sets up default wavetable.
68 // An oscillator is always mono.
69 addOutput(AudioNodeOutput::create(this, 1));
74 OscillatorNode::~OscillatorNode()
76 ASSERT(!isInitialized());
79 void OscillatorNode::dispose()
82 AudioScheduledSourceNode::dispose();
85 String OscillatorNode::type() const
104 void OscillatorNode::setType(const String& type)
108 else if (type == "square")
110 else if (type == "sawtooth")
112 else if (type == "triangle")
116 bool OscillatorNode::setType(unsigned type)
118 PeriodicWave* periodicWave = 0;
119 float sampleRate = this->sampleRate();
123 DEFINE_STATIC_REF_WILL_BE_PERSISTENT(PeriodicWave, periodicWaveSine, (PeriodicWave::createSine(sampleRate)));
124 periodicWave = periodicWaveSine;
128 DEFINE_STATIC_REF_WILL_BE_PERSISTENT(PeriodicWave, periodicWaveSquare, (PeriodicWave::createSquare(sampleRate)));
129 periodicWave = periodicWaveSquare;
133 DEFINE_STATIC_REF_WILL_BE_PERSISTENT(PeriodicWave, periodicWaveSawtooth, (PeriodicWave::createSawtooth(sampleRate)));
134 periodicWave = periodicWaveSawtooth;
138 DEFINE_STATIC_REF_WILL_BE_PERSISTENT(PeriodicWave, periodicWaveTriangle, (PeriodicWave::createTriangle(sampleRate)));
139 periodicWave = periodicWaveTriangle;
144 // Return error for invalid types, including CUSTOM since setPeriodicWave() method must be
145 // called explicitly.
149 setPeriodicWave(periodicWave);
154 bool OscillatorNode::calculateSampleAccuratePhaseIncrements(size_t framesToProcess)
156 bool isGood = framesToProcess <= m_phaseIncrements.size() && framesToProcess <= m_detuneValues.size();
162 m_firstRender = false;
163 m_frequency->resetSmoothedValue();
164 m_detune->resetSmoothedValue();
167 bool hasSampleAccurateValues = false;
168 bool hasFrequencyChanges = false;
169 float* phaseIncrements = m_phaseIncrements.data();
171 float finalScale = m_periodicWave->rateScale();
173 if (m_frequency->hasSampleAccurateValues()) {
174 hasSampleAccurateValues = true;
175 hasFrequencyChanges = true;
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);
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;
187 if (m_detune->hasSampleAccurateValues()) {
188 hasSampleAccurateValues = true;
190 // Get the sample-accurate detune values.
191 float* detuneValues = hasFrequencyChanges ? m_detuneValues.data() : phaseIncrements;
192 m_detune->calculateSampleAccurateValues(detuneValues, framesToProcess);
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.
200 if (hasFrequencyChanges) {
201 // Multiply frequencies by detune scalings.
202 vmul(detuneValues, 1, phaseIncrements, 1, phaseIncrements, 1, framesToProcess);
205 // Handle ordinary parameter smoothing/de-zippering if there are no scheduled changes.
207 float detune = m_detune->smoothedValue();
208 float detuneScale = powf(2, detune / 1200);
209 finalScale *= detuneScale;
212 if (hasSampleAccurateValues) {
213 // Convert from frequency to wavetable increment.
214 vsmul(phaseIncrements, 1, &finalScale, phaseIncrements, 1, framesToProcess);
217 return hasSampleAccurateValues;
220 void OscillatorNode::process(size_t framesToProcess)
222 AudioBus* outputBus = output(0)->bus();
224 if (!isInitialized() || !outputBus->numberOfChannels()) {
229 ASSERT(framesToProcess <= m_phaseIncrements.size());
230 if (framesToProcess > m_phaseIncrements.size())
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.
241 // We must access m_periodicWave only inside the lock.
242 if (!m_periodicWave.get()) {
247 size_t quantumFrameOffset;
248 size_t nonSilentFramesToProcess;
250 updateSchedulingInfo(framesToProcess, outputBus, quantumFrameOffset, nonSilentFramesToProcess);
252 if (!nonSilentFramesToProcess) {
257 unsigned periodicWaveSize = m_periodicWave->periodicWaveSize();
258 double invPeriodicWaveSize = 1.0 / periodicWaveSize;
260 float* destP = outputBus->channel(0)->mutableData();
262 ASSERT(quantumFrameOffset <= framesToProcess);
264 // We keep virtualReadIndex double-precision since we're accumulating values.
265 double virtualReadIndex = m_virtualReadIndex;
267 float rateScale = m_periodicWave->rateScale();
268 float invRateScale = 1 / rateScale;
269 bool hasSampleAccurateValues = calculateSampleAccuratePhaseIncrements(framesToProcess);
272 float* higherWaveData = 0;
273 float* lowerWaveData = 0;
274 float tableInterpolationFactor = 0;
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);
284 float incr = frequency * rateScale;
285 float* phaseIncrements = m_phaseIncrements.data();
287 unsigned readIndexMask = periodicWaveSize - 1;
289 // Start rendering at the correct offset.
290 destP += quantumFrameOffset;
291 int n = nonSilentFramesToProcess;
294 unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
295 unsigned readIndex2 = readIndex + 1;
297 // Contain within valid range.
298 readIndex = readIndex & readIndexMask;
299 readIndex2 = readIndex2 & readIndexMask;
301 if (hasSampleAccurateValues) {
302 incr = *phaseIncrements++;
304 frequency = invRateScale * incr;
305 m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWaveData, higherWaveData, tableInterpolationFactor);
308 float sample1Lower = lowerWaveData[readIndex];
309 float sample2Lower = lowerWaveData[readIndex2];
310 float sample1Higher = higherWaveData[readIndex];
311 float sample2Higher = higherWaveData[readIndex2];
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;
318 // Then interpolate between the two tables.
319 float sample = (1 - tableInterpolationFactor) * sampleHigher + tableInterpolationFactor * sampleLower;
323 // Increment virtual read index and wrap virtualReadIndex into the range 0 -> periodicWaveSize.
324 virtualReadIndex += incr;
325 virtualReadIndex -= floor(virtualReadIndex * invPeriodicWaveSize) * periodicWaveSize;
328 m_virtualReadIndex = virtualReadIndex;
330 outputBus->clearSilentFlag();
333 void OscillatorNode::setPeriodicWave(PeriodicWave* periodicWave)
335 ASSERT(isMainThread());
337 // This synchronizes with process().
338 MutexLocker processLocker(m_processLock);
339 m_periodicWave = periodicWave;
343 bool OscillatorNode::propagatesSilence() const
345 return !isPlayingOrScheduled() || hasFinished() || !m_periodicWave.get();
348 void OscillatorNode::trace(Visitor* visitor)
350 visitor->trace(m_frequency);
351 visitor->trace(m_detune);
352 visitor->trace(m_periodicWave);
353 AudioScheduledSourceNode::trace(visitor);
358 #endif // ENABLE(WEB_AUDIO)