Changeset 113769 in webkit
- Timestamp:
- Apr 10, 2012 2:28:57 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r113759 r113769 1 2012-04-10 Chris Rogers <crogers@google.com> 2 3 AudioParam must support connections from audio-rate signals 4 https://bugs.webkit.org/show_bug.cgi?id=83524 5 6 Reviewed by Eric Carlson. 7 8 * webaudio/audioparam-connect-audioratesignal-expected.txt: Added. 9 * webaudio/audioparam-connect-audioratesignal.html: Added. 10 * webaudio/resources/audio-testing.js: 11 (createLinearRampBuffer): 12 (createConstantBuffer): 13 1 14 2012-04-10 Abhishek Arya <inferno@chromium.org> 2 15 -
trunk/LayoutTests/webaudio/resources/audio-testing.js
r109518 r113769 116 116 } 117 117 118 // Create a buffer of the given length with a linear ramp having values 0 <= x < 1. 119 function createLinearRampBuffer(context, sampleFrameLength) { 120 var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate); 121 var n = audioBuffer.length; 122 var dataL = audioBuffer.getChannelData(0); 123 124 for (var i = 0; i < n; ++i) 125 dataL[i] = i / n; 126 127 return audioBuffer; 128 } 129 130 // Create a buffer of the given length having a constant value. 131 function createConstantBuffer(context, sampleFrameLength, constantValue) { 132 var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate); 133 var n = audioBuffer.length; 134 var dataL = audioBuffer.getChannelData(0); 135 136 for (var i = 0; i < n; ++i) 137 dataL[i] = constantValue; 138 139 return audioBuffer; 140 } 141 118 142 // Convert time (in seconds) to sample frames. 119 143 function timeToSampleFrame(time, sampleRate) { -
trunk/Source/WebCore/ChangeLog
r113764 r113769 1 2012-04-10 Chris Rogers <crogers@google.com> 2 3 AudioParam must support connections from audio-rate signals 4 https://bugs.webkit.org/show_bug.cgi?id=83524 5 6 Reviewed by Eric Carlson. 7 8 In the Web Audio API, it's possible to connect one AudioNode to another AudioNode. 9 Similary we should allow an AudioNode to connect to an AudioParam, thus controlling 10 a parameter with an audio-rate signal. This is important in many audio processing 11 applications. 12 13 Test: webaudio/audioparam-connect-audioratesignal.html 14 15 Simple method name change of AudioParam::hasTimelineValues() to AudioParam::hasSampleAccurateValues(). 16 * Modules/webaudio/AudioGainNode.cpp: 17 (WebCore::AudioGainNode::process): 18 19 * Modules/webaudio/AudioNode.cpp: 20 (WebCore::AudioNode::connect): Add connect() method from AudioNode -> AudioParam. 21 (WebCore): 22 (WebCore::AudioNode::disconnect): 23 (WebCore::AudioNode::finishDeref): 24 Use AudioNodeOutput::disconnectAll() instead of AudioNodeOutput::disconnectAllInputs(). 25 * Modules/webaudio/AudioNode.h: Add connect() method from AudioNode -> AudioParam. 26 (WebCore): 27 (AudioNode): 28 * Modules/webaudio/AudioNode.idl: Add connect() method from AudioNode -> AudioParam. 29 30 Implement support for an AudioNodeOutput to fanout to multiple AudioParams. 31 * Modules/webaudio/AudioNodeOutput.cpp: 32 (WebCore::AudioNodeOutput::AudioNodeOutput): 33 (WebCore::AudioNodeOutput::updateRenderingState): Update rendering state related to AudioParams. 34 (WebCore::AudioNodeOutput::pull): pull() must now take into account fanout to AudioParams for in-place processing. 35 (WebCore::AudioNodeOutput::fanOutCount): 36 (WebCore): 37 (WebCore::AudioNodeOutput::paramFanOutCount): New method keeping track of number of connections to AudioParams. 38 (WebCore::AudioNodeOutput::renderingParamFanOutCount): New method keeping track of number of connections to AudioParams for rendering. 39 (WebCore::AudioNodeOutput::addParam): Add a connection to an AudioParam. 40 (WebCore::AudioNodeOutput::removeParam): Remove a connection to an AudioParam. 41 (WebCore::AudioNodeOutput::disconnectAllParams): Remove all connections to AudioParams. 42 (WebCore::AudioNodeOutput::disconnectAll): New method to disconnect all AudioNodeInputs and AudioParams. 43 * Modules/webaudio/AudioNodeOutput.h: 44 (AudioNodeOutput): 45 46 Allow an AudioParam to accept a connection from an AudioNodeOutput, thus being controlled 47 by an audio-rate signal. 48 * Modules/webaudio/AudioParam.cpp: 49 (WebCore::AudioParam::calculateSampleAccurateValues): Calculates sample-accurate values from timeline or an AudioNode. 50 (WebCore): 51 (WebCore::AudioParam::calculateAudioRateSignalValues): Calculates sample-accurate values from an AudioNode. 52 (WebCore::AudioParam::calculateTimelineValues): Calculates sample-accurate values scheduled on the timeline. 53 (WebCore::AudioParam::connect): Connect from an AudioNodeOutput for control from an audio-rate signal. 54 (WebCore::AudioParam::disconnect): Disconnect from an AudioNodeOutput. 55 * Modules/webaudio/AudioParam.h: 56 (WebCore): 57 (WebCore::AudioParam::AudioParam): 58 (WebCore::AudioParam::hasSampleAccurateValues): Change name from hasTimelineValues() and return true 59 either if we have timeline values or if we've been connected from an AudioNode. 60 (AudioParam): 61 62 Simple method name change of AudioParam::hasTimelineValues() to AudioParam::hasSampleAccurateValues(). 63 * Modules/webaudio/Oscillator.cpp: 64 (WebCore::Oscillator::calculateSampleAccuratePhaseIncrements): 65 (WebCore::Oscillator::process): 66 1 67 2012-04-10 Patrick Gansterer <paroga@webkit.org> 2 68 -
trunk/Source/WebCore/Modules/webaudio/AudioGainNode.cpp
r111474 r113769 65 65 AudioBus* inputBus = input(0)->bus(); 66 66 67 if (gain()->has TimelineValues()) {67 if (gain()->hasSampleAccurateValues()) { 68 68 // Apply sample-accurate gain scaling for precise envelopes, grain windows, etc. 69 69 ASSERT(framesToProcess <= m_sampleAccurateGainValues.size()); -
trunk/Source/WebCore/Modules/webaudio/AudioNode.cpp
r113728 r113769 32 32 #include "AudioNodeInput.h" 33 33 #include "AudioNodeOutput.h" 34 #include "AudioParam.h" 34 35 #include "ExceptionCode.h" 35 36 #include <wtf/Atomics.h> … … 150 151 } 151 152 153 void AudioNode::connect(AudioParam* param, unsigned outputIndex, ExceptionCode& ec) 154 { 155 ASSERT(isMainThread()); 156 AudioContext::AutoLocker locker(context()); 157 158 if (!param) { 159 ec = SYNTAX_ERR; 160 return; 161 } 162 163 if (outputIndex >= numberOfOutputs()) { 164 ec = INDEX_SIZE_ERR; 165 return; 166 } 167 168 if (context() != param->context()) { 169 ec = SYNTAX_ERR; 170 return; 171 } 172 173 AudioNodeOutput* output = this->output(outputIndex); 174 param->connect(output); 175 } 176 152 177 void AudioNode::disconnect(unsigned outputIndex, ExceptionCode& ec) 153 178 { … … 162 187 163 188 AudioNodeOutput* output = this->output(outputIndex); 164 output->disconnectAll Inputs();189 output->disconnectAll(); 165 190 } 166 191 … … 338 363 // All references are gone - we need to go away. 339 364 for (unsigned i = 0; i < m_outputs.size(); ++i) 340 output(i)->disconnectAll Inputs(); // this will deref() nodes we're connected to...365 output(i)->disconnectAll(); // This will deref() nodes we're connected to. 341 366 342 367 // Mark for deletion at end of each render quantum or when context shuts down. -
trunk/Source/WebCore/Modules/webaudio/AudioNode.h
r113728 r113769 38 38 class AudioNodeInput; 39 39 class AudioNodeOutput; 40 class AudioParam; 40 41 41 42 typedef int ExceptionCode; … … 117 118 // Called from main thread by corresponding JavaScript methods. 118 119 void connect(AudioNode*, unsigned outputIndex, unsigned inputIndex, ExceptionCode&); 120 void connect(AudioParam*, unsigned outputIndex, ExceptionCode&); 119 121 void disconnect(unsigned outputIndex, ExceptionCode&); 120 122 -
trunk/Source/WebCore/Modules/webaudio/AudioNode.idl
r111474 r113769 34 34 raises(DOMException); 35 35 36 void connect(in AudioParam destination, in [Optional=DefaultIsUndefined] unsigned long output) 37 raises(DOMException); 38 36 39 void disconnect(in [Optional=DefaultIsUndefined] unsigned long output) 37 40 raises(DOMException); -
trunk/Source/WebCore/Modules/webaudio/AudioNodeOutput.cpp
r111474 r113769 32 32 #include "AudioContext.h" 33 33 #include "AudioNodeInput.h" 34 #include "AudioParam.h" 34 35 #include <wtf/Threading.h> 35 36 … … 43 44 , m_isEnabled(true) 44 45 , m_renderingFanOutCount(0) 46 , m_renderingParamFanOutCount(0) 45 47 { 46 48 ASSERT(numberOfChannels <= AudioContext::maxNumberOfChannels()); … … 81 83 updateNumberOfChannels(); 82 84 m_renderingFanOutCount = fanOutCount(); 85 m_renderingParamFanOutCount = paramFanOutCount(); 83 86 } 84 87 … … 111 114 { 112 115 ASSERT(context()->isAudioThread()); 113 ASSERT(m_renderingFanOutCount > 0 );116 ASSERT(m_renderingFanOutCount > 0 || m_renderingParamFanOutCount > 0); 114 117 115 118 // Causes our AudioNode to process if it hasn't already for this render quantum. … … 119 122 // cause our node to process() only the first time, caching the output in m_internalOutputBus for subsequent calls. 120 123 121 bool isInPlace = inPlaceBus && inPlaceBus->numberOfChannels() == numberOfChannels() && m_renderingFanOutCount== 1;124 bool isInPlace = inPlaceBus && inPlaceBus->numberOfChannels() == numberOfChannels() && (m_renderingFanOutCount + m_renderingParamFanOutCount) == 1; 122 125 123 126 // Setup the actual destination bus for processing when our node's process() method gets called in processIfNecessary() below. … … 135 138 } 136 139 140 unsigned AudioNodeOutput::fanOutCount() 141 { 142 ASSERT(context()->isGraphOwner()); 143 return m_inputs.size(); 144 } 145 146 unsigned AudioNodeOutput::paramFanOutCount() 147 { 148 ASSERT(context()->isGraphOwner()); 149 return m_params.size(); 150 } 151 137 152 unsigned AudioNodeOutput::renderingFanOutCount() const 138 153 { … … 140 155 } 141 156 142 unsigned AudioNodeOutput::fanOutCount() 143 { 144 ASSERT(context()->isGraphOwner()); 145 return m_inputs.size(); 157 unsigned AudioNodeOutput::renderingParamFanOutCount() const 158 { 159 return m_renderingParamFanOutCount; 146 160 } 147 161 … … 177 191 input->disconnect(this); 178 192 } 193 } 194 195 void AudioNodeOutput::addParam(AudioParam* param) 196 { 197 ASSERT(context()->isGraphOwner()); 198 199 ASSERT(param); 200 if (!param) 201 return; 202 203 m_params.add(param); 204 } 205 206 void AudioNodeOutput::removeParam(AudioParam* param) 207 { 208 ASSERT(context()->isGraphOwner()); 209 210 ASSERT(param); 211 if (!param) 212 return; 213 214 m_params.remove(param); 215 } 216 217 void AudioNodeOutput::disconnectAllParams() 218 { 219 ASSERT(context()->isGraphOwner()); 220 221 for (ParamsIterator i = m_params.begin(); i != m_params.end(); ++i) { 222 AudioParam* param = *i; 223 param->disconnect(this); 224 } 225 226 m_params.clear(); 227 } 228 229 void AudioNodeOutput::disconnectAll() 230 { 231 disconnectAllInputs(); 232 disconnectAllParams(); 179 233 } 180 234 -
trunk/Source/WebCore/Modules/webaudio/AudioNodeOutput.h
r111474 r113769 58 58 AudioBus* bus() const; 59 59 60 // fanOutCount() is the number of AudioNodeInputs that we're connected to.61 // This function should not be called in audio thread rendering code, instead renderingFanOutCount() should be used.62 // It must be called with the context's graph lock.63 unsigned fanOutCount();64 65 60 // renderingFanOutCount() is the number of AudioNodeInputs that we're connected to during rendering. 66 61 // Unlike fanOutCount() it will not change during the course of a render quantum. 67 62 unsigned renderingFanOutCount() const; 68 63 69 // It must be called with the context's graph lock. 70 void disconnectAllInputs(); 64 // renderingParamFanOutCount() is the number of AudioParams that we're connected to during rendering. 65 // Unlike paramFanOutCount() it will not change during the course of a render quantum. 66 unsigned renderingParamFanOutCount() const; 67 68 // Must be called with the context's graph lock. 69 void disconnectAll(); 71 70 72 71 void setNumberOfChannels(unsigned); … … 88 87 89 88 friend class AudioNodeInput; 89 friend class AudioParam; 90 90 91 91 // These are called from AudioNodeInput. … … 93 93 void addInput(AudioNodeInput*); 94 94 void removeInput(AudioNodeInput*); 95 void addParam(AudioParam*); 96 void removeParam(AudioParam*); 97 98 // fanOutCount() is the number of AudioNodeInputs that we're connected to. 99 // This method should not be called in audio thread rendering code, instead renderingFanOutCount() should be used. 100 // It must be called with the context's graph lock. 101 unsigned fanOutCount(); 102 103 // Similar to fanOutCount(), paramFanOutCount() is the number of AudioParams that we're connected to. 104 // This method should not be called in audio thread rendering code, instead renderingParamFanOutCount() should be used. 105 // It must be called with the context's graph lock. 106 unsigned paramFanOutCount(); 107 108 // Must be called with the context's graph lock. 109 void disconnectAllInputs(); 110 void disconnectAllParams(); 95 111 96 112 // updateInternalBus() updates m_internalBus appropriately for the number of channels. … … 121 137 typedef HashSet<AudioNodeInput*>::iterator InputsIterator; 122 138 bool m_isEnabled; 123 124 // For the purposes of rendering, keeps track of the number of inputs we're connected to.125 // Th isvalue should only be changed at the very start or end of the rendering quantum.139 140 // For the purposes of rendering, keeps track of the number of inputs and AudioParams we're connected to. 141 // These value should only be changed at the very start or end of the rendering quantum. 126 142 unsigned m_renderingFanOutCount; 143 unsigned m_renderingParamFanOutCount; 144 145 HashSet<AudioParam*> m_params; 146 typedef HashSet<AudioParam*>::iterator ParamsIterator; 127 147 }; 128 148 -
trunk/Source/WebCore/Modules/webaudio/AudioParam.cpp
r111474 r113769 31 31 32 32 #include "AudioNode.h" 33 #include "AudioNodeOutput.h" 33 34 #include "AudioUtilities.h" 34 35 #include "FloatConversion.h" … … 96 97 void AudioParam::calculateSampleAccurateValues(float* values, unsigned numberOfValues) 97 98 { 98 bool isSafe = context() && context()->isAudioThread() && values ;99 bool isSafe = context() && context()->isAudioThread() && values && numberOfValues; 99 100 ASSERT(isSafe); 100 101 if (!isSafe) 101 102 return; 102 103 104 if (m_audioRateSignal) 105 calculateAudioRateSignalValues(values, numberOfValues); 106 else 107 calculateTimelineValues(values, numberOfValues); 108 } 109 110 void AudioParam::calculateAudioRateSignalValues(float* values, unsigned numberOfValues) 111 { 112 // FIXME: support fan-in (multiple audio connections to this parameter with unity-gain summing). 113 // https://bugs.webkit.org/show_bug.cgi?id=83610 114 ASSERT(m_audioRateSignal); 115 116 AudioBus* bus = m_audioRateSignal->pull(0, numberOfValues); 117 bool isBusGood = bus && bus->numberOfChannels() && bus->length() >= numberOfValues; 118 ASSERT(isBusGood); 119 if (!isBusGood) 120 return; 121 122 if (bus->numberOfChannels() == 1) { 123 // The normal case is to deal with a mono audio-rate signal. 124 memcpy(values, bus->channel(0)->data(), sizeof(float) * numberOfValues); 125 } else { 126 // Do a standard mixdown to one channel if necessary. 127 AudioBus wrapperBus(1, numberOfValues, false); 128 wrapperBus.setChannelMemory(0, values, numberOfValues); 129 wrapperBus.copyFrom(*bus); // Mixdown. 130 } 131 m_value = values[0]; // Update to first value. 132 } 133 134 void AudioParam::calculateTimelineValues(float* values, unsigned numberOfValues) 135 { 103 136 // Calculate values for this render quantum. 104 137 // Normally numberOfValues will equal AudioNode::ProcessingSizeInFrames (the render quantum size). … … 112 145 } 113 146 147 void AudioParam::connect(AudioNodeOutput* audioRateSignal) 148 { 149 ASSERT(context()->isGraphOwner()); 150 ASSERT(audioRateSignal); 151 if (!audioRateSignal) 152 return; 153 154 if (m_audioRateSignal && m_audioRateSignal != audioRateSignal) { 155 // Because we don't currently support fan-in we must explicitly disconnect from an old output. 156 m_audioRateSignal->removeParam(this); 157 } 158 159 audioRateSignal->addParam(this); 160 m_audioRateSignal = audioRateSignal; 161 } 162 163 void AudioParam::disconnect(AudioNodeOutput* audioRateSignal) 164 { 165 ASSERT(context()->isGraphOwner()); 166 ASSERT(audioRateSignal); 167 if (!audioRateSignal) 168 return; 169 170 // FIXME: support fan-in (multiple audio connections to this parameter with unity-gain summing). 171 // https://bugs.webkit.org/show_bug.cgi?id=83610 172 if (m_audioRateSignal == audioRateSignal) 173 m_audioRateSignal = 0; 174 } 175 114 176 } // namespace WebCore 115 177 -
trunk/Source/WebCore/Modules/webaudio/AudioParam.h
r111474 r113769 40 40 namespace WebCore { 41 41 42 class AudioNodeOutput; 43 42 44 class AudioParam : public RefCounted<AudioParam> { 43 45 public: … … 59 61 , m_smoothedValue(defaultValue) 60 62 , m_smoothingConstant(DefaultSmoothingConstant) 63 , m_audioRateSignal(0) 61 64 { 62 65 } … … 97 100 void cancelScheduledValues(float startTime) { m_timeline.cancelScheduledValues(startTime); } 98 101 99 bool has TimelineValues() { return m_timeline.hasValues(); }102 bool hasSampleAccurateValues() { return m_timeline.hasValues() || m_audioRateSignal; } 100 103 101 104 // Calculates numberOfValues parameter values starting at the context's current time. … … 103 106 void calculateSampleAccurateValues(float* values, unsigned numberOfValues); 104 107 108 // Connect an audio-rate signal to control this parameter. 109 void connect(AudioNodeOutput*); 110 void disconnect(AudioNodeOutput*); 111 105 112 private: 113 void calculateAudioRateSignalValues(float* values, unsigned numberOfValues); 114 void calculateTimelineValues(float* values, unsigned numberOfValues); 115 106 116 RefPtr<AudioContext> m_context; 107 117 String m_name; … … 117 127 118 128 AudioParamTimeline m_timeline; 129 130 // An audio-rate signal directly providing parameter values. 131 // FIXME: support fan-in (multiple audio connections to this parameter with unity-gain summing). 132 // https://bugs.webkit.org/show_bug.cgi?id=83610 133 AudioNodeOutput* m_audioRateSignal; 119 134 }; 120 135 -
trunk/Source/WebCore/Modules/webaudio/Oscillator.cpp
r113245 r113769 113 113 return false; 114 114 115 bool has TimelineValues = false;115 bool hasSampleAccurateValues = false; 116 116 bool hasFrequencyChanges = false; 117 117 float* phaseIncrements = m_phaseIncrements.data(); … … 119 119 float finalScale = m_waveTable->rateScale(); 120 120 121 if (m_frequency->has TimelineValues()) {122 has TimelineValues = true;121 if (m_frequency->hasSampleAccurateValues()) { 122 hasSampleAccurateValues = true; 123 123 hasFrequencyChanges = true; 124 124 … … 133 133 } 134 134 135 if (m_detune->has TimelineValues()) {136 has TimelineValues = true;135 if (m_detune->hasSampleAccurateValues()) { 136 hasSampleAccurateValues = true; 137 137 138 138 // Get the sample-accurate detune values. … … 158 158 } 159 159 160 if (has TimelineValues) {160 if (hasSampleAccurateValues) { 161 161 // Convert from frequency to wavetable increment. 162 162 vsmul(phaseIncrements, 1, &finalScale, phaseIncrements, 1, framesToProcess); 163 163 } 164 164 165 return has TimelineValues;165 return hasSampleAccurateValues; 166 166 } 167 167 … … 169 169 { 170 170 AudioBus* outputBus = output(0)->bus(); 171 172 outputBus->zero();173 171 174 172 if (!isInitialized() || !outputBus->numberOfChannels()) { … … 207 205 float rateScale = m_waveTable->rateScale(); 208 206 float invRateScale = 1 / rateScale; 209 bool has TimelineValues = calculateSampleAccuratePhaseIncrements(framesToProcess);207 bool hasSampleAccurateValues = calculateSampleAccuratePhaseIncrements(framesToProcess); 210 208 211 209 float frequency = 0; … … 214 212 float tableInterpolationFactor; 215 213 216 if (!has TimelineValues) {214 if (!hasSampleAccurateValues) { 217 215 frequency = m_frequency->smoothedValue(); 218 216 float detune = m_detune->smoothedValue(); … … 235 233 readIndex2 = readIndex2 & readIndexMask; 236 234 237 if (has TimelineValues) {235 if (hasSampleAccurateValues) { 238 236 incr = *phaseIncrements++; 239 237
Note: See TracChangeset
for help on using the changeset viewer.