Skip to content

Instantly share code, notes, and snippets.

@paceaux
Created September 3, 2019 17:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paceaux/d3f312a27fe9e3f7a73d5406a4a5cadc to your computer and use it in GitHub Desktop.
Save paceaux/d3f312a27fe9e3f7a73d5406a4a5cadc to your computer and use it in GitHub Desktop.
Interface for speech synthesis in the browser
/**
* @typedef SpeakerDefaults
* @type {object}
* @property {string} voiceURI voice that the browser uses
* @property {Number} volume loudness. Between 0 and 1.0
* @property {Number} rate speed at which words are spoken. Between 0 and 2.
* @property {Number} pitch Between 0 and 2
* @property {string} lang ISO language
*/
const SpeakerDefaults = {
voiceURI: 'native',
volume: .4,
rate: 0.8,
pitch: 0.0,
lang: 'en-EN'
};
/**
* Class for getting the browser to "talk"
* @example //Create an instance
* const mySpeaker = new Speaker();
* @example //Get it to talk
* mySpeaker.say('something sooper cool');
*/
class Speaker {
/** Create an interface for the browser to speak
* @param {SpeakerDefaults} defaults=SpeakerDefaults
* @param {string} defaults.voiceURI
* @param {Number} defaults.volume loudness. Between 0 and 1.0
* @param {Number} defaults.rate speed at which words are spoken. Between 0 and 2.
* @param {Number} defaults.pitch Between 0 and 2
* @param {string} defaults.lang ISO language
*
*/
constructor(defaults = SpeakerDefaults) {
this.defaults = Object.assign({},defaults); // make a copy of the defaults
Object.freeze(this.defaults); // freeze the defaults; that way we can return to them at any time
this.config = defaults;
this.messageHistory = [];
}
/**
* Creates a new SpeechSynthesisUtterance
* @return SpeechSynthesisUtterance
*/
utterance() {
const speech = new SpeechSynthesisUtterance();
speech.voiceURI = this.config.voiceURI;
speech.volume = this.config.volume;
speech.rate = this.config.rate;
speech.pitch = this.config.pitch;
speech.lang = this.config.lang;
return speech;
}
utteranceHistory(utterance) {
const obj = {
timestamp: Date.now()
};
// screwy object aliasing
({
text: obj.text,
rate: obj.rate,
pitch: obj.pitch,
lang: obj.lang,
volume: obj.volume,
voiceURI: obj.voiceURI
} = utterance);
return obj;
}
get eventCallbacks() {
return {
/** records a history of the utterance once it's ended
* @callback Speaker~utterance
* @param {} event
*/
onend(event) {
const history = this.utteranceHistory(event.utterance);
this.messageHistory.push(history);
console.log(this.messageHistory);
console.log('finished in ' + event.elapsedTime);
}
};
}
/** Instructs the browser to speak a message
* @param {string} msg
*/
say(msg) {
const speech = this.utterance();
speech.text = msg;
speech.onend = this.eventCallbacks.onend.bind(this);
speechSynthesis.speak(speech);
}
/**
* Determine if the browser is currently speaking
* @return {boolean}
*/
get isSpeaking() {
return speechSynthesis.speaking;
}
/**
* Pause the browser
*/
pause() {
speechSynthesis.pause();
}
/**
* Tell the browser to start speaking
*/
play() {
speechSynthesis.play()
}
/**
* Toggle speech
*/
toggle() {
if (!speechSynthesis.speaking) {
this.play();
} else {
this.pause();
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment