From 3f509664b68cc611e71c6795dc23d4e87c2c008c Mon Sep 17 00:00:00 2001 From: SoulMelody Date: Mon, 22 Jan 2024 10:57:56 +0800 Subject: [PATCH] update vocaloid phoneme parsers --- libresvip/plugins/svip/binsvip_generator.py | 3 +-- libresvip/plugins/vpr/vpr_parser.py | 2 +- libresvip/plugins/vsq/options.py | 12 ++++++++++++ libresvip/plugins/vsq/vsq_parser.py | 14 +++++++++++--- libresvip/plugins/vsqx/vsqx_parser.py | 2 +- 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/libresvip/plugins/svip/binsvip_generator.py b/libresvip/plugins/svip/binsvip_generator.py index 16975d752..c2c4b60c4 100644 --- a/libresvip/plugins/svip/binsvip_generator.py +++ b/libresvip/plugins/svip/binsvip_generator.py @@ -175,13 +175,12 @@ def generate_note(self, note: Note) -> XSNote: value=svip_note_head_tags.get(note.head_tag, XSNoteHeadTagEnum.NoTag) ), lyric=note.lyric or DEFAULT_CHINESE_LYRIC, + pronouncing=note.pronunciation or "", ) xs_note.width_pos = ( round(self.synchronizer.get_actual_ticks_from_ticks(note.end_pos)) - xs_note.start_pos ) - if note.pronunciation: - xs_note.pronouncing = note.pronunciation if note.edited_phones is not None: xs_note.note_phone_info = self.generate_phones(note.edited_phones) if note.vibrato is not None: diff --git a/libresvip/plugins/vpr/vpr_parser.py b/libresvip/plugins/vpr/vpr_parser.py index 819dced3e..3384b2ba2 100644 --- a/libresvip/plugins/vpr/vpr_parser.py +++ b/libresvip/plugins/vpr/vpr_parser.py @@ -140,7 +140,7 @@ def parse_notes(self, notes: list[VocaloidNotes], pos: int, default_lyric: str) length=note.duration, key_number=note.number, lyric=note.lyric or default_lyric, - pronunciation=note.phoneme, + pronunciation=None, ) for note in notes ] diff --git a/libresvip/plugins/vsq/options.py b/libresvip/plugins/vsq/options.py index 63d633ea7..24c5fa0d8 100644 --- a/libresvip/plugins/vsq/options.py +++ b/libresvip/plugins/vsq/options.py @@ -1,12 +1,24 @@ +from enum import Enum +from typing import Annotated + from pydantic import BaseModel, Field +class BreathOption(Enum): + IGNORE: Annotated[str, Field(title="Ignore all breath notes")] = "ignore" + KEEP: Annotated[str, Field(title="Keep as normal notes")] = "keep" + + class InputOptions(BaseModel): lyric_encoding: str = Field( default="shift-jis", title="Lyric text encoding", description="Unless the lyrics are garbled, this option should not be changed.", ) + breath: BreathOption = Field( + default=BreathOption.IGNORE, + title="The way to handle breath notes", + ) class OutputOptions(BaseModel): diff --git a/libresvip/plugins/vsq/vsq_parser.py b/libresvip/plugins/vsq/vsq_parser.py index 36600db20..00818d78e 100644 --- a/libresvip/plugins/vsq/vsq_parser.py +++ b/libresvip/plugins/vsq/vsq_parser.py @@ -1,6 +1,7 @@ import configparser import dataclasses import math +import re from typing import Optional import mido_fix as mido @@ -16,13 +17,15 @@ TimeSignature, ) -from .options import InputOptions +from .options import BreathOption, InputOptions from .vocaloid_pitch import ( ControllerEvent, VocaloidPartPitchData, pitch_from_vocaloid_parts, ) +BREATH_PATTERN = re.compile("br[1-5]") + @dataclasses.dataclass class VsqParser: @@ -188,16 +191,21 @@ def parse_notes(self, vsq_track: configparser.ConfigParser, tick_prefix: int) -> if vsq_note["type"] == "Anote": if (length := vsq_note.getint("length")) and (key := vsq_note.getint("note#")): lyric_handle = vsq_note.get("lyrichandle", fallback="") - lyric_value, xsampa_value = vsq_track.get( + lyric_value, phoneme_value = vsq_track.get( lyric_handle, "L0", fallback="," ).split(",")[:2] + if ( + self.options.breath == BreathOption.IGNORE + and BREATH_PATTERN.fullmatch(phoneme_value.strip('"')) is not None + ): + continue notes.append( Note( start_pos=tick, length=length, key_number=key, lyric=lyric_value.strip('"'), - pronunciation=xsampa_value.strip('"'), + pronunciation=None, ) ) return notes diff --git a/libresvip/plugins/vsqx/vsqx_parser.py b/libresvip/plugins/vsqx/vsqx_parser.py index c5adb8dc9..8711b4809 100644 --- a/libresvip/plugins/vsqx/vsqx_parser.py +++ b/libresvip/plugins/vsqx/vsqx_parser.py @@ -126,7 +126,7 @@ def parse_notes(self, notes: list[VsqxNote], tick_offset: int) -> list[Note]: start_pos=note.pos_tick + tick_offset, length=note.dur_tick, lyric=note.lyric or DEFAULT_ENGLISH_LYRIC, - pronunciation=note.phnms.value if note.phnms is not None else None, + pronunciation=None, key_number=note.note_num, ) for note in notes