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 PassRefPtr<OscillatorNode> OscillatorNode::create(AudioContext* context, float sampleRate) 47 { 48 return adoptRef(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 else 111 ASSERT_NOT_REACHED(); 112 } 113 114 bool OscillatorNode::setType(unsigned type) 115 { 116 PeriodicWave* periodicWave = 0; 117 float sampleRate = this->sampleRate(); 118 119 switch (type) { 120 case SINE: { 121 DEFINE_STATIC_REF(PeriodicWave, periodicWaveSine, (PeriodicWave::createSine(sampleRate))); 122 periodicWave = periodicWaveSine; 123 break; 124 } 125 case SQUARE: { 126 DEFINE_STATIC_REF(PeriodicWave, periodicWaveSquare, (PeriodicWave::createSquare(sampleRate))); 127 periodicWave = periodicWaveSquare; 128 break; 129 } 130 case SAWTOOTH: { 131 DEFINE_STATIC_REF(PeriodicWave, periodicWaveSawtooth, (PeriodicWave::createSawtooth(sampleRate))); 132 periodicWave = periodicWaveSawtooth; 133 break; 134 } 135 case TRIANGLE: { 136 DEFINE_STATIC_REF(PeriodicWave, periodicWaveTriangle, (PeriodicWave::createTriangle(sampleRate))); 137 periodicWave = periodicWaveTriangle; 138 break; 139 } 140 case CUSTOM: 141 default: 142 // Return error for invalid types, including CUSTOM since setPeriodicWave() method must be 143 // called explicitly. 144 return false; 145 } 146 147 setPeriodicWave(periodicWave); 148 m_type = type; 149 return true; 150 } 151 152 bool OscillatorNode::calculateSampleAccuratePhaseIncrements(size_t framesToProcess) 153 { 154 bool isGood = framesToProcess <= m_phaseIncrements.size() && framesToProcess <= m_detuneValues.size(); 155 ASSERT(isGood); 156 if (!isGood) 157 return false; 158 159 if (m_firstRender) { 160 m_firstRender = false; 161 m_frequency->resetSmoothedValue(); 162 m_detune->resetSmoothedValue(); 163 } 164 165 bool hasSampleAccurateValues = false; 166 bool hasFrequencyChanges = false; 167 float* phaseIncrements = m_phaseIncrements.data(); 168 169 float finalScale = m_periodicWave->rateScale(); 170 171 if (m_frequency->hasSampleAccurateValues()) { 172 hasSampleAccurateValues = true; 173 hasFrequencyChanges = true; 174 175 // Get the sample-accurate frequency values and convert to phase increments. 176 // They will be converted to phase increments below. 177 m_frequency->calculateSampleAccurateValues(phaseIncrements, framesToProcess); 178 } else { 179 // Handle ordinary parameter smoothing/de-zippering if there are no scheduled changes. 180 m_frequency->smooth(); 181 float frequency = m_frequency->smoothedValue(); 182 finalScale *= frequency; 183 } 184 185 if (m_detune->hasSampleAccurateValues()) { 186 hasSampleAccurateValues = true; 187 188 // Get the sample-accurate detune values. 189 float* detuneValues = hasFrequencyChanges ? m_detuneValues.data() : phaseIncrements; 190 m_detune->calculateSampleAccurateValues(detuneValues, framesToProcess); 191 192 // Convert from cents to rate scalar. 193 float k = 1.0 / 1200; 194 vsmul(detuneValues, 1, &k, detuneValues, 1, framesToProcess); 195 for (unsigned i = 0; i < framesToProcess; ++i) 196 detuneValues[i] = powf(2, detuneValues[i]); // FIXME: converting to expf() will be faster. 197 198 if (hasFrequencyChanges) { 199 // Multiply frequencies by detune scalings. 200 vmul(detuneValues, 1, phaseIncrements, 1, phaseIncrements, 1, framesToProcess); 201 } 202 } else { 203 // Handle ordinary parameter smoothing/de-zippering if there are no scheduled changes. 204 m_detune->smooth(); 205 float detune = m_detune->smoothedValue(); 206 float detuneScale = powf(2, detune / 1200); 207 finalScale *= detuneScale; 208 } 209 210 if (hasSampleAccurateValues) { 211 // Convert from frequency to wavetable increment. 212 vsmul(phaseIncrements, 1, &finalScale, phaseIncrements, 1, framesToProcess); 213 } 214 215 return hasSampleAccurateValues; 216 } 217 218 void OscillatorNode::process(size_t framesToProcess) 219 { 220 AudioBus* outputBus = output(0)->bus(); 221 222 if (!isInitialized() || !outputBus->numberOfChannels()) { 223 outputBus->zero(); 224 return; 225 } 226 227 ASSERT(framesToProcess <= m_phaseIncrements.size()); 228 if (framesToProcess > m_phaseIncrements.size()) 229 return; 230 231 // The audio thread can't block on this lock, so we call tryLock() instead. 232 MutexTryLocker tryLocker(m_processLock); 233 if (!tryLocker.locked()) { 234 // Too bad - the tryLock() failed. We must be in the middle of changing wave-tables. 235 outputBus->zero(); 236 return; 237 } 238 239 // We must access m_periodicWave only inside the lock. 240 if (!m_periodicWave.get()) { 241 outputBus->zero(); 242 return; 243 } 244 245 size_t quantumFrameOffset; 246 size_t nonSilentFramesToProcess; 247 248 updateSchedulingInfo(framesToProcess, outputBus, quantumFrameOffset, nonSilentFramesToProcess); 249 250 if (!nonSilentFramesToProcess) { 251 outputBus->zero(); 252 return; 253 } 254 255 unsigned periodicWaveSize = m_periodicWave->periodicWaveSize(); 256 double invPeriodicWaveSize = 1.0 / periodicWaveSize; 257 258 float* destP = outputBus->channel(0)->mutableData(); 259 260 ASSERT(quantumFrameOffset <= framesToProcess); 261 262 // We keep virtualReadIndex double-precision since we're accumulating values. 263 double virtualReadIndex = m_virtualReadIndex; 264 265 float rateScale = m_periodicWave->rateScale(); 266 float invRateScale = 1 / rateScale; 267 bool hasSampleAccurateValues = calculateSampleAccuratePhaseIncrements(framesToProcess); 268 269 float frequency = 0; 270 float* higherWaveData = 0; 271 float* lowerWaveData = 0; 272 float tableInterpolationFactor; 273 274 if (!hasSampleAccurateValues) { 275 frequency = m_frequency->smoothedValue(); 276 float detune = m_detune->smoothedValue(); 277 float detuneScale = powf(2, detune / 1200); 278 frequency *= detuneScale; 279 m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWaveData, higherWaveData, tableInterpolationFactor); 280 } 281 282 float incr = frequency * rateScale; 283 float* phaseIncrements = m_phaseIncrements.data(); 284 285 unsigned readIndexMask = periodicWaveSize - 1; 286 287 // Start rendering at the correct offset. 288 destP += quantumFrameOffset; 289 int n = nonSilentFramesToProcess; 290 291 while (n--) { 292 unsigned readIndex = static_cast<unsigned>(virtualReadIndex); 293 unsigned readIndex2 = readIndex + 1; 294 295 // Contain within valid range. 296 readIndex = readIndex & readIndexMask; 297 readIndex2 = readIndex2 & readIndexMask; 298 299 if (hasSampleAccurateValues) { 300 incr = *phaseIncrements++; 301 302 frequency = invRateScale * incr; 303 m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWaveData, higherWaveData, tableInterpolationFactor); 304 } 305 306 float sample1Lower = lowerWaveData[readIndex]; 307 float sample2Lower = lowerWaveData[readIndex2]; 308 float sample1Higher = higherWaveData[readIndex]; 309 float sample2Higher = higherWaveData[readIndex2]; 310 311 // Linearly interpolate within each table (lower and higher). 312 float interpolationFactor = static_cast<float>(virtualReadIndex) - readIndex; 313 float sampleHigher = (1 - interpolationFactor) * sample1Higher + interpolationFactor * sample2Higher; 314 float sampleLower = (1 - interpolationFactor) * sample1Lower + interpolationFactor * sample2Lower; 315 316 // Then interpolate between the two tables. 317 float sample = (1 - tableInterpolationFactor) * sampleHigher + tableInterpolationFactor * sampleLower; 318 319 *destP++ = sample; 320 321 // Increment virtual read index and wrap virtualReadIndex into the range 0 -> periodicWaveSize. 322 virtualReadIndex += incr; 323 virtualReadIndex -= floor(virtualReadIndex * invPeriodicWaveSize) * periodicWaveSize; 324 } 325 326 m_virtualReadIndex = virtualReadIndex; 327 328 outputBus->clearSilentFlag(); 329 } 330 331 void OscillatorNode::reset() 332 { 333 m_virtualReadIndex = 0; 334 } 335 336 void OscillatorNode::setPeriodicWave(PeriodicWave* periodicWave) 337 { 338 ASSERT(isMainThread()); 339 340 // This synchronizes with process(). 341 MutexLocker processLocker(m_processLock); 342 m_periodicWave = periodicWave; 343 m_type = CUSTOM; 344 } 345 346 bool OscillatorNode::propagatesSilence() const 347 { 348 return !isPlayingOrScheduled() || hasFinished() || !m_periodicWave.get(); 349 } 350 351 } // namespace WebCore 352 353 #endif // ENABLE(WEB_AUDIO) 354