| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2012, Google Inc. All rights reserved. | 2 * Copyright (C) 2012, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 | 26 |
| 27 #if ENABLE(WEB_AUDIO) | 27 #if ENABLE(WEB_AUDIO) |
| 28 | 28 |
| 29 #include "modules/webaudio/OscillatorNode.h" | 29 #include "modules/webaudio/OscillatorNode.h" |
| 30 | 30 |
| 31 #include "core/dom/ExceptionCode.h" | 31 #include "core/dom/ExceptionCode.h" |
| 32 #include "core/platform/audio/AudioUtilities.h" | 32 #include "core/platform/audio/AudioUtilities.h" |
| 33 #include "core/platform/audio/VectorMath.h" | 33 #include "core/platform/audio/VectorMath.h" |
| 34 #include "modules/webaudio/AudioContext.h" | 34 #include "modules/webaudio/AudioContext.h" |
| 35 #include "modules/webaudio/AudioNodeOutput.h" | 35 #include "modules/webaudio/AudioNodeOutput.h" |
| 36 #include "modules/webaudio/WaveTable.h" | 36 #include "modules/webaudio/PeriodicWave.h" |
| 37 #include <algorithm> | 37 #include <algorithm> |
| 38 #include "wtf/MathExtras.h" | 38 #include "wtf/MathExtras.h" |
| 39 | 39 |
| 40 using namespace std; | 40 using namespace std; |
| 41 | 41 |
| 42 namespace WebCore { | 42 namespace WebCore { |
| 43 | 43 |
| 44 using namespace VectorMath; | 44 using namespace VectorMath; |
| 45 | 45 |
| 46 WaveTable* OscillatorNode::s_waveTableSine = 0; | 46 PeriodicWave* OscillatorNode::s_periodicWaveSine = 0; |
| 47 WaveTable* OscillatorNode::s_waveTableSquare = 0; | 47 PeriodicWave* OscillatorNode::s_periodicWaveSquare = 0; |
| 48 WaveTable* OscillatorNode::s_waveTableSawtooth = 0; | 48 PeriodicWave* OscillatorNode::s_periodicWaveSawtooth = 0; |
| 49 WaveTable* OscillatorNode::s_waveTableTriangle = 0; | 49 PeriodicWave* OscillatorNode::s_periodicWaveTriangle = 0; |
| 50 | 50 |
| 51 PassRefPtr<OscillatorNode> OscillatorNode::create(AudioContext* context, float s
ampleRate) | 51 PassRefPtr<OscillatorNode> OscillatorNode::create(AudioContext* context, float s
ampleRate) |
| 52 { | 52 { |
| 53 return adoptRef(new OscillatorNode(context, sampleRate)); | 53 return adoptRef(new OscillatorNode(context, sampleRate)); |
| 54 } | 54 } |
| 55 | 55 |
| 56 OscillatorNode::OscillatorNode(AudioContext* context, float sampleRate) | 56 OscillatorNode::OscillatorNode(AudioContext* context, float sampleRate) |
| 57 : AudioScheduledSourceNode(context, sampleRate) | 57 : AudioScheduledSourceNode(context, sampleRate) |
| 58 , m_type(SINE) | 58 , m_type(SINE) |
| 59 , m_firstRender(true) | 59 , m_firstRender(true) |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 else if (type == "sawtooth") | 111 else if (type == "sawtooth") |
| 112 setType(SAWTOOTH); | 112 setType(SAWTOOTH); |
| 113 else if (type == "triangle") | 113 else if (type == "triangle") |
| 114 setType(TRIANGLE); | 114 setType(TRIANGLE); |
| 115 else | 115 else |
| 116 ASSERT_NOT_REACHED(); | 116 ASSERT_NOT_REACHED(); |
| 117 } | 117 } |
| 118 | 118 |
| 119 bool OscillatorNode::setType(unsigned type) | 119 bool OscillatorNode::setType(unsigned type) |
| 120 { | 120 { |
| 121 WaveTable* waveTable = 0; | 121 PeriodicWave* periodicWave = 0; |
| 122 float sampleRate = this->sampleRate(); | 122 float sampleRate = this->sampleRate(); |
| 123 | 123 |
| 124 switch (type) { | 124 switch (type) { |
| 125 case SINE: | 125 case SINE: |
| 126 if (!s_waveTableSine) | 126 if (!s_periodicWaveSine) |
| 127 s_waveTableSine = WaveTable::createSine(sampleRate).leakRef(); | 127 s_periodicWaveSine = PeriodicWave::createSine(sampleRate).leakRef(); |
| 128 waveTable = s_waveTableSine; | 128 periodicWave = s_periodicWaveSine; |
| 129 break; | 129 break; |
| 130 case SQUARE: | 130 case SQUARE: |
| 131 if (!s_waveTableSquare) | 131 if (!s_periodicWaveSquare) |
| 132 s_waveTableSquare = WaveTable::createSquare(sampleRate).leakRef(); | 132 s_periodicWaveSquare = PeriodicWave::createSquare(sampleRate).leakRe
f(); |
| 133 waveTable = s_waveTableSquare; | 133 periodicWave = s_periodicWaveSquare; |
| 134 break; | 134 break; |
| 135 case SAWTOOTH: | 135 case SAWTOOTH: |
| 136 if (!s_waveTableSawtooth) | 136 if (!s_periodicWaveSawtooth) |
| 137 s_waveTableSawtooth = WaveTable::createSawtooth(sampleRate).leakRef(
); | 137 s_periodicWaveSawtooth = PeriodicWave::createSawtooth(sampleRate).le
akRef(); |
| 138 waveTable = s_waveTableSawtooth; | 138 periodicWave = s_periodicWaveSawtooth; |
| 139 break; | 139 break; |
| 140 case TRIANGLE: | 140 case TRIANGLE: |
| 141 if (!s_waveTableTriangle) | 141 if (!s_periodicWaveTriangle) |
| 142 s_waveTableTriangle = WaveTable::createTriangle(sampleRate).leakRef(
); | 142 s_periodicWaveTriangle = PeriodicWave::createTriangle(sampleRate).le
akRef(); |
| 143 waveTable = s_waveTableTriangle; | 143 periodicWave = s_periodicWaveTriangle; |
| 144 break; | 144 break; |
| 145 case CUSTOM: | 145 case CUSTOM: |
| 146 default: | 146 default: |
| 147 // Return error for invalid types, including CUSTOM since setWaveTable()
method must be | 147 // Return error for invalid types, including CUSTOM since setPeriodicWav
e() method must be |
| 148 // called explicitly. | 148 // called explicitly. |
| 149 return false; | 149 return false; |
| 150 } | 150 } |
| 151 | 151 |
| 152 setWaveTable(waveTable); | 152 setPeriodicWave(periodicWave); |
| 153 m_type = type; | 153 m_type = type; |
| 154 return true; | 154 return true; |
| 155 } | 155 } |
| 156 | 156 |
| 157 bool OscillatorNode::calculateSampleAccuratePhaseIncrements(size_t framesToProce
ss) | 157 bool OscillatorNode::calculateSampleAccuratePhaseIncrements(size_t framesToProce
ss) |
| 158 { | 158 { |
| 159 bool isGood = framesToProcess <= m_phaseIncrements.size() && framesToProcess
<= m_detuneValues.size(); | 159 bool isGood = framesToProcess <= m_phaseIncrements.size() && framesToProcess
<= m_detuneValues.size(); |
| 160 ASSERT(isGood); | 160 ASSERT(isGood); |
| 161 if (!isGood) | 161 if (!isGood) |
| 162 return false; | 162 return false; |
| 163 | 163 |
| 164 if (m_firstRender) { | 164 if (m_firstRender) { |
| 165 m_firstRender = false; | 165 m_firstRender = false; |
| 166 m_frequency->resetSmoothedValue(); | 166 m_frequency->resetSmoothedValue(); |
| 167 m_detune->resetSmoothedValue(); | 167 m_detune->resetSmoothedValue(); |
| 168 } | 168 } |
| 169 | 169 |
| 170 bool hasSampleAccurateValues = false; | 170 bool hasSampleAccurateValues = false; |
| 171 bool hasFrequencyChanges = false; | 171 bool hasFrequencyChanges = false; |
| 172 float* phaseIncrements = m_phaseIncrements.data(); | 172 float* phaseIncrements = m_phaseIncrements.data(); |
| 173 | 173 |
| 174 float finalScale = m_waveTable->rateScale(); | 174 float finalScale = m_periodicWave->rateScale(); |
| 175 | 175 |
| 176 if (m_frequency->hasSampleAccurateValues()) { | 176 if (m_frequency->hasSampleAccurateValues()) { |
| 177 hasSampleAccurateValues = true; | 177 hasSampleAccurateValues = true; |
| 178 hasFrequencyChanges = true; | 178 hasFrequencyChanges = true; |
| 179 | 179 |
| 180 // Get the sample-accurate frequency values and convert to phase increme
nts. | 180 // Get the sample-accurate frequency values and convert to phase increme
nts. |
| 181 // They will be converted to phase increments below. | 181 // They will be converted to phase increments below. |
| 182 m_frequency->calculateSampleAccurateValues(phaseIncrements, framesToProc
ess); | 182 m_frequency->calculateSampleAccurateValues(phaseIncrements, framesToProc
ess); |
| 183 } else { | 183 } else { |
| 184 // Handle ordinary parameter smoothing/de-zippering if there are no sche
duled changes. | 184 // Handle ordinary parameter smoothing/de-zippering if there are no sche
duled changes. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 return; | 234 return; |
| 235 | 235 |
| 236 // The audio thread can't block on this lock, so we call tryLock() instead. | 236 // The audio thread can't block on this lock, so we call tryLock() instead. |
| 237 MutexTryLocker tryLocker(m_processLock); | 237 MutexTryLocker tryLocker(m_processLock); |
| 238 if (!tryLocker.locked()) { | 238 if (!tryLocker.locked()) { |
| 239 // Too bad - the tryLock() failed. We must be in the middle of changing
wave-tables. | 239 // Too bad - the tryLock() failed. We must be in the middle of changing
wave-tables. |
| 240 outputBus->zero(); | 240 outputBus->zero(); |
| 241 return; | 241 return; |
| 242 } | 242 } |
| 243 | 243 |
| 244 // We must access m_waveTable only inside the lock. | 244 // We must access m_periodicWave only inside the lock. |
| 245 if (!m_waveTable.get()) { | 245 if (!m_periodicWave.get()) { |
| 246 outputBus->zero(); | 246 outputBus->zero(); |
| 247 return; | 247 return; |
| 248 } | 248 } |
| 249 | 249 |
| 250 size_t quantumFrameOffset; | 250 size_t quantumFrameOffset; |
| 251 size_t nonSilentFramesToProcess; | 251 size_t nonSilentFramesToProcess; |
| 252 | 252 |
| 253 updateSchedulingInfo(framesToProcess, outputBus, quantumFrameOffset, nonSile
ntFramesToProcess); | 253 updateSchedulingInfo(framesToProcess, outputBus, quantumFrameOffset, nonSile
ntFramesToProcess); |
| 254 | 254 |
| 255 if (!nonSilentFramesToProcess) { | 255 if (!nonSilentFramesToProcess) { |
| 256 outputBus->zero(); | 256 outputBus->zero(); |
| 257 return; | 257 return; |
| 258 } | 258 } |
| 259 | 259 |
| 260 unsigned waveTableSize = m_waveTable->waveTableSize(); | 260 unsigned periodicWaveSize = m_periodicWave->periodicWaveSize(); |
| 261 double invWaveTableSize = 1.0 / waveTableSize; | 261 double invPeriodicWaveSize = 1.0 / periodicWaveSize; |
| 262 | 262 |
| 263 float* destP = outputBus->channel(0)->mutableData(); | 263 float* destP = outputBus->channel(0)->mutableData(); |
| 264 | 264 |
| 265 ASSERT(quantumFrameOffset <= framesToProcess); | 265 ASSERT(quantumFrameOffset <= framesToProcess); |
| 266 | 266 |
| 267 // We keep virtualReadIndex double-precision since we're accumulating values
. | 267 // We keep virtualReadIndex double-precision since we're accumulating values
. |
| 268 double virtualReadIndex = m_virtualReadIndex; | 268 double virtualReadIndex = m_virtualReadIndex; |
| 269 | 269 |
| 270 float rateScale = m_waveTable->rateScale(); | 270 float rateScale = m_periodicWave->rateScale(); |
| 271 float invRateScale = 1 / rateScale; | 271 float invRateScale = 1 / rateScale; |
| 272 bool hasSampleAccurateValues = calculateSampleAccuratePhaseIncrements(frames
ToProcess); | 272 bool hasSampleAccurateValues = calculateSampleAccuratePhaseIncrements(frames
ToProcess); |
| 273 | 273 |
| 274 float frequency = 0; | 274 float frequency = 0; |
| 275 float* higherWaveData = 0; | 275 float* higherWaveData = 0; |
| 276 float* lowerWaveData = 0; | 276 float* lowerWaveData = 0; |
| 277 float tableInterpolationFactor; | 277 float tableInterpolationFactor; |
| 278 | 278 |
| 279 if (!hasSampleAccurateValues) { | 279 if (!hasSampleAccurateValues) { |
| 280 frequency = m_frequency->smoothedValue(); | 280 frequency = m_frequency->smoothedValue(); |
| 281 float detune = m_detune->smoothedValue(); | 281 float detune = m_detune->smoothedValue(); |
| 282 float detuneScale = powf(2, detune / 1200); | 282 float detuneScale = powf(2, detune / 1200); |
| 283 frequency *= detuneScale; | 283 frequency *= detuneScale; |
| 284 m_waveTable->waveDataForFundamentalFrequency(frequency, lowerWaveData, h
igherWaveData, tableInterpolationFactor); | 284 m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWaveData
, higherWaveData, tableInterpolationFactor); |
| 285 } | 285 } |
| 286 | 286 |
| 287 float incr = frequency * rateScale; | 287 float incr = frequency * rateScale; |
| 288 float* phaseIncrements = m_phaseIncrements.data(); | 288 float* phaseIncrements = m_phaseIncrements.data(); |
| 289 | 289 |
| 290 unsigned readIndexMask = waveTableSize - 1; | 290 unsigned readIndexMask = periodicWaveSize - 1; |
| 291 | 291 |
| 292 // Start rendering at the correct offset. | 292 // Start rendering at the correct offset. |
| 293 destP += quantumFrameOffset; | 293 destP += quantumFrameOffset; |
| 294 int n = nonSilentFramesToProcess; | 294 int n = nonSilentFramesToProcess; |
| 295 | 295 |
| 296 while (n--) { | 296 while (n--) { |
| 297 unsigned readIndex = static_cast<unsigned>(virtualReadIndex); | 297 unsigned readIndex = static_cast<unsigned>(virtualReadIndex); |
| 298 unsigned readIndex2 = readIndex + 1; | 298 unsigned readIndex2 = readIndex + 1; |
| 299 | 299 |
| 300 // Contain within valid range. | 300 // Contain within valid range. |
| 301 readIndex = readIndex & readIndexMask; | 301 readIndex = readIndex & readIndexMask; |
| 302 readIndex2 = readIndex2 & readIndexMask; | 302 readIndex2 = readIndex2 & readIndexMask; |
| 303 | 303 |
| 304 if (hasSampleAccurateValues) { | 304 if (hasSampleAccurateValues) { |
| 305 incr = *phaseIncrements++; | 305 incr = *phaseIncrements++; |
| 306 | 306 |
| 307 frequency = invRateScale * incr; | 307 frequency = invRateScale * incr; |
| 308 m_waveTable->waveDataForFundamentalFrequency(frequency, lowerWaveDat
a, higherWaveData, tableInterpolationFactor); | 308 m_periodicWave->waveDataForFundamentalFrequency(frequency, lowerWave
Data, higherWaveData, tableInterpolationFactor); |
| 309 } | 309 } |
| 310 | 310 |
| 311 float sample1Lower = lowerWaveData[readIndex]; | 311 float sample1Lower = lowerWaveData[readIndex]; |
| 312 float sample2Lower = lowerWaveData[readIndex2]; | 312 float sample2Lower = lowerWaveData[readIndex2]; |
| 313 float sample1Higher = higherWaveData[readIndex]; | 313 float sample1Higher = higherWaveData[readIndex]; |
| 314 float sample2Higher = higherWaveData[readIndex2]; | 314 float sample2Higher = higherWaveData[readIndex2]; |
| 315 | 315 |
| 316 // Linearly interpolate within each table (lower and higher). | 316 // Linearly interpolate within each table (lower and higher). |
| 317 float interpolationFactor = static_cast<float>(virtualReadIndex) - readI
ndex; | 317 float interpolationFactor = static_cast<float>(virtualReadIndex) - readI
ndex; |
| 318 float sampleHigher = (1 - interpolationFactor) * sample1Higher + interpo
lationFactor * sample2Higher; | 318 float sampleHigher = (1 - interpolationFactor) * sample1Higher + interpo
lationFactor * sample2Higher; |
| 319 float sampleLower = (1 - interpolationFactor) * sample1Lower + interpola
tionFactor * sample2Lower; | 319 float sampleLower = (1 - interpolationFactor) * sample1Lower + interpola
tionFactor * sample2Lower; |
| 320 | 320 |
| 321 // Then interpolate between the two tables. | 321 // Then interpolate between the two tables. |
| 322 float sample = (1 - tableInterpolationFactor) * sampleHigher + tableInte
rpolationFactor * sampleLower; | 322 float sample = (1 - tableInterpolationFactor) * sampleHigher + tableInte
rpolationFactor * sampleLower; |
| 323 | 323 |
| 324 *destP++ = sample; | 324 *destP++ = sample; |
| 325 | 325 |
| 326 // Increment virtual read index and wrap virtualReadIndex into the range
0 -> waveTableSize. | 326 // Increment virtual read index and wrap virtualReadIndex into the range
0 -> periodicWaveSize. |
| 327 virtualReadIndex += incr; | 327 virtualReadIndex += incr; |
| 328 virtualReadIndex -= floor(virtualReadIndex * invWaveTableSize) * waveTab
leSize; | 328 virtualReadIndex -= floor(virtualReadIndex * invPeriodicWaveSize) * peri
odicWaveSize; |
| 329 } | 329 } |
| 330 | 330 |
| 331 m_virtualReadIndex = virtualReadIndex; | 331 m_virtualReadIndex = virtualReadIndex; |
| 332 | 332 |
| 333 outputBus->clearSilentFlag(); | 333 outputBus->clearSilentFlag(); |
| 334 } | 334 } |
| 335 | 335 |
| 336 void OscillatorNode::reset() | 336 void OscillatorNode::reset() |
| 337 { | 337 { |
| 338 m_virtualReadIndex = 0; | 338 m_virtualReadIndex = 0; |
| 339 } | 339 } |
| 340 | 340 |
| 341 void OscillatorNode::setWaveTable(WaveTable* waveTable) | 341 void OscillatorNode::setPeriodicWave(PeriodicWave* periodicWave) |
| 342 { | 342 { |
| 343 ASSERT(isMainThread()); | 343 ASSERT(isMainThread()); |
| 344 | 344 |
| 345 // This synchronizes with process(). | 345 // This synchronizes with process(). |
| 346 MutexLocker processLocker(m_processLock); | 346 MutexLocker processLocker(m_processLock); |
| 347 m_waveTable = waveTable; | 347 m_periodicWave = periodicWave; |
| 348 m_type = CUSTOM; | 348 m_type = CUSTOM; |
| 349 } | 349 } |
| 350 | 350 |
| 351 bool OscillatorNode::propagatesSilence() const | 351 bool OscillatorNode::propagatesSilence() const |
| 352 { | 352 { |
| 353 return !isPlayingOrScheduled() || hasFinished() || !m_waveTable.get(); | 353 return !isPlayingOrScheduled() || hasFinished() || !m_periodicWave.get(); |
| 354 } | 354 } |
| 355 | 355 |
| 356 } // namespace WebCore | 356 } // namespace WebCore |
| 357 | 357 |
| 358 #endif // ENABLE(WEB_AUDIO) | 358 #endif // ENABLE(WEB_AUDIO) |
| OLD | NEW |