|
1 if (window.testRunner) |
|
2 testRunner.overridePreference("WebKitWebAudioEnabled", "1"); |
|
3 |
|
4 function writeString(s, a, offset) { |
|
5 for (var i = 0; i < s.length; ++i) { |
|
6 a[offset + i] = s.charCodeAt(i); |
|
7 } |
|
8 } |
|
9 |
|
10 function writeInt16(n, a, offset) { |
|
11 n = Math.floor(n); |
|
12 |
|
13 var b1 = n & 255; |
|
14 var b2 = (n >> 8) & 255; |
|
15 |
|
16 a[offset + 0] = b1; |
|
17 a[offset + 1] = b2; |
|
18 } |
|
19 |
|
20 function writeInt32(n, a, offset) { |
|
21 n = Math.floor(n); |
|
22 var b1 = n & 255; |
|
23 var b2 = (n >> 8) & 255; |
|
24 var b3 = (n >> 16) & 255; |
|
25 var b4 = (n >> 24) & 255; |
|
26 |
|
27 a[offset + 0] = b1; |
|
28 a[offset + 1] = b2; |
|
29 a[offset + 2] = b3; |
|
30 a[offset + 3] = b4; |
|
31 } |
|
32 |
|
33 function writeAudioBuffer(audioBuffer, a, offset) { |
|
34 var n = audioBuffer.length; |
|
35 var channels = audioBuffer.numberOfChannels; |
|
36 |
|
37 for (var i = 0; i < n; ++i) { |
|
38 for (var k = 0; k < channels; ++k) { |
|
39 var buffer = audioBuffer.getChannelData(k); |
|
40 var sample = buffer[i] * 32768.0; |
|
41 |
|
42 // Clip samples to the limitations of 16-bit. |
|
43 // If we don't do this then we'll get nasty wrap-around distortion. |
|
44 if (sample < -32768) |
|
45 sample = -32768; |
|
46 if (sample > 32767) |
|
47 sample = 32767; |
|
48 |
|
49 writeInt16(sample, a, offset); |
|
50 offset += 2; |
|
51 } |
|
52 } |
|
53 } |
|
54 |
|
55 function createWaveFileData(audioBuffer) { |
|
56 var frameLength = audioBuffer.length; |
|
57 var numberOfChannels = audioBuffer.numberOfChannels; |
|
58 var sampleRate = audioBuffer.sampleRate; |
|
59 var bitsPerSample = 16; |
|
60 var byteRate = sampleRate * numberOfChannels * bitsPerSample/8; |
|
61 var blockAlign = numberOfChannels * bitsPerSample/8; |
|
62 var wavDataByteLength = frameLength * numberOfChannels * 2; // 16-bit audio |
|
63 var headerByteLength = 44; |
|
64 var totalLength = headerByteLength + wavDataByteLength; |
|
65 |
|
66 var waveFileData = new Uint8Array(totalLength); |
|
67 |
|
68 var subChunk1Size = 16; // for linear PCM |
|
69 var subChunk2Size = wavDataByteLength; |
|
70 var chunkSize = 4 + (8 + subChunk1Size) + (8 + subChunk2Size); |
|
71 |
|
72 writeString("RIFF", waveFileData, 0); |
|
73 writeInt32(chunkSize, waveFileData, 4); |
|
74 writeString("WAVE", waveFileData, 8); |
|
75 writeString("fmt ", waveFileData, 12); |
|
76 |
|
77 writeInt32(subChunk1Size, waveFileData, 16); // SubChunk1Size (4) |
|
78 writeInt16(1, waveFileData, 20); // AudioFormat (2) |
|
79 writeInt16(numberOfChannels, waveFileData, 22); // NumChannels (2) |
|
80 writeInt32(sampleRate, waveFileData, 24); // SampleRate (4) |
|
81 writeInt32(byteRate, waveFileData, 28); // ByteRate (4) |
|
82 writeInt16(blockAlign, waveFileData, 32); // BlockAlign (2) |
|
83 writeInt32(bitsPerSample, waveFileData, 34); // BitsPerSample (4) |
|
84 |
|
85 writeString("data", waveFileData, 36); |
|
86 writeInt32(subChunk2Size, waveFileData, 40); // SubChunk2Size (4) |
|
87 |
|
88 // Write actual audio data starting at offset 44. |
|
89 writeAudioBuffer(audioBuffer, waveFileData, 44); |
|
90 |
|
91 return waveFileData; |
|
92 } |
|
93 |
|
94 function createAudioData(audioBuffer) { |
|
95 return createWaveFileData(audioBuffer); |
|
96 } |
|
97 |
|
98 function finishAudioTest(event) { |
|
99 var audioData = createAudioData(event.renderedBuffer); |
|
100 testRunner.setAudioData(audioData); |
|
101 testRunner.notifyDone(); |
|
102 } |
|
103 |
|
104 // Create an impulse in a buffer of length sampleFrameLength |
|
105 function createImpulseBuffer(context, sampleFrameLength) { |
|
106 var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate); |
|
107 var n = audioBuffer.length; |
|
108 var dataL = audioBuffer.getChannelData(0); |
|
109 |
|
110 for (var k = 0; k < n; ++k) { |
|
111 dataL[k] = 0; |
|
112 } |
|
113 dataL[0] = 1; |
|
114 |
|
115 return audioBuffer; |
|
116 } |
|
117 |
|
118 // Create a buffer of the given length with a linear ramp having values 0 <= x < 1. |
|
119 function createLinearRampBuffer(context, sampleFrameLength) { |
|
120 var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate); |
|
121 var n = audioBuffer.length; |
|
122 var dataL = audioBuffer.getChannelData(0); |
|
123 |
|
124 for (var i = 0; i < n; ++i) |
|
125 dataL[i] = i / n; |
|
126 |
|
127 return audioBuffer; |
|
128 } |
|
129 |
|
130 // Create a buffer of the given length having a constant value. |
|
131 function createConstantBuffer(context, sampleFrameLength, constantValue) { |
|
132 var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate); |
|
133 var n = audioBuffer.length; |
|
134 var dataL = audioBuffer.getChannelData(0); |
|
135 |
|
136 for (var i = 0; i < n; ++i) |
|
137 dataL[i] = constantValue; |
|
138 |
|
139 return audioBuffer; |
|
140 } |
|
141 |
|
142 // Create a stereo impulse in a buffer of length sampleFrameLength |
|
143 function createStereoImpulseBuffer(context, sampleFrameLength) { |
|
144 var audioBuffer = context.createBuffer(2, sampleFrameLength, context.sampleRate); |
|
145 var n = audioBuffer.length; |
|
146 var dataL = audioBuffer.getChannelData(0); |
|
147 var dataR = audioBuffer.getChannelData(1); |
|
148 |
|
149 for (var k = 0; k < n; ++k) { |
|
150 dataL[k] = 0; |
|
151 dataR[k] = 0; |
|
152 } |
|
153 dataL[0] = 1; |
|
154 dataR[0] = 1; |
|
155 |
|
156 return audioBuffer; |
|
157 } |
|
158 |
|
159 // Convert time (in seconds) to sample frames. |
|
160 function timeToSampleFrame(time, sampleRate) { |
|
161 return Math.floor(0.5 + time * sampleRate); |
|
162 } |
|
163 |
|
164 // Compute the number of sample frames consumed by start with |
|
165 // the specified |grainOffset|, |duration|, and |sampleRate|. |
|
166 function grainLengthInSampleFrames(grainOffset, duration, sampleRate) { |
|
167 var startFrame = timeToSampleFrame(grainOffset, sampleRate); |
|
168 var endFrame = timeToSampleFrame(grainOffset + duration, sampleRate); |
|
169 |
|
170 return endFrame - startFrame; |
|
171 } |
|
172 |
|
173 // True if the number is not an infinity or NaN |
|
174 function isValidNumber(x) { |
|
175 return !isNaN(x) && (x != Infinity) && (x != -Infinity); |
|
176 } |
|
177 |
|
178 function shouldThrowTypeError(func, text) { |
|
179 var ok = false; |
|
180 try { |
|
181 func(); |
|
182 } catch (e) { |
|
183 if (e instanceof TypeError) { |
|
184 ok = true; |
|
185 } |
|
186 } |
|
187 if (ok) { |
|
188 testPassed(text + " threw TypeError."); |
|
189 } else { |
|
190 testFailed(text + " should throw TypeError."); |
|
191 } |
|
192 } |