Skip to content

Commit eb422f8

Browse files
committed
WIP: read(): Don't ignore "frames" argument
Partial solution to #210, but this breaks blocks()! The tests can be run without testing blocks(): python3 -m pytest -k"not blocks"
1 parent 969b742 commit eb422f8

File tree

2 files changed

+56
-21
lines changed

2 files changed

+56
-21
lines changed

soundfile.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,10 @@ def read(file, frames=-1, start=0, stop=None, dtype='float64', always_2d=False,
211211
array anyway.
212212
213213
If `out` was specified, it is returned. If `out` has more
214-
frames than available in the file (or if `frames` is smaller
215-
than the length of `out`) and no `fill_value` is given, then
216-
only a part of `out` is overwritten and a view containing all
217-
valid frames is returned.
214+
frames than available in the file and no `fill_value` is given,
215+
or if `frames` is smaller than the length of `out`, then only a
216+
part of `out` is overwritten and a view containing all valid
217+
frames is returned.
218218
samplerate : int
219219
The sample rate of the audio file.
220220
@@ -806,12 +806,11 @@ def read(self, frames=-1, dtype='float64', always_2d=False,
806806
one-dimensional array is returned. Use ``always_2d=True``
807807
to return a two-dimensional array anyway.
808808
809-
If `out` was specified, it is returned. If `out` has more
810-
frames than available in the file (or if `frames` is
811-
smaller than the length of `out`) and no `fill_value` is
812-
given, then only a part of `out` is overwritten and a view
813-
containing all valid frames is returned. numpy.ndarray or
814-
type(out)
809+
If `out` was specified, it is returned. If `out` has more
810+
frames than available in the file and no `fill_value` is
811+
given, or if `frames` is smaller than the length of `out`,
812+
then only a part of `out` is overwritten and a view
813+
containing all valid frames is returned.
815814
816815
Other Parameters
817816
----------------
@@ -850,18 +849,25 @@ def read(self, frames=-1, dtype='float64', always_2d=False,
850849
buffer_read, .write
851850
852851
"""
852+
explicit_frames = frames >= 0
853+
if out is not None and (frames < 0 or frames > len(out)):
854+
frames = len(out)
855+
max_frames = self._check_frames(frames, fill_value)
853856
if out is None:
854-
frames = self._check_frames(frames, fill_value)
855-
out = self._create_empty_array(frames, always_2d, dtype)
856-
else:
857-
if frames < 0 or frames > len(out):
858-
frames = len(out)
859-
frames = self._array_io('read', out, frames)
860-
if len(out) > frames:
857+
out = self._create_empty_array(max_frames, always_2d, dtype)
858+
read_frames = self._array_io('read', out, max_frames)
859+
if read_frames < max_frames:
861860
if fill_value is None:
862-
out = out[:frames]
861+
# NB: This can only happen in non-seekable files
862+
assert not self.seekable()
863+
out = out[:read_frames]
864+
else:
865+
out[read_frames:max_frames] = fill_value
866+
if max_frames < len(out):
867+
if explicit_frames or fill_value is None:
868+
out = out[:max_frames]
863869
else:
864-
out[frames:] = fill_value
870+
out[max_frames:] = fill_value
865871
return out
866872

867873
def buffer_read(self, frames=-1, dtype=None):

tests/test_pysoundfile.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,7 @@ def test_blocks_with_frames(file_stereo_r):
364364
def test_blocks_with_frames_and_fill_value(file_stereo_r):
365365
blocks = list(
366366
sf.blocks(file_stereo_r, blocksize=2, frames=3, fill_value=0))
367-
last_block = np.row_stack((data_stereo[2:3], np.zeros((1, 2))))
368-
assert_equal_list_of_arrays(blocks, [data_stereo[0:2], last_block])
367+
assert_equal_list_of_arrays(blocks, [data_stereo[0:2], data_stereo[2:3]])
369368

370369

371370
def test_blocks_with_out(file_stereo_r):
@@ -742,6 +741,36 @@ def test_read_into_out_over_end_with_fill_should_return_full_data_and_write_into
742741
assert out.shape == (4, sf_stereo_r.channels)
743742

744743

744+
def test_read_into_out_with_frames_and_fill_value(sf_stereo_r):
745+
out = np.ones((8, sf_stereo_r.channels), dtype='float64')
746+
data = sf_stereo_r.read(3, out=out, fill_value=0)
747+
assert len(data) == 3
748+
assert np.all(data == data_stereo[:3])
749+
assert np.all(data == out[:3])
750+
assert data.base is out
751+
assert np.all(out[3:] == 1)
752+
753+
754+
def test_read_into_out_over_end_with_frames_and_fill_value(sf_stereo_r):
755+
out = np.ones((8, sf_stereo_r.channels), dtype='float64')
756+
data = sf_stereo_r.read(6, out=out, fill_value=0)
757+
assert len(data) == 6
758+
assert np.all(out[:4] == data_stereo)
759+
assert np.all(out[4:6] == 0)
760+
assert np.all(out[6:8] == 1)
761+
assert np.all(data == out[:6])
762+
assert data.base is out
763+
764+
765+
def test_read_into_out_over_end_with_too_large_frames_and_fill_value(sf_stereo_r):
766+
out = np.ones((8, sf_stereo_r.channels), dtype='float64')
767+
data = sf_stereo_r.read(99, out=out, fill_value=0)
768+
assert len(data) == 8
769+
assert np.all(out[:4] == data_stereo)
770+
assert np.all(out[4:8] == 0)
771+
assert data is out
772+
773+
745774
# -----------------------------------------------------------------------------
746775
# Test buffer read
747776
# -----------------------------------------------------------------------------

0 commit comments

Comments
 (0)