+ final void programChangeReceived(ProgramChange pc) {
+ if (!enabled) {
+ return;
+ }
+ if (logMidi()) {
+ println(getLabel() + " :: Program Change :: " + pc.getNumber());
+ }
+ handleProgramChange(pc);
+ }
+
+ final void controllerChangeReceived(rwmidi.Controller cc) {
+ if (!enabled) {
+ return;
+ }
+ if (logMidi()) {
+ println(getLabel() + " :: Controller :: " + cc.getChannel() + " :: " + cc.getCC() + ":" + cc.getValue());
+ }
+ if (!handleGridControllerChange(cc)) {
+ if (!midiEngine.getFocusedPattern().controllerChange(cc)) {
+ handleControllerChange(cc);
+ }
+ }
+ }
+
+ final void noteOnReceived(Note note) {
+ if (!enabled) {
+ return;
+ }
+ if (logMidi()) {
+ println(getLabel() + " :: Note On :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
+ }
+ if (!handleGridNoteOn(note)) {
+ if (!midiEngine.getFocusedPattern().noteOn(note)) {
+ handleNoteOn(note);
+ }
+ }
+ }
+
+ final void noteOffReceived(Note note) {
+ if (!enabled) {
+ return;
+ }
+ if (logMidi()) {
+ println(getLabel() + " :: Note Off :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
+ }
+ if (!handleGridNoteOff(note)) {
+ if (!midiEngine.getFocusedPattern().noteOff(note)) {
+ handleNoteOff(note);
+ }
+ }
+ }
+
+ // Subclasses may implement these to map top-level functionality
+ protected boolean handleGridNoteOn(Note note) { return false; }
+ protected boolean handleGridNoteOff(Note note) { return false; }
+ protected boolean handleGridControllerChange(rwmidi.Controller cc) { return false; }
+ protected void handleProgramChange(ProgramChange pc) {}
+ protected void handleControllerChange(rwmidi.Controller cc) {}
+ protected void handleNoteOn(Note note) {}
+ protected void handleNoteOff(Note note) {}
+}
+
+public class VirtualKeyMidiInput extends SCMidiInput {
+
+ public static final int KEYS = 1;
+ public static final int APC = 2;
+
+ private final int mode;
+
+ private int octaveShift = 0;
+
+ class NoteMeta {
+ int channel;
+ int number;
+ NoteMeta(int channel, int number) {
+ this.channel = channel;
+ this.number = number;
+ }
+ }
+
+ final Map<Character, NoteMeta> keyToNote = new HashMap<Character, NoteMeta>();
+
+ VirtualKeyMidiInput(MidiEngine midiEngine, int mode) {
+ super(midiEngine, "QWERTY (" + (mode == APC ? "APC" : "Key") + " Mode)");