在不重新采样的情况下调整 PCM 数组的大小

Posted

技术标签:

【中文标题】在不重新采样的情况下调整 PCM 数组的大小【英文标题】:Resize PCM array without resample 【发布时间】:2015-07-03 10:25:40 【问题描述】:

我从网络收到采样率为 8 kHz、长度为 320 的 PCM 字节数组。

现在我想将数组的长度调整为 2n,即 256 或 512,同时将采样率保持在 8 kHz。

有人知道算法可以做到这一点吗?

【问题讨论】:

只切阵列。 当你调整大小时,你只是想添加静音,还是想以某种方式拉伸声音以适应? @Phil Freihofner:我想适应新的尺寸,而不是添加静音。 采取的策略取决于您想要的结果。如果一个声音有 N 帧长并且你希望它是 N+M,并且没有额外的材料可以添加,那么可以通过保留音高来拉伸声音(更困难的是,将声音分解成“颗粒”重复并可能混合)或允许音调下降(通常使用线性插值从“隐含”音频波中获取更多样本)。如果您指明要采用哪种方法,我或其他人可以填写更多详细信息。 @Phil Freihofner:第二种方法似乎更容易和流行。你能给我一些提示或例子吗?谢谢。 【参考方案1】:

假设数据是一系列 PCM 值,范围从 -1 到 1。(对于 16 位编码,声音值实际上可能是 -32768 到 32767,或者是 Short 的范围。)

数组 A 有数据,数组 B 是目标。 如果 A.length = 320 和 B.length = 256,那么以下应该有效:

float incr = B.length / (float) A.length;
for (int i = 0; i < 256; i++) 
    B[i] = linearInterpolation(A, incr * i);

要进行线性插值,假设 incr * i [0.8 * 3] 计算为介于 n 和 n+1 之间的某个值,例如 2.4(介于 2 和 3 之间)。首先,得到小数部分(0.4):

fract = i * incr - (int)(i * incr);

然后计算如下:

return ( (A[n] * (1 - fract)) + (A[n+1] * (fract)) ) / 2; 

您可能需要将字节编码/解码为 PCM。这是一个单独的问题,但在 *** 上已多次处理。

【讨论】:

对不起我的愚蠢。在这种情况下 incr = 0.8,如何从 n = 2 和 n = i 中获得值 2.75?谢谢。 很抱歉没有保持示例的一致性。我编辑了我的答案,以便 incr 将是从您的示例案例中得出的实际值。我希望这能让事情更清楚!

以上是关于在不重新采样的情况下调整 PCM 数组的大小的主要内容,如果未能解决你的问题,请参考以下文章

iOS - 如何在不调整大小和重新定位按钮视图的情况下更改按钮图像

如何在不更改特定列的情况下对数据框中的数据进行重新采样?

如何在不更改特定列的情况下对数据框中的数据进行重新采样?

如何在不使用 ffmpeg 保持视频持续时间的情况下重新采样 FPS?

在不破坏动画的情况下调整动画 GIF 文件的大小

在不关闭实例的情况下调整云 VM 磁盘大小(谷歌云)