2008-06-02 17:41:35 -04:00
|
|
|
#! /usr/bin/ruby
|
|
|
|
# Copyright (C) 2006,2007 John Anderson
|
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, write to the Free Software
|
|
|
|
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
2008-12-12 17:55:03 -05:00
|
|
|
this_dir = File.dirname(__FILE__)
|
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
require 'faster_csv'
|
2008-12-12 17:55:03 -05:00
|
|
|
require "#{this_dir}/mackie.rb"
|
2008-06-02 17:41:35 -04:00
|
|
|
|
|
|
|
class Control
|
|
|
|
attr_accessor :id, :led, :group, :name, :ordinal, :switch
|
|
|
|
|
|
|
|
def initialize( obj, group )
|
|
|
|
@id = obj.id
|
|
|
|
@name = obj.name
|
|
|
|
@ordinal = obj.ordinal
|
|
|
|
@switch = obj.switch
|
|
|
|
@group = group
|
|
|
|
end
|
|
|
|
|
|
|
|
def ordinal_name
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Fader < Control
|
|
|
|
def self.midi_zero_byte
|
|
|
|
0xe0
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.mask_for_id( bytes )
|
|
|
|
bytes[0] & 0b00001111
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Button < Control
|
|
|
|
def self.midi_zero_byte
|
|
|
|
0x90
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.mask_for_id( bytes )
|
|
|
|
bytes[1]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Led < Control
|
|
|
|
end
|
|
|
|
|
|
|
|
class LedRing < Led
|
|
|
|
end
|
|
|
|
|
|
|
|
class Pot < Control
|
|
|
|
def self.midi_zero_byte
|
|
|
|
0xb0
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.mask_for_id( bytes )
|
|
|
|
bytes[1] & 0b00011111
|
|
|
|
end
|
|
|
|
|
|
|
|
def led=( rhs )
|
|
|
|
@led = LedRing.new( rhs, group )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Group < Array
|
|
|
|
attr_accessor :name, :controls
|
|
|
|
|
|
|
|
def initialize( name )
|
|
|
|
@name = name
|
|
|
|
end
|
|
|
|
|
|
|
|
def add_control( control )
|
|
|
|
@controls ||= Array.new
|
|
|
|
@controls << control
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Strip < Group
|
|
|
|
|
|
|
|
attr_accessor :ordinal
|
|
|
|
def initialize( name, ordinal )
|
|
|
|
super( name )
|
|
|
|
@ordinal = ordinal
|
|
|
|
end
|
|
|
|
|
|
|
|
def name
|
|
|
|
@name == 'master' ? @name : "#{@name}_#{@ordinal}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def is_master
|
|
|
|
name == 'master'
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
types = { 0xe0 => Fader, 0x90 => Button, 0xb0 => Pot }
|
|
|
|
|
|
|
|
# number of controls, name, switch, led, id
|
|
|
|
# anything that doesn't have the correct number
|
|
|
|
# of columns will be ignored
|
|
|
|
# actually, 'switch' means it generates data
|
|
|
|
# whereas 'led' means it receives data
|
|
|
|
|
|
|
|
class Row
|
|
|
|
attr_accessor :count, :name, :switch, :led, :start_id, :type, :group
|
|
|
|
attr_accessor :id, :ordinal_name, :ordinal_group, :ordinal
|
|
|
|
|
|
|
|
def initialize( hash )
|
|
|
|
@count = hash['count'].to_i
|
|
|
|
@name = hash['name']
|
|
|
|
@switch = hash['switch'].to_b
|
|
|
|
@led = hash['led'].to_b
|
|
|
|
@start_id = hash['id'].hex
|
|
|
|
@type = hash['type']
|
|
|
|
@group = hash['group']
|
|
|
|
|
|
|
|
@hash = hash
|
|
|
|
end
|
|
|
|
|
|
|
|
def each_ordinal( &block )
|
|
|
|
for i in 0...count
|
|
|
|
@ordinal = i + 1
|
|
|
|
@ordinal_name = count > 1 ? "#{name}_#{ordinal}" : name
|
|
|
|
@ordinal_group = count > 1 ? "#{group}_#{ordinal}" : group
|
|
|
|
@id = start_id + i
|
|
|
|
|
|
|
|
@hash['ordinal_name'] = @ordinal_name
|
|
|
|
@hash['ordinal_group'] = @ordinal_group
|
|
|
|
|
|
|
|
yield( self )
|
|
|
|
end
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_hash
|
|
|
|
@hash
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Surface
|
|
|
|
attr_reader :groups, :controls_by_id, :types, :midis, :controls, :name
|
|
|
|
|
|
|
|
def initialize( name = 'none' )
|
|
|
|
@name = name
|
|
|
|
@types = Hash.new
|
|
|
|
@groups = Hash.new
|
|
|
|
@controls = Array.new
|
|
|
|
@controls_by_id = Hash.new
|
|
|
|
@midis = Hash.new
|
|
|
|
end
|
|
|
|
|
|
|
|
def add_or_create_group( name, ordinal = nil )
|
|
|
|
if name.nil?
|
|
|
|
@groups['none'] = Group.new('none')
|
|
|
|
else
|
|
|
|
group = name =~ /strip/ || name == 'master' ? Strip.new( name, ordinal ) : Group.new( name )
|
|
|
|
@groups[group.name] ||= group
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def parse( control_data )
|
|
|
|
FasterCSV.parse( control_data, :headers => true ) do |csv_row|
|
|
|
|
next if csv_row.entries.size < 5 || csv_row[0] =~ /^\s*#/ || csv_row['id'].nil?
|
|
|
|
row = Row.new( csv_row )
|
|
|
|
|
|
|
|
row.each_ordinal do |row|
|
|
|
|
group = add_or_create_group( row.group, row.ordinal )
|
|
|
|
if row.switch
|
|
|
|
# for controls
|
|
|
|
control = eval "#{row.type.capitalize}.new( row, group )"
|
|
|
|
|
|
|
|
# for controls with leds
|
|
|
|
control.led = Led.new( row, group ) if row.led
|
|
|
|
else
|
|
|
|
# for LED-only entries
|
|
|
|
if row.led
|
|
|
|
control = Led.new( row, group )
|
|
|
|
control.led = control
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# add the new control to the various lookups
|
2008-12-12 17:55:03 -05:00
|
|
|
# but first print a warning if the id is duplicated
|
|
|
|
if @controls_by_id.has_key?( row.id ) && control.group.class != Strip
|
|
|
|
duplicated = @controls_by_id[row.id]
|
|
|
|
puts "duplicate id #{control.id}:#{control.name} of #{duplicated.id}:#{duplicated.name}"
|
|
|
|
end
|
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
@controls_by_id[row.id] = control
|
|
|
|
@controls << control
|
|
|
|
group << control
|
|
|
|
|
|
|
|
# add incoming midi bytes
|
|
|
|
if row.switch
|
|
|
|
types[control.class.midi_zero_byte] = control.class
|
|
|
|
midis[control.class.midi_zero_byte] ||= Hash.new
|
|
|
|
midis[control.class.midi_zero_byte][row.id] = control
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
self
|
|
|
|
end
|
|
|
|
end
|