From e860931399947d929376ce0368e8989ae8e33510 Mon Sep 17 00:00:00 2001 From: sabonerune <102559104+sabonerune@users.noreply.github.com> Date: Fri, 5 Jan 2024 01:08:48 +0900 Subject: [PATCH 1/8] =?UTF-8?q?TYP:=20numpy=E3=81=AE=E5=9E=8B=E6=83=85?= =?UTF-8?q?=E5=A0=B1=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- voicevox_engine/core_adapter.py | 49 +++++---- voicevox_engine/core_wrapper.py | 62 ++++++----- voicevox_engine/dev/core/mock.py | 17 +-- voicevox_engine/dev/tts_engine/mock.py | 11 +- voicevox_engine/morphing.py | 26 ++--- .../acoustic_feature_extractor.py | 7 +- voicevox_engine/tts_pipeline/tts_engine.py | 102 ++++++++++-------- .../utility/connect_base64_waves.py | 8 +- 8 files changed, 152 insertions(+), 130 deletions(-) diff --git a/voicevox_engine/core_adapter.py b/voicevox_engine/core_adapter.py index 1d9bc1ed6..692d3fa1a 100644 --- a/voicevox_engine/core_adapter.py +++ b/voicevox_engine/core_adapter.py @@ -1,7 +1,7 @@ import threading -import numpy -from numpy import ndarray +import numpy as np +import numpy.typing as npt from .core_wrapper import CoreWrapper, OldCoreError from .metas.Metas import StyleId @@ -67,55 +67,58 @@ def is_initialized_style_id_synthesis(self, style_id: StyleId) -> bool: return True # コアが古い場合はどうしようもないのでTrueを返す def safe_yukarin_s_forward( - self, phoneme_list_s: ndarray, style_id: StyleId - ) -> ndarray: + self, phoneme_list_s: npt.NDArray[np.integer], style_id: StyleId + ) -> npt.NDArray[np.float32]: # 「指定スタイルを初期化」「mutexによる安全性」「系列長・データ型に関するアダプター」を提供する self.initialize_style_id_synthesis(style_id, skip_reinit=True) with self.mutex: phoneme_length = self.core.yukarin_s_forward( length=len(phoneme_list_s), phoneme_list=phoneme_list_s, - style_id=numpy.array(style_id, dtype=numpy.int64).reshape(-1), + style_id=np.array(style_id, dtype=np.int64).reshape(-1), ) return phoneme_length def safe_yukarin_sa_forward( self, - vowel_phoneme_list: ndarray, - consonant_phoneme_list: ndarray, - start_accent_list: ndarray, - end_accent_list: ndarray, - start_accent_phrase_list: ndarray, - end_accent_phrase_list: ndarray, + vowel_phoneme_list: npt.NDArray[np.integer], + consonant_phoneme_list: npt.NDArray[np.integer], + start_accent_list: npt.NDArray[np.integer], + end_accent_list: npt.NDArray[np.integer], + start_accent_phrase_list: npt.NDArray[np.integer], + end_accent_phrase_list: npt.NDArray[np.integer], style_id: StyleId, - ) -> ndarray: + ) -> npt.NDArray[np.float32]: # 「指定スタイルを初期化」「mutexによる安全性」「系列長・データ型に関するアダプター」を提供する self.initialize_style_id_synthesis(style_id, skip_reinit=True) with self.mutex: f0_list = self.core.yukarin_sa_forward( length=vowel_phoneme_list.shape[0], - vowel_phoneme_list=vowel_phoneme_list[numpy.newaxis], - consonant_phoneme_list=consonant_phoneme_list[numpy.newaxis], - start_accent_list=start_accent_list[numpy.newaxis], - end_accent_list=end_accent_list[numpy.newaxis], - start_accent_phrase_list=start_accent_phrase_list[numpy.newaxis], - end_accent_phrase_list=end_accent_phrase_list[numpy.newaxis], - style_id=numpy.array(style_id, dtype=numpy.int64).reshape(-1), + vowel_phoneme_list=vowel_phoneme_list[np.newaxis], + consonant_phoneme_list=consonant_phoneme_list[np.newaxis], + start_accent_list=start_accent_list[np.newaxis], + end_accent_list=end_accent_list[np.newaxis], + start_accent_phrase_list=start_accent_phrase_list[np.newaxis], + end_accent_phrase_list=end_accent_phrase_list[np.newaxis], + style_id=np.array(style_id, dtype=np.int64).reshape(-1), )[0] return f0_list def safe_decode_forward( - self, phoneme: ndarray, f0: ndarray, style_id: StyleId - ) -> tuple[ndarray, int]: + self, + phoneme: npt.NDArray[np.floating], + f0: npt.NDArray[np.floating], + style_id: StyleId, + ) -> tuple[npt.NDArray[np.float32], int]: # 「指定スタイルを初期化」「mutexによる安全性」「系列長・データ型に関するアダプター」を提供する self.initialize_style_id_synthesis(style_id, skip_reinit=True) with self.mutex: wave = self.core.decode_forward( length=phoneme.shape[0], phoneme_size=phoneme.shape[1], - f0=f0[:, numpy.newaxis], + f0=f0[:, np.newaxis], phoneme=phoneme, - style_id=numpy.array(style_id, dtype=numpy.int64).reshape(-1), + style_id=np.array(style_id, dtype=np.int64).reshape(-1), ) sr_wave = self.default_sampling_rate return wave, sr_wave diff --git a/voicevox_engine/core_wrapper.py b/voicevox_engine/core_wrapper.py index 6ba4eeadc..61bd5a692 100644 --- a/voicevox_engine/core_wrapper.py +++ b/voicevox_engine/core_wrapper.py @@ -8,6 +8,7 @@ from typing import Literal import numpy as np +import numpy.typing as npt class OldCoreError(Exception): @@ -525,21 +526,24 @@ def metas(self) -> str: return self.core.metas().decode("utf-8") def yukarin_s_forward( - self, length: int, phoneme_list: np.ndarray, style_id: np.ndarray - ) -> np.ndarray: + self, + length: int, + phoneme_list: npt.NDArray[np.integer], + style_id: npt.NDArray[np.integer], + ) -> npt.NDArray[np.float32]: """ 音素列から、音素ごとの長さを求める関数 Parameters ---------- length : int 音素列の長さ - phoneme_list : np.ndarray + phoneme_list : npt.NDArray[np.integer] 音素列 - style_id : np.ndarray + style_id : npt.NDArray[np.integer] スタイル番号 Returns ------- - output : np.ndarray + output : npt.NDArray[np.float32] 音素ごとの長さ """ output = np.zeros((length,), dtype=np.float32) @@ -556,37 +560,37 @@ def yukarin_s_forward( def yukarin_sa_forward( self, length: int, - vowel_phoneme_list: np.ndarray, - consonant_phoneme_list: np.ndarray, - start_accent_list: np.ndarray, - end_accent_list: np.ndarray, - start_accent_phrase_list: np.ndarray, - end_accent_phrase_list: np.ndarray, - style_id: np.ndarray, - ) -> np.ndarray: + vowel_phoneme_list: npt.NDArray[np.integer], + consonant_phoneme_list: npt.NDArray[np.integer], + start_accent_list: npt.NDArray[np.integer], + end_accent_list: npt.NDArray[np.integer], + start_accent_phrase_list: npt.NDArray[np.integer], + end_accent_phrase_list: npt.NDArray[np.integer], + style_id: npt.NDArray[np.integer], + ) -> npt.NDArray[np.float32]: """ モーラごとの音素列とアクセント情報から、モーラごとの音高を求める関数 Parameters ---------- length : int モーラ列の長さ - vowel_phoneme_list : np.ndarray + vowel_phoneme_list : npt.NDArray[np.integer] 母音の音素列 - consonant_phoneme_list : np.ndarray + consonant_phoneme_list : npt.NDArray[np.integer] 子音の音素列 - start_accent_list : np.ndarray + start_accent_list : npt.NDArray[np.integer] アクセントの開始位置 - end_accent_list : np.ndarray + end_accent_list : npt.NDArray[np.integer] アクセントの終了位置 - start_accent_phrase_list : np.ndarray + start_accent_phrase_list : npt.NDArray[np.integer] アクセント句の開始位置 - end_accent_phrase_list : np.ndarray + end_accent_phrase_list : npt.NDArray[np.integer] アクセント句の終了位置 - style_id : np.ndarray + style_id : npt.NDArray[np.integer] スタイル番号 Returns ------- - output : np.ndarray + output : npt.NDArray[np.float32] モーラごとの音高 """ output = np.empty( @@ -615,10 +619,10 @@ def decode_forward( self, length: int, phoneme_size: int, - f0: np.ndarray, - phoneme: np.ndarray, - style_id: np.ndarray, - ) -> np.ndarray: + f0: npt.NDArray[np.floating], + phoneme: npt.NDArray[np.floating], + style_id: npt.NDArray[np.integer], + ) -> npt.NDArray[np.float32]: """ フレームごとの音素と音高から波形を求める関数 Parameters @@ -627,15 +631,15 @@ def decode_forward( フレームの長さ phoneme_size : int 音素の種類数 - f0 : np.ndarray + f0 : npt.NDArray[np.floating] フレームごとの音高 - phoneme : np.ndarray + phoneme : npt.NDArray[np.floating] フレームごとの音素 - style_id : np.ndarray + style_id : npt.NDArray[np.integer] スタイル番号 Returns ------- - output : np.ndarray + output : npt.NDArray[np.float32] 音声波形 """ diff --git a/voicevox_engine/dev/core/mock.py b/voicevox_engine/dev/core/mock.py index 31918e0f3..3aa2b7f4a 100644 --- a/voicevox_engine/dev/core/mock.py +++ b/voicevox_engine/dev/core/mock.py @@ -1,7 +1,8 @@ import json from pathlib import Path -import numpy +import numpy as np +import numpy.typing as npt from numpy import ndarray from ...core_wrapper import CoreWrapper @@ -65,13 +66,13 @@ def metas(self) -> str: def yukarin_s_forward( self, length: int, phoneme_list: ndarray, style_id: ndarray - ) -> ndarray: + ) -> npt.NDArray[np.floating]: """音素系列サイズ・音素ID系列・スタイルIDから音素長系列を生成する""" result = [] # mockとしての適当な処理、特に意味はない for i in range(length): result.append(round((phoneme_list[i] * 0.0625 + style_id).item(), 2)) - return numpy.array(result) + return np.array(result) def yukarin_sa_forward( self, @@ -83,7 +84,7 @@ def yukarin_sa_forward( start_accent_phrase_list: ndarray, end_accent_phrase_list: ndarray, style_id: ndarray, - ) -> ndarray: + ) -> npt.NDArray[np.floating]: """モーラ系列サイズ・母音系列・子音系列・アクセント位置・アクセント句区切り・スタイルIDからモーラ音高系列を生成する""" assert length > 1, "前後無音を必ず付与しなければならない" @@ -107,7 +108,7 @@ def yukarin_sa_forward( 2, ) ) - return numpy.array(result)[numpy.newaxis] + return np.array(result)[np.newaxis] def decode_forward( self, @@ -116,15 +117,15 @@ def decode_forward( f0: ndarray, phoneme: ndarray, style_id: ndarray, - ) -> ndarray: + ) -> npt.NDArray[np.floating]: """フレーム長・音素種類数・フレーム音高・フレーム音素onehot・スタイルIDからダミー音声波形を生成する""" # 入力値を反映し、長さが 256 倍であるダミー配列を出力する result: list[ndarray] = [] for i in range(length): result += [ - (f0[i, 0] * (numpy.where(phoneme[i] == 1)[0] / phoneme_size) + style_id) + (f0[i, 0] * (np.where(phoneme[i] == 1)[0] / phoneme_size) + style_id) ] * 256 - return numpy.array(result) + return np.array(result) def supported_devices(self): return json.dumps( diff --git a/voicevox_engine/dev/tts_engine/mock.py b/voicevox_engine/dev/tts_engine/mock.py index c91e06aa6..4ba8cc655 100644 --- a/voicevox_engine/dev/tts_engine/mock.py +++ b/voicevox_engine/dev/tts_engine/mock.py @@ -1,8 +1,9 @@ import copy from logging import getLogger -from typing import Any, Dict +from typing import Any import numpy as np +import numpy.typing as npt from pyopenjtalk import tts from soxr import resample @@ -24,7 +25,7 @@ def synthesize_wave( query: AudioQuery, style_id: StyleId, enable_interrogative_upspeak: bool = True, - ) -> np.ndarray: + ) -> npt.NDArray[np.float64]: """音声合成用のクエリに含まれる読み仮名に基づいてOpenJTalkで音声波形を生成する""" # モーフィング時などに同一参照のqueryで複数回呼ばれる可能性があるので、元の引数のqueryに破壊的変更を行わない query = copy.deepcopy(query) @@ -38,9 +39,9 @@ def synthesize_wave( # volume wave *= query.volumeScale - return wave.astype("int16") + return wave - def forward(self, text: str, **kwargs: Dict[str, Any]) -> np.ndarray: + def forward(self, text: str, **kwargs: dict[str, Any]) -> npt.NDArray[np.float64]: """ forward tts via pyopenjtalk.tts() 参照→TTSEngine のdocstring [Mock] @@ -52,7 +53,7 @@ def forward(self, text: str, **kwargs: Dict[str, Any]) -> np.ndarray: Returns ------- - wave [npt.NDArray[np.int16]] + wave [npt.NDArray[np.float64]] 音声波形データをNumPy配列で返します Note diff --git a/voicevox_engine/morphing.py b/voicevox_engine/morphing.py index f94fbb061..9f9dfadbb 100644 --- a/voicevox_engine/morphing.py +++ b/voicevox_engine/morphing.py @@ -1,9 +1,9 @@ from copy import deepcopy from dataclasses import dataclass from itertools import chain -from typing import Dict, List, Tuple import numpy as np +import numpy.typing as npt import pyworld as pw from soxr import resample @@ -24,15 +24,15 @@ class MorphingParameter: fs: int frame_period: float - base_f0: np.ndarray - base_aperiodicity: np.ndarray - base_spectrogram: np.ndarray - target_spectrogram: np.ndarray + base_f0: npt.NDArray[np.double] + base_aperiodicity: npt.NDArray[np.double] + base_spectrogram: npt.NDArray[np.double] + target_spectrogram: npt.NDArray[np.double] def create_morphing_parameter( - base_wave: np.ndarray, - target_wave: np.ndarray, + base_wave: npt.NDArray[np.double], + target_wave: npt.NDArray[np.double], fs: int, ) -> MorphingParameter: frame_period = 1.0 @@ -55,9 +55,9 @@ def create_morphing_parameter( def get_morphable_targets( - speakers: List[Speaker], - base_style_ids: List[StyleId], -) -> List[Dict[StyleId, MorphableTargetInfo]]: + speakers: list[Speaker], + base_style_ids: list[StyleId], +) -> list[dict[StyleId, MorphableTargetInfo]]: """ speakers: 全話者の情報 base_speakers: モーフィング可能か判定したいベースのスタイルIDリスト @@ -81,7 +81,7 @@ def get_morphable_targets( def is_synthesis_morphing_permitted( - speaker_lookup: Dict[StyleId, Tuple[Speaker, SpeakerStyle]], + speaker_lookup: dict[StyleId, tuple[Speaker, SpeakerStyle]], base_style_id: StyleId, target_style_id: StyleId, ) -> bool: @@ -163,7 +163,7 @@ def synthesis_morphing( morph_rate: float, output_fs: int, output_stereo: bool = False, -) -> np.ndarray: +) -> npt.NDArray[np.float64]: """ 指定した割合で、パラメータをもとにモーフィングした音声を生成します。 @@ -178,7 +178,7 @@ def synthesis_morphing( Returns ------- - generated : np.ndarray + generated : npt.NDArray[np.float64] モーフィングした音声 Raises diff --git a/voicevox_engine/tts_pipeline/acoustic_feature_extractor.py b/voicevox_engine/tts_pipeline/acoustic_feature_extractor.py index a3e774ec4..72968593e 100644 --- a/voicevox_engine/tts_pipeline/acoustic_feature_extractor.py +++ b/voicevox_engine/tts_pipeline/acoustic_feature_extractor.py @@ -1,6 +1,7 @@ from typing import Literal -import numpy +import numpy as np +import numpy.typing as npt # NOTE: `Vowel` は母音 (a/i/u/e/o の有声・無声) + 無音 pau + 撥音 N ("ん") + 促音 cl ("っ") # NOTE: 型の名称は暫定的 @@ -121,8 +122,8 @@ def phoneme_id(self) -> int: return self._PHONEME_LIST.index(self.phoneme) @property - def onehot(self): + def onehot(self) -> npt.NDArray[np.float32]: """音素onehotベクトルを取得する""" - vec = numpy.zeros(self._NUM_PHONEME, dtype=numpy.float32) + vec = np.zeros(self._NUM_PHONEME, dtype=np.float32) vec[self.phoneme_id] = 1.0 return vec diff --git a/voicevox_engine/tts_pipeline/tts_engine.py b/voicevox_engine/tts_pipeline/tts_engine.py index 1e12eddd6..22f17c6f3 100644 --- a/voicevox_engine/tts_pipeline/tts_engine.py +++ b/voicevox_engine/tts_pipeline/tts_engine.py @@ -1,8 +1,9 @@ import copy import math +from typing import TypeVar -import numpy -from numpy import ndarray +import numpy as np +import numpy.typing as npt from soxr import resample from ..core_adapter import CoreAdapter @@ -131,7 +132,9 @@ def apply_speed_scale(moras: list[Mora], query: AudioQuery) -> list[Mora]: return moras -def count_frame_per_unit(moras: list[Mora]) -> tuple[ndarray, ndarray]: +def count_frame_per_unit( + moras: list[Mora], +) -> tuple[npt.NDArray[np.integer], npt.NDArray[np.integer]]: """ 音素あたり・モーラあたりのフレーム長を算出する Parameters @@ -140,9 +143,9 @@ def count_frame_per_unit(moras: list[Mora]) -> tuple[ndarray, ndarray]: モーラ系列 Returns ------- - frame_per_phoneme : ndarray + frame_per_phoneme : npt.NDArray[np.integer] 音素あたりのフレーム長。端数丸め。shape = (Phoneme,) - frame_per_mora : ndarray + frame_per_mora : npt.NDArray[np.integer] モーラあたりのフレーム長。端数丸め。shape = (Mora,) """ frame_per_phoneme: list[int] = [] @@ -159,13 +162,13 @@ def count_frame_per_unit(moras: list[Mora]) -> tuple[ndarray, ndarray]: frame_per_phoneme += [vowel_frames] frame_per_mora += [mora_frames] - return numpy.array(frame_per_phoneme), numpy.array(frame_per_mora) + return np.array(frame_per_phoneme), np.array(frame_per_mora) def _to_frame(sec: float) -> int: FRAMERATE = 93.75 # 24000 / 256 [frame/sec] # NOTE: `round` は偶数丸め。移植時に取扱い注意。詳細は voicevox_engine#552 - return numpy.round(sec * FRAMERATE).astype(numpy.int32).item() + return np.round(sec * FRAMERATE).astype(np.int32).item() def apply_pitch_scale(moras: list[Mora], query: AudioQuery) -> list[Mora]: @@ -179,22 +182,24 @@ def apply_intonation_scale(moras: list[Mora], query: AudioQuery) -> list[Mora]: """モーラ系列へ音声合成用のクエリがもつ抑揚スケール(`intonationScale`)を適用する""" # 有声音素 (f0>0) の平均値に対する乖離度をスケール voiced = list(filter(lambda mora: mora.pitch > 0, moras)) - mean_f0 = numpy.mean(list(map(lambda mora: mora.pitch, voiced))).item() + mean_f0 = np.mean(list(map(lambda mora: mora.pitch, voiced))).item() if mean_f0 != math.nan: # 空リスト -> NaN for mora in voiced: mora.pitch = (mora.pitch - mean_f0) * query.intonationScale + mean_f0 return moras -def apply_volume_scale(wave: numpy.ndarray, query: AudioQuery) -> numpy.ndarray: +def apply_volume_scale(wave: np.ndarray, query: AudioQuery) -> npt.NDArray[np.floating]: """音声波形へ音声合成用のクエリがもつ音量スケール(`volumeScale`)を適用する""" - wave *= query.volumeScale - return wave + return wave * query.volumeScale + + +_SoxrType = TypeVar("_SoxrType", np.float32, np.float64, np.int16, np.int32) def apply_output_sampling_rate( - wave: ndarray, sr_wave: int, query: AudioQuery -) -> ndarray: + wave: npt.NDArray[_SoxrType], sr_wave: float, query: AudioQuery +) -> npt.NDArray[_SoxrType]: """音声波形へ音声合成用のクエリがもつ出力サンプリングレート(`outputSamplingRate`)を適用する""" # サンプリングレート一致のときはスルー if sr_wave == query.outputSamplingRate: @@ -203,14 +208,19 @@ def apply_output_sampling_rate( return wave -def apply_output_stereo(wave: ndarray, query: AudioQuery) -> ndarray: +T = TypeVar("T", bound=np.generic) + + +def apply_output_stereo(wave: npt.NDArray[T], query: AudioQuery) -> npt.NDArray[T]: """音声波形へ音声合成用のクエリがもつステレオ出力設定(`outputStereo`)を適用する""" if query.outputStereo: - wave = numpy.array([wave, wave]).T + wave = np.array([wave, wave]).T return wave -def query_to_decoder_feature(query: AudioQuery) -> tuple[ndarray, ndarray]: +def query_to_decoder_feature( + query: AudioQuery, +) -> tuple[npt.NDArray[np.float32], npt.NDArray[np.float32]]: """音声合成用のクエリからフレームごとの音素 (shape=(フレーム長, 音素数)) と音高 (shape=(フレーム長,)) を得る""" moras = to_flatten_moras(query.accent_phrases) @@ -221,18 +231,20 @@ def query_to_decoder_feature(query: AudioQuery) -> tuple[ndarray, ndarray]: moras = apply_intonation_scale(moras, query) # 表現を変更する(音素クラス → 音素 onehot ベクトル、モーラクラス → 音高スカラ) - phoneme = numpy.stack([p.onehot for p in to_flatten_phonemes(moras)]) - f0 = numpy.array([mora.pitch for mora in moras], dtype=numpy.float32) + phoneme = np.stack([p.onehot for p in to_flatten_phonemes(moras)]) + f0 = np.array([mora.pitch for mora in moras], dtype=np.float32) # 時間スケールを変更する(音素・モーラ → フレーム) frame_per_phoneme, frame_per_mora = count_frame_per_unit(moras) - phoneme = numpy.repeat(phoneme, frame_per_phoneme, axis=0) - f0 = numpy.repeat(f0, frame_per_mora) + phoneme = np.repeat(phoneme, frame_per_phoneme, axis=0) + f0 = np.repeat(f0, frame_per_mora) return phoneme, f0 -def raw_wave_to_output_wave(query: AudioQuery, wave: ndarray, sr_wave: int) -> ndarray: +def raw_wave_to_output_wave( + query: AudioQuery, wave: np.ndarray, sr_wave: int +) -> npt.NDArray[np.floating]: """生音声波形に音声合成用のクエリを適用して出力音声波形を生成する""" wave = apply_volume_scale(wave, query) wave = apply_output_sampling_rate(wave, sr_wave, query) @@ -260,7 +272,7 @@ def update_length( phonemes = [Phoneme("pau")] + phonemes + [Phoneme("pau")] # 音素クラスから音素IDスカラへ表現を変換する - phoneme_ids = numpy.array([p.phoneme_id for p in phonemes], dtype=numpy.int64) + phoneme_ids = np.array([p.phoneme_id for p in phonemes], dtype=np.int64) # コアを用いて音素長を生成する phoneme_lengths = self._core.safe_yukarin_s_forward(phoneme_ids, style_id) @@ -287,9 +299,11 @@ def update_pitch( return [] # accent - def _create_one_hot(accent_phrase: AccentPhrase, position: int) -> ndarray: + def _create_one_hot( + accent_phrase: AccentPhrase, position: int + ) -> npt.NDArray[np.floating]: """ - 単位行列(numpy.eye)を応用し、accent_phrase内でone hotな配列(リスト)を作る + 単位行列(np.eye)を応用し、accent_phrase内でone hotな配列(リスト)を作る 例えば、accent_phraseのmorasの長さが12、positionが1なら [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] morasの長さが同じく12、positionが-1なら @@ -304,16 +318,16 @@ def _create_one_hot(accent_phrase: AccentPhrase, position: int) -> ndarray: one hotにするindex Returns ------- - one_hot : numpy.ndarray + one_hot : npt.NDArray[np.floating] one hotな配列(リスト) """ - return numpy.r_[ - numpy.eye(len(accent_phrase.moras))[position], + return np.r_[ + np.eye(len(accent_phrase.moras))[position], (0 if accent_phrase.pause_mora is not None else []), ] # アクセントの開始/終了位置リストを作る - start_accent_list = numpy.concatenate( + start_accent_list = np.concatenate( [ # accentはプログラミング言語におけるindexのように0始まりではなく1始まりなので、 # accentが1の場合は0番目を指定している @@ -322,7 +336,7 @@ def _create_one_hot(accent_phrase: AccentPhrase, position: int) -> ndarray: for accent_phrase in accent_phrases ] ) - end_accent_list = numpy.concatenate( + end_accent_list = np.concatenate( [ # accentはプログラミング言語におけるindexのように0始まりではなく1始まりなので、1を引いている _create_one_hot(accent_phrase, accent_phrase.accent - 1) @@ -331,35 +345,33 @@ def _create_one_hot(accent_phrase: AccentPhrase, position: int) -> ndarray: ) # アクセント句の開始/終了位置リストを作る - start_accent_phrase_list = numpy.concatenate( + start_accent_phrase_list = np.concatenate( [_create_one_hot(accent_phrase, 0) for accent_phrase in accent_phrases] ) - end_accent_phrase_list = numpy.concatenate( + end_accent_phrase_list = np.concatenate( [_create_one_hot(accent_phrase, -1) for accent_phrase in accent_phrases] ) # 前後無音を付加する - start_accent_list = numpy.r_[0, start_accent_list, 0] - end_accent_list = numpy.r_[0, end_accent_list, 0] - start_accent_phrase_list = numpy.r_[0, start_accent_phrase_list, 0] - end_accent_phrase_list = numpy.r_[0, end_accent_phrase_list, 0] + start_accent_list = np.r_[0, start_accent_list, 0] + end_accent_list = np.r_[0, end_accent_list, 0] + start_accent_phrase_list = np.r_[0, start_accent_phrase_list, 0] + end_accent_phrase_list = np.r_[0, end_accent_phrase_list, 0] # キャスト - start_accent_list = numpy.array(start_accent_list, dtype=numpy.int64) - end_accent_list = numpy.array(end_accent_list, dtype=numpy.int64) - start_accent_phrase_list = numpy.array( - start_accent_phrase_list, dtype=numpy.int64 - ) - end_accent_phrase_list = numpy.array(end_accent_phrase_list, dtype=numpy.int64) + start_accent_list = np.array(start_accent_list, dtype=np.int64) + end_accent_list = np.array(end_accent_list, dtype=np.int64) + start_accent_phrase_list = np.array(start_accent_phrase_list, dtype=np.int64) + end_accent_phrase_list = np.array(end_accent_phrase_list, dtype=np.int64) # アクセント句系列から(前後の無音含まない)モーラ系列と(前後の無音含む)音素系列を抽出する moras, phonemes = pre_process(accent_phrases) # 前後無音付加済みの音素系列から子音ID系列・母音ID系列を抽出する consonants, vowels = split_mora(phonemes) - vowel_ids = numpy.array([p.phoneme_id for p in vowels], dtype=numpy.int64) - consonant_ids = numpy.array( - [p.phoneme_id if p else -1 for p in consonants], dtype=numpy.int64 + vowel_ids = np.array([p.phoneme_id for p in vowels], dtype=np.int64) + consonant_ids = np.array( + [p.phoneme_id if p else -1 for p in consonants], dtype=np.int64 ) # コアを用いてモーラ音高を生成する @@ -411,7 +423,7 @@ def synthesize_wave( query: AudioQuery, style_id: StyleId, enable_interrogative_upspeak: bool = True, - ) -> ndarray: + ) -> npt.NDArray[np.floating]: """音声合成用のクエリ・スタイルID・疑問文語尾自動調整フラグに基づいて音声波形を生成する""" # モーフィング時などに同一参照のqueryで複数回呼ばれる可能性があるので、元の引数のqueryに破壊的変更を行わない query = copy.deepcopy(query) diff --git a/voicevox_engine/utility/connect_base64_waves.py b/voicevox_engine/utility/connect_base64_waves.py index 900211e3c..c17a58ded 100644 --- a/voicevox_engine/utility/connect_base64_waves.py +++ b/voicevox_engine/utility/connect_base64_waves.py @@ -1,8 +1,8 @@ import base64 import io -from typing import List, Tuple import numpy as np +import numpy.typing as npt import soundfile from soxr import resample @@ -12,7 +12,7 @@ def __init__(self, message: str): self.message = message -def decode_base64_waves(waves: List[str]) -> List[Tuple[np.ndarray, int]]: +def decode_base64_waves(waves: list[str]) -> list[tuple[npt.NDArray[np.float64], int]]: """ base64エンコードされた複数のwavデータをデコードする Parameters @@ -21,7 +21,7 @@ def decode_base64_waves(waves: List[str]) -> List[Tuple[np.ndarray, int]]: base64エンコードされたwavデータのリスト Returns ------- - waves_nparray_sr: List[Tuple[np.ndarray, int]] + waves_nparray_sr: List[Tuple[npt.NDArray[np.float64], int]] (NumPy配列の音声波形データ, サンプリングレート) 形式のタプルのリスト """ if len(waves) == 0: @@ -42,7 +42,7 @@ def decode_base64_waves(waves: List[str]) -> List[Tuple[np.ndarray, int]]: return waves_nparray_sr -def connect_base64_waves(waves: List[str]) -> Tuple[np.ndarray, int]: +def connect_base64_waves(waves: list[str]) -> tuple[npt.NDArray[np.float64], int]: waves_nparray_sr = decode_base64_waves(waves) max_sampling_rate = max([sr for _, sr in waves_nparray_sr]) From 28480d2ca7cd1226786c541a554418a568e52373 Mon Sep 17 00:00:00 2001 From: sabonerune <102559104+sabonerune@users.noreply.github.com> Date: Mon, 8 Jan 2024 00:16:16 +0900 Subject: [PATCH 2/8] =?UTF-8?q?FIX:=20mock=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- voicevox_engine/dev/tts_engine/mock.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/voicevox_engine/dev/tts_engine/mock.py b/voicevox_engine/dev/tts_engine/mock.py index 4ba8cc655..ce9ab50f1 100644 --- a/voicevox_engine/dev/tts_engine/mock.py +++ b/voicevox_engine/dev/tts_engine/mock.py @@ -25,7 +25,7 @@ def synthesize_wave( query: AudioQuery, style_id: StyleId, enable_interrogative_upspeak: bool = True, - ) -> npt.NDArray[np.float64]: + ) -> npt.NDArray[np.float32]: """音声合成用のクエリに含まれる読み仮名に基づいてOpenJTalkで音声波形を生成する""" # モーフィング時などに同一参照のqueryで複数回呼ばれる可能性があるので、元の引数のqueryに破壊的変更を行わない query = copy.deepcopy(query) @@ -41,7 +41,7 @@ def synthesize_wave( return wave - def forward(self, text: str, **kwargs: dict[str, Any]) -> npt.NDArray[np.float64]: + def forward(self, text: str, **kwargs: dict[str, Any]) -> npt.NDArray[np.float32]: """ forward tts via pyopenjtalk.tts() 参照→TTSEngine のdocstring [Mock] @@ -64,10 +64,11 @@ def forward(self, text: str, **kwargs: dict[str, Any]) -> npt.NDArray[np.float64 dtype=np.float64, 16 bit, mono 48000 Hz # resampleの説明 - 非モック実装(decode_forward)と合わせるために、出力を24kHzに変換した。 + 非モック実装(decode_forward)と合わせるために、出力を24kHz、32bit浮動小数に変換した。 """ logger = getLogger("uvicorn") # FastAPI / Uvicorn 内からの利用のため logger.info("[Mock] input text: %s" % text) wave, sr = tts(text) + wave /= 2**15 wave = resample(wave, 48000, 24000) - return wave + return wave.astype(np.float32) From 8912b0462b8aa8070fe65e5e13dde1c391005925 Mon Sep 17 00:00:00 2001 From: Hiroshiba Date: Mon, 8 Jan 2024 01:52:29 +0900 Subject: [PATCH 3/8] npt.NDArray -> NDArray --- voicevox_engine/core_adapter.py | 26 ++++---- voicevox_engine/core_wrapper.py | 62 +++++++++---------- voicevox_engine/dev/core/mock.py | 8 +-- voicevox_engine/dev/tts_engine/mock.py | 8 +-- voicevox_engine/morphing.py | 18 +++--- .../acoustic_feature_extractor.py | 4 +- voicevox_engine/tts_pipeline/tts_engine.py | 26 ++++---- .../utility/connect_base64_waves.py | 8 +-- 8 files changed, 80 insertions(+), 80 deletions(-) diff --git a/voicevox_engine/core_adapter.py b/voicevox_engine/core_adapter.py index 692d3fa1a..a11904551 100644 --- a/voicevox_engine/core_adapter.py +++ b/voicevox_engine/core_adapter.py @@ -1,7 +1,7 @@ import threading import numpy as np -import numpy.typing as npt +from numpy.typing import NDArray from .core_wrapper import CoreWrapper, OldCoreError from .metas.Metas import StyleId @@ -67,8 +67,8 @@ def is_initialized_style_id_synthesis(self, style_id: StyleId) -> bool: return True # コアが古い場合はどうしようもないのでTrueを返す def safe_yukarin_s_forward( - self, phoneme_list_s: npt.NDArray[np.integer], style_id: StyleId - ) -> npt.NDArray[np.float32]: + self, phoneme_list_s: NDArray[np.integer], style_id: StyleId + ) -> NDArray[np.float32]: # 「指定スタイルを初期化」「mutexによる安全性」「系列長・データ型に関するアダプター」を提供する self.initialize_style_id_synthesis(style_id, skip_reinit=True) with self.mutex: @@ -81,14 +81,14 @@ def safe_yukarin_s_forward( def safe_yukarin_sa_forward( self, - vowel_phoneme_list: npt.NDArray[np.integer], - consonant_phoneme_list: npt.NDArray[np.integer], - start_accent_list: npt.NDArray[np.integer], - end_accent_list: npt.NDArray[np.integer], - start_accent_phrase_list: npt.NDArray[np.integer], - end_accent_phrase_list: npt.NDArray[np.integer], + vowel_phoneme_list: NDArray[np.integer], + consonant_phoneme_list: NDArray[np.integer], + start_accent_list: NDArray[np.integer], + end_accent_list: NDArray[np.integer], + start_accent_phrase_list: NDArray[np.integer], + end_accent_phrase_list: NDArray[np.integer], style_id: StyleId, - ) -> npt.NDArray[np.float32]: + ) -> NDArray[np.float32]: # 「指定スタイルを初期化」「mutexによる安全性」「系列長・データ型に関するアダプター」を提供する self.initialize_style_id_synthesis(style_id, skip_reinit=True) with self.mutex: @@ -106,10 +106,10 @@ def safe_yukarin_sa_forward( def safe_decode_forward( self, - phoneme: npt.NDArray[np.floating], - f0: npt.NDArray[np.floating], + phoneme: NDArray[np.floating], + f0: NDArray[np.floating], style_id: StyleId, - ) -> tuple[npt.NDArray[np.float32], int]: + ) -> tuple[NDArray[np.float32], int]: # 「指定スタイルを初期化」「mutexによる安全性」「系列長・データ型に関するアダプター」を提供する self.initialize_style_id_synthesis(style_id, skip_reinit=True) with self.mutex: diff --git a/voicevox_engine/core_wrapper.py b/voicevox_engine/core_wrapper.py index 61bd5a692..c97646345 100644 --- a/voicevox_engine/core_wrapper.py +++ b/voicevox_engine/core_wrapper.py @@ -8,7 +8,7 @@ from typing import Literal import numpy as np -import numpy.typing as npt +from numpy.typing import NDArray class OldCoreError(Exception): @@ -528,22 +528,22 @@ def metas(self) -> str: def yukarin_s_forward( self, length: int, - phoneme_list: npt.NDArray[np.integer], - style_id: npt.NDArray[np.integer], - ) -> npt.NDArray[np.float32]: + phoneme_list: NDArray[np.integer], + style_id: NDArray[np.integer], + ) -> NDArray[np.float32]: """ 音素列から、音素ごとの長さを求める関数 Parameters ---------- length : int 音素列の長さ - phoneme_list : npt.NDArray[np.integer] + phoneme_list : NDArray[np.integer] 音素列 - style_id : npt.NDArray[np.integer] + style_id : NDArray[np.integer] スタイル番号 Returns ------- - output : npt.NDArray[np.float32] + output : NDArray[np.float32] 音素ごとの長さ """ output = np.zeros((length,), dtype=np.float32) @@ -560,37 +560,37 @@ def yukarin_s_forward( def yukarin_sa_forward( self, length: int, - vowel_phoneme_list: npt.NDArray[np.integer], - consonant_phoneme_list: npt.NDArray[np.integer], - start_accent_list: npt.NDArray[np.integer], - end_accent_list: npt.NDArray[np.integer], - start_accent_phrase_list: npt.NDArray[np.integer], - end_accent_phrase_list: npt.NDArray[np.integer], - style_id: npt.NDArray[np.integer], - ) -> npt.NDArray[np.float32]: + vowel_phoneme_list: NDArray[np.integer], + consonant_phoneme_list: NDArray[np.integer], + start_accent_list: NDArray[np.integer], + end_accent_list: NDArray[np.integer], + start_accent_phrase_list: NDArray[np.integer], + end_accent_phrase_list: NDArray[np.integer], + style_id: NDArray[np.integer], + ) -> NDArray[np.float32]: """ モーラごとの音素列とアクセント情報から、モーラごとの音高を求める関数 Parameters ---------- length : int モーラ列の長さ - vowel_phoneme_list : npt.NDArray[np.integer] + vowel_phoneme_list : NDArray[np.integer] 母音の音素列 - consonant_phoneme_list : npt.NDArray[np.integer] + consonant_phoneme_list : NDArray[np.integer] 子音の音素列 - start_accent_list : npt.NDArray[np.integer] + start_accent_list : NDArray[np.integer] アクセントの開始位置 - end_accent_list : npt.NDArray[np.integer] + end_accent_list : NDArray[np.integer] アクセントの終了位置 - start_accent_phrase_list : npt.NDArray[np.integer] + start_accent_phrase_list : NDArray[np.integer] アクセント句の開始位置 - end_accent_phrase_list : npt.NDArray[np.integer] + end_accent_phrase_list : NDArray[np.integer] アクセント句の終了位置 - style_id : npt.NDArray[np.integer] + style_id : NDArray[np.integer] スタイル番号 Returns ------- - output : npt.NDArray[np.float32] + output : NDArray[np.float32] モーラごとの音高 """ output = np.empty( @@ -619,10 +619,10 @@ def decode_forward( self, length: int, phoneme_size: int, - f0: npt.NDArray[np.floating], - phoneme: npt.NDArray[np.floating], - style_id: npt.NDArray[np.integer], - ) -> npt.NDArray[np.float32]: + f0: NDArray[np.floating], + phoneme: NDArray[np.floating], + style_id: NDArray[np.integer], + ) -> NDArray[np.float32]: """ フレームごとの音素と音高から波形を求める関数 Parameters @@ -631,15 +631,15 @@ def decode_forward( フレームの長さ phoneme_size : int 音素の種類数 - f0 : npt.NDArray[np.floating] + f0 : NDArray[np.floating] フレームごとの音高 - phoneme : npt.NDArray[np.floating] + phoneme : NDArray[np.floating] フレームごとの音素 - style_id : npt.NDArray[np.integer] + style_id : NDArray[np.integer] スタイル番号 Returns ------- - output : npt.NDArray[np.float32] + output : NDArray[np.float32] 音声波形 """ diff --git a/voicevox_engine/dev/core/mock.py b/voicevox_engine/dev/core/mock.py index 3aa2b7f4a..51b06db28 100644 --- a/voicevox_engine/dev/core/mock.py +++ b/voicevox_engine/dev/core/mock.py @@ -2,8 +2,8 @@ from pathlib import Path import numpy as np -import numpy.typing as npt from numpy import ndarray +from numpy.typing import NDArray from ...core_wrapper import CoreWrapper @@ -66,7 +66,7 @@ def metas(self) -> str: def yukarin_s_forward( self, length: int, phoneme_list: ndarray, style_id: ndarray - ) -> npt.NDArray[np.floating]: + ) -> NDArray[np.floating]: """音素系列サイズ・音素ID系列・スタイルIDから音素長系列を生成する""" result = [] # mockとしての適当な処理、特に意味はない @@ -84,7 +84,7 @@ def yukarin_sa_forward( start_accent_phrase_list: ndarray, end_accent_phrase_list: ndarray, style_id: ndarray, - ) -> npt.NDArray[np.floating]: + ) -> NDArray[np.floating]: """モーラ系列サイズ・母音系列・子音系列・アクセント位置・アクセント句区切り・スタイルIDからモーラ音高系列を生成する""" assert length > 1, "前後無音を必ず付与しなければならない" @@ -117,7 +117,7 @@ def decode_forward( f0: ndarray, phoneme: ndarray, style_id: ndarray, - ) -> npt.NDArray[np.floating]: + ) -> NDArray[np.floating]: """フレーム長・音素種類数・フレーム音高・フレーム音素onehot・スタイルIDからダミー音声波形を生成する""" # 入力値を反映し、長さが 256 倍であるダミー配列を出力する result: list[ndarray] = [] diff --git a/voicevox_engine/dev/tts_engine/mock.py b/voicevox_engine/dev/tts_engine/mock.py index ce9ab50f1..e23419381 100644 --- a/voicevox_engine/dev/tts_engine/mock.py +++ b/voicevox_engine/dev/tts_engine/mock.py @@ -3,7 +3,7 @@ from typing import Any import numpy as np -import numpy.typing as npt +from numpy.typing import NDArray from pyopenjtalk import tts from soxr import resample @@ -25,7 +25,7 @@ def synthesize_wave( query: AudioQuery, style_id: StyleId, enable_interrogative_upspeak: bool = True, - ) -> npt.NDArray[np.float32]: + ) -> NDArray[np.float32]: """音声合成用のクエリに含まれる読み仮名に基づいてOpenJTalkで音声波形を生成する""" # モーフィング時などに同一参照のqueryで複数回呼ばれる可能性があるので、元の引数のqueryに破壊的変更を行わない query = copy.deepcopy(query) @@ -41,7 +41,7 @@ def synthesize_wave( return wave - def forward(self, text: str, **kwargs: dict[str, Any]) -> npt.NDArray[np.float32]: + def forward(self, text: str, **kwargs: dict[str, Any]) -> NDArray[np.float32]: """ forward tts via pyopenjtalk.tts() 参照→TTSEngine のdocstring [Mock] @@ -53,7 +53,7 @@ def forward(self, text: str, **kwargs: dict[str, Any]) -> npt.NDArray[np.float32 Returns ------- - wave [npt.NDArray[np.float64]] + wave [NDArray[np.float64]] 音声波形データをNumPy配列で返します Note diff --git a/voicevox_engine/morphing.py b/voicevox_engine/morphing.py index 9f9dfadbb..6fe69c1cf 100644 --- a/voicevox_engine/morphing.py +++ b/voicevox_engine/morphing.py @@ -3,8 +3,8 @@ from itertools import chain import numpy as np -import numpy.typing as npt import pyworld as pw +from numpy.typing import NDArray from soxr import resample from .core_adapter import CoreAdapter @@ -24,15 +24,15 @@ class MorphingParameter: fs: int frame_period: float - base_f0: npt.NDArray[np.double] - base_aperiodicity: npt.NDArray[np.double] - base_spectrogram: npt.NDArray[np.double] - target_spectrogram: npt.NDArray[np.double] + base_f0: NDArray[np.double] + base_aperiodicity: NDArray[np.double] + base_spectrogram: NDArray[np.double] + target_spectrogram: NDArray[np.double] def create_morphing_parameter( - base_wave: npt.NDArray[np.double], - target_wave: npt.NDArray[np.double], + base_wave: NDArray[np.double], + target_wave: NDArray[np.double], fs: int, ) -> MorphingParameter: frame_period = 1.0 @@ -163,7 +163,7 @@ def synthesis_morphing( morph_rate: float, output_fs: int, output_stereo: bool = False, -) -> npt.NDArray[np.float64]: +) -> NDArray[np.float64]: """ 指定した割合で、パラメータをもとにモーフィングした音声を生成します。 @@ -178,7 +178,7 @@ def synthesis_morphing( Returns ------- - generated : npt.NDArray[np.float64] + generated : NDArray[np.float64] モーフィングした音声 Raises diff --git a/voicevox_engine/tts_pipeline/acoustic_feature_extractor.py b/voicevox_engine/tts_pipeline/acoustic_feature_extractor.py index 72968593e..6c861e16a 100644 --- a/voicevox_engine/tts_pipeline/acoustic_feature_extractor.py +++ b/voicevox_engine/tts_pipeline/acoustic_feature_extractor.py @@ -1,7 +1,7 @@ from typing import Literal import numpy as np -import numpy.typing as npt +from numpy.typing import NDArray # NOTE: `Vowel` は母音 (a/i/u/e/o の有声・無声) + 無音 pau + 撥音 N ("ん") + 促音 cl ("っ") # NOTE: 型の名称は暫定的 @@ -122,7 +122,7 @@ def phoneme_id(self) -> int: return self._PHONEME_LIST.index(self.phoneme) @property - def onehot(self) -> npt.NDArray[np.float32]: + def onehot(self) -> NDArray[np.float32]: """音素onehotベクトルを取得する""" vec = np.zeros(self._NUM_PHONEME, dtype=np.float32) vec[self.phoneme_id] = 1.0 diff --git a/voicevox_engine/tts_pipeline/tts_engine.py b/voicevox_engine/tts_pipeline/tts_engine.py index 22f17c6f3..a50bc4e6b 100644 --- a/voicevox_engine/tts_pipeline/tts_engine.py +++ b/voicevox_engine/tts_pipeline/tts_engine.py @@ -3,7 +3,7 @@ from typing import TypeVar import numpy as np -import numpy.typing as npt +from numpy.typing import NDArray from soxr import resample from ..core_adapter import CoreAdapter @@ -134,7 +134,7 @@ def apply_speed_scale(moras: list[Mora], query: AudioQuery) -> list[Mora]: def count_frame_per_unit( moras: list[Mora], -) -> tuple[npt.NDArray[np.integer], npt.NDArray[np.integer]]: +) -> tuple[NDArray[np.integer], NDArray[np.integer]]: """ 音素あたり・モーラあたりのフレーム長を算出する Parameters @@ -143,9 +143,9 @@ def count_frame_per_unit( モーラ系列 Returns ------- - frame_per_phoneme : npt.NDArray[np.integer] + frame_per_phoneme : NDArray[np.integer] 音素あたりのフレーム長。端数丸め。shape = (Phoneme,) - frame_per_mora : npt.NDArray[np.integer] + frame_per_mora : NDArray[np.integer] モーラあたりのフレーム長。端数丸め。shape = (Mora,) """ frame_per_phoneme: list[int] = [] @@ -189,7 +189,7 @@ def apply_intonation_scale(moras: list[Mora], query: AudioQuery) -> list[Mora]: return moras -def apply_volume_scale(wave: np.ndarray, query: AudioQuery) -> npt.NDArray[np.floating]: +def apply_volume_scale(wave: np.ndarray, query: AudioQuery) -> NDArray[np.floating]: """音声波形へ音声合成用のクエリがもつ音量スケール(`volumeScale`)を適用する""" return wave * query.volumeScale @@ -198,8 +198,8 @@ def apply_volume_scale(wave: np.ndarray, query: AudioQuery) -> npt.NDArray[np.fl def apply_output_sampling_rate( - wave: npt.NDArray[_SoxrType], sr_wave: float, query: AudioQuery -) -> npt.NDArray[_SoxrType]: + wave: NDArray[_SoxrType], sr_wave: float, query: AudioQuery +) -> NDArray[_SoxrType]: """音声波形へ音声合成用のクエリがもつ出力サンプリングレート(`outputSamplingRate`)を適用する""" # サンプリングレート一致のときはスルー if sr_wave == query.outputSamplingRate: @@ -211,7 +211,7 @@ def apply_output_sampling_rate( T = TypeVar("T", bound=np.generic) -def apply_output_stereo(wave: npt.NDArray[T], query: AudioQuery) -> npt.NDArray[T]: +def apply_output_stereo(wave: NDArray[T], query: AudioQuery) -> NDArray[T]: """音声波形へ音声合成用のクエリがもつステレオ出力設定(`outputStereo`)を適用する""" if query.outputStereo: wave = np.array([wave, wave]).T @@ -220,7 +220,7 @@ def apply_output_stereo(wave: npt.NDArray[T], query: AudioQuery) -> npt.NDArray[ def query_to_decoder_feature( query: AudioQuery, -) -> tuple[npt.NDArray[np.float32], npt.NDArray[np.float32]]: +) -> tuple[NDArray[np.float32], NDArray[np.float32]]: """音声合成用のクエリからフレームごとの音素 (shape=(フレーム長, 音素数)) と音高 (shape=(フレーム長,)) を得る""" moras = to_flatten_moras(query.accent_phrases) @@ -244,7 +244,7 @@ def query_to_decoder_feature( def raw_wave_to_output_wave( query: AudioQuery, wave: np.ndarray, sr_wave: int -) -> npt.NDArray[np.floating]: +) -> NDArray[np.floating]: """生音声波形に音声合成用のクエリを適用して出力音声波形を生成する""" wave = apply_volume_scale(wave, query) wave = apply_output_sampling_rate(wave, sr_wave, query) @@ -301,7 +301,7 @@ def update_pitch( # accent def _create_one_hot( accent_phrase: AccentPhrase, position: int - ) -> npt.NDArray[np.floating]: + ) -> NDArray[np.floating]: """ 単位行列(np.eye)を応用し、accent_phrase内でone hotな配列(リスト)を作る 例えば、accent_phraseのmorasの長さが12、positionが1なら @@ -318,7 +318,7 @@ def _create_one_hot( one hotにするindex Returns ------- - one_hot : npt.NDArray[np.floating] + one_hot : NDArray[np.floating] one hotな配列(リスト) """ return np.r_[ @@ -423,7 +423,7 @@ def synthesize_wave( query: AudioQuery, style_id: StyleId, enable_interrogative_upspeak: bool = True, - ) -> npt.NDArray[np.floating]: + ) -> NDArray[np.floating]: """音声合成用のクエリ・スタイルID・疑問文語尾自動調整フラグに基づいて音声波形を生成する""" # モーフィング時などに同一参照のqueryで複数回呼ばれる可能性があるので、元の引数のqueryに破壊的変更を行わない query = copy.deepcopy(query) diff --git a/voicevox_engine/utility/connect_base64_waves.py b/voicevox_engine/utility/connect_base64_waves.py index c17a58ded..287e14078 100644 --- a/voicevox_engine/utility/connect_base64_waves.py +++ b/voicevox_engine/utility/connect_base64_waves.py @@ -2,8 +2,8 @@ import io import numpy as np -import numpy.typing as npt import soundfile +from numpy.typing import NDArray from soxr import resample @@ -12,7 +12,7 @@ def __init__(self, message: str): self.message = message -def decode_base64_waves(waves: list[str]) -> list[tuple[npt.NDArray[np.float64], int]]: +def decode_base64_waves(waves: list[str]) -> list[tuple[NDArray[np.float64], int]]: """ base64エンコードされた複数のwavデータをデコードする Parameters @@ -21,7 +21,7 @@ def decode_base64_waves(waves: list[str]) -> list[tuple[npt.NDArray[np.float64], base64エンコードされたwavデータのリスト Returns ------- - waves_nparray_sr: List[Tuple[npt.NDArray[np.float64], int]] + waves_nparray_sr: List[Tuple[NDArray[np.float64], int]] (NumPy配列の音声波形データ, サンプリングレート) 形式のタプルのリスト """ if len(waves) == 0: @@ -42,7 +42,7 @@ def decode_base64_waves(waves: list[str]) -> list[tuple[npt.NDArray[np.float64], return waves_nparray_sr -def connect_base64_waves(waves: list[str]) -> tuple[npt.NDArray[np.float64], int]: +def connect_base64_waves(waves: list[str]) -> tuple[NDArray[np.float64], int]: waves_nparray_sr = decode_base64_waves(waves) max_sampling_rate = max([sr for _, sr in waves_nparray_sr]) From 53104c25c21f73e8759dcafb12cf96efdeca41a6 Mon Sep 17 00:00:00 2001 From: Hiroshiba Date: Mon, 8 Jan 2024 01:56:45 +0900 Subject: [PATCH 4/8] integer -> int64 --- voicevox_engine/core_adapter.py | 14 ++++++------ voicevox_engine/core_wrapper.py | 40 ++++++++++++++++----------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/voicevox_engine/core_adapter.py b/voicevox_engine/core_adapter.py index a11904551..9b48877c5 100644 --- a/voicevox_engine/core_adapter.py +++ b/voicevox_engine/core_adapter.py @@ -67,7 +67,7 @@ def is_initialized_style_id_synthesis(self, style_id: StyleId) -> bool: return True # コアが古い場合はどうしようもないのでTrueを返す def safe_yukarin_s_forward( - self, phoneme_list_s: NDArray[np.integer], style_id: StyleId + self, phoneme_list_s: NDArray[np.int64], style_id: StyleId ) -> NDArray[np.float32]: # 「指定スタイルを初期化」「mutexによる安全性」「系列長・データ型に関するアダプター」を提供する self.initialize_style_id_synthesis(style_id, skip_reinit=True) @@ -81,12 +81,12 @@ def safe_yukarin_s_forward( def safe_yukarin_sa_forward( self, - vowel_phoneme_list: NDArray[np.integer], - consonant_phoneme_list: NDArray[np.integer], - start_accent_list: NDArray[np.integer], - end_accent_list: NDArray[np.integer], - start_accent_phrase_list: NDArray[np.integer], - end_accent_phrase_list: NDArray[np.integer], + vowel_phoneme_list: NDArray[np.int64], + consonant_phoneme_list: NDArray[np.int64], + start_accent_list: NDArray[np.int64], + end_accent_list: NDArray[np.int64], + start_accent_phrase_list: NDArray[np.int64], + end_accent_phrase_list: NDArray[np.int64], style_id: StyleId, ) -> NDArray[np.float32]: # 「指定スタイルを初期化」「mutexによる安全性」「系列長・データ型に関するアダプター」を提供する diff --git a/voicevox_engine/core_wrapper.py b/voicevox_engine/core_wrapper.py index c97646345..aac76b552 100644 --- a/voicevox_engine/core_wrapper.py +++ b/voicevox_engine/core_wrapper.py @@ -528,8 +528,8 @@ def metas(self) -> str: def yukarin_s_forward( self, length: int, - phoneme_list: NDArray[np.integer], - style_id: NDArray[np.integer], + phoneme_list: NDArray[np.int64], + style_id: NDArray[np.int64], ) -> NDArray[np.float32]: """ 音素列から、音素ごとの長さを求める関数 @@ -537,9 +537,9 @@ def yukarin_s_forward( ---------- length : int 音素列の長さ - phoneme_list : NDArray[np.integer] + phoneme_list : NDArray[np.int64] 音素列 - style_id : NDArray[np.integer] + style_id : NDArray[np.int64] スタイル番号 Returns ------- @@ -560,13 +560,13 @@ def yukarin_s_forward( def yukarin_sa_forward( self, length: int, - vowel_phoneme_list: NDArray[np.integer], - consonant_phoneme_list: NDArray[np.integer], - start_accent_list: NDArray[np.integer], - end_accent_list: NDArray[np.integer], - start_accent_phrase_list: NDArray[np.integer], - end_accent_phrase_list: NDArray[np.integer], - style_id: NDArray[np.integer], + vowel_phoneme_list: NDArray[np.int64], + consonant_phoneme_list: NDArray[np.int64], + start_accent_list: NDArray[np.int64], + end_accent_list: NDArray[np.int64], + start_accent_phrase_list: NDArray[np.int64], + end_accent_phrase_list: NDArray[np.int64], + style_id: NDArray[np.int64], ) -> NDArray[np.float32]: """ モーラごとの音素列とアクセント情報から、モーラごとの音高を求める関数 @@ -574,19 +574,19 @@ def yukarin_sa_forward( ---------- length : int モーラ列の長さ - vowel_phoneme_list : NDArray[np.integer] + vowel_phoneme_list : NDArray[np.int64] 母音の音素列 - consonant_phoneme_list : NDArray[np.integer] + consonant_phoneme_list : NDArray[np.int64] 子音の音素列 - start_accent_list : NDArray[np.integer] + start_accent_list : NDArray[np.int64] アクセントの開始位置 - end_accent_list : NDArray[np.integer] + end_accent_list : NDArray[np.int64] アクセントの終了位置 - start_accent_phrase_list : NDArray[np.integer] + start_accent_phrase_list : NDArray[np.int64] アクセント句の開始位置 - end_accent_phrase_list : NDArray[np.integer] + end_accent_phrase_list : NDArray[np.int64] アクセント句の終了位置 - style_id : NDArray[np.integer] + style_id : NDArray[np.int64] スタイル番号 Returns ------- @@ -621,7 +621,7 @@ def decode_forward( phoneme_size: int, f0: NDArray[np.floating], phoneme: NDArray[np.floating], - style_id: NDArray[np.integer], + style_id: NDArray[np.int64], ) -> NDArray[np.float32]: """ フレームごとの音素と音高から波形を求める関数 @@ -635,7 +635,7 @@ def decode_forward( フレームごとの音高 phoneme : NDArray[np.floating] フレームごとの音素 - style_id : NDArray[np.integer] + style_id : NDArray[np.int64] スタイル番号 Returns ------- From ea72eb8e034d27de235bbf0f4954d5d115c383e7 Mon Sep 17 00:00:00 2001 From: Hiroshiba Date: Mon, 8 Jan 2024 02:05:37 +0900 Subject: [PATCH 5/8] =?UTF-8?q?np.floating=E3=82=92=E3=81=84=E3=81=8F?= =?UTF-8?q?=E3=81=A4=E3=81=8B=E6=8E=92=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- voicevox_engine/core_adapter.py | 4 ++-- voicevox_engine/core_wrapper.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/voicevox_engine/core_adapter.py b/voicevox_engine/core_adapter.py index 9b48877c5..9197e3876 100644 --- a/voicevox_engine/core_adapter.py +++ b/voicevox_engine/core_adapter.py @@ -106,8 +106,8 @@ def safe_yukarin_sa_forward( def safe_decode_forward( self, - phoneme: NDArray[np.floating], - f0: NDArray[np.floating], + phoneme: NDArray[np.float32], + f0: NDArray[np.float32], style_id: StyleId, ) -> tuple[NDArray[np.float32], int]: # 「指定スタイルを初期化」「mutexによる安全性」「系列長・データ型に関するアダプター」を提供する diff --git a/voicevox_engine/core_wrapper.py b/voicevox_engine/core_wrapper.py index aac76b552..83fa5f417 100644 --- a/voicevox_engine/core_wrapper.py +++ b/voicevox_engine/core_wrapper.py @@ -619,8 +619,8 @@ def decode_forward( self, length: int, phoneme_size: int, - f0: NDArray[np.floating], - phoneme: NDArray[np.floating], + f0: NDArray[np.float32], + phoneme: NDArray[np.float32], style_id: NDArray[np.int64], ) -> NDArray[np.float32]: """ @@ -631,9 +631,9 @@ def decode_forward( フレームの長さ phoneme_size : int 音素の種類数 - f0 : NDArray[np.floating] + f0 : NDArray[np.float32] フレームごとの音高 - phoneme : NDArray[np.floating] + phoneme : NDArray[np.float32] フレームごとの音素 style_id : NDArray[np.int64] スタイル番号 From 2b6f3eaf216bccdc523b7ef1f25975b2b0853a81 Mon Sep 17 00:00:00 2001 From: Hiroshiba Date: Mon, 8 Jan 2024 02:16:42 +0900 Subject: [PATCH 6/8] Apply suggestions from code review --- voicevox_engine/dev/tts_engine/mock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voicevox_engine/dev/tts_engine/mock.py b/voicevox_engine/dev/tts_engine/mock.py index e23419381..e85c44aa5 100644 --- a/voicevox_engine/dev/tts_engine/mock.py +++ b/voicevox_engine/dev/tts_engine/mock.py @@ -53,7 +53,7 @@ def forward(self, text: str, **kwargs: dict[str, Any]) -> NDArray[np.float32]: Returns ------- - wave [NDArray[np.float64]] + wave [NDArray[np.float32]] 音声波形データをNumPy配列で返します Note From 5f7f349a4a8cead44afb0bea4dd82bae3b21b096 Mon Sep 17 00:00:00 2001 From: Hiroshiba Date: Mon, 8 Jan 2024 02:30:55 +0900 Subject: [PATCH 7/8] =?UTF-8?q?=E8=A6=81=E3=82=89=E3=81=AA=E3=81=8F?= =?UTF-8?q?=E3=81=AA=E3=81=A3=E3=81=9F=E3=81=AF=E3=81=9A=E3=81=AEgenerics?= =?UTF-8?q?=E3=81=AE=E6=92=A4=E5=8E=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- voicevox_engine/morphing.py | 1 - voicevox_engine/tts_pipeline/tts_engine.py | 14 +++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/voicevox_engine/morphing.py b/voicevox_engine/morphing.py index 6fe69c1cf..e5d7cbd7e 100644 --- a/voicevox_engine/morphing.py +++ b/voicevox_engine/morphing.py @@ -19,7 +19,6 @@ from .tts_pipeline import TTSEngine -# FIXME: ndarray type hint, https://github.com/JeremyCCHsu/Python-Wrapper-for-World-Vocoder/blob/2b64f86197573497c685c785c6e0e743f407b63e/pyworld/pyworld.pyx#L398 # noqa @dataclass(frozen=True) class MorphingParameter: fs: int diff --git a/voicevox_engine/tts_pipeline/tts_engine.py b/voicevox_engine/tts_pipeline/tts_engine.py index a50bc4e6b..449511c6c 100644 --- a/voicevox_engine/tts_pipeline/tts_engine.py +++ b/voicevox_engine/tts_pipeline/tts_engine.py @@ -194,12 +194,9 @@ def apply_volume_scale(wave: np.ndarray, query: AudioQuery) -> NDArray[np.floati return wave * query.volumeScale -_SoxrType = TypeVar("_SoxrType", np.float32, np.float64, np.int16, np.int32) - - def apply_output_sampling_rate( - wave: NDArray[_SoxrType], sr_wave: float, query: AudioQuery -) -> NDArray[_SoxrType]: + wave: NDArray[np.floating], sr_wave: float, query: AudioQuery +) -> NDArray[np.floating]: """音声波形へ音声合成用のクエリがもつ出力サンプリングレート(`outputSamplingRate`)を適用する""" # サンプリングレート一致のときはスルー if sr_wave == query.outputSamplingRate: @@ -208,10 +205,9 @@ def apply_output_sampling_rate( return wave -T = TypeVar("T", bound=np.generic) - - -def apply_output_stereo(wave: NDArray[T], query: AudioQuery) -> NDArray[T]: +def apply_output_stereo( + wave: NDArray[np.floating], query: AudioQuery +) -> NDArray[np.floating]: """音声波形へ音声合成用のクエリがもつステレオ出力設定(`outputStereo`)を適用する""" if query.outputStereo: wave = np.array([wave, wave]).T From 4bd562c9fbbfd9b7050ae5d0c2f48f85485c6ec2 Mon Sep 17 00:00:00 2001 From: Hiroshiba Date: Mon, 8 Jan 2024 02:33:42 +0900 Subject: [PATCH 8/8] =?UTF-8?q?lint=E3=83=9F=E3=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- voicevox_engine/tts_pipeline/tts_engine.py | 1 - 1 file changed, 1 deletion(-) diff --git a/voicevox_engine/tts_pipeline/tts_engine.py b/voicevox_engine/tts_pipeline/tts_engine.py index 449511c6c..69692ec40 100644 --- a/voicevox_engine/tts_pipeline/tts_engine.py +++ b/voicevox_engine/tts_pipeline/tts_engine.py @@ -1,6 +1,5 @@ import copy import math -from typing import TypeVar import numpy as np from numpy.typing import NDArray