Beispiel #1
0
    def check_espeak(cls):
        """
        Check whether ``espeak`` can be called.

        Return ``True`` on failure and ``False`` on success.

        :rtype: bool
        """
        try:
            from aeneas.textfile import TextFile
            from aeneas.textfile import TextFragment
            from aeneas.ttswrappers.espeakttswrapper import ESPEAKTTSWrapper
            text = u"From fairest creatures we desire increase,"
            text_file = TextFile()
            text_file.add_fragment(TextFragment(language=u"eng", lines=[text], filtered_lines=[text]))
            handler, output_file_path = gf.tmp_file(suffix=u".wav")
            ESPEAKTTSWrapper().synthesize_multiple(text_file, output_file_path)
            gf.delete_file(handler, output_file_path)
            gf.print_success(u"espeak         OK")
            return False
        except:
            pass
        gf.print_error(u"espeak         ERROR")
        gf.print_info(u"  Please make sure you have espeak installed correctly")
        gf.print_info(u"  and that its path is in your PATH environment variable")
        gf.print_info(u"  You might also want to check that the espeak-data directory")
        gf.print_info(u"  is set up correctly, for example, it has the correct permissions")
        return True
Beispiel #2
0
 def _select_tts_engine(self):
     """
     Select the TTS engine to be used by looking at the rconf object.
     """
     self.log(u"Selecting TTS engine...")
     requested_tts_engine = self.rconf[RuntimeConfiguration.TTS]
     if requested_tts_engine == self.CUSTOM:
         self.log(u"TTS engine: custom")
         tts_path = self.rconf[RuntimeConfiguration.TTS_PATH]
         if tts_path is None:
             self.log_exc(u"You must specify a value for tts_path", None, True, ValueError)
         if not gf.file_can_be_read(tts_path):
             self.log_exc(u"Cannot read tts_path", None, True, OSError)
         try:
             import imp
             self.log([u"Loading CustomTTSWrapper module from '%s'...", tts_path])
             imp.load_source("CustomTTSWrapperModule", tts_path)
             self.log([u"Loading CustomTTSWrapper module from '%s'... done", tts_path])
             self.log(u"Importing CustomTTSWrapper...")
             from CustomTTSWrapperModule import CustomTTSWrapper
             self.log(u"Importing CustomTTSWrapper... done")
             self.log(u"Creating CustomTTSWrapper instance...")
             self.tts_engine = CustomTTSWrapper(rconf=self.rconf, logger=self.logger)
             self.log(u"Creating CustomTTSWrapper instance... done")
         except Exception as exc:
             self.log_exc(u"Unable to load custom TTS wrapper", exc, True, OSError)
     elif requested_tts_engine == self.AWS:
         try:
             import boto3
         except ImportError as exc:
             self.log_exc(u"Unable to import boto3 for AWS Polly TTS API wrapper", exc, True, ImportError)
         self.log(u"TTS engine: AWS Polly TTS API")
         self.tts_engine = AWSTTSWrapper(rconf=self.rconf, logger=self.logger)
     elif requested_tts_engine == self.NUANCE:
         try:
             import requests
         except ImportError as exc:
             self.log_exc(u"Unable to import requests for Nuance TTS API wrapper", exc, True, ImportError)
         self.log(u"TTS engine: Nuance TTS API")
         self.tts_engine = NuanceTTSWrapper(rconf=self.rconf, logger=self.logger)
     elif requested_tts_engine == self.ESPEAKNG:
         self.log(u"TTS engine: eSpeak-ng")
         self.tts_engine = ESPEAKNGTTSWrapper(rconf=self.rconf, logger=self.logger)
     elif requested_tts_engine == self.FESTIVAL:
         self.log(u"TTS engine: Festival")
         self.tts_engine = FESTIVALTTSWrapper(rconf=self.rconf, logger=self.logger)
     elif requested_tts_engine == self.MACOS:
         self.log(u"TTS engine: macOS")
         self.tts_engine = MacOSTTSWrapper(rconf=self.rconf, logger=self.logger)
     else:
         self.log(u"TTS engine: eSpeak")
         self.tts_engine = ESPEAKTTSWrapper(rconf=self.rconf, logger=self.logger)
     self.log(u"Selecting TTS engine... done")
