ブラウザのテキスト読み上げ機能（SpeechSynthesis）をJavaScriptで良い感じに使えるパッケージ「roudokuka」を作った話【直ぐに試せるサンプルページもあるよ】

#前置き（スキップ可
皆さんはブラウザにテキスト読み上げ機能が実装されている事をご存知でしょうか？
SpeechSynthesisと言う名前の機能で、所謂モダンブラウザには大体実装されています。（闇：仕様が揃ってる＆不具合が無いとは言ってない…）

試しに↓のコードをお使いのブラウザのコンソールに入力して実行してみて下さい。SpeechSynthesisが実装されていれば読み上げが開始されます。※注意：音が鳴ります

```js
speechSynthesis.speak(new SpeechSynthesisUtterance('1, 2, 3'))
```

以前はテキスト読み上げ機能と言うのは、外部アプリとの連携で煩雑な設定が必要だったり、外部サービスを使ってデカい音声データ持って来ないといけなかったりと、様々な要素の所為で中々敷居が高めな機能でした…が、これがブラウザに実装された事により上記の問題から解放され、とてもカジュアルに使える機能になりました！
(｀・ω・´)b

今回はこの面白い機能をより使い易くした、自作のパッケージ「roudokuka」について書いていこうと思いまーす。

#なんで作ったの？
ブラウザの読み上げ機能（SpeechSynthesis）…とても面白くて良いのですが、シンプルな実装過ぎて、ちょっと凝った使い方をしようとすると大分使い難いんですよね…他の人が作ってるパッケージとかも、あるっちゃあるけどシンプルなのが無い…
(´・ω・｀)

なので__それを改善し、拡張性を高め、ブラウザの読み上げ機能を色々な所で使い易くする為にroudokukaを作成しました！__
………と言う意識高めな理由を書きましたが、一番の理由は次回予告の拡張機能を作り易くする為です… :blush: 

それではroudokukaとは何なのか？使うとどんなメリットがあるのか？等を例を交えながら簡単に書いていきたいと思います！

#roudokuka is 何？
> roudokuka is simple web reader, it's working with browser feature only.
> https://github.com/snowsunny/roudokuka

日本語：__roudokukaはブラウザの機能しか使わないシンプルなウェブリーダーです。__

もう少し詳しく書くと、__JavaScriptベースのSpeechSynthesisを良い感じに使える様にするパッケージ__です。
npmに公開済み。CDNのおすすめはjsDelivr。
[![](https://data.jsdelivr.com/v1/package/npm/roudokuka/badge)](https://www.jsdelivr.com/package/npm/roudokuka)

#使い方集とドキュメントっぽいもの
それではメリットの説明をする前に、早速ですが使い方を集めたページを作ってあるので、是非一度試してみてください！
d(｀・ω・´)b

各例のCodePenの「Start」をクリックすると動作します。※SpeechSynthesisが実装されているブラウザでお試しください。


> roudokuka examples
> https://snowsunny.github.io/roudokuka

ドキュメントっぽい物は↓のページに書いてあります。
https://github.com/snowsunny/roudokuka
まだしっかり書けていない部分もあるのですがご容赦ください… :bow: 

使い方集とドキュメントで、合わせて100回くらい「英語が上手くなりたい…(´・ω・｀)」って思いながら書きました…ｗ

#roudokukaを使うメリット６選
では、サンプルを見て貰った所で手前味噌ですが、roudokukaを使うメリットを６つ程ご紹介してみようと思います。
※SpeechSynthesisを直に使う場合と比較した時のメリットです。（作者比）

#####__1. シンプルなコードで動かせる！__
なるべく短めに書いた、複数のテキストを読み上げさせる時の例↓

```js:SpeechSynthesisを直に使う場合
speechSynthesis.speak(new SpeechSynthesisUtterance('1, 2, 3'))
speechSynthesis.speak(new SpeechSynthesisUtterance('4, 5, 6'))
```
```js:roudokukaを使う場合
new Roudokuka(['1, 2, 3', '4, 5, 6']).start()
```
いかがでしょうか？まぁroudokukaを使う場合はそれを読み込む手間が増えるのですが、かなりシンプルに書けるようになってるかと思います。

#####__2. 各テキストの連続再生制御が簡単に出来る！__
1のメリットで紹介したコードの`.start()`に読み上げるテキストのインデックス番号を渡してあげることで、どのテキストから読み始めるかを簡単に指定する事が出来ます。
直に使う場合には出来ない割り込み再生にも対応しており、読み上げ中の場合はそれを停めてから指定のインデックスを再生します。

```js:「4,&nbsp;5,&nbsp;6」から読み始める場合
let roudokuka = new Roudokuka(['1, 2, 3', '4, 5, 6', '7, 8, 9'])
roudokuka.start(1)
```
この機能は途中で停止した後に再開する時とかも便利に使えます！

```js:最初から読み直す場合
roudokuka.start(0)
```

#####__3. 発声オプションやイベントコールバックの一括指定や、個別指定が簡単に出来る！__
roudokukaでは第２引数でグローバルなオプションを設定出来る様にしています。さらに第１引数内でもオプションを指定出来る様にしているので、色々使い易くなってると思います。
※使い方集ページの「with global utterance options」の所のやつです。

```js

let lines = ['1, 2, 3', '4, 5, 6', {
  text: '7, 8, 9',
  rate: 1,
  pitch: 1
}]

let globalOptions = {
  rate: 1.5,
  pitch: 1.5
}

let roudokuka = new Roudokuka(lines, globalOptions)
roudokuka.start()
```

オプションの優先順位は「__linesのオプション ＞ globalOptionsのオプション ＞ roudokukaのデフォルトオプション ＞ ブラウザのデフォルトオプション__」の順になっています。

#####__4. 台本の概念を導入。それが終わった時のイベントもあるよ！__
`SpeechSynthesisUtterance`をまとめる`Libretto`クラスを作り、その中の`SpeechSynthesisUtterance`が全て読み上げ終わった時に発火する`onLibrettoEnd`イベントを追加しました。
これにより、文章の段落毎に`SpeechSynthesisUtterance`を作った時、文章自体の終わりを`onLibrettoEnd`イベントでキャッチする事が出来ます。

#####__5. 各種ブラウザ（主にChrome…）で発生するspeechSynthesisの不具合に対応！__
前置きにも少し書きましたがこの`speechSynthesis`と言う機能、ブラウザ毎に仕様が違ったり、不具合が結構あります…

その中でもChromeには「素で長文を読ませようとすると`speechSynthesis`が死ぬ」と言う割りと致命的な不具合があるのですが、roudokukaではその不具合を解消するコードを仕込んであります。

※本当はこんな事やりたくないんですけどね…これからに期待です。(´；ω；｀)

#####__6. 任意のデータをイベント発火時に受け取れる！__
これは素で`SpeechSynthesisUtterance`に追加したデータでも特にサニタイズされる事はないので、`SpeechSynthesisEvent.utterance`で受け取れるのですが、roudokukaではonendイベントの時にユーザーが設定した任意のデータ＋roudokuka専用変数を受けとれる様にしてあります。

これによりroudokukaを使う際に任意のデータを設定した時、ちょっとだけ使い易くなります。

#ちょっとアレな所…(´・ω・｀)
これはroudokukaと言うより`speechSynthesis`のアレな所なのですが、幾つかの所で書いた様に、この`speechSynthesis`と言う機能は、ブラウザ毎に仕様が違ったり、不具合が結構あります…

なので、roudokukaをプロダクションで使いたいなーと言う方は、その辺をご注意下さい。
早く仕様が統一されて全てのブラウザで安全に使える様になると良いなー…(´ - ω - ｀)

因みに自分で試した中だと、デスクトップ版は大分アレですが、Android Chromeが一番しっかり実装されてそうな感じでした。（AndroidのTTSを使ってるっぽいから？）

#まとめ
いかがでしたか？「roudokukaを使えば、良い感じに読み上げ機能が使えそう」って思って貰えたなら幸いです。
読み上げ機能がご入り用の際には是非使ってみて下さい！d(｀・ω・´)b

今回はWeb Speech APIの読み上げ機能の方にフォーカスしたやつを作ったのですが、本命機能は聞き取り機能（今世間を賑わせてるスマートスピーカーっぽいやつが出来る機能）の方だと思うので、今度はそっちも触ってみたいなーと思います！

こっちに関しては既に便利そうなライブラリが色々あった覚えがあるので自作するかは分からないのですが、その時はまた何か書こうと思うのでよろしくお願いします！

#次回予告
__「小説家になろう」の小説を良い感じに朗読してくれるChrome拡張機能作ったよー（仮）__
ご期待ください！(｀・ω・´)b

#####フライング紹介
実は拡張機能自体はもう完成していてるんですよね。まだ何も説明を書いて無いですが良ければどぞー。
https://github.com/snowsunny/novels-reader

__雑な使い方説明：__
上記リポジトリのデータをクローン、またはZIPをダウンロードして解凍しておく。
↓
Chromeで拡張機能の管理画面（chrome://extensions）を開く。
↓
デベロッパーモードを有効にする。
↓
クローン、またはZIPをダウンロードしたフォルダーを開く。
↓
直下に入っている「novels-reader-crx」と言うフォルダーが拡張機能の本体なので、それをChromeの拡張機能管理画面にドラッグ＆ドロップする。
↓
「小説家になろう」の小説ページを開く、って感じでーす。
オプションを弄りたい方は拡張機能のアイコンを右クリックして開けるオプションページからどぞー。