00ffa87ec7dba9521c57c5318772b9624bddcca9
[WebKit-https.git] / LayoutTests / webaudio / audiobuffersource-loop-points.html
1 <!DOCTYPE html>
2
3 <!--
4 Tests that AudioBufferSourceNode supports loop-points with .loopStart and .loopEnd.
5 -->
6
7 <html>
8 <head>
9 <script type="text/javascript" src="resources/audio-testing.js"></script>
10
11 </head>
12 <body>
13
14 <script>
15
16 window.onload = init;
17
18 var sampleRate = 44100.0;
19 var numberOfNotes = 72; // play over a 6 octave range
20 var noteDuration = 0.100;
21 var noteSpacing = noteDuration + 0.005; // leave 5ms of silence between each "note"
22 var lengthInSeconds = numberOfNotes * noteSpacing;
23
24 var context = 0;
25 var buffer = 0;
26
27 function createTestBuffer(frequency, sampleRate) {
28     // Create a buffer containing two periods at this frequency.
29     // The 1st half is a pure sine wave period scaled by a linear ramp from 0 -> 1.
30     // The 2nd half of the buffer corresponds exactly to one pure sine wave period.
31     var onePeriodDuration = 1 / frequency;
32     var sampleFrameLength = 2 * onePeriodDuration * sampleRate;
33
34     var audioBuffer = context.createBuffer(1, sampleFrameLength, sampleRate);
35
36     var n = audioBuffer.length;
37     var channelData = audioBuffer.getChannelData(0);
38
39     for (var i = 0; i < n; ++i) {
40         var sample = Math.sin(frequency * 2.0*Math.PI * i / sampleRate);
41
42         // Linear ramp from 0 -> 1 for the first period.
43         // Stay at 1 for the 2nd period.
44         var scale = i < n / 2 ? i / (n / 2) : 1;
45         sample *= scale;
46
47         channelData[i] = sample;
48     }
49
50     return audioBuffer;
51 }
52
53 function playNote(time, duration, playbackRate) {
54     var source = context.createBufferSource();
55     source.buffer = buffer;
56     source.playbackRate.value = playbackRate;
57
58     var gainNode = context.createGainNode();
59     source.connect(gainNode);
60     gainNode.connect(context.destination);
61
62     // Loop the 2nd half of the buffer.
63     // We should be able to hear any problems as glitches if the looping incorrectly indexes to
64     // anywhere outside of the desired loop-points, since only the 2nd half is a perfect sine-wave cycle,
65     // while the 1st half of the buffer contains a linear ramp of a sine-wave cycle.
66     source.loop = true;
67     source.loopStart = 0.5 * buffer.duration;
68     source.loopEnd = buffer.duration;
69
70     // Play for the given duration.
71     source.start(time);
72     source.stop(time + duration);
73
74     // Apply a quick linear fade-out to avoid a click at the end of the note.
75     gainNode.gain.value = 1;
76     gainNode.gain.setValueAtTime(1, time + duration - 0.005);
77     gainNode.gain.linearRampToValueAtTime(0, time + duration);
78 }
79
80 function init() {
81     if (!window.testRunner)
82         return;
83
84     // Create offline audio context.
85     context = new webkitAudioContext(2, sampleRate * lengthInSeconds, sampleRate);
86
87     // Create the test buffer.
88     // We'll loop this with the loop-points set for the 2nd half of this buffer.
89     buffer = createTestBuffer(440.0, sampleRate);
90
91     // Play all the notes as a chromatic scale.
92     for (var i = 0; i < numberOfNotes; ++i) {
93         var time = i * noteSpacing;
94         var semitone = i - numberOfNotes/2; // start three octaves down
95
96         // Convert from semitone to rate.
97         var playbackRate = Math.pow(2, semitone / 12);
98
99         playNote(time, noteDuration, playbackRate);
100     }
101
102     context.oncomplete = finishAudioTest;
103     context.startRendering();
104
105     testRunner.waitUntilDone();
106 }
107
108 </script>
109
110 </body>
111 </html>