Compare commits

...

15 Commits

12 changed files with 648 additions and 57 deletions

View File

@@ -1 +1 @@
version=0.3.0 version=0.3.4

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -3,6 +3,7 @@ package uk.co.majenko.audiobookrecorder;
import javax.sound.sampled.*; import javax.sound.sampled.*;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.*; import javax.swing.event.*;
import javax.swing.text.*;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.nio.file.*; import java.nio.file.*;
@@ -32,11 +33,15 @@ import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource; import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.OutputKeys;
import org.w3c.dom.Attr; import org.w3c.dom.Attr;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
public class AudiobookRecorder extends JFrame { import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
public class AudiobookRecorder extends JFrame implements DocumentListener {
// Settings - tweakable // Settings - tweakable
@@ -75,6 +80,7 @@ public class AudiobookRecorder extends JFrame {
JMenuItem toolsMerge; JMenuItem toolsMerge;
JMenuItem toolsArchive; JMenuItem toolsArchive;
JMenuItem toolsCoverArt; JMenuItem toolsCoverArt;
JMenuItem toolsManuscript;
JMenuItem toolsOptions; JMenuItem toolsOptions;
JMenuItem helpAbout; JMenuItem helpAbout;
@@ -100,6 +106,18 @@ public class AudiobookRecorder extends JFrame {
JPanel sampleControl; JPanel sampleControl;
public Waveform sampleWaveform; public Waveform sampleWaveform;
JScrollBar sampleScroll; JScrollBar sampleScroll;
JSplitPane mainSplit;
JTabbedPane notesTabs;
JTextArea bookNotesArea;
JScrollPane bookNotesScroll;
JTextArea chapterNotesArea;
JScrollPane chapterNotesScroll;
JTextArea sentenceNotesArea;
JScrollPane sentenceNotesScroll;
JSpinner postSentenceGap; JSpinner postSentenceGap;
JSpinner gainPercent; JSpinner gainPercent;
@@ -286,6 +304,13 @@ public class AudiobookRecorder extends JFrame {
} }
}); });
toolsManuscript = new JMenuItem("Import Manuscript...");
toolsManuscript.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
loadManuscript();
}
});
toolsOptions = new JMenuItem("Options"); toolsOptions = new JMenuItem("Options");
toolsOptions.addActionListener(new ActionListener() { toolsOptions.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
@@ -296,6 +321,7 @@ public class AudiobookRecorder extends JFrame {
toolsMenu.add(toolsMerge); toolsMenu.add(toolsMerge);
toolsMenu.add(toolsArchive); toolsMenu.add(toolsArchive);
toolsMenu.add(toolsCoverArt); toolsMenu.add(toolsCoverArt);
toolsMenu.add(toolsManuscript);
toolsMenu.addSeparator(); toolsMenu.addSeparator();
toolsMenu.add(toolsOptions); toolsMenu.add(toolsOptions);
@@ -557,11 +583,11 @@ public class AudiobookRecorder extends JFrame {
controlsTop.add(attention); controlsTop.add(attention);
controlsTop.add(Box.createHorizontalGlue()); controlsTop.add(Box.createHorizontalGlue());
controlsTop.add(new JLabel("Post gap:")); controlsTop.add(new JLabel(" Post gap:"));
controlsTop.add(postSentenceGap); controlsTop.add(postSentenceGap);
controlsTop.add(new JLabel("ms")); controlsTop.add(new JLabel("ms "));
controlsTop.add(new JLabel("Gain:")); controlsTop.add(new JLabel(" Gain:"));
controlsTop.add(gainPercent); controlsTop.add(gainPercent);
controlsTop.add(new JLabel("%")); controlsTop.add(new JLabel("%"));
@@ -621,29 +647,13 @@ public class AudiobookRecorder extends JFrame {
buildToolbar(centralPanel); buildToolbar(centralPanel);
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F"), "startRecordShort");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released F"), "stopRecord");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("R"), "startRecord");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released R"), "stopRecord");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("T"), "startRecordNewPara");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released T"), "stopRecord");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("Y"), "startRecordNewSection");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released Y"), "stopRecord");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released D"), "deleteLast");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("SPACE"), "startStopPlayback");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.SHIFT_DOWN_MASK), "startPlaybackFrom");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("E"), "startRerecord");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released E"), "stopRecord");
centralPanel.getActionMap().put("startRecord", new AbstractAction() { centralPanel.getActionMap().put("startRecord", new AbstractAction() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (!getLock()) return; if (!getLock()) return;
if (getFocusOwner() == bookNotesArea) { freeLock(); return; }
if (getFocusOwner() == chapterNotesArea) { freeLock(); return; }
if (getFocusOwner() == sentenceNotesArea) { freeLock(); return; }
if (bookTree.isEditing()) { if (bookTree.isEditing()) {
freeLock(); freeLock();
return; return;
@@ -659,6 +669,9 @@ public class AudiobookRecorder extends JFrame {
centralPanel.getActionMap().put("startRecordShort", new AbstractAction() { centralPanel.getActionMap().put("startRecordShort", new AbstractAction() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (!getLock()) return; if (!getLock()) return;
if (getFocusOwner() == bookNotesArea) { freeLock(); return; }
if (getFocusOwner() == chapterNotesArea) { freeLock(); return; }
if (getFocusOwner() == sentenceNotesArea) { freeLock(); return; }
if (bookTree.isEditing()) { if (bookTree.isEditing()) {
freeLock(); freeLock();
return; return;
@@ -674,6 +687,9 @@ public class AudiobookRecorder extends JFrame {
centralPanel.getActionMap().put("startRecordNewPara", new AbstractAction() { centralPanel.getActionMap().put("startRecordNewPara", new AbstractAction() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (!getLock()) return; if (!getLock()) return;
if (getFocusOwner() == bookNotesArea) { freeLock(); return; }
if (getFocusOwner() == chapterNotesArea) { freeLock(); return; }
if (getFocusOwner() == sentenceNotesArea) { freeLock(); return; }
if (bookTree.isEditing()) { if (bookTree.isEditing()) {
freeLock(); freeLock();
return; return;
@@ -689,6 +705,9 @@ public class AudiobookRecorder extends JFrame {
centralPanel.getActionMap().put("startRecordNewSection", new AbstractAction() { centralPanel.getActionMap().put("startRecordNewSection", new AbstractAction() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (!getLock()) return; if (!getLock()) return;
if (getFocusOwner() == bookNotesArea) { freeLock(); return; }
if (getFocusOwner() == chapterNotesArea) { freeLock(); return; }
if (getFocusOwner() == sentenceNotesArea) { freeLock(); return; }
if (bookTree.isEditing()) { if (bookTree.isEditing()) {
freeLock(); freeLock();
return; return;
@@ -704,6 +723,9 @@ public class AudiobookRecorder extends JFrame {
centralPanel.getActionMap().put("startRerecord", new AbstractAction() { centralPanel.getActionMap().put("startRerecord", new AbstractAction() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (!getLock()) return; if (!getLock()) return;
if (getFocusOwner() == bookNotesArea) { freeLock(); return; }
if (getFocusOwner() == chapterNotesArea) { freeLock(); return; }
if (getFocusOwner() == sentenceNotesArea) { freeLock(); return; }
if (bookTree.isEditing()) { if (bookTree.isEditing()) {
freeLock(); freeLock();
return; return;
@@ -718,6 +740,9 @@ public class AudiobookRecorder extends JFrame {
}); });
centralPanel.getActionMap().put("stopRecord", new AbstractAction() { centralPanel.getActionMap().put("stopRecord", new AbstractAction() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (getFocusOwner() == bookNotesArea) { return; }
if (getFocusOwner() == chapterNotesArea) { return; }
if (getFocusOwner() == sentenceNotesArea) { return; }
if (bookTree.isEditing()) return; if (bookTree.isEditing()) return;
stopLock(); stopLock();
stopRecording(); stopRecording();
@@ -726,6 +751,9 @@ public class AudiobookRecorder extends JFrame {
}); });
centralPanel.getActionMap().put("deleteLast", new AbstractAction() { centralPanel.getActionMap().put("deleteLast", new AbstractAction() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (getFocusOwner() == bookNotesArea) { return; }
if (getFocusOwner() == chapterNotesArea) { return; }
if (getFocusOwner() == sentenceNotesArea) { return; }
if (bookTree.isEditing()) return; if (bookTree.isEditing()) return;
deleteLastRecording(); deleteLastRecording();
} }
@@ -733,6 +761,9 @@ public class AudiobookRecorder extends JFrame {
centralPanel.getActionMap().put("startStopPlayback", new AbstractAction() { centralPanel.getActionMap().put("startStopPlayback", new AbstractAction() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (getFocusOwner() == bookNotesArea) { return; }
if (getFocusOwner() == chapterNotesArea) { return; }
if (getFocusOwner() == sentenceNotesArea) { return; }
if (bookTree.isEditing()) return; if (bookTree.isEditing()) return;
if (playing == null) { if (playing == null) {
playSelectedSentence(); playSelectedSentence();
@@ -744,6 +775,9 @@ public class AudiobookRecorder extends JFrame {
centralPanel.getActionMap().put("startPlaybackFrom", new AbstractAction() { centralPanel.getActionMap().put("startPlaybackFrom", new AbstractAction() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (getFocusOwner() == bookNotesArea) { return; }
if (getFocusOwner() == chapterNotesArea) { return; }
if (getFocusOwner() == sentenceNotesArea) { return; }
if (bookTree.isEditing()) return; if (bookTree.isEditing()) return;
if (playing == null) { if (playing == null) {
playFromSelectedSentence(); playFromSelectedSentence();
@@ -752,16 +786,65 @@ public class AudiobookRecorder extends JFrame {
}); });
mainScroll = new JScrollPane(); mainScroll = new JScrollPane();
centralPanel.add(mainScroll, BorderLayout.CENTER);
bookNotesArea = new JTextArea();
bookNotesArea.setFont(new Font("Monospaced", Font.PLAIN, 10));
bookNotesScroll = new JScrollPane();
bookNotesScroll.setViewportView(bookNotesArea);
chapterNotesArea = new JTextArea();
chapterNotesArea.setFont(new Font("Monospaced", Font.PLAIN, 10));
chapterNotesArea.getDocument().addDocumentListener(this);
chapterNotesScroll = new JScrollPane();
chapterNotesScroll.setViewportView(chapterNotesArea);
sentenceNotesArea = new JTextArea();
sentenceNotesArea.setFont(new Font("Monospaced", Font.PLAIN, 10));
sentenceNotesArea.getDocument().addDocumentListener(this);
sentenceNotesScroll = new JScrollPane();
sentenceNotesScroll.setViewportView(sentenceNotesArea);
notesTabs = new JTabbedPane();
notesTabs.add("Book", bookNotesScroll);
notesTabs.add("Chapter", chapterNotesScroll);
notesTabs.add("Phrase", sentenceNotesScroll);
mainSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, mainScroll, notesTabs);
centralPanel.add(mainSplit, BorderLayout.CENTER);
mainSplit.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent ev) {
if (ev.getPropertyName().equals("dividerLocation")) {
if ((bookTreeModel != null) && (book != null)) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
bookTreeModel.reload(book);
}
});
}
}
}
});
setTitle("AudioBook Recorder"); setTitle("AudioBook Recorder");
setIconImage(Icons.appIcon.getImage()); setIconImage(Icons.appIcon.getImage());
bindKeys(centralPanel);
mainSplit.setResizeWeight(0.8d);
pack(); pack();
setVisible(true); setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
mainSplit.setDividerLocation(0.8d);
}
});
String lastBook = Options.get("path.last-book"); String lastBook = Options.get("path.last-book");
if (lastBook != null && !lastBook.equals("")) { if (lastBook != null && !lastBook.equals("")) {
@@ -792,6 +875,50 @@ public class AudiobookRecorder extends JFrame {
} }
void bindKeys(JComponent component) {
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F"), "startRecordShort");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released F"), "stopRecord");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("R"), "startRecord");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released R"), "stopRecord");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("T"), "startRecordNewPara");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released T"), "stopRecord");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("Y"), "startRecordNewSection");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released Y"), "stopRecord");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released D"), "deleteLast");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("SPACE"), "startStopPlayback");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.SHIFT_DOWN_MASK), "startPlaybackFrom");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("E"), "startRerecord");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released E"), "stopRecord");
}
void unbindKeys(JComponent component) {
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F"), "ignore");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released F"), "ignore");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("R"), "ignore");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released R"), "ignore");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("T"), "ignore");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released T"), "ignore");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("Y"), "ignore");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released Y"), "ignore");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released D"), "ignore");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("SPACE"), "ignore");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.SHIFT_DOWN_MASK), "ignore");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("E"), "ignore");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released E"), "ignore");
}
public static void main(String args[]) { public static void main(String args[]) {
try { try {
config.load(AudiobookRecorder.class.getResourceAsStream("config.txt")); config.load(AudiobookRecorder.class.getResourceAsStream("config.txt"));
@@ -846,6 +973,8 @@ public class AudiobookRecorder extends JFrame {
// write the content into xml file // write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance(); TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(); Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
DOMSource source = new DOMSource(doc); DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(xml); StreamResult result = new StreamResult(xml);
transformer.transform(source, result); transformer.transform(source, result);
@@ -951,7 +1080,6 @@ public class AudiobookRecorder extends JFrame {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
void treePopup(MouseEvent e) { void treePopup(MouseEvent e) {
int selRow = bookTree.getRowForLocation(e.getX(), e.getY()); int selRow = bookTree.getRowForLocation(e.getX(), e.getY());
TreePath selPath = bookTree.getPathForLocation(e.getX(), e.getY()); TreePath selPath = bookTree.getPathForLocation(e.getX(), e.getY());
if (selRow != -1) { if (selRow != -1) {
@@ -1118,6 +1246,7 @@ public class AudiobookRecorder extends JFrame {
Chapter c = (Chapter)s.getParent(); Chapter c = (Chapter)s.getParent();
int idx = bookTreeModel.getIndexOfChild(c, s); int idx = bookTreeModel.getIndexOfChild(c, s);
bookTreeModel.insertNodeInto(newSentence, c, idx); bookTreeModel.insertNodeInto(newSentence, c, idx);
bookTree.setSelectionPath(new TreePath(newSentence.getPath()));
} catch (Exception ex) { } catch (Exception ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
@@ -1196,6 +1325,34 @@ public class AudiobookRecorder extends JFrame {
} }
}); });
JMenuObject peaknew = new JMenuObject("Auto-trim new (Peak)", c, new ActionListener() {
public void actionPerformed(ActionEvent e) {
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.NewOnly);
Thread nt = new Thread(t);
nt.start();
ed.setVisible(true);
}
});
JMenuObject fftnew = new JMenuObject("Auto-trim new (FFT)", c, new ActionListener() {
public void actionPerformed(ActionEvent e) {
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);
}
});
JMenuObject peak = new JMenuObject("Auto-trim all (Peak)", c, new ActionListener() { JMenuObject peak = new JMenuObject("Auto-trim all (Peak)", c, new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
JMenuObject o = (JMenuObject)e.getSource(); JMenuObject o = (JMenuObject)e.getSource();
@@ -1203,7 +1360,7 @@ public class AudiobookRecorder extends JFrame {
ProgressDialog ed = new ProgressDialog("Auto-trimming " + chap.getName()); ProgressDialog ed = new ProgressDialog("Auto-trimming " + chap.getName());
AutoTrimThread t = new AutoTrimThread(chap, ed, AutoTrimThread.Peak); AutoTrimThread t = new AutoTrimThread(chap, ed, AutoTrimThread.Peak, AutoTrimThread.All);
Thread nt = new Thread(t); Thread nt = new Thread(t);
nt.start(); nt.start();
ed.setVisible(true); ed.setVisible(true);
@@ -1217,7 +1374,7 @@ public class AudiobookRecorder extends JFrame {
ProgressDialog ed = new ProgressDialog("Auto-trimming " + chap.getName()); ProgressDialog ed = new ProgressDialog("Auto-trimming " + chap.getName());
AutoTrimThread t = new AutoTrimThread(chap, ed, AutoTrimThread.FFT); AutoTrimThread t = new AutoTrimThread(chap, ed, AutoTrimThread.FFT, AutoTrimThread.All);
Thread nt = new Thread(t); Thread nt = new Thread(t);
nt.start(); nt.start();
ed.setVisible(true); ed.setVisible(true);
@@ -1410,6 +1567,8 @@ public class AudiobookRecorder extends JFrame {
menu.addSeparator(); menu.addSeparator();
menu.add(mergeWith); menu.add(mergeWith);
menu.addSeparator(); menu.addSeparator();
menu.add(peaknew);
menu.add(fftnew);
menu.add(peak); menu.add(peak);
menu.add(fft); menu.add(fft);
menu.addSeparator(); menu.addSeparator();
@@ -1832,6 +1991,8 @@ public class AudiobookRecorder extends JFrame {
// write the content into xml file // write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance(); TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(); Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
DOMSource source = new DOMSource(doc); DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(xml); StreamResult result = new StreamResult(xml);
transformer.transform(source, result); transformer.transform(source, result);
@@ -1874,6 +2035,12 @@ public class AudiobookRecorder extends JFrame {
bookTree.addTreeSelectionListener(new TreeSelectionListener() { bookTree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) { public void valueChanged(TreeSelectionEvent e) {
DefaultMutableTreeNode n = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent(); DefaultMutableTreeNode n = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
if (n instanceof BookTreeNode) {
BookTreeNode btn = (BookTreeNode)n;
btn.onSelect();
}
if (n instanceof Sentence) { if (n instanceof Sentence) {
Sentence s = (Sentence)n; Sentence s = (Sentence)n;
selectedSentence = s; selectedSentence = s;
@@ -2041,6 +2208,11 @@ public class AudiobookRecorder extends JFrame {
bookTree.addTreeSelectionListener(new TreeSelectionListener() { bookTree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) { public void valueChanged(TreeSelectionEvent e) {
DefaultMutableTreeNode n = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent(); DefaultMutableTreeNode n = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
if (n instanceof BookTreeNode) {
BookTreeNode btn = (BookTreeNode)n;
btn.onSelect();
}
if (n instanceof Sentence) { if (n instanceof Sentence) {
Sentence s = (Sentence)n; Sentence s = (Sentence)n;
selectedSentence = s; selectedSentence = s;
@@ -2361,11 +2533,17 @@ public class AudiobookRecorder extends JFrame {
int numKids = chapter.getChildCount(); int numKids = chapter.getChildCount();
int kidCount = 0; int kidCount = 0;
double lastGain = -1;
double variance = Options.getInteger("audio.recording.variance") / 100d;
for (Enumeration s = chapter.children(); s.hasMoreElements();) { for (Enumeration s = chapter.children(); s.hasMoreElements();) {
kidCount++; kidCount++;
dialog.setProgress(kidCount * 2000 / numKids); dialog.setProgress(kidCount * 2000 / numKids);
Sentence snt = (Sentence)s.nextElement(); Sentence snt = (Sentence)s.nextElement();
snt.normalize(); if (lastGain == -1) {
lastGain = snt.normalize();
} else {
lastGain = snt.normalize(lastGain - variance, lastGain + variance);
}
} }
dialog.closeDialog(); dialog.closeDialog();
@@ -2376,15 +2554,19 @@ public class AudiobookRecorder extends JFrame {
ProgressDialog dialog; ProgressDialog dialog;
Chapter chapter; Chapter chapter;
int type; int type;
int scope;
public final static int FFT = 0; public final static int FFT = 0;
public final static int Peak = 1; 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) { public AutoTrimThread(Chapter c, ProgressDialog e, int t, int sc) {
super(); super();
dialog = e; dialog = e;
chapter = c; chapter = c;
type = t; type = t;
scope = sc;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -2396,6 +2578,9 @@ public class AudiobookRecorder extends JFrame {
kidCount++; kidCount++;
dialog.setProgress(kidCount * 2000 / numKids); dialog.setProgress(kidCount * 2000 / numKids);
Sentence snt = (Sentence)s.nextElement(); Sentence snt = (Sentence)s.nextElement();
if (scope == NewOnly) {
if (snt.isProcessed()) continue;
}
switch (type) { switch (type) {
case FFT: case FFT:
snt.autoTrimSampleFFT(); snt.autoTrimSampleFFT();
@@ -2621,7 +2806,7 @@ public class AudiobookRecorder extends JFrame {
play.close(); play.close();
} }
play = null; play = null;
e.printStackTrace(); // e.printStackTrace();
} }
} }
}); });
@@ -3533,8 +3718,12 @@ public class AudiobookRecorder extends JFrame {
public void doSplit(int at) { public void doSplit(int at) {
try { try {
Sentence newSentence = selectedSentence.cloneSentence(); if (selectedSentence == null) {
System.err.println("Selected sentence is NULL in split. That CANNOT happen!");
return;
}
Chapter c = (Chapter)selectedSentence.getParent(); Chapter c = (Chapter)selectedSentence.getParent();
Sentence newSentence = selectedSentence.cloneSentence();
int idx = bookTreeModel.getIndexOfChild(c, selectedSentence); int idx = bookTreeModel.getIndexOfChild(c, selectedSentence);
bookTreeModel.insertNodeInto(newSentence, c, idx); bookTreeModel.insertNodeInto(newSentence, c, idx);
@@ -3585,4 +3774,127 @@ public class AudiobookRecorder extends JFrame {
System.err.println("Effects Enabled: " + b); System.err.println("Effects Enabled: " + b);
} }
public void setBookNotes(String text) {
bookNotesArea.setText(text);
}
public void setChapterNotes(String text) {
chapterNotesArea.setText(text);
}
public void setSentenceNotes(String text) {
sentenceNotesArea.setText(text);
}
public String getBookNotes() {
return bookNotesArea.getText();
}
public String getChapterNotes() {
return chapterNotesArea.getText();
}
public String getSentenceNotes() {
return sentenceNotesArea.getText();
}
public void openManuscript() {
if (book == null) return;
File ms = book.getManuscript();
if (ms == null) return;
try {
Desktop.getDesktop().open(ms);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void loadManuscript() {
if (book == null) return;
JFileChooser jc = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("Document Files", "doc", "docx", "pdf", "odt");
jc.addChoosableFileFilter(filter);
jc.setFileFilter(filter);
jc.setDialogTitle("Select manuscript");
int r = jc.showOpenDialog(this);
if (r == JFileChooser.APPROVE_OPTION) {
File src = jc.getSelectedFile();
if (src.exists()) {
book.setManuscript(src);
}
}
}
//* DocumentListener
public void changedUpdate(DocumentEvent e) {
javax.swing.text.Document doc = e.getDocument();
if (doc == chapterNotesArea.getDocument()) {
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
if (selectedNode instanceof Sentence) {
selectedNode = (DefaultMutableTreeNode)selectedNode.getParent();
}
if (! (selectedNode instanceof Chapter)) {
return;
}
Chapter c = (Chapter)selectedNode;
c.setNotes(chapterNotesArea.getText());
} else if (doc == sentenceNotesArea.getDocument()) {
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
if (! (selectedNode instanceof Sentence)) {
return;
}
Sentence s = (Sentence)selectedNode;
s.setNotes(sentenceNotesArea.getText());
}
}
public void removeUpdate(DocumentEvent e) {
javax.swing.text.Document doc = e.getDocument();
if (doc == chapterNotesArea.getDocument()) {
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
if (selectedNode instanceof Sentence) {
selectedNode = (DefaultMutableTreeNode)selectedNode.getParent();
}
if (! (selectedNode instanceof Chapter)) {
return;
}
Chapter c = (Chapter)selectedNode;
c.setNotes(chapterNotesArea.getText());
} else if (doc == sentenceNotesArea.getDocument()) {
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
if (! (selectedNode instanceof Sentence)) {
return;
}
Sentence s = (Sentence)selectedNode;
s.setNotes(sentenceNotesArea.getText());
}
}
public void insertUpdate(DocumentEvent e) {
javax.swing.text.Document doc = e.getDocument();
if (doc == chapterNotesArea.getDocument()) {
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
if (selectedNode instanceof Sentence) {
selectedNode = (DefaultMutableTreeNode)selectedNode.getParent();
}
if (! (selectedNode instanceof Chapter)) {
return;
}
Chapter c = (Chapter)selectedNode;
c.setNotes(chapterNotesArea.getText());
} else if (doc == sentenceNotesArea.getDocument()) {
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
if (! (selectedNode instanceof Sentence)) {
return;
}
Sentence s = (Sentence)selectedNode;
s.setNotes(sentenceNotesArea.getText());
}
}
// DocumentListener *//
} }

View File

@@ -31,6 +31,7 @@ public class Book extends DefaultMutableTreeNode {
String genre; String genre;
String comment; String comment;
String ACX; String ACX;
String manuscript;
String defaultEffect = "none"; String defaultEffect = "none";
@@ -63,6 +64,9 @@ public class Book extends DefaultMutableTreeNode {
genre = getTextNode(root, "genre"); genre = getTextNode(root, "genre");
comment = getTextNode(root, "comment"); comment = getTextNode(root, "comment");
ACX = getTextNode(root, "acx"); ACX = getTextNode(root, "acx");
manuscript = getTextNode(root, "manuscript");
AudiobookRecorder.window.setBookNotes(getTextNode(root, "notes"));
Element settings = getNode(root, "settings"); Element settings = getNode(root, "settings");
Element audioSettings = getNode(settings, "audio"); Element audioSettings = getNode(settings, "audio");
@@ -95,8 +99,12 @@ public class Book extends DefaultMutableTreeNode {
} }
public static String getTextNode(Element r, String n) { public static String getTextNode(Element r, String n) {
return getTextNode(r, n, "");
}
public static String getTextNode(Element r, String n, String d) {
Element node = getNode(r, n); Element node = getNode(r, n);
if (node == null) return ""; if (node == null) return d;
return node.getTextContent(); return node.getTextContent();
} }
@@ -181,8 +189,12 @@ public class Book extends DefaultMutableTreeNode {
} }
} }
public File getBookPath() {
return new File(Options.get("path.storage"), name);
}
public void renameBook(String newName) { public void renameBook(String newName) {
File oldDir = new File(Options.get("path.storage"), name); File oldDir = getBookPath();
File newDir = new File(Options.get("path.storage"), newName); File newDir = new File(Options.get("path.storage"), newName);
if (newDir.exists()) { if (newDir.exists()) {
@@ -296,6 +308,9 @@ public class Book extends DefaultMutableTreeNode {
root.appendChild(makeTextNode(doc, "comment", comment)); root.appendChild(makeTextNode(doc, "comment", comment));
root.appendChild(makeTextNode(doc, "genre", genre)); root.appendChild(makeTextNode(doc, "genre", genre));
root.appendChild(makeTextNode(doc, "acx", ACX)); root.appendChild(makeTextNode(doc, "acx", ACX));
root.appendChild(makeTextNode(doc, "manuscript", manuscript));
root.appendChild(makeTextNode(doc, "notes", AudiobookRecorder.window.getBookNotes()));
Element settingsNode = doc.createElement("settings"); Element settingsNode = doc.createElement("settings");
root.appendChild(settingsNode); root.appendChild(settingsNode);
@@ -329,7 +344,7 @@ public class Book extends DefaultMutableTreeNode {
public static Element makeTextNode(Document doc, String name, String text) { public static Element makeTextNode(Document doc, String name, String text) {
Element node = doc.createElement(name); Element node = doc.createElement(name);
Text tnode = doc.createTextNode(text); Text tnode = doc.createTextNode(text == null ? "" : text);
node.appendChild(tnode); node.appendChild(tnode);
return node; return node;
} }
@@ -363,4 +378,24 @@ public class Book extends DefaultMutableTreeNode {
defaultEffect = eff; defaultEffect = eff;
} }
public void setManuscript(File f) {
manuscript = f.getName();
File dst = new File(getBookPath(), manuscript);
try {
Files.copy(f.toPath(), dst.toPath());
} catch (Exception ex) {
ex.printStackTrace();
}
}
public File getManuscript() {
if (manuscript == null) return null;
if (manuscript.equals("")) return null;
File f = new File(getBookPath(), manuscript);
if (f.exists()) {
return f;
}
return null;
}
} }

View File

@@ -0,0 +1,20 @@
package uk.co.majenko.audiobookrecorder;
import javax.swing.tree.DefaultMutableTreeNode;
public abstract class BookTreeNode extends DefaultMutableTreeNode {
public BookTreeNode(String t) {
super(t);
}
public BookTreeNode() {
super("");
}
public abstract void setNotes(String t);
public abstract String getNotes();
public abstract void onSelect();
}

View File

@@ -9,24 +9,32 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer {
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
JLabel ret = (JLabel) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); JLabel ret = (JLabel) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
ret.setIconTextGap(0); ret.setIconTextGap(5);
ret.setBorder(new EmptyBorder(0, 0, 0, 0)); ret.setBorder(new EmptyBorder(0, 0, 0, 0));
if (value instanceof Sentence) { if (value instanceof Sentence) {
Sentence s = (Sentence)value; Sentence s = (Sentence)value;
JPanel p = new JPanel();
p.setLayout(new GridBagLayout());
GridBagConstraints ctx = new GridBagConstraints();
OverlayIcon icn = new OverlayIcon(Icons.sentence); OverlayIcon icn = new OverlayIcon(Icons.sentence);
if (s.getOverrideText() != null) { if (s.getOverrideText() != null) {
ret.setText(s.getOverrideText()); ret.setText(s.getOverrideText());
} }
if (!s.isProcessed()) {
ret.setForeground(new Color(0x88, 0x88, 0x88));
}
if (s.getAttentionFlag()) { if (s.getAttentionFlag()) {
ret.setForeground(new Color(0xFF, 0xFF, 0x00)); ret.setForeground(new Color(0xFF, 0xFF, 0x00));
icn.add(Overlays.attention, OverlayIcon.TOP_LEFT); icn.add(Overlays.attention, OverlayIcon.TOP_LEFT);
} }
if (s.isLocked()) { if (s.isLocked()) {
ret.setForeground(new Color(0x00, 0x80, 0xFF)); ret.setForeground(new Color(0x30, 0xb0, 0xFF));
icn.add(Overlays.locked, OverlayIcon.BOTTOM_LEFT); icn.add(Overlays.locked, OverlayIcon.BOTTOM_LEFT);
} }
@@ -59,17 +67,72 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer {
} }
if (gaptype.equals("sentence")) { if (gaptype.equals("sentence")) {
ret.setBorder(new EmptyBorder(0, 0, 0, 0)); p.setBorder(new EmptyBorder(0, 0, 0, 0));
} else if (gaptype.equals("continuation")) { } else if (gaptype.equals("continuation")) {
ret.setBorder(new EmptyBorder(0, 0, 0, 0)); p.setBorder(new EmptyBorder(0, 0, 0, 0));
} else if (gaptype.equals("paragraph")) { } else if (gaptype.equals("paragraph")) {
ret.setBorder(new EmptyBorder(0, 0, 7, 0)); p.setBorder(new EmptyBorder(0, 0, 7, 0));
} else if (gaptype.equals("section")) { } else if (gaptype.equals("section")) {
ret.setBorder(new EmptyBorder(0, 0, 15, 0)); p.setBorder(new EmptyBorder(0, 0, 15, 0));
} }
JLabel time = new JLabel(Utils.secToTime(s.getLength(), "mm:ss.SSS") + " ");
ctx.gridx = 0;
ctx.gridy = 0;
ctx.fill = GridBagConstraints.HORIZONTAL;
ctx.anchor = GridBagConstraints.LINE_START;
String effectChain = s.getEffectChain();
if ((effectChain == null) || (effectChain.equals("none"))) {
ctx.weightx = 1.0d;
ctx.gridwidth = 2;
p.add(ret, ctx);
} else {
ctx.weightx = 0.1d;
ctx.gridwidth = 1;
p.add(ret, ctx);
Effect e = AudiobookRecorder.window.effects.get(effectChain);
JLabel eff = new JLabel(e.toString() + " ");
ctx.weightx = 0.0d;
ctx.gridwidth = 1;
ctx.gridx = 1;
p.add(eff);
}
ctx.weightx = 0.0d;
ctx.gridx = 2;
ctx.anchor = GridBagConstraints.LINE_END;
p.add(time, ctx);
p.setOpaque(false);
return p;
} else if (value instanceof Chapter) { } else if (value instanceof Chapter) {
Chapter c = (Chapter)value;
ret.setIcon(Icons.chapter); ret.setIcon(Icons.chapter);
JPanel p = new JPanel();
p.setLayout(new GridBagLayout());
GridBagConstraints ctx = new GridBagConstraints();
JLabel time = new JLabel(Utils.secToTime(c.getLength(), "mm:ss") + " ");
ctx.gridx = 0;
ctx.gridy = 0;
ctx.fill = GridBagConstraints.HORIZONTAL;
ctx.anchor = GridBagConstraints.LINE_START;
ctx.weightx = 1.0d;
p.add(ret, ctx);
ctx.weightx = 0.0d;
ctx.gridx = 1;
ctx.anchor = GridBagConstraints.LINE_END;
p.add(time, ctx);
p.setOpaque(false);
return p;
} else if (value instanceof Book) { } else if (value instanceof Book) {
ret.setIcon(((Book)value).getIcon()); ret.setIcon(((Book)value).getIcon());
} }

View File

@@ -26,7 +26,7 @@ import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import org.w3c.dom.Text; import org.w3c.dom.Text;
public class Chapter extends DefaultMutableTreeNode { public class Chapter extends BookTreeNode {
String name; String name;
String id; String id;
@@ -34,6 +34,8 @@ public class Chapter extends DefaultMutableTreeNode {
int preGap; int preGap;
int postGap; int postGap;
String notes;
public Chapter(String i, String chaptername) { public Chapter(String i, String chaptername) {
super(chaptername); super(chaptername);
@@ -46,9 +48,12 @@ public class Chapter extends DefaultMutableTreeNode {
public Chapter(Element root, DefaultTreeModel model) { public Chapter(Element root, DefaultTreeModel model) {
name = Book.getTextNode(root, "name"); name = Book.getTextNode(root, "name");
id = root.getAttribute("id");
preGap = Utils.s2i(Book.getTextNode(root, "pre-gap")); preGap = Utils.s2i(Book.getTextNode(root, "pre-gap"));
postGap = Utils.s2i(Book.getTextNode(root, "post-gap")); postGap = Utils.s2i(Book.getTextNode(root, "post-gap"));
notes = Book.getTextNode(root, "notes");
Element sentencesNode = Book.getNode(root, "sentences"); Element sentencesNode = Book.getNode(root, "sentences");
NodeList sentences = sentencesNode.getElementsByTagName("sentence"); NodeList sentences = sentencesNode.getElementsByTagName("sentence");
@@ -283,6 +288,7 @@ public class Chapter extends DefaultMutableTreeNode {
chapterNode.appendChild(Book.makeTextNode(doc, "name", name)); chapterNode.appendChild(Book.makeTextNode(doc, "name", name));
chapterNode.appendChild(Book.makeTextNode(doc, "pre-gap", preGap)); chapterNode.appendChild(Book.makeTextNode(doc, "pre-gap", preGap));
chapterNode.appendChild(Book.makeTextNode(doc, "post-gap", postGap)); chapterNode.appendChild(Book.makeTextNode(doc, "post-gap", postGap));
chapterNode.appendChild(Book.makeTextNode(doc, "notes", notes));
Element sentencesNode = doc.createElement("sentences"); Element sentencesNode = doc.createElement("sentences");
chapterNode.appendChild(sentencesNode); chapterNode.appendChild(sentencesNode);
@@ -298,4 +304,28 @@ public class Chapter extends DefaultMutableTreeNode {
return chapterNode; return chapterNode;
} }
public String getNotes() {
return notes;
}
public void setNotes(String t) {
notes = t;
}
public void onSelect() {
AudiobookRecorder.window.setChapterNotes(notes);
}
public double getLength() {
double len = 0;
for (Enumeration o = children(); o.hasMoreElements();) {
Object ob = (Object)o.nextElement();
if (ob instanceof Sentence) {
Sentence s = (Sentence)ob;
len += s.getLength();
}
}
return len;
}
} }

View File

@@ -38,4 +38,5 @@ public class Icons {
static public final ImageIcon docut = new ImageIcon(Icons.class.getResource("icons/do-cut.png")); static public final ImageIcon docut = new ImageIcon(Icons.class.getResource("icons/do-cut.png"));
static public final ImageIcon playto = new ImageIcon(Icons.class.getResource("icons/play-to.png")); static public final ImageIcon playto = new ImageIcon(Icons.class.getResource("icons/play-to.png"));
static public final ImageIcon disable = new ImageIcon(Icons.class.getResource("icons/disable-effects.png")); 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"));
} }

View File

@@ -17,6 +17,7 @@ public class MainToolBar extends JToolBar {
JButtonSpacePlay playtoSentence; JButtonSpacePlay playtoSentence;
JButtonSpacePlay stopPlaying; JButtonSpacePlay stopPlaying;
JButtonSpacePlay eq; JButtonSpacePlay eq;
JButtonSpacePlay openManuscript;
JToggleButtonSpacePlay mic; JToggleButtonSpacePlay mic;
JComboBox<String> playbackSpeed; JComboBox<String> playbackSpeed;
@@ -171,6 +172,15 @@ public class MainToolBar extends JToolBar {
playbackSpeed.setSelectedIndex(1); playbackSpeed.setSelectedIndex(1);
add(playbackSpeed); add(playbackSpeed);
addSeparator();
openManuscript = new JButtonSpacePlay(Icons.manuscript, "Open Manuscript", new ActionListener() {
public void actionPerformed(ActionEvent e) {
root.openManuscript();
}
});
add(openManuscript);
setFloatable(false); setFloatable(false);
} }

View File

@@ -34,6 +34,7 @@ public class Options extends JDialog {
JSpinner shortSentenceGap; JSpinner shortSentenceGap;
JSpinner postParagraphGap; JSpinner postParagraphGap;
JSpinner postSectionGap; JSpinner postSectionGap;
JSpinner maxGainVariance;
JTextField ffmpegLocation; JTextField ffmpegLocation;
JComboBox<KVPair> bitRate; JComboBox<KVPair> bitRate;
JComboBox<KVPair> channels; JComboBox<KVPair> channels;
@@ -301,6 +302,7 @@ public class Options extends JDialog {
trimMethod = addDropdown(optionsPanel, "Auto-trim method:", getTrimMethods(), get("audio.recording.trim")); trimMethod = addDropdown(optionsPanel, "Auto-trim method:", getTrimMethods(), get("audio.recording.trim"));
fftThreshold = addSpinner(optionsPanel, "FFT threshold:", 0, 100, 1, getInteger("audio.recording.trim.fft"), ""); fftThreshold = addSpinner(optionsPanel, "FFT threshold:", 0, 100, 1, getInteger("audio.recording.trim.fft"), "");
fftBlockSize = addDropdown(optionsPanel, "FFT Block size:", getFFTBlockSizes(), get("audio.recording.trim.blocksize")); fftBlockSize = addDropdown(optionsPanel, "FFT Block size:", getFFTBlockSizes(), get("audio.recording.trim.blocksize"));
maxGainVariance = addSpinner(optionsPanel, "Maximum gain variance:", 0, 100, 1, getInteger("audio.recording.variance"), "");
addSeparator(optionsPanel); addSeparator(optionsPanel);
@@ -582,6 +584,7 @@ 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("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());
@@ -718,6 +721,7 @@ 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.trim.blocksize", ((KVPair)fftBlockSize.getSelectedItem()).key); set("audio.recording.trim.blocksize", ((KVPair)fftBlockSize.getSelectedItem()).key);
set("audio.playback.blocksize", ((KVPair)playbackBlockSize.getSelectedItem()).key); set("audio.playback.blocksize", ((KVPair)playbackBlockSize.getSelectedItem()).key);

View File

@@ -41,10 +41,11 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Text; import org.w3c.dom.Text;
public class Sentence extends DefaultMutableTreeNode implements Cacheable { public class Sentence extends BookTreeNode implements Cacheable {
String text; String text;
String id; String id;
String notes;
int postGap; int postGap;
int startOffset = 0; int startOffset = 0;
int endOffset = 0; int endOffset = 0;
@@ -60,6 +61,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
boolean inSample; boolean inSample;
boolean attention = false; boolean attention = false;
boolean processed = false;
String effectChain = null; String effectChain = null;
@@ -76,7 +78,8 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
TargetDataLine line; TargetDataLine line;
AudioInputStream inputStream; AudioInputStream inputStream;
AudioFormat storedFormat = null; AudioFormat storedFormat = null;
double storedLength = -1d;
double runtime = -1d;
double[][] audioData = null; double[][] audioData = null;
@@ -86,20 +89,26 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
boolean effectEthereal = false; boolean effectEthereal = false;
public void setSampleSize(int s) {
sampleSize = s;
}
static class RecordingThread implements Runnable { static class RecordingThread implements Runnable {
boolean running = false; boolean running = false;
boolean recording = false; boolean recording = false;
Sentence sent = null;
File tempFile; File tempFile;
File wavFile; File wavFile;
AudioFormat format; AudioFormat format;
public RecordingThread(File tf, File wf, AudioFormat af) { public RecordingThread(File tf, File wf, AudioFormat af, Sentence s) {
tempFile = tf; tempFile = tf;
wavFile = wf; wavFile = wf;
format = af; format = af;
sent = s;
} }
public void run() { public void run() {
@@ -121,6 +130,8 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
fos.write(buf, 0, nr); fos.write(buf, 0, nr);
fos.close(); fos.close();
sent.setSampleSize(len / format.getFrameSize());
FileInputStream fis = new FileInputStream(tempFile); FileInputStream fis = new FileInputStream(tempFile);
AudioInputStream ais = new AudioInputStream(fis, format, len / format.getFrameSize()); AudioInputStream ais = new AudioInputStream(fis, format, len / format.getFrameSize());
fos = new FileOutputStream(wavFile); fos = new FileOutputStream(wavFile);
@@ -170,16 +181,28 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
super(""); super("");
id = root.getAttribute("id"); id = root.getAttribute("id");
text = Book.getTextNode(root, "text"); text = Book.getTextNode(root, "text");
notes = Book.getTextNode(root, "notes");
setUserObject(text); setUserObject(text);
setPostGap(Utils.s2i(Book.getTextNode(root, "post-gap"))); setPostGap(Utils.s2i(Book.getTextNode(root, "post-gap")));
setStartOffset(Utils.s2i(Book.getTextNode(root, "start-offset"))); setStartOffset(Utils.s2i(Book.getTextNode(root, "start-offset")));
setEndOffset(Utils.s2i(Book.getTextNode(root, "end-offset"))); setEndOffset(Utils.s2i(Book.getTextNode(root, "end-offset")));
crossStartOffset = Utils.s2i(Book.getTextNode(root, "cross-start-offset", "-1"));
crossEndOffset = Utils.s2i(Book.getTextNode(root, "end-offset", "-1"));
setLocked(Utils.s2b(Book.getTextNode(root, "locked"))); setLocked(Utils.s2b(Book.getTextNode(root, "locked")));
setAttentionFlag(Utils.s2b(Book.getTextNode(root, "attention"))); setAttentionFlag(Utils.s2b(Book.getTextNode(root, "attention")));
setGain(Utils.s2d(Book.getTextNode(root, "gain"))); setGain(Utils.s2d(Book.getTextNode(root, "gain")));
setEffectChain(Book.getTextNode(root, "effect")); setEffectChain(Book.getTextNode(root, "effect"));
setPostGapType(Book.getTextNode(root, "gaptype")); setPostGapType(Book.getTextNode(root, "gaptype"));
sampleSize = Utils.s2i(Book.getTextNode(root, "samples")); sampleSize = Utils.s2i(Book.getTextNode(root, "samples"));
processed = Utils.s2b(Book.getTextNode(root, "processed"));
runtime = Utils.s2d(Book.getTextNode(root, "time", "-1.000"));
if ((crossStartOffset == -1) || (crossEndOffset == -1)) {
System.err.println("Updating " + id);
updateCrossings(true);
}
if (runtime <= 0.01d) getLength();
} }
public boolean startRecording() { public boolean startRecording() {
@@ -190,7 +213,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
CacheManager.removeFromCache(this); CacheManager.removeFromCache(this);
recordingThread = new RecordingThread(getTempFile(), getFile(), Options.getAudioFormat()); recordingThread = new RecordingThread(getTempFile(), getFile(), Options.getAudioFormat(), this);
Thread rc = new Thread(recordingThread); Thread rc = new Thread(recordingThread);
rc.setDaemon(true); rc.setDaemon(true);
@@ -230,6 +253,12 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
autoTrimSamplePeak(useRaw); autoTrimSamplePeak(useRaw);
} else if (tm.equals("fft")) { } else if (tm.equals("fft")) {
autoTrimSampleFFT(useRaw); autoTrimSampleFFT(useRaw);
} else {
startOffset = 0;
crossStartOffset = 0;
endOffset = sampleSize - 1;
crossEndOffset = sampleSize - 1;
processed = false;
} }
} }
@@ -331,7 +360,8 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
updateCrossings(useRaw); updateCrossings(useRaw);
intens = null; intens = null;
samples = null; samples = null;
processed = true;
reloadTree();
} }
public void autoTrimSamplePeak() { public void autoTrimSamplePeak() {
@@ -387,6 +417,8 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
if (startOffset < 0) startOffset = 0; if (startOffset < 0) startOffset = 0;
if (endOffset >= samples.length) endOffset = samples.length-1; if (endOffset >= samples.length) endOffset = samples.length-1;
updateCrossings(useRaw); updateCrossings(useRaw);
processed = true;
reloadTree();
} }
public String getId() { public String getId() {
@@ -396,6 +428,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
public void setText(String t) { public void setText(String t) {
overrideText = null; overrideText = null;
text = t; text = t;
reloadTree();
} }
public String getText() { public String getText() {
@@ -428,11 +461,14 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
} }
public String toString() { public String toString() {
return text;
/*
if (effectChain == null) return text; if (effectChain == null) return text;
if (effectChain.equals("none")) return text; if (effectChain.equals("none")) return text;
Effect e = AudiobookRecorder.window.effects.get(effectChain); Effect e = AudiobookRecorder.window.effects.get(effectChain);
if (e == null) return text; if (e == null) return text;
return text + " (" + e.toString() + ")"; return text + " (" + e.toString() + ")";
*/
} }
public boolean isRecording() { public boolean isRecording() {
@@ -443,6 +479,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
if (o instanceof String) { if (o instanceof String) {
String so = (String)o; String so = (String)o;
text = so; text = so;
reloadTree();
} }
} }
@@ -476,6 +513,8 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
public void updateCrossings(boolean useRaw) { public void updateCrossings(boolean useRaw) {
updateStartCrossing(useRaw); updateStartCrossing(useRaw);
updateEndCrossing(useRaw); updateEndCrossing(useRaw);
runtime = -1d;
getLength();
} }
public void updateStartCrossing() { public void updateStartCrossing() {
@@ -502,6 +541,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
if (startOffset != o) { if (startOffset != o) {
startOffset = o; startOffset = o;
crossStartOffset = -1; crossStartOffset = -1;
reloadTree();
} }
} }
@@ -517,9 +557,18 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
if (endOffset != o) { if (endOffset != o) {
endOffset = o; endOffset = o;
crossEndOffset = -1; crossEndOffset = -1;
reloadTree();
} }
} }
public void setStartCrossing(int o) {
crossStartOffset = o;
}
public void setEndCrossing(int o) {
crossEndOffset = o;
}
public int getSampleSize() { public int getSampleSize() {
if (sampleSize == -1) { if (sampleSize == -1) {
loadFile(); loadFile();
@@ -545,7 +594,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
public void doRecognition(StreamSpeechRecognizer recognizer) { public void doRecognition(StreamSpeechRecognizer recognizer) {
try { try {
setText("[recognising...]"); setText("[recognising...]");
AudiobookRecorder.window.bookTreeModel.reload(this); reloadTree();
byte[] inData = getPCMData(); byte[] inData = getPCMData();
@@ -560,7 +609,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
recognizer.stopRecognition(); recognizer.stopRecognition();
setText(res); setText(res);
AudiobookRecorder.window.bookTreeModel.reload(this); reloadTree();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -596,7 +645,9 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
} }
public void setLocked(boolean l) { public void setLocked(boolean l) {
if (locked == l) return;
locked = l; locked = l;
reloadTree();
} }
public boolean isLocked() { public boolean isLocked() {
@@ -615,7 +666,6 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
audioData = null; audioData = null;
processedAudio = null; processedAudio = null;
storedFormat = null; storedFormat = null;
storedLength = -1;
} }
public boolean lockedInCache() { public boolean lockedInCache() {
@@ -671,13 +721,16 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
/* Get the length of the sample in seconds */ /* Get the length of the sample in seconds */
public double getLength() { public double getLength() {
if (storedLength > -1d) return storedLength; if (runtime > 0.01d) return runtime;
File f = getFile();
if (!f.exists()) { // Not recorded yet!
return 0;
}
AudioFormat format = getAudioFormat(); AudioFormat format = getAudioFormat();
float sampleFrequency = format.getFrameRate(); float sampleFrequency = format.getFrameRate();
int length = crossEndOffset - crossStartOffset; int length = crossEndOffset - crossStartOffset;
double time = (double)length / (double)sampleFrequency; runtime = (double)length / (double)sampleFrequency;
storedLength = time; return runtime;
return time;
} }
public Sentence cloneSentence() throws IOException { public Sentence cloneSentence() throws IOException {
@@ -688,17 +741,21 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
} }
sentence.setStartOffset(getStartOffset()); sentence.setStartOffset(getStartOffset());
sentence.setEndOffset(getEndOffset()); sentence.setEndOffset(getEndOffset());
sentence.setStartCrossing(getStartCrossing());
sentence.setEndCrossing(getEndCrossing());
File from = getFile(); File from = getFile();
File to = sentence.getFile(); File to = sentence.getFile();
Files.copy(from.toPath(), to.toPath()); Files.copy(from.toPath(), to.toPath());
sentence.updateCrossings(); // sentence.updateCrossings();
return sentence; return sentence;
} }
public void setAttentionFlag(boolean f) { public void setAttentionFlag(boolean f) {
if (attention == f) return;
attention = f; attention = f;
reloadTree();
} }
public boolean getAttentionFlag() { public boolean getAttentionFlag() {
@@ -760,12 +817,24 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
return gain; return gain;
} }
public void normalize() { public double normalize(double low, double high) {
if (locked) return; if (locked) return gain;
double max = getPeakValue(true, false);
double d = 0.708 / max;
if (d > 1d) d = 1d;
if (d < low) d = low;
if (d > high) d = high;
setGain(d);
return d;
}
public double normalize() {
if (locked) return gain;
double max = getPeakValue(true, false); double max = getPeakValue(true, false);
double d = 0.708 / max; double d = 0.708 / max;
if (d > 1d) d = 1d; if (d > 1d) d = 1d;
setGain(d); setGain(d);
return d;
} }
class ExternalEditor implements Runnable { class ExternalEditor implements Runnable {
@@ -1294,10 +1363,14 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
} }
public void setEffectChain(String key) { public void setEffectChain(String key) {
if ((effectChain != null) && (effectChain.equals(key))) {
return;
}
if ((effectChain != null) && (!effectChain.equals(key))) { if ((effectChain != null) && (!effectChain.equals(key))) {
CacheManager.removeFromCache(this); CacheManager.removeFromCache(this);
} }
effectChain = key; effectChain = key;
reloadTree();
} }
public String getEffectChain() { public String getEffectChain() {
@@ -1324,6 +1397,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
} }
} }
postGapType = t; postGapType = t;
reloadTree();
} }
public void resetPostGap() { public void resetPostGap() {
@@ -1385,13 +1459,45 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
sentenceNode.appendChild(Book.makeTextNode(doc, "post-gap", getPostGap())); sentenceNode.appendChild(Book.makeTextNode(doc, "post-gap", getPostGap()));
sentenceNode.appendChild(Book.makeTextNode(doc, "start-offset", getStartOffset())); sentenceNode.appendChild(Book.makeTextNode(doc, "start-offset", getStartOffset()));
sentenceNode.appendChild(Book.makeTextNode(doc, "end-offset", getEndOffset())); sentenceNode.appendChild(Book.makeTextNode(doc, "end-offset", getEndOffset()));
sentenceNode.appendChild(Book.makeTextNode(doc, "cross-start-offset", crossStartOffset));
sentenceNode.appendChild(Book.makeTextNode(doc, "cross-end-offset", crossEndOffset));
sentenceNode.appendChild(Book.makeTextNode(doc, "locked", isLocked())); sentenceNode.appendChild(Book.makeTextNode(doc, "locked", isLocked()));
sentenceNode.appendChild(Book.makeTextNode(doc, "attention", getAttentionFlag())); sentenceNode.appendChild(Book.makeTextNode(doc, "attention", getAttentionFlag()));
sentenceNode.appendChild(Book.makeTextNode(doc, "gain", getGain())); sentenceNode.appendChild(Book.makeTextNode(doc, "gain", getGain()));
sentenceNode.appendChild(Book.makeTextNode(doc, "effect", getEffectChain())); sentenceNode.appendChild(Book.makeTextNode(doc, "effect", getEffectChain()));
sentenceNode.appendChild(Book.makeTextNode(doc, "gaptype", getPostGapType())); sentenceNode.appendChild(Book.makeTextNode(doc, "gaptype", getPostGapType()));
sentenceNode.appendChild(Book.makeTextNode(doc, "samples", getSampleSize())); sentenceNode.appendChild(Book.makeTextNode(doc, "samples", getSampleSize()));
sentenceNode.appendChild(Book.makeTextNode(doc, "processed", isProcessed()));
sentenceNode.appendChild(Book.makeTextNode(doc, "notes", getNotes()));
sentenceNode.appendChild(Book.makeTextNode(doc, "time", getLength()));
return sentenceNode; return sentenceNode;
} }
public boolean isProcessed() {
return processed;
}
public void setProcessed(boolean p) {
processed = p;
reloadTree();
}
public void setNotes(String n) {
notes = n;
}
public String getNotes() {
return notes;
}
public void onSelect() {
AudiobookRecorder.window.setSentenceNotes(notes);
}
void reloadTree() {
if (id.equals("room-noise")) return;
if (getParent() == null) return;
AudiobookRecorder.window.bookTreeModel.reload(this);
}
} }

View File

@@ -10,6 +10,8 @@ import java.util.*;
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.text.SimpleDateFormat;
public class Utils { public class Utils {
public static Image getScaledImage(Image srcImg, int w, int h){ public static Image getScaledImage(Image srcImg, int w, int h){
BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
@@ -76,4 +78,12 @@ public class Utils {
Runtime.getRuntime().freeMemory() Runtime.getRuntime().freeMemory()
)); ));
} }
public static String secToTime(double sec, String fmt) {
Date d = new Date((long)(sec * 1000d));
SimpleDateFormat df = new SimpleDateFormat(fmt);
df.setTimeZone(TimeZone.getTimeZone("GMT"));
String time = df.format(d);
return time;
}
} }