Skip to content

GH-60729: Add IEEE format wave audio support#145384

Open
mbeijen wants to merge 12 commits intopython:mainfrom
mbeijen:GH-60729-add-ieee-wave-audio-support
Open

GH-60729: Add IEEE format wave audio support#145384
mbeijen wants to merge 12 commits intopython:mainfrom
mbeijen:GH-60729-add-ieee-wave-audio-support

Conversation

@mbeijen
Copy link
Contributor

@mbeijen mbeijen commented Mar 1, 2026

This is an updated version of #102574, the original PR where @lkoenig added support for IEEE Wave Audio.

As requested by @encukou

I've

  • Renamed the new 'getencoding/setencoding' to 'getformat/setformat' - format is the term used in the specifications
  • Added format to getparams
  • Added FACT chunk to written non-PCM wave files, which is required by the spec (and is what Audacity does)
  • Added documentation!

Closes: #102574


📚 Documentation preview 📚: https://cpython-previews--145384.org.readthedocs.build/

lkoenig and others added 5 commits March 1, 2026 09:54
This adds support for floating point wav files and fix python#60729.
'format' is the term used in the wave audio specification
Per the RIFF/WAVE Rev. 3 documentation, non-PCM formats require a fact chunk, while PCM does not.
This is also what libsdnfile/audacity do

Reference: https://mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html (see the 'fact Chunk' section and linked Rev. 3 RIFF docs).
These methods are public but were previously not documented. This caused
the unit tests to fail when I mentioned changes to getparams() in the
whats new ;-)
@mbeijen mbeijen requested a review from aisk March 1, 2026 15:49
Copy link

@lkoenig lkoenig left a comment

Choose a reason for hiding this comment

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

Thanks for pushing that forward.

Copy link
Member

@encukou encukou left a comment

Choose a reason for hiding this comment

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

Thank you for the PR!
I didn't finish reviewing today; sending the comments I have.

Comment on lines +110 to +111
This is one of ``WAVE_FORMAT_PCM``, ``WAVE_FORMAT_IEEE_FLOAT``, or
``WAVE_FORMAT_EXTENSIBLE``.
Copy link
Member

Choose a reason for hiding this comment

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

Could you document these using .. data::, and link to them using :data:?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Comment on lines +128 to +129
framerate, nframes, comptype, compname, format)``, equivalent to output
of the ``get*()`` methods.
Copy link
Member

Choose a reason for hiding this comment

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

This is a backwards-incompatible change: before someone could write:

    nc, sw, fr, nf, ct, cn = wav.getparams()

This could be solved by adding format as a named-only attribute (which, unfortunately, isn't easy with namedtuple), or maybe an argument to getparams.
You might want to leave getparams alone for now & tackle this in a focused follow-up PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I reverted those changes now

class MiscTestCase(unittest.TestCase):
def test__all__(self):
not_exported = {'WAVE_FORMAT_PCM', 'WAVE_FORMAT_EXTENSIBLE', 'KSDATAFORMAT_SUBTYPE_PCM'}
not_exported = {'WAVE_FORMAT_PCM', 'WAVE_FORMAT_IEEE_FLOAT', 'WAVE_FORMAT_EXTENSIBLE', 'KSDATAFORMAT_SUBTYPE_PCM'}
Copy link
Member

Choose a reason for hiding this comment

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

Please export the WAVE_FORMAT_ ones (add to __all__) instead, and remove them here.
No point in hiding them; they're needed for documented functionality.

Copy link
Member

Choose a reason for hiding this comment

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

(I'd keep KSDATAFORMAT_SUBTYPE_PCM hidden until it's documented; that seems out of scope for this PR.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, they're exported now

Comment on lines +650 to +653
try:
self._fact_sample_count_pos = self._file.tell()
except (AttributeError, OSError):
self._fact_sample_count_pos = None
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, what's the story about supporting files without tell?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I’m not trying to extend unseekable support in this PR. I’m keeping the existing behavior: if output is seekable, header fields (including fact) are patched as needed; for unseekable outputs, writing works when header values are already final, and mismatches can still fail as before.

Co-authored-by: Petr Viktorin <[email protected]>
@mbeijen mbeijen requested a review from encukou March 3, 2026 20:06

.. 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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants