diff --git a/CHANGELOG.md b/CHANGELOG.md index ea6f689..098ffaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +- 1.24.1 + - Various optimisations + - Mic-based control is now slightly smoother + + - 1.24.0 - Add spinners to all effect sliders - Add spinner to frequency slider diff --git a/pom.xml b/pom.xml index 6bbc2c8..d44b9f5 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sh.ball osci-render - 1.24.0 + 1.24.1 osci-render diff --git a/src/main/java/sh/ball/audio/ShapeAudioPlayer.java b/src/main/java/sh/ball/audio/ShapeAudioPlayer.java index 96c8ae8..4413482 100644 --- a/src/main/java/sh/ball/audio/ShapeAudioPlayer.java +++ b/src/main/java/sh/ball/audio/ShapeAudioPlayer.java @@ -57,7 +57,7 @@ public class ShapeAudioPlayer implements AudioPlayer> { private final Callable audioEngineBuilder; private final BlockingQueue> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE); private final Map effects = new ConcurrentHashMap<>(); - private final List listeners = new CopyOnWriteArrayList<>(); + private final Queue listeners = new ConcurrentLinkedQueue<>(); private AudioEngine audioEngine; private ByteArrayOutputStream outputStream; @@ -223,17 +223,19 @@ public class ShapeAudioPlayer implements AudioPlayer> { } private Vector2 cutoff(Vector2 vector) { - if (vector.getX() < -1) { - vector = vector.setX(-1); - } else if (vector.getX() > 1) { - vector = vector.setX(1); + double x = vector.x; + double y = vector.y; + if (x < -1) { + x = -1; + } else if (x > 1) { + x = 1; } - if (vector.getY() < -1) { - vector = vector.setY(-1); - } else if (vector.getY() > 1) { - vector = vector.setY(1); + if (y < -1) { + y = -1; + } else if (y > 1) { + y = 1; } - return vector; + return new Vector2(x, y); } private Vector2 applyEffects(int frame, Vector2 vector) { diff --git a/src/main/java/sh/ball/audio/effect/BitCrushEffect.java b/src/main/java/sh/ball/audio/effect/BitCrushEffect.java index c29f805..a1d1cfb 100644 --- a/src/main/java/sh/ball/audio/effect/BitCrushEffect.java +++ b/src/main/java/sh/ball/audio/effect/BitCrushEffect.java @@ -12,9 +12,7 @@ public class BitCrushEffect implements SettableEffect { @Override public Vector2 apply(int count, Vector2 vector) { - double x = vector.getX(); - double y = vector.getY(); - return new Vector2(round(x, crush), round(y, crush)); + return new Vector2(round(vector.x, crush), round(vector.y, crush)); } @Override diff --git a/src/main/java/sh/ball/audio/effect/WobbleEffect.java b/src/main/java/sh/ball/audio/effect/WobbleEffect.java index 01d6c49..ea2fb57 100644 --- a/src/main/java/sh/ball/audio/effect/WobbleEffect.java +++ b/src/main/java/sh/ball/audio/effect/WobbleEffect.java @@ -39,8 +39,9 @@ public class WobbleEffect extends PhaseEffect implements FrequencyListener, Sett @Override public Vector2 apply(int count, Vector2 vector) { double theta = nextTheta(); - double x = vector.getX() + volume * Math.sin(frequency * theta); - double y = vector.getY() + volume * Math.sin(frequency * theta); + double delta = volume * Math.sin(frequency * theta); + double x = vector.x + delta; + double y = vector.y + delta; return new Vector2(x, y); } diff --git a/src/main/java/sh/ball/audio/engine/JavaAudioInput.java b/src/main/java/sh/ball/audio/engine/JavaAudioInput.java index 9cbcbc0..88a8c19 100644 --- a/src/main/java/sh/ball/audio/engine/JavaAudioInput.java +++ b/src/main/java/sh/ball/audio/engine/JavaAudioInput.java @@ -9,7 +9,8 @@ import java.util.List; public class JavaAudioInput implements AudioInput { private static final int DEFAULT_SAMPLE_RATE = 44100; - private static final int BUFFER_SIZE = 50; + private static final int CHUNK_SIZE = 512; + private static final int STEP_SIZE = 32; // java sound doesn't support anything more than 16 bit :( private static final int BIT_DEPTH = 16; // mono @@ -45,17 +46,19 @@ public class JavaAudioInput implements AudioInput { return; } try { - microphone.open(format, BUFFER_SIZE); + microphone.open(format); - // I am well aware this is inefficient - sufficient for the needs of - // modifying sliders - byte[] data = new byte[2]; + byte[] data = new byte[CHUNK_SIZE]; microphone.start(); while (!stopped) { - microphone.read(data, 0, 2); - short sample = (short) ((data[1] << 8) + data[0]); - for (AudioInputListener listener : listeners) { - listener.transmit((double) sample / Short.MAX_VALUE); + if (microphone.available() >= CHUNK_SIZE) { + microphone.read(data, 0, CHUNK_SIZE); + for (int i = 0; i < CHUNK_SIZE / 2; i += 2 * STEP_SIZE) { + short sample = (short) ((data[2 * i + 1] << 8) + data[2 * i]); + for (AudioInputListener listener : listeners) { + listener.transmit((double) sample / Short.MAX_VALUE); + } + } } } microphone.close(); diff --git a/src/main/java/sh/ball/gui/controller/MainController.java b/src/main/java/sh/ball/gui/controller/MainController.java index d7d7555..5e1b779 100644 --- a/src/main/java/sh/ball/gui/controller/MainController.java +++ b/src/main/java/sh/ball/gui/controller/MainController.java @@ -1109,8 +1109,7 @@ public class MainController implements Initializable, FrequencyListener, MidiLis } else if (sliderValue < slider.getMin()) { sliderValue = slider.getMin(); } - // TODO: Correctly update frequency spinner! - subControllers().forEach(sub -> sub.micSignalReceived()); + subControllers().forEach(SubController::micSignalReceived); sliders.get(i).setValue(sliderValue); } } diff --git a/src/main/java/sh/ball/shapes/Line.java b/src/main/java/sh/ball/shapes/Line.java index c160b03..c5b8a23 100644 --- a/src/main/java/sh/ball/shapes/Line.java +++ b/src/main/java/sh/ball/shapes/Line.java @@ -59,7 +59,10 @@ public final class Line extends Shape { @Override public Vector2 nextVector(double drawingProgress) { - return a.add(b.sub(a).scale(drawingProgress)); + return new Vector2( + a.x + drawingProgress * (b.x - a.x), + a.y + drawingProgress * (b.y - a.y) + ); } public Vector2 getA() { diff --git a/src/main/java/sh/ball/shapes/Vector2.java b/src/main/java/sh/ball/shapes/Vector2.java index ad68fd9..f753de2 100644 --- a/src/main/java/sh/ball/shapes/Vector2.java +++ b/src/main/java/sh/ball/shapes/Vector2.java @@ -61,10 +61,12 @@ public final class Vector2 extends Shape { @Override public Vector2 rotate(double theta) { - Vector2 vector = setX(getX() * Math.cos(theta) - getY() * Math.sin(theta)); - vector = vector.setY(getX() * Math.sin(theta) + getY() * Math.cos(theta)); - - return vector; + double cosTheta = Math.cos(theta); + double sinTheta = Math.sin(theta); + return new Vector2( + x * cosTheta - y * sinTheta, + x * sinTheta + y * cosTheta + ); } @Override @@ -74,12 +76,12 @@ public final class Vector2 extends Shape { @Override public Vector2 scale(Vector2 vector) { - return new Vector2(getX() * vector.getX(), getY() * vector.getY()); + return new Vector2(x * vector.x, y * vector.y); } @Override public Vector2 translate(Vector2 vector) { - return new Vector2(getX() + vector.getX(), getY() + vector.getY()); + return new Vector2(x + vector.x, y + vector.y); } @Override @@ -96,13 +98,12 @@ public final class Vector2 extends Shape { return false; } Vector2 point = (Vector2) obj; - return round(x, 2) == round(point.x, 2) - && round(y, 2) == round(point.y, 2); + return x == point.x && y == point.y; } @Override public int hashCode() { - return Objects.hash(round(x, 2), round(y, 2)); + return Objects.hash(x, y); } @Override