From 949cf630bd4be5dc9495a3fecfdc3ef2b347bd6b Mon Sep 17 00:00:00 2001 From: Joe Todd Date: Sun, 31 Mar 2024 12:21:09 +0100 Subject: [PATCH] Automatically detect bit depth in FileEncoder, and raise error --- CHANGELOG.rst | 4 +++- pyflac/__main__.py | 2 -- pyflac/decoder.py | 2 +- pyflac/encoder.py | 16 ++++++++++------ pyproject.toml | 4 ++-- tests/test_decoder.py | 2 +- tests/test_encoder.py | 9 +-------- 7 files changed, 18 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f9b7cf5..634b67a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,9 +1,11 @@ pyFLAC Changelog ---------------- -**v2.3.0** +**v3.0.0** * Fixed bug in the shutdown behaviour of the decoder (see #22 and #23). +* Automatically detect bit depth of input data in the `FileEncoder`, and + raise an error if not 16-bit or 32-bit PCM (see #24). **v2.2.0** diff --git a/pyflac/__main__.py b/pyflac/__main__.py index 2a14dd7..fdbe233 100644 --- a/pyflac/__main__.py +++ b/pyflac/__main__.py @@ -27,7 +27,6 @@ def get_args(): parser.add_argument('-c', '--compression-level', type=int, choices=range(0, 9), default=5, help='0 is the fastest compression, 5 is the default, 8 is the highest compression') parser.add_argument('-b', '--block-size', type=int, default=0, help='The block size') - parser.add_argument('-d', '--dtype', default='int16', help='The encoded data type (int16 or int32)') parser.add_argument('-v', '--verify', action='store_false', default=True, help='Verify the compressed data') args = parser.parse_args() return args @@ -45,7 +44,6 @@ def main(): input_file=args.input_file, output_file=args.output_file, blocksize=args.block_size, - dtype=args.dtype, compression_level=args.compression_level, verify=args.verify ) diff --git a/pyflac/decoder.py b/pyflac/decoder.py index 7f791f0..bc8b80a 100644 --- a/pyflac/decoder.py +++ b/pyflac/decoder.py @@ -4,7 +4,7 @@ # # pyFLAC decoder # -# Copyright (c) 2020-2021, Sonos, Inc. +# Copyright (c) 2020-2024, Sonos, Inc. # All rights reserved. # # ------------------------------------------------------------------------------ diff --git a/pyflac/encoder.py b/pyflac/encoder.py index fde1797..5261f75 100644 --- a/pyflac/encoder.py +++ b/pyflac/encoder.py @@ -4,7 +4,7 @@ # # pyFLAC encoder # -# Copyright (c) 2020-2021, Sonos, Inc. +# Copyright (c) 2020-2024, Sonos, Inc. # All rights reserved. # # ------------------------------------------------------------------------------ @@ -335,6 +335,8 @@ class FileEncoder(_Encoder): The pyFLAC file encoder reads the raw audio data from the WAV file and writes the encoded audio data to a FLAC file. + Note that the input WAV file must be either PCM_16 or PCM_32. + Args: input_file (pathlib.Path): Path to the input WAV file output_file (pathlib.Path): Path to the output FLAC file, a temporary @@ -345,8 +347,6 @@ class FileEncoder(_Encoder): blocksize (int): The size of the block to be returned in the callback. The default is 0 which allows libFLAC to determine the best block size. - dtype (str): The data type to use in the FLAC encoder, either int16 or int32, - defaults to int16. streamable_subset (bool): Whether to use the streamable subset for encoding. If true the encoder will check settings for compatibility. If false, the settings may take advantage of the full range that the format allows. @@ -365,13 +365,17 @@ def __init__(self, output_file: Path = None, compression_level: int = 5, blocksize: int = 0, - dtype: str = 'int16', streamable_subset: bool = True, verify: bool = False): super().__init__() - if dtype not in ('int16', 'int32'): - raise ValueError('FLAC encoding data type must be either int16 or int32') + info = sf.info(str(input_file)) + if info.subtype == 'PCM_16': + dtype = 'int16' + elif info.subtype == 'PCM_32': + dtype = 'int32' + else: + raise ValueError(f'WAV input data type must be either PCM_16 or PCM_32: Got {info.subtype}') self.__raw_audio, sample_rate = sf.read(str(input_file), dtype=dtype) if output_file: diff --git a/pyproject.toml b/pyproject.toml index afac4d2..ece5d91 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ # # pyFLAC # -# Copyright (c) 2020-2023, Sonos, Inc. +# Copyright (c) 2020-2024, Sonos, Inc. # All rights reserved. # # ------------------------------------------------------------------------------ @@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta" [project] name = "pyFLAC" -version = "2.3.0" +version = "3.0.0" description = "A Python wrapper for libFLAC" readme = "README.rst" authors = [{ name = "Joe Todd", email = "joe.todd@sonos.com" }] diff --git a/tests/test_decoder.py b/tests/test_decoder.py index 9017f7c..7998efc 100644 --- a/tests/test_decoder.py +++ b/tests/test_decoder.py @@ -4,7 +4,7 @@ # # pyFLAC decoder test suite # -# Copyright (c) 2020-2021, Sonos, Inc. +# Copyright (c) 2020-2024, Sonos, Inc. # All rights reserved. # # ------------------------------------------------------------------------------ diff --git a/tests/test_encoder.py b/tests/test_encoder.py index f84dca7..ac876e0 100644 --- a/tests/test_encoder.py +++ b/tests/test_encoder.py @@ -4,7 +4,7 @@ # # pyFLAC encoder test suite # -# Copyright (c) 2020-2021, Sonos, Inc. +# Copyright (c) 2020-2024, Sonos, Inc. # All rights reserved. # # ------------------------------------------------------------------------------ @@ -237,12 +237,6 @@ def test_invalid_blocksize(self): with self.assertRaisesRegex(EncoderInitException, 'FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE'): self.encoder._init() - def test_invalid_dtype(self): - """ Test than an exception is raised if given an invalid dtype """ - self.default_kwargs['dtype'] = 'int24' - with self.assertRaisesRegex(ValueError, 'FLAC encoding data type must be either int16 or int32'): - self.encoder = FileEncoder(**self.default_kwargs) - def test_blocksize_streamable_subset(self): """ Test that an exception is raised if blocksize is outside the streamable subset """ self.default_kwargs['blocksize'] = 65535 @@ -291,7 +285,6 @@ def test_process_32_bit_file(self): test_path = pathlib.Path(__file__).parent.absolute() / 'data/32bit.wav' self.default_kwargs['input_file'] = test_path self.default_kwargs['output_file'] = pathlib.Path(self.temp_file.name) - self.default_kwargs['dtype'] = 'int32' self.encoder = FileEncoder(**self.default_kwargs) self.encoder.process()