speak.py 技術ドキュメント
プログラムの動作
speak.py は、複数のテキスト読み上げ (Text-to-Speech, TTS) エンジンを統合し、指定されたテキストを音声に変換して再生またはファイルに保存するためのコマンドラインツールです。このプログラムは、pyttsx3, WinRT, VOICEVOX, Qwen3-TTS, Irodori-TTS, AquesTalkPlayer, OpenAI といった多様なTTSエンジンをサポートしており、ユーザーはコマンドライン引数を通じて簡単にエンジンを選択し、その詳細な設定を調整できます。
主な機能
多様なTTSエンジンのサポート: 複数のTTSエンジンから選択し、テキストを音声に変換します。
柔軟な入力元: クリップボードから直接テキストを取得するか、ファイルパスを指定してテキストを読み込みます。
テキスト解析: 対話形式(話者とセリフ)または独話形式(すべての行を読み上げ)でテキストを解析できます。
話者と音声のマッピング: 検出された話者名に応じて、TTSエンジンの特定音声(ボイス)を自動的に割り当てる機能があります。ユーザーはこのマッピングを上書きできます。
音声出力: 生成された音声をリアルタイムで再生するか、指定された音声ファイル(例: WAV)として保存します。
エンジン固有の設定: 各TTSエンジンに対応する詳細なパラメータ(読み上げ速度、ピッチ、モデルID、リファレンス音声など)をコマンドライン引数で設定できます。
情報表示機能: 利用可能な音声の一覧や、現在の音声マップを表示して確認できます。
解決する課題
ユーザーが異なるTTSエンジンやその複雑な設定を、単一の統一されたコマンドラインインターフェースから利用できるようにすることで、TTSプロセスの簡素化を図ります。特に、対話形式のテキストを異なる声で読み分けたいというニーズに対し、話者と音声の自動マッピング機能を提供することで、手間なく高品質な対話音声を作成することを可能にします。
原理
speak.py は、tktts と呼ばれるカスタムライブラリを介して、様々なTTSエンジンを抽象化し、統一されたインターフェースを提供します。このプログラムの主要な処理フローは以下のようになります。
引数の解析:
argparseモジュールを使用して、コマンドラインから渡された引数を解析し、実行するTTSエンジン、入力元、出力先、および各種設定を決定します。tkTTSインスタンスの初期化: 選択されたTTSエンジンと設定(速度、ピッチなど)に基づいて、tktts.tkTTSクラスのインスタンスを生成します。このインスタンスが、実際の音声合成処理を各バックエンドエンジンに委譲します。テキストの読み込みと解析:
--infileで指定された入力元(クリップボードまたはファイル)からテキストを取得します。テキストは、
--monologueオプションの有無に基づいて解析されます。デフォルトの対話形式では、各行を「話者名,セリフ」として解釈します。独話形式では、すべての行が単一の話者によって読み上げられるテキストとして扱われます。解析後、テキスト内の話者名が抽出されます。
話者と音声のマッピング:
プログラムに組み込まれた
VOICE_MAPS辞書、および--voices引数で指定された上書きルールに基づいて、検出された話者名にTTSエンジンの具体的な音声(ボイス)が割り当てられます。例えば、
pyttsx3エンジンでは「四国めたん」に「Zira」というシステムボイスが割り当てられます。
文字列置換の適用:
--replace引数で指定された置換ルールに基づいて、セリフ内の特定の文字列を別の文字列に置き換えます。これは、読み上げ時に誤読されやすい単語や、特殊な表現を修正するために利用されます。音声合成と出力:
tkTTSインスタンスのspeak_dialogueメソッドを呼び出し、解析されたテキストデータと決定された音声マップ、置換ルールを渡します。speak_dialogueメソッドは、各セリフに対応するTTSエンジンを呼び出し、音声を生成します。--outfileが指定されている場合、生成された個々の音声ファイル(一時ファイルとして作成されることが多い)が結合され、指定されたファイルに保存されます。この際、pydubライブラリと外部ツールffmpeg.exeが音声ファイルの結合やフォーマット変換に利用されます。--tintervalオプションが指定されている場合、結合される音声ファイルの間に指定された長さの無音区間が挿入されます。--outfileが未指定の場合、音声はリアルタイムで再生されます。
必要な非標準ライブラリとインストール方法
speak.py の実行には、以下のPythonライブラリと外部依存が必要です。
Pythonライブラリ
chardet: テキストファイルの文字コードを自動検出するために使用されます。pyttsx3: オフラインで動作するPythonのテキスト読み上げライブラリです。openai: OpenAI社のTTS APIと連携するために使用されます。pydub: 音声ファイルの処理(結合、フォーマット変換など)に使用されます。pyperclip: クリップボードからのテキスト入力を取得するために使用されます。tktts:speak.pyが複数のTTSエンジンを統合するために内部的に利用するカスタムライブラリです。
インストール方法
これらのPythonライブラリは、以下の pip コマンドでまとめてインストールできます。
pip install chardet pyttsx3 openai pydub pyperclip tktts
外部依存
ffmpeg.exe:pydubライブラリが音声ファイルの結合や形式変換を行う際に必要となる、オープンソースのマルチメディアフレームワークです。環境PATHに設定するか、
pydubが検出できるシステム上の適切な場所に配置する必要があります。
AquesTalkPlayer.exe:--tts aquestalkplayerオプションを使用する場合に必要となる、Windows専用のAquesTalkPlayerアプリケーションです。実行パスを
--aquestalk_path引数で指定する必要があります。
OpenAI API Key:--tts openaiオプションを使用する場合に必要です。OpenAIのウェブサイトで取得したAPIキーを、環境変数
OPENAI_API_KEYに設定する必要があります。
必要な入力ファイル
プログラムは、テキストの入力元としてクリップボードまたはファイルパスをサポートしています。
入力元
clip(デフォルト):--infileオプションを省略するか、--infile clipと指定した場合、クリップボードにコピーされたテキストが読み込まれます。ファイルパス:
--infile <ファイルパス>と指定した場合、指定されたパスのテキストファイルが読み込まれます。
期待されるファイル形式とデータ構造
文字コード:
chardetライブラリによって自動検出されますが、一般的にはUTF-8でエンコードされたテキストファイルが推奨されます。内容の構造:
対話形式 (デフォルト): 各行が「話者名,セリフ」の形式であると解釈されます。 例:
四国めたん,こんにちは、四国めたんです。 ずんだもん,やっほー、ずんだもんなのだ! 四国めたん,今日は何を話しましょうか? ずんだもん,そうですね、まずはこのプログラムについてなのだ。
独話形式 (
--monologue=1):--monologueオプションが1に設定されている場合、すべての行がそのまま読み上げられます。この場合、行頭に話者名が指定されていても無視されるか、単一のデフォルト話者が割り当てられます。カンマを含まない行も読み上げられます。 例:これは独話形式のサンプルテキストです。 全ての行がそのまま読み上げられます。 話者は一つにまとめられます。
生成される出力ファイル
speak.py は、テキストを音声に変換した結果を、リアルタイム再生するか、ファイルとして保存します。
出力音声ファイル
ファイル名:
--outfile <ファイル名>引数で指定します。例えば--outfile output.wav。内容: 指定された入力テキストが読み上げられた音声データが含まれます。
フォーマット: 通常は
.wav形式で出力されますが、pydubライブラリがサポートする他の音声形式(例:.mp3)も、指定された拡張子に応じて出力される可能性があります。AquesTalkPlayerやOpenAIなどのエンジンを使用し、かつ--outfileが指定された場合、個々のセリフに対応する音声ファイルが一時的に生成された後、一つのファイルに結合されて保存されます。
一時ファイル
一部のTTSエンジン(特に
AquesTalkPlayerやOpenAI)では、音声合成の過程で個々のセリフに対応する一時的な.wavファイルが生成されます。これらのファイルは
--temp_dirオプションで指定されたディレクトリ(デフォルトはtts_temp_wavs)に保存されます。通常、
--outfileを指定して最終的な音声ファイルが作成された後、これらの個々の一時ファイルは削除されず、中間ファイルとして残る可能性があります。
コマンドラインでの使用例 (Usage)
speak.py をコマンドラインで実行する際の基本的な構文と引数の一覧です。
usage: speak.py [-h] [--tts {pyttsx3,winrt,voicevox,qwen3,qwen,irodori,irodori-tts,aquestalkplayer,atp,openai}]
[--endpoint ENDPOINT] [--monologue MONOLOGUE] [--voices VOICES] [--replace REPLACE]
[--infile INFILE] [--outfile OUTFILE] [--temp_dir TEMP_DIR] [--list] [--map] [--pause PAUSE]
[--wait_for_clipboard WAIT_FOR_CLIPBOARD] [--speak_rate SPEAK_RATE]
[--fspeak_rate FSPEAK_RATE] [--fspeak_pitch FSPEAK_PITCH] [--aquestalk_path AQUESTALK_PATH]
[--tinterval TINTERVAL] [--qwen3_language QWEN3_LANGUAGE] [--qwen3_model_id QWEN3_MODEL_ID]
[--qwen3_device QWEN3_DEVICE] [--qwen3_dtype {auto,bfloat16,bf16,float16,fp16,float32,fp32}]
[--qwen3_instruct QWEN3_INSTRUCT] [--irodori_caption IRODORI_CAPTION]
[--irodori_ref_wav IRODORI_REF_WAV] [--irodori_ref_wavs IRODORI_REF_WAVS]
[--irodori_model_id IRODORI_MODEL_ID] [--irodori_device IRODORI_DEVICE]
[--irodori_precision {auto,bf16,bfloat16,fp32,float32}]
[--irodori_codec_device IRODORI_CODEC_DEVICE]
[--irodori_codec_precision IRODORI_CODEC_PRECISION] [--irodori_num_steps IRODORI_NUM_STEPS]
[--irodori_cfg_scale_text IRODORI_CFG_SCALE_TEXT]
[--irodori_cfg_scale_caption IRODORI_CFG_SCALE_CAPTION]
[--irodori_cfg_scale_speaker IRODORI_CFG_SCALE_SPEAKER]
[--irodori_duration_scale IRODORI_DURATION_SCALE] [--irodori_seed IRODORI_SEED]
[--irodori_lora_adapter IRODORI_LORA_ADAPTER] [--instruction INSTRUCTION]
統合TTS (pyttsx3, WinRT, VOICEVOX, Qwen3-TTS, Irodori-TTS, AquesTalkPlayer, OpenAI) CLIツール
options:
-h, --help show this help message and exit
--tts {pyttsx3,winrt,voicevox,qwen3,qwen,irodori,irodori-tts,aquestalkplayer,atp,openai}, -t {pyttsx3,winrt,voicevox,qwen3,qwen,irodori,irodori-tts,aquestalkplayer,atp,openai}
TTSエンジンを選択 (デフォルト: pyttsx3)
--endpoint ENDPOINT VOICEVOX Engineのendpoint (デフォルト: http://127.0.0.1:50021)
--monologue MONOLOGUE, -m MONOLOGUE
独話形式 (カンマのない行も読み込む、0:OFF, 1:ON) (デフォルト: 0)
--voices VOICES, -v VOICES
voice_map の上書き (key=val;key=val 形式)
--replace REPLACE, -r REPLACE
文字列置換ルール (key=val;key=val 形式)
--infile INFILE, -i INFILE
入力元 ('clip' またはファイルパス) (デフォルト: clip)
--outfile OUTFILE, -o OUTFILE
出力音声ファイル (未指定の場合、リアルタイム再生)
--temp_dir TEMP_DIR 一時ファイルを作成するディレクトリ名 (AquesTalkPlayer/OpenAI使用時) (デフォルト: tts_temp_wavs)
--list 利用可能な voices を表示して終了
--map voice map を表示して終了
--pause PAUSE, -p PAUSE
終了時に入力待ちする (0:OFF, 1:ON) (デフォルト: 0)
--wait_for_clipboard WAIT_FOR_CLIPBOARD
クリップボードからテキストを取得する際に入力待ちする (0:OFF, 1:ON) (デフォルト: 1)
--speak_rate SPEAK_RATE
pyttsx3 の読み上げ速度 (Word Per Minute) (デフォルト: 150)
--fspeak_rate FSPEAK_RATE
VOICEVOX の読み上げ速度比 (標準: 1.0) (デフォルト: 1.0)
--fspeak_pitch FSPEAK_PITCH
VOICEVOX の声の高さ (標準: 0.0) (デフォルト: 0.0)
--aquestalk_path AQUESTALK_PATH
AquesTalkPlayer.exe の実行パス (AquesTalkPlayer使用時) (デフォルト: AquesTalkPlayer.exe)
--tinterval TINTERVAL
AquesTalkPlayer/OpenAIの音声ファイル間に挿入する無音区間の長さ(秒) (デフォルト: 0.5)
# Qwen3-TTS 関連引数
--qwen3_language QWEN3_LANGUAGE
Qwen3-TTS language (デフォルト: Japanese)
--qwen3_model_id QWEN3_MODEL_ID
Qwen3-TTS model ID (デフォルト: Qwen/Qwen3-TTS-12Hz-0.6B-CustomVoice)
--qwen3_device QWEN3_DEVICE
Qwen3-TTS device: auto/cuda:0/cpu (デフォルト: auto)
--qwen3_dtype {auto,bfloat16,bf16,float16,fp16,float32,fp32}
Qwen3-TTS dtype (デフォルト: auto)
--qwen3_instruct QWEN3_INSTRUCT
Qwen3-TTS CustomVoiceへの追加指示
# Irodori-TTS 関連引数
--irodori_caption IRODORI_CAPTION
Irodori-TTS voice/style caption (デフォルト: 落ち着いた自然な声で、明瞭に読み上げる。)
--irodori_ref_wav IRODORI_REF_WAV
Irodori-TTS reference WAV (ファイルパス)
--irodori_ref_wavs IRODORI_REF_WAVS
Irodori-TTS reference WAVs (;区切り)
--irodori_model_id IRODORI_MODEL_ID
Irodori-TTS model ID (デフォルト: Aratako/Irodori-TTS-v4.1-Small)
--irodori_device IRODORI_DEVICE
Irodori-TTS device: auto/cuda/cuda:0/cpu (デフォルト: auto)
--irodori_precision {auto,bf16,bfloat16,fp32,float32}
Irodori-TTS precision (デフォルト: auto)
--irodori_codec_device IRODORI_CODEC_DEVICE
Irodori codec device (未指定ならmodel device)
--irodori_codec_precision IRODORI_CODEC_PRECISION
Irodori codec precision (未指定ならmodel precision)
--irodori_num_steps IRODORI_NUM_STEPS
Irodori-TTS sampling steps (デフォルト: 40)
--irodori_cfg_scale_text IRODORI_CFG_SCALE_TEXT
Irodori-TTS CFG scale for text (デフォルト: 3.5)
--irodori_cfg_scale_caption IRODORI_CFG_SCALE_CAPTION
Irodori-TTS CFG scale for caption (デフォルト: 3.0)
--irodori_cfg_scale_speaker IRODORI_CFG_SCALE_SPEAKER
Irodori-TTS CFG scale for speaker/reference (デフォルト: 5.0)
--irodori_duration_scale IRODORI_DURATION_SCALE
Irodori-TTS duration scale (デフォルト: 1.0)
--irodori_seed IRODORI_SEED
Irodori-TTS seed; 'none'/'random'でランダム (デフォルト: 0)
--irodori_lora_adapter IRODORI_LORA_ADAPTER
Irodori-TTS LoRA adapter path
# OpenAI 関連引数
--instruction INSTRUCTION
OpenAI TTS APIへの追加指示 (OpenAI使用時)
コマンドラインでの具体的な使用例
1. クリップボードからの読み上げ (pyttsx3, リアルタイム再生)
クリップボードに「こんにちは、世界!」とコピーしてから以下のコマンドを実行します。デフォルトの pyttsx3 エンジンで読み上げ、リアルタイムで再生されます。
python speak.py
実行結果: クリップボードのテキストがデフォルトの音声で読み上げられます。
2. ファイルからの対話形式読み上げ (VOICEVOX, ファイル保存)
まず、dialogue.txt というファイルを作成し、以下の内容を記述します。
四国めたん,こんにちは、VOICEVOXです。
ずんだもん,ずんだもんもいるのだ!
次に、VOICEVOX Engineがローカルで起動していることを確認し、以下のコマンドを実行します。
python speak.py --tts voicevox -i dialogue.txt -o output.wav --fspeak_rate 1.2
実行結果:
dialogue.txt の内容がVOICEVOXの「四国めたん」と「ずんだもん」の声で読み上げられ、output.wav というファイルに保存されます。読み上げ速度は標準の1.2倍になります。
3. AquesTalkPlayerでの独話形式読み上げ (外部パス指定)
まず、monologue.txt というファイルを作成し、以下の内容を記述します。
AquesTalkPlayerテスト。
これは独話形式で読み上げられます。
AquesTalkPlayer.exe が C:\Program Files\AquesTalkPlayer\AquesTalkPlayer.exe にインストールされていると仮定して、以下のコマンドを実行します。
python speak.py --tts aquestalkplayer -m 1 -i monologue.txt --aquestalk_path "C:\Program Files\AquesTalkPlayer\AquesTalkPlayer.exe" -o aques_output.wav --voices "0=青山龍星"
実行結果:
monologue.txt の内容がAquesTalkPlayerの「青山龍星」の声で独話形式で読み上げられ、aques_output.wav というファイルに保存されます。
4. OpenAI TTSでの読み上げ (novaボイス, ファイル保存)
環境変数 OPENAI_API_KEY が設定されていることを確認してください。クリップボードに「OpenAI TTSは素晴らしい音声合成を提供します。」とコピーしてから、以下のコマンドを実行します。
python speak.py --tts openai -i clip -o openai_output.mp3 --voices "0=nova" --instruction "プロのナレーターのように、落ち着いた声で"
実行結果:
クリップボードのテキストがOpenAI TTSの「nova」ボイスで、指定された指示(instruction)に従って読み上げられ、openai_output.mp3 というファイルに保存されます。
5. 利用可能な声の一覧表示 (pyttsx3)
pyttsx3 エンジンで利用可能なシステム音声の一覧を表示します。
python speak.py --tts pyttsx3 --list
実行結果例:
===== 統合TTS CLIツール speak.py =====
TTS engine : pyttsx3
is monologue: 0
Input : clip
Output :
Language: japanese
pyttsx3 speak_rate: 150
VOICEVOX speak_rate: 1.0
VOICEVOX speak_pitch: 0.0
VOICEVOX Engine endpoint: http://127.0.0.1:50021
wait_for_clipboard: 1
Available voices for pyttsx3:
id: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_EN-US_ZIRA_11.0, name: Microsoft Zira Desktop - English (United States), lang: en-US
id: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_EN-US_DAVID_11.0, name: Microsoft David Desktop - English (United States), lang: en-US
...
--- 処理完了 ---
6. デフォルトの音声マップの表示
プログラムに設定されている各TTSエンジンのデフォルトの音声マップを表示します。
python speak.py --map
実行結果例:
===== 統合TTS CLIツール speak.py =====
TTS engine : pyttsx3
is monologue: 0
Input : clip
Output :
Language: japanese
pyttsx3 speak_rate: 150
VOICEVOX speak_rate: 1.0
VOICEVOX speak_pitch: 0.0
VOICEVOX Engine endpoint: http://127.0.0.1:50021
wait_for_clipboard: 1
Voice maps for all engines:
pyttsx3: {'四国めたん': 'Zira', 'ずんだもん': 'David', 'れいむ': 'Zira', 'まりさ': 'David'}
qwen3: {'四国めたん': 'Ono_Anna', 'ずんだもん': 'Ono_Anna', 'れいむ': 'Ono_Anna', 'まりさ': 'Ono_Anna'}
qwen: {'四国めたん': 'Ono_Anna', 'ずんだもん': 'Ono_Anna', 'れいむ': 'Ono_Anna', 'まりさ': 'Ono_Anna'}
irodori: {'四国めたん': 'default', 'ずんだもん': 'default', 'れいむ': 'default', 'まりさ': 'default'}
irodori-tts: {'四国めたん': 'default', 'ずんだもん': 'default', 'れいむ': 'default', 'まりさ': 'default'}
aquestalkplayer: {'四国めたん': 'れいむ', 'ずんだもん': 'まりさ', 'れいむ': 'れいむ', 'まりさ': 'まりさ', '青山龍星': '青山龍星'}
openai: {'四国めたん': 'nova', 'ずんだもん': 'shimmer', 'れいむ': 'alloy', 'まりさ': 'fable'}
--- 処理完了 ---