Compare commits

...

17 Commits

22 changed files with 545 additions and 55 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
.DS_Store
._*
bin
AudiobookRecorder.jar
AudiobookRecorder.dmg
AudiobookRecorder.exe

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "universalJavaApplicationStub"]
path = universalJavaApplicationStub
url = ./universalJavaApplicationStub

View File

@@ -34,4 +34,4 @@ Third party software
* CMU Sphinx: https://github.com/mpatric/mp3agic * CMU Sphinx: https://github.com/mpatric/mp3agic
* JAVE ffmpeg wrapper: http://www.sauronsoftware.it/projects/jave/ * JAVE ffmpeg wrapper: http://www.sauronsoftware.it/projects/jave/
* JTattoo: 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

View File

@@ -1,3 +1,5 @@
![Application Icon](https://github.com/MajenkoProjects/AudiobookRecorder/raw/master/resources/uk/co/majenko/audiobookrecorder/icons/appIcon.png)
Audiobook Recorder 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 * 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. 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 "D" to delete the last phrase you recorded.
* Press "E" to re-record the currently selected phrase. * Press "E" to re-record the currently selected phrase.

8
TODO.md Normal file
View File

@@ -0,0 +1,8 @@
ToDo
====
* Merge chapters
* Identify and export 5 minute retail sample
* Identify and export 15 minute checkpoint
* Archive (Zip and delete) audiobooks
* File path browser buttons in options

Binary file not shown.

View File

@@ -1,6 +1,8 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<project name="Audiobook Recorder" default="build"> <project name="Audiobook Recorder" default="build">
<taskdef name="jarbundler" classname="com.ultramixer.jarbundler.JarBundler" classpath="ant-libs/jarbundler-2.3.2.jar" />
<target name="clean" description="Clean out the build directories"> <target name="clean" description="Clean out the build directories">
<delete dir="bin" /> <delete dir="bin" />
<delete file="AudiobookRecorder.jar" /> <delete file="AudiobookRecorder.jar" />
@@ -43,4 +45,46 @@
<chmod perm="0755" file="uecide.jar" /> <chmod perm="0755" file="uecide.jar" />
</target> </target>
<target name="release" depends="macapp">
</target>
<target name="macapp" depends="build">
<mkdir dir="tmp"/>
<jarbundler
name="AudiobookRecorder"
shortname="AudiobookRecorder"
icon="dist/macosx/audiobookrecorder.icns"
stubfile="universalJavaApplicationStub/src/universalJavaApplicationStub"
dir="tmp"
jar="AudiobookRecorder.jar"
mainclass="uk.co.majenko.audiobookrecorder.AudiobookRecorder"
jvmversion="1.7+"
>
</jarbundler>
<symlink link="tmp/Applications" resource="/Applications" overwrite="true" />
<!--copy file="dist/macosx/dmg.icns" tofile="tmp/.VolumeIcon.icns" /-->
<exec executable="genisoimage">
<arg value="-D" />
<arg value="-V" />
<arg value="AudiobookRecorder" />
<arg value="-no-pad" />
<arg value="-r" />
<arg value="-apple" />
<arg value="-o" />
<arg value="AudiobookRecorder.dmg" />
<arg value="-dir-mode" />
<arg value="0755" />
<arg value="-file-mode" />
<arg value="0755" />
<arg value="tmp" />
</exec>
<delete dir="tmp" />
</target>
</project> </project>

BIN
dist/macosx/audiobookrecorder.icns vendored Normal file

Binary file not shown.

BIN
dist/macosx/dmg.icns vendored Normal file

Binary file not shown.

26
installers/linux.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
NAME=AudiobookRecorder
BIN=/usr/bin
DESKTOP=/usr/share/applications
SHARE=/usr/share
ICON=/usr/share/icons
mkdir -p "$BIN"
mkdir -p "$SHARE/$NAME"
cp AudiobookRecorder.jar "$SHARE/$NAME/$NAME.jar"
echo "#!/bin/bash" > "$BIN/$NAME"
echo "java -jar \"$SHARE/$NAME/$NAME.jar\"" >> "$BIN/$NAME"
chmod 755 "$BIN/$NAME"
echo "[Desktop Entry]" > "$DESKTOP/$NAME.desktop"
echo "Version=1.0" >> "$DESKTOP/$NAME.desktop"
echo "Name=$NAME" >> "$DESKTOP/$NAME.desktop"
echo "Exec=$NAME" >> "$DESKTOP/$NAME.desktop"
echo "Icon=$NAME" >> "$DESKTOP/$NAME.desktop"
echo "Categories=Multimedia" >> "$DESKTOP/$NAME.desktop"
cp resources/uk/co/majenko/audiobookrecorder/icons/appIcon.png "$ICON/$NAME.png"

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -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("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("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("released D"), "deleteLast");
centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("SPACE"), "startPlayback"); centralPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("SPACE"), "startPlayback");
@@ -477,6 +480,12 @@ public class AudiobookRecorder extends JFrame {
startRecording(); startRecording();
} }
}); });
centralPanel.getActionMap().put("startRecordNewPara", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
if (bookTree.isEditing()) return;
startRecordingNewParagraph();
}
});
centralPanel.getActionMap().put("startRerecord", new AbstractAction() { centralPanel.getActionMap().put("startRerecord", new AbstractAction() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (bookTree.isEditing()) return; if (bookTree.isEditing()) return;
@@ -512,6 +521,18 @@ public class AudiobookRecorder extends JFrame {
pack(); pack();
setVisible(true); 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[]) { public static void main(String args[]) {
@@ -538,6 +559,9 @@ public class AudiobookRecorder extends JFrame {
prefs.setProperty("book.author", info.getAuthor()); prefs.setProperty("book.author", info.getAuthor());
prefs.setProperty("book.genre", info.getGenre()); prefs.setProperty("book.genre", info.getGenre());
prefs.setProperty("book.comment", info.getComment()); 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.name", "Opening Credits");
prefs.setProperty("chapter.open.pre-gap", Options.get("catenation.pre-chapter")); prefs.setProperty("chapter.open.pre-gap", Options.get("catenation.pre-chapter"));
prefs.setProperty("chapter.open.post-gap", Options.get("catenation.post-chapter")); prefs.setProperty("chapter.open.post-gap", Options.get("catenation.post-chapter"));
@@ -573,6 +597,40 @@ public class AudiobookRecorder extends JFrame {
} }
} }
class JMenuObject2 extends JMenuItem {
Object ob1;
Object ob2;
public JMenuObject2(String p) {
super(p);
ob1 = null;
ob2 = null;
}
public JMenuObject2(String p, Object o1, Object o2) {
super(p);
ob1 = o1;
ob2 = o2;
}
public void setObject1(Object o) {
ob1 = o;
}
public void setObject2(Object o) {
ob2 = o;
}
public Object getObject1() {
return ob1;
}
public Object getObject2() {
return ob2;
}
}
@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());
@@ -588,6 +646,52 @@ public class AudiobookRecorder extends JFrame {
JPopupMenu menu = new JPopupMenu(); JPopupMenu menu = new JPopupMenu();
JMenuObject rec = new JMenuObject("Recognise text from audio", s); JMenuObject rec = new JMenuObject("Recognise text from audio", s);
JMenu moveMenu = new JMenu("Move sentence to...");
for (Enumeration<Chapter> c = book.children(); c.hasMoreElements();) {
Chapter chp = c.nextElement();
JMenuObject2 m = new JMenuObject2(chp.getName(), s, chp);
m.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JMenuObject2 ob = (JMenuObject2)e.getSource();
Sentence sentence = (Sentence)ob.getObject1();
Chapter target = (Chapter)ob.getObject2();
bookTreeModel.removeNodeFromParent(sentence);
bookTreeModel.insertNodeInto(sentence, target, target.getChildCount());
}
});
moveMenu.add(m);
}
JMenuObject moveUp = new JMenuObject("Move Up", s);
JMenuObject moveDown = new JMenuObject("Move Down", s);
moveUp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JMenuObject o = (JMenuObject)e.getSource();
Sentence sent = (Sentence)o.getObject();
Chapter chap = (Chapter)sent.getParent();
int pos = bookTreeModel.getIndexOfChild(chap, sent);
if (pos > 0) pos--;
bookTreeModel.removeNodeFromParent(sent);
bookTreeModel.insertNodeInto(sent, chap, pos);
}
});
moveDown.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JMenuObject o = (JMenuObject)e.getSource();
Sentence sent = (Sentence)o.getObject();
Chapter chap = (Chapter)sent.getParent();
int pos = bookTreeModel.getIndexOfChild(chap, sent);
if (pos < chap.getChildCount() - 1) pos++;
bookTreeModel.removeNodeFromParent(sent);
bookTreeModel.insertNodeInto(sent, chap, pos);
}
});
JMenuObject ins = new JMenuObject("Insert sentence above", s); JMenuObject ins = new JMenuObject("Insert sentence above", s);
JMenuObject del = new JMenuObject("Delete sentence", s); JMenuObject del = new JMenuObject("Delete sentence", s);
@@ -632,6 +736,10 @@ public class AudiobookRecorder extends JFrame {
menu.add(rec); menu.add(rec);
menu.addSeparator(); menu.addSeparator();
menu.add(moveUp);
menu.add(moveDown);
menu.add(moveMenu);
menu.addSeparator();
menu.add(ins); menu.add(ins);
menu.add(del); menu.add(del);
menu.show(bookTree, e.getX(), e.getY()); menu.show(bookTree, e.getX(), e.getY());
@@ -641,18 +749,72 @@ public class AudiobookRecorder extends JFrame {
bookTree.setSelectionPath(new TreePath(c.getPath())); bookTree.setSelectionPath(new TreePath(c.getPath()));
JPopupMenu menu = new JPopupMenu(); JPopupMenu menu = new JPopupMenu();
JMenuObject ren = new JMenuObject("Rename chapter", c); JMenuObject peak = new JMenuObject("Auto-trim all (Peak)", c);
JMenuObject moveUp = new JMenuObject("Move Up", c);
JMenuObject moveDown = new JMenuObject("Move Down", c);
ren.addActionListener(new ActionListener() { int idNumber = s2i(c.getId());
moveUp.setEnabled(idNumber > 0);
moveDown.setEnabled(idNumber > 0);
moveUp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
JMenuObject o = (JMenuObject)e.getSource(); JMenuObject o = (JMenuObject)e.getSource();
Chapter c = (Chapter)o.getObject(); Chapter chap = (Chapter)o.getObject();
c.renameChapter(); int pos = bookTreeModel.getIndexOfChild(book, chap);
bookTreeModel.reload(c); if (pos > 0) pos--;
int id = s2i(chap.getId());
if (id > 0) {
Chapter prevChap = (Chapter)bookTreeModel.getChild(book, pos);
id = s2i(prevChap.getId());
if (id > 0) {
bookTreeModel.removeNodeFromParent(chap);
bookTreeModel.insertNodeInto(chap, book, pos);
}
}
}
});
moveDown.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JMenuObject o = (JMenuObject)e.getSource();
Chapter chap = (Chapter)o.getObject();
int pos = bookTreeModel.getIndexOfChild(book, chap);
pos++;
int id = s2i(chap.getId());
if (id > 0) {
Chapter nextChap = (Chapter)bookTreeModel.getChild(book, pos);
if (nextChap != null) {
id = s2i(nextChap.getId());
if (id > 0) {
bookTreeModel.removeNodeFromParent(chap);
bookTreeModel.insertNodeInto(chap, book, pos);
}
}
}
} }
}); });
menu.add(ren); peak.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JMenuObject o = (JMenuObject)e.getSource();
Chapter c = (Chapter)o.getObject();
for (Enumeration<Sentence> s = c.children(); s.hasMoreElements();) {
Sentence snt = s.nextElement();
if (!snt.isLocked()) {
snt.autoTrimSamplePeak();
}
}
}
});
menu.add(moveUp);
menu.add(moveDown);
menu.addSeparator();
menu.add(peak);
menu.show(bookTree, e.getX(), e.getY()); menu.show(bookTree, e.getX(), e.getY());
} }
@@ -687,6 +849,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() { public void startRecording() {
if (recording != null) return; if (recording != null) return;
@@ -851,6 +1060,15 @@ public class AudiobookRecorder extends JFrame {
prefs.loadFromXML(fis); prefs.loadFromXML(fis);
buildBook(prefs); buildBook(prefs);
File r = f.getParentFile();
File cf = new File(r, "coverart.png");
if (cf.exists()) {
ImageIcon i = new ImageIcon(cf.getAbsolutePath());
Image ri = Utils.getScaledImage(i.getImage(), 22, 22);
book.setIcon(new ImageIcon(ri));
bookTreeModel.reload(book);
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -950,7 +1168,25 @@ public class AudiobookRecorder extends JFrame {
mainScroll.setViewportView(bookTree); 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.setPostGap(s2i(prefs.getProperty("chapter.open.post-gap")));
c.setPreGap(s2i(prefs.getProperty("chapter.open.pre-gap"))); c.setPreGap(s2i(prefs.getProperty("chapter.open.pre-gap")));
bookTreeModel.insertNodeInto(c, book, 0); bookTreeModel.insertNodeInto(c, book, 0);
@@ -968,6 +1204,8 @@ public class AudiobookRecorder extends JFrame {
bookTreeModel.insertNodeInto(s, c, c.getChildCount()); bookTreeModel.insertNodeInto(s, c, c.getChildCount());
} }
for (int cno = 1; cno < 10000; cno++) { for (int cno = 1; cno < 10000; cno++) {
String cname = prefs.getProperty(String.format("chapter.%04d.name", cno)); String cname = prefs.getProperty(String.format("chapter.%04d.name", cno));
if (cname == null) break; if (cname == null) break;
@@ -1013,6 +1251,7 @@ public class AudiobookRecorder extends JFrame {
toolBar.enableBook(); toolBar.enableBook();
statusLabel.setText("Noise floor: " + getNoiseFloor()); statusLabel.setText("Noise floor: " + getNoiseFloor());
book.setIcon(Icons.book);
} }
public void openBook() { public void openBook() {
@@ -1037,6 +1276,9 @@ public class AudiobookRecorder extends JFrame {
} }
loadBookStructure(f); loadBookStructure(f);
Options.set("path.last-book", book.getName());
Options.savePreferences();
} }
@@ -1233,6 +1475,7 @@ public class AudiobookRecorder extends JFrame {
tags.setTrack(Integer.toString(s2i(c.getId()) - 0)); tags.setTrack(Integer.toString(s2i(c.getId()) - 0));
tags.setTitle(c.getName()); tags.setTitle(c.getName());
tags.setAlbum(book.getName());
tags.setArtist(book.getAuthor()); tags.setArtist(book.getAuthor());
// ID3v2TextFrameData g = new ID3v2TextFrameData(false, new EncodedText(book.getGenre())); // ID3v2TextFrameData g = new ID3v2TextFrameData(false, new EncodedText(book.getGenre()));
@@ -1310,7 +1553,6 @@ public class AudiobookRecorder extends JFrame {
bookTree.setSelectionPath(new TreePath(s.getPath())); bookTree.setSelectionPath(new TreePath(s.getPath()));
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
playing = null; playing = null;
} }
toolBar.enableSentence(); toolBar.enableSentence();

View File

@@ -16,6 +16,8 @@ public class Book extends DefaultMutableTreeNode {
String genre; String genre;
String comment; String comment;
ImageIcon icon;
public Book(String bookname) { public Book(String bookname) {
super(bookname); super(bookname);
name = bookname; name = bookname;
@@ -99,4 +101,39 @@ public class Book extends DefaultMutableTreeNode {
public String getName() { public String getName() {
return name; return name;
} }
public ImageIcon getIcon() {
return icon;
}
public void setIcon(ImageIcon i) {
icon = i;
}
public void setUserObject(Object o) {
if (o instanceof String) {
String newName = (String)o;
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 (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();
}
}
}
public String toString() {
return name;
}
} }

View File

@@ -0,0 +1,96 @@
package uk.co.majenko.audiobookrecorder;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.border.*;
import java.util.*;
import java.io.*;
public class BookPanel extends JPanel {
String name;
String author;
String genre;
String comment;
ImageIcon cover;
Image resizedCover;
JLabel iconLabel;
JLabel titleLabel;
JLabel authorLabel;
JLabel otherLabel;
JPanel panel;
File root;
boolean highlight = false;
public BookPanel(File r) {
try {
root = r;
Properties props = new Properties();
props.loadFromXML(new FileInputStream(new File(root, "audiobook.abk")));
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()) {
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("");
}
iconLabel.setSize(new Dimension(75, 75));
iconLabel.setPreferredSize(new Dimension(75, 75));
titleLabel = new JLabel(name);
authorLabel = new JLabel(author);
otherLabel = new JLabel(genre + " :: " + comment);
authorLabel.setForeground(new Color(0x80, 0x80, 0x80));
otherLabel.setForeground(new Color(0x80, 0x80, 0x80));
setLayout(new BorderLayout());
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setBorder(new EmptyBorder(10, 10, 10, 10));
panel.add(titleLabel);
panel.add(authorLabel);
panel.add(otherLabel);
add(iconLabel, BorderLayout.WEST);
add(panel, BorderLayout.CENTER);
panel.setBackground(new Color(0x20, 0x20, 0x20));
panel.setOpaque(true);
setBackground(new Color(0x20, 0x20, 0x20));
setOpaque(true);
} catch (Exception e) {
}
}
public File getConfigFile() {
return new File(root, "audiobook.abk");
}
public void highlight() {
setBackground(new Color(0x00, 0x20, 0x40));
panel.setBackground(new Color(0x00, 0x20, 0x40));
}
public void lowlight() {
setBackground(new Color(0x20, 0x20, 0x20));
panel.setBackground(new Color(0x20, 0x20, 0x20));
}
}

View File

@@ -19,7 +19,7 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer {
} else if (value instanceof Chapter) { } else if (value instanceof Chapter) {
ret.setIcon(Icons.chapter); ret.setIcon(Icons.chapter);
} else if (value instanceof Book) { } else if (value instanceof Book) {
ret.setIcon(Icons.book); ret.setIcon(((Book)value).getIcon());
} }
return ret; return ret;
} }

View File

@@ -37,13 +37,6 @@ public class Chapter extends DefaultMutableTreeNode {
return null; return null;
} }
public void renameChapter() {
String n = JOptionPane.showInputDialog(null, "Rename Chapter", name);
if (n != null) {
name = n;
}
}
public String toString() { public String toString() {
return name; return name;
} }

View File

@@ -28,13 +28,28 @@ public class OpenBookPanel extends JPanel {
} }
} }
public class BookCellRenderer implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value == null) return null;
BookPanel p = (BookPanel)value;
if (isSelected) {
p.highlight();
} else {
p.lowlight();
}
return p;
}
};
class BookTableModel extends AbstractTableModel { class BookTableModel extends AbstractTableModel {
ArrayList<BookInfo> books; ArrayList<BookPanel> books;
public BookTableModel() { public BookTableModel() {
super(); super();
books = new ArrayList<BookInfo>(); books = new ArrayList<BookPanel>();
} }
public int getRowCount() { public int getRowCount() {
@@ -42,38 +57,27 @@ public class OpenBookPanel extends JPanel {
} }
public int getColumnCount() { public int getColumnCount() {
return 4; return 1;
} }
public boolean isCellEditable(int row, int column) { public boolean isCellEditable(int row, int column) {
return false; return false;
} }
public void addBook(BookInfo b) { public void addBook(BookPanel b) {
books.add(b); books.add(b);
} }
public Object getValueAt(int r, int c) { public Object getValueAt(int r, int c) {
if (c > 3) return null; return books.get(r);
if (r > books.size()) return null;
BookInfo b = books.get(r);
switch (c) {
case 0: return b.name;
case 1: return b.author;
case 2: return b.genre;
case 4: return b.comment;
}
return null;
} }
public String getColumnName(int i) { public String getColumnName(int i) {
switch(i) { return "Book";
case 0: return "Name"; }
case 1: return "Author";
case 2: return "Genre"; public Class getColumnClass(int i) {
case 3: return "Comment"; return BookPanel.class;
}
return null;
} }
} }
@@ -85,7 +89,6 @@ public class OpenBookPanel extends JPanel {
model = new BookTableModel(); model = new BookTableModel();
setLayout(new BorderLayout()); setLayout(new BorderLayout());
scroll = new JScrollPane(); scroll = new JScrollPane();
add(scroll, BorderLayout.CENTER); add(scroll, BorderLayout.CENTER);
@@ -97,22 +100,17 @@ public class OpenBookPanel extends JPanel {
if (!b.isDirectory()) continue; if (!b.isDirectory()) continue;
File xml = new File(b, "audiobook.abk"); File xml = new File(b, "audiobook.abk");
if (xml.exists()) { if (xml.exists()) {
Properties props = new Properties(); BookPanel book = new BookPanel(b);
props.loadFromXML(new FileInputStream(xml));
BookInfo book = new BookInfo(
props.getProperty("book.name"),
props.getProperty("book.author"),
props.getProperty("book.genre"),
props.getProperty("book.comment")
);
model.addBook(book); model.addBook(book);
} }
} }
table = new JTable(model); table = new JTable(model);
table.setDefaultRenderer(BookPanel.class, new BookCellRenderer());
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setRowHeight(80);
table.getTableHeader().setUI(null);
scroll.setViewportView(table); scroll.setViewportView(table);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -126,9 +124,7 @@ public class OpenBookPanel extends JPanel {
return null; return null;
} }
String name = (String)table.getValueAt(sel, 0); BookPanel b = (BookPanel)table.getValueAt(sel, 0);
File d = new File(Options.get("path.storage"), name); return b.getConfigFile();
File f = new File(d, "audiobook.abk");
return f;
} }
} }

