From c12187cae922a006fe2fd8145cbc3c5bb94270ce Mon Sep 17 00:00:00 2001 From: Matt Jenkins Date: Sat, 6 Apr 2024 21:21:23 +0100 Subject: [PATCH] Implemented export profiles --- ExampleExportFilters/librivox.abprof | 21 +++ .../audiobookrecorder/AudiobookRecorder.java | 118 ++++++--------- src/uk/co/majenko/audiobookrecorder/Book.java | 29 ++++ .../audiobookrecorder/BookInfoPanel.java | 45 +++++- .../co/majenko/audiobookrecorder/Chapter.java | 66 +++------ .../audiobookrecorder/ExportProfile.java | 139 ++++++++++++++++++ .../co/majenko/audiobookrecorder/Options.java | 12 -- .../majenko/audiobookrecorder/Sentence.java | 22 ++- 8 files changed, 312 insertions(+), 140 deletions(-) create mode 100644 ExampleExportFilters/librivox.abprof create mode 100644 src/uk/co/majenko/audiobookrecorder/ExportProfile.java diff --git a/ExampleExportFilters/librivox.abprof b/ExampleExportFilters/librivox.abprof new file mode 100644 index 0000000..88a51a2 --- /dev/null +++ b/ExampleExportFilters/librivox.abprof @@ -0,0 +1,21 @@ + + librivox + LibriVox.org + + 128000 + 1 + 44100 + {chapter.name:lower}_{book.author.short:lower}_{narrator.initials:lower}_{file.bitrate.kb}kb + + + 500 + 5000 + 400 + 100 + 1000 + 1200 + + + diff --git a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java index 448f787..140573a 100644 --- a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java +++ b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java @@ -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 exportProfiles = new HashMap(); + 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); + } + } + } + } + } diff --git a/src/uk/co/majenko/audiobookrecorder/Book.java b/src/uk/co/majenko/audiobookrecorder/Book.java index 86328fb..93ac82c 100644 --- a/src/uk/co/majenko/audiobookrecorder/Book.java +++ b/src/uk/co/majenko/audiobookrecorder/Book.java @@ -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 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; + } } diff --git a/src/uk/co/majenko/audiobookrecorder/BookInfoPanel.java b/src/uk/co/majenko/audiobookrecorder/BookInfoPanel.java index e3f4f7a..c4b59cb 100644 --- a/src/uk/co/majenko/audiobookrecorder/BookInfoPanel.java +++ b/src/uk/co/majenko/audiobookrecorder/BookInfoPanel.java @@ -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; - 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(); + 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); } } diff --git a/src/uk/co/majenko/audiobookrecorder/Chapter.java b/src/uk/co/majenko/audiobookrecorder/Chapter.java index cc4d941..5adec94 100644 --- a/src/uk/co/majenko/audiobookrecorder/Chapter.java +++ b/src/uk/co/majenko/audiobookrecorder/Chapter.java @@ -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 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; } diff --git a/src/uk/co/majenko/audiobookrecorder/ExportProfile.java b/src/uk/co/majenko/audiobookrecorder/ExportProfile.java new file mode 100644 index 0000000..7fa21ea --- /dev/null +++ b/src/uk/co/majenko/audiobookrecorder/ExportProfile.java @@ -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(); + } + +} diff --git a/src/uk/co/majenko/audiobookrecorder/Options.java b/src/uk/co/majenko/audiobookrecorder/Options.java index e693900..2d2e2ab 100644 --- a/src/uk/co/majenko/audiobookrecorder/Options.java +++ b/src/uk/co/majenko/audiobookrecorder/Options.java @@ -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); diff --git a/src/uk/co/majenko/audiobookrecorder/Sentence.java b/src/uk/co/majenko/audiobookrecorder/Sentence.java index 917a818..6d4f35f 100644 --- a/src/uk/co/majenko/audiobookrecorder/Sentence.java +++ b/src/uk/co/majenko/audiobookrecorder/Sentence.java @@ -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()); } }