はじめに
@t-yamanashi さんの記事を参考に、 Livebook で VOICEVOX の ずんだもん や WhiteCUL に喋ってもらいました
実装したノートブックはこちら
クレジット
VOICEVOX:ずんだもん
VOICEVOX:WhiteCUL
VOICEVOX とは
商用・非商用問わず無料で使えるテキスト読み上げソフトウェアです
様々なキャラクターの音声でテキストを読み上げることができます
音声の利用については各音声の利用規約に則ります
実行環境
- macOS Ventura 13.4.1
- VOICEVOX 0.14.7
- Elixir 1.15.4
- Erlang 26.0.2
- Livebook 0.10.0
事前準備
VOICEVOX 公式から VOICEVOX をインストールし、起動しておきます
VOICEVOX を起動している状態では、 http://localhost:50021 で VOICEVOX の API が呼び出せます
また、以下の URL で API の仕様を確認できます
やはり OpenAPI は偉大
これさえ参照すれば Elixir から VOICEVOX を操作し放題です
この状態で Livebook を起動し、ノートブックを作成します
セットアップ
Mix.install([
{:kino, "~> 0.10"},
{:req, "~> 0.3"}
])
音声出力等のために Kino 、 VOICEVOX API へのリクエストのために Req をインストールしています
音声一覧の取得
VOICEVOX には 2023年7月現在、 26 キャラクターの音声が存在します
また、各キャラに「ノーマル」「たのしい」「かなしい」「びえーん」などのスタイルが複数存在します
音声を喋ってもらうとき、どの声にするのかを指定する必要があるため、まずは音声ID、キャラクター、スタイルの一覧を取得し、目当ての音声を探します
音声一覧を取得するためには core_version を指定する必要があります
以下のコードを実行し、 VOICEVOX の core_version を取得します
core_version =
"http://localhost:50021/core_versions"
|> Req.get!()
|> Map.get(:body)
|> Enum.at(0)
実行結果は "0.14.4"
になります
VOICEVOX 本体のバージョンは 0.14.7 ですが、コアのバージョンは 0.14.4 のようです
では、この値を使って音声の一覧を取得します
Req.new(url: "http://localhost:50021/speakers", params: %{core_version: core_version})
|> Req.get!()
|> Map.get(:body)
|> Enum.flat_map(fn speaker ->
speaker["styles"]
|> Enum.map(fn style ->
%{
name: speaker["name"],
id: style["id"],
style_name: style["name"]
}
end)
end)
|> Enum.sort_by(& &1.id)
|> Kino.DataTable.new()
id: 0
が「四国めたん」の「あまあま」、 id: 1
が「ずんだもん」の「あまあま」というように一覧が取得できました
この一覧から id を選択し、音声を喋ってもらいます
音声合成
まず「ずんだもん」の「ノーマル」に喋ってもらいます
喋ってもらいたい内容を text
に指定し、「ずんだもん」「ノーマル」の音声id 3 を指定します
先に音声合成用のクエリを生成します
クエリ生成によってテキストをカナに変換し、各音毎に高さやアクセントを設定しています
その後、生成したクエリを使って音声合成し、結果として音声のバイナリデータを取得します
text = "ずんだもんなのだ。エリクサー使いのアルケミストになったのだ"
speaker_id = 3
# 音声合成用のクエリを生成する
audio_query =
Req.new(
url: "http://localhost:50021/audio_query",
params: %{
text: text,
speaker: speaker_id
}
)
|> Req.post!()
|> Map.get(:body)
# クエリを使って音声を合成する
data =
Req.new(
url: "http://localhost:50021/synthesis",
params: %{speaker: speaker_id}
)
|> Req.post!(json: audio_query)
|> Map.get(:body)
音声再生
VOICEVOX から取得したバイナリのままでは Web 上で再生できないので、 Base64 エンコードします
base64 = Base.encode64(data)
結果は "UklGRiRSBABXQVZFZm10IBAAAAABA..."
というような長い文字列になります
この文字列を HTML の audio タグの src に指定することで音声を再生します
Kino.HTML.new("""
<audio controls src="data:audio/wav;base64,#{base64}">
</audio>
""")
モジュール化
使いやすいようにモジュール化しました
defmodule VoiceVox do
@base_url "http://localhost:50021"
defp get_audio_query(text, speaker_id) do
Req.new(
url: "#{@base_url}/audio_query",
params: %{
text: text,
speaker: speaker_id
}
)
|> Req.post!()
|> Map.get(:body)
end
defp synthesis(audio_query, speaker_id) do
Req.new(
url: "#{@base_url}/synthesis",
params: %{speaker: speaker_id}
)
|> Req.post!(json: audio_query)
|> Map.get(:body)
end
defp view(data) do
base64 = Base.encode64(data)
Kino.HTML.new("""
<audio controls src="data:audio/wav;base64,#{base64}">
</audio>
""")
end
def new(text, speaker_id) do
text
|> get_audio_query(speaker_id)
|> synthesis(speaker_id)
|> view()
end
end
今度はVOICEVOXの「面白い女」で有名な「WhiteCUL」「びえーん」で喋ってもらいます
VoiceVox.new("こんにちは。WhiteCULです。今日はライブブックから喋っています", 26)
まとめ
VOICEVOX は API を備えているので、 Elixir からも簡単に操作できました
また、音声データも Base64 エンコーディングすることで Livebook 上で再生できました
実は初めて YouTube に動画を投稿したので、これからちょくちょく Livebook ネタを投稿していこうと思います