diff options
author | Guido van Rossum <guido@python.org> | 2000-02-04 15:28:42 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2000-02-04 15:28:42 (GMT) |
commit | e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757 (patch) | |
tree | e1dda862f680cf4a1169220af2ecbca3322caf4d /Lib/wave.py | |
parent | 54f22ed30bab2e64909ba2d79205cb4b87c69db2 (diff) | |
download | cpython-e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757.zip cpython-e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757.tar.gz cpython-e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757.tar.bz2 |
The third and final doc-string sweep by Ka-Ping Yee.
The attached patches update the standard library so that all modules
have docstrings beginning with one-line summaries.
A new docstring was added to formatter. The docstring for os.py
was updated to mention nt, os2, ce in addition to posix, dos, mac.
Diffstat (limited to 'Lib/wave.py')
-rw-r--r-- | Lib/wave.py | 899 |
1 files changed, 451 insertions, 448 deletions
diff --git a/Lib/wave.py b/Lib/wave.py index aec9bdf..8bb9ff7 100644 --- a/Lib/wave.py +++ b/Lib/wave.py @@ -1,74 +1,75 @@ -# Stuff to parse WAVE files. -# -# Usage. -# -# Reading WAVE files: -# f = wave.open(file, 'r') -# where file is either the name of a file or an open file pointer. -# The open file pointer must have methods read(), seek(), and close(). -# When the setpos() and rewind() methods are not used, the seek() -# method is not necessary. -# -# This returns an instance of a class with the following public methods: -# getnchannels() -- returns number of audio channels (1 for -# mono, 2 for stereo) -# getsampwidth() -- returns sample width in bytes -# getframerate() -- returns sampling frequency -# getnframes() -- returns number of audio frames -# getcomptype() -- returns compression type ('NONE' for linear samples) -# getcompname() -- returns human-readable version of -# compression type ('not compressed' linear samples) -# getparams() -- returns a tuple consisting of all of the -# above in the above order -# getmarkers() -- returns None (for compatibility with the -# aifc module) -# getmark(id) -- raises an error since the mark does not -# exist (for compatibility with the aifc module) -# readframes(n) -- returns at most n frames of audio -# rewind() -- rewind to the beginning of the audio stream -# setpos(pos) -- seek to the specified position -# tell() -- return the current position -# close() -- close the instance (make it unusable) -# The position returned by tell() and the position given to setpos() -# are compatible and have nothing to do with the actual postion in the -# file. -# The close() method is called automatically when the class instance -# is destroyed. -# -# Writing WAVE files: -# f = wave.open(file, 'w') -# where file is either the name of a file or an open file pointer. -# The open file pointer must have methods write(), tell(), seek(), and -# close(). -# -# This returns an instance of a class with the following public methods: -# setnchannels(n) -- set the number of channels -# setsampwidth(n) -- set the sample width -# setframerate(n) -- set the frame rate -# setnframes(n) -- set the number of frames -# setcomptype(type, name) -# -- set the compression type and the -# human-readable compression type -# setparams(tuple) -# -- set all parameters at once -# tell() -- return current position in output file -# writeframesraw(data) -# -- write audio frames without pathing up the -# file header -# writeframes(data) -# -- write audio frames and patch up the file header -# close() -- patch up the file header and close the -# output file -# You should set the parameters before the first writeframesraw or -# writeframes. The total number of frames does not need to be set, -# but when it is set to the correct value, the header does not have to -# be patched up. -# It is best to first set all parameters, perhaps possibly the -# compression type, and then write audio frames using writeframesraw. -# When all frames have been written, either call writeframes('') or -# close() to patch up the sizes in the header. -# The close() method is called automatically when the class instance -# is destroyed. +"""Stuff to parse WAVE files. + +Usage. + +Reading WAVE files: + f = wave.open(file, 'r') +where file is either the name of a file or an open file pointer. +The open file pointer must have methods read(), seek(), and close(). +When the setpos() and rewind() methods are not used, the seek() +method is not necessary. + +This returns an instance of a class with the following public methods: + getnchannels() -- returns number of audio channels (1 for + mono, 2 for stereo) + getsampwidth() -- returns sample width in bytes + getframerate() -- returns sampling frequency + getnframes() -- returns number of audio frames + getcomptype() -- returns compression type ('NONE' for linear samples) + getcompname() -- returns human-readable version of + compression type ('not compressed' linear samples) + getparams() -- returns a tuple consisting of all of the + above in the above order + getmarkers() -- returns None (for compatibility with the + aifc module) + getmark(id) -- raises an error since the mark does not + exist (for compatibility with the aifc module) + readframes(n) -- returns at most n frames of audio + rewind() -- rewind to the beginning of the audio stream + setpos(pos) -- seek to the specified position + tell() -- return the current position + close() -- close the instance (make it unusable) +The position returned by tell() and the position given to setpos() +are compatible and have nothing to do with the actual postion in the +file. +The close() method is called automatically when the class instance +is destroyed. + +Writing WAVE files: + f = wave.open(file, 'w') +where file is either the name of a file or an open file pointer. +The open file pointer must have methods write(), tell(), seek(), and +close(). + +This returns an instance of a class with the following public methods: + setnchannels(n) -- set the number of channels + setsampwidth(n) -- set the sample width + setframerate(n) -- set the frame rate + setnframes(n) -- set the number of frames + setcomptype(type, name) + -- set the compression type and the + human-readable compression type + setparams(tuple) + -- set all parameters at once + tell() -- return current position in output file + writeframesraw(data) + -- write audio frames without pathing up the + file header + writeframes(data) + -- write audio frames and patch up the file header + close() -- patch up the file header and close the + output file +You should set the parameters before the first writeframesraw or +writeframes. The total number of frames does not need to be set, +but when it is set to the correct value, the header does not have to +be patched up. +It is best to first set all parameters, perhaps possibly the +compression type, and then write audio frames using writeframesraw. +When all frames have been written, either call writeframes('') or +close() to patch up the sizes in the header. +The close() method is called automatically when the class instance +is destroyed. +""" import __builtin__ @@ -81,391 +82,393 @@ _array_fmts = None, 'b', 'h', None, 'l' # Determine endian-ness import struct if struct.pack("h", 1) == "\000\001": - big_endian = 1 + big_endian = 1 else: - big_endian = 0 + big_endian = 0 from chunk import Chunk class Wave_read: - # Variables used in this class: - # - # These variables are available to the user though appropriate - # methods of this class: - # _file -- the open file with methods read(), close(), and seek() - # set through the __init__() method - # _nchannels -- the number of audio channels - # available through the getnchannels() method - # _nframes -- the number of audio frames - # available through the getnframes() method - # _sampwidth -- the number of bytes per audio sample - # available through the getsampwidth() method - # _framerate -- the sampling frequency - # available through the getframerate() method - # _comptype -- the AIFF-C compression type ('NONE' if AIFF) - # available through the getcomptype() method - # _compname -- the human-readable AIFF-C compression type - # available through the getcomptype() method - # _soundpos -- the position in the audio stream - # available through the tell() method, set through the - # setpos() method - # - # These variables are used internally only: - # _fmt_chunk_read -- 1 iff the FMT chunk has been read - # _data_seek_needed -- 1 iff positioned correctly in audio - # file for readframes() - # _data_chunk -- instantiation of a chunk class for the DATA chunk - # _framesize -- size of one frame in the file - - def initfp(self, file): - self._convert = None - self._soundpos = 0 - self._file = Chunk(file, bigendian = 0) - if self._file.getname() != 'RIFF': - raise Error, 'file does not start with RIFF id' - if self._file.read(4) != 'WAVE': - raise Error, 'not a WAVE file' - self._fmt_chunk_read = 0 - self._data_chunk = None - while 1: - self._data_seek_needed = 1 - try: - chunk = Chunk(self._file, bigendian = 0) - except EOFError: - break - chunkname = chunk.getname() - if chunkname == 'fmt ': - self._read_fmt_chunk(chunk) - self._fmt_chunk_read = 1 - elif chunkname == 'data': - if not self._fmt_chunk_read: - raise Error, 'data chunk before fmt chunk' - self._data_chunk = chunk - self._nframes = chunk.chunksize / self._framesize - self._data_seek_needed = 0 - break - chunk.skip() - if not self._fmt_chunk_read or not self._data_chunk: - raise Error, 'fmt chunk and/or data chunk missing' - - def __init__(self, f): - if type(f) == type(''): - f = __builtin__.open(f, 'rb') - # else, assume it is an open file object already - self.initfp(f) - - # - # User visible methods. - # - def getfp(self): - return self._file - - def rewind(self): - self._data_seek_needed = 1 - self._soundpos = 0 - - def close(self): - self._file = None - - def tell(self): - return self._soundpos - - def getnchannels(self): - return self._nchannels - - def getnframes(self): - return self._nframes - - def getsampwidth(self): - return self._sampwidth - - def getframerate(self): - return self._framerate - - def getcomptype(self): - return self._comptype - - def getcompname(self): - return self._compname - - def getparams(self): - return self.getnchannels(), self.getsampwidth(), \ - self.getframerate(), self.getnframes(), \ - self.getcomptype(), self.getcompname() - - def getmarkers(self): - return None - - def getmark(self, id): - raise Error, 'no marks' - - def setpos(self, pos): - if pos < 0 or pos > self._nframes: - raise Error, 'position not in range' - self._soundpos = pos - self._data_seek_needed = 1 - - def readframes(self, nframes): - if self._data_seek_needed: - self._data_chunk.seek(0, 0) - pos = self._soundpos * self._framesize - if pos: - self._data_chunk.seek(pos, 0) - self._data_seek_needed = 0 - if nframes == 0: - return '' - if self._sampwidth > 1 and big_endian: - # unfortunately the fromfile() method does not take - # something that only looks like a file object, so - # we have to reach into the innards of the chunk object - import array - chunk = self._data_chunk - data = array.array(_array_fmts[self._sampwidth]) - nitems = nframes * self._nchannels - if nitems * self._sampwidth > chunk.chunksize - chunk.size_read: - nitems = (chunk.chunksize - chunk.size_read) / self._sampwidth - data.fromfile(chunk.file.file, nitems) - # "tell" data chunk how much was read - chunk.size_read = chunk.size_read + nitems * self._sampwidth - # do the same for the outermost chunk - chunk = chunk.file - chunk.size_read = chunk.size_read + nitems * self._sampwidth - data.byteswap() - data = data.tostring() - else: - data = self._data_chunk.read(nframes * self._framesize) - if self._convert and data: - data = self._convert(data) - self._soundpos = self._soundpos + len(data) / (self._nchannels * self._sampwidth) - return data - - # - # Internal methods. - # - - def _read_fmt_chunk(self, chunk): - wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack('<hhllh', chunk.read(14)) - if wFormatTag == WAVE_FORMAT_PCM: - sampwidth = struct.unpack('<h', chunk.read(2))[0] - self._sampwidth = (sampwidth + 7) / 8 - else: - raise Error, 'unknown format: ' + `wFormatTag` - self._framesize = self._nchannels * self._sampwidth - self._comptype = 'NONE' - self._compname = 'not compressed' + """Variables used in this class: + + These variables are available to the user though appropriate + methods of this class: + _file -- the open file with methods read(), close(), and seek() + set through the __init__() method + _nchannels -- the number of audio channels + available through the getnchannels() method + _nframes -- the number of audio frames + available through the getnframes() method + _sampwidth -- the number of bytes per audio sample + available through the getsampwidth() method + _framerate -- the sampling frequency + available through the getframerate() method + _comptype -- the AIFF-C compression type ('NONE' if AIFF) + available through the getcomptype() method + _compname -- the human-readable AIFF-C compression type + available through the getcomptype() method + _soundpos -- the position in the audio stream + available through the tell() method, set through the + setpos() method + + These variables are used internally only: + _fmt_chunk_read -- 1 iff the FMT chunk has been read + _data_seek_needed -- 1 iff positioned correctly in audio + file for readframes() + _data_chunk -- instantiation of a chunk class for the DATA chunk + _framesize -- size of one frame in the file + """ + + def initfp(self, file): + self._convert = None + self._soundpos = 0 + self._file = Chunk(file, bigendian = 0) + if self._file.getname() != 'RIFF': + raise Error, 'file does not start with RIFF id' + if self._file.read(4) != 'WAVE': + raise Error, 'not a WAVE file' + self._fmt_chunk_read = 0 + self._data_chunk = None + while 1: + self._data_seek_needed = 1 + try: + chunk = Chunk(self._file, bigendian = 0) + except EOFError: + break + chunkname = chunk.getname() + if chunkname == 'fmt ': + self._read_fmt_chunk(chunk) + self._fmt_chunk_read = 1 + elif chunkname == 'data': + if not self._fmt_chunk_read: + raise Error, 'data chunk before fmt chunk' + self._data_chunk = chunk + self._nframes = chunk.chunksize / self._framesize + self._data_seek_needed = 0 + break + chunk.skip() + if not self._fmt_chunk_read or not self._data_chunk: + raise Error, 'fmt chunk and/or data chunk missing' + + def __init__(self, f): + if type(f) == type(''): + f = __builtin__.open(f, 'rb') + # else, assume it is an open file object already + self.initfp(f) + + # + # User visible methods. + # + def getfp(self): + return self._file + + def rewind(self): + self._data_seek_needed = 1 + self._soundpos = 0 + + def close(self): + self._file = None + + def tell(self): + return self._soundpos + + def getnchannels(self): + return self._nchannels + + def getnframes(self): + return self._nframes + + def getsampwidth(self): + return self._sampwidth + + def getframerate(self): + return self._framerate + + def getcomptype(self): + return self._comptype + + def getcompname(self): + return self._compname + + def getparams(self): + return self.getnchannels(), self.getsampwidth(), \ + self.getframerate(), self.getnframes(), \ + self.getcomptype(), self.getcompname() + + def getmarkers(self): + return None + + def getmark(self, id): + raise Error, 'no marks' + + def setpos(self, pos): + if pos < 0 or pos > self._nframes: + raise Error, 'position not in range' + self._soundpos = pos + self._data_seek_needed = 1 + + def readframes(self, nframes): + if self._data_seek_needed: + self._data_chunk.seek(0, 0) + pos = self._soundpos * self._framesize + if pos: + self._data_chunk.seek(pos, 0) + self._data_seek_needed = 0 + if nframes == 0: + return '' + if self._sampwidth > 1 and big_endian: + # unfortunately the fromfile() method does not take + # something that only looks like a file object, so + # we have to reach into the innards of the chunk object + import array + chunk = self._data_chunk + data = array.array(_array_fmts[self._sampwidth]) + nitems = nframes * self._nchannels + if nitems * self._sampwidth > chunk.chunksize - chunk.size_read: + nitems = (chunk.chunksize - chunk.size_read) / self._sampwidth + data.fromfile(chunk.file.file, nitems) + # "tell" data chunk how much was read + chunk.size_read = chunk.size_read + nitems * self._sampwidth + # do the same for the outermost chunk + chunk = chunk.file + chunk.size_read = chunk.size_read + nitems * self._sampwidth + data.byteswap() + data = data.tostring() + else: + data = self._data_chunk.read(nframes * self._framesize) + if self._convert and data: + data = self._convert(data) + self._soundpos = self._soundpos + len(data) / (self._nchannels * self._sampwidth) + return data + + # + # Internal methods. + # + + def _read_fmt_chunk(self, chunk): + wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack('<hhllh', chunk.read(14)) + if wFormatTag == WAVE_FORMAT_PCM: + sampwidth = struct.unpack('<h', chunk.read(2))[0] + self._sampwidth = (sampwidth + 7) / 8 + else: + raise Error, 'unknown format: ' + `wFormatTag` + self._framesize = self._nchannels * self._sampwidth + self._comptype = 'NONE' + self._compname = 'not compressed' class Wave_write: - # Variables used in this class: - # - # These variables are user settable through appropriate methods - # of this class: - # _file -- the open file with methods write(), close(), tell(), seek() - # set through the __init__() method - # _comptype -- the AIFF-C compression type ('NONE' in AIFF) - # set through the setcomptype() or setparams() method - # _compname -- the human-readable AIFF-C compression type - # set through the setcomptype() or setparams() method - # _nchannels -- the number of audio channels - # set through the setnchannels() or setparams() method - # _sampwidth -- the number of bytes per audio sample - # set through the setsampwidth() or setparams() method - # _framerate -- the sampling frequency - # set through the setframerate() or setparams() method - # _nframes -- the number of audio frames written to the header - # set through the setnframes() or setparams() method - # - # These variables are used internally only: - # _datalength -- the size of the audio samples written to the header - # _nframeswritten -- the number of frames actually written - # _datawritten -- the size of the audio samples actually written - - def __init__(self, f): - if type(f) == type(''): - f = __builtin__.open(f, 'wb') - self.initfp(f) - - def initfp(self, file): - self._file = file - self._convert = None - self._nchannels = 0 - self._sampwidth = 0 - self._framerate = 0 - self._nframes = 0 - self._nframeswritten = 0 - self._datawritten = 0 - self._datalength = 0 - - def __del__(self): - if self._file: - self.close() - - # - # User visible methods. - # - def setnchannels(self, nchannels): - if self._datawritten: - raise Error, 'cannot change parameters after starting to write' - if nchannels < 1: - raise Error, 'bad # of channels' - self._nchannels = nchannels - - def getnchannels(self): - if not self._nchannels: - raise Error, 'number of channels not set' - return self._nchannels - - def setsampwidth(self, sampwidth): - if self._datawritten: - raise Error, 'cannot change parameters after starting to write' - if sampwidth < 1 or sampwidth > 4: - raise Error, 'bad sample width' - self._sampwidth = sampwidth - - def getsampwidth(self): - if not self._sampwidth: - raise Error, 'sample width not set' - return self._sampwidth - - def setframerate(self, framerate): - if self._datawritten: - raise Error, 'cannot change parameters after starting to write' - if framerate <= 0: - raise Error, 'bad frame rate' - self._framerate = framerate - - def getframerate(self): - if not self._framerate: - raise Error, 'frame rate not set' - return self._framerate - - def setnframes(self, nframes): - if self._datawritten: - raise Error, 'cannot change parameters after starting to write' - self._nframes = nframes - - def getnframes(self): - return self._nframeswritten - - def setcomptype(self, comptype, compname): - if self._datawritten: - raise Error, 'cannot change parameters after starting to write' - if comptype not in ('NONE',): - raise Error, 'unsupported compression type' - self._comptype = comptype - self._compname = compname - - def getcomptype(self): - return self._comptype - - def getcompname(self): - return self._compname - - def setparams(self, (nchannels, sampwidth, framerate, nframes, comptype, compname)): - if self._datawritten: - raise Error, 'cannot change parameters after starting to write' - self.setnchannels(nchannels) - self.setsampwidth(sampwidth) - self.setframerate(framerate) - self.setnframes(nframes) - self.setcomptype(comptype, compname) - - def getparams(self): - if not self._nchannels or not self._sampwidth or not self._framerate: - raise Error, 'not all parameters set' - return self._nchannels, self._sampwidth, self._framerate, \ - self._nframes, self._comptype, self._compname - - def setmark(self, id, pos, name): - raise Error, 'setmark() not supported' - - def getmark(self, id): - raise Error, 'no marks' - - def getmarkers(self): - return None - - def tell(self): - return self._nframeswritten - - def writeframesraw(self, data): - self._ensure_header_written(len(data)) - nframes = len(data) / (self._sampwidth * self._nchannels) - if self._convert: - data = self._convert(data) - if self._sampwidth > 1 and big_endian: - import array - data = array.array(_array_fmts[self._sampwidth], data) - data.byteswap() - data.tofile(self._file) - self._datawritten = self._datawritten + len(data) * self._sampwidth - else: - self._file.write(data) - self._datawritten = self._datawritten + len(data) - self._nframeswritten = self._nframeswritten + nframes - - def writeframes(self, data): - self.writeframesraw(data) - if self._datalength != self._datawritten: - self._patchheader() - - def close(self): - self._ensure_header_written(0) - if self._datalength != self._datawritten: - self._patchheader() - self._file.flush() - self._file = None - - # - # Internal methods. - # - - def _ensure_header_written(self, datasize): - if not self._datawritten: - if not self._nchannels: - raise Error, '# channels not specified' - if not self._sampwidth: - raise Error, 'sample width not specified' - if not self._framerate: - raise Error, 'sampling rate not specified' - self._write_header(datasize) - - def _write_header(self, initlength): - self._file.write('RIFF') - if not self._nframes: - self._nframes = initlength / (self._nchannels * self._sampwidth) - self._datalength = self._nframes * self._nchannels * self._sampwidth - self._form_length_pos = self._file.tell() - self._file.write(struct.pack('<lsslhhllhhs', - 36 + self._datalength, 'WAVE', 'fmt ', 16, - WAVE_FORMAT_PCM, self._nchannels, self._framerate, - self._nchannels * self._framerate * self._sampwidth, - self._nchannels * self._sampwidth, - self._sampwidth * 8, 'data')) - self._data_length_pos = self._file.tell() - self._file.write(struct.pack('<l', self._datalength)) - - def _patchheader(self): - if self._datawritten == self._datalength: - return - curpos = self._file.tell() - self._file.seek(self._form_length_pos, 0) - self._file.write(struct.pack('<l', 36 + self._datawritten)) - self._file.seek(self._data_length_pos, 0) - self._file.write(struct.pack('<l', self._datawritten)) - self._file.seek(curpos, 0) - self._datalength = self._datawritten + """Variables used in this class: + + These variables are user settable through appropriate methods + of this class: + _file -- the open file with methods write(), close(), tell(), seek() + set through the __init__() method + _comptype -- the AIFF-C compression type ('NONE' in AIFF) + set through the setcomptype() or setparams() method + _compname -- the human-readable AIFF-C compression type + set through the setcomptype() or setparams() method + _nchannels -- the number of audio channels + set through the setnchannels() or setparams() method + _sampwidth -- the number of bytes per audio sample + set through the setsampwidth() or setparams() method + _framerate -- the sampling frequency + set through the setframerate() or setparams() method + _nframes -- the number of audio frames written to the header + set through the setnframes() or setparams() method + + These variables are used internally only: + _datalength -- the size of the audio samples written to the header + _nframeswritten -- the number of frames actually written + _datawritten -- the size of the audio samples actually written + """ + + def __init__(self, f): + if type(f) == type(''): + f = __builtin__.open(f, 'wb') + self.initfp(f) + + def initfp(self, file): + self._file = file + self._convert = None + self._nchannels = 0 + self._sampwidth = 0 + self._framerate = 0 + self._nframes = 0 + self._nframeswritten = 0 + self._datawritten = 0 + self._datalength = 0 + + def __del__(self): + if self._file: + self.close() + + # + # User visible methods. + # + def setnchannels(self, nchannels): + if self._datawritten: + raise Error, 'cannot change parameters after starting to write' + if nchannels < 1: + raise Error, 'bad # of channels' + self._nchannels = nchannels + + def getnchannels(self): + if not self._nchannels: + raise Error, 'number of channels not set' + return self._nchannels + + def setsampwidth(self, sampwidth): + if self._datawritten: + raise Error, 'cannot change parameters after starting to write' + if sampwidth < 1 or sampwidth > 4: + raise Error, 'bad sample width' + self._sampwidth = sampwidth + + def getsampwidth(self): + if not self._sampwidth: + raise Error, 'sample width not set' + return self._sampwidth + + def setframerate(self, framerate): + if self._datawritten: + raise Error, 'cannot change parameters after starting to write' + if framerate <= 0: + raise Error, 'bad frame rate' + self._framerate = framerate + + def getframerate(self): + if not self._framerate: + raise Error, 'frame rate not set' + return self._framerate + + def setnframes(self, nframes): + if self._datawritten: + raise Error, 'cannot change parameters after starting to write' + self._nframes = nframes + + def getnframes(self): + return self._nframeswritten + + def setcomptype(self, comptype, compname): + if self._datawritten: + raise Error, 'cannot change parameters after starting to write' + if comptype not in ('NONE',): + raise Error, 'unsupported compression type' + self._comptype = comptype + self._compname = compname + + def getcomptype(self): + return self._comptype + + def getcompname(self): + return self._compname + + def setparams(self, (nchannels, sampwidth, framerate, nframes, comptype, compname)): + if self._datawritten: + raise Error, 'cannot change parameters after starting to write' + self.setnchannels(nchannels) + self.setsampwidth(sampwidth) + self.setframerate(framerate) + self.setnframes(nframes) + self.setcomptype(comptype, compname) + + def getparams(self): + if not self._nchannels or not self._sampwidth or not self._framerate: + raise Error, 'not all parameters set' + return self._nchannels, self._sampwidth, self._framerate, \ + self._nframes, self._comptype, self._compname + + def setmark(self, id, pos, name): + raise Error, 'setmark() not supported' + + def getmark(self, id): + raise Error, 'no marks' + + def getmarkers(self): + return None + + def tell(self): + return self._nframeswritten + + def writeframesraw(self, data): + self._ensure_header_written(len(data)) + nframes = len(data) / (self._sampwidth * self._nchannels) + if self._convert: + data = self._convert(data) + if self._sampwidth > 1 and big_endian: + import array + data = array.array(_array_fmts[self._sampwidth], data) + data.byteswap() + data.tofile(self._file) + self._datawritten = self._datawritten + len(data) * self._sampwidth + else: + self._file.write(data) + self._datawritten = self._datawritten + len(data) + self._nframeswritten = self._nframeswritten + nframes + + def writeframes(self, data): + self.writeframesraw(data) + if self._datalength != self._datawritten: + self._patchheader() + + def close(self): + self._ensure_header_written(0) + if self._datalength != self._datawritten: + self._patchheader() + self._file.flush() + self._file = None + + # + # Internal methods. + # + + def _ensure_header_written(self, datasize): + if not self._datawritten: + if not self._nchannels: + raise Error, '# channels not specified' + if not self._sampwidth: + raise Error, 'sample width not specified' + if not self._framerate: + raise Error, 'sampling rate not specified' + self._write_header(datasize) + + def _write_header(self, initlength): + self._file.write('RIFF') + if not self._nframes: + self._nframes = initlength / (self._nchannels * self._sampwidth) + self._datalength = self._nframes * self._nchannels * self._sampwidth + self._form_length_pos = self._file.tell() + self._file.write(struct.pack('<lsslhhllhhs', + 36 + self._datalength, 'WAVE', 'fmt ', 16, + WAVE_FORMAT_PCM, self._nchannels, self._framerate, + self._nchannels * self._framerate * self._sampwidth, + self._nchannels * self._sampwidth, + self._sampwidth * 8, 'data')) + self._data_length_pos = self._file.tell() + self._file.write(struct.pack('<l', self._datalength)) + + def _patchheader(self): + if self._datawritten == self._datalength: + return + curpos = self._file.tell() + self._file.seek(self._form_length_pos, 0) + self._file.write(struct.pack('<l', 36 + self._datawritten)) + self._file.seek(self._data_length_pos, 0) + self._file.write(struct.pack('<l', self._datawritten)) + self._file.seek(curpos, 0) + self._datalength = self._datawritten def open(f, mode=None): - if mode is None: - if hasattr(f, 'mode'): - mode = f.mode - else: - mode = 'rb' - if mode in ('r', 'rb'): - return Wave_read(f) - elif mode in ('w', 'wb'): - return Wave_write(f) - else: - raise Error, "mode must be 'r', 'rb', 'w', or 'wb'" + if mode is None: + if hasattr(f, 'mode'): + mode = f.mode + else: + mode = 'rb' + if mode in ('r', 'rb'): + return Wave_read(f) + elif mode in ('w', 'wb'): + return Wave_write(f) + else: + raise Error, "mode must be 'r', 'rb', 'w', or 'wb'" openfp = open # B/W compatibility |