Skip to content

Instantly share code, notes, and snippets.

@Visuelle-Musik
Created September 19, 2009 22:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Visuelle-Musik/189610 to your computer and use it in GitHub Desktop.
Save Visuelle-Musik/189610 to your computer and use it in GitHub Desktop.
basic MIDI I/O for JRuby
# --- 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