clean up WavAdapter
This commit is contained in:
parent
e2def5f88b
commit
5a051024e6
|
@ -32,7 +32,7 @@ export class WavAdapter extends RecordingAdapter {
|
||||||
_audioSource = null;
|
_audioSource = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Length of the WAVE file, in units of {@code sizeof(Float32)}.
|
* Length of the WAVE file, in number of samples.
|
||||||
*/
|
*/
|
||||||
_wavLength = 0;
|
_wavLength = 0;
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ export class WavAdapter extends RecordingAdapter {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._saveWavPCM = this._saveWavPCM.bind(this);
|
this._onReceivePCM = this._onReceivePCM.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,7 +73,6 @@ export class WavAdapter extends RecordingAdapter {
|
||||||
return this._initPromise.then(() => {
|
return this._initPromise.then(() => {
|
||||||
this._wavBuffers = [];
|
this._wavBuffers = [];
|
||||||
this._wavLength = 0;
|
this._wavLength = 0;
|
||||||
this._wavBuffers.push(this._createWavHeader());
|
|
||||||
|
|
||||||
this._audioSource.connect(this._audioProcessingNode);
|
this._audioSource.connect(this._audioProcessingNode);
|
||||||
this._audioProcessingNode
|
this._audioProcessingNode
|
||||||
|
@ -180,9 +179,10 @@ export class WavAdapter extends RecordingAdapter {
|
||||||
* Creates a WAVE file header.
|
* Creates a WAVE file header.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
|
* @param {number} dataLength - Length of the payload (PCM data), in bytes.
|
||||||
* @returns {Uint8Array}
|
* @returns {Uint8Array}
|
||||||
*/
|
*/
|
||||||
_createWavHeader() {
|
_createWavHeader(dataLength) {
|
||||||
// adapted from
|
// adapted from
|
||||||
// https://github.com/mmig/speech-to-flac/blob/master/encoder.js
|
// https://github.com/mmig/speech-to-flac/blob/master/encoder.js
|
||||||
|
|
||||||
|
@ -221,11 +221,11 @@ export class WavAdapter extends RecordingAdapter {
|
||||||
// data sub-chunk
|
// data sub-chunk
|
||||||
writeUTFBytes(view, 36, 'data');
|
writeUTFBytes(view, 36, 'data');
|
||||||
|
|
||||||
// DUMMY file length (set real value on export)
|
// file length
|
||||||
view.setUint32(4, 10, true);
|
view.setUint32(4, 32 + dataLength, true);
|
||||||
|
|
||||||
// DUMMY data chunk length (set real value on export)
|
// data chunk length
|
||||||
view.setUint32(40, 10, true);
|
view.setUint32(40, dataLength, true);
|
||||||
|
|
||||||
return new Uint8Array(buffer);
|
return new Uint8Array(buffer);
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,7 @@ export class WavAdapter extends RecordingAdapter {
|
||||||
// See: https://developer.mozilla.org/en-US/docs/Web/API/
|
// See: https://developer.mozilla.org/en-US/docs/Web/API/
|
||||||
// AudioBuffer/getChannelData
|
// AudioBuffer/getChannelData
|
||||||
// The returned value is an Float32Array.
|
// The returned value is an Float32Array.
|
||||||
this._saveWavPCM(channelLeft);
|
this._onReceivePCM(channelLeft);
|
||||||
};
|
};
|
||||||
this._isInitialized = true;
|
this._isInitialized = true;
|
||||||
resolve();
|
resolve();
|
||||||
|
@ -280,7 +280,7 @@ export class WavAdapter extends RecordingAdapter {
|
||||||
* @param {Float32Array} data - The audio PCM data.
|
* @param {Float32Array} data - The audio PCM data.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_saveWavPCM(data) {
|
_onReceivePCM(data) {
|
||||||
// Need to copy the Float32Array:
|
// Need to copy the Float32Array:
|
||||||
// unlike passing to WebWorker, this data is passed by reference,
|
// unlike passing to WebWorker, this data is passed by reference,
|
||||||
// so we need to copy it, otherwise the resulting audio file will be
|
// so we need to copy it, otherwise the resulting audio file will be
|
||||||
|
@ -293,35 +293,23 @@ export class WavAdapter extends RecordingAdapter {
|
||||||
* Combines buffers and export to a wav file.
|
* Combines buffers and export to a wav file.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {*} buffers - The stored buffers.
|
* @param {Float32Array[]} buffers - The stored buffers.
|
||||||
* @param {*} length - Total length (number of samples).
|
* @param {number} length - Total length (number of samples).
|
||||||
* @returns {Blob}
|
* @returns {Blob}
|
||||||
*/
|
*/
|
||||||
_exportMonoWAV(buffers, length) {
|
_exportMonoWAV(buffers, length) {
|
||||||
// buffers: array with
|
|
||||||
// buffers[0] = header information (with missing length information)
|
|
||||||
// buffers[1] = Float32Array object (audio data)
|
|
||||||
// ...
|
|
||||||
// buffers[n] = Float32Array object (audio data)
|
|
||||||
|
|
||||||
const dataLength = length * 2; // each sample = 16 bit = 2 bytes
|
const dataLength = length * 2; // each sample = 16 bit = 2 bytes
|
||||||
const buffer = new ArrayBuffer(44 + dataLength);
|
const buffer = new ArrayBuffer(44 + dataLength);
|
||||||
const view = new DataView(buffer);
|
const view = new DataView(buffer);
|
||||||
|
|
||||||
// copy WAV header data into the array buffer
|
// copy WAV header data into the array buffer
|
||||||
const header = buffers[0];
|
const header = this._createWavHeader(dataLength);
|
||||||
const len = header.length;
|
const len = header.length;
|
||||||
|
|
||||||
for (let i = 0; i < len; ++i) {
|
for (let i = 0; i < len; ++i) {
|
||||||
view.setUint8(i, header[i]);
|
view.setUint8(i, header[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add file length in header
|
|
||||||
view.setUint32(4, 32 + dataLength, true);
|
|
||||||
|
|
||||||
// add data chunk length in header
|
|
||||||
view.setUint32(40, dataLength, true);
|
|
||||||
|
|
||||||
// write audio data
|
// write audio data
|
||||||
floatTo16BitPCM(view, 44, buffers);
|
floatTo16BitPCM(view, 44, buffers);
|
||||||
|
|
||||||
|
@ -358,17 +346,16 @@ function writeUTFBytes(view, offset, string) {
|
||||||
*/
|
*/
|
||||||
function floatTo16BitPCM(output, offset, inputBuffers) {
|
function floatTo16BitPCM(output, offset, inputBuffers) {
|
||||||
|
|
||||||
let i, input, isize, s;
|
let i, j;
|
||||||
const jsize = inputBuffers.length;
|
let input, s, sampleCount;
|
||||||
|
const bufferCount = inputBuffers.length;
|
||||||
let o = offset;
|
let o = offset;
|
||||||
|
|
||||||
// first entry is header information (already used in exportMonoWAV),
|
for (i = 0; i < bufferCount; ++i) {
|
||||||
// rest is Float32Array-entries -> ignore header entry
|
input = inputBuffers[i];
|
||||||
for (let j = 1; j < jsize; ++j) {
|
sampleCount = input.length;
|
||||||
input = inputBuffers[j];
|
for (j = 0; j < sampleCount; ++j, o += 2) {
|
||||||
isize = input.length;
|
s = Math.max(-1, Math.min(1, input[j]));
|
||||||
for (i = 0; i < isize; ++i, o += 2) {
|
|
||||||
s = Math.max(-1, Math.min(1, input[i]));
|
|
||||||
output.setInt16(o, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
|
output.setInt16(o, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue