mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-09 00:04:56 +01:00
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:
parent
e00506b0ad
commit
6c717a56e2
8 changed files with 354 additions and 120 deletions
|
|
@ -64,6 +64,7 @@ namespace MIDI {
|
|||
|
||||
namespace PBD {
|
||||
class Controllable;
|
||||
class ControllableDescriptor;
|
||||
}
|
||||
|
||||
namespace Evoral {
|
||||
|
|
@ -769,7 +770,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
/* Controllables */
|
||||
|
||||
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 remove_controllable (PBD::Controllable*);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
#include "midi++/port.h"
|
||||
|
||||
#include "pbd/boost_debug.h"
|
||||
#include "pbd/controllable_descriptor.h"
|
||||
#include "pbd/enumwriter.h"
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/pathscanner.h"
|
||||
|
|
@ -2680,89 +2681,114 @@ Session::controllable_by_id (const PBD::ID& id)
|
|||
}
|
||||
|
||||
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<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) {
|
||||
return c;
|
||||
}
|
||||
|
||||
if (strncmp (what, "gain", 4) == 0) {
|
||||
switch (desc.subtype()) {
|
||||
case ControllableDescriptor::Gain:
|
||||
c = r->gain_control ();
|
||||
} else if (strncmp (what, "solo", 4) == 0) {
|
||||
break;
|
||||
case ControllableDescriptor::Solo:
|
||||
c = r->solo_control();
|
||||
} else if (strncmp (what, "mute", 4) == 0) {
|
||||
break;
|
||||
|
||||
case ControllableDescriptor::Mute:
|
||||
c = r->mute_control();
|
||||
} else if (strncmp (what, "pan", 3) == 0) {
|
||||
|
||||
/* 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, ¶meter_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) {
|
||||
break;
|
||||
|
||||
case ControllableDescriptor::Recenable:
|
||||
{
|
||||
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
|
||||
|
||||
|
||||
if (t) {
|
||||
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;
|
||||
|
|
|
|||
150
libs/pbd/controllable_descriptor.cc
Normal file
150
libs/pbd/controllable_descriptor.cc
Normal 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;
|
||||
}
|
||||
83
libs/pbd/pbd/controllable_descriptor.h
Normal file
83
libs/pbd/pbd/controllable_descriptor.h
Normal 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__ */
|
||||
|
|
@ -57,6 +57,7 @@ def build(bld):
|
|||
command.cc
|
||||
convert.cc
|
||||
controllable.cc
|
||||
controllable_descriptor.cc
|
||||
crossthread.cc
|
||||
enumwriter.cc
|
||||
event_loop.cc
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "pbd/controllable_descriptor.h"
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/failed_constructor.h"
|
||||
#include "pbd/pathscanner.h"
|
||||
|
|
@ -711,11 +712,13 @@ GenericMidiControlProtocol::reset_controllables ()
|
|||
MIDIControllable* existingBinding = (*iter);
|
||||
|
||||
if (!existingBinding->learned()) {
|
||||
uint32_t rid = existingBinding->rid();
|
||||
if (existingBinding->bank_relative()) {
|
||||
rid += _current_bank * _bank_size;
|
||||
ControllableDescriptor& desc (existingBinding->descriptor());
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <climits>
|
||||
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/controllable_descriptor.h"
|
||||
#include "pbd/xml++.h"
|
||||
|
||||
#include "midi++/port.h"
|
||||
|
|
@ -41,6 +42,7 @@ using namespace ARDOUR;
|
|||
|
||||
MIDIControllable::MIDIControllable (Port& p, bool is_bistate)
|
||||
: controllable (0)
|
||||
, _descriptor (0)
|
||||
, _port (p)
|
||||
, bistate (is_bistate)
|
||||
{
|
||||
|
|
@ -55,8 +57,10 @@ MIDIControllable::MIDIControllable (Port& p, bool is_bistate)
|
|||
|
||||
MIDIControllable::MIDIControllable (Port& p, Controllable& c, bool is_bistate)
|
||||
: controllable (&c)
|
||||
, _descriptor (0)
|
||||
, _port (p)
|
||||
, bistate (is_bistate)
|
||||
|
||||
{
|
||||
_learned = true; /* from controllable */
|
||||
setting = false;
|
||||
|
|
@ -76,48 +80,9 @@ int
|
|||
MIDIControllable::init (const std::string& s)
|
||||
{
|
||||
_current_uri = s;
|
||||
|
||||
if (!_current_uri.empty()) {
|
||||
|
||||
/* 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;
|
||||
delete _descriptor;
|
||||
_descriptor = new ControllableDescriptor;
|
||||
return _descriptor->set (s);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -30,12 +30,14 @@
|
|||
|
||||
#include "ardour/types.h"
|
||||
|
||||
namespace PBD {
|
||||
class ControllableDescriptor;
|
||||
}
|
||||
|
||||
namespace MIDI {
|
||||
|
||||
class Channel;
|
||||
class Port;
|
||||
class Parser;
|
||||
|
||||
class Channel;
|
||||
class Port;
|
||||
class Parser;
|
||||
}
|
||||
|
||||
class MIDIControllable : public PBD::Stateful
|
||||
|
|
@ -74,6 +76,8 @@ class MIDIControllable : public PBD::Stateful
|
|||
void set_controllable (PBD::Controllable*);
|
||||
const std::string& current_uri() const { return _current_uri; }
|
||||
|
||||
PBD::ControllableDescriptor& descriptor() const { return *_descriptor; }
|
||||
|
||||
std::string control_description() const { return _control_description; }
|
||||
|
||||
XMLNode& get_state (void);
|
||||
|
|
@ -86,6 +90,7 @@ class MIDIControllable : public PBD::Stateful
|
|||
|
||||
private:
|
||||
PBD::Controllable* controllable;
|
||||
PBD::ControllableDescriptor* _descriptor;
|
||||
std::string _current_uri;
|
||||
MIDI::Port& _port;
|
||||
bool setting;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue