Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(604)

Side by Side Diff: Source/modules/webaudio/PannerNode.cpp

Issue 189143010: Cache values for panning and spatialization effects to enhance performance on pannerNode. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/modules/webaudio/PannerNode.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 42
43 static void fixNANs(double &x) 43 static void fixNANs(double &x)
44 { 44 {
45 if (std::isnan(x) || std::isinf(x)) 45 if (std::isnan(x) || std::isinf(x))
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_position(0, 0, 0)
53 , m_orientation(1, 0, 0)
54 , m_velocity(0, 0, 0)
55 , m_cachedPosition(0, 0, 0)
56 , m_cachedOrientation(1, 0, 0)
57 , m_cachedVelocity(0, 0, 0)
52 , m_lastGain(-1.0) 58 , m_lastGain(-1.0)
59 , m_cachedAzimuth(0)
60 , m_cachedElevation(0)
61 , m_cachedDistanceConeGain(0)
62 , m_cachedDopplerRate(1)
53 , m_connectionCount(0) 63 , m_connectionCount(0)
54 { 64 {
55 // Load the HRTF database asynchronously so we don't block the Javascript th read while creating the HRTF database. 65 // Load the HRTF database asynchronously so we don't block the Javascript th read while creating the HRTF database.
56 // The HRTF panner will return zeroes until the database is loaded. 66 // The HRTF panner will return zeroes until the database is loaded.
57 m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNece ssary(context->sampleRate()); 67 m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNece ssary(context->sampleRate());
58 68
59 ScriptWrappable::init(this); 69 ScriptWrappable::init(this);
60 addInput(adoptPtr(new AudioNodeInput(this))); 70 addInput(adoptPtr(new AudioNodeInput(this)));
61 addOutput(adoptPtr(new AudioNodeOutput(this, 2))); 71 addOutput(adoptPtr(new AudioNodeOutput(this, 2)));
62 72
63 // Node-specific default mixing rules. 73 // Node-specific default mixing rules.
64 m_channelCount = 2; 74 m_channelCount = 2;
65 m_channelCountMode = ClampedMax; 75 m_channelCountMode = ClampedMax;
66 m_channelInterpretation = AudioBus::Speakers; 76 m_channelInterpretation = AudioBus::Speakers;
67 77
68 m_distanceGain = AudioParam::create(context, "distanceGain", 1.0, 0.0, 1.0); 78 m_distanceGain = AudioParam::create(context, "distanceGain", 1.0, 0.0, 1.0);
69 m_coneGain = AudioParam::create(context, "coneGain", 1.0, 0.0, 1.0); 79 m_coneGain = AudioParam::create(context, "coneGain", 1.0, 0.0, 1.0);
70 80
71 m_position = FloatPoint3D(0, 0, 0); 81 m_cachedListener = AudioListener::create();
72 m_orientation = FloatPoint3D(1, 0, 0);
73 m_velocity = FloatPoint3D(0, 0, 0);
74 82
75 setNodeType(NodeTypePanner); 83 setNodeType(NodeTypePanner);
76 84
77 initialize(); 85 initialize();
78 } 86 }
79 87
80 PannerNode::~PannerNode() 88 PannerNode::~PannerNode()
81 { 89 {
82 uninitialize(); 90 uninitialize();
83 } 91 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 return; 132 return;
125 } 133 }
126 } 134 }
127 135
128 // The audio thread can't block on this lock, so we call tryLock() instead. 136 // The audio thread can't block on this lock, so we call tryLock() instead.
129 MutexTryLocker tryLocker(m_pannerLock); 137 MutexTryLocker tryLocker(m_pannerLock);
130 if (tryLocker.locked()) { 138 if (tryLocker.locked()) {
131 // Apply the panning effect. 139 // Apply the panning effect.
132 double azimuth; 140 double azimuth;
133 double elevation; 141 double elevation;
134 getAzimuthElevation(&azimuth, &elevation); 142 azimuthElevation(&azimuth, &elevation);
143
135 m_panner->pan(azimuth, elevation, source, destination, framesToProcess); 144 m_panner->pan(azimuth, elevation, source, destination, framesToProcess);
136 145
137 // Get the distance and cone gain. 146 // Get the distance and cone gain.
138 double totalGain = distanceConeGain(); 147 float totalGain = distanceConeGain();
139 148
140 // Snap to desired gain at the beginning. 149 // Snap to desired gain at the beginning.
141 if (m_lastGain == -1.0) 150 if (m_lastGain == -1.0)
142 m_lastGain = totalGain; 151 m_lastGain = totalGain;
143 152
144 // Apply gain in-place with de-zippering. 153 // Apply gain in-place with de-zippering.
145 destination->copyWithGainFrom(*destination, &m_lastGain, totalGain); 154 destination->copyWithGainFrom(*destination, &m_lastGain, totalGain);
155
156 // Update the cached listener in case listener has moved.
157 updateCachedListener();
158 // Now update the cached source location in case the source has changed.
159 updateCachedSourceLocationInfo();
146 } else { 160 } else {
147 // Too bad - The tryLock() failed. We must be in the middle of changing the panner. 161 // Too bad - The tryLock() failed. We must be in the middle of changing the panner.
148 destination->zero(); 162 destination->zero();
149 } 163 }
150 } 164 }
151 165
152 void PannerNode::initialize() 166 void PannerNode::initialize()
153 { 167 {
154 if (isInitialized()) 168 if (isInitialized())
155 return; 169 return;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 m_panningModel = model; 224 m_panningModel = model;
211 } 225 }
212 break; 226 break;
213 default: 227 default:
214 return false; 228 return false;
215 } 229 }
216 230
217 return true; 231 return true;
218 } 232 }
219 233
234 void PannerNode::setPosition(float x, float y, float z)
235 {
236 // FIXME : consider thread safety about m_position in audio thread.
237 // See http://crbugs.com/350583.
238 FloatPoint3D position = FloatPoint3D(x, y, z);
239
240 if (m_position == position)
241 return;
242
243 m_position = position;
244 }
245
246 void PannerNode::setOrientation(float x, float y, float z)
247 {
248 // FIXME : consider thread safety about m_orientation in audio thread.
249 // See http://crbugs.com/350583.
250 FloatPoint3D orientation = FloatPoint3D(x, y, z);
251
252 if (m_orientation == orientation)
253 return;
254
255 m_orientation = orientation;
256 }
257
258 void PannerNode::setVelocity(float x, float y, float z)
259 {
260 // FIXME : consider thread safety about m_velocity in audio thread.
261 // See http://crbugs.com/350583.
262 FloatPoint3D velocity = FloatPoint3D(x, y, z);
263
264 if (m_velocity == velocity)
265 return;
266
267 m_velocity = velocity;
268 }
269
220 String PannerNode::distanceModel() const 270 String PannerNode::distanceModel() const
221 { 271 {
222 switch (const_cast<PannerNode*>(this)->m_distanceEffect.model()) { 272 switch (const_cast<PannerNode*>(this)->m_distanceEffect.model()) {
223 case DistanceEffect::ModelLinear: 273 case DistanceEffect::ModelLinear:
224 return "linear"; 274 return "linear";
225 case DistanceEffect::ModelInverse: 275 case DistanceEffect::ModelInverse:
226 return "inverse"; 276 return "inverse";
227 case DistanceEffect::ModelExponential: 277 case DistanceEffect::ModelExponential:
228 return "exponential"; 278 return "exponential";
229 default: 279 default:
(...skipping 22 matching lines...) Expand all
252 case DistanceEffect::ModelExponential: 302 case DistanceEffect::ModelExponential:
253 m_distanceEffect.setModel(static_cast<DistanceEffect::ModelType>(model), true); 303 m_distanceEffect.setModel(static_cast<DistanceEffect::ModelType>(model), true);
254 break; 304 break;
255 default: 305 default:
256 return false; 306 return false;
257 } 307 }
258 308
259 return true; 309 return true;
260 } 310 }
261 311
262 void PannerNode::getAzimuthElevation(double* outAzimuth, double* outElevation) 312 void PannerNode::calculateAzimuthElevation(double* outAzimuth, double* outElevat ion)
263 { 313 {
264 // FIXME: we should cache azimuth and elevation (if possible), so we only re -calculate if a change has been made.
265
266 double azimuth = 0.0; 314 double azimuth = 0.0;
267 315
268 // Calculate the source-listener vector 316 // Calculate the source-listener vector
269 FloatPoint3D listenerPosition = listener()->position(); 317 FloatPoint3D listenerPosition = listener()->position();
270 FloatPoint3D sourceListener = m_position - listenerPosition; 318 FloatPoint3D sourceListener = m_position - listenerPosition;
271 319
272 if (sourceListener.isZero()) { 320 if (sourceListener.isZero()) {
273 // degenerate case if source and listener are at the same point 321 // degenerate case if source and listener are at the same point
274 *outAzimuth = 0.0; 322 *outAzimuth = 0.0;
275 *outElevation = 0.0; 323 *outElevation = 0.0;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 elevation = 180.0 - elevation; 364 elevation = 180.0 - elevation;
317 else if (elevation < -90.0) 365 else if (elevation < -90.0)
318 elevation = -180.0 - elevation; 366 elevation = -180.0 - elevation;
319 367
320 if (outAzimuth) 368 if (outAzimuth)
321 *outAzimuth = azimuth; 369 *outAzimuth = azimuth;
322 if (outElevation) 370 if (outElevation)
323 *outElevation = elevation; 371 *outElevation = elevation;
324 } 372 }
325 373
326 float PannerNode::dopplerRate() 374
375 double PannerNode::calculateDopplerRate()
327 { 376 {
328 double dopplerShift = 1.0; 377 double dopplerShift = 1.0;
329
330 // FIXME: optimize for case when neither source nor listener has changed...
331 double dopplerFactor = listener()->dopplerFactor(); 378 double dopplerFactor = listener()->dopplerFactor();
332 379
333 if (dopplerFactor > 0.0) { 380 if (dopplerFactor > 0.0) {
334 double speedOfSound = listener()->speedOfSound(); 381 double speedOfSound = listener()->speedOfSound();
335 382
336 const FloatPoint3D &sourceVelocity = m_velocity; 383 const FloatPoint3D &sourceVelocity = m_velocity;
337 const FloatPoint3D &listenerVelocity = listener()->velocity(); 384 const FloatPoint3D &listenerVelocity = listener()->velocity();
338 385
339 // Don't bother if both source and listener have no velocity 386 // Don't bother if both source and listener have no velocity
340 bool sourceHasVelocity = !sourceVelocity.isZero(); 387 bool sourceHasVelocity = !sourceVelocity.isZero();
(...skipping 20 matching lines...) Expand all
361 fixNANs(dopplerShift); // avoid illegal values 408 fixNANs(dopplerShift); // avoid illegal values
362 409
363 // Limit the pitch shifting to 4 octaves up and 3 octaves down. 410 // Limit the pitch shifting to 4 octaves up and 3 octaves down.
364 if (dopplerShift > 16.0) 411 if (dopplerShift > 16.0)
365 dopplerShift = 16.0; 412 dopplerShift = 16.0;
366 else if (dopplerShift < 0.125) 413 else if (dopplerShift < 0.125)
367 dopplerShift = 0.125; 414 dopplerShift = 0.125;
368 } 415 }
369 } 416 }
370 417
371 return static_cast<float>(dopplerShift); 418 return dopplerShift;
372 } 419 }
373 420
374 float PannerNode::distanceConeGain() 421 float PannerNode::calculateDistanceConeGain()
375 { 422 {
376 FloatPoint3D listenerPosition = listener()->position(); 423 FloatPoint3D listenerPosition = listener()->position();
377 424
378 double listenerDistance = m_position.distanceTo(listenerPosition); 425 double listenerDistance = m_position.distanceTo(listenerPosition);
379 double distanceGain = m_distanceEffect.gain(listenerDistance); 426 double distanceGain = m_distanceEffect.gain(listenerDistance);
380 427
381 m_distanceGain->setValue(static_cast<float>(distanceGain)); 428 m_distanceGain->setValue(static_cast<float>(distanceGain));
382 429
383 // FIXME: could optimize by caching coneGain
384 double coneGain = m_coneEffect.gain(m_position, m_orientation, listenerPosit ion); 430 double coneGain = m_coneEffect.gain(m_position, m_orientation, listenerPosit ion);
385 431
386 m_coneGain->setValue(static_cast<float>(coneGain)); 432 m_coneGain->setValue(static_cast<float>(coneGain));
387 433
388 return float(distanceGain * coneGain); 434 return float(distanceGain * coneGain);
389 } 435 }
390 436
437 void PannerNode::azimuthElevation(double* outAzimuth, double* outElevation)
438 {
439 if (isAzimuthElevationDirty())
440 calculateAzimuthElevation(&m_cachedAzimuth, &m_cachedElevation);
441
442 *outAzimuth = m_cachedAzimuth;
443 *outElevation = m_cachedElevation;
444 }
445
446 double PannerNode::dopplerRate()
447 {
448 if (isDopplerRateDirty())
449 m_cachedDopplerRate = calculateDopplerRate();
450
451 return m_cachedDopplerRate;
452 }
453
454 float PannerNode::distanceConeGain()
455 {
456 if (isDistanceConeGainDirty())
457 m_cachedDistanceConeGain = calculateDistanceConeGain();
458
459 return m_cachedDistanceConeGain;
460 }
461
462 bool PannerNode::isAzimuthElevationDirty()
463 {
464 // Do a quick test and return if possible.
465 if (m_cachedPosition != m_position)
466 return true;
467
468 if (m_cachedListener->position() != listener()->position()
469 || m_cachedListener->orientation() != listener()->orientation()
470 || m_cachedListener->upVector() != listener()->upVector())
471 return true;
472
473 return false;
474 }
475
476 bool PannerNode::isDistanceConeGainDirty()
477 {
478 // Do a quick test and return if possible.
479 if (m_cachedPosition != m_position || m_cachedOrientation != m_orientation)
480 return true;
481
482 if (m_cachedListener->position() != listener()->position())
483 return true;
484
485 return false;
486 }
487
488 bool PannerNode::isDopplerRateDirty()
489 {
490 // Do a quick test and return if possible.
491 if (m_cachedPosition != m_position || m_cachedVelocity != m_velocity)
492 return true;
493
494 if (m_cachedListener->position() != listener()->position()
495 || m_cachedListener->velocity() != listener()->velocity()
496 || m_cachedListener->dopplerFactor() != listener()->dopplerFactor()
497 || m_cachedListener->speedOfSound() != listener()->speedOfSound())
498 return true;
499
500 return false;
501 }
502
391 void PannerNode::notifyAudioSourcesConnectedToNode(AudioNode* node, HashMap<Audi oNode*, bool>& visitedNodes) 503 void PannerNode::notifyAudioSourcesConnectedToNode(AudioNode* node, HashMap<Audi oNode*, bool>& visitedNodes)
392 { 504 {
393 ASSERT(node); 505 ASSERT(node);
394 if (!node) 506 if (!node)
395 return; 507 return;
396 508
397 // 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. 509 // 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.
398 if (node->nodeType() == NodeTypeAudioBufferSource) { 510 if (node->nodeType() == NodeTypeAudioBufferSource) {
399 AudioBufferSourceNode* bufferSourceNode = static_cast<AudioBufferSourceN ode*>(node); 511 AudioBufferSourceNode* bufferSourceNode = static_cast<AudioBufferSourceN ode*>(node);
400 bufferSourceNode->setPannerNode(this); 512 bufferSourceNode->setPannerNode(this);
(...skipping 12 matching lines...) Expand all
413 // mark it as visited and recurse through the node looking for s ources. 525 // mark it as visited and recurse through the node looking for s ources.
414 if (iterator == visitedNodes.end()) { 526 if (iterator == visitedNodes.end()) {
415 visitedNodes.set(connectedNode, true); 527 visitedNodes.set(connectedNode, true);
416 notifyAudioSourcesConnectedToNode(connectedNode, visitedNode s); // recurse 528 notifyAudioSourcesConnectedToNode(connectedNode, visitedNode s); // recurse
417 } 529 }
418 } 530 }
419 } 531 }
420 } 532 }
421 } 533 }
422 534
535 void PannerNode::updateCachedListener()
536 {
537 m_cachedListener->setPosition(listener()->position());
538 m_cachedListener->setOrientation(listener()->orientation());
539 m_cachedListener->setUpVector(listener()->upVector());
540 m_cachedListener->setVelocity(listener()->velocity());
541 m_cachedListener->setDopplerFactor(listener()->dopplerFactor());
542 m_cachedListener->setSpeedOfSound(listener()->speedOfSound());
543 }
544
545 void PannerNode::updateCachedSourceLocationInfo()
546 {
547 m_cachedPosition = m_position;
548 m_cachedOrientation = m_orientation;
549 m_cachedVelocity = m_velocity;
550 }
551
423 } // namespace WebCore 552 } // namespace WebCore
424 553
425 #endif // ENABLE(WEB_AUDIO) 554 #endif // ENABLE(WEB_AUDIO)
OLDNEW
« no previous file with comments | « Source/modules/webaudio/PannerNode.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698