1

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 ファイルはサーバーから読み込まれるため、元のデータはもうありません)。その関数で実際に何が起こっているのか、データがどのように変換されているのかわかりません。

4

2 に答える 2

8

これがうまくいくと思われるものです。応答タイプ「arraybuffer」を使用して ajax 呼び出しでデータをロードします。そうしないと、応答が文字列になってしまい、処理が面倒になります。次に、16 ビット配列に変換します。次に、WAV エンコーディングで動作する方法で、それを Float32 配列に変換します。また、WAV のヘッダーと、その末尾にあるいくつかのメタデータも破棄する必要がありました。

// 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();
于 2016-02-07T01:56:07.773 に答える
0

配列入力の各実数データは [-1, 1] の間隔に縮小されます

  • Math.min(1, x) は、x<=1 の場合は x を返し、それ以外の場合は 1 を返します。
  • Math.max(-1, y) は、y>=-1 の場合は y を返し、それ以外の場合は -1 を返します。

次に、この -1 ~ 1 の実数が符号付き 16 ビット整数に変換されます。

正または負に 32767 または -32768 を掛けたものであるかどうかに関係なく、キャストによって整数部分のみが保持されます。これは、2 進数表現で小数点以下 16 ビットのみを保持することと同じです。

16 ビット整数は、バッファ内の 2 バイトのリトル エンディアンで (2 を 2 に進めるオフセットに従って) 次々に格納されます。

逆の操作を行うには、単に int16 に連続する 2 バイトを配置します。それを実数に変換するには、符号に続いて 32768 または 32767 で割る 2 つのケースを区別します。ただし、操作はデータの損失で行われます。

于 2016-02-05T23:03:25.267 に答える