diff --git a/index.bs b/index.bs index 0cd9c1db6..ca42e35d2 100644 --- a/index.bs +++ b/index.bs @@ -4650,7 +4650,7 @@ Methods
when: Thewhenparameter describes at what time (in seconds) the sound should start playing. It is in the same time coordinate system as the {{AudioContext}}'s {{BaseAudioContext/currentTime}} attribute. If 0 is passed in for this value or if the value is less than currentTime, then the sound will start playing immediately. A {{RangeError}} exception MUST be thrown ifwhenis negative. offset: Theoffsetparameter supplies a playhead position where playback will begin. If 0 is passed in for this value, then playback will start from the beginning of the buffer. A {{RangeError}} exception MUST be thrown ifoffsetis negative. Ifoffsetis greater than {{AudioBufferSourceNode/loopEnd}}, playback will begin at {{AudioBufferSourceNode/loopEnd}} (and immediately loop to {{AudioBufferSourceNode/loopStart}}).offsetis silently clamped to [0,duration], whenstartTimeis reached, wheredurationis the value of thedurationattribute of the {{AudioBuffer}} set to the {{AudioBufferSourceNode/buffer}} attribute of thisAudioBufferSourceNode. - duration: The {{AudioBufferSourceNode/start(when, offset, duration)/duration}} parameter describes the duration of the sound (in seconds) to be played. If this parameter is passed, this method has exactly the same effect as the invocation ofstart(when, offset)followed bystop(when + duration). A {{RangeError}} exception MUST be thrown ifdurationis negative. + duration: The {{AudioBufferSourceNode/start(when, offset, duration)/duration}} parameter describes the duration of sound to be played, expressed as seconds of total buffer content to be output, including any whole or partial loop iterations. The units of {{AudioBufferSourceNode/start(when, offset, duration)/duration}} are independent of the effects of {{AudioBufferSourceNode/playbackRate}}. For example, a {{AudioBufferSourceNode/start(when, offset, duration)/duration}} of 5 seconds with a playback rate of 0.5 will output 5 seconds of buffer content at half speed, producing 10 seconds of audible output. A {{RangeError}} exception MUST be thrown ifdurationis negative.
duration values noted in the figures refer to the buffer, not arguments to {{AudioBufferSourceNode/start()}}
+
This figure illustrates basic playback of a buffer, with a simple
loop that ends after the last sample frame in the buffer:
diff --git a/index.html b/index.html
index 2e90a1d21..78fd2e3b8 100644
--- a/index.html
+++ b/index.html
@@ -1218,9 +1218,9 @@
background-attachment: fixed;
}
-
+
-
+
@@ -1622,7 +1622,7 @@
duration parameter describes the duration of the sound (in seconds) to be played. If this parameter is passed, this method has exactly the same effect as the invocation of start(when, offset) followed by stop(when + duration). A RangeError exception MUST be thrown if duration is negative.
+ duration parameter describes the duration of sound to be played, expressed as seconds of total buffer content to be output, including any whole or partial loop iterations. The units of duration are independent of the effects of playbackRate. For example, a duration of 5 seconds with a playback rate of 0.5 will output 5 seconds of buffer content at half speed, producing 10 seconds of audible output. A RangeError exception MUST be thrown if duration is negative.
void playbackRate, of type float, defaulting to 1
The initial value for the playbackRate AudioParam.
The initial value for the playbackRate AudioParam.
This section is non-normative. Please see the playback algorithm for
@@ -6188,7 +6188,7 @@ playbackRate parameter which can vary
+these values are independent of the node’s
playbackRate parameter which can vary
dynamically during the course of playback.
This normative section specifies the playback of the contents of @@ -6220,7 +6220,7 @@
let buffer; // AudioBuffer employed by this nodelet context; // AudioContext employed by this node// The following variables capture attribute and AudioParam values for the node.// They are updated on a k-rate basis, prior to each invocation of process().let loop;let detune;let loopStart;let loopEnd;let playbackRate;// Variables for the node’s playback parameterslet start = 0, offset = 0, duration = Infinity; // Set by start()let stop = Infinity; // Set by stop()// Variables for tracking node’s playback statelet bufferTime = 0, started = false, enteredLoop = false;let bufferDuration = 0;let dt = 1 / context.sampleRate;// Handle invocation of start method callfunction handleStart(when, pos, dur) { if (arguments.length >= 1) { start = when; } offset = pos; if (arguments.length >= 3) { duration = dur; }}// Handle invocation of stop method callfunction handleStop(when) { if (arguments.length >= 1) { stop = when; } else { stop = context.currentTime; }}// Interpolate a multi-channel signal value for some sample frame.// Returns an array of signal values.function playbackSignal(position) { /* This function provides the playback signal function for buffer, which is a function that maps from a playhead position to a set of output signal values, one for each output channel. If |position| corresponds to the location of an exact sample frame in the buffer, this function returns that frame. Otherwise, its return value is determined by a UA-supplied algorithm that interpolates between sample frames in the neighborhood of position. If position is greater than or equal to loopEnd and there is no subsequent sample frame in buffer, then interpolation should be based on the sequence of subsequent frames beginning at loopStart. */ ...}// Generate a single render quantum of audio to be placed// in the channel arrays defined by output. Returns an array// of |numberOfFrames| sample frames to be output.function process(numberOfFrames) { let currentTime = context.currentTime; // context time of next rendered frame let output = []; // accumulates rendered sample frames // Combine the two k-rate parameters affecting playback rate let computedPlaybackRate = playbackRate * Math.pow(2, detune / 1200); // Determine loop endpoints as applicable let actualLoopStart, actualLoopEnd; if (loop && buffer != null) { if (loopStart >= 0 && loopEnd > 0 && loopStart < loopEnd) { actualLoopStart = loopStart; actualLoopEnd = Math.min(loopEnd, buffer.duration); } else { actualLoopStart = 0; actualLoopEnd = buffer.duration; } } else { // If the loop flag is false, remove any record of the loop having been entered enteredLoop = false; } // Handle null buffer case if (buffer == null) { stop = currentTime; // force zero output for all time } // Render each sample frame in the quantum for (let index = 0; index < numberOfFrames; index++) { // Check that currentTime and bufferDuration are within allowable range for playback if (currentTime < start || currentTime >= stop || bufferDuration >= duration) { output.push(0); // this sample frame is silent currentTime += dt; continue; } if (!started) { // Take note that buffer has started playing and get initial playhead position. bufferTime = offset + bufferDuration; started = true; } // Handle loop-related calculations if (loop) { // Determine if looped portion has been entered for the first time if (!enteredLoop) { if (offset < actualLoopEnd && bufferTime >= actualLoopStart) { // playback began before or within loop, and playhead is now past loop start enteredLoop = true; } if (offset >= actualLoopEnd && bufferTime < actualLoopEnd) { // playback began after loop, and playhead is now prior to the loop end enteredLoop = true; } } // Wrap loop iterations as needed. Note that enteredLoop // may become true inside the preceding conditional. if (enteredLoop) { while (bufferTime >= actualLoopEnd) { bufferTime -= actualLoopEnd - actualLoopStart; } while (bufferTime < actualLoopStart) { bufferTime += actualLoopEnd - actualLoopStart; } } } if (bufferTime >= 0 && bufferTime < buffer.duration) { output.push(playbackSignal(bufferTime)); } else { output.push(0); // past end of buffer, so output silent frame } bufferTime += dt * computedPlaybackRate; bufferDuration += dt * computedPlaybackRate; currentTime += dt; } // End of render quantum loop if (currentTime >= stop) { // end playback state of this node. // no further invocations of process() will occur. } return output;}
The following non-normative figures illustrate the behavior of the algorithm in assorted key scenarios. Dynamic resampling of the buffer is not considered, but as long as the times of loop @@ -6238,6 +6238,8 @@
linear interpolation is depicted throughout, although a UA could employ other interpolation techniques.
+the duration values noted in the figures refer to the buffer, not arguments to start()
This figure illustrates basic playback of a buffer, with a simple loop that ends after the last sample frame in the buffer:
@@ -14381,7 +14383,7 @@