Compare commits

..

4 Commits

Author SHA1 Message Date
4a4d7f2a38 Checkpoint release 2018-10-02 14:37:23 +01:00
f7848228a2 Added cover art import #6 2018-10-02 14:36:37 +01:00
8c22315b15 Added import archive #4 2018-10-02 14:21:12 +01:00
718c982578 Added batch conversion of text #8 2018-10-02 12:00:11 +01:00
4 changed files with 360 additions and 159 deletions

View File

@@ -1 +1 @@
version=0.1.0
version=0.1.1

View File

@@ -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,14 @@ public class AudiobookRecorder extends JFrame {
JMenuItem fileOpenBook;
JMenuItem fileSave;
JMenuItem fileExit;
JMenuItem fileOpenArchive;
JMenuItem bookNewChapter;
JMenuItem bookExportAudio;
JMenuItem toolsMerge;
JMenuItem toolsArchive;
JMenuItem toolsCoverArt;
JMenuItem toolsOptions;
JMenuItem helpAbout;
@@ -137,6 +141,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 +160,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);
@@ -193,6 +206,13 @@ public class AudiobookRecorder extends JFrame {
}
});
toolsCoverArt = new JMenuItem("Import Cover Art...");
toolsCoverArt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
loadCoverArt();
}
});
toolsOptions = new JMenuItem("Options");
toolsOptions.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
@@ -202,6 +222,7 @@ public class AudiobookRecorder extends JFrame {
toolsMenu.add(toolsMerge);
toolsMenu.add(toolsArchive);
toolsMenu.add(toolsCoverArt);
toolsMenu.addSeparator();
toolsMenu.add(toolsOptions);
@@ -595,9 +616,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 +641,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 +665,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() / 3f));
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 +715,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 +746,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 +758,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 +771,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 +783,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 +794,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 +809,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 +824,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() {
JMenuObject fft = new JMenuObject("Auto-trim all (FFT)", c, 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 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 +875,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 +897,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 +933,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 +946,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 +977,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();
@@ -1497,6 +1547,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;
@@ -2041,6 +2092,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 +2137,126 @@ public class AudiobookRecorder extends JFrame {
mainScroll.setViewportView(null);
}
}
public void openArchive() {
JFileChooser jc = new JFileChooser(new File(Options.get("path.storage"), "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();
}
}
}
}
}

View File

@@ -28,15 +28,28 @@ 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");
if (i == null) {
File icon = new File(root, "coverart.png");
if (!icon.exists()) {
icon = new File(root, "coverart.jpg");
@@ -53,6 +66,11 @@ public class BookPanel extends JPanel {
resizedCover = null;
iconLabel = new JLabel("");
}
} else {
cover = i;
resizedCover = Utils.getScaledImage(cover.getImage(), 75, 75);
iconLabel = new JLabel(new ImageIcon(resizedCover));
}
iconLabel.setSize(new Dimension(75, 75));
iconLabel.setPreferredSize(new Dimension(75, 75));

View File

@@ -574,27 +574,14 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
return null;
}
public void recognise() {
Thread t = new Thread(new Runnable() {
public void run() {
public void doRecognition(StreamSpeechRecognizer recognizer) {
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");
StreamSpeechRecognizer recognizer;
recognizer = new StreamSpeechRecognizer(sphinxConfig);
setText("[recognising...]");
AudiobookRecorder.window.bookTreeModel.reload(this);
AudioInputStream s = AudioSystem.getAudioInputStream(getFile());
AudioFormat format = getAudioFormat();
int frameSize = format.getFrameSize();
int length = (int)s.getFrameLength();
byte[] data = new byte[length * frameSize];
@@ -615,7 +602,6 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
}
}
ByteArrayInputStream bas = new ByteArrayInputStream(decimated);
recognizer.startRecognition(bas);
SpeechResult result;
@@ -629,11 +615,34 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
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() / 3f));
StreamSpeechRecognizer recognizer;
recognizer = new StreamSpeechRecognizer(sphinxConfig);
doRecognition(recognizer);
} catch (Exception e) {
e.printStackTrace();
}
}
});