Created
September 19, 2009 22:25
-
-
Save Visuelle-Musik/189610 to your computer and use it in GitHub Desktop.
basic MIDI I/O for JRuby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# --- Very basic Midi-Implementation for JRuby (note on/off, pitchbend, controller, aftertouch), especially for use with ruby-processing, http://wiki.github.com/jashkenas/ruby-processing --- | |
module JavaMidi | |
midi = javax.sound.midi | |
import midi.MidiSystem | |
import midi.MidiDevice | |
import midi.MidiEvent | |
import midi.ShortMessage | |
import midi.Receiver | |
end | |
class JRmidi # Java midi Interface for JRuby (ruby-processing and others) | |
# --- If you want to extent this class, use send(), send_note_on() and other send_.*-methods as a "blueprint" --- | |
# --- For details on the use of Java-MIDI see: http://java.sun.com/j2se/1.5.0/docs/api/javax/sound/midi/MidiSystem.html --- | |
@@RPmidiIn = Hash.new # class variable to monitor number of initialisations... | |
@@RPmidiOut = Hash.new # class variable to monitor number of initialisations... | |
def initialize( processing_instance, instance_name, params ) # establish new MIDI-in or out-connections to be used in the application | |
@processing_instance = processing_instance | |
@name = instance_name | |
@verbose = params[:verbose] | |
@midi_in_port = params[:in_port] | |
@midi_out_port = params[:out_port] | |
@midiMsg = JavaMidi::ShortMessage.new | |
if( @@RPmidiIn[instance_name] || @@RPmidiOut[instance_name] ) # true if initialized before: avoid multiple instances with identical functionality, to be called by Processing for instance... | |
@outputDevice = @@RPmidiOut[instance_name] # "reload" midi-out handle as remembered be previous instance... | |
@inputDevice = @@RPmidiIn[instance_name] # "reload" midi-in handle as remembered be previous instance... | |
else | |
if( @midi_in_port ) # use MIDI-in for this instance? | |
in_port = JavaMidi::MidiSystem.getMidiDeviceInfo[@midi_in_port] | |
puts "INport: " + in_port.to_s | |
@inputDevice = JavaMidi::MidiSystem.getMidiDevice(in_port) | |
@inputDevice.open() | |
transmit = @inputDevice.getTransmitter() | |
puts transmit.to_s if @verbose | |
transmit.setReceiver(self) | |
@@RPmidiIn[instance_name] = @inputDevice # remember "handle" associated to the given MIDI-out, in case if instanciated more than once for midi-out-methods later | |
end | |
if( @midi_out_port ) # use MIDI-out for this instance? | |
out_port = JavaMidi::MidiSystem.getMidiDeviceInfo[@midi_out_port] | |
puts "OUTport: " + out_port.to_s | |
outputDevice = JavaMidi::MidiSystem.getMidiDevice(out_port) | |
outputDevice.open | |
@outputDevice = outputDevice.getReceiver() | |
puts @outputDevice.to_s if @verbose | |
@@RPmidiOut[instance_name] = @outputDevice # remember "handle" associated to the given MIDI-out, in case if instanciated more than once for midi-out-methods later | |
end | |
end | |
end | |
def name; @name.to_s; end # just in case, somebody wants to retreive the "process_name" of a connected "MIDI-out-handle"... | |
def send(msg, time_stamp) # "Interface"-method for javax.sound.midi.Receiver, "callback-method" for MIDI-input | |
case msg.getCommand | |
when 0x90 | |
@processing_instance.note_on( msg.getChannel, msg.getData1, msg.getData2 ) | |
when 0x80 | |
@processing_instance.note_off( msg.getChannel, msg.getData1, msg.getData2 ) | |
when 0xe0 | |
@processing_instance.pitch_bend( msg.getChannel, ((msg.getData2 << 7 ) | msg.getData1)-8192 ) | |
when 0xb0 | |
@processing_instance.control_change( msg.getChannel, msg.getData1, msg.getData2 ) | |
when 0xd0 | |
@processing_instance.channel_pressure( msg.getChannel, msg.getData1 ) # single data-byte message! | |
else | |
# puts "new MIDI-message 0x%x, channel: %d, data1: %d, data2: %d" % [msg.getCommand, msg.getChannel, msg.getData1, msg.getData2] | |
return # we got a MIDI-message here, that we do not want to process... | |
end | |
rescue # We mainly get here, if a supported message comes in and its "callback-function" is not implemented [correctly] in the user-application | |
if( @verbose ) | |
puts "MIDI-message 0x%x, channel: %d, data1: %d, data2: %d, not processed..." % | |
[msg.getCommand, msg.getChannel+1, msg.getData1, msg.getData2] | |
end | |
end | |
def close # "Interface"-method for javax.sound.midi.Receiver, can be called remotely to close the device | |
@inputDevice.close | |
end | |
# === User-functions for MIDI-output === | |
def send_note_on( channel, note, velocity ) | |
@midiMsg.setMessage( 0x90, channel, note, velocity ) | |
@outputDevice.send(@midiMsg, -1) # timestamp is second parameter, set to "immediate" | |
end | |
def send_note_off( channel, note, velocity ) | |
@midiMsg.setMessage( 0x80, channel, note, velocity ) | |
@outputDevice.send(@midiMsg, -1) | |
end | |
def send_pitch_bend( channel, pitch ) | |
pitch += 8192 | |
@midiMsg.setMessage( 0xe0, channel, pitch & 0x7f, pitch >> 7 ) | |
@outputDevice.send(@midiMsg, -1) | |
end | |
def send_control_change( channel, controller, value ) | |
@midiMsg.setMessage( 0xb0, channel, controller, value ) | |
@outputDevice.send(@midiMsg, -1) | |
end | |
def send_channel_pressure( channel, touch_value ) | |
@midiMsg.setMessage( 0xd0, channel, touch_value, 0 ) | |
@outputDevice.send(@midiMsg, -1) | |
end | |
end # class JRmidi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment