首页 > 解决方案 > 通过IOSink.Add写UInt16List,结果如何?

问题描述

尝试将音频样本写入文件。我有 16 位整数列表

UInt16List _samples = new UInt16List(0);

当样本进入时,我将元素添加到此列表中。然后我可以像这样写入 IOSink:

IOSink _ios = ...

List<int> _toWrite;
_toWrite.addAll(_samples);
_ios.add(_toWrite);

或者

_ios.add(_samples);

List<int>可以正常工作,尽管有 add take和 not的签名,但类型没有问题UInt16List

正如我所读到的,在 Dart 中,“int”类型是 64 位的。上面写的都是一样的吗?他们是否在此文件中生成打包的 16 位整数?

标签: dart

解决方案


一个Uint16List是一个List<int>。它是一个整数列表,它将写入截断为 16 位,并且总是读出 16 位整数,但它是一个整数列表。

如果将这些整数复制到普通的 growableList<int>中,它将包含相同的整数值。

因此,doingios.add(_sample)与 的作用相同ios.add(_toWrite),而且很可能两者都不是你想要的。

的方法需要一个字节列表IOSink。因此,它将采用整数列表并假设它们是字节。这意味着它将只使用每个整数的低 8 位,如果您尝试将其作为 16 位音频样本播放,这可能听起来很糟糕。add

如果要存储所有 16 位,则需要弄清楚如何将每个 16 位值存储在两个字节中。简单的选择是假设平台字节顺序很好,然后做ios.add(_samples.buffer.asUint8List(_samples.offsetInBytes, _samples.lengthInBytes)). 这将使 16 位数据视图的字节数增加两倍,然后写入这些字节。

这些字节的字节顺序(高字节在前还是最后)取决于平台,因此如果您想安全起见,可以先将字节转换为固定字节顺序:

if (Endian.host == Endian.little) {
  ios.add(
      _samples.buffer.asUint8List(_samples.offsetInBytes, _samples.lengthInBytes);
} else {
  var byteData = ByteData(_samples.length * 2);
  for (int i = 0; i < _samples.length; i++) {
    byteData.setUint16(i * 2, _samples[i], Endian.little);
  }
  var littleEndianData = byteData.buffer.asUint8List(0, _samples.length * 2);
  ios.add(littleEndianData);
}

推荐阅读