diff --git a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java index 1ba5887..41fefa9 100644 --- a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java +++ b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java @@ -1246,6 +1246,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { Chapter c = (Chapter)s.getParent(); int idx = bookTreeModel.getIndexOfChild(c, s); bookTreeModel.insertNodeInto(newSentence, c, idx); + bookTree.setSelectionPath(new TreePath(newSentence.getPath())); } catch (Exception ex) { ex.printStackTrace(); } @@ -2805,7 +2806,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { play.close(); } play = null; - e.printStackTrace(); +// e.printStackTrace(); } } }); diff --git a/src/uk/co/majenko/audiobookrecorder/Book.java b/src/uk/co/majenko/audiobookrecorder/Book.java index 31433ff..8ac8405 100644 --- a/src/uk/co/majenko/audiobookrecorder/Book.java +++ b/src/uk/co/majenko/audiobookrecorder/Book.java @@ -99,8 +99,12 @@ public class Book extends DefaultMutableTreeNode { } public static String getTextNode(Element r, String n) { + return getTextNode(r, n, ""); + } + + public static String getTextNode(Element r, String n, String d) { Element node = getNode(r, n); - if (node == null) return ""; + if (node == null) return d; return node.getTextContent(); } diff --git a/src/uk/co/majenko/audiobookrecorder/BookTreeRenderer.java b/src/uk/co/majenko/audiobookrecorder/BookTreeRenderer.java index 18e58dc..95dde2d 100644 --- a/src/uk/co/majenko/audiobookrecorder/BookTreeRenderer.java +++ b/src/uk/co/majenko/audiobookrecorder/BookTreeRenderer.java @@ -9,11 +9,15 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer { public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { JLabel ret = (JLabel) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); - ret.setIconTextGap(0); + ret.setIconTextGap(5); ret.setBorder(new EmptyBorder(0, 0, 0, 0)); if (value instanceof Sentence) { Sentence s = (Sentence)value; + JPanel p = new JPanel(); + p.setLayout(new GridBagLayout()); + GridBagConstraints ctx = new GridBagConstraints(); + OverlayIcon icn = new OverlayIcon(Icons.sentence); if (s.getOverrideText() != null) { @@ -63,17 +67,72 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer { } if (gaptype.equals("sentence")) { - ret.setBorder(new EmptyBorder(0, 0, 0, 0)); + p.setBorder(new EmptyBorder(0, 0, 0, 0)); } else if (gaptype.equals("continuation")) { - ret.setBorder(new EmptyBorder(0, 0, 0, 0)); + p.setBorder(new EmptyBorder(0, 0, 0, 0)); } else if (gaptype.equals("paragraph")) { - ret.setBorder(new EmptyBorder(0, 0, 7, 0)); + p.setBorder(new EmptyBorder(0, 0, 7, 0)); } else if (gaptype.equals("section")) { - ret.setBorder(new EmptyBorder(0, 0, 15, 0)); + p.setBorder(new EmptyBorder(0, 0, 15, 0)); } + + JLabel time = new JLabel(Utils.secToTime(s.getLength(), "mm:ss.SSS") + " "); + + ctx.gridx = 0; + ctx.gridy = 0; + ctx.fill = GridBagConstraints.HORIZONTAL; + ctx.anchor = GridBagConstraints.LINE_START; + + String effectChain = s.getEffectChain(); + if ((effectChain == null) || (effectChain.equals("none"))) { + ctx.weightx = 1.0d; + ctx.gridwidth = 2; + p.add(ret, ctx); + } else { + ctx.weightx = 0.1d; + ctx.gridwidth = 1; + p.add(ret, ctx); + Effect e = AudiobookRecorder.window.effects.get(effectChain); + JLabel eff = new JLabel(e.toString() + " "); + ctx.weightx = 0.0d; + ctx.gridwidth = 1; + ctx.gridx = 1; + p.add(eff); + } + + ctx.weightx = 0.0d; + ctx.gridx = 2; + ctx.anchor = GridBagConstraints.LINE_END; + p.add(time, ctx); + + p.setOpaque(false); + + return p; + } else if (value instanceof Chapter) { + Chapter c = (Chapter)value; + ret.setIcon(Icons.chapter); + + JPanel p = new JPanel(); + p.setLayout(new GridBagLayout()); + GridBagConstraints ctx = new GridBagConstraints(); + + JLabel time = new JLabel(Utils.secToTime(c.getLength(), "mm:ss") + " "); + + ctx.gridx = 0; + ctx.gridy = 0; + ctx.fill = GridBagConstraints.HORIZONTAL; + ctx.anchor = GridBagConstraints.LINE_START; + ctx.weightx = 1.0d; + p.add(ret, ctx); + ctx.weightx = 0.0d; + ctx.gridx = 1; + ctx.anchor = GridBagConstraints.LINE_END; + p.add(time, ctx); + p.setOpaque(false); + return p; } else if (value instanceof Book) { ret.setIcon(((Book)value).getIcon()); } diff --git a/src/uk/co/majenko/audiobookrecorder/Chapter.java b/src/uk/co/majenko/audiobookrecorder/Chapter.java index 298d44e..309c0ef 100644 --- a/src/uk/co/majenko/audiobookrecorder/Chapter.java +++ b/src/uk/co/majenko/audiobookrecorder/Chapter.java @@ -316,4 +316,16 @@ public class Chapter extends BookTreeNode { AudiobookRecorder.window.setChapterNotes(notes); } + public double getLength() { + double len = 0; + for (Enumeration o = children(); o.hasMoreElements();) { + Object ob = (Object)o.nextElement(); + if (ob instanceof Sentence) { + Sentence s = (Sentence)ob; + len += s.getLength(); + } + } + return len; + } + } diff --git a/src/uk/co/majenko/audiobookrecorder/Sentence.java b/src/uk/co/majenko/audiobookrecorder/Sentence.java index 9f59f94..307140b 100644 --- a/src/uk/co/majenko/audiobookrecorder/Sentence.java +++ b/src/uk/co/majenko/audiobookrecorder/Sentence.java @@ -78,7 +78,8 @@ public class Sentence extends BookTreeNode implements Cacheable { TargetDataLine line; AudioInputStream inputStream; AudioFormat storedFormat = null; - double storedLength = -1d; + + double runtime = -1d; double[][] audioData = null; @@ -185,6 +186,8 @@ public class Sentence extends BookTreeNode implements Cacheable { setPostGap(Utils.s2i(Book.getTextNode(root, "post-gap"))); setStartOffset(Utils.s2i(Book.getTextNode(root, "start-offset"))); setEndOffset(Utils.s2i(Book.getTextNode(root, "end-offset"))); + crossStartOffset = Utils.s2i(Book.getTextNode(root, "cross-start-offset", "-1")); + crossEndOffset = Utils.s2i(Book.getTextNode(root, "end-offset", "-1")); setLocked(Utils.s2b(Book.getTextNode(root, "locked"))); setAttentionFlag(Utils.s2b(Book.getTextNode(root, "attention"))); setGain(Utils.s2d(Book.getTextNode(root, "gain"))); @@ -192,6 +195,14 @@ public class Sentence extends BookTreeNode implements Cacheable { setPostGapType(Book.getTextNode(root, "gaptype")); sampleSize = Utils.s2i(Book.getTextNode(root, "samples")); processed = Utils.s2b(Book.getTextNode(root, "processed")); + runtime = Utils.s2d(Book.getTextNode(root, "time", "-1.000")); + + if ((crossStartOffset == -1) || (crossEndOffset == -1)) { + System.err.println("Updating " + id); + updateCrossings(true); + } + + if (runtime <= 0.01d) getLength(); } public boolean startRecording() { @@ -450,11 +461,14 @@ public class Sentence extends BookTreeNode implements Cacheable { } public String toString() { + return text; +/* if (effectChain == null) return text; if (effectChain.equals("none")) return text; Effect e = AudiobookRecorder.window.effects.get(effectChain); if (e == null) return text; return text + " (" + e.toString() + ")"; +*/ } public boolean isRecording() { @@ -499,6 +513,8 @@ public class Sentence extends BookTreeNode implements Cacheable { public void updateCrossings(boolean useRaw) { updateStartCrossing(useRaw); updateEndCrossing(useRaw); + runtime = -1d; + getLength(); } public void updateStartCrossing() { @@ -642,7 +658,6 @@ public class Sentence extends BookTreeNode implements Cacheable { audioData = null; processedAudio = null; storedFormat = null; - storedLength = -1; } public boolean lockedInCache() { @@ -698,13 +713,12 @@ public class Sentence extends BookTreeNode implements Cacheable { /* Get the length of the sample in seconds */ public double getLength() { - if (storedLength > -1d) return storedLength; + if (runtime > 0.01d) return runtime; AudioFormat format = getAudioFormat(); float sampleFrequency = format.getFrameRate(); int length = crossEndOffset - crossStartOffset; - double time = (double)length / (double)sampleFrequency; - storedLength = time; - return time; + runtime = (double)length / (double)sampleFrequency; + return runtime; } public Sentence cloneSentence() throws IOException { @@ -1431,6 +1445,8 @@ public class Sentence extends BookTreeNode implements Cacheable { sentenceNode.appendChild(Book.makeTextNode(doc, "post-gap", getPostGap())); sentenceNode.appendChild(Book.makeTextNode(doc, "start-offset", getStartOffset())); sentenceNode.appendChild(Book.makeTextNode(doc, "end-offset", getEndOffset())); + sentenceNode.appendChild(Book.makeTextNode(doc, "cross-start-offset", crossStartOffset)); + sentenceNode.appendChild(Book.makeTextNode(doc, "cross-end-offset", crossEndOffset)); sentenceNode.appendChild(Book.makeTextNode(doc, "locked", isLocked())); sentenceNode.appendChild(Book.makeTextNode(doc, "attention", getAttentionFlag())); sentenceNode.appendChild(Book.makeTextNode(doc, "gain", getGain())); @@ -1439,6 +1455,7 @@ public class Sentence extends BookTreeNode implements Cacheable { sentenceNode.appendChild(Book.makeTextNode(doc, "samples", getSampleSize())); sentenceNode.appendChild(Book.makeTextNode(doc, "processed", isProcessed())); sentenceNode.appendChild(Book.makeTextNode(doc, "notes", getNotes())); + sentenceNode.appendChild(Book.makeTextNode(doc, "time", getLength())); return sentenceNode; } diff --git a/src/uk/co/majenko/audiobookrecorder/Utils.java b/src/uk/co/majenko/audiobookrecorder/Utils.java index 8bf2edc..ba113ee 100644 --- a/src/uk/co/majenko/audiobookrecorder/Utils.java +++ b/src/uk/co/majenko/audiobookrecorder/Utils.java @@ -10,6 +10,8 @@ import java.util.*; import java.io.*; import java.net.*; +import java.text.SimpleDateFormat; + public class Utils { public static Image getScaledImage(Image srcImg, int w, int h){ BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); @@ -76,4 +78,12 @@ public class Utils { Runtime.getRuntime().freeMemory() )); } + + public static String secToTime(double sec, String fmt) { + Date d = new Date((long)(sec * 1000d)); + SimpleDateFormat df = new SimpleDateFormat(fmt); + df.setTimeZone(TimeZone.getTimeZone("GMT")); + String time = df.format(d); + return time; + } }