Javascript:从 Int16 转换为 Float32
Javascript: Converting from Int16 to Float32
我正在尝试将 WAV 文件放入 AudioBuffer 中,以便我可以对其进行操作。我之前从 AudioBuffer 创建了 WAV 文件,这需要将 Float32Array 转换为包含 Int16 值的 DataView。我使用了这个方便的功能:
function floatTo16BitPCM(output, offset, input){
for (var i = 0; i < input.length; i++, offset+=2){
var s = Math.max(-1, Math.min(1, input[i]));
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
}
好吧,我现在需要做的就是反转这个(WAV文件是从服务器加载的,所以我没有原始数据了)。我无法弄清楚该函数中实际发生了什么或数据是如何转换的。
数组输入的每个实数数据都缩减到区间[-1, 1]
- Math.min(1, x) 如果 x<=1 则给出 x,否则给出 1
- Math.max(-1, y) 如果 y>=-1 则给出 y,否则给出 -1
然后将这个介于-1和1之间的实数转换为有符号的16位整数。
无论是正数还是负数乘以32767或-32768,都只保留整数部分。这相当于在二进制表示中只保留小数点后16位有效位。
16位整数以little Endian的方式存储在buffer中的两个字节,一个接一个(按照二进二进的偏移量)
对于反向操作,只需将两个连续的字节放入一个int16 中即可。转换成真正区分符号后的两种情况和除以32768或32767。但是操作会丢失数据。
这似乎有效。我在响应类型为 "arraybuffer" 的 ajax 调用中加载数据。否则,响应最终会变成一个字符串,使用起来会很麻烦。然后我转换为 16 位数组。然后我以与 WAV 编码一起使用的方式将其转换为 Float32 数组。我还需要丢弃 WAV 的 header,以及它末尾的一些元数据。
// These are ready to be copied into an AudioBufferSourceNode's channel data.
var theWavDataInFloat32;
function floatTo16Bit(inputArray, startIndex){
var output = new Uint16Array(inputArray.length-startIndex);
for (var i = 0; i < inputArray.length; i++){
var s = Math.max(-1, Math.min(1, inputArray[i]));
output[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
}
return output;
}
// This is passed in an unsigned 16-bit integer array. It is converted to a 32-bit float array.
// The first startIndex items are skipped, and only 'length' number of items is converted.
function int16ToFloat32(inputArray, startIndex, length) {
var output = new Float32Array(inputArray.length-startIndex);
for (var i = startIndex; i < length; i++) {
var int = inputArray[i];
// If the high bit is on, then it is a negative number, and actually counts backwards.
var float = (int >= 0x8000) ? -(0x10000 - int) / 0x8000 : int / 0x7FFF;
output[i] = float;
}
return output;
}
// TEST
var data = [ 65424, 18, 0, 32700, 33000, 1000, 50000 ];
var testDataInt = new Uint16Array(data);
var testDataFloat = int16ToFloat32(testDataInt, 0, data.length);
var testDataInt2 = floatTo16Bit(testDataFloat, 0);
// At this point testDataInt2 should be pretty close to the original data array (there is a little rounding.)
var xhr = new XMLHttpRequest();
xhr.open('GET', '/my-sound.wav', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if (this.status === 200) {
// This retrieves the entire wav file. We're only interested in the data portion.
// At the beginning is 44 bytes (22 words) of header, and at the end is some metadata about the file.
// The actual data length is held in bytes 40 - 44.
var data = new Uint16Array(this.response);
var length = (data[20] + data[21] * 0x10000) / 2; // The length is in bytes, but the array is 16 bits, so divide by 2.
theWavDataInFloat32 = int16ToFloat32(data, 22, length);
}
};
xhr.send();
我正在尝试将 WAV 文件放入 AudioBuffer 中,以便我可以对其进行操作。我之前从 AudioBuffer 创建了 WAV 文件,这需要将 Float32Array 转换为包含 Int16 值的 DataView。我使用了这个方便的功能:
function floatTo16BitPCM(output, offset, input){
for (var i = 0; i < input.length; i++, offset+=2){
var s = Math.max(-1, Math.min(1, input[i]));
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
}
好吧,我现在需要做的就是反转这个(WAV文件是从服务器加载的,所以我没有原始数据了)。我无法弄清楚该函数中实际发生了什么或数据是如何转换的。
数组输入的每个实数数据都缩减到区间[-1, 1]
- Math.min(1, x) 如果 x<=1 则给出 x,否则给出 1
- Math.max(-1, y) 如果 y>=-1 则给出 y,否则给出 -1
然后将这个介于-1和1之间的实数转换为有符号的16位整数。
无论是正数还是负数乘以32767或-32768,都只保留整数部分。这相当于在二进制表示中只保留小数点后16位有效位。
16位整数以little Endian的方式存储在buffer中的两个字节,一个接一个(按照二进二进的偏移量)
对于反向操作,只需将两个连续的字节放入一个int16 中即可。转换成真正区分符号后的两种情况和除以32768或32767。但是操作会丢失数据。
这似乎有效。我在响应类型为 "arraybuffer" 的 ajax 调用中加载数据。否则,响应最终会变成一个字符串,使用起来会很麻烦。然后我转换为 16 位数组。然后我以与 WAV 编码一起使用的方式将其转换为 Float32 数组。我还需要丢弃 WAV 的 header,以及它末尾的一些元数据。
// These are ready to be copied into an AudioBufferSourceNode's channel data.
var theWavDataInFloat32;
function floatTo16Bit(inputArray, startIndex){
var output = new Uint16Array(inputArray.length-startIndex);
for (var i = 0; i < inputArray.length; i++){
var s = Math.max(-1, Math.min(1, inputArray[i]));
output[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
}
return output;
}
// This is passed in an unsigned 16-bit integer array. It is converted to a 32-bit float array.
// The first startIndex items are skipped, and only 'length' number of items is converted.
function int16ToFloat32(inputArray, startIndex, length) {
var output = new Float32Array(inputArray.length-startIndex);
for (var i = startIndex; i < length; i++) {
var int = inputArray[i];
// If the high bit is on, then it is a negative number, and actually counts backwards.
var float = (int >= 0x8000) ? -(0x10000 - int) / 0x8000 : int / 0x7FFF;
output[i] = float;
}
return output;
}
// TEST
var data = [ 65424, 18, 0, 32700, 33000, 1000, 50000 ];
var testDataInt = new Uint16Array(data);
var testDataFloat = int16ToFloat32(testDataInt, 0, data.length);
var testDataInt2 = floatTo16Bit(testDataFloat, 0);
// At this point testDataInt2 should be pretty close to the original data array (there is a little rounding.)
var xhr = new XMLHttpRequest();
xhr.open('GET', '/my-sound.wav', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if (this.status === 200) {
// This retrieves the entire wav file. We're only interested in the data portion.
// At the beginning is 44 bytes (22 words) of header, and at the end is some metadata about the file.
// The actual data length is held in bytes 40 - 44.
var data = new Uint16Array(this.response);
var length = (data[20] + data[21] * 0x10000) / 2; // The length is in bytes, but the array is 16 bits, so divide by 2.
theWavDataInFloat32 = int16ToFloat32(data, 22, length);
}
};
xhr.send();