Changeset 116201 in webkit
- Timestamp:
- May 4, 2012 6:28:38 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r116197 r116201 1 2012-05-04 Chris Rogers <crogers@google.com> 2 3 Oscillator must implement noteOn() and noteOff() 4 https://bugs.webkit.org/show_bug.cgi?id=85236 5 6 Reviewed by Kenneth Russell. 7 8 * webaudio/oscillator-scheduling-expected.wav: Added. 9 * webaudio/resources/oscillator-testing.js: 10 (generateExponentialOscillatorSweep): 11 1 12 2012-05-04 David Barr <davidbarr@chromium.org> 2 13 -
trunk/LayoutTests/webaudio/resources/oscillator-testing.js
r115140 r116201 48 48 gainNode.connect(context.destination); 49 49 50 osc.noteOn(0); 51 50 52 var nyquist = 0.5 * sampleRate; 51 53 osc.frequency.setValueAtTime(10, 0); -
trunk/Source/WebCore/ChangeLog
r116198 r116201 1 2012-05-04 Chris Rogers <crogers@google.com> 2 3 Oscillator must implement noteOn() and noteOff() 4 https://bugs.webkit.org/show_bug.cgi?id=85236 5 6 Reviewed by Kenneth Russell. 7 8 Test: webaudio/oscillator-scheduling.html 9 to be landed separately to get proper platform baselines 10 11 * Modules/webaudio/AudioBufferSourceNode.cpp: 12 (WebCore::AudioBufferSourceNode::process): 13 Simplify/remove zeroing-out silence at end of buffer, since it's now handled in the base-class AudioScheduledSourceNode::updateSchedulingInfo(). 14 15 * Modules/webaudio/AudioContext.cpp: 16 (WebCore::AudioContext::createBufferSource): 17 Improve comment about ownership and dynamic-lifetime of AudioBufferSourceNode. 18 19 (WebCore::AudioContext::createOscillator): 20 AudioContext keeps a reference to the Oscillator and that reference is released in AudioScheduledSourceNode, 21 when it has finished playing. 22 23 * Modules/webaudio/AudioScheduledSourceNode.h: 24 * Modules/webaudio/AudioScheduledSourceNode.cpp: 25 (WebCore::AudioScheduledSourceNode::updateSchedulingInfo): 26 updateSchedulingInfo() is now responsible for zeroing out the very start (before a note starts) 27 and the very end (after note ends) of the output AudioBus. We've also simplified the number 28 of arguments passed to this method, because of this. It now handles playbackState transition to FINISHED_STATE. 29 30 * Modules/webaudio/Oscillator.cpp: 31 (WebCore::Oscillator::Oscillator): 32 (WebCore::Oscillator::calculateSampleAccuratePhaseIncrements): 33 The frequency value needs to snap immediately to its correct value the very first time. 34 This bug needs to be fixed here so that the Oscillator layout scheduling test works correctly. 35 36 (WebCore::Oscillator::process): 37 Since Oscillator in now changing to be a AudioScheduledSourceNode, we need to call AudioScheduledSourceNode::updateSchedulingInfo() 38 to handle playbackState for us. 39 40 (WebCore::Oscillator::propagatesSilence): 41 Add scheduling logic for propagatesSilence(). 42 43 (Oscillator): 44 * Modules/webaudio/Oscillator.idl: 45 Add noteOn(), noteOff() methods and playbackState according to specification. 46 1 47 2012-05-04 Andy Estes <aestes@apple.com> 2 48 -
trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp
r115485 r116201 102 102 } 103 103 104 size_t quantumStartFrame;105 size_t quantumEndFrame;106 size_t startFrame;107 size_t endFrame;108 104 size_t quantumFrameOffset; 109 105 size_t bufferFramesToProcess; 110 106 111 107 updateSchedulingInfo(framesToProcess, 112 quantumStartFrame, 113 quantumEndFrame, 114 startFrame, 115 endFrame, 108 outputBus, 116 109 quantumFrameOffset, 117 110 bufferFramesToProcess); … … 131 124 float totalGain = gain()->value() * m_buffer->gain(); 132 125 outputBus->copyWithGainFrom(*outputBus, &m_lastGain, totalGain); 133 134 // If the end time is somewhere in the middle of this time quantum, then simply zero out the135 // frames starting at the end time.136 if (m_endTime != UnknownTime && endFrame >= quantumStartFrame && endFrame < quantumEndFrame) {137 size_t zeroStartFrame = endFrame - quantumStartFrame;138 size_t framesToZero = framesToProcess - zeroStartFrame;139 140 bool isSafe = zeroStartFrame < framesToProcess && framesToZero <= framesToProcess && zeroStartFrame + framesToZero <= framesToProcess;141 ASSERT(isSafe);142 143 if (isSafe) {144 for (unsigned i = 0; i < outputBus->numberOfChannels(); ++i)145 memset(m_destinationChannels[i] + zeroStartFrame, 0, sizeof(float) * framesToZero);146 }147 148 m_virtualReadIndex = 0;149 150 finish();151 }152 153 126 outputBus->clearSilentFlag(); 154 127 } else { -
trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp
r115787 r116201 351 351 RefPtr<AudioBufferSourceNode> node = AudioBufferSourceNode::create(this, m_destinationNode->sampleRate()); 352 352 353 refNode(node.get()); // context keeps reference until source has finished playing 353 // Because this is an AudioScheduledSourceNode, the context keeps a reference until it has finished playing. 354 // When this happens, AudioScheduledSourceNode::finish() calls AudioContext::notifyNodeFinishedProcessing(). 355 refNode(node.get()); 356 354 357 return node; 355 358 } … … 517 520 ASSERT(isMainThread()); 518 521 lazyInitialize(); 519 return Oscillator::create(this, m_destinationNode->sampleRate()); 522 523 RefPtr<Oscillator> node = Oscillator::create(this, m_destinationNode->sampleRate()); 524 525 // Because this is an AudioScheduledSourceNode, the context keeps a reference until it has finished playing. 526 // When this happens, AudioScheduledSourceNode::finish() calls AudioContext::notifyNodeFinishedProcessing(). 527 refNode(node.get()); 528 529 return node; 520 530 } 521 531 -
trunk/Source/WebCore/Modules/webaudio/AudioScheduledSourceNode.cpp
r115485 r116201 49 49 50 50 void AudioScheduledSourceNode::updateSchedulingInfo(size_t quantumFrameSize, 51 size_t& quantumStartFrame, 52 size_t& quantumEndFrame, 53 size_t& startFrame, 54 size_t& endFrame, 51 AudioBus* outputBus, 55 52 size_t& quantumFrameOffset, 56 53 size_t& nonSilentFramesToProcess) 57 54 { 55 ASSERT(outputBus); 56 if (!outputBus) 57 return; 58 58 59 ASSERT(quantumFrameSize == AudioNode::ProcessingSizeInFrames); 59 60 if (quantumFrameSize != AudioNode::ProcessingSizeInFrames) 60 61 return; 61 62 // Check if it's time to start playing. 62 63 63 double sampleRate = this->sampleRate(); 64 quantumStartFrame = context()->currentSampleFrame(); 65 quantumEndFrame = quantumStartFrame + quantumFrameSize; 66 startFrame = AudioUtilities::timeToSampleFrame(m_startTime, sampleRate); 67 endFrame = m_endTime == UnknownTime ? 0 : AudioUtilities::timeToSampleFrame(m_endTime, sampleRate); 64 65 // quantumStartFrame : Start frame of the current time quantum. 66 // quantumEndFrame : End frame of the current time quantum. 67 // startFrame : Start frame for this source. 68 // endFrame : End frame for this source. 69 size_t quantumStartFrame = context()->currentSampleFrame(); 70 size_t quantumEndFrame = quantumStartFrame + quantumFrameSize; 71 size_t startFrame = AudioUtilities::timeToSampleFrame(m_startTime, sampleRate); 72 size_t endFrame = m_endTime == UnknownTime ? 0 : AudioUtilities::timeToSampleFrame(m_endTime, sampleRate); 68 73 69 74 // If we know the end time and it's already passed, then don't bother doing any more rendering this cycle. … … 73 78 if (m_playbackState == UNSCHEDULED_STATE || m_playbackState == FINISHED_STATE || startFrame >= quantumEndFrame) { 74 79 // Output silence. 80 outputBus->zero(); 75 81 nonSilentFramesToProcess = 0; 76 82 return; 77 83 } 78 84 85 // Check if it's time to start playing. 79 86 if (m_playbackState == SCHEDULED_STATE) { 80 87 // Increment the active source count only if we're transitioning from SCHEDULED_STATE to PLAYING_STATE. … … 86 93 quantumFrameOffset = min(quantumFrameOffset, quantumFrameSize); // clamp to valid range 87 94 nonSilentFramesToProcess = quantumFrameSize - quantumFrameOffset; 95 96 if (!nonSilentFramesToProcess) { 97 // Output silence. 98 outputBus->zero(); 99 return; 100 } 101 102 // Handle silence before we start playing. 103 // Zero any initial frames representing silence leading up to a rendering start time in the middle of the quantum. 104 if (quantumFrameOffset) { 105 for (unsigned i = 0; i < outputBus->numberOfChannels(); ++i) 106 memset(outputBus->channel(i)->mutableData(), 0, sizeof(float) * quantumFrameOffset); 107 } 108 109 // Handle silence after we're done playing. 110 // If the end time is somewhere in the middle of this time quantum, then zero out the 111 // frames from the end time to the very end of the quantum. 112 if (m_endTime != UnknownTime && endFrame >= quantumStartFrame && endFrame < quantumEndFrame) { 113 size_t zeroStartFrame = endFrame - quantumStartFrame; 114 size_t framesToZero = quantumFrameSize - zeroStartFrame; 115 116 bool isSafe = zeroStartFrame < quantumFrameSize && framesToZero <= quantumFrameSize && zeroStartFrame + framesToZero <= quantumFrameSize; 117 ASSERT(isSafe); 118 119 if (isSafe) { 120 nonSilentFramesToProcess -= framesToZero; 121 for (unsigned i = 0; i < outputBus->numberOfChannels(); ++i) 122 memset(outputBus->channel(i)->mutableData() + zeroStartFrame, 0, sizeof(float) * framesToZero); 123 } 124 125 finish(); 126 } 88 127 89 128 return; -
trunk/Source/WebCore/Modules/webaudio/AudioScheduledSourceNode.h
r115485 r116201 34 34 namespace WebCore { 35 35 36 class AudioBus; 37 36 38 class AudioScheduledSourceNode : public AudioSourceNode { 37 39 public: … … 65 67 protected: 66 68 // Get frame information for the current time quantum. 69 // We handle the transition into PLAYING_STATE and FINISHED_STATE here, 70 // zeroing out portions of the outputBus which are outside the range of startFrame and endFrame. 71 // 67 72 // Each frame time is relative to the context's currentSampleFrame(). 68 // quantumStartFrame : Start frame of the current time quantum.69 // quantumEndFrame : End frame of the current time quantum.70 // startFrame : Start frame for this source.71 // endFrame : End frame for this source.72 73 // quantumFrameOffset : Offset frame in this time quantum to start rendering. 73 74 // nonSilentFramesToProcess : Number of frames rendering non-silence (will be <= quantumFrameSize). 74 75 void updateSchedulingInfo(size_t quantumFrameSize, 75 size_t& quantumStartFrame, 76 size_t& quantumEndFrame, 77 size_t& startFrame, 78 size_t& endFrame, 76 AudioBus* outputBus, 79 77 size_t& quantumFrameOffset, 80 78 size_t& nonSilentFramesToProcess); -
trunk/Source/WebCore/Modules/webaudio/Oscillator.cpp
r114988 r116201 49 49 50 50 Oscillator::Oscillator(AudioContext* context, float sampleRate) 51 : AudioS ourceNode(context, sampleRate)51 : AudioScheduledSourceNode(context, sampleRate) 52 52 , m_type(SINE) 53 , m_firstRender(true) 53 54 , m_virtualReadIndex(0) 54 55 , m_phaseIncrements(AudioNode::ProcessingSizeInFrames) … … 112 113 if (!isGood) 113 114 return false; 115 116 if (m_firstRender) { 117 m_firstRender = false; 118 m_frequency->resetSmoothedValue(); 119 m_detune->resetSmoothedValue(); 120 } 114 121 115 122 bool hasSampleAccurateValues = false; … … 193 200 } 194 201 202 size_t quantumFrameOffset; 203 size_t nonSilentFramesToProcess; 204 205 updateSchedulingInfo(framesToProcess, 206 outputBus, 207 quantumFrameOffset, 208 nonSilentFramesToProcess); 209 210 if (!nonSilentFramesToProcess) { 211 outputBus->zero(); 212 return; 213 } 214 195 215 unsigned waveTableSize = m_waveTable->waveTableSize(); 196 216 double invWaveTableSize = 1.0 / waveTableSize; … … 198 218 float* destP = outputBus->channel(0)->mutableData(); 199 219 200 int n = framesToProcess;220 ASSERT(quantumFrameOffset <= framesToProcess); 201 221 202 222 // We keep virtualReadIndex double-precision since we're accumulating values. … … 225 245 unsigned readIndexMask = waveTableSize - 1; 226 246 247 // Start rendering at the correct offset. 248 destP += quantumFrameOffset; 249 int n = nonSilentFramesToProcess; 250 227 251 while (n--) { 228 252 unsigned readIndex = static_cast<unsigned>(virtualReadIndex); … … 261 285 262 286 m_virtualReadIndex = virtualReadIndex; 287 288 outputBus->clearSilentFlag(); 263 289 } 264 290 … … 278 304 } 279 305 306 bool Oscillator::propagatesSilence() const 307 { 308 return !isPlayingOrScheduled() || hasFinished() || !m_waveTable.get(); 309 } 310 280 311 } // namespace WebCore 281 312 -
trunk/Source/WebCore/Modules/webaudio/Oscillator.h
r113728 r116201 28 28 #include "AudioBus.h" 29 29 #include "AudioParam.h" 30 #include "AudioS ourceNode.h"30 #include "AudioScheduledSourceNode.h" 31 31 #include <wtf/OwnArrayPtr.h> 32 32 #include <wtf/PassRefPtr.h> … … 41 41 // Oscillator is an audio generator of periodic waveforms. 42 42 43 class Oscillator : public AudioS ourceNode {43 class Oscillator : public AudioScheduledSourceNode { 44 44 public: 45 45 // The waveform type. … … 75 75 bool calculateSampleAccuratePhaseIncrements(size_t framesToProcess); 76 76 77 // As a pure generator, Oscillator will never propagate silence. 78 virtual bool propagatesSilence() const OVERRIDE { return false; } 77 virtual bool propagatesSilence() const OVERRIDE; 79 78 80 79 // One of the waveform types defined in the enum. … … 86 85 // Detune value (deviating from the frequency) in Cents. 87 86 RefPtr<AudioParam> m_detune; 87 88 bool m_firstRender; 88 89 89 90 // m_virtualReadIndex is a sample-frame index into our buffer representing the current playback position. -
trunk/Source/WebCore/Modules/webaudio/Oscillator.idl
r112938 r116201 36 36 const unsigned short TRIANGLE = 3; 37 37 const unsigned short CUSTOM = 4; 38 38 39 39 attribute unsigned short type; 40 41 // Playback state constants. 42 const unsigned short UNSCHEDULED_STATE = 0; 43 const unsigned short SCHEDULED_STATE = 1; 44 const unsigned short PLAYING_STATE = 2; 45 const unsigned short FINISHED_STATE = 3; 46 47 readonly attribute unsigned short playbackState; 40 48 41 49 readonly attribute AudioParam frequency; // in Hertz 42 50 readonly attribute AudioParam detune; // in Cents 43 51 52 void noteOn(in double when); 53 void noteOff(in double when); 44 54 void setWaveTable(in WaveTable waveTable); 45 55
Note: See TracChangeset
for help on using the changeset viewer.