Closed5

Microsoft Edge のTTSを簡単に使える「edge-tts」を試す

kun432kun432

GitHubレポジトリ

https://github.com/rany2/edge-tts

edge-tts

edge-tts は、Python コード内から、または提供されているedge-ttsまたはedge-playbackコマンドを使用して、Microsoft Edge のオンラインテキスト読み上げサービスを利用できる Python モジュールです。

kun432kun432

インストール

Colaboratoryで。

パッケージインストール

!pip install edge-tts
!pip freeze | grep -i edge-tts
出力
edge-tts==7.0.0
kun432kun432

CLIでの利用(edge-ttsコマンド)

CLIはedge-ttsコマンドとedge-playbackコマンドがある。edge-ttsコマンドはファイルへの出力、edge-playbackコマンドはどうやらその場で再生される様子(mpvというCLIのプレイヤーが別途必要になる)

Colaboratoryだとその場で再生はできないと思うので、edge-ttsコマンドでファイル出力してIPythonで再生させて試す。

まずUsage。

!edge-tts --help
出力
usage: edge-tts [-h] [-t TEXT] [-f FILE] [-v VOICE] [-l] [--rate RATE] [--volume VOLUME]
                [--pitch PITCH] [--words-in-cue WORDS_IN_CUE] [--write-media WRITE_MEDIA]
                [--write-subtitles WRITE_SUBTITLES] [--proxy PROXY]

Text-to-speech using Microsoft Edge's online TTS service.

options:
  -h, --help            show this help message and exit
  -t TEXT, --text TEXT  what TTS will say
  -f FILE, --file FILE  same as --text but read from file
  -v VOICE, --voice VOICE
                        voice for TTS. Default: en-US-EmmaMultilingualNeural
  -l, --list-voices     lists available voices and exits
  --rate RATE           set TTS rate. Default +0%.
  --volume VOLUME       set TTS volume. Default +0%.
  --pitch PITCH         set TTS pitch. Default +0Hz.
  --words-in-cue WORDS_IN_CUE
                        number of words in a subtitle cue. Default: 10.
  --write-media WRITE_MEDIA
                        send media output to file instead of stdout
  --write-subtitles WRITE_SUBTITLES
                        send subtitle output to provided file instead of stderr
  --proxy PROXY         use a proxy for TTS and voice list.

ではサンプル。

「Hello, World」と発話させたものをファイルに出力させてみる。

!edge-tts --text "Hello, world!" --write-media hello.mp3 --write-subtitles hello.srt

再生して確認

from IPython.display import Audio

display(Audio("hello.mp3", autoplay=True))

実際に生成されたものは以下

https://audio.com/kun432/audio/edge-tts-sample-1

--write-subtitlesで字幕用のタイムスタンプ入りのテキストが出力される。

!cat hello.srt
出力
1
00:00:00,050 --> 00:00:00,887
Hello world

音声は--voiceで指定できる。利用可能な音声の一覧は--list-voicesで確認できる。

!edge-tts --list-voices

めっちゃたくさんある。全142言語、全324音声。一部抜粋。

出力
Name                               Gender    ContentCategories      VoicePersonalities
---------------------------------  --------  ---------------------  --------------------------------------
af-ZA-AdriNeural                   Female    General                Friendly, Positive
af-ZA-WillemNeural                 Male      General                Friendly, Positive
am-ET-AmehaNeural                  Male      General                Friendly, Positive
am-ET-MekdesNeural                 Female    General                Friendly, Positive
ar-AE-FatimaNeural                 Female    General                Friendly, Positive
(snip)
ja-JP-KeitaNeural                  Male      General                Friendly, Positive
ja-JP-NanamiNeural                 Female    General                Friendly, Positive
(snip)
zh-TW-HsiaoChenNeural              Female    General                Friendly, Positive
zh-TW-HsiaoYuNeural                Female    General                Friendly, Positive
zh-TW-YunJheNeural                 Male      General                Friendly, Positive
zu-ZA-ThandoNeural                 Female    General                Friendly, Positive
zu-ZA-ThembaNeural                 Male      General                Friendly, Positive

日本語の場合は、男性用がja-JP-KeitaNeural、女性用がja-JP-NanamiNeuralになるみたい。

日本語で試してみる。

