<!DOCTYPE html>
<html lang="en">
<head>
<title>meSpeak.js: Text-to-Speech on the Web</title>
<meta name="description" content="meSpeak.js (modulary enhanced speak.js) is a 100% client-side JavaScript text-to-speech library based on the speak.js project." />
<link href="http://fonts.googleapis.com/css?family=Open+Sans&subset=latin" rel="stylesheet" type="text/css" />
<link href="http://fonts.googleapis.com/css?family=Lato:300&subset=latin" rel="stylesheet" type="text/css" />
<script>
// This demo is licensed under the GNU GPL.
</script>
<script type="text/javascript" src="mespeak.js"></script>
<script type="text/javascript">
meSpeak.loadConfig("mespeak_config.json");
meSpeak.loadVoice("voices/en/en.json");
function loadVoice(id) {
var fname="voices/"+id+".json";
meSpeak.loadVoice(fname, voiceLoaded);
}
function voiceLoaded(success, message) {
if (success) {
alert("Voice loaded: "+message+".");
}
else {
alert("Failed to load a voice: "+message);
}
}
/*
auto-speak glue:
additional functions for generating a link and parsing any url-params provided for auto-speak
*/
var formFields = ['text','amplitude','wordgap','pitch','speed'];
function autoSpeak() {
// checks url for speech params, sets and plays them, if found.
// also adds eventListeners to update a link with those params using current values
var i,l,n,params,pairs,pair,
speakNow=null,
useDefaultVoice=true,
q=document.location.search,
f=document.getElementById('speakData'),
s1=document.getElementById('variantSelect'),
s2=document.getElementById('voiceSelect');
if (!f || !s2) return; // form and/or select not found
if (q.length>1) {
// parse url-params
params={};
pairs=q.substring(1).split('&');
for (i=0, l=pairs.length; i<l; i++) {
pair=pairs[i].split('=');
if (pair.length==2) params[pair[0]]=decodeURIComponent(pair[1]);
}
// insert params into the form or complete them from defaults in form
for (i=0, l=formFields.length; i<l; i++) {
n=formFields[i];
if (params[n]) {
f.elements[n].value=params[n];
}
else {
params[n]=f.elements[n].value;
}
}
if (params.variant) {
for (i=0, l=s1.options.length; i<l; i++) {
if (s1.options[i].value==params.variant) {
s1.selectedIndex=i;
break;
}
}
}
else {
params.variant='';
}
// compile a function to speak with given params for later use
// play only, if param "auto" is set to "true" or "1"
if (params.auto=='true' || params.auto=='1') {
speakNow = function() {
meSpeak.speak(params.text, {
amplitude: params.amplitude,
wordgap: params.wordgap,
pitch: params.pitch,
speed: params.speed,
variant: params.variant
});
};
}
// check for any voice specified by the params (other than the default)
if (params.voice && params.voice!=s2.options[s2.selectedIndex].value) {
// search selected voice in selector
for (i=0, l=s2.options.length; i<l; i++) {
if (s2.options[i].value==params.voice) {
// voice found: adjust the form, load voice-data and provide a callback to speak
s2.selectedIndex=i;
meSpeak.loadVoice('voices/'+params.voice+'.json', function(success, message) {
if (success) {
if (speakNow) setTimeout(speakNow, 10);
}
else {
if (window.console) console.log('Failed to load requested voice: '+message);
}
});
useDefaultVoice=false;
break;
}
}
}
// standard voice: speak (deferred until config is loaded)
if (speakNow && useDefaultVoice) speakNow();
}
// initial url-processing done, add eventListeners for updating the link
for (i=0, l=formFields.length; i<l; i++) {
f.elements[formFields[i]].addEventListener('change', updateSpeakLink, false);
}
s1.addEventListener('change', updateSpeakLink, false);
s2.addEventListener('change', updateSpeakLink, false);
// finally, inject a link with current values into the page
updateSpeakLink();
}
function updateSpeakLink() {
// injects a link for auto-execution using current values into the page
var i,l,n,f,s,v,url,el,params=new Array();
// collect values from form
f=document.getElementById('speakData');
for (i=0, l=formFields.length; i<l; i++) {
n=formFields[i];
params.push(n+'='+encodeURIComponent(f.elements[n].value));
}
// get variant
s=document.getElementById('variantSelect');
if (s.selectedIndex>=0) params.push('variant='+s.options[s.selectedIndex].value);
// get current voice, default to 'en/en' as a last resort
s=document.getElementById('voiceSelect');
if (s.selectedIndex>=0) v=s.options[s.selectedIndex].value;
if (!v) v=meSpeak.getDefaultVoice() || 'en/en';
params.push('voice='+encodeURIComponent(v));
params.push('auto=true');
// assemble the url and add it as GET-link to the page
url='?'+params.join('&');
url=url.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');
el=document.getElementById('linkdisplay');
if (el) el.innerHTML='Instant Link: <a href="'+url+'">Speak this</a>.';
}
// trigger auto-speak at DOMContentLoaded
if (document.addEventListener) document.addEventListener( "DOMContentLoaded", autoSpeak, false );
/*
end of auto-speak glue
*/
</script>
<style type="text/css">
html
{
margin: 0;
padding: 2em 1.5em 4.5em 1.5em;
background-color: #e2e3e4;
}
body
{
max-width: 900px;
padding: 2px 40px 60px 40px;
margin: 0 auto 0 auto;
background-color: #fafafb;
color: #111;
font-family: 'Open Sans',sans-serif;
font-size: 13px;
line-height: 19px;
}
h1,h2,h3
{
font-family: 'Lato',sans-serif;
font-weight: 300;
}
h1 {
font-size: 46px;
line-height: 46px;
color: #2681a7;
margin-top: 0.5em;
margin-bottom: 0.5em;
padding: 0;
}
h2
{
font-size: 36px;
color: #111;
margin-top: 0;
margin-bottom: 1.5em;
clear: both;
}
h3
{
font-size: 24px;
color: #111;
margin-top: 2em;
}
h1 span.pict { font-size: 38px; color: #ccc; margin-left: 0.5em; letter-spacing: -2px; }
h3.about { font-size: 28px; }
form p
{
margin-top: 0.5em;
margin-bottom: 0.5em;
}
p.codesample
{
margin: 1em 0;
padding: 1em 0 1em 2em;
white-space: pre;
font-family: monospace;
line-height: 18px;
background-color: #f2f3f5;
color: #111;
}
p.codesample strong { color: #222; }
hr.separator
{
margin-top: 2em;
margin-bottom: 2em;
}
blockquote.note
{
margin-left: 2em;
font-size: 90%;
}
a.noteLink { text-decoration: none; }
ul.bottomMargin li { margin-bottom: 0.2em; }
dl.history dt
{
font-weight: normal;
font-variant: normal;
float: left;
vertical-align: top;
clear: both;
}
dl.history dd
{
vertical-align: top;
margin-left: 4em;
margin-bottom: 0.4em;
}
table.opttable { margin-left: 2em; }
table.opttable td { white-space: nowrap; }
table.opttable td:first-child { padding-right: 1.5em; }
p.history_codesample
{
padding: 1em;
white-space: pre;
font-family: monospace;
font-size: 90%;
line-height: 120%;
background-color: #eee;
}
p.history_codesample span.comment { color: #555; }
a { color: #006f9e; }
a:hover,a:focus { color: #2681a7; }
a:active { color: #cd360e; }