我有一些原始的 ADPCM 压缩音频流,我想用 pygame 播放它们,但据我所知,用 pygame 是不可能的。如何用 python 将它们解压缩为正常的 PCM 流(或 pygame 可以播放的其他东西),然后用 pygame 播放它们?
我已经尝试过 audioop 模块,因为它可以将 ADPCM 转换为线性流,但我不知道什么是线性流,也不知道如何使用转换它们的函数。
我已经尝试过 audioop 模块,因为它可以将 ADPCM 转换为线性流,但我不知道什么是线性流,也不知道如何使用转换它们的函数。
简短的版本:“线性”是你想要的。*所以,你想要的功能是adpcm2lin
.
你如何使用它?
几乎所有内容都以audioop
相同的方式工作:循环帧,并在每个帧上调用一个函数。如果您的输入数据具有某些固有的帧大小,例如当您从 MP3 文件中读取时(使用外部库),或者您的输出库需要某些特定的帧大小,那么您在确定帧的方式上会受到一些限制。但是,当您处理原始 PCM 格式时,帧是您想要的任何大小,从单个样本到整个文件。**
为简单起见,让我们先完成整个文件:
with open('spam.adpcm', 'rb') as f:
adpcm = f.read()
pcm, _ = audioop.adpcm2lin(adpcm, 2, None)
如果您的adpcm
文件太大而无法一次加载到内存中并进行处理,则需要跟踪state
,因此:
with open('spam.adpcm', 'rb') as f:
state = None
while True:
adpcm = f.read(BLOCKSIZE)
if not adpcm:
return
pcm, state = audioop.adpcm2lin(adpcm, 2, state)
yield pcm
当然,我假设您不需要转换采样率或做任何其他事情。如果这样做,任何此类转换都应在 ADPCM 解压缩之后进行。***
* 长版:“线性”表示样本直接编码,而不是通过其他算法映射。例如,如果您有一个 16 位 A-to-D,并且您将音频保存在一个 8 位线性 PCM 文件中,那么您只是保存了每个样本的前 8 位。这为您提供了非常动态的范围,因此更安静的声音会消失在噪音中。有多种压扩算法可以为相同的位数提供更宽的动态范围(当然,代价是在其他地方丢失其他信息);有关它们如何工作的详细信息,请参阅 μ-law 算法。但是如果你可以保持 16 位,那么线性就可以了。
** 实际上,使用 4 位原始 ADPCM,你真的不能做一个样本……但你可以做 2 个样本,这已经足够接近了。
***如果你真的很挑剔,你可能想先转换成32位,然后做工作,然后再转换回16位以避免累积损失。但是,当您开始使用 4 位 ADPCM 时,您不会在这里追求发烧级的声音。