wave.py revision 5397c97451413b544593313651964facf9502c4a
1e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum"""Stuff to parse WAVE files. 2e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 3e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumUsage. 4e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 5e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumReading WAVE files: 6e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum f = wave.open(file, 'r') 7e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossumwhere file is either the name of a file or an open file pointer. 8e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumThe open file pointer must have methods read(), seek(), and close(). 9e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumWhen the setpos() and rewind() methods are not used, the seek() 10e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossummethod is not necessary. 11e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 12e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumThis returns an instance of a class with the following public methods: 13e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum getnchannels() -- returns number of audio channels (1 for 14e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum mono, 2 for stereo) 15e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum getsampwidth() -- returns sample width in bytes 16e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum getframerate() -- returns sampling frequency 17e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum getnframes() -- returns number of audio frames 18e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum getcomptype() -- returns compression type ('NONE' for linear samples) 19e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum getcompname() -- returns human-readable version of 20e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum compression type ('not compressed' linear samples) 21e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum getparams() -- returns a tuple consisting of all of the 22e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum above in the above order 23e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum getmarkers() -- returns None (for compatibility with the 24e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum aifc module) 25e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum getmark(id) -- raises an error since the mark does not 26e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum exist (for compatibility with the aifc module) 27e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum readframes(n) -- returns at most n frames of audio 28e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum rewind() -- rewind to the beginning of the audio stream 29e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum setpos(pos) -- seek to the specified position 30e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum tell() -- return the current position 31e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum close() -- close the instance (make it unusable) 32e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumThe position returned by tell() and the position given to setpos() 337e47402264cf87b9bbb61fc9ff610af08add7c7bThomas Woutersare compatible and have nothing to do with the actual position in the 34e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossumfile. 35e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumThe close() method is called automatically when the class instance 36e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossumis destroyed. 37e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 38e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumWriting WAVE files: 39e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum f = wave.open(file, 'w') 40e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossumwhere file is either the name of a file or an open file pointer. 41e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumThe open file pointer must have methods write(), tell(), seek(), and 42e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossumclose(). 43e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 44e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumThis returns an instance of a class with the following public methods: 45e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum setnchannels(n) -- set the number of channels 46e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum setsampwidth(n) -- set the sample width 47e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum setframerate(n) -- set the frame rate 48e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum setnframes(n) -- set the number of frames 49e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum setcomptype(type, name) 50e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum -- set the compression type and the 51e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum human-readable compression type 52e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum setparams(tuple) 53e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum -- set all parameters at once 54e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum tell() -- return current position in output file 55e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum writeframesraw(data) 56e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum -- write audio frames without pathing up the 57e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum file header 58e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum writeframes(data) 59e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum -- write audio frames and patch up the file header 60e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum close() -- patch up the file header and close the 61e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum output file 62e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumYou should set the parameters before the first writeframesraw or 63e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossumwriteframes. The total number of frames does not need to be set, 64e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossumbut when it is set to the correct value, the header does not have to 65e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossumbe patched up. 66e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumIt is best to first set all parameters, perhaps possibly the 67e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossumcompression type, and then write audio frames using writeframesraw. 68e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumWhen all frames have been written, either call writeframes('') or 69e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossumclose() to patch up the sizes in the header. 70e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van RossumThe close() method is called automatically when the class instance 71e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossumis destroyed. 72e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum""" 733ed23cc158f6609742229a7d912ace5533595a86Guido van Rossum 743ed23cc158f6609742229a7d912ace5533595a86Guido van Rossumimport __builtin__ 753ed23cc158f6609742229a7d912ace5533595a86Guido van Rossum 7640fc16059f04ee8fda0b5956cc4883eb21ca8f8cSkip Montanaro__all__ = ["open", "openfp", "Error"] 7740fc16059f04ee8fda0b5956cc4883eb21ca8f8cSkip Montanaro 789b8d801c37fa29420848ebc1b50c601893b36287Fred Drakeclass Error(Exception): 799b8d801c37fa29420848ebc1b50c601893b36287Fred Drake pass 803ed23cc158f6609742229a7d912ace5533595a86Guido van Rossum 813ed23cc158f6609742229a7d912ace5533595a86Guido van RossumWAVE_FORMAT_PCM = 0x0001 823ed23cc158f6609742229a7d912ace5533595a86Guido van Rossum 837137803238ff54ae339e09ff676f6631000cfb28Serhiy Storchaka_array_fmts = None, 'b', 'h', None, 'i' 843ed23cc158f6609742229a7d912ace5533595a86Guido van Rossum 85ebb9c922cb1f1b72fe929cfba223e42df7492a1cGuido van Rossumimport struct 86c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchakaimport sys 873601e88cb3a41f805216e9b9feda591f678f4014Guido van Rossumfrom chunk import Chunk 883ed23cc158f6609742229a7d912ace5533595a86Guido van Rossum 89c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchakadef _byteswap3(data): 90c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka ba = bytearray(data) 91c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka ba[::3] = data[2::3] 92c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka ba[2::3] = data[::3] 93c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka return bytes(ba) 94c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka 953ed23cc158f6609742229a7d912ace5533595a86Guido van Rossumclass Wave_read: 96e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum """Variables used in this class: 97e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 98e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum These variables are available to the user though appropriate 99e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum methods of this class: 100e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _file -- the open file with methods read(), close(), and seek() 101e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum set through the __init__() method 102e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _nchannels -- the number of audio channels 103e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum available through the getnchannels() method 104e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _nframes -- the number of audio frames 105e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum available through the getnframes() method 106e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _sampwidth -- the number of bytes per audio sample 107e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum available through the getsampwidth() method 108e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _framerate -- the sampling frequency 109e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum available through the getframerate() method 110e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _comptype -- the AIFF-C compression type ('NONE' if AIFF) 111e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum available through the getcomptype() method 112e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _compname -- the human-readable AIFF-C compression type 113e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum available through the getcomptype() method 114e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _soundpos -- the position in the audio stream 115e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum available through the tell() method, set through the 116e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum setpos() method 117e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 118e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum These variables are used internally only: 119e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _fmt_chunk_read -- 1 iff the FMT chunk has been read 120e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _data_seek_needed -- 1 iff positioned correctly in audio 121e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum file for readframes() 122e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _data_chunk -- instantiation of a chunk class for the DATA chunk 123e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _framesize -- size of one frame in the file 124e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum """ 125e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 126e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def initfp(self, file): 127e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._convert = None 128e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._soundpos = 0 129e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._file = Chunk(file, bigendian = 0) 130e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._file.getname() != 'RIFF': 131e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'file does not start with RIFF id' 132e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._file.read(4) != 'WAVE': 133e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'not a WAVE file' 134e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._fmt_chunk_read = 0 135e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._data_chunk = None 136e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum while 1: 137e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._data_seek_needed = 1 138e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum try: 139e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum chunk = Chunk(self._file, bigendian = 0) 140e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum except EOFError: 141e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum break 142e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum chunkname = chunk.getname() 143e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if chunkname == 'fmt ': 144e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._read_fmt_chunk(chunk) 145e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._fmt_chunk_read = 1 146e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum elif chunkname == 'data': 147e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if not self._fmt_chunk_read: 148e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'data chunk before fmt chunk' 149e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._data_chunk = chunk 15054e54c6877329e105406c48490f218faff59db39Guido van Rossum self._nframes = chunk.chunksize // self._framesize 151e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._data_seek_needed = 0 152e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum break 153e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum chunk.skip() 154e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if not self._fmt_chunk_read or not self._data_chunk: 155e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'fmt chunk and/or data chunk missing' 156e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 157e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def __init__(self, f): 158cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters self._i_opened_the_file = None 1590e67fd478f04d8634ea1e196e6ade2c4394984eeNeal Norwitz if isinstance(f, basestring): 160e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum f = __builtin__.open(f, 'rb') 161cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters self._i_opened_the_file = f 162e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # else, assume it is an open file object already 163ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl try: 164ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl self.initfp(f) 165ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl except: 166ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl if self._i_opened_the_file: 167ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl f.close() 168ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl raise 169e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 170cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters def __del__(self): 171cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters self.close() 172e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # 173e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # User visible methods. 174e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # 175e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getfp(self): 176e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._file 177e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 178e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def rewind(self): 179e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._data_seek_needed = 1 180e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._soundpos = 0 181e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 182e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def close(self): 183cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters if self._i_opened_the_file: 184cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters self._i_opened_the_file.close() 185cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters self._i_opened_the_file = None 186e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._file = None 187e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 188e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def tell(self): 189e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._soundpos 190e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 191e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getnchannels(self): 192e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._nchannels 193e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 194e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getnframes(self): 195e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._nframes 196e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 197e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getsampwidth(self): 198e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._sampwidth 199e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 200e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getframerate(self): 201e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._framerate 202e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 203e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getcomptype(self): 204e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._comptype 205e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 206e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getcompname(self): 207e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._compname 208e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 209e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getparams(self): 210e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self.getnchannels(), self.getsampwidth(), \ 211e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self.getframerate(), self.getnframes(), \ 212e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self.getcomptype(), self.getcompname() 213e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 214e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getmarkers(self): 215e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return None 216e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 217e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getmark(self, id): 218e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'no marks' 219e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 220e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def setpos(self, pos): 221e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if pos < 0 or pos > self._nframes: 222e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'position not in range' 223e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._soundpos = pos 224e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._data_seek_needed = 1 225e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 226e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def readframes(self, nframes): 227e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._data_seek_needed: 228e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._data_chunk.seek(0, 0) 229e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum pos = self._soundpos * self._framesize 230e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if pos: 231e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._data_chunk.seek(pos, 0) 232e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._data_seek_needed = 0 233e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if nframes == 0: 234e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return '' 235c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka if self._sampwidth in (2, 4) and sys.byteorder == 'big': 236e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # unfortunately the fromfile() method does not take 237e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # something that only looks like a file object, so 238e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # we have to reach into the innards of the chunk object 239e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum import array 240e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum chunk = self._data_chunk 241e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum data = array.array(_array_fmts[self._sampwidth]) 2427137803238ff54ae339e09ff676f6631000cfb28Serhiy Storchaka assert data.itemsize == self._sampwidth 243e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum nitems = nframes * self._nchannels 244e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if nitems * self._sampwidth > chunk.chunksize - chunk.size_read: 245e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum nitems = (chunk.chunksize - chunk.size_read) / self._sampwidth 246e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum data.fromfile(chunk.file.file, nitems) 247e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # "tell" data chunk how much was read 248e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum chunk.size_read = chunk.size_read + nitems * self._sampwidth 249e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # do the same for the outermost chunk 250e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum chunk = chunk.file 251e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum chunk.size_read = chunk.size_read + nitems * self._sampwidth 252e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum data.byteswap() 253e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum data = data.tostring() 254e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum else: 255e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum data = self._data_chunk.read(nframes * self._framesize) 256c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka if self._sampwidth == 3 and sys.byteorder == 'big': 257c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka data = _byteswap3(data) 258e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._convert and data: 259e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum data = self._convert(data) 26054e54c6877329e105406c48490f218faff59db39Guido van Rossum self._soundpos = self._soundpos + len(data) // (self._nchannels * self._sampwidth) 261e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return data 262e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 263e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # 264e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # Internal methods. 265e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # 266e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 267e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def _read_fmt_chunk(self, chunk): 268f34e4de3f5f4ae1c695773457349386722ae0719Jesus Cea wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack('<HHLLH', chunk.read(14)) 269e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if wFormatTag == WAVE_FORMAT_PCM: 270f34e4de3f5f4ae1c695773457349386722ae0719Jesus Cea sampwidth = struct.unpack('<H', chunk.read(2))[0] 27154e54c6877329e105406c48490f218faff59db39Guido van Rossum self._sampwidth = (sampwidth + 7) // 8 272e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum else: 27370a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald raise Error, 'unknown format: %r' % (wFormatTag,) 274e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._framesize = self._nchannels * self._sampwidth 275e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._comptype = 'NONE' 276e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._compname = 'not compressed' 2773ed23cc158f6609742229a7d912ace5533595a86Guido van Rossum 2783ed23cc158f6609742229a7d912ace5533595a86Guido van Rossumclass Wave_write: 279e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum """Variables used in this class: 280e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 281e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum These variables are user settable through appropriate methods 282e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum of this class: 283e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _file -- the open file with methods write(), close(), tell(), seek() 284e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum set through the __init__() method 285e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _comptype -- the AIFF-C compression type ('NONE' in AIFF) 286e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum set through the setcomptype() or setparams() method 287e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _compname -- the human-readable AIFF-C compression type 288e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum set through the setcomptype() or setparams() method 289e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _nchannels -- the number of audio channels 290e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum set through the setnchannels() or setparams() method 291e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _sampwidth -- the number of bytes per audio sample 292e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum set through the setsampwidth() or setparams() method 293e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _framerate -- the sampling frequency 294e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum set through the setframerate() or setparams() method 295e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _nframes -- the number of audio frames written to the header 296e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum set through the setnframes() or setparams() method 297e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 298e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum These variables are used internally only: 299e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _datalength -- the size of the audio samples written to the header 300e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _nframeswritten -- the number of frames actually written 301e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum _datawritten -- the size of the audio samples actually written 302e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum """ 303e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 304e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def __init__(self, f): 305cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters self._i_opened_the_file = None 3060e67fd478f04d8634ea1e196e6ade2c4394984eeNeal Norwitz if isinstance(f, basestring): 307e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum f = __builtin__.open(f, 'wb') 308cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters self._i_opened_the_file = f 309ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl try: 310ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl self.initfp(f) 311ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl except: 312ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl if self._i_opened_the_file: 313ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl f.close() 314ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl raise 315e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 316e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def initfp(self, file): 317e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._file = file 318e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._convert = None 319e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._nchannels = 0 320e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._sampwidth = 0 321e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._framerate = 0 322e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._nframes = 0 323e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._nframeswritten = 0 324e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._datawritten = 0 325e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._datalength = 0 326ef805a6b17198c11c357462ca581c065b4e722a8Georg Brandl self._headerwritten = False 327e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 328e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def __del__(self): 329cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters self.close() 330e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 331e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # 332e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # User visible methods. 333e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # 334e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def setnchannels(self, nchannels): 335e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._datawritten: 336e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'cannot change parameters after starting to write' 337e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if nchannels < 1: 338e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'bad # of channels' 339e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._nchannels = nchannels 340e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 341e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getnchannels(self): 342e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if not self._nchannels: 343e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'number of channels not set' 344e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._nchannels 345e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 346e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def setsampwidth(self, sampwidth): 347e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._datawritten: 348e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'cannot change parameters after starting to write' 349e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if sampwidth < 1 or sampwidth > 4: 350e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'bad sample width' 351e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._sampwidth = sampwidth 352e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 353e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getsampwidth(self): 354e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if not self._sampwidth: 355e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'sample width not set' 356e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._sampwidth 357e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 358e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def setframerate(self, framerate): 359e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._datawritten: 360e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'cannot change parameters after starting to write' 361e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if framerate <= 0: 362e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'bad frame rate' 363e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._framerate = framerate 364e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 365e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getframerate(self): 366e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if not self._framerate: 367e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'frame rate not set' 368e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._framerate 369e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 370e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def setnframes(self, nframes): 371e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._datawritten: 372e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'cannot change parameters after starting to write' 373e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._nframes = nframes 374e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 375e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getnframes(self): 376e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._nframeswritten 377e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 378e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def setcomptype(self, comptype, compname): 379e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._datawritten: 380e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'cannot change parameters after starting to write' 381e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if comptype not in ('NONE',): 382e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'unsupported compression type' 383e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._comptype = comptype 384e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._compname = compname 385e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 386e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getcomptype(self): 387e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._comptype 388e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 389e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getcompname(self): 390e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._compname 391e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 392b9d4963a989accce30234b7b74bce874c0142209Antoine Pitrou def setparams(self, params): 393b9d4963a989accce30234b7b74bce874c0142209Antoine Pitrou nchannels, sampwidth, framerate, nframes, comptype, compname = params 394e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._datawritten: 395e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'cannot change parameters after starting to write' 396e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self.setnchannels(nchannels) 397e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self.setsampwidth(sampwidth) 398e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self.setframerate(framerate) 399e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self.setnframes(nframes) 400e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self.setcomptype(comptype, compname) 401e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 402e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getparams(self): 403e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if not self._nchannels or not self._sampwidth or not self._framerate: 404e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'not all parameters set' 405e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._nchannels, self._sampwidth, self._framerate, \ 406e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._nframes, self._comptype, self._compname 407e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 408e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def setmark(self, id, pos, name): 409e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'setmark() not supported' 410e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 411e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getmark(self, id): 412e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'no marks' 413e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 414e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def getmarkers(self): 415e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return None 416e119006e7dc0df0a5ff6b60764b2ce3cd9477688Tim Peters 417e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def tell(self): 418e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return self._nframeswritten 419e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 420e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def writeframesraw(self, data): 421e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._ensure_header_written(len(data)) 42254e54c6877329e105406c48490f218faff59db39Guido van Rossum nframes = len(data) // (self._sampwidth * self._nchannels) 423e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._convert: 424e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum data = self._convert(data) 425c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka if self._sampwidth in (2, 4) and sys.byteorder == 'big': 426e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum import array 4275397c97451413b544593313651964facf9502c4aSerhiy Storchaka a = array.array(_array_fmts[self._sampwidth]) 4285397c97451413b544593313651964facf9502c4aSerhiy Storchaka a.fromstring(data) 4295397c97451413b544593313651964facf9502c4aSerhiy Storchaka data = a 4307137803238ff54ae339e09ff676f6631000cfb28Serhiy Storchaka assert data.itemsize == self._sampwidth 431e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum data.byteswap() 432e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum data.tofile(self._file) 433e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._datawritten = self._datawritten + len(data) * self._sampwidth 434e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum else: 435c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka if self._sampwidth == 3 and sys.byteorder == 'big': 436c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka data = _byteswap3(data) 437e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._file.write(data) 438e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._datawritten = self._datawritten + len(data) 439e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._nframeswritten = self._nframeswritten + nframes 440e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 441e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def writeframes(self, data): 442e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self.writeframesraw(data) 443e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._datalength != self._datawritten: 444e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._patchheader() 445e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 446e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def close(self): 447cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters if self._file: 448499d82136dbe48680b9a90e7e5f4ed48eea7866aSerhiy Storchaka try: 449499d82136dbe48680b9a90e7e5f4ed48eea7866aSerhiy Storchaka self._ensure_header_written(0) 450499d82136dbe48680b9a90e7e5f4ed48eea7866aSerhiy Storchaka if self._datalength != self._datawritten: 451499d82136dbe48680b9a90e7e5f4ed48eea7866aSerhiy Storchaka self._patchheader() 452499d82136dbe48680b9a90e7e5f4ed48eea7866aSerhiy Storchaka self._file.flush() 453499d82136dbe48680b9a90e7e5f4ed48eea7866aSerhiy Storchaka finally: 454499d82136dbe48680b9a90e7e5f4ed48eea7866aSerhiy Storchaka self._file = None 455cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters if self._i_opened_the_file: 456cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters self._i_opened_the_file.close() 457cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters self._i_opened_the_file = None 458e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 459e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # 460e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # Internal methods. 461e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum # 462e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 463e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def _ensure_header_written(self, datasize): 464ef805a6b17198c11c357462ca581c065b4e722a8Georg Brandl if not self._headerwritten: 465e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if not self._nchannels: 466e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, '# channels not specified' 467e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if not self._sampwidth: 468e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'sample width not specified' 469e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if not self._framerate: 470e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, 'sampling rate not specified' 471e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._write_header(datasize) 472e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 473e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def _write_header(self, initlength): 474ef805a6b17198c11c357462ca581c065b4e722a8Georg Brandl assert not self._headerwritten 475e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._file.write('RIFF') 476e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if not self._nframes: 477e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._nframes = initlength / (self._nchannels * self._sampwidth) 478e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._datalength = self._nframes * self._nchannels * self._sampwidth 479e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._form_length_pos = self._file.tell() 480f34e4de3f5f4ae1c695773457349386722ae0719Jesus Cea self._file.write(struct.pack('<L4s4sLHHLLHH4s', 481e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 36 + self._datalength, 'WAVE', 'fmt ', 16, 482e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum WAVE_FORMAT_PCM, self._nchannels, self._framerate, 483e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._nchannels * self._framerate * self._sampwidth, 484e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._nchannels * self._sampwidth, 485e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._sampwidth * 8, 'data')) 486e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._data_length_pos = self._file.tell() 487f34e4de3f5f4ae1c695773457349386722ae0719Jesus Cea self._file.write(struct.pack('<L', self._datalength)) 488ef805a6b17198c11c357462ca581c065b4e722a8Georg Brandl self._headerwritten = True 489e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum 490e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum def _patchheader(self): 491ef805a6b17198c11c357462ca581c065b4e722a8Georg Brandl assert self._headerwritten 492e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if self._datawritten == self._datalength: 493e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return 494e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum curpos = self._file.tell() 495e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._file.seek(self._form_length_pos, 0) 496f34e4de3f5f4ae1c695773457349386722ae0719Jesus Cea self._file.write(struct.pack('<L', 36 + self._datawritten)) 497e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._file.seek(self._data_length_pos, 0) 498f34e4de3f5f4ae1c695773457349386722ae0719Jesus Cea self._file.write(struct.pack('<L', self._datawritten)) 499e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._file.seek(curpos, 0) 500e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum self._datalength = self._datawritten 5013ed23cc158f6609742229a7d912ace5533595a86Guido van Rossum 502f9607821ade54ec75d8d91952b64ecf1bfde4923Fred Drakedef open(f, mode=None): 503e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if mode is None: 504e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if hasattr(f, 'mode'): 505e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum mode = f.mode 506e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum else: 507e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum mode = 'rb' 508e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum if mode in ('r', 'rb'): 509e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return Wave_read(f) 510e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum elif mode in ('w', 'wb'): 511e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum return Wave_write(f) 512e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum else: 513e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum raise Error, "mode must be 'r', 'rb', 'w', or 'wb'" 5143ed23cc158f6609742229a7d912ace5533595a86Guido van Rossum 5153ed23cc158f6609742229a7d912ace5533595a86Guido van Rossumopenfp = open # B/W compatibility 516