!edge-tts --voice ja-JP-KeitaNeural --text "あけましておめでとうございます。今年の競馬も楽しみですね!" --write-media jp_male.mp3
!edge-tts --voice ja-JP-NanamiNeural --text "あけましておめでとうございます。今年の競馬も楽しみですね!" --write-media jp_female.mp3
display(Audio("jp_male.mp3", autoplay=True))
display(Audio("jp_female.mp3", autoplay=True))

それぞれこんな感じ

https://audio.com/kun432/audio/edge-tts-sample-jp-male

https://audio.com/kun432/audio/edge-tts-sample-jp-female

発話を調整できる。

  • --rate: 発話スピード。%で指定。プラスで速く、マイナスで遅くなる。ex) +50%, -50%
  • --volume: 発話の音量。%で指定。プラスで大きく、マイナスで小さくなる。ex) +50%, -50%
  • --pitch: 声の高さ。Hzで指定。プラスで高く、マイナスで低くなる。ex) +50Hz, -50Hz

発話スピードを少し下げて、ボリュームを大きく、ピッチも上げてみた。

!edge-tts --voice ja-JP-KeitaNeural --text "あけましておめでとうございます。今年の競馬も楽しみですね!" --write-media jp_male_change.mp3 --rate=-20% --volume=+50% --pitch=+50Hz
display(Audio("jp_male_change.mp3", autoplay=True))

実際のものは以下

https://audio.com/kun432/audio/edge-tts-sample-jp-male-change

なお、以前はSSMLが使えていたようなのだが、今はもう使えないらしい。

Microsoft Edge 自体で生成できない SSML の使用を Microsoft が禁止しているため、カスタム SSML のサポートは廃止されました。つまり、カスタム SSML が役立つであろうすべてのケースはサポートできません。サービスでは、1つの <voice> タグ内に1つの <prosody> タグのみを許可しているためです。 <prosody> タグで使用できるカスタマイズオプションは、ライブラリまたはコマンドライン自体ですでに利用可能です。

kun432kun432

Pythonでの利用

READMEには個別に書いていないのだが、以下にPythonで利用する場合のサンプルがある。

https://github.com/rany2/edge-tts/tree/master/examples

import edge_tts
from IPython.display import Audio

communicate = edge_tts.Communicate(
    "あけましておめでとうございます。今年の競馬も楽しみですね!",
    "ja-JP-NanamiNeural",
    rate="+10%",
    volume="+10%",
    pitch="+10Hz",
)
communicate.save_sync("jp_female.mp3")

非同期の場合

import edge_tts
from IPython.display import Audio
import asyncio

# notebook環境では必要
import nest_asyncio
nest_asyncio.apply()


async def amain() -> None:
    communicate = edge_tts.Communicate(
        "あけましておめでとうございます。今年の競馬も楽しみですね!",
        "ja-JP-NanamiNeural",
        rate="+10%",
        volume="+10%",
        pitch="+10Hz",
    )
    await communicate.save("jp_female.mp3")

if __name__ == "__main__":
    asyncio.run(amain())

非同期ストリーミング、かつ、字幕ファイルを生成する場合。

import edge_tts
from IPython.display import Audio
import asyncio

# notebook環境では必要
import nest_asyncio
nest_asyncio.apply()


async def amain() -> None:
    communicate = edge_tts.Communicate(
        "あけましておめでとうございます。今年の競馬も楽しみですね!",
        "ja-JP-NanamiNeural",
        rate="+10%",
        volume="+10%",
        pitch="+10Hz",
    )
    submaker = edge_tts.SubMaker()
    with open("jp_female.mp3", "wb") as file:
        async for chunk in communicate.stream():
            if chunk["type"] == "audio":
                file.write(chunk["data"])
            elif chunk["type"] == "WordBoundary":
                submaker.feed(chunk)

    with open("jp_female.srt", "w", encoding="utf-8") as file:
        file.write(submaker.get_srt())


if __name__ == "__main__":
    asyncio.run(amain())

あとは、音声を個別に指定するのではなく、言語・性別・ロケール等で動的に選択するやり方についても記載がある。

kun432kun432

特にAPIキー等不要で使えるようなのだけど、これはどういう理屈なんだろう?ドキュメント的なものを探してみたけど、見当たらなかった。

TTSのクオリティはそんなに悪くはないように思えるので、個人レベルでお手軽に使うにはありかもしれない。ただ、商用では流石に使えなさそう。

このスクラップは2025/01/08にクローズされました