"""Stuff to parse Sun and NeXT audio files.An audio file consists of a header followed by the data. The structureof 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 theinfo field, all header fields are 4 bytes in size. They are all32-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 otherparameters 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 ahuman-readable description of the audio file. The info field ispadded with NUL bytes to the header size.Usage.Reading audio files:f = sunau.open(file, 'r')where file is either the name of a file or an open file pointer.The open file pointer must have methods read(), seek(), and close().When the setpos() and rewind() methods are not used, the seek()method is not necessary.This returns an instance of a class with the following public methods:getnchannels() -- returns number of audio channels (1 formono, 2 for stereo)getsampwidth() -- returns sample width in bytesgetframerate() -- returns sampling frequencygetnframes() -- returns number of audio framesgetcomptype() -- returns compression type ('NONE' or 'ULAW')getcompname() -- returns human-readable version ofcompression type ('not compressed' matches 'NONE')getparams() -- returns a namedtuple consisting of all of theabove in the above ordergetmarkers() -- returns None (for compatibility with theaifc module)getmark(id) -- raises an error since the mark does notexist (for compatibility with the aifc module)readframes(n) -- returns at most n frames of audiorewind() -- rewind to the beginning of the audio streamsetpos(pos) -- seek to the specified positiontell() -- return the current positionclose() -- 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 position in thefile.The close() method is called automatically when the class instanceis destroyed.Writing audio files:f = sunau.open(file, 'w')where file is either the name of a file or an open file pointer.The open file pointer must have methods write(), tell(), seek(), andclose().This returns an instance of a class with the following public methods:setnchannels(n) -- set the number of channelssetsampwidth(n) -- set the sample widthsetframerate(n) -- set the frame ratesetnframes(n) -- set the number of framessetcomptype(type, name)-- set the compression type and thehuman-readable compression typesetparams(tuple)-- set all parameters at oncetell() -- return current position in output filewriteframesraw(data)-- write audio frames without pathing up thefile headerwriteframes(data)-- write audio frames and patch up the file headerclose() -- patch up the file header and close theoutput fileYou should set the parameters before the first writeframesraw orwriteframes. 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 tobe patched up.It is best to first set all parameters, perhaps possibly thecompression type, and then write audio frames using writeframesraw.When all frames have been written, either call writeframes(b'') orclose() to patch up the sizes in the header.The close() method is called automatically when the class instanceis destroyed."""from collections import namedtupleimport warnings_sunau_params = namedtuple('_sunau_params','nchannels sampwidth framerate nframes comptype compname')# from <multimedia/audio_filehdr.h>AUDIO_FILE_MAGIC = 0x2e736e64AUDIO_FILE_ENCODING_MULAW_8 = 1AUDIO_FILE_ENCODING_LINEAR_8 = 2AUDIO_FILE_ENCODING_LINEAR_16 = 3AUDIO_FILE_ENCODING_LINEAR_24 = 4AUDIO_FILE_ENCODING_LINEAR_32 = 5AUDIO_FILE_ENCODING_FLOAT = 6AUDIO_FILE_ENCODING_DOUBLE = 7AUDIO_FILE_ENCODING_ADPCM_G721 = 23AUDIO_FILE_ENCODING_ADPCM_G722 = 24AUDIO_FILE_ENCODING_ADPCM_G723_3 = 25AUDIO_FILE_ENCODING_ADPCM_G723_5 = 26AUDIO_FILE_ENCODING_ALAW_8 = 27# from <multimedia/audio_hdr.h>AUDIO_UNKNOWN_SIZE = 0xFFFFFFFF # ((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]class Error(Exception):passdef _read_u32(file):x = 0for i in range(4):byte = file.read(1)if not byte:raise EOFErrorx = x*256 + ord(byte)return xdef _write_u32(file, x):data = []for i in range(4):d, m = divmod(x, 256)data.insert(0, int(m))x = dfile.write(bytes(data))class Au_read:def __init__(self, f):if type(f) == type(''):import builtinsf = builtins.open(f, 'rb')self._opened = Trueelse:self._opened = Falseself.initfp(f)def __del__(self):if self._file:self.close()def __enter__(self):return selfdef __exit__(self, *args):self.close()def initfp(self, file):self._file = fileself._soundpos = 0magic = 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 ridiculously 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_ALAW_8):self._sampwidth = 2self._framesize = 1elif self._encoding == AUDIO_FILE_ENCODING_LINEAR_8:self._framesize = self._sampwidth = 1elif self._encoding == AUDIO_FILE_ENCODING_LINEAR_16:self._framesize = self._sampwidth = 2elif self._encoding == AUDIO_FILE_ENCODING_LINEAR_24:self._framesize = self._sampwidth = 3elif self._encoding == AUDIO_FILE_ENCODING_LINEAR_32:self._framesize = self._sampwidth = 4else:raise Error('unknown encoding')self._framerate = int(_read_u32(file))self._nchannels = int(_read_u32(file))if not self._nchannels:raise Error('bad # of channels')self._framesize = self._framesize * self._nchannelsif self._hdr_size > 24:self._info = file.read(self._hdr_size - 24)self._info, _, _ = self._info.partition(b'0円')else:self._info = b''try:self._data_pos = file.tell()except (AttributeError, OSError):self._data_pos = Nonedef getfp(self):return self._filedef getnchannels(self):return self._nchannelsdef getsampwidth(self):return self._sampwidthdef getframerate(self):return self._frameratedef getnframes(self):if self._data_size == AUDIO_UNKNOWN_SIZE:return AUDIO_UNKNOWN_SIZEif self._encoding in _simple_encodings:return self._data_size // self._framesizereturn 0 # XXX--must do some arithmetic heredef 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 _sunau_params(self.getnchannels(), self.getsampwidth(),self.getframerate(), self.getnframes(),self.getcomptype(), self.getcompname())def getmarkers(self):return Nonedef 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:data = self._file.read(nframes * self._framesize)self._soundpos += len(data) // self._framesizeif self._encoding == AUDIO_FILE_ENCODING_MULAW_8:import audioopdata = audioop.ulaw2lin(data, self._sampwidth)return datareturn None # XXX--not implemented yetdef rewind(self):if self._data_pos is None:raise OSError('cannot seek')self._file.seek(self._data_pos)self._soundpos = 0def tell(self):return self._soundposdef setpos(self, pos):if pos < 0 or pos > self.getnframes():raise Error('position not in range')if self._data_pos is None:raise OSError('cannot seek')self._file.seek(self._data_pos + pos * self._framesize)self._soundpos = posdef close(self):file = self._fileif file:self._file = Noneif self._opened:file.close()class Au_write:def __init__(self, f):if type(f) == type(''):import builtinsf = builtins.open(f, 'wb')self._opened = Trueelse:self._opened = Falseself.initfp(f)def __del__(self):if self._file:self.close()self._file = Nonedef __enter__(self):return selfdef __exit__(self, *args):self.close()def initfp(self, file):self._file = fileself._framerate = 0self._nchannels = 0self._sampwidth = 0self._framesize = 0self._nframes = AUDIO_UNKNOWN_SIZEself._nframeswritten = 0self._datawritten = 0self._datalength = 0self._info = b''self._comptype = 'ULAW' # default is U-lawdef 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 = nchannelsdef getnchannels(self):if not self._nchannels:raise Error('number of channels not set')return self._nchannelsdef setsampwidth(self, sampwidth):if self._nframeswritten:raise Error('cannot change parameters after starting to write')if sampwidth not in (1, 2, 3, 4):raise Error('bad sample width')self._sampwidth = sampwidthdef getsampwidth(self):if not self._framerate:raise Error('sample width not specified')return self._sampwidthdef setframerate(self, framerate):if self._nframeswritten:raise Error('cannot change parameters after starting to write')self._framerate = frameratedef getframerate(self):if not self._framerate:raise Error('frame rate not set')return self._frameratedef 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 = nframesdef getnframes(self):return self._nframeswrittendef setcomptype(self, type, name):if type in ('NONE', 'ULAW'):self._comptype = typeelse:raise Error('unknown compression type')def getcomptype(self):return self._comptypedef 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, params):nchannels, sampwidth, framerate, nframes, comptype, compname = paramsself.setnchannels(nchannels)self.setsampwidth(sampwidth)self.setframerate(framerate)self.setnframes(nframes)self.setcomptype(comptype, compname)def getparams(self):return _sunau_params(self.getnchannels(), self.getsampwidth(),self.getframerate(), self.getnframes(),self.getcomptype(), self.getcompname())def tell(self):return self._nframeswrittendef writeframesraw(self, data):if not isinstance(data, (bytes, bytearray)):data = memoryview(data).cast('B')self._ensure_header_written()if self._comptype == 'ULAW':import audioopdata = audioop.lin2ulaw(data, self._sampwidth)nframes = len(data) // self._framesizeself._file.write(data)self._nframeswritten = self._nframeswritten + nframesself._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):if self._file:try:self._ensure_header_written()if self._nframeswritten != self._nframes or \self._datalength != self._datawritten:self._patchheader()self._file.flush()finally:file = self._fileself._file = Noneif self._opened:file.close()## private methods#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_8self._framesize = 1elif self._sampwidth == 2:encoding = AUDIO_FILE_ENCODING_LINEAR_16self._framesize = 2elif self._sampwidth == 3:encoding = AUDIO_FILE_ENCODING_LINEAR_24self._framesize = 3elif self._sampwidth == 4:encoding = AUDIO_FILE_ENCODING_LINEAR_32self._framesize = 4else:raise Error('internal error')elif self._comptype == 'ULAW':encoding = AUDIO_FILE_ENCODING_MULAW_8self._framesize = 1else: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_SIZEelse:length = self._nframes * self._framesizetry:self._form_length_pos = self._file.tell()except (AttributeError, OSError):self._form_length_pos = None_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(b'0円'*(header_size - len(self._info) - 24))def _patchheader(self):if self._form_length_pos is None:raise OSError('cannot seek')self._file.seek(self._form_length_pos)_write_u32(self._file, self._datawritten)self._datalength = self._datawrittenself._file.seek(0, 2)def open(f, mode=None):if mode is None:if hasattr(f, 'mode'):mode = f.modeelse:mode = 'rb'if mode in ('r', 'rb'):return Au_read(f)elif mode in ('w', 'wb'):return Au_write(f)else:raise Error("mode must be 'r', 'rb', 'w', or 'wb'")def openfp(f, mode=None):warnings.warn("sunau.openfp is deprecated since Python 3.7. ""Use sunau.open instead.", DeprecationWarning, stacklevel=2)return open(f, mode=mode)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。