Complete overhaul of recording to allow better recording from microphones that require a warmup and self-calibration period

This commit is contained in:
2018-09-26 14:26:44 +01:00
parent e626da0c5e
commit 955227e9e3
7 changed files with 223 additions and 61 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

View File

@@ -85,7 +85,10 @@ public class AudiobookRecorder extends JFrame {
Random rng = new Random(); Random rng = new Random();
SourceDataLine play; SourceDataLine play = null;
public TargetDataLine microphone = null;
public AudioInputStream microphoneStream = null;
public Configuration sphinxConfig; public Configuration sphinxConfig;
public StreamSpeechRecognizer recognizer; public StreamSpeechRecognizer recognizer;
@@ -227,6 +230,9 @@ public class AudiobookRecorder extends JFrame {
Options.loadPreferences(); Options.loadPreferences();
execScript(Options.get("scripts.startup"));
CacheManager.setCacheSize(Options.getInteger("cache.size")); CacheManager.setCacheSize(Options.getInteger("cache.size"));
setLayout(new BorderLayout()); setLayout(new BorderLayout());
@@ -951,6 +957,11 @@ public class AudiobookRecorder extends JFrame {
if (recording != null) return; if (recording != null) return;
if (book == null) return; if (book == null) return;
if (microphone == null) {
JOptionPane.showMessageDialog(this, "Microphone not started. Start microphone first.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
toolBar.disableBook(); toolBar.disableBook();
toolBar.disableSentence(); toolBar.disableSentence();
@@ -979,6 +990,11 @@ public class AudiobookRecorder extends JFrame {
if (recording != null) return; if (recording != null) return;
if (book == null) return; if (book == null) return;
if (microphone == null) {
JOptionPane.showMessageDialog(this, "Microphone not started. Start microphone first.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
toolBar.disableBook(); toolBar.disableBook();
toolBar.disableSentence(); toolBar.disableSentence();
@@ -1026,6 +1042,11 @@ public class AudiobookRecorder extends JFrame {
if (recording != null) return; if (recording != null) return;
if (book == null) return; if (book == null) return;
if (microphone == null) {
JOptionPane.showMessageDialog(this, "Microphone not started. Start microphone first.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
toolBar.disableBook(); toolBar.disableBook();
toolBar.disableSentence(); toolBar.disableSentence();
@@ -1656,4 +1677,68 @@ public class AudiobookRecorder extends JFrame {
} }
equaliserWindow.setVisible(true); equaliserWindow.setVisible(true);
} }
public boolean enableMicrophone() {
AudioFormat format = new AudioFormat(
Options.getInteger("audio.recording.samplerate"),
16,
Options.getInteger("audio.recording.channels"),
true,
false
);
Mixer.Info mixer = Options.getRecordingMixer();
microphone = null;
try {
microphone = AudioSystem.getTargetDataLine(format, mixer);
} catch (Exception e) {
e.printStackTrace();
microphone = null;
return false;
}
if (microphone == null) {
JOptionPane.showMessageDialog(AudiobookRecorder.window, "Sample format not supported", "Error", JOptionPane.ERROR_MESSAGE);
return false;
}
microphoneStream = new AudioInputStream(microphone);
try {
microphone.open();
} catch (Exception e) {
e.printStackTrace();
microphone = null;
return false;
}
microphone.start();
return true;
}
public void disableMicrophone() {
try {
microphoneStream.close();
microphone.stop();
microphone.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void execScript(String s) {
if (s == null) return;
String[] lines = s.split("\n");
for (String line : lines) {
try {
Process p = Runtime.getRuntime().exec(line);
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
}
} }

View File

@@ -48,8 +48,21 @@ public class Equaliser extends JPanel {
} }
} }
}); });
JButton def = new JButton("Set as default");
def.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < 31; i++) {
Options.set("audio.eq." + i, channels[i].getValue());
}
}
});
add(smooth, BorderLayout.SOUTH); JPanel buttons = new JPanel();
buttons.setLayout(new FlowLayout());
buttons.add(smooth);
buttons.add(def);
add(buttons, BorderLayout.SOUTH);
} }
public float getChannel(int c) { public float getChannel(int c) {

View File

@@ -27,5 +27,5 @@ public class Icons {
static public final ImageIcon spinner2 = new ImageIcon(Icons.class.getResource("icons/spinner2.png")); static public final ImageIcon spinner2 = new ImageIcon(Icons.class.getResource("icons/spinner2.png"));
static public final ImageIcon spinner3 = new ImageIcon(Icons.class.getResource("icons/spinner3.png")); static public final ImageIcon spinner3 = new ImageIcon(Icons.class.getResource("icons/spinner3.png"));
static public final ImageIcon eq = new ImageIcon(Icons.class.getResource("icons/eq.png")); static public final ImageIcon eq = new ImageIcon(Icons.class.getResource("icons/eq.png"));
static public final ImageIcon mic = new ImageIcon(Icons.class.getResource("icons/mic.png"));
} }

View File

@@ -16,6 +16,7 @@ public class MainToolBar extends JToolBar {
JButton playonSentence; JButton playonSentence;
JButton stopPlaying; JButton stopPlaying;
JButton eq; JButton eq;
JToggleButton mic;
AudiobookRecorder root; AudiobookRecorder root;
@@ -111,7 +112,24 @@ public class MainToolBar extends JToolBar {
add(eq); add(eq);
addSeparator();
mic = new JToggleButton(Icons.mic);
mic.setToolTipText("Enable/disable microphone");
mic.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JToggleButton b = (JToggleButton)e.getSource();
if (b.isSelected()) {
if (!root.enableMicrophone()) {
b.setSelected(false);
}
} else {
root.disableMicrophone();
}
}
});
add(mic);
setFloatable(false); setFloatable(false);

