Convert a 3-byte stereo WAV file to a numpy array

I was provided with a large WAV continuous underwater recording file that I would like to convert to a numpy array for analysis. I'm struggling to do this.

So far, I:

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 tried to unzip it using a struct, but unzip everything I do. I get the following error: " str size does not match format ". I think this is due to the fact that the Python structure cannot process 24-bit data.

The wave file parameter is as follows:

  • nchannels = 2
  • sampwidth = 3
  • = 48000 frame rate
  • nframes = 283516532L
  • CompType = 'NONE'
  • compname = 'not compression'

Does anyone know how to read a 24-bit stereo WAV file into a numpy array?

+4
source share
2 answers

For those who have similar problems, I submit my solution. Note that this converts the 24-bit wave file to a fixed-point floating-point array. Leave the / int 2float part as part when you only convert 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
source

Here's a loop that processes 2, 3, and 4 byte WAV files with an arbitrary number 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 
+3
source

Source: https://habr.com/ru/post/1213562/


All Articles