]> git.proxmox.com Git - mirror_edk2.git/blame - AppPkg/Applications/Python/Python-2.7.2/Lib/wave.py
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Lib / wave.py
CommitLineData
4710c53d 1"""Stuff to parse WAVE files.\r
2\r
3Usage.\r
4\r
5Reading WAVE files:\r
6 f = wave.open(file, 'r')\r
7where file is either the name of a file or an open file pointer.\r
8The open file pointer must have methods read(), seek(), and close().\r
9When the setpos() and rewind() methods are not used, the seek()\r
10method is not necessary.\r
11\r
12This returns an instance of a class with the following public methods:\r
13 getnchannels() -- returns number of audio channels (1 for\r
14 mono, 2 for stereo)\r
15 getsampwidth() -- returns sample width in bytes\r
16 getframerate() -- returns sampling frequency\r
17 getnframes() -- returns number of audio frames\r
18 getcomptype() -- returns compression type ('NONE' for linear samples)\r
19 getcompname() -- returns human-readable version of\r
20 compression type ('not compressed' linear samples)\r
21 getparams() -- returns a tuple consisting of all of the\r
22 above in the above order\r
23 getmarkers() -- returns None (for compatibility with the\r
24 aifc module)\r
25 getmark(id) -- raises an error since the mark does not\r
26 exist (for compatibility with the aifc module)\r
27 readframes(n) -- returns at most n frames of audio\r
28 rewind() -- rewind to the beginning of the audio stream\r
29 setpos(pos) -- seek to the specified position\r
30 tell() -- return the current position\r
31 close() -- close the instance (make it unusable)\r
32The position returned by tell() and the position given to setpos()\r
33are compatible and have nothing to do with the actual position in the\r
34file.\r
35The close() method is called automatically when the class instance\r
36is destroyed.\r
37\r
38Writing WAVE files:\r
39 f = wave.open(file, 'w')\r
40where file is either the name of a file or an open file pointer.\r
41The open file pointer must have methods write(), tell(), seek(), and\r
42close().\r
43\r
44This returns an instance of a class with the following public methods:\r
45 setnchannels(n) -- set the number of channels\r
46 setsampwidth(n) -- set the sample width\r
47 setframerate(n) -- set the frame rate\r
48 setnframes(n) -- set the number of frames\r
49 setcomptype(type, name)\r
50 -- set the compression type and the\r
51 human-readable compression type\r
52 setparams(tuple)\r
53 -- set all parameters at once\r
54 tell() -- return current position in output file\r
55 writeframesraw(data)\r
56 -- write audio frames without pathing up the\r
57 file header\r
58 writeframes(data)\r
59 -- write audio frames and patch up the file header\r
60 close() -- patch up the file header and close the\r
61 output file\r
62You should set the parameters before the first writeframesraw or\r
63writeframes. The total number of frames does not need to be set,\r
64but when it is set to the correct value, the header does not have to\r
65be patched up.\r
66It is best to first set all parameters, perhaps possibly the\r
67compression type, and then write audio frames using writeframesraw.\r
68When all frames have been written, either call writeframes('') or\r
69close() to patch up the sizes in the header.\r
70The close() method is called automatically when the class instance\r
71is destroyed.\r
72"""\r
73\r
74import __builtin__\r
75\r
76__all__ = ["open", "openfp", "Error"]\r
77\r
78class Error(Exception):\r
79 pass\r
80\r
81WAVE_FORMAT_PCM = 0x0001\r
82\r
83_array_fmts = None, 'b', 'h', None, 'l'\r
84\r
85# Determine endian-ness\r
86import struct\r
87if struct.pack("h", 1) == "\000\001":\r
88 big_endian = 1\r
89else:\r
90 big_endian = 0\r
91\r
92from chunk import Chunk\r
93\r
94class Wave_read:\r
95 """Variables used in this class:\r
96\r
97 These variables are available to the user though appropriate\r
98 methods of this class:\r
99 _file -- the open file with methods read(), close(), and seek()\r
100 set through the __init__() method\r
101 _nchannels -- the number of audio channels\r
102 available through the getnchannels() method\r
103 _nframes -- the number of audio frames\r
104 available through the getnframes() method\r
105 _sampwidth -- the number of bytes per audio sample\r
106 available through the getsampwidth() method\r
107 _framerate -- the sampling frequency\r
108 available through the getframerate() method\r
109 _comptype -- the AIFF-C compression type ('NONE' if AIFF)\r
110 available through the getcomptype() method\r
111 _compname -- the human-readable AIFF-C compression type\r
112 available through the getcomptype() method\r
113 _soundpos -- the position in the audio stream\r
114 available through the tell() method, set through the\r
115 setpos() method\r
116\r
117 These variables are used internally only:\r
118 _fmt_chunk_read -- 1 iff the FMT chunk has been read\r
119 _data_seek_needed -- 1 iff positioned correctly in audio\r
120 file for readframes()\r
121 _data_chunk -- instantiation of a chunk class for the DATA chunk\r
122 _framesize -- size of one frame in the file\r
123 """\r
124\r
125 def initfp(self, file):\r
126 self._convert = None\r
127 self._soundpos = 0\r
128 self._file = Chunk(file, bigendian = 0)\r
129 if self._file.getname() != 'RIFF':\r
130 raise Error, 'file does not start with RIFF id'\r
131 if self._file.read(4) != 'WAVE':\r
132 raise Error, 'not a WAVE file'\r
133 self._fmt_chunk_read = 0\r
134 self._data_chunk = None\r
135 while 1:\r
136 self._data_seek_needed = 1\r
137 try:\r
138 chunk = Chunk(self._file, bigendian = 0)\r
139 except EOFError:\r
140 break\r
141 chunkname = chunk.getname()\r
142 if chunkname == 'fmt ':\r
143 self._read_fmt_chunk(chunk)\r
144 self._fmt_chunk_read = 1\r
145 elif chunkname == 'data':\r
146 if not self._fmt_chunk_read:\r
147 raise Error, 'data chunk before fmt chunk'\r
148 self._data_chunk = chunk\r
149 self._nframes = chunk.chunksize // self._framesize\r
150 self._data_seek_needed = 0\r
151 break\r
152 chunk.skip()\r
153 if not self._fmt_chunk_read or not self._data_chunk:\r
154 raise Error, 'fmt chunk and/or data chunk missing'\r
155\r
156 def __init__(self, f):\r
157 self._i_opened_the_file = None\r
158 if isinstance(f, basestring):\r
159 f = __builtin__.open(f, 'rb')\r
160 self._i_opened_the_file = f\r
161 # else, assume it is an open file object already\r
162 try:\r
163 self.initfp(f)\r
164 except:\r
165 if self._i_opened_the_file:\r
166 f.close()\r
167 raise\r
168\r
169 def __del__(self):\r
170 self.close()\r
171 #\r
172 # User visible methods.\r
173 #\r
174 def getfp(self):\r
175 return self._file\r
176\r
177 def rewind(self):\r
178 self._data_seek_needed = 1\r
179 self._soundpos = 0\r
180\r
181 def close(self):\r
182 if self._i_opened_the_file:\r
183 self._i_opened_the_file.close()\r
184 self._i_opened_the_file = None\r
185 self._file = None\r
186\r
187 def tell(self):\r
188 return self._soundpos\r
189\r
190 def getnchannels(self):\r
191 return self._nchannels\r
192\r
193 def getnframes(self):\r
194 return self._nframes\r
195\r
196 def getsampwidth(self):\r
197 return self._sampwidth\r
198\r
199 def getframerate(self):\r
200 return self._framerate\r
201\r
202 def getcomptype(self):\r
203 return self._comptype\r
204\r
205 def getcompname(self):\r
206 return self._compname\r
207\r
208 def getparams(self):\r
209 return self.getnchannels(), self.getsampwidth(), \\r
210 self.getframerate(), self.getnframes(), \\r
211 self.getcomptype(), self.getcompname()\r
212\r
213 def getmarkers(self):\r
214 return None\r
215\r
216 def getmark(self, id):\r
217 raise Error, 'no marks'\r
218\r
219 def setpos(self, pos):\r
220 if pos < 0 or pos > self._nframes:\r
221 raise Error, 'position not in range'\r
222 self._soundpos = pos\r
223 self._data_seek_needed = 1\r
224\r
225 def readframes(self, nframes):\r
226 if self._data_seek_needed:\r
227 self._data_chunk.seek(0, 0)\r
228 pos = self._soundpos * self._framesize\r
229 if pos:\r
230 self._data_chunk.seek(pos, 0)\r
231 self._data_seek_needed = 0\r
232 if nframes == 0:\r
233 return ''\r
234 if self._sampwidth > 1 and big_endian:\r
235 # unfortunately the fromfile() method does not take\r
236 # something that only looks like a file object, so\r
237 # we have to reach into the innards of the chunk object\r
238 import array\r
239 chunk = self._data_chunk\r
240 data = array.array(_array_fmts[self._sampwidth])\r
241 nitems = nframes * self._nchannels\r
242 if nitems * self._sampwidth > chunk.chunksize - chunk.size_read:\r
243 nitems = (chunk.chunksize - chunk.size_read) / self._sampwidth\r
244 data.fromfile(chunk.file.file, nitems)\r
245 # "tell" data chunk how much was read\r
246 chunk.size_read = chunk.size_read + nitems * self._sampwidth\r
247 # do the same for the outermost chunk\r
248 chunk = chunk.file\r
249 chunk.size_read = chunk.size_read + nitems * self._sampwidth\r
250 data.byteswap()\r
251 data = data.tostring()\r
252 else:\r
253 data = self._data_chunk.read(nframes * self._framesize)\r
254 if self._convert and data:\r
255 data = self._convert(data)\r
256 self._soundpos = self._soundpos + len(data) // (self._nchannels * self._sampwidth)\r
257 return data\r
258\r
259 #\r
260 # Internal methods.\r
261 #\r
262\r
263 def _read_fmt_chunk(self, chunk):\r
264 wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack('<hhllh', chunk.read(14))\r
265 if wFormatTag == WAVE_FORMAT_PCM:\r
266 sampwidth = struct.unpack('<h', chunk.read(2))[0]\r
267 self._sampwidth = (sampwidth + 7) // 8\r
268 else:\r
269 raise Error, 'unknown format: %r' % (wFormatTag,)\r
270 self._framesize = self._nchannels * self._sampwidth\r
271 self._comptype = 'NONE'\r
272 self._compname = 'not compressed'\r
273\r
274class Wave_write:\r
275 """Variables used in this class:\r
276\r
277 These variables are user settable through appropriate methods\r
278 of this class:\r
279 _file -- the open file with methods write(), close(), tell(), seek()\r
280 set through the __init__() method\r
281 _comptype -- the AIFF-C compression type ('NONE' in AIFF)\r
282 set through the setcomptype() or setparams() method\r
283 _compname -- the human-readable AIFF-C compression type\r
284 set through the setcomptype() or setparams() method\r
285 _nchannels -- the number of audio channels\r
286 set through the setnchannels() or setparams() method\r
287 _sampwidth -- the number of bytes per audio sample\r
288 set through the setsampwidth() or setparams() method\r
289 _framerate -- the sampling frequency\r
290 set through the setframerate() or setparams() method\r
291 _nframes -- the number of audio frames written to the header\r
292 set through the setnframes() or setparams() method\r
293\r
294 These variables are used internally only:\r
295 _datalength -- the size of the audio samples written to the header\r
296 _nframeswritten -- the number of frames actually written\r
297 _datawritten -- the size of the audio samples actually written\r
298 """\r
299\r
300 def __init__(self, f):\r
301 self._i_opened_the_file = None\r
302 if isinstance(f, basestring):\r
303 f = __builtin__.open(f, 'wb')\r
304 self._i_opened_the_file = f\r
305 try:\r
306 self.initfp(f)\r
307 except:\r
308 if self._i_opened_the_file:\r
309 f.close()\r
310 raise\r
311\r
312 def initfp(self, file):\r
313 self._file = file\r
314 self._convert = None\r
315 self._nchannels = 0\r
316 self._sampwidth = 0\r
317 self._framerate = 0\r
318 self._nframes = 0\r
319 self._nframeswritten = 0\r
320 self._datawritten = 0\r
321 self._datalength = 0\r
322 self._headerwritten = False\r
323\r
324 def __del__(self):\r
325 self.close()\r
326\r
327 #\r
328 # User visible methods.\r
329 #\r
330 def setnchannels(self, nchannels):\r
331 if self._datawritten:\r
332 raise Error, 'cannot change parameters after starting to write'\r
333 if nchannels < 1:\r
334 raise Error, 'bad # of channels'\r
335 self._nchannels = nchannels\r
336\r
337 def getnchannels(self):\r
338 if not self._nchannels:\r
339 raise Error, 'number of channels not set'\r
340 return self._nchannels\r
341\r
342 def setsampwidth(self, sampwidth):\r
343 if self._datawritten:\r
344 raise Error, 'cannot change parameters after starting to write'\r
345 if sampwidth < 1 or sampwidth > 4:\r
346 raise Error, 'bad sample width'\r
347 self._sampwidth = sampwidth\r
348\r
349 def getsampwidth(self):\r
350 if not self._sampwidth:\r
351 raise Error, 'sample width not set'\r
352 return self._sampwidth\r
353\r
354 def setframerate(self, framerate):\r
355 if self._datawritten:\r
356 raise Error, 'cannot change parameters after starting to write'\r
357 if framerate <= 0:\r
358 raise Error, 'bad frame rate'\r
359 self._framerate = framerate\r
360\r
361 def getframerate(self):\r
362 if not self._framerate:\r
363 raise Error, 'frame rate not set'\r
364 return self._framerate\r
365\r
366 def setnframes(self, nframes):\r
367 if self._datawritten:\r
368 raise Error, 'cannot change parameters after starting to write'\r
369 self._nframes = nframes\r
370\r
371 def getnframes(self):\r
372 return self._nframeswritten\r
373\r
374 def setcomptype(self, comptype, compname):\r
375 if self._datawritten:\r
376 raise Error, 'cannot change parameters after starting to write'\r
377 if comptype not in ('NONE',):\r
378 raise Error, 'unsupported compression type'\r
379 self._comptype = comptype\r
380 self._compname = compname\r
381\r
382 def getcomptype(self):\r
383 return self._comptype\r
384\r
385 def getcompname(self):\r
386 return self._compname\r
387\r
388 def setparams(self, params):\r
389 nchannels, sampwidth, framerate, nframes, comptype, compname = params\r
390 if self._datawritten:\r
391 raise Error, 'cannot change parameters after starting to write'\r
392 self.setnchannels(nchannels)\r
393 self.setsampwidth(sampwidth)\r
394 self.setframerate(framerate)\r
395 self.setnframes(nframes)\r
396 self.setcomptype(comptype, compname)\r
397\r
398 def getparams(self):\r
399 if not self._nchannels or not self._sampwidth or not self._framerate:\r
400 raise Error, 'not all parameters set'\r
401 return self._nchannels, self._sampwidth, self._framerate, \\r
402 self._nframes, self._comptype, self._compname\r
403\r
404 def setmark(self, id, pos, name):\r
405 raise Error, 'setmark() not supported'\r
406\r
407 def getmark(self, id):\r
408 raise Error, 'no marks'\r
409\r
410 def getmarkers(self):\r
411 return None\r
412\r
413 def tell(self):\r
414 return self._nframeswritten\r
415\r
416 def writeframesraw(self, data):\r
417 self._ensure_header_written(len(data))\r
418 nframes = len(data) // (self._sampwidth * self._nchannels)\r
419 if self._convert:\r
420 data = self._convert(data)\r
421 if self._sampwidth > 1 and big_endian:\r
422 import array\r
423 data = array.array(_array_fmts[self._sampwidth], data)\r
424 data.byteswap()\r
425 data.tofile(self._file)\r
426 self._datawritten = self._datawritten + len(data) * self._sampwidth\r
427 else:\r
428 self._file.write(data)\r
429 self._datawritten = self._datawritten + len(data)\r
430 self._nframeswritten = self._nframeswritten + nframes\r
431\r
432 def writeframes(self, data):\r
433 self.writeframesraw(data)\r
434 if self._datalength != self._datawritten:\r
435 self._patchheader()\r
436\r
437 def close(self):\r
438 if self._file:\r
439 self._ensure_header_written(0)\r
440 if self._datalength != self._datawritten:\r
441 self._patchheader()\r
442 self._file.flush()\r
443 self._file = None\r
444 if self._i_opened_the_file:\r
445 self._i_opened_the_file.close()\r
446 self._i_opened_the_file = None\r
447\r
448 #\r
449 # Internal methods.\r
450 #\r
451\r
452 def _ensure_header_written(self, datasize):\r
453 if not self._headerwritten:\r
454 if not self._nchannels:\r
455 raise Error, '# channels not specified'\r
456 if not self._sampwidth:\r
457 raise Error, 'sample width not specified'\r
458 if not self._framerate:\r
459 raise Error, 'sampling rate not specified'\r
460 self._write_header(datasize)\r
461\r
462 def _write_header(self, initlength):\r
463 assert not self._headerwritten\r
464 self._file.write('RIFF')\r
465 if not self._nframes:\r
466 self._nframes = initlength / (self._nchannels * self._sampwidth)\r
467 self._datalength = self._nframes * self._nchannels * self._sampwidth\r
468 self._form_length_pos = self._file.tell()\r
469 self._file.write(struct.pack('<l4s4slhhllhh4s',\r
470 36 + self._datalength, 'WAVE', 'fmt ', 16,\r
471 WAVE_FORMAT_PCM, self._nchannels, self._framerate,\r
472 self._nchannels * self._framerate * self._sampwidth,\r
473 self._nchannels * self._sampwidth,\r
474 self._sampwidth * 8, 'data'))\r
475 self._data_length_pos = self._file.tell()\r
476 self._file.write(struct.pack('<l', self._datalength))\r
477 self._headerwritten = True\r
478\r
479 def _patchheader(self):\r
480 assert self._headerwritten\r
481 if self._datawritten == self._datalength:\r
482 return\r
483 curpos = self._file.tell()\r
484 self._file.seek(self._form_length_pos, 0)\r
485 self._file.write(struct.pack('<l', 36 + self._datawritten))\r
486 self._file.seek(self._data_length_pos, 0)\r
487 self._file.write(struct.pack('<l', self._datawritten))\r
488 self._file.seek(curpos, 0)\r
489 self._datalength = self._datawritten\r
490\r
491def open(f, mode=None):\r
492 if mode is None:\r
493 if hasattr(f, 'mode'):\r
494 mode = f.mode\r
495 else:\r
496 mode = 'rb'\r
497 if mode in ('r', 'rb'):\r
498 return Wave_read(f)\r
499 elif mode in ('w', 'wb'):\r
500 return Wave_write(f)\r
501 else:\r
502 raise Error, "mode must be 'r', 'rb', 'w', or 'wb'"\r
503\r
504openfp = open # B/W compatibility\r