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 OscillatorNode* OscillatorNode::create(AudioContext* context, float sampleRate)
46 return 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 setNodeType(NodeTypeOscillator);
59 // Use musical pitch standard A440 as a default.
60 m_frequency = AudioParam::create(context, 440);
61 // Default to no detuning.
62 m_detune = AudioParam::create(context, 0);
64 // Sets up default wavetable.
67 // An oscillator is always mono.
68 addOutput(AudioNodeOutput::create(this, 1));
73 OscillatorNode::~OscillatorNode()
75 ASSERT(!isInitialized());
78 void OscillatorNode::dispose()
81 AudioScheduledSourceNode::dispose();
84 String OscillatorNode::type() const
103 void OscillatorNode::setType(const String& type)
107 else if (type == "square")
109 else if (type == "sawtooth")
111 else if (type == "triangle")
115 bool OscillatorNode::setType(unsigned type)
117 PeriodicWave* periodicWave = 0;
118 float sampleRate = this->sampleRate();
122 DEFINE_STATIC_LOCAL(Persistent<PeriodicWave>, periodicWaveSine, (PeriodicWave::createSine(sampleRate)));
123 periodicWave = periodicWaveSine;
127 DEFINE_STATIC_LOCAL(Persistent<PeriodicWave>, periodicWaveSquare, (PeriodicWave::createSquare(sampleRate)));
128 periodicWave = periodicWaveSquare;
132 DEFINE_STATIC_LOCAL(Persistent<PeriodicWave>, periodicWaveSawtooth, (PeriodicWave::createSawtooth(sampleRate)));
133 periodicWave = periodicWaveSawtooth;
137 DEFINE_STATIC_LOCAL(Persistent<PeriodicWave>, periodicWaveTriangle, (PeriodicWave::createTriangle(sampleRate)));
138 periodicWave = periodicWaveTriangle;
143 // Return error for invalid types, including CUSTOM since setPeriodicWave() method must be
144 // called explicitly.
148 setPeriodicWave(periodicWave);
153 bool OscillatorNode::calculateSampleAccuratePhaseIncrements(size_t framesToProcess)
155 bool isGood = framesToProcess <= m_phaseIncrements.size() && framesToProcess <= m_detuneValues.size();
161 m_firstRender = false;
162 m_frequency->resetSmoothedValue();
163 m_detune->resetSmoothedValue();
166 bool hasSampleAccurateValues = false;
167 bool hasFrequencyChanges = false;
168 float* phaseIncrements = m_phaseIncrements.data();
170 float finalScale = m_periodicWave->rateScale();
172 if (m_frequency->hasSampleAccurateValues()) {
173 hasSampleAccurateValues = true;
174 hasFrequencyChanges = true;
176 // Get the sample-accurate frequency values and convert to phase increments.
177 // They will be converted to phase increments below.
178 m_frequency->calculateSampleAccurateValues(phaseIncrements, framesToProcess);
180 // Handle ordinary parameter smoothing/de-zippering if there are no scheduled changes.
181 m_frequency->smooth();
182 float frequency = m_frequency->smoothedValue();
183 finalScale *= frequency;
186 if (m_detune->hasSampleAccurateValues()) {
187 hasSampleAccurateValues = true;
189 // Get the sample-accurate detune values.
190 float* detuneValues = hasFrequencyChanges ? m_detuneValues.data() : phaseIncrements;
191 m_detune->calculateSampleAccurateValues(detuneValues, framesToProcess);
193 // Convert from cents to rate scalar.
194 float k = 1.0 / 1200;
195 vsmul(detuneValues, 1, &k, detuneValues, 1, framesToProcess);
196 for (unsigned i = 0; i < framesToProcess; ++i)
197 detuneValues[i] = powf(2, detuneValues[i]); // FIXME: converting to expf() will be faster.
199 if (hasFrequencyChanges) {
200 // Multiply frequencies by detune scalings.
201 vmul(detuneValues, 1, phaseIncrements, 1, phaseIncrements, 1, framesToProcess);
204 // Handle ordinary parameter smoothing/de-zippering if there are no scheduled changes.
206 float detune = m_detune->smoothedValue();
207 float detuneScale = powf(2, detune / 1200);
208 finalScale *= detuneScale;
211 if (hasSampleAccurateValues) {
212 // Convert from frequency to wavetable increment.
213 vsmul(phaseIncrements, 1, &finalScale, phaseIncrements, 1, framesToProcess);
216 return hasSampleAccurateValues;
219 void OscillatorNode::process(size_t framesToProcess)
221 AudioBus* outputBus = output(0)->bus();
223 if (!isInitialized() || !outputBus->numberOfChannels()) {
228 ASSERT(framesToProcess <= m_phaseIncrements.size());
229 if (framesToProcess > m_phaseIncrements.size())
232 // The audio thread can't block on this lock, so we call tryLock() instead.
233 MutexTryLocker tryLocker(m_processLock);
234 if (!tryLocker.locked()) {
235 // Too bad - the tryLock() failed. We must be in the middle of changing wave-tables.
240 // We must access m_periodicWave only inside the lock.
241 if (!m_periodicWave.get()) {
246 size_t quantumFrameOffset;
247 size_t nonSilentFramesToProcess;
249 updateSchedulingInfo(framesToProcess, outputBus, quantumFrameOffset, nonSilentFramesToProcess);
251 if (!nonSilentFramesToProcess) {
256 unsigned periodicWaveSize = m_periodicWave->periodicWaveSize();
257 double invPeriodicWaveSize = 1.0 / periodicWaveSize;
259 float* destP = outputBus->channel(0)->mutableData();
261 ASSERT(quantumFrameOffset <= framesToProcess);
263 // We keep virtualReadIndex double-precision since we're accumulating values.
264 double virtualReadIndex = m_virtualReadIndex;
266 float rateScale = m_periodicWave->rateScale();
267 float invRateScale = 1 / rateScale;
268 bool hasSampleAccurateValues = calculateSampleAccuratePhaseIncrements(framesToProcess);
271 float* higherWaveData = 0;
272 float* lowerWaveData = 0;
273 float tableInterpolationFactor = 0;
275 if (!hasSampleAccurateValues) {
276 frequency = m_frequency->smoothedValue();
277 float detune = m_detune->smoothedValue();
278 float detuneScale = powf(2, detune / 1200);
279 frequency *= detuneScale;
280 m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWaveData, higherWaveData, tableInterpolationFactor);
283 float incr = frequency * rateScale;
284 float* phaseIncrements = m_phaseIncrements.data();
286 unsigned readIndexMask = periodicWaveSize - 1;
288 // Start rendering at the correct offset.
289 destP += quantumFrameOffset;
290 int n = nonSilentFramesToProcess;
293 unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
294 unsigned readIndex2 = readIndex + 1;
296 // Contain within valid range.
297 readIndex = readIndex & readIndexMask;
298 readIndex2 = readIndex2 & readIndexMask;
300 if (hasSampleAccurateValues) {
301 incr = *phaseIncrements++;
303 frequency = invRateScale * incr;
304 m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWaveData, higherWaveData, tableInterpolationFactor);
307 float sample1Lower = lowerWaveData[readIndex];
308 float sample2Lower = lowerWaveData[readIndex2];
309 float sample1Higher = higherWaveData[readIndex];
310 float sample2Higher = higherWaveData[readIndex2];
312 // Linearly interpolate within each table (lower and higher).
313 float interpolationFactor = static_cast<float>(virtualReadIndex) - readIndex;
314 float sampleHigher = (1 - interpolationFactor) * sample1Higher + interpolationFactor * sample2Higher;
315 float sampleLower = (1 - interpolationFactor) * sample1Lower + interpolationFactor * sample2Lower;
317 // Then interpolate between the two tables.
318 float sample = (1 - tableInterpolationFactor) * sampleHigher + tableInterpolationFactor * sampleLower;
322 // Increment virtual read index and wrap virtualReadIndex into the range 0 -> periodicWaveSize.
323 virtualReadIndex += incr;
324 virtualReadIndex -= floor(virtualReadIndex * invPeriodicWaveSize) * periodicWaveSize;
327 m_virtualReadIndex = virtualReadIndex;
329 outputBus->clearSilentFlag();
332 void OscillatorNode::setPeriodicWave(PeriodicWave* periodicWave)
334 ASSERT(isMainThread());
336 // This synchronizes with process().
337 MutexLocker processLocker(m_processLock);
338 m_periodicWave = periodicWave;
342 bool OscillatorNode::propagatesSilence() const
344 return !isPlayingOrScheduled() || hasFinished() || !m_periodicWave.get();
347 void OscillatorNode::trace(Visitor* visitor)
349 visitor->trace(m_frequency);
350 visitor->trace(m_detune);
351 visitor->trace(m_periodicWave);
352 AudioScheduledSourceNode::trace(visitor);
357 #endif // ENABLE(WEB_AUDIO)