mirror of
https://github.com/python/cpython.git
synced 2026-04-14 15:50:50 +00:00
GH-60729: Revert "Add IEEE format wave audio support (GH-145384)" (GH-145928)
Revert "GH-60729: Add IEEE format wave audio support (GH-145384)"
This reverts commit 61f2a1a599 for now;
as tests fail on big-endian machines.
This commit is contained in:
parent
00a25859a9
commit
747ef70faa
7 changed files with 25 additions and 352 deletions
|
|
@ -9,19 +9,14 @@
|
|||
--------------
|
||||
|
||||
The :mod:`!wave` module provides a convenient interface to the Waveform Audio
|
||||
"WAVE" (or "WAV") file format.
|
||||
|
||||
The module supports uncompressed PCM and IEEE floating-point WAV formats.
|
||||
"WAVE" (or "WAV") file format. Only uncompressed PCM encoded wave files are
|
||||
supported.
|
||||
|
||||
.. 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:
|
||||
|
||||
|
||||
|
|
@ -65,21 +60,6 @@ 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.
|
||||
|
||||
|
||||
.. data:: WAVE_FORMAT_EXTENSIBLE
|
||||
|
||||
Format code for WAVE extensible headers.
|
||||
|
||||
|
||||
.. _wave-read-objects:
|
||||
|
||||
Wave_read Objects
|
||||
|
|
@ -118,14 +98,6 @@ 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).
|
||||
|
|
@ -140,8 +112,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)
|
||||
|
|
@ -218,9 +190,6 @@ Wave_write Objects
|
|||
|
||||
Set the sample width to *n* bytes.
|
||||
|
||||
For :data:`WAVE_FORMAT_IEEE_FLOAT`, only 4-byte (32-bit) and
|
||||
8-byte (64-bit) sample widths are supported.
|
||||
|
||||
|
||||
.. method:: getsampwidth()
|
||||
|
||||
|
|
@ -269,32 +238,11 @@ 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`.
|
||||
|
||||
When setting :data:`WAVE_FORMAT_IEEE_FLOAT`, the sample width must be
|
||||
4 or 8 bytes.
|
||||
|
||||
|
||||
.. method:: getformat()
|
||||
|
||||
Return the current frame format code.
|
||||
|
||||
|
||||
.. method:: setparams(tuple)
|
||||
|
||||
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`.
|
||||
|
||||
For ``format=WAVE_FORMAT_IEEE_FLOAT``, *sampwidth* must be 4 or 8.
|
||||
The *tuple* should be ``(nchannels, sampwidth, framerate, nframes, comptype,
|
||||
compname)``, with values valid for the ``set*()`` methods. Sets all
|
||||
parameters.
|
||||
|
||||
|
||||
.. method:: getparams()
|
||||
|
|
@ -331,6 +279,3 @@ 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.
|
||||
|
|
|
|||
|
|
@ -1518,21 +1518,6 @@ 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.
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -27,18 +27,17 @@ def tearDown(self):
|
|||
unlink(TESTFN)
|
||||
|
||||
def check_params(self, f, nchannels, sampwidth, framerate, nframes,
|
||||
comptype, compname, format):
|
||||
comptype, compname):
|
||||
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)
|
||||
|
|
@ -52,17 +51,13 @@ 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):
|
||||
|
|
@ -72,14 +67,13 @@ 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.format)
|
||||
self.nframes, self.comptype, self.compname)
|
||||
f.close()
|
||||
|
||||
def test_write_context_manager_calls_close(self):
|
||||
|
|
@ -263,7 +257,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.format)
|
||||
self.sndfilenframes, self.comptype, self.compname)
|
||||
|
||||
def test_close(self):
|
||||
with open(self.sndfilepath, 'rb') as testfile:
|
||||
|
|
@ -304,8 +298,6 @@ 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())
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import unittest
|
||||
from test import audiotests
|
||||
from test import support
|
||||
from test.support.os_helper import FakePath, unlink
|
||||
from test.support.os_helper import FakePath
|
||||
import io
|
||||
import os
|
||||
import struct
|
||||
|
|
@ -22,7 +22,6 @@ class WavePCM8Test(WaveTest, unittest.TestCase):
|
|||
sampwidth = 1
|
||||
framerate = 11025
|
||||
nframes = 48
|
||||
format = wave.WAVE_FORMAT_PCM
|
||||
comptype = 'NONE'
|
||||
compname = 'not compressed'
|
||||
frames = bytes.fromhex("""\
|
||||
|
|
@ -40,7 +39,6 @@ class WavePCM16Test(WaveTest, unittest.TestCase):
|
|||
sampwidth = 2
|
||||
framerate = 11025
|
||||
nframes = 48
|
||||
format = wave.WAVE_FORMAT_PCM
|
||||
comptype = 'NONE'
|
||||
compname = 'not compressed'
|
||||
frames = bytes.fromhex("""\
|
||||
|
|
@ -62,7 +60,6 @@ class WavePCM24Test(WaveTest, unittest.TestCase):
|
|||
sampwidth = 3
|
||||
framerate = 11025
|
||||
nframes = 48
|
||||
format = wave.WAVE_FORMAT_PCM
|
||||
comptype = 'NONE'
|
||||
compname = 'not compressed'
|
||||
frames = bytes.fromhex("""\
|
||||
|
|
@ -90,8 +87,6 @@ class WavePCM24ExtTest(WaveTest, unittest.TestCase):
|
|||
sampwidth = 3
|
||||
framerate = 11025
|
||||
nframes = 48
|
||||
format = wave.WAVE_FORMAT_EXTENSIBLE
|
||||
readonly = True # Writing EXTENSIBLE wave format is not supported.
|
||||
comptype = 'NONE'
|
||||
compname = 'not compressed'
|
||||
frames = bytes.fromhex("""\
|
||||
|
|
@ -119,7 +114,6 @@ class WavePCM32Test(WaveTest, unittest.TestCase):
|
|||
sampwidth = 4
|
||||
framerate = 11025
|
||||
nframes = 48
|
||||
format = wave.WAVE_FORMAT_PCM
|
||||
comptype = 'NONE'
|
||||
compname = 'not compressed'
|
||||
frames = bytes.fromhex("""\
|
||||
|
|
@ -140,140 +134,14 @@ class WavePCM32Test(WaveTest, unittest.TestCase):
|
|||
frames = wave._byteswap(frames, 4)
|
||||
|
||||
|
||||
class WaveIeeeFloatingPointTest(WaveTest, unittest.TestCase):
|
||||
sndfilename = 'pluck-float32.wav'
|
||||
sndfilenframes = 3307
|
||||
nchannels = 2
|
||||
sampwidth = 4
|
||||
framerate = 11025
|
||||
nframes = 48
|
||||
format = wave.WAVE_FORMAT_IEEE_FLOAT
|
||||
comptype = 'NONE'
|
||||
compname = 'not compressed'
|
||||
frames = bytes.fromhex("""\
|
||||
60598B3C001423BA 1FB4163F8054FA3B 0E4FC43E80C51D3D 53467EBF4030843D \
|
||||
FC84D0BE304C563D 3053113F40BEFC3C B72F00BFC03E583C E0FEDA3C805142BC \
|
||||
54510FBFE02638BD 569F16BF40FDCABD C060A63EECA421BE 3CE5523E2C3349BE \
|
||||
0C2E10BE14725BBE 5268E7BEDC3B6CBE 985AE03D80497ABE B4B606BEECB67EBE \
|
||||
B0B12E3FC87C6CBE 005519BD4C0F3EBE F8BD1B3EECDF03BE 924E9FBE588D8DBD \
|
||||
D4E150BF501711BD B079A0BD20FBFBBC 5863863D40760CBD 0E3C83BE40E217BD \
|
||||
04FF0B3EF07839BD E29AFB3E80A714BD B91007BFE042D3BC B5AD4D3F80CDA0BB \
|
||||
1AB1C3BEB04E023D D33A063FC0A8973D 8012F9BEE074EC3D 7341223FD415153E \
|
||||
D80409BE04A63A3E 00F27BBFBC25333E 0000803FFC29223E 000080BF38A7143E \
|
||||
3638133F283BEB3D 7C6E253F00CADB3D 686A02BE88FDF53D 920CC7BE28E1FB3D \
|
||||
185B5ABED8A2CE3D 5189463FC8A7A53D E88F8C3DF0FFA13D 1CE6AE3EE0A0B03D \
|
||||
DF90223F184EE43D 376768BF2CD8093E 281612BF60B3EE3D 2F26083F88B4A53D \
|
||||
""")
|
||||
|
||||
class MiscTestCase(unittest.TestCase):
|
||||
def test__all__(self):
|
||||
not_exported = {'KSDATAFORMAT_SUBTYPE_PCM'}
|
||||
not_exported = {'WAVE_FORMAT_PCM', 'WAVE_FORMAT_EXTENSIBLE', 'KSDATAFORMAT_SUBTYPE_PCM'}
|
||||
support.check__all__(self, wave, not_exported=not_exported)
|
||||
|
||||
|
||||
class WaveLowLevelTest(unittest.TestCase):
|
||||
|
||||
def test_setparams_6_tuple_defaults_to_pcm(self):
|
||||
with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
|
||||
filename = fp.name
|
||||
self.addCleanup(unlink, filename)
|
||||
|
||||
with wave.open(filename, 'wb') as w:
|
||||
w.setformat(wave.WAVE_FORMAT_IEEE_FLOAT)
|
||||
w.setparams((1, 2, 22050, 0, 'NONE', 'not compressed'))
|
||||
self.assertEqual(w.getformat(), wave.WAVE_FORMAT_PCM)
|
||||
|
||||
def test_setparams_7_tuple_uses_format(self):
|
||||
with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
|
||||
filename = fp.name
|
||||
self.addCleanup(unlink, filename)
|
||||
|
||||
with wave.open(filename, 'wb') as w:
|
||||
w.setparams((1, 4, 22050, 0, 'NONE', 'not compressed',
|
||||
wave.WAVE_FORMAT_IEEE_FLOAT))
|
||||
self.assertEqual(w.getformat(), wave.WAVE_FORMAT_IEEE_FLOAT)
|
||||
|
||||
def test_setparams_7_tuple_ieee_64bit_sampwidth(self):
|
||||
with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
|
||||
filename = fp.name
|
||||
self.addCleanup(unlink, filename)
|
||||
|
||||
with wave.open(filename, 'wb') as w:
|
||||
w.setparams((1, 8, 22050, 0, 'NONE', 'not compressed',
|
||||
wave.WAVE_FORMAT_IEEE_FLOAT))
|
||||
self.assertEqual(w.getformat(), wave.WAVE_FORMAT_IEEE_FLOAT)
|
||||
self.assertEqual(w.getsampwidth(), 8)
|
||||
|
||||
def test_getparams_backward_compatible_shape(self):
|
||||
with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
|
||||
filename = fp.name
|
||||
self.addCleanup(unlink, filename)
|
||||
|
||||
with wave.open(filename, 'wb') as w:
|
||||
w.setparams((1, 4, 22050, 0, 'NONE', 'not compressed',
|
||||
wave.WAVE_FORMAT_IEEE_FLOAT))
|
||||
params = w.getparams()
|
||||
self.assertEqual(params, (1, 4, 22050, 0, 'NONE', 'not compressed'))
|
||||
|
||||
def test_getformat_setformat(self):
|
||||
with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
|
||||
filename = fp.name
|
||||
self.addCleanup(unlink, filename)
|
||||
|
||||
with wave.open(filename, 'wb') as w:
|
||||
w.setnchannels(1)
|
||||
w.setsampwidth(4)
|
||||
w.setframerate(22050)
|
||||
self.assertEqual(w.getformat(), wave.WAVE_FORMAT_PCM)
|
||||
w.setformat(wave.WAVE_FORMAT_IEEE_FLOAT)
|
||||
self.assertEqual(w.getformat(), wave.WAVE_FORMAT_IEEE_FLOAT)
|
||||
|
||||
def test_setformat_ieee_requires_32_or_64_bit_sampwidth(self):
|
||||
with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
|
||||
filename = fp.name
|
||||
self.addCleanup(unlink, filename)
|
||||
|
||||
with wave.open(filename, 'wb') as w:
|
||||
w.setnchannels(1)
|
||||
w.setsampwidth(2)
|
||||
w.setframerate(22050)
|
||||
with self.assertRaisesRegex(wave.Error,
|
||||
'unsupported sample width for IEEE float format'):
|
||||
w.setformat(wave.WAVE_FORMAT_IEEE_FLOAT)
|
||||
|
||||
def test_setsampwidth_ieee_requires_32_or_64_bit(self):
|
||||
with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
|
||||
filename = fp.name
|
||||
self.addCleanup(unlink, filename)
|
||||
|
||||
with wave.open(filename, 'wb') as w:
|
||||
w.setnchannels(1)
|
||||
w.setframerate(22050)
|
||||
w.setformat(wave.WAVE_FORMAT_IEEE_FLOAT)
|
||||
with self.assertRaisesRegex(wave.Error,
|
||||
'unsupported sample width for IEEE float format'):
|
||||
w.setsampwidth(2)
|
||||
w.setsampwidth(4)
|
||||
|
||||
def test_setsampwidth_ieee_accepts_64_bit(self):
|
||||
with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
|
||||
filename = fp.name
|
||||
self.addCleanup(unlink, filename)
|
||||
|
||||
with wave.open(filename, 'wb') as w:
|
||||
w.setnchannels(1)
|
||||
w.setframerate(22050)
|
||||
w.setformat(wave.WAVE_FORMAT_IEEE_FLOAT)
|
||||
w.setsampwidth(8)
|
||||
self.assertEqual(w.getsampwidth(), 8)
|
||||
|
||||
def test_read_getformat(self):
|
||||
b = b'RIFF' + struct.pack('<L', 36) + b'WAVE'
|
||||
b += b'fmt ' + struct.pack('<LHHLLHH', 16, 1, 1, 11025, 11025, 1, 8)
|
||||
b += b'data' + struct.pack('<L', 0)
|
||||
with wave.open(io.BytesIO(b), 'rb') as r:
|
||||
self.assertEqual(r.getformat(), wave.WAVE_FORMAT_PCM)
|
||||
|
||||
def test_read_no_chunks(self):
|
||||
b = b'SPAM'
|
||||
with self.assertRaises(EOFError):
|
||||
|
|
@ -339,58 +207,6 @@ def test_open_in_write_raises(self):
|
|||
support.gc_collect()
|
||||
self.assertIsNone(cm.unraisable)
|
||||
|
||||
def test_ieee_float_has_fact_chunk(self):
|
||||
nframes = 100
|
||||
with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
|
||||
filename = fp.name
|
||||
self.addCleanup(unlink, filename)
|
||||
|
||||
with wave.open(filename, 'wb') as w:
|
||||
w.setnchannels(1)
|
||||
w.setsampwidth(4)
|
||||
w.setframerate(22050)
|
||||
w.setformat(wave.WAVE_FORMAT_IEEE_FLOAT)
|
||||
w.writeframes(b'\x00\x00\x00\x00' * nframes)
|
||||
|
||||
with open(filename, 'rb') as f:
|
||||
f.read(12)
|
||||
fact_found = False
|
||||
fact_samples = None
|
||||
while True:
|
||||
chunk_id = f.read(4)
|
||||
if len(chunk_id) < 4:
|
||||
break
|
||||
chunk_size = struct.unpack('<L', f.read(4))[0]
|
||||
if chunk_id == b'fact':
|
||||
fact_found = True
|
||||
fact_samples = struct.unpack('<L', f.read(4))[0]
|
||||
break
|
||||
f.seek(chunk_size + (chunk_size & 1), 1)
|
||||
|
||||
self.assertTrue(fact_found)
|
||||
self.assertEqual(fact_samples, nframes)
|
||||
|
||||
def test_pcm_has_no_fact_chunk(self):
|
||||
with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
|
||||
filename = fp.name
|
||||
self.addCleanup(unlink, filename)
|
||||
|
||||
with wave.open(filename, 'wb') as w:
|
||||
w.setnchannels(1)
|
||||
w.setsampwidth(2)
|
||||
w.setframerate(22050)
|
||||
w.writeframes(b'\x00\x00' * 100)
|
||||
|
||||
with open(filename, 'rb') as f:
|
||||
f.read(12)
|
||||
while True:
|
||||
chunk_id = f.read(4)
|
||||
if len(chunk_id) < 4:
|
||||
break
|
||||
chunk_size = struct.unpack('<L', f.read(4))[0]
|
||||
self.assertNotEqual(chunk_id, b'fact')
|
||||
f.seek(chunk_size + (chunk_size & 1), 1)
|
||||
|
||||
|
||||
class WaveOpen(unittest.TestCase):
|
||||
def test_open_pathlike(self):
|
||||
|
|
|
|||
88
Lib/wave.py
88
Lib/wave.py
|
|
@ -15,8 +15,6 @@
|
|||
getsampwidth() -- returns sample width in bytes
|
||||
getframerate() -- returns sampling frequency
|
||||
getnframes() -- returns number of audio frames
|
||||
getformat() -- returns frame encoding (WAVE_FORMAT_PCM, WAVE_FORMAT_IEEE_FLOAT
|
||||
or WAVE_FORMAT_EXTENSIBLE)
|
||||
getcomptype() -- returns compression type ('NONE' for linear samples)
|
||||
getcompname() -- returns human-readable version of
|
||||
compression type ('not compressed' linear samples)
|
||||
|
|
@ -44,9 +42,6 @@
|
|||
setsampwidth(n) -- set the sample width
|
||||
setframerate(n) -- set the frame rate
|
||||
setnframes(n) -- set the number of frames
|
||||
setformat(format)
|
||||
-- set the frame format. Only WAVE_FORMAT_PCM and
|
||||
WAVE_FORMAT_IEEE_FLOAT are supported.
|
||||
setcomptype(type, name)
|
||||
-- set the compression type and the
|
||||
human-readable compression type
|
||||
|
|
@ -79,21 +74,12 @@
|
|||
import sys
|
||||
|
||||
|
||||
__all__ = [
|
||||
"open",
|
||||
"Error",
|
||||
"Wave_read",
|
||||
"Wave_write",
|
||||
"WAVE_FORMAT_PCM",
|
||||
"WAVE_FORMAT_IEEE_FLOAT",
|
||||
"WAVE_FORMAT_EXTENSIBLE",
|
||||
]
|
||||
__all__ = ["open", "Error", "Wave_read", "Wave_write"]
|
||||
|
||||
class Error(Exception):
|
||||
pass
|
||||
|
||||
WAVE_FORMAT_PCM = 0x0001
|
||||
WAVE_FORMAT_IEEE_FLOAT = 0x0003
|
||||
WAVE_FORMAT_EXTENSIBLE = 0xFFFE
|
||||
# Derived from uuid.UUID("00000001-0000-0010-8000-00aa00389b71").bytes_le
|
||||
KSDATAFORMAT_SUBTYPE_PCM = b'\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x008\x9bq'
|
||||
|
|
@ -240,10 +226,6 @@ class Wave_read:
|
|||
available through the getsampwidth() method
|
||||
_framerate -- the sampling frequency
|
||||
available through the getframerate() method
|
||||
_format -- frame format
|
||||
One of WAVE_FORMAT_PCM, WAVE_FORMAT_IEEE_FLOAT
|
||||
or WAVE_FORMAT_EXTENSIBLE available through
|
||||
getformat() method
|
||||
_comptype -- the AIFF-C compression type ('NONE' if AIFF)
|
||||
available through the getcomptype() method
|
||||
_compname -- the human-readable AIFF-C compression type
|
||||
|
|
@ -345,9 +327,6 @@ def getsampwidth(self):
|
|||
def getframerate(self):
|
||||
return self._framerate
|
||||
|
||||
def getformat(self):
|
||||
return self._format
|
||||
|
||||
def getcomptype(self):
|
||||
return self._comptype
|
||||
|
||||
|
|
@ -388,16 +367,16 @@ def readframes(self, nframes):
|
|||
|
||||
def _read_fmt_chunk(self, chunk):
|
||||
try:
|
||||
self._format, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack_from('<HHLLH', chunk.read(14))
|
||||
wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack_from('<HHLLH', chunk.read(14))
|
||||
except struct.error:
|
||||
raise EOFError from None
|
||||
if self._format not in (WAVE_FORMAT_PCM, WAVE_FORMAT_IEEE_FLOAT, WAVE_FORMAT_EXTENSIBLE):
|
||||
raise Error('unknown format: %r' % (self._format,))
|
||||
if wFormatTag != WAVE_FORMAT_PCM and wFormatTag != WAVE_FORMAT_EXTENSIBLE:
|
||||
raise Error('unknown format: %r' % (wFormatTag,))
|
||||
try:
|
||||
sampwidth = struct.unpack_from('<H', chunk.read(2))[0]
|
||||
except struct.error:
|
||||
raise EOFError from None
|
||||
if self._format == WAVE_FORMAT_EXTENSIBLE:
|
||||
if wFormatTag == WAVE_FORMAT_EXTENSIBLE:
|
||||
try:
|
||||
cbSize, wValidBitsPerSample, dwChannelMask = struct.unpack_from('<HHL', chunk.read(8))
|
||||
# Read the entire UUID from the chunk
|
||||
|
|
@ -440,8 +419,6 @@ class Wave_write:
|
|||
set through the setsampwidth() or setparams() method
|
||||
_framerate -- the sampling frequency
|
||||
set through the setframerate() or setparams() method
|
||||
_format -- frame format
|
||||
set through setformat() method
|
||||
_nframes -- the number of audio frames written to the header
|
||||
set through the setnframes() or setparams() method
|
||||
|
||||
|
|
@ -469,14 +446,12 @@ def initfp(self, file):
|
|||
self._file = file
|
||||
self._convert = None
|
||||
self._nchannels = 0
|
||||
self._format = WAVE_FORMAT_PCM
|
||||
self._sampwidth = 0
|
||||
self._framerate = 0
|
||||
self._nframes = 0
|
||||
self._nframeswritten = 0
|
||||
self._datawritten = 0
|
||||
self._datalength = 0
|
||||
self._fact_sample_count_pos = None
|
||||
self._headerwritten = False
|
||||
|
||||
def __del__(self):
|
||||
|
|
@ -506,10 +481,7 @@ def getnchannels(self):
|
|||
def setsampwidth(self, sampwidth):
|
||||
if self._datawritten:
|
||||
raise Error('cannot change parameters after starting to write')
|
||||
if self._format == WAVE_FORMAT_IEEE_FLOAT:
|
||||
if sampwidth not in (4, 8):
|
||||
raise Error('unsupported sample width for IEEE float format')
|
||||
elif sampwidth < 1 or sampwidth > 4:
|
||||
if sampwidth < 1 or sampwidth > 4:
|
||||
raise Error('bad sample width')
|
||||
self._sampwidth = sampwidth
|
||||
|
||||
|
|
@ -546,18 +518,6 @@ def setcomptype(self, comptype, compname):
|
|||
self._comptype = comptype
|
||||
self._compname = compname
|
||||
|
||||
def setformat(self, format):
|
||||
if self._datawritten:
|
||||
raise Error('cannot change parameters after starting to write')
|
||||
if format not in (WAVE_FORMAT_IEEE_FLOAT, WAVE_FORMAT_PCM):
|
||||
raise Error('unsupported wave format')
|
||||
if format == WAVE_FORMAT_IEEE_FLOAT and self._sampwidth and self._sampwidth not in (4, 8):
|
||||
raise Error('unsupported sample width for IEEE float format')
|
||||
self._format = format
|
||||
|
||||
def getformat(self):
|
||||
return self._format
|
||||
|
||||
def getcomptype(self):
|
||||
return self._comptype
|
||||
|
||||
|
|
@ -565,15 +525,10 @@ def getcompname(self):
|
|||
return self._compname
|
||||
|
||||
def setparams(self, params):
|
||||
nchannels, sampwidth, framerate, nframes, comptype, compname = params
|
||||
if self._datawritten:
|
||||
raise Error('cannot change parameters after starting to write')
|
||||
if len(params) == 6:
|
||||
nchannels, sampwidth, framerate, nframes, comptype, compname = params
|
||||
format = WAVE_FORMAT_PCM
|
||||
else:
|
||||
nchannels, sampwidth, framerate, nframes, comptype, compname, format = params
|
||||
self.setnchannels(nchannels)
|
||||
self.setformat(format)
|
||||
self.setsampwidth(sampwidth)
|
||||
self.setframerate(framerate)
|
||||
self.setnframes(nframes)
|
||||
|
|
@ -634,9 +589,6 @@ def _ensure_header_written(self, datasize):
|
|||
raise Error('sampling rate not specified')
|
||||
self._write_header(datasize)
|
||||
|
||||
def _needs_fact_chunk(self):
|
||||
return self._format == WAVE_FORMAT_IEEE_FLOAT
|
||||
|
||||
def _write_header(self, initlength):
|
||||
assert not self._headerwritten
|
||||
self._file.write(b'RIFF')
|
||||
|
|
@ -647,23 +599,12 @@ def _write_header(self, initlength):
|
|||
self._form_length_pos = self._file.tell()
|
||||
except (AttributeError, OSError):
|
||||
self._form_length_pos = None
|
||||
has_fact = self._needs_fact_chunk()
|
||||
header_overhead = 36 + (12 if has_fact else 0)
|
||||
self._file.write(struct.pack('<L4s4sLHHLLHH',
|
||||
header_overhead + self._datalength, b'WAVE', b'fmt ', 16,
|
||||
self._format, self._nchannels, self._framerate,
|
||||
self._file.write(struct.pack('<L4s4sLHHLLHH4s',
|
||||
36 + self._datalength, b'WAVE', b'fmt ', 16,
|
||||
WAVE_FORMAT_PCM, self._nchannels, self._framerate,
|
||||
self._nchannels * self._framerate * self._sampwidth,
|
||||
self._nchannels * self._sampwidth,
|
||||
self._sampwidth * 8))
|
||||
if has_fact:
|
||||
self._file.write(b'fact')
|
||||
self._file.write(struct.pack('<L', 4))
|
||||
try:
|
||||
self._fact_sample_count_pos = self._file.tell()
|
||||
except (AttributeError, OSError):
|
||||
self._fact_sample_count_pos = None
|
||||
self._file.write(struct.pack('<L', self._nframes))
|
||||
self._file.write(b'data')
|
||||
self._sampwidth * 8, b'data'))
|
||||
if self._form_length_pos is not None:
|
||||
self._data_length_pos = self._file.tell()
|
||||
self._file.write(struct.pack('<L', self._datalength))
|
||||
|
|
@ -674,13 +615,8 @@ def _patchheader(self):
|
|||
if self._datawritten == self._datalength:
|
||||
return
|
||||
curpos = self._file.tell()
|
||||
header_overhead = 36 + (12 if self._needs_fact_chunk() else 0)
|
||||
self._file.seek(self._form_length_pos, 0)
|
||||
self._file.write(struct.pack('<L', header_overhead + self._datawritten))
|
||||
if self._fact_sample_count_pos is not None:
|
||||
self._file.seek(self._fact_sample_count_pos, 0)
|
||||
nframes = self._datawritten // (self._nchannels * self._sampwidth)
|
||||
self._file.write(struct.pack('<L', nframes))
|
||||
self._file.write(struct.pack('<L', 36 + self._datawritten))
|
||||
self._file.seek(self._data_length_pos, 0)
|
||||
self._file.write(struct.pack('<L', self._datawritten))
|
||||
self._file.seek(curpos, 0)
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
Add support for floating point audio wave files in :mod:`wave`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue