音声読み上げについてSpeechSynthesis(Web Speech API)

らら
らら

はじめに

となりのほうで、アクセシビリティの音声読み上げの話が聞こえてきて、あ!IEもそろそろないし、javascriptでコントロールできるSpeechSynthesisって

どうなったんだろと気になり、3-4年前に試したのを再チャレンジ。

前回は、IEで使えない。Chromeの音声Google 日本語ja-JPがおかしい・・、漢字の読み上げの読みが変などで断念した記憶が・・

いろいろ、公的機関のホームページ見てみると、ReadSpeakerってがよく目につく、あとブラウザー標準で読み上げをする方法が記載されているのもちらほらと・・

これは・・・・

あとWindows7の時代Google 日本語ja-JPというのがひとつだけだったようでWindows 10 からMicrosoft Ayumi - Japanese (Japan) ja-JP、Microsoft Haruka - Japanese (Japan) ja-JP、Microsoft Ichiro - Japanese (Japan) ja-JP、Microsoft Sayaka - Japanese (Japan) ja-JP

が追加されたよう・・

Chromeの不具合、下記から参照、対応ブラウザーも確認できます。

https://caniuse.com/?search=Speech%20Synthesis

バージョン55以降のChromeでの音声合成は、Windows 7および10、Ubuntu 14.04、場合によっては他のプラットフォームで約15秒後に再生を停止します。

これは当時Google 日本語ja-JPのみだったので、Googleの音声データの特性らしい。

ReadSpeakerについて

https://readspeaker.jp/

再テスト

前に作った、サンプルを探してきて、公的機関のホームページで見たブラウザー標準で読み上げをする方法でまず、読み上げる文字を選択して読み上げるます。って

あったので、ボタンでさくっていうのを作るか・・・

その前に、githubとか検索していたら、Articulate.jsをいうのを発見!見た目思った通りな感じ。。いいんじゃないか?これ!

Articulate.jsは、内部でSpeechSynthesisを使用していて、jQueryと同様のセレクターで読み上げする箇所を指定できる。

日本語の説明が無かったのでとりあえず下記に日本語(適当)を作成しておく、本家とはかなり違うので、本家参照してくださいね。

複数の読み上げボタンがありますが、再生中は、他の再生は行えません。なので上部に追従の停止ボタンを付けています。一度停止してから読み上げしてください。

設定も停止して、読み上げボタンを押したときに反映されます。

デモでArticulate.jsで作ったサンプル

articulate.min.jsインストール

articulate.min.jsを下記からダウンロードしてjQueryと一緒に呼び出しします。

http://articulate.purefreedom.com/

<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js'></script>
<script src='./articulate.js'></script>

使い方

jQueryと同様のセレクターの記述が可能なので、読み上げしたい箇所をセレクター単位で指定できます。


	$('article').articulate('speak');

h1,h2,pタグをだけを読み上げする


	$('h1,h2,p').articulate('speak');

内部的には、Articulate.jsは、一致した要素のセットとそのすべての子の要素およびテキストノードのクローンを作成します。 次に、デフォルトのルールセットを使用してこのクローンを解析し、何を読み上げして無視するかを決定し、適切な一時停止を追加して、すべてが物語のように聞こえるようにします。

ドキュメント

基本の関数

メソッド 説明
$(selector).articulate('speak'); jQueryのセレクターを使用して指定した DOM エレメントのテキストの部分の読み上げをします。子のDOM エレメントまで反映します。
$().articulate('pause'); 読み上げを一時停止します。
$().articulate('resume'); 読み上げを一時停止した後で再開します。
$().articulate('stop'); 読み上げを停止します。

音声パラメータ

メソッド 説明
$().articulate('rate', number); 音声の速度を設定します。 デフォルト = 1.1; 設定範囲 = [0.1 - 10]
$().articulate('pitch', number); 音声の再生ピッチを設定します。 デフォルト = 1.0; 設定範囲 = [0 - 2]
$().articulate('volume', number); 音声の音量を設定します。デフォルト = 1.0; 設定範囲 = [0 - 1]

