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数据按通道顺序存储在每个通道一个样本中.PCM 帧由每个通道的一组样本组成.如果你有左右声道的立体声音频,那么每个声道的一个样本组成一个帧.
每个样本是瞬时时间点的压力的测量和数字量化.也就是说,如果每个样本有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问题,你的样本不是真正的大端.
让我们首先了解一些术语
大端和小端音频格式都存在,并且取决于用例。然而,在系统之间交换数据时,这通常是一个问题 - 在处理或与操作系统音频组件交互时,您将始终使用本机字节顺序。
您没有说您使用的是小端还是大端系统,但我怀疑可能是前者。在这种情况下,您需要对样本进行字节反转。
虽然不是一成不变的,但使用浮点时样本通常在范围内-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)
实际上,您正在处理一个几乎典型的音频 CD 质量的 WAVE 文件,也就是说:
我说几乎是因为大尾数通常用在 AIFF 文件(Mac 世界)中,而不是 WAVE 文件(PC 世界)中。如果不搜索,我不知道如何处理 Java 中的字节序,所以我将这部分留给您。
关于样本的存储方式非常简单:
然后,为了提供音频回调,通常需要提供 32 位浮点,范围从 -1 到 +1。也许这就是你的算法中缺少某些东西的地方。将整数除以 32768 (2^(16-1)) 应该会使其听起来符合预期。
| 归档时间: |
|
| 查看次数: |
3474 次 |
| 最近记录: |