From 746f47a5faea245c46b7b0303a121f9df98e06bf Mon Sep 17 00:00:00 2001 From: Matt Jenkins Date: Mon, 3 Feb 2020 20:27:15 +0000 Subject: [PATCH] Added release version checker --- deps/json-20190722.jar | 3 + .../co/majenko/audiobookrecorder/config.txt | 2 +- .../audiobookrecorder/AudiobookRecorder.java | 23 ++- .../co/majenko/audiobookrecorder/Biquad.java | 18 -- src/uk/co/majenko/audiobookrecorder/Book.java | 5 +- src/uk/co/majenko/audiobookrecorder/FFT.java | 191 +++++++----------- .../co/majenko/audiobookrecorder/KVPair.java | 4 - .../majenko/audiobookrecorder/NoiseFloor.java | 51 +++++ .../audiobookrecorder/OverlayIcon.java | 30 --- .../audiobookrecorder/VersionChecker.java | 80 ++++++++ 10 files changed, 231 insertions(+), 176 deletions(-) create mode 100644 deps/json-20190722.jar create mode 100644 src/uk/co/majenko/audiobookrecorder/NoiseFloor.java create mode 100644 src/uk/co/majenko/audiobookrecorder/VersionChecker.java diff --git a/deps/json-20190722.jar b/deps/json-20190722.jar new file mode 100644 index 0000000..b148e8d --- /dev/null +++ b/deps/json-20190722.jar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e35b3830de02a8992ca8beb6936f52ee80e509753d64469c8f0dde93e17a880b +size 65003 diff --git a/resources/uk/co/majenko/audiobookrecorder/config.txt b/resources/uk/co/majenko/audiobookrecorder/config.txt index 4ed6b91..12251dc 100644 --- a/resources/uk/co/majenko/audiobookrecorder/config.txt +++ b/resources/uk/co/majenko/audiobookrecorder/config.txt @@ -1 +1 @@ -version=0.3.8 +version=0.3.9 diff --git a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java index ed8bc64..51d8485 100644 --- a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java +++ b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java @@ -149,7 +149,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { JPanel statusBar; - JLabel statusLabel; + NoiseFloor noiseFloorLabel; JScrollPane mainScroll; @@ -767,11 +767,13 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { centralPanel.add(sampleControl, BorderLayout.SOUTH); statusBar = new JPanel(); - statusBar.setLayout(new FlowLayout(FlowLayout.CENTER)); + statusBar.setLayout(new FlowLayout(FlowLayout.RIGHT)); add(statusBar, BorderLayout.SOUTH); - statusLabel = new JLabel("Noise floor: " + getNoiseFloorDB() + "dB"); - statusBar.add(statusLabel); + noiseFloorLabel = new NoiseFloor(); + + statusBar.add(noiseFloorLabel); +// statusBar.add(Box.createHorizontalStrut(2)); statusBar.add(queueMonitor); buildToolbar(centralPanel); @@ -1010,6 +1012,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { Options.savePreferences(); } + queueJob(new VersionChecker()); + } void bindKeys(JComponent component) { @@ -2328,7 +2332,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { bookTree.expandPath(new TreePath(book.getPath())); - statusLabel.setText("Noise floor: " + getNoiseFloorDB() + "dB"); + noiseFloorLabel.setNoiseFloor(getNoiseFloorDB()); } catch (Exception ex) { ex.printStackTrace(); @@ -2586,7 +2590,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { bookTree.expandPath(new TreePath(book.getPath())); - statusLabel.setText("Noise floor: " + getNoiseFloorDB() + "dB"); + noiseFloorLabel.setNoiseFloor(getNoiseFloorDB()); book.setIcon(Icons.book); } @@ -2659,7 +2663,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { Debug.trace(); roomNoise.stopRecording(); centralPanel.setFlash(false); - statusLabel.setText("Noise floor: " + getNoiseFloorDB() + "dB"); + noiseFloorLabel.setNoiseFloor(getNoiseFloorDB()); } }, 5000); // 5 seconds of recording } @@ -4194,7 +4198,10 @@ public class AudiobookRecorder extends JFrame implements DocumentListener { } } if (orphans.getChildCount() == 0) { - bookTreeModel.removeNodeFromParent(orphans); + try { + bookTreeModel.removeNodeFromParent(orphans); + } catch (Exception ignored) { + } } } diff --git a/src/uk/co/majenko/audiobookrecorder/Biquad.java b/src/uk/co/majenko/audiobookrecorder/Biquad.java index c819839..dce80c2 100644 --- a/src/uk/co/majenko/audiobookrecorder/Biquad.java +++ b/src/uk/co/majenko/audiobookrecorder/Biquad.java @@ -1,23 +1,5 @@ package uk.co.majenko.audiobookrecorder; -// Biquad.java -// -// Created by Nigel Redmon on 11/24/12 -// EarLevel Engineering: earlevel.com -// Copyright 2012 Nigel Redmon -// Translated to Java 2019 Majenko Technologies -// -// For a complete explanation of the Biquad code: -// http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/ -// -// License: -// -// This source code is provided as is, without warranty. -// You may copy and distribute verbatim copies of this document. -// You may modify and use this source code to create binary code -// for your own purposes, free or commercial. -// - import java.util.ArrayList; public class Biquad implements Effect { diff --git a/src/uk/co/majenko/audiobookrecorder/Book.java b/src/uk/co/majenko/audiobookrecorder/Book.java index 3f40cbb..1e3bc8e 100644 --- a/src/uk/co/majenko/audiobookrecorder/Book.java +++ b/src/uk/co/majenko/audiobookrecorder/Book.java @@ -450,7 +450,10 @@ public class Book extends BookTreeNode { public void run() { if (AudiobookRecorder.window == null) return; if (AudiobookRecorder.window.bookTreeModel == null) return; - AudiobookRecorder.window.bookTreeModel.reload(Book.this); + try { + AudiobookRecorder.window.bookTreeModel.reload(Book.this); + } catch (Exception ignored) { + } } }); } diff --git a/src/uk/co/majenko/audiobookrecorder/FFT.java b/src/uk/co/majenko/audiobookrecorder/FFT.java index 1258b09..5f7c3ee 100644 --- a/src/uk/co/majenko/audiobookrecorder/FFT.java +++ b/src/uk/co/majenko/audiobookrecorder/FFT.java @@ -1,130 +1,93 @@ package uk.co.majenko.audiobookrecorder; -/** -* @author Orlando Selenu -* -*/ public class FFT { -/** - * The Fast Fourier Transform (generic version, with NO optimizations). - * - * @param inputReal - * an array of length n, the real part - * @param inputImag - * an array of length n, the imaginary part - * @param DIRECT - * TRUE = direct transform, FALSE = inverse transform - * @return a new array of length 2n - */ -public static double[] fft(final double[] inputReal, double[] inputImag, - boolean DIRECT) { - // - n is the dimension of the problem - // - nu is its logarithm in base e - int n = inputReal.length; + public static double[] fft(final double[] inputReal, double[] inputImag, boolean DIRECT) { + int n = inputReal.length; - // If n is a power of 2, then ld is an integer (_without_ decimals) - double ld = Math.log(n) / Math.log(2.0); + double ld = Math.log(n) / Math.log(2.0); - // Here I check if n is a power of 2. If exist decimals in ld, I quit - // from the function returning null. - if (((int) ld) - ld != 0) { - System.out.println("The number of elements is not a power of 2."); - return null; - } + if (((int) ld) - ld != 0) { + System.out.println("The number of elements is not a power of 2."); + return null; + } - // Declaration and initialization of the variables - // ld should be an integer, actually, so I don't lose any information in - // the cast - int nu = (int) ld; - int n2 = n / 2; - int nu1 = nu - 1; - double[] xReal = new double[n]; - double[] xImag = new double[n]; - double tReal, tImag, p, arg, c, s; + int nu = (int) ld; + int n2 = n / 2; + int nu1 = nu - 1; + double[] xReal = new double[n]; + double[] xImag = new double[n]; + double tReal, tImag, p, arg, c, s; + + double constant; + if (DIRECT) { + constant = -2 * Math.PI; + } else { + constant = 2 * Math.PI; + } - // Here I check if I'm going to do the direct transform or the inverse - // transform. - double constant; - if (DIRECT) - constant = -2 * Math.PI; - else - constant = 2 * Math.PI; + for (int i = 0; i < n; i++) { + xReal[i] = inputReal[i]; + xImag[i] = inputImag[i]; + } - // I don't want to overwrite the input arrays, so here I copy them. This - // choice adds \Theta(2n) to the complexity. - for (int i = 0; i < n; i++) { - xReal[i] = inputReal[i]; - xImag[i] = inputImag[i]; - } - - // First phase - calculation - int k = 0; - for (int l = 1; l <= nu; l++) { - while (k < n) { - for (int i = 1; i <= n2; i++) { - p = bitreverseReference(k >> nu1, nu); - // direct FFT or inverse FFT - arg = constant * p / n; - c = Math.cos(arg); - s = Math.sin(arg); - tReal = xReal[k + n2] * c + xImag[k + n2] * s; - tImag = xImag[k + n2] * c - xReal[k + n2] * s; - xReal[k + n2] = xReal[k] - tReal; - xImag[k + n2] = xImag[k] - tImag; - xReal[k] += tReal; - xImag[k] += tImag; - k++; + int k = 0; + for (int l = 1; l <= nu; l++) { + while (k < n) { + for (int i = 1; i <= n2; i++) { + p = bitreverseReference(k >> nu1, nu); + // direct FFT or inverse FFT + arg = constant * p / n; + c = Math.cos(arg); + s = Math.sin(arg); + tReal = xReal[k + n2] * c + xImag[k + n2] * s; + tImag = xImag[k + n2] * c - xReal[k + n2] * s; + xReal[k + n2] = xReal[k] - tReal; + xImag[k + n2] = xImag[k] - tImag; + xReal[k] += tReal; + xImag[k] += tImag; + k++; + } + k += n2; } - k += n2; + k = 0; + nu1--; + n2 /= 2; } + k = 0; - nu1--; - n2 /= 2; - } - - // Second phase - recombination - k = 0; - int r; - while (k < n) { - r = bitreverseReference(k, nu); - if (r > k) { - tReal = xReal[k]; - tImag = xImag[k]; - xReal[k] = xReal[r]; - xImag[k] = xImag[r]; - xReal[r] = tReal; - xImag[r] = tImag; + int r; + while (k < n) { + r = bitreverseReference(k, nu); + if (r > k) { + tReal = xReal[k]; + tImag = xImag[k]; + xReal[k] = xReal[r]; + xImag[k] = xImag[r]; + xReal[r] = tReal; + xImag[r] = tImag; + } + k++; } - k++; + + double[] newArray = new double[xReal.length * 2]; + double radice = 1 / Math.sqrt(n); + for (int i = 0; i < newArray.length; i += 2) { + int i2 = i / 2; + newArray[i] = xReal[i2] * radice; + newArray[i + 1] = xImag[i2] * radice; + } + return newArray; } - // Here I have to mix xReal and xImag to have an array (yes, it should - // be possible to do this stuff in the earlier parts of the code, but - // it's here to readibility). - double[] newArray = new double[xReal.length * 2]; - double radice = 1 / Math.sqrt(n); - for (int i = 0; i < newArray.length; i += 2) { - int i2 = i / 2; - // I used Stephen Wolfram's Mathematica as a reference so I'm going - // to normalize the output while I'm copying the elements. - newArray[i] = xReal[i2] * radice; - newArray[i + 1] = xImag[i2] * radice; + private static int bitreverseReference(int j, int nu) { + int j2; + int j1 = j; + int k = 0; + for (int i = 1; i <= nu; i++) { + j2 = j1 / 2; + k = 2 * k + j1 - 2 * j2; + j1 = j2; + } + return k; } - return newArray; -} - -/** - * The reference bitreverse function. - */ -private static int bitreverseReference(int j, int nu) { - int j2; - int j1 = j; - int k = 0; - for (int i = 1; i <= nu; i++) { - j2 = j1 / 2; - k = 2 * k + j1 - 2 * j2; - j1 = j2; - } - return k; - } } diff --git a/src/uk/co/majenko/audiobookrecorder/KVPair.java b/src/uk/co/majenko/audiobookrecorder/KVPair.java index 7d156dd..a368b0f 100644 --- a/src/uk/co/majenko/audiobookrecorder/KVPair.java +++ b/src/uk/co/majenko/audiobookrecorder/KVPair.java @@ -14,10 +14,6 @@ public class KVPair implements Comparable { } public int compareTo(Object o) { -// if (o instanceof KVPair) { -// KVPair ko = (KVPair)o; -// return key.compareTo(ko.key); -// } return 0; } diff --git a/src/uk/co/majenko/audiobookrecorder/NoiseFloor.java b/src/uk/co/majenko/audiobookrecorder/NoiseFloor.java new file mode 100644 index 0000000..31a7b23 --- /dev/null +++ b/src/uk/co/majenko/audiobookrecorder/NoiseFloor.java @@ -0,0 +1,51 @@ +package uk.co.majenko.audiobookrecorder; + +import javax.swing.JPanel; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Dimension; +import java.awt.Color; + +public class NoiseFloor extends JPanel { + + int noiseFloor = 0; + + public NoiseFloor() { + super(); + noiseFloor = 0; + } + + public void setNoiseFloor(int n) { + noiseFloor = n; + repaint(); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(128, 24); + } + + @Override + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + @Override + public Dimension getMaximumSize() { + return getPreferredSize(); + } + + @Override + public void paintComponent(Graphics g) { + Rectangle size = g.getClipBounds(); + g.setColor(getBackground()); + g.fillRect(0, 0, size.width - 1, size.height - 1); + g.setColor(new Color(10, 10, 10)); + g.drawRect(0, 0, size.width - 1, size.height - 1); + g.setFont(getFont()); + + g.setColor(getForeground()); + g.drawString("Noise Floor: " + noiseFloor + "dB", 6, 16); + } +} + diff --git a/src/uk/co/majenko/audiobookrecorder/OverlayIcon.java b/src/uk/co/majenko/audiobookrecorder/OverlayIcon.java index 6e295b1..ccadc02 100644 --- a/src/uk/co/majenko/audiobookrecorder/OverlayIcon.java +++ b/src/uk/co/majenko/audiobookrecorder/OverlayIcon.java @@ -1,33 +1,3 @@ -/* - * Copyright (c) 2015, Majenko Technologies - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * * Neither the name of Majenko Technologies nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - package uk.co.majenko.audiobookrecorder; import javax.swing.ImageIcon; diff --git a/src/uk/co/majenko/audiobookrecorder/VersionChecker.java b/src/uk/co/majenko/audiobookrecorder/VersionChecker.java new file mode 100644 index 0000000..f792ded --- /dev/null +++ b/src/uk/co/majenko/audiobookrecorder/VersionChecker.java @@ -0,0 +1,80 @@ +package uk.co.majenko.audiobookrecorder; + +import java.lang.Runnable; +import java.net.URL; +import javax.net.ssl.HttpsURLConnection; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.BufferedReader; +import org.json.JSONObject; +import javax.swing.JButton; +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; + +public class VersionChecker implements Runnable { + public VersionChecker() { + } + + public void run() { + try { + URL url = new URL("https://api.github.com/repos/MajenkoProjects/AudiobookRecorder/releases/latest"); + HttpsURLConnection conn = (HttpsURLConnection)url.openConnection(); + InputStream is = conn.getInputStream(); + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + + String inputLine; + StringBuilder jsonData = new StringBuilder(); + + while ((inputLine = br.readLine()) != null) { + jsonData.append(inputLine); + } + + br.close(); + + JSONObject job = new JSONObject(jsonData.toString()); + + String installed = AudiobookRecorder.config.getProperty("version"); + String available = job.getString("tag_name"); + if (available.startsWith("v")) { + available = available.substring(1); + } + String website = job.getString("html_url"); + + + String[] installedParts = installed.split("\\."); + String[] availableParts = available.split("\\."); + // Must be x.y.z + + System.err.println(installedParts.length); + System.err.println(availableParts.length); + + if (installedParts.length != 3) return; + if (availableParts.length != 3) return; + + // Convert to xxxyyyzzz + String installedVersion = String.format("%03d%03d%03d", Utils.s2i(installedParts[0]), Utils.s2i(installedParts[1]), Utils.s2i(installedParts[2])); + String availableVersion = String.format("%03d%03d%03d", Utils.s2i(availableParts[0]), Utils.s2i(availableParts[1]), Utils.s2i(availableParts[2])); + + if (Utils.s2i(installedVersion) >= Utils.s2i(availableVersion)) return; + + System.err.println("Version installed: " + installed); + System.err.println("Version available: " + available); + System.err.println("URL: " + website); + + JButton upgrade = new JButton("A new version is available."); + upgrade.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + Utils.browse(website); + } + }); + + AudiobookRecorder.window.statusBar.add(upgrade); + AudiobookRecorder.window.statusBar.revalidate(); + + } catch (Exception ignored) { + ignored.printStackTrace(); + } + + } +}