メモ: 数値を省略すると、パラメータはデフォルト値にリセットされます。変更は、次の再生時に有効になります。途中から変更は有効になりません。

Read-Only属性

メソッド 説明
$().articulate('enabled'); ブラウザーがWeb Speech API(window.speechSynthesis)をサポートしているか戻り値 (true / false)で返します。試してみたが動作しない・・・みたいです。
$().articulate('isSpeaking'); 読み上げが完了したか。停止されていないかを戻り値 (true / false) で返します。window.speechSynthesis.speaking
$().articulate('isPaused'); 読み上げが一時停止中か確認します。(true / false) で返します。window.speechSynthesis.paused

メモ: $().articulate('isSpeaking');は一時停止中でも trueが返ります。

音声データの取得と設定

メソッド 説明
$().articulate('getVoices'); 音声オブジェクトを配列に返します。オブジェクトは音声名と言語の2つが返ります。日本語はja-JP
$().articulate('getVoices',selector,text); selectorに音声選択メニューの内容を設定します。 text は未選択時のテキストを指定します。デフォルトは英語なのでお好みの日本語で設定します・
$().articulate('setVoice','name',voice); デフォルトの音声を変更する場合に指定しますnameは、正式名称すべて記述する必要があります。
$().articulate('setVoice','language',twoDigit); 言語コードに一致する最初の音声を見つけることによって音声を設定します。大文字と小文字を区別しない
$().articulate('setVoice','language',code); 完全な言語コードに正確に一致する最初の音声を見つかった音声を設定します。日本語はja

メモ:getVoicesの デフォルトの言語選択英語メニューは 'Choose a Different Voice'です

メモ: 言語コードは、言語を指定する 2 文字から成り、その後にハイフンが続き、その言語の特定の国または地域の方言を指定する追加の文字が続きます。たとえば、コード "en-US" と "en-GB" はどちらも英語ですが、それぞれが異なる国を表します。

メモ: 2 桁の言語コードのみを指定して音声を設定すると、別の言語でページにテキストが表示されているが、その言語が使用できるかどうかを確認する必要がない場合に便利です。たとえば、英語以外のページには、話したい段落がドイツ語で表示される場合があります。その段落には、次のようなリンクを設定できます。:

$('p').articulate('setVoice','language','ja').articulate('speak');

日本語が利用可能な場合は、適切に話されます。表示されない場合、現在の音声は残ります

テキスト操作

メソッド 説明
$().articulate('ignore',tagName,tagName,...); ユーザーが任意で無視するHTMLタグを指定できます。"tagName,tagName,"でカンマで区切って指定します。tagNameを省略するとユーザー指定のHTMLタグはクリアされます。
$().articulate('recognize',tagName,tagName,...); 無視されたHTMLタグを削除します。tagNameを省略するとユーザー指定のHTMLタグはクリアされます。
$().articulate('replace',oldText,newText,...); 読み上げするときに oldText newText に置き換えます。 これは大文字と小文字を区別しません。 テキストの複数のペアを指定できます。 パラメータを省略すると、以前の置換コマンドが削除されます
$().articulate('customize',tagName,prepend); HTML タグ <img>, <table>, and <figure>;の説明の前に読み上げされたデフォルトのテキストを置き換えます パラメータを省略すると、値がデフォルトに戻ります。
$().articulate('customize',tagName,prepend,append); HTML タグ <q>, <ol>, <ul>, and <blockquote>; のコンテンツの前後に話されるデフォルトのテキストを置き換えます、 および&lt; blockquote&gt; ; パラメータを省略すると、値がデフォルトに戻ります。

HTML データ属性

