Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2064184093 | |||
| 2e6ea5eecc | |||
| 0dde64e5fc | |||
| 28a3326a35 | |||
| df6b893171 | |||
| ead577521d | |||
|
|
cc1c76bd47 | ||
| b74f1aedb4 | |||
| 67d1e787ee | |||
| 11ca88ee38 | |||
|
|
ae4e3db0d7 | ||
|
|
4314790271 | ||
| 9c58276119 | |||
| 16380a9752 | |||
| b523d80c25 | |||
| 34d1f504c0 | |||
| d4a64d4e72 | |||
| 44201a0bbb | |||
|
|
1d19cd4c98 | ||
| 4c89c70b05 | |||
|
|
33eb219904 |
2
dist/linux/stub
vendored
2
dist/linux/stub
vendored
@@ -5,6 +5,6 @@ java=java
|
|||||||
if test -n "$JAVA_HOME"; then
|
if test -n "$JAVA_HOME"; then
|
||||||
java="$JAVA_HOME/bin/java"
|
java="$JAVA_HOME/bin/java"
|
||||||
fi
|
fi
|
||||||
java_args=-Xmx1g
|
java_args=-Xmx8g
|
||||||
exec "$java" $java_args -jar $MYSELF "$@"
|
exec "$java" $java_args -jar $MYSELF "$@"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
<groupId>commons-collections</groupId>
|
<groupId>commons-collections</groupId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
<version>1.7.0</version>
|
<version>1.9.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-logging</groupId>
|
<groupId>commons-logging</groupId>
|
||||||
@@ -138,12 +138,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.thoughtworks.xstream</groupId>
|
<groupId>com.thoughtworks.xstream</groupId>
|
||||||
<artifactId>xstream</artifactId>
|
<artifactId>xstream</artifactId>
|
||||||
<version>1.4.8</version>
|
<version>1.4.15</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.ant</groupId>
|
<groupId>org.apache.ant</groupId>
|
||||||
<artifactId>ant</artifactId>
|
<artifactId>ant</artifactId>
|
||||||
<version>1.8.2</version>
|
<version>1.9.15</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
version=0.4.2
|
version=0.4.4
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
JToggleButtonSpacePlay selectCutMode;
|
JToggleButtonSpacePlay selectCutMode;
|
||||||
JButtonSpacePlay doCutSplit;
|
JButtonSpacePlay doCutSplit;
|
||||||
JToggleButtonSpacePlay editGainCurve;
|
JToggleButtonSpacePlay editGainCurve;
|
||||||
|
JButtonSpacePlay autoCreatePoints;
|
||||||
|
|
||||||
JButtonSpacePlay refreshSentence;
|
JButtonSpacePlay refreshSentence;
|
||||||
|
|
||||||
@@ -203,6 +204,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
public Queue<Runnable>processQueue = null;
|
public Queue<Runnable>processQueue = null;
|
||||||
public QueueMonitor queueMonitor = null;
|
public QueueMonitor queueMonitor = null;
|
||||||
|
|
||||||
|
boolean effectsUpdating = false; // crude lock
|
||||||
|
|
||||||
void buildToolbar(Container ob) {
|
void buildToolbar(Container ob) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
toolBar = new MainToolBar(this);
|
toolBar = new MainToolBar(this);
|
||||||
@@ -449,9 +452,20 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
autoCreatePoints = new JButtonSpacePlay(Icons.normalize, "Create peak points", new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
Debug.trace();
|
||||||
|
if (selectedSentence != null) {
|
||||||
|
selectedSentence.autoAddPeakGainPoints();
|
||||||
|
updateWaveform(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
editGainCurve = new JToggleButtonSpacePlay(Icons.normalize, "Edit gain curve", new ActionListener() {
|
editGainCurve = new JToggleButtonSpacePlay(Icons.normalize, "Edit gain curve", new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
|
autoCreatePoints.setEnabled(editGainCurve.isSelected());
|
||||||
sampleWaveform.setDisplayGainCurve(editGainCurve.isSelected());
|
sampleWaveform.setDisplayGainCurve(editGainCurve.isSelected());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -625,16 +639,20 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
Debug.d(e);
|
Debug.d(e);
|
||||||
|
if (effectsUpdating) return;
|
||||||
if (selectedSentence != null) {
|
if (selectedSentence != null) {
|
||||||
int i = effectChain.getSelectedIndex();
|
int i = effectChain.getSelectedIndex();
|
||||||
KVPair<String, String> p = effectChain.getItemAt(i);
|
KVPair<String, String> p = effectChain.getItemAt(i);
|
||||||
if (p == null) return;
|
if (p == null) return;
|
||||||
|
System.err.println("I want to select effect " + p.getKey());
|
||||||
selectedSentence.setEffectChain(p.getKey());
|
selectedSentence.setEffectChain(p.getKey());
|
||||||
updateWaveform(true);
|
updateWaveform(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
controlsBottom.add(autoCreatePoints);
|
||||||
|
autoCreatePoints.setEnabled(false);
|
||||||
controlsBottom.add(editGainCurve);
|
controlsBottom.add(editGainCurve);
|
||||||
controlsBottom.addSeparator();
|
controlsBottom.addSeparator();
|
||||||
controlsBottom.add(selectSplitMode);
|
controlsBottom.add(selectSplitMode);
|
||||||
@@ -809,8 +827,6 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
locked.setSelected(s.isLocked());
|
locked.setSelected(s.isLocked());
|
||||||
attention.setSelected(s.getAttentionFlag());
|
attention.setSelected(s.getAttentionFlag());
|
||||||
|
|
||||||
setEffectChain(s.getEffectChain());
|
|
||||||
|
|
||||||
postSentenceGap.setEnabled(!s.isLocked());
|
postSentenceGap.setEnabled(!s.isLocked());
|
||||||
gainPercent.setEnabled(!s.isLocked());
|
gainPercent.setEnabled(!s.isLocked());
|
||||||
reprocessAudioFFT.setEnabled(!s.isLocked());
|
reprocessAudioFFT.setEnabled(!s.isLocked());
|
||||||
@@ -1675,12 +1691,17 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
JMenuObject o = (JMenuObject)e.getSource();
|
JMenuObject o = (JMenuObject)e.getSource();
|
||||||
Chapter chap = (Chapter)o.getObject();
|
Chapter chap = (Chapter)o.getObject();
|
||||||
|
|
||||||
ProgressDialog ed = new ProgressDialog("Normalizing " + chap.getName());
|
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||||
|
Sentence snt = (Sentence)s.nextElement();
|
||||||
NormalizeThread t = new NormalizeThread(chap, ed);
|
if (!snt.isLocked()) {
|
||||||
Thread nt = new Thread(t);
|
queueJob(new SentenceJob(snt) {
|
||||||
nt.start();
|
public void run() {
|
||||||
ed.setVisible(true);
|
sentence.normalize();
|
||||||
|
sentence.autoAddPeakGainPoints();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2332,7 +2353,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
book.save();
|
book.save();
|
||||||
|
|
||||||
// Add the book to the tree
|
// Add the book to the tree
|
||||||
loadXMLBookStructure(new File(book.getLocation(), "audiobook.abx"));
|
loadXMLBookStructure(book.getLocation("audiobook.abx"));
|
||||||
updateOpenBookList();
|
updateOpenBookList();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
@@ -2430,40 +2451,6 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
playingThread.start();
|
playingThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
class NormalizeThread implements Runnable {
|
|
||||||
ProgressDialog dialog;
|
|
||||||
Chapter chapter;
|
|
||||||
|
|
||||||
public NormalizeThread(Chapter c, ProgressDialog e) {
|
|
||||||
super();
|
|
||||||
Debug.trace();
|
|
||||||
dialog = e;
|
|
||||||
chapter = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void run() {
|
|
||||||
Debug.trace();
|
|
||||||
|
|
||||||
int numKids = chapter.getChildCount();
|
|
||||||
int kidCount = 0;
|
|
||||||
double lastGain = -1;
|
|
||||||
double variance = Options.getInteger("audio.recording.variance") / 100d;
|
|
||||||
for (Enumeration s = chapter.children(); s.hasMoreElements();) {
|
|
||||||
kidCount++;
|
|
||||||
dialog.setProgress(kidCount * 2000 / numKids);
|
|
||||||
Sentence snt = (Sentence)s.nextElement();
|
|
||||||
if (lastGain == -1) {
|
|
||||||
lastGain = snt.normalize();
|
|
||||||
} else {
|
|
||||||
lastGain = snt.normalize(lastGain - variance, lastGain + variance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog.closeDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExportThread implements Runnable {
|
class ExportThread implements Runnable {
|
||||||
ProgressDialog exportDialog;
|
ProgressDialog exportDialog;
|
||||||
Chapter chapter;
|
Chapter chapter;
|
||||||
@@ -2827,6 +2814,11 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
try {
|
try {
|
||||||
|
pd.setMessage("Purging backups...");
|
||||||
|
book.purgeBackups();
|
||||||
|
|
||||||
|
pd.setMessage("Archiving book...");
|
||||||
|
|
||||||
String name = book.getName();
|
String name = book.getName();
|
||||||
File storageDir = new File(Options.get("path.storage"));
|
File storageDir = new File(Options.get("path.storage"));
|
||||||
File bookDir = book.getLocation();
|
File bookDir = book.getLocation();
|
||||||
@@ -2913,6 +2905,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
zos.flush();
|
zos.flush();
|
||||||
zos.close();
|
zos.close();
|
||||||
|
|
||||||
|
pd.setMessage("Cleaning up...");
|
||||||
|
|
||||||
while (fileList.size() > 0) {
|
while (fileList.size() > 0) {
|
||||||
File f = fileList.remove(fileList.size() - 1);
|
File f = fileList.remove(fileList.size() - 1);
|
||||||
f.delete();
|
f.delete();
|
||||||
@@ -2926,7 +2920,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
|
|
||||||
public void archiveBook(Book book) {
|
public void archiveBook(Book book) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
int r = JOptionPane.showConfirmDialog(this, "This will stash the current book away\nin the archives folder in a compressed\nform. The existing book files will be deleted\nand the book closed.\n\nAre you sure you want to do this?", "Archive Book", JOptionPane.OK_CANCEL_OPTION);
|
int r = JOptionPane.showConfirmDialog(this, "This will stash the current book away\nin the archives folder in a compressed\nform. All backups will be purged, the existing book files will be deleted\nand the book closed.\n\nAre you sure you want to do this?", "Archive Book", JOptionPane.OK_CANCEL_OPTION);
|
||||||
|
|
||||||
if (r == JOptionPane.OK_OPTION) {
|
if (r == JOptionPane.OK_OPTION) {
|
||||||
|
|
||||||
@@ -2937,17 +2931,23 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
Thread t = new Thread(runnable);
|
Thread t = new Thread(runnable);
|
||||||
t.start();
|
t.start();
|
||||||
pd.setVisible(true);
|
pd.setVisible(true);
|
||||||
closeBook(book);
|
closeBook(book, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeBook(Book b) {
|
public void closeBook(Book b) {
|
||||||
|
closeBook(b, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeBook(Book b, boolean save) {
|
||||||
if (selectedBook == b) {
|
if (selectedBook == b) {
|
||||||
setSelectedBook(null);
|
setSelectedBook(null);
|
||||||
setSelectedSentence(null);
|
setSelectedSentence(null);
|
||||||
setSelectedChapter(null);
|
setSelectedChapter(null);
|
||||||
}
|
}
|
||||||
|
if (save) {
|
||||||
saveBook(b);
|
saveBook(b);
|
||||||
|
}
|
||||||
bookTreeModel.removeNodeFromParent(b);
|
bookTreeModel.removeNodeFromParent(b);
|
||||||
updateOpenBookList();
|
updateOpenBookList();
|
||||||
}
|
}
|
||||||
@@ -3111,8 +3111,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
|
|
||||||
public void updateEffectChains(TreeMap<String, EffectGroup> effs) {
|
public void updateEffectChains(TreeMap<String, EffectGroup> effs) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
int sel = effectChain.getSelectedIndex();
|
effectsUpdating = true;
|
||||||
KVPair<String, String> ent = effectChain.getItemAt(sel);
|
System.err.println("Updating effect chains");
|
||||||
while (effectChain.getItemCount() > 0) {
|
while (effectChain.getItemCount() > 0) {
|
||||||
effectChain.removeItemAt(0);
|
effectChain.removeItemAt(0);
|
||||||
}
|
}
|
||||||
@@ -3124,15 +3124,40 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
KVPair<String, String> p = new KVPair<String, String>(k, e.toString());
|
KVPair<String, String> p = new KVPair<String, String>(k, e.toString());
|
||||||
effectChain.addItem(p);
|
effectChain.addItem(p);
|
||||||
}
|
}
|
||||||
if (ent != null) {
|
if (selectedSentence != null) {
|
||||||
setEffectChain(ent.getKey());
|
String key = selectedSentence.getEffectChain();
|
||||||
// } else {
|
for (int i = 0; i < effectChain.getItemCount(); i++) {
|
||||||
// setEffectChain(getBook().getDefaultEffect());
|
KVPair<String, String> p = effectChain.getItemAt(i);
|
||||||
|
if (p.getKey().equals(key)) {
|
||||||
|
effectChain.setSelectedIndex(i);
|
||||||
|
effectsUpdating = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
effectsUpdating = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showSelectedEffectChain(String key) {
|
||||||
|
Debug.trace();
|
||||||
|
effectsUpdating = true;
|
||||||
|
System.err.println("Looking for effect " + key + "...");
|
||||||
|
for (int i = 0; i < effectChain.getItemCount(); i++) {
|
||||||
|
KVPair<String, String> p = effectChain.getItemAt(i);
|
||||||
|
System.err.println(" Testing " + p.getKey() + "...");
|
||||||
|
if (p.getKey().equals(key)) {
|
||||||
|
System.err.println(" Found it.");
|
||||||
|
effectChain.setSelectedIndex(i);
|
||||||
|
effectsUpdating = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
effectsUpdating = false;
|
||||||
|
}
|
||||||
|
|
||||||
public void setEffectChain(String key) {
|
public void setEffectChain(String key) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
|
System.err.println("Setting effect " + key);
|
||||||
for (int i = 0; i < effectChain.getItemCount(); i++) {
|
for (int i = 0; i < effectChain.getItemCount(); i++) {
|
||||||
KVPair<String, String> p = effectChain.getItemAt(i);
|
KVPair<String, String> p = effectChain.getItemAt(i);
|
||||||
if (p.getKey().equals(key)) {
|
if (p.getKey().equals(key)) {
|
||||||
@@ -3255,8 +3280,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
newSentence.writeAudioData(startSamples);
|
newSentence.writeAudioData(startSamples);
|
||||||
newSentence.setPostGapType("continuation");
|
newSentence.setPostGapType("sentence");
|
||||||
newSentence.setPostGap(Options.getInteger("catenation.short-sentence"));
|
newSentence.setPostGap(Options.getInteger("catenation.post-sentence"));
|
||||||
|
|
||||||
selectedSentence.writeAudioData(endSamples);
|
selectedSentence.writeAudioData(endSamples);
|
||||||
selectedSentence.autoTrimSample();
|
selectedSentence.autoTrimSample();
|
||||||
|
|||||||
@@ -78,6 +78,21 @@ public class Biquad implements Effect {
|
|||||||
setPeakGain(peakGainDB);
|
setPeakGain(peakGainDB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special single channel version for wave profile processing
|
||||||
|
public void process(double[] samples) {
|
||||||
|
Debug.trace();
|
||||||
|
lz1 = 0d;
|
||||||
|
lz2 = 0d;
|
||||||
|
for (int i = 0; i < samples.length; i++) {
|
||||||
|
double lout = samples[i] * a0 + lz1;
|
||||||
|
|
||||||
|
lz1 = samples[i] * a1 + lz2 - b1 * lout;
|
||||||
|
lz2 = samples[i] * a2 - b2 * lout;
|
||||||
|
|
||||||
|
samples[i] = lout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void process(double[][] samples) {
|
public void process(double[][] samples) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
lz1 = 0d;
|
lz1 = 0d;
|
||||||
|
|||||||
@@ -472,13 +472,14 @@ public class Book extends BookTreeNode {
|
|||||||
public void onSelect(BookTreeNode target) {
|
public void onSelect(BookTreeNode target) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
AudiobookRecorder.setSelectedBook(this);
|
AudiobookRecorder.setSelectedBook(this);
|
||||||
|
AudiobookRecorder.window.setTitle("AudioBook Recorder :: " + name);
|
||||||
if (target == this) {
|
if (target == this) {
|
||||||
AudiobookRecorder.setSelectedChapter(null);
|
AudiobookRecorder.setSelectedChapter(null);
|
||||||
AudiobookRecorder.setSelectedSentence(null);
|
AudiobookRecorder.setSelectedSentence(null);
|
||||||
}
|
}
|
||||||
AudiobookRecorder.window.setBookNotes(notes);
|
AudiobookRecorder.window.setBookNotes(notes);
|
||||||
AudiobookRecorder.window.noiseFloorLabel.setNoiseFloor(getNoiseFloorDB());
|
AudiobookRecorder.window.noiseFloorLabel.setNoiseFloor(getNoiseFloorDB());
|
||||||
// AudiobookRecorder.window.updateEffectChains(effects);
|
AudiobookRecorder.window.updateEffectChains(effects);
|
||||||
TreeNode p = getParent();
|
TreeNode p = getParent();
|
||||||
if (p instanceof BookTreeNode) {
|
if (p instanceof BookTreeNode) {
|
||||||
BookTreeNode btn = (BookTreeNode)p;
|
BookTreeNode btn = (BookTreeNode)p;
|
||||||
@@ -501,6 +502,11 @@ public class Book extends BookTreeNode {
|
|||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public File getLocation(String dir) {
|
||||||
|
Debug.trace();
|
||||||
|
return new File(location, dir);
|
||||||
|
}
|
||||||
|
|
||||||
public void setLocation(File l) {
|
public void setLocation(File l) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
location = l;
|
location = l;
|
||||||
@@ -588,9 +594,7 @@ public class Book extends BookTreeNode {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
effects = new TreeMap<String,EffectGroup>();
|
effects = new TreeMap<String,EffectGroup>();
|
||||||
loadEffectsFromFolder(new File(Options.get("path.storage"), "System"));
|
loadEffectsFromFolder(new File(Options.get("path.storage"), "System"));
|
||||||
if (location != null) {
|
loadEffectsFromFolder(getLocation());
|
||||||
loadEffectsFromFolder(location);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadEffectsFromFolder(File dir) {
|
public void loadEffectsFromFolder(File dir) {
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ public class CacheManager {
|
|||||||
static int cacheSize = 10;
|
static int cacheSize = 10;
|
||||||
|
|
||||||
public static void addToCache(Cacheable c) {
|
public static void addToCache(Cacheable c) {
|
||||||
|
Debug.trace();
|
||||||
while (cache.size() >= cacheSize) {
|
while (cache.size() >= cacheSize) {
|
||||||
Cacheable ob = cache.remove(0);
|
Cacheable ob = cache.remove(0);
|
||||||
|
if (ob != null) {
|
||||||
if (ob.lockedInCache()) {
|
if (ob.lockedInCache()) {
|
||||||
cache.add(ob);
|
cache.add(ob);
|
||||||
} else {
|
} else {
|
||||||
@@ -19,6 +21,7 @@ public class CacheManager {
|
|||||||
ob.clearCache();
|
ob.clearCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cache.add(c);
|
cache.add(c);
|
||||||
}
|
}
|
||||||
@@ -28,6 +31,7 @@ public class CacheManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void removeFromCache(Cacheable c) {
|
public static void removeFromCache(Cacheable c) {
|
||||||
|
Debug.trace();
|
||||||
if (c instanceof Sentence) {
|
if (c instanceof Sentence) {
|
||||||
Sentence s = (Sentence)c;
|
Sentence s = (Sentence)c;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,12 +172,7 @@ public class Chapter extends BookTreeNode {
|
|||||||
|
|
||||||
Book book = getBook();
|
Book book = getBook();
|
||||||
|
|
||||||
File bookRoot = new File(Options.get("path.storage"), book.getName());
|
File export = book.getLocation("export");
|
||||||
if (!bookRoot.exists()) {
|
|
||||||
bookRoot.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
File export = new File(bookRoot, "export");
|
|
||||||
if (!export.exists()) {
|
if (!export.exists()) {
|
||||||
export.mkdirs();
|
export.mkdirs();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,9 @@ public class Options extends JDialog {
|
|||||||
JSpinner shortSentenceGap;
|
JSpinner shortSentenceGap;
|
||||||
JSpinner postParagraphGap;
|
JSpinner postParagraphGap;
|
||||||
JSpinner postSectionGap;
|
JSpinner postSectionGap;
|
||||||
JSpinner maxGainVariance;
|
JSpinner rmsLow;
|
||||||
|
JSpinner rmsHigh;
|
||||||
|
JCheckBox autoNormalize;
|
||||||
JTextField ffmpegLocation;
|
JTextField ffmpegLocation;
|
||||||
JComboBox<KVPair> bitRate;
|
JComboBox<KVPair> bitRate;
|
||||||
JComboBox<KVPair> channels;
|
JComboBox<KVPair> channels;
|
||||||
@@ -358,7 +360,9 @@ public class Options extends JDialog {
|
|||||||
trimMethod = addDropdown(optionsPanel, "Auto-trim method:", getTrimMethods(), get("audio.recording.trim"), "None: don't auto-trim. FFT: Compare the FFT profile of blocks to the room noise profile and trim silent blocks, Peak: Look for the start and end rise and fall points");
|
trimMethod = addDropdown(optionsPanel, "Auto-trim method:", getTrimMethods(), get("audio.recording.trim"), "None: don't auto-trim. FFT: Compare the FFT profile of blocks to the room noise profile and trim silent blocks, Peak: Look for the start and end rise and fall points");
|
||||||
fftThreshold = addSpinner(optionsPanel, "FFT threshold:", 0, 100, 1, getInteger("audio.recording.trim.fft"), "", "This specifies the difference (in hundredths) between the power of FFT buckets in a sample block compared to the overall power of the same FFT bucket in the room noise. Raising this number makes the FFT trimming less sensitive.");
|
fftThreshold = addSpinner(optionsPanel, "FFT threshold:", 0, 100, 1, getInteger("audio.recording.trim.fft"), "", "This specifies the difference (in hundredths) between the power of FFT buckets in a sample block compared to the overall power of the same FFT bucket in the room noise. Raising this number makes the FFT trimming less sensitive.");
|
||||||
fftBlockSize = addDropdown(optionsPanel, "FFT Block size:", getFFTBlockSizes(), get("audio.recording.trim.blocksize"), "How large an FFT block should be when processing. Larger values increase sensitivity but at the epxense of resolution.");
|
fftBlockSize = addDropdown(optionsPanel, "FFT Block size:", getFFTBlockSizes(), get("audio.recording.trim.blocksize"), "How large an FFT block should be when processing. Larger values increase sensitivity but at the epxense of resolution.");
|
||||||
maxGainVariance = addSpinner(optionsPanel, "Maximum gain variance:", 0, 100, 1, getInteger("audio.recording.variance"), "", "This is how much the gain is allowed to vary by from phrase to phrase when normalizing an entire chapter.");
|
rmsLow = addSpinner(optionsPanel, "Target RMS (low):", -100, 0, 1, getInteger("audio.recording.rms.low"), "", "When normalizing this is the lowest target average RMS to aim for");
|
||||||
|
rmsHigh = addSpinner(optionsPanel, "Target RMS (high):", -100, 0, 1, getInteger("audio.recording.rms.high"), "", "When normalizing this is the highest target average RMS to aim for");
|
||||||
|
autoNormalize = addCheckBox(optionsPanel, "Enable automatic normalization", getBoolean("process.normalize"), "This will automatically normalize each phrase after recording");
|
||||||
|
|
||||||
addSeparator(optionsPanel);
|
addSeparator(optionsPanel);
|
||||||
|
|
||||||
@@ -599,7 +603,9 @@ public class Options extends JDialog {
|
|||||||
defaultPrefs.put("catenation.post-section", "3000");
|
defaultPrefs.put("catenation.post-section", "3000");
|
||||||
|
|
||||||
defaultPrefs.put("audio.recording.trim.fft", "10");
|
defaultPrefs.put("audio.recording.trim.fft", "10");
|
||||||
defaultPrefs.put("audio.recording.variance", "10");
|
defaultPrefs.put("audio.recording.rms.low", "-22");
|
||||||
|
defaultPrefs.put("audio.recording.rms.high", "-20");
|
||||||
|
defaultPrefs.put("process.normalize", "true");
|
||||||
|
|
||||||
defaultPrefs.put("path.storage", (new File(System.getProperty("user.home"), "Recordings")).toString());
|
defaultPrefs.put("path.storage", (new File(System.getProperty("user.home"), "Recordings")).toString());
|
||||||
defaultPrefs.put("path.archive", (new File(new File(System.getProperty("user.home"), "Recordings"),"archive")).toString());
|
defaultPrefs.put("path.archive", (new File(new File(System.getProperty("user.home"), "Recordings"),"archive")).toString());
|
||||||
@@ -736,7 +742,9 @@ public class Options extends JDialog {
|
|||||||
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());
|
||||||
set("audio.recording.variance", maxGainVariance.getValue());
|
set("audio.recording.rms.low", rmsLow.getValue());
|
||||||
|
set("audio.recording.rms.high", rmsHigh.getValue());
|
||||||
|
set("process.normalize", autoNormalize.isSelected());
|
||||||
if (fftBlockSize.getSelectedItem() != null) set("audio.recording.trim.blocksize", ((KVPair)fftBlockSize.getSelectedItem()).key);
|
if (fftBlockSize.getSelectedItem() != null) set("audio.recording.trim.blocksize", ((KVPair)fftBlockSize.getSelectedItem()).key);
|
||||||
if (playbackBlockSize.getSelectedItem() != null) set("audio.playback.blocksize", ((KVPair)playbackBlockSize.getSelectedItem()).key);
|
if (playbackBlockSize.getSelectedItem() != null) set("audio.playback.blocksize", ((KVPair)playbackBlockSize.getSelectedItem()).key);
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
|
|
||||||
double[] fftProfile = null;
|
double[] fftProfile = null;
|
||||||
|
|
||||||
|
double[] waveProfile = null;
|
||||||
|
|
||||||
TreeMap<Integer, Double> gainPoints = null;
|
TreeMap<Integer, Double> gainPoints = null;
|
||||||
|
|
||||||
RecordingThread recordingThread;
|
RecordingThread recordingThread;
|
||||||
@@ -233,6 +235,11 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
peak = Utils.s2d(Book.getTextNode(root, "peak", "-1.000"));
|
peak = Utils.s2d(Book.getTextNode(root, "peak", "-1.000"));
|
||||||
isDetected = Utils.s2b(Book.getTextNode(root, "detected"));
|
isDetected = Utils.s2b(Book.getTextNode(root, "detected"));
|
||||||
|
|
||||||
|
if (sampleSize == 0) {
|
||||||
|
loadFile();
|
||||||
|
autoTrimSample();
|
||||||
|
}
|
||||||
|
|
||||||
gainPoints = new TreeMap<Integer, Double>();
|
gainPoints = new TreeMap<Integer, Double>();
|
||||||
Element gp = Book.getNode(root, "gainpoints");
|
Element gp = Book.getNode(root, "gainpoints");
|
||||||
if (gp != null) {
|
if (gp != null) {
|
||||||
@@ -332,6 +339,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
public void run() {
|
public void run() {
|
||||||
sentence.autoTrimSamplePeak();
|
sentence.autoTrimSamplePeak();
|
||||||
AudiobookRecorder.window.updateWaveformMarkers();
|
AudiobookRecorder.window.updateWaveformMarkers();
|
||||||
|
if (Options.getBoolean("process.normalize")) sentence.normalize();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (tm.equals("fft")) {
|
} else if (tm.equals("fft")) {
|
||||||
@@ -339,6 +347,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
public void run() {
|
public void run() {
|
||||||
sentence.autoTrimSampleFFT();
|
sentence.autoTrimSampleFFT();
|
||||||
AudiobookRecorder.window.updateWaveformMarkers();
|
AudiobookRecorder.window.updateWaveformMarkers();
|
||||||
|
if (Options.getBoolean("process.normalize")) sentence.normalize();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -449,6 +458,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
updateCrossings();
|
updateCrossings();
|
||||||
intens = null;
|
intens = null;
|
||||||
samples = null;
|
samples = null;
|
||||||
|
waveProfile = null;
|
||||||
processed = true;
|
processed = true;
|
||||||
reloadTree();
|
reloadTree();
|
||||||
}
|
}
|
||||||
@@ -575,7 +585,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
Debug.d("Get file for", id);
|
Debug.d("Get file for", id);
|
||||||
Book book = getBook();
|
Book book = getBook();
|
||||||
if (book == null) return null;
|
if (book == null) return null;
|
||||||
File b = new File(book.getLocation(), "files");
|
File b = book.getLocation("files");
|
||||||
if (!b.exists()) {
|
if (!b.exists()) {
|
||||||
b.mkdirs();
|
b.mkdirs();
|
||||||
}
|
}
|
||||||
@@ -584,7 +594,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
|
|
||||||
public File getTempFile() {
|
public File getTempFile() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
File b = new File(getBook().getLocation(), "files");
|
File b = getBook().getLocation("files");
|
||||||
if (!b.exists()) {
|
if (!b.exists()) {
|
||||||
b.mkdirs();
|
b.mkdirs();
|
||||||
}
|
}
|
||||||
@@ -791,13 +801,16 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
public void clearCache() {
|
public void clearCache() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
audioData = null;
|
audioData = null;
|
||||||
|
waveProfile = null;
|
||||||
processedAudio = null;
|
processedAudio = null;
|
||||||
storedFormat = null;
|
storedFormat = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean lockedInCache() {
|
public boolean lockedInCache() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
return id.equals("room-noise");
|
if (id.equals("room-noise")) return true;
|
||||||
|
if (isProcessing()) return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int findNearestZeroCrossing(int pos, int range) {
|
public int findNearestZeroCrossing(int pos, int range) {
|
||||||
@@ -940,6 +953,10 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setGain(double g) {
|
public void setGain(double g) {
|
||||||
|
setGain(g, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGain(double g, boolean batch) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
if (g <= 0.0001d) g = 1.0d;
|
if (g <= 0.0001d) g = 1.0d;
|
||||||
if (g == gain) return;
|
if (g == gain) return;
|
||||||
@@ -950,7 +967,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
if (gint != gainint) {
|
if (gint != gainint) {
|
||||||
refreshAllData();
|
refreshAllData();
|
||||||
peak = -1;
|
peak = -1;
|
||||||
reloadTree();
|
if (!batch) reloadTree();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -962,27 +979,38 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
public double normalize(double low, double high) {
|
public double normalize(double low, double high) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
if (locked) return gain;
|
if (locked) return gain;
|
||||||
double max = getPeakValue(false);
|
|
||||||
double d = 0.708 / max;
|
int targetLow = Options.getInteger("audio.recording.rms.low");
|
||||||
if (d < low) d = low;
|
int targetHigh = Options.getInteger("audio.recording.rms.high");
|
||||||
if (d > high) d = high;
|
|
||||||
setGain(d);
|
long ts = System.currentTimeMillis();
|
||||||
|
while ((int)getRMS() < targetLow) {
|
||||||
|
if (System.currentTimeMillis() - ts > 10000) {
|
||||||
|
System.err.println("Aborted gain boost: took too long");
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
setGain(gain + 0.1);
|
||||||
|
if (gain >= 10.0d) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ts = System.currentTimeMillis();
|
||||||
|
while ((int)getRMS() > targetHigh) {
|
||||||
|
if (System.currentTimeMillis() - ts > 10000) {
|
||||||
|
System.err.println("Aborted gain cut: took too long");
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
setGain(gain - 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshAllData();
|
||||||
peak = -1;
|
peak = -1;
|
||||||
getPeak();
|
getPeak();
|
||||||
reloadTree();
|
reloadTree();
|
||||||
return d;
|
return gain;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double normalize() {
|
public double normalize() {
|
||||||
Debug.trace();
|
return normalize(0, 0);
|
||||||
if (locked) return gain;
|
|
||||||
double max = getPeakValue(false);
|
|
||||||
double d = 0.708 / max;
|
|
||||||
setGain(d);
|
|
||||||
peak = -1;
|
|
||||||
getPeak();
|
|
||||||
reloadTree();
|
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExternalEditor implements Runnable {
|
class ExternalEditor implements Runnable {
|
||||||
@@ -1455,11 +1483,11 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
|
|
||||||
synchronized public double[][] getProcessedAudioData(boolean effectsEnabled, boolean applyGain) {
|
synchronized public double[][] getProcessedAudioData(boolean effectsEnabled, boolean applyGain) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
Book book = getBook();
|
|
||||||
loadFile();
|
|
||||||
if (processedAudio != null) {
|
if (processedAudio != null) {
|
||||||
return processedAudio;
|
return processedAudio;
|
||||||
}
|
}
|
||||||
|
Book book = getBook();
|
||||||
|
loadFile();
|
||||||
|
|
||||||
if (audioData == null) return null;
|
if (audioData == null) return null;
|
||||||
processedAudio = new double[2][audioData[LEFT].length];
|
processedAudio = new double[2][audioData[LEFT].length];
|
||||||
@@ -1486,7 +1514,12 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
eff = book.effects.get(effectChain);
|
eff = book.effects.get(effectChain);
|
||||||
if (eff != null) {
|
if (eff != null) {
|
||||||
eff.init(getAudioFormat().getFrameRate());
|
eff.init(getAudioFormat().getFrameRate());
|
||||||
|
// There is a chance another thread could cripple the audio data cache
|
||||||
|
// so we'll just ignore any errors here.
|
||||||
|
try {
|
||||||
eff.process(processedAudio);
|
eff.process(processedAudio);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1730,6 +1763,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
AudiobookRecorder.setSelectedSentence(this);
|
AudiobookRecorder.setSelectedSentence(this);
|
||||||
AudiobookRecorder.window.setSentenceNotes(notes);
|
AudiobookRecorder.window.setSentenceNotes(notes);
|
||||||
|
AudiobookRecorder.window.showSelectedEffectChain(getEffectChain());
|
||||||
TreeNode p = getParent();
|
TreeNode p = getParent();
|
||||||
if (p instanceof BookTreeNode) {
|
if (p instanceof BookTreeNode) {
|
||||||
BookTreeNode btn = (BookTreeNode)p;
|
BookTreeNode btn = (BookTreeNode)p;
|
||||||
@@ -1832,6 +1866,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
peak = -1d;
|
peak = -1d;
|
||||||
sampleSize = -1;
|
sampleSize = -1;
|
||||||
audioData = null;
|
audioData = null;
|
||||||
|
waveProfile = null;
|
||||||
processedAudio = null;
|
processedAudio = null;
|
||||||
fftProfile = null;
|
fftProfile = null;
|
||||||
CacheManager.removeFromCache(this);
|
CacheManager.removeFromCache(this);
|
||||||
@@ -1868,6 +1903,10 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void adjustGainPoint(Integer loc, Double adj) {
|
public void adjustGainPoint(Integer loc, Double adj) {
|
||||||
|
adjustGainPoint(loc, adj, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void adjustGainPoint(Integer loc, Double adj, boolean reload) {
|
||||||
if (gainPoints == null) {
|
if (gainPoints == null) {
|
||||||
gainPoints = new TreeMap<Integer, Double>();
|
gainPoints = new TreeMap<Integer, Double>();
|
||||||
return;
|
return;
|
||||||
@@ -1876,8 +1915,10 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
if (gp == null) return;
|
if (gp == null) return;
|
||||||
gp += adj;
|
gp += adj;
|
||||||
gainPoints.put(loc, gp);
|
gainPoints.put(loc, gp);
|
||||||
|
if (reload) {
|
||||||
refreshAllData();
|
refreshAllData();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public double[] calculateGains() {
|
public double[] calculateGains() {
|
||||||
double[] gains = new double[sampleSize];
|
double[] gains = new double[sampleSize];
|
||||||
@@ -1901,7 +1942,10 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
double ystep = diff / (double)range;
|
double ystep = diff / (double)range;
|
||||||
for (int x = 0; x < range; x++) {
|
for (int x = 0; x < range; x++) {
|
||||||
y += ystep;
|
y += ystep;
|
||||||
|
try {
|
||||||
gains[x1 + x] = y;
|
gains[x1 + x] = y;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
x1 = x2;
|
x1 = x2;
|
||||||
}
|
}
|
||||||
@@ -1937,6 +1981,24 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
return rms;
|
return rms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isClipping(int start, int end) {
|
||||||
|
|
||||||
|
double[][] samples = getProcessedAudioData();
|
||||||
|
if (samples == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = start; i <= end; i++) {
|
||||||
|
if (Math.abs(samples[LEFT][i]) > 0.708) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Math.abs(samples[RIGHT][i]) > 0.708) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isClipping() {
|
public boolean isClipping() {
|
||||||
if (clipping > 0) {
|
if (clipping > 0) {
|
||||||
if (clipping == 1) return false;
|
if (clipping == 1) return false;
|
||||||
@@ -1950,15 +2012,177 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
|
|
||||||
clipping = 1;
|
clipping = 1;
|
||||||
for (int i = 0; i < samples[LEFT].length; i++) {
|
for (int i = 0; i < samples[LEFT].length; i++) {
|
||||||
if (samples[LEFT][i] > 0.708) {
|
if (Math.abs(samples[LEFT][i]) > 0.708) {
|
||||||
clipping = 2;
|
clipping = 2;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (samples[RIGHT][i] > 0.708) {
|
if (Math.abs(samples[RIGHT][i]) > 0.708) {
|
||||||
clipping = 2;
|
clipping = 2;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double mix(double a, double b) {
|
||||||
|
return (a + b) / 2d;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int window = 500;
|
||||||
|
|
||||||
|
public double[] getWaveProfile() {
|
||||||
|
if (waveProfile != null) return waveProfile;
|
||||||
|
double[][] samples = getProcessedAudioData();
|
||||||
|
if (samples[LEFT].length == 0) return null;
|
||||||
|
waveProfile = new double[samples[LEFT].length];
|
||||||
|
|
||||||
|
double rt = 0;
|
||||||
|
|
||||||
|
int nsamp = samples[LEFT].length;
|
||||||
|
int nbuckets = nsamp / window;
|
||||||
|
|
||||||
|
double[] buckets = new double[nbuckets + 1];
|
||||||
|
|
||||||
|
for (int i = 0; i < nsamp; i++) {
|
||||||
|
double sval = Math.abs(mix(samples[LEFT][i], samples[RIGHT][i]));
|
||||||
|
int bnum = i / window;
|
||||||
|
if (sval > buckets[bnum]) buckets[bnum] = sval;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < nsamp; i++) {
|
||||||
|
waveProfile[i] = buckets[i / window];
|
||||||
|
}
|
||||||
|
|
||||||
|
return waveProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
int findBiggestPeak() {
|
||||||
|
double[][] samples = getProcessedAudioData();
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
double peak = 0;
|
||||||
|
|
||||||
|
if (samples == null) {
|
||||||
|
System.err.println("Um.... no samples...?");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < samples[LEFT].length; i++) {
|
||||||
|
if (Math.abs(samples[LEFT][i]) > peak) {
|
||||||
|
peak = Math.abs(samples[LEFT][i]);
|
||||||
|
pos = i;
|
||||||
|
}
|
||||||
|
if (Math.abs(samples[RIGHT][i]) > peak) {
|
||||||
|
peak = Math.abs(samples[RIGHT][i]);
|
||||||
|
pos = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
int findPreviousZero(int offset) {
|
||||||
|
double[] profile = getWaveProfile();
|
||||||
|
|
||||||
|
int pos = offset;
|
||||||
|
while (pos > 0) {
|
||||||
|
if (profile[pos] < 0.05) return pos - (window/2);
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int findNextZero(int offset) {
|
||||||
|
double[] profile = getWaveProfile();
|
||||||
|
|
||||||
|
int pos = offset;
|
||||||
|
while (pos < profile.length) {
|
||||||
|
if (profile[pos] < 0.05) return pos + (window / 2);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int findNearestGainPoint(int pos) {
|
||||||
|
int closest = Integer.MAX_VALUE;
|
||||||
|
int cpos = -1;
|
||||||
|
|
||||||
|
if (gainPoints == null) return -1;
|
||||||
|
|
||||||
|
for (Integer loc : gainPoints.keySet()) {
|
||||||
|
int diff = pos - loc;
|
||||||
|
if (diff < 0) diff = 0 - diff;
|
||||||
|
if (diff < closest) {
|
||||||
|
closest = diff;
|
||||||
|
cpos = loc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void autoAddPeakGainPoints() {
|
||||||
|
long ts = System.currentTimeMillis();
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
if (System.currentTimeMillis() - ts > 10000) {
|
||||||
|
System.err.println("Terminated: running too long!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
processedAudio = null;
|
||||||
|
double[][] samples = getProcessedAudioData();
|
||||||
|
int pos = findBiggestPeak();
|
||||||
|
if (pos == -1) return;
|
||||||
|
|
||||||
|
System.err.println("Biggest peak: " + pos);
|
||||||
|
|
||||||
|
int closest = findNearestGainPoint(pos);
|
||||||
|
if (closest >= 0) {
|
||||||
|
int diff = closest - pos;
|
||||||
|
if (diff < 0) diff = 0 - diff;
|
||||||
|
if (diff < 10) {
|
||||||
|
System.err.println("Readjusting location: " + closest + " - diff = " + diff);
|
||||||
|
pos = closest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Math.abs(samples[LEFT][pos]) < 0.708) && (Math.abs(samples[RIGHT][pos]) < 0.708)) {
|
||||||
|
System.err.println("No more peaks");
|
||||||
|
refreshAllData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int start = findPreviousZero(pos);
|
||||||
|
int end = findNextZero(pos);
|
||||||
|
if (start == -1) {
|
||||||
|
System.err.println("Unable to find previous zero");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (end == -1) {
|
||||||
|
System.err.println("Unable to find next zero");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
addGainPoint(start, 1d);
|
||||||
|
addGainPoint(pos, 1d);
|
||||||
|
addGainPoint(end, 1d);
|
||||||
|
|
||||||
|
double val = 1d;
|
||||||
|
|
||||||
|
while (isClipping(pos - 10, pos + 10)) {
|
||||||
|
adjustGainPoint(pos, -0.05, false);
|
||||||
|
val -= 0.05d;
|
||||||
|
if (val < 0.1d) {
|
||||||
|
System.err.println("Aborting: gain too low");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
processedAudio = null; // Force a refresh
|
||||||
|
}
|
||||||
|
System.err.println("Result: " + gainPoints.get(pos));
|
||||||
|
try {
|
||||||
|
Thread.sleep(1);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ public class VersionChecker implements Runnable {
|
|||||||
if (Utils.s2i(installedVersion) >= Utils.s2i(availableVersion)) return;
|
if (Utils.s2i(installedVersion) >= Utils.s2i(availableVersion)) return;
|
||||||
|
|
||||||
JButton upgrade = new JButton("A new version is available.");
|
JButton upgrade = new JButton("A new version is available.");
|
||||||
|
upgrade.setFocusable(false);
|
||||||
upgrade.addActionListener(new ActionListener() {
|
upgrade.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent evt) {
|
public void actionPerformed(ActionEvent evt) {
|
||||||
Utils.browse(website);
|
Utils.browse(website);
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
|
|||||||
|
|
||||||
if (sentence != null) {
|
if (sentence != null) {
|
||||||
double[][] samples = sentence.getDoubleAudioData(true);
|
double[][] samples = sentence.getDoubleAudioData(true);
|
||||||
|
double[] waveProfile = sentence.getWaveProfile();
|
||||||
|
|
||||||
int num = samples[Sentence.LEFT].length;
|
int num = samples[Sentence.LEFT].length;
|
||||||
step = num / zoomFactor / w;
|
step = num / zoomFactor / w;
|
||||||
@@ -117,9 +118,13 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
|
|||||||
double lave = 0;
|
double lave = 0;
|
||||||
double lmax = 0;
|
double lmax = 0;
|
||||||
|
|
||||||
|
double prof = 0;
|
||||||
|
|
||||||
for (int o = 0; o < step; o++) {
|
for (int o = 0; o < step; o++) {
|
||||||
if (offset + (n * step) + o >= samples[Sentence.LEFT].length) break;
|
if (offset + (n * step) + o >= samples[Sentence.LEFT].length) break;
|
||||||
double sample = (samples[Sentence.LEFT][offset + (n * step) + o] + samples[Sentence.RIGHT][offset + (n * step) + o]) / 2d;
|
double sample = (samples[Sentence.LEFT][offset + (n * step) + o] + samples[Sentence.RIGHT][offset + (n * step) + o]) / 2d;
|
||||||
|
double asamp = waveProfile[offset + (n * step) + o];
|
||||||
|
if (asamp > prof) prof = asamp;
|
||||||
if (sample >= 0) {
|
if (sample >= 0) {
|
||||||
have += sample;
|
have += sample;
|
||||||
hcnt++;
|
hcnt++;
|
||||||
@@ -158,6 +163,12 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
|
|||||||
g.drawLine(n, (int)(h/2 + lmax), n, (int)(h/2 - hmax));
|
g.drawLine(n, (int)(h/2 + lmax), n, (int)(h/2 - hmax));
|
||||||
g.setColor(new Color(0, 100, 255));
|
g.setColor(new Color(0, 100, 255));
|
||||||
g.drawLine(n, (int)(h/2 + lave), n, (int)(h/2 - have));
|
g.drawLine(n, (int)(h/2 + lave), n, (int)(h/2 - have));
|
||||||
|
if (prof < 0.05d) {
|
||||||
|
g.setColor(new Color(0, 255, 0));
|
||||||
|
} else {
|
||||||
|
g.setColor(new Color(0, 100, 0));
|
||||||
|
}
|
||||||
|
g.drawLine(n, (int)(h/2 - prof * scale), n, (int)(h/2 - prof * scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
g.setColor(new Color(255, 0, 0, 64));
|
g.setColor(new Color(255, 0, 0, 64));
|
||||||
|
|||||||
Reference in New Issue
Block a user