I am having a problem with the Sphinx voice recognition library for Java. I am using it to get input and handle it. In the grammar file , I wrote like this:
#JSGF V1.0;
grammar hello;
public <sentence> = (play | pause | next | previous);
My grammar is simple , just includes 4 words : "play" , "pause" , "next" , "previous". I have used Sphinx to detect them sucessfully . But I want my app to show a message like : "Unrecognized word" when I speak some words that do not belong to the grammar. Currently, For example, if I speak to the microphone a not belong to the grammar like :"stop" , it still show up the word that it detects that it is the nearest result.
My code is like this :
public class SphinxDemo {
static int i = 1;
static String resultText;
public static void main(String[] args) {
try {
URL url;
if (args.length > 0) {
url = new File(args[0]).toURI().toURL();
} else {
url = SphinxDemo.class.getResource("helloworld.config.xml");
}
System.out.println("Loading...");
ConfigurationManager cm = new ConfigurationManager(url);
Recognizer recognizer = (Recognizer) cm.lookup("recognizer");
Microphone microphone = (Microphone) cm.lookup("microphone");
/* allocate the resource necessary for the recognizer */
recognizer.allocate();
/* the microphone will keep recording until the program exits */
if (microphone.startRecording()) {
System.out
.println("Say: play|pause|previous|next");
while (true) {
System.out
.println("Start speaking. Press Ctrl-C to quit.\n");
Result result = recognizer.recognize();
if (result != null) {
System.out.println("Enter your choise" + "\n");
resultText = result.getBestFinalResultNoFiller();
System.out.println("You said: " + resultText + "\n");
}
if(!(resultText.equalsIgnoreCase("play") || resultText.equalsIgnoreCase("previous") || resultText.equalsIgnoreCase("pause")||resultText.equalsIgnoreCase("next"))){
System.out.println("Unrecognized word\n");
}
}
} else {
System.out.println("Cannot start microphone.");
recognizer.deallocate();
System.exit(1);
}
} catch (IOException e) {
System.err.println("Problem when loading SphinxDemo: " + e);
e.printStackTrace();
} catch (PropertyException e) {
System.err.println("Problem configuring SphinxDemo: " + e);
e.printStackTrace();
} catch (InstantiationException e) {
System.err.println("Problem creating SphinxDemo: " + e);
e.printStackTrace();
}
}
}
I have tried to add something like this to detect unrecognized word but it does not work:
if(!(resultText.equalsIgnoreCase("play") || resultText.equalsIgnoreCase("previous") || resultText.equalsIgnoreCase("pause")||resultText.equalsIgnoreCase("next"))){
System.out.println("Unrecognized word\n");
}
If you use latest cmusphinx, it will return <unk> when word is not in the grammar.
Related
I am trying to write a method which recursively gathers data from files, and writes erroneous data to an error file. See code block:
public static LinkedQueue<Stock> getStockData(LinkedQueue<Stock> stockQueue, String startPath) throws Exception {
File dir = new File(getValidDirectory(startPath));
try (PrintStream recordErrors = new PrintStream(new File("EODdataERRORS.txt"))) {
for (File name : dir.listFiles()) {
if (name.isDirectory()) {
getStockData(stockQueue, name.getPath());
}
else if (name.canRead()) {
Scanner readFile = new Scanner(name);
readFile.nextLine();
while (readFile.hasNext()) {
String line = readFile.nextLine();
String[] lineArray = line.split(",+");
if (lineArray.length == 8) {
try {
Stock stock = new Stock(name.getName().replaceAll("_+(.*)", ""));
stock.fromRecord(lineArray);
stockQueue.enqueue(stock);
}
catch (Exception ex) {
recordErrors.println(line + " ERROR: " + ex.getMessage());
System.err.println(line + " ERROR: " + ex.getMessage());
}
}
else {
recordErrors.println(line + " ERROR: Invalid record length.");
System.err.println(line + " ERROR: Invalid record length.");
}
}
}
}
}
catch (FileNotFoundException ex) {
System.err.println("FileNotFoundException. Please ensure the directory is configured properly.");
}
return stockQueue;
}
However, the error file is always blank.
I've tried calling the .flush() and .close() methods. System.err is outputting so I know the code is being run. I've tried instantiating the PrintStream outside of the try-with-resources, no change.
I've tried calling the method at earlier points in the code (i.e. right after instantiation of the printStream, and in the if{} block) and it does output to the error file. It's only within the catch{} and else{} blocks (where I actually need it to work) that it refuses to print anything. I've also tried storing the error data and using a loop after the blocks to print the data and it still won't work. See code block:
public static LinkedQueue<Stock> getStockData(LinkedQueue<Stock> stockQueue, String startPath) throws Exception {
File dir = new File(getValidDirectory(startPath));
LinkedQueue errors = new LinkedQueue();
try (PrintStream recordErrors = new PrintStream(new File("EODdataERRORS.txt"))) {
for (File name : dir.listFiles()) {
if (name.isDirectory()) {
getStockData(stockQueue, name.getPath());
}
else if (name.canRead()) {
Scanner readFile = new Scanner(name);
readFile.nextLine();
while (readFile.hasNext()) {
String line = readFile.nextLine();
String[] lineArray = line.split(",+");
if (lineArray.length == 8) {
try {
Stock stock = new Stock(name.getName().replaceAll("_+(.*)", ""));
stock.fromRecord(lineArray);
stockQueue.enqueue(stock);
}
catch (Exception ex) {
errors.enqueue(line + " ERROR: " + ex.getMessage());
System.err.println(line + " ERROR: " + ex.getMessage());
}
}
else {
errors.enqueue(line + " ERROR: Invalid record length.");
System.err.println(line + " ERROR: Invalid record length.");
}
}
}
}
while (!errors.isEmpty()) {
recordErrors.println(errors.dequeue());
}
}
catch (FileNotFoundException ex) {
System.err.println("FileNotFoundException. Please ensure the directory is configured properly.");
}
return stockQueue;
}
Edit
Code has been edited to show instantiation of the PrintStream only once. The error persists. I am sorry there is no Repex, I cannot recreate this error except for in this specific case.
I have solved the issue. I'm not really sure what the issue was, but it appears to have something to do with the PrintStream being instantiated in a method other than the main{} method. This would also explain why I was unable to recreate this error, try as I might.
As such, I've solved it by simply storing the errors in a list and printing them in the main{} method.
public static void getStockData(LinkedQueue<Stock> stockQueue, LinkedQueue<String> errorQueue, String startPath) {
File dir = new File(getValidDirectory(startPath));
try {
for (File name : dir.listFiles()) {
if (name.isDirectory()) {
getStockData(stockQueue, errorQueue, name.getPath());
}
else if (name.canRead()) {
Scanner readFile = new Scanner(name);
readFile.nextLine();
while (readFile.hasNext()) {
String line = readFile.nextLine();
String[] lineArray = line.split(",+");
if (lineArray.length == 8) {
try {
Stock stock = new Stock(name.getName().replaceAll("_+(.*)", ""));
stock.fromRecord(lineArray);
stockQueue.enqueue(stock);
}
catch (Exception ex) {
errorQueue.enqueue(line + "; ERROR: " + ex.getMessage());
System.err.println(line + "; ERROR: " + ex.getMessage());
}
}
else {
errorQueue.enqueue(line + "; ERROR: Invalid record length.");
System.err.println(line + "; ERROR: Invalid record length.");
}
}
}
}
}
catch (FileNotFoundException ex) {
System.err.println("FileNotFoundException. Please ensure the directory is configured properly.");
}
}
This has the downside of taking up more memory, but I see no other way to get this to work the way I want it to. Thanks for the help!
(using jfugue 5.0.9) I wanted to convert .mid to .txt (staccato), and later to .mid again, to confirm conversions worked. Both .mid (original and converted) should be equal ideally, but the converted (midi -> staccato -> midi) file has weird delayed notes, and one enlargened note duration. JFugue probably struggles because the midi is a human, hyper-sensible recording. Is there any way to fix this?
Heres the 3 files https://drive.google.com/drive/folders/1DepX0lCqNaIRCoHRfGwBRsO1xRFCbCpl?usp=sharing
And here are the 2 methods used:
public static Pattern convMidToStac(String fileName, boolean makeAFile) {
Pattern p = new Pattern();
// Convert midi file to a JFugue Staccato pattern.
try {
p = MidiFileManager.loadPatternFromMidi(new File("D:/eclipse-workspace/MidiReader/" + fileName + ".mid"));
if (makeAFile) {
makeFile(fileName, p.toString());
}
return p;
} catch (Exception e) {
System.out.println("An error occurred.");
e.printStackTrace();
return null;
}
}
public static void convStacToMid(String fileName) {
Pattern p = new Pattern();
try {
p = MidiFileManager.loadPatternFromMidi(new File("D:/eclipse-workspace/MidiReader/" + fileName + ".mid"));
File filePath = new File("D:/eclipse-workspace/MidiReader/" + fileName + "MIDI.mid");
MidiFileManager.savePatternToMidi(p, filePath);
} catch (Exception e) {
e.printStackTrace();
}
}
We are doing a project which user's answers are saved as .wav files and evaluated after. We have created grammars for each and every question. There are two questions we are having a recognition problem. Problems are probably the same since user must speak approximately 7-8 seconds for both of these questions.
This is the grammar file that we are using for one of the questions;
#JSGF V1.0;grammar Question8; public <Question8> = ( one hundred | ninety three | eighty six | seventy nine | seventy two | sixty five) * ;
Here, user must count numbers backwards by 7s. It recognizes fine if I speak too fast. When I speak slowly, for instance after saying "one hundred" and wait for 1 second and carry on until sixty five like this, it will only recognize one hundred and it won't recognize other words.
Two main parts are responsible for these processes:
The class that we created for microphone;
public final class SpeechRecorder {
static Configuration configuration = new Configuration();
static Microphone mic = new Microphone(16000, 16, 1, true, true, false, 10, true, "average", 0, "default", 6400);
public static void startMic() {
mic.initialize();
mic.startRecording();
mic.getAudioFormat();
mic.getUtterance();
System.out.println("Audio Format is" + mic.getAudioFormat());
}
public static void stopMic(String questionName) {
mic.stopRecording();
Utterance u = mic.getUtterance();
try {
u.save("Resources/Answers/" + questionName + ".wav", AudioFileFormat.Type.WAVE);
} catch (IOException e) {
e.printStackTrace();
}
}
public static String getAnswersOfSpeech(String question) throws IOException {
Evaluation.disableLogMessages();
configuration.setAcousticModelPath("resource:/edu/cmu/sphinx/models/en-us/en-us");
configuration.setDictionaryPath("resource:/edu/cmu/sphinx/models/en-us/cmudict-en-us.dict");
configuration.setGrammarPath("resource:/Grammer");
configuration.setGrammarName(question);
configuration.setUseGrammar(true);
StreamSpeechRecognizer recognizer = new StreamSpeechRecognizer(configuration);
recognizer.startRecognition(new FileInputStream("Resources/Answers/" + question + ".wav"));
SpeechResult Result = recognizer.getResult();
String speechWords = Result.getHypothesis();
return speechWords;
}
public static String getSavedAnswer(int question) {
return User.getAnswers(question);
}
}
This is where we save user's answer as .wav files into our resources.
btn_microphone.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
click++;
if (click % 2 == 1) {
SpeechRecorder.startMic();
btn_microphone.setIcon(new ImageIcon("Resources/Images/record.png"));
} else {
SpeechRecorder.stopMic("Question" + Integer.toString(question));
btn_Next.setVisible(true);
btn_microphone.setIcon(new ImageIcon("Resources/Images/microphone.png"));
lbl_speechAnswer.setVisible(true);
try {
userAnswer = SpeechRecorder.getAnswersOfSpeech("Question" + Integer.toString(question));
} catch (IOException e1) {
e1.printStackTrace();
}
if (userAnswer.equals("")) {
lbl_speechAnswer.setText(
"<html>No answer was given, click on microphone button to record again</html>");
} else {
lbl_speechAnswer.setText("<html>Your answer is " + userAnswer
+ ", click on microphone button to record again</html>");
}
}
}
});
I don't how can we overcome this problem. I would be so grateful if anyone could help me.
You need a loop as in transcriber demo:
while ((result = recognizer.getResult()) != null) {
System.out.format("Hypothesis: %s\n", result.getHypothesis());
}
recognizer.stopRecognition();
I'm working on a PC asistant, which means it should recognize my voice and give feedback or do things, the feedback should be a computer generated voice.
I know there's a way inside Java itself to achieve this, using javax.speech for example. This voice isn't really of good quality, but it's doesn't require all kinds of libraries and it should be easy to use. I currently have this prototype code:
public static void speech(String text) {
if(text.trim() == "")
return;
String voiceName = "kevin16";
try {
SynthesizerModeDesc desc = new SynthesizerModeDesc(null, "general", Locale.US, null, null);
Synthesizer synth = Central.createSynthesizer(desc);
synth.allocate();
synth.resume();
desc = (SynthesizerModeDesc) synth.getEngineModeDesc();
Voice[] voices = desc.getVoices();
Voice voice = null;
for(Voice entry : voices) {
if(entry.getName().equals(voiceName)) {
voice = entry;
break;
}
}
synth.getSynthesizerProperties().setVoice(voice);
synth.speakPlainText(text, null);
synth.waitEngineState(Synthesizer.QUEUE_EMPTY);
synth.deallocate();
} catch(Exception ex) {
String message = " missing speech.properties in " + System.getProperty("user.home") + "\n";
System.out.println("" + ex);
System.out.println(message);
ex.printStackTrace();
}
}
From: converting text to speech java code
When I execute the code it causes an error, that's because the file speech.properties is not found, it should be in my users directory. The problem is that I don't know where to get this file from, or what should be in this file, could anyone help me?
Also, it would be great if anyone could send me a link to a good speech tutorial, I searched the web but it's hard to find!
I could fix your example with just a few changes.
First, I Added these lines in the beggining of your try-catch block:
System.setProperty("FreeTTSSynthEngineCentral", "com.sun.speech.freetts.jsapi.FreeTTSEngineCentral");
System.setProperty("freetts.voices", "com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory");
Central.registerEngineCentral("com.sun.speech.freetts.jsapi.FreeTTSEngineCentral");
These lines bypass the need for that pesky speech.properties file.
Second, the voice name is "kevin16", not "kelvin16".
Third, I moved the synth.resume() to after the synth.getSynthesizerProperties().setVoice(voice) line. This is because it can't start talking anything without a predefined voice.
Forth, your if(text.trim() == "") is bad because comparing Strings using == is not a good idea.
Here is the resulting code:
public static void speech(String text) {
if (text == null || text.trim().isEmpty()) return;
String voiceName = "kevin16";
try {
System.setProperty("FreeTTSSynthEngineCentral", "com.sun.speech.freetts.jsapi.FreeTTSEngineCentral");
System.setProperty("freetts.voices", "com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory");
Central.registerEngineCentral("com.sun.speech.freetts.jsapi.FreeTTSEngineCentral");
SynthesizerModeDesc desc = new SynthesizerModeDesc(null, "general", Locale.US, null, null);
Synthesizer synth = Central.createSynthesizer(desc);
synth.allocate();
desc = (SynthesizerModeDesc) synth.getEngineModeDesc();
Voice[] voices = desc.getVoices();
Voice voice = null;
for (Voice entry : voices) {
if(entry.getName().equals(voiceName)) {
voice = entry;
break;
}
}
synth.getSynthesizerProperties().setVoice(voice);
synth.resume();
synth.speakPlainText(text, null);
synth.waitEngineState(Synthesizer.QUEUE_EMPTY);
synth.deallocate();
} catch(Exception ex) {
String message = " missing speech.properties in " + System.getProperty("user.home") + "\n";
System.out.println("" + ex);
System.out.println(message);
ex.printStackTrace();
}
}
I'm busy writing a Program that Transmits GPS Coordinates to a Server from a mobile phone where the coordinates are then used for calculations. But I'm constantly hitting a wall with blackberry. I have built the Android App and it works great but can't seem to contact the server on a real blackberry device. I have tested the application in a simulator and it works perfectly but when I install it on a real phone I get no request the phone.
I have read quite a bit about the secret strings to append at the end of the url so I adapted some demo code to get me the first available transport but still nothing ...
The Application is Signed and I normally then either install it by debugging through eclipse or directly on the device from the .jad file and allow the application the required permissions.
The current code was adapted from the HTTP Connection Demo in the Blackberry SDK.
Could you have a look and give me some direction. I'm losing too much hair here ...
The Backend Service that keeps running:
public void run() {
System.out.println("Starting Loop");
Criteria cr = new Criteria();
cr.setHorizontalAccuracy(Criteria.NO_REQUIREMENT);
cr.setVerticalAccuracy(Criteria.NO_REQUIREMENT);
cr.setCostAllowed(false);
cr.setPreferredPowerConsumption(Criteria.NO_REQUIREMENT);
cr.setPreferredResponseTime(1000);
LocationProvider lp = null;
try {
lp = LocationProvider.getInstance(cr);
} catch (LocationException e) {
System.out.println("*****************Exception" + e);
}
if (lp == null) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert("GPS not supported!");
return;
}
});
} else {
System.out
.println(lp.getState() + "-" + LocationProvider.AVAILABLE);
switch (lp.getState()) {
case LocationProvider.AVAILABLE:
// System.out.println("Provider is AVAILABLE");
while (true) {
Location l = null;
int timeout = 120;
try {
l = lp.getLocation(timeout);
final Location fi = l;
System.out.println("Got a Coordinate "
+ l.getQualifiedCoordinates().getLatitude()
+ ", "
+ l.getQualifiedCoordinates().getLongitude());
System.out.println("http://" + Constants.website_base
+ "/apis/location?device_uid=" + Constants.uid
+ "&lat="
+ l.getQualifiedCoordinates().getLatitude()
+ "&lng="
+ l.getQualifiedCoordinates().getLongitude());
if (!_connectionThread.isStarted()) {
fetchPage("http://"
+ Constants.website_base
+ "/apis/location?device_uid="
+ Constants.uid
+ "&lat="
+ l.getQualifiedCoordinates().getLatitude()
+ "&lng="
+ l.getQualifiedCoordinates()
.getLongitude());
} else {
createNewFetch("http://"
+ Constants.website_base
+ "/apis/location?device_uid="
+ Constants.uid
+ "&lat="
+ l.getQualifiedCoordinates().getLatitude()
+ "&lng="
+ l.getQualifiedCoordinates()
.getLongitude());
}
Thread.sleep(1000 * 60);
} catch (LocationException e) {
System.out.println("Location timeout");
} catch (InterruptedException e) {
System.out.println("InterruptedException"
+ e.getMessage());
} catch (Exception ex) {
System.err.println(ex.getMessage());
ex.printStackTrace();
}
}
}
}
My Connection is Made with:
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc = connFact.getConnection(getUrl());
// Open the connection and extract the data.
try {
// StreamConnection s = null;
// s = (StreamConnection) Connector.open(getUrl());
HttpConnection httpConn = (HttpConnection) connDesc.getConnection();
/* Data is Read here with a Input Stream */
Any Ideas ?
Figured it out!
Using a function I found online to determine which ; extension to use when connecting by using numerous Try / Catch. Then had to set the Internet APN settings. I'm in South-Africa using Vodacom so the APN is "Internet" with no Password.
Barely have hair left ....