package org.myrobotlab.service;
import org.myrobotlab.framework.Service;
import org.myrobotlab.framework.ServiceType;
import org.myrobotlab.logging.Level;
import org.myrobotlab.logging.LoggerFactory;
import org.myrobotlab.logging.Logging;
import org.myrobotlab.logging.LoggingFactory;
import org.myrobotlab.service.interfaces.SpeechSynthesis;
import org.slf4j.Logger;
/**
*
* MouthControl - This service will animate a jaw servo to move as its speaking
* It's peers are the jaw servo, speech service and an arduino.
*
*/
public class MouthControl extends Service {
private static final long serialVersionUID = 1L;
public final static Logger log = LoggerFactory.getLogger(MouthControl.class.getCanonicalName());
public int mouthClosedPos = 20;
public int mouthOpenedPos = 4;
public int delaytime = 100;
public int delaytimestop = 200;
public int delaytimeletter = 60;
transient Servo jaw;
transient Arduino arduino;
transient SpeechSynthesis mouth;
public boolean autoAttach = true;
public MouthControl(String n) {
super(n);
jaw = (Servo) createPeer("jaw");
arduino = (Arduino) createPeer("arduino");
mouth = (SpeechSynthesis) createPeer("mouth");
// TODO: mouth should probably implement speech synthesis.
// in a way of speaking, one day, people may be able to read the lips
// of the inmoov.. so you're synthesising speech in a mechanical way.
// similar to sign language maybe?
subscribe(mouth.getName(), "publishStartSpeaking");
subscribe(mouth.getName(), "publishEndSpeaking");
}
// FIXME make interface
public boolean connect(String port) throws Exception {
startService(); // NEEDED? I DONT THINK SO....
if (arduino == null) {
error("arduino is invalid");
return false;
}
arduino.connect(port);
if (!arduino.isConnected()) {
error("arduino %s not connected", arduino.getName());
return false;
}
// arduino.servoAttach(jaw);
arduino.servoAttach(jaw, 26);
return true;
}
public Arduino getArduino() {
return arduino;
}
public Servo getJaw() {
return jaw;
}
public void setJaw(Servo jaw) {
this.jaw = jaw;
}
public SpeechSynthesis getMouth() {
return mouth;
}
public void setMouth(SpeechSynthesis mouth) {
this.mouth = mouth;
subscribe(mouth.getName(), "publishStartSpeaking");
}
public void setArduino(Arduino arduino) {
this.arduino = arduino;
}
public String[] getCategories() {
return new String[] { "control" };
}
@Override
public String getDescription() {
return "mouth movements based on spoken text";
}
public synchronized void onStartSpeaking(String text) {
log.info("move moving to :" + text);
if (jaw != null) { // mouthServo.moveTo(Mouthopen);
if (autoAttach) {
if (!jaw.isAttached()) {
// attach the jaw if it's not attached.
jaw.attach();
}
}
boolean ison = false;
String testword;
String[] a = text.split(" ");
for (int w = 0; w < a.length; w++) {
// String word = ;
// log.info(String.valueOf(a[w].length()));
if (a[w].endsWith("es")) {
testword = a[w].substring(0, a[w].length() - 2);
} else if (a[w].endsWith("e")) {
testword = a[w].substring(0, a[w].length() - 1);
// log.info("e gone");
} else {
testword = a[w];
}
char[] c = testword.toCharArray();
for (int x = 0; x < c.length; x++) {
char s = c[x];
if ((s == 'a' || s == 'e' || s == 'i' || s == 'o' || s == 'u' || s == 'y') && !ison) {
jaw.moveTo(mouthOpenedPos); // # move the servo to the
// open spot
ison = true;
sleep(delaytime);
jaw.moveTo(mouthClosedPos);// #// close the servo
} else if (s == '.') {
ison = false;
sleep(delaytimestop);
} else {
ison = false;
sleep(delaytimeletter); // # sleep half a second
}
}
sleep(80);
}
} else {
log.info("need to attach first");
}
// We're done annimating, lets detach the jaw while not in use.
if (autoAttach && jaw != null) {
if (jaw.isAttached()) {
// attach the jaw if it's not attached.
jaw.detach();
}
}
}
public synchronized void onEndSpeaking(String utterance) {
log.info("Mouth control recognized end speaking.");
// TODO: consider a jaw move to closed position
if (jaw != null && jaw.isAttached()) {
jaw.moveTo(mouthClosedPos);
}
// else {
// log.info("Not closing my mouth?");
// }
}
public void setdelays(Integer d1, Integer d2, Integer d3) {
delaytime = d1;
delaytimestop = d2;
delaytimeletter = d3;
}
public void setmouth(Integer closed, Integer opened) {
// jaw.setMinMax(closed, opened);
mouthClosedPos = closed;
mouthOpenedPos = opened;
if (closed < opened) {
jaw.setMinMax(closed, opened);
} else {
jaw.setMinMax(opened, closed);
}
}
@Override
public void startService() {
super.startService();
jaw.startService();
arduino.startService();
// mouth.startService();
}
/**
* This static method returns all the details of the class without it having
* to be constructed. It has description, categories, dependencies, and peer
* definitions.
*
* @return ServiceType - returns all the data
*
*/
static public ServiceType getMetaData() {
ServiceType meta = new ServiceType(MouthControl.class.getCanonicalName());
meta.addDescription("Mouth movements based on spoken text");
meta.addCategory("control");
meta.addPeer("jaw", "Servo", "shared Jaw servo instance");
meta.addPeer("arduino", "Arduino", "shared Arduino instance");
meta.addPeer("mouth", "AcapelaSpeech", "shared Speech instance");
return meta;
}
public static void main(String[] args) {
LoggingFactory.init(Level.DEBUG);
try {
// LoggingFactory.getInstance().setLevel(Level.INFO);
MouthControl MouthControl = new MouthControl("MouthControl");
MouthControl.startService();
Runtime.createAndStart("gui", "GUIService");
MouthControl.autoAttach = true;
MouthControl.onStartSpeaking("test on");
} catch (Exception e) {
Logging.logError(e);
}
}
}