はじめに
ローカル音声合成(TTS)の世界は日々進化しており、表現豊かな対話音声を生成できる「Style-Bert-VITS2」、最新のFlow MatchingとDACVAE連続表現を採用した「Irodori-TTS v3」、そして長文分割生成や独立ASRによる品質判定を統合した「Qwen3-TTS(日本語スタジオ)」など、それぞれ特徴を持つモデルが登場しています。
しかし、これら複数のツールを個別に起動・管理し、学習データの連携を行うのは煩雑です。特に、Style-Bert-VITS2のGUIで作成した高精度なスライス・文字起こし済みの音声資産を、Irodori-TTS v3のLoRA学習にシームレスに横展開したいというニーズは強く存在します。また、Irodori-TTSの生成音声に自動挿入される「音声透かし」の処理コストや音質への微細な影響を回避するため、無効化したいケースもあります。
本稿では、Style-Bert-VITS2からIrodori-TTS v3へのデータセット一括変換、音声透かしの無効化ロジック、およびこれら3大TTS環境の起動と稼働監視を一元化する「TTS Unified Portal」の開発と技術検証プロセスをコードレベルで詳しく解説します。
1. Irodori-TTS v3における音声透かし(SilentCipher)の無効化ロジック
コールフローの解析
Irodori-TTS v3では、音声生成のパイプラインにおいて自動的に SilentCipher による音声透かしを適用する処理が走ります。このコールフローは以下の通りです。
infer.py / Gradio
→ InferenceRuntime.synthesize() (Trimmed audios 取得直後)
→ self.watermarker.encode_batch(...)
→ watermark.py の SilentCipherWatermarker.encode_one()
→ silentcipher.get_model(...).encode_wav(...)
このため、SilentCipherのロード失敗による起動エラーの防止や、透かし処理によるCPU/GPUのオーバーヘッド削減、および音質評価用のピュアなデコード音声の取得には、このコールフローを安全にスキップする設計が必要です。
「デフォルト無効化(Disabled by Default)」設計への改善
本検証では、利便性と安全性を最大限確保するため、音声透かし処理をデフォルト無効化とする改修を irodori_tts/watermark.py および irodori_tts/inference_runtime.py に施しました。環境変数 IRODORI_ENABLE_WATERMARK=1 が明示的に指定されている場合のみ透かしが有効化され、それ以外は完全にスキップされます。
# irodori_tts/watermark.py の改修箇所
WATERMARK_ENABLE_ENV = "IRODORI_ENABLE_WATERMARK"
_TRUE_VALUES = {"1", "true", "yes", "on"}
def watermark_enabled_from_env() -> bool:
return os.getenv(WATERMARK_ENABLE_ENV, "").strip().lower() in _TRUE_VALUES
class SilentCipherWatermarker:
def __init__(self, *, device: str, model_type: str = "44.1k", enabled: bool | None = None) -> None:
self.enabled = watermark_enabled_from_env() if enabled is None else bool(enabled)
if not self.enabled:
logger.info("SilentCipher watermark is disabled by default. Enable by setting %s=1.", WATERMARK_ENABLE_ENV)
self.model = self._load_backend(device=device, model_type=model_type) if self.enabled else None
これにより、WebUIやバッチファイル起動時に特別な環境変数を設定しなくても、標準の状態で透かし処理が自動でスキップされるようになり、デコードされたオリジナル波形がそのまま出力されます。
2. Style-Bert-VITS2からIrodori-TTS v3へのデータセット一括変換
esd.list の構造とマニフェストJSONLへの変換ロジック
Style-Bert-VITS2のデータ作成GUIで長尺音声を処理すると、Data/<モデル名>/esd.list にスライス音声と文字起こしテキストが以下のフォーマットで出力されます。
相対パス|話者名|言語|テキスト
例: conversation\shigeru-qa-100090-113030.wav|shigeru-ishiba|JP|おそらく御批判は...
一方、Irodori-TTS v3の前処理スクリプト prepare_manifest.py は、ローカルデータソースとして各要素が絶対パスを持つJSONL形式(マニフェスト)を要求します。そこで、両者の差分を埋める変換スクリプト convert_sbv2_to_irodori.py を開発しました。
# 変換のコアロジック (convert_sbv2_to_irodori.py)
records = []
with open(esd_path, "r", encoding="utf-8") as f:
for line in f:
parts = line.strip().split("|")
if len(parts) < 4: continue
rel_path, speaker, lang, text = parts[0], parts[1], parts[2], parts[3]
# パスセパレータを正規化して絶対パスを算出
audio_path = (raw_dir / rel_path.replace("\\", "/")).resolve()
if not audio_path.exists(): continue
records.append({
"audio": str(audio_path),
"text": text,
"speaker": speaker
})
このスクリプトにより、Style-Bert-VITS2側で作成した高精度なデータセット資産をそのままIrodori-TTS形式に変換し、DACVAEの潜在変数(latents)抽出ステップへと引き渡すことができます。
3. 生音声からの一気通貫学習自動化パイプライン (train_from_raw_inputs.bat) の構築
Style-Bert-VITS2 の inputs ディレクトリに配置された未処理の生音声ファイルから、スライス、文字起こし、形式変換、潜在変数計算、そしてLoRA学習の開始・再開までを数クリックで自動実行可能にする統合バッチファイル train_from_raw_inputs.bat を開発しました。本スクリプトは、以下に示す堅牢かつ柔軟な仕組みを搭載しています。
① 各ステージにおける「再利用・再作成」選択機能
学習処理はリソースと時間を大量に消費するため、途中で失敗した場合や前処理をスキップしたい場合に、既存の成果物(スライス済みWAV、文字起こし esd.list、中間JSONL、潜在変数)を自動検知し、それぞれ「再利用」または「最初から再生成」を個別に選択できる対話メニューを設けています。
② 学習のシームレスな再開 (Resume) サポート
学習を中断した際、出力ディレクトリ内の最新のチェックポイントフォルダ(例: checkpoint_1000 など)をバッチファイルが日付順で自動スキャンし、train.py に対し --resume 引数と最新チェックポイントパスを動的に引き渡すことで、中断箇所から即時再開できるようにしました。
③ パラメータ制御と動的オーバーライド
prepare_manifest.py に引き渡すデータセットパラメータ(--dataset, --data-files, --audio-column, --text-column, --speaker-column, --caption-column)を起動時に確認・編集できる機能を実装。また、VRAM 12GB 環境への配慮として、バッチサイズの動的オーバーライドをサポートしています。
4. 3大WebUIを統括する「TTS Unified Portal」の開発
Python標準ライブラリによる軽量ダッシュボードの実装
各音声合成プロジェクトはそれぞれ異なるポート(Style-Bert-VITS2: 5000, Irodori-TTS: 7860, Qwen3-TTS: 7873)で個別のWebUIを提供しています。これらを集約し、稼働状態の可視化とプロセスの起動・停止を一元管理できる「TTS Unified Portal」(tts_portal.py)を構築しました。
余計な外部ライブラリ依存を防ぐため、Pythonの標準モジュール http.server および socket を使用して記述されています。
ポート疎通確認による稼働検知
# socketを用いた軽量な生存検知ロジック
def is_port_open(port):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.3)
try:
s.connect(("127.0.0.1", port))
return True
except (socket.timeout, ConnectionRefusedError):
return False
非同期プロセス起動とコンソール分離
WebUIの起動要求があった際、親プロセスのWebサーバーをブロックせずに、かつユーザーが実行ログを確認できるよう、Windowsの CREATE_NEW_CONSOLE フラグを利用して別コンソールでバッチファイルを走らせます。
# Windows向けの別コンソール非同期起動
proc = subprocess.Popen(
["cmd.exe", "/c", cmd],
cwd=cwd,
creationflags=subprocess.CREATE_NEW_CONSOLE,
env=env
)
5. ポータルのデザインとユーザー体験
ポータルのUIは、暗色系を基調としたグラデーション背景とグラスモルフィズム(半透明ぼかし効果)を取り入れ、一目で各サービスのオンライン/オフライン状態が判定できるよう設計されています。状態チェックはJavaScriptにより3秒間隔で自動ポーリングされ、ポートが解放されると「ONLINE」バッジが緑色に点灯し、「開く」ボタンが有効化されます。また、停止ボタンを押すことで、稼働中のバックグラウンドプロセスツリー(taskkill /F /T)を強制終了し、不要なGPUメモリを即座に解放できます。
まとめと今後の展望
Style-Bert-VITS2、Irodori-TTS v3、Qwen3-TTSという異なる技術基盤を持つ音声合成環境をひとつのポータルにまとめ、データセット変換からLoRA学習、そして音声透かし無効化までを統合したことで、ローカル音声合成の実験サイクルは効率化されました。今後は、ポータル上から直接学習進行度の進捗(TensorBoard/WandB等)をグラフ表示するモニタリング機能の拡張や、生成された音声ファイルの音響診断スコアをその場で比較できるプレイバック機能の実装を進め、更なる運用性の向上を目指します。