Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 54 additions & 7 deletions Doc/library/wave.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,19 @@
--------------

The :mod:`!wave` module provides a convenient interface to the Waveform Audio
"WAVE" (or "WAV") file format. Only uncompressed PCM encoded wave files are
supported.
"WAVE" (or "WAV") file format.

The module supports uncompressed PCM and IEEE floating-point WAV formats.

.. versionchanged:: 3.12

Support for ``WAVE_FORMAT_EXTENSIBLE`` headers was added, provided that the
extended format is ``KSDATAFORMAT_SUBTYPE_PCM``.

.. versionchanged:: next

Support for reading and writing ``WAVE_FORMAT_IEEE_FLOAT`` files was added.

The :mod:`!wave` module defines the following function and exception:


Expand Down Expand Up @@ -60,6 +65,21 @@ The :mod:`!wave` module defines the following function and exception:
specification or hits an implementation deficiency.


.. data:: WAVE_FORMAT_PCM

Format code for uncompressed PCM audio.


.. data:: WAVE_FORMAT_IEEE_FLOAT

Format code for IEEE floating-point audio.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the size of a sample? 32-bit? Or does it accept different sizes?



.. data:: WAVE_FORMAT_EXTENSIBLE

Format code for WAVE extensible headers.


.. _wave-read-objects:

Wave_read Objects
Expand Down Expand Up @@ -98,6 +118,14 @@ Wave_read Objects
Returns number of audio frames.


.. method:: getformat()

Returns the frame format code.

This is one of :data:`WAVE_FORMAT_PCM`,
:data:`WAVE_FORMAT_IEEE_FLOAT`, or :data:`WAVE_FORMAT_EXTENSIBLE`.


.. method:: getcomptype()

Returns compression type (``'NONE'`` is the only supported type).
Expand All @@ -112,8 +140,8 @@ Wave_read Objects
.. method:: getparams()

Returns a :func:`~collections.namedtuple` ``(nchannels, sampwidth,
framerate, nframes, comptype, compname)``, equivalent to output of the
``get*()`` methods.
framerate, nframes, comptype, compname)``, equivalent to output
of the ``get*()`` methods.


.. method:: readframes(n)
Expand Down Expand Up @@ -238,11 +266,27 @@ Wave_write Objects
Return the human-readable compression type name.


.. method:: setformat(format)

Set the frame format code.

Supported values are :data:`WAVE_FORMAT_PCM` and
:data:`WAVE_FORMAT_IEEE_FLOAT`.


.. method:: getformat()

Return the current frame format code.


.. method:: setparams(tuple)

The *tuple* should be ``(nchannels, sampwidth, framerate, nframes, comptype,
compname)``, with values valid for the ``set*()`` methods. Sets all
parameters.
The *tuple* should be
``(nchannels, sampwidth, framerate, nframes, comptype, compname, format)``,
with values valid for the ``set*()`` methods. Sets all parameters.

For backwards compatibility, a 6-item tuple without *format* is also
accepted and defaults to :data:`WAVE_FORMAT_PCM`.


.. method:: getparams()
Expand Down Expand Up @@ -279,3 +323,6 @@ Wave_write Objects
Note that it is invalid to set any parameters after calling :meth:`writeframes`
or :meth:`writeframesraw`, and any attempt to do so will raise
:exc:`wave.Error`.

For :data:`WAVE_FORMAT_IEEE_FLOAT` output, a ``fact`` chunk is written as
required by the WAVE specification for non-PCM formats.
15 changes: 15 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1493,6 +1493,21 @@ typing
wave
----

* Added support for IEEE floating-point WAVE audio
(``WAVE_FORMAT_IEEE_FLOAT``) in :mod:`wave`.

* Added :meth:`wave.Wave_read.getformat`, :meth:`wave.Wave_write.getformat`,
and :meth:`wave.Wave_write.setformat` for explicit frame format handling.

