kopia lustrzana https://github.com/jameshball/osci-render
rodzic
16acb3857c
commit
27215863ef
2
pom.xml
2
pom.xml
|
@ -6,7 +6,7 @@
|
|||
|
||||
<groupId>sh.ball</groupId>
|
||||
<artifactId>osci-render</artifactId>
|
||||
<version>1.32.3</version>
|
||||
<version>1.33.0</version>
|
||||
|
||||
<name>osci-render</name>
|
||||
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
package sh.ball.audio.effect;
|
||||
|
||||
public enum AnimationType {
|
||||
STATIC("Static"),
|
||||
SEESAW("Seesaw"),
|
||||
LINEAR("Linear"),
|
||||
FORWARD("Forward"),
|
||||
REVERSE("Reverse");
|
||||
STATIC("Static", "Static"),
|
||||
SINE("Sine", "Sine"),
|
||||
SQUARE("Square", "Square"),
|
||||
SEESAW("Seesaw", "Seesaw"),
|
||||
LINEAR("Linear", "Triangle"),
|
||||
FORWARD("Forward", "Sawtooth"),
|
||||
REVERSE("Reverse", "Reverse Sawtooth");
|
||||
|
||||
private final String name;
|
||||
private final String displayName;
|
||||
|
||||
AnimationType(String name) {
|
||||
AnimationType(String name, String displayName) {
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public static AnimationType fromString(String name) {
|
||||
|
@ -22,8 +26,12 @@ public enum AnimationType {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return displayName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,15 +6,12 @@ public class EffectAnimator extends PhaseEffect implements SettableEffect {
|
|||
|
||||
public static final int DEFAULT_SAMPLE_RATE = 192000;
|
||||
|
||||
private static final double SPEED_SCALE = 20.0;
|
||||
|
||||
private final SettableEffect effect;
|
||||
|
||||
private AnimationType type = AnimationType.STATIC;
|
||||
private boolean justSetToStatic = true;
|
||||
private double targetValue = 0.5;
|
||||
private double actualValue = 0.5;
|
||||
private boolean linearDirection = true;
|
||||
private double min;
|
||||
private double max;
|
||||
|
||||
|
@ -31,7 +28,6 @@ public class EffectAnimator extends PhaseEffect implements SettableEffect {
|
|||
|
||||
public void setAnimation(AnimationType type) {
|
||||
this.type = type;
|
||||
this.linearDirection = true;
|
||||
if (type == AnimationType.STATIC) {
|
||||
justSetToStatic = true;
|
||||
}
|
||||
|
@ -58,48 +54,26 @@ public class EffectAnimator extends PhaseEffect implements SettableEffect {
|
|||
|
||||
double minValue = min;
|
||||
double maxValue = max;
|
||||
double range = maxValue - minValue;
|
||||
if (range <= 0) {
|
||||
return vector;
|
||||
}
|
||||
double normalisedTargetValue = (targetValue - minValue) / range;
|
||||
double normalisedActualValue = (actualValue - minValue) / range;
|
||||
double phase = nextTheta();
|
||||
double percentage = phase / (2 * Math.PI);
|
||||
switch (type) {
|
||||
case SEESAW -> {
|
||||
double scalar = 10 * Math.max(Math.min(normalisedActualValue, 1 - normalisedActualValue), 0.01);
|
||||
double change = range * scalar * SPEED_SCALE * normalisedTargetValue / sampleRate;
|
||||
if (actualValue + change > maxValue || actualValue - change < minValue) {
|
||||
linearDirection = !linearDirection;
|
||||
}
|
||||
if (linearDirection) {
|
||||
actualValue += change;
|
||||
} else {
|
||||
actualValue -= change;
|
||||
}
|
||||
// modified sigmoid function
|
||||
actualValue = (percentage < 0.5) ? percentage * 2 : (1 - percentage) * 2;
|
||||
actualValue = 1 / (1 + Math.exp(-16 * (actualValue - 0.5)));
|
||||
actualValue = actualValue * (maxValue - minValue) + minValue;
|
||||
}
|
||||
case SINE -> {
|
||||
actualValue = Math.sin(phase) * 0.5 + 0.5;
|
||||
actualValue = actualValue * (maxValue - minValue) + minValue;
|
||||
}
|
||||
case LINEAR -> {
|
||||
double change = range * SPEED_SCALE * normalisedTargetValue / sampleRate;
|
||||
if (actualValue + change > maxValue || actualValue - change < minValue) {
|
||||
linearDirection = !linearDirection;
|
||||
}
|
||||
if (linearDirection) {
|
||||
actualValue += change;
|
||||
} else {
|
||||
actualValue -= change;
|
||||
}
|
||||
}
|
||||
case FORWARD -> {
|
||||
actualValue += range * 0.5 * SPEED_SCALE * normalisedTargetValue / sampleRate;
|
||||
if (actualValue > maxValue) {
|
||||
actualValue = minValue;
|
||||
}
|
||||
}
|
||||
case REVERSE -> {
|
||||
actualValue -= range * 0.5 * SPEED_SCALE * normalisedTargetValue / sampleRate;
|
||||
if (actualValue < minValue) {
|
||||
actualValue = maxValue;
|
||||
}
|
||||
actualValue = (percentage < 0.5) ? percentage * 2 : (1 - percentage) * 2;
|
||||
actualValue = actualValue * (maxValue - minValue) + minValue;
|
||||
}
|
||||
case SQUARE -> actualValue = (percentage < 0.5) ? maxValue : minValue;
|
||||
case FORWARD -> actualValue = percentage * (maxValue - minValue) + minValue;
|
||||
case REVERSE -> actualValue = (1 - percentage) * (maxValue - minValue) + minValue;
|
||||
}
|
||||
if (actualValue > maxValue) {
|
||||
actualValue = maxValue;
|
||||
|
|
|
@ -2,14 +2,10 @@ package sh.ball.audio.effect;
|
|||
|
||||
public abstract class PhaseEffect implements Effect {
|
||||
|
||||
// sufficiently large so that nextTheta doesn't commonly reach it, otherwise
|
||||
// there are audio artifacts
|
||||
private static final double LARGE_VAL = 2 << 20;
|
||||
|
||||
protected int sampleRate;
|
||||
|
||||
protected double speed;
|
||||
private double phase = -LARGE_VAL;
|
||||
private double phase = 0;
|
||||
|
||||
protected PhaseEffect(int sampleRate, double speed) {
|
||||
this.sampleRate = sampleRate;
|
||||
|
@ -17,17 +13,17 @@ public abstract class PhaseEffect implements Effect {
|
|||
}
|
||||
|
||||
public void resetTheta() {
|
||||
phase = -LARGE_VAL;
|
||||
phase = 0;
|
||||
}
|
||||
|
||||
protected double nextTheta() {
|
||||
phase += speed / sampleRate;
|
||||
|
||||
if (phase >= LARGE_VAL) {
|
||||
phase = -LARGE_VAL;
|
||||
if (phase > 1) {
|
||||
phase -= 1;
|
||||
}
|
||||
|
||||
return phase * Math.PI;
|
||||
return phase * 2 * Math.PI;
|
||||
}
|
||||
|
||||
public void setSpeed(double speed) {
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
package sh.ball.audio.effect;
|
||||
|
||||
import sh.ball.shapes.Vector2;
|
||||
|
||||
// Plays a sine wave at the given frequency and volume
|
||||
public class SineEffect extends PhaseEffect {
|
||||
|
||||
private static final double DEFAULT_VOLUME = 1;
|
||||
|
||||
private double frequency;
|
||||
private double volume;
|
||||
|
||||
public SineEffect(int sampleRate, double frequency, double volume) {
|
||||
super(sampleRate, 2);
|
||||
this.frequency = frequency;
|
||||
this.volume = Math.max(Math.min(volume, 1), 0);
|
||||
}
|
||||
|
||||
public SineEffect(int sampleRate, double frequency) {
|
||||
this(sampleRate, frequency, DEFAULT_VOLUME);
|
||||
}
|
||||
|
||||
public void setVolume(double volume) {
|
||||
this.volume = volume;
|
||||
}
|
||||
|
||||
public void setFrequency(double frequency) {
|
||||
this.frequency = frequency;
|
||||
}
|
||||
|
||||
@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.cos(frequency * theta);
|
||||
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
}
|
|
@ -42,7 +42,7 @@ public class GitHubReleaseDetector {
|
|||
String latestRelease = null;
|
||||
for (int i = 0; i < releases.length(); i++) {
|
||||
JSONObject release = releases.getJSONObject(i);
|
||||
String version = release.getString("tag_name").replaceAll("^v", "");
|
||||
String version = release.getString("tag_name");
|
||||
|
||||
// Compare versions and update the latestRelease variable if necessary
|
||||
if (compareVersions(version, latestRelease) > 0) {
|
||||
|
@ -58,12 +58,14 @@ public class GitHubReleaseDetector {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static int compareVersions(String v1, String v2) {
|
||||
public static int compareVersions(String v1, String v2) {
|
||||
if (v1 == null) {
|
||||
return -1;
|
||||
} else if (v2 == null) {
|
||||
return 1;
|
||||
}
|
||||
v1 = v1.replaceAll("^v", "");
|
||||
v2 = v2.replaceAll("^v", "");
|
||||
// Split the version strings on "." characters
|
||||
String[] v1Parts = v1.split("\\.");
|
||||
String[] v2Parts = v2.split("\\.");
|
||||
|
|
|
@ -34,7 +34,6 @@ public class EffectComponentGroup extends HBox {
|
|||
private final DoubleProperty min = new SimpleDoubleProperty();
|
||||
private final DoubleProperty max = new SimpleDoubleProperty();
|
||||
private final BooleanProperty micSelected = new SimpleBooleanProperty(false);
|
||||
private final BooleanProperty enabled = new SimpleBooleanProperty(false);
|
||||
|
||||
public EffectComponentGroup() {
|
||||
EffectComponentGroupController temp;
|
||||
|
@ -67,8 +66,12 @@ public class EffectComponentGroup extends HBox {
|
|||
public synchronized void hideSpinner() {
|
||||
controller.spinner.setVisible(false);
|
||||
controller.spinner.setPrefWidth(0);
|
||||
controller.animationSpinner.setVisible(false);
|
||||
controller.animationSpinner.setPrefWidth(0);
|
||||
controller.label.setPrefWidth(90);
|
||||
controller.slider.setPrefWidth(170);
|
||||
controller.animationSlider.setPrefWidth(170);
|
||||
controller.animationSlider.setMajorTickUnit(20);
|
||||
HBox.setMargin(controller.midi, new Insets(11, 5, 0, -7));
|
||||
}
|
||||
|
||||
|
|
|
@ -70,8 +70,12 @@ public class EffectComponentGroupController implements Initializable, SubControl
|
|||
@FXML
|
||||
public Slider slider;
|
||||
@FXML
|
||||
public Slider animationSlider;
|
||||
@FXML
|
||||
public Spinner<Double> spinner;
|
||||
@FXML
|
||||
public Spinner<Double> animationSpinner;
|
||||
@FXML
|
||||
public SVGPath midi;
|
||||
@FXML
|
||||
public ComboBox<AnimationType> comboBox;
|
||||
|
@ -138,7 +142,12 @@ public class EffectComponentGroupController implements Initializable, SubControl
|
|||
spinner.valueProperty().addListener((o, oldValue, newValue) -> slider.setValue(newValue));
|
||||
slider.valueProperty().addListener((o, oldValue, newValue) -> spinner.getValueFactory().setValue(newValue.doubleValue()));
|
||||
|
||||
List<AnimationType> animations = List.of(AnimationType.STATIC, AnimationType.SEESAW, AnimationType.LINEAR, AnimationType.FORWARD, AnimationType.REVERSE);
|
||||
animationSpinner.valueProperty().addListener((o, oldValue, newValue) -> animationSlider.setValue(newValue));
|
||||
animationSlider.valueProperty().addListener((o, oldValue, newValue) -> animationSpinner.getValueFactory().setValue(newValue.doubleValue()));
|
||||
|
||||
animationSpinner.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0, 100, 1, 0.05));
|
||||
|
||||
List<AnimationType> animations = List.of(AnimationType.values());
|
||||
|
||||
comboBox.setItems(FXCollections.observableList(animations));
|
||||
comboBox.setValue(AnimationType.STATIC);
|
||||
|
@ -180,9 +189,12 @@ public class EffectComponentGroupController implements Initializable, SubControl
|
|||
document.createTextNode(effectCheckBox.selectedProperty().getValue().toString())
|
||||
);
|
||||
Element animation = document.createElement("animation");
|
||||
animation.appendChild(document.createTextNode(comboBox.getValue().toString()));
|
||||
animation.appendChild(document.createTextNode(comboBox.getValue().getName()));
|
||||
Element animationSpeed = document.createElement("animationSpeed");
|
||||
animationSpeed.appendChild(document.createTextNode(Double.toString(animationSlider.getValue())));
|
||||
checkBox.appendChild(selected);
|
||||
checkBox.appendChild(animation);
|
||||
checkBox.appendChild(animationSpeed);
|
||||
return List.of(checkBox);
|
||||
}
|
||||
|
||||
|
@ -203,11 +215,23 @@ public class EffectComponentGroupController implements Initializable, SubControl
|
|||
selected = checkBox.getElementsByTagName("selected").item(0).getTextContent();
|
||||
if (checkBox.getElementsByTagName("animation").getLength() > 0) {
|
||||
String animation = checkBox.getElementsByTagName("animation").item(0).getTextContent();
|
||||
comboBox.setValue(AnimationType.fromString(animation));
|
||||
AnimationType type = AnimationType.fromString(animation);
|
||||
comboBox.setValue(type);
|
||||
|
||||
if (checkBox.getElementsByTagName("animationSpeed").getLength() > 0) {
|
||||
String animationSpeed = checkBox.getElementsByTagName("animationSpeed").item(0).getTextContent();
|
||||
animationSlider.setValue(Double.parseDouble(animationSpeed));
|
||||
} else if (type != AnimationType.STATIC) {
|
||||
// backwards compatibility - must translate the old animation that uses the slider value,
|
||||
// to the new animation that uses the animation slider value
|
||||
double percentage = (slider.getValue() - slider.getMin()) / (slider.getMax() - slider.getMin());
|
||||
animationSlider.setValue(percentage * 10);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selected = checkBox.getTextContent();
|
||||
comboBox.setValue(AnimationType.STATIC);
|
||||
animationSlider.setValue(1.0);
|
||||
}
|
||||
effectCheckBox.setSelected(Boolean.parseBoolean(selected) || model.isAlwaysEnabled());
|
||||
}
|
||||
|
@ -227,7 +251,9 @@ public class EffectComponentGroupController implements Initializable, SubControl
|
|||
this.animator.setValue(slider.getValue());
|
||||
updater.run(model.getType(), selected, this.animator);
|
||||
slider.setDisable(!selected);
|
||||
animationSlider.setDisable(!selected);
|
||||
spinner.setDisable(!selected);
|
||||
animationSpinner.setDisable(!selected);
|
||||
};
|
||||
|
||||
effectCheckBox.selectedProperty().addListener(listener);
|
||||
|
@ -250,12 +276,23 @@ public class EffectComponentGroupController implements Initializable, SubControl
|
|||
slider.minProperty().addListener((e, old, min) -> this.animator.setMin(min.doubleValue()));
|
||||
slider.maxProperty().addListener((e, old, max) -> this.animator.setMax(max.doubleValue()));
|
||||
slider.valueProperty().addListener((e, old, value) -> this.animator.setValue(value.doubleValue()));
|
||||
animationSlider.valueProperty().addListener((e, old, value) -> this.animator.setSpeed(value.doubleValue()));
|
||||
comboBox.valueProperty().addListener((options, old, animationType) -> {
|
||||
this.animator.setAnimation(animationType);
|
||||
if (animationType != AnimationType.STATIC) {
|
||||
slider.setStyle("-thumb-color: #00ff00;");
|
||||
animationSlider.setVisible(true);
|
||||
slider.setVisible(false);
|
||||
if (!model.isSpinnerHidden()) {
|
||||
animationSpinner.setVisible(true);
|
||||
}
|
||||
spinner.setVisible(false);
|
||||
} else {
|
||||
slider.setStyle("");
|
||||
animationSlider.setVisible(false);
|
||||
slider.setVisible(true);
|
||||
animationSpinner.setVisible(false);
|
||||
if (!model.isSpinnerHidden()) {
|
||||
spinner.setVisible(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -284,7 +321,9 @@ public class EffectComponentGroupController implements Initializable, SubControl
|
|||
|
||||
public void setInactive(boolean inactive) {
|
||||
slider.setDisable(inactive);
|
||||
animationSlider.setDisable(inactive);
|
||||
spinner.setDisable(inactive);
|
||||
animationSpinner.setDisable(inactive);
|
||||
}
|
||||
|
||||
public void setValue(double value) {
|
||||
|
|
|
@ -55,6 +55,7 @@ import sh.ball.audio.midi.MidiListener;
|
|||
import sh.ball.audio.midi.MidiNote;
|
||||
import sh.ball.engine.ObjectServer;
|
||||
import sh.ball.engine.ObjectSet;
|
||||
import sh.ball.gui.GitHubReleaseDetector;
|
||||
import sh.ball.gui.Gui;
|
||||
import sh.ball.gui.components.EffectComponentGroup;
|
||||
import sh.ball.oscilloscope.ByteWebSocketServer;
|
||||
|
@ -1095,9 +1096,14 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
|
|||
}
|
||||
}
|
||||
|
||||
private void loadSliderValues(List<Slider> sliders, List<String> labels, Element root) {
|
||||
private void loadSliderValues(List<Slider> sliders, List<String> labels, Element root, String version) {
|
||||
for (int i = 0; i < sliders.size(); i++) {
|
||||
NodeList nodes = root.getElementsByTagName(labels.get(i));
|
||||
String label = labels.get(i);
|
||||
NodeList nodes = root.getElementsByTagName(label);
|
||||
|
||||
// backwards compatibility (PhaseEffect speed was doubled in v1.33.0)
|
||||
boolean phaseEffectSpeedDoubled = (label.equals("translationSpeed") || label.equals("rotateSpeed")) && (version == null || GitHubReleaseDetector.compareVersions(version, "1.33.0") < 0);
|
||||
|
||||
// backwards compatibility
|
||||
if (nodes.getLength() > 0) {
|
||||
Element sliderElement = (Element) nodes.item(0);
|
||||
|
@ -1110,13 +1116,24 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
|
|||
value = sliderElement.getElementsByTagName("value").item(0).getTextContent();
|
||||
String min = sliderElement.getElementsByTagName("min").item(0).getTextContent();
|
||||
String max = sliderElement.getElementsByTagName("max").item(0).getTextContent();
|
||||
slider.setMin(Double.parseDouble(min));
|
||||
slider.setMax(Double.parseDouble(max));
|
||||
double minValue = Double.parseDouble(min);
|
||||
double maxValue = Double.parseDouble(max);
|
||||
if (phaseEffectSpeedDoubled) {
|
||||
minValue /= 2;
|
||||
maxValue /= 2;
|
||||
}
|
||||
slider.setMin(minValue);
|
||||
slider.setMax(maxValue);
|
||||
updateSliderUnits(slider);
|
||||
}
|
||||
|
||||
slider.setValue(Double.parseDouble(value));
|
||||
targetSliderValue[i] = Double.parseDouble(value);
|
||||
double sliderValue = Double.parseDouble(value);
|
||||
if (phaseEffectSpeedDoubled) {
|
||||
sliderValue /= 2;
|
||||
}
|
||||
|
||||
slider.setValue(sliderValue);
|
||||
targetSliderValue[i] = sliderValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1310,8 +1327,12 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
|
|||
generalController.disablePlayback();
|
||||
|
||||
Element root = document.getDocumentElement();
|
||||
String version = null;
|
||||
if (root.getElementsByTagName("version").getLength() > 0) {
|
||||
version = root.getElementsByTagName("version").item(0).getTextContent();
|
||||
}
|
||||
Element slidersElement = (Element) root.getElementsByTagName("sliders").item(0);
|
||||
loadSliderValues(sliders, labels, slidersElement);
|
||||
loadSliderValues(sliders, labels, slidersElement, version);
|
||||
|
||||
// doesn't exist on newer projects - backwards compatibility
|
||||
Element objectRotation = (Element) root.getElementsByTagName("objectRotation").item(0);
|
||||
|
|
|
@ -95,7 +95,7 @@ public class ProjectSelectController implements Initializable {
|
|||
Platform.runLater(() -> {
|
||||
String currentVersion = versionLabel.getText().replaceAll("^v", "");
|
||||
if (!latestRelease.equals(currentVersion)) {
|
||||
latestReleaseHyperlink.setText("v" + latestRelease + " is the latest version on GitHub!");
|
||||
latestReleaseHyperlink.setText(latestRelease + " is the latest version on GitHub!");
|
||||
projectVBox.getChildren().add(projectVBox.getChildren().size() - 1, latestReleaseHyperlink);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
- 1.33.0
|
||||
- Overhaul how animations work in the interface for more precise and intuitive control over the animation speed
|
||||
- When the animation type changes, the range of the slider changes and changing the slider changes the frequency of the animation
|
||||
- The value of the slider when there is no animation (Static) is saved and restored when the animation is removed
|
||||
- Animation speeds vary from 0Hz to 100Hz
|
||||
- You should not notice any difference in how animation is enabled or controlled, but the animation speed slider now goes much faster
|
||||
- As before, to control the range of the animation, just change the range of the slider from the "Slider" menu
|
||||
- Add new animation type: "Sine"
|
||||
- Add new animation type: "Square"
|
||||
- Rename "Linear" animation to "Triangle"
|
||||
- Rename "Forward" animation to "Sawtooth"
|
||||
- Rename "Reverse" animation to "Reverse Sawtooth"
|
||||
- These new changes should be backwards compatible with projects in prior versions
|
||||
- If you notice any issues or differences in projects loaded from older versions, please let me know!
|
||||
|
||||
|
||||
- 1.32.3
|
||||
- Only check for XTAudio devices if not on macOS as it is not available on macOS
|
||||
|
||||
|
|
|
@ -129,6 +129,10 @@
|
|||
-fx-shape: "M460,530.874 1,265.87 460,0.866z";
|
||||
}
|
||||
|
||||
.animationSlider > .thumb {
|
||||
-thumb-color: #00ff00;
|
||||
}
|
||||
|
||||
.thresholdSlider > .track {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
<?import javafx.scene.control.Spinner?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.shape.SVGPath?>
|
||||
|
||||
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="41.0" prefWidth="567.0" type="HBox" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sh.ball.gui.components.EffectComponentGroupController">
|
||||
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="41.0" prefWidth="567.0" type="HBox" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sh.ball.gui.components.EffectComponentGroupController">
|
||||
<children>
|
||||
<Region prefHeight="0.0" prefWidth="5.0" />
|
||||
<CheckBox fx:id="effectCheckBox" mnemonicParsing="false" prefHeight="18.0" prefWidth="125.0" text="Vector cancel">
|
||||
|
@ -17,16 +18,40 @@
|
|||
<Insets top="5.0" />
|
||||
</HBox.margin>
|
||||
</CheckBox>
|
||||
<Slider fx:id="slider" blockIncrement="0.005" disable="true" majorTickUnit="0.1" max="1.0" prefHeight="42.0" prefWidth="208.0" showTickLabels="true" showTickMarks="true" value="0.11111111">
|
||||
<HBox.margin>
|
||||
<Insets right="2.0" />
|
||||
</HBox.margin>
|
||||
</Slider>
|
||||
<Spinner fx:id="spinner" disable="true" editable="true" prefHeight="26.0" prefWidth="66.0">
|
||||
<HBox.margin>
|
||||
<Insets top="1.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
<StackPane>
|
||||
<children>
|
||||
<Slider fx:id="slider" blockIncrement="0.005" disable="true" majorTickUnit="0.1" max="1.0" prefHeight="42.0" prefWidth="208.0" showTickLabels="true" showTickMarks="true" value="0.11111111">
|
||||
<HBox.margin>
|
||||
<Insets right="2.0" />
|
||||
</HBox.margin>
|
||||
</Slider>
|
||||
<Slider fx:id="animationSlider" blockIncrement="0.05" disable="true" majorTickUnit="10" max="100.0" prefHeight="42.0" prefWidth="208.0" showTickLabels="true" showTickMarks="true" styleClass="animationSlider" value="1" visible="false">
|
||||
<HBox.margin>
|
||||
<Insets right="2.0" />
|
||||
</HBox.margin>
|
||||
</Slider>
|
||||
</children>
|
||||
</StackPane>
|
||||
<StackPane>
|
||||
<children>
|
||||
<Spinner fx:id="spinner" disable="true" editable="true" prefHeight="26.0" prefWidth="66.0">
|
||||
<HBox.margin>
|
||||
<Insets top="1.0" />
|
||||
</HBox.margin>
|
||||
<StackPane.margin>
|
||||
<Insets top="-14.0" />
|
||||
</StackPane.margin>
|
||||
</Spinner>
|
||||
<Spinner fx:id="animationSpinner" disable="true" editable="true" prefHeight="26.0" prefWidth="66.0" visible="false">
|
||||
<HBox.margin>
|
||||
<Insets top="1.0" />
|
||||
</HBox.margin>
|
||||
<StackPane.margin>
|
||||
<Insets top="-14.0" />
|
||||
</StackPane.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</StackPane>
|
||||
<SVGPath fx:id="midi" content="M20.15 8.26H22V15.74H20.15M13 8.26H18.43C19 8.26 19.3 8.74 19.3 9.3V14.81C19.3 15.5 19 15.74 18.38 15.74H13V11H14.87V13.91H17.5V9.95H13M10.32 8.26H12.14V15.74H10.32M2 8.26H8.55C9.1 8.26 9.41 8.74 9.41 9.3V15.74H7.59V10.15H6.5V15.74H4.87V10.15H3.83V15.74H2Z" fill="WHITE" pickOnBounds="true">
|
||||
<HBox.margin>
|
||||
<Insets left="3.0" right="3.0" top="11.0" />
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
</children>
|
||||
</AnchorPane>
|
||||
<EffectComponentGroup fx:id="translationScale" alwaysEnabled="true" increment="0.05" label="translationScale" majorTickUnit="1.0" max="10.0" min="0.0" name="Translation scale" type="TRANSLATE" value="1.0" />
|
||||
<EffectComponentGroup fx:id="translationSpeed" alwaysEnabled="true" increment="0.05" label="translationSpeed" majorTickUnit="1.0" max="10.0" min="0.0" name="Translation speed" type="TRANSLATE_SPEED" value="1.0" />
|
||||
<EffectComponentGroup fx:id="translationSpeed" alwaysEnabled="true" increment="0.01" label="translationSpeed" majorTickUnit="0.5" max="5.0" min="0.0" name="Translation speed" type="TRANSLATE_SPEED" value="1.0" />
|
||||
<EffectComponentGroup fx:id="backingMidi" alwaysEnabled="true" increment="0.005" label="visibility" majorTickUnit="0.1" max="1.0" min="0.0" name="MIDI volume" type="VISIBILITY" value="0.0" />
|
||||
</children>
|
||||
</VBox>
|
||||
|
@ -127,7 +127,7 @@
|
|||
<Insets bottom="5.0" />
|
||||
</padding>
|
||||
</Separator>
|
||||
<EffectComponentGroup fx:id="rotateSpeed" increment="0.05" label="rotateSpeed" majorTickUnit="1.0" max="10.0" min="0.0" name="2D Rotate speed" type="ROTATE" value="0.0" />
|
||||
<EffectComponentGroup fx:id="rotateSpeed" increment="0.01" label="rotateSpeed" majorTickUnit="0.5" max="5.0" min="0.0" name="2D Rotate speed" type="ROTATE" value="0.0" />
|
||||
<AnchorPane prefHeight="34.0" prefWidth="602.0">
|
||||
<children>
|
||||
<Button fx:id="resetRotationButton" layoutX="245.0" layoutY="1.0" mnemonicParsing="false" text="Reset 2D Rotation" />
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<CheckBox fx:id="startMutedCheckBox" mnemonicParsing="false" text="Start muted" />
|
||||
<HBox alignment="CENTER" spacing="20.0">
|
||||
<children>
|
||||
<Label fx:id="versionLabel" minWidth="42.0" prefHeight="18.0" prefWidth="42.0" text="v1.32.3" />
|
||||
<Label fx:id="versionLabel" minWidth="42.0" prefHeight="18.0" prefWidth="42.0" text="v1.33.0" />
|
||||
<Label prefHeight="54.0" prefWidth="379.0" text="Email me at james@ball.sh or create an issue on GitHub for feature suggestions, issues, or opportunites I might be interested in!" textAlignment="CENTER" wrapText="true" />
|
||||
<Button fx:id="logButton" minWidth="102.0" mnemonicParsing="false" prefWidth="102.0" text="Open log folder" />
|
||||
</children>
|
||||
|
|
Ładowanie…
Reference in New Issue