Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 21d7d9d597 | |||
| 746f47a5fa | |||
| c67e6d6abc | |||
| 1f722f5df3 | |||
| df4eae1d66 | |||
| 4d435b4fc1 | |||
| f95ae10d03 |
BIN
deps/json-20190722.jar
LFS
vendored
Normal file
BIN
deps/json-20190722.jar
LFS
vendored
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
version=0.3.8
|
version=0.3.9
|
||||||
|
|||||||
BIN
resources/uk/co/majenko/audiobookrecorder/icons/close.png
Normal file
BIN
resources/uk/co/majenko/audiobookrecorder/icons/close.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -68,6 +68,7 @@ import javax.swing.JTree;
|
|||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.tree.TreeCellRenderer;
|
||||||
import javax.swing.tree.DefaultTreeModel;
|
import javax.swing.tree.DefaultTreeModel;
|
||||||
import javax.swing.tree.DefaultMutableTreeNode;
|
import javax.swing.tree.DefaultMutableTreeNode;
|
||||||
import javax.swing.tree.TreePath;
|
import javax.swing.tree.TreePath;
|
||||||
@@ -139,6 +140,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
JMenuItem toolsArchive;
|
JMenuItem toolsArchive;
|
||||||
JMenuItem toolsCoverArt;
|
JMenuItem toolsCoverArt;
|
||||||
JMenuItem toolsManuscript;
|
JMenuItem toolsManuscript;
|
||||||
|
JMenuItem toolsReloadEffects;
|
||||||
JMenuItem toolsOptions;
|
JMenuItem toolsOptions;
|
||||||
|
|
||||||
JMenuItem helpAbout;
|
JMenuItem helpAbout;
|
||||||
@@ -147,7 +149,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
|
|
||||||
JPanel statusBar;
|
JPanel statusBar;
|
||||||
|
|
||||||
JLabel statusLabel;
|
NoiseFloor noiseFloorLabel;
|
||||||
|
|
||||||
JScrollPane mainScroll;
|
JScrollPane mainScroll;
|
||||||
|
|
||||||
@@ -372,6 +374,18 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
loadManuscript();
|
loadManuscript();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
toolsReloadEffects = new JMenuItem("Reload effects");
|
||||||
|
toolsReloadEffects.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
Debug.trace();
|
||||||
|
queueJob(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
loadEffects();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
toolsOptions = new JMenuItem("Options");
|
toolsOptions = new JMenuItem("Options");
|
||||||
toolsOptions.addActionListener(new ActionListener() {
|
toolsOptions.addActionListener(new ActionListener() {
|
||||||
@@ -385,6 +399,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
toolsMenu.add(toolsArchive);
|
toolsMenu.add(toolsArchive);
|
||||||
toolsMenu.add(toolsCoverArt);
|
toolsMenu.add(toolsCoverArt);
|
||||||
toolsMenu.add(toolsManuscript);
|
toolsMenu.add(toolsManuscript);
|
||||||
|
toolsMenu.add(toolsReloadEffects);
|
||||||
toolsMenu.addSeparator();
|
toolsMenu.addSeparator();
|
||||||
toolsMenu.add(toolsOptions);
|
toolsMenu.add(toolsOptions);
|
||||||
|
|
||||||
@@ -752,11 +767,13 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
centralPanel.add(sampleControl, BorderLayout.SOUTH);
|
centralPanel.add(sampleControl, BorderLayout.SOUTH);
|
||||||
|
|
||||||
statusBar = new JPanel();
|
statusBar = new JPanel();
|
||||||
statusBar.setLayout(new FlowLayout(FlowLayout.CENTER));
|
statusBar.setLayout(new FlowLayout(FlowLayout.RIGHT));
|
||||||
add(statusBar, BorderLayout.SOUTH);
|
add(statusBar, BorderLayout.SOUTH);
|
||||||
|
|
||||||
statusLabel = new JLabel("Noise floor: " + getNoiseFloorDB() + "dB");
|
noiseFloorLabel = new NoiseFloor();
|
||||||
statusBar.add(statusLabel);
|
|
||||||
|
statusBar.add(noiseFloorLabel);
|
||||||
|
// statusBar.add(Box.createHorizontalStrut(2));
|
||||||
statusBar.add(queueMonitor);
|
statusBar.add(queueMonitor);
|
||||||
|
|
||||||
buildToolbar(centralPanel);
|
buildToolbar(centralPanel);
|
||||||
@@ -995,6 +1012,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
Options.savePreferences();
|
Options.savePreferences();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queueJob(new VersionChecker());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bindKeys(JComponent component) {
|
void bindKeys(JComponent component) {
|
||||||
@@ -1429,7 +1448,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
JMenuObject o = (JMenuObject)e.getSource();
|
JMenuObject o = (JMenuObject)e.getSource();
|
||||||
Sentence s = (Sentence)o.getObject();
|
Sentence s = (Sentence)o.getObject();
|
||||||
s.runExternalProcessor(Utils.s2i(o.getActionCommand()));
|
queueJob(new SentenceExternalJob(s, Utils.s2i(o.getActionCommand())));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ob.setActionCommand(Integer.toString(i));
|
ob.setActionCommand(Integer.toString(i));
|
||||||
@@ -1725,7 +1744,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||||
Sentence snt = (Sentence)s.nextElement();
|
Sentence snt = (Sentence)s.nextElement();
|
||||||
if (!snt.isLocked()) {
|
if (!snt.isLocked()) {
|
||||||
snt.runExternalProcessor(Utils.s2i(o.getActionCommand()));
|
queueJob(new SentenceExternalJob(snt, Utils.s2i(o.getActionCommand())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2155,9 +2174,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
public void addChapter() {
|
public void addChapter() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
Chapter c = book.addChapter();
|
Chapter c = book.addChapter();
|
||||||
Chapter lc = book.getLastChapter();
|
bookTreeModel.insertNodeInto(c, book, book.getChildCount());
|
||||||
int i = bookTreeModel.getIndexOfChild(book, lc);
|
|
||||||
bookTreeModel.insertNodeInto(c, book, i+1);
|
|
||||||
bookTree.scrollPathToVisible(new TreePath(c.getPath()));
|
bookTree.scrollPathToVisible(new TreePath(c.getPath()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2212,11 +2229,11 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
bookTree.setEditable(true);
|
bookTree.setEditable(true);
|
||||||
bookTree.setUI(new CustomTreeUI(mainScroll));
|
bookTree.setUI(new CustomTreeUI(mainScroll));
|
||||||
|
|
||||||
|
TreeCellRenderer renderer = new BookTreeRenderer();
|
||||||
try {
|
try {
|
||||||
bookTree.setCellRenderer(new BookTreeRenderer());
|
bookTree.setCellRenderer(renderer);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
bookTree.setCellRenderer(renderer);
|
||||||
bookTree.setCellRenderer(new BookTreeRenderer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InputMap im = bookTree.getInputMap(JComponent.WHEN_FOCUSED);
|
InputMap im = bookTree.getInputMap(JComponent.WHEN_FOCUSED);
|
||||||
@@ -2315,7 +2332,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
|
|
||||||
bookTree.expandPath(new TreePath(book.getPath()));
|
bookTree.expandPath(new TreePath(book.getPath()));
|
||||||
|
|
||||||
statusLabel.setText("Noise floor: " + getNoiseFloorDB() + "dB");
|
noiseFloorLabel.setNoiseFloor(getNoiseFloorDB());
|
||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
@@ -2573,7 +2590,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
|
|
||||||
bookTree.expandPath(new TreePath(book.getPath()));
|
bookTree.expandPath(new TreePath(book.getPath()));
|
||||||
|
|
||||||
statusLabel.setText("Noise floor: " + getNoiseFloorDB() + "dB");
|
noiseFloorLabel.setNoiseFloor(getNoiseFloorDB());
|
||||||
book.setIcon(Icons.book);
|
book.setIcon(Icons.book);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2646,7 +2663,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
roomNoise.stopRecording();
|
roomNoise.stopRecording();
|
||||||
centralPanel.setFlash(false);
|
centralPanel.setFlash(false);
|
||||||
statusLabel.setText("Noise floor: " + getNoiseFloorDB() + "dB");
|
noiseFloorLabel.setNoiseFloor(getNoiseFloorDB());
|
||||||
}
|
}
|
||||||
}, 5000); // 5 seconds of recording
|
}, 5000); // 5 seconds of recording
|
||||||
}
|
}
|
||||||
@@ -4180,6 +4197,12 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (orphans.getChildCount() == 0) {
|
||||||
|
try {
|
||||||
|
bookTreeModel.removeNodeFromParent(orphans);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Chapter getChapterById(String id) {
|
public Chapter getChapterById(String id) {
|
||||||
|
|||||||
@@ -1,23 +1,5 @@
|
|||||||
package uk.co.majenko.audiobookrecorder;
|
package uk.co.majenko.audiobookrecorder;
|
||||||
|
|
||||||
// Biquad.java
|
|
||||||
//
|
|
||||||
// Created by Nigel Redmon on 11/24/12
|
|
||||||
// EarLevel Engineering: earlevel.com
|
|
||||||
// Copyright 2012 Nigel Redmon
|
|
||||||
// Translated to Java 2019 Majenko Technologies
|
|
||||||
//
|
|
||||||
// For a complete explanation of the Biquad code:
|
|
||||||
// http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/
|
|
||||||
//
|
|
||||||
// License:
|
|
||||||
//
|
|
||||||
// This source code is provided as is, without warranty.
|
|
||||||
// You may copy and distribute verbatim copies of this document.
|
|
||||||
// You may modify and use this source code to create binary code
|
|
||||||
// for your own purposes, free or commercial.
|
|
||||||
//
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class Biquad implements Effect {
|
public class Biquad implements Effect {
|
||||||
|
|||||||
@@ -155,12 +155,7 @@ public class Book extends BookTreeNode {
|
|||||||
|
|
||||||
public Chapter getLastChapter() {
|
public Chapter getLastChapter() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
Chapter cc = getClosingCredits();
|
return (Chapter)getLastLeaf();
|
||||||
if (cc == null) return null;
|
|
||||||
Chapter c = (Chapter)getChildBefore(cc);
|
|
||||||
if (c == null) return null;
|
|
||||||
if (c.getId().equals("open")) return null;
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Chapter getChapter(int n) {
|
public Chapter getChapter(int n) {
|
||||||
@@ -453,7 +448,12 @@ public class Book extends BookTreeNode {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
AudiobookRecorder.window.bookTreeModel.reload(Book.this);
|
if (AudiobookRecorder.window == null) return;
|
||||||
|
if (AudiobookRecorder.window.bookTreeModel == null) return;
|
||||||
|
try {
|
||||||
|
AudiobookRecorder.window.bookTreeModel.reload(Book.this);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,130 +1,93 @@
|
|||||||
package uk.co.majenko.audiobookrecorder;
|
package uk.co.majenko.audiobookrecorder;
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Orlando Selenu
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class FFT {
|
public class FFT {
|
||||||
/**
|
public static double[] fft(final double[] inputReal, double[] inputImag, boolean DIRECT) {
|
||||||
* The Fast Fourier Transform (generic version, with NO optimizations).
|
int n = inputReal.length;
|
||||||
*
|
|
||||||
* @param inputReal
|
|
||||||
* an array of length n, the real part
|
|
||||||
* @param inputImag
|
|
||||||
* an array of length n, the imaginary part
|
|
||||||
* @param DIRECT
|
|
||||||
* TRUE = direct transform, FALSE = inverse transform
|
|
||||||
* @return a new array of length 2n
|
|
||||||
*/
|
|
||||||
public static double[] fft(final double[] inputReal, double[] inputImag,
|
|
||||||
boolean DIRECT) {
|
|
||||||
// - n is the dimension of the problem
|
|
||||||
// - nu is its logarithm in base e
|
|
||||||
int n = inputReal.length;
|
|
||||||
|
|
||||||
// If n is a power of 2, then ld is an integer (_without_ decimals)
|
double ld = Math.log(n) / Math.log(2.0);
|
||||||
double ld = Math.log(n) / Math.log(2.0);
|
|
||||||
|
|
||||||
// Here I check if n is a power of 2. If exist decimals in ld, I quit
|
if (((int) ld) - ld != 0) {
|
||||||
// from the function returning null.
|
System.out.println("The number of elements is not a power of 2.");
|
||||||
if (((int) ld) - ld != 0) {
|
return null;
|
||||||
System.out.println("The number of elements is not a power of 2.");
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Declaration and initialization of the variables
|
int nu = (int) ld;
|
||||||
// ld should be an integer, actually, so I don't lose any information in
|
int n2 = n / 2;
|
||||||
// the cast
|
int nu1 = nu - 1;
|
||||||
int nu = (int) ld;
|
double[] xReal = new double[n];
|
||||||
int n2 = n / 2;
|
double[] xImag = new double[n];
|
||||||
int nu1 = nu - 1;
|
double tReal, tImag, p, arg, c, s;
|
||||||
double[] xReal = new double[n];
|
|
||||||
double[] xImag = new double[n];
|
double constant;
|
||||||
double tReal, tImag, p, arg, c, s;
|
if (DIRECT) {
|
||||||
|
constant = -2 * Math.PI;
|
||||||
|
} else {
|
||||||
|
constant = 2 * Math.PI;
|
||||||
|
}
|
||||||
|
|
||||||
// Here I check if I'm going to do the direct transform or the inverse
|
for (int i = 0; i < n; i++) {
|
||||||
// transform.
|
xReal[i] = inputReal[i];
|
||||||
double constant;
|
xImag[i] = inputImag[i];
|
||||||
if (DIRECT)
|
}
|
||||||
constant = -2 * Math.PI;
|
|
||||||
else
|
|
||||||
constant = 2 * Math.PI;
|
|
||||||
|
|
||||||
// I don't want to overwrite the input arrays, so here I copy them. This
|
int k = 0;
|
||||||
// choice adds \Theta(2n) to the complexity.
|
for (int l = 1; l <= nu; l++) {
|
||||||
for (int i = 0; i < n; i++) {
|
while (k < n) {
|
||||||
xReal[i] = inputReal[i];
|
for (int i = 1; i <= n2; i++) {
|
||||||
xImag[i] = inputImag[i];
|
p = bitreverseReference(k >> nu1, nu);
|
||||||
}
|
// direct FFT or inverse FFT
|
||||||
|
arg = constant * p / n;
|
||||||
// First phase - calculation
|
c = Math.cos(arg);
|
||||||
int k = 0;
|
s = Math.sin(arg);
|
||||||
for (int l = 1; l <= nu; l++) {
|
tReal = xReal[k + n2] * c + xImag[k + n2] * s;
|
||||||
while (k < n) {
|
tImag = xImag[k + n2] * c - xReal[k + n2] * s;
|
||||||
for (int i = 1; i <= n2; i++) {
|
xReal[k + n2] = xReal[k] - tReal;
|
||||||
p = bitreverseReference(k >> nu1, nu);
|
xImag[k + n2] = xImag[k] - tImag;
|
||||||
// direct FFT or inverse FFT
|
xReal[k] += tReal;
|
||||||
arg = constant * p / n;
|
xImag[k] += tImag;
|
||||||
c = Math.cos(arg);
|
k++;
|
||||||
s = Math.sin(arg);
|
}
|
||||||
tReal = xReal[k + n2] * c + xImag[k + n2] * s;
|
k += n2;
|
||||||
tImag = xImag[k + n2] * c - xReal[k + n2] * s;
|
|
||||||
xReal[k + n2] = xReal[k] - tReal;
|
|
||||||
xImag[k + n2] = xImag[k] - tImag;
|
|
||||||
xReal[k] += tReal;
|
|
||||||
xImag[k] += tImag;
|
|
||||||
k++;
|
|
||||||
}
|
}
|
||||||
k += n2;
|
k = 0;
|
||||||
|
nu1--;
|
||||||
|
n2 /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
k = 0;
|
k = 0;
|
||||||
nu1--;
|
int r;
|
||||||
n2 /= 2;
|
while (k < n) {
|
||||||
}
|
r = bitreverseReference(k, nu);
|
||||||
|
if (r > k) {
|
||||||
// Second phase - recombination
|
tReal = xReal[k];
|
||||||
k = 0;
|
tImag = xImag[k];
|
||||||
int r;
|
xReal[k] = xReal[r];
|
||||||
while (k < n) {
|
xImag[k] = xImag[r];
|
||||||
r = bitreverseReference(k, nu);
|
xReal[r] = tReal;
|
||||||
if (r > k) {
|
xImag[r] = tImag;
|
||||||
tReal = xReal[k];
|
}
|
||||||
tImag = xImag[k];
|
k++;
|
||||||
xReal[k] = xReal[r];
|
|
||||||
xImag[k] = xImag[r];
|
|
||||||
xReal[r] = tReal;
|
|
||||||
xImag[r] = tImag;
|
|
||||||
}
|
}
|
||||||
k++;
|
|
||||||
|
double[] newArray = new double[xReal.length * 2];
|
||||||
|
double radice = 1 / Math.sqrt(n);
|
||||||
|
for (int i = 0; i < newArray.length; i += 2) {
|
||||||
|
int i2 = i / 2;
|
||||||
|
newArray[i] = xReal[i2] * radice;
|
||||||
|
newArray[i + 1] = xImag[i2] * radice;
|
||||||
|
}
|
||||||
|
return newArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here I have to mix xReal and xImag to have an array (yes, it should
|
private static int bitreverseReference(int j, int nu) {
|
||||||
// be possible to do this stuff in the earlier parts of the code, but
|
int j2;
|
||||||
// it's here to readibility).
|
int j1 = j;
|
||||||
double[] newArray = new double[xReal.length * 2];
|
int k = 0;
|
||||||
double radice = 1 / Math.sqrt(n);
|
for (int i = 1; i <= nu; i++) {
|
||||||
for (int i = 0; i < newArray.length; i += 2) {
|
j2 = j1 / 2;
|
||||||
int i2 = i / 2;
|
k = 2 * k + j1 - 2 * j2;
|
||||||
// I used Stephen Wolfram's Mathematica as a reference so I'm going
|
j1 = j2;
|
||||||
// to normalize the output while I'm copying the elements.
|
}
|
||||||
newArray[i] = xReal[i2] * radice;
|
return k;
|
||||||
newArray[i + 1] = xImag[i2] * radice;
|
|
||||||
}
|
}
|
||||||
return newArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The reference bitreverse function.
|
|
||||||
*/
|
|
||||||
private static int bitreverseReference(int j, int nu) {
|
|
||||||
int j2;
|
|
||||||
int j1 = j;
|
|
||||||
int k = 0;
|
|
||||||
for (int i = 1; i <= nu; i++) {
|
|
||||||
j2 = j1 / 2;
|
|
||||||
k = 2 * k + j1 - 2 * j2;
|
|
||||||
j1 = j2;
|
|
||||||
}
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,4 +42,5 @@ public class Icons {
|
|||||||
static public final ImageIcon tooltip = new ImageIcon(Icons.class.getResource("icons/tooltip.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 queued = new ImageIcon(Icons.class.getResource("icons/queued.png"));
|
||||||
static public final ImageIcon processing = new ImageIcon(Icons.class.getResource("icons/processing.png"));
|
static public final ImageIcon processing = new ImageIcon(Icons.class.getResource("icons/processing.png"));
|
||||||
|
static public final ImageIcon close = new ImageIcon(Icons.class.getResource("icons/close.png"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ public class KVPair<K,V> implements Comparable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(Object o) {
|
public int compareTo(Object o) {
|
||||||
// if (o instanceof KVPair) {
|
|
||||||
// KVPair ko = (KVPair)o;
|
|
||||||
// return key.compareTo(ko.key);
|
|
||||||
// }
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ public class MainToolBar extends JToolBar {
|
|||||||
JButtonSpacePlay playonSentence;
|
JButtonSpacePlay playonSentence;
|
||||||
JButtonSpacePlay playtoSentence;
|
JButtonSpacePlay playtoSentence;
|
||||||
JButtonSpacePlay stopPlaying;
|
JButtonSpacePlay stopPlaying;
|
||||||
JButtonSpacePlay eq;
|
|
||||||
JButtonSpacePlay openManuscript;
|
JButtonSpacePlay openManuscript;
|
||||||
JToggleButtonSpacePlay mic;
|
JToggleButtonSpacePlay mic;
|
||||||
|
|
||||||
@@ -102,16 +101,6 @@ public class MainToolBar extends JToolBar {
|
|||||||
});
|
});
|
||||||
add(stopPlaying);
|
add(stopPlaying);
|
||||||
|
|
||||||
addSeparator();
|
|
||||||
eq = new JButtonSpacePlay(Icons.eq, "Reload Effects", new ActionListener() {
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
root.loadEffects();
|
|
||||||
CacheManager.purgeCache();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add(eq);
|
|
||||||
|
|
||||||
addSeparator();
|
addSeparator();
|
||||||
|
|
||||||
mic = new JToggleButtonSpacePlay(Icons.mic, "Enable / disable microphone", new ActionListener() {
|
mic = new JToggleButtonSpacePlay(Icons.mic, "Enable / disable microphone", new ActionListener() {
|
||||||
|
|||||||
51
src/uk/co/majenko/audiobookrecorder/NoiseFloor.java
Normal file
51
src/uk/co/majenko/audiobookrecorder/NoiseFloor.java
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package uk.co.majenko.audiobookrecorder;
|
||||||
|
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
public class NoiseFloor extends JPanel {
|
||||||
|
|
||||||
|
int noiseFloor = 0;
|
||||||
|
|
||||||
|
public NoiseFloor() {
|
||||||
|
super();
|
||||||
|
noiseFloor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNoiseFloor(int n) {
|
||||||
|
noiseFloor = n;
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
return new Dimension(128, 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());
|
||||||
|
|
||||||
|
g.setColor(getForeground());
|
||||||
|
g.drawString("Noise Floor: " + noiseFloor + "dB", 6, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -388,7 +388,7 @@ public class Options extends JDialog {
|
|||||||
|
|
||||||
enableParsing = addCheckBox(optionsPanel, "Enable automatic speech-to-text (**SLOW**)", getBoolean("process.sphinx"), "This will automatically start recognising the speech in every sentence you record. This can really slow down recording though so it's recommended to leave it turned off and do your recognition afterwards as a batch operation.");
|
enableParsing = addCheckBox(optionsPanel, "Enable automatic speech-to-text (**SLOW**)", getBoolean("process.sphinx"), "This will automatically start recognising the speech in every sentence you record. This can really slow down recording though so it's recommended to leave it turned off and do your recognition afterwards as a batch operation.");
|
||||||
speechCommand = addTextField(optionsPanel, "Speech to text command (must take 1 filename parameter):", get("process.command"), "This specifies what command to run to recognize the speech. This command must take only one parameter, which is the full path of the WAV file. It should return (on standard output) the recognised speech.");
|
speechCommand = addTextField(optionsPanel, "Speech to text command (must take 1 filename parameter):", get("process.command"), "This specifies what command to run to recognize the speech. This command must take only one parameter, which is the full path of the WAV file. It should return (on standard output) the recognised speech.");
|
||||||
workerThreads = addSpinner(optionsPanel, "Worker threads:", 1, 100, 1, getInteger("process.threads"), "", "How many concurrent threads to run when processing speech. This should ideally be no more than the number of CPU cores you have in your computer.");
|
workerThreads = addSpinner(optionsPanel, "Worker threads:", 1, 100, 1, getInteger("process.threads"), "", "How many concurrent threads to run when processing speech. This should ideally be no more than the number of CPU cores you have in your computer minus one.");
|
||||||
|
|
||||||
addSeparator(optionsPanel);
|
addSeparator(optionsPanel);
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,3 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, Majenko Technologies
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright notice, this
|
|
||||||
* list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright notice, this
|
|
||||||
* list of conditions and the following disclaimer in the documentation and/or
|
|
||||||
* other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of Majenko Technologies nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from
|
|
||||||
* this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package uk.co.majenko.audiobookrecorder;
|
package uk.co.majenko.audiobookrecorder;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
|||||||
@@ -7,15 +7,18 @@ import java.awt.Graphics;
|
|||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.MouseListener;
|
||||||
|
|
||||||
public class QueueMonitor extends JPanel {
|
public class QueueMonitor extends JPanel implements MouseListener {
|
||||||
|
|
||||||
ArrayList<WorkerThread> threadList = new ArrayList<WorkerThread>();
|
ArrayList<WorkerThread> threadList = new ArrayList<WorkerThread>();
|
||||||
Queue queue;
|
Queue<Runnable> queue;
|
||||||
|
|
||||||
public QueueMonitor(Queue q) {
|
public QueueMonitor(Queue<Runnable> q) {
|
||||||
super();
|
super();
|
||||||
queue = q;
|
queue = q;
|
||||||
|
addMouseListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addThread(WorkerThread t) {
|
public void addThread(WorkerThread t) {
|
||||||
@@ -23,15 +26,22 @@ public class QueueMonitor extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void purgeQueue() {
|
public void purgeQueue() {
|
||||||
|
Runnable work;
|
||||||
synchronized (queue) {
|
synchronized (queue) {
|
||||||
queue.clear();
|
while (queue.size() > 0) {
|
||||||
|
work = queue.remove();
|
||||||
|
if (work instanceof SentenceJob) {
|
||||||
|
SentenceJob sj = (SentenceJob)work;
|
||||||
|
sj.setDequeued();
|
||||||
|
}
|
||||||
|
}
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dimension getPreferredSize() {
|
public Dimension getPreferredSize() {
|
||||||
return new Dimension(100 + (24 * threadList.size()), 24);
|
return new Dimension(150 + (24 * threadList.size()), 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -65,6 +75,35 @@ public class QueueMonitor extends JPanel {
|
|||||||
|
|
||||||
g.setColor(getForeground());
|
g.setColor(getForeground());
|
||||||
g.drawString("Queued: " + queue.size(), threadList.size() * 24 + 4, 16);
|
g.drawString("Queued: " + queue.size(), threadList.size() * 24 + 4, 16);
|
||||||
|
|
||||||
|
if (queue.size() > 0) {
|
||||||
|
Icons.close.paintIcon(this, g, size.width - 23, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseEntered(MouseEvent evt) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseExited(MouseEvent evt) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mousePressed(MouseEvent evt) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseReleased(MouseEvent evt) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent evt) {
|
||||||
|
if (queue.size() == 0) return; // No button - ignore it
|
||||||
|
Dimension size = getPreferredSize();
|
||||||
|
if (evt.getX() > (size.width - 24)) {
|
||||||
|
purgeQueue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -956,8 +956,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
public void openInExternalEditor() {
|
public void openInExternalEditor() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
ExternalEditor ed = new ExternalEditor(this);
|
ExternalEditor ed = new ExternalEditor(this);
|
||||||
Thread t = new Thread(ed);
|
ed.run();
|
||||||
t.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void backup() throws IOException {
|
public void backup() throws IOException {
|
||||||
@@ -1051,8 +1050,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
if (isLocked()) return;
|
if (isLocked()) return;
|
||||||
ExternalProcessor ed = new ExternalProcessor(this, num);
|
ExternalProcessor ed = new ExternalProcessor(this, num);
|
||||||
Thread t = new Thread(ed);
|
ed.run();
|
||||||
t.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void undo() {
|
public void undo() {
|
||||||
|
|||||||
17
src/uk/co/majenko/audiobookrecorder/SentenceExternalJob.java
Normal file
17
src/uk/co/majenko/audiobookrecorder/SentenceExternalJob.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package uk.co.majenko.audiobookrecorder;
|
||||||
|
|
||||||
|
import java.lang.Runnable;
|
||||||
|
|
||||||
|
public class SentenceExternalJob extends SentenceJob {
|
||||||
|
protected int command;
|
||||||
|
|
||||||
|
public SentenceExternalJob(Sentence s, int c) {
|
||||||
|
super(s);
|
||||||
|
command = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
sentence.runExternalProcessor(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
77
src/uk/co/majenko/audiobookrecorder/VersionChecker.java
Normal file
77
src/uk/co/majenko/audiobookrecorder/VersionChecker.java
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package uk.co.majenko.audiobookrecorder;
|
||||||
|
|
||||||
|
import java.lang.Runnable;
|
||||||
|
import java.net.URL;
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
|
||||||
|
public class VersionChecker implements Runnable {
|
||||||
|
public VersionChecker() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
URL url = new URL("https://api.github.com/repos/MajenkoProjects/AudiobookRecorder/releases/latest");
|
||||||
|
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
|
||||||
|
InputStream is = conn.getInputStream();
|
||||||
|
InputStreamReader isr = new InputStreamReader(is);
|
||||||
|
BufferedReader br = new BufferedReader(isr);
|
||||||
|
|
||||||
|
String inputLine;
|
||||||
|
StringBuilder jsonData = new StringBuilder();
|
||||||
|
|
||||||
|
while ((inputLine = br.readLine()) != null) {
|
||||||
|
jsonData.append(inputLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
br.close();
|
||||||
|
|
||||||
|
JSONObject job = new JSONObject(jsonData.toString());
|
||||||
|
|
||||||
|
String installed = AudiobookRecorder.config.getProperty("version");
|
||||||
|
String available = job.getString("tag_name");
|
||||||
|
if (available.startsWith("v")) {
|
||||||
|
available = available.substring(1);
|
||||||
|
}
|
||||||
|
String website = job.getString("html_url");
|
||||||
|
|
||||||
|
|
||||||
|
String[] installedParts = installed.split("\\.");
|
||||||
|
String[] availableParts = available.split("\\.");
|
||||||
|
// Must be x.y.z
|
||||||
|
|
||||||
|
if (installedParts.length != 3) return;
|
||||||
|
if (availableParts.length != 3) return;
|
||||||
|
|
||||||
|
// Convert to xxxyyyzzz
|
||||||
|
String installedVersion = String.format("%03d%03d%03d", Utils.s2i(installedParts[0]), Utils.s2i(installedParts[1]), Utils.s2i(installedParts[2]));
|
||||||
|
String availableVersion = String.format("%03d%03d%03d", Utils.s2i(availableParts[0]), Utils.s2i(availableParts[1]), Utils.s2i(availableParts[2]));
|
||||||
|
|
||||||
|
if (Utils.s2i(installedVersion) >= Utils.s2i(availableVersion)) return;
|
||||||
|
|
||||||
|
System.err.println("Version installed: " + installed);
|
||||||
|
System.err.println("Version available: " + available);
|
||||||
|
System.err.println("URL: " + website);
|
||||||
|
|
||||||
|
JButton upgrade = new JButton("A new version is available.");
|
||||||
|
upgrade.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent evt) {
|
||||||
|
Utils.browse(website);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AudiobookRecorder.window.statusBar.add(upgrade);
|
||||||
|
AudiobookRecorder.window.statusBar.revalidate();
|
||||||
|
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
ignored.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user