Compare commits
5 Commits
v0.0.1-3f4
...
v0.0.2-fef
| Author | SHA1 | Date | |
|---|---|---|---|
| fef1d19ddd | |||
| 08408d2ae5 | |||
| 8380128bc8 | |||
| e01bc29ef0 | |||
| 415b93931b |
@@ -34,4 +34,4 @@ Third party software
|
||||
* CMU Sphinx: https://github.com/mpatric/mp3agic
|
||||
* JAVE ffmpeg wrapper: http://www.sauronsoftware.it/projects/jave/
|
||||
* JTattoo: http://www.sauronsoftware.it/projects/jave/
|
||||
|
||||
* Icons from, or based on, Oxygen: https://github.com/KDE/oxygen-icons
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||

|
||||
|
||||
Audiobook Recorder
|
||||
==================
|
||||
|
||||
@@ -24,6 +26,7 @@ From here on much is controlled by key presses.
|
||||
|
||||
* Press and hold "R" to record a new phrase - the screen flashes red while it's recording. The phrase is
|
||||
appended to the currently selected chapter, or to the last chapter if none is selected.
|
||||
* Press and hold "T" to record a new phrase that is the start of a new paragraph. This adds the "post paragraph" gap to the previous sentence. Otherwise it does the same as "R".
|
||||
* Press "D" to delete the last phrase you recorded.
|
||||
* Press "E" to re-record the currently selected phrase.
|
||||
|
||||
|
||||
BIN
resources/uk/co/majenko/audiobookrecorder/icons/appIcon.png
Normal file
BIN
resources/uk/co/majenko/audiobookrecorder/icons/appIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
@@ -464,6 +464,9 @@ public class AudiobookRecorder extends JFrame {
|
||||
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("released D"), "deleteLast");
|
||||
|
||||
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("SPACE"), "startPlayback");
|
||||
@@ -477,6 +480,12 @@ public class AudiobookRecorder extends JFrame {
|
||||
startRecording();
|
||||
}
|
||||
});
|
||||
centralPanel.getActionMap().put("startRecordNewPara", new AbstractAction() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (bookTree.isEditing()) return;
|
||||
startRecordingNewParagraph();
|
||||
}
|
||||
});
|
||||
centralPanel.getActionMap().put("startRerecord", new AbstractAction() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (bookTree.isEditing()) return;
|
||||
@@ -512,6 +521,18 @@ public class AudiobookRecorder extends JFrame {
|
||||
|
||||
pack();
|
||||
setVisible(true);
|
||||
|
||||
String lastBook = Options.get("path.last-book");
|
||||
|
||||
if (lastBook != null && !lastBook.equals("")) {
|
||||
File f = new File(Options.get("path.storage"), lastBook);
|
||||
if (f.exists() && f.isDirectory()) {
|
||||
File x = new File(f, "audiobook.abk");
|
||||
if (x.exists()) {
|
||||
loadBookStructure(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
@@ -538,6 +559,9 @@ public class AudiobookRecorder extends JFrame {
|
||||
prefs.setProperty("book.author", info.getAuthor());
|
||||
prefs.setProperty("book.genre", info.getGenre());
|
||||
prefs.setProperty("book.comment", info.getComment());
|
||||
prefs.setProperty("chapter.audition.name", "Audition");
|
||||
prefs.setProperty("chapter.audition.pre-gap", Options.get("catenation.pre-chapter"));
|
||||
prefs.setProperty("chapter.audition.post-gap", Options.get("catenation.post-chapter"));
|
||||
prefs.setProperty("chapter.open.name", "Opening Credits");
|
||||
prefs.setProperty("chapter.open.pre-gap", Options.get("catenation.pre-chapter"));
|
||||
prefs.setProperty("chapter.open.post-gap", Options.get("catenation.post-chapter"));
|
||||
@@ -641,18 +665,22 @@ public class AudiobookRecorder extends JFrame {
|
||||
bookTree.setSelectionPath(new TreePath(c.getPath()));
|
||||
|
||||
JPopupMenu menu = new JPopupMenu();
|
||||
JMenuObject ren = new JMenuObject("Rename chapter", c);
|
||||
JMenuObject peak = new JMenuObject("Auto-trim all (Peak)", c);
|
||||
|
||||
ren.addActionListener(new ActionListener() {
|
||||
peak.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
c.renameChapter();
|
||||
bookTreeModel.reload(c);
|
||||
for (Enumeration<Sentence> s = c.children(); s.hasMoreElements();) {
|
||||
Sentence snt = s.nextElement();
|
||||
if (!snt.isLocked()) {
|
||||
snt.autoTrimSamplePeak();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
menu.add(ren);
|
||||
menu.add(peak);
|
||||
menu.show(bookTree, e.getX(), e.getY());
|
||||
}
|
||||
|
||||
@@ -687,6 +715,53 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
}
|
||||
|
||||
public void startRecordingNewParagraph() {
|
||||
|
||||
if (recording != null) return;
|
||||
if (book == null) return;
|
||||
|
||||
toolBar.disableBook();
|
||||
toolBar.disableSentence();
|
||||
|
||||
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
|
||||
|
||||
if (selectedNode == null) {
|
||||
selectedNode = book.getLastChapter();
|
||||
bookTree.setSelectionPath(new TreePath(selectedNode.getPath()));
|
||||
}
|
||||
|
||||
if (selectedNode instanceof Book) {
|
||||
selectedNode = book.getLastChapter();
|
||||
bookTree.setSelectionPath(new TreePath(selectedNode.getPath()));
|
||||
}
|
||||
|
||||
if (selectedNode instanceof Sentence) {
|
||||
selectedNode = (DefaultMutableTreeNode)selectedNode.getParent();
|
||||
bookTree.setSelectionPath(new TreePath(selectedNode.getPath()));
|
||||
}
|
||||
|
||||
Chapter c = (Chapter)selectedNode;
|
||||
|
||||
DefaultMutableTreeNode lastLeaf = c.getLastLeaf();
|
||||
|
||||
if (lastLeaf instanceof Sentence) {
|
||||
Sentence lastSentence = (Sentence)lastLeaf;
|
||||
lastSentence.setPostGap(Options.getInteger("catenation.post-paragraph"));
|
||||
}
|
||||
|
||||
Sentence s = new Sentence();
|
||||
bookTreeModel.insertNodeInto(s, c, c.getChildCount());
|
||||
|
||||
bookTree.expandPath(new TreePath(c.getPath()));
|
||||
bookTree.setSelectionPath(new TreePath(s.getPath()));
|
||||
bookTree.scrollPathToVisible(new TreePath(s.getPath()));
|
||||
|
||||
if (s.startRecording()) {
|
||||
recording = s;
|
||||
centralPanel.setFlash(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void startRecording() {
|
||||
|
||||
if (recording != null) return;
|
||||
@@ -950,7 +1025,25 @@ public class AudiobookRecorder extends JFrame {
|
||||
mainScroll.setViewportView(bookTree);
|
||||
|
||||
|
||||
Chapter c = new Chapter("open", prefs.getProperty("chapter.open.name"));
|
||||
Chapter c = new Chapter("audition", prefs.getProperty("chapter.audition.name"));
|
||||
c.setPostGap(s2i(prefs.getProperty("chapter.audition.post-gap")));
|
||||
c.setPreGap(s2i(prefs.getProperty("chapter.audition.pre-gap")));
|
||||
bookTreeModel.insertNodeInto(c, book, 0);
|
||||
|
||||
for (int i = 0; i < 100000000; i++) {
|
||||
String id = prefs.getProperty(String.format("chapter.audition.sentence.%08d.id", i));
|
||||
String text = prefs.getProperty(String.format("chapter.audition.sentence.%08d.text", i));
|
||||
int gap = s2i(prefs.getProperty(String.format("chapter.audition.sentence.%08d.post-gap", i)));
|
||||
if (id == null) break;
|
||||
Sentence s = new Sentence(id, text);
|
||||
s.setPostGap(gap);
|
||||
s.setStartOffset(s2i(prefs.getProperty(String.format("chapter.audition.sentence.%08d.start-offset", i))));
|
||||
s.setEndOffset(s2i(prefs.getProperty(String.format("chapter.audition.sentence.%08d.end-offset", i))));
|
||||
s.setLocked(s2b(prefs.getProperty(String.format("chapter.audition.sentence.%08d.locked", i))));
|
||||
bookTreeModel.insertNodeInto(s, c, c.getChildCount());
|
||||
}
|
||||
|
||||
c = new Chapter("open", prefs.getProperty("chapter.open.name"));
|
||||
c.setPostGap(s2i(prefs.getProperty("chapter.open.post-gap")));
|
||||
c.setPreGap(s2i(prefs.getProperty("chapter.open.pre-gap")));
|
||||
bookTreeModel.insertNodeInto(c, book, 0);
|
||||
@@ -968,6 +1061,8 @@ public class AudiobookRecorder extends JFrame {
|
||||
bookTreeModel.insertNodeInto(s, c, c.getChildCount());
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (int cno = 1; cno < 10000; cno++) {
|
||||
String cname = prefs.getProperty(String.format("chapter.%04d.name", cno));
|
||||
if (cname == null) break;
|
||||
@@ -1037,6 +1132,9 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
|
||||
loadBookStructure(f);
|
||||
|
||||
Options.set("path.last-book", book.getName());
|
||||
Options.savePreferences();
|
||||
|
||||
}
|
||||
|
||||
@@ -1233,6 +1331,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
|
||||
tags.setTrack(Integer.toString(s2i(c.getId()) - 0));
|
||||
tags.setTitle(c.getName());
|
||||
tags.setAlbum(book.getName());
|
||||
tags.setArtist(book.getAuthor());
|
||||
|
||||
// ID3v2TextFrameData g = new ID3v2TextFrameData(false, new EncodedText(book.getGenre()));
|
||||
@@ -1310,7 +1409,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
bookTree.setSelectionPath(new TreePath(s.getPath()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
playing = null;
|
||||
}
|
||||
toolBar.enableSentence();
|
||||
|
||||
@@ -37,13 +37,6 @@ public class Chapter extends DefaultMutableTreeNode {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void renameChapter() {
|
||||
String n = JOptionPane.showInputDialog(null, "Rename Chapter", name);
|
||||
if (n != null) {
|
||||
name = n;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ public class Options extends JDialog {
|
||||
JSpinner preChapterGap;
|
||||
JSpinner postChapterGap;
|
||||
JSpinner postSentenceGap;
|
||||
JSpinner postParagraphGap;
|
||||
JTextField ffmpegLocation;
|
||||
JComboBox<KVPair> bitRate;
|
||||
JComboBox<KVPair> exportRate;
|
||||
@@ -190,6 +191,7 @@ public class Options extends JDialog {
|
||||
preChapterGap = addSpinner("Default pre-chapter gap:", 0, 5000, 100, getInteger("catenation.pre-chapter"), "ms");
|
||||
postChapterGap = addSpinner("Default post-chapter gap:", 0, 5000, 100, getInteger("catenation.post-chapter"), "ms");
|
||||
postSentenceGap = addSpinner("Default post-sentence gap:", 0, 5000, 100, getInteger("catenation.post-sentence"), "ms");
|
||||
postParagraphGap = addSpinner("Default post-paragraph gap:", 0, 5000, 100, getInteger("catenation.post-paragraph"), "ms");
|
||||
|
||||
addSeparator();
|
||||
|
||||
@@ -277,7 +279,7 @@ public class Options extends JDialog {
|
||||
}
|
||||
|
||||
if (supported) {
|
||||
KVPair p = new KVPair(i.getName(), i.getDescription());
|
||||
KVPair p = new KVPair(i.getName(), i.getName()); //i.getDescription());
|
||||
list.add(p);
|
||||
}
|
||||
}
|
||||
@@ -316,7 +318,7 @@ public class Options extends JDialog {
|
||||
|
||||
|
||||
if (supported) {
|
||||
KVPair p = new KVPair(i.getName(), i.getDescription());
|
||||
KVPair p = new KVPair(i.getName(), i.getName()); //i.getDescription());
|
||||
list.add(p);
|
||||
}
|
||||
}
|
||||
@@ -361,6 +363,7 @@ public class Options extends JDialog {
|
||||
defaultPrefs.put("catenation.pre-chapter", "2000");
|
||||
defaultPrefs.put("catenation.post-chapter", "2000");
|
||||
defaultPrefs.put("catenation.post-sentence", "1000");
|
||||
defaultPrefs.put("catenation.post-paragraph", "2000");
|
||||
|
||||
defaultPrefs.put("path.storage", (new File(System.getProperty("user.home"), "Recordings")).toString());
|
||||
defaultPrefs.put("path.ffmpeg", "");
|
||||
@@ -426,6 +429,7 @@ public class Options extends JDialog {
|
||||
set("catenation.pre-chapter", "" + preChapterGap.getValue());
|
||||
set("catenation.post-chapter", "" + postChapterGap.getValue());
|
||||
set("catenation.post-sentence", "" + postSentenceGap.getValue());
|
||||
set("catenation.post-paragraph", "" + postParagraphGap.getValue());
|
||||
set("audio.export.bitrate", ((KVPair)bitRate.getSelectedItem()).key);
|
||||
set("audio.export.samplerate", ((KVPair)exportRate.getSelectedItem()).key);
|
||||
set("process.sphinx", enableParsing.isSelected() ? "true" : "false");
|
||||
|
||||
@@ -222,6 +222,8 @@ public class Sentence extends DefaultMutableTreeNode {
|
||||
startOffset = 0;
|
||||
}
|
||||
|
||||
startOffset -= 4096;
|
||||
|
||||
for (int i = samples.length-1; i >= 0; i--) {
|
||||
endOffset = i;
|
||||
if (Math.abs(samples[i]) > noiseFloor) {
|
||||
@@ -230,10 +232,16 @@ public class Sentence extends DefaultMutableTreeNode {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
endOffset += 4096;
|
||||
|
||||
if (endOffset <= startOffset) endOffset = startOffset + 4096;
|
||||
if (endOffset <= 0) {
|
||||
endOffset = samples.length-1;
|
||||
}
|
||||
|
||||
if (startOffset < 0) startOffset = 0;
|
||||
if (endOffset >= samples.length) endOffset = samples.length-1;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
|
||||
Reference in New Issue
Block a user