Moved speech recognition to configrable external command with worther thread pool
This commit is contained in:
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -21,9 +21,6 @@ import javax.imageio.*;
|
|||||||
import org.w3c.dom.*;
|
import org.w3c.dom.*;
|
||||||
import javax.xml.parsers.*;
|
import javax.xml.parsers.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import edu.cmu.sphinx.api.*;
|
|
||||||
import edu.cmu.sphinx.decoder.adaptation.*;
|
|
||||||
import edu.cmu.sphinx.result.*;
|
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
@@ -45,8 +42,6 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
|
|
||||||
// Settings - tweakable
|
// Settings - tweakable
|
||||||
|
|
||||||
public static final String SPHINX_MODEL = "resource:/edu/cmu/sphinx/models/en-us/en-us";
|
|
||||||
|
|
||||||
static Properties config = new Properties();
|
static Properties config = new Properties();
|
||||||
TreeMap<String, EffectGroup> effects;
|
TreeMap<String, EffectGroup> effects;
|
||||||
|
|
||||||
@@ -147,25 +142,9 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
public TargetDataLine microphone = null;
|
public TargetDataLine microphone = null;
|
||||||
public AudioInputStream microphoneStream = null;
|
public AudioInputStream microphoneStream = null;
|
||||||
|
|
||||||
public Configuration sphinxConfig;
|
|
||||||
public StreamSpeechRecognizer recognizer;
|
|
||||||
|
|
||||||
public static AudiobookRecorder window;
|
public static AudiobookRecorder window;
|
||||||
|
|
||||||
void initSphinx() {
|
public Queue<Runnable>speechProcessQueue = null;
|
||||||
Debug.trace();
|
|
||||||
sphinxConfig = new Configuration();
|
|
||||||
|
|
||||||
sphinxConfig.setAcousticModelPath(AudiobookRecorder.SPHINX_MODEL);
|
|
||||||
sphinxConfig.setDictionaryPath("resource:/edu/cmu/sphinx/models/en-us/cmudict-en-us.dict");
|
|
||||||
sphinxConfig.setLanguageModelPath("resource:/edu/cmu/sphinx/models/en-us/en-us.lm.bin");
|
|
||||||
|
|
||||||
try {
|
|
||||||
recognizer = new StreamSpeechRecognizer(sphinxConfig);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void buildToolbar(Container ob) {
|
void buildToolbar(Container ob) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
@@ -381,6 +360,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
Debug.debugEnabled = CLI.isSet("debug");
|
Debug.debugEnabled = CLI.isSet("debug");
|
||||||
Debug.traceEnabled = CLI.isSet("trace");
|
Debug.traceEnabled = CLI.isSet("trace");
|
||||||
|
|
||||||
|
speechProcessQueue = new ArrayDeque<Runnable>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
String clsname = "com.jtattoo.plaf.hifi.HiFiLookAndFeel";
|
String clsname = "com.jtattoo.plaf.hifi.HiFiLookAndFeel";
|
||||||
@@ -404,6 +385,12 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
|
|
||||||
Options.loadPreferences();
|
Options.loadPreferences();
|
||||||
|
|
||||||
|
for (int i = 0; i < Options.getInteger("process.threads"); i++) {
|
||||||
|
WorkerThread worker = new WorkerThread(speechProcessQueue);
|
||||||
|
worker.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
execScript(Options.get("scripts.startup"));
|
execScript(Options.get("scripts.startup"));
|
||||||
|
|
||||||
CacheManager.setCacheSize(Options.getInteger("cache.size"));
|
CacheManager.setCacheSize(Options.getInteger("cache.size"));
|
||||||
@@ -1136,24 +1123,11 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
try {
|
try {
|
||||||
Configuration sphinxConfig = new Configuration();
|
|
||||||
|
|
||||||
sphinxConfig.setAcousticModelPath(AudiobookRecorder.SPHINX_MODEL);
|
|
||||||
sphinxConfig.setDictionaryPath("resource:/edu/cmu/sphinx/models/en-us/cmudict-en-us.dict");
|
|
||||||
sphinxConfig.setLanguageModelPath("resource:/edu/cmu/sphinx/models/en-us/en-us.lm.bin");
|
|
||||||
|
|
||||||
sphinxConfig.setSampleRate((int)(book.getAudioFormat().getSampleRate() / 4f));
|
|
||||||
|
|
||||||
StreamSpeechRecognizer recognizer;
|
|
||||||
|
|
||||||
recognizer = new StreamSpeechRecognizer(sphinxConfig);
|
|
||||||
|
|
||||||
|
|
||||||
for (Enumeration s = chapter.children(); s.hasMoreElements();) {
|
for (Enumeration s = chapter.children(); s.hasMoreElements();) {
|
||||||
Sentence snt = (Sentence)s.nextElement();
|
Sentence snt = (Sentence)s.nextElement();
|
||||||
if (!snt.isLocked()) {
|
if (!snt.isLocked()) {
|
||||||
if (snt.getId().equals(snt.getText())) {
|
if (snt.getId().equals(snt.getText())) {
|
||||||
snt.doRecognition(recognizer);
|
snt.doRecognition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1629,9 +1603,20 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
JMenuObject o = (JMenuObject)e.getSource();
|
JMenuObject o = (JMenuObject)e.getSource();
|
||||||
Chapter c = (Chapter)o.getObject();
|
Chapter c = (Chapter)o.getObject();
|
||||||
BatchConversionThread r = new BatchConversionThread(c);
|
|
||||||
Thread t = new Thread(r);
|
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||||
t.start();
|
Sentence snt = (Sentence)s.nextElement();
|
||||||
|
if (!snt.isLocked()) {
|
||||||
|
if (snt.getId().equals(snt.getText())) {
|
||||||
|
Debug.d("Queueing recognition of", snt.getId());
|
||||||
|
synchronized(speechProcessQueue) {
|
||||||
|
Runnable r = snt.getRecognitionRunnable();
|
||||||
|
speechProcessQueue.add(r);
|
||||||
|
speechProcessQueue.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ public class Options extends JDialog {
|
|||||||
|
|
||||||
JTextField externalEditor;
|
JTextField externalEditor;
|
||||||
|
|
||||||
|
JTextField speechCommand;
|
||||||
|
JSpinner workerThreads;
|
||||||
|
|
||||||
JTextArea startupScript;
|
JTextArea startupScript;
|
||||||
|
|
||||||
ArrayList<JTextField[]> processorList;
|
ArrayList<JTextField[]> processorList;
|
||||||
@@ -331,7 +334,9 @@ public class Options extends JDialog {
|
|||||||
|
|
||||||
addSeparator(optionsPanel);
|
addSeparator(optionsPanel);
|
||||||
|
|
||||||
enableParsing = addCheckBox(optionsPanel, "Enable automatic sphinx speech-to-text (**SLOW**)", getBoolean("process.sphinx"));
|
enableParsing = addCheckBox(optionsPanel, "Enable automatic speech-to-text (**SLOW**)", getBoolean("process.sphinx"));
|
||||||
|
speechCommand = addTextField(optionsPanel, "Speech to text command (must take 1 filename parameter):", get("process.command"));
|
||||||
|
workerThreads = addSpinner(optionsPanel, "Worker threads:", 1, 100, 1, getInteger("process.threads"), "");
|
||||||
|
|
||||||
addSeparator(optionsPanel);
|
addSeparator(optionsPanel);
|
||||||
|
|
||||||
@@ -594,6 +599,8 @@ public class Options extends JDialog {
|
|||||||
defaultPrefs.put("audio.export.channels", "2");
|
defaultPrefs.put("audio.export.channels", "2");
|
||||||
defaultPrefs.put("audio.export.samplerate", "44100");
|
defaultPrefs.put("audio.export.samplerate", "44100");
|
||||||
defaultPrefs.put("process.sphinx", "false");
|
defaultPrefs.put("process.sphinx", "false");
|
||||||
|
defaultPrefs.put("process.command", "speech-to-text \"%f\"");
|
||||||
|
defaultPrefs.put("process.threads", "10");
|
||||||
|
|
||||||
defaultPrefs.put("editor.external", "");
|
defaultPrefs.put("editor.external", "");
|
||||||
|
|
||||||
@@ -718,6 +725,8 @@ public class Options extends JDialog {
|
|||||||
set("audio.export.channels", ((KVPair)channels.getSelectedItem()).key);
|
set("audio.export.channels", ((KVPair)channels.getSelectedItem()).key);
|
||||||
set("audio.export.samplerate", ((KVPair)exportRate.getSelectedItem()).key);
|
set("audio.export.samplerate", ((KVPair)exportRate.getSelectedItem()).key);
|
||||||
set("process.sphinx", enableParsing.isSelected());
|
set("process.sphinx", enableParsing.isSelected());
|
||||||
|
set("process.command", speechCommand.getText());
|
||||||
|
set("process.threads", workerThreads.getValue());
|
||||||
set("editor.external", externalEditor.getText());
|
set("editor.external", externalEditor.getText());
|
||||||
set("cache.size", cacheSize.getValue());
|
set("cache.size", cacheSize.getValue());
|
||||||
set("audio.recording.trim.fft", fftThreshold.getValue());
|
set("audio.recording.trim.fft", fftThreshold.getValue());
|
||||||
|
|||||||
@@ -21,10 +21,6 @@ import org.apache.http.impl.client.CloseableHttpClient;
|
|||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.impl.client.HttpClients;
|
||||||
import org.apache.http.util.EntityUtils;
|
import org.apache.http.util.EntityUtils;
|
||||||
|
|
||||||
import edu.cmu.sphinx.api.*;
|
|
||||||
import edu.cmu.sphinx.decoder.adaptation.*;
|
|
||||||
import edu.cmu.sphinx.result.*;
|
|
||||||
|
|
||||||
import org.json.*;
|
import org.json.*;
|
||||||
|
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
@@ -685,23 +681,35 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doRecognition(StreamSpeechRecognizer recognizer) {
|
public Runnable getRecognitionRunnable() {
|
||||||
|
Runnable r = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
Debug.d("Starting recognition of", getId());
|
||||||
|
doRecognition();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doRecognition() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
try {
|
try {
|
||||||
setText("[recognising...]");
|
setText("[recognising...]");
|
||||||
reloadTree();
|
reloadTree();
|
||||||
|
|
||||||
byte[] inData = getPCMData();
|
String command = Options.get("process.command");
|
||||||
|
Debug.d("Recognizing with command", command);
|
||||||
|
|
||||||
|
ProcessBuilder builder = new ProcessBuilder(command, getFile().getCanonicalPath());
|
||||||
|
Process process = builder.start();
|
||||||
|
InputStream is = process.getInputStream();
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||||
|
|
||||||
ByteArrayInputStream bas = new ByteArrayInputStream(inData);
|
|
||||||
recognizer.startRecognition(bas);
|
|
||||||
SpeechResult result;
|
|
||||||
String res = "";
|
String res = "";
|
||||||
while ((result = recognizer.getResult()) != null) {
|
String line = null;
|
||||||
res += result.getHypothesis();
|
while ((line = reader.readLine()) != null) {
|
||||||
res += " ";
|
res += line;
|
||||||
}
|
}
|
||||||
recognizer.stopRecognition();
|
|
||||||
|
|
||||||
setText(res);
|
setText(res);
|
||||||
reloadTree();
|
reloadTree();
|
||||||
@@ -712,32 +720,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
|
|
||||||
public void recognise() {
|
public void recognise() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
Thread t = new Thread(new Runnable() {
|
Thread t = new Thread(getRecognitionRunnable());
|
||||||
public void run() {
|
|
||||||
Debug.trace();
|
|
||||||
try {
|
|
||||||
Configuration sphinxConfig = new Configuration();
|
|
||||||
|
|
||||||
sphinxConfig.setAcousticModelPath(AudiobookRecorder.SPHINX_MODEL);
|
|
||||||
sphinxConfig.setDictionaryPath("resource:/edu/cmu/sphinx/models/en-us/cmudict-en-us.dict");
|
|
||||||
sphinxConfig.setLanguageModelPath("resource:/edu/cmu/sphinx/models/en-us/en-us.lm.bin");
|
|
||||||
|
|
||||||
AudioInputStream s = AudioSystem.getAudioInputStream(getFile());
|
|
||||||
AudioFormat format = getAudioFormat();
|
|
||||||
|
|
||||||
sphinxConfig.setSampleRate((int)(format.getSampleRate()));
|
|
||||||
|
|
||||||
StreamSpeechRecognizer recognizer;
|
|
||||||
|
|
||||||
recognizer = new StreamSpeechRecognizer(sphinxConfig);
|
|
||||||
|
|
||||||
doRecognition(recognizer);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1668,7 +1651,9 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
if (id.equals("room-noise")) return;
|
if (id.equals("room-noise")) return;
|
||||||
if (getParent() == null) return;
|
if (getParent() == null) return;
|
||||||
AudiobookRecorder.window.bookTreeModel.reload(this);
|
synchronized (AudiobookRecorder.window.bookTreeModel) {
|
||||||
|
AudiobookRecorder.window.bookTreeModel.reload(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getPeak() {
|
public double getPeak() {
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package uk.co.majenko.audiobookrecorder;
|
||||||
|
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
public class WorkerThread extends Thread {
|
||||||
|
private static int instance = 0;
|
||||||
|
private final Queue<Runnable> queue;
|
||||||
|
|
||||||
|
public WorkerThread(Queue<Runnable> queue) {
|
||||||
|
this.queue = queue;
|
||||||
|
setName("Worker Thread " + (instance++));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Debug.d(getName(), "started");
|
||||||
|
while ( true ) {
|
||||||
|
try {
|
||||||
|
Runnable work = null;
|
||||||
|
|
||||||
|
synchronized ( queue ) {
|
||||||
|
while ( queue.isEmpty() ) {
|
||||||
|
Debug.d(getName(), "waiting on work");
|
||||||
|
queue.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.d(getName(), "got work");
|
||||||
|
|
||||||
|
// Get the next work item off of the queue
|
||||||
|
work = queue.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the work item
|
||||||
|
work.run();
|
||||||
|
}
|
||||||
|
catch ( InterruptedException ie ) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
break; // Terminate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Debug.d(getName(), "died");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user