View File

@@ -32,6 +32,8 @@ public class Options extends JDialog {
Equaliser equaliser; Equaliser equaliser;
JTextArea startupScript;
static HashMap<String, String> defaultPrefs; static HashMap<String, String> defaultPrefs;
static Preferences prefs = null; static Preferences prefs = null;
@@ -282,10 +284,19 @@ public class Options extends JDialog {
equaliser.setChannel(i, Options.getFloat("audio.eq." + i)); equaliser.setChannel(i, Options.getFloat("audio.eq." + i));
} }
tabs.add("EQ", equaliser); tabs.add("Default EQ", equaliser);
JPanel startScript = new JPanel();
startScript.setLayout(new BorderLayout());
startupScript = new JTextArea(get("scripts.startup"));
startScript.add(startupScript, BorderLayout.CENTER);
tabs.add("Startup Script", startScript);
add(tabs, BorderLayout.CENTER); add(tabs, BorderLayout.CENTER);
setTitle("Options"); setTitle("Options");
setModalityType(Dialog.ModalityType.APPLICATION_MODAL); setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
@@ -482,6 +493,8 @@ public class Options extends JDialog {
defaultPrefs.put("audio.eq.29", "-11.00"); defaultPrefs.put("audio.eq.29", "-11.00");
defaultPrefs.put("audio.eq.30", "-12.00"); defaultPrefs.put("audio.eq.30", "-12.00");
defaultPrefs.put("scripts.startup", "");
if (prefs == null) { if (prefs == null) {
prefs = Preferences.userNodeForPackage(AudiobookRecorder.class); prefs = Preferences.userNodeForPackage(AudiobookRecorder.class);
} }
@@ -587,6 +600,8 @@ public class Options extends JDialog {
set("audio.eq." + i, equaliser.getChannel(i)); set("audio.eq." + i, equaliser.getChannel(i));
} }
set("scripts.startup", startupScript.getText());
savePreferences(); savePreferences();
} }

View File

