From 8bdb06749f168e5155ecbd4af3f81b39b140a60e Mon Sep 17 00:00:00 2001 From: Matt Jenkins Date: Fri, 10 Jan 2020 18:29:22 +0000 Subject: [PATCH] Improvements to LFO --- .../audiobookrecorder/AudiobookRecorder.java | 35 +++++++++++- .../audiobookrecorder/BookTreeRenderer.java | 4 ++ src/uk/co/majenko/audiobookrecorder/LFO.java | 56 +++++++++++++++---- .../majenko/audiobookrecorder/Waveform.java | 1 + 4 files changed, 85 insertions(+), 11 deletions(-) diff --git a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java index 04dd422..7db0cce 100644 --- a/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java +++ b/src/uk/co/majenko/audiobookrecorder/AudiobookRecorder.java @@ -3227,7 +3227,40 @@ public class AudiobookRecorder extends JFrame { double f = Utils.s2d(root.getAttribute("frequency")); double d = Utils.s2d(root.getAttribute("depth")); double p = Utils.s2d(root.getAttribute("phase")); - return new LFO(f, d, p); + double dty = Math.PI; + String waveform = root.getAttribute("waveform"); + if (waveform == null) { + waveform = "sine"; + } + + int w = LFO.SINE; + + switch (waveform.toLowerCase()) { + case "sine": w = LFO.SINE; break; + case "cosine": w = LFO.COSINE; break; + case "square": w = LFO.SQUARE; break; + case "triangle": w = LFO.TRIANGLE; break; + case "sawtooth": w = LFO.SAWTOOTH; break; + } + + int m = LFO.ADD; + + String mode = root.getAttribute("mode"); + + if (mode == null) { + mode = "add"; + } + + switch (mode.toLowerCase()) { + case "add": m = LFO.ADD; break; + case "replace": m = LFO.REPLACE; break; + } + + if (root.getAttribute("duty") != null) { + int di = Utils.s2i(root.getAttribute("duty")); // 0-100; + dty = (Math.PI * 2) * ((double)di / 100d); + } + return new LFO(f, d, p, w, dty, m); } public AGC loadAGC(Element root) { diff --git a/src/uk/co/majenko/audiobookrecorder/BookTreeRenderer.java b/src/uk/co/majenko/audiobookrecorder/BookTreeRenderer.java index 1552c9d..abd7a65 100644 --- a/src/uk/co/majenko/audiobookrecorder/BookTreeRenderer.java +++ b/src/uk/co/majenko/audiobookrecorder/BookTreeRenderer.java @@ -34,6 +34,10 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer { icn.add(Overlays.important, OverlayIcon.TOP_RIGHT); } + if (s.getEndOffset() == s.getSampleSize() - 1) { + icn.add(Overlays.important, OverlayIcon.TOP_RIGHT); + } + if (s.getEffectChain() != null) { if (!s.getEffectChain().equals("none")) { icn.add(Overlays.filter, OverlayIcon.BOTTOM_RIGHT); diff --git a/src/uk/co/majenko/audiobookrecorder/LFO.java b/src/uk/co/majenko/audiobookrecorder/LFO.java index 7689385..e10c107 100644 --- a/src/uk/co/majenko/audiobookrecorder/LFO.java +++ b/src/uk/co/majenko/audiobookrecorder/LFO.java @@ -9,37 +9,73 @@ public class LFO implements Effect { double depth; double sampleRate; double sampleStep; + int waveform; + double duty; + int mode; + + public static final int SINE = 0; + public static final int COSINE = 1; + public static final int SQUARE = 2; + public static final int TRIANGLE = 3; + public static final int SAWTOOTH = 4; + + public static final int ADD = 0; + public static final int REPLACE = 1; public LFO(double f, double d) { - frequency = f; - depth = d; - phase = 0; + this(f, d, 0, SINE, Math.PI, REPLACE); } public LFO(double f, double d, double p) { + this(f, d, p, SINE, Math.PI, REPLACE); + } + + public LFO(double f, double d, double p, int w) { + this(f, d, p, w, Math.PI, REPLACE); + } + + public LFO(double f, double d, double p, int w, double dty) { + this(f, d, p, w, dty, REPLACE); + } + + public LFO(double f, double d, double p, int w, double dty, int m) { frequency = f; depth = d; phase = p; + waveform = w; + duty = dty; + mode = m; } public void process(double[][] samples) { for (double[] sample : samples) { - double v = Math.sin(phase); + double v = 0; + switch (waveform) { + case SINE: v = Math.sin(phase); break; + case COSINE: v = Math.cos(phase); break; + case SQUARE: v = (phase > duty) ? 1d : 0d; break; + case TRIANGLE: v = (phase < Math.PI) ? (phase / Math.PI) : (1d - ((phase - Math.PI) / Math.PI)); break; + case SAWTOOTH: v = (phase / (Math.PI*2d)); break; + } phase += sampleStep; if (phase > (Math.PI * 2d)) { phase -= (Math.PI * 2d); } -// // Make it between 0 and 1. -// v = 1d + v; -// v /= 2d; - // Multiply it by the gain factor v *= depth; // Apply it to the sample - sample[Sentence.LEFT] += (sample[Sentence.LEFT] * v); - sample[Sentence.RIGHT] += (sample[Sentence.RIGHT] * v); + switch (mode) { + case REPLACE: + sample[Sentence.LEFT] = (sample[Sentence.LEFT] * v); + sample[Sentence.RIGHT] = (sample[Sentence.RIGHT] * v); + break; + case ADD: + sample[Sentence.LEFT] += (sample[Sentence.LEFT] * v); + sample[Sentence.RIGHT] += (sample[Sentence.RIGHT] * v); + break; + } } } diff --git a/src/uk/co/majenko/audiobookrecorder/Waveform.java b/src/uk/co/majenko/audiobookrecorder/Waveform.java index 3deb789..79ee36d 100644 --- a/src/uk/co/majenko/audiobookrecorder/Waveform.java +++ b/src/uk/co/majenko/audiobookrecorder/Waveform.java @@ -97,6 +97,7 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen double lmax = 0; for (int o = 0; o < step; o++) { + if (offset + (n * step) + o >= samples.length) break; double sample = (samples[offset + (n * step) + o][Sentence.LEFT] + samples[offset + (n * step) + o][Sentence.RIGHT]) / 2d; if (sample >= 0) { have += sample;