Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert 3-byte stereo WAV-file to numpy array

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 I have:

import numpy as np
import scipy as sp
import wave as wv
import struct

wavefile = wv.open(filename,'r')
(nchannels,sampwidth,framerate,nframes,comptype,compname) = wavefile.getparams()

// read a sample as example

wavedata =wavefile.readframes(1)

The first frame looks like this: '\xcd\xbc\xff@\x01\x00'. I have tried to unpack it using struct but unpack whatever I do I get the following error: "str size does not match format". I guess this is related to the fact that Python struct cannot handle 24-bit data.

The parameter of the wave-file looks as following:

  • nchannels=2
  • sampwidth=3
  • framerate=48000
  • nframes=283516532L
  • comptype='NONE'
  • compname='not compressed'

Someone know hows to read a 24-bit stereo WAV-file into a numpy array?

like image 971
Cnoobplusplus Avatar asked Oct 31 '13 14:10

Cnoobplusplus


1 Answers

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
like image 170
mtrw Avatar answered Sep 22 '22 05:09

mtrw