Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ff08db3e44 | |||
| 7431550d61 | |||
| 448910b8d7 | |||
| 991c4fbf8e | |||
| ced0aaa597 | |||
| 498247c793 | |||
| ad5c3808cd | |||
| c658dc6a50 | |||
|
|
100adec397 | ||
|
|
f4b793574d | ||
| d8c52575fb | |||
| 1b2945d9c4 | |||
| 1244bd60ed | |||
| b566b9e89e | |||
| 4a4d7f2a38 | |||
| f7848228a2 | |||
| 8c22315b15 | |||
| 718c982578 |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.jar filter=lfs diff=lfs merge=lfs -text
|
||||
12
README.md
12
README.md
@@ -72,3 +72,15 @@ files) is placed.
|
||||
|
||||
When you export the book as MP3 a new folder "export" is created within the book's folder where the MP3 files are placed.
|
||||
MP3 files are all tagged with the book title, chapter title, chapter number and comment.
|
||||
|
||||
|
||||
Building
|
||||
========
|
||||
|
||||
1. Check out this repo
|
||||
2. Install `ant` and `default-jdk`
|
||||
3. Install [git LFS support](https://help.github.com/articles/installing-git-large-file-storage/)
|
||||
4. Pull the large files with `git lfs pull`
|
||||
5. Build with `ant build`
|
||||
6. Run with `java -jar ./AudiobookRecorder.jar`
|
||||
|
||||
|
||||
Binary file not shown.
BIN
deps/mp3agic-0.9.1.jar
vendored
BIN
deps/mp3agic-0.9.1.jar
vendored
Binary file not shown.
BIN
deps/sphinx4-core-5prealpha-SNAPSHOT.jar
vendored
BIN
deps/sphinx4-core-5prealpha-SNAPSHOT.jar
vendored
Binary file not shown.
BIN
deps/sphinx4-data-5prealpha-SNAPSHOT.jar
vendored
BIN
deps/sphinx4-data-5prealpha-SNAPSHOT.jar
vendored
Binary file not shown.
13
dist/linux/audiobookrecorder.desktop
vendored
Normal file
13
dist/linux/audiobookrecorder.desktop
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
[Desktop Entry]
|
||||
Name=AudiobookRecorder
|
||||
GenericName=Audiobook Recorder
|
||||
X-GNOME-FullName=AudiobookRecorder
|
||||
Comment=Record audiobooks with ease
|
||||
Keywords=audio
|
||||
Exec=AudiobookRecorder
|
||||
Terminal=false
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Icon=AudiobookRecorder
|
||||
Categories=AudioVideo;Audio;Recorder;
|
||||
X-AppStream-Ignore=true
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
version=0.1.0
|
||||
version=0.1.2
|
||||
|
||||
BIN
resources/uk/co/majenko/audiobookrecorder/icons/attention.png
Normal file
BIN
resources/uk/co/majenko/audiobookrecorder/icons/attention.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 952 B |
Binary file not shown.
|
Before Width: | Height: | Size: 592 B After Width: | Height: | Size: 1.2 KiB |
@@ -18,6 +18,8 @@ import edu.cmu.sphinx.decoder.adaptation.*;
|
||||
import edu.cmu.sphinx.result.*;
|
||||
import java.nio.file.Files;
|
||||
import java.util.zip.*;
|
||||
import javax.swing.filechooser.*;
|
||||
import javax.imageio.*;
|
||||
|
||||
public class AudiobookRecorder extends JFrame {
|
||||
|
||||
@@ -35,12 +37,18 @@ public class AudiobookRecorder extends JFrame {
|
||||
JMenuItem fileOpenBook;
|
||||
JMenuItem fileSave;
|
||||
JMenuItem fileExit;
|
||||
JMenuItem fileOpenArchive;
|
||||
|
||||
JMenuItem bookNewChapter;
|
||||
JMenuItem bookExportAudio;
|
||||
JMenu bookVisitACX;
|
||||
JMenuItem bookVisitTitle;
|
||||
JMenuItem bookVisitAudition;
|
||||
JMenuItem bookVisitProduce;
|
||||
|
||||
JMenuItem toolsMerge;
|
||||
JMenuItem toolsArchive;
|
||||
JMenuItem toolsCoverArt;
|
||||
JMenuItem toolsOptions;
|
||||
|
||||
JMenuItem helpAbout;
|
||||
@@ -71,6 +79,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
|
||||
JSpinner postSentenceGap;
|
||||
JCheckBox locked;
|
||||
JCheckBox attention;
|
||||
|
||||
JButtonSpacePlay reprocessAudioFFT;
|
||||
JButtonSpacePlay reprocessAudioPeak;
|
||||
@@ -87,7 +96,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
public Configuration sphinxConfig;
|
||||
public StreamSpeechRecognizer recognizer;
|
||||
|
||||
|
||||
public static AudiobookRecorder window;
|
||||
|
||||
void initSphinx() {
|
||||
@@ -106,8 +114,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
|
||||
void buildToolbar(Container ob) {
|
||||
toolBar = new MainToolBar(this);
|
||||
toolBar.disableBook();
|
||||
toolBar.disableSentence();
|
||||
ob.add(toolBar, BorderLayout.NORTH);
|
||||
}
|
||||
|
||||
@@ -137,6 +143,13 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
});
|
||||
|
||||
fileOpenArchive = new JMenuItem("Open Archive...");
|
||||
fileOpenArchive.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
openArchive();
|
||||
}
|
||||
});
|
||||
|
||||
fileExit = new JMenuItem("Exit");
|
||||
fileExit.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
@@ -149,6 +162,8 @@ public class AudiobookRecorder extends JFrame {
|
||||
fileMenu.add(fileOpenBook);
|
||||
fileMenu.add(fileSave);
|
||||
fileMenu.addSeparator();
|
||||
fileMenu.add(fileOpenArchive);
|
||||
fileMenu.addSeparator();
|
||||
fileMenu.add(fileExit);
|
||||
|
||||
menuBar.add(fileMenu);
|
||||
@@ -173,6 +188,33 @@ public class AudiobookRecorder extends JFrame {
|
||||
bookMenu.add(bookNewChapter);
|
||||
bookMenu.add(bookExportAudio);
|
||||
|
||||
bookVisitACX = new JMenu("Visit ACX");
|
||||
bookMenu.add(bookVisitACX);
|
||||
|
||||
bookVisitTitle = new JMenuItem("Title");
|
||||
bookVisitTitle.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Utils.browse("https://www.acx.com/titleview/" + book.getACX());
|
||||
}
|
||||
});
|
||||
bookVisitACX.add(bookVisitTitle);
|
||||
|
||||
bookVisitAudition = new JMenuItem("Audition");
|
||||
bookVisitAudition.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Utils.browse("https://www.acx.com/titleview/" + book.getACX() + "?bucket=AUDITION_READY");
|
||||
}
|
||||
});
|
||||
bookVisitACX.add(bookVisitAudition);
|
||||
|
||||
bookVisitProduce = new JMenuItem("Produce");
|
||||
bookVisitProduce.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Utils.browse("https://www.acx.com/titleview/" + book.getACX() + "?bucket=PRODUCE");
|
||||
}
|
||||
});
|
||||
bookVisitACX.add(bookVisitProduce);
|
||||
|
||||
menuBar.add(bookMenu);
|
||||
|
||||
toolsMenu = new JMenu("Tools");
|
||||
@@ -192,6 +234,13 @@ public class AudiobookRecorder extends JFrame {
|
||||
archiveBook();
|
||||
}
|
||||
});
|
||||
|
||||
toolsCoverArt = new JMenuItem("Import Cover Art...");
|
||||
toolsCoverArt.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
loadCoverArt();
|
||||
}
|
||||
});
|
||||
|
||||
toolsOptions = new JMenuItem("Options");
|
||||
toolsOptions.addActionListener(new ActionListener() {
|
||||
@@ -202,6 +251,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
|
||||
toolsMenu.add(toolsMerge);
|
||||
toolsMenu.add(toolsArchive);
|
||||
toolsMenu.add(toolsCoverArt);
|
||||
toolsMenu.addSeparator();
|
||||
toolsMenu.add(toolsOptions);
|
||||
|
||||
@@ -384,9 +434,29 @@ public class AudiobookRecorder extends JFrame {
|
||||
bookTreeModel.reload(selectedSentence);
|
||||
}
|
||||
});
|
||||
|
||||
controlsTop.add(locked);
|
||||
|
||||
attention = new JCheckBox("Flag for attention");
|
||||
attention.setFocusable(false);
|
||||
|
||||
attention.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JCheckBox c = (JCheckBox)e.getSource();
|
||||
if (c.isSelected()) {
|
||||
if (selectedSentence != null) {
|
||||
selectedSentence.setAttentionFlag(true);
|
||||
}
|
||||
} else {
|
||||
if (selectedSentence != null) {
|
||||
selectedSentence.setAttentionFlag(false);
|
||||
}
|
||||
}
|
||||
bookTreeModel.reload(selectedSentence);
|
||||
}
|
||||
});
|
||||
|
||||
controlsTop.add(attention);
|
||||
|
||||
controlsTop.add(Box.createHorizontalGlue());
|
||||
controlsTop.add(new JLabel("Post gap:"));
|
||||
controlsTop.add(postSentenceGap);
|
||||
@@ -550,7 +620,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
|
||||
public void createNewBook() {
|
||||
BookInfoPanel info = new BookInfoPanel("", "", "", "");
|
||||
BookInfoPanel info = new BookInfoPanel("", "", "", "", "");
|
||||
int r = JOptionPane.showConfirmDialog(this, info, "New Book", JOptionPane.OK_CANCEL_OPTION);
|
||||
if (r != JOptionPane.OK_OPTION) return;
|
||||
|
||||
@@ -569,6 +639,7 @@ 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("book.acx", info.getACX());
|
||||
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"));
|
||||
@@ -595,9 +666,10 @@ public class AudiobookRecorder extends JFrame {
|
||||
ob = null;
|
||||
}
|
||||
|
||||
public JMenuObject(String p, Object o) {
|
||||
public JMenuObject(String p, Object o, ActionListener l) {
|
||||
super(p);
|
||||
ob = o;
|
||||
addActionListener(l);
|
||||
}
|
||||
|
||||
public void setObject(Object o) {
|
||||
@@ -619,10 +691,11 @@ public class AudiobookRecorder extends JFrame {
|
||||
ob2 = null;
|
||||
}
|
||||
|
||||
public JMenuObject2(String p, Object o1, Object o2) {
|
||||
public JMenuObject2(String p, Object o1, Object o2, ActionListener l) {
|
||||
super(p);
|
||||
ob1 = o1;
|
||||
ob2 = o2;
|
||||
addActionListener(l);
|
||||
}
|
||||
|
||||
public void setObject1(Object o) {
|
||||
@@ -642,6 +715,41 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
}
|
||||
|
||||
class BatchConversionThread implements Runnable {
|
||||
Chapter chapter;
|
||||
|
||||
public BatchConversionThread(Chapter c) {
|
||||
chapter = c;
|
||||
}
|
||||
public void run() {
|
||||
try {
|
||||
Configuration sphinxConfig = new Configuration();
|
||||
|
||||
sphinxConfig.setAcousticModelPath("resource:/edu/cmu/sphinx/models/en-us/en-us");
|
||||
sphinxConfig.setDictionaryPath("resource:/edu/cmu/sphinx/models/en-us/cmudict-en-us.dict");
|
||||
sphinxConfig.setLanguageModelPath("resource:/edu/cmu/sphinx/models/en-us/en-us.lm.bin");
|
||||
|
||||
sphinxConfig.setSampleRate((int)(book.getAudioFormat().getSampleRate() / 4f));
|
||||
|
||||
StreamSpeechRecognizer recognizer;
|
||||
|
||||
recognizer = new StreamSpeechRecognizer(sphinxConfig);
|
||||
|
||||
|
||||
for (Enumeration s = chapter.children(); s.hasMoreElements();) {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
if (!snt.isLocked()) {
|
||||
if (snt.getId().equals(snt.getText())) {
|
||||
snt.doRecognition(recognizer);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void treePopup(MouseEvent e) {
|
||||
|
||||
@@ -657,13 +765,25 @@ public class AudiobookRecorder extends JFrame {
|
||||
bookTree.setSelectionPath(new TreePath(s.getPath()));
|
||||
|
||||
JPopupMenu menu = new JPopupMenu();
|
||||
JMenuObject rec = new JMenuObject("Recognise text from audio", s);
|
||||
|
||||
JMenuObject rec = new JMenuObject("Recognise text from audio", s, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Sentence s = (Sentence)o.getObject();
|
||||
if (!s.isLocked()) {
|
||||
s.recognise();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
JMenu moveMenu = new JMenu("Move phrase to...");
|
||||
|
||||
|
||||
for (Enumeration c = book.children(); c.hasMoreElements();) {
|
||||
Chapter chp = (Chapter)c.nextElement();
|
||||
JMenuObject2 m = new JMenuObject2(chp.getName(), s, chp);
|
||||
m.addActionListener(new ActionListener() {
|
||||
JMenuObject2 m = new JMenuObject2(chp.getName(), s, chp, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject2 ob = (JMenuObject2)e.getSource();
|
||||
Sentence sentence = (Sentence)ob.getObject1();
|
||||
@@ -676,10 +796,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
moveMenu.add(m);
|
||||
}
|
||||
|
||||
JMenuObject moveUp = new JMenuObject("Move Up", s);
|
||||
JMenuObject moveDown = new JMenuObject("Move Down", s);
|
||||
|
||||
moveUp.addActionListener(new ActionListener() {
|
||||
JMenuObject moveUp = new JMenuObject("Move Up", s, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Sentence sent = (Sentence)o.getObject();
|
||||
@@ -691,7 +808,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
});
|
||||
|
||||
moveDown.addActionListener(new ActionListener() {
|
||||
JMenuObject moveDown = new JMenuObject("Move Down", s, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Sentence sent = (Sentence)o.getObject();
|
||||
@@ -704,12 +821,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
});
|
||||
|
||||
|
||||
JMenuObject ins = new JMenuObject("Insert phrase above", s);
|
||||
JMenuObject del = new JMenuObject("Delete phrase", s);
|
||||
JMenuObject dup = new JMenuObject("Duplicate phrase", s);
|
||||
|
||||
|
||||
ins.addActionListener(new ActionListener() {
|
||||
JMenuObject ins = new JMenuObject("Insert phrase above", s, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Sentence s = (Sentence)o.getObject();
|
||||
@@ -721,7 +833,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
|
||||
});
|
||||
|
||||
del.addActionListener(new ActionListener() {
|
||||
JMenuObject del = new JMenuObject("Delete phrase", s, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Sentence s = (Sentence)o.getObject();
|
||||
@@ -732,7 +844,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
});
|
||||
|
||||
dup.addActionListener(new ActionListener() {
|
||||
JMenuObject dup = new JMenuObject("Duplicate phrase", s, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
@@ -747,18 +859,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
});
|
||||
|
||||
rec.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Sentence s = (Sentence)o.getObject();
|
||||
if (!s.isLocked()) {
|
||||
s.setText("[recognising...]");
|
||||
bookTreeModel.reload(s);
|
||||
s.recognise();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
menu.add(rec);
|
||||
@@ -774,65 +874,39 @@ public class AudiobookRecorder extends JFrame {
|
||||
menu.show(bookTree, e.getX(), e.getY());
|
||||
} else if (node instanceof Chapter) {
|
||||
Chapter c = (Chapter)node;
|
||||
int idNumber = Utils.s2i(c.getId());
|
||||
|
||||
bookTree.setSelectionPath(new TreePath(c.getPath()));
|
||||
|
||||
JPopupMenu menu = new JPopupMenu();
|
||||
JMenuObject peak = new JMenuObject("Auto-trim all (Peak)", c);
|
||||
JMenuObject fft = new JMenuObject("Auto-trim all (FFT)", c);
|
||||
JMenuObject moveUp = new JMenuObject("Move Up", c);
|
||||
JMenuObject moveDown = new JMenuObject("Move Down", c);
|
||||
JMenu mergeWith = new JMenu("Merge chapter with");
|
||||
JMenuObject lockAll = new JMenuObject("Lock all phrases", c);
|
||||
JMenuObject unlockAll = new JMenuObject("Unlock all phrases", c);
|
||||
JMenuObject exportChapter = new JMenuObject("Export chapter", c);
|
||||
JMenuObject deleteChapter = new JMenuObject("Delete chapter", c);
|
||||
|
||||
exportChapter.addActionListener(new ActionListener() {
|
||||
JMenuObject peak = new JMenuObject("Auto-trim all (Peak)", c, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter chap = (Chapter)o.getObject();
|
||||
|
||||
ProgressDialog ed = new ProgressDialog("Exporting " + chap.getName());
|
||||
|
||||
ExportThread t = new ExportThread(chap, ed);
|
||||
Thread nt = new Thread(t);
|
||||
nt.start();
|
||||
ed.setVisible(true);
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
if (!snt.isLocked()) {
|
||||
snt.autoTrimSamplePeak();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (Enumeration bc = book.children(); bc.hasMoreElements();) {
|
||||
Chapter chp = (Chapter)bc.nextElement();
|
||||
if (chp.getId().equals(c.getId())) {
|
||||
continue;
|
||||
}
|
||||
JMenuObject2 m = new JMenuObject2(chp.getName(), c, chp);
|
||||
m.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject2 ob = (JMenuObject2)e.getSource();
|
||||
Chapter source = (Chapter)ob.getObject1();
|
||||
Chapter target = (Chapter)ob.getObject2();
|
||||
|
||||
DefaultMutableTreeNode n = source.getFirstLeaf();
|
||||
while (n instanceof Sentence) {
|
||||
bookTreeModel.removeNodeFromParent(n);
|
||||
bookTreeModel.insertNodeInto(n, target, target.getChildCount());
|
||||
n = source.getFirstLeaf();
|
||||
JMenuObject fft = new JMenuObject("Auto-trim all (FFT)", c, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
if (!snt.isLocked()) {
|
||||
snt.autoTrimSampleFFT();
|
||||
}
|
||||
}
|
||||
});
|
||||
mergeWith.add(m);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
int idNumber = Utils.s2i(c.getId());
|
||||
|
||||
moveUp.setEnabled(idNumber > 0);
|
||||
moveDown.setEnabled(idNumber > 0);
|
||||
|
||||
moveUp.addActionListener(new ActionListener() {
|
||||
JMenuObject moveUp = new JMenuObject("Move Up", c, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter chap = (Chapter)o.getObject();
|
||||
@@ -851,7 +925,9 @@ public class AudiobookRecorder extends JFrame {
|
||||
book.renumberChapters();
|
||||
}
|
||||
});
|
||||
moveDown.addActionListener(new ActionListener() {
|
||||
moveUp.setEnabled(idNumber > 0);
|
||||
|
||||
JMenuObject moveDown = new JMenuObject("Move Down", c, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter chap = (Chapter)o.getObject();
|
||||
@@ -871,34 +947,32 @@ public class AudiobookRecorder extends JFrame {
|
||||
book.renumberChapters();
|
||||
}
|
||||
});
|
||||
moveDown.setEnabled(idNumber > 0);
|
||||
|
||||
peak.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
if (!snt.isLocked()) {
|
||||
snt.autoTrimSamplePeak();
|
||||
JMenu mergeWith = new JMenu("Merge chapter with");
|
||||
for (Enumeration bc = book.children(); bc.hasMoreElements();) {
|
||||
Chapter chp = (Chapter)bc.nextElement();
|
||||
if (chp.getId().equals(c.getId())) {
|
||||
continue;
|
||||
}
|
||||
JMenuObject2 m = new JMenuObject2(chp.getName(), c, chp, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject2 ob = (JMenuObject2)e.getSource();
|
||||
Chapter source = (Chapter)ob.getObject1();
|
||||
Chapter target = (Chapter)ob.getObject2();
|
||||
|
||||
DefaultMutableTreeNode n = source.getFirstLeaf();
|
||||
while (n instanceof Sentence) {
|
||||
bookTreeModel.removeNodeFromParent(n);
|
||||
bookTreeModel.insertNodeInto(n, target, target.getChildCount());
|
||||
n = source.getFirstLeaf();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
mergeWith.add(m);
|
||||
}
|
||||
|
||||
fft.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
for (Enumeration s = c.children(); s.hasMoreElements();) {
|
||||
Sentence snt = (Sentence)s.nextElement();
|
||||
if (!snt.isLocked()) {
|
||||
snt.autoTrimSampleFFT();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
lockAll.addActionListener(new ActionListener() {
|
||||
JMenuObject lockAll = new JMenuObject("Lock all phrases", c, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
@@ -909,7 +983,8 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
}
|
||||
});
|
||||
unlockAll.addActionListener(new ActionListener() {
|
||||
|
||||
JMenuObject unlockAll = new JMenuObject("Unlock all phrases", c, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
@@ -921,7 +996,21 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
});
|
||||
|
||||
deleteChapter.addActionListener(new ActionListener() {
|
||||
JMenuObject exportChapter = new JMenuObject("Export chapter", c, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter chap = (Chapter)o.getObject();
|
||||
|
||||
ProgressDialog ed = new ProgressDialog("Exporting " + chap.getName());
|
||||
|
||||
ExportThread t = new ExportThread(chap, ed);
|
||||
Thread nt = new Thread(t);
|
||||
nt.start();
|
||||
ed.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
JMenuObject deleteChapter = new JMenuObject("Delete chapter", c, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
@@ -938,7 +1027,18 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
});
|
||||
|
||||
JMenuObject convertAll = new JMenuObject("Detect all text", c, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter c = (Chapter)o.getObject();
|
||||
BatchConversionThread r = new BatchConversionThread(c);
|
||||
Thread t = new Thread(r);
|
||||
t.start();
|
||||
}
|
||||
});
|
||||
|
||||
menu.add(convertAll);
|
||||
menu.addSeparator();
|
||||
menu.add(moveUp);
|
||||
menu.add(moveDown);
|
||||
menu.addSeparator();
|
||||
@@ -954,6 +1054,40 @@ public class AudiobookRecorder extends JFrame {
|
||||
menu.addSeparator();
|
||||
menu.add(deleteChapter);
|
||||
|
||||
menu.show(bookTree, e.getX(), e.getY());
|
||||
} else if (node instanceof Book) {
|
||||
JPopupMenu menu = new JPopupMenu();
|
||||
|
||||
JMenuItem editData = new JMenuItem("Edit Data...");
|
||||
editData.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
BookInfoPanel info = new BookInfoPanel(
|
||||
book.getName(),
|
||||
book.getAuthor(),
|
||||
book.getGenre(),
|
||||
book.getComment(),
|
||||
book.getACX()
|
||||
);
|
||||
int r = JOptionPane.showConfirmDialog(AudiobookRecorder.this, info, "Edit Book", JOptionPane.OK_CANCEL_OPTION);
|
||||
if (r != JOptionPane.OK_OPTION) return;
|
||||
|
||||
String tit = info.getTitle();
|
||||
String aut = info.getAuthor();
|
||||
String gen = info.getGenre();
|
||||
String com = info.getComment();
|
||||
String acx = info.getACX();
|
||||
|
||||
book.setAuthor(aut);
|
||||
book.setGenre(gen);
|
||||
book.setComment(com);
|
||||
book.setACX(acx);
|
||||
if (!(book.getName().equals(tit))) {
|
||||
book.renameBook(tit);
|
||||
}
|
||||
}
|
||||
});
|
||||
menu.add(editData);
|
||||
|
||||
menu.show(bookTree, e.getX(), e.getY());
|
||||
}
|
||||
|
||||
@@ -970,9 +1104,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
return;
|
||||
}
|
||||
|
||||
toolBar.disableBook();
|
||||
toolBar.disableSentence();
|
||||
|
||||
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
|
||||
|
||||
if (selectedNode == null) {
|
||||
@@ -1003,9 +1134,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
return;
|
||||
}
|
||||
|
||||
toolBar.disableBook();
|
||||
toolBar.disableSentence();
|
||||
|
||||
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
|
||||
|
||||
if (selectedNode == null) {
|
||||
@@ -1056,9 +1184,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
return;
|
||||
}
|
||||
|
||||
toolBar.disableBook();
|
||||
toolBar.disableSentence();
|
||||
|
||||
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
|
||||
|
||||
if (selectedNode == null) {
|
||||
@@ -1108,9 +1233,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
return;
|
||||
}
|
||||
|
||||
toolBar.disableBook();
|
||||
toolBar.disableSentence();
|
||||
|
||||
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)bookTree.getLastSelectedPathComponent();
|
||||
|
||||
if (selectedNode == null) {
|
||||
@@ -1153,10 +1275,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
bookTree.setSelectionPath(new TreePath(recording.getPath()));
|
||||
bookTree.scrollPathToVisible(new TreePath(recording.getPath()));
|
||||
|
||||
toolBar.enableBook();
|
||||
toolBar.enableSentence();
|
||||
toolBar.disableStop();
|
||||
|
||||
centralPanel.setFlash(false);
|
||||
recording = null;
|
||||
saveBookStructure();
|
||||
@@ -1230,6 +1348,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
prefs.setProperty("book.author", book.getAuthor());
|
||||
prefs.setProperty("book.genre", book.getGenre());
|
||||
prefs.setProperty("book.comment", book.getComment());
|
||||
prefs.setProperty("book.acx", book.getACX());
|
||||
|
||||
prefs.setProperty("audio.recording.samplerate", "" + book.getSampleRate());
|
||||
prefs.setProperty("audio.recording.resolution", "" + book.getResolution());
|
||||
@@ -1256,6 +1375,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
prefs.setProperty(String.format("%s.sentence.%08d.start-offset", keybase, i), Integer.toString(snt.getStartOffset()));
|
||||
prefs.setProperty(String.format("%s.sentence.%08d.end-offset", keybase, i), Integer.toString(snt.getEndOffset()));
|
||||
prefs.setProperty(String.format("%s.sentence.%08d.locked", keybase, i), snt.isLocked() ? "true" : "false");
|
||||
prefs.setProperty(String.format("%s.sentence.%08d.attention", keybase, i), snt.getAttentionFlag() ? "true" : "false");
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -1310,6 +1430,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
book.setAuthor(prefs.getProperty("book.author"));
|
||||
book.setGenre(prefs.getProperty("book.genre"));
|
||||
book.setComment(prefs.getProperty("book.comment"));
|
||||
book.setACX(prefs.getProperty("book.acx"));
|
||||
|
||||
int sr = Utils.s2i(prefs.getProperty("audio.recording.samplerate"));
|
||||
if (sr == 0) {
|
||||
@@ -1347,7 +1468,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
|
||||
|
||||
InputMap im = bookTree.getInputMap(JComponent.WHEN_FOCUSED);
|
||||
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "startPlayback");
|
||||
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "startStopPlayback");
|
||||
|
||||
roomNoise = new Sentence("room-noise", "Room Noise");
|
||||
|
||||
@@ -1363,25 +1484,17 @@ public class AudiobookRecorder extends JFrame {
|
||||
sampleWaveform.setAltMarkers(s.getStartCrossing(), s.getEndCrossing());
|
||||
postSentenceGap.setValue(s.getPostGap());
|
||||
locked.setSelected(s.isLocked());
|
||||
attention.setSelected(s.getAttentionFlag());
|
||||
|
||||
postSentenceGap.setEnabled(!s.isLocked());
|
||||
reprocessAudioFFT.setEnabled(!s.isLocked());
|
||||
reprocessAudioPeak.setEnabled(!s.isLocked());
|
||||
|
||||
if (playing == null) {
|
||||
toolBar.enableSentence();
|
||||
toolBar.disableStop();
|
||||
} else {
|
||||
toolBar.disableSentence();
|
||||
toolBar.enableStop();
|
||||
}
|
||||
} else {
|
||||
selectedSentence = null;
|
||||
toolBar.disableSentence();
|
||||
sampleWaveform.clearData();
|
||||
toolBar.disableStop();
|
||||
postSentenceGap.setValue(0);
|
||||
locked.setSelected(false);
|
||||
attention.setSelected(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1420,6 +1533,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
s.setStartOffset(Utils.s2i(prefs.getProperty(String.format("chapter.audition.sentence.%08d.start-offset", i))));
|
||||
s.setEndOffset(Utils.s2i(prefs.getProperty(String.format("chapter.audition.sentence.%08d.end-offset", i))));
|
||||
s.setLocked(Utils.s2b(prefs.getProperty(String.format("chapter.audition.sentence.%08d.locked", i))));
|
||||
s.setAttentionFlag(Utils.s2b(prefs.getProperty(String.format("chapter.audition.sentence.%08d.attention", i))));
|
||||
bookTreeModel.insertNodeInto(s, c, c.getChildCount());
|
||||
}
|
||||
|
||||
@@ -1438,6 +1552,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
s.setStartOffset(Utils.s2i(prefs.getProperty(String.format("chapter.open.sentence.%08d.start-offset", i))));
|
||||
s.setEndOffset(Utils.s2i(prefs.getProperty(String.format("chapter.open.sentence.%08d.end-offset", i))));
|
||||
s.setLocked(Utils.s2b(prefs.getProperty(String.format("chapter.open.sentence.%08d.locked", i))));
|
||||
s.setAttentionFlag(Utils.s2b(prefs.getProperty(String.format("chapter.open.sentence.%08d.attention", i))));
|
||||
bookTreeModel.insertNodeInto(s, c, c.getChildCount());
|
||||
}
|
||||
|
||||
@@ -1462,6 +1577,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
s.setStartOffset(Utils.s2i(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.start-offset", cno, i))));
|
||||
s.setEndOffset(Utils.s2i(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.end-offset", cno, i))));
|
||||
s.setLocked(Utils.s2b(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.locked", cno, i))));
|
||||
s.setAttentionFlag(Utils.s2b(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.attention", cno, i))));
|
||||
bookTreeModel.insertNodeInto(s, c, c.getChildCount());
|
||||
}
|
||||
}
|
||||
@@ -1481,12 +1597,12 @@ public class AudiobookRecorder extends JFrame {
|
||||
s.setStartOffset(Utils.s2i(prefs.getProperty(String.format("chapter.close.sentence.%08d.start-offset", i))));
|
||||
s.setEndOffset(Utils.s2i(prefs.getProperty(String.format("chapter.close.sentence.%08d.end-offset", i))));
|
||||
s.setLocked(Utils.s2b(prefs.getProperty(String.format("chapter.close.sentence.%08d.locked", i))));
|
||||
s.setAttentionFlag(Utils.s2b(prefs.getProperty(String.format("chapter.close.sentence.%08d.attention", i))));
|
||||
bookTreeModel.insertNodeInto(s, c, c.getChildCount());
|
||||
}
|
||||
|
||||
bookTree.expandPath(new TreePath(book.getPath()));
|
||||
|
||||
toolBar.enableBook();
|
||||
statusLabel.setText("Noise floor: " + getNoiseFloorDB() + "dB");
|
||||
book.setIcon(Icons.book);
|
||||
}
|
||||
@@ -1497,6 +1613,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
int r = JOptionPane.showConfirmDialog(this, info, "Open Book", JOptionPane.OK_CANCEL_OPTION);
|
||||
if (r == JOptionPane.OK_OPTION) {
|
||||
File f = info.getSelectedFile();
|
||||
if (f == null) return;
|
||||
if (!f.exists()) {
|
||||
JOptionPane.showMessageDialog(this, "File not found.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
@@ -1582,8 +1699,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
return;
|
||||
}
|
||||
playing = selectedSentence;
|
||||
toolBar.disableSentence();
|
||||
toolBar.enableStop();
|
||||
|
||||
playingThread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
@@ -1610,6 +1725,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
play.stop();
|
||||
play.close();
|
||||
play = null;
|
||||
playing = null;
|
||||
} catch (Exception e) {
|
||||
playing = null;
|
||||
if (play != null) {
|
||||
@@ -1619,8 +1735,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
play = null;
|
||||
}
|
||||
toolBar.enableSentence();
|
||||
toolBar.disableStop();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1677,8 +1791,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
return;
|
||||
}
|
||||
playing = selectedSentence;
|
||||
toolBar.disableSentence();
|
||||
toolBar.enableStop();
|
||||
|
||||
playingThread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
@@ -1747,8 +1859,6 @@ public class AudiobookRecorder extends JFrame {
|
||||
}
|
||||
play = null;
|
||||
}
|
||||
toolBar.enableSentence();
|
||||
toolBar.disableStop();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1797,7 +1907,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
if (equaliserWindow == null) {
|
||||
equaliserWindow = new JDialog();
|
||||
equaliserWindow.setTitle("Equaliser");
|
||||
equaliserWindow.add(book.equaliser);
|
||||
equaliserWindow.add(new JScrollPane(book.equaliser));
|
||||
equaliserWindow.pack();
|
||||
}
|
||||
equaliserWindow.setVisible(true);
|
||||
@@ -2003,7 +2113,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
String name = AudiobookRecorder.this.book.getName();
|
||||
File storageDir = new File(Options.get("path.storage"));
|
||||
File bookDir = new File(storageDir, name);
|
||||
File archiveDir = new File(storageDir, "archive");
|
||||
File archiveDir = new File(Options.get("path.archive"));
|
||||
|
||||
ArrayList<File> fileList = gatherFiles(bookDir);
|
||||
|
||||
@@ -2041,6 +2151,7 @@ public class AudiobookRecorder extends JFrame {
|
||||
zos.closeEntry();
|
||||
} else {
|
||||
ZipEntry entry = new ZipEntry(path);
|
||||
entry.setSize(f.length());
|
||||
entry.setTime(f.lastModified());
|
||||
zos.putNextEntry(entry);
|
||||
|
||||
@@ -2085,4 +2196,126 @@ public class AudiobookRecorder extends JFrame {
|
||||
mainScroll.setViewportView(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void openArchive() {
|
||||
JFileChooser jc = new JFileChooser(new File(Options.get("path.archive")));
|
||||
FileNameExtensionFilter filter = new FileNameExtensionFilter("Audiobook Archives", "abz");
|
||||
jc.addChoosableFileFilter(filter);
|
||||
jc.setFileFilter(filter);
|
||||
jc.setDialogTitle("Select Audiobook Archive");
|
||||
int r = jc.showOpenDialog(this);
|
||||
|
||||
if (r == JFileChooser.APPROVE_OPTION) {
|
||||
File f = jc.getSelectedFile();
|
||||
if (f.exists()) {
|
||||
|
||||
try {
|
||||
ZipInputStream zis = new ZipInputStream(new FileInputStream(f)) {
|
||||
public void close() throws IOException {
|
||||
return;
|
||||
}
|
||||
};
|
||||
ZipEntry entry = null;
|
||||
ImageIcon cover = null;
|
||||
Properties props = new Properties();
|
||||
|
||||
boolean gotMeta = false;
|
||||
boolean gotCover = false;
|
||||
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (gotMeta && gotCover) break;
|
||||
|
||||
if (entry.getName().endsWith("/audiobook.abk")) {
|
||||
props.loadFromXML(zis);
|
||||
gotMeta = true;
|
||||
}
|
||||
|
||||
if (
|
||||
entry.getName().endsWith("/coverart.png") ||
|
||||
entry.getName().endsWith("/coverart.jpg") ||
|
||||
entry.getName().endsWith("/coverart.gif")
|
||||
) {
|
||||
cover = new ImageIcon(ImageIO.read(zis));
|
||||
gotCover = true;
|
||||
}
|
||||
}
|
||||
zis.close();
|
||||
|
||||
BookPanel pan = new BookPanel(props, cover);
|
||||
int okToImport = JOptionPane.showConfirmDialog(this, pan, "Import this book?", JOptionPane.OK_CANCEL_OPTION);
|
||||
if (okToImport == JOptionPane.OK_OPTION) {
|
||||
zis = new ZipInputStream(new FileInputStream(f));
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
File out = new File(Options.get("path.storage"), entry.getName());
|
||||
if (entry.isDirectory()) {
|
||||
out.mkdirs();
|
||||
} else {
|
||||
byte[] buffer = new byte[1024];
|
||||
int nr;
|
||||
FileOutputStream fos = new FileOutputStream(out);
|
||||
while ((nr = zis.read(buffer, 0, 1024)) > 0) {
|
||||
fos.write(buffer, 0, nr);
|
||||
}
|
||||
fos.close();
|
||||
}
|
||||
}
|
||||
zis.close();
|
||||
|
||||
File bookdir = new File(Options.get("path.storage"), props.getProperty("book.name"));
|
||||
File conf = new File(bookdir, "audiobook.abk");
|
||||
loadBookStructure(conf);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadCoverArt() {
|
||||
if (book == null) return;
|
||||
|
||||
JFileChooser jc = new JFileChooser();
|
||||
FileNameExtensionFilter filter = new FileNameExtensionFilter("Image Files", "png", "jpg", "gif");
|
||||
jc.addChoosableFileFilter(filter);
|
||||
jc.setFileFilter(filter);
|
||||
jc.setDialogTitle("Select coverart image");
|
||||
int r = jc.showOpenDialog(this);
|
||||
|
||||
if (r == JFileChooser.APPROVE_OPTION) {
|
||||
File src = jc.getSelectedFile();
|
||||
if (src.exists()) {
|
||||
File dest = null;
|
||||
File bookFolder = new File(Options.get("path.storage"), book.getName());
|
||||
if (src.getName().endsWith(".png")) {
|
||||
dest = new File(bookFolder, "coverart.png");
|
||||
} else if (src.getName().endsWith(".jpg")) {
|
||||
dest = new File(bookFolder, "coverart.jpg");
|
||||
} else if (src.getName().endsWith(".gif")) {
|
||||
dest = new File(bookFolder, "coverart.gif");
|
||||
}
|
||||
|
||||
if (dest == null) {
|
||||
JOptionPane.showMessageDialog(this, "Invalid image format or filename", "Error", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
new File(bookFolder, "coverart.png").delete();
|
||||
new File(bookFolder, "coverart.jpg").delete();
|
||||
new File(bookFolder, "coverart.gif").delete();
|
||||
|
||||
Files.copy(src.toPath(), dest.toPath());
|
||||
|
||||
ImageIcon i = new ImageIcon(dest.getAbsolutePath());
|
||||
Image ri = Utils.getScaledImage(i.getImage(), 22, 22);
|
||||
book.setIcon(new ImageIcon(ri));
|
||||
bookTreeModel.reload(book);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ public class Book extends DefaultMutableTreeNode {
|
||||
String author;
|
||||
String genre;
|
||||
String comment;
|
||||
String ACX;
|
||||
|
||||
int sampleRate;
|
||||
int channels;
|
||||
@@ -32,31 +33,18 @@ public class Book extends DefaultMutableTreeNode {
|
||||
super(bookname);
|
||||
name = bookname;
|
||||
equaliser = new Equaliser();
|
||||
AudiobookRecorder.window.setTitle("AudioBook Recorder :: " + name);
|
||||
}
|
||||
|
||||
public void setAuthor(String a) {
|
||||
author = a;
|
||||
}
|
||||
public void setAuthor(String a) { author = a; }
|
||||
public void setGenre(String g) { genre = g; }
|
||||
public void setComment(String c) { comment = c; }
|
||||
public void setACX(String c) { ACX = c; }
|
||||
|
||||
public void setGenre(String g) {
|
||||
genre = g;
|
||||
}
|
||||
|
||||
public void setComment(String c) {
|
||||
comment = c;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public String getGenre() {
|
||||
return genre;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
public String getAuthor() { return author; }
|
||||
public String getGenre() { return genre; }
|
||||
public String getComment() { return comment; }
|
||||
public String getACX() { if (ACX == null) return ""; return ACX; }
|
||||
|
||||
public Chapter getClosingCredits() {
|
||||
return getChapterById("close");
|
||||
@@ -124,23 +112,28 @@ public class Book extends DefaultMutableTreeNode {
|
||||
public void setUserObject(Object o) {
|
||||
if (o instanceof String) {
|
||||
String newName = (String)o;
|
||||
if (newName.equals(name)) return;
|
||||
renameBook(newName);
|
||||
}
|
||||
}
|
||||
|
||||
File oldDir = new File(Options.get("path.storage"), name);
|
||||
File newDir = new File(Options.get("path.storage"), newName);
|
||||
public void renameBook(String newName) {
|
||||
File oldDir = new File(Options.get("path.storage"), name);
|
||||
File newDir = new File(Options.get("path.storage"), newName);
|
||||
|
||||
if (newDir.exists()) {
|
||||
JOptionPane.showMessageDialog(AudiobookRecorder.window, "Book already exists", "Error", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
if (newDir.exists()) {
|
||||
JOptionPane.showMessageDialog(AudiobookRecorder.window, "Book already exists", "Error", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldDir.exists() && oldDir.isDirectory()) {
|
||||
oldDir.renameTo(newDir);
|
||||
name = newName;
|
||||
AudiobookRecorder.window.saveBookStructure();
|
||||
AudiobookRecorder.window.bookTreeModel.reload(this);
|
||||
Options.set("path.last-book", name);
|
||||
Options.savePreferences();
|
||||
}
|
||||
if (oldDir.exists() && oldDir.isDirectory()) {
|
||||
oldDir.renameTo(newDir);
|
||||
name = newName;
|
||||
AudiobookRecorder.window.saveBookStructure();
|
||||
AudiobookRecorder.window.bookTreeModel.reload(this);
|
||||
Options.set("path.last-book", name);
|
||||
Options.savePreferences();
|
||||
AudiobookRecorder.window.setTitle("AudioBook Recorder :: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.regex.*;
|
||||
|
||||
public class BookInfoPanel extends JPanel {
|
||||
|
||||
@@ -11,8 +12,9 @@ public class BookInfoPanel extends JPanel {
|
||||
JTextField author;
|
||||
JTextField genre;
|
||||
JTextField comment;
|
||||
JTextField acx;
|
||||
|
||||
public BookInfoPanel(String t, String a, String g, String c) {
|
||||
public BookInfoPanel(String t, String a, String g, String c, String x) {
|
||||
super();
|
||||
setLayout(new GridBagLayout());
|
||||
GridBagConstraints con = new GridBagConstraints();
|
||||
@@ -56,37 +58,36 @@ public class BookInfoPanel extends JPanel {
|
||||
con.gridx = 0;
|
||||
con.gridy++;
|
||||
|
||||
add(new JLabel("AXC Code:"), con);
|
||||
con.gridx = 1;
|
||||
acx = new JTextField(x);
|
||||
acx.setPreferredSize(new Dimension(200, 20));
|
||||
add(acx, con);
|
||||
|
||||
con.gridx = 0;
|
||||
con.gridy++;
|
||||
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title.getText();
|
||||
public String getTitle() { return title.getText(); }
|
||||
public String getAuthor() { return author.getText(); }
|
||||
public String getGenre() { return genre.getText(); }
|
||||
public String getComment() { return comment.getText(); }
|
||||
|
||||
public String getACX() {
|
||||
Pattern p = Pattern.compile("\\/titleview\\/([A-Z0-9]{14})");
|
||||
Matcher m = p.matcher(acx.getText());
|
||||
if (m.find()) {
|
||||
System.err.println(m);
|
||||
return m.group(1);
|
||||
}
|
||||
return acx.getText();
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author.getText();
|
||||
}
|
||||
public void setTitle(String t) { title.setText(t); }
|
||||
public void setAuthor(String a) { author.setText(a); }
|
||||
public void setGenre(String g) { genre.setText(g); }
|
||||
public void setComment(String c) { comment.setText(c); }
|
||||
public void setACX(String a) { acx.setText(a); }
|
||||
|
||||
public String getGenre() {
|
||||
return genre.getText();
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return comment.getText();
|
||||
}
|
||||
|
||||
public void setTitle(String t) {
|
||||
title.setText(t);
|
||||
}
|
||||
|
||||
public void setAuthor(String a) {
|
||||
author.setText(a);
|
||||
}
|
||||
|
||||
public void setGenre(String g) {
|
||||
genre.setText(g);
|
||||
}
|
||||
|
||||
public void setComment(String c) {
|
||||
comment.setText(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,30 +28,48 @@ public class BookPanel extends JPanel {
|
||||
|
||||
boolean highlight = false;
|
||||
|
||||
public BookPanel(Properties p, ImageIcon i) {
|
||||
loadBookData(p, i);
|
||||
}
|
||||
|
||||
public BookPanel(File r) {
|
||||
try {
|
||||
root = r;
|
||||
Properties props = new Properties();
|
||||
props.loadFromXML(new FileInputStream(new File(root, "audiobook.abk")));
|
||||
loadBookData(props, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadBookData(Properties props, ImageIcon i) {
|
||||
try {
|
||||
name = props.getProperty("book.name");
|
||||
author = props.getProperty("book.author");
|
||||
genre = props.getProperty("book.genre");
|
||||
comment = props.getProperty("book.comment");
|
||||
File icon = new File(root, "coverart.png");
|
||||
if (!icon.exists()) {
|
||||
icon = new File(root, "coverart.jpg");
|
||||
}
|
||||
if (!icon.exists()) {
|
||||
icon = new File(root, "coverart.gif");
|
||||
}
|
||||
if (icon.exists()) {
|
||||
cover = new ImageIcon(icon.getAbsolutePath());
|
||||
if (i == null) {
|
||||
File icon = new File(root, "coverart.png");
|
||||
if (!icon.exists()) {
|
||||
icon = new File(root, "coverart.jpg");
|
||||
}
|
||||
if (!icon.exists()) {
|
||||
icon = new File(root, "coverart.gif");
|
||||
}
|
||||
if (icon.exists()) {
|
||||
cover = new ImageIcon(icon.getAbsolutePath());
|
||||
resizedCover = Utils.getScaledImage(cover.getImage(), 75, 75);
|
||||
iconLabel = new JLabel(new ImageIcon(resizedCover));
|
||||
} else {
|
||||
cover = null;
|
||||
resizedCover = null;
|
||||
iconLabel = new JLabel("");
|
||||
}
|
||||
} else {
|
||||
cover = i;
|
||||
resizedCover = Utils.getScaledImage(cover.getImage(), 75, 75);
|
||||
iconLabel = new JLabel(new ImageIcon(resizedCover));
|
||||
} else {
|
||||
cover = null;
|
||||
resizedCover = null;
|
||||
iconLabel = new JLabel("");
|
||||
}
|
||||
|
||||
iconLabel.setSize(new Dimension(75, 75));
|
||||
|
||||
@@ -11,8 +11,11 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer {
|
||||
if (value instanceof Sentence) {
|
||||
Sentence s = (Sentence)value;
|
||||
|
||||
if (s.isLocked()) {
|
||||
ret.setForeground(new Color(0x20, 0x00, 0x00));
|
||||
if (s.getAttentionFlag()) {
|
||||
ret.setForeground(new Color(0xFF, 0xFF, 0x00));
|
||||
ret.setIcon(Icons.attention);
|
||||
} else if (s.isLocked()) {
|
||||
ret.setForeground(new Color(0x00, 0x80, 0xFF));
|
||||
ret.setIcon(Icons.locked);
|
||||
} else if (s.getStartOffset() == 0) {
|
||||
ret.setIcon(Icons.important);
|
||||
|
||||
@@ -40,12 +40,7 @@ public class DonationPanel extends JPanel {
|
||||
JButton donate = new JButton("Donate!");
|
||||
donate.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (Desktop.isDesktopSupported()) {
|
||||
try {
|
||||
Desktop.getDesktop().browse(new URI("https://paypal.me/majenko"));
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
Utils.browse("https://paypal.me/majenko");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -31,4 +31,5 @@ public class Icons {
|
||||
static public final ImageIcon zoomIn = new ImageIcon(Icons.class.getResource("icons/zoom-in.png"));
|
||||
static public final ImageIcon zoomOut = new ImageIcon(Icons.class.getResource("icons/zoom-out.png"));
|
||||
static public final ImageIcon dollar = new ImageIcon(Icons.class.getResource("icons/dollar.png"));
|
||||
static public final ImageIcon attention = new ImageIcon(Icons.class.getResource("icons/attention.png"));
|
||||
}
|
||||
|
||||
@@ -124,31 +124,4 @@ public class MainToolBar extends JToolBar {
|
||||
setFloatable(false);
|
||||
}
|
||||
|
||||
public void enableBook() {
|
||||
newChapter.setEnabled(true);
|
||||
recordRoomNoise.setEnabled(true);
|
||||
}
|
||||
|
||||
public void disableBook() {
|
||||
newChapter.setEnabled(false);
|
||||
recordRoomNoise.setEnabled(false);
|
||||
}
|
||||
|
||||
public void enableSentence() {
|
||||
playSentence.setEnabled(true);
|
||||
playonSentence.setEnabled(true);
|
||||
}
|
||||
|
||||
public void disableSentence() {
|
||||
playSentence.setEnabled(false);
|
||||
playonSentence.setEnabled(false);
|
||||
}
|
||||
|
||||
public void enableStop() {
|
||||
stopPlaying.setEnabled(true);
|
||||
}
|
||||
|
||||
public void disableStop() {
|
||||
stopPlaying.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ public class Options extends JDialog {
|
||||
JComboBox<KVPair> bitDepth;
|
||||
JComboBox<KVPair> trimMethod;
|
||||
JTextField storageFolder;
|
||||
JTextField archiveFolder;
|
||||
JSpinner preChapterGap;
|
||||
JSpinner postChapterGap;
|
||||
JSpinner postSentenceGap;
|
||||
@@ -256,6 +257,7 @@ public class Options extends JDialog {
|
||||
playbackList = addDropdown(optionsPanel, "Playback device:", getPlaybackMixerList(), get("audio.playback.device"));
|
||||
addSeparator(optionsPanel);
|
||||
storageFolder = addFilePath(optionsPanel, "Storage folder:", get("path.storage"), true);
|
||||
archiveFolder = addFilePath(optionsPanel, "Archive folder:", get("path.archive"), true);
|
||||
|
||||
addSeparator(optionsPanel);
|
||||
|
||||
@@ -281,28 +283,20 @@ public class Options extends JDialog {
|
||||
cacheSize = addSpinner(optionsPanel, "Cache size:", 0, 5000, 1, getInteger("cache.size"), "");
|
||||
|
||||
addSeparator(optionsPanel);
|
||||
|
||||
tabs.add("Options", optionsPanel);
|
||||
|
||||
tabs.add("Options", new JScrollPane(optionsPanel));
|
||||
equaliser = new Equaliser();
|
||||
|
||||
for (int i = 0; i < 31; i++) {
|
||||
equaliser.setChannel(i, Options.getFloat("audio.eq." + i));
|
||||
}
|
||||
|
||||
tabs.add("Default EQ", equaliser);
|
||||
tabs.add("Default EQ", new JScrollPane(equaliser));
|
||||
|
||||
JPanel startScript = new JPanel();
|
||||
startScript.setLayout(new BorderLayout());
|
||||
startupScript = new JTextArea(get("scripts.startup"));
|
||||
startScript.add(startupScript, BorderLayout.CENTER);
|
||||
|
||||
tabs.add("Startup Script", startScript);
|
||||
|
||||
add(tabs, BorderLayout.CENTER);
|
||||
|
||||
|
||||
|
||||
setTitle("Options");
|
||||
|
||||
setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
|
||||
@@ -462,6 +456,7 @@ public class Options extends JDialog {
|
||||
defaultPrefs.put("catenation.post-paragraph", "2000");
|
||||
|
||||
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.ffmpeg", "");
|
||||
|
||||
defaultPrefs.put("audio.export.bitrate", "256000");
|
||||
@@ -598,6 +593,7 @@ public class Options extends JDialog {
|
||||
set("audio.recording.trim", ((KVPair)trimMethod.getSelectedItem()).key);
|
||||
set("audio.playback.device", ((KVPair)playbackList.getSelectedItem()).key);
|
||||
set("path.storage", storageFolder.getText());
|
||||
set("path.archive", archiveFolder.getText());
|
||||
set("path.ffmpeg", ffmpegLocation.getText());
|
||||
set("catenation.pre-chapter", preChapterGap.getValue());
|
||||
set("catenation.post-chapter", postChapterGap.getValue());
|
||||
|
||||
@@ -32,6 +32,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
|
||||
boolean recording;
|
||||
|
||||
boolean inSample;
|
||||
boolean attention = false;
|
||||
|
||||
TargetDataLine line;
|
||||
AudioInputStream inputStream;
|
||||
@@ -574,66 +575,68 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void doRecognition(StreamSpeechRecognizer recognizer) {
|
||||
try {
|
||||
setText("[recognising...]");
|
||||
AudiobookRecorder.window.bookTreeModel.reload(this);
|
||||
|
||||
AudioFormat format = getAudioFormat();
|
||||
|
||||
byte[] inData = getRawAudioData();
|
||||
int inLength = inData.length;
|
||||
int bps = format.getFrameSize();
|
||||
int inSamples = inLength / bps;
|
||||
|
||||
int outSamples = inSamples / 4;
|
||||
byte[] outData = new byte[outSamples * bps];
|
||||
|
||||
for (int i = 0; i < outSamples; i++) {
|
||||
for (int j = 0; j < bps; j++) {
|
||||
outData[i * bps + j] = inData[(i * 4) * bps + j];
|
||||
}
|
||||
}
|
||||
|
||||
ByteArrayInputStream bas = new ByteArrayInputStream(outData);
|
||||
recognizer.startRecognition(bas);
|
||||
SpeechResult result;
|
||||
String res = "";
|
||||
while ((result = recognizer.getResult()) != null) {
|
||||
res += result.getHypothesis();
|
||||
res += " ";
|
||||
}
|
||||
recognizer.stopRecognition();
|
||||
|
||||
text = res;
|
||||
|
||||
AudiobookRecorder.window.bookTreeModel.reload(Sentence.this);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void recognise() {
|
||||
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
|
||||
Configuration sphinxConfig = new Configuration();
|
||||
|
||||
sphinxConfig.setAcousticModelPath("resource:/edu/cmu/sphinx/models/en-us/en-us");
|
||||
sphinxConfig.setDictionaryPath("resource:/edu/cmu/sphinx/models/en-us/cmudict-en-us.dict");
|
||||
sphinxConfig.setLanguageModelPath("resource:/edu/cmu/sphinx/models/en-us/en-us.lm.bin");
|
||||
|
||||
AudioInputStream s = AudioSystem.getAudioInputStream(getFile());
|
||||
AudioFormat format = getAudioFormat();
|
||||
|
||||
sphinxConfig.setSampleRate((int)(format.getSampleRate() / 4f));
|
||||
|
||||
StreamSpeechRecognizer recognizer;
|
||||
|
||||
recognizer = new StreamSpeechRecognizer(sphinxConfig);
|
||||
|
||||
AudioInputStream s = AudioSystem.getAudioInputStream(getFile());
|
||||
AudioFormat format = getAudioFormat();
|
||||
int frameSize = format.getFrameSize();
|
||||
int length = (int)s.getFrameLength();
|
||||
byte[] data = new byte[length * frameSize];
|
||||
|
||||
s.read(data);
|
||||
|
||||
int channels = format.getChannels();
|
||||
int newLen = (length / 3);
|
||||
byte[] decimated = new byte[newLen * 2];
|
||||
|
||||
for (int i = 0; i < newLen; i++) {
|
||||
if (channels == 1) {
|
||||
decimated[i * 2] = data[i * 6];
|
||||
decimated[i * 2 + 1] = data[i * 6 + 1];
|
||||
} else {
|
||||
decimated[i * 2] = data[i * 12];
|
||||
decimated[i * 2 + 1] = data[i * 12 + 1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ByteArrayInputStream bas = new ByteArrayInputStream(decimated);
|
||||
recognizer.startRecognition(bas);
|
||||
SpeechResult result;
|
||||
String res = "";
|
||||
while ((result = recognizer.getResult()) != null) {
|
||||
res += result.getHypothesis();
|
||||
res += " ";
|
||||
}
|
||||
recognizer.stopRecognition();
|
||||
|
||||
text = res;
|
||||
|
||||
AudiobookRecorder.window.bookTreeModel.reload(Sentence.this);
|
||||
|
||||
doRecognition(recognizer);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -730,4 +733,12 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
|
||||
sentence.updateCrossings();
|
||||
return sentence;
|
||||
}
|
||||
|
||||
public void setAttentionFlag(boolean f) {
|
||||
attention = f;
|
||||
}
|
||||
|
||||
public boolean getAttentionFlag() {
|
||||
return attention;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.awt.image.*;
|
||||
import javax.swing.border.*;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
||||
public class Utils {
|
||||
public static Image getScaledImage(Image srcImg, int w, int h){
|
||||
@@ -46,4 +47,12 @@ public class Utils {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
public static void browse(String url) {
|
||||
if (Desktop.isDesktopSupported()) {
|
||||
try {
|
||||
Desktop.getDesktop().browse(new URI(url));
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user