Commit 649bf910 authored by Raymond Toy's avatar Raymond Toy Committed by Commit Bot

Move WAV creation utilities to separate file

Everything related to creating a WAV file from an AudioBuffer is moved
from audit-util.js to a new file.

Every test depending on these utilities now needs to import this
script.

No functional changes.

Bug: 776110
Change-Id: Ib3d4ddd4bc3fe5e743dd5c3f7b758b6f57940e7d
Reviewed-on: https://chromium-review.googlesource.com/726947Reviewed-by: default avatarHongchan Choi <hongchan@chromium.org>
Commit-Queue: Raymond Toy <rtoy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#512954}
parent b8bdebfd
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<script src="../resources/audit.js"></script> <script src="../resources/audit.js"></script>
<script src="../resources/audiobuffersource-testing.js"></script> <script src="../resources/audiobuffersource-testing.js"></script>
<script src="../resources/buffer-loader.js"></script> <script src="../resources/buffer-loader.js"></script>
<script src="../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<script src="../resources/audit.js"></script> <script src="../resources/audit.js"></script>
<script src="../resources/audiobuffersource-testing.js"></script> <script src="../resources/audiobuffersource-testing.js"></script>
<script src="../resources/buffer-loader.js"></script> <script src="../resources/buffer-loader.js"></script>
<script src="../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<script src="../resources/audit.js"></script> <script src="../resources/audit.js"></script>
<script src="../resources/buffer-loader.js"></script> <script src="../resources/buffer-loader.js"></script>
<script src="../resources/oscillator-testing.js"></script> <script src="../resources/oscillator-testing.js"></script>
<script src="../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<script src="../resources/audit.js"></script> <script src="../resources/audit.js"></script>
<script src="../resources/buffer-loader.js"></script> <script src="../resources/buffer-loader.js"></script>
<script src="../resources/oscillator-testing.js"></script> <script src="../resources/oscillator-testing.js"></script>
<script src="../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<script src="../resources/audit.js"></script> <script src="../resources/audit.js"></script>
<script src="../resources/buffer-loader.js"></script> <script src="../resources/buffer-loader.js"></script>
<script src="../resources/oscillator-testing.js"></script> <script src="../resources/oscillator-testing.js"></script>
<script src="../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<script src="../resources/audit.js"></script> <script src="../resources/audit.js"></script>
<script src="../resources/buffer-loader.js"></script> <script src="../resources/buffer-loader.js"></script>
<script src="../resources/oscillator-testing.js"></script> <script src="../resources/oscillator-testing.js"></script>
<script src="../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<script src="../resources/audit.js"></script> <script src="../resources/audit.js"></script>
<script src="../resources/buffer-loader.js"></script> <script src="../resources/buffer-loader.js"></script>
<script src="../resources/oscillator-testing.js"></script> <script src="../resources/oscillator-testing.js"></script>
<script src="../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<script src="../resources/audit.js"></script> <script src="../resources/audit.js"></script>
<script src="../resources/buffer-loader.js"></script> <script src="../resources/buffer-loader.js"></script>
<script src="../resources/oscillator-testing.js"></script> <script src="../resources/oscillator-testing.js"></script>
<script src="../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
<script src="../../resources/audit-util.js"></script> <script src="../../resources/audit-util.js"></script>
<script src="../../resources/buffer-loader.js"></script> <script src="../../resources/buffer-loader.js"></script>
<script src="../../resources/audio-codec-test.js"></script> <script src="../../resources/audio-codec-test.js"></script>
<script src="../../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<script src="../../resources/audio-codec-test.js"></script> <script src="../../resources/audio-codec-test.js"></script>
<script src="../../resources/audit-util.js"></script> <script src="../../resources/audit-util.js"></script>
<script src="../../resources/buffer-loader.js"></script> <script src="../../resources/buffer-loader.js"></script>
<script src="../../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<script src="../../resources/audio-codec-test.js"></script> <script src="../../resources/audio-codec-test.js"></script>
<script src="../../resources/audit-util.js"></script> <script src="../../resources/audit-util.js"></script>
<script src="../../resources/buffer-loader.js"></script> <script src="../../resources/buffer-loader.js"></script>
<script src="../../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<script src="../../resources/audio-codec-test.js"></script> <script src="../../resources/audio-codec-test.js"></script>
<script src="../../resources/audit-util.js"></script> <script src="../../resources/audit-util.js"></script>
<script src="../../resources/buffer-loader.js"></script> <script src="../../resources/buffer-loader.js"></script>
<script src="../../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<script src="../../resources/audio-codec-test.js"></script> <script src="../../resources/audio-codec-test.js"></script>
<script src="../../resources/audit-util.js"></script> <script src="../../resources/audit-util.js"></script>
<script src="../../resources/buffer-loader.js"></script> <script src="../../resources/buffer-loader.js"></script>
<script src="../../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<script src="../../resources/audio-codec-test.js"></script> <script src="../../resources/audio-codec-test.js"></script>
<script src="../../resources/audit-util.js"></script> <script src="../../resources/audit-util.js"></script>
<script src="../../resources/buffer-loader.js"></script> <script src="../../resources/buffer-loader.js"></script>
<script src="../../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<script src="../../resources/audio-codec-test.js"></script> <script src="../../resources/audio-codec-test.js"></script>
<script src="../../resources/audit-util.js"></script> <script src="../../resources/audit-util.js"></script>
<script src="../../resources/buffer-loader.js"></script> <script src="../../resources/buffer-loader.js"></script>
<script src="../../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
</title> </title>
<script src="../../resources/audio-codec-test.js"></script> <script src="../../resources/audio-codec-test.js"></script>
<script src="../../resources/audit-util.js"></script> <script src="../../resources/audit-util.js"></script>
<script src="../../resources/audio-file-utils.js"></script>
<script src="../../resources/buffer-loader.js"></script> <script src="../../resources/buffer-loader.js"></script>
</head> </head>
<body> <body>
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<script src="../../resources/audio-codec-test.js"></script> <script src="../../resources/audio-codec-test.js"></script>
<script src="../../resources/audit-util.js"></script> <script src="../../resources/audit-util.js"></script>
<script src="../../resources/buffer-loader.js"></script> <script src="../../resources/buffer-loader.js"></script>
<script src="../../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<script src="../../resources/audio-codec-test.js"></script> <script src="../../resources/audio-codec-test.js"></script>
<script src="../../resources/audit-util.js"></script> <script src="../../resources/audit-util.js"></script>
<script src="../../resources/buffer-loader.js"></script> <script src="../../resources/buffer-loader.js"></script>
<script src="../../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<script src="../../resources/audio-codec-test.js"></script> <script src="../../resources/audio-codec-test.js"></script>
<script src="../../resources/audit-util.js"></script> <script src="../../resources/audit-util.js"></script>
<script src="../../resources/buffer-loader.js"></script> <script src="../../resources/buffer-loader.js"></script>
<script src="../../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
<script src="../../resources/audit-util.js"></script> <script src="../../resources/audit-util.js"></script>
<script src="../../resources/audit.js"></script> <script src="../../resources/audit.js"></script>
<script src="../../resources/buffer-loader.js"></script> <script src="../../resources/buffer-loader.js"></script>
<script src="../../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
...@@ -10,6 +10,7 @@ See if we can load an AudioBuffer, create an AudioBufferSourceNode, attach the b ...@@ -10,6 +10,7 @@ See if we can load an AudioBuffer, create an AudioBufferSourceNode, attach the b
<script src="../../resources/js-test.js"></script> <script src="../../resources/js-test.js"></script>
<script src="../resources/audit-util.js"></script> <script src="../resources/audit-util.js"></script>
<script src="../resources/buffer-loader.js"></script> <script src="../resources/buffer-loader.js"></script>
<script src="../resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
// Utilities for creating a 16-bit PCM WAV file from an AudioBuffer
// when using Chrome testRunner, and for downloading an AudioBuffer as
// a float WAV file when running in a browser.
function writeString(s, a, offset) {
for (let i = 0; i < s.length; ++i) {
a[offset + i] = s.charCodeAt(i);
}
}
function writeInt16(n, a, offset) {
n = Math.floor(n);
let b1 = n & 255;
let b2 = (n >> 8) & 255;
a[offset + 0] = b1;
a[offset + 1] = b2;
}
function writeInt32(n, a, offset) {
n = Math.floor(n);
let b1 = n & 255;
let b2 = (n >> 8) & 255;
let b3 = (n >> 16) & 255;
let b4 = (n >> 24) & 255;
a[offset + 0] = b1;
a[offset + 1] = b2;
a[offset + 2] = b3;
a[offset + 3] = b4;
}
// Return the bits of the float as a 32-bit integer value. This
// produces the raw bits; no intepretation of the value is done.
function floatBits(f) {
let buf = new ArrayBuffer(4);
(new Float32Array(buf))[0] = f;
let bits = (new Uint32Array(buf))[0];
// Return as a signed integer.
return bits | 0;
}
function writeAudioBuffer(audioBuffer, a, offset, asFloat) {
let n = audioBuffer.length;
let channels = audioBuffer.numberOfChannels;
for (let i = 0; i < n; ++i) {
for (let k = 0; k < channels; ++k) {
let buffer = audioBuffer.getChannelData(k);
if (asFloat) {
let sample = floatBits(buffer[i]);
writeInt32(sample, a, offset);
offset += 4;
} else {
let sample = buffer[i] * 32768.0;
// Clip samples to the limitations of 16-bit.
// If we don't do this then we'll get nasty wrap-around distortion.
if (sample < -32768)
sample = -32768;
if (sample > 32767)
sample = 32767;
writeInt16(sample, a, offset);
offset += 2;
}
}
}
}
// See http://soundfile.sapp.org/doc/WaveFormat/ and
// http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
// for a quick introduction to the WAVE PCM format.
function createWaveFileData(audioBuffer, asFloat) {
let bytesPerSample = asFloat ? 4 : 2;
let frameLength = audioBuffer.length;
let numberOfChannels = audioBuffer.numberOfChannels;
let sampleRate = audioBuffer.sampleRate;
let bitsPerSample = 8 * bytesPerSample;
let byteRate = sampleRate * numberOfChannels * bitsPerSample / 8;
let blockAlign = numberOfChannels * bitsPerSample / 8;
let wavDataByteLength = frameLength * numberOfChannels * bytesPerSample;
let headerByteLength = 44;
let totalLength = headerByteLength + wavDataByteLength;
let waveFileData = new Uint8Array(totalLength);
let subChunk1Size = 16; // for linear PCM
let subChunk2Size = wavDataByteLength;
let chunkSize = 4 + (8 + subChunk1Size) + (8 + subChunk2Size);
writeString('RIFF', waveFileData, 0);
writeInt32(chunkSize, waveFileData, 4);
writeString('WAVE', waveFileData, 8);
writeString('fmt ', waveFileData, 12);
writeInt32(subChunk1Size, waveFileData, 16); // SubChunk1Size (4)
// The format tag value is 1 for integer PCM data and 3 for IEEE
// float data.
writeInt16(asFloat ? 3 : 1, waveFileData, 20); // AudioFormat (2)
writeInt16(numberOfChannels, waveFileData, 22); // NumChannels (2)
writeInt32(sampleRate, waveFileData, 24); // SampleRate (4)
writeInt32(byteRate, waveFileData, 28); // ByteRate (4)
writeInt16(blockAlign, waveFileData, 32); // BlockAlign (2)
writeInt32(bitsPerSample, waveFileData, 34); // BitsPerSample (4)
writeString('data', waveFileData, 36);
writeInt32(subChunk2Size, waveFileData, 40); // SubChunk2Size (4)
// Write actual audio data starting at offset 44.
writeAudioBuffer(audioBuffer, waveFileData, 44, asFloat);
return waveFileData;
}
function createAudioData(audioBuffer, asFloat) {
return createWaveFileData(audioBuffer, asFloat);
}
function finishAudioTest(event) {
let audioData = createAudioData(event.renderedBuffer);
testRunner.setAudioData(audioData);
testRunner.notifyDone();
}
// Save the given |audioBuffer| to a WAV file using the name given by
// |filename|. This is intended to be run from a browser. The
// developer is expected to use the console to run downloadAudioBuffer
// when necessary to create a new reference file for a test. If
// |asFloat| is given and is true, the WAV file produced uses 32-bit
// float format (full WebAudio resolution). Otherwise a 16-bit PCM
// WAV file is produced.
function downloadAudioBuffer(audioBuffer, filename, asFloat) {
// Don't download if testRunner is defined; we're running a layout
// test where this won't be useful in general.
if (window.testRunner)
return false;
// Convert the audio buffer to an array containing the WAV file
// contents. Then convert it to a blob that can be saved as a WAV
// file.
let wavData = createAudioData(audioBuffer, asFloat);
let blob = new Blob([wavData], {type: 'audio/wav'});
// Manually create html tags for downloading, and simulate a click
// to download the file to the given file name.
let a = document.createElement('a');
a.style.display = 'none';
a.download = filename;
let audioURL = window.URL.createObjectURL(blob);
let audio = new Audio();
audio.src = audioURL;
a.href = audioURL;
document.body.appendChild(a);
a.click();
return true;
}
...@@ -11,159 +11,6 @@ ...@@ -11,159 +11,6 @@
// How many frames in a WebAudio render quantum. // How many frames in a WebAudio render quantum.
let RENDER_QUANTUM_FRAMES = 128; let RENDER_QUANTUM_FRAMES = 128;
function writeString(s, a, offset) {
for (let i = 0; i < s.length; ++i) {
a[offset + i] = s.charCodeAt(i);
}
}
function writeInt16(n, a, offset) {
n = Math.floor(n);
let b1 = n & 255;
let b2 = (n >> 8) & 255;
a[offset + 0] = b1;
a[offset + 1] = b2;
}
function writeInt32(n, a, offset) {
n = Math.floor(n);
let b1 = n & 255;
let b2 = (n >> 8) & 255;
let b3 = (n >> 16) & 255;
let b4 = (n >> 24) & 255;
a[offset + 0] = b1;
a[offset + 1] = b2;
a[offset + 2] = b3;
a[offset + 3] = b4;
}
// Return the bits of the float as a 32-bit integer value. This
// produces the raw bits; no intepretation of the value is done.
function floatBits(f) {
let buf = new ArrayBuffer(4);
(new Float32Array(buf))[0] = f;
let bits = (new Uint32Array(buf))[0];
// Return as a signed integer.
return bits | 0;
}
function writeAudioBuffer(audioBuffer, a, offset, asFloat) {
let n = audioBuffer.length;
let channels = audioBuffer.numberOfChannels;
for (let i = 0; i < n; ++i) {
for (let k = 0; k < channels; ++k) {
let buffer = audioBuffer.getChannelData(k);
if (asFloat) {
let sample = floatBits(buffer[i]);
writeInt32(sample, a, offset);
offset += 4;
} else {
let sample = buffer[i] * 32768.0;
// Clip samples to the limitations of 16-bit.
// If we don't do this then we'll get nasty wrap-around distortion.
if (sample < -32768)
sample = -32768;
if (sample > 32767)
sample = 32767;
writeInt16(sample, a, offset);
offset += 2;
}
}
}
}
// See http://soundfile.sapp.org/doc/WaveFormat/ and
// http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
// for a quick introduction to the WAVE PCM format.
function createWaveFileData(audioBuffer, asFloat) {
let bytesPerSample = asFloat ? 4 : 2;
let frameLength = audioBuffer.length;
let numberOfChannels = audioBuffer.numberOfChannels;
let sampleRate = audioBuffer.sampleRate;
let bitsPerSample = 8 * bytesPerSample;
let byteRate = sampleRate * numberOfChannels * bitsPerSample / 8;
let blockAlign = numberOfChannels * bitsPerSample / 8;
let wavDataByteLength = frameLength * numberOfChannels * bytesPerSample;
let headerByteLength = 44;
let totalLength = headerByteLength + wavDataByteLength;
let waveFileData = new Uint8Array(totalLength);
let subChunk1Size = 16; // for linear PCM
let subChunk2Size = wavDataByteLength;
let chunkSize = 4 + (8 + subChunk1Size) + (8 + subChunk2Size);
writeString('RIFF', waveFileData, 0);
writeInt32(chunkSize, waveFileData, 4);
writeString('WAVE', waveFileData, 8);
writeString('fmt ', waveFileData, 12);
writeInt32(subChunk1Size, waveFileData, 16); // SubChunk1Size (4)
// The format tag value is 1 for integer PCM data and 3 for IEEE
// float data.
writeInt16(asFloat ? 3 : 1, waveFileData, 20); // AudioFormat (2)
writeInt16(numberOfChannels, waveFileData, 22); // NumChannels (2)
writeInt32(sampleRate, waveFileData, 24); // SampleRate (4)
writeInt32(byteRate, waveFileData, 28); // ByteRate (4)
writeInt16(blockAlign, waveFileData, 32); // BlockAlign (2)
writeInt32(bitsPerSample, waveFileData, 34); // BitsPerSample (4)
writeString('data', waveFileData, 36);
writeInt32(subChunk2Size, waveFileData, 40); // SubChunk2Size (4)
// Write actual audio data starting at offset 44.
writeAudioBuffer(audioBuffer, waveFileData, 44, asFloat);
return waveFileData;
}
function createAudioData(audioBuffer, asFloat) {
return createWaveFileData(audioBuffer, asFloat);
}
function finishAudioTest(event) {
let audioData = createAudioData(event.renderedBuffer);
testRunner.setAudioData(audioData);
testRunner.notifyDone();
}
// Save the given |audioBuffer| to a WAV file using the name given by
// |filename|. This is intended to be run from a browser. The
// developer is expected to use the console to run downloadAudioBuffer
// when necessary to create a new reference file for a test. If
// |asFloat| is given and is true, the WAV file produced uses 32-bit
// float format (full WebAudio resolution). Otherwise a 16-bit PCM
// WAV file is produced.
function downloadAudioBuffer(audioBuffer, filename, asFloat) {
// Don't download if testRunner is defined; we're running a layout
// test where this won't be useful in general.
if (window.testRunner)
return false;
// Convert the audio buffer to an array containing the WAV file
// contents. Then convert it to a blob that can be saved as a WAV
// file.
let wavData = createAudioData(audioBuffer, asFloat);
let blob = new Blob([wavData], {type: 'audio/wav'});
// Manually create html tags for downloading, and simulate a click
// to download the file to the given file name.
let a = document.createElement('a');
a.style.display = 'none';
a.download = filename;
let audioURL = window.URL.createObjectURL(blob);
let audio = new Audio();
audio.src = audioURL;
a.href = audioURL;
document.body.appendChild(a);
a.click();
return true;
}
// Compare two arrays (commonly extracted from buffer.getChannelData()) with // Compare two arrays (commonly extracted from buffer.getChannelData()) with
// constraints: // constraints:
// options.thresholdSNR: Minimum allowed SNR between the actual and expected // options.thresholdSNR: Minimum allowed SNR between the actual and expected
......
...@@ -13,6 +13,7 @@ The left channel will be a 880Hz tone, while the right will be 440Hz. ...@@ -13,6 +13,7 @@ The left channel will be a 880Hz tone, while the right will be 440Hz.
<script src="../resources/testharnessreport.js"></script> <script src="../resources/testharnessreport.js"></script>
<script src="resources/audit-util.js"></script> <script src="resources/audit-util.js"></script>
<script src="resources/audit.js"></script> <script src="resources/audit.js"></script>
<script src="resources/audio-file-utils.js"></script>
</head> </head>
<body> <body>
<script id="layout-test-code"> <script id="layout-test-code">
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment