在Python中从立体声波文件读取单声道数据

5 投票
3 回答
21297 浏览
提问于 2025-04-18 03:16

我需要在Python中从一个立体声波文件中读取一个通道的数据。为此,我尝试使用了scipy.io:

import scipy.io.wavfile as wf
import numpy

def read(path):
    data = wf.read(path)
    for frame in data[1]:
        data = numpy.append(data, frame[0])
    return data

但是这个代码运行得很慢,特别是当我需要处理较长的文件时。所以有没有人知道更快的方法?我想到了标准的wave模块,想用wave.readframes()来读取,但那里的帧是怎么存储的呢?

3 个回答

2

这行代码的意思是,从指定的路径读取一个音频文件,并把它的采样率和音频数据分别存储在变量rate和audio中。

接下来的这行代码是把音频数据的多个声道(比如立体声有两个声道)合并成一个声道。具体来说,它计算每个时间点上两个声道的平均值,这样就把音频变成了单声道。

7

wave模块会把音频的帧以字节字符串的形式返回,这些字节可以用struct模块转换成数字。比如:

def oneChannel(fname, chanIdx):
""" list with specified channel's data from multichannel wave with 16-bit data """
    f = wave.open(fname, 'rb')
    chans = f.getnchannels()
    samps = f.getnframes()
    sampwidth = f.getsampwidth()
    assert sampwidth == 2
    s = f.readframes(samps) #read the all the samples from the file into a byte string
    f.close()
    unpstr = '<{0}h'.format(samps*chans) #little-endian 16-bit samples
    x = list(struct.unpack(unpstr, s)) #convert the byte string into a list of ints
    return x[chanIdx::chans] #return the desired channel

如果你的WAV文件有其他的采样大小,你可以使用我在另一个回答中写的(虽然看起来不太好)函数,链接在这里

我从来没有使用过scipywavfile函数,所以无法比较速度,但我在这里使用的wavestruct的方法一直对我有效。

18

scipy.io.wavfile.read 这个函数会返回一个元组 (rate, data)。如果文件是立体声的,data 就是一个形状为 (nsamples, 2) 的 numpy 数组。要获取特定的声道,可以使用 切片 来处理 data。比如说,

rate, data = wavfile.read(path)
# data0 is the data from channel 0.
data0 = data[:, 0]

撰写回答