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