Convert 3-byte stereo WAV-file to numpy array

后端 未结 3 1499
小蘑菇
小蘑菇 2021-01-13 04:29

I have been given a large WAV-file of continuous underwater recording which I would like to convert to a numpy array for analysis. I am struggling to do this.

So far

相关标签:
3条回答
  • 2021-01-13 05:20

    Here's a loop that handles 2, 3, and 4 byte WAV files with arbitrary numbers of channels:

    def dataFromWave(fname):
    """ return list with interleaved samples """
        f = wave.open(fname, 'rb')
        chans = f.getnchannels()
        samps = f.getnframes()
        sampwidth = f.getsampwidth()
        if  sampwidth == 3: #have to read this one sample at a time
            s = ''
            for k in xrange(samps):
                fr = f.readframes(1)
                for c in xrange(0,3*chans,3):                
                    s += '\0'+fr[c:(c+3)] # put TRAILING 0 to make 32-bit (file is little-endian)
        else:
            s = f.readframes(samps)
        f.close()
        unpstr = '<{0}{1}'.format(samps*chans, {1:'b',2:'h',3:'i',4:'i',8:'q'}[sampwidth])
        x = list(struct.unpack(unpstr, s))
        if sampwidth == 3:
            x = [k >> 8 for k in x] #downshift to get +/- 2^24 with sign extension
        return x
    
    0 讨论(0)
  • 2021-01-13 05:26

    For those with similar issues I post my solution. Note that this converts a 24-bit wave file into a signed floating point numpy array. Leave the /int2float part out when only converting to integers.

    frames = wavfile.readframes(nsamples)
    
    ch1 = np.zeros(nsamples)
    ch2 = np.zeros(nsamples)
    int2float = (2**23)-1
    
    for x in np.arange(int(nsamples)):
        ch1_24bit_sample = frames[x*6:x*6+3]
        ch2_24bit_sample = frames[x*6+3:x*6+6]
        ch1_32bit_sample = bit24_2_32(ch1_24bit_sample)
        ch2_32bit_sample = bit24_2_32(ch2_24bit_sample)
        ch1[x]=struct.unpack('i',ch_32bit_sample)[0]
        ch2[x]=struct.unpack('i',ch_32bit_sample)[0]
        ch1[x]=ch1[x]/int2float
        ch2[x]=ch2[x]/int2float
    
    def bit24_2_32(strbytes):
        if strbytes[2] < '\x80':
           return strbytes+'\x00'
        else:
           return strbytes+'\xff'
    
    0 讨论(0)
  • 2021-01-13 05:29

    This is an old question but if someone needs additional options and there is no restriction on using external modules, then you can probably use librosa

    myNdArray = librosa.core.load(wav_path, sr=sample_rate)[0]
    
    0 讨论(0)
提交回复
热议问题