データ属性 説明
data-articulate-ignore 指定したDOM要素とその子孫のコンテンツは無視されます。
data-articulate-recognize 指定したDOM要素のコンテンツが読み上げられ、デフォルトをオーバーライドします。
data-articulate-spell 指定したDOM要素の内容はスペルアウトされます。
data-articulate-prepend=text 指定されたテキストは、DOM要素の内容の前に読み上げられます。
data-articulate-append=text 指定されたテキストは、そのDOM要素の内容に後で読み上げられます。
data-articulate-swap=text 指定されたテキストは、DOM 要素の内容の代わりに読み上げられます。

その他


<!-- <articulate>text</articulate> -->

上記で記載することで、HTMLのコメントは通常、読み上げしませんが、上記コメントタグと<articulate>タグで記載することで読み上げすることができます。スペース、--の数は上記でなければいけません。

Reference Information

チェーンコールは許容されます。下記の記述は問題なく動作します。:


	$('article').articulate('rate',1.3).articulate('speak');

無視されるタグ: audio, button, canvas, code, del, dialog, dl, embed, form, head, iframe, meter, nav, noscript, object, s, script, select, style, textarea, video

デフォルトのままだと、下記のタグで下記の英語で読み上げされます、必要に応じてarticulate.jsを修正するか、customizeコマンドで変更する必要があります。

HTML タグ デフォルトのプリペンドテキスト デフォルトの追加テキスト
<img> There's an embedded image with the description, n/a
<table> There's an embedded table with the caption, n/a
<figure> There's an embedded figure with the caption, n/a
<q> and " " Quote, , Unquote,
<ol> Start of list. End of list.
<ul> Start of list. End of list.
<blockquote> Blockquote start. Blockquote end.

メモ: カンマの後にスペースが続くと、読み上げされたときに一時停止します。ピリオドにより、一時停止が少し長くなります

$().articulate('ignore','h5','h6','em'); // Do not speak the content of <h5>, <h6>, and <em> tags
$().articulate('recognize','button','code'); // Speak the content of <button> and <code> tags
$().articulate('replace','i.e.','That is'); // When 'i.e.' is encountered, say 'That is'
$().articulate('customize','img','Embedded'); // Change default intro text spoken when <img> is encountered
$().articulate('customize','ol','Start of numbered List.','End of Numbered List'); // Change default intro and outro text spoken when <ol> is encountered

上記、翻訳を見ながら作ってみた、ソース

英語の部分を置き換えるのと、その他の機能を使ってみた。


$(function () {
	if(!('speechSynthesis' in window)) {
		/* speech synthesis not supported */
		$('#msg').text("ご使用のブラウザーは、読み上げに対応しておりません。");
	}
});
function create(obj) {
	$().articulate('getVoices', obj, '音声タイプの選択');
};
//日本語に置き換えまたは、機能削除
$().articulate('customize','q','引用開始,',', 引用終了,');
$().articulate('customize','ol','ここからリストが開始します.','リストが終了します.');
$().articulate('customize','ul','ここからリストが開始します','リストが終了します.');
$().articulate('customize','blockquote','ブロック引用開始.','ブロック引用終了.');
$().articulate('customize','img',"説明付きの埋め込み画像があります,");
$().articulate('customize','table',"キャプション付きの埋め込みテーブルがあります,");
$().articulate('customize','figure',"キャプション付きの埋め込みテーブルがあります,");
function speak(obj) {
	var r = parseFloat(document.getElementById('rate').value);
	var p = parseFloat(document.getElementById('pitch').value);
	var v = parseFloat(document.getElementById('volume').value);
	$(obj).articulate('rate', r).articulate('pitch', p).articulate('volume', v).articulate('speak');
};
function speak_fix(obj) {
	$().articulate('replace','都心で骨粗鬆症だった方もコロナで39度5分あった。','としんでこつそしょうしょうだったかたもコロナで39ど5ぶあった。,');
	var r = parseFloat(document.getElementById('rate').value);
	var p = parseFloat(document.getElementById('pitch').value);
	var v = parseFloat(document.getElementById('volume').value);
	$(obj).articulate('rate', r).articulate('pitch', p).articulate('volume', v).articulate('speak');
};
function speak_textarea(inp,obj) {
	$(obj).text($(inp).val());
	var r = parseFloat(document.getElementById('rate').value);
	var p = parseFloat(document.getElementById('pitch').value);
	var v = parseFloat(document.getElementById('volume').value);
	$(obj).articulate('rate', r).articulate('pitch', p).articulate('volume', v).articulate('speak');
};
function pause() {
	$().articulate('pause');
};
function resume() {
	$().articulate('resume');
};
function stop() {
	$().articulate('stop');
};
function populate() {
	$('div.voice-table').show();
	var voices = $().articulate('getVoices');
	for (var i = 0; i < voices.length; i++) {
		voiceName = voices[i].name;
		voiceLang = voices[i].language;
		row = "" + voiceName + "";
		row += "" + voiceLang + "";
		$('.voice-table tbody').append(row);
    }
};

