【问题标题】:Converting Float32Array to Uint8Array while Preserving IEEE 754 Representation在保留 IEEE 754 表示的同时将 Float32Array 转换为 Uint8Array
【发布时间】:2018-03-20 07:35:50
【问题描述】:

我有一个来自 decodeAudioData 方法的 float32Array,我想将它转换为 Uint8Array,同时保留 float32 IEEE 754 音频数据

到目前为止我试过了,

var length = float32Array.length;

var emptyBuffer = new ArrayBuffer(length * 4);
var view = new DataView(emptyBuffer);

for (var i = 0; i < length; i++) {
  view.setFloat32(i * 4, float32Array[i], true);
}

var outputArray = new Uint8Array(length);

for (var j = 0; j < length; j++) {
  outputArray[j] = view.getUint8(j * 4);
}

return outputArray;

编辑:

我只需要保留二进制表示,就像在 answer. 中一样

【问题讨论】:

  • 为什么不将Uint8Array 映射到同一个缓冲区?那么你就不必复制任何东西了。
  • 你也没有真正描述你的代码有什么问题。出了什么问题?是否报告了错误?
  • @Pointy 你能多解释一下映射吗?以这种方式保留 IEEE 754 表示是否可行?
  • 如果您可以在输入和输出数组中添加特定的输入和输出数值,这将非常有帮助。
  • 我注意到您正在使用音频缓冲区,这意味着您的值将在浮动的 [1,-1] 之间。如果将其直接转换为 8 位类型,则只会在此范围内获得 2 或 3 个数字(-1,0 和 1 取决于舍入和符号)。您是否尝试将数据转换为文件格式存储,例如 8 位 16 位音频?在这种情况下,您需要将数字缩放到这些格式所代表的区间。没有办法将浮点表示中的实际 数字 保留为 8 位数字,除非它们恰好是 [0,255] 或有符号的 [-128,127] 整数。

标签: javascript ieee-754 typed-arrays


【解决方案1】:
var output = new Uint8Array(float32Array.length);

for (var i = 0; i < float32Array.length; i++) {
  var tmp = Math.max(-1, Math.min(1, float32Array[i]));
  tmp = tmp < 0 ? (tmp * 0x8000) : (tmp * 0x7FFF);
  tmp = tmp / 256;
  output[i] = tmp + 128;
}

return output;

任何有疑问的人都可以使用Audacity导入原始数据 功能轻松测试。

  1. 下载我使用 Web Audio Api 的 decodeAudioData 方法从视频文件中解码的sample raw data
  2. 使用上述方法将 sample raw data 填充的 Float32Array 转换为 Uint8Array(或使用您自己的方法,例如 new Uint8Array(float32Array.buffer) 来听到损坏的咝咝声)并下载 uint8 pcm 文件.

    forceDownload(new Blob([output], { type: 'application/octet-binary' }));

  3. 在 Audacity 中使用 File-> Import -> Raw Data...对您下载的数据进行编码... 编码应设置为 Unsigned 8-bit PCM 和 Sample由于原始解码音频文件为 16000 Hz,因此速率应为 16000 Hz。

【讨论】:

  • 乘以0x7FFF/0x8000再除以256是什么原因?看起来我们正在转换为有符号的 2 字节短,然后转换为无符号的 1 字节 int。为什么不直接去无符号的 1 字节呢?如果 tmp 为负数,是否与签名有关?
【解决方案2】:

你问的不是很清楚;或者,更确切地说,它看起来你问的是一个没有意义的事情。

Float32Array 实例是“原始”字节值缓冲区的视图,与所有类型化数组一样。数组的每个元素代表这些原始字节中的 4 个。通过简单的数组查找提取值:

var n = float32array[1];

将这 4 个字节隐式解释为 IEEE 32 位浮点值,然后将该值转换为标准 JavaScript 数字。 JavaScript 数字始终是 64 位 IEEE 浮点值。

同样,Uint8Array 是缓冲区的视图,每个元素给出一个字节的无符号整数值。也就是说,

var n = uint8array[1];

访问该元素,将其解释为无符号单字节整数,并将其转换为 JavaScript 数字。

所以:如果您想检查一个 32 位浮点值列表作为每个字节的原始整数值,您可以创建一个 Uint8Array,它与 Float32Array“共享”相同的缓冲区:

var uintShared = new Uint8Array(float32array.buffer);

您从Uint8Array 值中看到的数值似乎与您从Float32Array 元素中得到的数值没有任何关系,这是意料之中的。

另一方面,如果你想创建一个新的Uint8Array 来保存Float32Array 中的明显,你可以创建一个相同长度的新数组并复制每个价值:

var uintCopy = new Uint8Array(float32array.length);
for (let i = 0; i < float32array.length; ++i)
  uintCopy[i] = float32array[i]; // deeply problematic; see below

现在这通常不会很好地工作,因为Float32Array 中的数值范围远远大于Uint8Array 中的数值范围。一方面,32 位浮点值可以是负数。更重要的是,即使你知道浮点值都是 0 到 255 范围内的整数,你肯定不会在Uint8Array 中得到相同的位模式,原因很简单,32 位浮点数是只是与 8 位无符号整数不同。 “保留 IEEE-754 表示”毫无意义。

这就是现实情况。如果您要解释为什么您认为您想以某种方式将 32 位 IEEE 浮点数的所有 32 位填充到 8 位无符号整数中,则可以提供更直接有用的答案。

【讨论】:

    猜你喜欢
    • 2019-10-23
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 1970-01-01
    • 2013-11-17
    • 2012-01-06
    • 2013-10-04
    • 2016-04-02
    相关资源
    最近更新 更多