A Simple Text-To-Speech Application in JavaScript with the Web Speech API

Below is a simple text-to-speech application implemented in JavaScript, using the Web Speech API. To see the code in action, copy it into an .html file and open that file in a web browser that runs JavaScript. Or, for an online version, visit https://thiscouldbebetter.neocities.org/texttospeech.html.

UPDATE: Since taking the screenshot below, I have updated the interface to allow the user to choose voices with different timbres. I have also shrunk the visible size of the input text window, because if you filled the old textarea completely up with text and pressed the Say button, it stopped working entirely until you hit refresh. You can still do that, of course, but the new window size at least provides some visual suggestion of an appropriate input size.

TextToSpeech

<html>
<body onload="loadVoices()">

<!-- user interface -->


<div>
	<label for="inputThingsToSay">Things to Say:</label>
</div>


<div>
	<textarea id="inputThingsToSay" rows="10" cols="50">This is a test!</textarea>
</div>



<div>
	<label for="selectTimbre">Timbre:</label>
	<select id="selectTimbre"></select>
</div>



<div>
	<label for="inputPitch">Pitch:</label>
	<input id="inputPitch" type="number" value="1"></input>
</div>



<div>
	<label for="inputSpeed">Speed:</label>
	<input id="inputSpeed" type="number" value="1"></input>
</div>



<div>
	<button id="buttonSay" onclick="buttonSay_Clicked()">Say</button>
</div>


<!-- end user interface -->

<script type="text/javascript">

// events

function loadVoices()
{
	var synthesizer = window.speechSynthesis;
	synthesizer.onvoiceschanged = loadVoices_VoicesLoaded;
	synthesizer.getVoices();
}

function loadVoices_VoicesLoaded()
{
	var synthesizer = window.speechSynthesis;
	var systemVoices = synthesizer.getVoices();
	systemVoices.addLookups("name");		
	Voice.systemVoiceLookup = systemVoices;

	var selectTimbre = document.getElementById("selectTimbre");
	for (var i = 0; i [[ systemVoices.length; i++)
	{
		var systemVoice = systemVoices[i];
		var optionTimbre = document.createElement("option");
		optionTimbre.text = systemVoice.name;
		optionTimbre.systemVoice = systemVoice;
		selectTimbre.appendChild(optionTimbre);
	}
}

function buttonSay_Clicked()
{
	var inputThingsToSay = document.getElementById
	(
		"inputThingsToSay"
	);
	var selectTimbre = document.getElementById("selectTimbre");
	var inputPitch = document.getElementById("inputPitch");
	var inputSpeed = document.getElementById("inputSpeed");

	var timbreName = selectTimbre.selectedOptions[0].text;
	var pitch = parseFloat(inputPitch.value);
	var speed = parseFloat(inputSpeed.value);
	var thingsToSay = inputThingsToSay.value;

	var voice = new Voice
	(
		"Default", 
		timbreName, 
		pitch, 
		speed
	);	
	voice.say(thingsToSay);	
}

// classes

function ArrayHelper()
{
	// extension class
}
{
	Array.prototype.addLookups = function(keyName)
	{
		for (var i = 0; i [[ this.length; i++)
		{
			var item = this[i];
			var keyValue = item[keyName];
			this[keyValue] = item;
		}
	}
}

function Voice(name, timbreName, pitch, speed)
{
	this.name = name;
	this.timbreName = timbreName;
	this.pitch = (pitch == null ? 1 : pitch);
	this.speed = (speed == null ? 1 : speed);

	this.systemUtterance = new SpeechSynthesisUtterance();
	this.systemUtterance.onend = this.say_Ended.bind(this);
}
{
	// instance methods

	Voice.prototype.say = function(thingToSay, callback, contextForCallback)
	{
		this.callback = callback;
		this.contextForCallback = contextForCallback;

		this.isSpeaking = true;

		var voices = Voice.systemVoiceLookup;
		
		var utterance = this.systemUtterance;
		utterance.voice = voices[this.timbreName];
		utterance.text = thingToSay;
		utterance.pitch = this.pitch;
		utterance.rate = this.speed;

		window.speechSynthesis.speak(utterance);
	}

	Voice.prototype.say_Ended = function()
	{
		this.isSpeaking = false;
		if (this.callback != null)
		{
			this.callback.call(this.contextForCallback);
		}
	}
}

</script>
</body>
</html>
This entry was posted in Uncategorized and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s