Google Cloud Text-to-SpeechでSSMLを使いこなす
3行で
文章を音声に変換(生成)するText To Speech(TTS)という分野に興味を持ちました。
日本語の文章を読ませるといろいろ変だったので改善方法を探したところSSMLというのを見つけました。
SSMLで色々実験してみたので書き残します。
SSMLとは?
SSML(Speech Synthesis Markup Language)は、音声合成システムに音声の出力方法を指示するためのXMLベースのマークアップ言語です。
SSMLを使用することで、テキストをそのまま読み上げるだけでなく、以下のような細かな制御を行うことができます。
- 音声のピッチ(高低)の調整
- 発話速度の変更
- 音量の調整
- 一時停止の挿入
- 発音の明示
- 特定の単語の強調
SSMLは、W3Cによって標準化されており、様々な音声合成システムで利用することができます。
SSMLの基本的な書き方
SSMLは、<speak>タグで囲まれたテキストの中に、様々なタグを埋め込むことで音声の出力方法を指定します。
例えば、何も手を加えない以下のようなSSMLを記述すると「こんにちは。今日はいい天気ですね。」という文章を、読み上げます。
<speak>
こんにちは。今日はいい天気ですね。
</speak>
また、以下のようなSSMLを記述すると、ゆっくりとした速度で少し高いピッチで「こんにちは」、速い速度で少し低いピッチで「今日はいい天気ですね」と読み上げることができます。
<speak>
<prosody rate="slow" pitch="+5st">こんにちは。</prosody>
<prosody rate="fast" pitch="-5st">今日はいい天気ですね。</prosody>
</speak>
SSMLを使うメリット
SSMLを使用することで、音声合成による音声出力をより細かく制御し、表現力を豊かにすることができます。具体的には、読み上げのスピード、ピッチ、音量、ポーズの長さなどを自由に調整することが可能です。これにより、機械的な読み上げ音声を、より自然で人間らしい表現に近づけることができます。
個人的には青空文庫などの物語の読み上げの生成に使いたいと思っています。登場人物のセリフや場面の雰囲気に合わせて音声特性を変更することで、より臨場感のある朗読体験を提供できるのではないでしょうか。
Google Cloud Text-to-SpeechでSSMLを使う
というわけで、Google Cloud Text-to-Speechで色々実験してみたので、その結果を残しておきたいと思います。今回は青空文庫から太宰治の斜陽の最初の冒頭を対象として、いろいろいじってみました。
XMLスケルトン
Document Formによれば、SSMLのヘッダー例として2つ上げられています。
<?xml version="1.0"?>
<speak version="1.1" xmlns="http://www.w3.org/2001/10/synthesis"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/2001/10/synthesis
http://www.w3.org/TR/speech-synthesis11/synthesis.xsd"
xml:lang="en-US">
<?xml version="1.0"?>
<speak version="1.1" xmlns="http://www.w3.org/2001/10/synthesis"
xml:lang="en-US">
ここではスキーマを指定することとし、langはja-JPに変更します。というわけで、下記のようなスケルトンを作成しました。
<?xml version="1.0"?>
<speak version="1.1" xmlns="http://www.w3.org/2001/10/synthesis"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/2001/10/synthesis
http://www.w3.org/TR/speech-synthesis11/synthesis.xsd"
xml:lang="ja-JP">
</speak>
ここから色々追加していくのですが、なんか面倒(というか規格に厳密に沿っていなくていいんだけど)・・という場合は下記から始めてもOKです。
<speak>
</speak>
meta, metadata
いわゆるメタデータを記述するにはmeta要素、または、metadata要素で記述します。metaは1行ごと、metadataはメタデータのコンテナのようなイメージです。
なお、metadataはドキュメントによれば、RDF+Dublin Core Metadataを推奨する(recommended)とのこと。Dublin Core MetadataはRFC5013に規定されているようです。
あと重要な点としてはmetaもmetadataもspeakの最初の要素として記述しないといけないことです。生成側としては無視してくれるかもしれませんが、xmllintを実施すると怒られます。
$ xmllint --noout --schema synthesis.xsd shayo.xml
shayo.xml:17: element meta: Schemas validity error : Element '{http://www.w3.org/2001/10/synthesis}meta': This element is not expected. Expected is one of ( {http://www.w3.org/2001/10/synthesis}aws, {http://www.w3.org/2001/10/synthesis}token, {http://www.w3.org/2001/10/synthesis}w, {http://www.w3.org/2001/10/synthesis}voice, {http://www.w3.org/2001/10/synthesis}prosody, {http://www.w3.org/2001/10/synthesis}audio, {http://www.w3.org/2001/10/synthesis}emphasis, {http://www.w3.org/2001/10/synthesis}sub, {http://www.w3.org/2001/10/synthesis}say-as, {http://www.w3.org/2001/10/synthesis}phoneme ).
shayo.xml fails to validate
以上を踏まえてスケルトンは以下のようになりました。斜陽を朗読したいので、既にそのようなデータになっています。
<?xml version="1.0"?>
<speak version="1.1" xmlns="http://www.w3.org/2001/10/synthesis"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/2001/10/synthesis
http://www.w3.org/TR/speech-synthesis11/synthesis.xsd"
xml:lang="ja-JP">
<metadata>
<rdf:RDF xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs = "http://www.w3.org/2000/01/rdf-schema#"
xmlns:dc = "http://purl.org/dc/elements/1.1/">
<!-- Metadata about the synthesis document -->
<rdf:Description dc:title="斜陽 朗読"
dc:description="Google Cloud Text-to-Speechによる斜陽の朗読です"
dc:language="ja-JP"
dc:date="2024-12-31"
dc:rights="Copyright 2002 Akira Otaka"
dc:format="application/ssml+xml" >
<dc:creator>
<rdf:Seq ID="CreatorsAlphabeticalBySurname">
<rdf:li>Akira Otaka</rdf:li>
</rdf:Seq>
</dc:creator>
</rdf:Description>
</rdf:RDF>
</metadata>
</speak>
p,s要素
ドキュメントによればオプション(optional)だとされています。XMLを直書きしているとある方が分かりやすいですが、出来上がってみるとタグ数が多くて「うーん」という気持ちになります。正直、これは好みかもしれません。
p,s要素をつけない例とつける例を示し、それぞれText-to-Speechがどのように朗読しているのかも置いておきます。(ちゃんとそれぞれ生成していますが、違いが分かりますでしょうか?私は分かりませんでした・・)
p,s要素なし
<speak>
こんにちは。今日はいい天気ですね。
</speak>
p,s要素あり
<speak>
<p>
<s>こんにちは。</s>
<s>今日はいい天気ですね。</s>
</p>
</speak>
sub要素
今回はこれが一つの肝だと思います。このSSMLの策定に(たぶん)中国の方と思しき名前が多いのも、こういった難しさ故なのかと。なお、sub要素を使用する場合、alias属性は必須(required)となります。
使い方と生成例をどうぞ
「一さじ」をsub要素なし
<speak>
一さじ
</speak>
「一さじ」をsub要素あり
<speak>
<sub alias="ひとさじ">一さじ</sub>
</speak>
prosody要素
ドキュメントによれば、ピッチ、話速、音量を制御できるとあります。個人的にはこれが少し面白くてSSMLをいろいろ弄っていたまであります。なお、全ての属性はオプション(optional)です。
prosody要素なし
<speak>
<p>
<s>朝、食堂でスウプを<sub alias="ひとさじ">一さじ</sub>、すっと吸ってお母さまが、</s>
<s>「あ」</s>
<s>と幽かな叫び声をお挙げになった。</s>
</p>
</speak>
私の中のお母さまはこんな野太い「あ」は出さないと思うんですよね。
prosody要素あり
<speak>
<p>
<s>朝、食堂でスウプを<sub alias="ひとさじ">一さじ</sub>、すっと吸ってお母さまが、</s>
<s><prosody rate="slow" pitch="+7st">「あ」</prosody></s>
<s>と幽かな叫び声をお挙げになった。</s>
</p>
</speak>
少なくとも野太い「あ」はなくなりました。もっと高くてもっとクリアな音声を出したいと思ってドキュメントと格闘しているところです。
最終的にどうなったか
というわけで斜陽の冒頭を書いてみるとこうなります。読み仮名を指定したり、声の抑揚などを変えることで感情を(少しは)表現出来た気がしています。
<?xml version="1.0"?>
<speak version="1.1" xmlns="http://www.w3.org/2001/10/synthesis"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/2001/10/synthesis
http://www.w3.org/TR/speech-synthesis11/synthesis.xsd"
xml:lang="ja-JP">
<metadata>
<rdf:RDF xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs = "http://www.w3.org/2000/01/rdf-schema#"
xmlns:dc = "http://purl.org/dc/elements/1.1/">
<!-- Metadata about the synthesis document -->
<rdf:Description dc:title="斜陽 朗読"
dc:description="Google Cloud Text-to-Speechによる斜陽の朗読です"
dc:language="ja-JP"
dc:date="2024-12-31"
dc:rights="Copyright 2002 Akira Otaka"
dc:format="application/ssml+xml" >
<dc:creator>
<rdf:Seq ID="CreatorsAlphabeticalBySurname">
<rdf:li>Akira Otaka</rdf:li>
</rdf:Seq>
</dc:creator>
</rdf:Description>
</rdf:RDF>
</metadata>
<p>
<s>朝、食堂でスウプを<sub alias="ひとさじ">一さじ</sub>、すっと吸ってお母さまが、</s>
<s><prosody rate="slow" pitch="+7st">「あ」</prosody></s>
<s>と<sub alias="かすかな">幽かな</sub>叫び声をお挙げになった。</s>
<s>「髪の毛?」</s>
<s>スウプに何か、イヤなものでも入っていたのかしら、と思った。</s>
<s><prosody rate="slow" pitch="+4st">「いいえ」</prosody></s>
<s>お母さまは、何事も無かったように、またひらりと<sub alias="ひとさじ">一さじ</sub>、スウプをお口に流し込み、すましてお顔を横に向け、お勝手の窓の、満開の<sub alias="やまざくら">山桜</sub>に視線を送り、そうしてお顔を横に向けたまま、またひらりと<sub alias="ひとさじ">一さじ</sub>、スウプを小さなお唇のあいだに滑り込ませた。</s>
<s><prosody rate="slow">ヒラリ</prosody>、という形容は、お母さまの場合、決して誇張では無い。</s>
<s>婦人雑誌などに出ているお食事のいただき方などとは、てんでまるで、違っていらっしゃる。</s>
<s>弟の<sub alias="なおじ">直治</sub>がいつか、お酒を飲みながら、姉の私に向ってこう言った事がある。</s>
</p>
</speak>
文節の間はもう少し取りたいとか好みがいろいろ出てきて楽しいですね。
まとめ
本記事では、SSMLの概要、基本的な書き方、Google Cloud Text-to-Speechでの生成結果について説明しました。
SSMLを使用することで、音声のピッチ、速度、音量などを細かく調整し、より自然で聞き取りやすい音声を作成することができます。Google Cloud Text-to-SpeechでSSMLを活用することで、音声合成の可能性をさらに広げることが可能になります。たぶん。
ぜひSSMLを試してみてください。
参考文献
- Google Cloud Text-to-Speech:音声合成マークアップ言語(SSML)
- Microsoft Speech Service:音声合成マークアップ言語 (SSML) の概要
- Speech Synthesis Markup Language (SSML) Version 1.1
- RFC5013: The Dublin Core Metadata Element Set
- xmllintがうまく動かないのでGeminiさんと問題点を探してみた
参考コード
Text-to-Speechで作成したmp3音源を、mp4としてYouTubeに上げるための前処理
ffmpeg -f lavfi -i color=c=black:s=1280x720 -i sample9.mp3 -vf "drawtext=text='sample-09':fontcolor=white:fontsize=30:x=(w-text_w)/2:y=(h-text_h)/2" -c:v libx264 -c:a copy -shortest sample-09.mp4
XMLのチェック
xmllint --noout --schema synthesis.xsd shayo.xml
Discussion