docs: def buffer_read(self, frames=-1, dtype=None):
          """Read from the file and return data as buffer object.
  
          Reads the given number of `frames` in the given data format
          starting at the current read/write position.  This advances the
          read/write position by the same number of frames.
          By default, all frames from the current read/write position to
          the end of the file are returned.
          Use :meth:`.seek` to move the current read/write position.
  
          Parameters
          ----------
          frames : int, optional
              The number of frames to read. If `frames < 0`, the whole
              rest of the file is read.
          dtype : {'float64', 'float32', 'int32', 'int16'}
              Audio data will be converted to the given data type.
  
          Returns
          -------
          buffer
              A buffer containing the read data.
  
          See Also
          --------
          buffer_read_into, .read, buffer_write
  
          """
          frames = self._check_frames(frames, fill_value=None)
          ctype = self._check_dtype(dtype)
          cdata = _ffi.new(ctype + '[]', frames * self.channels)
          read_frames = self._cdata_io('read', cdata, ctype, frames)
          assert read_frames == frames
          return _ffi.buffer(cdata)