<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def read_frames(file_path, frame_size, hop_size, start=0.0, end=float('inf'), buffer_size=5760000):
 """ Read an audio file frame by frame. The frames are yielded one after another. Args: file_path (str):
 Path to the file to read. frame_size (int):
 The number of samples per frame. hop_size (int):
 The number of samples between two frames. start (float):
 Start in seconds to read from. end (float):
 End in seconds to read to. ``inf`` means to the end of the file. buffer_size (int):
 Number of samples to load into memory at once and return as a single block. The exact number of loaded samples depends on the block-size of the audioread library. So it can be of x higher, where the x is typically 1024 or 4096. Returns: Generator: A generator yielding a tuple for every frame. The first item is the frame and the second a boolean indicating if it is the last frame. """

    rest_samples = np.array([], dtype=np.float32)

    for block in read_blocks(file_path, start=start, end=end, buffer_size=buffer_size):

        # Prepend rest samples from previous block
        block = np.concatenate([rest_samples, block])

        current_sample = 0

        # Get frames that are fully contained in the block
        while current_sample + frame_size < block.size:
            frame = block[current_sample:current_sample + frame_size]
            yield frame, False
            current_sample += hop_size

        # Store rest samples for next block
        rest_samples = block[current_sample:]

    if rest_samples.size > 0:
        rest_samples = np.pad(
            rest_samples,
            (0, frame_size - rest_samples.size),
            mode='constant',
            constant_values=0
        )
        yield rest_samples, True