Coqui TTS (コキー・ティーティーエス)

ソフトウェア

オフラインで利用可能な、英語の自然な音声合成ソフトウェアです。2021年にMozilla TTS の開発が停止し、その後継として作られました。名前の由来は、プエルトリコに生息する小さなカエル「Coquí」とのことです。TTSは、Text-to-Speech の略です。

Git bash を使って説明しているので、Git for Windows をインストールしておく必要があります。また、Visual C++ も必要になるので Visual Studio の コミュニティ版などをインストールする必要があります。

Coqui TTS の特徴

  • 高品質な音声合成:Deep Learning ベースで、非常に自然な音声が生成可能です。
  • マルチスピーカー対応:複数の話者のモデルを使って、話者の切り替えが可能。
  • 多言語対応:英語、日本語、スペイン語など、複数言語に対応(ただしモデルによる)。
  • 学習も可能:自分でデータを用意すれば、独自の TTS モデルをトレーニング可能。
  • Web UI あり:簡単に試せる Web インターフェースも提供されています。(この記事では取り扱っていません)
  • CLI・Python API:コマンドラインまたは Python スクリプトで使える。

準備:前提条件

必須項目内容
OSWindows 10 / 11
Python3.8〜3.11(推奨:3.11)
環境管理仮想環境(venv)推奨
コンパイラVisual Studio Build Tools(C++付き)インストール済み

Git bash で実行する

言語系を設定する。

vi ~/.bashrc

以下のようになっていること

PS1='\$ '
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
export PYTHONUTF8=1

Python 3.11を入れる

pyenv install 3.11.9
pyenv global 3.11.9

バージョンを確認

python --version

ステップ 1:仮想環境の作成(任意)

python -m venv myenv
source myenv/Scripts/activate

ステップ 2:pip を更新し必要なツールを入れる

python -m pip install --upgrade pip

pip install setuptools wheel

ステップ 3:Coqui TTS をインストール

pip install TTS

これで TTS コマンドが使えるようになります。

後で設定するもので、一部バージョンが合わないものがあるので入れ替え。

pip uninstall -y torch torchaudio
pip install -y torch==2.3.0 torchaudio==2.3.0

ステップ 4:モデルを探す(一覧表示)

tts --list_models

おすすめの英語モデル:

モデル名特徴
tts_models/en/ljspeech/tacotron2-DDC自然なナレーション向き、安定性あり
tts_models/en/vctk/vits複数話者対応、イントネーション自然
tts_models/en/ljspeech/glow-tts高速生成タイプ

ステップ 5:音声を生成(例)

tts --text "Hello, this is a test." \
     --model_name "tts_models/en/ljspeech/tacotron2-DDC" \
     --out_path output.wav
  • output.wav が生成されます。

ステップ 6(任意):モデルを事前ダウンロード(オフライン用)

tts --model_name "tts_models/en/ljspeech/tacotron2-DDC" --download_only

別音声対応

espeak-ng をインストール

別の音声で使うので espeak-ng をインストールします。

Release 1.52 · espeak-ng/espeak-ng ← このページから espeal-ng.msi をダウンロードしてインストールします。(ダウンロード時にWindows が警告を出すかもしれません)

インストール後、Git bash を再起動する必要があります。

自動化

途中いろいろ書いていますが、「自動化」のところまで読み飛ばしてもらって大丈夫です。

補足:エラー対策

日本語音声対応

日本語の音声もあったので試してみました。

男性の声で、品質はそれほど高くありませんでした。たぶん、別のソフトを使った方が良いです。

pip install TTS[ja]

実行

tts --text "こんにちは、これはテストです。" \
     --model_name tts_models/ja/kokoro/tacotron2-DDC \
     --vocoder_name vocoder_models/ja/kokoro/hifigan_v1 \
     --out_path output-ja.wav

別の英語音声を使う

vctk/vits を使うと espeak-ng が必要になる

espeak-ng.msi をインストールする

espeak-ng をインストールすると環境変数にパスが追加されます。Git bash を再起動します。

英語マルチスピーカーモデル tts_models/en/vctk/vits 用のおすすめ男女話者 各3名ずつ

