Question

I have to read the data from just one channel in a stereo wave file in Python. For this I tried it with 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

But this code is very slow, especially if I have to work with longer files. So does anybody know a faster way to do this? I thought about the standard wave module by using wave.readframes(), but how are the frames stored there?

Was it helpful?

Solution

scipy.io.wavfile.read returns the tuple (rate, data). If the file is stereo, data is a numpy array with shape (nsamples, 2). To get a specific channel, use a slice of data. For example,

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

OTHER TIPS

The wave module returns the frames as a string of bytes, which can be converted to numbers with the struct module. For instance:

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

If your WAV file has some other sample size, you can use the (uglier) function in another answer I wrote here.

I've never used scipy's wavfile function so I can't compare speed, but the wave and struct approach I use here has always worked for me.

rate, audio = wavfile.read(path)

audio = np.mean(audio, axis=1)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top