SSMLと韻律の制御
Speech Synthesis Markup Languageによる、間、強調、速度、ピッチの指定を学びます。
「SSMLと韻律の制御」はCoddyKit上の無料AI Prompt Engineeringレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Prompt Engineering学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Prompt Engineeringコースには全4レッスンが含まれています。
SSMLとは
SSML(Speech Synthesis Markup Language、音声合成マークアップ言語)は、TTSエンジンがテキストを読み上げる方法を細かく制御できるXMLベースの言語です。Google Cloud TTS、Amazon Polly、Microsoft Azure TTSなど、多くのサービスでサポートされています。
プレーンテキストでは単語しか指定できませんが、SSMLでは間、強調、速度、ピッチ、発音などを制御できます。
SSMLの基本構造
すべてのSSMLドキュメントは<speak>タグで囲みます。内部では、プレーンテキストとSSMLのマークアップ要素を組み合わせます。TTSエンジンはSSMLを処理し、それに応じて音声を生成します。
# SSML document structure
SSML_BASIC = """
<speak>
Welcome to the course.
<break time="500ms"/>
Today we will cover three topics.
First, we will discuss SSML basics.
<break time="300ms"/>
Second, we will explore prosody control.
<break time="300ms"/>
And third, we will look at advanced features.
</speak>
"""
# Send to Google Cloud TTS
from google.cloud import texttospeech
client_tts = texttospeech.TextToSpeechClient()
input_text = texttospeech.SynthesisInput(ssml=SSML_BASIC)
voice = texttospeech.VoiceSelectionParams(
language_code='en-US',
ssml_gender=texttospeech.SsmlVoiceGender.NEUTRAL
)
audio_config = texttospeech.AudioConfig(
audio_encoding=texttospeech.AudioEncoding.MP3
)
print('SSML document ready to synthesize')break要素
<break>は音声に間を挿入します。自然なリズムを作ったり、リスト項目を区切ったり、演出効果を加えたりするために使用します。time属性はミリ秒(ms)または秒(s)を受け取ります。
# break element examples
BREAK_EXAMPLES = """
<speak>
Are you ready?
<break time="1s"/>
Let us begin.
The three rules are:
number one,
<break time="300ms"/>
always test your code.
<break time="200ms"/>
Number two,
<break time="300ms"/>
write clear documentation.
<break time="200ms"/>
And number three,
<break time="300ms"/>
review before you ship.
<break strength="x-strong"/>
That is all for today.
</speak>
"""
# break strength values: none, x-weak, weak, medium, strong, x-strong
# These map to approximate pause durations defined by the engine
print('break time: explicit duration (e.g. 500ms)')
print('break strength: semantic pause level (weak/medium/strong)')emphasis要素
<emphasis>は単語を強調します。エンジンはその単語を、より大きな声、遅い速度、または高いピッチで発音します。控えめに使用してください。強調しすぎると不自然に聞こえます。
EMPHASIS_EXAMPLES = """
<speak>
This update is
<emphasis level="strong">critically important</emphasis>.
Please read it carefully.
The deadline is
<emphasis level="moderate">this Friday</emphasis>,
not next week.
We
<emphasis level="reduced">recommend</emphasis>
enabling this feature, but it is optional.
</speak>
"""
# emphasis level values:
# strong — much more stress (louder, slower, higher pitch)
# moderate — some additional stress (default if level omitted)
# reduced — less stress (quieter, faster)
print('Use strong for critical information')
print('Use reduced for parenthetical or secondary information')prosody要素:rate
<prosody rate>は話す速度を制御します。重要な情報では速度を落とし、補足情報や免責事項では速度を上げます。
PROSODY_RATE_EXAMPLES = """
<speak>
<prosody rate="slow">
This is the most important thing to remember.
Take a moment to let it sink in.
</prosody>
<prosody rate="medium">
Now, for some context about how we got here.
</prosody>
<prosody rate="fast">
And now a quick summary of less critical details that you
can refer back to in the documentation.
</prosody>
</speak>
"""
# rate values:
# x-slow, slow, medium (default), fast, x-fast
# Or percentage: rate="75%" (75% of normal speed)
# Or absolute: rate="200 words per minute"
print('Slow: for emphasis, complex information, or pauses for thought')
print('Fast: for disclaimers, secondary info, rapid listing')prosody要素:pitch
<prosody pitch>は声の基本周波数を調整します。疑問、興奮、深刻な内容など、トーンの変化を示すために使用します。
PROSODY_PITCH_EXAMPLES = """
<speak>
<prosody pitch="high" rate="medium">
Exciting news! We just launched a brand new feature!
</prosody>
<prosody pitch="low" rate="slow">
Unfortunately, this service will be discontinued.
We apologize for any inconvenience.
</prosody>
<prosody pitch="+20%">
Did you know that our users save three hours per week on average?
</prosody>
<prosody pitch="-15%">
Please review the terms and conditions carefully.
</prosody>
</speak>
"""
# pitch values:
# x-low, low, medium, high, x-high
# Or relative: +20%, -15%
# Or semitones: +2st, -4st
print('High pitch: excitement, questions, announcements')
print('Low pitch: serious, cautionary, or somber content')say-as要素
<say-as>は、テキストをどのように解釈するかをTTSエンジンに伝えます。日付、電話番号、通貨、文字などとして解釈させることができます。数字や特殊な値を確実に処理する方法です。
SAY_AS_EXAMPLES = """
<speak>
Your appointment is on
<say-as interpret-as="date" format="mdy">01/15/2025</say-as>.
Call us at
<say-as interpret-as="telephone">1-800-555-1234</say-as>.
Your confirmation code is
<say-as interpret-as="characters">XK7T9</say-as>.
The total is
<say-as interpret-as="currency" language="en-US">$47.50</say-as>.
This is version
<say-as interpret-as="characters">2.3.1</say-as>
of the software.
</speak>
"""
# interpret-as values:
# characters — spell out each character
# cardinal — number as cardinal ("forty-seven")
# ordinal — "forty-seventh"
# fraction — "three halves"
# date — format string controls order
# telephone — phone number formatting
# currency — monetary value with currency name
print('say-as is the most reliable way to control number pronunciation')phoneme要素
<phoneme>は、TTSエンジンが繰り返し誤発音する単語(ブランド名、技術用語、外国語)に、明示的な発音を指定します。
PHONEME_EXAMPLES = """
<speak>
Welcome to
<phoneme alphabet="ipa" ph="ent.ro.pi">Entropiq</phoneme>,
the leading analytics platform.
Our CEO,
<phoneme alphabet="ipa" ph="joo.serf">Josef</phoneme>,
will present the results.
This API uses
<phoneme alphabet="ipa" ph="kwer.i">GraphQL</phoneme>
for data fetching.
</speak>
"""
# IPA (International Phonetic Alphabet) is the most precise
# x-sampa is an alternative ASCII-friendly phonetic alphabet
# Use an IPA converter tool to find the right phonemes:
# - https://tophonetics.com
# - Dictionary.com pronunciation guides use IPA
print('Use phoneme for brand names, technical terms, proper nouns')
print('Test with multiple phoneme values until it sounds right')Amazon PollyでのSSML
Amazon Pollyは標準SSMLに加えて、Polly固有の拡張機能をサポートしています。APIの使用方法はGoogle Cloud TTSと少し異なりますが、SSMLマークアップ自体は同じです。
import boto3
polly = boto3.client('polly', region_name='us-east-1')
SSML_CONTENT = """
<speak>
<prosody rate="slow" pitch="low">
Welcome to our quarterly earnings call.
</prosody>
<break time="1s"/>
We are pleased to report
<emphasis level="strong">record revenue</emphasis>
of
<say-as interpret-as="currency" language="en-US">$4200000</say-as>
this quarter.
</speak>
"""
response = polly.synthesize_speech(
Text=SSML_CONTENT,
TextType='ssml', # Tell Polly this is SSML
OutputFormat='mp3',
VoiceId='Joanna', # US English female voice
)
if 'AudioStream' in response:
with open('output.mp3', 'wb') as f:
f.write(response['AudioStream'].read())
print('Audio saved to output.mp3')LLMでSSMLを生成する
プレーンテキストをSSMLで注釈付けした音声スクリプトに変換するために、LLMを使用できます。これにより、通常どおりコンテンツを作成してから、TTSで最適に読み上げられるよう後処理できます。
import anthropic
client = anthropic.Anthropic(api_key='sk-ant-...')
SSML_GENERATION_PROMPT = (
'Convert the following text into an SSML document for Google Cloud TTS.\n\n'
'Rules:\n'
'- Wrap the entire output in <speak> tags\n'
'- Add <break time="500ms"/> between major points\n'
'- Add <emphasis level="strong"> around key terms or critical information\n'
'- Use <prosody rate="slow"> for important warnings or summaries\n'
'- Use <say-as interpret-as="date"> for all dates\n'
'- Use <say-as interpret-as="telephone"> for phone numbers\n'
'- Return only the SSML, no explanation\n\n'
'Text: {text}'
)
def text_to_ssml(text):
prompt = SSML_GENERATION_PROMPT.format(text=text)
r = client.messages.create(
model='claude-opus-4-5',
max_tokens=2000,
messages=[{'role': 'user', 'content': prompt}]
)
return r.content[0].textSSMLの検証とテスト
不正なSSMLはTTS APIエラーを引き起こすか、生のXMLタグをそのまま読み上げる状態にフォールバックします。本番環境に送る前に、必ずSSMLを検証してください。
import xml.etree.ElementTree as ET
def validate_ssml(ssml_string):
"""
Basic SSML validation: checks XML is well-formed
and has a <speak> root element.
"""
try:
root = ET.fromstring(ssml_string)
if root.tag != 'speak':
return False, 'Root element must be <speak>'
# Check for common misuse patterns
warnings = []
for elem in root.iter():
if elem.tag == 'break' and 'time' not in elem.attrib and 'strength' not in elem.attrib:
warnings.append('<break> has no time or strength attribute')
return True, warnings if warnings else 'Valid'
except ET.ParseError as e:
return False, f'XML parse error: {e}'
# Test
valid_ssml = '<speak>Hello <break time="500ms"/> world.</speak>'
bad_ssml = '<speak>Hello <break> world.</speak>' # break not self-closed
print(validate_ssml(valid_ssml))
print(validate_ssml(bad_ssml))理解度チェック:SSMLのsay-as
SSMLの<say-as>要素の主な目的は何ですか。
まとめ:SSMLとプロソディ制御
SSMLはTTS出力を細かく制御できます。主な要素は、<break>(時間または強度による間)、<emphasis>(強調レベル:strong/moderate/reduced)、<prosody rate>(読み上げ速度)、<prosody pitch>(声の周波数)、<say-as>(数字、日付、電話番号の意味解釈)、<phoneme>(IPAによる明示的な発音)です。Google Cloud TTSとAmazon Pollyはいずれも、同じ中核タグセットでSSMLをサポートしています。LLMを使ってプレーンテキストからSSMLを自動生成し、本番環境に送る前に、XMLの整形式性を必ず検証してください。
AI チューターと学ぶ AI Prompt Engineering — 無料
ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。
- コース
- 53
- レッスン
- 199
よくある質問
「SSMLと韻律の制御」レッスンは無料ですか?
はい。「SSMLと韻律の制御」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Prompt Engineeringコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Prompt Engineeringコースには全4レッスンが含まれています。
「SSMLと韻律の制御」で何を学びますか?
Speech Synthesis Markup Languageによる、間、強調、速度、ピッチの指定を学びます。 ブラウザで直接実行するハンズオンコードでAI Prompt Engineeringを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Prompt Engineeringを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Prompt Engineeringは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「SSMLと韻律の制御」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Prompt Engineeringレッスンでコードを書いて実行できますか?
はい。すべてのAI Prompt Engineeringレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。