5 <script src=
"resources/audio-testing.js"></script>
6 <script src=
"resources/compatibility.js"></script>
7 <script src=
"resources/audiobuffersource-testing.js"></script>
8 <script src=
"../resources/js-test.js"></script>
13 description("Tests AudioBufferSourceNode looping with a variety of loop points.");
15 // The following test cases assume an AudioBuffer of length 8 whose PCM data is a linear ramp, 0, 1, 2, 3,...
16 // |description| is optional and will be computed from the other parameters. |offsetFrame| is
17 // optional and defaults to 0.
21 { description
: "loop whole buffer by default with loopStart == loopEnd == 0",
26 expected
: [0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7] },
28 { description
: "loop whole buffer explicitly",
33 expected
: [0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7] },
35 { description
: "loop from middle to end of buffer",
40 expected
: [0,1,2,3,4,5,6,7,4,5,6,7,4,5,6,7] },
42 { description
: "loop from start to middle of buffer",
47 expected
: [0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3] },
53 expected
: [0,1,2,3,4,5,4,5,4,5,4,5,4,5,4,5] },
59 expected
: [0,1,2,3,4,5,6,3,4,5,6,3,4,5,6,3] },
65 expected
: [0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 4, 4.5, 5, 5.5] },
71 expected
: [0, 1.5, 3, 4.5, 4, 5.5, 5, 4.5, 4, 5.5, 5, 4.5, 4, 5.5, 5, 4.5] },
73 // Offset past loop end, so playback starts at loop start
79 expected
: [2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2] },
81 // Offset before loop start, so start at offset and continue
87 expected
: [1, 2, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4] },
89 // Offset between loop start and loop end, so start at offset and continue
95 expected
: [4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4] },
97 { description
: "illegal playbackRate of 47 greater than loop length",
102 expected
: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] },
104 // Try illegal loop-points - they should be ignored and we'll loop the whole buffer.
106 { description
: "illegal loop: loopStartFrame > loopEndFrame",
111 expected
: [0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7] },
113 { description
: "illegal loop: loopStartFrame == loopEndFrame",
118 expected
: [0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7] },
120 { description
: "illegal loop: loopStartFrame < 0",
125 expected
: [0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7] },
127 { description
: "illegal loop: loopEndFrame > bufferLength",
132 expected
: [0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7] },
134 // Start a loop with a duration longer than the buffer. The output should be the data from frame 1
135 // to 6, and then looping from 3 to 5 until 20 frames have been played.
136 { description
: "loop from 3 -> 6 with offset 1 for 20 frames",
143 expected
: [1, 2, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
145 // Start a loop with a duration less than the length of the looping frames. The output should be
146 // the data from frame 1 to 3, and then stopping because duration = 3
147 { description
: "loop from 3 -> 8 with offset 1 for 3 frames",
154 expected
: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
156 // Start a loop with a duration less than the length of the looping frames. The output should be
157 // the data from frame 1 to 3, and then stopping because duration = 3
158 { description
: "loop from 3 -> 8 with offset 7 for 3 frames",
165 expected
: [7, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }
169 var sampleRate
= 44100;
171 var bufferFrameLength
= 8;
172 var testSpacingFrames
= 32;
173 var testSpacingSeconds
= testSpacingFrames
/ sampleRate
;
174 var totalRenderLengthFrames
= tests
.length
* testSpacingFrames
;
176 function runLoopTest(context
, testNumber
, test
) {
177 var source
= context
.createBufferSource();
179 source
.buffer
= buffer
;
180 source
.playbackRate
.value
= test
.playbackRate
;
182 source
.loopStart
= test
.loopStartFrame
/ context
.sampleRate
;
183 source
.loopEnd
= test
.loopEndFrame
/ context
.sampleRate
;
185 var offset
= test
.offsetFrame
? test
.offsetFrame
/ context
.sampleRate
: 0;
187 source
.connect(context
.destination
);
189 // Render each test one after the other, spaced apart by testSpacingSeconds.
190 var startTime
= testNumber
* testSpacingSeconds
;
192 // If durationFrames is given, run the test for the specified duration.
193 if (test
.durationFrames
) {
194 if (!test
.renderFrames
) {
195 testFailed("renderFrames is required for test " + testNumber
+ ": " + test
.description
);
197 if (test
.durationFrames
> testSpacingFrames
|| test
.durationFrames
< 0) {
198 testFailed("Test " + testNumber
199 + ": durationFrames (" + test
.durationFrames
+ ") outside the range [0, "
200 + testSpacingFrames
+ "]");
202 source
.start(startTime
, offset
, test
.durationFrames
/ context
.sampleRate
);
204 } else if (test
.renderFrames
) {
205 var duration
= test
.renderFrames
/ context
.sampleRate
;
206 if (test
.renderFrames
> testSpacingFrames
|| test
.renderFrames
< 0) {
207 testFailed("Test " + testNumber
208 + ": renderFrames (" + test
.renderFrames
+ ") outside the range [0, "
209 + testSpacingFrames
+ "]");
211 source
.start(startTime
, offset
);
212 source
.stop(startTime
+ duration
);
214 testFailed("Test " + testNumber
+ " must specify renderFrames and possibly durationFrames");
219 window
.jsTestIsAsync
= true;
221 // Create offline audio context.
222 var context
= new OfflineAudioContext(1, totalRenderLengthFrames
, sampleRate
);
223 buffer
= createTestBuffer(context
, bufferFrameLength
);
225 for (var i
= 0; i
< tests
.length
; ++i
)
226 runLoopTest(context
, i
, tests
[i
]);
228 context
.oncomplete
= checkAllTests
;
229 context
.startRendering();
233 successfullyParsed
= true;