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 46 PassRefPtrWillBeRawPtr<OscillatorNode> OscillatorNode::create(AudioContext* context, float sampleRate) 47 { 48 return adoptRefWillBeNoop(new OscillatorNode(context, sampleRate)); 49 } 50 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 76 OscillatorNode::~OscillatorNode() 77 { 78 uninitialize(); 79 } 80 81 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 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 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 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 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 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 339 bool OscillatorNode::propagatesSilence() const 340 { 341 return !isPlayingOrScheduled() || hasFinished() || !m_periodicWave.get(); 342 } 343 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