Class: PM::Connection
- Inherits:
-
Object
- Object
- PM::Connection
- Defined in:
- lib/patchmaster/connection.rb
Overview
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.
Instance Attribute Summary collapse
-
#bank ⇒ Object
Returns the value of attribute bank.
-
#filter ⇒ Object
Returns the value of attribute filter.
-
#input ⇒ Object
Returns the value of attribute input.
-
#input_chan ⇒ Object
Returns the value of attribute input_chan.
-
#output ⇒ Object
Returns the value of attribute output.
-
#output_chan ⇒ Object
Returns the value of attribute output_chan.
-
#pc_prog ⇒ Object
Returns the value of attribute pc_prog.
-
#xpose ⇒ Object
Returns the value of attribute xpose.
-
#zone ⇒ Object
Returns the value of attribute zone.
Instance Method Summary collapse
- #accept_from_input?(bytes) ⇒ Boolean
-
#initialize(input, input_chan, output, output_chan, filter = nil, opts = {}) ⇒ Connection
constructor
If input_chan is nil than all messages from input will be sent to output.
-
#inside_zone?(note) ⇒ Boolean
Returns true if the @zone is nil (allowing all notes throught) or if @zone is a Range and
note
is inside @zone. -
#midi_in(bytes) ⇒ Object
The workhorse.
- #midi_out(bytes) ⇒ Object
- #note_num_to_name(n) ⇒ Object
- #pc? ⇒ Boolean
- #start(start_bytes = nil) ⇒ Object
- #stop(stop_bytes = nil) ⇒ Object
- #to_s ⇒ Object
Constructor Details
#initialize(input, input_chan, output, output_chan, filter = nil, opts = {}) ⇒ Connection
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.
19 20 21 22 23 24 25 |
# 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 |
Instance Attribute Details
#bank ⇒ Object
Returns the value of attribute bank.
11 12 13 |
# File 'lib/patchmaster/connection.rb', line 11 def bank @bank end |
#filter ⇒ Object
Returns the value of attribute filter.
11 12 13 |
# File 'lib/patchmaster/connection.rb', line 11 def filter @filter end |
#input ⇒ Object
Returns the value of attribute input.
11 12 13 |
# File 'lib/patchmaster/connection.rb', line 11 def input @input end |
#input_chan ⇒ Object
Returns the value of attribute input_chan.
11 12 13 |
# File 'lib/patchmaster/connection.rb', line 11 def input_chan @input_chan end |
#output ⇒ Object
Returns the value of attribute output.
11 12 13 |
# File 'lib/patchmaster/connection.rb', line 11 def output @output end |
#output_chan ⇒ Object
Returns the value of attribute output_chan.
11 12 13 |
# File 'lib/patchmaster/connection.rb', line 11 def output_chan @output_chan end |
#pc_prog ⇒ Object
Returns the value of attribute pc_prog.
11 12 13 |
# File 'lib/patchmaster/connection.rb', line 11 def pc_prog @pc_prog end |
#xpose ⇒ Object
Returns the value of attribute xpose.
11 12 13 |
# File 'lib/patchmaster/connection.rb', line 11 def xpose @xpose end |
#zone ⇒ Object
Returns the value of attribute zone.
11 12 13 |
# File 'lib/patchmaster/connection.rb', line 11 def zone @zone end |
Instance Method Details
#accept_from_input?(bytes) ⇒ Boolean
42 43 44 45 46 |
# 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 |
#inside_zone?(note) ⇒ Boolean
Returns true if the @zone is nil (allowing all notes throught) or if @zone is a Range and note
is inside @zone.
50 51 52 |
# File 'lib/patchmaster/connection.rb', line 50 def inside_zone?(note) @zone == nil || @zone.include?(note) end |
#midi_in(bytes) ⇒ Object
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.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# 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 |
#midi_out(bytes) ⇒ Object
103 104 105 |
# File 'lib/patchmaster/connection.rb', line 103 def midi_out(bytes) @output.midi_out(bytes) end |
#note_num_to_name(n) ⇒ Object
111 112 113 114 115 |
# 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 |
#pc? ⇒ Boolean
107 108 109 |
# File 'lib/patchmaster/connection.rb', line 107 def pc? @pc_prog != nil end |
#start(start_bytes = nil) ⇒ Object
27 28 29 30 31 32 33 34 35 |
# 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 |
#stop(stop_bytes = nil) ⇒ Object
37 38 39 40 |
# File 'lib/patchmaster/connection.rb', line 37 def stop(stop_bytes=nil) midi_out(stop_bytes) if stop_bytes @input.remove_connection(self) end |
#to_s ⇒ Object
117 118 119 120 121 122 123 |
# 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 |