交错立体声PCM线性Int16大端音频是什么样的?

Wil*_*oom 4 java audio pcm audioformat interleave

我知道在线有很多资源可以解释如何对PCM数据进行解交织.在我的当前项目的过程中,我已经看过他们大多......但我在音频处理没有背景,我有一个很很难找到如何详细的解释正是音频的这种常见的形式被存储.

我明白我的音频将有两个通道,因此样本将以[左] [右] [左] [右]的格式存储...我不明白的是这究竟是什么意思.我还读过每个样本以[左MSB] [左LSB] [右MSB] [右LSB]的格式存储.这是否意味着每个16位整数实际上编码两个8位帧,或者每个16位整数它自己的帧是指向左还是右通道?

谢谢大家.任何帮助表示赞赏.

编辑:如果您选择举例,请参阅以下内容.

方法上下文

具体来说,我要做的是将交错的short []转换为两个float [],每个float []代表左或右通道.我将用Java实现它.

public static float[][] deinterleaveAudioData(short[] interleavedData) {
    //initialize the channel arrays
    float[] left = new float[interleavedData.length / 2];
    float[] right = new float[interleavedData.length / 2];
    //iterate through the buffer
    for (int i = 0; i < interleavedData.length; i++) {
        //THIS IS WHERE I DON'T KNOW WHAT TO DO
    }
    //return the separated left and right channels
    return new float[][]{left, right};
}
Run Code Online (Sandbox Code Playgroud)

我目前的实施

我试过播放由此产生的音频.它非常接近,足够接近,你可以理解一首歌的词,但显然仍然不是正确的方法.

public static float[][] deinterleaveAudioData(short[] interleavedData) {
    //initialize the channel arrays
    float[] left = new float[interleavedData.length / 2];
    float[] right = new float[interleavedData.length / 2];
    //iterate through the buffer
    for (int i = 0; i < left.length; i++) {
        left[i] = (float) interleavedData[2 * i];
        right[i] = (float) interleavedData[2 * i + 1];
    }
    //return the separated left and right channels
    return new float[][]{left, right};
}
Run Code Online (Sandbox Code Playgroud)

格式

如果有人想了解有关音频格式的更多信息,以下是我所拥有的一切.

  • 格式为PCM 2通道交错大端线性int16
  • 采样率为44100
  • 每个short []缓冲区的短路数是2048
  • 每个short []缓冲区的帧数为1024
  • 每个数据包的帧数为1

Bra*_*rad 8

我明白我的音频将有两个通道,因此样本将以[左] [右] [左] [右]的格式存储...我不明白的是这究竟是什么意思.

在进入下一个样本之前,交错的PCM数据按通道顺序存储在每个通道一个样本中.PCM 由每个通道的一组样本组成.如果你有左右声道的立体声音频,那么每个声道的一个样本组成一个帧.

  • 第0帧:[左侧样本] [右侧样本]
  • 第1帧:[左侧样本] [右侧样本]
  • 第2帧:[左侧样本] [右侧样本]
  • 第3帧:[左侧样本] [右侧样本]
  • 等等...

每个样本是瞬时时间点的压力的测量和数字量化.也就是说,如果每个样本有8位,则可以获得256个可能的压力精度级别.知道声波是......波浪......有山峰和山谷,我们希望能够测量距离中心的距离.因此,我们可以将中心定义为127左右,并从那里减去并加上(0到255,无符号),或者我们可以将这8位视为有符号(相同的值,只是它们的不同解释)并从-128到127.

对于单通道(单声道)音频,每个采样使用8位,每个采样使用一个字节,这意味着在44.1kHz采样的一秒钟音频正好使用了4410个字节的存储空间.

现在,我们假设每个样本8位,但在立体声44.1.kHz.每隔一个字节都是左边的,而其他每个字节都是针对R.

LRLRLRLRLRLRLRLRLRLRLR...
Run Code Online (Sandbox Code Playgroud)

其放大到16位,并且您有每个样本两个字节(样品设置用括号[],空格表示帧边界)

[LL][RR] [LL][RR] [LL][RR] [LL][RR] [LL][RR] [LL][RR]...
Run Code Online (Sandbox Code Playgroud)

我还读过每个样本以[左MSB] [左LSB] [右MSB] [右LSB]的格式存储.

不必要.音频可以以任何字节顺序存储.小端是最常见的,但这不是一个神奇的规则.我确实认为所有频道总是顺序排列,而左前方在大多数情况下都是频道0.

这是否意味着每个16位整数实际上编码两个8位帧,或者每个16位整数它自己的帧是指向左还是右通道?

每个值(在这种情况下为16位整数)的目的地是单个通道.永远不会有两个多字节值相互冲突.

我希望这很有帮助.我无法运行你的代码,但鉴于你的描述,我怀疑你有一个endian问题,你的样本不是真正的大端.


mar*_*rko 5

让我们首先了解一些术语

  • 通道单声道样本流。该术语并不一定意味着样本在数据流中是连续的。
  • 帧是一组同时发生的样本对于立体声音频(例如L&R通道),帧包含两个样本。
  • 一个数据包是 1 个或多个帧,通常是系统一次可以处理的最小帧数。对于 PCM 音频,一个数据包通常包含 1 帧,但对于压缩音频,它会更大。
  • 交错是一个通常用于立体声音频的术语,其中数据流由连续的音频帧组成。因此该流看起来像 L1R1L2R2L3R3......LnRn

大端和小端音频格式都存在,并且取决于用例。然而,在系统之间交换数据时,这通常是一个问题 - 在处理或与操作系统音频组件交互时,您将始终使用本机字节顺序。

您没有说您使用的是小端还是大端系统,但我怀疑可能是前者。在这种情况下,您需要对样本进行字节反转。

虽然不是一成不变的,但使用浮点时样本通常在范围内-1.0<x<+1.0,因此您需要将样本除以1<<15。当使用 16 位线性类型时,它们通常是有符号的。

处理字节交换和格式转换:

int s = (int) interleavedData[2 * i];
short revS = (short) (((s & 0xff) << 8) | ((s >> 8) & 0xff)) 
left[i] = ((float) revS) / 32767.0f;
Run Code Online (Sandbox Code Playgroud)


max*_*hon 4

实际上,您正在处理一个几乎典型的音频 CD 质量的 WAVE 文件,也就是说:

  • 2个频道
  • 采样率 44100 kHz
  • 每个幅度样本均以 16 位有符号整数量化

我说几乎是因为大尾数通常用在 AIFF 文件(Mac 世界)中,而不是 WAVE 文件(PC 世界)中。如果不搜索,我不知道如何处理 Java 中的字节序,所以我将这部分留给您。

关于样本的存储方式非常简单:

  • 每个样本占用 16 位(从 -32768 到 +32767 的整数)
  • 如果通道交错:(L,1),(R,1),(L,2),(R,2),...,(L,n),(R,n)
  • 如果通道不是:(L,1),(L,2),...,(L,n),(R,1),(R,2),...,(R,n)

然后,为了提供音频回调,通常需要提供 32 位浮点,范围从 -1 到 +1。也许这就是你的算法中缺少某些东西的地方。将整数除以 32768 (2^(16-1)) 应该会使其听起来符合预期。