はじめに
前回は、テキスト読み上げツールの画面をHTMLとCSSで作りました。
今回は、JavaScriptを使って実際に音声読み上げ機能を実装します。
読み上げ処理の中心になるのは、ブラウザの音声合成機能です。
入力欄に文章を入力し、「読み上げる」ボタンを押すと、その文章をブラウザが音声で読み上げます。
JavaScriptで行う処理
今回JavaScriptで行う処理は、次の通りです。
| 処理 | 内容 |
|---|---|
| 入力文の取得 | テキストエリアの文章を取得 |
| 空欄チェック | 文章がない場合は実行しない |
| 音声一覧の取得 | ブラウザ内の音声を取得 |
| 音声設定 | 速度、高さ、音量を反映 |
| 読み上げ実行 | 入力文を音声で再生 |
| 一時停止 | 読み上げを途中で止める |
| 再開 | 一時停止した音声を再開 |
| 停止 | 読み上げを取り消す |
| 状態表示 | 現在の状態を画面に表示 |
HTML要素を取得する
最初に、HTMLで作った要素をJavaScriptから操作できるようにします。
const textArea = document.getElementById('ttsText');
const voiceSelect = document.getElementById('voiceSelect');
const speakBtn = document.getElementById('speakBtn');
const pauseBtn = document.getElementById('pauseBtn');
const resumeBtn = document.getElementById('resumeBtn');
const stopBtn = document.getElementById('stopBtn');
const clearBtn = document.getElementById('clearBtn');
const status = document.getElementById('ttsStatus');
document.getElementById() は、指定したIDを持つHTML要素を取得する命令です。
たとえば、入力欄はHTML側で次のように作っています。
<textarea id="ttsText"></textarea>
そのため、JavaScriptでは次のように取得できます。
const textArea = document.getElementById('ttsText');
スライダーの値も取得する
速度、高さ、音量のスライダーも取得します。
const rate = document.getElementById('rate');
const pitch = document.getElementById('pitch');
const volume = document.getElementById('volume');
const rateValue = document.getElementById('rateValue');
const pitchValue = document.getElementById('pitchValue');
const volumeValue = document.getElementById('volumeValue');
rate は速度、pitch は高さ、volume は音量です。
rateValue などは、スライダーの横に現在値を表示するために使います。
ブラウザ対応を確認する
音声読み上げに対応していないブラウザもあるため、最初に確認します。
if (!('speechSynthesis' in window)) {
status.textContent = 'このブラウザは音声読み上げに対応していません。';
speakBtn.disabled = true;
pauseBtn.disabled = true;
resumeBtn.disabled = true;
stopBtn.disabled = true;
}
speechSynthesis が使えない場合、読み上げ処理は実行できません。
そのため、ボタンを無効化して、ユーザーに対応していないことを知らせます。
状態表示用の関数を作る
画面に状態メッセージを表示するため、関数を作ります。
function setStatus(message) {
status.textContent = message;
}
これにより、状態表示を変えたいときは次のように書けます。
setStatus('読み上げ中です。');
毎回 status.textContent と書くより、処理が分かりやすくなります。
音声一覧を取得する
ブラウザに登録されている音声一覧を取得します。
let voices = [];
function loadVoices() {
voices = window.speechSynthesis.getVoices();
voiceSelect.innerHTML = '';
}
getVoices() により、利用可能な音声の一覧を取得できます。
ただし、音声一覧はページ読み込み直後に空になる場合があります。
そのため、後から音声一覧が読み込まれたときにも対応します。
if (typeof speechSynthesis.onvoiceschanged !== 'undefined') {
speechSynthesis.onvoiceschanged = loadVoices;
}
これにより、音声一覧が変更されたタイミングで loadVoices() が再実行されます。
日本語音声を優先する
日本語読み上げツールとして使いやすくするため、日本語音声を優先して表示します。
const japaneseVoices = voices.filter(function (voice) {
return voice.lang && voice.lang.toLowerCase().startsWith('ja');
});
voice.lang には、音声の言語情報が入っています。
日本語の場合は、ja-JP のような値になります。
プルダウンに音声を追加する
取得した音声を、選択欄に追加します。
const displayVoices = japaneseVoices.length > 0 ? japaneseVoices : voices;
displayVoices.forEach(function (voice, index) {
const option = document.createElement('option');
option.value = voice.name;
option.textContent = voice.name + '(' + voice.lang + ')';
if (index === 0) {
option.selected = true;
}
voiceSelect.appendChild(option);
});
日本語音声がある場合は日本語音声だけを表示し、ない場合はすべての音声を表示します。
選択された音声を取得する
ユーザーが選んだ音声を取得する関数です。
function getSelectedVoice() {
return voices.find(function (voice) {
return voice.name === voiceSelect.value;
});
}
プルダウンで選ばれた音声名と、音声一覧の中の名前が一致するものを探しています。
入力文を取得する
読み上げ処理では、まず入力欄の文字を取得します。
const text = textArea.value.trim();
trim() により、前後の余分な空白を取り除きます。
入力欄が空の場合は、読み上げを実行しません。
if (!text) {
setStatus('読み上げる文章を入力してください。');
return;
}
読み上げ処理を作る
読み上げの中心になる関数です。
function speakText() {
const text = textArea.value.trim();
if (!text) {
setStatus('読み上げる文章を入力してください。');
return;
}
window.speechSynthesis.cancel();
const selectedVoice = getSelectedVoice();
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = selectedVoice ? selectedVoice.lang : 'ja-JP';
utterance.voice = selectedVoice || null;
utterance.rate = Number(rate.value);
utterance.pitch = Number(pitch.value);
utterance.volume = Number(volume.value);
utterance.onstart = function () {
setStatus('読み上げ中です。');
};
utterance.onend = function () {
setStatus('読み上げが完了しました。');
};
utterance.onerror = function () {
setStatus('読み上げ中にエラーが発生しました。');
};
window.speechSynthesis.speak(utterance);
}
この処理の中で、入力文、音声、速度、高さ、音量をまとめて設定しています。
SpeechSynthesisUtteranceとは
SpeechSynthesisUtterance は、読み上げる内容をまとめるためのものです。
const utterance = new SpeechSynthesisUtterance(text);
この中に、次の設定を入れます。
| 設定 | 内容 |
|---|---|
| lang | 読み上げ言語 |
| voice | 読み上げ音声 |
| rate | 速度 |
| pitch | 高さ |
| volume | 音量 |
そして最後に、次のコードで読み上げます。
window.speechSynthesis.speak(utterance);
ボタンに処理をつなぐ
作った関数を、ボタンのクリックに接続します。
speakBtn.addEventListener('click', speakText);
これで、「読み上げる」ボタンをクリックしたときに speakText() が実行されます。
一時停止、再開、停止を作る
音声読み上げには、一時停止、再開、停止も追加できます。
pauseBtn.addEventListener('click', function () {
window.speechSynthesis.pause();
setStatus('一時停止しました。');
});
resumeBtn.addEventListener('click', function () {
window.speechSynthesis.resume();
setStatus('読み上げを再開しました。');
});
stopBtn.addEventListener('click', function () {
window.speechSynthesis.cancel();
setStatus('読み上げを停止しました。');
});
それぞれの違いは次の通りです。
| 処理 | 内容 |
|---|---|
| pause | 途中で一時停止 |
| resume | 一時停止した位置から再開 |
| cancel | 読み上げを完全に取り消す |
クリアボタンを作る
入力欄を空にするボタンも作ります。
clearBtn.addEventListener('click', function () {
window.speechSynthesis.cancel();
textArea.value = '';
setStatus('');
});
クリア時には、読み上げも停止します。
これにより、入力欄を消したあとに音声だけが流れ続ける状態を防げます。
スライダーの表示値を更新する
速度、高さ、音量の数字表示も更新します。
rate.addEventListener('input', function () {
rateValue.textContent = Number(rate.value).toFixed(1);
});
pitch.addEventListener('input', function () {
pitchValue.textContent = Number(pitch.value).toFixed(1);
});
volume.addEventListener('input', function () {
volumeValue.textContent = Number(volume.value).toFixed(1);
});
input イベントは、スライダーを動かしたときに発生します。
toFixed(1) により、小数点1桁で表示しています。
まとめ
今回は、JavaScriptでテキスト読み上げ機能を作りました。
重要な流れは次の通りです。
| 順番 | 処理 |
|---|---|
| 1 | 入力欄の文章を取得 |
| 2 | 空欄か確認 |
| 3 | 音声設定を取得 |
| 4 | SpeechSynthesisUtteranceを作成 |
| 5 | 速度、高さ、音量を設定 |
| 6 | speechSynthesis.speakで読み上げ |
| 7 | 一時停止、再開、停止に対応 |
この仕組みを使えば、外部APIなしで、ブラウザ上だけで音声読み上げツールを作れます。
次回は、WordPressやWebサイトに設置し、お役立ちツールとして公開する方法を解説します。
