[Scipy-svn] r3230 - trunk/Lib/io
scipy-svn at scipy.org
scipy-svn at scipy.org
Tue Aug 14 13:01:58 EDT 2007
Author: oliphant
Date: 2007-08-14 12:01:55 -0500 (Tue, 14 Aug 2007)
New Revision: 3230
Added:
trunk/Lib/io/wavfile.py
Log:
Add wavfile.py to read and write basic .wav files.
Added: trunk/Lib/io/wavfile.py
===================================================================
--- trunk/Lib/io/wavfile.py 2007-08-13 19:16:51 UTC (rev 3229)
+++ trunk/Lib/io/wavfile.py 2007-08-14 17:01:55 UTC (rev 3230)
@@ -0,0 +1,109 @@
+import numpy
+import struct
+
+# assumes file pointer is immediately
+# after the 'fmt ' id
+def _read_fmt_chunk(fid):
+ res = struct.unpack('lhHLLHH',fid.read(20))
+ size, comp, noc, rate, sbytes, ba, bits = res
+ if (comp != 1 or size > 16):
+ print "Warning: unfamiliar format bytes..."
+ if (size>16):
+ fid.read(size-16)
+ return size, comp, noc, rate, sbytes, ba, bits
+
+# assumes file pointer is immediately
+# after the 'data' id
+def _read_data_chunk(fid, noc, bits):
+ size = struct.unpack('l',fid.read(4))[0]
+ if bits == 8:
+ data = numpy.fromfile(fid, dtype=numpy.ubyte, count=size)
+ if noc > 1:
+ data = data.reshape(-1,noc)
+ else:
+ bytes = bits//8
+ dtype = 'i%d' % bytes
+ data = numpy.fromfile(fid, dtype=dtype, count=size//bytes)
+ if noc > 1:
+ data = data.reshape(-1,noc)
+ return data
+
+def _read_riff_chunk(fid):
+ str1 = fid.read(4)
+ fsize = struct.unpack('L', fid.read(4))[0] + 8
+ str2 = fid.read(4)
+ if (str1 != 'RIFF' or str2 != 'WAVE'):
+ raise ValueError, "Not a WAV file."
+ return fsize
+
+# open a wave-file
+def read(file):
+ """Return the sample rate (in samples/sec) and data from a WAV file
+
+ The file can be an open file or a filename.
+ The returned sample rate is a Python integer
+ The data is returned as a numpy array with a
+ data-type determined from the file.
+ """
+ if hasattr(file,'read'):
+ fid = file
+ else:
+ fid = open(file, 'rb')
+
+ fsize = _read_riff_chunk(fid)
+ noc = 1
+ bits = 8
+ while (fid.tell() < fsize):
+ # read the next chunk
+ chunk_id = fid.read(4)
+ if chunk_id == 'fmt ':
+ print "Reading fmt chunk"
+ size, comp, noc, rate, sbytes, ba, bits = _read_fmt_chunk(fid)
+ elif chunk_id == 'data':
+ print "Reading data chunk"
+ data = _read_data_chunk(fid, noc, bits)
+ else:
+ print "Warning: %s chunk not understood"
+ size = struct.unpack('L',fid.read(4))[0]
+ bytes = fid.read(size)
+ fid.close()
+ return rate, data
+
+# Write a wave-file
+# sample rate, data
+def write(filename, rate, data):
+ """Write a numpy array as a WAV file
+
+ filename -- The name of the file to write (will be over-written)
+ rate -- The sample rate (in samples/sec).
+ data -- A 1-d or 2-d numpy array of integer data-type.
+ The bits-per-sample will be determined by the data-type
+ To write multiple-channels, use a 2-d array of shape
+ (Nsamples, Nchannels)
+
+ Writes a simple uncompressed WAV file.
+ """
+ fid = open(filename, 'wb')
+ fid.write('RIFF')
+ fid.write('\x00\x00\x00\x00')
+ fid.write('WAVE')
+ # fmt chunk
+ fid.write('fmt ')
+ if data.ndim == 1:
+ noc = 1
+ else:
+ noc = data.shape[1]
+ bits = data.dtype.itemsize * 8
+ sbytes = rate*(bits / 8)*noc
+ ba = noc * (bits / 8)
+ fid.write(struct.pack('lhHLLHH', 16, 1, noc, rate, sbytes, ba, bits))
+ # data chunk
+ fid.write('data')
+ fid.write(struct.pack('l', data.nbytes))
+ data.tofile(fid)
+ # Determine file size and place it in correct
+ # position at start of the file.
+ size = fid.tell()
+ fid.seek(4)
+ fid.write(struct.pack('l', size-8))
+ fid.close()
More information about the Scipy-svn
mailing list