From cc48d49b5caa91407e8abe330ab2a94f4c7edbbe Mon Sep 17 00:00:00 2001 From: Matt Jenkins Date: Mon, 1 Oct 2018 19:41:27 +0100 Subject: [PATCH] Added duplicate sentence and moved all playing out of Sentence and into main program --- .../audiobookrecorder/AudiobookRecorder.java | 66 ++++++++++--- .../audiobookrecorder/BookTreeRenderer.java | 1 + .../co/majenko/audiobookrecorder/Chapter.java | 14 +++ .../majenko/audiobookrecorder/Sentence.java | 94 ++++++++----------- 4 files changed, 111 insertions(+), 64 deletions(-) diff --git a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java index c57c253..7492922 100644 --- a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java +++ b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java @@ -693,6 +693,7 @@ public class AudiobookRecorder extends JFrame { JMenuObject ins = new JMenuObject("Insert phrase above", s); JMenuObject del = new JMenuObject("Delete phrase", s); + JMenuObject dup = new JMenuObject("Duplicate phrase", s); ins.addActionListener(new ActionListener() { @@ -718,6 +719,21 @@ public class AudiobookRecorder extends JFrame { } }); + dup.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + try { + JMenuObject o = (JMenuObject)e.getSource(); + Sentence s = (Sentence)o.getObject(); + Sentence newSentence = s.cloneSentence(); + Chapter c = (Chapter)s.getParent(); + int idx = bookTreeModel.getIndexOfChild(c, s); + bookTreeModel.insertNodeInto(newSentence, c, idx); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + }); + rec.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JMenuObject o = (JMenuObject)e.getSource(); @@ -740,6 +756,8 @@ public class AudiobookRecorder extends JFrame { menu.addSeparator(); menu.add(ins); menu.add(del); + menu.addSeparator(); + menu.add(dup); menu.show(bookTree, e.getX(), e.getY()); } else if (node instanceof Chapter) { Chapter c = (Chapter)node; @@ -1542,21 +1560,52 @@ public class AudiobookRecorder extends JFrame { } } + public void playSelectedSentence() { if (selectedSentence == null) return; - if (playing != null) return; - + if (getNoiseFloor() == 0) { + alertNoRoomNoise(); + return; + } playing = selectedSentence; - toolBar.disableSentence(); toolBar.enableStop(); - playingThread = new Thread(new Runnable() { public void run() { - playing.play(); - playing = null; + Sentence s = playing; + byte[] data; + + try { + + AudioFormat format = s.getAudioFormat(); + play = AudioSystem.getSourceDataLine(format, Options.getPlaybackMixer()); + play.open(format); + play.start(); + + bookTree.scrollPathToVisible(new TreePath(s.getPath())); + data = s.getRawAudioData(); + for (int pos = 0; pos < data.length; pos += 1024) { + sampleWaveform.setPlayMarker(pos / format.getFrameSize()); + int l = data.length - pos; + if (l > 1024) l = 1024; + play.write(data, pos, l); + } + + play.drain(); + play.stop(); + play.close(); + play = null; + } catch (Exception e) { + playing = null; + if (play != null) { + play.drain(); + play.stop(); + play.close(); + } + play = null; + } toolBar.enableSentence(); toolBar.disableStop(); } @@ -1564,7 +1613,6 @@ public class AudiobookRecorder extends JFrame { playingThread.setDaemon(true); playingThread.start(); - } class ExportThread implements Runnable { @@ -1726,9 +1774,6 @@ public class AudiobookRecorder extends JFrame { play = null; } playing = null; - if (selectedSentence != null) { - selectedSentence.stopPlaying(); - } } public void alertNoRoomNoise() { @@ -1872,7 +1917,6 @@ public class AudiobookRecorder extends JFrame { public void mergeChapter(Properties prefs, String chid) { Chapter c = book.addChapter(); -System.err.println("Added chapter " + c.getId()); c.setName("Merged-" + prefs.getProperty("chapter." + chid + ".name")); c.setPostGap(Utils.s2i(prefs.getProperty("chapter." + chid + ".post-gap"))); c.setPreGap(Utils.s2i(prefs.getProperty("chapter." + chid + ".pre-gap"))); diff --git a/src/uk/co/majenko/audiobookrecorder/BookTreeRenderer.java b/src/uk/co/majenko/audiobookrecorder/BookTreeRenderer.java index f5232de..855f92f 100644 --- a/src/uk/co/majenko/audiobookrecorder/BookTreeRenderer.java +++ b/src/uk/co/majenko/audiobookrecorder/BookTreeRenderer.java @@ -23,6 +23,7 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer { if (s.isInSample()) { ret.setIcon(Icons.star); } + } else if (value instanceof Chapter) { ret.setIcon(Icons.chapter); } else if (value instanceof Book) { diff --git a/src/uk/co/majenko/audiobookrecorder/Chapter.java b/src/uk/co/majenko/audiobookrecorder/Chapter.java index 58dc2fa..46f373a 100644 --- a/src/uk/co/majenko/audiobookrecorder/Chapter.java +++ b/src/uk/co/majenko/audiobookrecorder/Chapter.java @@ -200,4 +200,18 @@ public class Chapter extends DefaultMutableTreeNode { wavFile.delete(); } + public double getChapterLength() { + double totalTime = Options.getInteger("audio.recording.pre-chapter") / 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; + } + } + return totalTime; + } + } diff --git a/src/uk/co/majenko/audiobookrecorder/Sentence.java b/src/uk/co/majenko/audiobookrecorder/Sentence.java index 22f40f9..1446bd7 100644 --- a/src/uk/co/majenko/audiobookrecorder/Sentence.java +++ b/src/uk/co/majenko/audiobookrecorder/Sentence.java @@ -30,12 +30,13 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable { boolean locked; boolean recording; - boolean playing; boolean inSample; TargetDataLine line; AudioInputStream inputStream; + AudioFormat storedFormat = null; + double storedLength = -1d; int[] storedAudioData = null; @@ -148,6 +149,8 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable { } storedAudioData = null; + storedFormat = null; + storedLength = -1; if (!id.equals("room-noise")) { String tm = Options.get("audio.recording.trim"); @@ -421,7 +424,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable { File f = getFile(); try { AudioInputStream s = AudioSystem.getAudioInputStream(f); - AudioFormat format = s.getFormat(); + AudioFormat format = getAudioFormat(); int[] samples = null; @@ -503,7 +506,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable { try { AudioInputStream s = AudioSystem.getAudioInputStream(f); EqualizerInputStream eq = new EqualizerInputStream(s, 31); - AudioFormat format = eq.getFormat(); + AudioFormat format = getAudioFormat(); IIRControls controls = eq.getControls(); AudiobookRecorder.window.book.equaliser.apply(controls, format.getChannels()); @@ -519,63 +522,20 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable { } public AudioFormat getAudioFormat() { + if (storedFormat != null) return storedFormat; + File f = getFile(); try { AudioInputStream s = AudioSystem.getAudioInputStream(f); - AudioFormat format = s.getFormat(); - return format; + storedFormat = s.getFormat(); + s.close(); + return storedFormat; } catch (Exception e) { e.printStackTrace(); } return null; } - public void play() { - File f = getFile(); - try { - AudioInputStream s = AudioSystem.getAudioInputStream(f); - EqualizerInputStream eq = new EqualizerInputStream(s, 31); - - AudioFormat format = eq.getFormat(); - - IIRControls controls = eq.getControls(); - AudiobookRecorder.window.book.equaliser.apply(controls, format.getChannels()); - - int frameSize = format.getFrameSize(); - - updateCrossings(); - - int pos = crossStartOffset * frameSize; - - SourceDataLine play = AudioSystem.getSourceDataLine(format, Options.getPlaybackMixer()); - play.open(format); - - play.start(); - - byte[] buffer = new byte[1024]; - - eq.skip(pos); - - playing = true; - while ((pos < crossEndOffset * frameSize) && playing) { - AudiobookRecorder.window.sampleWaveform.setPlayMarker((pos - crossStartOffset) / frameSize); - int nr = eq.read(buffer); - pos += nr; - - - play.write(buffer, 0, nr); - }; - play.drain(); - play.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void stopPlaying() { - playing = false; - } - public byte[] getRawAudioData() { File f = getFile(); try { @@ -584,7 +544,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable { EqualizerInputStream eq = new EqualizerInputStream(s, 31); - AudioFormat format = eq.getFormat(); + AudioFormat format = getAudioFormat(); IIRControls controls = eq.getControls(); AudiobookRecorder.window.book.equaliser.apply(controls, format.getChannels()); @@ -634,7 +594,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable { recognizer = new StreamSpeechRecognizer(sphinxConfig); AudioInputStream s = AudioSystem.getAudioInputStream(getFile()); - AudioFormat format = s.getFormat(); + AudioFormat format = getAudioFormat(); int frameSize = format.getFrameSize(); int length = (int)s.getFrameLength(); byte[] data = new byte[length * frameSize]; @@ -742,4 +702,32 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable { } return pos; } + + /* Get the length of the sample in seconds */ + public double getLength() { + if (storedLength > -1d) return storedLength; + AudioFormat format = getAudioFormat(); + float sampleFrequency = format.getFrameRate(); + int length = crossEndOffset - crossStartOffset; + double time = (double)length / (double)sampleFrequency; + storedLength = time; + return time; + } + + public Sentence cloneSentence() throws IOException { + Sentence sentence = new Sentence(); + sentence.setPostGap(getPostGap()); + if (!id.equals(text)) { + sentence.setText(text); + } + sentence.setStartOffset(getStartOffset()); + sentence.setEndOffset(getEndOffset()); + + File from = getFile(); + File to = sentence.getFile(); + Files.copy(from.toPath(), to.toPath()); + + sentence.updateCrossings(); + return sentence; + } }