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 |