OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010, Google Inc. All rights reserved. | 2 * Copyright (C) 2010, 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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 x = 0.0; | 46 x = 0.0; |
47 } | 47 } |
48 | 48 |
49 PannerNode::PannerNode(AudioContext* context, float sampleRate) | 49 PannerNode::PannerNode(AudioContext* context, float sampleRate) |
50 : AudioNode(context, sampleRate) | 50 : AudioNode(context, sampleRate) |
51 , m_panningModel(Panner::PanningModelHRTF) | 51 , m_panningModel(Panner::PanningModelHRTF) |
52 , m_distanceModel(DistanceEffect::ModelInverse) | 52 , m_distanceModel(DistanceEffect::ModelInverse) |
53 , m_position(0, 0, 0) | 53 , m_position(0, 0, 0) |
54 , m_orientation(1, 0, 0) | 54 , m_orientation(1, 0, 0) |
55 , m_velocity(0, 0, 0) | 55 , m_velocity(0, 0, 0) |
56 , m_cachedPosition(0, 0, 0) | 56 , m_isAzimuthElevationDirty(true) |
57 , m_cachedOrientation(1, 0, 0) | 57 , m_isDistanceConeGainDirty(true) |
58 , m_cachedVelocity(0, 0, 0) | 58 , m_isDopplerRateDirty(true) |
59 , m_lastGain(-1.0) | 59 , m_lastGain(-1.0) |
60 , m_cachedAzimuth(0) | 60 , m_cachedAzimuth(0) |
61 , m_cachedElevation(0) | 61 , m_cachedElevation(0) |
62 , m_cachedDistanceConeGain(1.0f) | 62 , m_cachedDistanceConeGain(1.0f) |
63 , m_cachedDopplerRate(1) | 63 , m_cachedDopplerRate(1) |
64 , m_connectionCount(0) | 64 , m_connectionCount(0) |
65 { | 65 { |
66 // Load the HRTF database asynchronously so we don't block the Javascript th
read while creating the HRTF database. | 66 // Load the HRTF database asynchronously so we don't block the Javascript th
read while creating the HRTF database. |
67 // The HRTF panner will return zeroes until the database is loaded. | 67 // The HRTF panner will return zeroes until the database is loaded. |
68 m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNece
ssary(context->sampleRate()); | 68 m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNece
ssary(context->sampleRate()); |
69 | 69 |
70 ScriptWrappable::init(this); | 70 ScriptWrappable::init(this); |
71 addInput(adoptPtr(new AudioNodeInput(this))); | 71 addInput(adoptPtr(new AudioNodeInput(this))); |
72 addOutput(adoptPtr(new AudioNodeOutput(this, 2))); | 72 addOutput(adoptPtr(new AudioNodeOutput(this, 2))); |
73 | 73 |
74 // Node-specific default mixing rules. | 74 // Node-specific default mixing rules. |
75 m_channelCount = 2; | 75 m_channelCount = 2; |
76 m_channelCountMode = ClampedMax; | 76 m_channelCountMode = ClampedMax; |
77 m_channelInterpretation = AudioBus::Speakers; | 77 m_channelInterpretation = AudioBus::Speakers; |
78 | 78 |
79 m_cachedListener = AudioListener::create(); | |
80 | |
81 setNodeType(NodeTypePanner); | 79 setNodeType(NodeTypePanner); |
82 | 80 |
83 initialize(); | 81 initialize(); |
84 } | 82 } |
85 | 83 |
86 PannerNode::~PannerNode() | 84 PannerNode::~PannerNode() |
87 { | 85 { |
88 uninitialize(); | 86 uninitialize(); |
89 } | 87 } |
90 | 88 |
(...skipping 25 matching lines...) Expand all Loading... |
116 } | 114 } |
117 | 115 |
118 AudioBus* source = input(0)->bus(); | 116 AudioBus* source = input(0)->bus(); |
119 if (!source) { | 117 if (!source) { |
120 destination->zero(); | 118 destination->zero(); |
121 return; | 119 return; |
122 } | 120 } |
123 | 121 |
124 // The audio thread can't block on this lock, so we call tryLock() instead. | 122 // The audio thread can't block on this lock, so we call tryLock() instead. |
125 MutexTryLocker tryLocker(m_processLock); | 123 MutexTryLocker tryLocker(m_processLock); |
126 if (tryLocker.locked()) { | 124 MutexTryLocker tryListenerLocker(listener()->listenerLock()); |
| 125 |
| 126 if (tryLocker.locked() && tryListenerLocker.locked()) { |
127 // HRTFDatabase should be loaded before proceeding for offline audio con
text when the panning model is HRTF. | 127 // HRTFDatabase should be loaded before proceeding for offline audio con
text when the panning model is HRTF. |
128 if (m_panningModel == HRTF && !m_hrtfDatabaseLoader->isLoaded()) { | 128 if (m_panningModel == HRTF && !m_hrtfDatabaseLoader->isLoaded()) { |
129 if (context()->isOfflineContext()) { | 129 if (context()->isOfflineContext()) { |
130 m_hrtfDatabaseLoader->waitForLoaderThreadCompletion(); | 130 m_hrtfDatabaseLoader->waitForLoaderThreadCompletion(); |
131 } else { | 131 } else { |
132 destination->zero(); | 132 destination->zero(); |
133 return; | 133 return; |
134 } | 134 } |
135 } | 135 } |
136 | 136 |
137 // Apply the panning effect. | 137 // Apply the panning effect. |
138 double azimuth; | 138 double azimuth; |
139 double elevation; | 139 double elevation; |
140 azimuthElevation(&azimuth, &elevation); | 140 azimuthElevation(&azimuth, &elevation); |
141 | 141 |
142 m_panner->pan(azimuth, elevation, source, destination, framesToProcess); | 142 m_panner->pan(azimuth, elevation, source, destination, framesToProcess); |
143 | 143 |
144 // Get the distance and cone gain. | 144 // Get the distance and cone gain. |
145 float totalGain = distanceConeGain(); | 145 float totalGain = distanceConeGain(); |
146 | 146 |
147 // Snap to desired gain at the beginning. | 147 // Snap to desired gain at the beginning. |
148 if (m_lastGain == -1.0) | 148 if (m_lastGain == -1.0) |
149 m_lastGain = totalGain; | 149 m_lastGain = totalGain; |
150 | 150 |
151 // Apply gain in-place with de-zippering. | 151 // Apply gain in-place with de-zippering. |
152 destination->copyWithGainFrom(*destination, &m_lastGain, totalGain); | 152 destination->copyWithGainFrom(*destination, &m_lastGain, totalGain); |
153 | |
154 // Update the cached listener in case listener has moved. | |
155 updateCachedListener(); | |
156 // Now update the cached source location in case the source has changed. | |
157 updateCachedSourceLocationInfo(); | |
158 } else { | 153 } else { |
159 // Too bad - The tryLock() failed. | 154 // Too bad - The tryLock() failed. |
160 // We must be in the middle of changing the panning model, the distance
model, or the source's location information. | 155 // We must be in the middle of changing the properties of the panner or
the listener. |
161 destination->zero(); | 156 destination->zero(); |
162 } | 157 } |
163 } | 158 } |
164 | 159 |
165 void PannerNode::initialize() | 160 void PannerNode::initialize() |
166 { | 161 { |
167 if (isInitialized()) | 162 if (isInitialized()) |
168 return; | 163 return; |
169 | 164 |
170 m_panner = Panner::create(m_panningModel, sampleRate(), m_hrtfDatabaseLoader
.get()); | 165 m_panner = Panner::create(m_panningModel, sampleRate(), m_hrtfDatabaseLoader
.get()); |
| 166 listener()->addPanner(this); |
171 | 167 |
172 AudioNode::initialize(); | 168 AudioNode::initialize(); |
173 } | 169 } |
174 | 170 |
175 void PannerNode::uninitialize() | 171 void PannerNode::uninitialize() |
176 { | 172 { |
177 if (!isInitialized()) | 173 if (!isInitialized()) |
178 return; | 174 return; |
179 | 175 |
180 m_panner.clear(); | 176 m_panner.clear(); |
| 177 listener()->removePanner(this); |
| 178 |
181 AudioNode::uninitialize(); | 179 AudioNode::uninitialize(); |
182 } | 180 } |
183 | 181 |
184 AudioListener* PannerNode::listener() | 182 AudioListener* PannerNode::listener() |
185 { | 183 { |
186 return context()->listener(); | 184 return context()->listener(); |
187 } | 185 } |
188 | 186 |
189 String PannerNode::panningModel() const | 187 String PannerNode::panningModel() const |
190 { | 188 { |
(...skipping 17 matching lines...) Expand all Loading... |
208 } | 206 } |
209 | 207 |
210 bool PannerNode::setPanningModel(unsigned model) | 208 bool PannerNode::setPanningModel(unsigned model) |
211 { | 209 { |
212 switch (model) { | 210 switch (model) { |
213 case EQUALPOWER: | 211 case EQUALPOWER: |
214 case HRTF: | 212 case HRTF: |
215 if (!m_panner.get() || model != m_panningModel) { | 213 if (!m_panner.get() || model != m_panningModel) { |
216 // This synchronizes with process(). | 214 // This synchronizes with process(). |
217 MutexLocker processLocker(m_processLock); | 215 MutexLocker processLocker(m_processLock); |
218 | |
219 OwnPtr<Panner> newPanner = Panner::create(model, sampleRate(), m_hrt
fDatabaseLoader.get()); | 216 OwnPtr<Panner> newPanner = Panner::create(model, sampleRate(), m_hrt
fDatabaseLoader.get()); |
220 m_panner = newPanner.release(); | 217 m_panner = newPanner.release(); |
221 m_panningModel = model; | 218 m_panningModel = model; |
222 } | 219 } |
223 break; | 220 break; |
224 default: | 221 default: |
225 return false; | 222 return false; |
226 } | 223 } |
227 | 224 |
228 return true; | 225 return true; |
229 } | 226 } |
230 | 227 |
231 void PannerNode::setPosition(float x, float y, float z) | |
232 { | |
233 FloatPoint3D position = FloatPoint3D(x, y, z); | |
234 | |
235 if (m_position == position) | |
236 return; | |
237 | |
238 // This synchronizes with process(). | |
239 MutexLocker processLocker(m_processLock); | |
240 | |
241 m_position = position; | |
242 } | |
243 | |
244 void PannerNode::setOrientation(float x, float y, float z) | |
245 { | |
246 FloatPoint3D orientation = FloatPoint3D(x, y, z); | |
247 | |
248 if (m_orientation == orientation) | |
249 return; | |
250 | |
251 // This synchronizes with process(). | |
252 MutexLocker processLocker(m_processLock); | |
253 | |
254 m_orientation = orientation; | |
255 } | |
256 | |
257 void PannerNode::setVelocity(float x, float y, float z) | |
258 { | |
259 FloatPoint3D velocity = FloatPoint3D(x, y, z); | |
260 | |
261 if (m_velocity == velocity) | |
262 return; | |
263 | |
264 // This synchronizes with process(). | |
265 MutexLocker processLocker(m_processLock); | |
266 | |
267 m_velocity = velocity; | |
268 } | |
269 | |
270 String PannerNode::distanceModel() const | 228 String PannerNode::distanceModel() const |
271 { | 229 { |
272 switch (const_cast<PannerNode*>(this)->m_distanceEffect.model()) { | 230 switch (const_cast<PannerNode*>(this)->m_distanceEffect.model()) { |
273 case DistanceEffect::ModelLinear: | 231 case DistanceEffect::ModelLinear: |
274 return "linear"; | 232 return "linear"; |
275 case DistanceEffect::ModelInverse: | 233 case DistanceEffect::ModelInverse: |
276 return "inverse"; | 234 return "inverse"; |
277 case DistanceEffect::ModelExponential: | 235 case DistanceEffect::ModelExponential: |
278 return "exponential"; | 236 return "exponential"; |
279 default: | 237 default: |
(...skipping 25 matching lines...) Expand all Loading... |
305 m_distanceModel = model; | 263 m_distanceModel = model; |
306 } | 264 } |
307 break; | 265 break; |
308 default: | 266 default: |
309 return false; | 267 return false; |
310 } | 268 } |
311 | 269 |
312 return true; | 270 return true; |
313 } | 271 } |
314 | 272 |
| 273 void PannerNode::setRefDistance(double distance) |
| 274 { |
| 275 if (refDistance() == distance) |
| 276 return; |
| 277 |
| 278 // This synchronizes with process(). |
| 279 MutexLocker processLocker(m_processLock); |
| 280 m_distanceEffect.setRefDistance(distance); |
| 281 markPannerAsDirty(PannerNode::DistanceConeGainDirty); |
| 282 } |
| 283 |
| 284 void PannerNode::setMaxDistance(double distance) |
| 285 { |
| 286 if (maxDistance() == distance) |
| 287 return; |
| 288 |
| 289 // This synchronizes with process(). |
| 290 MutexLocker processLocker(m_processLock); |
| 291 m_distanceEffect.setMaxDistance(distance); |
| 292 markPannerAsDirty(PannerNode::DistanceConeGainDirty); |
| 293 } |
| 294 |
| 295 void PannerNode::setRolloffFactor(double factor) |
| 296 { |
| 297 if (rolloffFactor() == factor) |
| 298 return; |
| 299 |
| 300 // This synchronizes with process(). |
| 301 MutexLocker processLocker(m_processLock); |
| 302 m_distanceEffect.setRolloffFactor(factor); |
| 303 markPannerAsDirty(PannerNode::DistanceConeGainDirty); |
| 304 } |
| 305 |
| 306 void PannerNode::setConeInnerAngle(double angle) |
| 307 { |
| 308 if (coneInnerAngle() == angle) |
| 309 return; |
| 310 |
| 311 // This synchronizes with process(). |
| 312 MutexLocker processLocker(m_processLock); |
| 313 m_coneEffect.setInnerAngle(angle); |
| 314 markPannerAsDirty(PannerNode::DistanceConeGainDirty); |
| 315 } |
| 316 |
| 317 void PannerNode::setConeOuterAngle(double angle) |
| 318 { |
| 319 if (coneOuterAngle() == angle) |
| 320 return; |
| 321 |
| 322 // This synchronizes with process(). |
| 323 MutexLocker processLocker(m_processLock); |
| 324 m_coneEffect.setOuterAngle(angle); |
| 325 markPannerAsDirty(PannerNode::DistanceConeGainDirty); |
| 326 } |
| 327 |
| 328 void PannerNode::setConeOuterGain(double angle) |
| 329 { |
| 330 if (coneOuterGain() == angle) |
| 331 return; |
| 332 |
| 333 // This synchronizes with process(). |
| 334 MutexLocker processLocker(m_processLock); |
| 335 m_coneEffect.setOuterGain(angle); |
| 336 markPannerAsDirty(PannerNode::DistanceConeGainDirty); |
| 337 } |
| 338 |
| 339 void PannerNode::setPosition(float x, float y, float z) |
| 340 { |
| 341 FloatPoint3D position = FloatPoint3D(x, y, z); |
| 342 |
| 343 if (m_position == position) |
| 344 return; |
| 345 |
| 346 // This synchronizes with process(). |
| 347 MutexLocker processLocker(m_processLock); |
| 348 m_position = position; |
| 349 markPannerAsDirty(PannerNode::AzimuthElevationDirty | PannerNode::DistanceCo
neGainDirty | PannerNode::DopplerRateDirty); |
| 350 } |
| 351 |
| 352 void PannerNode::setOrientation(float x, float y, float z) |
| 353 { |
| 354 FloatPoint3D orientation = FloatPoint3D(x, y, z); |
| 355 |
| 356 if (m_orientation == orientation) |
| 357 return; |
| 358 |
| 359 // This synchronizes with process(). |
| 360 MutexLocker processLocker(m_processLock); |
| 361 m_orientation = orientation; |
| 362 markPannerAsDirty(PannerNode::DistanceConeGainDirty); |
| 363 } |
| 364 |
| 365 void PannerNode::setVelocity(float x, float y, float z) |
| 366 { |
| 367 FloatPoint3D velocity = FloatPoint3D(x, y, z); |
| 368 |
| 369 if (m_velocity == velocity) |
| 370 return; |
| 371 |
| 372 // This synchronizes with process(). |
| 373 MutexLocker processLocker(m_processLock); |
| 374 m_velocity = velocity; |
| 375 markPannerAsDirty(PannerNode::DopplerRateDirty); |
| 376 } |
| 377 |
315 void PannerNode::calculateAzimuthElevation(double* outAzimuth, double* outElevat
ion) | 378 void PannerNode::calculateAzimuthElevation(double* outAzimuth, double* outElevat
ion) |
316 { | 379 { |
317 double azimuth = 0.0; | 380 double azimuth = 0.0; |
318 | 381 |
319 // Calculate the source-listener vector | 382 // Calculate the source-listener vector |
320 FloatPoint3D listenerPosition = listener()->position(); | 383 FloatPoint3D listenerPosition = listener()->position(); |
321 FloatPoint3D sourceListener = m_position - listenerPosition; | 384 FloatPoint3D sourceListener = m_position - listenerPosition; |
322 | 385 |
323 if (sourceListener.isZero()) { | 386 if (sourceListener.isZero()) { |
324 // degenerate case if source and listener are at the same point | 387 // degenerate case if source and listener are at the same point |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 double distanceGain = m_distanceEffect.gain(listenerDistance); | 491 double distanceGain = m_distanceEffect.gain(listenerDistance); |
429 double coneGain = m_coneEffect.gain(m_position, m_orientation, listenerPosit
ion); | 492 double coneGain = m_coneEffect.gain(m_position, m_orientation, listenerPosit
ion); |
430 | 493 |
431 return float(distanceGain * coneGain); | 494 return float(distanceGain * coneGain); |
432 } | 495 } |
433 | 496 |
434 void PannerNode::azimuthElevation(double* outAzimuth, double* outElevation) | 497 void PannerNode::azimuthElevation(double* outAzimuth, double* outElevation) |
435 { | 498 { |
436 ASSERT(context()->isAudioThread()); | 499 ASSERT(context()->isAudioThread()); |
437 | 500 |
438 if (isAzimuthElevationDirty()) | 501 if (isAzimuthElevationDirty()) { |
439 calculateAzimuthElevation(&m_cachedAzimuth, &m_cachedElevation); | 502 calculateAzimuthElevation(&m_cachedAzimuth, &m_cachedElevation); |
| 503 m_isAzimuthElevationDirty = false; |
| 504 } |
440 | 505 |
441 *outAzimuth = m_cachedAzimuth; | 506 *outAzimuth = m_cachedAzimuth; |
442 *outElevation = m_cachedElevation; | 507 *outElevation = m_cachedElevation; |
443 } | 508 } |
444 | 509 |
445 double PannerNode::dopplerRate() | 510 double PannerNode::dopplerRate() |
446 { | 511 { |
447 ASSERT(context()->isAudioThread()); | 512 ASSERT(context()->isAudioThread()); |
448 | 513 |
449 if (isDopplerRateDirty()) | 514 if (isDopplerRateDirty()) { |
450 m_cachedDopplerRate = calculateDopplerRate(); | 515 m_cachedDopplerRate = calculateDopplerRate(); |
| 516 m_isDopplerRateDirty = false; |
| 517 } |
451 | 518 |
452 return m_cachedDopplerRate; | 519 return m_cachedDopplerRate; |
453 } | 520 } |
454 | 521 |
455 float PannerNode::distanceConeGain() | 522 float PannerNode::distanceConeGain() |
456 { | 523 { |
457 ASSERT(context()->isAudioThread()); | 524 ASSERT(context()->isAudioThread()); |
458 | 525 |
459 if (isDistanceConeGainDirty()) | 526 if (isDistanceConeGainDirty()) { |
460 m_cachedDistanceConeGain = calculateDistanceConeGain(); | 527 m_cachedDistanceConeGain = calculateDistanceConeGain(); |
| 528 m_isDistanceConeGainDirty = false; |
| 529 } |
461 | 530 |
462 return m_cachedDistanceConeGain; | 531 return m_cachedDistanceConeGain; |
463 } | 532 } |
464 | 533 |
465 bool PannerNode::isAzimuthElevationDirty() | 534 void PannerNode::markPannerAsDirty(unsigned dirty) |
466 { | 535 { |
467 // Do a quick test and return if possible. | 536 if (dirty & PannerNode::AzimuthElevationDirty) |
468 if (m_cachedPosition != m_position) | 537 m_isAzimuthElevationDirty = true; |
469 return true; | |
470 | 538 |
471 if (m_cachedListener->position() != listener()->position() | 539 if (dirty & PannerNode::DistanceConeGainDirty) |
472 || m_cachedListener->orientation() != listener()->orientation() | 540 m_isDistanceConeGainDirty = true; |
473 || m_cachedListener->upVector() != listener()->upVector()) | |
474 return true; | |
475 | 541 |
476 return false; | 542 if (dirty & PannerNode::DopplerRateDirty) |
477 } | 543 m_isDopplerRateDirty = true; |
478 | |
479 bool PannerNode::isDistanceConeGainDirty() | |
480 { | |
481 // Do a quick test and return if possible. | |
482 if (m_cachedPosition != m_position || m_cachedOrientation != m_orientation) | |
483 return true; | |
484 | |
485 if (m_cachedListener->position() != listener()->position()) | |
486 return true; | |
487 | |
488 return false; | |
489 } | |
490 | |
491 bool PannerNode::isDopplerRateDirty() | |
492 { | |
493 // Do a quick test and return if possible. | |
494 if (m_cachedPosition != m_position || m_cachedVelocity != m_velocity) | |
495 return true; | |
496 | |
497 if (m_cachedListener->position() != listener()->position() | |
498 || m_cachedListener->velocity() != listener()->velocity() | |
499 || m_cachedListener->dopplerFactor() != listener()->dopplerFactor() | |
500 || m_cachedListener->speedOfSound() != listener()->speedOfSound()) | |
501 return true; | |
502 | |
503 return false; | |
504 } | 544 } |
505 | 545 |
506 void PannerNode::notifyAudioSourcesConnectedToNode(AudioNode* node, HashMap<Audi
oNode*, bool>& visitedNodes) | 546 void PannerNode::notifyAudioSourcesConnectedToNode(AudioNode* node, HashMap<Audi
oNode*, bool>& visitedNodes) |
507 { | 547 { |
508 ASSERT(node); | 548 ASSERT(node); |
509 if (!node) | 549 if (!node) |
510 return; | 550 return; |
511 | 551 |
512 // First check if this node is an AudioBufferSourceNode. If so, let it know
about us so that doppler shift pitch can be taken into account. | 552 // First check if this node is an AudioBufferSourceNode. If so, let it know
about us so that doppler shift pitch can be taken into account. |
513 if (node->nodeType() == NodeTypeAudioBufferSource) { | 553 if (node->nodeType() == NodeTypeAudioBufferSource) { |
(...skipping 14 matching lines...) Expand all Loading... |
528 // mark it as visited and recurse through the node looking for s
ources. | 568 // mark it as visited and recurse through the node looking for s
ources. |
529 if (iterator == visitedNodes.end()) { | 569 if (iterator == visitedNodes.end()) { |
530 visitedNodes.set(connectedNode, true); | 570 visitedNodes.set(connectedNode, true); |
531 notifyAudioSourcesConnectedToNode(connectedNode, visitedNode
s); // recurse | 571 notifyAudioSourcesConnectedToNode(connectedNode, visitedNode
s); // recurse |
532 } | 572 } |
533 } | 573 } |
534 } | 574 } |
535 } | 575 } |
536 } | 576 } |
537 | 577 |
538 void PannerNode::updateCachedListener() | |
539 { | |
540 ASSERT(context()->isAudioThread()); | |
541 | |
542 m_cachedListener->setPosition(listener()->position()); | |
543 m_cachedListener->setOrientation(listener()->orientation()); | |
544 m_cachedListener->setUpVector(listener()->upVector()); | |
545 m_cachedListener->setVelocity(listener()->velocity()); | |
546 m_cachedListener->setDopplerFactor(listener()->dopplerFactor()); | |
547 m_cachedListener->setSpeedOfSound(listener()->speedOfSound()); | |
548 } | |
549 | |
550 void PannerNode::updateCachedSourceLocationInfo() | |
551 { | |
552 ASSERT(context()->isAudioThread()); | |
553 | |
554 m_cachedPosition = m_position; | |
555 m_cachedOrientation = m_orientation; | |
556 m_cachedVelocity = m_velocity; | |
557 } | |
558 | |
559 } // namespace WebCore | 578 } // namespace WebCore |
560 | 579 |
561 #endif // ENABLE(WEB_AUDIO) | 580 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |