<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def from_dir(dirpath: Path, feat_type: str) -> None: """ Performs feature extraction from the WAV files in a directory. Args: dirpath: A `Path` to the directory where the WAV files reside. feat_type: The type of features that are being used. """


    logger.info("Extracting features from directory {}".format(dirpath))

    dirname = str(dirpath)

    def all_wavs_processed() -> bool:
        """
        True if all wavs in the directory have corresponding numpy feature
        file; False otherwise.
        """

        for fn in os.listdir(dirname):
            prefix, ext = os.path.splitext(fn)
            if ext == ".wav":
                if not os.path.exists(
                        os.path.join(dirname, "%s.%s.npy" % (prefix, feat_type))):
                    return False
        return True

    if all_wavs_processed():
        # Then nothing needs to be done here
        logger.info("All WAV files already preprocessed")
        return
    # Otherwise, go on and process everything...

    # If pitch features are needed as part of this, extract them
    if feat_type == "pitch" or feat_type == "fbank_and_pitch":
        kaldi_pitch(dirname, dirname)

    # Then apply file-wise feature extraction
    for filename in os.listdir(dirname):
        logger.info("Preparing %s features for %s", feat_type, filename)
        path = os.path.join(dirname, filename)
        if path.endswith(".wav"):
            if empty_wav(path):
                raise PersephoneException("Can't extract features for {} since it is an empty WAV file. Remove it from the corpus.".format(path))
            if feat_type == "fbank":
                fbank(path)
            elif feat_type == "fbank_and_pitch":
                fbank(path)
                prefix = os.path.splitext(filename)[0]
                combine_fbank_and_pitch(dirname, prefix)
            elif feat_type == "pitch":
                # Already extracted pitch at the start of this function.
                pass
            elif feat_type == "mfcc13_d":
                mfcc(path)
            else:
                logger.warning("Feature type not found: %s", feat_type)
                raise PersephoneException("Feature type not found: %s" % feat_type)