* :meth:`wave.Wave_write.setparams` accepts both 7-item tuples including
``format`` and 6-item tuples for backwards compatibility (defaulting to
``WAVE_FORMAT_PCM``).

* ``WAVE_FORMAT_IEEE_FLOAT`` output now includes a ``fact`` chunk,
as required for non-PCM WAVE formats.

(Contributed by Lionel Koenig and Michiel W. Beijen in :gh:`60729`.)

* Removed the ``getmark()``, ``setmark()`` and ``getmarkers()`` methods
of the :class:`~wave.Wave_read` and :class:`~wave.Wave_write` classes,
which were deprecated since Python 3.13.
Expand Down
Binary file added Lib/test/audiodata/pluck-float32.wav
Binary file not shown.
16 changes: 12 additions & 4 deletions Lib/test/audiotests.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,18 @@ def tearDown(self):
unlink(TESTFN)

def check_params(self, f, nchannels, sampwidth, framerate, nframes,
comptype, compname):
comptype, compname, format):
self.assertEqual(f.getnchannels(), nchannels)
self.assertEqual(f.getsampwidth(), sampwidth)
self.assertEqual(f.getframerate(), framerate)
self.assertEqual(f.getnframes(), nframes)
self.assertEqual(f.getcomptype(), comptype)
self.assertEqual(f.getcompname(), compname)
self.assertEqual(f.getformat(), format)

params = f.getparams()
self.assertEqual(params,
(nchannels, sampwidth, framerate, nframes, comptype, compname))
(nchannels, sampwidth, framerate, nframes, comptype, compname))
self.assertEqual(params.nchannels, nchannels)
self.assertEqual(params.sampwidth, sampwidth)
self.assertEqual(params.framerate, framerate)
Expand All @@ -51,13 +52,17 @@ def check_params(self, f, nchannels, sampwidth, framerate, nframes,


class AudioWriteTests(AudioTests):
readonly = False

def create_file(self, testfile):
if self.readonly:
self.skipTest('Read only file format')
f = self.fout = self.module.open(testfile, 'wb')
f.setnchannels(self.nchannels)
f.setsampwidth(self.sampwidth)
f.setframerate(self.framerate)
f.setcomptype(self.comptype, self.compname)
f.setformat(self.format)
return f

def check_file(self, testfile, nframes, frames):
Expand All @@ -67,13 +72,14 @@ def check_file(self, testfile, nframes, frames):
self.assertEqual(f.getframerate(), self.framerate)
self.assertEqual(f.getnframes(), nframes)
self.assertEqual(f.readframes(nframes), frames)
self.assertEqual(f.getformat(), self.format)

def test_write_params(self):
f = self.create_file(TESTFN)
f.setnframes(self.nframes)
f.writeframes(self.frames)
self.check_params(f, self.nchannels, self.sampwidth, self.framerate,
self.nframes, self.comptype, self.compname)
self.nframes, self.comptype, self.compname, self.format)
f.close()

def test_write_context_manager_calls_close(self):
Expand Down Expand Up @@ -257,7 +263,7 @@ def test_read_params(self):
f = self.f = self.module.open(self.sndfilepath)
#self.assertEqual(f.getfp().name, self.sndfilepath)
self.check_params(f, self.nchannels, self.sampwidth, self.framerate,
self.sndfilenframes, self.comptype, self.compname)
self.sndfilenframes, self.comptype, self.compname, self.format)

def test_close(self):
with open(self.sndfilepath, 'rb') as testfile:
Expand Down Expand Up @@ -298,6 +304,8 @@ def test_read(self):
f.setpos(f.getnframes() + 1)

def test_copy(self):
if self.readonly:
self.skipTest('Read only file format')
f = self.f = self.module.open(self.sndfilepath)
fout = self.fout = self.module.open(TESTFN, 'wb')
fout.setparams(f.getparams())
Expand Down
Loading
Loading