<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_stems( filename, out_type=np.float_, stem_id=None, start=0, duration=None, info=None ):
 """Read STEMS format into numpy Tensor Parameters filename : str Filename of STEMS format. Typically `filename.stem.mp4`. out_type : type Output type. Defaults to 32bit float aka `np.float32`. stem_id : int Stem ID (Stream ID) to read. Defaults to `None`, which reads all available stems. start : float Start position (seek) in seconds, defaults to 0. duration : float Read `duration` seconds. End position then is `start + duration`. Defaults to `None`: read till the end. info : object provide info object, useful if read_stems is called frequently on file with same configuration (#streams, #channels, samplerate). Returns ------- stems : array_like The tensor of Matrix of stems. The data shape is formatted as :code:`stems x channels x samples`. Notes ----- Input is expected to be in 16bit/44.1 kHz """

    if info is None:
        FFinfo = Info(filename)
    else:
        FFinfo = info

    if stem_id is not None:
        substreams = stem_id
    else:
        substreams = FFinfo.audio_stream_idx()

    if not isinstance(substreams, list):
        substreams = [substreams]

    stems = []
    tmps = [
        tmp.NamedTemporaryFile(delete=False, suffix='.wav')
        for t in substreams
    ]
    for tmp_id, stem in enumerate(substreams):
        rate = FFinfo.rate(stem)
        channels = FFinfo.channels(stem)
        cmd = [
            'ffmpeg',
            '-y',
            '-vn',
            '-i', filename,
            '-map', '0:' + str(stem),
            '-acodec', 'pcm_s16le',
            '-ar', str(rate),
            '-ac', str(channels),
            '-loglevel', 'error',
            tmps[tmp_id].name
        ]
        if start:
            cmd.insert(3, '-ss')
            cmd.insert(4, str(start))

        if duration is not None:
            cmd.insert(-1, '-t')
            cmd.insert(-1, str(duration))

        sp.call(cmd)
        # read wav files
        audio, rate = sf.read(tmps[tmp_id].name)
        tmps[tmp_id].close()
        os.remove(tmps[tmp_id].name)
        stems.append(audio)

    # check if all stems have the same duration
    stem_durations = np.array([t.shape[0] for t in stems])
    if not (stem_durations == stem_durations[0]).all():
        warnings.warn("Warning.......Stems differ in length and were shortend")
        min_length = np.min(stem_durations)
        stems = [t[:min_length, :] for t in stems]

    stems = np.array(stems)
    stems = np.squeeze(stems).astype(out_type)
    return stems, rate