// All MIDI global variables & global MIDI functions are in this tab. import javax.sound.midi.* ; // Get everything in the Java MIDI (Musical Instrument Digital Interface) package. // MIDI VARIABLES, see http://faculty.kutztown.edu/parson/spring2017/MidiKBSpring2016Parson.txt final int midiDeviceIndex = 0 ; // setup() checks for number of devices. Use one for output. // NOTE: A final variable is in fact a constant that cannot be changed. MidiDevice.Info[] midiDeviceInfo = null ; // See javax.sound.midi.MidiSystem and javax.sound.midi.MidiDevice MidiDevice device = null ; // See javax.sound.midi.MidiSystem and javax.sound.midi.MidiDevice Receiver receiver = null ; // javax.sound.midi.Receiver receives your OUTPUT MIDI messages (counterintuitive?) // SEE https://www.midi.org/specifications/item/gm-level-1-sound-set but start at 0, not 1 int patch = 98 ; // tonal percussion per above link, change with up & down arrow keys int lastnote = -1 ; // most recent midi note in the range 0..127 int lastvelocity = -1 ; // most recent midi note in the range 0..127 int interval = 64 ; // for sending out a harmonic interval int controller = 1 ; // start with modwheel, let user adjust int controllerDegree = 0 ; // initially no audio effect amount void initMIDI() { // MIDI: // 1. FIND OUT WHAT MIDI DEVICES ARE AVAILABLE FOR VARIABLE midiDeviceIndex. midiDeviceInfo = MidiSystem.getMidiDeviceInfo(); for (int i = 0 ; i < midiDeviceInfo.length ; i++) { println("MIDI DEVICE NUMBER " + i + " Name: " + midiDeviceInfo[i].getName() + ", Vendor: " + midiDeviceInfo[i].getVendor() + ", Description: " + midiDeviceInfo[i].getDescription()); } // 2. OPEN ONE OF THE MIDI DEVICES UP FOR OUTPUT. try { device = MidiSystem.getMidiDevice(midiDeviceInfo[midiDeviceIndex]); device.open(); // Make sure to close it before this sketch terminates!!! // There should be a way to schedule a method when Processing closes this // sketch, so we can close the device there, but it is not documented for Processing 3. receiver = device.getReceiver(); // NOTE: Either of the above method calls can throw MidiUnavailableException // if there is no available device or if it does not have a Receiver to // which we can send messages. The catch clause intercepts those error messages. // See https://www.midi.org/specifications/item/gm-level-1-sound-set, use patch variable ShortMessage noteMessage1 = new ShortMessage() ; noteMessage1.setMessage(ShortMessage.PROGRAM_CHANGE, 0, patch, 0); // to channel 0 receiver.send(noteMessage1, -1L); // send it now ShortMessage noteMessage2 = new ShortMessage() ; noteMessage2.setMessage(ShortMessage.PROGRAM_CHANGE, 1, (patch+32)%128, 0); // to channel 1 receiver.send(noteMessage2, -1L); // send it now } catch (MidiUnavailableException mx) { System.err.println("MIDI UNAVAILABLE"); // Error messages go here. device = null ; receiver = null ; // Do not try to use them. } catch (InvalidMidiDataException dx) { System.err.println("MIDI ERROR: " + dx.getMessage()); // Error messages go here. } } void sendMIDI(int command, int channel, int data1, int data2) { // Construct & send a ShortMessage with these parameters. try { ShortMessage message = new ShortMessage(command, channel, data1, data2); receiver.send(message, -1L); // -1L means send it now, not queued for later. } catch (InvalidMidiDataException ix) { System.err.println("InvalidMidiDataException: " + ix.getMessage()); } }