diff --git a/pom.xml b/pom.xml index d7ae9ef..31a5f1c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sh.ball osci-render - 1.18.0 + 1.18.1 osci-render diff --git a/src/main/java/sh/ball/audio/ShapeAudioPlayer.java b/src/main/java/sh/ball/audio/ShapeAudioPlayer.java index d6b4c8a..95085b4 100644 --- a/src/main/java/sh/ball/audio/ShapeAudioPlayer.java +++ b/src/main/java/sh/ball/audio/ShapeAudioPlayer.java @@ -91,7 +91,7 @@ public class ShapeAudioPlayer implements AudioPlayer> { communicator.addListener(this); } - private void resetMidi() { + public void resetMidi() { keysDown.clear(); for (int i = 0; i < keyTargetVolumes.length; i++) { Arrays.fill(keyTargetVolumes[i], (short) 0); @@ -102,6 +102,7 @@ public class ShapeAudioPlayer implements AudioPlayer> { keyActualVolumes[0][60] = (short) MidiNote.MAX_VELOCITY; keysDown.add(new MidiNote(60)); midiStarted = false; + notesChanged(); } public void stopMidiNotes() { @@ -118,6 +119,11 @@ public class ShapeAudioPlayer implements AudioPlayer> { public void setVolume(DoubleProperty volume) { this.volume = Objects.requireNonNullElseGet(volume, () -> new SimpleDoubleProperty(1)); + this.volume.addListener(e -> { + if (keysDown.size() == 0) { + resetMidi(); + } + }); } private Vector2 generateChannels() throws InterruptedException { @@ -477,6 +483,7 @@ public class ShapeAudioPlayer implements AudioPlayer> { return; } } + } public void setTrace(double trace) { @@ -489,7 +496,8 @@ public class ShapeAudioPlayer implements AudioPlayer> { return; } int command = message.getCommand(); - if (!midiStarted) { + + if (!midiStarted && (command == ShortMessage.NOTE_ON || command == ShortMessage.NOTE_OFF)) { stopMidiNotes(); midiStarted = true; } diff --git a/src/main/java/sh/ball/audio/effect/TranslateEffect.java b/src/main/java/sh/ball/audio/effect/TranslateEffect.java index b862f1d..55576e2 100644 --- a/src/main/java/sh/ball/audio/effect/TranslateEffect.java +++ b/src/main/java/sh/ball/audio/effect/TranslateEffect.java @@ -8,6 +8,7 @@ public class TranslateEffect extends PhaseEffect { private Vector2 translation; private boolean ellipse = false; + private double scale; public TranslateEffect(int sampleRate, double speed, Vector2 translation) { super(sampleRate, speed); @@ -22,9 +23,9 @@ public class TranslateEffect extends PhaseEffect { public Vector2 apply(int count, Vector2 vector) { if (ellipse) { double theta = nextTheta(); - return vector.translate(translation.scale(new Vector2(Math.sin(theta), Math.cos(theta)))); + return vector.translate(translation.scale(new Vector2(Math.sin(theta), Math.cos(theta))).scale(scale)); } else { - return vector.translate(translation); + return vector.translate(translation.scale(scale)); } } @@ -38,4 +39,8 @@ public class TranslateEffect extends PhaseEffect { } this.ellipse = ellipse; } + + public void setScale(double scale) { + this.scale = scale; + } } diff --git a/src/main/java/sh/ball/gui/controller/ImageController.java b/src/main/java/sh/ball/gui/controller/ImageController.java index 40eeecc..1286718 100644 --- a/src/main/java/sh/ball/gui/controller/ImageController.java +++ b/src/main/java/sh/ball/gui/controller/ImageController.java @@ -51,6 +51,10 @@ public class ImageController implements Initializable, SubController { @FXML private CheckBox translateCheckBox; @FXML + private Slider translationScaleSlider; + @FXML + private SVGPath translationScaleMidi; + @FXML private Slider frequencySlider; @FXML private SVGPath frequencyMidi; @@ -133,6 +137,8 @@ public class ImageController implements Initializable, SubController { translateEllipseCheckBox.selectedProperty().addListener((e, old, ellipse) -> translateEffect.setEllipse(ellipse)); + translationScaleSlider.valueProperty().addListener((e, old, scale) -> translateEffect.setScale(scale.doubleValue())); + // converts the value of frequencySlider to the actual frequency that it represents so that it // can increase at an exponential scale. frequencySlider.valueProperty().addListener((o, old, f) -> frequency.set(Math.pow(MAX_FREQUENCY, f.doubleValue()))); @@ -150,20 +156,21 @@ public class ImageController implements Initializable, SubController { rotateSpeedMidi, rotateSpeedSlider, translationSpeedMidi, translationSpeedSlider, volumeMidi, volumeSlider, - visibilityMidi, visibilitySlider + visibilityMidi, visibilitySlider, + translationScaleMidi, translationScaleSlider ); } @Override public List sliders() { return List.of(frequencySlider, rotateSpeedSlider, translationSpeedSlider, - volumeSlider, visibilitySlider); + volumeSlider, visibilitySlider, translationScaleSlider); } @Override public List labels() { return List.of("frequency", "rotateSpeed", "translationSpeed", "volume", - "visibility"); + "visibility", "translationScale"); } @Override diff --git a/src/main/java/sh/ball/gui/controller/MainController.java b/src/main/java/sh/ball/gui/controller/MainController.java index eed6edf..e558436 100644 --- a/src/main/java/sh/ball/gui/controller/MainController.java +++ b/src/main/java/sh/ball/gui/controller/MainController.java @@ -102,6 +102,8 @@ public class MainController implements Initializable, FrequencyListener, MidiLis @FXML private MenuItem stopMidiNotesMenuItem; @FXML + private MenuItem resetMidiMenuItem; + @FXML private Spinner midiChannelSpinner; public MainController() throws Exception { @@ -198,8 +200,8 @@ public class MainController implements Initializable, FrequencyListener, MidiLis }); resetMidiMappingMenuItem.setOnAction(e -> resetCCMap()); - stopMidiNotesMenuItem.setOnAction(e -> audioPlayer.stopMidiNotes()); + resetMidiMenuItem.setOnAction(e -> audioPlayer.resetMidi()); NumberFormat format = NumberFormat.getIntegerInstance(); UnaryOperator filter = c -> { @@ -489,8 +491,12 @@ public class MainController implements Initializable, FrequencyListener, MidiLis private void loadSliderValues(List sliders, List labels, Element root) { for (int i = 0; i < sliders.size(); i++) { - String value = root.getElementsByTagName(labels.get(i)).item(0).getTextContent(); - sliders.get(i).setValue(Float.parseFloat(value)); + NodeList nodes = root.getElementsByTagName(labels.get(i)); + // backwards compatibility + if (nodes.getLength() > 0) { + String value = nodes.item(0).getTextContent(); + sliders.get(i).setValue(Float.parseFloat(value)); + } } } @@ -581,6 +587,7 @@ public class MainController implements Initializable, FrequencyListener, MidiLis resetCCMap(); for (int i = 0; i < labels.size(); i++) { NodeList elements = midiElement.getElementsByTagName(labels.get(i)); + // backwards compatibility if (elements.getLength() > 0) { Element midi = (Element) elements.item(0); int cc = Integer.parseInt(midi.getTextContent()); diff --git a/src/main/resources/fxml/image.fxml b/src/main/resources/fxml/image.fxml index f353048..508b96a 100644 --- a/src/main/resources/fxml/image.fxml +++ b/src/main/resources/fxml/image.fxml @@ -8,28 +8,28 @@ - + - - diff --git a/src/main/resources/fxml/main.fxml b/src/main/resources/fxml/main.fxml index 49a16dd..63382d3 100644 --- a/src/main/resources/fxml/main.fxml +++ b/src/main/resources/fxml/main.fxml @@ -43,6 +43,7 @@ +