我有一些原始的ADPCM压缩音频流,我想用pygame播放它们,但据我所知,使用pygame不可能。如何使用python将它们解压缩为普通PCM流(或pygame可以播放的其他内容),然后使用pygame播放它们?
我已经尝试过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位。这样可以为您提供非常动态的范围,因此安静的声音会在噪音中消失。有多种压扩算法,可以为相同数量的比特提供更大的动态范围(当然会以丢失其他位置的其他信息为代价);有关其工作原理的详细信息,请参见μ律算法。但是,如果您可以保留16位,则线性是可以的。
**实际上,使用4位原始ADPCM,您确实无法执行单个采样...但是您可以执行2个采样,这已经足够接近了。
***如果您确实很挑剔,则可能需要先转换为32位,然后再进行工作,然后再转换回16位,以避免累积损失。但是,当您从4位ADPCM开始时,您不会在这里获得发烧级声音。