package util.input; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.FileInputStream; import java.io.OutputStream; import java.util.List; import javax.swing.JComponent; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; import org.jdom2.output.XMLOutputter; import edu.cmu.sphinx.frontend.util.Microphone; import edu.cmu.sphinx.recognizer.Recognizer; import edu.cmu.sphinx.result.Result; import edu.cmu.sphinx.util.props.ConfigurationManager; /** * Voice Input listens for a specific word from a set of commands to be sopoken before notifying Input * @author Ying Chen */ public class VoiceInput extends InputDevice implements Runnable { private static final String DEVICE = "Voice"; private final String DefaultConfigFilePath = "dict.config.xml"; private final String DefaultDictionaryFilePath = "util/input"; private final String DefaultDictionaryFileName = "dict.gram"; private ConfigurationManager voiceManager; private Recognizer myRecognizer; private String configFilePath = DefaultConfigFilePath; private String dictFilePath = DefaultDictionaryFilePath; private String dictFileName = DefaultDictionaryFileName; private boolean configFileUpdated = false; /** * Constructs a Voice Input object which listens for specific voice commands and notifies input. * @param component * @param input */ public VoiceInput(JComponent component, Input input) { super(DEVICE, input); setVoiceManager(); //this.changeDictionary("input/newDict.gram"); new Thread(this).start(); } /** * Load the config file and set up the environment for speech recognition */ private void setVoiceManager() { voiceManager = new ConfigurationManager( VoiceInput.class.getResource(configFilePath)); //System.out.println(configFilePath); myRecognizer = (Recognizer) voiceManager.lookup("recognizer"); myRecognizer.allocate(); Microphone microphone = (Microphone) voiceManager.lookup("microphone"); if (!microphone.startRecording()) { System.out.println("Cannot start microphone."); myRecognizer.deallocate(); System.exit(1); } } /** * Generates an Alert Object for game behaviors to get the event time. * @return */ private AlertObject generateAlertObject() { long currentTimeStamp = System.currentTimeMillis(); return new AlertObject(currentTimeStamp); } /** * Starts listening to the user. */ @Override public void run() { while (true) { System.out.println("Start speaking. Press Ctrl-C to quit."); Result result = myRecognizer.recognize(); if (result != null) { String resultText = result.getBestFinalResultNoFiller(); notifyInputAction(DEVICE + "_" + resultText.substring(0, 1).toUpperCase() + resultText.substring(1), generateAlertObject()); } else { System.out.println("I can't hear what you said.\n"); } } } /** * Change the dictionary file Need to duplicate the default config file and * generate a new one Then change the file path and file name in the new * config file * * @param filePath */ public void changeDictionary(String filePath) { updateDictFile(filePath); if (!configFileUpdated) { try { duplicateConfigFile(); } catch (IOException e) { e.printStackTrace(); } } // Update the dict file info in the setting file SAXBuilder builder = new SAXBuilder(); File xmlFile = new File("src/util/input/" + configFilePath); try { Document doc = (Document) builder.build(xmlFile); Element rootNode = doc.getRootElement(); List<Element> elements = rootNode.getChildren("component"); List<Element> childElements = null; for (Element e : elements) { if (e.getAttributeValue("name").equals("jsgfGrammar")) { childElements = e.getChildren(); break; } } for (Element element : childElements) { if (element.getAttributeValue("name").equals("grammarLocation")) { element.getAttribute("value").setValue( "resource:/" + dictFilePath+"/"); } else if (element.getAttributeValue("name").equals( "grammarName")) { element.getAttribute("value").setValue(dictFileName); } } XMLOutputter xmlOutput = new XMLOutputter(); xmlOutput .output(doc, new FileWriter("src/util/input/" + configFilePath)); // Reload the setting file setVoiceManager(); } catch (JDOMException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * Update the dictFile path and name Hard coded * * @param filePath */ private void updateDictFile(String filePath) { System.out.println(filePath); int pos = filePath.lastIndexOf(File.separator); if (pos == -1) { dictFilePath = ""; dictFileName = filePath.substring(0, filePath.length() - 5); } else { dictFilePath = filePath.substring(0, pos); dictFileName = filePath.substring(pos + 1, filePath.length() - 5); } // System.out.println(dictFilePath); // System.out.println(dictFileName); } /** * Duplicate the default config file The new file's name is * "duplicated.config.xml" * * @throws IOException */ private void duplicateConfigFile() throws IOException { InputStream in = new FileInputStream("src/util/input/" + configFilePath); configFilePath = "newDict.config.xml"; OutputStream out = new FileOutputStream("src/util/input/" + configFilePath); byte[] buffer = new byte[1024]; int len; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } in.close(); out.close(); } }