package com.akjava.gwt.html5test.client;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.akjava.gwt.html5.client.HTML5InputRange;
import com.akjava.gwt.html5.client.InputRangeWidget;
import com.akjava.gwt.html5.client.extra.HTML5Builder;
import com.akjava.gwt.html5.client.speechsynthesis.SpeechSynthesis;
import com.akjava.gwt.html5.client.speechsynthesis.SpeechSynthesisEvent;
import com.akjava.gwt.html5.client.speechsynthesis.SpeechSynthesisUtterance;
import com.akjava.gwt.html5.client.speechsynthesis.SpeechUtils;
import com.akjava.gwt.html5.client.speechsynthesis.Voice;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisBoundaryListener;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisEndListener;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisErrorListener;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisMarkListener;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisPauseListener;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisResumeListener;
import com.akjava.gwt.html5.client.speechsynthesis.listeners.SpeechSynthesisStartListener;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.text.shared.Renderer;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.ValueListBox;
import com.google.gwt.user.client.ui.VerticalPanel;
public class SpeechTest extends VerticalPanel{
private TextBox textBox;
public SpeechTest(){
if(!SpeechSynthesis.supported()){
add(new Label("SpeechSynthesis not supported.use Chrome 33 later"));
return;
}
//final List<Voice> voices=speechSynthesis.getVoicesAsList();
Button bt=new Button("update",new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
createWidget();
}
});
add(bt);
/*:
* finaly,entry,deffered
*/
//wait finish load
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
HTML5Test.log("deferred");
//only work on android
createWidget();
}
});
Scheduler.get().scheduleFinally(new ScheduledCommand() {
@Override
public void execute() {
HTML5Test.log("finally");
}
});
Scheduler.get().scheduleEntry(new ScheduledCommand() {
@Override
public void execute() {
HTML5Test.log("entry");
}
});
}
private SpeechSynthesis speechSynthesis;
private Label label;
private SpeechSynthesisUtterance utterance;
private InputRangeWidget rateRange;
private InputRangeWidget pitchRange;
private TextBox defaultLangBox;
private ValueListBox<Voice> voiceListBox;
public void createWidget(){
Timer timer=new Timer(){
@Override
public void run() {
long s=System.currentTimeMillis();
speechSynthesis = SpeechSynthesis.get();
List<Voice> voices=speechSynthesis.getVoicesAsList();
if(voices.size()>0){
Voice voice=Objects.firstNonNull(SpeechUtils.getVoiceAtLang(voices, SpeechUtils.JA_JP), voices.get(0));
voiceListBox = new ValueListBox<Voice>(new Renderer<Voice>() {
@Override
public String render(Voice voice) {
return voice.getName()+"("+voice.getLang()+")";
}
@Override
public void render(Voice object, Appendable appendable) throws IOException {
}
});
voiceListBox.setValue(voice);
voiceListBox.setAcceptableValues(voices);
add(voiceListBox);
HorizontalPanel h1=new HorizontalPanel();
add(h1);
ValueListBox<String> speakTests=new ValueListBox<String>(new Renderer<String>() {
@Override
public String render(String object) {
return object;
}
@Override
public void render(String object, Appendable appendable) throws IOException {
// TODO Auto-generated method stub
}
});
speakTests.addValueChangeHandler(new ValueChangeHandler<String>() {
@Override
public void onValueChange(ValueChangeEvent<String> event) {
textBox.setText(event.getValue());
}
});
List<String> tests=Lists.newArrayList("hello world","こんにちは",
"<speak version=\"1.1\">Speak it</speak>",
"<speak version=\"1.1\"> That is a <emphasis> big </emphasis> car!</speak>",
"<speak version=\"1.0\" xmlns=\"http://www.w3.org/2001/10/synthesis\"> That is a <emphasis> big </emphasis> car!</speak>"
);
speakTests.setValue(tests.get(0));
speakTests.setAcceptableValues(tests);
add(speakTests);
textBox = new TextBox();
//<speak version=\"1.0\" xmlns=\"http://www.w3.org/2001/10/synthesis\" xml:lang=\"en-US\">Hello world<voice xml:lang=\"fr-FR\" gender=\"female\">do you know me?</voice></speak>
textBox.setText(tests.get(0));
h1.add(textBox);
Button speakBt=new Button("speak",new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
execSpeak();
}
});
h1.add(speakBt);
Button cancelBt=new Button("cancel",new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
if(speechSynthesis!=null){
speechSynthesis.cancel();
updateStatus();
}
}
});
h1.add(cancelBt);
Button pauseBt=new Button("pause",new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
if(speechSynthesis!=null){
speechSynthesis.pause();
updateStatus();
}
}
});
h1.add(pauseBt);
Button resumeBt=new Button("resume",new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
if(speechSynthesis!=null){
speechSynthesis.resume();
updateStatus();
}
}
});
h1.add(resumeBt);
HorizontalPanel h2=new HorizontalPanel();
add(h2);
rateRange = HTML5InputRange.createInputRange(1, 100, 10);
Label rateLabel=HTML5Builder.createRangeLabel("rate:", rateRange, 10, 1);
rateLabel.setWidth("50px");
h2.add(rateLabel);
h2.add(rateRange);
HorizontalPanel h3=new HorizontalPanel();
add(h3);
pitchRange = HTML5InputRange.createInputRange(0, 20, 10);
Label pitchLabel=HTML5Builder.createRangeLabel("pitch:", pitchRange);
pitchLabel.setWidth("50px");
h3.add(pitchLabel);
h3.add(pitchRange);
cancel();
label = new Label("");
add(label);
add(new Label("defalt-lang"));
defaultLangBox = new TextBox();
defaultLangBox.setText(SpeechUtils.JA_JP);
add(defaultLangBox);
TextArea output=new TextArea();
output.setSize("600px", "150px");
output.setReadOnly(true);
add(output);
String list=Joiner.on("\n").join(Iterables.transform(voices, new VoiceToCsvFunction()));
output.setText(list);
HTML5Test.log(list);
}
if(s+30000<System.currentTimeMillis()){
add(new Label("voices is empty"));
cancel();
}
}
};
//timer.scheduleRepeating(100);
timer.schedule(100);
}
private void execSpeak() {
HTML5Test.log(""+System.currentTimeMillis()/1000);
utterance = SpeechSynthesisUtterance.create(textBox.getText());
utterance.setVoice(voiceListBox.getValue());
String lang=voiceListBox.getValue().getLang();
if(Strings.isNullOrEmpty(lang)){
lang=defaultLangBox.getText();
}
utterance.setLang(lang);//need set lang
HTML5Test.log("lang:"+lang);
utterance.setRate((double)rateRange.getValue()/10);
utterance.setPitch((double)pitchRange.getValue()/10);
utterance.setOnStart(new SpeechSynthesisStartListener() {
@Override
public void onStart(SpeechSynthesisEvent event) {
HTML5Test.log("start:"+event.getCharIndex()+","+event.getName()+","+event.getElapsedTime());
updateStatus();
}
});
utterance.setOnEnd(new SpeechSynthesisEndListener() {
@Override
public void onEnd(SpeechSynthesisEvent event) {
HTML5Test.log("end:"+event.getCharIndex()+","+event.getName()+","+event.getElapsedTime());
updateStatus();
}
});
utterance.setOnPause(new SpeechSynthesisPauseListener() {
@Override
public void onPause(SpeechSynthesisEvent event) {
HTML5Test.log("pause:"+event.getCharIndex()+","+event.getName()+","+event.getElapsedTime());
updateStatus();
}
});
utterance.setOnResume(new SpeechSynthesisResumeListener() {
@Override
public void onResume(SpeechSynthesisEvent event) {
HTML5Test.log("resume:"+event.getCharIndex()+","+event.getName()+","+event.getElapsedTime());
updateStatus();
}
});
utterance.setOnError(new SpeechSynthesisErrorListener() {
@Override
public void onError(SpeechSynthesisEvent event) {
HTML5Test.log("error:"+event.getCharIndex()+","+event.getName()+","+event.getElapsedTime());
updateStatus();
}
});
utterance.setOnBoundary(new SpeechSynthesisBoundaryListener() {
@Override
public void onBoundary(SpeechSynthesisEvent event) {
HTML5Test.log("boundary:"+event.getCharIndex()+","+event.getName()+","+event.getElapsedTime());
updateStatus();
}
});
utterance.setOnMark(new SpeechSynthesisMarkListener() {
@Override
public void onMark(SpeechSynthesisEvent event) {
HTML5Test.log("mark:"+event.getCharIndex()+","+event.getName()+","+event.getElapsedTime());
updateStatus();
}
});
speechSynthesis.speak(utterance);
}
public class VoiceToCsvFunction implements Function<Voice, String>{
@Override
public String apply(Voice input) {
List<String> values=new ArrayList<String>();
values.add(input.getName());
values.add(input.getLang());
values.add(input.getVoiceURI());
values.add(""+input.isDefault());
values.add(""+input.isLocalService());
return Joiner.on("\t").join(values);
}
}
private void updateStatus() {
String status="paused="+speechSynthesis.isPaused()+",pending="+speechSynthesis.isPending()+",speaking="+speechSynthesis.isSpeaking();
label.setText(status);
}
}