VCTK話者の性別はエディンバラ大学の公式サイトに基づいています。

女性話者(おすすめ)

話者ID備考
p225ナチュラルで柔らかめな英語発音
p227標準的なナレーション風
p248若干高め、テンポがよい

男性話者(おすすめ)

話者ID備考
p226落ち着いた自然な低音
p228ややはきはきした声、ニュース風
p252やや若々しく明るい印象

テストスクリプト

# 女性話者テスト
tts --text "This is a test spoken by speaker p225." \
    --model_name "tts_models/en/vctk/vits" \
    --speaker_idx p225 \
    --out_path "female_p225.wav"

tts --text "This is a test spoken by speaker p227." \
    --model_name "tts_models/en/vctk/vits" \
    --speaker_idx p227 \
    --out_path "female_p227.wav"v"

tts --text "This is a test spoken by speaker p248." \
    --model_name "tts_models/en/vctk/vits" \
    --speaker_idx p248 \
    --out_path "female_p248.wav"

# 男性話者テスト
tts --text "This is a test spoken by speaker p226." \
    --model_name "tts_models/en/vctk/vits" \
    --speaker_idx p226 \
    --out_path "male_p226.wav"

tts --text "This is a test spoken by speaker p228." \
    --model_name "tts_models/en/vctk/vits" \
    --speaker_idx p228 \
    --out_path "male_p228.wa

tts --text "This is a test spoken by speaker p252." \
    --model_name "tts_models/en/vctk/vits" \
    --speaker_idx p252 \
    --out_path "male_p252.wav"

クレジット表記が不要のモデル

以下に、Coqui TTS に含まれる「商用利用可能・クレジット表記不要・無償・オフライン利用可能」な英語音声モデルのおすすめをまとめました。


選定条件

  • 商用利用可能(無償)
  • クレジット表記不要
  • オフラインで動作可能
  • 明瞭で中立的な成人の声
  • 高品質なTTSモデル(Tacotron2, VITSなど)

推奨モデル一覧(日本語まとめ)

