| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | # Stuff to parse Sun and NeXT audio files. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # An audio consists of a header followed by the data.  The structure | 
					
						
							|  |  |  | # of the header is as follows. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #	+---------------+ | 
					
						
							|  |  |  | #	| magic word    | | 
					
						
							|  |  |  | #	+---------------+ | 
					
						
							|  |  |  | #	| header size   | | 
					
						
							|  |  |  | #	+---------------+ | 
					
						
							|  |  |  | #	| data size     | | 
					
						
							|  |  |  | #	+---------------+ | 
					
						
							|  |  |  | #	| encoding      | | 
					
						
							|  |  |  | #	+---------------+ | 
					
						
							|  |  |  | #	| sample rate   | | 
					
						
							|  |  |  | #	+---------------+ | 
					
						
							|  |  |  | #	| # of channels | | 
					
						
							|  |  |  | #	+---------------+ | 
					
						
							|  |  |  | #	| info          | | 
					
						
							|  |  |  | #	|               | | 
					
						
							|  |  |  | #	+---------------+ | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # The magic word consists of the 4 characters '.snd'.  Apart from the | 
					
						
							|  |  |  | # info field, all header fields are 4 bytes in size.  They are all | 
					
						
							|  |  |  | # 32-bit unsigned integers encoded in big-endian byte order. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # The header size really gives the start of the data. | 
					
						
							|  |  |  | # The data size is the physical size of the data.  From the other | 
					
						
							|  |  |  | # parameter the number of frames can be calculated. | 
					
						
							|  |  |  | # The encoding gives the way in which audio samples are encoded. | 
					
						
							|  |  |  | # Possible values are listed below. | 
					
						
							|  |  |  | # The info field currently consists of an ASCII string giving a | 
					
						
							|  |  |  | # human-readable description of the audio file.  The info field is | 
					
						
							|  |  |  | # padded with NUL bytes to the header size. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Usage. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Reading audio files: | 
					
						
							| 
									
										
										
										
											1994-02-03 14:19:21 +00:00
										 |  |  | #	f = sunau.open(file, 'r') | 
					
						
							| 
									
										
										
										
											1993-12-20 09:36:01 +00:00
										 |  |  | # where file is either the name of a file or an open file pointer. | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | # The open file pointer must have methods read(), seek(), and close(). | 
					
						
							|  |  |  | # When the setpos() and rewind() methods are not used, the seek() | 
					
						
							|  |  |  | # method is not  necessary. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This returns an instance of a class with the following public methods: | 
					
						
							|  |  |  | #	getnchannels()	-- returns number of audio channels (1 for | 
					
						
							|  |  |  | #			   mono, 2 for stereo) | 
					
						
							|  |  |  | #	getsampwidth()	-- returns sample width in bytes | 
					
						
							|  |  |  | #	getframerate()	-- returns sampling frequency | 
					
						
							|  |  |  | #	getnframes()	-- returns number of audio frames | 
					
						
							| 
									
										
										
										
											1998-04-23 21:40:02 +00:00
										 |  |  | #	getcomptype()	-- returns compression type ('NONE' or 'ULAW') | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | #	getcompname()	-- returns human-readable version of | 
					
						
							| 
									
										
										
										
											1998-04-23 21:40:02 +00:00
										 |  |  | #			   compression type ('not compressed' matches 'NONE') | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | #	getparams()	-- returns a tuple consisting of all of the | 
					
						
							|  |  |  | #			   above in the above order | 
					
						
							|  |  |  | #	getmarkers()	-- returns None (for compatibility with the | 
					
						
							|  |  |  | #			   aifc module) | 
					
						
							|  |  |  | #	getmark(id)	-- raises an error since the mark does not | 
					
						
							|  |  |  | #			   exist (for compatibility with the aifc module) | 
					
						
							|  |  |  | #	readframes(n)	-- returns at most n frames of audio | 
					
						
							|  |  |  | #	rewind()	-- rewind to the beginning of the audio stream | 
					
						
							|  |  |  | #	setpos(pos)	-- seek to the specified position | 
					
						
							|  |  |  | #	tell()		-- return the current position | 
					
						
							|  |  |  | #	close()		-- close the instance (make it unusable) | 
					
						
							|  |  |  | # The position returned by tell() and the position given to setpos() | 
					
						
							|  |  |  | # are compatible and have nothing to do with the actual postion in the | 
					
						
							|  |  |  | # file. | 
					
						
							|  |  |  | # The close() method is called automatically when the class instance | 
					
						
							|  |  |  | # is destroyed. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Writing audio files: | 
					
						
							| 
									
										
										
										
											1994-02-03 14:19:21 +00:00
										 |  |  | #	f = sunau.open(file, 'w') | 
					
						
							| 
									
										
										
										
											1993-12-20 09:36:01 +00:00
										 |  |  | # where file is either the name of a file or an open file pointer. | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | # The open file pointer must have methods write(), tell(), seek(), and | 
					
						
							|  |  |  | # close(). | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This returns an instance of a class with the following public methods: | 
					
						
							|  |  |  | #	setnchannels(n)	-- set the number of channels | 
					
						
							|  |  |  | #	setsampwidth(n)	-- set the sample width | 
					
						
							|  |  |  | #	setframerate(n)	-- set the frame rate | 
					
						
							|  |  |  | #	setnframes(n)	-- set the number of frames | 
					
						
							|  |  |  | #	setcomptype(type, name) | 
					
						
							|  |  |  | #			-- set the compression type and the | 
					
						
							|  |  |  | #			   human-readable compression type | 
					
						
							| 
									
										
										
										
											1998-04-23 21:40:02 +00:00
										 |  |  | #	setparams(tuple)-- set all parameters at once | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | #	tell()		-- return current position in output file | 
					
						
							|  |  |  | #	writeframesraw(data) | 
					
						
							|  |  |  | #			-- write audio frames without pathing up the | 
					
						
							|  |  |  | #			   file header | 
					
						
							|  |  |  | #	writeframes(data) | 
					
						
							|  |  |  | #			-- write audio frames and patch up the file header | 
					
						
							|  |  |  | #	close()		-- patch up the file header and close the | 
					
						
							|  |  |  | #			   output file | 
					
						
							|  |  |  | # You should set the parameters before the first writeframesraw or | 
					
						
							|  |  |  | # writeframes.  The total number of frames does not need to be set, | 
					
						
							|  |  |  | # but when it is set to the correct value, the header does not have to | 
					
						
							|  |  |  | # be patched up. | 
					
						
							|  |  |  | # It is best to first set all parameters, perhaps possibly the | 
					
						
							|  |  |  | # compression type, and then write audio frames using writeframesraw. | 
					
						
							|  |  |  | # When all frames have been written, either call writeframes('') or | 
					
						
							|  |  |  | # close() to patch up the sizes in the header. | 
					
						
							|  |  |  | # The close() method is called automatically when the class instance | 
					
						
							|  |  |  | # is destroyed. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # from <multimedia/audio_filehdr.h> | 
					
						
							|  |  |  | AUDIO_FILE_MAGIC = 0x2e736e64 | 
					
						
							|  |  |  | AUDIO_FILE_ENCODING_MULAW_8 = 1 | 
					
						
							|  |  |  | AUDIO_FILE_ENCODING_LINEAR_8 = 2 | 
					
						
							|  |  |  | AUDIO_FILE_ENCODING_LINEAR_16 = 3 | 
					
						
							|  |  |  | AUDIO_FILE_ENCODING_LINEAR_24 = 4 | 
					
						
							|  |  |  | AUDIO_FILE_ENCODING_LINEAR_32 = 5 | 
					
						
							|  |  |  | AUDIO_FILE_ENCODING_FLOAT = 6 | 
					
						
							|  |  |  | AUDIO_FILE_ENCODING_DOUBLE = 7 | 
					
						
							|  |  |  | AUDIO_FILE_ENCODING_ADPCM_G721 = 23 | 
					
						
							|  |  |  | AUDIO_FILE_ENCODING_ADPCM_G722 = 24 | 
					
						
							|  |  |  | AUDIO_FILE_ENCODING_ADPCM_G723_3 = 25 | 
					
						
							|  |  |  | AUDIO_FILE_ENCODING_ADPCM_G723_5 = 26 | 
					
						
							|  |  |  | AUDIO_FILE_ENCODING_ALAW_8 = 27 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # from <multimedia/audio_hdr.h> | 
					
						
							|  |  |  | AUDIO_UNKNOWN_SIZE = 0xFFFFFFFFL	# ((unsigned)(~0)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _simple_encodings = [AUDIO_FILE_ENCODING_MULAW_8, | 
					
						
							|  |  |  | 		     AUDIO_FILE_ENCODING_LINEAR_8, | 
					
						
							|  |  |  | 		     AUDIO_FILE_ENCODING_LINEAR_16, | 
					
						
							|  |  |  | 		     AUDIO_FILE_ENCODING_LINEAR_24, | 
					
						
							|  |  |  | 		     AUDIO_FILE_ENCODING_LINEAR_32, | 
					
						
							|  |  |  | 		     AUDIO_FILE_ENCODING_ALAW_8] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-08-14 07:49:51 +00:00
										 |  |  | Error = 'sunau.Error' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | def _read_u32(file): | 
					
						
							|  |  |  | 	x = 0L | 
					
						
							|  |  |  | 	for i in range(4): | 
					
						
							|  |  |  | 		byte = file.read(1) | 
					
						
							|  |  |  | 		if byte == '': | 
					
						
							|  |  |  | 			raise EOFError | 
					
						
							|  |  |  | 		x = x*256 + ord(byte) | 
					
						
							|  |  |  | 	return x | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _write_u32(file, x): | 
					
						
							|  |  |  | 	data = [] | 
					
						
							|  |  |  | 	for i in range(4): | 
					
						
							|  |  |  | 		d, m = divmod(x, 256) | 
					
						
							|  |  |  | 		data.insert(0, m) | 
					
						
							|  |  |  | 		x = d | 
					
						
							|  |  |  | 	for i in range(4): | 
					
						
							|  |  |  | 		file.write(chr(int(data[i]))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Au_read: | 
					
						
							| 
									
										
										
										
											1996-08-20 20:40:07 +00:00
										 |  |  | ## 	access _file, _soundpos, _hdr_size, _data_size, _encoding, \ | 
					
						
							|  |  |  | ## 		  _sampwidth, _framesize, _framerate, _nchannels, \ | 
					
						
							|  |  |  | ## 		  _info: private | 
					
						
							| 
									
										
										
										
											1993-12-20 09:36:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	def __init__(self, f): | 
					
						
							|  |  |  | 		if type(f) == type(''): | 
					
						
							| 
									
										
										
										
											1994-01-28 09:59:35 +00:00
										 |  |  | 			import __builtin__ | 
					
						
							|  |  |  | 			f = __builtin__.open(f, 'r') | 
					
						
							| 
									
										
										
										
											1993-12-20 09:36:01 +00:00
										 |  |  | 		self.initfp(f) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def __del__(self): | 
					
						
							|  |  |  | 		if self._file: | 
					
						
							|  |  |  | 			self.close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | 	def initfp(self, file): | 
					
						
							|  |  |  | 		self._file = file | 
					
						
							|  |  |  | 		self._soundpos = 0 | 
					
						
							|  |  |  | 		magic = int(_read_u32(file)) | 
					
						
							|  |  |  | 		if magic != AUDIO_FILE_MAGIC: | 
					
						
							|  |  |  | 			raise Error, 'bad magic number' | 
					
						
							|  |  |  | 		self._hdr_size = int(_read_u32(file)) | 
					
						
							|  |  |  | 		if self._hdr_size < 24: | 
					
						
							|  |  |  | 			raise Error, 'header size too small' | 
					
						
							|  |  |  | 		if self._hdr_size > 100: | 
					
						
							|  |  |  | 			raise Error, 'header size rediculously large' | 
					
						
							|  |  |  | 		self._data_size = _read_u32(file) | 
					
						
							|  |  |  | 		if self._data_size != AUDIO_UNKNOWN_SIZE: | 
					
						
							|  |  |  | 			self._data_size = int(self._data_size) | 
					
						
							|  |  |  | 		self._encoding = int(_read_u32(file)) | 
					
						
							|  |  |  | 		if self._encoding not in _simple_encodings: | 
					
						
							|  |  |  | 			raise Error, 'encoding not (yet) supported' | 
					
						
							|  |  |  | 		if self._encoding in (AUDIO_FILE_ENCODING_MULAW_8, | 
					
						
							|  |  |  | 			  AUDIO_FILE_ENCODING_LINEAR_8, | 
					
						
							|  |  |  | 			  AUDIO_FILE_ENCODING_ALAW_8): | 
					
						
							|  |  |  | 			self._sampwidth = 2 | 
					
						
							|  |  |  | 			self._framesize = 1 | 
					
						
							|  |  |  | 		elif self._encoding == AUDIO_FILE_ENCODING_LINEAR_16: | 
					
						
							|  |  |  | 			self._framesize = self._sampwidth = 2 | 
					
						
							|  |  |  | 		elif self._encoding == AUDIO_FILE_ENCODING_LINEAR_24: | 
					
						
							|  |  |  | 			self._framesize = self._sampwidth = 3 | 
					
						
							|  |  |  | 		elif self._encoding == AUDIO_FILE_ENCODING_LINEAR_32: | 
					
						
							|  |  |  | 			self._framesize = self._sampwidth = 4 | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			raise Error, 'unknown encoding' | 
					
						
							|  |  |  | 		self._framerate = int(_read_u32(file)) | 
					
						
							|  |  |  | 		self._nchannels = int(_read_u32(file)) | 
					
						
							|  |  |  | 		self._framesize = self._framesize * self._nchannels | 
					
						
							|  |  |  | 		if self._hdr_size > 24: | 
					
						
							|  |  |  | 			self._info = file.read(self._hdr_size - 24) | 
					
						
							|  |  |  | 			for i in range(len(self._info)): | 
					
						
							|  |  |  | 				if self._info[i] == '\0': | 
					
						
							|  |  |  | 					self._info = self._info[:i] | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			self._info = '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getfp(self): | 
					
						
							|  |  |  | 		return self._file | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getnchannels(self): | 
					
						
							|  |  |  | 		return self._nchannels | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getsampwidth(self): | 
					
						
							|  |  |  | 		return self._sampwidth | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getframerate(self): | 
					
						
							|  |  |  | 		return self._framerate | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getnframes(self): | 
					
						
							|  |  |  | 		if self._data_size == AUDIO_UNKNOWN_SIZE: | 
					
						
							|  |  |  | 			return AUDIO_UNKNOWN_SIZE | 
					
						
							|  |  |  | 		if self._encoding in _simple_encodings: | 
					
						
							|  |  |  | 			return self._data_size / self._framesize | 
					
						
							|  |  |  | 		return 0		# XXX--must do some arithmetic here | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getcomptype(self): | 
					
						
							|  |  |  | 		if self._encoding == AUDIO_FILE_ENCODING_MULAW_8: | 
					
						
							|  |  |  | 			return 'ULAW' | 
					
						
							|  |  |  | 		elif self._encoding == AUDIO_FILE_ENCODING_ALAW_8: | 
					
						
							|  |  |  | 			return 'ALAW' | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			return 'NONE' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getcompname(self): | 
					
						
							|  |  |  | 		if self._encoding == AUDIO_FILE_ENCODING_MULAW_8: | 
					
						
							|  |  |  | 			return 'CCITT G.711 u-law' | 
					
						
							|  |  |  | 		elif self._encoding == AUDIO_FILE_ENCODING_ALAW_8: | 
					
						
							|  |  |  | 			return 'CCITT G.711 A-law' | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			return 'not compressed' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getparams(self): | 
					
						
							|  |  |  | 		return self.getnchannels(), self.getsampwidth(), \ | 
					
						
							|  |  |  | 			  self.getframerate(), self.getnframes(), \ | 
					
						
							|  |  |  | 			  self.getcomptype(), self.getcompname() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getmarkers(self): | 
					
						
							|  |  |  | 		return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getmark(self, id): | 
					
						
							|  |  |  | 		raise Error, 'no marks' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def readframes(self, nframes): | 
					
						
							|  |  |  | 		if self._encoding in _simple_encodings: | 
					
						
							|  |  |  | 			if nframes == AUDIO_UNKNOWN_SIZE: | 
					
						
							|  |  |  | 				data = self._file.read() | 
					
						
							|  |  |  | 			else: | 
					
						
							| 
									
										
										
										
											1994-01-28 09:56:05 +00:00
										 |  |  | 				data = self._file.read(nframes * self._framesize * self._nchannels) | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | 			if self._encoding == AUDIO_FILE_ENCODING_MULAW_8: | 
					
						
							|  |  |  | 				import audioop | 
					
						
							|  |  |  | 				data = audioop.ulaw2lin(data, self._sampwidth) | 
					
						
							|  |  |  | 			return data | 
					
						
							|  |  |  | 		return None		# XXX--not implemented yet | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def rewind(self): | 
					
						
							|  |  |  | 		self._soundpos = 0 | 
					
						
							|  |  |  | 		self._file.seek(self._hdr_size) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def tell(self): | 
					
						
							|  |  |  | 		return self._soundpos | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def setpos(self, pos): | 
					
						
							|  |  |  | 		if pos < 0 or pos > self.getnframes(): | 
					
						
							|  |  |  | 			raise Error, 'position not in range' | 
					
						
							|  |  |  | 		self._file.seek(pos * self._framesize + self._hdr_size) | 
					
						
							|  |  |  | 		self._soundpos = pos | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def close(self): | 
					
						
							|  |  |  | 		self._file = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Au_write: | 
					
						
							| 
									
										
										
										
											1996-08-20 20:40:07 +00:00
										 |  |  | ## 	access _file, _framerate, _nchannels, _sampwidth, _framesize, \ | 
					
						
							|  |  |  | ## 		  _nframes, _nframeswritten, _datawritten, _info, \ | 
					
						
							|  |  |  | ## 		  _comptype: private | 
					
						
							| 
									
										
										
										
											1993-12-20 09:36:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-12-17 15:25:27 +00:00
										 |  |  | 	def __init__(self, f): | 
					
						
							|  |  |  | 		if type(f) == type(''): | 
					
						
							| 
									
										
										
										
											1994-01-28 09:59:35 +00:00
										 |  |  | 			import __builtin__ | 
					
						
							|  |  |  | 			f = __builtin__.open(f, 'w') | 
					
						
							| 
									
										
										
										
											1993-12-17 15:25:27 +00:00
										 |  |  | 		self.initfp(f) | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-12-20 09:36:01 +00:00
										 |  |  | 	def __del__(self): | 
					
						
							|  |  |  | 		if self._file: | 
					
						
							|  |  |  | 			self.close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | 	def initfp(self, file): | 
					
						
							|  |  |  | 		self._file = file | 
					
						
							|  |  |  | 		self._framerate = 0 | 
					
						
							|  |  |  | 		self._nchannels = 0 | 
					
						
							|  |  |  | 		self._sampwidth = 0 | 
					
						
							|  |  |  | 		self._framesize = 0 | 
					
						
							|  |  |  | 		self._nframes = AUDIO_UNKNOWN_SIZE | 
					
						
							|  |  |  | 		self._nframeswritten = 0 | 
					
						
							|  |  |  | 		self._datawritten = 0 | 
					
						
							|  |  |  | 		self._datalength = 0 | 
					
						
							|  |  |  | 		self._info = '' | 
					
						
							|  |  |  | 		self._comptype = 'ULAW'	# default is U-law | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def setnchannels(self, nchannels): | 
					
						
							|  |  |  | 		if self._nframeswritten: | 
					
						
							|  |  |  | 			raise Error, 'cannot change parameters after starting to write' | 
					
						
							|  |  |  | 		if nchannels not in (1, 2, 4): | 
					
						
							|  |  |  | 			raise Error, 'only 1, 2, or 4 channels supported' | 
					
						
							|  |  |  | 		self._nchannels = nchannels | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getnchannels(self): | 
					
						
							|  |  |  | 		if not self._nchannels: | 
					
						
							|  |  |  | 			raise Error, 'number of channels not set' | 
					
						
							|  |  |  | 		return self._nchannels | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def setsampwidth(self, sampwidth): | 
					
						
							|  |  |  | 		if self._nframeswritten: | 
					
						
							|  |  |  | 			raise Error, 'cannot change parameters after starting to write' | 
					
						
							|  |  |  | 		if sampwidth not in (1, 2, 4): | 
					
						
							|  |  |  | 			raise Error, 'bad sample width' | 
					
						
							|  |  |  | 		self._sampwidth = sampwidth | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getsampwidth(self): | 
					
						
							|  |  |  | 		if not self._framerate: | 
					
						
							|  |  |  | 			raise Error, 'sample width not specified' | 
					
						
							|  |  |  | 		return self._sampwidth | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def setframerate(self, framerate): | 
					
						
							|  |  |  | 		if self._nframeswritten: | 
					
						
							|  |  |  | 			raise Error, 'cannot change parameters after starting to write' | 
					
						
							|  |  |  | 		self._framerate = framerate | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getframerate(self): | 
					
						
							|  |  |  | 		if not self._framerate: | 
					
						
							|  |  |  | 			raise Error, 'frame rate not set' | 
					
						
							|  |  |  | 		return self._framerate | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def setnframes(self, nframes): | 
					
						
							|  |  |  | 		if self._nframeswritten: | 
					
						
							|  |  |  | 			raise Error, 'cannot change parameters after starting to write' | 
					
						
							|  |  |  | 		if nframes < 0: | 
					
						
							|  |  |  | 			raise Error, '# of frames cannot be negative' | 
					
						
							|  |  |  | 		self._nframes = nframes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getnframes(self): | 
					
						
							|  |  |  | 		return self._nframeswritten | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def setcomptype(self, type, name): | 
					
						
							|  |  |  | 		if type in ('NONE', 'ULAW'): | 
					
						
							|  |  |  | 			self._comptype = type | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			raise Error, 'unknown compression type' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getcomptype(self): | 
					
						
							|  |  |  | 		return self._comptype | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getcompname(self): | 
					
						
							|  |  |  | 		if self._comptype == 'ULAW': | 
					
						
							|  |  |  | 			return 'CCITT G.711 u-law' | 
					
						
							|  |  |  | 		elif self._comptype == 'ALAW': | 
					
						
							|  |  |  | 			return 'CCITT G.711 A-law' | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			return 'not compressed' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def setparams(self, (nchannels, sampwidth, framerate, nframes, comptype, compname)): | 
					
						
							|  |  |  | 		self.setnchannels(nchannels) | 
					
						
							|  |  |  | 		self.setsampwidth(sampwidth) | 
					
						
							|  |  |  | 		self.setframerate(framerate) | 
					
						
							|  |  |  | 		self.setnframes(nframes) | 
					
						
							|  |  |  | 		self.setcomptype(comptype, compname) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def getparams(self): | 
					
						
							|  |  |  | 		return self.getnchannels(), self.getsampwidth(), \ | 
					
						
							|  |  |  | 			  self.getframerate(), self.getnframes(), \ | 
					
						
							|  |  |  | 			  self.getcomptype(), self.getcompname() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def tell(self): | 
					
						
							|  |  |  | 		return self._nframeswritten | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def writeframesraw(self, data): | 
					
						
							|  |  |  | 		self._ensure_header_written() | 
					
						
							|  |  |  | 		nframes = len(data) / self._framesize | 
					
						
							|  |  |  | 		if self._comptype == 'ULAW': | 
					
						
							|  |  |  | 			import audioop | 
					
						
							|  |  |  | 			data = audioop.lin2ulaw(data, self._sampwidth) | 
					
						
							|  |  |  | 		self._file.write(data) | 
					
						
							|  |  |  | 		self._nframeswritten = self._nframeswritten + nframes | 
					
						
							|  |  |  | 		self._datawritten = self._datawritten + len(data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def writeframes(self, data): | 
					
						
							|  |  |  | 		self.writeframesraw(data) | 
					
						
							|  |  |  | 		if self._nframeswritten != self._nframes or \ | 
					
						
							|  |  |  | 			  self._datalength != self._datawritten: | 
					
						
							|  |  |  | 			self._patchheader() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def close(self): | 
					
						
							|  |  |  | 		self._ensure_header_written() | 
					
						
							|  |  |  | 		if self._nframeswritten != self._nframes or \ | 
					
						
							|  |  |  | 			  self._datalength != self._datawritten: | 
					
						
							|  |  |  | 			self._patchheader() | 
					
						
							| 
									
										
										
										
											1993-12-16 14:02:44 +00:00
										 |  |  | 		self._file.flush() | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | 		self._file = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	# | 
					
						
							|  |  |  | 	# private methods | 
					
						
							|  |  |  | 	# | 
					
						
							| 
									
										
										
										
											1996-08-20 20:40:07 +00:00
										 |  |  | ## 	if 0: access *: private | 
					
						
							| 
									
										
										
										
											1993-12-20 09:36:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | 	def _ensure_header_written(self): | 
					
						
							|  |  |  | 		if not self._nframeswritten: | 
					
						
							|  |  |  | 			if not self._nchannels: | 
					
						
							|  |  |  | 				raise Error, '# of channels not specified' | 
					
						
							|  |  |  | 			if not self._sampwidth: | 
					
						
							|  |  |  | 				raise Error, 'sample width not specified' | 
					
						
							|  |  |  | 			if not self._framerate: | 
					
						
							|  |  |  | 				raise Error, 'frame rate not specified' | 
					
						
							|  |  |  | 			self._write_header() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def _write_header(self): | 
					
						
							|  |  |  | 		if self._comptype == 'NONE': | 
					
						
							|  |  |  | 			if self._sampwidth == 1: | 
					
						
							|  |  |  | 				encoding = AUDIO_FILE_ENCODING_LINEAR_8 | 
					
						
							|  |  |  | 				self._framesize = 1 | 
					
						
							|  |  |  | 			elif self._sampwidth == 2: | 
					
						
							|  |  |  | 				encoding = AUDIO_FILE_ENCODING_LINEAR_16 | 
					
						
							|  |  |  | 				self._framesize = 2 | 
					
						
							|  |  |  | 			elif self._sampwidth == 4: | 
					
						
							|  |  |  | 				encoding = AUDIO_FILE_ENCODING_LINEAR_32 | 
					
						
							|  |  |  | 				self._framesize = 4 | 
					
						
							|  |  |  | 			else: | 
					
						
							|  |  |  | 				raise Error, 'internal error' | 
					
						
							|  |  |  | 		elif self._comptype == 'ULAW': | 
					
						
							|  |  |  | 			encoding = AUDIO_FILE_ENCODING_MULAW_8 | 
					
						
							|  |  |  | 			self._framesize = 1 | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			raise Error, 'internal error' | 
					
						
							|  |  |  | 		self._framesize = self._framesize * self._nchannels | 
					
						
							|  |  |  | 		_write_u32(self._file, AUDIO_FILE_MAGIC) | 
					
						
							|  |  |  | 		header_size = 25 + len(self._info) | 
					
						
							|  |  |  | 		header_size = (header_size + 7) & ~7 | 
					
						
							|  |  |  | 		_write_u32(self._file, header_size) | 
					
						
							|  |  |  | 		if self._nframes == AUDIO_UNKNOWN_SIZE: | 
					
						
							|  |  |  | 			length = AUDIO_UNKNOWN_SIZE | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			length = self._nframes * self._framesize | 
					
						
							|  |  |  | 		_write_u32(self._file, length) | 
					
						
							|  |  |  | 		self._datalength = length | 
					
						
							|  |  |  | 		_write_u32(self._file, encoding) | 
					
						
							|  |  |  | 		_write_u32(self._file, self._framerate) | 
					
						
							|  |  |  | 		_write_u32(self._file, self._nchannels) | 
					
						
							|  |  |  | 		self._file.write(self._info) | 
					
						
							|  |  |  | 		self._file.write('\0'*(header_size - len(self._info) - 24)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def _patchheader(self): | 
					
						
							|  |  |  | 		self._file.seek(8) | 
					
						
							|  |  |  | 		_write_u32(self._file, self._datawritten) | 
					
						
							|  |  |  | 		self._datalength = self._datawritten | 
					
						
							|  |  |  | 		self._file.seek(0, 2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-12-17 15:25:27 +00:00
										 |  |  | def open(f, mode): | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | 	if mode == 'r': | 
					
						
							| 
									
										
										
										
											1993-12-17 15:25:27 +00:00
										 |  |  | 		return Au_read(f) | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | 	elif mode == 'w': | 
					
						
							| 
									
										
										
										
											1993-12-17 15:25:27 +00:00
										 |  |  | 		return Au_write(f) | 
					
						
							| 
									
										
										
										
											1993-12-13 11:42:39 +00:00
										 |  |  | 	else: | 
					
						
							|  |  |  | 		raise Error, "mode must be 'r' or 'w'" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-12-17 15:25:27 +00:00
										 |  |  | openfp = open |