new PBD::ControllableDescriptor class to encapsulate parsing of binding URIs and speed up lookup at runtime

git-svn-id: svn://localhost/ardour2/branches/3.0@6427 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2009-12-31 23:43:47 +00:00
parent e00506b0ad
commit 6c717a56e2
8 changed files with 354 additions and 120 deletions

View file

@ -64,6 +64,7 @@ namespace MIDI {
namespace PBD { namespace PBD {
class Controllable; class Controllable;
class ControllableDescriptor;
} }
namespace Evoral { namespace Evoral {
@ -769,7 +770,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
/* Controllables */ /* Controllables */
boost::shared_ptr<PBD::Controllable> controllable_by_id (const PBD::ID&); boost::shared_ptr<PBD::Controllable> controllable_by_id (const PBD::ID&);
boost::shared_ptr<PBD::Controllable> controllable_by_rid_and_name (uint32_t, const char* const); boost::shared_ptr<PBD::Controllable> controllable_by_descriptor (const PBD::ControllableDescriptor&);
void add_controllable (boost::shared_ptr<PBD::Controllable>); void add_controllable (boost::shared_ptr<PBD::Controllable>);
void remove_controllable (PBD::Controllable*); void remove_controllable (PBD::Controllable*);

View file

@ -57,6 +57,7 @@
#include "midi++/port.h" #include "midi++/port.h"
#include "pbd/boost_debug.h" #include "pbd/boost_debug.h"
#include "pbd/controllable_descriptor.h"
#include "pbd/enumwriter.h" #include "pbd/enumwriter.h"
#include "pbd/error.h" #include "pbd/error.h"
#include "pbd/pathscanner.h" #include "pbd/pathscanner.h"
@ -2680,89 +2681,114 @@ Session::controllable_by_id (const PBD::ID& id)
} }
boost::shared_ptr<Controllable> boost::shared_ptr<Controllable>
Session::controllable_by_rid_and_name (uint32_t rid, const char* const what) Session::controllable_by_descriptor (const ControllableDescriptor& desc)
{ {
boost::shared_ptr<Controllable> c; boost::shared_ptr<Controllable> c;
boost::shared_ptr<Route> r = route_by_remote_id (rid); boost::shared_ptr<Route> r;
switch (desc.top_level_type()) {
case ControllableDescriptor::NamedRoute:
{
std::string str = desc.top_level_name();
if (str == "master") {
r = _master_out;
} else if (str == "control" || str == "listen") {
r = _control_out;
} else {
r = route_by_name (desc.top_level_name());
}
break;
}
case ControllableDescriptor::RemoteControlID:
r = route_by_remote_id (desc.rid());
break;
}
if (!r) { if (!r) {
return c; return c;
} }
if (strncmp (what, "gain", 4) == 0) { switch (desc.subtype()) {
case ControllableDescriptor::Gain:
c = r->gain_control (); c = r->gain_control ();
} else if (strncmp (what, "solo", 4) == 0) { break;
case ControllableDescriptor::Solo:
c = r->solo_control(); c = r->solo_control();
} else if (strncmp (what, "mute", 4) == 0) { break;
case ControllableDescriptor::Mute:
c = r->mute_control(); c = r->mute_control();
} else if (strncmp (what, "pan", 3) == 0) { break;
/* XXX pan control */
} else if (strncmp (what, "plugin", 6) == 0) {
/* parse to identify plugin & parameter */
uint32_t plugin;
uint32_t parameter_index;
if (sscanf (what, "plugin%" PRIu32 ":%" PRIu32, &plugin, &parameter_index) == 2) {
/* revert to zero based counting */
if (plugin > 0) {
--plugin;
}
if (parameter_index > 0) {
--parameter_index;
}
boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
if (p) {
c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
p->data().control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
}
}
} else if (strncmp (what, "send", 4) == 0) {
/* parse to identify send & property */
uint32_t send;
char property[64];
if (sscanf (what, "send%" PRIu32 ":%63s", &send, property) == 2) {
/* revert to zero-based counting */
if (send > 0) {
--send;
}
boost::shared_ptr<Processor> p = r->nth_send (send);
if (p) {
boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
if (strcmp (property, "gain") == 0) {
boost::shared_ptr<Amp> a = s->amp();
if (a) {
c = s->amp()->gain_control();
}
}
/* XXX pan control */
}
}
} else if (strncmp (what, "recenable", 9) == 0) {
case ControllableDescriptor::Recenable:
{
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r); boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
if (t) { if (t) {
c = t->rec_enable_control (); c = t->rec_enable_control ();
} }
break;
}
case ControllableDescriptor::Pan:
/* XXX pan control */
break;
case ControllableDescriptor::Balance:
/* XXX simple pan control */
break;
case ControllableDescriptor::PluginParameter:
{
uint32_t plugin = desc.target (0);
uint32_t parameter_index = desc.target (1);
/* revert to zero based counting */
if (plugin > 0) {
--plugin;
}
if (parameter_index > 0) {
--parameter_index;
}
boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
if (p) {
c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
p->data().control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
}
break;
}
case ControllableDescriptor::SendGain:
{
uint32_t send = desc.target (0);
/* revert to zero-based counting */
if (send > 0) {
--send;
}
boost::shared_ptr<Processor> p = r->nth_send (send);
if (p) {
boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
boost::shared_ptr<Amp> a = s->amp();
if (a) {
c = s->amp()->gain_control();
}
}
break;
}
default:
/* relax and return a null pointer */
break;
} }
return c; return c;

View file

@ -0,0 +1,150 @@
/*
Copyright (C) 2009 Paul Davis
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.
*/
#include "pbd/controllable_descriptor.h"
#include "pbd/strsplit.h"
#include "pbd/convert.h"
using namespace std;
using namespace PBD;
int
ControllableDescriptor::set (const std::string& str)
{
string::size_type first_space = str.find_first_of (" ");
if (first_space == string::npos) {
return -1;
}
string front = str.substr (0, first_space);
string back = str.substr (first_space);
vector<string> path;
split (front, path, '/');
if (path.size() < 2) {
return -1;
}
vector<string> rest;
split (back, rest, ' ');
if (rest.size() < 1) {
return -1;
}
cerr << "Path: " << endl;
for (vector<string>::iterator x = path.begin(); x != path.end(); ++x) {
cerr << '[' << (*x) << "] ";
}
cerr << endl;
cerr << "Rest: " << endl;
for (vector<string>::iterator x = rest.begin(); x != rest.end(); ++x) {
cerr << '[' << (*x) << "] ";
}
cerr << endl;
if (path[0] == "route" || path[0] == "rid") {
_top_level_type = RemoteControlID;
if (rest[0][0] == 'B') {
_banked = true;
_rid = atoi (rest[0].substr (1));
} else if (isdigit (rest[0][0])) {
_banked = false;
_rid = atoi (rest[0]);
} else {
return -1;
}
} else if (path[0] == "bus" || path[0] == "track") {
_top_level_type = NamedRoute;
_top_level_name = rest[0];
}
if (path[1] == "gain") {
_subtype = Gain;
} else if (path[1] == "solo") {
_subtype = Solo;
} else if (path[1] == "mute") {
_subtype = Mute;
} else if (path[1] == "recenable") {
_subtype = Recenable;
} else if (path[1] == "balance") {
_subtype = Balance;
} else if (path[1] == "pan") {
_subtype = Pan;
_target.push_back (atoi (rest[1]));
} else if (path[1] == "plugin") {
if (path.size() == 3 && rest.size() == 3) {
if (path[2] == "parameter") {
_subtype = PluginParameter;
_target.push_back (atoi (rest[1]));
_target.push_back (atoi (rest[2]));
} else {
return -1;
}
} else {
return -1;
}
} else if (path[1] == "send") {
if (path.size() == 3 && rest.size() == 2) {
if (path[2] == "gain") {
_subtype = SendGain;
_target.push_back (atoi (rest[1]));
} else {
return -1;
}
} else {
return -1;
}
}
return 0;
}
uint32_t
ControllableDescriptor::rid() const
{
if (banked()) {
return _rid + _bank_offset;
}
return _rid;
}
uint32_t
ControllableDescriptor::target (uint32_t n) const
{
if (n < _target.size()) {
return _target[n];
}
return 0;
}

View file

@ -0,0 +1,83 @@
/*
Copyright (C) 2009 Paul Davis
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.
*/
#ifndef __pbd_controllable_descriptor_h__
#define __pbd_controllable_descriptor_h__
#include <vector>
#include <string>
#include <stdint.h>
namespace PBD {
class ControllableDescriptor {
public:
enum TopLevelType {
RemoteControlID,
NamedRoute
};
enum SubType {
Gain,
Solo,
Mute,
Recenable,
Pan,
Balance,
SendGain,
PluginParameter
};
ControllableDescriptor ()
: _top_level_type (RemoteControlID)
, _subtype (Gain)
, _rid (0)
, _banked (false)
, _bank_offset (0)
{}
int set (const std::string&);
/* it is only valid to call top_level_name() if top_level_type() returns
NamedRoute
*/
TopLevelType top_level_type() const { return _top_level_type; }
const std::string& top_level_name() const { return _top_level_name; }
SubType subtype() const { return _subtype; }
uint32_t rid() const;
uint32_t target (uint32_t n) const;
bool banked() const { return _banked; }
void set_bank_offset (uint32_t o) { _bank_offset = o; }
private:
TopLevelType _top_level_type;
SubType _subtype;
std::string _top_level_name;
uint32_t _rid;
std::vector<uint32_t> _target;
uint32_t _banked;
uint32_t _bank_offset;
};
}
#endif /* __pbd_controllable_descriptor_h__ */

View file

@ -57,6 +57,7 @@ def build(bld):
command.cc command.cc
convert.cc convert.cc
controllable.cc controllable.cc
controllable_descriptor.cc
crossthread.cc crossthread.cc
enumwriter.cc enumwriter.cc
event_loop.cc event_loop.cc

View file

@ -23,6 +23,7 @@
#include <sstream> #include <sstream>
#include <algorithm> #include <algorithm>
#include "pbd/controllable_descriptor.h"
#include "pbd/error.h" #include "pbd/error.h"
#include "pbd/failed_constructor.h" #include "pbd/failed_constructor.h"
#include "pbd/pathscanner.h" #include "pbd/pathscanner.h"
@ -711,11 +712,13 @@ GenericMidiControlProtocol::reset_controllables ()
MIDIControllable* existingBinding = (*iter); MIDIControllable* existingBinding = (*iter);
if (!existingBinding->learned()) { if (!existingBinding->learned()) {
uint32_t rid = existingBinding->rid(); ControllableDescriptor& desc (existingBinding->descriptor());
if (existingBinding->bank_relative()) {
rid += _current_bank * _bank_size; if (desc.banked()) {
desc.set_bank_offset (_current_bank * _bank_size);
} }
boost::shared_ptr<Controllable> c = session->controllable_by_rid_and_name (rid, existingBinding->what().c_str());
boost::shared_ptr<Controllable> c = session->controllable_by_descriptor (desc);
existingBinding->set_controllable (c.get()); existingBinding->set_controllable (c.get());
} }
} }

