kopia lustrzana https://github.com/jameshball/osci-render
Refactor MIDI code out of Controller and into ShapeAudioPlayer
rodzic
ce0dca7179
commit
cdc5139141
|
@ -2,11 +2,12 @@ package sh.ball.audio;
|
|||
|
||||
import sh.ball.audio.effect.Effect;
|
||||
import sh.ball.audio.engine.AudioDevice;
|
||||
import sh.ball.audio.midi.MidiListener;
|
||||
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import java.util.List;
|
||||
|
||||
public interface AudioPlayer<S> extends Runnable {
|
||||
public interface AudioPlayer<S> extends Runnable, MidiListener {
|
||||
|
||||
void reset() throws Exception;
|
||||
|
||||
|
@ -18,8 +19,6 @@ public interface AudioPlayer<S> extends Runnable {
|
|||
|
||||
void setMainFrequencyScale(double scale);
|
||||
|
||||
void setBaseFrequencies(List<Double> frequency);
|
||||
|
||||
void setPitchBendFactor(double pitchBend);
|
||||
|
||||
List<Double> getFrequencies();
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
package sh.ball.audio;
|
||||
|
||||
import javafx.animation.Interpolator;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.KeyValue;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.util.Duration;
|
||||
import sh.ball.audio.effect.Effect;
|
||||
|
||||
import java.io.*;
|
||||
|
@ -10,9 +18,12 @@ import java.util.stream.Collectors;
|
|||
import sh.ball.audio.effect.SineEffect;
|
||||
import sh.ball.audio.engine.AudioDevice;
|
||||
import sh.ball.audio.engine.AudioEngine;
|
||||
import sh.ball.audio.midi.MidiCommunicator;
|
||||
import sh.ball.audio.midi.MidiNote;
|
||||
import sh.ball.shapes.Shape;
|
||||
import sh.ball.shapes.Vector2;
|
||||
|
||||
import javax.sound.midi.ShortMessage;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
|
||||
|
@ -30,6 +41,13 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
|||
private static final double MIN_LENGTH_INCREMENT = 0.0000000001;
|
||||
private static final double MIDDLE_C = 261.63;
|
||||
|
||||
// MIDI
|
||||
private static final int PITCH_BEND_DATA_LENGTH = 7;
|
||||
private static final int PITCH_BEND_MAX = 16383;
|
||||
private static final int PITCH_BEND_SEMITONES = 2;
|
||||
private final List<MidiNote> downKeys = new CopyOnWriteArrayList<>();
|
||||
private Timeline volumeTimeline;
|
||||
|
||||
private final Callable<AudioEngine> audioEngineBuilder;
|
||||
private final BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);
|
||||
private final Map<Object, Effect> effects = new ConcurrentHashMap<>();
|
||||
|
@ -45,19 +63,35 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
|||
private double lengthIncrement = MIN_LENGTH_INCREMENT;
|
||||
private double lengthDrawn = 0;
|
||||
private int count = 0;
|
||||
private DoubleProperty volume;
|
||||
private List<Double> frequencies = List.of(MIDDLE_C);
|
||||
private double mainFrequency = MIDDLE_C;
|
||||
private double octaveFrequency;
|
||||
private DoubleProperty frequency;
|
||||
private double mainFrequencyScale = 0.5;
|
||||
private double maxFrequency = MIDDLE_C;
|
||||
private double maxFrequency;
|
||||
private double pitchBend = 1.0;
|
||||
private double trace = 0.5;
|
||||
private int octave = 0;
|
||||
|
||||
private AudioDevice device;
|
||||
|
||||
public ShapeAudioPlayer(Callable<AudioEngine> audioEngineBuilder) throws Exception {
|
||||
public ShapeAudioPlayer(Callable<AudioEngine> audioEngineBuilder, MidiCommunicator communicator) throws Exception {
|
||||
this.audioEngineBuilder = audioEngineBuilder;
|
||||
this.audioEngine = audioEngineBuilder.call();
|
||||
setFrequency(new SimpleDoubleProperty(0));
|
||||
this.maxFrequency = frequency.get();
|
||||
setFrequency(new SimpleDoubleProperty(0));
|
||||
|
||||
communicator.addListener(this);
|
||||
}
|
||||
|
||||
public void setFrequency(DoubleProperty frequency) {
|
||||
this.frequency = frequency;
|
||||
frequency.addListener((o, old, f) -> setBaseFrequencies(List.of(f.doubleValue())));
|
||||
}
|
||||
|
||||
public void setVolume(DoubleProperty volume) {
|
||||
this.volume = volume;
|
||||
}
|
||||
|
||||
private Vector2 generateChannels() throws InterruptedException {
|
||||
|
@ -143,14 +177,14 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
|||
for (Effect effect : effects.values()) {
|
||||
vector = effect.apply(frame, vector);
|
||||
}
|
||||
return vector;
|
||||
|
||||
return vector.scale(volume.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBaseFrequencies(List<Double> frequencies) {
|
||||
private void setBaseFrequencies(List<Double> frequencies) {
|
||||
this.frequencies = frequencies;
|
||||
this.maxFrequency = frequencies.stream().max(Double::compareTo).get();
|
||||
this.mainFrequency = maxFrequency * Math.pow(2, octave - 1);
|
||||
octaveFrequency = maxFrequency * Math.pow(2, octave - 1);
|
||||
updateLengthIncrement();
|
||||
|
||||
sineEffects.clear();
|
||||
|
@ -186,10 +220,12 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
|||
}
|
||||
|
||||
private void updateLengthIncrement() {
|
||||
double totalLength = Shape.totalLength(frame);
|
||||
int sampleRate = device.sampleRate();
|
||||
double actualFrequency = mainFrequency * pitchBend;
|
||||
lengthIncrement = Math.max(totalLength / (sampleRate / actualFrequency), MIN_LENGTH_INCREMENT);
|
||||
if (frame != null) {
|
||||
double totalLength = Shape.totalLength(frame);
|
||||
int sampleRate = device.sampleRate();
|
||||
double actualFrequency = octaveFrequency * pitchBend;
|
||||
lengthIncrement = Math.max(totalLength / (sampleRate / actualFrequency), MIN_LENGTH_INCREMENT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -234,7 +270,7 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
|||
@Override
|
||||
public void setOctave(int octave) {
|
||||
this.octave = octave;
|
||||
this.mainFrequency = maxFrequency * Math.pow(2, octave - 1);
|
||||
octaveFrequency = maxFrequency * Math.pow(2, octave - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -311,6 +347,63 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
|||
return new AudioInputStream(new ByteArrayInputStream(input), audioFormat, framesRecorded);
|
||||
}
|
||||
|
||||
private void playNotes(double noteVolume) {
|
||||
List<Double> frequencies = downKeys.stream().map(MidiNote::frequency).collect(Collectors.toList());
|
||||
double mainFrequency = frequencies.get(frequencies.size() - 1);
|
||||
frequency.set(mainFrequency);
|
||||
setBaseFrequencies(frequencies);
|
||||
volume.set(noteVolume);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMidiMessage(ShortMessage message) {
|
||||
int command = message.getCommand();
|
||||
|
||||
if (command == ShortMessage.NOTE_ON || command == ShortMessage.NOTE_OFF) {
|
||||
MidiNote note = new MidiNote(message.getData1());
|
||||
int velocity = message.getData2();
|
||||
|
||||
double oldVolume = volume.get();
|
||||
double newVolume = velocity / 127.0;
|
||||
|
||||
if (command == ShortMessage.NOTE_OFF) {
|
||||
downKeys.remove(note);
|
||||
if (downKeys.isEmpty()) {
|
||||
KeyValue kv = new KeyValue(volume, 0, Interpolator.EASE_OUT);
|
||||
KeyFrame kf = new KeyFrame(Duration.millis(500), kv);
|
||||
volumeTimeline = new Timeline(kf);
|
||||
Platform.runLater(volumeTimeline::play);
|
||||
} else {
|
||||
playNotes(oldVolume);
|
||||
}
|
||||
} else {
|
||||
downKeys.add(note);
|
||||
if (volumeTimeline != null) {
|
||||
volumeTimeline.stop();
|
||||
volumeTimeline = null;
|
||||
}
|
||||
playNotes(newVolume);
|
||||
KeyValue kv = new KeyValue(volume, volume.get() * 0.75, Interpolator.EASE_OUT);
|
||||
KeyFrame kf = new KeyFrame(Duration.millis(250), kv);
|
||||
volumeTimeline = new Timeline(kf);
|
||||
Platform.runLater(volumeTimeline::play);
|
||||
}
|
||||
} else if (command == ShortMessage.PITCH_BEND) {
|
||||
// using these instructions https://sites.uci.edu/camp2014/2014/04/30/managing-midi-pitchbend-messages/
|
||||
|
||||
int pitchBend = (message.getData2() << PITCH_BEND_DATA_LENGTH) | message.getData1();
|
||||
// get pitch bend in range -1 to 1
|
||||
double pitchBendFactor = (double) pitchBend / PITCH_BEND_MAX;
|
||||
pitchBendFactor = 2 * pitchBendFactor - 1;
|
||||
pitchBendFactor *= PITCH_BEND_SEMITONES;
|
||||
// 12 tone equal temperament
|
||||
pitchBendFactor /= 12;
|
||||
pitchBendFactor = Math.pow(2, pitchBendFactor);
|
||||
|
||||
setPitchBendFactor(pitchBendFactor);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Listener {
|
||||
private final byte[] buffer;
|
||||
private final Semaphore sema;
|
||||
|
|
|
@ -2,6 +2,8 @@ package sh.ball.gui;
|
|||
|
||||
import javafx.animation.*;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.beans.value.WritableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.scene.control.*;
|
||||
|
@ -41,6 +43,7 @@ import org.xml.sax.SAXException;
|
|||
import sh.ball.audio.effect.Effect;
|
||||
import sh.ball.audio.effect.EffectType;
|
||||
import sh.ball.audio.engine.AudioDevice;
|
||||
import sh.ball.audio.engine.ConglomerateAudioEngine;
|
||||
import sh.ball.audio.midi.MidiCommunicator;
|
||||
import sh.ball.audio.midi.MidiListener;
|
||||
import sh.ball.audio.midi.MidiNote;
|
||||
|
@ -52,33 +55,30 @@ import sh.ball.parser.ParserFactory;
|
|||
import sh.ball.shapes.Shape;
|
||||
import sh.ball.shapes.Vector2;
|
||||
|
||||
public class Controller implements Initializable, FrequencyListener, MidiListener, Listener, WritableValue<Double> {
|
||||
public class Controller implements Initializable, FrequencyListener, Listener, WritableValue<Double>, MidiListener {
|
||||
|
||||
private static final InputStream DEFAULT_OBJ = Controller.class.getResourceAsStream("/models/cube.obj");
|
||||
private static final double MAX_FREQUENCY = 12000;
|
||||
private static final int PITCH_BEND_DATA_LENGTH = 7;
|
||||
private static final int PITCH_BEND_MAX = 16383;
|
||||
private static final int PITCH_BEND_SEMITONES = 2;
|
||||
private static final double MIDDLE_C = 261.63;
|
||||
|
||||
private final FileChooser fileChooser = new FileChooser();
|
||||
private final DirectoryChooser folderChooser = new DirectoryChooser();
|
||||
private final AudioPlayer<List<Shape>> audioPlayer;
|
||||
private final ShapeAudioPlayer audioPlayer;
|
||||
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
private final Map<Integer, SVGPath> CCMap = new HashMap<>();
|
||||
private final List<MidiNote> downKeys = new CopyOnWriteArrayList<>();
|
||||
private Map<SVGPath, Slider> midiButtonMap;
|
||||
|
||||
private final RotateEffect rotateEffect;
|
||||
private final TranslateEffect translateEffect;
|
||||
private final WobbleEffect wobbleEffect;
|
||||
private final ScaleEffect scaleEffect;
|
||||
|
||||
private final DoubleProperty frequency;
|
||||
|
||||
private int sampleRate;
|
||||
private FrequencyAnalyser<List<Shape>> analyser;
|
||||
private final AudioDevice defaultDevice;
|
||||
private boolean recording = false;
|
||||
private Timeline recordingTimeline;
|
||||
private Timeline volumeTimeline;
|
||||
private Paint armedMidiPaint;
|
||||
private SVGPath armedMidi;
|
||||
|
||||
|
@ -188,8 +188,12 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
@FXML
|
||||
private ComboBox<AudioDevice> deviceComboBox;
|
||||
|
||||
public Controller(AudioPlayer<List<Shape>> audioPlayer) throws IOException {
|
||||
this.audioPlayer = audioPlayer;
|
||||
public Controller() throws Exception {
|
||||
MidiCommunicator midiCommunicator = new MidiCommunicator();
|
||||
midiCommunicator.addListener(this);
|
||||
new Thread(midiCommunicator).start();
|
||||
|
||||
this.audioPlayer = new ShapeAudioPlayer(ConglomerateAudioEngine::new, midiCommunicator);
|
||||
FrameSet<List<Shape>> frames = new ObjParser(DEFAULT_OBJ).parse();
|
||||
frameSets.add(frames);
|
||||
frameSetPaths.add("cube.obj");
|
||||
|
@ -204,7 +208,7 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
this.rotateEffect = new RotateEffect(sampleRate);
|
||||
this.translateEffect = new TranslateEffect(sampleRate);
|
||||
this.wobbleEffect = new WobbleEffect(sampleRate);
|
||||
this.scaleEffect = new ScaleEffect();
|
||||
this.frequency = new SimpleDoubleProperty(0);
|
||||
}
|
||||
|
||||
private Map<SVGPath, Slider> initializeMidiButtonMap() {
|
||||
|
@ -227,10 +231,8 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
|
||||
private Map<Slider, Consumer<Double>> initializeSliderMap() {
|
||||
return Map.of(
|
||||
frequencySlider, f -> audioPlayer.setBaseFrequencies(List.of(Math.pow(MAX_FREQUENCY, f))),
|
||||
rotateSpeedSlider, rotateEffect::setSpeed,
|
||||
translationSpeedSlider, translateEffect::setSpeed,
|
||||
scaleSlider, scaleEffect::setScale,
|
||||
focalLengthSlider, d -> updateFocalLength(),
|
||||
objectRotateSpeedSlider, d -> updateObjectRotateSpeed(),
|
||||
visibilitySlider, audioPlayer::setMainFrequencyScale
|
||||
|
@ -256,6 +258,12 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
frequencySlider.valueProperty().addListener((o, old, f) -> frequency.set(Math.pow(MAX_FREQUENCY, f.doubleValue())));
|
||||
frequency.addListener((o, old, f) -> frequencySlider.setValue(Math.log(f.doubleValue()) / Math.log(MAX_FREQUENCY)));
|
||||
audioPlayer.setFrequency(frequency);
|
||||
frequency.set(MIDDLE_C);
|
||||
audioPlayer.setVolume(scaleSlider.valueProperty());
|
||||
|
||||
this.midiButtonMap = initializeMidiButtonMap();
|
||||
|
||||
midiButtonMap.keySet().forEach(midi -> midi.setOnMouseClicked(e -> {
|
||||
|
@ -271,7 +279,7 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
}
|
||||
armedMidiPaint = midi.getFill();
|
||||
armedMidi = midi;
|
||||
midi.setFill(Color.color(1, 0, 0));
|
||||
midi.setFill(Color.RED);
|
||||
}
|
||||
}));
|
||||
|
||||
|
@ -360,7 +368,6 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
|
||||
updateObjectRotateSpeed();
|
||||
|
||||
audioPlayer.addEffect(EffectType.SCALE, scaleEffect);
|
||||
audioPlayer.addEffect(EffectType.ROTATE, rotateEffect);
|
||||
audioPlayer.addEffect(EffectType.TRANSLATE, translateEffect);
|
||||
|
||||
|
@ -373,9 +380,6 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
analyser = new FrequencyAnalyser<>(audioPlayer, 2, sampleRate);
|
||||
startFrequencyAnalyser(analyser);
|
||||
startAudioPlayerThread();
|
||||
MidiCommunicator midiCommunicator = new MidiCommunicator();
|
||||
midiCommunicator.addListener(this);
|
||||
new Thread(midiCommunicator).start();
|
||||
|
||||
deviceComboBox.valueProperty().addListener((options, oldDevice, newDevice) -> {
|
||||
if (newDevice != null) {
|
||||
|
@ -639,99 +643,6 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
return (double) tmp / factor;
|
||||
}
|
||||
|
||||
private double midiPressureToPressure(Slider slider, int midiPressure) {
|
||||
double max = slider.getMax();
|
||||
double min = slider.getMin();
|
||||
double range = max - min;
|
||||
return min + (midiPressure / 127.0) * range;
|
||||
}
|
||||
|
||||
private void playNotes(double volume) {
|
||||
List<Double> frequencies = downKeys.stream().map(MidiNote::frequency).collect(Collectors.toList());
|
||||
double mainFrequency = frequencies.get(frequencies.size() - 1);
|
||||
frequencySlider.setValue(Math.log(mainFrequency) / Math.log(MAX_FREQUENCY));
|
||||
audioPlayer.setBaseFrequencies(frequencies);
|
||||
scaleSlider.setValue(volume);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMidiMessage(ShortMessage message) {
|
||||
Platform.runLater(() -> {
|
||||
int command = message.getCommand();
|
||||
|
||||
if (command == ShortMessage.CONTROL_CHANGE) {
|
||||
int id = message.getData1();
|
||||
int value = message.getData2();
|
||||
|
||||
if (armedMidi != null) {
|
||||
if (CCMap.containsValue(armedMidi)) {
|
||||
CCMap.values().remove(armedMidi);
|
||||
}
|
||||
if (CCMap.containsKey(id)) {
|
||||
CCMap.get(id).setFill(Color.color(1, 1, 1));
|
||||
}
|
||||
CCMap.put(id, armedMidi);
|
||||
armedMidi.setFill(Color.color(0, 1, 0));
|
||||
armedMidiPaint = null;
|
||||
armedMidi = null;
|
||||
}
|
||||
if (CCMap.containsKey(id)) {
|
||||
Slider slider = midiButtonMap.get(CCMap.get(id));
|
||||
double sliderValue = midiPressureToPressure(slider, value);
|
||||
|
||||
if (slider.isSnapToTicks()) {
|
||||
double increment = slider.getMajorTickUnit() / (slider.getMinorTickCount() + 1);
|
||||
sliderValue = increment * (Math.round(sliderValue / increment));
|
||||
}
|
||||
slider.setValue(sliderValue);
|
||||
}
|
||||
} else if (command == ShortMessage.NOTE_ON || command == ShortMessage.NOTE_OFF) {
|
||||
MidiNote note = new MidiNote(message.getData1());
|
||||
int velocity = message.getData2();
|
||||
|
||||
double oldVolume = scaleSlider.getValue();
|
||||
double volume = midiPressureToPressure(scaleSlider, velocity);
|
||||
volume /= 10;
|
||||
|
||||
if (command == ShortMessage.NOTE_OFF) {
|
||||
downKeys.remove(note);
|
||||
if (downKeys.isEmpty()) {
|
||||
KeyValue kv = new KeyValue(scaleSlider.valueProperty(), 0, Interpolator.EASE_OUT);
|
||||
KeyFrame kf = new KeyFrame(Duration.millis(500), kv);
|
||||
volumeTimeline = new Timeline(kf);
|
||||
Platform.runLater(volumeTimeline::play);
|
||||
} else {
|
||||
playNotes(oldVolume);
|
||||
}
|
||||
} else {
|
||||
downKeys.add(note);
|
||||
if (volumeTimeline != null) {
|
||||
volumeTimeline.stop();
|
||||
volumeTimeline = null;
|
||||
}
|
||||
playNotes(volume);
|
||||
KeyValue kv = new KeyValue(scaleSlider.valueProperty(), scaleSlider.valueProperty().get() * 0.75, Interpolator.EASE_OUT);
|
||||
KeyFrame kf = new KeyFrame(Duration.millis(250), kv);
|
||||
volumeTimeline = new Timeline(kf);
|
||||
Platform.runLater(volumeTimeline::play);
|
||||
}
|
||||
} else if (command == ShortMessage.PITCH_BEND) {
|
||||
// using these instructions https://sites.uci.edu/camp2014/2014/04/30/managing-midi-pitchbend-messages/
|
||||
|
||||
int pitchBend = (message.getData2() << PITCH_BEND_DATA_LENGTH) | message.getData1();
|
||||
// get pitch bend in range -1 to 1
|
||||
double pitchBendFactor = (double) pitchBend / PITCH_BEND_MAX;
|
||||
pitchBendFactor = 2 * pitchBendFactor - 1;
|
||||
pitchBendFactor *= PITCH_BEND_SEMITONES;
|
||||
// 12 tone equal temperament
|
||||
pitchBendFactor /= 12;
|
||||
pitchBendFactor = Math.pow(2, pitchBendFactor);
|
||||
|
||||
audioPlayer.setPitchBendFactor(pitchBendFactor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// gets the volume/scale
|
||||
@Override
|
||||
public Double getValue() {
|
||||
|
@ -742,4 +653,44 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
|
|||
public void setValue(Double scale) {
|
||||
scaleSlider.setValue(scale);
|
||||
}
|
||||
|
||||
private double midiPressureToPressure(Slider slider, int midiPressure) {
|
||||
double max = slider.getMax();
|
||||
double min = slider.getMin();
|
||||
double range = max - min;
|
||||
return min + (midiPressure / 127.0) * range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMidiMessage(ShortMessage message) {
|
||||
int command = message.getCommand();
|
||||
|
||||
if (command == ShortMessage.CONTROL_CHANGE) {
|
||||
int id = message.getData1();
|
||||
int value = message.getData2();
|
||||
|
||||
if (armedMidi != null) {
|
||||
if (CCMap.containsValue(armedMidi)) {
|
||||
CCMap.values().remove(armedMidi);
|
||||
}
|
||||
if (CCMap.containsKey(id)) {
|
||||
CCMap.get(id).setFill(Color.WHITE);
|
||||
}
|
||||
CCMap.put(id, armedMidi);
|
||||
armedMidi.setFill(Color.LIME);
|
||||
armedMidiPaint = null;
|
||||
armedMidi = null;
|
||||
}
|
||||
if (CCMap.containsKey(id)) {
|
||||
Slider slider = midiButtonMap.get(CCMap.get(id));
|
||||
double sliderValue = midiPressureToPressure(slider, value);
|
||||
|
||||
if (slider.isSnapToTicks()) {
|
||||
double increment = slider.getMajorTickUnit() / (slider.getMinorTickCount() + 1);
|
||||
sliderValue = increment * (Math.round(sliderValue / increment));
|
||||
}
|
||||
slider.setValue(sliderValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class Gui extends Application {
|
|||
System.setProperty("prism.lcdtext", "false");
|
||||
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/osci-render.fxml"));
|
||||
Controller controller = new Controller(new ShapeAudioPlayer(ConglomerateAudioEngine::new));
|
||||
Controller controller = new Controller();
|
||||
loader.setController(controller);
|
||||
Parent root = loader.load();
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue