lib/patchmaster/connection.rb in patchmaster-1.0.0 vs lib/patchmaster/connection.rb in patchmaster-1.1.2
- old
+ new
@@ -16,20 +16,21 @@
#
# All channels (input_chan, output_chan, etc.) are 1-based here but are
# turned into 0-based channels for later use.
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
- @pc_prog, @zone, @xpose = opts[:pc_prog], opts[:zone], opts[:xpose]
+ @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
def start(start_bytes=nil)
bytes = []
bytes += start_bytes if start_bytes
- bytes += [CC_BANK_SELECT + @output_chan, @bank] if @bank
+ # 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
@@ -48,24 +49,53 @@
# +@zone+ is a Range and +note+ is inside +@zone+.
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.
def midi_in(bytes)
return unless accept_from_input?(bytes)
- # TODO handle running bytes if needed
+ 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
- bytes[0] = high_nibble + @output_chan
+ if bytes[0] != high_nibble + @output_chan
+ bytes = bytes.dup
+ bytes_duped = true
+ bytes[0] = high_nibble + @output_chan
+ end
end
- bytes = @filter.call(self, bytes) if @filter
+ # 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