improve generation of surfaces from csv files. Move generated code into separate files from written code. Various comments and tweaks.

git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2172 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
John Anderson 2007-07-22 20:50:10 +00:00
parent a856825e97
commit 0e7d75e7a0
14 changed files with 3140 additions and 3053 deletions

View file

@ -34,7 +34,9 @@ types.cc
surface.cc
mackie_control_protocol.cc
bcf_surface.cc
bcf_surface_generated.cc
mackie_surface.cc
mackie_surface_generated.cc
mackie_jog_wheel.cc
""")

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
#ifndef mackie_surface_bcf_h
#define mackie_surface_bcf_h
/*
Generated by scripts/generate-surface.rb
Initially generated by scripts/generate-surface.rb
*/
#include "surface.h"
@ -20,6 +20,9 @@ public:
virtual void handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button );
virtual void init_controls();
virtual float scrub_scaling_factor() { return 50.0; }
virtual float scaled_delta( const ControlState & state, float current_speed );
};
}

File diff suppressed because it is too large Load diff

View file

@ -486,23 +486,26 @@ bool MackieControlProtocol::handle_strip_button( Control & control, ButtonState
void MackieControlProtocol::update_led( Mackie::Button & button, Mackie::LedState ls )
{
MackiePort * port = 0;
if ( button.group().is_strip() )
if ( ls != none )
{
if ( button.group().is_master() )
MackiePort * port = 0;
if ( button.group().is_strip() )
{
port = &mcu_port();
if ( button.group().is_master() )
{
port = &mcu_port();
}
else
{
port = &port_for_id( dynamic_cast<const Strip&>( button.group() ).index() );
}
}
else
{
port = &port_for_id( dynamic_cast<const Strip&>( button.group() ).index() );
port = &mcu_port();
}
port->write( builder.build_led( button, ls ) );
}
else
{
port = &mcu_port();
}
if ( ls != none ) port->write( builder.build_led( button, ls ) );
}
void MackieControlProtocol::update_global_button( const string & name, LedState ls )
@ -517,7 +520,7 @@ void MackieControlProtocol::update_global_button( const string & name, LedState
#ifdef DEBUG
cout << "Button " << name << " not found" << endl;
#endif
}
}
}
// send messages to surface to set controls to correct values

View file

@ -3,6 +3,7 @@
#include "mackie_control_protocol.h"
#include "surface_port.h"
#include "controls.h"
#include "surface.h"
#include <algorithm>
@ -40,11 +41,6 @@ void JogWheel::scroll_event( SurfacePort & port, Control & control, const Contro
{
}
float scaled_delta( const ControlState & state, float current_speed )
{
return state.sign * ( pow( state.ticks + 1, 2 ) + current_speed ) / 100.0;
}
void JogWheel::jog_event( SurfacePort & port, Control & control, const ControlState & state )
{
// TODO use current snap-to setting?
@ -80,7 +76,7 @@ void JogWheel::jog_event( SurfacePort & port, Control & control, const ControlSt
case speed:
// locally, _transport_speed is an positive value
// fairly arbitrary scaling function
_transport_speed += scaled_delta( state, _mcp.get_session().transport_speed() );
_transport_speed += _mcp.surface().scaled_delta( state, _mcp.get_session().transport_speed() );
// make sure not weirdness get so the session
if ( _transport_speed < 0 || isnan( _transport_speed ) )
@ -95,23 +91,15 @@ void JogWheel::jog_event( SurfacePort & port, Control & control, const ControlSt
case scrub:
{
add_scrub_interval( _scrub_timer.restart() );
float speed = 0.0;
// This should really be part of the surface object
if ( _mcp.mcu_port().emulation() == MackiePort::bcf2000 )
// 5 clicks per second => speed == 1.0
speed = 50.0 / average_scrub_interval() * state.ticks;
else
// 10 clicks per second => speed == 1.0
speed = 100.0 / average_scrub_interval() * state.ticks;
// x clicks per second => speed == 1.0
float speed = _mcp.surface().scrub_scaling_factor() / average_scrub_interval() * state.ticks;
_mcp.get_session().request_transport_speed( speed * state.sign );
break;
}
case shuttle:
_shuttle_speed = _mcp.get_session().transport_speed();
_shuttle_speed += scaled_delta( state, _mcp.get_session().transport_speed() );
_shuttle_speed += _mcp.surface().scaled_delta( state, _mcp.get_session().transport_speed() );
_mcp.get_session().request_transport_speed( _shuttle_speed );
break;

View file

@ -113,60 +113,6 @@ const MidiByteArray & MackiePort::sysex_hdr() const
return mackie_sysex_hdr;
}
Control & MackiePort::lookup_control( MIDI::byte * bytes, size_t count )
{
Control * control = 0;
MIDI::byte midi_type = bytes[0] & 0xf0; //0b11110000
switch( midi_type )
{
// fader
case MackieMidiBuilder::midi_fader_id:
{
int midi_id = bytes[0] & 0x0f;
control = _mcp.surface().faders[midi_id];
if ( control == 0 )
{
MidiByteArray mba( count, bytes );
ostringstream os;
os << "control for fader" << bytes << " id " << midi_id << " is null";
throw MackieControlException( os.str() );
}
break;
}
// button
case MackieMidiBuilder::midi_button_id:
control = _mcp.surface().buttons[bytes[1]];
if ( control == 0 )
{
MidiByteArray mba( count, bytes );
ostringstream os;
os << "control for button " << bytes << " is null";
throw MackieControlException( os.str() );
}
break;
// pot (jog wheel, external control)
case MackieMidiBuilder::midi_pot_id:
control = _mcp.surface().pots[bytes[1]];
if ( control == 0 )
{
MidiByteArray mba( count, bytes );
ostringstream os;
os << "control for rotary " << mba << " is null";
throw MackieControlException( os.str() );
}
break;
default:
MidiByteArray mba( count, bytes );
ostringstream os;
os << "Cannot find control for " << bytes;
throw MackieControlException( os.str() );
}
return *control;
}
MidiByteArray calculate_challenge_response( MidiByteArray::iterator begin, MidiByteArray::iterator end )
{
MidiByteArray l;
@ -266,11 +212,16 @@ void MackiePort::init()
void MackiePort::finalise_init( bool yn )
{
//cout << "MackiePort::finalise_init" << endl;
#ifdef PORT_DEBUG
cout << "MackiePort::finalise_init" << endl;
#endif
bool emulation_ok = false;
// probing doesn't work very well, so just use a config variable
// to set the emulation mode
// TODO This might have to be specified on a per-port basis
// in the config file
// if an mcu and a bcf are needed to work as one surface
if ( _emulation == none )
{
if ( ARDOUR::Config->get_mackie_emulation() == "bcf" )
@ -314,7 +265,7 @@ void MackiePort::connect_any()
if ( find( slots.begin(), slots.end(), mem_fun( *this, &MackiePort::handle_midi_any ) ) == slots.end() )
*/
// but this will break if midi tracing is turned on
// TODO but this will break if midi tracing is turned on
if ( port().input()->any.empty() )
{
#ifdef DEBUG
@ -370,7 +321,66 @@ void MackiePort::handle_midi_sysex (MIDI::Parser & parser, MIDI::byte * raw_byte
}
}
Control & MackiePort::lookup_control( MIDI::byte * bytes, size_t count )
{
// Don't instantiate a MidiByteArray here unless it's needed for exceptions.
// Reason being that this method is called for every single incoming
// midi event, and it needs to be as efficient as possible.
Control * control = 0;
MIDI::byte midi_type = bytes[0] & 0xf0; //0b11110000
switch( midi_type )
{
// fader
case MackieMidiBuilder::midi_fader_id:
{
int midi_id = bytes[0] & 0x0f;
control = _mcp.surface().faders[midi_id];
if ( control == 0 )
{
MidiByteArray mba( count, bytes );
ostringstream os;
os << "control for fader" << bytes << " id " << midi_id << " is null";
throw MackieControlException( os.str() );
}
break;
}
// button
case MackieMidiBuilder::midi_button_id:
control = _mcp.surface().buttons[bytes[1]];
if ( control == 0 )
{
MidiByteArray mba( count, bytes );
ostringstream os;
os << "control for button " << bytes << " is null";
throw MackieControlException( os.str() );
}
break;
// pot (jog wheel, external control)
case MackieMidiBuilder::midi_pot_id:
control = _mcp.surface().pots[bytes[1]];
if ( control == 0 )
{
MidiByteArray mba( count, bytes );
ostringstream os;
os << "control for rotary " << mba << " is null";
throw MackieControlException( os.str() );
}
break;
default:
MidiByteArray mba( count, bytes );
ostringstream os;
os << "Cannot find control for " << bytes;
throw MackieControlException( os.str() );
}
return *control;
}
// converts midi messages into control_event signals
// it might be worth combining this with lookup_control
// because they have similar logic flows.
void MackiePort::handle_midi_any (MIDI::Parser & parser, MIDI::byte * raw_bytes, size_t count )
{
#ifdef DEBUG
@ -402,12 +412,14 @@ void MackiePort::handle_midi_any (MIDI::Parser & parser, MIDI::byte * raw_bytes,
{
// only the top-order 10 bits out of 14 are used
int midi_pos = ( ( raw_bytes[2] << 7 ) + raw_bytes[1] ) >> 4;
// relies on implicit ControlState constructor
control_event( *this, control, float(midi_pos) / float(0x3ff) );
}
break;
// button
case Control::type_button:
// relies on implicit ControlState constructor
control_event( *this, control, raw_bytes[2] == 0x7f ? press : release );
break;

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,9 @@ public:
virtual void handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button );
virtual void init_controls();
virtual float scrub_scaling_factor() { return 100.0; }
virtual float scaled_delta( const ControlState & state, float current_speed );
};
}

File diff suppressed because it is too large Load diff

View file

@ -15,8 +15,10 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
this_dir = File.dirname(__FILE__)
require 'faster_csv'
require 'mackie.rb'
require "#{this_dir}/mackie.rb"
class Control
attr_accessor :id, :led, :group, :name, :ordinal, :switch

View file

@ -1,28 +0,0 @@
#! /usr/bin/ruby
this_dir = File.dirname(__FILE__)
require 'erb'
require this_dir + '/controls.rb'
cc_template = ''
File.open( this_dir + "/surface-cc-template.erb", "r" ) { |f| cc_template = f.read }
h_template = ''
File.open( this_dir + "/surface-h-template.erb", "r" ) { |f| h_template = f.read }
sf = Surface.new( ARGV[0] )
control_data = ''
File.open( this_dir + "/#{sf.name.downcase}-controls.csv", "r") { |f| control_data = f.read }
sf.parse control_data
@result = ""
erb = ERB.new( cc_template , 0, "%<>-", "@result" )
erb.result
File.open( "#{sf.name.downcase}_surface.cc", "w" ) { |f| f.write @result }
erb = ERB.new( h_template , 0, "%<>-", "@result" )
erb.result
File.open( "#{sf.name.downcase}_surface.h", "w" ) { |f| f.write @result }

View file

@ -0,0 +1,64 @@
#! /usr/bin/ruby
require 'getoptlong'
require 'csv'
require 'erb'
this_dir = File.dirname(__FILE__)
require this_dir + '/mackie.rb'
require this_dir + '/controls.rb'
read_opts = GetoptLong.new(
[ "--headers", '-e', GetoptLong::NO_ARGUMENT ],
[ "--version","-v", GetoptLong::NO_ARGUMENT ],
[ "--help", "-h", "-?", GetoptLong::NO_ARGUMENT ]
)
# process the parsed options
read_opts.each do |opt, arg|
case opt
when "--headers"
$generate_headers = true
else
$generate_headers = false
end
end
cc_template = ''
File.open( this_dir + "/surface-cc-template.erb", "r" ) { |f| cc_template = f.read }
h_template = ''
File.open( this_dir + "/surface-h-template.erb", "r" ) { |f| h_template = f.read }
# needs to be defined outside the loop otherwise ERB can't find it
sf = nil
files =
if ARGV.size == 0
Dir.glob "#{this_dir}/*csv"
else
ARGV
end
files.each do |csv_file|
csv_file =~ /(\w+)-controls.csv/
sf = Surface.new( $1.capitalize )
control_data = ''
File.open( csv_file, "r") { |f| control_data = f.read }
sf.parse control_data
@result = ""
erb = ERB.new( cc_template , 0, "%<>-", "@result" )
erb.result
File.open( "#{sf.name.downcase}_surface_generated.cc", "w" ) { |f| f.write @result }
if $generate_headers
erb = ERB.new( h_template , 0, "%<>-", "@result" )
erb.result
File.open( "#{sf.name.downcase}_surface.h", "w" ) { |f| f.write @result }
end
end

View file

@ -81,7 +81,24 @@ public:
/// map button ids to calls to press_ and release_ in mbh
virtual void handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button ) = 0;
public:
/**
This is used to calculate the clicks per second that define
a transport speed of 1.0 for the jog wheel. 100.0 is 10 clicks
per second, 50.5 is 5 clicks per second.
*/
virtual float scrub_scaling_factor() = 0;
/**
The scaling factor function for speed increase and decrease. At
low transport speeds this should return a small value, for high transport
speeds, this should return an exponentially larger value. This provides
high definition control at low speeds and quick speed changes to/from
higher speeds.
*/
virtual float scaled_delta( const ControlState & state, float current_speed ) = 0;
protected:
virtual void init_controls() = 0;
virtual void init_strips( uint32_t max_strips, uint32_t unit_strips );