解析WAV数据

7 投票
6 回答
12734 浏览
提问于 2025-04-15 19:03

我正在尝试写一个程序来显示PCM数据。为了找到合适的库,我感到非常沮丧,但我找到了Python的wave库,并开始使用它。不过,我不太确定该如何解读这些数据。

wave.getparams函数返回的信息是(2个声道,2个字节,44100赫兹,96333帧,未压缩,未压缩)。这些信息看起来都不错,但当我尝试打印一个单独的帧时,得到了'\xc0\xff\xd0\xff',这总共是4个字节。我想可能一帧包含2个样本,但问题并不止于此。

96333帧 * 2样本/帧 * (1/44.1k秒/样本) = 4.3688秒

然而,iTunes显示的时间更接近2秒,而根据文件大小和比特率的计算结果大约是2.7秒。这到底是怎么回事呢?

另外,我怎么知道这些字节是有符号的还是无符号的呢?

非常感谢!

6 个回答

4

我知道已经有人接受了答案,但我之前做过一些音频相关的事情,你需要像这样解压波形文件。

pcmdata = wave.struct.unpack("%dh"%(wavedatalength),wavedata)

另外,我用过一个叫做PyAudio的库,不过我还是需要和它一起使用wave这个库。

21

谢谢你的帮助!我已经搞定了这个问题,我会把解决方案发在这里,方便其他遇到同样问题的人使用:

import wave
import struct

def pcm_channels(wave_file):
    """Given a file-like object or file path representing a wave file,
    decompose it into its constituent PCM data streams.

    Input: A file like object or file path
    Output: A list of lists of integers representing the PCM coded data stream channels
        and the sample rate of the channels (mixed rate channels not supported)
    """
    stream = wave.open(wave_file,"rb")

    num_channels = stream.getnchannels()
    sample_rate = stream.getframerate()
    sample_width = stream.getsampwidth()
    num_frames = stream.getnframes()

    raw_data = stream.readframes( num_frames ) # Returns byte data
    stream.close()

    total_samples = num_frames * num_channels

    if sample_width == 1: 
        fmt = "%iB" % total_samples # read unsigned chars
    elif sample_width == 2:
        fmt = "%ih" % total_samples # read signed 2 byte shorts
    else:
        raise ValueError("Only supports 8 and 16 bit audio formats.")

    integer_data = struct.unpack(fmt, raw_data)
    del raw_data # Keep memory tidy (who knows how big it might be)

    channels = [ [] for time in range(num_channels) ]

    for index, value in enumerate(integer_data):
        bucket = index % num_channels
        channels[bucket].append(value)

    return channels, sample_rate
10

“两个通道”就是立体声,所以把每个通道的时长相加是没有意义的——这样算出来的时间会多一倍(应该是2.18秒,而不是4.37秒)。至于有符号和无符号的区别,像这里所解释的,我引用一下:

8位的音频样本是以无符号字节的形式存储,范围是0到255。而16位的样本则是以2的补码形式存储的有符号整数,范围是-32768到32767。

这部分内容是WAV格式的规范(实际上是它的超集RIFF的一部分),所以和你使用哪个库来处理WAV文件没有关系。

撰写回答