def total_FA(soundfile, mylines, myhead, mytail, config=None): """Runs Aeneas as a library. This function isn't in use, currently, as we haven't managed to get reliable results in this way.""" # create Task object if config is None: config_string = ( u"task_language=nor|is_text_type=plain|os_task_file_format=json|is_audio_file_head_length=%s|is_audio_file_tail_length=%s" % (myhead, mytail)) print(config_string) else: config_string = ( u"task_language=nor|is_text_type=plain|os_task_file_format=json|is_audio_file_head_length=%s|is_audio_file_tail_length=%s|%s" % (myhead, mytail, config)) print(config_string) task = Task(config_string=config_string) print(task) task.audio_file_path_absolute = soundfile textfile = TextFile() print(textfile) #task.sync_map_file_path_absolute = outfile for identifier, frag_text in mylines: textfile.add_fragment( TextFragment(identifier, Language.NOR, frag_text, frag_text)) task.text_file = textfile print(len(task.text_file)) ExecuteTask(task).execute() syncmaplist = task.sync_map.fragments return syncmaplist
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
def test_read_from_list_with_ids(self): tfl = TextFile() text_list = [["a1", "fragment 1"], ["b2", "fragment 2"], ["c3", "fragment 3"], ["d4", "fragment 4"], ["e5", "fragment 5"]] tfl.read_from_list_with_ids(text_list) self.assertEqual(len(tfl), 5)
def main(): """ Entry point """ if len(sys.argv) < 3: usage() return file_path = sys.argv[1] text_format = sys.argv[2] parameters = {} for i in range(3, len(sys.argv)): args = sys.argv[i].split("=") if len(args) == 2: key, value = args if key == "id_regex": parameters[gc.PPN_JOB_IS_TEXT_UNPARSED_ID_REGEX] = value if key == "class_regex": parameters[gc.PPN_JOB_IS_TEXT_UNPARSED_CLASS_REGEX] = value if key == "sort": parameters[gc.PPN_JOB_IS_TEXT_UNPARSED_ID_SORT] = value if text_format == "list": text_file = TextFile() text_file.read_from_list(file_path.split("|")) else: text_file = TextFile(file_path, text_format, parameters) print str(text_file)
def test_synthesize_with_unicode(self): handler, output_file_path = tempfile.mkstemp(suffix=".wav") tfl = TextFile(get_abs_path("res/inputtext/de_utf8.txt"), TextFileFormat.PARSED) tfl.set_language(Language.DE) synth = Synthesizer() anchors = synth.synthesize(tfl, output_file_path) self.assertGreater(len(anchors), 0) os.remove(output_file_path)
def test_read_from_list_with_ids(self): tfl = TextFile() text_list = [(u"a1", u"fragment 1"), (u"b2", u"fragment 2"), (u"c3", u"fragment 3"), (u"d4", u"fragment 4"), (u"e5", u"fragment 5")] tfl.read_from_list_with_ids(text_list) self.assertEqual(len(tfl), 5) self.assertEqual(tfl.chars, 50)
def perform(self, path, logger=None, quit_after=None, backwards=False): handler, output_file_path = tempfile.mkstemp(suffix=".wav") tfl = TextFile(get_abs_path(path), TextFileFormat.PLAIN) tfl.set_language(Language.EN) synth = Synthesizer(logger=logger) result = synth.synthesize(tfl, output_file_path, quit_after=quit_after, backwards=backwards) delete_file(handler, output_file_path) return result
def test_read_from_list(self): tfl = TextFile() text_list = [ "fragment 1", "fragment 2", "fragment 3", "fragment 4", "fragment 5" ] tfl.read_from_list(text_list) self.assertEqual(len(tfl), 5)
def tfl(self, frags): tfl = TextFile() for language, lines in frags: tfl.add_fragment( TextFragment(language=language, lines=lines, filtered_lines=lines)) return tfl
def test_synthesize(self): handler, output_file_path = tempfile.mkstemp(suffix=".wav") tfl = TextFile(get_abs_path("res/inputtext/sonnet_plain.txt"), TextFileFormat.PLAIN) tfl.set_language(Language.EN) synth = Synthesizer() anchors = synth.synthesize(tfl, output_file_path) self.assertGreater(len(anchors), 0) os.remove(output_file_path)
def test_set_language(self): tfl = TextFile(get_abs_path("res/inputtext/sonnet_plain.txt"), TextFileFormat.PLAIN) self.assertEqual(len(tfl), 15) tfl.set_language(Language.EN) for fragment in tfl.fragments: self.assertEqual(fragment.language, Language.EN) tfl.set_language(Language.IT) for fragment in tfl.fragments: self.assertEqual(fragment.language, Language.IT)
def test_read_from_list_with_ids(self): tfl = TextFile() text_list = [ ["a1", "fragment 1"], ["b2", "fragment 2"], ["c3", "fragment 3"], ["d4", "fragment 4"], ["e5", "fragment 5"] ] tfl.read_from_list_with_ids(text_list) self.assertEqual(len(tfl), 5)
def test_read_from_list_with_ids(self): tfl = TextFile() text_list = [ (u"a1", u"fragment 1"), (u"b2", u"fragment 2"), (u"c3", u"fragment 3"), (u"d4", u"fragment 4"), (u"e5", u"fragment 5") ] tfl.read_from_list_with_ids(text_list) self.assertEqual(len(tfl), 5) self.assertEqual(tfl.chars, 50)
def inner(c_ext, cew_subprocess): handler, output_file_path = gf.tmp_file(suffix=".wav") tfl = TextFile(gf.absolute_path(path, __file__), TextFileFormat.PLAIN) tfl.set_language(Language.ENG) synth = Synthesizer(logger=logger) synth.rconf[RuntimeConfiguration.C_EXTENSIONS] = c_ext synth.rconf[RuntimeConfiguration.CEW_SUBPROCESS_ENABLED] = cew_subprocess result = synth.synthesize(tfl, output_file_path, quit_after=quit_after, backwards=backwards) gf.delete_file(handler, output_file_path) self.assertEqual(len(result[0]), expected) if expected2 is not None: self.assertAlmostEqual(result[1], expected2, places=0)
def get_text_file(self, text_format, text, parameters): if text_format == u"list": text_file = TextFile(logger=self.logger) text_file.read_from_list(text.split(u"|")) return text_file else: if text_format not in TextFileFormat.ALLOWED_VALUES: self.print_error(u"File format '%s' is not allowed" % (text_format)) self.print_error(u"Allowed text file formats: %s" % (" ".join(TextFileFormat.ALLOWED_VALUES))) return None try: return TextFile(text, text_format, parameters, logger=self.logger) except OSError: self.print_error(u"Cannot read file '%s'" % (text)) return None
def _populate_text_file(self): """ Create the ``self.text_file`` object by reading the text file at ``self.text_file_path_absolute``. """ self.log(u"Populate text file...") if ( (self.text_file_path_absolute is not None) and (self.configuration["language"] is not None) ): # the following values might be None parameters = { gc.PPN_TASK_IS_TEXT_FILE_IGNORE_REGEX : self.configuration["i_t_ignore_regex"], gc.PPN_TASK_IS_TEXT_FILE_TRANSLITERATE_MAP : self.configuration["i_t_transliterate_map"], gc.PPN_TASK_IS_TEXT_MPLAIN_WORD_SEPARATOR : self.configuration["i_t_mplain_word_separator"], gc.PPN_TASK_IS_TEXT_MUNPARSED_L1_ID_REGEX : self.configuration["i_t_munparsed_l1_id_regex"], gc.PPN_TASK_IS_TEXT_MUNPARSED_L2_ID_REGEX : self.configuration["i_t_munparsed_l2_id_regex"], gc.PPN_TASK_IS_TEXT_MUNPARSED_L3_ID_REGEX : self.configuration["i_t_munparsed_l3_id_regex"], gc.PPN_TASK_IS_TEXT_UNPARSED_CLASS_REGEX : self.configuration["i_t_unparsed_class_regex"], gc.PPN_TASK_IS_TEXT_UNPARSED_ID_REGEX : self.configuration["i_t_unparsed_id_regex"], gc.PPN_TASK_IS_TEXT_UNPARSED_ID_SORT : self.configuration["i_t_unparsed_id_sort"], gc.PPN_TASK_OS_FILE_ID_REGEX : self.configuration["o_id_regex"] } self.text_file = TextFile( file_path=self.text_file_path_absolute, file_format=self.configuration["i_t_format"], parameters=parameters, logger=self.logger ) self.text_file.set_language(self.configuration["language"]) else: self.log(u"text_file_path_absolute and/or language is None") self.log(u"Populate text file... done")
def test_append_fragment_multiple(self): tfl = TextFile() self.assertEqual(len(tfl), 0) tfl.append_fragment(TextFragment("a1", Language.EN, "fragment 1")) self.assertEqual(len(tfl), 1) tfl.append_fragment(TextFragment("a2", Language.EN, "fragment 2")) self.assertEqual(len(tfl), 2) tfl.append_fragment(TextFragment("a3", Language.EN, "fragment 3")) self.assertEqual(len(tfl), 3)
def load(self, input_file_path=PLAIN_FILE_PATH, fmt=TextFileFormat.PLAIN, expected_length=15, parameters=None): tfl = TextFile(get_abs_path(input_file_path), fmt, parameters) self.assertEqual(len(tfl), expected_length) return tfl
def test_add_fragment_multiple(self): tfl = TextFile() self.assertEqual(len(tfl), 0) tfl.add_fragment(TextFragment(u"a1", Language.ENG, [u"fragment 1"])) self.assertEqual(len(tfl), 1) tfl.add_fragment(TextFragment(u"a2", Language.ENG, [u"fragment 2"])) self.assertEqual(len(tfl), 2) tfl.add_fragment(TextFragment(u"a3", Language.ENG, [u"fragment 3"])) self.assertEqual(len(tfl), 3) self.assertEqual(tfl.chars, 30)
def _populate_text_file(self): """ Create the ``self.text_file`` object by reading the text file at ``self.text_file_path_absolute``. """ self.log(u"Populate text file...") if ((self.text_file_path_absolute is not None) and (self.configuration["language"] is not None)): # the following values might be None parameters = { gc.PPN_TASK_IS_TEXT_FILE_IGNORE_REGEX: self.configuration["i_t_ignore_regex"], gc.PPN_TASK_IS_TEXT_FILE_TRANSLITERATE_MAP: self.configuration["i_t_transliterate_map"], gc.PPN_TASK_IS_TEXT_MPLAIN_WORD_SEPARATOR: self.configuration["i_t_mplain_word_separator"], gc.PPN_TASK_IS_TEXT_MUNPARSED_L1_ID_REGEX: self.configuration["i_t_munparsed_l1_id_regex"], gc.PPN_TASK_IS_TEXT_MUNPARSED_L2_ID_REGEX: self.configuration["i_t_munparsed_l2_id_regex"], gc.PPN_TASK_IS_TEXT_MUNPARSED_L3_ID_REGEX: self.configuration["i_t_munparsed_l3_id_regex"], gc.PPN_TASK_IS_TEXT_UNPARSED_CLASS_REGEX: self.configuration["i_t_unparsed_class_regex"], gc.PPN_TASK_IS_TEXT_UNPARSED_ID_REGEX: self.configuration["i_t_unparsed_id_regex"], gc.PPN_TASK_IS_TEXT_UNPARSED_ID_SORT: self.configuration["i_t_unparsed_id_sort"], gc.PPN_TASK_OS_FILE_ID_REGEX: self.configuration["o_id_regex"] } self.text_file = TextFile( file_path=self.text_file_path_absolute, file_format=self.configuration["i_t_format"], parameters=parameters, logger=self.logger) self.text_file.set_language(self.configuration["language"]) else: self.log(u"text_file_path_absolute and/or language is None") self.log(u"Populate text file... done")
def _populate_text_file(self): """ Create the ``self.text_file`` object by reading the text file at ``self.text_file_path_absolute``. """ if ((self.text_file_path_absolute is not None) and (self.configuration.language is not None)): parameters = dict() parameters[ gc. PPN_TASK_IS_TEXT_UNPARSED_CLASS_REGEX] = self.configuration.is_text_unparsed_class_regex parameters[ gc. PPN_TASK_IS_TEXT_UNPARSED_ID_REGEX] = self.configuration.is_text_unparsed_id_regex parameters[ gc. PPN_TASK_IS_TEXT_UNPARSED_ID_SORT] = self.configuration.is_text_unparsed_id_sort self.text_file = TextFile( file_path=self.text_file_path_absolute, file_format=self.configuration.is_text_file_format, parameters=parameters, logger=None) self.text_file.set_language(self.configuration.language)
def _populate_text_file(self): """ Create the ``self.text_file`` object by reading the text file at ``self.text_file_path_absolute``. """ if ((self.text_file_path_absolute is not None) and (self.configuration.language is not None)): parameters = dict() parameters[gc.PPN_TASK_IS_TEXT_UNPARSED_CLASS_REGEX] = self.configuration.is_text_unparsed_class_regex parameters[gc.PPN_TASK_IS_TEXT_UNPARSED_ID_REGEX] = self.configuration.is_text_unparsed_id_regex parameters[gc.PPN_TASK_IS_TEXT_UNPARSED_ID_SORT] = self.configuration.is_text_unparsed_id_sort self.text_file = TextFile( file_path=self.text_file_path_absolute, file_format=self.configuration.is_text_file_format, parameters=parameters, logger=None ) self.text_file.set_language(self.configuration.language)
def test_add_fragment(self): tfl = TextFile() self.assertEqual(len(tfl), 0) tfl.add_fragment(TextFragment(u"a1", Language.ENG, [u"fragment 1"])) self.assertEqual(len(tfl), 1) self.assertEqual(tfl.chars, 10)
def test_invalid_add_fragment(self): tfl = TextFile() with self.assertRaises(TypeError): tfl.add_fragment("foo")
def test_empty_fragments(self): tfl = TextFile() self.assertEqual(len(tfl), 0)
def test_invalid_parameters(self): with self.assertRaises(TypeError): tfl = TextFile(parameters=["foo"])
class Task(object): """ A structure representing a task, that is, an audio file and a list of text fragments to be synchronized. :param config_string: the task configuration string :type config_string: string """ TAG = "Task" def __init__(self, config_string=None): # task properties self.identifier = str(uuid.uuid4()).lower() self.configuration = None self.audio_file_path = None # relative to input container root self.audio_file_path_absolute = None # concrete path, file will be read from this! self.audio_file = None self.text_file_path = None # relative to input container root self.text_file_path_absolute = None # concrete path, file will be read from this! self.text_file = None self.sync_map_file_path = None # relative to output container root self.sync_map_file_path_absolute = None # concrete path, file will be written to this! self.sync_map = None if config_string is not None: self.configuration = TaskConfiguration(config_string) def __str__(self): accumulator = "" accumulator += "%s: '%s'\n" % (gc.RPN_TASK_IDENTIFIER, self.identifier) accumulator += "Configuration:\n%s\n" % str(self.configuration) accumulator += "Audio file path: %s\n" % self.audio_file_path accumulator += "Audio file path (absolute): %s\n" % self.audio_file_path_absolute accumulator += "Text file path: %s\n" % self.text_file_path accumulator += "Text file path (absolute): %s\n" % self.text_file_path_absolute accumulator += "Sync map file path: %s\n" % self.sync_map_file_path accumulator += "Sync map file path (absolute): %s\n" % self.sync_map_file_path_absolute return accumulator @property def identifier(self): """ The identifier of the task. :rtype: string """ return self.__identifier @identifier.setter def identifier(self, value): self.__identifier = value @property def audio_file_path_absolute(self): """ The absolute path of the audio file. :rtype: string (path) """ return self.__audio_file_path_absolute @audio_file_path_absolute.setter def audio_file_path_absolute(self, audio_file_path_absolute): self.__audio_file_path_absolute = audio_file_path_absolute self._populate_audio_file() @property def text_file_path_absolute(self): """ The absolute path of the text file. :rtype: string (path) """ return self.__text_file_path_absolute @text_file_path_absolute.setter def text_file_path_absolute(self, text_file_path_absolute): self.__text_file_path_absolute = text_file_path_absolute self._populate_text_file() @property def sync_map_file_path_absolute(self): """ The absolute path of the sync map file. :rtype: string (path) """ return self.__sync_map_file_path_absolute @sync_map_file_path_absolute.setter def sync_map_file_path_absolute(self, sync_map_file_path_absolute): self.__sync_map_file_path_absolute = sync_map_file_path_absolute def _populate_audio_file(self): """ Create the ``self.audio_file`` object by reading the audio file at ``self.audio_file_path_absolute``. """ if self.audio_file_path_absolute is not None: self.audio_file = AudioFile( file_path=self.audio_file_path_absolute, logger=None) self.audio_file.read_properties() def _populate_text_file(self): """ Create the ``self.text_file`` object by reading the text file at ``self.text_file_path_absolute``. """ if ((self.text_file_path_absolute is not None) and (self.configuration.language is not None)): parameters = dict() parameters[ gc. PPN_TASK_IS_TEXT_UNPARSED_CLASS_REGEX] = self.configuration.is_text_unparsed_class_regex parameters[ gc. PPN_TASK_IS_TEXT_UNPARSED_ID_REGEX] = self.configuration.is_text_unparsed_id_regex parameters[ gc. PPN_TASK_IS_TEXT_UNPARSED_ID_SORT] = self.configuration.is_text_unparsed_id_sort self.text_file = TextFile( file_path=self.text_file_path_absolute, file_format=self.configuration.is_text_file_format, parameters=parameters, logger=None) self.text_file.set_language(self.configuration.language) def output_sync_map_file(self, container_root_path=None): """ Output the sync map file for this task. If ``container_root_path`` is specified, the output sync map file will be created at the path obtained by joining the ``container_root_path`` and the relative path of the sync map inside the container. Otherwise, the sync map file will be created at the path ``sync_map_file_path_absolute``. Return the the path of the sync map file created, or ``None`` if an error occurred. :param container_root_path: the path to the root directory for the output container :type container_root_path: string (path) :rtype: return the path of the sync map file created """ if self.sync_map is None: return None if (container_root_path is not None) and (self.sync_map_file_path is None): return None if (container_root_path is not None) and (self.sync_map_file_path is not None): path = os.path.join(container_root_path, self.sync_map_file_path) elif self.sync_map_file_path_absolute: path = self.sync_map_file_path_absolute sync_map_format = self.configuration.os_file_format parameters = dict() parameters[ gc. PPN_TASK_OS_FILE_SMIL_PAGE_REF] = self.configuration.os_file_smil_page_ref parameters[ gc. PPN_TASK_OS_FILE_SMIL_AUDIO_REF] = self.configuration.os_file_smil_audio_ref result = self.sync_map.write(sync_map_format, path, parameters) if not result: return None return path
def test_append_fragment(self): tfl = TextFile() self.assertEqual(len(tfl), 0) tfl.append_fragment(TextFragment("a1", Language.EN, "fragment 1")) self.assertEqual(len(tfl), 1)
def load(self): audio_file_mfcc = AudioFileMFCC(self.AUDIO_FILE) text_file = TextFile(self.TEXT_FILE, file_format=TextFileFormat.PLAIN) text_file.set_language(Language.ENG) return SD(audio_file_mfcc, text_file)
class Task(object): """ A structure representing a task, that is, an audio file and a list of text fragments to be synchronized. :param config_string: the task configuration string :type config_string: string """ TAG = "Task" def __init__(self, config_string=None): # task properties self.identifier = str(uuid.uuid4()).lower() self.configuration = None self.audio_file_path = None # relative to input container root self.audio_file_path_absolute = None # concrete path, file will be read from this! self.audio_file = None self.text_file_path = None # relative to input container root self.text_file_path_absolute = None # concrete path, file will be read from this! self.text_file = None self.sync_map_file_path = None # relative to output container root self.sync_map_file_path_absolute = None # concrete path, file will be written to this! self.sync_map = None if config_string is not None: self.configuration = TaskConfiguration(config_string) def __str__(self): accumulator = "" accumulator += "%s: '%s'\n" % (gc.RPN_TASK_IDENTIFIER, self.identifier) accumulator += "Configuration:\n%s\n" % str(self.configuration) accumulator += "Audio file path: %s\n" % self.audio_file_path accumulator += "Audio file path (absolute): %s\n" % self.audio_file_path_absolute accumulator += "Text file path: %s\n" % self.text_file_path accumulator += "Text file path (absolute): %s\n" % self.text_file_path_absolute accumulator += "Sync map file path: %s\n" % self.sync_map_file_path accumulator += "Sync map file path (absolute): %s\n" % self.sync_map_file_path_absolute return accumulator @property def identifier(self): """ The identifier of the task. :rtype: string """ return self.__identifier @identifier.setter def identifier(self, value): self.__identifier = value @property def audio_file_path_absolute(self): """ The absolute path of the audio file. :rtype: string (path) """ return self.__audio_file_path_absolute @audio_file_path_absolute.setter def audio_file_path_absolute(self, audio_file_path_absolute): self.__audio_file_path_absolute = audio_file_path_absolute self._populate_audio_file() @property def text_file_path_absolute(self): """ The absolute path of the text file. :rtype: string (path) """ return self.__text_file_path_absolute @text_file_path_absolute.setter def text_file_path_absolute(self, text_file_path_absolute): self.__text_file_path_absolute = text_file_path_absolute self._populate_text_file() @property def sync_map_file_path_absolute(self): """ The absolute path of the sync map file. :rtype: string (path) """ return self.__sync_map_file_path_absolute @sync_map_file_path_absolute.setter def sync_map_file_path_absolute(self, sync_map_file_path_absolute): self.__sync_map_file_path_absolute = sync_map_file_path_absolute def _populate_audio_file(self): """ Create the ``self.audio_file`` object by reading the audio file at ``self.audio_file_path_absolute``. """ if self.audio_file_path_absolute is not None: self.audio_file = AudioFile( file_path=self.audio_file_path_absolute, logger=None ) self.audio_file.read_properties() def _populate_text_file(self): """ Create the ``self.text_file`` object by reading the text file at ``self.text_file_path_absolute``. """ if ((self.text_file_path_absolute is not None) and (self.configuration.language is not None)): parameters = dict() parameters[gc.PPN_TASK_IS_TEXT_UNPARSED_CLASS_REGEX] = self.configuration.is_text_unparsed_class_regex parameters[gc.PPN_TASK_IS_TEXT_UNPARSED_ID_REGEX] = self.configuration.is_text_unparsed_id_regex parameters[gc.PPN_TASK_IS_TEXT_UNPARSED_ID_SORT] = self.configuration.is_text_unparsed_id_sort self.text_file = TextFile( file_path=self.text_file_path_absolute, file_format=self.configuration.is_text_file_format, parameters=parameters, logger=None ) self.text_file.set_language(self.configuration.language) def output_sync_map_file(self, container_root_path=None): """ Output the sync map file for this task. If ``container_root_path`` is specified, the output sync map file will be created at the path obtained by joining the ``container_root_path`` and the relative path of the sync map inside the container. Otherwise, the sync map file will be created at the path ``sync_map_file_path_absolute``. Return the the path of the sync map file created, or ``None`` if an error occurred. :param container_root_path: the path to the root directory for the output container :type container_root_path: string (path) :rtype: return the path of the sync map file created """ if self.sync_map is None: return None if (container_root_path is not None) and (self.sync_map_file_path is None): return None if (container_root_path is not None) and (self.sync_map_file_path is not None): path = os.path.join(container_root_path, self.sync_map_file_path) elif self.sync_map_file_path_absolute: path = self.sync_map_file_path_absolute sync_map_format = self.configuration.os_file_format parameters = dict() parameters[gc.PPN_TASK_OS_FILE_SMIL_PAGE_REF] = self.configuration.os_file_smil_page_ref parameters[gc.PPN_TASK_OS_FILE_SMIL_AUDIO_REF] = self.configuration.os_file_smil_audio_ref result = self.sync_map.write(sync_map_format, path, parameters) if not result: return None return path
def main(): """ Entry point """ if len(sys.argv) < 5: usage() return language = sys.argv[1] text_file_path = sys.argv[2] text_format = sys.argv[3] audio_file_path = sys.argv[-1] verbose = False parameters = {} for i in range(4, len(sys.argv)-1): args = sys.argv[i].split("=") if len(args) == 1: verbose = (args[0] in ["v", "-v", "verbose", "--verbose"]) if len(args) == 2: key, value = args if key == "id_regex": parameters[gc.PPN_JOB_IS_TEXT_UNPARSED_ID_REGEX] = value if key == "class_regex": parameters[gc.PPN_JOB_IS_TEXT_UNPARSED_CLASS_REGEX] = value if key == "sort": parameters[gc.PPN_JOB_IS_TEXT_UNPARSED_ID_SORT] = value if key == "min_head_length": parameters["min_head_length"] = float(value) if key == "max_head_length": parameters["max_head_length"] = float(value) if key == "min_tail_length": parameters["min_head_length"] = float(value) if key == "max_tail_length": parameters["max_tail_length"] = float(value) if not gf.can_run_c_extension(): print "[WARN] Unable to load Python C Extensions" print "[WARN] Running the slower pure Python code" print "[WARN] See the README file for directions to compile the Python C Extensions" logger = Logger(tee=verbose) print "[INFO] Reading audio..." tmp_handler, tmp_file_path = tempfile.mkstemp( suffix=".wav", dir=gf.custom_tmp_dir() ) converter = FFMPEGWrapper(logger=logger) converter.convert(audio_file_path, tmp_file_path) audio_file = AudioFile(tmp_file_path) print "[INFO] Reading audio... done" print "[INFO] Reading text..." if text_format == "list": text_file = TextFile() text_file.read_from_list(text_file_path.split("|")) else: text_file = TextFile(text_file_path, text_format, parameters) text_file.set_language(language) print "[INFO] Reading text... done" print "[INFO] Detecting audio interval..." sd = SD(audio_file, text_file, logger=logger) min_head_length = gc.SD_MIN_HEAD_LENGTH if "min_head_length" in parameters: min_head_length = parameters["min_head_length"] max_head_length = gc.SD_MAX_HEAD_LENGTH if "max_head_length" in parameters: max_head_length = parameters["max_head_length"] min_tail_length = gc.SD_MIN_TAIL_LENGTH if "min_tail_length" in parameters: min_tail_length = parameters["min_tail_length"] max_tail_length = gc.SD_MAX_TAIL_LENGTH if "max_tail_length" in parameters: max_tail_length = parameters["max_tail_length"] start, end = sd.detect_interval( min_head_length, max_head_length, min_tail_length, max_tail_length ) zero = 0 audio_len = audio_file.audio_length head_len = start text_len = end - start tail_len = audio_len - end print "[INFO] Detecting audio interval... done" print "[INFO] " print "[INFO] Head: %.3f %.3f (%.3f)" % (zero, start, head_len) print "[INFO] Text: %.3f %.3f (%.3f)" % (start, end, text_len) print "[INFO] Tail: %.3f %.3f (%.3f)" % (end, audio_len, tail_len) print "[INFO] " zero_h = gf.time_to_hhmmssmmm(0) start_h = gf.time_to_hhmmssmmm(start) end_h = gf.time_to_hhmmssmmm(end) audio_len_h = gf.time_to_hhmmssmmm(audio_len) head_len_h = gf.time_to_hhmmssmmm(head_len) text_len_h = gf.time_to_hhmmssmmm(text_len) tail_len_h = gf.time_to_hhmmssmmm(tail_len) print "[INFO] Head: %s %s (%s)" % (zero_h, start_h, head_len_h) print "[INFO] Text: %s %s (%s)" % (start_h, end_h, text_len_h) print "[INFO] Tail: %s %s (%s)" % (end_h, audio_len_h, tail_len_h) #print "[INFO] Cleaning up..." cleanup(tmp_handler, tmp_file_path)
def test_invalid_format(self): with self.assertRaises(ValueError): tfl = TextFile(file_format="foo")
def test_set_language_on_empty(self): tfl = TextFile() self.assertEqual(len(tfl), 0) tfl.set_language(Language.EN) self.assertEqual(len(tfl), 0)
def test_no_fragments(self): tfl = TextFile() tfl.set_language(self.TTS_LANGUAGE) self.synthesize(tfl, expected_exc=ValueError)
def main(): """ Entry point """ if len(sys.argv) < 5: usage() return language = sys.argv[1] text_file_path = sys.argv[2] text_format = sys.argv[3] audio_file_path = sys.argv[-1] backwards = False quit_after = None parameters = {} for i in range(4, len(sys.argv) - 1): args = sys.argv[i].split("=") if len(args) == 1: backwards = (args[0] in ["b", "-b", "backwards", "--backwards"]) if len(args) == 2: key, value = args if key == "id_regex": parameters[gc.PPN_JOB_IS_TEXT_UNPARSED_ID_REGEX] = value if key == "class_regex": parameters[gc.PPN_JOB_IS_TEXT_UNPARSED_CLASS_REGEX] = value if key == "sort": parameters[gc.PPN_JOB_IS_TEXT_UNPARSED_ID_SORT] = value if (key == "start") or (key == "end"): try: parameters[key] = int(value) except: pass if key == "quit_after": quit_after = float(value) if text_format == "list": text_file = TextFile() text_file.read_from_list(text_file_path.split("|")) else: text_file = TextFile(text_file_path, text_format, parameters) text_file.set_language(language) start_fragment = None if "start" in parameters: start_fragment = parameters["start"] end_fragment = None if "end" in parameters: end_fragment = parameters["end"] print "[INFO] Read input text file with %d fragments" % (len(text_file)) if start_fragment is not None: print "[INFO] Slicing from index %d" % (start_fragment) if end_fragment is not None: print "[INFO] Slicing to index %d" % (end_fragment) text_slice = text_file.get_slice(start_fragment, end_fragment) print "[INFO] Synthesizing %d fragments" % (len(text_slice)) if quit_after is not None: print "[INFO] Stop synthesizing after reaching %.3f seconds" % ( quit_after) if backwards: print "[INFO] Synthesizing backwards" synt = Synthesizer() synt.synthesize(text_slice, audio_file_path, quit_after, backwards) print "[INFO] Created file '%s'" % audio_file_path
class Task(Loggable): """ A structure representing a task, that is, an audio file and an ordered set of text fragments to be synchronized. :param string config_string: the task configuration string :param rconf: a runtime configuration :type rconf: :class:`~aeneas.runtimeconfiguration.RuntimeConfiguration` :param logger: the logger object :type logger: :class:`~aeneas.logger.Logger` :raises: TypeError: if ``config_string`` is not ``None`` and it is not a Unicode string """ TAG = u"Task" def __init__(self, config_string=None, rconf=None, logger=None): super(Task, self).__init__(rconf=rconf, logger=logger) self.identifier = gf.uuid_string() self.configuration = None self.audio_file_path = None # relative to input container root self.audio_file_path_absolute = None # concrete path, file will be read from this! self.audio_file = None self.text_file_path = None # relative to input container root self.text_file_path_absolute = None # concrete path, file will be read from this! self.text_file = None self.sync_map_file_path = None # relative to output container root self.sync_map_file_path_absolute = None # concrete path, file will be written to this! self.sync_map = None if config_string is not None: self.configuration = TaskConfiguration(config_string) def __unicode__(self): msg = [ u"%s: '%s'" % (gc.RPN_TASK_IDENTIFIER, self.identifier), u"Configuration:\n%s" % self.configuration.__unicode__(), u"Audio file path: %s" % self.audio_file_path, u"Audio file path (absolute): %s" % self.audio_file_path_absolute, u"Text file path: %s" % self.text_file_path, u"Text file path (absolute): %s" % self.text_file_path_absolute, u"Sync map file path: %s" % self.sync_map_file_path, u"Sync map file path (absolute): %s" % self.sync_map_file_path_absolute ] return u"\n".join(msg) def __str__(self): return gf.safe_str(self.__unicode__()) @property def identifier(self): """ The identifier of the task. :rtype: string """ return self.__identifier @identifier.setter def identifier(self, value): self.__identifier = value @property def audio_file_path_absolute(self): """ The absolute path of the audio file. :rtype: string """ return self.__audio_file_path_absolute @audio_file_path_absolute.setter def audio_file_path_absolute(self, audio_file_path_absolute): self.__audio_file_path_absolute = audio_file_path_absolute self._populate_audio_file() @property def text_file_path_absolute(self): """ The absolute path of the text file. :rtype: string """ return self.__text_file_path_absolute @text_file_path_absolute.setter def text_file_path_absolute(self, text_file_path_absolute): self.__text_file_path_absolute = text_file_path_absolute self._populate_text_file() @property def sync_map_file_path_absolute(self): """ The absolute path of the sync map file. :rtype: string """ return self.__sync_map_file_path_absolute @sync_map_file_path_absolute.setter def sync_map_file_path_absolute(self, sync_map_file_path_absolute): self.__sync_map_file_path_absolute = sync_map_file_path_absolute def sync_map_leaves(self, fragment_type=None): """ Return the list of non-empty leaves in the sync map associated with the task. If ``fragment_type`` has been specified, return only leaves of that fragment type. :param int fragment_type: type of fragment to return :rtype: list .. versionadded:: 1.7.0 """ if (self.sync_map is None) or (self.sync_map.fragments_tree is None): return [] return [f for f in self.sync_map.leaves(fragment_type)] def output_sync_map_file(self, container_root_path=None): """ Output the sync map file for this task. If ``container_root_path`` is specified, the output sync map file will be created at the path obtained by joining the ``container_root_path`` and the relative path of the sync map inside the container. Otherwise, the sync map file will be created at the path ``self.sync_map_file_path_absolute``. Return the the path of the sync map file created, or ``None`` if an error occurred. :param string container_root_path: the path to the root directory for the output container :rtype: string """ if self.sync_map is None: self.log_exc(u"The sync_map object has not been set", None, True, TypeError) if (container_root_path is not None) and (self.sync_map_file_path is None): self.log_exc(u"The (internal) path of the sync map has been set", None, True, TypeError) self.log([u"container_root_path is %s", container_root_path]) self.log([u"self.sync_map_file_path is %s", self.sync_map_file_path]) self.log([ u"self.sync_map_file_path_absolute is %s", self.sync_map_file_path_absolute ]) if (container_root_path is not None) and (self.sync_map_file_path is not None): path = os.path.join(container_root_path, self.sync_map_file_path) elif self.sync_map_file_path_absolute: path = self.sync_map_file_path_absolute gf.ensure_parent_directory(path) self.log([u"Output sync map to %s", path]) eaf_audio_ref = self.configuration["o_eaf_audio_ref"] head_tail_format = self.configuration["o_h_t_format"] levels = self.configuration["o_levels"] smil_audio_ref = self.configuration["o_smil_audio_ref"] smil_page_ref = self.configuration["o_smil_page_ref"] sync_map_format = self.configuration["o_format"] self.log([u"eaf_audio_ref is %s", eaf_audio_ref]) self.log([u"head_tail_format is %s", head_tail_format]) self.log([u"levels is %s", levels]) self.log([u"smil_audio_ref is %s", smil_audio_ref]) self.log([u"smil_page_ref is %s", smil_page_ref]) self.log([u"sync_map_format is %s", sync_map_format]) self.log(u"Calling sync_map.write...") parameters = { gc.PPN_TASK_OS_FILE_EAF_AUDIO_REF: eaf_audio_ref, gc.PPN_TASK_OS_FILE_HEAD_TAIL_FORMAT: head_tail_format, gc.PPN_TASK_OS_FILE_LEVELS: levels, gc.PPN_TASK_OS_FILE_SMIL_AUDIO_REF: smil_audio_ref, gc.PPN_TASK_OS_FILE_SMIL_PAGE_REF: smil_page_ref, } self.sync_map.write(sync_map_format, path, parameters) self.log(u"Calling sync_map.write... done") return path def _populate_audio_file(self): """ Create the ``self.audio_file`` object by reading the audio file at ``self.audio_file_path_absolute``. """ self.log(u"Populate audio file...") if self.audio_file_path_absolute is not None: self.log([ u"audio_file_path_absolute is '%s'", self.audio_file_path_absolute ]) self.audio_file = AudioFile( file_path=self.audio_file_path_absolute, logger=self.logger) self.audio_file.read_properties() else: self.log(u"audio_file_path_absolute is None") self.log(u"Populate audio file... done") def _populate_text_file(self): """ Create the ``self.text_file`` object by reading the text file at ``self.text_file_path_absolute``. """ self.log(u"Populate text file...") if ((self.text_file_path_absolute is not None) and (self.configuration["language"] is not None)): # the following values might be None parameters = { gc.PPN_TASK_IS_TEXT_FILE_IGNORE_REGEX: self.configuration["i_t_ignore_regex"], gc.PPN_TASK_IS_TEXT_FILE_TRANSLITERATE_MAP: self.configuration["i_t_transliterate_map"], gc.PPN_TASK_IS_TEXT_MPLAIN_WORD_SEPARATOR: self.configuration["i_t_mplain_word_separator"], gc.PPN_TASK_IS_TEXT_MUNPARSED_L1_ID_REGEX: self.configuration["i_t_munparsed_l1_id_regex"], gc.PPN_TASK_IS_TEXT_MUNPARSED_L2_ID_REGEX: self.configuration["i_t_munparsed_l2_id_regex"], gc.PPN_TASK_IS_TEXT_MUNPARSED_L3_ID_REGEX: self.configuration["i_t_munparsed_l3_id_regex"], gc.PPN_TASK_IS_TEXT_UNPARSED_CLASS_REGEX: self.configuration["i_t_unparsed_class_regex"], gc.PPN_TASK_IS_TEXT_UNPARSED_ID_REGEX: self.configuration["i_t_unparsed_id_regex"], gc.PPN_TASK_IS_TEXT_UNPARSED_ID_SORT: self.configuration["i_t_unparsed_id_sort"], gc.PPN_TASK_OS_FILE_ID_REGEX: self.configuration["o_id_regex"] } self.text_file = TextFile( file_path=self.text_file_path_absolute, file_format=self.configuration["i_t_format"], parameters=parameters, logger=self.logger) self.text_file.set_language(self.configuration["language"]) else: self.log(u"text_file_path_absolute and/or language is None") self.log(u"Populate text file... done")
class Task(Loggable): """ A structure representing a task, that is, an audio file and an ordered set of text fragments to be synchronized. :param string config_string: the task configuration string :param rconf: a runtime configuration :type rconf: :class:`~aeneas.runtimeconfiguration.RuntimeConfiguration` :param logger: the logger object :type logger: :class:`~aeneas.logger.Logger` :raises: TypeError: if ``config_string`` is not ``None`` and it is not a Unicode string """ TAG = u"Task" def __init__(self, config_string=None, rconf=None, logger=None): super(Task, self).__init__(rconf=rconf, logger=logger) self.identifier = gf.uuid_string() self.configuration = None self.audio_file_path = None # relative to input container root self.audio_file_path_absolute = None # concrete path, file will be read from this! self.audio_file = None self.text_file_path = None # relative to input container root self.text_file_path_absolute = None # concrete path, file will be read from this! self.text_file = None self.sync_map_file_path = None # relative to output container root self.sync_map_file_path_absolute = None # concrete path, file will be written to this! self.sync_map = None if config_string is not None: self.configuration = TaskConfiguration(config_string) def __unicode__(self): msg = [ u"%s: '%s'" % (gc.RPN_TASK_IDENTIFIER, self.identifier), u"Configuration:\n%s" % self.configuration.__unicode__(), u"Audio file path: %s" % self.audio_file_path, u"Audio file path (absolute): %s" % self.audio_file_path_absolute, u"Text file path: %s" % self.text_file_path, u"Text file path (absolute): %s" % self.text_file_path_absolute, u"Sync map file path: %s" % self.sync_map_file_path, u"Sync map file path (absolute): %s" % self.sync_map_file_path_absolute ] return u"\n".join(msg) def __str__(self): return gf.safe_str(self.__unicode__()) @property def identifier(self): """ The identifier of the task. :rtype: string """ return self.__identifier @identifier.setter def identifier(self, value): self.__identifier = value @property def audio_file_path_absolute(self): """ The absolute path of the audio file. :rtype: string """ return self.__audio_file_path_absolute @audio_file_path_absolute.setter def audio_file_path_absolute(self, audio_file_path_absolute): self.__audio_file_path_absolute = audio_file_path_absolute self._populate_audio_file() @property def text_file_path_absolute(self): """ The absolute path of the text file. :rtype: string """ return self.__text_file_path_absolute @text_file_path_absolute.setter def text_file_path_absolute(self, text_file_path_absolute): self.__text_file_path_absolute = text_file_path_absolute self._populate_text_file() @property def sync_map_file_path_absolute(self): """ The absolute path of the sync map file. :rtype: string """ return self.__sync_map_file_path_absolute @sync_map_file_path_absolute.setter def sync_map_file_path_absolute(self, sync_map_file_path_absolute): self.__sync_map_file_path_absolute = sync_map_file_path_absolute def output_sync_map_file(self, container_root_path=None): """ Output the sync map file for this task. If ``container_root_path`` is specified, the output sync map file will be created at the path obtained by joining the ``container_root_path`` and the relative path of the sync map inside the container. Otherwise, the sync map file will be created at the path ``self.sync_map_file_path_absolute``. Return the the path of the sync map file created, or ``None`` if an error occurred. :param string container_root_path: the path to the root directory for the output container :rtype: string """ if self.sync_map is None: self.log_exc(u"The sync_map object has not been set", None, True, TypeError) if (container_root_path is not None) and (self.sync_map_file_path is None): self.log_exc(u"The (internal) path of the sync map has been set", None, True, TypeError) self.log([u"container_root_path is %s", container_root_path]) self.log([u"self.sync_map_file_path is %s", self.sync_map_file_path]) self.log([u"self.sync_map_file_path_absolute is %s", self.sync_map_file_path_absolute]) if (container_root_path is not None) and (self.sync_map_file_path is not None): path = os.path.join(container_root_path, self.sync_map_file_path) elif self.sync_map_file_path_absolute: path = self.sync_map_file_path_absolute gf.ensure_parent_directory(path) self.log([u"Output sync map to %s", path]) sync_map_format = self.configuration["o_format"] audio_ref = self.configuration["o_smil_audio_ref"] page_ref = self.configuration["o_smil_page_ref"] self.log([u"sync_map_format is %s", sync_map_format]) self.log([u"page_ref is %s", page_ref]) self.log([u"audio_ref is %s", audio_ref]) self.log(u"Calling sync_map.write...") afpa = self.audio_file_path_absolute if afpa is not None: afpa = os.path.abspath(afpa) parameters = { "audio_file_path_absolute": afpa, gc.PPN_TASK_OS_FILE_SMIL_PAGE_REF : page_ref, gc.PPN_TASK_OS_FILE_SMIL_AUDIO_REF : audio_ref } self.sync_map.write(sync_map_format, path, parameters) self.log(u"Calling sync_map.write... done") return path def _populate_audio_file(self): """ Create the ``self.audio_file`` object by reading the audio file at ``self.audio_file_path_absolute``. """ self.log(u"Populate audio file...") if self.audio_file_path_absolute is not None: self.log([u"audio_file_path_absolute is '%s'", self.audio_file_path_absolute]) self.audio_file = AudioFile( file_path=self.audio_file_path_absolute, logger=self.logger ) self.audio_file.read_properties() else: self.log(u"audio_file_path_absolute is None") self.log(u"Populate audio file... done") def _populate_text_file(self): """ Create the ``self.text_file`` object by reading the text file at ``self.text_file_path_absolute``. """ self.log(u"Populate text file...") if ( (self.text_file_path_absolute is not None) and (self.configuration["language"] is not None) ): # the following values might be None parameters = { gc.PPN_TASK_IS_TEXT_FILE_IGNORE_REGEX : self.configuration["i_t_ignore_regex"], gc.PPN_TASK_IS_TEXT_FILE_TRANSLITERATE_MAP : self.configuration["i_t_transliterate_map"], gc.PPN_TASK_IS_TEXT_MPLAIN_WORD_SEPARATOR : self.configuration["i_t_mplain_word_separator"], gc.PPN_TASK_IS_TEXT_MUNPARSED_L1_ID_REGEX : self.configuration["i_t_munparsed_l1_id_regex"], gc.PPN_TASK_IS_TEXT_MUNPARSED_L2_ID_REGEX : self.configuration["i_t_munparsed_l2_id_regex"], gc.PPN_TASK_IS_TEXT_MUNPARSED_L3_ID_REGEX : self.configuration["i_t_munparsed_l3_id_regex"], gc.PPN_TASK_IS_TEXT_UNPARSED_CLASS_REGEX : self.configuration["i_t_unparsed_class_regex"], gc.PPN_TASK_IS_TEXT_UNPARSED_ID_REGEX : self.configuration["i_t_unparsed_id_regex"], gc.PPN_TASK_IS_TEXT_UNPARSED_ID_SORT : self.configuration["i_t_unparsed_id_sort"], gc.PPN_TASK_OS_FILE_ID_REGEX : self.configuration["o_id_regex"] } self.text_file = TextFile( file_path=self.text_file_path_absolute, file_format=self.configuration["i_t_format"], parameters=parameters, logger=self.logger ) self.text_file.set_language(self.configuration["language"]) else: self.log(u"text_file_path_absolute and/or language is None") self.log(u"Populate text file... done")
def test_multiple_no_fragments(self): tfl = TextFile() tfl.set_language(ESPEAKWrapper.ENG) with self.assertRaises(ValueError): self.synthesize_multiple(tfl)
def test_constructor(self): tfl = TextFile() self.assertEqual(len(tfl), 0)
def test_file_path_not_existing(self): with self.assertRaises(OSError): tfl = TextFile(file_path=self.NOT_EXISTING_PATH)
def tfl(self, frags): tfl = TextFile() for language, lines in frags: tfl.add_fragment(TextFragment(language=language, lines=lines, filtered_lines=lines)) return tfl
def test_synthesize_path_not_writeable(self): tfl = TextFile() synth = Synthesizer() with self.assertRaises(OSError): synth.synthesize(tfl, self.PATH_NOT_WRITEABLE)