モデル名(--model_nameライセンス声の特徴備考
tts_models/en/ljspeech/tacotron2-DDCApache 2.0女性、落ち着いたアメリカ英語Audiobook音源を元にした定番モデル。ナチュラルで安定した音声。
tts_models/en/ljspeech/vitsApache 2.0女性、自然な発音上記と同じ話者。VITSモデルでよりスムーズ
tts_models/en/sam/tacotron-DDCApache 2.0中性的な大人の声Accenture提供の「Sam」データセットを利用。性別の色が薄くニュートラル。
tts_models/en/ek1/tacotron2Apache 2.0女性、落ち着いたイギリス英語RP(英国標準発音)で非常に明瞭。
tts_models/en/vctk/vitsApache 2.0複数(男性・女性)英国系の複数話者から選択可(109人)。--speaker_idxで選べる。

モデル選びのポイント

  • 品質を重視するなら ljspeech/vits がおすすめ。
  • 話者を選びたいなら vctk/vits(複数話者から選択可能)。
  • 中性的な声が必要なら sam/tacotron-DDC

使い方の例(コマンド)

# ljspeech/vits モデルで英語音声を生成
tts --text "Welcome to our company event." \
    --model_name ljspeech/vits \
    --out_path output.wav

vctk/vits を使う場合は --speaker_idx も指定してください。


商用利用とライセンスについて

すべてのモデルは Apache License 2.0 です:

  • 商用利用可
  • クレジット(著作権表示)は不要
  • 改変・再配布も可

自動化

準備

requirements.txt

dotenv
soundfile
numpy
numba
librosa
torch==2.3.0
torchaudio==2.3.0
openpyxl
pandas

使うパッケージを入れておく

pip install -r requirements.txt

.env

INPUT_FILE=input.xlsx
OUTPUT_DIR=output_wav

input.xlsx

Excelのシート名はデフォルトの「Sheet1」を使用し、以下の形式で作成してください:

番号話者再生速度音声の文章
1lj_taco1.0Welcome to our event.
2p2251.0This is a test for speaker p225.
3p2261.0This is a test for speaker p226.
4sam1.0This is a test for speaker sam.

話者は、初期状態で、

lj_taco、lj_vits、sam、ek1、p225、p226、p227、p228、p248、p252

vctk/vits の話者は vctk_speakers 配列に名前を追加したら使えます。

main.py

import os
import numpy as np
import librosa
import pandas as pd
from dotenv import load_dotenv
from TTS.api import TTS
import soundfile as sf

# .env を読み込み
load_dotenv()

# 設定取得
input_excel = os.getenv("INPUT_FILE")
output_dir = os.getenv("OUTPUT_DIR")

# 出力フォルダがなければ作成
os.makedirs(output_dir, exist_ok=True)

# VCTK の話者名 をリストに
vctk_speakers = [
    "p225", "p226", "p227", "p228", "p248", "p252"
]

# モデル名 を話者コードから筛選する関数
def resolve_model_and_speaker(speaker_str):
    if speaker_str in vctk_speakers:
        return "tts_models/en/vctk/vits", speaker_str
    elif speaker_str == "lj_taco":
        return "tts_models/en/ljspeech/tacotron2-DDC", None
    elif speaker_str == "lj_vits":
        return "tts_models/en/ljspeech/vits", None
    elif speaker_str == "sam":
        return "tts_models/en/sam/tacotron-DDC", None
    elif speaker_str == "ek1":
        return "tts_models/en/ek1/tacotron2", None
    else:
        raise ValueError(f"Unknown speaker: {speaker_str}")

# モデルに対応する最適なボコーダー一覧
def resolve_vocoder(model_name):
    vocoder_map = {
        "tts_models/en/ljspeech/tacotron2-DDC": "vocoder_models/en/ljspeech/hifigan_v2",
        "tts_models/en/ljspeech/vits": None,
        "tts_models/en/vctk/vits": None,
        "tts_models/en/sam/tacotron-DDC": None,
        "tts_models/en/ek1/tacotron2": None
    }
    return vocoder_map.get(model_name)

# librosa による速度変更関数
def change_speed(wav, sr, speed):
    if isinstance(wav, list):
        processed = []
        for w in wav:
            if hasattr(w, 'cpu'):
                w = w.cpu().numpy()
            w = np.atleast_1d(w)
            processed.append(w)
        wav = np.concatenate(processed)
    elif hasattr(wav, 'cpu'):
        wav = wav.cpu().numpy()

    wav = np.atleast_1d(wav).astype(np.float32)
    return librosa.effects.time_stretch(wav, rate=speed)

# Excelファイルを読み込み
try:
    df = pd.read_excel(input_excel)
except Exception as e:
    print(f"[ERROR] Failed to read input Excel file: {e}")
    exit(1)

error_rows = []

for index, row in df.iterrows():
    try:
        num_str, speaker_str, speed, text = row.iloc[0], row.iloc[1], row.iloc[2], row.iloc[3]
        num_padded = f"{int(num_str):03d}"
        output_filename = f"{num_padded}_{speaker_str}.wav"
        output_path = os.path.join(output_dir, output_filename)

        model_name, speaker = resolve_model_and_speaker(speaker_str)
        vocoder_name = resolve_vocoder(model_name)

        speed = float(speed) if not pd.isna(speed) else 1.0

        print(f"[INFO] Generating {output_path} with model={model_name} speaker={speaker} speed={speed} vocoder={vocoder_name}")

        tts = TTS(model_name)

        if speaker is not None:
            wav = tts.tts(text, speaker=speaker)
        else:
            wav = tts.tts(text)

        if speed != 1.0:
            wav = change_speed(wav, tts.synthesizer.output_sample_rate, speed)

        sf.write(output_path, wav, samplerate=tts.synthesizer.output_sample_rate)

    except Exception as e:
        print(f"[ERROR] Failed processing row {index + 2}: {e}")
        error_rows.append(index + 2)

if error_rows:
    print(f"[DONE] Completed with errors at rows: {', '.join(map(str, error_rows))}")
else:
    print("[DONE] All files generated successfully.")

実行

python main.py

output_wav フォルダにファイルが生成される。

ファイル名は、Excel ファイルの 番号を3桁にしたもの + 話者名 です。