From 60ebff7d80c07be0be88a8691480a0b2a0983600 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 25 May 2023 16:14:43 +0200 Subject: [PATCH 1/3] gh-104773: PEP 594: Remove the aifc module --- Doc/library/aifc.rst | 247 --------- Doc/library/superseded.rst | 1 - Doc/library/wave.rst | 2 +- Doc/tools/.nitignore | 1 - Doc/whatsnew/2.0.rst | 2 +- Doc/whatsnew/3.11.rst | 2 +- Doc/whatsnew/3.12.rst | 2 +- Doc/whatsnew/3.4.rst | 8 +- Doc/whatsnew/3.7.rst | 4 +- Lib/aifc.py | 984 ----------------------------------- Lib/test/test_aifc.py | 439 ---------------- Lib/wave.py | 4 +- Misc/NEWS.d/3.7.0b3.rst | 2 +- Misc/NEWS.d/3.8.0a1.rst | 2 +- Python/stdlib_module_names.h | 1 - Tools/wasm/wasm_assets.py | 2 +- 16 files changed, 15 insertions(+), 1688 deletions(-) delete mode 100644 Doc/library/aifc.rst delete mode 100644 Lib/aifc.py delete mode 100644 Lib/test/test_aifc.py 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.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/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/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"], From b026c13f127cdb5e727048cbfb26da871842b7ae Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 25 May 2023 16:38:04 +0200 Subject: [PATCH 2/3] Remove audiodata test files * Remove .aifc and .aiff test files of Lib/test/audiodata/. * Remove Lib/test/Sine-1000Hz-300ms.aif test file. --- Lib/test/Sine-1000Hz-300ms.aif | Bin 61696 -> 0 bytes Lib/test/audiodata/pluck-alaw.aifc | Bin 6910 -> 0 bytes Lib/test/audiodata/pluck-pcm16.aiff | Bin 13506 -> 0 bytes Lib/test/audiodata/pluck-pcm24.aiff | Bin 20120 -> 0 bytes Lib/test/audiodata/pluck-pcm32.aiff | Bin 26734 -> 0 bytes Lib/test/audiodata/pluck-pcm8.aiff | Bin 6892 -> 0 bytes Lib/test/audiodata/pluck-ulaw.aifc | Bin 6910 -> 0 bytes 7 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Lib/test/Sine-1000Hz-300ms.aif delete mode 100644 Lib/test/audiodata/pluck-alaw.aifc delete mode 100644 Lib/test/audiodata/pluck-pcm16.aiff delete mode 100644 Lib/test/audiodata/pluck-pcm24.aiff delete mode 100644 Lib/test/audiodata/pluck-pcm32.aiff delete mode 100644 Lib/test/audiodata/pluck-pcm8.aiff delete mode 100644 Lib/test/audiodata/pluck-ulaw.aifc diff --git a/Lib/test/Sine-1000Hz-300ms.aif b/Lib/test/Sine-1000Hz-300ms.aif deleted file mode 100644 index bf08f5ce859429eeeab213fd29a201b0d851b9c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61696 zcmeI&F-t;G6ae5$QxH_-;Ns*IlCzCQp$4VU8$`!`gF`emiG#nv&1lHMO=u9Bnj^xc zA!uj`8XOw)(9%Ds;dAhL-@EtvIOu!tp7YgOXQwHBejOawYKN`U)#tR6)>7K9rtRwH z-PNkSdeu%&&QjXC|7m#_0TB=Z5fA|p5CIVo0TB=Z5fA|p_}>x8vgT1ruj{|ha^q>^ zDc{TYij(4`+$y&!rAn!qtLEx&^|$6_^D>)dv-Y4p=qx&m?x;J8ZM0*59FKm{KgPxQ zm?!3odEahkL#!Vm;0~h2hVSwKRrKNzgT}+KU%-b zKggfRU&+78AIjg#Kg*x1U#P#RAF1D|KdPUqU#q|K1N;C#zz^^P`~W||5AXy006)MF z@B{n+Kfn+01N;C#zz^^P`~W||5AXy006)MF@B{n+Kfn+01N;C#zz^^P`~W||5AXy0 z06)MF@B{n+Kfn+01N;C#zz^^P`~W||5AXy006)MF@B{n+Kfn+01N;C#zz^^P`~W|| z5AXy006)MF@B{n+Kfn+01N;C#zz^^P`~W||5AXy006)MF@B{n+Kfn+01N;C#zz^^P z`~W||5AXy006)MF@B{n+Kfn+01N;C#zz^^P`~W||5AXy006)MF@B{n+Kfn+01N;C# zzz^^P`~W||5AXy006)MF@B{n+Kfn+01N;C#zz^^P`~W||5AXy006)MF@B{n+Kfn+0 z1N;C#zz^^P`~W||5AXy006)MF@B{n+Kfn+01N;C#zz^^P`~W||5AXy006)MF@B{q7 HU;BY?t&pq( diff --git a/Lib/test/audiodata/pluck-alaw.aifc b/Lib/test/audiodata/pluck-alaw.aifc deleted file mode 100644 index 3b7fbd2af75a0a190b0a507ec43afbf8bd2b2267..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6910 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 B^uhoD diff --git a/Lib/test/audiodata/pluck-pcm16.aiff b/Lib/test/audiodata/pluck-pcm16.aiff deleted file mode 100644 index 6c8c40d14092893a4b4af626f6caf5c8c826017d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13506 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 diff --git a/Lib/test/audiodata/pluck-pcm8.aiff b/Lib/test/audiodata/pluck-pcm8.aiff deleted file mode 100644 index 5de4f3b2d879bae0a41710cea4d0b1aad9309124..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6892 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 Date: Thu, 25 May 2023 16:50:46 +0200 Subject: [PATCH 3/3] Add What's New and Changelog entry --- Doc/whatsnew/3.13.rst | 3 +++ .../Library/2023-05-25-16-50-43.gh-issue-104773.pmg0Fr.rst | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-05-25-16-50-43.gh-issue-104773.pmg0Fr.rst 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/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.