articulate.jsを修正 日本語だけの音声のリストにする 580行付近

if(voices[i].language == 'ja-JP') {を追加


            obj.append(jQuery("<select id='voiceSelect'><option value='none'>" + customTxt + "</option></select>"));
            for(var i = 0; i < voices.length ; i++) {
                if(voices[i].language == 'ja-JP') {
                    var option = document.createElement('option');
                    option.textContent = voices[i].name + ' (' + voices[i].language + ')';
                    option.setAttribute('value', voices[i].name);
                    option.setAttribute('data-articulate-language', voices[i].language);
                    obj.find("select").append(option);
                }
            }

articulate.jsを修正 tableタグが読み上げしないのでコメントにする 310行付近


//                jQuery(clone).find("table").addBack("table").each(function() {
//                    copy = jQuery(this).find("caption").text();
//                    if (customTags["table"]) {
//                        prepend = customTags["table"].prepend
//                    }
//                    else {
//                        prepend = voiceTags["table"].prepend
//                    }
//                    if ((copy !== undefined) && (copy != "")) {
//                        jQuery("<div>" + prepend + " " + copy + ".</div>").insertBefore(this);
//                    }
//                    jQuery(this).remove();
//                });

さいごに

以前より、読み上げ間違えが少なくなっている感じ、windowsの音声データが増えたのそちらの精度かもしれません。

ちなみにYahoo!デベロッパーネットワークのルビ振りAPIも同じ感じだった。これ使って、戻りを喋らすかともおもったけど・・

まぁ、ajaxとかでひらがなだけの文字を使って読ませてもよいんじゃとか・・・

以前よりは使える感じ、ただ、OS、ブラウザー、音声データによって動作が異なります。また、Google 日本語ja-JPを選択してもまったく再生してくれませんでした。

長文もデモではwindows 10 Edge ,Chrome iphone safariで再生できました。

articulate.jsでは、内部でスペースによる、制御だったり、タグの除外など入っているので、ノーマルのSpeechSynthesisとは動作が違います。注意してください。

一応、アクセシビリティ方法のリンク先参考までに、

みんなのウェブ

https://barrierfree.nict.go.jp/accessibility/index.html

https://barrierfree.nict.go.jp/accessibility/minna/minna.pdf

ウェブアクセシビリティ基盤委員会.

https://waic.jp/

https://waic.jp/files/cheatsheet/waic_jis-x-8341-3_cheatsheet_201812.pdf

総務省 

ウェブアクセシビリティ取組確認・評価表(Excel)EXCELはここ

https://www.soumu.go.jp/main_sosiki/joho_tsusin/b_free/guideline.html

総務省『公的機関に求められるホームページ等のアクセシビリティ対応』

https://www.soumu.go.jp/main_content/000438394.pdf

関連記事