我有一些原始的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开始时,您不会在这里获得发烧级声音。

10-02 05:36