diff --git a/Doc/library/aifc.rst b/Doc/library/aifc.rst deleted file mode 100644 index 9f20a30193fa70..00000000000000 --- a/Doc/library/aifc.rst +++ /dev/null @@ -1,247 +0,0 @@ -:mod:`aifc` --- Read and write AIFF and AIFC files -================================================== - -.. module:: aifc - :synopsis: Read and write audio files in AIFF or AIFC format. - :deprecated: - -**Source code:** :source:`Lib/aifc.py` - -.. index:: - single: Audio Interchange File Format - single: AIFF - single: AIFF-C - - -.. deprecated-removed:: 3.11 3.13 - The :mod:`aifc` module is deprecated - (see :pep:`PEP 594 <594#aifc>` for details). - --------------- - -This module provides support for reading and writing AIFF and AIFF-C files. -AIFF is Audio Interchange File Format, a format for storing digital audio -samples in a file. AIFF-C is a newer version of the format that includes the -ability to compress the audio data. - -Audio files have a number of parameters that describe the audio data. The -sampling rate or frame rate is the number of times per second the sound is -sampled. The number of channels indicate if the audio is mono, stereo, or -quadro. Each frame consists of one sample per channel. The sample size is the -size in bytes of each sample. Thus a frame consists of -``nchannels * samplesize`` bytes, and a second's worth of audio consists of -``nchannels * samplesize * framerate`` bytes. - -For example, CD quality audio has a sample size of two bytes (16 bits), uses two -channels (stereo) and has a frame rate of 44,100 frames/second. This gives a -frame size of 4 bytes (2\*2), and a second's worth occupies 2\*2\*44100 bytes -(176,400 bytes). - -Module :mod:`aifc` defines the following function: - - -.. function:: open(file, mode=None) - - Open an AIFF or AIFF-C file and return an object instance with methods that are - described below. The argument *file* is either a string naming a file or a - :term:`file object`. *mode* must be ``'r'`` or ``'rb'`` when the file must be - opened for reading, or ``'w'`` or ``'wb'`` when the file must be opened for writing. - If omitted, ``file.mode`` is used if it exists, otherwise ``'rb'`` is used. When - used for writing, the file object should be seekable, unless you know ahead of - time how many samples you are going to write in total and use - :meth:`writeframesraw` and :meth:`setnframes`. - The :func:`.open` function may be used in a :keyword:`with` statement. When - the :keyword:`!with` block completes, the :meth:`~aifc.close` method is called. - - .. versionchanged:: 3.4 - Support for the :keyword:`with` statement was added. - -Objects returned by :func:`.open` when a file is opened for reading have the -following methods: - - -.. method:: aifc.getnchannels() - - Return the number of audio channels (1 for mono, 2 for stereo). - - -.. method:: aifc.getsampwidth() - - Return the size in bytes of individual samples. - - -.. method:: aifc.getframerate() - - Return the sampling rate (number of audio frames per second). - - -.. method:: aifc.getnframes() - - Return the number of audio frames in the file. - - -.. method:: aifc.getcomptype() - - Return a bytes array of length 4 describing the type of compression - used in the audio file. For AIFF files, the returned value is - ``b'NONE'``. - - -.. method:: aifc.getcompname() - - Return a bytes array convertible to a human-readable description - of the type of compression used in the audio file. For AIFF files, - the returned value is ``b'not compressed'``. - - -.. method:: aifc.getparams() - - Returns a :func:`~collections.namedtuple` ``(nchannels, sampwidth, - framerate, nframes, comptype, compname)``, equivalent to output of the - :meth:`get\*` methods. - - -.. method:: aifc.getmarkers() - - Return a list of markers in the audio file. A marker consists of a tuple of - three elements. The first is the mark ID (an integer), the second is the mark - position in frames from the beginning of the data (an integer), the third is the - name of the mark (a string). - - -.. method:: aifc.getmark(id) - - Return the tuple as described in :meth:`getmarkers` for the mark with the given - *id*. - - -.. method:: aifc.readframes(nframes) - - Read and return the next *nframes* frames from the audio file. The returned - data is a string containing for each frame the uncompressed samples of all - channels. - - -.. method:: aifc.rewind() - - Rewind the read pointer. The next :meth:`readframes` will start from the - beginning. - - -.. method:: aifc.setpos(pos) - - Seek to the specified frame number. - - -.. method:: aifc.tell() - - Return the current frame number. - - -.. method:: aifc.close() - - Close the AIFF file. After calling this method, the object can no longer be - used. - -Objects returned by :func:`.open` when a file is opened for writing have all the -above methods, except for :meth:`readframes` and :meth:`setpos`. In addition -the following methods exist. The :meth:`get\*` methods can only be called after -the corresponding :meth:`set\*` methods have been called. Before the first -:meth:`writeframes` or :meth:`writeframesraw`, all parameters except for the -number of frames must be filled in. - - -.. method:: aifc.aiff() - - Create an AIFF file. The default is that an AIFF-C file is created, unless the - name of the file ends in ``'.aiff'`` in which case the default is an AIFF file. - - -.. method:: aifc.aifc() - - Create an AIFF-C file. The default is that an AIFF-C file is created, unless - the name of the file ends in ``'.aiff'`` in which case the default is an AIFF - file. - - -.. method:: aifc.setnchannels(nchannels) - - Specify the number of channels in the audio file. - - -.. method:: aifc.setsampwidth(width) - - Specify the size in bytes of audio samples. - - -.. method:: aifc.setframerate(rate) - - Specify the sampling frequency in frames per second. - - -.. method:: aifc.setnframes(nframes) - - Specify the number of frames that are to be written to the audio file. If this - parameter is not set, or not set correctly, the file needs to support seeking. - - -.. method:: aifc.setcomptype(type, name) - - .. index:: - single: u-LAW - single: A-LAW - single: G.722 - - Specify the compression type. If not specified, the audio data will - not be compressed. In AIFF files, compression is not possible. - The name parameter should be a human-readable description of the - compression type as a bytes array, the type parameter should be a - bytes array of length 4. Currently the following compression types - are supported: ``b'NONE'``, ``b'ULAW'``, ``b'ALAW'``, ``b'G722'``. - - -.. method:: aifc.setparams(nchannels, sampwidth, framerate, comptype, compname) - - Set all the above parameters at once. The argument is a tuple consisting of the - various parameters. This means that it is possible to use the result of a - :meth:`getparams` call as argument to :meth:`setparams`. - - -.. method:: aifc.setmark(id, pos, name) - - Add a mark with the given id (larger than 0), and the given name at the given - position. This method can be called at any time before :meth:`close`. - - -.. method:: aifc.tell() - :noindex: - - Return the current write position in the output file. Useful in combination - with :meth:`setmark`. - - -.. method:: aifc.writeframes(data) - - Write data to the output file. This method can only be called after the audio - file parameters have been set. - - .. versionchanged:: 3.4 - Any :term:`bytes-like object` is now accepted. - - -.. method:: aifc.writeframesraw(data) - - Like :meth:`writeframes`, except that the header of the audio file is not - updated. - - .. versionchanged:: 3.4 - Any :term:`bytes-like object` is now accepted. - - -.. method:: aifc.close() - :noindex: - - Close the AIFF file. The header of the file is updated to reflect the actual - size of the audio data. After calling this method, the object can no longer be - used. - diff --git a/Doc/library/superseded.rst b/Doc/library/superseded.rst index 7e05f0edf4b1bc..d2e052779b5e0c 100644 --- a/Doc/library/superseded.rst +++ b/Doc/library/superseded.rst @@ -10,7 +10,6 @@ backwards compatibility. They have been superseded by other modules. .. toctree:: - aifc.rst audioop.rst chunk.rst imghdr.rst diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst index 04a28d97d619eb..4dcbc3d4c2d182 100644 --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -119,7 +119,7 @@ Wave_read objects, as returned by :func:`.open`, have the following methods: Rewind the file pointer to the beginning of the audio stream. -The following two methods are defined for compatibility with the :mod:`aifc` +The following two methods are defined for compatibility with the old :mod:`!aifc` module, and don't do anything interesting. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 9f3a99e90bc91b..3d0354c3ab2a4f 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -75,7 +75,6 @@ Doc/install/index.rst Doc/library/__future__.rst Doc/library/_thread.rst Doc/library/abc.rst -Doc/library/aifc.rst Doc/library/ast.rst Doc/library/asyncio-dev.rst Doc/library/asyncio-eventloop.rst diff --git a/Doc/whatsnew/2.0.rst b/Doc/whatsnew/2.0.rst index e6c7ec93a16a17..b1e584987fb14d 100644 --- a/Doc/whatsnew/2.0.rst +++ b/Doc/whatsnew/2.0.rst @@ -1031,7 +1031,7 @@ Module changes Lots of improvements and bugfixes were made to Python's extensive standard library; some of the affected modules include :mod:`readline`, :mod:`ConfigParser`, :mod:`!cgi`, :mod:`calendar`, :mod:`posix`, :mod:`readline`, -:mod:`xmllib`, :mod:`aifc`, :mod:`chunk, wave`, :mod:`random`, :mod:`shelve`, +:mod:`xmllib`, :mod:`!aifc`, :mod:`chunk, wave`, :mod:`random`, :mod:`shelve`, and :mod:`!nntplib`. Consult the CVS logs for the exact patch-by-patch details. Brian Gallew contributed OpenSSL support for the :mod:`socket` module. OpenSSL diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index ece273c7d09039..982d20b622ba6d 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1731,7 +1731,7 @@ Modules slated for removal in Python 3.13: +---------------------+---------------------+---------------------+---------------------+---------------------+ - | :mod:`aifc` | :mod:`chunk` | :mod:`!msilib` | :mod:`!pipes` | :mod:`!telnetlib` | + | :mod:`!aifc` | :mod:`chunk` | :mod:`!msilib` | :mod:`!pipes` | :mod:`!telnetlib` | +---------------------+---------------------+---------------------+---------------------+---------------------+ | :mod:`audioop` | :mod:`!crypt` | :mod:`!nis` | :mod:`!sndhdr` | :mod:`!uu` | +---------------------+---------------------+---------------------+---------------------+---------------------+ diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 7c184063fba5f2..b8a5a0c0125318 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -918,7 +918,7 @@ and will be removed in Python 3.13. Modules (see :pep:`594`): -* :mod:`aifc` +* :mod:`!aifc` * :mod:`audioop` * :mod:`!cgi` * :mod:`!cgitb` diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 38526e1df87af8..9c95d1c70b5a7a 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -221,6 +221,9 @@ Removed the :mod:`base64` module is a modern alternative. (Contributed by Victor Stinner in :gh:`104773`.) +* :pep:`594`: Remove the :mod:`!aifc` module, deprecated in Python 3.11. + (Contributed by Victor Stinner in :gh:`104773`.) + Porting to Python 3.13 ====================== diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index b9008328b49fd5..bcc941065d9acf 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -605,15 +605,15 @@ Using ``ABC`` as a base class has essentially the same effect as specifying aifc ---- -The :meth:`~aifc.aifc.getparams` method now returns a namedtuple rather than a +The :meth:`~!aifc.aifc.getparams` method now returns a namedtuple rather than a plain tuple. (Contributed by Claudiu Popa in :issue:`17818`.) -:func:`aifc.open` now supports the context management protocol: when used in a -:keyword:`with` block, the :meth:`~aifc.aifc.close` method of the returned +:func:`!aifc.open` now supports the context management protocol: when used in a +:keyword:`with` block, the :meth:`~!aifc.aifc.close` method of the returned object will be called automatically at the end of the block. (Contributed by Serhiy Storchacha in :issue:`16486`.) -The :meth:`~aifc.aifc.writeframesraw` and :meth:`~aifc.aifc.writeframes` +The :meth:`~!aifc.aifc.writeframesraw` and :meth:`~!aifc.aifc.writeframes` methods now accept any :term:`bytes-like object`. (Contributed by Serhiy Storchaka in :issue:`8311`.) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index fa89b7db9736ac..24244ff17b1ea0 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -1940,8 +1940,8 @@ Deprecated Python modules, functions and methods aifc ---- -:func:`aifc.openfp` has been deprecated and will be removed in Python 3.9. -Use :func:`aifc.open` instead. +:func:`!aifc.openfp` has been deprecated and will be removed in Python 3.9. +Use :func:`!aifc.open` instead. (Contributed by Brian Curtin in :issue:`31985`.) diff --git a/Lib/aifc.py b/Lib/aifc.py deleted file mode 100644 index 5254987e22bc16..00000000000000 --- a/Lib/aifc.py +++ /dev/null @@ -1,984 +0,0 @@ -"""Stuff to parse AIFF-C and AIFF files. - -Unless explicitly stated otherwise, the description below is true -both for AIFF-C files and AIFF files. - -An AIFF-C file has the following structure. - - +-----------------+ - | FORM | - +-----------------+ - | | - +----+------------+ - | | AIFC | - | +------------+ - | | | - | | . | - | | . | - | | . | - +----+------------+ - -An AIFF file has the string "AIFF" instead of "AIFC". - -A chunk consists of an identifier (4 bytes) followed by a size (4 bytes, -big endian order), followed by the data. The size field does not include -the size of the 8 byte header. - -The following chunk types are recognized. - - FVER - (AIFF-C only). - MARK - <# of markers> (2 bytes) - list of markers: - (2 bytes, must be > 0) - (4 bytes) - ("pstring") - COMM - <# of channels> (2 bytes) - <# of sound frames> (4 bytes) - (2 bytes) - (10 bytes, IEEE 80-bit extended - floating point) - in AIFF-C files only: - (4 bytes) - ("pstring") - SSND - (4 bytes, not used by this program) - (4 bytes, not used by this program) - - -A pstring consists of 1 byte length, a string of characters, and 0 or 1 -byte pad to make the total length even. - -Usage. - -Reading AIFF files: - f = aifc.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(). -In some types of audio files, if the setpos() method is 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 - getcomptype() -- returns compression type ('NONE' for AIFF files) - getcompname() -- returns human-readable version of - compression type ('not compressed' for AIFF files) - getparams() -- returns a namedtuple consisting of all of the - above in the above order - getmarkers() -- get the list of marks in the audio file or None - if there are no marks - getmark(id) -- get mark with the specified id (raises an error - if the mark does not exist) - 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(), the position given to setpos() and -the position of marks are all compatible and have nothing to do with -the actual position in the file. -The close() method is called automatically when the class instance -is destroyed. - -Writing AIFF files: - f = aifc.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(), and -close(). - -This returns an instance of a class with the following public methods: - aiff() -- create an AIFF file (AIFF-C default) - aifc() -- create an AIFF-C file - 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 - setparams(tuple) - -- set all parameters at once - setmark(id, pos, name) - -- add specified mark to the list of marks - tell() -- return current position in output file (useful - in combination with setmark()) - 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(b'') or -close() to patch up the sizes in the header. -Marks can be added anytime. If there are any marks, you must call -close() after all frames have been written. -The close() method is called automatically when the class instance -is destroyed. - -When a file is opened with the extension '.aiff', an AIFF file is -written, otherwise an AIFF-C file is written. This default can be -changed by calling aiff() or aifc() before the first writeframes or -writeframesraw. -""" - -import struct -import builtins -import warnings - -__all__ = ["Error", "open"] - - -warnings._deprecated(__name__, remove=(3, 13)) - - -class Error(Exception): - pass - -_AIFC_version = 0xA2805140 # Version 1 of AIFF-C - -def _read_long(file): - try: - return struct.unpack('>l', file.read(4))[0] - except struct.error: - raise EOFError from None - -def _read_ulong(file): - try: - return struct.unpack('>L', file.read(4))[0] - except struct.error: - raise EOFError from None - -def _read_short(file): - try: - return struct.unpack('>h', file.read(2))[0] - except struct.error: - raise EOFError from None - -def _read_ushort(file): - try: - return struct.unpack('>H', file.read(2))[0] - except struct.error: - raise EOFError from None - -def _read_string(file): - length = ord(file.read(1)) - if length == 0: - data = b'' - else: - data = file.read(length) - if length & 1 == 0: - dummy = file.read(1) - return data - -_HUGE_VAL = 1.79769313486231e+308 # See - -def _read_float(f): # 10 bytes - expon = _read_short(f) # 2 bytes - sign = 1 - if expon < 0: - sign = -1 - expon = expon + 0x8000 - himant = _read_ulong(f) # 4 bytes - lomant = _read_ulong(f) # 4 bytes - if expon == himant == lomant == 0: - f = 0.0 - elif expon == 0x7FFF: - f = _HUGE_VAL - else: - expon = expon - 16383 - f = (himant * 0x100000000 + lomant) * pow(2.0, expon - 63) - return sign * f - -def _write_short(f, x): - f.write(struct.pack('>h', x)) - -def _write_ushort(f, x): - f.write(struct.pack('>H', x)) - -def _write_long(f, x): - f.write(struct.pack('>l', x)) - -def _write_ulong(f, x): - f.write(struct.pack('>L', x)) - -def _write_string(f, s): - if len(s) > 255: - raise ValueError("string exceeds maximum pstring length") - f.write(struct.pack('B', len(s))) - f.write(s) - if len(s) & 1 == 0: - f.write(b'\x00') - -def _write_float(f, x): - import math - if x < 0: - sign = 0x8000 - x = x * -1 - else: - sign = 0 - if x == 0: - expon = 0 - himant = 0 - lomant = 0 - else: - fmant, expon = math.frexp(x) - if expon > 16384 or fmant >= 1 or fmant != fmant: # Infinity or NaN - expon = sign|0x7FFF - himant = 0 - lomant = 0 - else: # Finite - expon = expon + 16382 - if expon < 0: # denormalized - fmant = math.ldexp(fmant, expon) - expon = 0 - expon = expon | sign - fmant = math.ldexp(fmant, 32) - fsmant = math.floor(fmant) - himant = int(fsmant) - fmant = math.ldexp(fmant - fsmant, 32) - fsmant = math.floor(fmant) - lomant = int(fsmant) - _write_ushort(f, expon) - _write_ulong(f, himant) - _write_ulong(f, lomant) - -with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - from chunk import Chunk -from collections import namedtuple - -_aifc_params = namedtuple('_aifc_params', - 'nchannels sampwidth framerate nframes comptype compname') - -_aifc_params.nchannels.__doc__ = 'Number of audio channels (1 for mono, 2 for stereo)' -_aifc_params.sampwidth.__doc__ = 'Sample width in bytes' -_aifc_params.framerate.__doc__ = 'Sampling frequency' -_aifc_params.nframes.__doc__ = 'Number of audio frames' -_aifc_params.comptype.__doc__ = 'Compression type ("NONE" for AIFF files)' -_aifc_params.compname.__doc__ = ("""\ -A human-readable version of the compression type -('not compressed' for AIFF files)""") - - -class Aifc_read: - # Variables used in this class: - # - # These variables are available to the user though appropriate - # methods of this class: - # _file -- the open file with methods read(), close(), and seek() - # set through the __init__() method - # _nchannels -- the number of audio channels - # available through the getnchannels() method - # _nframes -- the number of audio frames - # available through the getnframes() method - # _sampwidth -- the number of bytes per audio sample - # available through the getsampwidth() method - # _framerate -- the sampling frequency - # available through the getframerate() method - # _comptype -- the AIFF-C compression type ('NONE' if AIFF) - # available through the getcomptype() method - # _compname -- the human-readable AIFF-C compression type - # available through the getcomptype() method - # _markers -- the marks in the audio file - # available through the getmarkers() and getmark() - # methods - # _soundpos -- the position in the audio stream - # available through the tell() method, set through the - # setpos() method - # - # These variables are used internally only: - # _version -- the AIFF-C version number - # _decomp -- the decompressor from builtin module cl - # _comm_chunk_read -- 1 iff the COMM chunk has been read - # _aifc -- 1 iff reading an AIFF-C file - # _ssnd_seek_needed -- 1 iff positioned correctly in audio - # file for readframes() - # _ssnd_chunk -- instantiation of a chunk class for the SSND chunk - # _framesize -- size of one frame in the file - - _file = None # Set here since __del__ checks it - - def initfp(self, file): - self._version = 0 - self._convert = None - self._markers = [] - self._soundpos = 0 - self._file = file - chunk = Chunk(file) - if chunk.getname() != b'FORM': - raise Error('file does not start with FORM id') - formdata = chunk.read(4) - if formdata == b'AIFF': - self._aifc = 0 - elif formdata == b'AIFC': - self._aifc = 1 - else: - raise Error('not an AIFF or AIFF-C file') - self._comm_chunk_read = 0 - self._ssnd_chunk = None - while 1: - self._ssnd_seek_needed = 1 - try: - chunk = Chunk(self._file) - except EOFError: - break - chunkname = chunk.getname() - if chunkname == b'COMM': - self._read_comm_chunk(chunk) - self._comm_chunk_read = 1 - elif chunkname == b'SSND': - self._ssnd_chunk = chunk - dummy = chunk.read(8) - self._ssnd_seek_needed = 0 - elif chunkname == b'FVER': - self._version = _read_ulong(chunk) - elif chunkname == b'MARK': - self._readmark(chunk) - chunk.skip() - if not self._comm_chunk_read or not self._ssnd_chunk: - raise Error('COMM chunk and/or SSND chunk missing') - - def __init__(self, f): - if isinstance(f, str): - file_object = builtins.open(f, 'rb') - try: - self.initfp(file_object) - except: - file_object.close() - raise - else: - # assume it is an open file object already - self.initfp(f) - - def __enter__(self): - return self - - def __exit__(self, *args): - self.close() - - # - # User visible methods. - # - def getfp(self): - return self._file - - def rewind(self): - self._ssnd_seek_needed = 1 - self._soundpos = 0 - - def close(self): - file = self._file - if file is not None: - self._file = None - file.close() - - def tell(self): - return self._soundpos - - def getnchannels(self): - return self._nchannels - - def getnframes(self): - return self._nframes - - def getsampwidth(self): - return self._sampwidth - - def getframerate(self): - return self._framerate - - def getcomptype(self): - return self._comptype - - def getcompname(self): - return self._compname - -## def getversion(self): -## return self._version - - def getparams(self): - return _aifc_params(self.getnchannels(), self.getsampwidth(), - self.getframerate(), self.getnframes(), - self.getcomptype(), self.getcompname()) - - def getmarkers(self): - if len(self._markers) == 0: - return None - return self._markers - - def getmark(self, id): - for marker in self._markers: - if id == marker[0]: - return marker - raise Error('marker {0!r} does not exist'.format(id)) - - def setpos(self, pos): - if pos < 0 or pos > self._nframes: - raise Error('position not in range') - self._soundpos = pos - self._ssnd_seek_needed = 1 - - def readframes(self, nframes): - if self._ssnd_seek_needed: - self._ssnd_chunk.seek(0) - dummy = self._ssnd_chunk.read(8) - pos = self._soundpos * self._framesize - if pos: - self._ssnd_chunk.seek(pos + 8) - self._ssnd_seek_needed = 0 - if nframes == 0: - return b'' - data = self._ssnd_chunk.read(nframes * self._framesize) - if self._convert and data: - data = self._convert(data) - self._soundpos = self._soundpos + len(data) // (self._nchannels - * self._sampwidth) - return data - - # - # Internal methods. - # - - def _alaw2lin(self, data): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', category=DeprecationWarning) - import audioop - return audioop.alaw2lin(data, 2) - - def _ulaw2lin(self, data): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', category=DeprecationWarning) - import audioop - return audioop.ulaw2lin(data, 2) - - def _adpcm2lin(self, data): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', category=DeprecationWarning) - import audioop - if not hasattr(self, '_adpcmstate'): - # first time - self._adpcmstate = None - data, self._adpcmstate = audioop.adpcm2lin(data, 2, self._adpcmstate) - return data - - def _sowt2lin(self, data): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', category=DeprecationWarning) - import audioop - return audioop.byteswap(data, 2) - - def _read_comm_chunk(self, chunk): - self._nchannels = _read_short(chunk) - self._nframes = _read_long(chunk) - self._sampwidth = (_read_short(chunk) + 7) // 8 - self._framerate = int(_read_float(chunk)) - if self._sampwidth <= 0: - raise Error('bad sample width') - if self._nchannels <= 0: - raise Error('bad # of channels') - self._framesize = self._nchannels * self._sampwidth - if self._aifc: - #DEBUG: SGI's soundeditor produces a bad size :-( - kludge = 0 - if chunk.chunksize == 18: - kludge = 1 - warnings.warn('Warning: bad COMM chunk size') - chunk.chunksize = 23 - #DEBUG end - self._comptype = chunk.read(4) - #DEBUG start - if kludge: - length = ord(chunk.file.read(1)) - if length & 1 == 0: - length = length + 1 - chunk.chunksize = chunk.chunksize + length - chunk.file.seek(-1, 1) - #DEBUG end - self._compname = _read_string(chunk) - if self._comptype != b'NONE': - if self._comptype == b'G722': - self._convert = self._adpcm2lin - elif self._comptype in (b'ulaw', b'ULAW'): - self._convert = self._ulaw2lin - elif self._comptype in (b'alaw', b'ALAW'): - self._convert = self._alaw2lin - elif self._comptype in (b'sowt', b'SOWT'): - self._convert = self._sowt2lin - else: - raise Error('unsupported compression type') - self._sampwidth = 2 - else: - self._comptype = b'NONE' - self._compname = b'not compressed' - - def _readmark(self, chunk): - nmarkers = _read_short(chunk) - # Some files appear to contain invalid counts. - # Cope with this by testing for EOF. - try: - for i in range(nmarkers): - id = _read_short(chunk) - pos = _read_long(chunk) - name = _read_string(chunk) - if pos or name: - # some files appear to have - # dummy markers consisting of - # a position 0 and name '' - self._markers.append((id, pos, name)) - except EOFError: - w = ('Warning: MARK chunk contains only %s marker%s instead of %s' % - (len(self._markers), '' if len(self._markers) == 1 else 's', - nmarkers)) - warnings.warn(w) - -class Aifc_write: - # Variables used in this class: - # - # These variables are user settable through appropriate methods - # of this class: - # _file -- the open file with methods write(), close(), tell(), seek() - # set through the __init__() method - # _comptype -- the AIFF-C compression type ('NONE' in AIFF) - # set through the setcomptype() or setparams() method - # _compname -- the human-readable AIFF-C compression type - # set through the setcomptype() or setparams() method - # _nchannels -- the number of audio channels - # set through the setnchannels() or setparams() method - # _sampwidth -- the number of bytes per audio sample - # set through the setsampwidth() or setparams() method - # _framerate -- the sampling frequency - # set through the setframerate() or setparams() method - # _nframes -- the number of audio frames written to the header - # set through the setnframes() or setparams() method - # _aifc -- whether we're writing an AIFF-C file or an AIFF file - # set through the aifc() method, reset through the - # aiff() method - # - # These variables are used internally only: - # _version -- the AIFF-C version number - # _comp -- the compressor from builtin module cl - # _nframeswritten -- the number of audio frames actually written - # _datalength -- the size of the audio samples written to the header - # _datawritten -- the size of the audio samples actually written - - _file = None # Set here since __del__ checks it - - def __init__(self, f): - if isinstance(f, str): - file_object = builtins.open(f, 'wb') - try: - self.initfp(file_object) - except: - file_object.close() - raise - - # treat .aiff file extensions as non-compressed audio - if f.endswith('.aiff'): - self._aifc = 0 - else: - # assume it is an open file object already - self.initfp(f) - - def initfp(self, file): - self._file = file - self._version = _AIFC_version - self._comptype = b'NONE' - self._compname = b'not compressed' - self._convert = None - self._nchannels = 0 - self._sampwidth = 0 - self._framerate = 0 - self._nframes = 0 - self._nframeswritten = 0 - self._datawritten = 0 - self._datalength = 0 - self._markers = [] - self._marklength = 0 - self._aifc = 1 # AIFF-C is default - - def __del__(self): - self.close() - - def __enter__(self): - return self - - def __exit__(self, *args): - self.close() - - # - # User visible methods. - # - def aiff(self): - if self._nframeswritten: - raise Error('cannot change parameters after starting to write') - self._aifc = 0 - - def aifc(self): - if self._nframeswritten: - raise Error('cannot change parameters after starting to write') - self._aifc = 1 - - def setnchannels(self, nchannels): - if self._nframeswritten: - raise Error('cannot change parameters after starting to write') - if nchannels < 1: - raise Error('bad # of channels') - 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 < 1 or sampwidth > 4: - raise Error('bad sample width') - self._sampwidth = sampwidth - - def getsampwidth(self): - if not self._sampwidth: - raise Error('sample width not set') - return self._sampwidth - - def setframerate(self, framerate): - if self._nframeswritten: - raise Error('cannot change parameters after starting to write') - if framerate <= 0: - raise Error('bad frame rate') - 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') - self._nframes = nframes - - def getnframes(self): - return self._nframeswritten - - def setcomptype(self, comptype, compname): - if self._nframeswritten: - raise Error('cannot change parameters after starting to write') - if comptype not in (b'NONE', b'ulaw', b'ULAW', - b'alaw', b'ALAW', b'G722', b'sowt', b'SOWT'): - raise Error('unsupported compression type') - self._comptype = comptype - self._compname = compname - - def getcomptype(self): - return self._comptype - - def getcompname(self): - return self._compname - -## def setversion(self, version): -## if self._nframeswritten: -## raise Error, 'cannot change parameters after starting to write' -## self._version = version - - def setparams(self, params): - nchannels, sampwidth, framerate, nframes, comptype, compname = params - if self._nframeswritten: - raise Error('cannot change parameters after starting to write') - if comptype not in (b'NONE', b'ulaw', b'ULAW', - b'alaw', b'ALAW', b'G722', b'sowt', b'SOWT'): - raise Error('unsupported compression type') - self.setnchannels(nchannels) - self.setsampwidth(sampwidth) - self.setframerate(framerate) - self.setnframes(nframes) - self.setcomptype(comptype, compname) - - def getparams(self): - if not self._nchannels or not self._sampwidth or not self._framerate: - raise Error('not all parameters set') - return _aifc_params(self._nchannels, self._sampwidth, self._framerate, - self._nframes, self._comptype, self._compname) - - def setmark(self, id, pos, name): - if id <= 0: - raise Error('marker ID must be > 0') - if pos < 0: - raise Error('marker position must be >= 0') - if not isinstance(name, bytes): - raise Error('marker name must be bytes') - for i in range(len(self._markers)): - if id == self._markers[i][0]: - self._markers[i] = id, pos, name - return - self._markers.append((id, pos, name)) - - def getmark(self, id): - for marker in self._markers: - if id == marker[0]: - return marker - raise Error('marker {0!r} does not exist'.format(id)) - - def getmarkers(self): - if len(self._markers) == 0: - return None - return self._markers - - def tell(self): - return self._nframeswritten - - def writeframesraw(self, data): - if not isinstance(data, (bytes, bytearray)): - data = memoryview(data).cast('B') - self._ensure_header_written(len(data)) - nframes = len(data) // (self._sampwidth * self._nchannels) - if self._convert: - data = self._convert(data) - 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): - if self._file is None: - return - try: - self._ensure_header_written(0) - if self._datawritten & 1: - # quick pad to even size - self._file.write(b'\x00') - self._datawritten = self._datawritten + 1 - self._writemarkers() - if self._nframeswritten != self._nframes or \ - self._datalength != self._datawritten or \ - self._marklength: - self._patchheader() - finally: - # Prevent ref cycles - self._convert = None - f = self._file - self._file = None - f.close() - - # - # Internal methods. - # - - def _lin2alaw(self, data): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', category=DeprecationWarning) - import audioop - return audioop.lin2alaw(data, 2) - - def _lin2ulaw(self, data): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', category=DeprecationWarning) - import audioop - return audioop.lin2ulaw(data, 2) - - def _lin2adpcm(self, data): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', category=DeprecationWarning) - import audioop - if not hasattr(self, '_adpcmstate'): - self._adpcmstate = None - data, self._adpcmstate = audioop.lin2adpcm(data, 2, self._adpcmstate) - return data - - def _lin2sowt(self, data): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', category=DeprecationWarning) - import audioop - return audioop.byteswap(data, 2) - - def _ensure_header_written(self, datasize): - if not self._nframeswritten: - if self._comptype in (b'ULAW', b'ulaw', - b'ALAW', b'alaw', b'G722', - b'sowt', b'SOWT'): - if not self._sampwidth: - self._sampwidth = 2 - if self._sampwidth != 2: - raise Error('sample width must be 2 when compressing ' - 'with ulaw/ULAW, alaw/ALAW, sowt/SOWT ' - 'or G7.22 (ADPCM)') - if not self._nchannels: - raise Error('# channels not specified') - if not self._sampwidth: - raise Error('sample width not specified') - if not self._framerate: - raise Error('sampling rate not specified') - self._write_header(datasize) - - def _init_compression(self): - if self._comptype == b'G722': - self._convert = self._lin2adpcm - elif self._comptype in (b'ulaw', b'ULAW'): - self._convert = self._lin2ulaw - elif self._comptype in (b'alaw', b'ALAW'): - self._convert = self._lin2alaw - elif self._comptype in (b'sowt', b'SOWT'): - self._convert = self._lin2sowt - - def _write_header(self, initlength): - if self._aifc and self._comptype != b'NONE': - self._init_compression() - self._file.write(b'FORM') - if not self._nframes: - self._nframes = initlength // (self._nchannels * self._sampwidth) - self._datalength = self._nframes * self._nchannels * self._sampwidth - if self._datalength & 1: - self._datalength = self._datalength + 1 - if self._aifc: - if self._comptype in (b'ulaw', b'ULAW', b'alaw', b'ALAW'): - self._datalength = self._datalength // 2 - if self._datalength & 1: - self._datalength = self._datalength + 1 - elif self._comptype == b'G722': - self._datalength = (self._datalength + 3) // 4 - if self._datalength & 1: - self._datalength = self._datalength + 1 - try: - self._form_length_pos = self._file.tell() - except (AttributeError, OSError): - self._form_length_pos = None - commlength = self._write_form_length(self._datalength) - if self._aifc: - self._file.write(b'AIFC') - self._file.write(b'FVER') - _write_ulong(self._file, 4) - _write_ulong(self._file, self._version) - else: - self._file.write(b'AIFF') - self._file.write(b'COMM') - _write_ulong(self._file, commlength) - _write_short(self._file, self._nchannels) - if self._form_length_pos is not None: - self._nframes_pos = self._file.tell() - _write_ulong(self._file, self._nframes) - if self._comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): - _write_short(self._file, 8) - else: - _write_short(self._file, self._sampwidth * 8) - _write_float(self._file, self._framerate) - if self._aifc: - self._file.write(self._comptype) - _write_string(self._file, self._compname) - self._file.write(b'SSND') - if self._form_length_pos is not None: - self._ssnd_length_pos = self._file.tell() - _write_ulong(self._file, self._datalength + 8) - _write_ulong(self._file, 0) - _write_ulong(self._file, 0) - - def _write_form_length(self, datalength): - if self._aifc: - commlength = 18 + 5 + len(self._compname) - if commlength & 1: - commlength = commlength + 1 - verslength = 12 - else: - commlength = 18 - verslength = 0 - _write_ulong(self._file, 4 + verslength + self._marklength + \ - 8 + commlength + 16 + datalength) - return commlength - - def _patchheader(self): - curpos = self._file.tell() - if self._datawritten & 1: - datalength = self._datawritten + 1 - self._file.write(b'\x00') - else: - datalength = self._datawritten - if datalength == self._datalength and \ - self._nframes == self._nframeswritten and \ - self._marklength == 0: - self._file.seek(curpos, 0) - return - self._file.seek(self._form_length_pos, 0) - dummy = self._write_form_length(datalength) - self._file.seek(self._nframes_pos, 0) - _write_ulong(self._file, self._nframeswritten) - self._file.seek(self._ssnd_length_pos, 0) - _write_ulong(self._file, datalength + 8) - self._file.seek(curpos, 0) - self._nframes = self._nframeswritten - self._datalength = datalength - - def _writemarkers(self): - if len(self._markers) == 0: - return - self._file.write(b'MARK') - length = 2 - for marker in self._markers: - id, pos, name = marker - length = length + len(name) + 1 + 6 - if len(name) & 1 == 0: - length = length + 1 - _write_ulong(self._file, length) - self._marklength = length + 8 - _write_short(self._file, len(self._markers)) - for marker in self._markers: - id, pos, name = marker - _write_short(self._file, id) - _write_ulong(self._file, pos) - _write_string(self._file, name) - -def open(f, mode=None): - if mode is None: - if hasattr(f, 'mode'): - mode = f.mode - else: - mode = 'rb' - if mode in ('r', 'rb'): - return Aifc_read(f) - elif mode in ('w', 'wb'): - return Aifc_write(f) - else: - raise Error("mode must be 'r', 'rb', 'w', or 'wb'") - - -if __name__ == '__main__': - import sys - if not sys.argv[1:]: - sys.argv.append('/usr/demos/data/audio/bach.aiff') - fn = sys.argv[1] - with open(fn, 'r') as f: - print("Reading", fn) - print("nchannels =", f.getnchannels()) - print("nframes =", f.getnframes()) - print("sampwidth =", f.getsampwidth()) - print("framerate =", f.getframerate()) - print("comptype =", f.getcomptype()) - print("compname =", f.getcompname()) - if sys.argv[2:]: - gn = sys.argv[2] - print("Writing", gn) - with open(gn, 'w') as g: - g.setparams(f.getparams()) - while 1: - data = f.readframes(1024) - if not data: - break - g.writeframes(data) - print("Done.") diff --git a/Lib/test/Sine-1000Hz-300ms.aif b/Lib/test/Sine-1000Hz-300ms.aif deleted file mode 100644 index bf08f5ce859429..00000000000000 Binary files a/Lib/test/Sine-1000Hz-300ms.aif and /dev/null differ diff --git a/Lib/test/audiodata/pluck-alaw.aifc b/Lib/test/audiodata/pluck-alaw.aifc deleted file mode 100644 index 3b7fbd2af75a0a..00000000000000 Binary files a/Lib/test/audiodata/pluck-alaw.aifc and /dev/null differ diff --git a/Lib/test/audiodata/pluck-pcm16.aiff b/Lib/test/audiodata/pluck-pcm16.aiff deleted file mode 100644 index 6c8c40d1409289..00000000000000 Binary files a/Lib/test/audiodata/pluck-pcm16.aiff and /dev/null differ diff --git a/Lib/test/audiodata/pluck-pcm24.aiff b/Lib/test/audiodata/pluck-pcm24.aiff deleted file mode 100644 index 8eba145a44d37a..00000000000000 Binary files a/Lib/test/audiodata/pluck-pcm24.aiff and /dev/null differ diff --git a/Lib/test/audiodata/pluck-pcm32.aiff b/Lib/test/audiodata/pluck-pcm32.aiff deleted file mode 100644 index 46ac0373f6abbc..00000000000000 Binary files a/Lib/test/audiodata/pluck-pcm32.aiff and /dev/null differ diff --git a/Lib/test/audiodata/pluck-pcm8.aiff b/Lib/test/audiodata/pluck-pcm8.aiff deleted file mode 100644 index 5de4f3b2d879ba..00000000000000 Binary files a/Lib/test/audiodata/pluck-pcm8.aiff and /dev/null differ diff --git a/Lib/test/audiodata/pluck-ulaw.aifc b/Lib/test/audiodata/pluck-ulaw.aifc deleted file mode 100644 index 3085cf097fb18a..00000000000000 Binary files a/Lib/test/audiodata/pluck-ulaw.aifc and /dev/null differ diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py deleted file mode 100644 index d3863d4915d449..00000000000000 --- a/Lib/test/test_aifc.py +++ /dev/null @@ -1,439 +0,0 @@ -from test.support import findfile -from test.support.os_helper import TESTFN, unlink -from test.support.warnings_helper import check_no_resource_warning, import_deprecated -import unittest -from unittest import mock -from test import audiotests -import io -import sys -import struct - - -aifc = import_deprecated("aifc") -audioop = import_deprecated("audioop") - - -class AifcTest(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile): - module = aifc - close_fd = True - test_unseekable_read = None - - -class AifcPCM8Test(AifcTest, unittest.TestCase): - sndfilename = 'pluck-pcm8.aiff' - sndfilenframes = 3307 - nchannels = 2 - sampwidth = 1 - framerate = 11025 - nframes = 48 - comptype = b'NONE' - compname = b'not compressed' - frames = bytes.fromhex("""\ - 02FF 4B00 3104 8008 CB06 4803 BF01 03FE B8FA B4F3 29EB 1AE6 \ - EDE4 C6E2 0EE0 EFE0 57E2 FBE8 13EF D8F7 97FB F5FC 08FB DFFB \ - 11FA 3EFB BCFC 66FF CF04 4309 C10E 5112 EE17 8216 7F14 8012 \ - 490E 520D EF0F CE0F E40C 630A 080A 2B0B 510E 8B11 B60E 440A \ - """) - - -class AifcPCM16Test(AifcTest, unittest.TestCase): - sndfilename = 'pluck-pcm16.aiff' - sndfilenframes = 3307 - nchannels = 2 - sampwidth = 2 - framerate = 11025 - nframes = 48 - comptype = b'NONE' - compname = b'not compressed' - frames = bytes.fromhex("""\ - 022EFFEA 4B5D00F6 311804EA 80E10840 CBE106B1 48A903F5 BFE601B2 036CFE7B \ - B858FA3E B4B1F34F 299AEBCA 1A5DE6DA EDFAE491 C628E275 0E09E0B5 EF2AE029 \ - 5758E271 FB35E83F 1376EF86 D82BF727 9790FB76 F5FAFC0F 0867FB9C DF30FB43 \ - 117EFA36 3EE5FB5B BC79FCB1 66D9FF5D CF150412 431D097C C1BA0EC8 512112A1 \ - EEE21753 82071665 7FFF1443 8004128F 49A20EAF 52BB0DBA EFB40F60 CE3C0FBF \ - E4B30CEC 63430A5C 08C80A20 2BBB0B08 514A0E43 8BCF1139 B6F60EEB 44120A5E \ - """) - - -class AifcPCM24Test(AifcTest, unittest.TestCase): - sndfilename = 'pluck-pcm24.aiff' - sndfilenframes = 3307 - nchannels = 2 - sampwidth = 3 - framerate = 11025 - nframes = 48 - comptype = b'NONE' - compname = b'not compressed' - frames = bytes.fromhex("""\ - 022D65FFEB9D 4B5A0F00FA54 3113C304EE2B 80DCD6084303 \ - CBDEC006B261 48A99803F2F8 BFE82401B07D 036BFBFE7B5D \ - B85756FA3EC9 B4B055F3502B 299830EBCB62 1A5CA7E6D99A \ - EDFA3EE491BD C625EBE27884 0E05A9E0B6CF EF2929E02922 \ - 5758D8E27067 FB3557E83E16 1377BFEF8402 D82C5BF7272A \ - 978F16FB7745 F5F865FC1013 086635FB9C4E DF30FCFB40EE \ - 117FE0FA3438 3EE6B8FB5AC3 BC77A3FCB2F4 66D6DAFF5F32 \ - CF13B9041275 431D69097A8C C1BB600EC74E 5120B912A2BA \ - EEDF641754C0 8207001664B7 7FFFFF14453F 8000001294E6 \ - 499C1B0EB3B2 52B73E0DBCA0 EFB2B20F5FD8 CE3CDB0FBE12 \ - E4B49C0CEA2D 6344A80A5A7C 08C8FE0A1FFE 2BB9860B0A0E \ - 51486F0E44E1 8BCC64113B05 B6F4EC0EEB36 4413170A5B48 \ - """) - - -class AifcPCM32Test(AifcTest, unittest.TestCase): - sndfilename = 'pluck-pcm32.aiff' - sndfilenframes = 3307 - nchannels = 2 - sampwidth = 4 - framerate = 11025 - nframes = 48 - comptype = b'NONE' - compname = b'not compressed' - frames = bytes.fromhex("""\ - 022D65BCFFEB9D92 4B5A0F8000FA549C 3113C34004EE2BC0 80DCD680084303E0 \ - CBDEC0C006B26140 48A9980003F2F8FC BFE8248001B07D92 036BFB60FE7B5D34 \ - B8575600FA3EC920 B4B05500F3502BC0 29983000EBCB6240 1A5CA7A0E6D99A60 \ - EDFA3E80E491BD40 C625EB80E27884A0 0E05A9A0E0B6CFE0 EF292940E0292280 \ - 5758D800E2706700 FB3557D8E83E1640 1377BF00EF840280 D82C5B80F7272A80 \ - 978F1600FB774560 F5F86510FC101364 086635A0FB9C4E20 DF30FC40FB40EE28 \ - 117FE0A0FA3438B0 3EE6B840FB5AC3F0 BC77A380FCB2F454 66D6DA80FF5F32B4 \ - CF13B980041275B0 431D6980097A8C00 C1BB60000EC74E00 5120B98012A2BAA0 \ - EEDF64C01754C060 820700001664B780 7FFFFFFF14453F40 800000001294E6E0 \ - 499C1B000EB3B270 52B73E000DBCA020 EFB2B2E00F5FD880 CE3CDB400FBE1270 \ - E4B49CC00CEA2D90 6344A8800A5A7CA0 08C8FE800A1FFEE0 2BB986C00B0A0E00 \ - 51486F800E44E190 8BCC6480113B0580 B6F4EC000EEB3630 441317800A5B48A0 \ - """) - - -class AifcULAWTest(AifcTest, unittest.TestCase): - sndfilename = 'pluck-ulaw.aifc' - sndfilenframes = 3307 - nchannels = 2 - sampwidth = 2 - framerate = 11025 - nframes = 48 - comptype = b'ulaw' - compname = b'' - frames = bytes.fromhex("""\ - 022CFFE8 497C0104 307C04DC 8284083C CB84069C 497C03DC BE8401AC 036CFE74 \ - B684FA24 B684F344 2A7CEC04 19FCE704 EE04E504 C584E204 0E3CE104 EF04DF84 \ - 557CE204 FB24E804 12FCEF04 D784F744 9684FB64 F5C4FC24 083CFBA4 DF84FB24 \ - 11FCFA24 3E7CFB64 BA84FCB4 657CFF5C CF84041C 417C093C C1840EBC 517C12FC \ - EF0416FC 828415FC 7D7C13FC 828412FC 497C0EBC 517C0DBC F0040F3C CD840FFC \ - E5040CBC 617C0A3C 08BC0A3C 2C7C0B3C 517C0E3C 8A8410FC B6840EBC 457C0A3C \ - """) - if sys.byteorder != 'big': - frames = audioop.byteswap(frames, 2) - - -class AifcALAWTest(AifcTest, unittest.TestCase): - sndfilename = 'pluck-alaw.aifc' - sndfilenframes = 3307 - nchannels = 2 - sampwidth = 2 - framerate = 11025 - nframes = 48 - comptype = b'alaw' - compname = b'' - frames = bytes.fromhex("""\ - 0230FFE8 4A0000F8 310004E0 82000840 CB0006A0 4A0003F0 BE0001A8 0370FE78 \ - BA00FA20 B600F340 2900EB80 1A80E680 ED80E480 C700E280 0E40E080 EF80E080 \ - 5600E280 FB20E880 1380EF80 D900F740 9600FB60 F5C0FC10 0840FBA0 DF00FB20 \ - 1180FA20 3F00FB60 BE00FCB0 6600FF58 CF000420 42000940 C1000EC0 52001280 \ - EE801780 82001680 7E001480 82001280 4A000EC0 52000DC0 EF800F40 CF000FC0 \ - E4800CC0 62000A40 08C00A40 2B000B40 52000E40 8A001180 B6000EC0 46000A40 \ - """) - if sys.byteorder != 'big': - frames = audioop.byteswap(frames, 2) - - -class AifcMiscTest(unittest.TestCase): - def test_skipunknown(self): - #Issue 2245 - #This file contains chunk types aifc doesn't recognize. - f = aifc.open(findfile('Sine-1000Hz-300ms.aif')) - f.close() - - def test_close_opened_files_on_error(self): - non_aifc_file = findfile('pluck-pcm8.wav', subdir='audiodata') - with check_no_resource_warning(self): - with self.assertRaises(aifc.Error): - # Try opening a non-AIFC file, with the expectation that - # `aifc.open` will fail (without raising a ResourceWarning) - self.f = aifc.open(non_aifc_file, 'rb') - - # Aifc_write.initfp() won't raise in normal case. But some errors - # (e.g. MemoryError, KeyboardInterrupt, etc..) can happen. - with mock.patch.object(aifc.Aifc_write, 'initfp', - side_effect=RuntimeError): - with self.assertRaises(RuntimeError): - self.fout = aifc.open(TESTFN, 'wb') - - def test_params_added(self): - f = self.f = aifc.open(TESTFN, 'wb') - f.aiff() - f.setparams((1, 1, 1, 1, b'NONE', b'')) - f.close() - - f = aifc.open(TESTFN, 'rb') - self.addCleanup(f.close) - params = f.getparams() - self.assertEqual(params.nchannels, f.getnchannels()) - self.assertEqual(params.sampwidth, f.getsampwidth()) - self.assertEqual(params.framerate, f.getframerate()) - self.assertEqual(params.nframes, f.getnframes()) - self.assertEqual(params.comptype, f.getcomptype()) - self.assertEqual(params.compname, f.getcompname()) - - def test_write_header_comptype_sampwidth(self): - for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): - fout = aifc.open(io.BytesIO(), 'wb') - fout.setnchannels(1) - fout.setframerate(1) - fout.setcomptype(comptype, b'') - fout.close() - self.assertEqual(fout.getsampwidth(), 2) - fout.initfp(None) - - def test_write_markers_values(self): - fout = aifc.open(io.BytesIO(), 'wb') - self.assertEqual(fout.getmarkers(), None) - fout.setmark(1, 0, b'foo1') - fout.setmark(1, 1, b'foo2') - self.assertEqual(fout.getmark(1), (1, 1, b'foo2')) - self.assertEqual(fout.getmarkers(), [(1, 1, b'foo2')]) - fout.initfp(None) - - def test_read_markers(self): - fout = self.fout = aifc.open(TESTFN, 'wb') - fout.aiff() - fout.setparams((1, 1, 1, 1, b'NONE', b'')) - fout.setmark(1, 0, b'odd') - fout.setmark(2, 0, b'even') - fout.writeframes(b'\x00') - fout.close() - f = aifc.open(TESTFN, 'rb') - self.addCleanup(f.close) - self.assertEqual(f.getmarkers(), [(1, 0, b'odd'), (2, 0, b'even')]) - self.assertEqual(f.getmark(1), (1, 0, b'odd')) - self.assertEqual(f.getmark(2), (2, 0, b'even')) - self.assertRaises(aifc.Error, f.getmark, 3) - - -class AIFCLowLevelTest(unittest.TestCase): - - def test_read_written(self): - def read_written(self, what): - f = io.BytesIO() - getattr(aifc, '_write_' + what)(f, x) - f.seek(0) - return getattr(aifc, '_read_' + what)(f) - for x in (-1, 0, 0.1, 1): - self.assertEqual(read_written(x, 'float'), x) - for x in (float('NaN'), float('Inf')): - self.assertEqual(read_written(x, 'float'), aifc._HUGE_VAL) - for x in (b'', b'foo', b'a' * 255): - self.assertEqual(read_written(x, 'string'), x) - for x in (-0x7FFFFFFF, -1, 0, 1, 0x7FFFFFFF): - self.assertEqual(read_written(x, 'long'), x) - for x in (0, 1, 0xFFFFFFFF): - self.assertEqual(read_written(x, 'ulong'), x) - for x in (-0x7FFF, -1, 0, 1, 0x7FFF): - self.assertEqual(read_written(x, 'short'), x) - for x in (0, 1, 0xFFFF): - self.assertEqual(read_written(x, 'ushort'), x) - - def test_read_raises(self): - f = io.BytesIO(b'\x00') - self.assertRaises(EOFError, aifc._read_ulong, f) - self.assertRaises(EOFError, aifc._read_long, f) - self.assertRaises(EOFError, aifc._read_ushort, f) - self.assertRaises(EOFError, aifc._read_short, f) - - def test_write_long_string_raises(self): - f = io.BytesIO() - with self.assertRaises(ValueError): - aifc._write_string(f, b'too long' * 255) - - def test_wrong_open_mode(self): - with self.assertRaises(aifc.Error): - aifc.open(TESTFN, 'wrong_mode') - - def test_read_wrong_form(self): - b1 = io.BytesIO(b'WRNG' + struct.pack('>L', 0)) - b2 = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'WRNG') - self.assertRaises(aifc.Error, aifc.open, b1) - self.assertRaises(aifc.Error, aifc.open, b2) - - def test_read_no_comm_chunk(self): - b = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'AIFF') - self.assertRaises(aifc.Error, aifc.open, b) - - def test_read_no_ssnd_chunk(self): - b = b'FORM' + struct.pack('>L', 4) + b'AIFC' - b += b'COMM' + struct.pack('>LhlhhLL', 38, 1, 0, 8, - 0x4000 | 12, 11025<<18, 0) - b += b'NONE' + struct.pack('B', 14) + b'not compressed' + b'\x00' - with self.assertRaisesRegex(aifc.Error, 'COMM chunk and/or SSND chunk' - ' missing'): - aifc.open(io.BytesIO(b)) - - def test_read_wrong_compression_type(self): - b = b'FORM' + struct.pack('>L', 4) + b'AIFC' - b += b'COMM' + struct.pack('>LhlhhLL', 23, 1, 0, 8, - 0x4000 | 12, 11025<<18, 0) - b += b'WRNG' + struct.pack('B', 0) - self.assertRaises(aifc.Error, aifc.open, io.BytesIO(b)) - - def test_read_wrong_number_of_channels(self): - for nchannels in 0, -1: - b = b'FORM' + struct.pack('>L', 4) + b'AIFC' - b += b'COMM' + struct.pack('>LhlhhLL', 38, nchannels, 0, 8, - 0x4000 | 12, 11025<<18, 0) - b += b'NONE' + struct.pack('B', 14) + b'not compressed' + b'\x00' - b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 - with self.assertRaisesRegex(aifc.Error, 'bad # of channels'): - aifc.open(io.BytesIO(b)) - - def test_read_wrong_sample_width(self): - for sampwidth in 0, -1: - b = b'FORM' + struct.pack('>L', 4) + b'AIFC' - b += b'COMM' + struct.pack('>LhlhhLL', 38, 1, 0, sampwidth, - 0x4000 | 12, 11025<<18, 0) - b += b'NONE' + struct.pack('B', 14) + b'not compressed' + b'\x00' - b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 - with self.assertRaisesRegex(aifc.Error, 'bad sample width'): - aifc.open(io.BytesIO(b)) - - def test_read_wrong_marks(self): - b = b'FORM' + struct.pack('>L', 4) + b'AIFF' - b += b'COMM' + struct.pack('>LhlhhLL', 18, 1, 0, 8, - 0x4000 | 12, 11025<<18, 0) - b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 - b += b'MARK' + struct.pack('>LhB', 3, 1, 1) - with self.assertWarns(UserWarning) as cm: - f = aifc.open(io.BytesIO(b)) - self.assertEqual(str(cm.warning), 'Warning: MARK chunk contains ' - 'only 0 markers instead of 1') - self.assertEqual(f.getmarkers(), None) - - def test_read_comm_kludge_compname_even(self): - b = b'FORM' + struct.pack('>L', 4) + b'AIFC' - b += b'COMM' + struct.pack('>LhlhhLL', 18, 1, 0, 8, - 0x4000 | 12, 11025<<18, 0) - b += b'NONE' + struct.pack('B', 4) + b'even' + b'\x00' - b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 - with self.assertWarns(UserWarning) as cm: - f = aifc.open(io.BytesIO(b)) - self.assertEqual(str(cm.warning), 'Warning: bad COMM chunk size') - self.assertEqual(f.getcompname(), b'even') - - def test_read_comm_kludge_compname_odd(self): - b = b'FORM' + struct.pack('>L', 4) + b'AIFC' - b += b'COMM' + struct.pack('>LhlhhLL', 18, 1, 0, 8, - 0x4000 | 12, 11025<<18, 0) - b += b'NONE' + struct.pack('B', 3) + b'odd' - b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 - with self.assertWarns(UserWarning) as cm: - f = aifc.open(io.BytesIO(b)) - self.assertEqual(str(cm.warning), 'Warning: bad COMM chunk size') - self.assertEqual(f.getcompname(), b'odd') - - def test_write_params_raises(self): - fout = aifc.open(io.BytesIO(), 'wb') - wrong_params = (0, 0, 0, 0, b'WRNG', '') - self.assertRaises(aifc.Error, fout.setparams, wrong_params) - self.assertRaises(aifc.Error, fout.getparams) - self.assertRaises(aifc.Error, fout.setnchannels, 0) - self.assertRaises(aifc.Error, fout.getnchannels) - self.assertRaises(aifc.Error, fout.setsampwidth, 0) - self.assertRaises(aifc.Error, fout.getsampwidth) - self.assertRaises(aifc.Error, fout.setframerate, 0) - self.assertRaises(aifc.Error, fout.getframerate) - self.assertRaises(aifc.Error, fout.setcomptype, b'WRNG', '') - fout.aiff() - fout.setnchannels(1) - fout.setsampwidth(1) - fout.setframerate(1) - fout.setnframes(1) - fout.writeframes(b'\x00') - self.assertRaises(aifc.Error, fout.setparams, (1, 1, 1, 1, 1, 1)) - self.assertRaises(aifc.Error, fout.setnchannels, 1) - self.assertRaises(aifc.Error, fout.setsampwidth, 1) - self.assertRaises(aifc.Error, fout.setframerate, 1) - self.assertRaises(aifc.Error, fout.setnframes, 1) - self.assertRaises(aifc.Error, fout.setcomptype, b'NONE', '') - self.assertRaises(aifc.Error, fout.aiff) - self.assertRaises(aifc.Error, fout.aifc) - - def test_write_params_singles(self): - fout = aifc.open(io.BytesIO(), 'wb') - fout.aifc() - fout.setnchannels(1) - fout.setsampwidth(2) - fout.setframerate(3) - fout.setnframes(4) - fout.setcomptype(b'NONE', b'name') - self.assertEqual(fout.getnchannels(), 1) - self.assertEqual(fout.getsampwidth(), 2) - self.assertEqual(fout.getframerate(), 3) - self.assertEqual(fout.getnframes(), 0) - self.assertEqual(fout.tell(), 0) - self.assertEqual(fout.getcomptype(), b'NONE') - self.assertEqual(fout.getcompname(), b'name') - fout.writeframes(b'\x00' * 4 * fout.getsampwidth() * fout.getnchannels()) - self.assertEqual(fout.getnframes(), 4) - self.assertEqual(fout.tell(), 4) - - def test_write_params_bunch(self): - fout = aifc.open(io.BytesIO(), 'wb') - fout.aifc() - p = (1, 2, 3, 4, b'NONE', b'name') - fout.setparams(p) - self.assertEqual(fout.getparams(), p) - fout.initfp(None) - - def test_write_header_raises(self): - fout = aifc.open(io.BytesIO(), 'wb') - self.assertRaises(aifc.Error, fout.close) - fout = aifc.open(io.BytesIO(), 'wb') - fout.setnchannels(1) - self.assertRaises(aifc.Error, fout.close) - fout = aifc.open(io.BytesIO(), 'wb') - fout.setnchannels(1) - fout.setsampwidth(1) - self.assertRaises(aifc.Error, fout.close) - - def test_write_header_comptype_raises(self): - for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): - fout = aifc.open(io.BytesIO(), 'wb') - fout.setsampwidth(1) - fout.setcomptype(comptype, b'') - self.assertRaises(aifc.Error, fout.close) - fout.initfp(None) - - def test_write_markers_raises(self): - fout = aifc.open(io.BytesIO(), 'wb') - self.assertRaises(aifc.Error, fout.setmark, 0, 0, b'') - self.assertRaises(aifc.Error, fout.setmark, 1, -1, b'') - self.assertRaises(aifc.Error, fout.setmark, 1, 0, None) - self.assertRaises(aifc.Error, fout.getmark, 1) - fout.initfp(None) - - def test_write_aiff_by_extension(self): - sampwidth = 2 - filename = TESTFN + '.aiff' - fout = self.fout = aifc.open(filename, 'wb') - self.addCleanup(unlink, filename) - fout.setparams((1, sampwidth, 1, 1, b'ULAW', b'')) - frames = b'\x00' * fout.getnchannels() * sampwidth - fout.writeframes(frames) - fout.close() - f = self.f = aifc.open(filename, 'rb') - self.assertEqual(f.getcomptype(), b'NONE') - f.close() - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/wave.py b/Lib/wave.py index d5858e5d4b80da..76b73de1d67ad8 100644 --- a/Lib/wave.py +++ b/Lib/wave.py @@ -21,9 +21,9 @@ getparams() -- returns a namedtuple consisting of all of the above in the above order getmarkers() -- returns None (for compatibility with the - aifc module) + old aifc module) getmark(id) -- raises an error since the mark does not - exist (for compatibility with the aifc module) + exist (for compatibility with the old 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 diff --git a/Misc/NEWS.d/3.7.0b3.rst b/Misc/NEWS.d/3.7.0b3.rst index 980110646b2940..c86963b7e42daf 100644 --- a/Misc/NEWS.d/3.7.0b3.rst +++ b/Misc/NEWS.d/3.7.0b3.rst @@ -325,7 +325,7 @@ documentation. .. section: Library Improved exceptions raised for invalid number of channels and sample width -when read an audio file in modules :mod:`aifc`, :mod:`wave` and +when read an audio file in modules :mod:`!aifc`, :mod:`wave` and :mod:`!sunau`. .. diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index 75902b47169419..2634832b78a96e 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -5576,7 +5576,7 @@ documentation. .. section: Library Improved exceptions raised for invalid number of channels and sample width -when read an audio file in modules :mod:`aifc`, :mod:`wave` and +when read an audio file in modules :mod:`!aifc`, :mod:`wave` and :mod:`!sunau`. .. diff --git a/Misc/NEWS.d/next/Library/2023-05-25-16-50-43.gh-issue-104773.pmg0Fr.rst b/Misc/NEWS.d/next/Library/2023-05-25-16-50-43.gh-issue-104773.pmg0Fr.rst new file mode 100644 index 00000000000000..162afb6f2727a8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-25-16-50-43.gh-issue-104773.pmg0Fr.rst @@ -0,0 +1,2 @@ +:pep:`594`: Remove the :mod:`!aifc` module, deprecated in Python 3.11. Patch +by Victor Stinner. diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index db574febd20fdd..d7ea70213c930e 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -89,7 +89,6 @@ static const char* _Py_stdlib_module_names[] = { "_winapi", "_zoneinfo", "abc", -"aifc", "antigravity", "argparse", "array", diff --git a/Tools/wasm/wasm_assets.py b/Tools/wasm/wasm_assets.py index 2cf5ac515a4d31..eb45c7dc4109c2 100755 --- a/Tools/wasm/wasm_assets.py +++ b/Tools/wasm/wasm_assets.py @@ -78,7 +78,7 @@ OMIT_MODULE_FILES = { "_asyncio": ["asyncio/"], - "audioop": ["aifc.py", "wave.py"], + "audioop": ["wave.py"], "_curses": ["curses/"], "_ctypes": ["ctypes/"], "_decimal": ["decimal.py"],