audio-testing.js (5982B)
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 }