Save and load mapped MIDI channels with osci file

pull/38/head
James Ball 2021-12-16 17:11:23 +00:00 zatwierdzone przez James H Ball
rodzic eae07e3e30
commit 2aa73c20d4
1 zmienionych plików z 71 dodań i 21 usunięć

Wyświetl plik

@ -42,7 +42,6 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
@ -57,14 +56,12 @@ import sh.ball.audio.midi.MidiCommunicator;
import sh.ball.audio.midi.MidiListener;
import sh.ball.audio.midi.MidiNote;
import sh.ball.engine.Vector3;
import sh.ball.parser.obj.ObjFrameSettings;
import sh.ball.parser.obj.ObjSettingsFactory;
import sh.ball.parser.obj.ObjParser;
import sh.ball.parser.ParserFactory;
import sh.ball.shapes.Shape;
import sh.ball.shapes.Vector2;
import static sh.ball.math.Math.round;
import static sh.ball.math.Math.tryParse;
public class Controller implements Initializable, FrequencyListener, MidiListener {
@ -711,6 +708,17 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
);
}
private void mapMidiCC(int cc, SVGPath midiButton) {
if (CCMap.containsValue(midiButton)) {
CCMap.values().remove(midiButton);
}
if (CCMap.containsKey(cc)) {
CCMap.get(cc).setFill(Color.WHITE);
}
CCMap.put(cc, midiButton);
midiButton.setFill(Color.LIME);
}
// converts MIDI pressure value into a valid value for a slider
private double midiPressureToPressure(Slider slider, int midiPressure) {
double max = slider.getMax();
@ -730,27 +738,20 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
// the audioPlayer handles all non-CC MIDI messages
if (command == ShortMessage.CONTROL_CHANGE) {
int id = message.getData1();
int cc = message.getData1();
int value = message.getData2();
// if a user has selected a MIDI logo next to a slider, create a mapping
// between the MIDI channel and the SVG MIDI logo
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);
mapMidiCC(cc, armedMidi);
armedMidiPaint = null;
armedMidi = null;
}
// If there is a slider associated with the MIDI channel, update the value
// of it
if (CCMap.containsKey(id)) {
Slider slider = midiButtonMap.get(CCMap.get(id));
if (CCMap.containsKey(cc)) {
Slider slider = midiButtonMap.get(CCMap.get(cc));
double sliderValue = midiPressureToPressure(slider, value);
if (slider.isSnapToTicks()) {
@ -786,6 +787,16 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
return List.of("octave", "frequency", "rotateSpeed", "translationSpeed", "volume",
"visibility", "focalLength", "objectRotateSpeed");
}
private List<Slider> allSliders() {
List<Slider> sliders = new ArrayList<>(checkBoxSliders());
sliders.addAll(otherSliders());
return sliders;
}
private List<String> allLabels() {
List<String> labels = new ArrayList<>(checkBoxLabels());
labels.addAll(otherLabels());
return labels;
}
private void appendSliders(List<Slider> sliders, List<String> labels, Element root, Document document) {
for (int i = 0; i < sliders.size(); i++) {
@ -813,16 +824,19 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
Element root = document.createElement("project");
document.appendChild(root);
// Is there a nicer way of doing this?!
List<CheckBox> checkBoxes = checkBoxes();
List<Slider> checkBoxSliders = checkBoxSliders();
List<String> checkBoxLabels = checkBoxLabels();
List<Slider> otherSliders = otherSliders();
List<String> otherLabels = otherLabels();
List<Slider> sliders = allSliders();
List<String> labels = allLabels();
Element sliders = document.createElement("sliders");
appendSliders(checkBoxSliders, checkBoxLabels, sliders, document);
appendSliders(otherSliders, otherLabels, sliders, document);
root.appendChild(sliders);
Element slidersElement = document.createElement("sliders");
appendSliders(checkBoxSliders, checkBoxLabels, slidersElement, document);
appendSliders(otherSliders, otherLabels, slidersElement, document);
root.appendChild(slidersElement);
Element checkBoxesElement = document.createElement("checkBoxes");
for (int i = 0; i < checkBoxes.size(); i++) {
@ -834,6 +848,17 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
}
root.appendChild(checkBoxesElement);
Element midiElement = document.createElement("midi");
for (Map.Entry<Integer, SVGPath> entry : CCMap.entrySet()) {
Slider slider = midiButtonMap.get(entry.getValue());
int index = sliders.indexOf(slider);
Integer cc = entry.getKey();
Element midiChannel = document.createElement(labels.get(index));
midiChannel.appendChild(document.createTextNode(cc.toString()));
midiElement.appendChild(midiChannel);
}
root.appendChild(midiElement);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource domSource = new DOMSource(document);
@ -845,6 +870,13 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
}
}
private void resetCCMap() {
armedMidi = null;
armedMidiPaint = null;
CCMap.clear();
midiButtonMap.keySet().forEach(button -> button.setFill(Color.WHITE));
}
private void openProject() {
try {
DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
@ -859,17 +891,35 @@ public class Controller implements Initializable, FrequencyListener, MidiListene
List<String> checkBoxLabels = checkBoxLabels();
List<Slider> otherSliders = otherSliders();
List<String> otherLabels = otherLabels();
List<Slider> sliders = allSliders();
List<String> labels = allLabels();
Element root = doc.getDocumentElement();
Element sliders = (Element) root.getElementsByTagName("sliders").item(0);
loadSliderValues(checkBoxSliders, checkBoxLabels, sliders);
loadSliderValues(otherSliders, otherLabels, sliders);
Element slidersElement = (Element) root.getElementsByTagName("sliders").item(0);
loadSliderValues(checkBoxSliders, checkBoxLabels, slidersElement);
loadSliderValues(otherSliders, otherLabels, slidersElement);
Element checkBoxesElement = (Element) root.getElementsByTagName("checkBoxes").item(0);
for (int i = 0; i < checkBoxes.size(); i++) {
String value = checkBoxesElement.getElementsByTagName(checkBoxLabels.get(i)).item(0).getTextContent();
checkBoxes.get(i).setSelected(Boolean.parseBoolean(value));
}
Element midiElement = (Element) root.getElementsByTagName("midi").item(0);
resetCCMap();
for (int i = 0; i < labels.size(); i++) {
NodeList elements = midiElement.getElementsByTagName(labels.get(i));
if (elements.getLength() > 0) {
Element midi = (Element) elements.item(0);
int cc = Integer.parseInt(midi.getTextContent());
Slider slider = sliders.get(i);
SVGPath midiButton = midiButtonMap.entrySet().stream()
.filter(entry -> entry.getValue() == slider)
.findFirst().orElseThrow().getKey();
mapMidiCC(cc, midiButton);
}
}
root.appendChild(midiElement);
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}