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
15 changes: 11 additions & 4 deletions soundfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
------
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand Down
17 changes: 17 additions & 0 deletions tests/test_soundfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]])
Expand Down
Loading