Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 423d840d83 | |||
| 1997b0bf9b | |||
| b206fb33aa | |||
| 11b26e396c | |||
| 94139e6ac6 | |||
| c0cc2432ff | |||
| f86aaa3782 |
38
README.md
38
README.md
@@ -29,12 +29,13 @@ From here on much is controlled by key presses.
|
||||
appended to the currently selected chapter, or to the last chapter if none is selected.
|
||||
* Press and hold "T" to record a new phrase that is the start of a new paragraph. This adds the "post paragraph" gap to the previous sentence. Otherwise it does the same as "R".
|
||||
* Press and hold "F" to record a "continuation" phrase. This sets the previous phrase's post-gap to be the "short" gap instead of the normal length gap.
|
||||
* Press and hold "Y" to record a new phrase that is the start of a new section. This add the "post section" gap to the previous sentence. Otherwise it does the same as "R".
|
||||
* Press "D" to delete the last phrase you recorded.
|
||||
* Press "E" to re-record the currently selected phrase.
|
||||
|
||||
Each phrase you record will be briefly analysed using FFT to find the start and end of the audio and set
|
||||
Each phrase you record can be automatically analysed to find the start and end of the audio and set
|
||||
crop marks appropriately. These can be adjusted in the waveform display when a phrase is selected. You can also
|
||||
re-run the analysis using either the default FFT method or using a peak detector method (finding the first and last points
|
||||
re-run the analysis using either FFT or a peak detector method (finding the first and last points
|
||||
where the audio amplitude rises above the backround noise).
|
||||
|
||||
The phrases also have a "post gap" associated with them. This is the amount of room noise (in milliseconds) to place between
|
||||
@@ -53,18 +54,14 @@ edit the text of this ID to identify the recordings. You
|
||||
may, for instance, change it to have the same text as the
|
||||
audio contains.
|
||||
|
||||
To help with this the Haven On-Demand online speech recognition
|
||||
service is integrated with the system and can be used to try and convert the
|
||||
audio into text. Right clicking on a recording brings
|
||||
up a menu which includes the option to try and convert
|
||||
the audio into text. The detected text is then used to
|
||||
replace the current recording ID / text.
|
||||
The audio can also be automatically converted to text if you have an suitable command-line
|
||||
executable that will work. One example is (on Linux) [DeepSpeech](https://github.com/mozilla/DeepSpeech) by Mozilla.
|
||||
|
||||
File layout
|
||||
-----------
|
||||
|
||||
All data is stored in your "storage" directory (specified in Options). Each book (which is a directory named after the
|
||||
title of the book) has an associated XML file (audiobook.abk) and a directory "files" where all the audio (stored as WAV
|
||||
title of the book) has an associated XML file (audiobook.abx) and a directory "files" where all the audio (stored as WAV
|
||||
files) is placed.
|
||||
|
||||
When you export the book as MP3 a new folder "export" is created within the book's folder where the MP3 files are placed.
|
||||
@@ -81,3 +78,26 @@ Building
|
||||
5. Build with `ant build`
|
||||
6. Run with `java -jar ./AudiobookRecorder.jar`
|
||||
|
||||
|
||||
----
|
||||
|
||||
Extra Resources
|
||||
===============
|
||||
|
||||
* DeepSpeech wrapper script
|
||||
|
||||
This is a small script that will convert the audio into a format DeepSpeech likes and call the `deepspeech` executable, removing any extra rubbish from the output. It
|
||||
also requires `sox` to be installed for the audio conversion.
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
|
||||
ID=$$
|
||||
FILE=$1
|
||||
BINPATH=${HOME}/local/bin
|
||||
MODELS=${HOME}/ds/deepspeech-0.6.1-models
|
||||
|
||||
sox "$FILE" -r 16000 -c 1 -b 16 "/tmp/ds-${ID}.wav"
|
||||
${BINPATH}/deepspeech --model ${MODELS}/output_graph.pbmm --lm ${MODELS}/lm.binary --trie ${MODELS}/trie --audio "/tmp/ds-${ID}.wav" 2>/dev/null
|
||||
rm /tmp/ds-${ID}.wav
|
||||
```
|
||||
|
||||
@@ -1 +1 @@
|
||||
version=0.3.6
|
||||
version=0.3.8
|
||||
|
||||
BIN
resources/uk/co/majenko/audiobookrecorder/icons/processing.png
Normal file
BIN
resources/uk/co/majenko/audiobookrecorder/icons/processing.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 489 B |
BIN
resources/uk/co/majenko/audiobookrecorder/icons/queued.png
Normal file
BIN
resources/uk/co/majenko/audiobookrecorder/icons/queued.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 717 B |
@@ -11,6 +11,7 @@ import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
import java.util.Queue;
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
@@ -18,6 +19,7 @@ import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Container;
|
||||
import java.awt.Desktop;
|
||||
@@ -177,6 +179,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
|
||||
JSpinner postSentenceGap;
|
||||
JSpinner gainPercent;
|
||||
Timer waveformUpdater = new Timer();
|
||||
JCheckBox locked;
|
||||
JCheckBox attention;
|
||||
JCheckBox rawAudio;
|
||||
@@ -203,7 +206,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
|
||||
public static AudiobookRecorder window;
|
||||
|
||||
public Queue<Runnable>speechProcessQueue = null;
|
||||
public Queue<Runnable>processQueue = null;
|
||||
public QueueMonitor queueMonitor = null;
|
||||
|
||||
void buildToolbar(Container ob) {
|
||||
Debug.trace();
|
||||
@@ -419,7 +423,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
Debug.debugEnabled = CLI.isSet("debug");
|
||||
Debug.traceEnabled = CLI.isSet("trace");
|
||||
|
||||
speechProcessQueue = new ArrayDeque<Runnable>();
|
||||
processQueue = new ArrayDeque<Runnable>();
|
||||
|
||||
try {
|
||||
|
||||
@@ -444,8 +448,11 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
|
||||
Options.loadPreferences();
|
||||
|
||||
queueMonitor = new QueueMonitor(processQueue);
|
||||
|
||||
for (int i = 0; i < Options.getInteger("process.threads"); i++) {
|
||||
WorkerThread worker = new WorkerThread(speechProcessQueue);
|
||||
WorkerThread worker = new WorkerThread(processQueue, queueMonitor);
|
||||
queueMonitor.addThread(worker);
|
||||
worker.start();
|
||||
}
|
||||
|
||||
@@ -529,11 +536,12 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Debug.trace();
|
||||
if (selectedSentence != null) {
|
||||
selectedSentence.autoTrimSampleFFT();
|
||||
sampleWaveform.setMarkers(selectedSentence.getStartOffset(), selectedSentence.getEndOffset());
|
||||
sampleWaveform.setAltMarkers(selectedSentence.getStartCrossing(), selectedSentence.getEndCrossing());
|
||||
postSentenceGap.setValue(selectedSentence.getPostGap());
|
||||
gainPercent.setValue((int)(selectedSentence.getGain() * 100d));
|
||||
queueJob(new SentenceJob(selectedSentence) {
|
||||
public void run() {
|
||||
sentence.autoTrimSampleFFT();
|
||||
updateWaveformMarkers();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -542,11 +550,12 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Debug.trace();
|
||||
if (selectedSentence != null) {
|
||||
selectedSentence.autoTrimSamplePeak();
|
||||
sampleWaveform.setMarkers(selectedSentence.getStartOffset(), selectedSentence.getEndOffset());
|
||||
sampleWaveform.setAltMarkers(selectedSentence.getStartCrossing(), selectedSentence.getEndCrossing());
|
||||
postSentenceGap.setValue(selectedSentence.getPostGap());
|
||||
gainPercent.setValue((int)(selectedSentence.getGain() * 100d));
|
||||
queueJob(new SentenceJob(selectedSentence) {
|
||||
public void run() {
|
||||
sentence.autoTrimSamplePeak();
|
||||
updateWaveformMarkers();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -654,8 +663,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
doCutSplit.setEnabled(false);
|
||||
selectCutMode.setSelected(false);
|
||||
selectSplitMode.setSelected(false);
|
||||
|
||||
bookTreeModel.reload(selectedSentence);
|
||||
selectedSentence.reloadTree();
|
||||
}
|
||||
});
|
||||
controlsTop.add(locked);
|
||||
@@ -676,7 +684,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
selectedSentence.setAttentionFlag(false);
|
||||
}
|
||||
}
|
||||
bookTreeModel.reload(selectedSentence);
|
||||
selectedSentence.reloadTree();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -744,10 +752,12 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
centralPanel.add(sampleControl, BorderLayout.SOUTH);
|
||||
|
||||
statusBar = new JPanel();
|
||||
statusBar.setLayout(new FlowLayout(FlowLayout.CENTER));
|
||||
add(statusBar, BorderLayout.SOUTH);
|
||||
|
||||
statusLabel = new JLabel("Noise floor: " + getNoiseFloorDB() + "dB");
|
||||
statusBar.add(statusLabel);
|
||||
statusBar.add(queueMonitor);
|
||||
|
||||
buildToolbar(centralPanel);
|
||||
|
||||
@@ -931,12 +941,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
Debug.trace();
|
||||
if (ev.getPropertyName().equals("dividerLocation")) {
|
||||
if ((bookTreeModel != null) && (book != null)) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
Debug.trace();
|
||||
bookTreeModel.reload(book);
|
||||
}
|
||||
});
|
||||
Debug.trace();
|
||||
book.reloadTree();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1039,6 +1045,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
|
||||
public static void main(String args[]) {
|
||||
Debug.trace();
|
||||
Properties props = System.getProperties();
|
||||
props.setProperty("sun.java2d.opengl", "true");
|
||||
try {
|
||||
config.load(AudiobookRecorder.class.getResourceAsStream("config.txt"));
|
||||
} catch (Exception e) {
|
||||
@@ -1191,10 +1199,11 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
if (!snt.isLocked()) {
|
||||
if (snt.getId().equals(snt.getText())) {
|
||||
Runnable r = snt.getRecognitionRunnable();
|
||||
snt.setQueued();
|
||||
speechProcessQueue.add(r);
|
||||
speechProcessQueue.notify();
|
||||
queueJob(new SentenceJob(snt) {
|
||||
public void run() {
|
||||
sentence.doRecognition();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1227,7 +1236,11 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Sentence s = (Sentence)o.getObject();
|
||||
if (!s.isLocked()) {
|
||||
s.recognise();
|
||||
queueJob(new SentenceJob(s) {
|
||||
public void run() {
|
||||
sentence.doRecognition();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1304,7 +1317,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
String type = (String)o.getObject2();
|
||||
sent.setPostGapType(type);
|
||||
sent.setPostGap(Options.getInteger("catenation.post-sentence"));
|
||||
bookTreeModel.reload(sent);
|
||||
sent.reloadTree();
|
||||
}
|
||||
});
|
||||
setGapType.add(gapTypeSentence);
|
||||
@@ -1317,7 +1330,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
String type = (String)o.getObject2();
|
||||
sent.setPostGapType(type);
|
||||
sent.setPostGap(Options.getInteger("catenation.short-sentence"));
|
||||
bookTreeModel.reload(sent);
|
||||
sent.reloadTree();
|
||||
}
|
||||
});
|
||||
setGapType.add(gapTypeContinuation);
|
||||
@@ -1330,7 +1343,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
String type = (String)o.getObject2();
|
||||
sent.setPostGapType(type);
|
||||
sent.setPostGap(Options.getInteger("catenation.post-paragraph"));
|
||||
bookTreeModel.reload(sent);
|
||||
sent.reloadTree();
|
||||
}
|
||||
});
|
||||
setGapType.add(gapTypeParagraph);
|
||||
@@ -1343,7 +1356,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
String type = (String)o.getObject2();
|
||||
sent.setPostGapType(type);
|
||||
sent.setPostGap(Options.getInteger("catenation.post-section"));
|
||||
bookTreeModel.reload(sent);
|
||||
sent.reloadTree();
|
||||
}
|
||||
});
|
||||
setGapType.add(gapTypeSection);
|
||||
@@ -1472,14 +1485,19 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Debug.trace();
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter chap = (Chapter)o.getObject();
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
if (!snt.isProcessed()) {
|
||||
queueJob(new SentenceJob(snt) {
|
||||
public void run() {
|
||||
sentence.autoTrimSampleFFT();
|
||||
updateWaveformMarkers();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ProgressDialog ed = new ProgressDialog("Auto-trimming " + chap.getName());
|
||||
|
||||
AutoTrimThread t = new AutoTrimThread(chap, ed, AutoTrimThread.Peak, AutoTrimThread.NewOnly);
|
||||
Thread nt = new Thread(t);
|
||||
nt.start();
|
||||
ed.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1487,14 +1505,18 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Debug.trace();
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter chap = (Chapter)o.getObject();
|
||||
|
||||
ProgressDialog ed = new ProgressDialog("Auto-trimming " + chap.getName());
|
||||
|
||||
AutoTrimThread t = new AutoTrimThread(chap, ed, AutoTrimThread.FFT, AutoTrimThread.NewOnly);
|
||||
Thread nt = new Thread(t);
|
||||
nt.start();
|
||||
ed.setVisible(true);
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
if (!snt.isProcessed()) {
|
||||
queueJob(new SentenceJob(snt) {
|
||||
public void run() {
|
||||
sentence.autoTrimSampleFFT();
|
||||
updateWaveformMarkers();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1502,14 +1524,16 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Debug.trace();
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter chap = (Chapter)o.getObject();
|
||||
|
||||
ProgressDialog ed = new ProgressDialog("Auto-trimming " + chap.getName());
|
||||
|
||||
AutoTrimThread t = new AutoTrimThread(chap, ed, AutoTrimThread.Peak, AutoTrimThread.All);
|
||||
Thread nt = new Thread(t);
|
||||
nt.start();
|
||||
ed.setVisible(true);
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
queueJob(new SentenceJob(snt) {
|
||||
public void run() {
|
||||
sentence.autoTrimSamplePeak();
|
||||
updateWaveformMarkers();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1517,14 +1541,16 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Debug.trace();
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter chap = (Chapter)o.getObject();
|
||||
|
||||
ProgressDialog ed = new ProgressDialog("Auto-trimming " + chap.getName());
|
||||
|
||||
AutoTrimThread t = new AutoTrimThread(chap, ed, AutoTrimThread.FFT, AutoTrimThread.All);
|
||||
Thread nt = new Thread(t);
|
||||
nt.start();
|
||||
ed.setVisible(true);
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
queueJob(new SentenceJob(snt) {
|
||||
public void run() {
|
||||
sentence.autoTrimSampleFFT();
|
||||
updateWaveformMarkers();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1597,7 +1623,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
snt.setLocked(true);
|
||||
bookTreeModel.reload(snt);
|
||||
snt.reloadTree();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1610,7 +1636,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
snt.setLocked(false);
|
||||
bookTreeModel.reload(snt);
|
||||
snt.reloadTree();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1658,13 +1684,11 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
if (!snt.isLocked()) {
|
||||
if (!snt.beenDetected()) {
|
||||
Debug.d("Queueing recognition of", snt.getId());
|
||||
synchronized(speechProcessQueue) {
|
||||
Runnable r = snt.getRecognitionRunnable();
|
||||
snt.setQueued();
|
||||
speechProcessQueue.add(r);
|
||||
speechProcessQueue.notify();
|
||||
}
|
||||
queueJob(new SentenceJob(snt) {
|
||||
public void run() {
|
||||
sentence.doRecognition();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2073,7 +2097,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
if (recording == null) return;
|
||||
recording.stopRecording();
|
||||
|
||||
bookTreeModel.reload(book);
|
||||
// book.reloadTree();
|
||||
|
||||
bookTree.expandPath(new TreePath(((DefaultMutableTreeNode)recording.getParent()).getPath()));
|
||||
bookTree.setSelectionPath(new TreePath(recording.getPath()));
|
||||
@@ -2188,8 +2212,12 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
bookTree.setEditable(true);
|
||||
bookTree.setUI(new CustomTreeUI(mainScroll));
|
||||
|
||||
bookTree.setCellRenderer(new BookTreeRenderer());
|
||||
|
||||
try {
|
||||
bookTree.setCellRenderer(new BookTreeRenderer());
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
bookTree.setCellRenderer(new BookTreeRenderer());
|
||||
}
|
||||
|
||||
InputMap im = bookTree.getInputMap(JComponent.WHEN_FOCUSED);
|
||||
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "startStopPlayback");
|
||||
@@ -2283,7 +2311,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
} else {
|
||||
book.setIcon(Icons.book);
|
||||
}
|
||||
bookTreeModel.reload(book);
|
||||
book.reloadTree();
|
||||
|
||||
bookTree.expandPath(new TreePath(book.getPath()));
|
||||
|
||||
@@ -2319,7 +2347,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
ImageIcon i = new ImageIcon(cf.getAbsolutePath());
|
||||
Image ri = Utils.getScaledImage(i.getImage(), 22, 22);
|
||||
book.setIcon(new ImageIcon(ri));
|
||||
bookTreeModel.reload(book);
|
||||
book.reloadTree();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -2719,55 +2747,6 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
}
|
||||
}
|
||||
|
||||
class AutoTrimThread implements Runnable {
|
||||
ProgressDialog dialog;
|
||||
Chapter chapter;
|
||||
int type;
|
||||
int scope;
|
||||
|
||||
public final static int FFT = 0;
|
||||
public final static int Peak = 1;
|
||||
public final static int NewOnly = 0;
|
||||
public final static int All = 1;
|
||||
|
||||
public AutoTrimThread(Chapter c, ProgressDialog e, int t, int sc) {
|
||||
super();
|
||||
Debug.trace();
|
||||
dialog = e;
|
||||
chapter = c;
|
||||
type = t;
|
||||
scope = sc;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void run() {
|
||||
Debug.trace();
|
||||
|
||||
int numKids = chapter.getChildCount();
|
||||
int kidCount = 0;
|
||||
for (Enumeration s = chapter.children(); s.hasMoreElements();) {
|
||||
kidCount++;
|
||||
dialog.setProgress(kidCount * 2000 / numKids);
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
if (scope == NewOnly) {
|
||||
if (snt.isProcessed()) continue;
|
||||
}
|
||||
switch (type) {
|
||||
case FFT:
|
||||
snt.autoTrimSampleFFT();
|
||||
break;
|
||||
case Peak:
|
||||
snt.autoTrimSamplePeak();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dialog.closeDialog();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class ExportThread implements Runnable {
|
||||
ProgressDialog exportDialog;
|
||||
Chapter chapter;
|
||||
@@ -3503,7 +3482,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
ImageIcon i = new ImageIcon(dest.getAbsolutePath());
|
||||
Image ri = Utils.getScaledImage(i.getImage(), 22, 22);
|
||||
book.setIcon(new ImageIcon(ri));
|
||||
bookTreeModel.reload(book);
|
||||
book.reloadTree();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -3516,16 +3495,42 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
updateWaveform(false);
|
||||
}
|
||||
|
||||
public void updateWaveform(boolean force) {
|
||||
TimerTask waveformUpdaterTask = null;
|
||||
|
||||
synchronized public void updateWaveform(boolean force) {
|
||||
Debug.trace();
|
||||
if (selectedSentence != null) {
|
||||
if ((!force) && (sampleWaveform.getId() != null) && (sampleWaveform.getId().equals(selectedSentence.getId()))) return;
|
||||
sampleWaveform.setId(selectedSentence.getId());
|
||||
if (rawAudio.isSelected()) {
|
||||
sampleWaveform.setData(selectedSentence.getRawAudioData());
|
||||
} else {
|
||||
sampleWaveform.setData(selectedSentence.getDoubleAudioData(effectsEnabled));
|
||||
|
||||
synchronized (waveformUpdater) {
|
||||
try {
|
||||
if (waveformUpdaterTask != null) {
|
||||
waveformUpdaterTask.cancel();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
|
||||
waveformUpdaterTask = new TimerTask() {
|
||||
public void run() {
|
||||
sampleWaveform.setId(selectedSentence.getId());
|
||||
if (rawAudio.isSelected()) {
|
||||
sampleWaveform.setData(selectedSentence.getRawAudioData());
|
||||
} else {
|
||||
sampleWaveform.setData(selectedSentence.getDoubleAudioData(effectsEnabled));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
waveformUpdater.schedule(waveformUpdaterTask, 20);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
synchronized public void updateWaveformMarkers() {
|
||||
if (selectedSentence != null) {
|
||||
sampleWaveform.setMarkers(selectedSentence.getStartOffset(), selectedSentence.getEndOffset());
|
||||
sampleWaveform.setAltMarkers(selectedSentence.getStartCrossing(), selectedSentence.getEndCrossing());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4185,4 +4190,14 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void queueJob(Runnable r) {
|
||||
synchronized(processQueue) {
|
||||
processQueue.add(r);
|
||||
if (r instanceof SentenceJob) {
|
||||
SentenceJob sj = (SentenceJob)r;
|
||||
sj.setQueued();
|
||||
}
|
||||
processQueue.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.util.UUID;
|
||||
import java.util.Properties;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
@@ -217,7 +218,7 @@ public class Book extends BookTreeNode {
|
||||
oldDir.renameTo(newDir);
|
||||
name = newName;
|
||||
AudiobookRecorder.window.saveBookStructure();
|
||||
AudiobookRecorder.window.bookTreeModel.reload(this);
|
||||
reloadTree();
|
||||
Options.set("path.last-book", name);
|
||||
Options.savePreferences();
|
||||
AudiobookRecorder.window.setTitle("AudioBook Recorder :: " + name);
|
||||
@@ -447,4 +448,13 @@ public class Book extends BookTreeNode {
|
||||
public void setLocation(File l) {
|
||||
location = l;
|
||||
}
|
||||
|
||||
public void reloadTree() {
|
||||
Debug.trace();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
AudiobookRecorder.window.bookTreeModel.reload(Book.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ package uk.co.majenko.audiobookrecorder;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTree;
|
||||
@@ -84,7 +86,8 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer {
|
||||
}
|
||||
|
||||
|
||||
JLabel time = new JLabel(Utils.secToTime(s.getLength(), "mm:ss.SSS") + " ");
|
||||
JLabel time = new JLabelFixedWidth(75, " " + Utils.secToTime(s.getLength(), "ss.SSS") + " ");
|
||||
time.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
|
||||
ctx.gridx = 0;
|
||||
ctx.gridy = 0;
|
||||
@@ -93,17 +96,18 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer {
|
||||
ctx.anchor = GridBagConstraints.LINE_START;
|
||||
p.add(ret, ctx);
|
||||
|
||||
if (s.isDetecting()) {
|
||||
JLabel eff = new JLabel(" recognising... ");
|
||||
if (s.isProcessing()) {
|
||||
JLabel eff = new JLabel();
|
||||
eff.setIcon(Icons.processing);
|
||||
ctx.weightx = 0.0d;
|
||||
ctx.gridx = 1;
|
||||
p.add(eff);
|
||||
} else if (s.isQueued()) {
|
||||
JLabel eff = new JLabel(" queued ");
|
||||
JLabel eff = new JLabel();
|
||||
eff.setIcon(Icons.queued);
|
||||
ctx.weightx = 0.0d;
|
||||
ctx.gridx = 1;
|
||||
p.add(eff);
|
||||
} else if (s.isQueued()) {
|
||||
}
|
||||
|
||||
String effectChain = s.getEffectChain();
|
||||
@@ -121,7 +125,8 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer {
|
||||
ctx.gridx = 3;
|
||||
ctx.anchor = GridBagConstraints.LINE_END;
|
||||
int peak = s.getPeakDB();
|
||||
JLabel peakLabel = new JLabel(peak + "dB ");
|
||||
JLabel peakLabel = new JLabelFixedWidth(50, peak + "dB ");
|
||||
peakLabel.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
if (peak > 0) {
|
||||
peakLabel.setForeground(new Color(0xCC, 0x00, 0x00));
|
||||
}
|
||||
|
||||
@@ -40,4 +40,6 @@ public class Icons {
|
||||
static public final ImageIcon disable = new ImageIcon(Icons.class.getResource("icons/disable-effects.png"));
|
||||
static public final ImageIcon manuscript = new ImageIcon(Icons.class.getResource("icons/manuscript.png"));
|
||||
static public final ImageIcon tooltip = new ImageIcon(Icons.class.getResource("icons/tooltip.png"));
|
||||
static public final ImageIcon queued = new ImageIcon(Icons.class.getResource("icons/queued.png"));
|
||||
static public final ImageIcon processing = new ImageIcon(Icons.class.getResource("icons/processing.png"));
|
||||
}
|
||||
|
||||
38
src/uk/co/majenko/audiobookrecorder/JLabelFixedWidth.java
Normal file
38
src/uk/co/majenko/audiobookrecorder/JLabelFixedWidth.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package uk.co.majenko.audiobookrecorder;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import java.awt.Dimension;
|
||||
|
||||
public class JLabelFixedWidth extends JLabel {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
Dimension size;
|
||||
public JLabelFixedWidth(int w, String txt) {
|
||||
super(txt);
|
||||
JLabel t = new JLabel(txt);
|
||||
size = t.getPreferredSize();
|
||||
size.width = w;
|
||||
}
|
||||
|
||||
public JLabelFixedWidth(int w) {
|
||||
super();
|
||||
JLabel t = new JLabel("nothing");
|
||||
size = t.getPreferredSize();
|
||||
size.width = w;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMaximumSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
71
src/uk/co/majenko/audiobookrecorder/QueueMonitor.java
Normal file
71
src/uk/co/majenko/audiobookrecorder/QueueMonitor.java
Normal file
@@ -0,0 +1,71 @@
|
||||
package uk.co.majenko.audiobookrecorder;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Queue;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Color;
|
||||
|
||||
public class QueueMonitor extends JPanel {
|
||||
|
||||
ArrayList<WorkerThread> threadList = new ArrayList<WorkerThread>();
|
||||
Queue queue;
|
||||
|
||||
public QueueMonitor(Queue q) {
|
||||
super();
|
||||
queue = q;
|
||||
}
|
||||
|
||||
public void addThread(WorkerThread t) {
|
||||
threadList.add(t);
|
||||
}
|
||||
|
||||
public void purgeQueue() {
|
||||
synchronized (queue) {
|
||||
queue.clear();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(100 + (24 * threadList.size()), 24);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMaximumSize() {
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
Rectangle size = g.getClipBounds();
|
||||
g.setColor(getBackground());
|
||||
g.fillRect(0, 0, size.width - 1, size.height - 1);
|
||||
g.setColor(new Color(10, 10, 10));
|
||||
g.drawRect(0, 0, size.width - 1, size.height - 1);
|
||||
g.setFont(getFont());
|
||||
|
||||
for (int i = 0; i < threadList.size(); i++) {
|
||||
WorkerThread t = threadList.get(i);
|
||||
if (t.isRunning()) {
|
||||
g.setColor(new Color(50, 200, 0));
|
||||
} else {
|
||||
g.setColor(new Color(80, 0, 0));
|
||||
}
|
||||
g.fillOval(i * 24 + 4, 4, 22 - 8, 22 - 8);
|
||||
}
|
||||
|
||||
g.setColor(getForeground());
|
||||
g.drawString("Queued: " + queue.size(), threadList.size() * 24 + 4, 16);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import java.io.FileInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.AudioFileFormat;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.util.UUID;
|
||||
@@ -65,8 +66,11 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
boolean attention = false;
|
||||
boolean processed = false;
|
||||
boolean isDetected = false;
|
||||
boolean detecting = false;
|
||||
boolean queued = false;
|
||||
|
||||
int state = IDLE;
|
||||
static final int IDLE = 0;
|
||||
static final int QUEUED = 1;
|
||||
static final int PROCESSING = 2;
|
||||
|
||||
String effectChain = null;
|
||||
|
||||
@@ -218,7 +222,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
if (text.equals("")) text = id;
|
||||
|
||||
if ((crossStartOffset == -1) || (crossEndOffset == -1)) {
|
||||
updateCrossings(true);
|
||||
updateCrossings();
|
||||
}
|
||||
|
||||
if (runtime <= 0.01d) getLength();
|
||||
@@ -256,26 +260,40 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
CacheManager.removeFromCache(this);
|
||||
|
||||
if (!id.equals("room-noise")) {
|
||||
autoTrimSample(true);
|
||||
autoTrimSample();
|
||||
if (Options.getBoolean("process.sphinx")) {
|
||||
recognise();
|
||||
AudiobookRecorder.window.queueJob(new SentenceJob(this) {
|
||||
public void run() {
|
||||
sentence.doRecognition();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void autoTrimSample() {
|
||||
public void autoTrimSample(boolean ignored) {
|
||||
Debug.trace();
|
||||
autoTrimSample(false);
|
||||
autoTrimSample();
|
||||
}
|
||||
|
||||
public void autoTrimSample(boolean useRaw) {
|
||||
public void autoTrimSample() {
|
||||
Debug.trace();
|
||||
String tm = Options.get("audio.recording.trim");
|
||||
if (tm.equals("peak")) {
|
||||
autoTrimSamplePeak(useRaw);
|
||||
AudiobookRecorder.window.queueJob(new SentenceJob(this) {
|
||||
public void run() {
|
||||
sentence.autoTrimSamplePeak();
|
||||
AudiobookRecorder.window.updateWaveformMarkers();
|
||||
}
|
||||
});
|
||||
} else if (tm.equals("fft")) {
|
||||
autoTrimSampleFFT(useRaw);
|
||||
AudiobookRecorder.window.queueJob(new SentenceJob(this) {
|
||||
public void run() {
|
||||
sentence.autoTrimSampleFFT();
|
||||
AudiobookRecorder.window.updateWaveformMarkers();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
startOffset = 0;
|
||||
crossStartOffset = 0;
|
||||
@@ -284,13 +302,13 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
processed = false;
|
||||
// peak = -1d;
|
||||
}
|
||||
AudiobookRecorder.window.updateWaveform(true);
|
||||
}
|
||||
|
||||
public static final int FFTBuckets = 1024;
|
||||
|
||||
public void autoTrimSampleFFT() {
|
||||
public void autoTrimSampleFFT(boolean ignored) {
|
||||
Debug.trace();
|
||||
autoTrimSampleFFT(false);
|
||||
}
|
||||
|
||||
public double bucketDifference(double[] a, double[] b) {
|
||||
@@ -304,16 +322,12 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
return diff;
|
||||
}
|
||||
|
||||
public void autoTrimSampleFFT(boolean useRaw) {
|
||||
public void autoTrimSampleFFT() {
|
||||
Debug.trace();
|
||||
crossStartOffset = -1;
|
||||
crossEndOffset = -1;
|
||||
double[][] samples;
|
||||
if (useRaw) {
|
||||
samples = getRawAudioData();
|
||||
} else {
|
||||
samples = getProcessedAudioData();
|
||||
}
|
||||
samples = getProcessedAudioData();
|
||||
if (samples == null) {
|
||||
return;
|
||||
}
|
||||
@@ -385,7 +399,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
if (endOffset <= startOffset) endOffset = startOffset + fftSize;
|
||||
if (endOffset < 0) endOffset = 0;
|
||||
if (endOffset >= samples[LEFT].length) endOffset = samples[LEFT].length;
|
||||
updateCrossings(useRaw);
|
||||
updateCrossings();
|
||||
intens = null;
|
||||
samples = null;
|
||||
processed = true;
|
||||
@@ -436,21 +450,17 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
}
|
||||
|
||||
|
||||
public void autoTrimSamplePeak() {
|
||||
public void autoTrimSamplePeak(boolean ignored) {
|
||||
Debug.trace();
|
||||
autoTrimSamplePeak(false);
|
||||
autoTrimSamplePeak();
|
||||
}
|
||||
|
||||
public void autoTrimSamplePeak(boolean useRaw) {
|
||||
public void autoTrimSamplePeak() {
|
||||
Debug.trace();
|
||||
crossStartOffset = -1;
|
||||
crossEndOffset = -1;
|
||||
double[][] samples;
|
||||
if (useRaw) {
|
||||
samples = getRawAudioData();
|
||||
} else {
|
||||
samples = getProcessedAudioData();
|
||||
}
|
||||
samples = getProcessedAudioData();
|
||||
if (samples == null) return;
|
||||
double noiseFloor = AudiobookRecorder.window.getNoiseFloor();
|
||||
noiseFloor *= 1.1;
|
||||
@@ -490,7 +500,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
|
||||
if (startOffset < 0) startOffset = 0;
|
||||
if (endOffset >= samples[LEFT].length) endOffset = samples[LEFT].length-1;
|
||||
updateCrossings(useRaw);
|
||||
updateCrossings();
|
||||
processed = true;
|
||||
reloadTree();
|
||||
}
|
||||
@@ -597,38 +607,23 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
|
||||
public void updateCrossings() {
|
||||
Debug.trace();
|
||||
updateCrossings(false);
|
||||
}
|
||||
|
||||
public void updateCrossings(boolean useRaw) {
|
||||
Debug.trace();
|
||||
updateStartCrossing(useRaw);
|
||||
updateEndCrossing(useRaw);
|
||||
updateStartCrossing();
|
||||
updateEndCrossing();
|
||||
runtime = -1d;
|
||||
getLength();
|
||||
}
|
||||
|
||||
public void updateStartCrossing() {
|
||||
Debug.trace();
|
||||
updateStartCrossing(false);
|
||||
}
|
||||
|
||||
public void updateStartCrossing(boolean useRaw) {
|
||||
Debug.trace();
|
||||
if (crossStartOffset == -1) {
|
||||
crossStartOffset = findNearestZeroCrossing(useRaw, startOffset, 4096);
|
||||
crossStartOffset = findNearestZeroCrossing(startOffset, 4096);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateEndCrossing() {
|
||||
Debug.trace();
|
||||
updateEndCrossing(false);
|
||||
}
|
||||
|
||||
public void updateEndCrossing(boolean useRaw) {
|
||||
Debug.trace();
|
||||
if (crossEndOffset == -1) {
|
||||
crossEndOffset = findNearestZeroCrossing(useRaw, endOffset, 4096);
|
||||
crossEndOffset = findNearestZeroCrossing(endOffset, 4096);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -694,20 +689,8 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Runnable getRecognitionRunnable() {
|
||||
Runnable r = new Runnable() {
|
||||
public void run() {
|
||||
Debug.d("Starting recognition of", getId());
|
||||
doRecognition();
|
||||
}
|
||||
};
|
||||
return r;
|
||||
}
|
||||
|
||||
public void doRecognition() {
|
||||
Debug.trace();
|
||||
detecting = true;
|
||||
queued = false;
|
||||
try {
|
||||
reloadTree();
|
||||
|
||||
@@ -727,18 +710,10 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
|
||||
setText(res);
|
||||
isDetected = true;
|
||||
detecting = false;
|
||||
reloadTree();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
detecting = false;
|
||||
}
|
||||
|
||||
public void recognise() {
|
||||
Debug.trace();
|
||||
Thread t = new Thread(getRecognitionRunnable());
|
||||
t.start();
|
||||
}
|
||||
|
||||
public void setLocked(boolean l) {
|
||||
@@ -776,18 +751,9 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
}
|
||||
|
||||
public int findNearestZeroCrossing(int pos, int range) {
|
||||
Debug.trace();
|
||||
return findNearestZeroCrossing(false, pos, range);
|
||||
}
|
||||
|
||||
public int findNearestZeroCrossing(boolean useRaw, int pos, int range) {
|
||||
Debug.trace();
|
||||
double[][] data = null;
|
||||
if (useRaw) {
|
||||
data = getRawAudioData();
|
||||
} else {
|
||||
data = getProcessedAudioData();
|
||||
}
|
||||
data = getProcessedAudioData();
|
||||
if (data == null) return 0;
|
||||
if (data[LEFT].length == 0) return 0;
|
||||
|
||||
@@ -855,7 +821,6 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
File to = sentence.getFile();
|
||||
Files.copy(from.toPath(), to.toPath());
|
||||
|
||||
// sentence.updateCrossings();
|
||||
return sentence;
|
||||
}
|
||||
|
||||
@@ -873,24 +838,15 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
|
||||
public double getPeakValue() {
|
||||
Debug.trace();
|
||||
return getPeakValue(false, true);
|
||||
return getPeakValue(true);
|
||||
}
|
||||
|
||||
public double getPeakValue(boolean useRaw) {
|
||||
Debug.trace();
|
||||
return getPeakValue(useRaw, true);
|
||||
}
|
||||
|
||||
public double getPeakValue(boolean useRaw, boolean applyGain) {
|
||||
public double getPeakValue(boolean applyGain) {
|
||||
Debug.trace();
|
||||
double oldGain = gain;
|
||||
gain = 1.0d;
|
||||
double[][] samples = null;
|
||||
if (useRaw) {
|
||||
samples = getRawAudioData();
|
||||
} else {
|
||||
samples = getProcessedAudioData(true, applyGain);
|
||||
}
|
||||
samples = getProcessedAudioData(true, applyGain);
|
||||
gain = oldGain;
|
||||
if (samples == null) {
|
||||
return 0;
|
||||
@@ -937,7 +893,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
public double normalize(double low, double high) {
|
||||
Debug.trace();
|
||||
if (locked) return gain;
|
||||
double max = getPeakValue(true, false);
|
||||
double max = getPeakValue(false);
|
||||
double d = 0.708 / max;
|
||||
if (d > 1d) d = 1d;
|
||||
if (d < low) d = low;
|
||||
@@ -952,7 +908,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
public double normalize() {
|
||||
Debug.trace();
|
||||
if (locked) return gain;
|
||||
double max = getPeakValue(true, false);
|
||||
double max = getPeakValue(false);
|
||||
double d = 0.708 / max;
|
||||
if (d > 1d) d = 1d;
|
||||
setGain(d);
|
||||
@@ -1427,21 +1383,23 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
|
||||
|
||||
String def = AudiobookRecorder.window.getDefaultEffectsChain();
|
||||
Effect eff = AudiobookRecorder.window.effects.get(def);
|
||||
|
||||
if (effectsEnabled) {
|
||||
if (eff != null) {
|
||||
eff.init(getAudioFormat().getFrameRate());
|
||||
eff.process(processedAudio);
|
||||
}
|
||||
if ((def != null) && (AudiobookRecorder.window.effects != null)) {
|
||||
Effect eff = AudiobookRecorder.window.effects.get(def);
|
||||
|
||||
if (effectsEnabled) {
|
||||
if (eff != null) {
|
||||
eff.init(getAudioFormat().getFrameRate());
|
||||
eff.process(processedAudio);
|
||||
}
|
||||
|
||||
if (effectChain != null) {
|
||||
// Don't double up the default chain
|
||||
if (!effectChain.equals(def)) {
|
||||
eff = AudiobookRecorder.window.effects.get(effectChain);
|
||||
if (eff != null) {
|
||||
eff.init(getAudioFormat().getFrameRate());
|
||||
eff.process(processedAudio);
|
||||
if (effectChain != null) {
|
||||
// Don't double up the default chain
|
||||
if (!effectChain.equals(def)) {
|
||||
eff = AudiobookRecorder.window.effects.get(effectChain);
|
||||
if (eff != null) {
|
||||
eff.init(getAudioFormat().getFrameRate());
|
||||
eff.process(processedAudio);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1670,9 +1628,11 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
Debug.trace();
|
||||
if (id.equals("room-noise")) return;
|
||||
if (getParent() == null) return;
|
||||
synchronized (AudiobookRecorder.window.bookTreeModel) {
|
||||
AudiobookRecorder.window.bookTreeModel.reload(this);
|
||||
}
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
AudiobookRecorder.window.bookTreeModel.reload(Sentence.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public double getPeak() {
|
||||
@@ -1707,20 +1667,31 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
return (int)db;
|
||||
}
|
||||
|
||||
public boolean isDetecting() {
|
||||
return detecting;
|
||||
}
|
||||
|
||||
public boolean beenDetected() {
|
||||
return isDetected;
|
||||
}
|
||||
|
||||
public boolean isProcessing() {
|
||||
return state == PROCESSING;
|
||||
}
|
||||
|
||||
public boolean isQueued() {
|
||||
return queued;
|
||||
return state == QUEUED;
|
||||
}
|
||||
|
||||
public void setProcessing() {
|
||||
state = PROCESSING;
|
||||
reloadTree();
|
||||
}
|
||||
|
||||
public void setQueued() {
|
||||
queued = true;
|
||||
state = QUEUED;
|
||||
reloadTree();
|
||||
}
|
||||
|
||||
public void setDequeued() {
|
||||
state = IDLE;
|
||||
reloadTree();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
25
src/uk/co/majenko/audiobookrecorder/SentenceJob.java
Normal file
25
src/uk/co/majenko/audiobookrecorder/SentenceJob.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package uk.co.majenko.audiobookrecorder;
|
||||
|
||||
import java.lang.Runnable;
|
||||
|
||||
public abstract class SentenceJob implements Runnable {
|
||||
protected Sentence sentence;
|
||||
|
||||
public SentenceJob(Sentence s) {
|
||||
sentence = s;
|
||||
}
|
||||
|
||||
public void setQueued() {
|
||||
sentence.setQueued();
|
||||
}
|
||||
|
||||
public void setDequeued() {
|
||||
sentence.setDequeued();
|
||||
}
|
||||
|
||||
public void setProcessing() {
|
||||
sentence.setProcessing();
|
||||
}
|
||||
|
||||
public abstract void run();
|
||||
}
|
||||
@@ -5,9 +5,13 @@ import java.util.Queue;
|
||||
public class WorkerThread extends Thread {
|
||||
private static int instance = 0;
|
||||
private final Queue<Runnable> queue;
|
||||
private final QueueMonitor monitor;
|
||||
|
||||
private boolean running = false;
|
||||
|
||||
public WorkerThread(Queue<Runnable> queue) {
|
||||
public WorkerThread(Queue<Runnable> queue, QueueMonitor mon) {
|
||||
this.queue = queue;
|
||||
monitor = mon;
|
||||
setName("Worker Thread " + (instance++));
|
||||
}
|
||||
|
||||
@@ -30,8 +34,19 @@ public class WorkerThread extends Thread {
|
||||
work = queue.remove();
|
||||
}
|
||||
|
||||
// Process the work item
|
||||
running = true;
|
||||
monitor.repaint();
|
||||
if (work instanceof SentenceJob) {
|
||||
SentenceJob sj = (SentenceJob)work;
|
||||
sj.setProcessing();
|
||||
}
|
||||
work.run();
|
||||
if (work instanceof SentenceJob) {
|
||||
SentenceJob sj = (SentenceJob)work;
|
||||
sj.setDequeued();
|
||||
}
|
||||
running = false;
|
||||
monitor.repaint();
|
||||
}
|
||||
catch ( InterruptedException ie ) {
|
||||
ie.printStackTrace();
|
||||
@@ -40,4 +55,8 @@ public class WorkerThread extends Thread {
|
||||
}
|
||||
Debug.d(getName(), "died");
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return running;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user