diff --git a/notebook/yohane.ipynb b/notebook/yohane.ipynb index a0e5781b..e574b880 100644 --- a/notebook/yohane.ipynb +++ b/notebook/yohane.ipynb @@ -167,7 +167,7 @@ "outputs": [], "source": [ "# @title Generate\n", - "# @markdown **Replace the song filename here if you uploaded it manually**\n", + "# @markdown **Replace the song filename here if you uploaded it manually, and don't forget to change the language of the song.**\n", "\n", "import logging\n", "from pathlib import Path\n", @@ -176,10 +176,11 @@ "logging.basicConfig(level=\"INFO\", force=True)\n", "\n", "song_filename = \"song\" # @param {type:\"string\"}\n", + "language = \"jp\" # @param {type: \"string\"}\n", "\n", "yohane = Yohane(vocals_extractor)\n", "yohane.load_song(Path(song_filename))\n", - "yohane.load_lyrics(lyrics_area.value)\n", + "yohane.load_lyrics(lyrics_area.value, language)\n", "yohane.extract_vocals()\n", "yohane.force_align()\n", "subs = yohane.make_subs()\n" @@ -236,7 +237,7 @@ }, "language_info": { "name": "python", - "version": "3.11.6" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/poetry.lock b/poetry.lock index 3fac5e17..8f029c91 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "audioread" @@ -1262,6 +1262,21 @@ files = [ [package.extras] diagrams = ["jinja2", "railroad-diagrams"] +[[package]] +name = "pyphen" +version = "0.14.0" +description = "Pure Python module to hyphenate text" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyphen-0.14.0-py3-none-any.whl", hash = "sha256:414c9355958ca3c6a3ff233f65678c245b8ecb56418fb291e2b93499d61cd510"}, + {file = "pyphen-0.14.0.tar.gz", hash = "sha256:596c8b3be1c1a70411ba5f6517d9ccfe3083c758ae2b94a45f2707346d8e66fa"}, +] + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["flake8", "isort", "pytest"] + [[package]] name = "pyright" version = "1.1.345" @@ -1872,4 +1887,4 @@ torch = ["torch", "torchaudio"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "52b1003ed855784cd5ddad613ac87a5209c725f71100ba1c711e96ee1ba0b17e" +content-hash = "2508028ca3abc143df9678d677c97a6b530e51b58f1958c5b949598d4c1e2913" diff --git a/pyproject.toml b/pyproject.toml index 83c7fcb4..796dbc97 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,7 @@ vocal-remover = {git = "https://github.com/Japan7/vocal-remover.git", rev = "24f pysubs2 = "^1.6.1" regex = "^2023.10.3" click = "^8.1.7" +pyphen = "^0.14.0" [tool.poetry.extras] torch = ["torch", "torchaudio"] diff --git a/yohane/__main__.py b/yohane/__main__.py index 8d85d46e..15bad29d 100644 --- a/yohane/__main__.py +++ b/yohane/__main__.py @@ -5,6 +5,7 @@ import click import torchaudio +from pyphen import LANGUAGES from yohane.audio import ( HybridDemucsVocalsExtractor, @@ -46,7 +47,14 @@ show_default=True, help="Vocals extractor to use. 'None' to disable.", ) -def cli(song_file: Path, lyrics_file: TextIOWrapper, vocals_extractor: str): +@click.option( + "-l", + "--language", + type=click.Choice(list(LANGUAGES.keys()) + ["jp"], case_sensitive=False), + default="jp", + help="Language of the lyrics from the available LibreOffice dictionaries. Default is Japanese (jp)." +) +def cli(song_file: Path, lyrics_file: TextIOWrapper, vocals_extractor: str, language: str): logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO").upper()) extractor_cls = CLI_VOCALS_EXTRACTORS_OPTS[vocals_extractor] @@ -55,7 +63,7 @@ def cli(song_file: Path, lyrics_file: TextIOWrapper, vocals_extractor: str): yohane = Yohane(extractor) yohane.load_song(song_file) - yohane.load_lyrics(lyrics_file.read()) + yohane.load_lyrics(lyrics_file.read(), language) yohane.extract_vocals() if yohane.vocals is not None: diff --git a/yohane/lyrics.py b/yohane/lyrics.py index 2616ab35..74104140 100644 --- a/yohane/lyrics.py +++ b/yohane/lyrics.py @@ -2,11 +2,12 @@ from functools import cached_property import regex as re - +import pyphen @dataclass class _Text: raw: str + language: str @cached_property def normalized(self): @@ -21,21 +22,28 @@ def transcript(self): class Lyrics(_Text): @cached_property def lines(self): - return [Line(line) for line in filter(None, self.raw.splitlines())] + return [Line(line, self.language) for line in filter(None, self.raw.splitlines())] @dataclass class Line(_Text): @cached_property def words(self): - return [Word(word) for word in filter(None, self.transcript)] + return [Word(word, self.language) for word in filter(None, self.transcript)] @dataclass class Word(_Text): @cached_property def syllables(self): - return auto_split(self.normalized) + res = self.normalized + if self.language == 'jp': + res = auto_split(res) + else: + dic = pyphen.Pyphen(lang=self.language) + res = dic.inserted(res) + res = res.split("-") + return res def normalize_uroman(text: str): diff --git a/yohane/pipeline.py b/yohane/pipeline.py index 08d29d64..6fba054b 100644 --- a/yohane/pipeline.py +++ b/yohane/pipeline.py @@ -34,9 +34,9 @@ def extract_vocals(self): assert self.song self.vocals = self.vocals_extractor(*self.song) - def load_lyrics(self, lyrics_str: str): + def load_lyrics(self, lyrics_str: str, language: str): logger.info("Loading lyrics") - self.lyrics = Lyrics(lyrics_str) + self.lyrics = Lyrics(lyrics_str, language) def force_align(self): logger.info("Computing forced alignment")