@@ -36,10 +36,75 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
TargetDataLine line; TargetDataLine line;
AudioInputStream inputStream; AudioInputStream inputStream;
Thread recordingThread = null;
int[] storedAudioData = null; int[] storedAudioData = null;
RecordingThread recordingThread;
static class RecordingThread implements Runnable {
boolean running = false;
boolean recording = false;
File tempFile;
File wavFile;
AudioFormat format;
public RecordingThread(File tf, File wf, AudioFormat af) {
tempFile = tf;
wavFile = wf;
format = af;
}
public void run() {
try {
running = true;
recording = true;
byte[] buf = new byte[AudiobookRecorder.window.microphone.getBufferSize()];
FileOutputStream fos = new FileOutputStream(tempFile);
int len = 0;
AudiobookRecorder.window.microphone.flush();
int nr = 0;
while (recording) {
nr = AudiobookRecorder.window.microphoneStream.read(buf, 0, buf.length);
len += nr;
fos.write(buf, 0, nr);
}
nr = AudiobookRecorder.window.microphoneStream.read(buf, 0, buf.length);
len += nr;
fos.write(buf, 0, nr);
fos.close();
FileInputStream fis = new FileInputStream(tempFile);
AudioInputStream ais = new AudioInputStream(fis, format, len / format.getFrameSize());
fos = new FileOutputStream(wavFile);
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, fos);
fos.close();
ais.close();
fis.close();
tempFile.delete();
recording = false;
running = false;
} catch (Exception e) {
e.printStackTrace();
running = false;
recording = false;
running = false;
}
}
public boolean isRunning() {
return running;
}
public void stopRecording() {
recording = false;
}
}
public Sentence() { public Sentence() {
super(""); super("");
id = UUID.randomUUID().toString(); id = UUID.randomUUID().toString();
@@ -57,72 +122,30 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
} }
public boolean startRecording() { public boolean startRecording() {
AudioFormat format = new AudioFormat( if (AudiobookRecorder.window.microphone == null) {
Options.getInteger("audio.recording.samplerate"), JOptionPane.showMessageDialog(AudiobookRecorder.window, "Microphone not started. Start the microphone first.", "Error", JOptionPane.ERROR_MESSAGE);
16,
Options.getInteger("audio.recording.channels"),
true,
false
);
Mixer.Info mixer = Options.getRecordingMixer();
line = null;
try {
line = AudioSystem.getTargetDataLine(format, mixer);
} catch (Exception e) {
e.printStackTrace();
}
if (line == null) {
JOptionPane.showMessageDialog(AudiobookRecorder.window, "Sample format not supported", "Error", JOptionPane.ERROR_MESSAGE);
return false; return false;
} }
inputStream = new AudioInputStream(line);
try { recordingThread = new RecordingThread(getTempFile(), getFile(), Options.getAudioFormat());
line.open();
} catch (Exception e) {
e.printStackTrace();
return false;
}
line.start(); Thread rc = new Thread(recordingThread);
rc.setDaemon(true);
rc.start();
File audioFile = getFile();
recordingThread = new Thread(new Runnable() {
public void run() {
try {
AudioSystem.write(inputStream, AudioFileFormat.Type.WAVE, audioFile);
} catch (Exception e) {
inputStream = null;
e.printStackTrace();
}
}
});
recordingThread.setDaemon(true);
recordingThread.start();
recording = true;
return true; return true;
} }
public void stopRecording() { public void stopRecording() {
try { recordingThread.stopRecording();
inputStream.close(); while (recordingThread.isRunning()) {
inputStream = null; try {
line.stop(); Thread.sleep(10);
line.close(); } catch (Exception e) {
line = null; }
} catch (Exception e) {
e.printStackTrace();
} }
recording = false;
storedAudioData = null; storedAudioData = null;
if (!id.equals("room-noise")) { if (!id.equals("room-noise")) {
@@ -277,6 +300,14 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
return new File(b, id + ".wav"); return new File(b, id + ".wav");
} }
public File getTempFile() {
File b = new File(AudiobookRecorder.window.getBookFolder(), "files");
if (!b.exists()) {
b.mkdirs();
}
return new File(b, id + ".wax");
}
public void editText() { public void editText() {
String t = JOptionPane.showInputDialog(null, "Edit Text", text); String t = JOptionPane.showInputDialog(null, "Edit Text", text);