From c9bada772118aef9ea21bd9eb140f3c31083d57a Mon Sep 17 00:00:00 2001 From: Matt Jenkins Date: Sun, 23 Sep 2018 17:51:54 +0100 Subject: [PATCH] Added progress dialog while exporting #14 --- .../audiobookrecorder/icons/spinner0.png | Bin 0 -> 896 bytes .../audiobookrecorder/icons/spinner1.png | Bin 0 -> 885 bytes .../audiobookrecorder/icons/spinner2.png | Bin 0 -> 834 bytes .../audiobookrecorder/icons/spinner3.png | Bin 0 -> 839 bytes src/it/sauronsoftware/jave/Encoder.java | 69 +++-- .../audiobookrecorder/AudiobookRecorder.java | 282 ++++++++++-------- .../audiobookrecorder/ExportDialog.java | 84 ++++++ .../co/majenko/audiobookrecorder/Icons.java | 4 + .../majenko/audiobookrecorder/Sentence.java | 3 + 9 files changed, 298 insertions(+), 144 deletions(-) create mode 100644 resources/uk/co/majenko/audiobookrecorder/icons/spinner0.png create mode 100644 resources/uk/co/majenko/audiobookrecorder/icons/spinner1.png create mode 100644 resources/uk/co/majenko/audiobookrecorder/icons/spinner2.png create mode 100644 resources/uk/co/majenko/audiobookrecorder/icons/spinner3.png create mode 100644 src/uk/co/majenko/audiobookrecorder/ExportDialog.java diff --git a/resources/uk/co/majenko/audiobookrecorder/icons/spinner0.png b/resources/uk/co/majenko/audiobookrecorder/icons/spinner0.png new file mode 100644 index 0000000000000000000000000000000000000000..8341a1b5d38da09ddb80d982d8fe5ce0c37a3ab6 GIT binary patch literal 896 zcmV-`1AqL9P)WFU8GbZ8()Nlj2>E@cM*00QJmL_t(&-sM^`lG`v0 z1d&|fF4yN~tU52S?+Ue^Nt?I0RqGd|%`e=t@#z`X%-sXrr884RvOy4}D4FCXW0tZl zEPw^b1+C!6PX(#ga#aHWfKs*dnK2pw0J>JEGN*0^U#%MewVnP$vxDPnQy%iKtS zzK#awcvy`63`e8Gft&LtDR2OQ<7)%vym10Hbg#+a9e$e~91n|>tCn_~puOT@<*&z4U^l zt6Db}&#jEBEe{}ic|KIXRk&)K%>mjjsROhNG5({Iu7NH?S8)m^g9B2ZAMAFmw&+7} zqUhC-E)isg0_ObYJg4>uPV}Bpq%(-a!_*Eq{dz0oqTp$ShjX{oUHC4TdP(oUaNlU2 z5p+ECa-GycuEqK7aNo`d`YGd4Lb+Gaj*SmRdPvW5M?GZ6gAqlq9Ss`DNS^RB>Zn@E z3R*xfUeD2_IaiN|W<{wQZ|7lY-p7iOe|+5mcxi}~mEv*s(BjvnC6(?jk==*3Ok*_0 zw50OghuQPAa1=L%*o`8mk{ZL)wJh?X2$$l0(2k7{9ga&1#v{Y>M4eNHC^}XH=pOca z&!tqQ9IlRzTlguLWTeN7Qw2a?4LeO3p(q3-`BhrO`s66ViE>2~emmSRq+u}2;PL4JK)nC}z~j>coZd8?-aGj6^#EP_ zD{H}?-gIwA6FR*R8EV;==kp&utCZ?MnAgh(GwX{Pr(`z(51%S6eid|p0}qT_!q+;| z1=`G;yQtlDqOJe>PU;SB14F6hTlt)O*qM~PqZ@F0i(UlJB{9*Eip Wm(jm}n-uu~000003B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00P-bL_t(&-sPITaw0Jd z$7LN9bfFJ3P~Q^}uGp5DYt!XDXlZ$ZwD%TiX-FPpnModijt*b3A6T}$tMz(6GI0qk z{!9KzNHPkZUlqh!%XI<(07@m!ds-g>0O0&_jJ2I=Eq?X12T;4_59$M?@B9A6FV_hu ze2aEs`nC-@kx4w!`cUG*30ba_J5JU~DSU&~rm+!n&$D>wgIBD`5h`K7Q;3sH{AzOz z+JHP)VJPRA^fYTHp2MWc(K<#~d{4k$C>O2|ke+7IQeDRRHS>C&LetZ%jGf{$Mfz0gKaS*m zLnpFUb(UEg8c?KBQ;(q&y){bTi*=Y8)UGZh7MgYU5Q~eml6^y0t`{8(`(oV}#I}bC z`}9O`6v%KLS5?_vVpCB&4Cj3hI@W6_x4KvNTj;2S(}$#49+LOE;?35lRDz?_DkNYc zY9ay~9x;!nI#y zNYt|dq*=P_L_Wh9e6v%89t~Ko6JN80-ZsqaV7vwxW4g|0@sDGE!SBEKq0{B-4D-bl zK>Yy#fcatym(L?yzRvLQcmkzfm_T}g`C1I&>|z{pS_yt=9+d>H{+HKvP)%C2%8QtNr2mnAnEA)XJo8Hsx* z#f`5e;ybyMs@vdO+y;seX>ku5*em~_8*r{c{&xR8sH?eq`q#&Qp$OTZSpFLP00000 LNkvXXu0mjfOdW|? literal 0 HcmV?d00001 diff --git a/resources/uk/co/majenko/audiobookrecorder/icons/spinner2.png b/resources/uk/co/majenko/audiobookrecorder/icons/spinner2.png new file mode 100644 index 0000000000000000000000000000000000000000..1a939e174b4d89425cc99966d557d8d9552b2850 GIT binary patch literal 834 zcmV-I1HJr-P)WFU8GbZ8()Nlj2>E@cM*00O2-L_t(&-tC&Pa^f%$ zhJPucpo{yEvFm#R1BKd~x%Rpgc?(*%JVDxfi?nV?9>dHe4?ss3UtzG<^2(Mi4H22B z1$IBJ{#~?d3;cZ+@U`Mp0RV(hozKcL2LSBfa$oL*Gkmhl0I?bW!*Yw_HM=}~oGJ+U z;_bxB&)-u{q6c~&0f)(C4A2%%V;mU6O#PgX}O z2S%WQjdFo0c5^p)PA2-%PSwASodFq1d+>6LVmGgiCCd!S>Nq)ZE1e&!sGmw`v76Vq zbN_J|fUK&$}(clSFSKK5`scdc~=dMqP!jdjPW4EQhLhj!y_BamDKg z{s(>%Jk8+H%O>S3%Urt>i?HD}J{f#@>?xa?=BLaYFB4G=54fdyUZq?wg~#Hr4vvpMrB^$HB;(q8!kZk#GD=YRJJ= zJPovxh{JPOOPRRAyXxFl|CZ}^lC#Ru+$<;CD)SZZ9t_>NFZ9;Oe`U$$NCWm@Pyhe` M07*qoM6N<$g1E1MeEWFU8GbZ8()Nlj2>E@cM*00OH?L_t(&-sPG-cET_W z$7MYhZV?|NVadt?dKT8KIYE!om8Inva0@ov0TTQnJF?@%>8nS0*gwmE$&!qKk52)) zMpd@}03bx`e5ceI003^6bFSsYYjTeK~AKuV-EVveRa&15!?v(s?wDZJ*&xktg4K$q{But030f*g&z!NVR{td3F zz*-BvI#-Wl7~FE;rN+SF_@NGOc(v+BC@=WDyd)|L=@CfdL~>UHn4$jy;5LuNiQZ^I z3}Q1YNY zD`|C4?uDdvof0BC@Y)=jBNSJu4{EvD>vD`U4w3sWfxE31sDehLrVBo)=P zBH?vC2THC@#CM%fsWYbRcm>m+I3XOjc=@m{$lJxT{1)PS@bpbSbZ*d+y07Zim5f%= zSw4VnvR_d5RMj?Sxf<7t7bl%%t>LTM0$fNI8stPvg9oZMqgZ-#qBq%JOZz@>L+eDb zob3HelY3$p20;CA=UiuZJj+t;g1y>NUlB9q|Z zKEFS!95*0NAe*$7M@%<45 0 && dot == time.length() - 2 - && duration > 0) { - String p1 = time.substring(0, dot); - String p2 = time.substring(dot + 1); - try { - long i1 = Long.parseLong(p1); - long i2 = Long.parseLong(p2); - progress = (i1 * 1000L) - + (i2 * 100L); - int perm = (int) Math - .round((double) (progress * 1000L) - / (double) duration); - if (perm > 1000) { - perm = 1000; - } - listener.progress(perm); - } catch (NumberFormatException e) { - ; - } + + Matcher tm = TIME_PATTERN.matcher(time); + if (tm.matches()) { + try { + long hours = Long.parseLong(tm.group(1)); + long minutes = Long.parseLong(tm.group(2)); + long seconds = Long.parseLong(tm.group(3)); + long millis = Long.parseLong(tm.group(4)); + progress = (hours * 3600L * 1000L) + + (minutes * 60L * 1000L) + + (seconds * 1000L) + + (millis * 100L); + + int perm = (int) Math + .round((double) (progress * 1000L) + / (double) duration); + if (perm > 1000) { + perm = 1000; + } + listener.progress(perm); + + } catch (NumberFormatException e) { + ; + } + } else { + int dot = time.indexOf('.'); + if (dot > 0 && dot == time.length() - 2 + && duration > 0) { + String p1 = time.substring(0, dot); + String p2 = time.substring(dot + 1); + try { + long i1 = Long.parseLong(p1); + long i2 = Long.parseLong(p2); + progress = (i1 * 1000L) + + (i2 * 100L); + int perm = (int) Math + .round((double) (progress * 1000L) + / (double) duration); + if (perm > 1000) { + perm = 1000; + } + listener.progress(perm); + } catch (NumberFormatException e) { + ; + } + } } } } diff --git a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java index d838d26..7f1525e 100644 --- a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java +++ b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java @@ -1145,13 +1145,20 @@ public class AudiobookRecorder extends JFrame { i++; } } + FileOutputStream fos = null; try { - FileOutputStream fos = new FileOutputStream(config); + fos = new FileOutputStream(config); prefs.storeToXML(fos, "Audiobook Recorder Description"); } catch (Exception e) { e.printStackTrace(); } + if (fos != null) { + try { + fos.close(); + } catch (Exception e) { + } + } } public void loadBookStructure(File f) { @@ -1471,133 +1478,160 @@ public class AudiobookRecorder extends JFrame { } + class ExportThread implements Runnable { + ExportDialog exportDialog; + + public ExportThread(ExportDialog e) { + super(); + exportDialog = e; + } + + public void run() { + + try { + File bookRoot = new File(Options.get("path.storage"), book.getName()); + if (!bookRoot.exists()) { + bookRoot.mkdirs(); + } + + File export = new File(bookRoot, "export"); + if (!export.exists()) { + export.mkdirs(); + } + Encoder encoder; + + String ffloc = Options.get("path.ffmpeg"); + if (ffloc != null && !ffloc.equals("")) { + encoder = new Encoder(new FFMPEGLocator() { + public String getFFMPEGExecutablePath() { + return Options.get("path.ffmpeg"); + } + }); + } else { + encoder = new Encoder(); + } + EncodingAttributes attributes = new EncodingAttributes(); + + AudioAttributes audioAttributes = new AudioAttributes(); + audioAttributes.setCodec("libmp3lame"); + audioAttributes.setBitRate(Options.getInteger("audio.export.bitrate")); + audioAttributes.setSamplingRate(Options.getInteger("audio.export.samplerate")); + audioAttributes.setChannels(new Integer(2)); + attributes.setFormat("mp3"); + attributes.setAudioAttributes(audioAttributes); + + + AudioFormat format = roomNoise.getAudioFormat(); + byte[] data; + + for (Enumeration o = book.children(); o.hasMoreElements();) { + + int fullLength = 0; + + + Chapter c = o.nextElement(); + + if (c.getChildCount() == 0) continue; + int kids = c.getChildCount(); + if (kids == 0) continue; + String name = c.getName(); + exportDialog.setMessage("Exporting " + name); + exportDialog.setProgress(0); + + File exportFile = new File(export, name + ".wax"); + File wavFile = new File(export, name + ".wav"); + + FileOutputStream fos = new FileOutputStream(exportFile); + data = getRoomNoise(s2i(Options.get("catenation.pre-chapter"))); + fullLength += data.length; + fos.write(data); + + int kidno = 0; + + + for (Enumeration s = c.children(); s.hasMoreElements();) { + kidno++; + exportDialog.setProgress(kidno * 1000 / kids); + Sentence snt = s.nextElement(); + data = snt.getRawAudioData(); + + fullLength += data.length; + fos.write(data); + + if (s.hasMoreElements()) { + data = getRoomNoise(snt.getPostGap()); + } else { + data = getRoomNoise(s2i(Options.get("catenation.post-chapter"))); + } + fullLength += data.length; + fos.write(data); + } + fos.close(); + FileInputStream fis = new FileInputStream(exportFile); + AudioInputStream ais = new AudioInputStream(fis, format, fullLength); + fos = new FileOutputStream(wavFile); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, fos); + fos.flush(); + fos.close(); + fis.close(); + exportFile.delete(); + } + + + + for (Enumeration o = book.children(); o.hasMoreElements();) { + + Chapter c = o.nextElement(); + if (c.getChildCount() == 0) continue; + String name = c.getName(); + + exportDialog.setMessage("Converting " + name); + + File wavFile = new File(export, name + ".wav"); + File mp3File = new File(export, name + "-untagged.mp3"); + File taggedFile = new File(export, name + ".mp3"); + + encoder.encode(wavFile, mp3File, attributes, exportDialog); + + Mp3File id3 = new Mp3File(mp3File); + + ID3v2 tags = new ID3v24Tag(); + id3.setId3v2Tag(tags); + + tags.setTrack(Integer.toString(s2i(c.getId()) - 0)); + tags.setTitle(c.getName()); + tags.setAlbum(book.getName()); + tags.setArtist(book.getAuthor()); + + // ID3v2TextFrameData g = new ID3v2TextFrameData(false, new EncodedText(book.getGenre())); + // tags.addFrame(tags.createFrame("TCON", g.toBytes(), true)); + + tags.setComment(book.getComment()); + + id3.save(taggedFile.getAbsolutePath()); + mp3File.delete(); + wavFile.delete(); + + } + + + } catch (Exception e) { + e.printStackTrace(); + } + + exportDialog.closeDialog(); + } + } + @SuppressWarnings("unchecked") public void exportAudio() { - try { - File bookRoot = new File(Options.get("path.storage"), book.getName()); - if (!bookRoot.exists()) { - bookRoot.mkdirs(); - } + ExportDialog ed = new ExportDialog("Exporting book..."); - File export = new File(bookRoot, "export"); - if (!export.exists()) { - export.mkdirs(); - } - - Encoder encoder; - - String ffloc = Options.get("path.ffmpeg"); - if (ffloc != null && !ffloc.equals("")) { - encoder = new Encoder(new FFMPEGLocator() { - public String getFFMPEGExecutablePath() { - return Options.get("path.ffmpeg"); - } - }); - } else { - encoder = new Encoder(); - } - EncodingAttributes attributes = new EncodingAttributes(); - - AudioAttributes audioAttributes = new AudioAttributes(); - audioAttributes.setCodec("libmp3lame"); - audioAttributes.setBitRate(Options.getInteger("audio.export.bitrate")); - audioAttributes.setSamplingRate(Options.getInteger("audio.export.samplerate")); - audioAttributes.setChannels(new Integer(2)); - - attributes.setFormat("mp3"); - attributes.setAudioAttributes(audioAttributes); - - - AudioFormat format = roomNoise.getAudioFormat(); - byte[] data; - - for (Enumeration o = book.children(); o.hasMoreElements();) { - - int fullLength = 0; - - Chapter c = o.nextElement(); - if (c.getChildCount() == 0) continue; - String name = c.getName(); - - File exportFile = new File(export, name + ".wax"); - File wavFile = new File(export, name + ".wav"); - - FileOutputStream fos = new FileOutputStream(exportFile); - - data = getRoomNoise(s2i(Options.get("catenation.pre-chapter"))); - fullLength += data.length; - fos.write(data); - - for (Enumeration s = c.children(); s.hasMoreElements();) { - Sentence snt = s.nextElement(); - data = snt.getRawAudioData(); - - fullLength += data.length; - fos.write(data); - - if (s.hasMoreElements()) { - data = getRoomNoise(snt.getPostGap()); - } else { - data = getRoomNoise(s2i(Options.get("catenation.post-chapter"))); - } - fullLength += data.length; - fos.write(data); - } - fos.close(); - - FileInputStream fis = new FileInputStream(exportFile); - AudioInputStream ais = new AudioInputStream(fis, format, fullLength); - fos = new FileOutputStream(wavFile); - AudioSystem.write(ais, AudioFileFormat.Type.WAVE, fos); - fos.flush(); - fos.close(); - fis.close(); - exportFile.delete(); - } - - - - for (Enumeration o = book.children(); o.hasMoreElements();) { - - Chapter c = o.nextElement(); - if (c.getChildCount() == 0) continue; - String name = c.getName(); - - File wavFile = new File(export, name + ".wav"); - File mp3File = new File(export, name + "-untagged.mp3"); - File taggedFile = new File(export, name + ".mp3"); - - encoder.encode(wavFile, mp3File, attributes); - - Mp3File id3 = new Mp3File(mp3File); - - ID3v2 tags = new ID3v24Tag(); - id3.setId3v2Tag(tags); - - tags.setTrack(Integer.toString(s2i(c.getId()) - 0)); - tags.setTitle(c.getName()); - tags.setAlbum(book.getName()); - tags.setArtist(book.getAuthor()); - -// ID3v2TextFrameData g = new ID3v2TextFrameData(false, new EncodedText(book.getGenre())); -// tags.addFrame(tags.createFrame("TCON", g.toBytes(), true)); - - tags.setComment(book.getComment()); - - id3.save(taggedFile.getAbsolutePath()); - - mp3File.delete(); - wavFile.delete(); - - } - - JOptionPane.showMessageDialog(this, "Book exported.", "Done", JOptionPane.INFORMATION_MESSAGE); - - - } catch (Exception e) { - e.printStackTrace(); - } + ExportThread t = new ExportThread(ed); + Thread nt = new Thread(t); + nt.start(); + ed.setVisible(true); } diff --git a/src/uk/co/majenko/audiobookrecorder/ExportDialog.java b/src/uk/co/majenko/audiobookrecorder/ExportDialog.java new file mode 100644 index 0000000..f284940 --- /dev/null +++ b/src/uk/co/majenko/audiobookrecorder/ExportDialog.java @@ -0,0 +1,84 @@ +package uk.co.majenko.audiobookrecorder; + +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.border.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import it.sauronsoftware.jave.*; + +public class ExportDialog extends JDialog implements EncoderProgressListener { + JLabel message; + JLabel icon; + + JProgressBar progress; + + int spin = 0; + + + + public ExportDialog(String m) { + super(); + + setModalityType(Dialog.ModalityType.APPLICATION_MODAL); + + message = new JLabel(m); + icon = new JLabel(Icons.spinner0); + progress = new JProgressBar(0, 1000); + + setLayout(new BorderLayout()); + add(message, BorderLayout.CENTER); + + icon.setBorder(new EmptyBorder(10, 10, 10, 10)); + + add(icon, BorderLayout.WEST); + + + add(progress, BorderLayout.SOUTH); + + setLocationRelativeTo(AudiobookRecorder.window); + + setPreferredSize(new Dimension(300, 100)); + + pack(); + + setSize(new Dimension(300, 100)); + +// setVisible(true); + } + + public void setMessage(String m) { + message.setText(m); + } + + public void closeDialog() { + dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); + } + + public void spin() { + spin++; + if (spin == 4) spin = 0; + + switch (spin) { + case 0: icon.setIcon(Icons.spinner0); break; + case 1: icon.setIcon(Icons.spinner1); break; + case 2: icon.setIcon(Icons.spinner2); break; + case 3: icon.setIcon(Icons.spinner3); break; + } + } + + public void progress(int p) { setProgress(p); } + + public void setProgress(int p) { + progress.setValue(p); + progress.setString((p / 10) + "%"); + spin(); + } + + public void message(String m) { + } + + public void sourceInfo(MultimediaInfo i) { + } +} diff --git a/src/uk/co/majenko/audiobookrecorder/Icons.java b/src/uk/co/majenko/audiobookrecorder/Icons.java index d82a267..4db759f 100644 --- a/src/uk/co/majenko/audiobookrecorder/Icons.java +++ b/src/uk/co/majenko/audiobookrecorder/Icons.java @@ -22,5 +22,9 @@ public class Icons { static public final ImageIcon appIcon = new ImageIcon(Icons.class.getResource("icons/appIcon.png")); static public final ImageIcon star = new ImageIcon(Icons.class.getResource("icons/star.png")); static public final ImageIcon important = new ImageIcon(Icons.class.getResource("icons/important.png")); + static public final ImageIcon spinner0 = new ImageIcon(Icons.class.getResource("icons/spinner0.png")); + static public final ImageIcon spinner1 = new ImageIcon(Icons.class.getResource("icons/spinner1.png")); + static public final ImageIcon spinner2 = new ImageIcon(Icons.class.getResource("icons/spinner2.png")); + static public final ImageIcon spinner3 = new ImageIcon(Icons.class.getResource("icons/spinner3.png")); } diff --git a/src/uk/co/majenko/audiobookrecorder/Sentence.java b/src/uk/co/majenko/audiobookrecorder/Sentence.java index e1ee121..f6df4a7 100644 --- a/src/uk/co/majenko/audiobookrecorder/Sentence.java +++ b/src/uk/co/majenko/audiobookrecorder/Sentence.java @@ -96,6 +96,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable { try { AudioSystem.write(inputStream, AudioFileFormat.Type.WAVE, audioFile); } catch (Exception e) { + inputStream = null; e.printStackTrace(); } } @@ -112,8 +113,10 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable { public void stopRecording() { try { inputStream.close(); + inputStream = null; line.stop(); line.close(); + line = null; } catch (Exception e) { e.printStackTrace(); }