View file

@ -24,6 +24,7 @@
#include <climits> #include <climits>
#include "pbd/error.h" #include "pbd/error.h"
#include "pbd/controllable_descriptor.h"
#include "pbd/xml++.h" #include "pbd/xml++.h"
#include "midi++/port.h" #include "midi++/port.h"
@ -41,6 +42,7 @@ using namespace ARDOUR;
MIDIControllable::MIDIControllable (Port& p, bool is_bistate) MIDIControllable::MIDIControllable (Port& p, bool is_bistate)
: controllable (0) : controllable (0)
, _descriptor (0)
, _port (p) , _port (p)
, bistate (is_bistate) , bistate (is_bistate)
{ {
@ -55,8 +57,10 @@ MIDIControllable::MIDIControllable (Port& p, bool is_bistate)
MIDIControllable::MIDIControllable (Port& p, Controllable& c, bool is_bistate) MIDIControllable::MIDIControllable (Port& p, Controllable& c, bool is_bistate)
: controllable (&c) : controllable (&c)
, _descriptor (0)
, _port (p) , _port (p)
, bistate (is_bistate) , bistate (is_bistate)
{ {
_learned = true; /* from controllable */ _learned = true; /* from controllable */
setting = false; setting = false;
@ -76,48 +80,9 @@ int
MIDIControllable::init (const std::string& s) MIDIControllable::init (const std::string& s)
{ {
_current_uri = s; _current_uri = s;
delete _descriptor;
if (!_current_uri.empty()) { _descriptor = new ControllableDescriptor;
return _descriptor->set (s);
/* parse URI to get remote control ID and "what" is to be controlled */
string::size_type last_slash;
string useful_part;
if ((last_slash = _current_uri.find_last_of ('/')) == string::npos) {
return -1;
}
useful_part = _current_uri.substr (last_slash+1);
char ridstr[64];
char what[64];
if (sscanf (useful_part.c_str(), "rid=%63[^?]?%63s", ridstr, what) != 2) {
return -1;
}
_what = what;
/* now parse RID string and determine if its a bank-driven ID */
if (strncmp (ridstr, "B-", 2) == 0) {
if (sscanf (&ridstr[2], "%" PRIu32, &_rid) != 1) {
return -1;
}
_bank_relative = true;
} else {
if (sscanf (&ridstr[2], "%" PRIu32, &_rid) != 1) {
return -1;
}
_bank_relative = false;
}
}
return 0;
} }
void void

View file

@ -30,12 +30,14 @@
#include "ardour/types.h" #include "ardour/types.h"
namespace PBD {
class ControllableDescriptor;
}
namespace MIDI { namespace MIDI {
class Channel;
class Channel; class Port;
class Port; class Parser;
class Parser;
} }
class MIDIControllable : public PBD::Stateful class MIDIControllable : public PBD::Stateful
@ -74,6 +76,8 @@ class MIDIControllable : public PBD::Stateful
void set_controllable (PBD::Controllable*); void set_controllable (PBD::Controllable*);
const std::string& current_uri() const { return _current_uri; } const std::string& current_uri() const { return _current_uri; }
PBD::ControllableDescriptor& descriptor() const { return *_descriptor; }
std::string control_description() const { return _control_description; } std::string control_description() const { return _control_description; }
XMLNode& get_state (void); XMLNode& get_state (void);
@ -86,6 +90,7 @@ class MIDIControllable : public PBD::Stateful
private: private:
PBD::Controllable* controllable; PBD::Controllable* controllable;
PBD::ControllableDescriptor* _descriptor;
std::string _current_uri; std::string _current_uri;
MIDI::Port& _port; MIDI::Port& _port;
bool setting; bool setting;