Implemented export profiles
This commit is contained in:
21
ExampleExportFilters/librivox.abprof
Normal file
21
ExampleExportFilters/librivox.abprof
Normal file
@@ -0,0 +1,21 @@
|
||||
<profile>
|
||||
<code>librivox</code>
|
||||
<name>LibriVox.org</name>
|
||||
<export>
|
||||
<bitrate>128000</bitrate>
|
||||
<channels>1</channels>
|
||||
<samples>44100</samples>
|
||||
<format>{chapter.name:lower}_{book.author.short:lower}_{narrator.initials:lower}_{file.bitrate.kb}kb</format>
|
||||
</export>
|
||||
<gaps>
|
||||
<pre-chapter>500</pre-chapter>
|
||||
<post-chapter>5000</post-chapter>
|
||||
<post-sentence>400</post-sentence>
|
||||
<followon>100</followon>
|
||||
<post-paragraph>1000</post-paragraph>
|
||||
<post-section>1200</post-section>
|
||||
</gaps>
|
||||
<audio>
|
||||
<rms>-19</rms>
|
||||
</audio>
|
||||
</profile>
|
||||
@@ -6,6 +6,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
@@ -119,6 +120,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
|
||||
public static CommandLine CLI = new CommandLine();
|
||||
|
||||
public static HashMap<String, ExportProfile> exportProfiles = new HashMap<String, ExportProfile>();
|
||||
|
||||
MainToolBar toolBar;
|
||||
|
||||
JMenuBar menuBar;
|
||||
@@ -357,6 +360,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
|
||||
Options.loadPreferences();
|
||||
|
||||
loadExportProfiles();
|
||||
|
||||
queueMonitor = new QueueMonitor(processQueue);
|
||||
|
||||
for (int i = 0; i < Options.getInteger("process.threads"); i++) {
|
||||
@@ -1079,7 +1084,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
|
||||
public void createNewBook() {
|
||||
Debug.trace();
|
||||
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;
|
||||
|
||||
@@ -1634,10 +1639,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
}
|
||||
});
|
||||
|
||||
JMenu exportChapter = new JMenu("Export chapter...");
|
||||
|
||||
|
||||
JMenuObject exportChapterACX = new JMenuObject("For ACX", c, new ActionListener() {
|
||||
JMenuObject exportChapter = new JMenuObject("Export Chapter", c, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Debug.trace();
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
@@ -1645,37 +1647,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
|
||||
ProgressDialog ed = new ProgressDialog("Exporting " + chap.getName());
|
||||
|
||||
ExportThread t = new ExportThread(chap, ed, "{book.title} - {chapter.number}");
|
||||
Thread nt = new Thread(t);
|
||||
nt.start();
|
||||
ed.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
JMenuObject exportChapterABU = new JMenuObject("For Audiobooks Unleashed", c, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Debug.trace();
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter chap = (Chapter)o.getObject();
|
||||
|
||||
ProgressDialog ed = new ProgressDialog("Exporting " + chap.getName());
|
||||
|
||||
ExportThread t = new ExportThread(chap, ed, "{book.isbn}_{chapter.number}");
|
||||
Thread nt = new Thread(t);
|
||||
nt.start();
|
||||
ed.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
JMenuObject exportChapterLibri = new JMenuObject("For LibriVox.org", c, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Debug.trace();
|
||||
JMenuObject o = (JMenuObject)e.getSource();
|
||||
Chapter chap = (Chapter)o.getObject();
|
||||
|
||||
ProgressDialog ed = new ProgressDialog("Exporting " + chap.getName());
|
||||
|
||||
ExportThread t = new ExportThread(chap, ed, "{chapter.name:lower}_{book.author:lower}_{narrator.initials:lower}_{file.bitrate.kb}kb");
|
||||
ExportThread t = new ExportThread(chap, ed);
|
||||
Thread nt = new Thread(t);
|
||||
nt.start();
|
||||
ed.setVisible(true);
|
||||
@@ -1785,9 +1757,6 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
menu.addSeparator();
|
||||
menu.add(importWav);
|
||||
menu.add(exportChapter);
|
||||
exportChapter.add(exportChapterACX);
|
||||
exportChapter.add(exportChapterABU);
|
||||
exportChapter.add(exportChapterLibri);
|
||||
menu.addSeparator();
|
||||
menu.add(deleteChapter);
|
||||
menu.addSeparator();
|
||||
@@ -1841,35 +1810,16 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
JMenu exportAll = new JMenu("Export All Audio...");
|
||||
menu.add(exportAll);
|
||||
|
||||
exportAll.add(new JMenuObject("For ACX", book, new ActionListener() {
|
||||
JMenuObject exportAll = new JMenuObject("Export Book", book, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Debug.trace();
|
||||
JMenuObject src = (JMenuObject)(e.getSource());
|
||||
Book thisBook = (Book)(src.getObject());
|
||||
exportAudio(thisBook, "{book.title} - {chapter.number}");
|
||||
exportAudio(thisBook);
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
exportAll.add(new JMenuObject("For Audiobooks Unleashed", book, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Debug.trace();
|
||||
JMenuObject src = (JMenuObject)(e.getSource());
|
||||
Book thisBook = (Book)(src.getObject());
|
||||
exportAudio(thisBook, "{book.isbn}_{chapter.number}");
|
||||
}
|
||||
}));
|
||||
|
||||
exportAll.add(new JMenuObject("For LibriVox.org", book, new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Debug.trace();
|
||||
JMenuObject src = (JMenuObject)(e.getSource());
|
||||
Book thisBook = (Book)(src.getObject());
|
||||
exportAudio(thisBook, "{chapter.name:lower}_{book.author:lower}_{narrator.initials:lower}_{file.bitrate.kb}kb");
|
||||
}
|
||||
}));
|
||||
menu.add(exportAll);
|
||||
|
||||
JMenu visitACX = new JMenu("Visit ACX");
|
||||
|
||||
@@ -2335,8 +2285,6 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
|
||||
public Chapter convertChapter(String name, String id, Properties data) {
|
||||
Chapter c = new Chapter(id, data.getProperty("chapter." + name + ".name"));
|
||||
c.setPostGap(Utils.s2i(data.getProperty("chapter." + name + ".post-gap")));
|
||||
c.setPreGap(Utils.s2i(data.getProperty("chapter." + name + ".pre-gap")));
|
||||
|
||||
for (int i = 0; i < 100000000; i++) {
|
||||
String sid = data.getProperty(String.format("chapter." + name + ".sentence.%08d.id", i));
|
||||
@@ -2517,14 +2465,12 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
class ExportThread implements Runnable {
|
||||
ProgressDialog exportDialog;
|
||||
Chapter chapter;
|
||||
String format;
|
||||
|
||||
public ExportThread(Chapter c, ProgressDialog e, String f) {
|
||||
public ExportThread(Chapter c, ProgressDialog e) {
|
||||
super();
|
||||
Debug.trace();
|
||||
exportDialog = e;
|
||||
chapter = c;
|
||||
format = f;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -2532,7 +2478,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
Debug.trace();
|
||||
|
||||
try {
|
||||
chapter.exportChapter(exportDialog, format);
|
||||
chapter.exportChapter(exportDialog);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -2542,7 +2488,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void exportAudio(Book book, String format) {
|
||||
public void exportAudio(Book book) {
|
||||
Debug.trace();
|
||||
|
||||
for (Enumeration o = book.children(); o.hasMoreElements();) {
|
||||
@@ -2550,7 +2496,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
if (c.getChildCount() == 0) continue;
|
||||
ProgressDialog ed = new ProgressDialog("Exporting " + c.getName());
|
||||
|
||||
ExportThread t = new ExportThread(c, ed, format);
|
||||
ExportThread t = new ExportThread(c, ed);
|
||||
Thread nt = new Thread(t);
|
||||
nt.start();
|
||||
ed.setVisible(true);
|
||||
@@ -3601,13 +3547,21 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
|
||||
public void editBookInfo(Book book) {
|
||||
JTabbedPane tabs = new JTabbedPane();
|
||||
String epc = "";
|
||||
if (book.getExportProfile() != null) {
|
||||
epc = book.getExportProfile().getCode();
|
||||
}
|
||||
|
||||
BookInfoPanel info = new BookInfoPanel(
|
||||
book.getName(),
|
||||
book.getShortTitle(),
|
||||
book.getAuthor(),
|
||||
book.getShortAuthor(),
|
||||
book.getGenre(),
|
||||
book.getComment(),
|
||||
book.getACX(),
|
||||
book.getISBN()
|
||||
book.getISBN(),
|
||||
epc
|
||||
);
|
||||
tabs.add("Data", info);
|
||||
|
||||
@@ -3644,7 +3598,9 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
if (r != JOptionPane.OK_OPTION) return;
|
||||
|
||||
String tit = info.getTitle();
|
||||
String stit = info.getShortTitle();
|
||||
String aut = info.getAuthor();
|
||||
String saut = info.getShortAuthor();
|
||||
String gen = info.getGenre();
|
||||
String com = info.getComment();
|
||||
String acx = info.getACX();
|
||||
@@ -3656,11 +3612,14 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
book.setDefaultEffect(de.getKey());
|
||||
}
|
||||
book.setTitle(tit);
|
||||
book.setShortTitle(stit);
|
||||
book.setAuthor(aut);
|
||||
book.setShortAuthor(saut);
|
||||
book.setGenre(gen);
|
||||
book.setComment(com);
|
||||
book.setACX(acx);
|
||||
book.setISBN(isbn);
|
||||
book.setExportProfile(info.getExportProfile());
|
||||
// if (!(book().getName().equals(tit))) {
|
||||
// book().renameBook(tit);
|
||||
// }
|
||||
@@ -3708,4 +3667,21 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadExportProfiles() {
|
||||
exportProfiles.clear();
|
||||
ExportProfile dp = new ExportProfile();
|
||||
exportProfiles.put(dp.getCode(), dp);
|
||||
File system = new File(Options.get("path.storage"), "system");
|
||||
if (system.exists() && system.isDirectory()) {
|
||||
File profiles = new File(system, "profiles");
|
||||
for (File f : profiles.listFiles()) {
|
||||
if (f.getName().endsWith(".abprof")) {
|
||||
ExportProfile p = new ExportProfile(f);
|
||||
exportProfiles.put(p.getCode(), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@ import org.xml.sax.SAXException;
|
||||
public class Book extends BookTreeNode {
|
||||
|
||||
String name;
|
||||
String shortName;
|
||||
String author;
|
||||
String shortAuthor;
|
||||
String genre;
|
||||
String comment;
|
||||
String ACX;
|
||||
@@ -53,6 +55,7 @@ public class Book extends BookTreeNode {
|
||||
Random rng = new Random();
|
||||
TreeMap<String, EffectGroup> effects;
|
||||
AudioFormat cachedFormat = null;
|
||||
ExportProfile exportProfile;
|
||||
|
||||
public Book(String bookname) {
|
||||
super(bookname);
|
||||
@@ -78,13 +81,16 @@ public class Book extends BookTreeNode {
|
||||
Element root = doc.getDocumentElement();
|
||||
|
||||
name = getTextNode(root, "title");
|
||||
shortName = getTextNode(root, "shorttitle");
|
||||
author = getTextNode(root, "author");
|
||||
shortAuthor = getTextNode(root, "shortauthor");
|
||||
genre = getTextNode(root, "genre");
|
||||
comment = getTextNode(root, "comment");
|
||||
ACX = getTextNode(root, "acx");
|
||||
ISBN = getTextNode(root, "isbn");
|
||||
manuscript = getTextNode(root, "manuscript");
|
||||
notes = getTextNode(root, "notes");
|
||||
exportProfile = AudiobookRecorder.exportProfiles.get(getTextNode(root, "exportprofile"));
|
||||
|
||||
Element settings = getNode(root, "settings");
|
||||
Element audioSettings = getNode(settings, "audio");
|
||||
@@ -131,13 +137,16 @@ public class Book extends BookTreeNode {
|
||||
public void loadBookXML(Element root, DefaultTreeModel model) {
|
||||
Debug.trace();
|
||||
name = getTextNode(root, "title");
|
||||
shortName = getTextNode(root, "shorttitle");
|
||||
author = getTextNode(root, "author");
|
||||
shortAuthor = getTextNode(root, "shortauthor");
|
||||
genre = getTextNode(root, "genre");
|
||||
comment = getTextNode(root, "comment");
|
||||
ACX = getTextNode(root, "acx");
|
||||
ISBN = getTextNode(root, "isbn");
|
||||
manuscript = getTextNode(root, "manuscript");
|
||||
notes = getTextNode(root, "notes");
|
||||
exportProfile = AudiobookRecorder.exportProfiles.get(getTextNode(root, "exportprofile"));
|
||||
|
||||
Element settings = getNode(root, "settings");
|
||||
Element audioSettings = getNode(settings, "audio");
|
||||
@@ -182,14 +191,18 @@ public class Book extends BookTreeNode {
|
||||
}
|
||||
|
||||
public void setTitle(String n) { Debug.trace(); name = n; }
|
||||
public void setShortTitle(String n) { Debug.trace(); shortName = n; }
|
||||
public void setAuthor(String a) { Debug.trace(); author = a; }
|
||||
public void setShortAuthor(String a) { Debug.trace(); shortAuthor = a; }
|
||||
public void setGenre(String g) { Debug.trace(); genre = g; }
|
||||
public void setComment(String c) { Debug.trace(); comment = c; }
|
||||
public void setACX(String c) { Debug.trace(); ACX = c; }
|
||||
public void setISBN(String c) { Debug.trace(); ISBN = c; }
|
||||
|
||||
public String getTitle() { Debug.trace(); return name; }
|
||||
public String getShortTitle() { Debug.trace(); return shortName; }
|
||||
public String getAuthor() { Debug.trace(); return author; }
|
||||
public String getShortAuthor() { Debug.trace(); return shortAuthor; }
|
||||
public String getGenre() { Debug.trace(); return genre; }
|
||||
public String getComment() { Debug.trace(); return comment; }
|
||||
public String getACX() { Debug.trace(); if (ACX == null) return ""; return ACX; }
|
||||
@@ -379,6 +392,8 @@ public class Book extends BookTreeNode {
|
||||
doc.appendChild(root);
|
||||
|
||||
root.appendChild(makeTextNode(doc, "title", name));
|
||||
root.appendChild(makeTextNode(doc, "shortauthor", shortAuthor));
|
||||
root.appendChild(makeTextNode(doc, "shorttitle", shortName));
|
||||
root.appendChild(makeTextNode(doc, "author", author));
|
||||
root.appendChild(makeTextNode(doc, "comment", comment));
|
||||
root.appendChild(makeTextNode(doc, "genre", genre));
|
||||
@@ -386,6 +401,9 @@ public class Book extends BookTreeNode {
|
||||
root.appendChild(makeTextNode(doc, "isbn", ISBN));
|
||||
root.appendChild(makeTextNode(doc, "manuscript", manuscript));
|
||||
root.appendChild(makeTextNode(doc, "notes", notes));
|
||||
if (exportProfile != null) {
|
||||
root.appendChild(makeTextNode(doc, "exportprofile", exportProfile.getCode()));
|
||||
}
|
||||
|
||||
Element settingsNode = doc.createElement("settings");
|
||||
root.appendChild(settingsNode);
|
||||
@@ -698,4 +716,15 @@ public class Book extends BookTreeNode {
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
public ExportProfile getExportProfile() {
|
||||
if (exportProfile == null) {
|
||||
return AudiobookRecorder.exportProfiles.get("librivox");
|
||||
}
|
||||
return exportProfile;
|
||||
}
|
||||
|
||||
public void setExportProfile(ExportProfile p) {
|
||||
exportProfile = p;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,17 +8,21 @@ import java.awt.GridBagConstraints;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JComboBox;
|
||||
|
||||
public class BookInfoPanel extends JPanel {
|
||||
|
||||
JTextField title;
|
||||
JTextField shortTitle;
|
||||
JTextField author;
|
||||
JTextField shortAuthor;
|
||||
JTextField genre;
|
||||
JTextField comment;
|
||||
JTextField acx;
|
||||
JTextField isbn;
|
||||
JComboBox<ExportProfile> exportProfile;
|
||||
|
||||
public BookInfoPanel(String t, String a, String g, String c, String x, String i) {
|
||||
public BookInfoPanel(String t, String st, String a, String sa, String g, String c, String x, String i, String epc) {
|
||||
super();
|
||||
Debug.trace();
|
||||
setLayout(new GridBagLayout());
|
||||
@@ -36,6 +40,15 @@ public class BookInfoPanel extends JPanel {
|
||||
con.gridx = 0;
|
||||
con.gridy++;
|
||||
|
||||
add(new JLabel("Short Title:"), con);
|
||||
con.gridx = 1;
|
||||
shortTitle = new JTextField(st);
|
||||
shortTitle.setPreferredSize(new Dimension(200, 20));
|
||||
add(shortTitle, con);
|
||||
|
||||
con.gridx = 0;
|
||||
con.gridy++;
|
||||
|
||||
add(new JLabel("Author:"), con);
|
||||
con.gridx = 1;
|
||||
author = new JTextField(a);
|
||||
@@ -45,6 +58,15 @@ public class BookInfoPanel extends JPanel {
|
||||
con.gridx = 0;
|
||||
con.gridy++;
|
||||
|
||||
add(new JLabel("Short Author:"), con);
|
||||
con.gridx = 1;
|
||||
shortAuthor = new JTextField(sa);
|
||||
shortAuthor.setPreferredSize(new Dimension(200, 20));
|
||||
add(shortAuthor, con);
|
||||
|
||||
con.gridx = 0;
|
||||
con.gridy++;
|
||||
|
||||
add(new JLabel("Genre:"), con);
|
||||
con.gridx = 1;
|
||||
genre = new JTextField(g);
|
||||
@@ -81,6 +103,20 @@ public class BookInfoPanel extends JPanel {
|
||||
con.gridx = 0;
|
||||
con.gridy++;
|
||||
|
||||
add(new JLabel("Export Profile:"), con);
|
||||
con.gridx = 1;
|
||||
exportProfile = new JComboBox<ExportProfile>();
|
||||
for (ExportProfile profile : AudiobookRecorder.exportProfiles.values()) {
|
||||
exportProfile.addItem(profile);
|
||||
if (profile.getCode() == epc) {
|
||||
exportProfile.setSelectedItem(profile);
|
||||
}
|
||||
}
|
||||
add(exportProfile, con);
|
||||
|
||||
con.gridx = 0;
|
||||
con.gridy++;
|
||||
|
||||
}
|
||||
|
||||
public String getTitle() { Debug.trace(); return title.getText(); }
|
||||
@@ -97,6 +133,9 @@ public class BookInfoPanel extends JPanel {
|
||||
}
|
||||
return acx.getText();
|
||||
}
|
||||
public String getShortTitle() { Debug.trace(); return shortTitle.getText(); }
|
||||
public String getShortAuthor() { Debug.trace(); return shortAuthor.getText(); }
|
||||
public ExportProfile getExportProfile() { Debug.trace(); return (ExportProfile)exportProfile.getSelectedItem(); }
|
||||
|
||||
public void setTitle(String t) { Debug.trace(); title.setText(t); }
|
||||
public void setAuthor(String a) { Debug.trace(); author.setText(a); }
|
||||
@@ -104,5 +143,7 @@ public class BookInfoPanel extends JPanel {
|
||||
public void setComment(String c) { Debug.trace(); comment.setText(c); }
|
||||
public void setACX(String a) { Debug.trace(); acx.setText(a); }
|
||||
public void setISBN(String i) { Debug.trace(); isbn.setText(i); }
|
||||
|
||||
public void setShortTitle(String t) { Debug.trace(); shortTitle.setText(t); }
|
||||
public void setShortAuthor(String a) { Debug.trace(); shortAuthor.setText(a); }
|
||||
public void setExportProfile(ExportProfile p) { Debug.trace(); exportProfile.setSelectedItem(p); }
|
||||
}
|
||||
|
||||
@@ -51,9 +51,6 @@ public class Chapter extends BookTreeNode {
|
||||
String name;
|
||||
String id;
|
||||
|
||||
int preGap;
|
||||
int postGap;
|
||||
|
||||
String notes;
|
||||
Book parentBook = null;
|
||||
|
||||
@@ -62,16 +59,12 @@ public class Chapter extends BookTreeNode {
|
||||
Debug.trace();
|
||||
id = i;
|
||||
name = chaptername;
|
||||
preGap = Options.getInteger("catenation.pre-chapter");
|
||||
postGap = Options.getInteger("catenation.post-chapter");
|
||||
}
|
||||
|
||||
public Chapter(Element root, DefaultTreeModel model) {
|
||||
Debug.trace();
|
||||
name = Book.getTextNode(root, "name");
|
||||
id = root.getAttribute("id");
|
||||
preGap = Utils.s2i(Book.getTextNode(root, "pre-gap"));
|
||||
postGap = Utils.s2i(Book.getTextNode(root, "post-gap"));
|
||||
|
||||
notes = Book.getTextNode(root, "notes");
|
||||
|
||||
@@ -89,8 +82,6 @@ public class Chapter extends BookTreeNode {
|
||||
Debug.trace();
|
||||
name = Book.getTextNode(root, "name");
|
||||
id = root.getAttribute("id");
|
||||
preGap = Utils.s2i(Book.getTextNode(root, "pre-gap"));
|
||||
postGap = Utils.s2i(Book.getTextNode(root, "post-gap"));
|
||||
|
||||
notes = Book.getTextNode(root, "notes");
|
||||
|
||||
@@ -160,26 +151,6 @@ public class Chapter extends BookTreeNode {
|
||||
name = n;
|
||||
}
|
||||
|
||||
public void setPreGap(int g) {
|
||||
Debug.trace();
|
||||
preGap = g;
|
||||
}
|
||||
|
||||
public int getPreGap() {
|
||||
Debug.trace();
|
||||
return preGap;
|
||||
}
|
||||
|
||||
public void setPostGap(int g) {
|
||||
Debug.trace();
|
||||
postGap = g;
|
||||
}
|
||||
|
||||
public int getPostGap() {
|
||||
Debug.trace();
|
||||
return postGap;
|
||||
}
|
||||
|
||||
public String createFilename(String format) {
|
||||
String out = "";
|
||||
|
||||
@@ -198,13 +169,15 @@ public class Chapter extends BookTreeNode {
|
||||
tokens.put("chapter.number", Integer.toString(getSequenceNumber()));
|
||||
tokens.put("chapter.id", getId());
|
||||
tokens.put("book.title", book.getTitle());
|
||||
tokens.put("book.title.short", book.getShortTitle());
|
||||
tokens.put("book.author", book.getAuthor());
|
||||
tokens.put("book.author.short", book.getShortAuthor());
|
||||
tokens.put("book.isbn", book.getISBN());
|
||||
tokens.put("book.acx", book.getACX());
|
||||
tokens.put("narrator.name", Options.get("narrator.name"));
|
||||
tokens.put("narrator.initials", Options.get("narrator.initials"));
|
||||
tokens.put("file.bitrate", Integer.toString(Options.getInteger("audio.export.bitrate")));
|
||||
tokens.put("file.bitrate.kb", Integer.toString(Options.getInteger("audio.export.bitrate") / 1000));
|
||||
tokens.put("file.bitrate", Integer.toString(book.getExportProfile().getExportBitrate()));
|
||||
tokens.put("file.bitrate.kb", Integer.toString(book.getExportProfile().getExportBitrate() / 1000));
|
||||
|
||||
for(Map.Entry<String, String> entry : tokens.entrySet()) {
|
||||
format = format.replace("{" + entry.getKey() + ":lower}", entry.getValue().toLowerCase());
|
||||
@@ -214,7 +187,7 @@ public class Chapter extends BookTreeNode {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void exportChapter(ProgressDialog exportDialog, String fnformat) throws
|
||||
public void exportChapter(ProgressDialog exportDialog) throws
|
||||
FileNotFoundException, IOException, InputFormatException, NotSupportedException,
|
||||
EncoderException, UnsupportedTagException, InvalidDataException {
|
||||
Debug.trace();
|
||||
@@ -223,6 +196,10 @@ public class Chapter extends BookTreeNode {
|
||||
|
||||
Book book = getBook();
|
||||
|
||||
ExportProfile profile = book.getExportProfile();
|
||||
|
||||
String fnformat = profile.getExportFormat();
|
||||
|
||||
File export = book.getLocation("export");
|
||||
if (!export.exists()) {
|
||||
export.mkdirs();
|
||||
@@ -243,9 +220,9 @@ public class Chapter extends BookTreeNode {
|
||||
|
||||
AudioAttributes audioAttributes = new AudioAttributes();
|
||||
audioAttributes.setCodec("libmp3lame");
|
||||
audioAttributes.setBitRate(Options.getInteger("audio.export.bitrate"));
|
||||
audioAttributes.setSamplingRate(Options.getInteger("audio.export.samplerate"));
|
||||
audioAttributes.setChannels(Options.getInteger("audio.export.channels")); //new Integer(2));
|
||||
audioAttributes.setBitRate(profile.getExportBitrate());
|
||||
audioAttributes.setSamplingRate(profile.getExportSamples());
|
||||
audioAttributes.setChannels(profile.getExportChannels());
|
||||
attributes.setFormat("mp3");
|
||||
attributes.setAudioAttributes(audioAttributes);
|
||||
|
||||
@@ -270,7 +247,7 @@ public class Chapter extends BookTreeNode {
|
||||
File taggedFile = new File(export, createFilename(fnformat) + ".mp3");
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(exportFile);
|
||||
data = getBook().getRoomNoise(Utils.s2i(Options.get("catenation.pre-chapter")));
|
||||
data = getBook().getRoomNoise(profile.getGapPreChapter());
|
||||
fullLength += data.length;
|
||||
fos.write(data);
|
||||
|
||||
@@ -289,7 +266,7 @@ public class Chapter extends BookTreeNode {
|
||||
if (s.hasMoreElements()) {
|
||||
data = getBook().getRoomNoise(snt.getPostGap());
|
||||
} else {
|
||||
data = getBook().getRoomNoise(Utils.s2i(Options.get("catenation.post-chapter")));
|
||||
data = getBook().getRoomNoise(profile.getGapPostChapter());
|
||||
}
|
||||
fullLength += data.length;
|
||||
fos.write(data);
|
||||
@@ -334,14 +311,16 @@ public class Chapter extends BookTreeNode {
|
||||
|
||||
public double getChapterLength() {
|
||||
Debug.trace();
|
||||
double totalTime = Options.getInteger("audio.recording.pre-chapter") / 1000d;
|
||||
Book book = getBook();
|
||||
ExportProfile exportProfile = book.getExportProfile();
|
||||
double totalTime = exportProfile.getGapPreChapter() / 1000d;
|
||||
for (Enumeration s = children(); s.hasMoreElements();) {
|
||||
Sentence sentence = (Sentence)s.nextElement();
|
||||
totalTime += sentence.getLength();
|
||||
if (s.hasMoreElements()) {
|
||||
totalTime += (sentence.getPostGap() / 1000d);
|
||||
} else {
|
||||
totalTime += Options.getInteger("audio.recording.post-chapter") / 1000d;
|
||||
totalTime += exportProfile.getGapPostChapter() / 1000d;
|
||||
}
|
||||
}
|
||||
return totalTime;
|
||||
@@ -389,8 +368,6 @@ public class Chapter extends BookTreeNode {
|
||||
Element chapterNode = doc.createElement("chapter");
|
||||
chapterNode.setAttribute("id", id);
|
||||
chapterNode.appendChild(Book.makeTextNode(doc, "name", name));
|
||||
chapterNode.appendChild(Book.makeTextNode(doc, "pre-gap", preGap));
|
||||
chapterNode.appendChild(Book.makeTextNode(doc, "post-gap", postGap));
|
||||
chapterNode.appendChild(Book.makeTextNode(doc, "notes", notes));
|
||||
|
||||
Element sentencesNode = doc.createElement("sentences");
|
||||
@@ -433,6 +410,9 @@ public class Chapter extends BookTreeNode {
|
||||
|
||||
@Override
|
||||
public double getLength() {
|
||||
Book book = getBook();
|
||||
ExportProfile exportProfile = book.getExportProfile();
|
||||
|
||||
Debug.trace();
|
||||
double len = 0;
|
||||
for (Enumeration o = children(); o.hasMoreElements();) {
|
||||
@@ -445,8 +425,8 @@ public class Chapter extends BookTreeNode {
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
len += (getPreGap() / 1000d);
|
||||
len += (getPostGap() / 1000d);
|
||||
len += (exportProfile.getGapPreChapter() / 1000d);
|
||||
len += (exportProfile.getGapPostChapter() / 1000d);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
139
src/uk/co/majenko/audiobookrecorder/ExportProfile.java
Normal file
139
src/uk/co/majenko/audiobookrecorder/ExportProfile.java
Normal file
@@ -0,0 +1,139 @@
|
||||
package uk.co.majenko.audiobookrecorder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Text;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
|
||||
public class ExportProfile {
|
||||
String name;
|
||||
String code;
|
||||
int export_bitrate;
|
||||
int export_channels;
|
||||
int export_samples;
|
||||
String export_format;
|
||||
int gap_pre_chapter;
|
||||
int gap_post_chapter;
|
||||
int gap_post_sentence;
|
||||
int gap_followon;
|
||||
int gap_post_paragraph;
|
||||
int gap_post_section;
|
||||
int audio_rms;
|
||||
|
||||
public ExportProfile() {
|
||||
name = "Default";
|
||||
code = "default";
|
||||
export_bitrate = 128000;
|
||||
export_channels = 1;
|
||||
export_samples = 44100;
|
||||
export_format = "{book.title} - {chapter.number} - {chapter.title}";
|
||||
gap_pre_chapter = 1000;
|
||||
gap_post_chapter = 1000;
|
||||
gap_post_sentence = 500;
|
||||
gap_followon = 300;
|
||||
gap_post_paragraph = 800;
|
||||
gap_post_section = 1200;
|
||||
audio_rms = -18;
|
||||
}
|
||||
|
||||
public ExportProfile(String filename) {
|
||||
loadProfileFromFile(new File(filename));
|
||||
}
|
||||
|
||||
public ExportProfile(File f) {
|
||||
loadProfileFromFile(f);
|
||||
}
|
||||
|
||||
public void loadProfileFromFile(File inputFile) {
|
||||
if (inputFile.exists()) {
|
||||
try {
|
||||
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
|
||||
Document doc = dBuilder.parse(inputFile);
|
||||
doc.getDocumentElement().normalize();
|
||||
Element root = doc.getDocumentElement();
|
||||
Element export = getNode(root, "export");
|
||||
Element gaps = getNode(root, "gaps");
|
||||
Element audio = getNode(root, "audio");
|
||||
|
||||
name = getTextNode(root, "name");
|
||||
code = getTextNode(root, "code");
|
||||
export_bitrate = Utils.s2i(getTextNode(export, "bitrate"));
|
||||
export_channels = Utils.s2i(getTextNode(export, "channels"));
|
||||
export_samples = Utils.s2i(getTextNode(export, "samples"));
|
||||
export_format = getTextNode(export, "format");
|
||||
gap_pre_chapter = Utils.s2i(getTextNode(gaps, "pre-chapter"));
|
||||
gap_post_chapter = Utils.s2i(getTextNode(gaps, "post-chapter"));
|
||||
gap_post_sentence = Utils.s2i(getTextNode(gaps, "post-sentence"));
|
||||
gap_followon = Utils.s2i(getTextNode(gaps, "followon"));
|
||||
gap_post_paragraph = Utils.s2i(getTextNode(gaps, "post-paragraph"));
|
||||
gap_post_section = Utils.s2i(getTextNode(gaps, "post-section"));
|
||||
audio_rms = Utils.s2i(getTextNode(audio, "rms"));
|
||||
|
||||
} catch (ParserConfigurationException ex) {
|
||||
System.err.println("Badly formatted XML file: " + inputFile.getPath());
|
||||
} catch (SAXException ex) {
|
||||
System.err.println("Badly formatted XML file: " + inputFile.getPath());
|
||||
} catch (IOException ex) {
|
||||
System.err.println("Error reading file: " + inputFile.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Element getNode(Element r, String n) {
|
||||
Debug.trace();
|
||||
NodeList nl = r.getElementsByTagName(n);
|
||||
if (nl == null) return null;
|
||||
if (nl.getLength() == 0) return null;
|
||||
return (Element)nl.item(0);
|
||||
}
|
||||
|
||||
public String getTextNode(Element r, String n) {
|
||||
Debug.trace();
|
||||
return getTextNode(r, n, "");
|
||||
}
|
||||
|
||||
public String getTextNode(Element r, String n, String d) {
|
||||
Debug.trace();
|
||||
Element node = getNode(r, n);
|
||||
if (node == null) return d;
|
||||
return node.getTextContent();
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
public String getCode() { return code; }
|
||||
public int getExportBitrate() { return export_bitrate; }
|
||||
public int getExportChannels() { return export_channels; }
|
||||
public int getExportSamples() { return export_samples; }
|
||||
public String getExportFormat() { return export_format; }
|
||||
public int getGapPreChapter() { return gap_pre_chapter; }
|
||||
public int getGapPostChapter() { return gap_post_chapter; }
|
||||
public int getGapFollowon() { return gap_followon; }
|
||||
public int getGapPostSentence() { return gap_post_sentence; }
|
||||
public int getGapPostParagraph() { return gap_post_paragraph; }
|
||||
public int getGapPostSection() { return gap_post_section; }
|
||||
public int getAudioRMS() { return audio_rms; }
|
||||
|
||||
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -377,19 +377,7 @@ public class Options extends JDialog {
|
||||
|
||||
addSeparator(optionsPanel);
|
||||
|
||||
preChapterGap = addSpinner(optionsPanel, "Default pre-chapter gap:", 0, 5000, 100, getInteger("catenation.pre-chapter"), "ms", "How much room noise to add at the beginning of a chapter.");
|
||||
postChapterGap = addSpinner(optionsPanel, "Default post-chapter gap:", 0, 5000, 100, getInteger("catenation.post-chapter"), "ms", "How much room noise to add to the end of a chapter.");
|
||||
postSentenceGap = addSpinner(optionsPanel, "Default post-sentence gap:", 0, 5000, 100, getInteger("catenation.post-sentence"), "ms", "How much room noise to add between normal sentences.");
|
||||
shortSentenceGap = addSpinner(optionsPanel, "Short post-sentence gap:", 0, 5000, 100, getInteger("catenation.short-sentence"), "ms", "How much room noise to add between 'continuations'.");
|
||||
postParagraphGap = addSpinner(optionsPanel, "Default post-paragraph gap:", 0, 5000, 100, getInteger("catenation.post-paragraph"), "ms", "How much room noise to add between paragraphs.");
|
||||
postSectionGap = addSpinner(optionsPanel, "Default post-section gap:", 0, 5000, 100, getInteger("catenation.post-section"), "ms", "How much room noise to add between sections.");
|
||||
|
||||
addSeparator(optionsPanel);
|
||||
|
||||
ffmpegLocation = addFilePath(optionsPanel, "FFMPEG location:", get("path.ffmpeg"), false, "Path to your ffmpeg executable.");
|
||||
bitRate = addDropdown(optionsPanel, "Export bitrate:", getBitrates(), get("audio.export.bitrate"), "The MP3 bitrate to produce");
|
||||
channels = addDropdown(optionsPanel, "Export channels:", getChannelCountList(), get("audio.export.channels"), "Mono or stereo MP3 production");
|
||||
exportRate = addDropdown(optionsPanel, "Export sample rate:", getSampleRateList(), get("audio.export.samplerate"), "Sample frequency of the produced MP3");
|
||||
|
||||
addSeparator(optionsPanel);
|
||||
|
||||
|
||||
@@ -198,7 +198,6 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
id = UUID.randomUUID().toString();
|
||||
text = id;
|
||||
setUserObject(text);
|
||||
postGap = Options.getInteger("catenation.post-sentence");
|
||||
}
|
||||
|
||||
public Sentence(String i, String t) {
|
||||
@@ -207,7 +206,6 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
id = i;
|
||||
text = t;
|
||||
setUserObject(text);
|
||||
postGap = Options.getInteger("catenation.post-sentence");
|
||||
}
|
||||
|
||||
public Sentence(Element root) {
|
||||
@@ -990,8 +988,8 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
Debug.trace();
|
||||
if (locked) return gain;
|
||||
|
||||
int targetLow = Options.getInteger("audio.recording.rms.low");
|
||||
int targetHigh = Options.getInteger("audio.recording.rms.high");
|
||||
int targetLow = getBook().getExportProfile().getAudioRMS();
|
||||
int targetHigh = getBook().getExportProfile().getAudioRMS();
|
||||
|
||||
long ts = System.currentTimeMillis();
|
||||
while ((int)getRMS() < targetLow) {
|
||||
@@ -1639,13 +1637,13 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
public void setPostGapType(String t) {
|
||||
Debug.trace();
|
||||
if (t == null || t.equals("none")) {
|
||||
if (getPostGap() == Options.getInteger("catenation.short-sentence")) {
|
||||
if (getPostGap() == getBook().getExportProfile().getGapFollowon()) {
|
||||
t = "continuation";
|
||||
} else if (getPostGap() == Options.getInteger("catenation.post-paragraph")) {
|
||||
} else if (getPostGap() == getBook().getExportProfile().getGapPostParagraph()) {
|
||||
t = "paragraph";
|
||||
} else if (getPostGap() == Options.getInteger("catenation.post-section")) {
|
||||
} else if (getPostGap() == getBook().getExportProfile().getGapPostSection()) {
|
||||
t = "section";
|
||||
} else if (getPostGap() == Options.getInteger("catenation.post-sentence")) {
|
||||
} else if (getPostGap() == getBook().getExportProfile().getGapPostSentence()) {
|
||||
t = "sentence";
|
||||
} else {
|
||||
t = "sentence";
|
||||
@@ -1661,13 +1659,13 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
||||
postGapType = "sentence";
|
||||
}
|
||||
if (postGapType.equals("continuation")) {
|
||||
setPostGap(Options.getInteger("catenation.short-sentence"));
|
||||
setPostGap(getBook().getExportProfile().getGapFollowon());
|
||||
} else if (postGapType.equals("paragraph")) {
|
||||
setPostGap(Options.getInteger("catenation.post-paragraph"));
|
||||
setPostGap(getBook().getExportProfile().getGapPostParagraph());
|
||||
} else if (postGapType.equals("section")) {
|
||||
setPostGap(Options.getInteger("catenation.post-section"));
|
||||
setPostGap(getBook().getExportProfile().getGapPostSection());
|
||||
} else {
|
||||
setPostGap(Options.getInteger("catenation.post-sentence"));
|
||||
setPostGap(getBook().getExportProfile().getGapPostSentence());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user