Skip to content
Merged
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
56 changes: 24 additions & 32 deletions pysoundfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,21 +356,14 @@ def __init__(self, file, mode='r', sample_rate=None, channels=None,
self._file = _snd.sf_open(file, mode_int, self._info)
elif isinstance(file, int):
self._file = _snd.sf_open_fd(file, mode_int, self._info, closefd)
else:
# Note: readinto() is not checked
for attr in ('seek', 'read', 'write', 'tell'):
if not hasattr(file, attr):
raise RuntimeError(
"file must be a filename, a file descriptor or "
"a file-like object with the methods "
"'seek()', 'read()', 'write()' and 'tell()'")
# Note: the callback functions in _vio must be kept alive!
self._vio = self._init_vio(file)
vio = _ffi.new("SF_VIRTUAL_IO*", self._vio)
self._file = _snd.sf_open_virtual(vio, mode_int, self._info,
_ffi.NULL)
elif all(hasattr(file, a) for a in ('seek', 'read', 'write', 'tell')):
self._file = _snd.sf_open_virtual(
self._init_virtual_io(file), mode_int, self._info, _ffi.NULL)
self._name = str(file)

else:
raise RuntimeError("file must be a filename, a file descriptor or "
"a file-like object with the methods "
"'seek()', 'read()', 'write()' and 'tell()'")
self._handle_error()

name = property(lambda self: self._name)
Expand All @@ -397,26 +390,23 @@ def __init__(self, file, mode='r', sample_rate=None, channels=None,
# avoid confusion if something goes wrong before assigning self._file:
_file = None

def _init_vio(self, file):
def _init_virtual_io(self, file):
@_ffi.callback("sf_vio_get_filelen")
def vio_get_filelen(user_data):
# Streams must set _length or implement __len__
if hasattr(file, '_length'):
size = file._length
elif not hasattr(file, '__len__'):
old_file_position = file.tell()
# first try __len__(), if not available fall back to seek()/tell()
try:
size = len(file)
except TypeError:
curr = file.tell()
file.seek(0, SEEK_END)
size = file.tell()
file.seek(old_file_position, SEEK_SET)
else:
size = len(file)
file.seek(curr, SEEK_SET)
return size

@_ffi.callback("sf_vio_seek")
def vio_seek(offset, whence, user_data):
file.seek(offset, whence)
curr = file.tell()
return curr
return file.tell()

@_ffi.callback("sf_vio_read")
def vio_read(ptr, count, user_data):
Expand All @@ -435,18 +425,20 @@ def vio_read(ptr, count, user_data):
def vio_write(ptr, count, user_data):
buf = _ffi.buffer(ptr, count)
data = buf[:]
length = file.write(data)
return length
return file.write(data)

@_ffi.callback("sf_vio_tell")
def vio_tell(user_data):
return file.tell()

return {'get_filelen': vio_get_filelen,
'seek': vio_seek,
'read': vio_read,
'write': vio_write,
'tell': vio_tell}
# Note: the callback functions must be kept alive!
self._virtual_io = {'get_filelen': vio_get_filelen,
'seek': vio_seek,
'read': vio_read,
'write': vio_write,
'tell': vio_tell}

return _ffi.new("SF_VIRTUAL_IO*", self._virtual_io)

def __del__(self):
self.close()
Expand Down