Read the digital samples from a single segment record's associated
    dat file(s).

    Parameters
    ----------
    file_name : list
        The names of the dat files to be read.
    dir_name : str
        The full directory where the dat file(s) are located, if the dat
        file(s) are local.
    pb_dir : str
        The physiobank directory where the dat file(s) are located, if
        the dat file(s) are remote.
    fmt : list
        The formats of the dat files
    n_sig : int
        The number of signals contained in the dat file
    sig_len : int
        The signal length (per channel) of the dat file
    byte_offset : int
        The byte offset of the dat file
    samps_per_frame : list
        The samples/frame for each signal of the dat file
    skew : list
        The skew for the signals of the dat file
    sampfrom : int
        The starting sample number to be read from the signals
    sampto : int
        The final sample number to be read from the signals
    smooth_frames : bool
        Whether to smooth channels with multiple samples/frame
    ignore_skew : bool, optional
        Used when reading records with at least one skewed signal.
        Specifies whether to apply the skew to align the signals in the
        output variable (False), or to ignore the skew field and load in
        all values contained in the dat files unaligned (True).

    Returns
    -------
    signals : numpy array, or list
        The signals read from the dat file(s). A 2d numpy array is
        returned if the signals have uniform samples/frame or if
        `smooth_frames` is True. Otherwise a list of 1d numpy arrays
        is returned.

    Notes
    -----
    'channels', 'sampfrom', 'sampto', 'smooth_frames', and 'ignore_skew'
    are user desired input fields. All other parameters are
    specifications of the segment

def _rd_segment(file_name, dir_name, pb_dir, fmt, n_sig, sig_len, byte_offset,
                samps_per_frame, skew, sampfrom, sampto, channels,
                smooth_frames, ignore_skew):
    """
    Read the digital samples from a single segment record's associated
    dat file(s).

    Parameters
    ----------
    file_name : list
        The names of the dat files to be read.
    dir_name : str
        The full directory where the dat file(s) are located, if the dat
        file(s) are local.
    pb_dir : str
        The physiobank directory where the dat file(s) are located, if
        the dat file(s) are remote.
    fmt : list
        The formats of the dat files
    n_sig : int
        The number of signals contained in the dat file
    sig_len : int
        The signal length (per channel) of the dat file
    byte_offset : int
        The byte offset of the dat file
    samps_per_frame : list
        The samples/frame for each signal of the dat file
    skew : list
        The skew for the signals of the dat file
    sampfrom : int
        The starting sample number to be read from the signals
    sampto : int
        The final sample number to be read from the signals
    smooth_frames : bool
        Whether to smooth channels with multiple samples/frame
    ignore_skew : bool, optional
        Used when reading records with at least one skewed signal.
        Specifies whether to apply the skew to align the signals in the
        output variable (False), or to ignore the skew field and load in
        all values contained in the dat files unaligned (True).

    Returns
    -------
    signals : numpy array, or list
        The signals read from the dat file(s). A 2d numpy array is
        returned if the signals have uniform samples/frame or if
        `smooth_frames` is True. Otherwise a list of 1d numpy arrays
        is returned.

    Notes
    -----
    'channels', 'sampfrom', 'sampto', 'smooth_frames', and 'ignore_skew'
    are user desired input fields. All other parameters are
    specifications of the segment

    """

    # Avoid changing outer variables
    byte_offset = byte_offset[:]
    samps_per_frame = samps_per_frame[:]
    skew = skew[:]

    # Set defaults for empty fields
    for i in range(n_sig):
        if byte_offset[i] == None:
            byte_offset[i] = 0
        if samps_per_frame[i] == None:
            samps_per_frame[i] = 1
        if skew[i] == None:
            skew[i] = 0

    # If skew is to be ignored, set all to 0
    if ignore_skew:
        skew = [0]*n_sig

    # Get the set of dat files, and the
    # channels that belong to each file.
    file_name, datchannel = describe_list_indices(file_name)

    # Some files will not be read depending on input channels.
    # Get the the wanted fields only.
    w_file_name = [] # one scalar per dat file
    w_fmt = {} # one scalar per dat file
    w_byte_offset = {} # one scalar per dat file
    w_samps_per_frame = {} # one list per dat file
    w_skew = {} # one list per dat file
    w_channel = {} # one list per dat file

    for fn in file_name:
        # intersecting dat channels between the input channels and the channels of the file
        idc = [c for c in datchannel[fn] if c in channels]

        # There is at least one wanted channel in the dat file
        if idc != []:
            w_file_name.append(fn)
            w_fmt[fn] = fmt[datchannel[fn][0]]
            w_byte_offset[fn] = byte_offset[datchannel[fn][0]]
            w_samps_per_frame[fn] = [samps_per_frame[c] for c in datchannel[fn]]
            w_skew[fn] = [skew[c] for c in datchannel[fn]]
            w_channel[fn] = idc

    # Wanted dat channels, relative to the dat file itself
    r_w_channel =  {}
    # The channels in the final output array that correspond to the read channels in each dat file
    out_dat_channel = {}
    for fn in w_channel:
        r_w_channel[fn] = [c - min(datchannel[fn]) for c in w_channel[fn]]
        out_dat_channel[fn] = [channels.index(c) for c in w_channel[fn]]

    # Signals with multiple samples/frame are smoothed, or all signals have 1 sample/frame.
    # Return uniform numpy array
    if smooth_frames or sum(samps_per_frame) == n_sig:
        # Figure out the largest required dtype for the segment to minimize memory usage
        max_dtype = _np_dtype(_fmt_res(fmt, max_res=True), discrete=True)
        # Allocate signal array. Minimize dtype
        signals = np.zeros([sampto-sampfrom, len(channels)], dtype=max_dtype)

        # Read each wanted dat file and store signals
        for fn in w_file_name:
            signals[:, out_dat_channel[fn]] = _rd_dat_signals(fn, dir_name, pb_dir,
                w_fmt[fn], len(datchannel[fn]), sig_len, w_byte_offset[fn],
                w_samps_per_frame[fn], w_skew[fn], sampfrom, sampto,
                smooth_frames)[:, r_w_channel[fn]]

    # Return each sample in signals with multiple samples/frame, without smoothing.
    # Return a list of numpy arrays for each signal.
    else:
        signals = [None] * len(channels)

        for fn in w_file_name:
            # Get the list of all signals contained in the dat file
            datsignals = _rd_dat_signals(fn, dir_name, pb_dir, w_fmt[fn],
                len(datchannel[fn]), sig_len, w_byte_offset[fn],
                w_samps_per_frame[fn], w_skew[fn], sampfrom, sampto,
                smooth_frames)

            # Copy over the wanted signals
            for cn in range(len(out_dat_channel[fn])):
                signals[out_dat_channel[fn][cn]] = datsignals[r_w_channel[fn][cn]]

    return signals