diff --git a/soundfile.py b/soundfile.py index 0bf3a6e..17fe08d 100644 --- a/soundfile.py +++ b/soundfile.py @@ -402,9 +402,10 @@ def blocks(file: FileDescriptorOrPath, blocksize: int | None = None, The file to read from. See `SoundFile` for details. blocksize : int The number of frames to read per block. - Either this or *out* must be given. + Either this or *out* must be given. Must be greater than zero. overlap : int, optional - The number of frames to rewind between each block. + The number of frames to rewind between each block. Must be + non-negative and smaller than *blocksize* (or the length of *out*). Yields ------ @@ -1132,9 +1133,10 @@ def blocks(self, blocksize: int | None = None, overlap: int = 0, ---------- blocksize : int The number of frames to read per block. Either this or *out* - must be given. + must be given. Must be greater than zero. overlap : int, optional - The number of frames to rewind between each block. + The number of frames to rewind between each block. Must be + non-negative and smaller than *blocksize* (or the length of *out*). frames : int, optional The number of frames to read. If ``frames < 0``, the file is read until the end. @@ -1189,6 +1191,11 @@ def blocks(self, blocksize: int | None = None, overlap: int = 0, blocksize = len(out) copy_out = False + if blocksize <= 0: + raise ValueError("blocksize must be greater than zero") + if overlap < 0 or overlap >= blocksize: + raise ValueError("overlap must be non-negative and smaller than blocksize") + overlap_memory = None while frames > 0: if overlap_memory is None: diff --git a/tests/test_soundfile.py b/tests/test_soundfile.py index 0c93f66..673d10f 100644 --- a/tests/test_soundfile.py +++ b/tests/test_soundfile.py @@ -373,6 +373,23 @@ def test_blocks_without_blocksize(): list(sf.blocks(filename_stereo)) +@pytest.mark.parametrize('blocksize, overlap', [(0, 0), (3, -1), (3, 3), (3, 4)]) +@pytest.mark.parametrize('use_out', [False, True]) +@pytest.mark.parametrize('use_method', [False, True]) +def test_blocks_invalid_size_or_overlap(blocksize, overlap, use_out, use_method): + kwargs = {'out': np.empty((blocksize, 2))} if use_out else {'blocksize': blocksize} + with sf.SoundFile(filename_stereo) as f: + generator = (f.blocks(overlap=overlap, **kwargs) if use_method else + sf.blocks(filename_stereo, overlap=overlap, **kwargs)) + try: + with pytest.raises(ValueError, match='blocksize|overlap'): + next(generator) + if use_method: + assert f.tell() == 0 + finally: + generator.close() + + def test_blocks_full_last_block(file_stereo_r): blocks = list(sf.blocks(file_stereo_r, blocksize=2)) assert_equal_list_of_arrays(blocks, [data_stereo[0:2], data_stereo[2:4]])