From 0c357fe959989fa2cf8cb8d74dcad8752077c5ad Mon Sep 17 00:00:00 2001 From: Matt Jenkins Date: Thu, 10 Jun 2021 01:17:45 +0100 Subject: [PATCH] Added Audiobooks Unleashed support --- .../audiobookrecorder/AudiobookRecorder.java | 61 ++++++++-- src/uk/co/majenko/audiobookrecorder/Book.java | 6 + .../audiobookrecorder/BookInfoPanel.java | 17 ++- .../audiobookrecorder/CacheManager.java | 14 ++- .../co/majenko/audiobookrecorder/Chapter.java | 107 +++++++++++++++++- .../majenko/audiobookrecorder/Sentence.java | 41 +++++-- 6 files changed, 216 insertions(+), 30 deletions(-) diff --git a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java index c8fca70..e8e683e 100644 --- a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java +++ b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java @@ -456,6 +456,9 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { public void actionPerformed(ActionEvent e) { Debug.trace(); if (selectedSentence != null) { + if ((e.getModifiers() & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) { + selectedSentence.clearPeakGainPoints(); + } selectedSentence.autoAddPeakGainPoints(); updateWaveform(true); } @@ -1076,7 +1079,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; @@ -1631,7 +1634,10 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { } }); - JMenuObject exportChapter = new JMenuObject("Export chapter", c, new ActionListener() { + JMenu exportChapter = new JMenu("Export chapter..."); + + + JMenuObject exportChapterACX = new JMenuObject("For ACX", c, new ActionListener() { public void actionPerformed(ActionEvent e) { Debug.trace(); JMenuObject o = (JMenuObject)e.getSource(); @@ -1639,7 +1645,22 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { ProgressDialog ed = new ProgressDialog("Exporting " + chap.getName()); - ExportThread t = new ExportThread(chap, ed); + ExportThread t = new ExportThread(chap, ed, "%t - %02n"); + 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, "%I_%03i"); Thread nt = new Thread(t); nt.start(); ed.setVisible(true); @@ -1696,6 +1717,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { if (!snt.isLocked()) { queueJob(new SentenceJob(snt) { public void run() { + sentence.clearPeakGainPoints(); sentence.normalize(); sentence.autoAddPeakGainPoints(); } @@ -1748,6 +1770,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { menu.addSeparator(); menu.add(importWav); menu.add(exportChapter); + exportChapter.add(exportChapterACX); + exportChapter.add(exportChapterABU); menu.addSeparator(); menu.add(deleteChapter); menu.addSeparator(); @@ -1801,12 +1825,24 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { menu.addSeparator(); - menu.add(new JMenuObject("Export All Audio", book, new ActionListener() { + JMenu exportAll = new JMenu("Export All Audio..."); + menu.add(exportAll); + + exportAll.add(new JMenuObject("For ACX", book, new ActionListener() { public void actionPerformed(ActionEvent e) { Debug.trace(); JMenuObject src = (JMenuObject)(e.getSource()); Book thisBook = (Book)(src.getObject()); - exportAudio(thisBook); + exportAudio(thisBook, "%t - %n"); + } + })); + + 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, "%I_%03i"); } })); @@ -2454,12 +2490,14 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { class ExportThread implements Runnable { ProgressDialog exportDialog; Chapter chapter; + String format; - public ExportThread(Chapter c, ProgressDialog e) { + public ExportThread(Chapter c, ProgressDialog e, String f) { super(); Debug.trace(); exportDialog = e; chapter = c; + format = f; } @SuppressWarnings("unchecked") @@ -2467,7 +2505,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { Debug.trace(); try { - chapter.exportChapter(exportDialog); + chapter.exportChapter(exportDialog, format); } catch (Exception e) { e.printStackTrace(); } @@ -2477,7 +2515,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { } @SuppressWarnings("unchecked") - public void exportAudio(Book book) { + public void exportAudio(Book book, String format) { Debug.trace(); for (Enumeration o = book.children(); o.hasMoreElements();) { @@ -2485,7 +2523,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); + ExportThread t = new ExportThread(c, ed, format); Thread nt = new Thread(t); nt.start(); ed.setVisible(true); @@ -3539,7 +3577,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { book.getAuthor(), book.getGenre(), book.getComment(), - book.getACX() + book.getACX(), + book.getISBN() ); tabs.add("Data", info); @@ -3580,6 +3619,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { String gen = info.getGenre(); String com = info.getComment(); String acx = info.getACX(); + String isbn = info.getISBN(); i = defEff.getSelectedIndex(); KVPair de = defEff.getItemAt(i); @@ -3590,6 +3630,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { book.setGenre(gen); book.setComment(com); book.setACX(acx); + book.setISBN(isbn); // if (!(book().getName().equals(tit))) { // book().renameBook(tit); // } diff --git a/src/uk/co/majenko/audiobookrecorder/Book.java b/src/uk/co/majenko/audiobookrecorder/Book.java index 7123bc3..b926384 100644 --- a/src/uk/co/majenko/audiobookrecorder/Book.java +++ b/src/uk/co/majenko/audiobookrecorder/Book.java @@ -43,6 +43,7 @@ public class Book extends BookTreeNode { String genre; String comment; String ACX; + String ISBN; String manuscript; String defaultEffect = "none"; Sentence roomNoise = null; @@ -81,6 +82,7 @@ public class Book extends BookTreeNode { genre = getTextNode(root, "genre"); comment = getTextNode(root, "comment"); ACX = getTextNode(root, "acx"); + ISBN = getTextNode(root, "isbn"); manuscript = getTextNode(root, "manuscript"); notes = getTextNode(root, "notes"); @@ -133,6 +135,7 @@ public class Book extends BookTreeNode { genre = getTextNode(root, "genre"); comment = getTextNode(root, "comment"); ACX = getTextNode(root, "acx"); + ISBN = getTextNode(root, "isbn"); manuscript = getTextNode(root, "manuscript"); notes = getTextNode(root, "notes"); @@ -183,12 +186,14 @@ public class Book extends BookTreeNode { 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 getAuthor() { Debug.trace(); return author; } 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; } + public String getISBN() { Debug.trace(); if (ISBN == null) return ""; return ISBN; } @SuppressWarnings("unchecked") public Chapter getChapterById(String id) { @@ -378,6 +383,7 @@ public class Book extends BookTreeNode { root.appendChild(makeTextNode(doc, "comment", comment)); root.appendChild(makeTextNode(doc, "genre", genre)); root.appendChild(makeTextNode(doc, "acx", ACX)); + root.appendChild(makeTextNode(doc, "isbn", ISBN)); root.appendChild(makeTextNode(doc, "manuscript", manuscript)); root.appendChild(makeTextNode(doc, "notes", notes)); diff --git a/src/uk/co/majenko/audiobookrecorder/BookInfoPanel.java b/src/uk/co/majenko/audiobookrecorder/BookInfoPanel.java index 9f1cca7..e3f4f7a 100644 --- a/src/uk/co/majenko/audiobookrecorder/BookInfoPanel.java +++ b/src/uk/co/majenko/audiobookrecorder/BookInfoPanel.java @@ -16,8 +16,9 @@ public class BookInfoPanel extends JPanel { JTextField genre; JTextField comment; JTextField acx; + JTextField isbn; - public BookInfoPanel(String t, String a, String g, String c, String x) { + public BookInfoPanel(String t, String a, String g, String c, String x, String i) { super(); Debug.trace(); setLayout(new GridBagLayout()); @@ -62,7 +63,7 @@ public class BookInfoPanel extends JPanel { con.gridx = 0; con.gridy++; - add(new JLabel("AXC Code:"), con); + add(new JLabel("ACX Code:"), con); con.gridx = 1; acx = new JTextField(x); acx.setPreferredSize(new Dimension(200, 20)); @@ -71,13 +72,22 @@ public class BookInfoPanel extends JPanel { con.gridx = 0; con.gridy++; + add(new JLabel("ISBN:"), con); + con.gridx = 1; + isbn = new JTextField(i); + isbn.setPreferredSize(new Dimension(200, 20)); + add(isbn, con); + + con.gridx = 0; + con.gridy++; + } public String getTitle() { Debug.trace(); return title.getText(); } public String getAuthor() { Debug.trace(); return author.getText(); } public String getGenre() { Debug.trace(); return genre.getText(); } public String getComment() { Debug.trace(); return comment.getText(); } - + public String getISBN() { Debug.trace(); return isbn.getText(); } public String getACX() { Debug.trace(); Pattern p = Pattern.compile("\\/titleview\\/([A-Z0-9]{14})"); @@ -93,5 +103,6 @@ public class BookInfoPanel extends JPanel { public void setGenre(String g) { Debug.trace(); genre.setText(g); } 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); } } diff --git a/src/uk/co/majenko/audiobookrecorder/CacheManager.java b/src/uk/co/majenko/audiobookrecorder/CacheManager.java index 2fdc4fa..614078a 100644 --- a/src/uk/co/majenko/audiobookrecorder/CacheManager.java +++ b/src/uk/co/majenko/audiobookrecorder/CacheManager.java @@ -9,15 +9,20 @@ public class CacheManager { public static void addToCache(Cacheable c) { Debug.trace(); + int iterations = 0; while (cache.size() >= cacheSize) { + iterations++; + if (iterations > cacheSize * 2) { + System.err.println("Cache locked. Flushing."); + cache.clear(); + cache.add(c); + return; + } Cacheable ob = cache.remove(0); if (ob != null) { if (ob.lockedInCache()) { cache.add(ob); } else { - if (ob instanceof Sentence) { - Sentence s = (Sentence)ob; - } ob.clearCache(); } } @@ -32,9 +37,6 @@ public class CacheManager { public static void removeFromCache(Cacheable c) { Debug.trace(); - if (c instanceof Sentence) { - Sentence s = (Sentence)c; - } cache.remove(c); c.clearCache(); } diff --git a/src/uk/co/majenko/audiobookrecorder/Chapter.java b/src/uk/co/majenko/audiobookrecorder/Chapter.java index 8d7ea9c..08002e8 100644 --- a/src/uk/co/majenko/audiobookrecorder/Chapter.java +++ b/src/uk/co/majenko/audiobookrecorder/Chapter.java @@ -102,6 +102,22 @@ public class Chapter extends BookTreeNode { } } + public int getSequenceNumber() { + Book book = getBook(); + int i = 1; + while (true) { + Chapter c = book.getChapter(i); + if (c == null) { + return -1; + } + System.err.println(c.getName()); + if (c.getName().equals(name)) { + return i; + } + i++; + } + } + public String getId() { Debug.trace(); return id; @@ -162,8 +178,93 @@ public class Chapter extends BookTreeNode { return postGap; } + public String createFilename(String format) { + String out = ""; + + char[] chars = format.toCharArray(); + + int mode = 0; // nothing + int len = 0; + boolean zeros = false; + boolean first = true; + + Book book = getBook(); + + for (char c : chars) { + switch (mode) { + case 0: + switch (c) { + case '%': { + mode = 1; + len = 0; + zeros = false; + first = true; + } + break; + default: out += c; break; + } + break; + + case 1: + switch (c) { + case '0': len = len * 10; first = false; break; + case '1': len = len * 10 + 1; first = false; break; + case '2': len = len * 10 + 2; first = false; break; + case '3': len = len * 10 + 3; first = false; break; + case '4': len = len * 10 + 4; first = false; break; + case '5': len = len * 10 + 5; first = false; break; + case '6': len = len * 10 + 6; first = false; break; + case '7': len = len * 10 + 7; first = false; break; + case '8': len = len * 10 + 8; first = false; break; + case '9': len = len * 10 + 9; first = false; break; + case 't': + if (len > 0) + out += String.format("%" + len + "s", book.getTitle()); + else + out += book.getTitle(); + mode = 0; + break; + case 'n': + if (len > 0) + out += String.format("%" + len + "s", name); + else + out += name; + mode = 0; + break; + + case '%': + out += '%'; + mode = 0; + break; + case 'I': + if (len > 0) + out += String.format("%" + len + "s", book.getISBN()); + else + out += book.getISBN(); + mode = 0; + break; + case 'A': + if (len > 0) + out += String.format("%" + len + "s", book.getACX()); + else + out += book.getACX(); + mode = 0; + break; + case 'i': + if (len > 0) + out += String.format("%0" + len + "d", getSequenceNumber()); + else + out += getId(); + mode = 0; + break; + } + } + } + return out; + } + @SuppressWarnings("unchecked") - public void exportChapter(ProgressDialog exportDialog) throws + public void exportChapter(ProgressDialog exportDialog, String fnformat) throws FileNotFoundException, IOException, InputFormatException, NotSupportedException, EncoderException, UnsupportedTagException, InvalidDataException { Debug.trace(); @@ -214,7 +315,9 @@ public class Chapter extends BookTreeNode { File exportFile = new File(export, name + ".wax"); File wavFile = new File(export, name + ".wav"); File mp3File = new File(export, name + "-untagged.mp3"); - File taggedFile = new File(export, book.getName() + " - " + name + ".mp3"); + + + File taggedFile = new File(export, createFilename(fnformat) + ".mp3"); FileOutputStream fos = new FileOutputStream(exportFile); data = getBook().getRoomNoise(Utils.s2i(Options.get("catenation.pre-chapter"))); diff --git a/src/uk/co/majenko/audiobookrecorder/Sentence.java b/src/uk/co/majenko/audiobookrecorder/Sentence.java index 2a96773..af73ee6 100644 --- a/src/uk/co/majenko/audiobookrecorder/Sentence.java +++ b/src/uk/co/majenko/audiobookrecorder/Sentence.java @@ -1815,33 +1815,40 @@ public class Sentence extends BookTreeNode implements Cacheable { } public boolean beenDetected() { + Debug.trace(); return isDetected; } public boolean isProcessing() { + Debug.trace(); return state == PROCESSING; } public boolean isQueued() { + Debug.trace(); return state == QUEUED; } public void setProcessing() { + Debug.trace(); state = PROCESSING; reloadTree(); } public void setQueued() { + Debug.trace(); state = QUEUED; reloadTree(); } public void setDequeued() { + Debug.trace(); state = IDLE; reloadTree(); } public Book getBook() { + Debug.trace(); if (parentBook != null) { Debug.d("Returning parent book"); return parentBook; // Override for room noise which isn't attached to a book tree @@ -2120,11 +2127,24 @@ public class Sentence extends BookTreeNode implements Cacheable { return cpos; } + int findGainPointBetween(int start, int end) { + for (Integer loc : gainPoints.keySet()) { + if (loc >= start && loc <= end) { + return loc; + } + } + return -1; + } + + public void clearPeakGainPoints() { + gainPoints.clear(); + } + public void autoAddPeakGainPoints() { long ts = System.currentTimeMillis(); while (true) { - if (System.currentTimeMillis() - ts > 10000) { + if (System.currentTimeMillis() - ts > 30000) { System.err.println("Terminated: running too long!"); return; } @@ -2136,6 +2156,12 @@ public class Sentence extends BookTreeNode implements Cacheable { System.err.println("Biggest peak: " + pos); + if ((Math.abs(samples[LEFT][pos]) < 0.708) && (Math.abs(samples[RIGHT][pos]) < 0.708)) { + System.err.println("No more peaks"); + refreshAllData(); + return; + } + int closest = findNearestGainPoint(pos); if (closest >= 0) { int diff = closest - pos; @@ -2146,12 +2172,6 @@ public class Sentence extends BookTreeNode implements Cacheable { } } - if ((Math.abs(samples[LEFT][pos]) < 0.708) && (Math.abs(samples[RIGHT][pos]) < 0.708)) { - System.err.println("No more peaks"); - refreshAllData(); - return; - } - int start = findPreviousZero(pos); int end = findNextZero(pos); if (start == -1) { @@ -2163,9 +2183,12 @@ public class Sentence extends BookTreeNode implements Cacheable { return; } - addGainPoint(start, 1d); + int betweenStart = findGainPointBetween(start, pos - 1); + int betweenEnd = findGainPointBetween(pos + 1, end); + + if (betweenStart == -1) addGainPoint(start, 1d); addGainPoint(pos, 1d); - addGainPoint(end, 1d); + if (betweenEnd == -1) addGainPoint(end, 1d); double val = 1d;