Beispiel #3
0
class Synthesizer(Loggable):
    """
    A class to synthesize text fragments into
    an audio file,
    along with the corresponding time anchors.

    :param rconf: a runtime configuration
    :type  rconf: :class:`~aeneas.runtimeconfiguration.RuntimeConfiguration`
    :param logger: the logger object
    :type  logger: :class:`~aeneas.logger.Logger`
    :raises: OSError: if a custom TTS engine is requested
                      but it cannot be loaded
    :raises: ImportError: if the AWS Polly TTS API wrapper is requested
                          but the ``boto3`` module is not installed, or
                          if the Nuance TTS API wrapper is requested
                          but the``requests`` module is not installed
    """

    AWS = "aws"
    """ Select AWS Polly TTS API wrapper """

    CUSTOM = "custom"
    """ Select custom TTS engine wrapper """

    ESPEAK = "espeak"
    """ Select eSpeak wrapper """

    ESPEAKNG = "espeak-ng"
    """ Select eSpeak-ng wrapper """

    FESTIVAL = "festival"
    """ Select Festival wrapper """

    MACOS = "macos"
    """ Select macOS "say" wrapper """

    NUANCE = "nuance"
    """ Select Nuance TTS API wrapper """

    ALLOWED_VALUES = [AWS, CUSTOM, ESPEAK, ESPEAKNG, FESTIVAL, MACOS, NUANCE]
    """ List of all the allowed values """

    TAG = u"Synthesizer"

    def __init__(self, rconf=None, logger=None):
        super(Synthesizer, self).__init__(rconf=rconf, logger=logger)
        self.tts_engine = None
        self._select_tts_engine()

    def _select_tts_engine(self):
        """
        Select the TTS engine to be used by looking at the rconf object.
        """
        self.log(u"Selecting TTS engine...")
        requested_tts_engine = self.rconf[RuntimeConfiguration.TTS]
        if requested_tts_engine == self.CUSTOM:
            self.log(u"TTS engine: custom")
            tts_path = self.rconf[RuntimeConfiguration.TTS_PATH]
            if tts_path is None:
                self.log_exc(u"You must specify a value for tts_path", None, True, ValueError)
            if not gf.file_can_be_read(tts_path):
                self.log_exc(u"Cannot read tts_path", None, True, OSError)
            try:
                import imp
                self.log([u"Loading CustomTTSWrapper module from '%s'...", tts_path])
                imp.load_source("CustomTTSWrapperModule", tts_path)
                self.log([u"Loading CustomTTSWrapper module from '%s'... done", tts_path])
                self.log(u"Importing CustomTTSWrapper...")
                from CustomTTSWrapperModule import CustomTTSWrapper
                self.log(u"Importing CustomTTSWrapper... done")
                self.log(u"Creating CustomTTSWrapper instance...")
                self.tts_engine = CustomTTSWrapper(rconf=self.rconf, logger=self.logger)
                self.log(u"Creating CustomTTSWrapper instance... done")
            except Exception as exc:
                self.log_exc(u"Unable to load custom TTS wrapper", exc, True, OSError)
        elif requested_tts_engine == self.AWS:
            try:
                import boto3
            except ImportError as exc:
                self.log_exc(u"Unable to import boto3 for AWS Polly TTS API wrapper", exc, True, ImportError)
            self.log(u"TTS engine: AWS Polly TTS API")
            self.tts_engine = AWSTTSWrapper(rconf=self.rconf, logger=self.logger)
        elif requested_tts_engine == self.NUANCE:
            try:
                import requests
            except ImportError as exc:
                self.log_exc(u"Unable to import requests for Nuance TTS API wrapper", exc, True, ImportError)
            self.log(u"TTS engine: Nuance TTS API")
            self.tts_engine = NuanceTTSWrapper(rconf=self.rconf, logger=self.logger)
        elif requested_tts_engine == self.ESPEAKNG:
            self.log(u"TTS engine: eSpeak-ng")
            self.tts_engine = ESPEAKNGTTSWrapper(rconf=self.rconf, logger=self.logger)
        elif requested_tts_engine == self.FESTIVAL:
            self.log(u"TTS engine: Festival")
            self.tts_engine = FESTIVALTTSWrapper(rconf=self.rconf, logger=self.logger)
        elif requested_tts_engine == self.MACOS:
            self.log(u"TTS engine: macOS")
            self.tts_engine = MacOSTTSWrapper(rconf=self.rconf, logger=self.logger)
        else:
            self.log(u"TTS engine: eSpeak")
            self.tts_engine = ESPEAKTTSWrapper(rconf=self.rconf, logger=self.logger)
        self.log(u"Selecting TTS engine... done")

    @property
    def output_audio_format(self):
        """
        Return a tuple ``(codec, channels, rate)``
        specifying the audio format
        generated by the actual TTS engine.

        :rtype: tuple
        """
        if self.tts_engine is not None:
            return self.tts_engine.OUTPUT_AUDIO_FORMAT
        return None

    def clear_cache(self):
        """
        Clear the TTS cache, removing all cache files from disk.

        .. versionadded:: 1.6.0
        """
        if self.tts_engine is not None:
            self.tts_engine.clear_cache()

    def synthesize(
            self,
            text_file,
            audio_file_path,
            quit_after=None,
            backwards=False
    ):
        """
        Synthesize the text contained in the given fragment list
        into a ``wav`` file.

        Return a tuple ``(anchors, total_time, num_chars)``.

        :param text_file: the text file to be synthesized
        :type  text_file: :class:`~aeneas.textfile.TextFile`
        :param string audio_file_path: the path to the output audio file
        :param float quit_after: stop synthesizing as soon as
                                 reaching this many seconds
        :param bool backwards: if ``True``, synthesizing from the end of the text file
        :rtype: tuple
        :raises: TypeError: if ``text_file`` is ``None`` or not an instance of ``TextFile``
        :raises: OSError: if ``audio_file_path`` cannot be written
        :raises: OSError: if ``tts=custom`` in the RuntimeConfiguration and ``tts_path`` cannot be read
        :raises: ValueError: if the TTS engine has not been set yet
        """
        if text_file is None:
            self.log_exc(u"text_file is None", None, True, TypeError)
        if not isinstance(text_file, TextFile):
            self.log_exc(u"text_file is not an instance of TextFile", None, True, TypeError)
        if not gf.file_can_be_written(audio_file_path):
            self.log_exc(u"Audio file path '%s' cannot be written" % (audio_file_path), None, True, OSError)
        if self.tts_engine is None:
            self.log_exc(u"Cannot select the TTS engine", None, True, ValueError)

        # synthesize
        self.log(u"Synthesizing text...")
        result = self.tts_engine.synthesize_multiple(
            text_file=text_file,
            output_file_path=audio_file_path,
            quit_after=quit_after,
            backwards=backwards
        )
        self.log(u"Synthesizing text... done")

        # check that the output file has been written
        if not gf.file_exists(audio_file_path):
            self.log_exc(u"Audio file path '%s' cannot be read" % (audio_file_path), None, True, OSError)

        return result