michael@0: if (window.testRunner) michael@0: testRunner.overridePreference("WebKitWebAudioEnabled", "1"); michael@0: michael@0: function writeString(s, a, offset) { michael@0: for (var i = 0; i < s.length; ++i) { michael@0: a[offset + i] = s.charCodeAt(i); michael@0: } michael@0: } michael@0: michael@0: function writeInt16(n, a, offset) { michael@0: n = Math.floor(n); michael@0: michael@0: var b1 = n & 255; michael@0: var b2 = (n >> 8) & 255; michael@0: michael@0: a[offset + 0] = b1; michael@0: a[offset + 1] = b2; michael@0: } michael@0: michael@0: function writeInt32(n, a, offset) { michael@0: n = Math.floor(n); michael@0: var b1 = n & 255; michael@0: var b2 = (n >> 8) & 255; michael@0: var b3 = (n >> 16) & 255; michael@0: var b4 = (n >> 24) & 255; michael@0: michael@0: a[offset + 0] = b1; michael@0: a[offset + 1] = b2; michael@0: a[offset + 2] = b3; michael@0: a[offset + 3] = b4; michael@0: } michael@0: michael@0: function writeAudioBuffer(audioBuffer, a, offset) { michael@0: var n = audioBuffer.length; michael@0: var channels = audioBuffer.numberOfChannels; michael@0: michael@0: for (var i = 0; i < n; ++i) { michael@0: for (var k = 0; k < channels; ++k) { michael@0: var buffer = audioBuffer.getChannelData(k); michael@0: var sample = buffer[i] * 32768.0; michael@0: michael@0: // Clip samples to the limitations of 16-bit. michael@0: // If we don't do this then we'll get nasty wrap-around distortion. michael@0: if (sample < -32768) michael@0: sample = -32768; michael@0: if (sample > 32767) michael@0: sample = 32767; michael@0: michael@0: writeInt16(sample, a, offset); michael@0: offset += 2; michael@0: } michael@0: } michael@0: } michael@0: michael@0: function createWaveFileData(audioBuffer) { michael@0: var frameLength = audioBuffer.length; michael@0: var numberOfChannels = audioBuffer.numberOfChannels; michael@0: var sampleRate = audioBuffer.sampleRate; michael@0: var bitsPerSample = 16; michael@0: var byteRate = sampleRate * numberOfChannels * bitsPerSample/8; michael@0: var blockAlign = numberOfChannels * bitsPerSample/8; michael@0: var wavDataByteLength = frameLength * numberOfChannels * 2; // 16-bit audio michael@0: var headerByteLength = 44; michael@0: var totalLength = headerByteLength + wavDataByteLength; michael@0: michael@0: var waveFileData = new Uint8Array(totalLength); michael@0: michael@0: var subChunk1Size = 16; // for linear PCM michael@0: var subChunk2Size = wavDataByteLength; michael@0: var chunkSize = 4 + (8 + subChunk1Size) + (8 + subChunk2Size); michael@0: michael@0: writeString("RIFF", waveFileData, 0); michael@0: writeInt32(chunkSize, waveFileData, 4); michael@0: writeString("WAVE", waveFileData, 8); michael@0: writeString("fmt ", waveFileData, 12); michael@0: michael@0: writeInt32(subChunk1Size, waveFileData, 16); // SubChunk1Size (4) michael@0: writeInt16(1, waveFileData, 20); // AudioFormat (2) michael@0: writeInt16(numberOfChannels, waveFileData, 22); // NumChannels (2) michael@0: writeInt32(sampleRate, waveFileData, 24); // SampleRate (4) michael@0: writeInt32(byteRate, waveFileData, 28); // ByteRate (4) michael@0: writeInt16(blockAlign, waveFileData, 32); // BlockAlign (2) michael@0: writeInt32(bitsPerSample, waveFileData, 34); // BitsPerSample (4) michael@0: michael@0: writeString("data", waveFileData, 36); michael@0: writeInt32(subChunk2Size, waveFileData, 40); // SubChunk2Size (4) michael@0: michael@0: // Write actual audio data starting at offset 44. michael@0: writeAudioBuffer(audioBuffer, waveFileData, 44); michael@0: michael@0: return waveFileData; michael@0: } michael@0: michael@0: function createAudioData(audioBuffer) { michael@0: return createWaveFileData(audioBuffer); michael@0: } michael@0: michael@0: function finishAudioTest(event) { michael@0: var audioData = createAudioData(event.renderedBuffer); michael@0: testRunner.setAudioData(audioData); michael@0: testRunner.notifyDone(); michael@0: } michael@0: michael@0: // Create an impulse in a buffer of length sampleFrameLength michael@0: function createImpulseBuffer(context, sampleFrameLength) { michael@0: var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate); michael@0: var n = audioBuffer.length; michael@0: var dataL = audioBuffer.getChannelData(0); michael@0: michael@0: for (var k = 0; k < n; ++k) { michael@0: dataL[k] = 0; michael@0: } michael@0: dataL[0] = 1; michael@0: michael@0: return audioBuffer; michael@0: } michael@0: michael@0: // Create a buffer of the given length with a linear ramp having values 0 <= x < 1. michael@0: function createLinearRampBuffer(context, sampleFrameLength) { michael@0: var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate); michael@0: var n = audioBuffer.length; michael@0: var dataL = audioBuffer.getChannelData(0); michael@0: michael@0: for (var i = 0; i < n; ++i) michael@0: dataL[i] = i / n; michael@0: michael@0: return audioBuffer; michael@0: } michael@0: michael@0: // Create a buffer of the given length having a constant value. michael@0: function createConstantBuffer(context, sampleFrameLength, constantValue) { michael@0: var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate); michael@0: var n = audioBuffer.length; michael@0: var dataL = audioBuffer.getChannelData(0); michael@0: michael@0: for (var i = 0; i < n; ++i) michael@0: dataL[i] = constantValue; michael@0: michael@0: return audioBuffer; michael@0: } michael@0: michael@0: // Create a stereo impulse in a buffer of length sampleFrameLength michael@0: function createStereoImpulseBuffer(context, sampleFrameLength) { michael@0: var audioBuffer = context.createBuffer(2, sampleFrameLength, context.sampleRate); michael@0: var n = audioBuffer.length; michael@0: var dataL = audioBuffer.getChannelData(0); michael@0: var dataR = audioBuffer.getChannelData(1); michael@0: michael@0: for (var k = 0; k < n; ++k) { michael@0: dataL[k] = 0; michael@0: dataR[k] = 0; michael@0: } michael@0: dataL[0] = 1; michael@0: dataR[0] = 1; michael@0: michael@0: return audioBuffer; michael@0: } michael@0: michael@0: // Convert time (in seconds) to sample frames. michael@0: function timeToSampleFrame(time, sampleRate) { michael@0: return Math.floor(0.5 + time * sampleRate); michael@0: } michael@0: michael@0: // Compute the number of sample frames consumed by start with michael@0: // the specified |grainOffset|, |duration|, and |sampleRate|. michael@0: function grainLengthInSampleFrames(grainOffset, duration, sampleRate) { michael@0: var startFrame = timeToSampleFrame(grainOffset, sampleRate); michael@0: var endFrame = timeToSampleFrame(grainOffset + duration, sampleRate); michael@0: michael@0: return endFrame - startFrame; michael@0: } michael@0: michael@0: // True if the number is not an infinity or NaN michael@0: function isValidNumber(x) { michael@0: return !isNaN(x) && (x != Infinity) && (x != -Infinity); michael@0: } michael@0: michael@0: function shouldThrowTypeError(func, text) { michael@0: var ok = false; michael@0: try { michael@0: func(); michael@0: } catch (e) { michael@0: if (e instanceof TypeError) { michael@0: ok = true; michael@0: } michael@0: } michael@0: if (ok) { michael@0: testPassed(text + " threw TypeError."); michael@0: } else { michael@0: testFailed(text + " should throw TypeError."); michael@0: } michael@0: }