Diff
Modified: trunk/LayoutTests/ChangeLog (179837 => 179838)
--- trunk/LayoutTests/ChangeLog 2015-02-09 18:59:44 UTC (rev 179837)
+++ trunk/LayoutTests/ChangeLog 2015-02-09 19:45:54 UTC (rev 179838)
@@ -1,3 +1,27 @@
+2015-02-09 Jer Noble <[email protected]>
+
+ [WebAudio] AudioBufferSourceNodes should accurately play backwards if given a negative playbackRate.
+ https://bugs.webkit.org/show_bug.cgi?id=140955
+
+ Reviewed by Eric Carlson.
+
+ * webaudio/audiobuffersource-negative-playbackrate-expected.txt: Added.
+ * webaudio/audiobuffersource-negative-playbackrate-interpolated-expected.txt: Added.
+ * webaudio/audiobuffersource-negative-playbackrate-interpolated-loop-expected.txt: Added.
+ * webaudio/audiobuffersource-negative-playbackrate-interpolated-loop.html: Added.
+ * webaudio/audiobuffersource-negative-playbackrate-interpolated.html:
+ * webaudio/audiobuffersource-negative-playbackrate-loop-expected.txt: Added.
+ * webaudio/audiobuffersource-negative-playbackrate-loop.html: Added.
+ * webaudio/audiobuffersource-negative-playbackrate.html:
+ * webaudio/resources/audiobuffersource-testing.js:
+ (createRamp):
+
+ Get rid of extra HRTF padding as it's now unnecessary.
+
+ * webaudio/resources/note-grain-on-testing.js:
+ (createSignalBuffer):
+ (verifyStartAndEndFrames):
+
2015-02-09 David Kilzer <[email protected]>
[iOS] Gardening: css3/masking/mask-repeat-space-padding.html
Added: trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-expected.txt (0 => 179838)
--- trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-expected.txt (rev 0)
+++ trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-expected.txt 2015-02-09 19:45:54 UTC (rev 179838)
@@ -0,0 +1,2 @@
+PASS Test playback at -1 playbackRate
+
Added: trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-interpolated-expected.txt (0 => 179838)
--- trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-interpolated-expected.txt (rev 0)
+++ trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-interpolated-expected.txt 2015-02-09 19:45:54 UTC (rev 179838)
@@ -0,0 +1,2 @@
+PASS Test playback at -0.75 playbackRate
+
Added: trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-interpolated-loop-expected.txt (0 => 179838)
--- trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-interpolated-loop-expected.txt (rev 0)
+++ trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-interpolated-loop-expected.txt 2015-02-09 19:45:54 UTC (rev 179838)
@@ -0,0 +1,2 @@
+PASS Test looping playback at -0.75 playbackRate
+
Added: trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-interpolated-loop.html (0 => 179838)
--- trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-interpolated-loop.html (rev 0)
+++ trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-interpolated-loop.html 2015-02-09 19:45:54 UTC (rev 179838)
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>audiobuffersource-negative-playbackrate-interpolated-loop</title>
+ <script src=""
+ <script src=""
+ <script src=""
+
+ <script>
+
+ var sampleRate = 44100.0;
+ var sourceFrames = 128;
+ var renderFrames = 10;
+ var testSpacingFrames = 0;
+ var startLoop = 100 / sampleRate;
+ var loopDuration = (renderFrames / 2) / sampleRate;
+ var endLoop = startLoop + loopDuration;
+
+ var tests = [{
+ description:"Test looping playback at -0.75 playbackRate",
+ offsetFrame:0,
+ renderFrames:renderFrames,
+ expected:[104,103.25,102.5,101.75,101,100.25,102,103.75,103,102.25],
+ }];
+
+ function go() {
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+ }
+
+ context = new webkitOfflineAudioContext(1, renderFrames, sampleRate);
+
+ var bufferSource = context.createBufferSource();
+ bufferSource.buffer = createRamp(context, 0, 127, sourceFrames);
+
+ bufferSource.connect(context.destination);
+ bufferSource.playbackRate.value = -0.75;
+ bufferSource.loop = true;
+ bufferSource.loopStart = startLoop;
+ bufferSource.loopEnd = endLoop;
+ bufferSource.start(0, startLoop, loopDuration);
+ bufferSource.stop(loopDuration * 2);
+
+ context._oncomplete_ = checkAllTests;
+ context.startRendering();
+ }
+
+ </script>
+</head>
+<body _onload_="go()">
+</body>
+</html>
Added: trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-interpolated.html (0 => 179838)
--- trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-interpolated.html (rev 0)
+++ trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-interpolated.html 2015-02-09 19:45:54 UTC (rev 179838)
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>audiobuffersource-negative-playbackrate-interpolated</title>
+ <script src=""
+ <script src=""
+ <script src=""
+
+ <script>
+
+ var sampleRate = 44100.0;
+ var sourceFrames = 128;
+ var renderFrames = 10;
+ var testSpacingFrames = 0;
+
+ var tests = [{
+ description:"Test playback at -0.75 playbackRate",
+ offsetFrame:0,
+ renderFrames:renderFrames,
+ expected:[127, 126.25, 125.5, 124.75, 124, 123.25, 122.5, 121.75, 121, 120.25]
+ }];
+
+ function go() {
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+ }
+
+ context = new webkitOfflineAudioContext(1, renderFrames, sampleRate);
+
+ var bufferSource = context.createBufferSource();
+ bufferSource.buffer = createRamp(context, 0, 127, sourceFrames);
+
+ bufferSource.connect(context.destination);
+ bufferSource.playbackRate.value = -0.75;
+ bufferSource.start(0);
+
+ context._oncomplete_ = checkAllTests;
+ context.startRendering();
+ }
+
+ </script>
+</head>
+<body _onload_="go()">
+</body>
+</html>
Added: trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-loop-expected.txt (0 => 179838)
--- trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-loop-expected.txt (rev 0)
+++ trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-loop-expected.txt 2015-02-09 19:45:54 UTC (rev 179838)
@@ -0,0 +1,2 @@
+PASS Test looping playback at -1 playbackRate
+
Added: trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-loop.html (0 => 179838)
--- trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-loop.html (rev 0)
+++ trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate-loop.html 2015-02-09 19:45:54 UTC (rev 179838)
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>audiobuffersource-negative-playbackrate-loop</title>
+ <script src=""
+ <script src=""
+ <script src=""
+
+ <script>
+
+ var sampleRate = 44100.0;
+ var sourceFrames = 128;
+ var renderFrames = 10;
+ var testSpacingFrames = 0;
+ var startLoop = 100 / sampleRate;
+ var loopDuration = (renderFrames / 2) / sampleRate;
+ var endLoop = startLoop + loopDuration;
+
+ var tests = [{
+ description:"Test looping playback at -1 playbackRate",
+ offsetFrame:0,
+ renderFrames:renderFrames,
+ expected:[104, 103, 102, 101, 100, 104, 103, 102, 101, 100],
+ }];
+
+ function go() {
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+ }
+
+ context = new webkitOfflineAudioContext(1, renderFrames, sampleRate);
+
+ var bufferSource = context.createBufferSource();
+ bufferSource.buffer = createRamp(context, 0, 127, sourceFrames);
+
+ bufferSource.connect(context.destination);
+ bufferSource.playbackRate.value = -1;
+ bufferSource.loop = true;
+ bufferSource.loopStart = startLoop;
+ bufferSource.loopEnd = endLoop;
+ bufferSource.start(0, startLoop, loopDuration);
+ bufferSource.stop(loopDuration * 2);
+
+ context._oncomplete_ = checkAllTests;
+ context.startRendering();
+ }
+
+ </script>
+</head>
+<body _onload_="go()">
+</body>
+</html>
Added: trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate.html (0 => 179838)
--- trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate.html (rev 0)
+++ trunk/LayoutTests/webaudio/audiobuffersource-negative-playbackrate.html 2015-02-09 19:45:54 UTC (rev 179838)
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>audiobuffersource-negative-playbackrate</title>
+ <script src=""
+ <script src=""
+ <script src=""
+
+ <script>
+
+ var sampleRate = 44100.0;
+ var sourceFrames = 128;
+ var renderFrames = 10;
+ var testSpacingFrames = 0;
+
+ var tests = [{
+ description:"Test playback at -1 playbackRate",
+ offsetFrame:0,
+ renderFrames:renderFrames,
+ expected:[127, 126, 125, 124, 123, 122, 121, 120, 119, 118],
+ }];
+
+ function go() {
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+ }
+
+ context = new webkitOfflineAudioContext(1, renderFrames, sampleRate);
+
+ var bufferSource = context.createBufferSource();
+ bufferSource.buffer = createRamp(context, 0, 127, sourceFrames);
+
+ bufferSource.connect(context.destination);
+ bufferSource.playbackRate.value = -1;
+ bufferSource.start(0);
+
+ context._oncomplete_ = checkAllTests;
+ context.startRendering();
+ }
+
+ </script>
+</head>
+<body _onload_="go()">
+</body>
+</html>
Modified: trunk/LayoutTests/webaudio/resources/audiobuffersource-testing.js (179837 => 179838)
--- trunk/LayoutTests/webaudio/resources/audiobuffersource-testing.js 2015-02-09 18:59:44 UTC (rev 179837)
+++ trunk/LayoutTests/webaudio/resources/audiobuffersource-testing.js 2015-02-09 19:45:54 UTC (rev 179838)
@@ -9,6 +9,21 @@
return audioBuffer;
}
+function createRamp(context, startValue, endValue, numberOfSamples) {
+ var audioBuffer = context.createBuffer(1, numberOfSamples, context.sampleRate);
+ var channelData = audioBuffer.getChannelData(0);
+
+ var delta = (endValue - startValue) / (numberOfSamples - 1);
+ var nextValue = startValue;
+
+ for (var i = 0; i < numberOfSamples; ++i) {
+ channelData[i] = nextValue;
+ nextValue += delta;
+ }
+
+ return audioBuffer;
+}
+
function checkSingleTest(renderedBuffer, i) {
var renderedData = renderedBuffer.getChannelData(0);
var offsetFrame = i * testSpacingFrames;
Modified: trunk/LayoutTests/webaudio/resources/note-grain-on-testing.js (179837 => 179838)
--- trunk/LayoutTests/webaudio/resources/note-grain-on-testing.js 2015-02-09 18:59:44 UTC (rev 179837)
+++ trunk/LayoutTests/webaudio/resources/note-grain-on-testing.js 2015-02-09 19:45:54 UTC (rev 179838)
@@ -1,21 +1,13 @@
var sampleRate = 44100.0;
-// HRTF extra frames. This is a magic constant currently in
-// AudioBufferSourceNode::process that always extends the
-// duration by this number of samples. See bug 77224
-// (https://bugs.webkit.org/show_bug.cgi?id=77224).
-var extraFramesHRTF = 512;
-
// How many grains to play.
var numberOfTests = 100;
// Duration of each grain to be played
var duration = 0.01;
-// Time step between the start of each grain. We need to add a little
-// bit of silence so we can detect grain boundaries and also account
-// for the extra frames for HRTF.
-var timeStep = duration + .005 + extraFramesHRTF / sampleRate;
+// Time step between the start of each grain.
+var timeStep = duration + .005;
// Time step between the start for each grain.
var grainOffsetStep = 0.001;
@@ -33,7 +25,7 @@
// Make sure the buffer has enough data for all of the possible
// grain offsets and durations. Need to include the extra frames
// for HRTF. The additional 1 is for any round-off errors.
- var signalLength = Math.floor(1 + extraFramesHRTF + sampleRate * (numberOfTests * grainOffsetStep + duration));
+ var signalLength = Math.floor(1 + sampleRate * (numberOfTests * grainOffsetStep + duration));
var buffer = context.createBuffer(2, signalLength, sampleRate);
var data = ""
@@ -135,7 +127,7 @@
var expectedStart = timeToSampleFrame(k * timeStep, sampleRate);
// The end point is the duration, plus the extra frames
// for HRTF.
- var expectedEnd = extraFramesHRTF + expectedStart + grainLengthInSampleFrames(k * grainOffsetStep, duration, sampleRate);
+ var expectedEnd = expectedStart + grainLengthInSampleFrames(k * grainOffsetStep, duration, sampleRate);
if (startFrames[k] != expectedStart) {
testFailed("Pulse " + k + " started at " + startFrames[k] + " but expected at " + expectedStart);
Modified: trunk/Source/WebCore/ChangeLog (179837 => 179838)
--- trunk/Source/WebCore/ChangeLog 2015-02-09 18:59:44 UTC (rev 179837)
+++ trunk/Source/WebCore/ChangeLog 2015-02-09 19:45:54 UTC (rev 179838)
@@ -1,3 +1,25 @@
+2015-02-09 Jer Noble <[email protected]>
+
+ [WebAudio] AudioBufferSourceNodes should accurately play backwards if given a negative playbackRate.
+ https://bugs.webkit.org/show_bug.cgi?id=140955
+
+ Reviewed by Eric Carlson.
+
+ Tests: webaudio/audiobuffersource-negative-playbackrate-interpolated.html
+ webaudio/audiobuffersource-negative-playbackrate.html
+
+ Add support for playing an AudioBufferSourceNode at a negative playbackRate. Change the meaning of
+ start() to set the initial playback position at the end of the play range if the rate of playback
+ is negtive.
+
+ * Modules/webaudio/AudioBufferSourceNode.cpp:
+ (WebCore::AudioBufferSourceNode::AudioBufferSourceNode): Allow the playbackRate AudioParam to range from [-32, 32].
+ (WebCore::AudioBufferSourceNode::renderFromBuffer): Change variable names from "start" and "end" to "min" and "max"
+ for clarity. Add a non-interpolated and interpolated render step for negative playback.
+ (WebCore::AudioBufferSourceNode::start): Drive-by fix: default value of grainDuration is not 0.02.
+ (WebCore::AudioBufferSourceNode::startPlaying): Start playing at the end of the buffer for negative playback.
+ (WebCore::AudioBufferSourceNode::totalPitchRate): Allow the pitch to be negative.
+
2015-02-09 Darin Adler <[email protected]>
Try to fix build on platforms that use SVG "all in one" file (Windows).
Modified: trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp (179837 => 179838)
--- trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp 2015-02-09 18:59:44 UTC (rev 179837)
+++ trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp 2015-02-09 19:45:54 UTC (rev 179838)
@@ -70,7 +70,7 @@
setNodeType(NodeTypeAudioBufferSource);
m_gain = AudioParam::create(context, "gain", 1.0, 0.0, 1.0);
- m_playbackRate = AudioParam::create(context, "playbackRate", 1.0, 0.0, MaxRate);
+ m_playbackRate = AudioParam::create(context, "playbackRate", 1.0, -MaxRate, MaxRate);
// Default to mono. A call to setBuffer() will set the number of output channels to that of the buffer.
addOutput(std::make_unique<AudioNodeOutput>(this, 1));
@@ -200,47 +200,54 @@
size_t bufferLength = buffer()->length();
double bufferSampleRate = buffer()->sampleRate();
+ double pitchRate = totalPitchRate();
+ bool reverse = pitchRate < 0;
// Avoid converting from time to sample-frames twice by computing
// the grain end time first before computing the sample frame.
- unsigned endFrame = m_isGrain ? AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, bufferSampleRate) : bufferLength;
-
- // This is a HACK to allow for HRTF tail-time - avoids glitch at end.
- // FIXME: implement tailTime for each AudioNode for a more general solution to this problem.
- // https://bugs.webkit.org/show_bug.cgi?id=77224
+ unsigned maxFrame;
if (m_isGrain)
- endFrame += 512;
+ maxFrame = AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, bufferSampleRate);
+ else
+ maxFrame = bufferLength;
// Do some sanity checking.
- if (endFrame > bufferLength)
- endFrame = bufferLength;
- if (m_virtualReadIndex >= endFrame)
+ if (maxFrame > bufferLength)
+ maxFrame = bufferLength;
+ if (reverse && m_virtualReadIndex <= 0)
+ m_virtualReadIndex = maxFrame - 1;
+ else if (!reverse && m_virtualReadIndex >= maxFrame)
m_virtualReadIndex = 0; // reset to start
// If the .loop attribute is true, then values of m_loopStart == 0 && m_loopEnd == 0 implies
// that we should use the entire buffer as the loop, otherwise use the loop values in m_loopStart and m_loopEnd.
- double virtualEndFrame = endFrame;
- double virtualDeltaFrames = endFrame;
+ double virtualMaxFrame = maxFrame;
+ double virtualMinFrame = 0;
+ double virtualDeltaFrames = maxFrame;
if (loop() && (m_loopStart || m_loopEnd) && m_loopStart >= 0 && m_loopEnd > 0 && m_loopStart < m_loopEnd) {
// Convert from seconds to sample-frames.
- double loopStartFrame = m_loopStart * buffer()->sampleRate();
- double loopEndFrame = m_loopEnd * buffer()->sampleRate();
+ double loopMinFrame = m_loopStart * buffer()->sampleRate();
+ double loopMaxFrame = m_loopEnd * buffer()->sampleRate();
- virtualEndFrame = std::min(loopEndFrame, virtualEndFrame);
- virtualDeltaFrames = virtualEndFrame - loopStartFrame;
+ virtualMaxFrame = std::min(loopMaxFrame, virtualMaxFrame);
+ virtualMinFrame = std::max(loopMinFrame, virtualMinFrame);
+ virtualDeltaFrames = virtualMaxFrame - virtualMinFrame;
}
- double pitchRate = totalPitchRate();
-
// Sanity check that our playback rate isn't larger than the loop size.
- if (pitchRate >= virtualDeltaFrames)
+ if (fabs(pitchRate) >= virtualDeltaFrames)
return false;
// Get local copy.
double virtualReadIndex = m_virtualReadIndex;
+ bool needsInterpolation = virtualReadIndex != floor(virtualReadIndex)
+ || virtualDeltaFrames != floor(virtualDeltaFrames)
+ || virtualMaxFrame != floor(virtualMaxFrame)
+ || virtualMinFrame != floor(virtualMinFrame);
+
// Render loop - reading from the source buffer to the destination using linear interpolation.
int framesToProcess = numberOfFrames;
@@ -249,14 +256,12 @@
// Optimize for the very common case of playing back with pitchRate == 1.
// We can avoid the linear interpolation.
- if (pitchRate == 1 && virtualReadIndex == floor(virtualReadIndex)
- && virtualDeltaFrames == floor(virtualDeltaFrames)
- && virtualEndFrame == floor(virtualEndFrame)) {
+ if (pitchRate == 1 && !needsInterpolation) {
unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
unsigned deltaFrames = static_cast<unsigned>(virtualDeltaFrames);
- endFrame = static_cast<unsigned>(virtualEndFrame);
+ maxFrame = static_cast<unsigned>(virtualMaxFrame);
while (framesToProcess > 0) {
- int framesToEnd = endFrame - readIndex;
+ int framesToEnd = maxFrame - readIndex;
int framesThisTime = std::min(framesToProcess, framesToEnd);
framesThisTime = std::max(0, framesThisTime);
@@ -268,13 +273,83 @@
framesToProcess -= framesThisTime;
// Wrap-around.
- if (readIndex >= endFrame) {
+ if (readIndex >= maxFrame) {
readIndex -= deltaFrames;
if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
break;
}
}
virtualReadIndex = readIndex;
+ } else if (pitchRate == -1 && !needsInterpolation) {
+ int readIndex = static_cast<int>(virtualReadIndex);
+ int deltaFrames = static_cast<int>(virtualDeltaFrames);
+ int minFrame = static_cast<int>(virtualMinFrame) - 1;
+ while (framesToProcess > 0) {
+ int framesToEnd = readIndex - minFrame;
+ int framesThisTime = std::min<int>(framesToProcess, framesToEnd);
+ framesThisTime = std::max<int>(0, framesThisTime);
+
+ while (framesThisTime--) {
+ for (unsigned i = 0; i < numberOfChannels; ++i) {
+ float* destination = destinationChannels[i];
+ const float* source = sourceChannels[i];
+
+ destination[writeIndex] = source[readIndex];
+ }
+
+ ++writeIndex;
+ --readIndex;
+ --framesToProcess;
+ }
+
+ // Wrap-around.
+ if (readIndex <= minFrame) {
+ readIndex += deltaFrames;
+ if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
+ break;
+ }
+ }
+ virtualReadIndex = readIndex;
+ } else if (!pitchRate) {
+ unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
+
+ for (unsigned i = 0; i < numberOfChannels; ++i)
+ std::fill_n(destinationChannels[i], framesToProcess, sourceChannels[i][readIndex]);
+ } else if (reverse) {
+ unsigned maxFrame = static_cast<unsigned>(virtualMaxFrame);
+ unsigned minFrame = static_cast<unsigned>(floorf(virtualMinFrame));
+
+ while (framesToProcess--) {
+ unsigned readIndex = static_cast<unsigned>(floorf(virtualReadIndex));
+ double interpolationFactor = virtualReadIndex - readIndex;
+
+ unsigned readIndex2 = readIndex + 1;
+ if (readIndex2 >= maxFrame)
+ readIndex2 = loop() ? minFrame : maxFrame - 1;
+
+ // Linear interpolation.
+ for (unsigned i = 0; i < numberOfChannels; ++i) {
+ float* destination = destinationChannels[i];
+ const float* source = sourceChannels[i];
+
+ double sample1 = source[readIndex];
+ double sample2 = source[readIndex2];
+ double sample = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2;
+
+ destination[writeIndex] = narrowPrecisionToFloat(sample);
+ }
+
+ writeIndex++;
+
+ virtualReadIndex += pitchRate;
+
+ // Wrap-around, retaining sub-sample position since virtualReadIndex is floating-point.
+ if (virtualReadIndex < virtualMinFrame) {
+ virtualReadIndex += virtualDeltaFrames;
+ if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
+ break;
+ }
+ }
} else {
while (framesToProcess--) {
unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
@@ -311,7 +386,7 @@
virtualReadIndex += pitchRate;
// Wrap-around, retaining sub-sample position since virtualReadIndex is floating-point.
- if (virtualReadIndex >= virtualEndFrame) {
+ if (virtualReadIndex >= virtualMaxFrame) {
virtualReadIndex -= virtualDeltaFrames;
if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
break;
@@ -382,7 +457,7 @@
void AudioBufferSourceNode::start(double when, double grainOffset, ExceptionCode& ec)
{
- startPlaying(Partial, when, grainOffset, 0, ec);
+ startPlaying(Partial, when, grainOffset, buffer() ? buffer()->duration() - grainOffset : 0, ec);
}
void AudioBufferSourceNode::start(double when, double grainOffset, double grainDuration, ExceptionCode& ec)
@@ -431,7 +506,7 @@
m_grainDuration = std::min(maxDuration, grainDuration);
} else {
m_grainOffset = 0.0;
- m_grainDuration = DefaultGrainDuration;
+ m_grainDuration = buffer()->duration();
}
m_startTime = when;
@@ -440,7 +515,10 @@
// at a sub-sample position since it will degrade the quality.
// When aligned to the sample-frame the playback will be identical to the PCM data stored in the buffer.
// Since playbackRate == 1 is very common, it's worth considering quality.
- m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer()->sampleRate());
+ if (totalPitchRate() < 0)
+ m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, buffer()->sampleRate()) - 1;
+ else
+ m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer()->sampleRate());
m_playbackState = SCHEDULED_STATE;
}
@@ -471,11 +549,7 @@
double totalRate = dopplerRate * sampleRateFactor * basePitchRate;
- // Sanity check the total rate. It's very important that the resampler not get any bad rate values.
- totalRate = std::max(0.0, totalRate);
- if (!totalRate)
- totalRate = 1; // zero rate is considered illegal
- totalRate = std::min(MaxRate, totalRate);
+ totalRate = std::max(-MaxRate, std::min(MaxRate, totalRate));
bool isTotalRateValid = !std::isnan(totalRate) && !std::isinf(totalRate);
ASSERT(isTotalRateValid);