mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-23 07:06:23 +01:00
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:
parent
a856825e97
commit
0e7d75e7a0
14 changed files with 3140 additions and 3053 deletions
|
|
@ -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
|
|
@ -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 );
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
1446
libs/surfaces/mackie/bcf_surface_generated.cc
Normal file
1446
libs/surfaces/mackie/bcf_surface_generated.cc
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 );
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
1507
libs/surfaces/mackie/mackie_surface_generated.cc
Normal file
1507
libs/surfaces/mackie/mackie_surface_generated.cc
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
||||
64
libs/surfaces/mackie/scripts/generate-surfaces
Executable file
64
libs/surfaces/mackie/scripts/generate-surfaces
Executable 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
|
||||
|
||||
|
|
@ -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 );
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue