OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "config.h" |
| 6 |
| 7 #if ENABLE(WEB_AUDIO) |
| 8 |
| 9 #include "modules/webaudio/StereoPannerNode.h" |
| 10 |
| 11 #include "bindings/core/v8/ExceptionMessages.h" |
| 12 #include "bindings/core/v8/ExceptionState.h" |
| 13 #include "core/dom/ExceptionCode.h" |
| 14 #include "core/dom/ExecutionContext.h" |
| 15 #include "modules/webaudio/AudioContext.h" |
| 16 #include "modules/webaudio/AudioNodeInput.h" |
| 17 #include "modules/webaudio/AudioNodeOutput.h" |
| 18 #include "platform/audio/StereoPanner.h" |
| 19 #include "wtf/MathExtras.h" |
| 20 |
| 21 namespace blink { |
| 22 |
| 23 StereoPannerNode::StereoPannerNode(AudioContext* context, float sampleRate) |
| 24 : AudioNode(context, sampleRate) |
| 25 , m_sampleAccuratePanValues(AudioNode::ProcessingSizeInFrames) |
| 26 { |
| 27 m_pan = AudioParam::create(context, 0); |
| 28 |
| 29 addInput(); |
| 30 addOutput(AudioNodeOutput::create(this, 2)); |
| 31 |
| 32 // The node-specific default mixing rules declare that StereoPannerNode |
| 33 // can handle mono to stereo and stereo to stereo conversion. |
| 34 m_channelCount = 2; |
| 35 m_channelCountMode = ClampedMax; |
| 36 m_channelInterpretation = AudioBus::Speakers; |
| 37 |
| 38 setNodeType(NodeTypeStereoPanner); |
| 39 |
| 40 initialize(); |
| 41 } |
| 42 |
| 43 StereoPannerNode::~StereoPannerNode() |
| 44 { |
| 45 ASSERT(!isInitialized()); |
| 46 } |
| 47 |
| 48 void StereoPannerNode::dispose() |
| 49 { |
| 50 uninitialize(); |
| 51 AudioNode::dispose(); |
| 52 } |
| 53 |
| 54 void StereoPannerNode::process(size_t framesToProcess) |
| 55 { |
| 56 AudioBus* outputBus = output(0)->bus(); |
| 57 |
| 58 if (!isInitialized() || !input(0)->isConnected() || !m_stereoPanner.get()) { |
| 59 outputBus->zero(); |
| 60 return; |
| 61 } |
| 62 |
| 63 AudioBus* inputBus = input(0)->bus(); |
| 64 if (!inputBus) { |
| 65 outputBus->zero(); |
| 66 return; |
| 67 } |
| 68 |
| 69 if (pan()->hasSampleAccurateValues()) { |
| 70 // Apply sample-accurate panning specified by AudioParam automation. |
| 71 ASSERT(framesToProcess <= m_sampleAccuratePanValues.size()); |
| 72 if (framesToProcess <= m_sampleAccuratePanValues.size()) { |
| 73 float* panValues = m_sampleAccuratePanValues.data(); |
| 74 pan()->calculateSampleAccurateValues(panValues, framesToProcess); |
| 75 m_stereoPanner->panWithSampleAccurateValues(inputBus, outputBus, pan
Values, framesToProcess); |
| 76 } |
| 77 } else { |
| 78 m_stereoPanner->panToTargetValue(inputBus, outputBus, pan()->value(), fr
amesToProcess); |
| 79 } |
| 80 } |
| 81 |
| 82 void StereoPannerNode::initialize() |
| 83 { |
| 84 if (isInitialized()) |
| 85 return; |
| 86 |
| 87 m_stereoPanner = Spatializer::create(Spatializer::PanningModelEqualPower, sa
mpleRate()); |
| 88 |
| 89 AudioNode::initialize(); |
| 90 } |
| 91 |
| 92 void StereoPannerNode::uninitialize() |
| 93 { |
| 94 if (!isInitialized()) |
| 95 return; |
| 96 |
| 97 m_stereoPanner.clear(); |
| 98 |
| 99 AudioNode::uninitialize(); |
| 100 } |
| 101 |
| 102 void StereoPannerNode::setChannelCount(unsigned long channelCount, ExceptionStat
e& exceptionState) |
| 103 { |
| 104 ASSERT(isMainThread()); |
| 105 AudioContext::AutoLocker locker(context()); |
| 106 |
| 107 // A PannerNode only supports 1 or 2 channels |
| 108 if (channelCount > 0 && channelCount <= 2) { |
| 109 if (m_channelCount != channelCount) { |
| 110 m_channelCount = channelCount; |
| 111 if (m_channelCountMode != Max) |
| 112 updateChannelsForInputs(); |
| 113 } |
| 114 } else { |
| 115 exceptionState.throwDOMException( |
| 116 NotSupportedError, |
| 117 ExceptionMessages::indexOutsideRange<unsigned long>( |
| 118 "channelCount", |
| 119 channelCount, |
| 120 1, |
| 121 ExceptionMessages::InclusiveBound, |
| 122 2, |
| 123 ExceptionMessages::InclusiveBound)); |
| 124 } |
| 125 } |
| 126 |
| 127 void StereoPannerNode::setChannelCountMode(const String& mode, ExceptionState& e
xceptionState) |
| 128 { |
| 129 ASSERT(isMainThread()); |
| 130 AudioContext::AutoLocker locker(context()); |
| 131 |
| 132 ChannelCountMode oldMode = m_channelCountMode; |
| 133 |
| 134 if (mode == "clamped-max") { |
| 135 m_newChannelCountMode = ClampedMax; |
| 136 } else if (mode == "explicit") { |
| 137 m_newChannelCountMode = Explicit; |
| 138 } else if (mode == "max") { |
| 139 // This is not supported for a StereoPannerNode, which can only handle |
| 140 // 1 or 2 channels. |
| 141 exceptionState.throwDOMException( |
| 142 NotSupportedError, |
| 143 ExceptionMessages::failedToSet( |
| 144 "channelCountMode", |
| 145 "StereoPannerNode", |
| 146 "'max' is not allowed")); |
| 147 m_newChannelCountMode = oldMode; |
| 148 } else { |
| 149 // Do nothing for other invalid values. |
| 150 m_newChannelCountMode = oldMode; |
| 151 } |
| 152 |
| 153 if (m_newChannelCountMode != oldMode) |
| 154 context()->addChangedChannelCountMode(this); |
| 155 } |
| 156 |
| 157 void StereoPannerNode::trace(Visitor* visitor) |
| 158 { |
| 159 visitor->trace(m_stereoPanner); |
| 160 visitor->trace(m_pan); |
| 161 AudioNode::trace(visitor); |
| 162 } |
| 163 |
| 164 } // namespace blink |
| 165 |
| 166 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |