Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/leaonline/easy-speech

๐Ÿ”Š Cross browser Speech Synthesis also known as Text to speech or TTS; no dependencies; uses Web Speech API
https://github.com/leaonline/easy-speech

browser cross-browser hacktoberfest hacktoberfest-accepted javascript js speech-synthesis standards text-to-speech tts web web-speech-api

Last synced: about 3 hours ago
JSON representation

๐Ÿ”Š Cross browser Speech Synthesis also known as Text to speech or TTS; no dependencies; uses Web Speech API

Awesome Lists containing this project

README

        

Easy Speech


Cross browser Speech Synthesis; no dependencies.




API docs ยป


[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
[![Project Status: Active โ€“ The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
[![Test suite](https://github.com/leaonline/easy-speech/actions/workflows/tests.yml/badge.svg)](https://github.com/leaonline/easy-speech/actions/workflows/tests.yml)
[![CodeQL Semantic Analysis](https://github.com/leaonline/easy-speech/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/leaonline/easy-speech/actions/workflows/codeql-analysis.yml)
![npm](https://img.shields.io/npm/v/easy-speech)
![npm bundle size](https://img.shields.io/bundlephobia/min/easy-speech)
![npm bundle size](https://img.shields.io/bundlephobia/minzip/easy-speech)
[![DOI](https://zenodo.org/badge/432159293.svg)](https://zenodo.org/doi/10.5281/zenodo.10816462)

## โญ๏ธ Why EasySpeech?

This project was created, because it's always a struggle to get the synthesis
part of `Web Speech API` running on most major browsers.

## โœจ Features

- ๐Ÿช„ Single API for using `speechSynthesis` across multiple browsers
- ๐ŸŒˆ Async API (Promises, async/await)
- ๐Ÿš€ Hooks for all events; global and/or voice-instance-specific
- ๐ŸŒฑ Easy to set up and integrate: auto-detects and loads available voices
- ๐Ÿ”ง Includes fixes or workarounds for many browser-specific quirks
- ๐Ÿ“ Internal logging via `EasySpeech.debug` hook
- ๐Ÿ“ฆ Multiple build targets
- ๐ŸŽฎ Live demo to test your browser

**Note:** this is not a polyfill package, if your target browser does not support speech synthesis or the Web Speech
API, this package is not usable.

## ๐Ÿš€ Live Demo

The live demo is available at https://leaonline.github.io/easy-speech/
You can use it to test your browser for `speechSynthesis` support and functionality.

[![live demo screenshot](./docs/demo_screenshot.png)](https://leaonline.github.io/easy-speech/)

## Table of Contents

**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*

- [๐Ÿ“ฆ Installation](#-installation)
- [๐Ÿ‘จโ€๐Ÿ’ป Usage](#-usage)
- [๐Ÿš€ Initialize](#-initialize)
- [๐Ÿ“ข Speak a voice](#-speak-a-voice)
- [๐Ÿ˜ตโ€๐Ÿ’ซ Troubleshooting / FAQ](#-troubleshooting--faq)
- [๐Ÿ”ฌ API](#-api)
- [โŒจ๏ธ Contribution and development](#-contribution-and-development)
- [๐Ÿ“– Resources](#-resources)
- [โš–๏ธ License](#-license)

## ๐Ÿ“ฆ Installation

Install from npm via

```bash
$ npm install easy-speech
```

You can also use the various builds for different targets, see the `dist` folder:

- `/dist/EasySpeech.js` - ESM
- `/dist/EasySpeech.cjs.js` - CommonJs
- `/dist/EasySpeech.es5.js` - Legacy node compatible
- `/dist/EasySpeech.iife.js` - Legacy compatible build, works even with older
or exotic browsers, as long as they support Promises (PRs welcome to transform
to callbacks!)
- `/dist/index.d.ts` - TypeScript type definitions

You can use them via CDN:

```html

import easySpeech from 'https://cdn.jsdelivr.net/npm/easy-speech/+esm'

```

```html

```

## ๐Ÿ‘จโ€๐Ÿ’ป Usage

Import `EasySpeech` and first, detect, if your browser is capable of tts (text
to speech):

```javascript
import EasySpeech from 'easy-speech'

EasySpeech.detect()
```

it returns an Object with the following information:

```javascript
{
speechSynthesis: SpeechSynthesis|undefined,
speechSynthesisUtterance: SpeechSynthesisUtterance|undefined,
speechSynthesisVoice: SpeechSynthesisVoice|undefined,
speechSynthesisEvent: SpeechSynthesisEvent|undefined,
speechSynthesisErrorEvent: SpeechSynthesisErrorEvent|undefined,
onvoiceschanged: Boolean,
onboundary: Boolean,
onend: Boolean,
onerror: Boolean,
onmark: Boolean,
onpause: Boolean,
onresume: Boolean,
onstart: Boolean
}
```

If at least `SpeechSynthesis` and `SpeechSynthesisUtterance` are defined you
are good to go.

### ๐Ÿš€ Initialize

Preparing everything to work is not as clear as it should, especially when
targeting cross-browser functionality. The asynchronous init function will help
you with this situation:

```javascript
EasySpeech.init({ maxTimeout: 5000, interval: 250 })
.then(() => console.debug('load complete'))
.catch(e => console.error(e))
```

#### ๐Ÿ’ฝ Loading voices

The init-routine will go through several stages to setup the environment:

- detect and that SpeechSynthesis is basically supported, if not -> fail
- load voices directly
- if not loaded but `onvoiceschanged` is available: use `onvoiceschanged`
- if `onvoiceschanged` is not available: fallback to timeout
- if `onvoiceschanged` is fired but no voices available: fallback to timeout
- timeout reloads voices in a given `interval` until a `maxTimeout` is reached
- if voices are loaded until then -> complete
- if no voices found -> fail

If your init routing has still not detected / loaded any voices, allthough
speechSynth is supported please leave an issue!

#### Placing a fallback voice

If voices are found it will place a fallback voice by the following rules:

- If there is a voice among all voices with the `default` property set to true
use this as fallback voice
- Otherwise find the first matching voice by current `navigator.language`
- Otherwise use the first voice in the Array

Note: This fallback voice is not overridden by `EasySpeech.defaults()`, your
default voice will be used in favor but the fallback voice will always be there
in case no voice is found when calling `EasySpeech.speak()`

### ๐Ÿ“ข Speak a voice

This is as easy as it gets:

```javascript
await EasySpeech.speak({
text: 'Hello, world!',
voice: myLangVoice, // optional, will use a default or fallback
pitch: 1,
rate: 1,
volume: 1,
// there are more events, see the API for supported events
boundary: e => console.debug('boundary reached')
})
```

The Promise will automatically resolve when the speaking ends or rejects when
an error occurred. You can additionally attach these event listeners if you like
or use `EasySpeech.on` to attach default listeners to every time you call
`EasySpeech.speak`.

### ๐Ÿ˜ตโ€๐Ÿ’ซ Troubleshooting / FAQ

There is an own [FAQ section](./FAQ.md) available that aims to help with common issues.

## ๐Ÿ”ฌ API

There is a full API documentation available: [api docs](./API.md)

## โŒจ๏ธ Contribution and development

Every contribution is welcomed, please open issues if anything is not working
as expected.

If you intend to contribute code, please read the
[guidelines on contributing](./CONTRIBUTING.md).

## ๐Ÿ“– Resources

This project used several resources to gain insights about how to get the best cross-browser SpeechSynthesis running:

- https://wicg.github.io/speech-api/#tts-section
- https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis
- https://gist.github.com/alrra/6741915
- https://github.com/ubershmekel/audio-language-tests
- https://stackoverflow.com/questions/33889107/speech-synthesis-in-chrome-for-android-not-loading-voices
- https://stackoverflow.com/questions/49506716/speechsynthesis-getvoices-returns-empty-array-on-windows
- https://stackoverflow.com/questions/21947730/chrome-speech-synthesis-with-longer-texts
- https://stackoverflow.com/a/34130734
- https://stackoverflow.com/a/68060634
- https://stackoverflow.com/a/48056986
- https://bugs.chromium.org/p/chromium/issues/detail?id=582455
- https://stackoverflow.com/a/65883556

## โš–๏ธ License

MIT, see [license file](./LICENSE)