wave.py revision f8cc2870f16e386476c6a62c4688a7bdd28dbaad
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):
183e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._file = None
1841aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka        file = self._i_opened_the_file
1851aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka        if file:
1861aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka            self._i_opened_the_file = None
1871aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka            file.close()
188e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
189e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def tell(self):
190e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._soundpos
191e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
192e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getnchannels(self):
193e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._nchannels
194e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
195e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getnframes(self):
196e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._nframes
197e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
198e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getsampwidth(self):
199e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._sampwidth
200e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
201e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getframerate(self):
202e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._framerate
203e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
204e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getcomptype(self):
205e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._comptype
206e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
207e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getcompname(self):
208e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._compname
209e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
210e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getparams(self):
211e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self.getnchannels(), self.getsampwidth(), \
212e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum               self.getframerate(), self.getnframes(), \
213e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum               self.getcomptype(), self.getcompname()
214e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
215e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getmarkers(self):
216e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return None
217e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
218e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getmark(self, id):
219e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        raise Error, 'no marks'
220e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
221e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def setpos(self, pos):
222e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if pos < 0 or pos > self._nframes:
223e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'position not in range'
224e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._soundpos = pos
225e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._data_seek_needed = 1
226e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
227e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def readframes(self, nframes):
228e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if self._data_seek_needed:
229e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            self._data_chunk.seek(0, 0)
230e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            pos = self._soundpos * self._framesize
231e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            if pos:
232e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum                self._data_chunk.seek(pos, 0)
233e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            self._data_seek_needed = 0
234e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if nframes == 0:
235e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            return ''
236c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka        if self._sampwidth in (2, 4) and sys.byteorder == 'big':
237e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            # unfortunately the fromfile() method does not take
238e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            # something that only looks like a file object, so
239e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            # we have to reach into the innards of the chunk object
240e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            import array
241e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            chunk = self._data_chunk
242e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            data = array.array(_array_fmts[self._sampwidth])
2437137803238ff54ae339e09ff676f6631000cfb28Serhiy Storchaka            assert data.itemsize == self._sampwidth
244e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            nitems = nframes * self._nchannels
245e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            if nitems * self._sampwidth > chunk.chunksize - chunk.size_read:
246f8cc2870f16e386476c6a62c4688a7bdd28dbaadSerhiy Storchaka                nitems = (chunk.chunksize - chunk.size_read) // self._sampwidth
247e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            data.fromfile(chunk.file.file, nitems)
248e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            # "tell" data chunk how much was read
249e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            chunk.size_read = chunk.size_read + nitems * self._sampwidth
250e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            # do the same for the outermost chunk
251e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            chunk = chunk.file
252e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            chunk.size_read = chunk.size_read + nitems * self._sampwidth
253e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            data.byteswap()
254e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            data = data.tostring()
255e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        else:
256e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            data = self._data_chunk.read(nframes * self._framesize)
257c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka            if self._sampwidth == 3 and sys.byteorder == 'big':
258c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka                data = _byteswap3(data)
259e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if self._convert and data:
260e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            data = self._convert(data)
26154e54c6877329e105406c48490f218faff59db39Guido van Rossum        self._soundpos = self._soundpos + len(data) // (self._nchannels * self._sampwidth)
262e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return data
263e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
264e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    #
265e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    # Internal methods.
266e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    #
267e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
268e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def _read_fmt_chunk(self, chunk):
269f34e4de3f5f4ae1c695773457349386722ae0719Jesus Cea        wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack('<HHLLH', chunk.read(14))
270e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if wFormatTag == WAVE_FORMAT_PCM:
271f34e4de3f5f4ae1c695773457349386722ae0719Jesus Cea            sampwidth = struct.unpack('<H', chunk.read(2))[0]
27254e54c6877329e105406c48490f218faff59db39Guido van Rossum            self._sampwidth = (sampwidth + 7) // 8
273e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        else:
27470a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald            raise Error, 'unknown format: %r' % (wFormatTag,)
275e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._framesize = self._nchannels * self._sampwidth
276e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._comptype = 'NONE'
277e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._compname = 'not compressed'
2783ed23cc158f6609742229a7d912ace5533595a86Guido van Rossum
2793ed23cc158f6609742229a7d912ace5533595a86Guido van Rossumclass Wave_write:
280e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    """Variables used in this class:
281e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
282e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    These variables are user settable through appropriate methods
283e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    of this class:
284e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    _file -- the open file with methods write(), close(), tell(), seek()
285e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum              set through the __init__() method
286e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    _comptype -- the AIFF-C compression type ('NONE' in AIFF)
287e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum              set through the setcomptype() or setparams() method
288e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    _compname -- the human-readable AIFF-C compression type
289e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum              set through the setcomptype() or setparams() method
290e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    _nchannels -- the number of audio channels
291e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum              set through the setnchannels() or setparams() method
292e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    _sampwidth -- the number of bytes per audio sample
293e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum              set through the setsampwidth() or setparams() method
294e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    _framerate -- the sampling frequency
295e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum              set through the setframerate() or setparams() method
296e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    _nframes -- the number of audio frames written to the header
297e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum              set through the setnframes() or setparams() method
298e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
299e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    These variables are used internally only:
300e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    _datalength -- the size of the audio samples written to the header
301e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    _nframeswritten -- the number of frames actually written
302e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    _datawritten -- the size of the audio samples actually written
303e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    """
304e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
305e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def __init__(self, f):
306cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters        self._i_opened_the_file = None
3070e67fd478f04d8634ea1e196e6ade2c4394984eeNeal Norwitz        if isinstance(f, basestring):
308e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            f = __builtin__.open(f, 'wb')
309cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters            self._i_opened_the_file = f
310ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl        try:
311ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl            self.initfp(f)
312ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl        except:
313ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl            if self._i_opened_the_file:
314ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl                f.close()
315ab1f4674ad14eb1430489a458c7654aa1ac9c51eGeorg Brandl            raise
316e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
317e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def initfp(self, file):
318e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._file = file
319e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._convert = None
320e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._nchannels = 0
321e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._sampwidth = 0
322e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._framerate = 0
323e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._nframes = 0
324e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._nframeswritten = 0
325e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._datawritten = 0
326e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._datalength = 0
327ef805a6b17198c11c357462ca581c065b4e722a8Georg Brandl        self._headerwritten = False
328e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
329e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def __del__(self):
330cfc4178e843f5f2b0f190bacd222c0f72ab91e53Tim Peters        self.close()
331e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
332e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    #
333e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    # User visible methods.
334e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    #
335e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def setnchannels(self, nchannels):
336e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if self._datawritten:
337e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'cannot change parameters after starting to write'
338e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if nchannels < 1:
339e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'bad # of channels'
340e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._nchannels = nchannels
341e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
342e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getnchannels(self):
343e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if not self._nchannels:
344e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'number of channels not set'
345e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._nchannels
346e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
347e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def setsampwidth(self, sampwidth):
348e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if self._datawritten:
349e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'cannot change parameters after starting to write'
350e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if sampwidth < 1 or sampwidth > 4:
351e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'bad sample width'
352e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._sampwidth = sampwidth
353e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
354e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getsampwidth(self):
355e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if not self._sampwidth:
356e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'sample width not set'
357e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._sampwidth
358e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
359e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def setframerate(self, framerate):
360e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if self._datawritten:
361e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'cannot change parameters after starting to write'
362e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if framerate <= 0:
363e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'bad frame rate'
364e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._framerate = framerate
365e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
366e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getframerate(self):
367e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if not self._framerate:
368e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'frame rate not set'
369e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._framerate
370e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
371e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def setnframes(self, nframes):
372e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if self._datawritten:
373e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'cannot change parameters after starting to write'
374e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._nframes = nframes
375e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
376e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getnframes(self):
377e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._nframeswritten
378e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
379e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def setcomptype(self, comptype, compname):
380e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if self._datawritten:
381e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'cannot change parameters after starting to write'
382e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if comptype not in ('NONE',):
383e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'unsupported compression type'
384e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._comptype = comptype
385e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._compname = compname
386e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
387e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getcomptype(self):
388e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._comptype
389e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
390e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getcompname(self):
391e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._compname
392e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
393b9d4963a989accce30234b7b74bce874c0142209Antoine Pitrou    def setparams(self, params):
394b9d4963a989accce30234b7b74bce874c0142209Antoine Pitrou        nchannels, sampwidth, framerate, nframes, comptype, compname = params
395e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if self._datawritten:
396e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'cannot change parameters after starting to write'
397e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self.setnchannels(nchannels)
398e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self.setsampwidth(sampwidth)
399e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self.setframerate(framerate)
400e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self.setnframes(nframes)
401e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self.setcomptype(comptype, compname)
402e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
403e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getparams(self):
404e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if not self._nchannels or not self._sampwidth or not self._framerate:
405e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            raise Error, 'not all parameters set'
406e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._nchannels, self._sampwidth, self._framerate, \
407e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum              self._nframes, self._comptype, self._compname
408e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
409e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def setmark(self, id, pos, name):
410e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        raise Error, 'setmark() not supported'
411e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
412e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getmark(self, id):
413e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        raise Error, 'no marks'
414e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
415e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def getmarkers(self):
416e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return None
417e119006e7dc0df0a5ff6b60764b2ce3cd9477688Tim Peters
418e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def tell(self):
419e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return self._nframeswritten
420e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
421e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def writeframesraw(self, data):
422e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._ensure_header_written(len(data))
42354e54c6877329e105406c48490f218faff59db39Guido van Rossum        nframes = len(data) // (self._sampwidth * self._nchannels)
424e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if self._convert:
425e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            data = self._convert(data)
426c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka        if self._sampwidth in (2, 4) and sys.byteorder == 'big':
427e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            import array
4285397c97451413b544593313651964facf9502c4aSerhiy Storchaka            a = array.array(_array_fmts[self._sampwidth])
4295397c97451413b544593313651964facf9502c4aSerhiy Storchaka            a.fromstring(data)
4305397c97451413b544593313651964facf9502c4aSerhiy Storchaka            data = a
4317137803238ff54ae339e09ff676f6631000cfb28Serhiy Storchaka            assert data.itemsize == self._sampwidth
432e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            data.byteswap()
433e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            data.tofile(self._file)
434e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            self._datawritten = self._datawritten + len(data) * self._sampwidth
435e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        else:
436c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka            if self._sampwidth == 3 and sys.byteorder == 'big':
437c47d723eb017636aea8504861b4465067aabd9d6Serhiy Storchaka                data = _byteswap3(data)
438e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            self._file.write(data)
439e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            self._datawritten = self._datawritten + len(data)
440e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._nframeswritten = self._nframeswritten + nframes
441e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
442e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def writeframes(self, data):
443e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self.writeframesraw(data)
444e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if self._datalength != self._datawritten:
445e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            self._patchheader()
446e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
447e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def close(self):
4481aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka        try:
4491aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka            if self._file:
450499d82136dbe48680b9a90e7e5f4ed48eea7866aSerhiy Storchaka                self._ensure_header_written(0)
451499d82136dbe48680b9a90e7e5f4ed48eea7866aSerhiy Storchaka                if self._datalength != self._datawritten:
452499d82136dbe48680b9a90e7e5f4ed48eea7866aSerhiy Storchaka                    self._patchheader()
453499d82136dbe48680b9a90e7e5f4ed48eea7866aSerhiy Storchaka                self._file.flush()
4541aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka        finally:
4551aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka            self._file = None
4561aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka            file = self._i_opened_the_file
4571aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka            if file:
4581aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka                self._i_opened_the_file = None
4591aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka                file.close()
460e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
461e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    #
462e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    # Internal methods.
463e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    #
464e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
465e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def _ensure_header_written(self, datasize):
466ef805a6b17198c11c357462ca581c065b4e722a8Georg Brandl        if not self._headerwritten:
467e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            if not self._nchannels:
468e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum                raise Error, '# channels not specified'
469e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            if not self._sampwidth:
470e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum                raise Error, 'sample width not specified'
471e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            if not self._framerate:
472e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum                raise Error, 'sampling rate not specified'
473e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            self._write_header(datasize)
474e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
475e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def _write_header(self, initlength):
476ef805a6b17198c11c357462ca581c065b4e722a8Georg Brandl        assert not self._headerwritten
477e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._file.write('RIFF')
478e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if not self._nframes:
479e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            self._nframes = initlength / (self._nchannels * self._sampwidth)
480e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._datalength = self._nframes * self._nchannels * self._sampwidth
481e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._form_length_pos = self._file.tell()
482f34e4de3f5f4ae1c695773457349386722ae0719Jesus Cea        self._file.write(struct.pack('<L4s4sLHHLLHH4s',
483e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            36 + self._datalength, 'WAVE', 'fmt ', 16,
484e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            WAVE_FORMAT_PCM, self._nchannels, self._framerate,
485e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            self._nchannels * self._framerate * self._sampwidth,
486e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            self._nchannels * self._sampwidth,
487e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            self._sampwidth * 8, 'data'))
488e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._data_length_pos = self._file.tell()
489f34e4de3f5f4ae1c695773457349386722ae0719Jesus Cea        self._file.write(struct.pack('<L', self._datalength))
490ef805a6b17198c11c357462ca581c065b4e722a8Georg Brandl        self._headerwritten = True
491e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum
492e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    def _patchheader(self):
493ef805a6b17198c11c357462ca581c065b4e722a8Georg Brandl        assert self._headerwritten
494e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if self._datawritten == self._datalength:
495e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            return
496e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        curpos = self._file.tell()
497e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._file.seek(self._form_length_pos, 0)
498f34e4de3f5f4ae1c695773457349386722ae0719Jesus Cea        self._file.write(struct.pack('<L', 36 + self._datawritten))
499e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._file.seek(self._data_length_pos, 0)
500f34e4de3f5f4ae1c695773457349386722ae0719Jesus Cea        self._file.write(struct.pack('<L', self._datawritten))
501e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._file.seek(curpos, 0)
502e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        self._datalength = self._datawritten
5033ed23cc158f6609742229a7d912ace5533595a86Guido van Rossum
504f9607821ade54ec75d8d91952b64ecf1bfde4923Fred Drakedef open(f, mode=None):
505e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    if mode is None:
506e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        if hasattr(f, 'mode'):
507e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            mode = f.mode
508e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        else:
509e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum            mode = 'rb'
510e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    if mode in ('r', 'rb'):
511e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return Wave_read(f)
512e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    elif mode in ('w', 'wb'):
513e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        return Wave_write(f)
514e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum    else:
515e7b146fb3bdca62a0d5ecc06dbf3348e5a4fe757Guido van Rossum        raise Error, "mode must be 'r', 'rb', 'w', or 'wb'"
5163ed23cc158f6609742229a7d912ace5533595a86Guido van Rossum
5173ed23cc158f6609742229a7d912ace5533595a86Guido van Rossumopenfp = open # B/W compatibility
518