View File

@@ -21,6 +21,7 @@ public class Options extends JDialog {
JSpinner preChapterGap; JSpinner preChapterGap;
JSpinner postChapterGap; JSpinner postChapterGap;
JSpinner postSentenceGap; JSpinner postSentenceGap;
JSpinner postParagraphGap;
JTextField ffmpegLocation; JTextField ffmpegLocation;
JComboBox<KVPair> bitRate; JComboBox<KVPair> bitRate;
JComboBox<KVPair> exportRate; 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"); 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"); 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"); 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(); addSeparator();
@@ -277,7 +279,7 @@ public class Options extends JDialog {
} }
if (supported) { if (supported) {
KVPair p = new KVPair(i.getName(), i.getDescription()); KVPair p = new KVPair(i.getName(), i.getName()); //i.getDescription());
list.add(p); list.add(p);
} }
} }
@@ -316,7 +318,7 @@ public class Options extends JDialog {
if (supported) { if (supported) {
KVPair p = new KVPair(i.getName(), i.getDescription()); KVPair p = new KVPair(i.getName(), i.getName()); //i.getDescription());
list.add(p); list.add(p);
} }
} }
@@ -361,6 +363,7 @@ public class Options extends JDialog {
defaultPrefs.put("catenation.pre-chapter", "2000"); defaultPrefs.put("catenation.pre-chapter", "2000");
defaultPrefs.put("catenation.post-chapter", "2000"); defaultPrefs.put("catenation.post-chapter", "2000");
defaultPrefs.put("catenation.post-sentence", "1000"); 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.storage", (new File(System.getProperty("user.home"), "Recordings")).toString());
defaultPrefs.put("path.ffmpeg", ""); defaultPrefs.put("path.ffmpeg", "");
@@ -426,6 +429,7 @@ public class Options extends JDialog {
set("catenation.pre-chapter", "" + preChapterGap.getValue()); set("catenation.pre-chapter", "" + preChapterGap.getValue());
set("catenation.post-chapter", "" + postChapterGap.getValue()); set("catenation.post-chapter", "" + postChapterGap.getValue());
set("catenation.post-sentence", "" + postSentenceGap.getValue()); set("catenation.post-sentence", "" + postSentenceGap.getValue());
set("catenation.post-paragraph", "" + postParagraphGap.getValue());
set("audio.export.bitrate", ((KVPair)bitRate.getSelectedItem()).key); set("audio.export.bitrate", ((KVPair)bitRate.getSelectedItem()).key);
set("audio.export.samplerate", ((KVPair)exportRate.getSelectedItem()).key); set("audio.export.samplerate", ((KVPair)exportRate.getSelectedItem()).key);
set("process.sphinx", enableParsing.isSelected() ? "true" : "false"); set("process.sphinx", enableParsing.isSelected() ? "true" : "false");

View File

@@ -222,6 +222,8 @@ public class Sentence extends DefaultMutableTreeNode {
startOffset = 0; startOffset = 0;
} }
startOffset -= 4096;
for (int i = samples.length-1; i >= 0; i--) { for (int i = samples.length-1; i >= 0; i--) {
endOffset = i; endOffset = i;
if (Math.abs(samples[i]) > noiseFloor) { if (Math.abs(samples[i]) > noiseFloor) {
@@ -230,10 +232,16 @@ public class Sentence extends DefaultMutableTreeNode {
break; break;
} }
} }
endOffset += 4096;
if (endOffset <= startOffset) endOffset = startOffset + 4096; if (endOffset <= startOffset) endOffset = startOffset + 4096;
if (endOffset <= 0) { if (endOffset <= 0) {
endOffset = samples.length-1; endOffset = samples.length-1;
} }
if (startOffset < 0) startOffset = 0;
if (endOffset >= samples.length) endOffset = samples.length-1;
} }
public String getId() { public String getId() {

View File

@@ -0,0 +1,23 @@
package uk.co.majenko.audiobookrecorder;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.border.*;
import java.util.*;
import java.io.*;
public class Utils {
public static Image getScaledImage(Image srcImg, int w, int h){
BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = resizedImg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(srcImg, 0, 0, w, h, null);
g2.dispose();
return resizedImg;
}
}