[Python-checkins] gh-104773: PEP 594: Remove the aifc module (#104933)
vstinner
webhook-mailer at python.org
Thu May 25 11:20:56 EDT 2023
https://github.com/python/cpython/commit/036da3bd43aa2593d17d2fb73d4794f9965c577d
commit: 036da3bd43aa2593d17d2fb73d4794f9965c577d
branch: main
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2023-05-25T17:20:48+02:00
summary:
gh-104773: PEP 594: Remove the aifc module (#104933)
* Remove .aifc and .aiff test files of Lib/test/audiodata/
* Remove Lib/test/Sine-1000Hz-300ms.aif test file
files:
A Misc/NEWS.d/next/Library/2023-05-25-16-50-43.gh-issue-104773.pmg0Fr.rst
D Doc/library/aifc.rst
D Lib/aifc.py
D Lib/test/Sine-1000Hz-300ms.aif
D Lib/test/audiodata/pluck-alaw.aifc
D Lib/test/audiodata/pluck-pcm16.aiff
D Lib/test/audiodata/pluck-pcm24.aiff
D Lib/test/audiodata/pluck-pcm32.aiff
D Lib/test/audiodata/pluck-pcm8.aiff
D Lib/test/audiodata/pluck-ulaw.aifc
D Lib/test/test_aifc.py
M Doc/library/superseded.rst
M Doc/library/wave.rst
M Doc/tools/.nitignore
M Doc/whatsnew/2.0.rst
M Doc/whatsnew/3.11.rst
M Doc/whatsnew/3.12.rst
M Doc/whatsnew/3.13.rst
M Doc/whatsnew/3.4.rst
M Doc/whatsnew/3.7.rst
M Lib/wave.py
M Misc/NEWS.d/3.7.0b3.rst
M Misc/NEWS.d/3.8.0a1.rst
M Python/stdlib_module_names.h
M Tools/wasm/wasm_assets.py
diff --git a/Doc/library/aifc.rst b/Doc/library/aifc.rst
deleted file mode 100644
index 9f20a30193fa..000000000000
--- 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 7e05f0edf4b1..d2e052779b5e 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 04a28d97d619..4dcbc3d4c2d1 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 9f3a99e90bc9..3d0354c3ab2a 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 e6c7ec93a16a..b1e584987fb1 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 ece273c7d090..982d20b622ba 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 7c184063fba5..b8a5a0c01253 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 38526e1df87a..9c95d1c70b5a 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 b9008328b49f..bcc941065d9a 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 fa89b7db9736..24244ff17b1e 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 5254987e22bc..000000000000
--- 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 |
- +-----------------+
- | <size> |
- +----+------------+
- | | AIFC |
- | +------------+
- | | <chunks> |
- | | . |
- | | . |
- | | . |
- +----+------------+
-
-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
- <version number of AIFF-C defining document> (AIFF-C only).
- MARK
- <# of markers> (2 bytes)
- list of markers:
- <marker ID> (2 bytes, must be > 0)
- <position> (4 bytes)
- <marker name> ("pstring")
- COMM
- <# of channels> (2 bytes)
- <# of sound frames> (4 bytes)
- <size of the samples> (2 bytes)
- <sampling frequency> (10 bytes, IEEE 80-bit extended
- floating point)
- in AIFF-C files only:
- <compression type> (4 bytes)
- <human-readable version of compression type> ("pstring")
- SSND
- <offset> (4 bytes, not used by this program)
- <blocksize> (4 bytes, not used by this program)
- <sound data>
-
-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 <limits.h>
-
-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 bf08f5ce8594..000000000000
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 3b7fbd2af75a..000000000000
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 6c8c40d14092..000000000000
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 8eba145a44d3..000000000000
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 46ac0373f6ab..000000000000
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 5de4f3b2d879..000000000000
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 3085cf097fb1..000000000000
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 d3863d4915d4..000000000000
--- 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 d5858e5d4b80..76b73de1d67a 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 980110646b29..c86963b7e42d 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 75902b471694..2634832b78a9 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 000000000000..162afb6f2727
--- /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 db574febd20f..d7ea70213c93 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 2cf5ac515a4d..eb45c7dc4109 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"],
More information about the Python-checkins
mailing list