class PM::Connection
A Connection
connects an InputInstrument
to an OutputInstrument
. Whenever MIDI data arrives at the InputInstrument
it is optionally modified or filtered, then the remaining modified data is sent to the OutputInstrument
.
Attributes
Public Class Methods
If input_chan
is nil than all messages from input will be sent to output.
All channels (input_chan
, output_chan
, etc.) are 1-based here but are turned into 0-based channels for later use.
# File lib/patchmaster/connection.rb, line 19 def initialize(input, input_chan, output, output_chan, filter=nil, opts={}) @input, @input_chan, @output, @output_chan, @filter = input, input_chan, output, output_chan, filter @bank, @pc_prog, @zone, @xpose = opts[:bank], opts[:pc_prog], opts[:zone], opts[:xpose] @input_chan -= 1 if @input_chan @output_chan -= 1 if @output_chan end
Public Instance Methods
# File lib/patchmaster/connection.rb, line 42 def accept_from_input?(bytes) return true if @input_chan == nil return true unless bytes.channel? bytes.channel == @input_chan end
Returns true if the +@zone+ is nil (allowing all notes throught) or if +@zone+ is a Range and note
is inside +@zone+.
# File lib/patchmaster/connection.rb, line 50 def inside_zone?(note) @zone == nil || @zone.include?(note) end
The workhorse. Ignore bytes that aren't from our input, or are outside the zone. Change to output channel. Filter
.
Note that running bytes are not handled, but unimidi doesn't seem to use them anyway.
Finally, we go through gyrations to avoid duping bytes unless they are actually modified in some way.
# File lib/patchmaster/connection.rb, line 62 def midi_in(bytes) return unless accept_from_input?(bytes) bytes_duped = false high_nibble = bytes.high_nibble case high_nibble when NOTE_ON, NOTE_OFF, POLY_PRESSURE return unless inside_zone?(bytes[1]) if bytes[0] != high_nibble + @output_chan || (@xpose && @xpose != 0) bytes = bytes.dup bytes_duped = true end bytes[0] = high_nibble + @output_chan bytes[1] = ((bytes[1] + @xpose) & 0xff) if @xpose when CONTROLLER, PROGRAM_CHANGE, CHANNEL_PRESSURE, PITCH_BEND if bytes[0] != high_nibble + @output_chan bytes = bytes.dup bytes_duped = true bytes[0] = high_nibble + @output_chan end end # We can't tell if a filter will modify the bytes, so we have to assume # they will be. If we didn't, we'd have to rely on the filter duping the # bytes and returning the dupe. if @filter if !bytes_duped bytes = bytes.dup bytes_duped = true end bytes = @filter.call(self, bytes) end if bytes && bytes.size > 0 midi_out(bytes) end end
# File lib/patchmaster/connection.rb, line 103 def midi_out(bytes) @output.midi_out(bytes) end
# File lib/patchmaster/connection.rb, line 111 def note_num_to_name(n) oct = (n / 12) - 1 note = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'][n % 12] "#{note}#{oct}" end
# File lib/patchmaster/connection.rb, line 107 def pc? @pc_prog != nil end
# File lib/patchmaster/connection.rb, line 27 def start(start_bytes=nil) bytes = [] bytes += start_bytes if start_bytes # Bank select uses MSB if we're only sending one byte bytes += [CONTROLLER + @output_chan, CC_BANK_SELECT+32, @bank] if @bank bytes += [PROGRAM_CHANGE + @output_chan, @pc_prog] if @pc_prog midi_out(bytes) unless bytes.empty? @input.add_connection(self) end
# File lib/patchmaster/connection.rb, line 37 def stop(stop_bytes=nil) midi_out(stop_bytes) if stop_bytes @input.remove_connection(self) end
# File lib/patchmaster/connection.rb, line 117 def to_s str = "#{@input.name} ch #{@input_chan ? @input_chan+1 : 'all'} -> #{@output.name} ch #{@output_chan+1}" str << "; pc #@pc_prog" if pc? str << "; xpose #@xpose" if @xpose str << "; zone #{note_num_to_name(@zone.begin)}..#{note_num_to_name(@zone.end)}" if @zone str end