Chromium Code Reviews| 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 13 matching lines...) Expand all Loading... | |
| 24 | 24 |
| 25 #include "config.h" | 25 #include "config.h" |
| 26 | 26 |
| 27 #if ENABLE(WEB_AUDIO) | 27 #if ENABLE(WEB_AUDIO) |
| 28 | 28 |
| 29 #include "modules/webaudio/PannerNode.h" | 29 #include "modules/webaudio/PannerNode.h" |
| 30 | 30 |
| 31 #include "core/dom/ExecutionContext.h" | 31 #include "core/dom/ExecutionContext.h" |
| 32 #include "platform/audio/HRTFPanner.h" | 32 #include "platform/audio/HRTFPanner.h" |
| 33 #include "modules/webaudio/AudioBufferSourceNode.h" | 33 #include "modules/webaudio/AudioBufferSourceNode.h" |
| 34 #include "modules/webaudio/AudioContext.h" | |
| 35 #include "modules/webaudio/AudioNodeInput.h" | 34 #include "modules/webaudio/AudioNodeInput.h" |
| 36 #include "modules/webaudio/AudioNodeOutput.h" | 35 #include "modules/webaudio/AudioNodeOutput.h" |
| 37 #include "wtf/MathExtras.h" | 36 #include "wtf/MathExtras.h" |
| 38 | 37 |
| 39 using namespace std; | 38 using namespace std; |
| 40 | 39 |
| 41 namespace WebCore { | 40 namespace WebCore { |
| 42 | 41 |
| 43 static void fixNANs(double &x) | 42 static void fixNANs(double &x) |
| 44 { | 43 { |
| 45 if (std::isnan(x) || std::isinf(x)) | 44 if (std::isnan(x) || std::isinf(x)) |
| 46 x = 0.0; | 45 x = 0.0; |
| 47 } | 46 } |
| 48 | 47 |
| 49 PannerNode::PannerNode(AudioContext* context, float sampleRate) | 48 PannerNode::PannerNode(AudioContext* context, float sampleRate) |
| 50 : AudioNode(context, sampleRate) | 49 : AudioNode(context, sampleRate) |
| 51 , m_panningModel(Panner::PanningModelHRTF) | 50 , m_panningModel(Panner::PanningModelHRTF) |
| 52 , m_distanceModel(DistanceEffect::ModelInverse) | 51 , m_distanceModel(DistanceEffect::ModelInverse) |
| 53 , m_position(0, 0, 0) | 52 , m_position(0, 0, 0) |
| 54 , m_orientation(1, 0, 0) | 53 , m_orientation(1, 0, 0) |
| 55 , m_velocity(0, 0, 0) | 54 , m_velocity(0, 0, 0) |
| 56 , m_cachedPosition(0, 0, 0) | 55 , m_isAzimuthElevationDirty(true) |
| 57 , m_cachedOrientation(1, 0, 0) | 56 , m_isDistanceConeGainDirty(true) |
| 58 , m_cachedVelocity(0, 0, 0) | 57 , m_isDopplerRateDirty(true) |
| 59 , m_lastGain(-1.0) | 58 , m_lastGain(-1.0) |
| 60 , m_cachedAzimuth(0) | 59 , m_cachedAzimuth(0) |
| 61 , m_cachedElevation(0) | 60 , m_cachedElevation(0) |
| 62 , m_cachedDistanceConeGain(1.0f) | 61 , m_cachedDistanceConeGain(1.0f) |
| 63 , m_cachedDopplerRate(1) | 62 , m_cachedDopplerRate(1) |
| 64 , m_connectionCount(0) | 63 , m_connectionCount(0) |
| 65 { | 64 { |
| 66 // 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. |
| 67 // The HRTF panner will return zeroes until the database is loaded. | 66 // The HRTF panner will return zeroes until the database is loaded. |
| 68 m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNece ssary(context->sampleRate()); | 67 m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNece ssary(context->sampleRate()); |
| 69 | 68 |
| 70 ScriptWrappable::init(this); | 69 ScriptWrappable::init(this); |
| 71 addInput(adoptPtr(new AudioNodeInput(this))); | 70 addInput(adoptPtr(new AudioNodeInput(this))); |
| 72 addOutput(adoptPtr(new AudioNodeOutput(this, 2))); | 71 addOutput(adoptPtr(new AudioNodeOutput(this, 2))); |
| 73 | 72 |
| 74 // Node-specific default mixing rules. | 73 // Node-specific default mixing rules. |
| 75 m_channelCount = 2; | 74 m_channelCount = 2; |
| 76 m_channelCountMode = ClampedMax; | 75 m_channelCountMode = ClampedMax; |
| 77 m_channelInterpretation = AudioBus::Speakers; | 76 m_channelInterpretation = AudioBus::Speakers; |
| 78 | 77 |
| 79 m_cachedListener = AudioListener::create(); | |
| 80 | |
| 81 setNodeType(NodeTypePanner); | 78 setNodeType(NodeTypePanner); |
| 82 | 79 |
| 83 initialize(); | 80 initialize(); |
| 84 } | 81 } |
| 85 | 82 |
| 86 PannerNode::~PannerNode() | 83 PannerNode::~PannerNode() |
| 87 { | 84 { |
| 88 uninitialize(); | 85 uninitialize(); |
| 89 } | 86 } |
| 90 | 87 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 116 } | 113 } |
| 117 | 114 |
| 118 AudioBus* source = input(0)->bus(); | 115 AudioBus* source = input(0)->bus(); |
| 119 if (!source) { | 116 if (!source) { |
| 120 destination->zero(); | 117 destination->zero(); |
| 121 return; | 118 return; |
| 122 } | 119 } |
| 123 | 120 |
| 124 // The audio thread can't block on this lock, so we call tryLock() instead. | 121 // The audio thread can't block on this lock, so we call tryLock() instead. |
| 125 MutexTryLocker tryLocker(m_processLock); | 122 MutexTryLocker tryLocker(m_processLock); |
| 126 if (tryLocker.locked()) { | 123 MutexTryLocker tryListenerLocker(listener()->listenerLock()); |
|
KhNo
2014/04/14 11:23:30
It is required to lock context's listener.
| |
| 124 | |
| 125 if (tryLocker.locked() && tryListenerLocker.locked()) { | |
| 127 // HRTFDatabase should be loaded before proceeding for offline audio con text when the panning model is HRTF. | 126 // 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()) { | 127 if (m_panningModel == HRTF && !m_hrtfDatabaseLoader->isLoaded()) { |
| 129 if (context()->isOfflineContext()) { | 128 if (context()->isOfflineContext()) { |
| 130 m_hrtfDatabaseLoader->waitForLoaderThreadCompletion(); | 129 m_hrtfDatabaseLoader->waitForLoaderThreadCompletion(); |
| 131 } else { | 130 } else { |
| 132 destination->zero(); | 131 destination->zero(); |
| 133 return; | 132 return; |
| 134 } | 133 } |
| 135 } | 134 } |
| 136 | 135 |
| 137 // Apply the panning effect. | 136 // Apply the panning effect. |
| 138 double azimuth; | 137 double azimuth; |
| 139 double elevation; | 138 double elevation; |
| 140 azimuthElevation(&azimuth, &elevation); | 139 azimuthElevation(&azimuth, &elevation); |
| 141 | 140 |
| 142 m_panner->pan(azimuth, elevation, source, destination, framesToProcess); | 141 m_panner->pan(azimuth, elevation, source, destination, framesToProcess); |
| 143 | 142 |
| 144 // Get the distance and cone gain. | 143 // Get the distance and cone gain. |
| 145 float totalGain = distanceConeGain(); | 144 float totalGain = distanceConeGain(); |
| 146 | 145 |
| 147 // Snap to desired gain at the beginning. | 146 // Snap to desired gain at the beginning. |
| 148 if (m_lastGain == -1.0) | 147 if (m_lastGain == -1.0) |
| 149 m_lastGain = totalGain; | 148 m_lastGain = totalGain; |
| 150 | 149 |
| 151 // Apply gain in-place with de-zippering. | 150 // Apply gain in-place with de-zippering. |
| 152 destination->copyWithGainFrom(*destination, &m_lastGain, totalGain); | 151 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 { | 152 } else { |
| 159 // Too bad - The tryLock() failed. | 153 // 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. | 154 // We must be in the middle of changing the panning model, source's loca tion information, listener, distance parameters and sound cones. |
| 161 destination->zero(); | 155 destination->zero(); |
| 162 } | 156 } |
| 163 } | 157 } |
| 164 | 158 |
| 165 void PannerNode::initialize() | 159 void PannerNode::initialize() |
| 166 { | 160 { |
| 167 if (isInitialized()) | 161 if (isInitialized()) |
| 168 return; | 162 return; |
| 169 | 163 |
| 170 m_panner = Panner::create(m_panningModel, sampleRate(), m_hrtfDatabaseLoader .get()); | 164 m_panner = Panner::create(m_panningModel, sampleRate(), m_hrtfDatabaseLoader .get()); |
| 165 listener()->addPanner(this); | |
| 171 | 166 |
| 172 AudioNode::initialize(); | 167 AudioNode::initialize(); |
| 173 } | 168 } |
| 174 | 169 |
| 175 void PannerNode::uninitialize() | 170 void PannerNode::uninitialize() |
| 176 { | 171 { |
| 177 if (!isInitialized()) | 172 if (!isInitialized()) |
| 178 return; | 173 return; |
| 179 | 174 |
| 180 m_panner.clear(); | 175 m_panner.clear(); |
| 176 listener()->removePanner(this); | |
| 177 | |
| 181 AudioNode::uninitialize(); | 178 AudioNode::uninitialize(); |
| 182 } | 179 } |
| 183 | 180 |
| 184 AudioListener* PannerNode::listener() | |
| 185 { | |
| 186 return context()->listener(); | |
| 187 } | |
| 188 | |
| 189 String PannerNode::panningModel() const | 181 String PannerNode::panningModel() const |
| 190 { | 182 { |
| 191 switch (m_panningModel) { | 183 switch (m_panningModel) { |
| 192 case EQUALPOWER: | 184 case EqualPower: |
| 193 return "equalpower"; | 185 return "equalpower"; |
| 194 case HRTF: | 186 case HRTF: |
| 195 return "HRTF"; | 187 return "HRTF"; |
| 196 default: | 188 default: |
| 197 ASSERT_NOT_REACHED(); | 189 ASSERT_NOT_REACHED(); |
| 198 return "HRTF"; | 190 return "HRTF"; |
| 199 } | 191 } |
| 200 } | 192 } |
| 201 | 193 |
| 202 void PannerNode::setPanningModel(const String& model) | 194 void PannerNode::setPanningModel(const String& model) |
| 203 { | 195 { |
| 204 if (model == "equalpower") | 196 if (model == "equalpower") |
| 205 setPanningModel(EQUALPOWER); | 197 setPanningModel(EqualPower); |
| 206 else if (model == "HRTF") | 198 else if (model == "HRTF") |
| 207 setPanningModel(HRTF); | 199 setPanningModel(HRTF); |
| 208 } | 200 } |
| 209 | 201 |
| 210 bool PannerNode::setPanningModel(unsigned model) | 202 bool PannerNode::setPanningModel(unsigned model) |
| 211 { | 203 { |
| 212 switch (model) { | 204 switch (model) { |
| 213 case EQUALPOWER: | 205 case EqualPower: |
| 214 case HRTF: | 206 case HRTF: |
| 215 if (!m_panner.get() || model != m_panningModel) { | 207 if (!m_panner.get() || model != m_panningModel) { |
| 216 // This synchronizes with process(). | 208 // This synchronizes with process(). |
| 217 MutexLocker processLocker(m_processLock); | 209 MutexLocker processLocker(m_processLock); |
| 218 | |
| 219 OwnPtr<Panner> newPanner = Panner::create(model, sampleRate(), m_hrt fDatabaseLoader.get()); | 210 OwnPtr<Panner> newPanner = Panner::create(model, sampleRate(), m_hrt fDatabaseLoader.get()); |
| 220 m_panner = newPanner.release(); | 211 m_panner = newPanner.release(); |
| 221 m_panningModel = model; | 212 m_panningModel = model; |
| 222 } | 213 } |
| 223 break; | 214 break; |
| 224 default: | 215 default: |
| 225 return false; | 216 return false; |
| 226 } | 217 } |
| 227 | 218 |
| 228 return true; | 219 return true; |
| 229 } | 220 } |
| 230 | 221 |
| 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 | 222 String PannerNode::distanceModel() const |
| 271 { | 223 { |
| 272 switch (const_cast<PannerNode*>(this)->m_distanceEffect.model()) { | 224 switch (const_cast<PannerNode*>(this)->m_distanceEffect.model()) { |
| 273 case DistanceEffect::ModelLinear: | 225 case DistanceEffect::ModelLinear: |
| 274 return "linear"; | 226 return "linear"; |
| 275 case DistanceEffect::ModelInverse: | 227 case DistanceEffect::ModelInverse: |
| 276 return "inverse"; | 228 return "inverse"; |
| 277 case DistanceEffect::ModelExponential: | 229 case DistanceEffect::ModelExponential: |
| 278 return "exponential"; | 230 return "exponential"; |
| 279 default: | 231 default: |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 305 m_distanceModel = model; | 257 m_distanceModel = model; |
| 306 } | 258 } |
| 307 break; | 259 break; |
| 308 default: | 260 default: |
| 309 return false; | 261 return false; |
| 310 } | 262 } |
| 311 | 263 |
| 312 return true; | 264 return true; |
| 313 } | 265 } |
| 314 | 266 |
| 267 void PannerNode::setRefDistance(double distance) | |
| 268 { | |
| 269 if (refDistance() == distance) | |
| 270 return; | |
| 271 | |
| 272 // This synchronizes with process(). | |
| 273 MutexLocker processLocker(m_processLock); | |
| 274 m_distanceEffect.setRefDistance(distance); | |
| 275 updatePannerDirty(PannerNode::DistanceConeGainDirty); | |
| 276 } | |
| 277 | |
| 278 void PannerNode::setMaxDistance(double distance) | |
| 279 { | |
| 280 if (maxDistance() == distance) | |
| 281 return; | |
| 282 | |
| 283 // This synchronizes with process(). | |
| 284 MutexLocker processLocker(m_processLock); | |
| 285 m_distanceEffect.setMaxDistance(distance); | |
| 286 updatePannerDirty(PannerNode::DistanceConeGainDirty); | |
| 287 } | |
| 288 | |
| 289 void PannerNode::setRolloffFactor(double factor) | |
| 290 { | |
| 291 if (rolloffFactor() == factor) | |
| 292 return; | |
| 293 | |
| 294 // This synchronizes with process(). | |
| 295 MutexLocker processLocker(m_processLock); | |
| 296 m_distanceEffect.setRolloffFactor(factor); | |
| 297 updatePannerDirty(PannerNode::DistanceConeGainDirty); | |
| 298 } | |
| 299 | |
| 300 void PannerNode::setConeInnerAngle(double angle) | |
| 301 { | |
| 302 if (coneInnerAngle() == angle) | |
| 303 return; | |
| 304 | |
| 305 // This synchronizes with process(). | |
| 306 MutexLocker processLocker(m_processLock); | |
| 307 m_coneEffect.setInnerAngle(angle); | |
| 308 updatePannerDirty(PannerNode::DistanceConeGainDirty); | |
| 309 } | |
| 310 | |
| 311 void PannerNode::setConeOuterAngle(double angle) | |
| 312 { | |
| 313 if (coneOuterAngle() == angle) | |
| 314 return; | |
| 315 | |
| 316 // This synchronizes with process(). | |
| 317 MutexLocker processLocker(m_processLock); | |
| 318 m_coneEffect.setOuterAngle(angle); | |
| 319 updatePannerDirty(PannerNode::DistanceConeGainDirty); | |
| 320 } | |
| 321 | |
| 322 void PannerNode::setConeOuterGain(double angle) | |
| 323 { | |
| 324 if (coneOuterGain() == angle) | |
| 325 return; | |
| 326 | |
| 327 // This synchronizes with process(). | |
| 328 MutexLocker processLocker(m_processLock); | |
| 329 m_coneEffect.setOuterGain(angle); | |
| 330 updatePannerDirty(PannerNode::DistanceConeGainDirty); | |
| 331 } | |
| 332 | |
| 333 void PannerNode::setPosition(float x, float y, float z) | |
| 334 { | |
| 335 FloatPoint3D position = FloatPoint3D(x, y, z); | |
| 336 | |
| 337 if (m_position == position) | |
| 338 return; | |
| 339 | |
| 340 // This synchronizes with process(). | |
| 341 MutexLocker processLocker(m_processLock); | |
| 342 m_position = position; | |
| 343 updatePannerDirty(PannerNode::AzimuthElevationDirty | PannerNode::DistanceCo neGainDirty | PannerNode::DopplerRateDirty); | |
| 344 } | |
| 345 | |
| 346 void PannerNode::setOrientation(float x, float y, float z) | |
| 347 { | |
| 348 FloatPoint3D orientation = FloatPoint3D(x, y, z); | |
| 349 | |
| 350 if (m_orientation == orientation) | |
| 351 return; | |
| 352 | |
| 353 // This synchronizes with process(). | |
| 354 MutexLocker processLocker(m_processLock); | |
| 355 m_orientation = orientation; | |
| 356 updatePannerDirty(PannerNode::DistanceConeGainDirty); | |
| 357 } | |
| 358 | |
| 359 void PannerNode::setVelocity(float x, float y, float z) | |
| 360 { | |
| 361 FloatPoint3D velocity = FloatPoint3D(x, y, z); | |
| 362 | |
| 363 if (m_velocity == velocity) | |
| 364 return; | |
| 365 | |
| 366 // This synchronizes with process(). | |
| 367 MutexLocker processLocker(m_processLock); | |
| 368 m_velocity = velocity; | |
| 369 updatePannerDirty(PannerNode::DopplerRateDirty); | |
| 370 } | |
| 371 | |
| 315 void PannerNode::calculateAzimuthElevation(double* outAzimuth, double* outElevat ion) | 372 void PannerNode::calculateAzimuthElevation(double* outAzimuth, double* outElevat ion) |
| 316 { | 373 { |
| 317 double azimuth = 0.0; | 374 double azimuth = 0.0; |
| 318 | 375 |
| 319 // Calculate the source-listener vector | 376 // Calculate the source-listener vector |
| 320 FloatPoint3D listenerPosition = listener()->position(); | 377 FloatPoint3D listenerPosition = listener()->position(); |
| 321 FloatPoint3D sourceListener = m_position - listenerPosition; | 378 FloatPoint3D sourceListener = m_position - listenerPosition; |
| 322 | 379 |
| 323 if (sourceListener.isZero()) { | 380 if (sourceListener.isZero()) { |
| 324 // degenerate case if source and listener are at the same point | 381 // 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); | 485 double distanceGain = m_distanceEffect.gain(listenerDistance); |
| 429 double coneGain = m_coneEffect.gain(m_position, m_orientation, listenerPosit ion); | 486 double coneGain = m_coneEffect.gain(m_position, m_orientation, listenerPosit ion); |
| 430 | 487 |
| 431 return float(distanceGain * coneGain); | 488 return float(distanceGain * coneGain); |
| 432 } | 489 } |
| 433 | 490 |
| 434 void PannerNode::azimuthElevation(double* outAzimuth, double* outElevation) | 491 void PannerNode::azimuthElevation(double* outAzimuth, double* outElevation) |
| 435 { | 492 { |
| 436 ASSERT(context()->isAudioThread()); | 493 ASSERT(context()->isAudioThread()); |
| 437 | 494 |
| 438 if (isAzimuthElevationDirty()) | 495 if (isAzimuthElevationDirty()) { |
| 439 calculateAzimuthElevation(&m_cachedAzimuth, &m_cachedElevation); | 496 calculateAzimuthElevation(&m_cachedAzimuth, &m_cachedElevation); |
| 497 m_isAzimuthElevationDirty = false; | |
| 498 } | |
| 440 | 499 |
| 441 *outAzimuth = m_cachedAzimuth; | 500 *outAzimuth = m_cachedAzimuth; |
| 442 *outElevation = m_cachedElevation; | 501 *outElevation = m_cachedElevation; |
| 443 } | 502 } |
| 444 | 503 |
| 445 double PannerNode::dopplerRate() | 504 double PannerNode::dopplerRate() |
| 446 { | 505 { |
| 447 ASSERT(context()->isAudioThread()); | 506 ASSERT(context()->isAudioThread()); |
| 448 | 507 |
| 449 if (isDopplerRateDirty()) | 508 if (isDopplerRateDirty()) { |
| 450 m_cachedDopplerRate = calculateDopplerRate(); | 509 m_cachedDopplerRate = calculateDopplerRate(); |
| 510 m_isDopplerRateDirty = false; | |
| 511 } | |
| 451 | 512 |
| 452 return m_cachedDopplerRate; | 513 return m_cachedDopplerRate; |
| 453 } | 514 } |
| 454 | 515 |
| 455 float PannerNode::distanceConeGain() | 516 float PannerNode::distanceConeGain() |
| 456 { | 517 { |
| 457 ASSERT(context()->isAudioThread()); | 518 ASSERT(context()->isAudioThread()); |
| 458 | 519 |
| 459 if (isDistanceConeGainDirty()) | 520 if (isDistanceConeGainDirty()) { |
| 460 m_cachedDistanceConeGain = calculateDistanceConeGain(); | 521 m_cachedDistanceConeGain = calculateDistanceConeGain(); |
| 522 m_isDistanceConeGainDirty = false; | |
| 523 } | |
| 461 | 524 |
| 462 return m_cachedDistanceConeGain; | 525 return m_cachedDistanceConeGain; |
| 463 } | 526 } |
| 464 | 527 |
| 465 bool PannerNode::isAzimuthElevationDirty() | 528 void PannerNode::updatePannerDirty(unsigned dirty) |
| 466 { | 529 { |
| 467 // Do a quick test and return if possible. | 530 if (dirty & PannerNode::AzimuthElevationDirty) |
| 468 if (m_cachedPosition != m_position) | 531 m_isAzimuthElevationDirty = true; |
| 469 return true; | |
| 470 | 532 |
| 471 if (m_cachedListener->position() != listener()->position() | 533 if (dirty & PannerNode::DistanceConeGainDirty) |
| 472 || m_cachedListener->orientation() != listener()->orientation() | 534 m_isDistanceConeGainDirty = true; |
| 473 || m_cachedListener->upVector() != listener()->upVector()) | |
| 474 return true; | |
| 475 | 535 |
| 476 return false; | 536 if (dirty & PannerNode::DopplerRateDirty) |
| 477 } | 537 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 } | 538 } |
| 505 | 539 |
| 506 void PannerNode::notifyAudioSourcesConnectedToNode(AudioNode* node, HashMap<Audi oNode*, bool>& visitedNodes) | 540 void PannerNode::notifyAudioSourcesConnectedToNode(AudioNode* node, HashMap<Audi oNode*, bool>& visitedNodes) |
| 507 { | 541 { |
| 508 ASSERT(node); | 542 ASSERT(node); |
| 509 if (!node) | 543 if (!node) |
| 510 return; | 544 return; |
| 511 | 545 |
| 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. | 546 // 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) { | 547 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. | 562 // mark it as visited and recurse through the node looking for s ources. |
| 529 if (iterator == visitedNodes.end()) { | 563 if (iterator == visitedNodes.end()) { |
| 530 visitedNodes.set(connectedNode, true); | 564 visitedNodes.set(connectedNode, true); |
| 531 notifyAudioSourcesConnectedToNode(connectedNode, visitedNode s); // recurse | 565 notifyAudioSourcesConnectedToNode(connectedNode, visitedNode s); // recurse |
| 532 } | 566 } |
| 533 } | 567 } |
| 534 } | 568 } |
| 535 } | 569 } |
| 536 } | 570 } |
| 537 | 571 |
| 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 | 572 } // namespace WebCore |
| 560 | 573 |
| 561 #endif // ENABLE(WEB_AUDIO) | 574 #endif // ENABLE(WEB_AUDIO) |
| OLD | NEW |