Automation of LV2 plugin properties.
Work towards ParameterDescriptor being used more universally to describe control characteristics.
This commit is contained in:
parent
6dfb11c2d0
commit
8a128b33d3
|
@ -36,7 +36,9 @@
|
|||
using namespace ARDOUR;
|
||||
using namespace Gtk;
|
||||
|
||||
AutomationController::AutomationController(boost::shared_ptr<Automatable> printer, boost::shared_ptr<AutomationControl> ac, Adjustment* adj)
|
||||
AutomationController::AutomationController(boost::shared_ptr<Automatable> printer,
|
||||
boost::shared_ptr<AutomationControl> ac,
|
||||
Adjustment* adj)
|
||||
: BarController (*adj, ac)
|
||||
, _ignore_change(false)
|
||||
, _printer (printer)
|
||||
|
@ -64,21 +66,27 @@ AutomationController::~AutomationController()
|
|||
}
|
||||
|
||||
boost::shared_ptr<AutomationController>
|
||||
AutomationController::create(
|
||||
boost::shared_ptr<Automatable> printer,
|
||||
const Evoral::Parameter& param,
|
||||
boost::shared_ptr<AutomationControl> ac)
|
||||
AutomationController::create(boost::shared_ptr<Automatable> printer,
|
||||
const Evoral::Parameter& param,
|
||||
const ParameterDescriptor& desc,
|
||||
boost::shared_ptr<AutomationControl> ac)
|
||||
{
|
||||
double const lo = ac->internal_to_interface(param.min());
|
||||
double const up = ac->internal_to_interface(param.max());
|
||||
const double lo = ac->internal_to_interface(desc.lower);
|
||||
const double up = ac->internal_to_interface(desc.upper);
|
||||
const double normal = ac->internal_to_interface(desc.normal);
|
||||
double smallstep = desc.smallstep;
|
||||
double largestep = desc.largestep;
|
||||
if (smallstep == 0.0) {
|
||||
smallstep = (up - lo) / 100;
|
||||
}
|
||||
if (largestep == 0.0) {
|
||||
largestep = (up - lo) / 10;
|
||||
}
|
||||
smallstep = ac->internal_to_interface(smallstep);
|
||||
largestep = ac->internal_to_interface(largestep);
|
||||
|
||||
Gtk::Adjustment* adjustment = manage (
|
||||
new Gtk::Adjustment (
|
||||
ac->internal_to_interface(param.normal()),
|
||||
lo, up,
|
||||
// TODO we should use explicit step-sizes if provided by Plugin::ParameterDescriptor
|
||||
(up - lo) / 100, (up - lo) / 10
|
||||
)
|
||||
);
|
||||
new Gtk::Adjustment (normal, lo, up, smallstep, largestep));
|
||||
|
||||
assert (ac);
|
||||
assert(ac->parameter() == param);
|
||||
|
|
|
@ -46,9 +46,10 @@ namespace ARDOUR {
|
|||
class AutomationController : public Gtkmm2ext::BarController {
|
||||
public:
|
||||
static boost::shared_ptr<AutomationController> create(
|
||||
boost::shared_ptr<ARDOUR::Automatable> parent,
|
||||
const Evoral::Parameter& param,
|
||||
boost::shared_ptr<ARDOUR::AutomationControl> ac);
|
||||
boost::shared_ptr<ARDOUR::Automatable> parent,
|
||||
const Evoral::Parameter& param,
|
||||
const ARDOUR::ParameterDescriptor& desc,
|
||||
boost::shared_ptr<ARDOUR::AutomationControl> ac);
|
||||
|
||||
~AutomationController();
|
||||
|
||||
|
@ -62,7 +63,9 @@ public:
|
|||
void stop_updating ();
|
||||
|
||||
private:
|
||||
AutomationController (boost::shared_ptr<ARDOUR::Automatable> printer, boost::shared_ptr<ARDOUR::AutomationControl> ac, Gtk::Adjustment* adj);
|
||||
AutomationController (boost::shared_ptr<ARDOUR::Automatable> printer,
|
||||
boost::shared_ptr<ARDOUR::AutomationControl> ac,
|
||||
Gtk::Adjustment* adj);
|
||||
std::string get_label (double&);
|
||||
|
||||
void start_touch();
|
||||
|
|
|
@ -69,8 +69,10 @@ using namespace Editing;
|
|||
/** @param converter A TimeConverter whose origin_b is the start time of the AutomationList in session frames.
|
||||
* This will not be deleted by AutomationLine.
|
||||
*/
|
||||
AutomationLine::AutomationLine (const string& name, TimeAxisView& tv, ArdourCanvas::Item& parent,
|
||||
boost::shared_ptr<AutomationList> al,
|
||||
AutomationLine::AutomationLine (const string& name,
|
||||
TimeAxisView& tv,
|
||||
ArdourCanvas::Item& parent,
|
||||
boost::shared_ptr<AutomationList> al,
|
||||
Evoral::TimeConverter<double, framepos_t>* converter)
|
||||
: trackview (tv)
|
||||
, _name (name)
|
||||
|
@ -1160,7 +1162,7 @@ AutomationLine::view_to_model_coord (double& x, double& y) const
|
|||
void
|
||||
AutomationLine::view_to_model_coord_y (double& y) const
|
||||
{
|
||||
/* TODO: This should be more generic ... */
|
||||
/* TODO: This should be more generic (use ParameterDescriptor) */
|
||||
if (alist->parameter().type() == GainAutomation ||
|
||||
alist->parameter().type() == EnvelopeAutomation) {
|
||||
y = slider_position_to_gain_with_max (y, Config->get_max_gain());
|
||||
|
@ -1171,17 +1173,15 @@ AutomationLine::view_to_model_coord_y (double& y) const
|
|||
y = 1.0 - y;
|
||||
} else if (alist->parameter().type() == PanWidthAutomation) {
|
||||
y = 2.0 * y - 1.0;
|
||||
} else if (alist->parameter().type() == PluginAutomation) {
|
||||
y = y * (double)(alist->get_max_y()- alist->get_min_y()) + alist->get_min_y();
|
||||
} else {
|
||||
y = rint (y * alist->parameter().max());
|
||||
y = y * (double)(alist->get_max_y() - alist->get_min_y()) + alist->get_min_y();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutomationLine::model_to_view_coord (double& x, double& y) const
|
||||
{
|
||||
/* TODO: This should be more generic ... */
|
||||
/* TODO: This should be more generic (use ParameterDescriptor) */
|
||||
if (alist->parameter().type() == GainAutomation ||
|
||||
alist->parameter().type() == EnvelopeAutomation) {
|
||||
y = gain_to_slider_position_with_max (y, Config->get_max_gain());
|
||||
|
@ -1190,10 +1190,8 @@ AutomationLine::model_to_view_coord (double& x, double& y) const
|
|||
y = 1.0 - y;
|
||||
} else if (alist->parameter().type() == PanWidthAutomation) {
|
||||
y = .5 + y * .5;
|
||||
} else if (alist->parameter().type() == PluginAutomation) {
|
||||
y = (y - alist->get_min_y()) / (double)(alist->get_max_y()- alist->get_min_y());
|
||||
} else {
|
||||
y = y / (double)alist->parameter().max(); /* ... like this */
|
||||
y = (y - alist->get_min_y()) / (double)(alist->get_max_y() - alist->get_min_y());
|
||||
}
|
||||
|
||||
x = _time_converter->to (x) - _offset;
|
||||
|
|
|
@ -60,9 +60,12 @@ public:
|
|||
SelectedControlPoints = 0x4
|
||||
};
|
||||
|
||||
AutomationLine (const std::string& name, TimeAxisView&, ArdourCanvas::Item&,
|
||||
boost::shared_ptr<ARDOUR::AutomationList>,
|
||||
AutomationLine (const std::string& name,
|
||||
TimeAxisView& tv,
|
||||
ArdourCanvas::Item& parent,
|
||||
boost::shared_ptr<ARDOUR::AutomationList> al,
|
||||
Evoral::TimeConverter<double, ARDOUR::framepos_t>* converter = 0);
|
||||
|
||||
virtual ~AutomationLine ();
|
||||
|
||||
void queue_reset ();
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "ardour/automation_control.h"
|
||||
#include "ardour/event_type_map.h"
|
||||
#include "ardour/parameter_types.h"
|
||||
#include "ardour/profile.h"
|
||||
#include "ardour/route.h"
|
||||
#include "ardour/session.h"
|
||||
|
@ -103,7 +104,7 @@ AutomationTimeAxisView::AutomationTimeAxisView (
|
|||
}
|
||||
|
||||
if (_automatable && _control) {
|
||||
_controller = AutomationController::create (_automatable, _control->parameter(), _control);
|
||||
_controller = AutomationController::create (_automatable, _control->parameter(), _control->desc(), _control);
|
||||
}
|
||||
|
||||
automation_menu = 0;
|
||||
|
@ -559,7 +560,7 @@ AutomationTimeAxisView::build_display_menu ()
|
|||
/* current interpolation state */
|
||||
AutomationList::InterpolationStyle const s = _view ? _view->interpolation() : _control->list()->interpolation ();
|
||||
|
||||
if (EventTypeMap::instance().is_midi_parameter(_parameter)) {
|
||||
if (ARDOUR::parameter_is_midi((AutomationType)_parameter.type())) {
|
||||
|
||||
Menu* auto_mode_menu = manage (new Menu);
|
||||
auto_mode_menu->set_name ("ArdourContextMenu");
|
||||
|
@ -838,7 +839,7 @@ AutomationTimeAxisView::what_has_visible_automation (const boost::shared_ptr<Aut
|
|||
|
||||
boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (i->second);
|
||||
|
||||
if (ac) {
|
||||
if (ac && ac->alist()) {
|
||||
|
||||
const XMLNode* gui_node = ac->extra_xml ("GUI");
|
||||
|
||||
|
|
|
@ -239,9 +239,9 @@ GenericPluginUI::build ()
|
|||
frame->add (*box);
|
||||
hpacker.pack_start(*frame, true, true);
|
||||
|
||||
/* find all ports. build control elements for all appropriate control ports */
|
||||
std::vector<ControlUI *> cui_controls_list;
|
||||
std::vector<ControlUI *> control_uis;
|
||||
|
||||
// Build a ControlUI for each control port
|
||||
for (i = 0; i < plugin->parameter_count(); ++i) {
|
||||
|
||||
if (plugin->parameter_is_control (i)) {
|
||||
|
@ -274,78 +274,74 @@ GenericPluginUI::build ()
|
|||
ARDOUR_UI::instance()->set_tip(cui, param_docs.c_str());
|
||||
}
|
||||
|
||||
if (cui->controller || cui->clickbox || cui->combo) {
|
||||
// Get all of the controls into a list, so that
|
||||
// we can lay them out a bit more nicely later.
|
||||
cui_controls_list.push_back(cui);
|
||||
} else if (cui->button) {
|
||||
|
||||
if (!is_scrollable && button_row == button_rows) {
|
||||
button_row = 0;
|
||||
if (++button_col == button_cols) {
|
||||
button_cols += 2;
|
||||
button_table.resize (button_rows, button_cols);
|
||||
}
|
||||
}
|
||||
|
||||
button_table.attach (*cui, button_col, button_col + 1, button_row, button_row+1,
|
||||
FILL|EXPAND, FILL);
|
||||
button_row++;
|
||||
|
||||
} else if (cui->display) {
|
||||
|
||||
output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1,
|
||||
FILL|EXPAND, FILL);
|
||||
|
||||
// TODO: The meters should be divided into multiple rows
|
||||
|
||||
if (++output_col == output_cols) {
|
||||
output_cols ++;
|
||||
output_table.resize (output_rows, output_cols);
|
||||
}
|
||||
}
|
||||
}
|
||||
control_uis.push_back(cui);
|
||||
}
|
||||
}
|
||||
|
||||
// Add property controls (currently file chooser button for paths only)
|
||||
typedef std::vector<ParameterDescriptor> Descs;
|
||||
Descs descs;
|
||||
plugin->get_supported_properties(descs);
|
||||
for (Descs::const_iterator d = descs.begin(); d != descs.end(); ++d) {
|
||||
if (d->datatype == Variant::PATH) {
|
||||
// Create/add label
|
||||
Gtk::Label* label = manage(new Label(d->label));
|
||||
button_table.attach(*label,
|
||||
0, button_cols, button_row, button_row + 1,
|
||||
FILL|EXPAND, FILL);
|
||||
++button_row;
|
||||
// Build a ControlUI for each property
|
||||
const Plugin::PropertyDescriptors& descs = plugin->get_supported_properties();
|
||||
for (Plugin::PropertyDescriptors::const_iterator d = descs.begin(); d != descs.end(); ++d) {
|
||||
const ParameterDescriptor& desc = d->second;
|
||||
|
||||
// Create/add controller
|
||||
Gtk::FileChooserButton* widget = manage(
|
||||
new Gtk::FileChooserButton(Gtk::FILE_CHOOSER_ACTION_OPEN));
|
||||
widget->set_title(d->label);
|
||||
_property_controls.insert(std::make_pair(d->key, widget));
|
||||
button_table.attach(*widget,
|
||||
0, button_cols, button_row, button_row + 1,
|
||||
FILL|EXPAND, FILL);
|
||||
++button_row;
|
||||
boost::shared_ptr<ARDOUR::AutomationControl> c
|
||||
= boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
|
||||
insert->control(Evoral::Parameter(PluginPropertyAutomation, 0, desc.key)));
|
||||
|
||||
// Connect signals
|
||||
widget->signal_file_set().connect(
|
||||
sigc::bind(sigc::mem_fun(*this, &GenericPluginUI::set_property), *d, widget));
|
||||
plugin->PropertyChanged.connect(*this, invalidator(*this),
|
||||
boost::bind(&GenericPluginUI::property_changed, this, _1, _2),
|
||||
gui_context());
|
||||
} else {
|
||||
// TODO: widgets for other datatypes, use ControlUI?
|
||||
std::cerr << "warning: unsupported property " << d->key
|
||||
<< " type " << d->datatype << std::endl;
|
||||
if (!c) {
|
||||
error << string_compose(_("Plugin Editor: no control for property %1"), desc.key) << endmsg;
|
||||
continue;
|
||||
}
|
||||
|
||||
ControlUI* cui = build_control_ui(desc, c, true);
|
||||
if (!cui) {
|
||||
error << string_compose(_("Plugin Editor: could not build control element for property %1"),
|
||||
desc.key) << endmsg;
|
||||
continue;
|
||||
}
|
||||
|
||||
control_uis.push_back(cui);
|
||||
}
|
||||
if (!descs.empty()) {
|
||||
plugin->announce_property_values();
|
||||
}
|
||||
|
||||
// Add special controls to UI, and build list of normal controls to be layed out later
|
||||
std::vector<ControlUI *> cui_controls_list;
|
||||
for (i = 0; i < control_uis.size(); ++i) {
|
||||
ControlUI* cui = control_uis[i];
|
||||
|
||||
if (cui->controller || cui->clickbox || cui->combo) {
|
||||
// Get all of the controls into a list, so that
|
||||
// we can lay them out a bit more nicely later.
|
||||
cui_controls_list.push_back(cui);
|
||||
} else if (cui->button || cui->file_button) {
|
||||
|
||||
if (!is_scrollable && button_row == button_rows) {
|
||||
button_row = 0;
|
||||
if (++button_col == button_cols) {
|
||||
button_cols += 2;
|
||||
button_table.resize (button_rows, button_cols);
|
||||
}
|
||||
}
|
||||
|
||||
button_table.attach (*cui, button_col, button_col + 1, button_row, button_row+1,
|
||||
FILL|EXPAND, FILL);
|
||||
button_row++;
|
||||
|
||||
} else if (cui->display) {
|
||||
|
||||
output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1,
|
||||
FILL|EXPAND, FILL);
|
||||
|
||||
// TODO: The meters should be divided into multiple rows
|
||||
|
||||
if (++output_col == output_cols) {
|
||||
output_cols ++;
|
||||
output_table.resize (output_rows, output_cols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over the list of controls to find which adjacent controls
|
||||
// are similar enough to be grouped together.
|
||||
|
||||
|
@ -455,6 +451,7 @@ GenericPluginUI::build ()
|
|||
|
||||
GenericPluginUI::ControlUI::ControlUI ()
|
||||
: automate_button (X_("")) // force creation of a label
|
||||
, file_button(NULL)
|
||||
{
|
||||
automate_button.set_name ("PluginAutomateButton");
|
||||
ARDOUR_UI::instance()->set_tip (automate_button, _("Automation control"));
|
||||
|
@ -652,10 +649,35 @@ GenericPluginUI::build_control_ui (const ParameterDescriptor& desc,
|
|||
return control_ui;
|
||||
}
|
||||
|
||||
if (desc.datatype == Variant::PATH) {
|
||||
|
||||
/* Build a file selector button */
|
||||
|
||||
// Create/add controller
|
||||
control_ui->file_button = manage(new Gtk::FileChooserButton(Gtk::FILE_CHOOSER_ACTION_OPEN));
|
||||
control_ui->file_button->set_title(desc.label);
|
||||
|
||||
control_ui->pack_start (control_ui->label, true, true);
|
||||
control_ui->pack_start (*control_ui->file_button, true, true);
|
||||
|
||||
// Connect signals (TODO: do this via the Control)
|
||||
control_ui->file_button->signal_file_set().connect(
|
||||
sigc::bind(sigc::mem_fun(*this, &GenericPluginUI::set_property),
|
||||
desc, control_ui->file_button));
|
||||
plugin->PropertyChanged.connect(*this, invalidator(*this),
|
||||
boost::bind(&GenericPluginUI::property_changed, this, _1, _2),
|
||||
gui_context());
|
||||
|
||||
_property_controls.insert(std::make_pair(desc.key, control_ui->file_button));
|
||||
control_ui->file_button = control_ui->file_button;
|
||||
|
||||
return control_ui;
|
||||
}
|
||||
|
||||
/* create the controller */
|
||||
|
||||
if (mcontrol) {
|
||||
control_ui->controller = AutomationController::create(insert, mcontrol->parameter(), mcontrol);
|
||||
control_ui->controller = AutomationController::create(insert, mcontrol->parameter(), desc, mcontrol);
|
||||
}
|
||||
|
||||
/* XXX this code is not right yet, because it doesn't handle
|
||||
|
@ -663,7 +685,6 @@ GenericPluginUI::build_control_ui (const ParameterDescriptor& desc,
|
|||
*/
|
||||
|
||||
Adjustment* adj = control_ui->controller->adjustment();
|
||||
boost::shared_ptr<PluginInsert::PluginControl> pc = boost::dynamic_pointer_cast<PluginInsert::PluginControl> (control_ui->control);
|
||||
|
||||
if (desc.integer_step) {
|
||||
control_ui->clickbox = new ClickBox (adj, "PluginUIClickBox");
|
||||
|
|
|
@ -56,7 +56,7 @@ LV2PluginUI::write_from_ui(void* controller,
|
|||
if (ac) {
|
||||
ac->set_value(*(const float*)buffer);
|
||||
}
|
||||
} else if (format == me->_lv2->urids.atom_eventTransfer) {
|
||||
} else if (format == URIMap::instance().urids.atom_eventTransfer) {
|
||||
|
||||
const int cnt = me->_pi->get_count();
|
||||
for (int i=0; i < cnt; i++ ) {
|
||||
|
|
|
@ -241,6 +241,7 @@ class GenericPluginUI : public PlugUIBase, public Gtk::VBox
|
|||
bool update_pending;
|
||||
char ignore_change;
|
||||
Gtk::Button automate_button;
|
||||
Gtk::FileChooserButton* file_button;
|
||||
|
||||
/* output */
|
||||
|
||||
|
|
|
@ -2103,7 +2103,7 @@ RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_
|
|||
request_redraw ();
|
||||
}
|
||||
|
||||
if (!EventTypeMap::instance().is_midi_parameter(param)) {
|
||||
if (!ARDOUR::parameter_is_midi((AutomationType)param.type())) {
|
||||
/* MIDI-related parameters are always in the menu, there's no
|
||||
reason to rebuild the menu just because we added a automation
|
||||
lane for one of them. But if we add a non-MIDI automation
|
||||
|
|
|
@ -79,7 +79,7 @@ public:
|
|||
struct GainControl : public AutomationControl {
|
||||
GainControl (std::string name, Session& session, Amp* a, const Evoral::Parameter ¶m,
|
||||
boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>() )
|
||||
: AutomationControl (session, param, al, name)
|
||||
: AutomationControl (session, param, ParameterDescriptor(param), al, name)
|
||||
, _amp (a) {
|
||||
set_flags (Controllable::Flag (flags() | Controllable::GainLike));
|
||||
alist()->reset_default (1.0);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "evoral/Sequence.hpp"
|
||||
#include "ardour/automatable.h"
|
||||
#include "ardour/event_type_map.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "ardour/libardour_visibility.h"
|
||||
#include "ardour/automation_list.h"
|
||||
#include "ardour/parameter_descriptor.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
|
@ -42,11 +43,12 @@ class LIBARDOUR_API AutomationControl : public PBD::Controllable, public Evoral:
|
|||
{
|
||||
public:
|
||||
AutomationControl(ARDOUR::Session&,
|
||||
const Evoral::Parameter& parameter,
|
||||
boost::shared_ptr<ARDOUR::AutomationList> l=boost::shared_ptr<ARDOUR::AutomationList>(),
|
||||
const std::string& name="");
|
||||
const Evoral::Parameter& parameter,
|
||||
const ParameterDescriptor& desc,
|
||||
boost::shared_ptr<ARDOUR::AutomationList> l=boost::shared_ptr<ARDOUR::AutomationList>(),
|
||||
const std::string& name="");
|
||||
|
||||
~AutomationControl ();
|
||||
~AutomationControl ();
|
||||
|
||||
boost::shared_ptr<AutomationList> alist() const {
|
||||
return boost::dynamic_pointer_cast<AutomationList>(_list);
|
||||
|
@ -78,16 +80,20 @@ public:
|
|||
void set_value (double);
|
||||
double get_value () const;
|
||||
|
||||
double lower() const { return parameter().min(); }
|
||||
double upper() const { return parameter().max(); }
|
||||
double normal() const { return parameter().normal(); }
|
||||
bool toggled() const { return parameter().toggled(); }
|
||||
double lower() const { return _desc.lower; }
|
||||
double upper() const { return _desc.upper; }
|
||||
double normal() const { return _desc.normal; }
|
||||
bool toggled() const { return _desc.toggled; }
|
||||
|
||||
const ParameterDescriptor& desc() const { return _desc; }
|
||||
|
||||
const ARDOUR::Session& session() const { return _session; }
|
||||
|
||||
protected:
|
||||
|
||||
ARDOUR::Session& _session;
|
||||
|
||||
const ParameterDescriptor _desc;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -29,11 +29,15 @@
|
|||
|
||||
namespace ARDOUR {
|
||||
|
||||
class URIMap;
|
||||
|
||||
/** This is the interface Ardour provides to Evoral about what
|
||||
* parameter and event types/ranges/names etc. to use.
|
||||
*/
|
||||
class LIBARDOUR_API EventTypeMap : public Evoral::TypeMap {
|
||||
public:
|
||||
static EventTypeMap& instance();
|
||||
|
||||
bool type_is_midi(uint32_t type) const;
|
||||
uint8_t parameter_midi_type(const Evoral::Parameter& param) const;
|
||||
uint32_t midi_event_type(uint8_t status) const;
|
||||
|
@ -46,10 +50,14 @@ public:
|
|||
|
||||
bool is_midi_parameter(const Evoral::Parameter& param);
|
||||
|
||||
static EventTypeMap& instance() { return event_type_map; }
|
||||
URIMap& uri_map() { return _uri_map; }
|
||||
|
||||
private:
|
||||
static EventTypeMap event_type_map;
|
||||
EventTypeMap(URIMap& uri_map) : _uri_map(uri_map) {}
|
||||
|
||||
URIMap& _uri_map;
|
||||
|
||||
static EventTypeMap* event_type_map;
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
|
@ -146,42 +146,16 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
|
|||
|
||||
Worker* worker() { return _worker; }
|
||||
|
||||
URIMap& uri_map() { return _uri_map; }
|
||||
const URIMap& uri_map() const { return _uri_map; }
|
||||
|
||||
int work(uint32_t size, const void* data);
|
||||
int work_response(uint32_t size, const void* data);
|
||||
|
||||
void set_property(uint32_t key, const Variant& value);
|
||||
void get_supported_properties(std::vector<ParameterDescriptor>& descs);
|
||||
void announce_property_values();
|
||||
|
||||
static URIMap _uri_map;
|
||||
|
||||
struct URIDs {
|
||||
uint32_t atom_Chunk;
|
||||
uint32_t atom_Path;
|
||||
uint32_t atom_Sequence;
|
||||
uint32_t atom_eventTransfer;
|
||||
uint32_t atom_URID;
|
||||
uint32_t atom_Blank;
|
||||
uint32_t atom_Object;
|
||||
uint32_t log_Error;
|
||||
uint32_t log_Note;
|
||||
uint32_t log_Warning;
|
||||
uint32_t midi_MidiEvent;
|
||||
uint32_t time_Position;
|
||||
uint32_t time_bar;
|
||||
uint32_t time_barBeat;
|
||||
uint32_t time_beatUnit;
|
||||
uint32_t time_beatsPerBar;
|
||||
uint32_t time_beatsPerMinute;
|
||||
uint32_t time_frame;
|
||||
uint32_t time_speed;
|
||||
uint32_t patch_Get;
|
||||
uint32_t patch_Set;
|
||||
uint32_t patch_property;
|
||||
uint32_t patch_value;
|
||||
};
|
||||
|
||||
static URIDs urids;
|
||||
void set_property(uint32_t key, const Variant& value);
|
||||
const PropertyDescriptors& get_supported_properties() const { return _property_descriptors; }
|
||||
const ParameterDescriptor& get_property_descriptor(uint32_t id) const;
|
||||
void announce_property_values();
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
|
@ -203,6 +177,7 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
|
|||
PBD::ID _insert_id;
|
||||
uint32_t _patch_port_in_index;
|
||||
uint32_t _patch_port_out_index;
|
||||
URIMap& _uri_map;
|
||||
|
||||
friend const void* lv2plugin_get_port_value(const char* port_symbol,
|
||||
void* user_data,
|
||||
|
@ -227,6 +202,8 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
|
|||
std::vector<size_t> _port_minimumSize;
|
||||
std::map<std::string,uint32_t> _port_indices;
|
||||
|
||||
PropertyDescriptors _property_descriptors;
|
||||
|
||||
/// Message send to/from UI via ports
|
||||
struct UIMessage {
|
||||
uint32_t index;
|
||||
|
@ -283,6 +260,8 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
|
|||
void allocate_atom_event_buffers ();
|
||||
void run (pframes_t nsamples);
|
||||
|
||||
void load_supported_properties(PropertyDescriptors& descs);
|
||||
|
||||
void latency_compute_run ();
|
||||
std::string do_save_preset (std::string);
|
||||
void do_remove_preset (std::string);
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "evoral/midi_util.h"
|
||||
#include "midi++/event.h"
|
||||
#include "ardour/buffer.h"
|
||||
#include "ardour/event_type_map.h"
|
||||
#include "ardour/parameter_types.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
|
@ -77,7 +77,7 @@ public:
|
|||
uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType);
|
||||
int event_size = Evoral::midi_event_size(ev_start);
|
||||
assert(event_size >= 0);
|
||||
return EventType(EventTypeMap::instance().midi_event_type(*ev_start),
|
||||
return EventType(midi_parameter_type(*ev_start),
|
||||
*((TimeType*)(buffer->_data + offset)),
|
||||
event_size, ev_start);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ public:
|
|||
uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType);
|
||||
int event_size = Evoral::midi_event_size(ev_start);
|
||||
assert(event_size >= 0);
|
||||
return EventType(EventTypeMap::instance().midi_event_type(*ev_start),
|
||||
return EventType(midi_parameter_type(*ev_start),
|
||||
*(reinterpret_cast<TimeType*>((uintptr_t)(buffer->_data + offset))),
|
||||
event_size, ev_start);
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ public:
|
|||
struct MidiControl : public AutomationControl {
|
||||
MidiControl(MidiTrack* route, const Evoral::Parameter& param,
|
||||
boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>())
|
||||
: AutomationControl (route->session(), param, al)
|
||||
: AutomationControl (route->session(), param, ParameterDescriptor(param), al)
|
||||
, _route (route)
|
||||
{}
|
||||
|
||||
|
|
|
@ -38,7 +38,11 @@ class LIBARDOUR_API PanControllable : public AutomationControl
|
|||
{
|
||||
public:
|
||||
PanControllable (Session& s, std::string name, Pannable* o, Evoral::Parameter param)
|
||||
: AutomationControl (s, param, boost::shared_ptr<AutomationList>(new AutomationList(param)), name)
|
||||
: AutomationControl (s,
|
||||
param,
|
||||
ParameterDescriptor(param),
|
||||
boost::shared_ptr<AutomationList>(new AutomationList(param)),
|
||||
name)
|
||||
, owner (o)
|
||||
{}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define __ardour_parameter_descriptor_h__
|
||||
|
||||
#include "ardour/variant.h"
|
||||
#include "evoral/Parameter.hpp"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
|
@ -32,9 +33,29 @@ typedef std::map<const std::string, const float> ScalePoints;
|
|||
*/
|
||||
struct ParameterDescriptor
|
||||
{
|
||||
ParameterDescriptor(const Evoral::Parameter& parameter)
|
||||
: key((uint32_t)-1)
|
||||
, datatype(Variant::VOID)
|
||||
, normal(parameter.normal())
|
||||
, lower(parameter.min())
|
||||
, upper(parameter.max())
|
||||
, step(0)
|
||||
, smallstep((upper - lower) / 100.0)
|
||||
, largestep((upper - lower) / 10.0)
|
||||
, integer_step(false)
|
||||
, toggled(parameter.toggled())
|
||||
, logarithmic(false)
|
||||
, sr_dependent(false)
|
||||
, min_unbound(0)
|
||||
, max_unbound(0)
|
||||
, enumeration(false)
|
||||
, midinote(false)
|
||||
{}
|
||||
|
||||
ParameterDescriptor()
|
||||
: key((uint32_t)-1)
|
||||
, datatype(Variant::VOID)
|
||||
, normal(0)
|
||||
, lower(0)
|
||||
, upper(0)
|
||||
, step(0)
|
||||
|
@ -54,6 +75,7 @@ struct ParameterDescriptor
|
|||
boost::shared_ptr<ScalePoints> scale_points;
|
||||
uint32_t key; ///< for properties
|
||||
Variant::Type datatype; ///< for properties
|
||||
float normal;
|
||||
float lower; ///< for frequencies, this is in Hz (not a fraction of the sample rate)
|
||||
float upper; ///< for frequencies, this is in Hz (not a fraction of the sample rate)
|
||||
float step;
|
||||
|
|
66
libs/ardour/ardour/parameter_types.h
Normal file
66
libs/ardour/ardour/parameter_types.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
Copyright (C) 2014 Paul Davis
|
||||
Author: David Robillard
|
||||
|
||||
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 __ardour_parameter_types_h__
|
||||
#define __ardour_parameter_types_h__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ardour/types.h"
|
||||
#include "evoral/midi_events.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
inline uint8_t
|
||||
parameter_midi_type(AutomationType type)
|
||||
{
|
||||
switch (type) {
|
||||
case MidiCCAutomation: return MIDI_CMD_CONTROL; break;
|
||||
case MidiPgmChangeAutomation: return MIDI_CMD_PGM_CHANGE; break;
|
||||
case MidiChannelPressureAutomation: return MIDI_CMD_CHANNEL_PRESSURE; break;
|
||||
case MidiPitchBenderAutomation: return MIDI_CMD_BENDER; break;
|
||||
case MidiSystemExclusiveAutomation: return MIDI_CMD_COMMON_SYSEX; break;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline AutomationType
|
||||
midi_parameter_type(uint8_t status)
|
||||
{
|
||||
switch (status & 0xF0) {
|
||||
case MIDI_CMD_CONTROL: return MidiCCAutomation; break;
|
||||
case MIDI_CMD_PGM_CHANGE: return MidiPgmChangeAutomation; break;
|
||||
case MIDI_CMD_CHANNEL_PRESSURE: return MidiChannelPressureAutomation; break;
|
||||
case MIDI_CMD_BENDER: return MidiPitchBenderAutomation; break;
|
||||
case MIDI_CMD_COMMON_SYSEX: return MidiSystemExclusiveAutomation; break;
|
||||
default: return NullAutomation;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
parameter_is_midi(AutomationType type)
|
||||
{
|
||||
return (type >= MidiCCAutomation) && (type <= MidiChannelPressureAutomation);
|
||||
}
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
#endif /* __ardour_parameter_types_h__ */
|
||||
|
|
@ -231,6 +231,8 @@ class LIBARDOUR_API Plugin : public PBD::StatefulDestructible, public Latent
|
|||
void set_cycles (uint32_t c) { _cycles = c; }
|
||||
cycles_t cycles() const { return _cycles; }
|
||||
|
||||
typedef std::map<uint32_t, ParameterDescriptor> PropertyDescriptors;
|
||||
|
||||
/** Get a descrption of all properties supported by this plugin.
|
||||
*
|
||||
* Properties are distinct from parameters in that they are potentially
|
||||
|
@ -239,7 +241,15 @@ class LIBARDOUR_API Plugin : public PBD::StatefulDestructible, public Latent
|
|||
* For LV2 plugins, properties are implemented by sending/receiving set/get
|
||||
* messages to/from the plugin via event ports.
|
||||
*/
|
||||
virtual void get_supported_properties(std::vector<ParameterDescriptor>& descs) {}
|
||||
virtual const PropertyDescriptors& get_supported_properties() const {
|
||||
static const PropertyDescriptors nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
virtual const ParameterDescriptor& get_property_descriptor(uint32_t id) const {
|
||||
static const ParameterDescriptor nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
/** Set a property from the UI.
|
||||
*
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "ardour/ardour.h"
|
||||
#include "ardour/libardour_visibility.h"
|
||||
#include "ardour/types.h"
|
||||
#include "ardour/parameter_descriptor.h"
|
||||
#include "ardour/processor.h"
|
||||
#include "ardour/automation_control.h"
|
||||
|
||||
|
@ -81,10 +82,13 @@ class LIBARDOUR_API PluginInsert : public Processor
|
|||
void realtime_locate ();
|
||||
void monitoring_changed ();
|
||||
|
||||
/** A control that manipulates a plugin parameter (control port). */
|
||||
struct PluginControl : public AutomationControl
|
||||
{
|
||||
PluginControl (PluginInsert* p, const Evoral::Parameter ¶m,
|
||||
boost::shared_ptr<AutomationList> list = boost::shared_ptr<AutomationList>());
|
||||
PluginControl (PluginInsert* p,
|
||||
const Evoral::Parameter& param,
|
||||
const ParameterDescriptor& desc,
|
||||
boost::shared_ptr<AutomationList> list=boost::shared_ptr<AutomationList>());
|
||||
|
||||
void set_value (double val);
|
||||
double get_value (void) const;
|
||||
|
@ -95,9 +99,24 @@ class LIBARDOUR_API PluginInsert : public Processor
|
|||
|
||||
private:
|
||||
PluginInsert* _plugin;
|
||||
bool _logarithmic;
|
||||
bool _sr_dependent;
|
||||
bool _toggled;
|
||||
};
|
||||
|
||||
/** A control that manipulates a plugin property (message). */
|
||||
struct PluginPropertyControl : public AutomationControl
|
||||
{
|
||||
PluginPropertyControl (PluginInsert* p,
|
||||
const Evoral::Parameter& param,
|
||||
const ParameterDescriptor& desc,
|
||||
boost::shared_ptr<AutomationList> list=boost::shared_ptr<AutomationList>());
|
||||
|
||||
void set_value (const Variant& val);
|
||||
void set_value (double val);
|
||||
double get_value (void) const;
|
||||
XMLNode& get_state();
|
||||
|
||||
private:
|
||||
PluginInsert* _plugin;
|
||||
Variant _value;
|
||||
};
|
||||
|
||||
boost::shared_ptr<Plugin> plugin(uint32_t num=0) const {
|
||||
|
|
|
@ -127,6 +127,7 @@ namespace ARDOUR {
|
|||
PanFrontBackAutomation,
|
||||
PanLFEAutomation,
|
||||
PluginAutomation,
|
||||
PluginPropertyAutomation,
|
||||
SoloAutomation,
|
||||
MuteAutomation,
|
||||
MidiCCAutomation,
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include <glibmm/threads.h>
|
||||
|
||||
#include "lv2.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/uri-map/uri-map.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
|
||||
|
@ -39,6 +41,8 @@ namespace ARDOUR {
|
|||
*/
|
||||
class LIBARDOUR_API URIMap : public boost::noncopyable {
|
||||
public:
|
||||
static URIMap& instance();
|
||||
|
||||
URIMap();
|
||||
|
||||
LV2_Feature* uri_map_feature() { return &_uri_map_feature; }
|
||||
|
@ -51,6 +55,38 @@ public:
|
|||
uint32_t uri_to_id(const char* uri);
|
||||
const char* id_to_uri(uint32_t id) const;
|
||||
|
||||
// Cached URIDs for use in real-time code
|
||||
struct URIDs {
|
||||
void init(URIMap& uri_map);
|
||||
|
||||
uint32_t atom_Chunk;
|
||||
uint32_t atom_Path;
|
||||
uint32_t atom_Sequence;
|
||||
uint32_t atom_eventTransfer;
|
||||
uint32_t atom_URID;
|
||||
uint32_t atom_Blank;
|
||||
uint32_t atom_Object;
|
||||
uint32_t atom_Float;
|
||||
uint32_t log_Error;
|
||||
uint32_t log_Note;
|
||||
uint32_t log_Warning;
|
||||
uint32_t midi_MidiEvent;
|
||||
uint32_t time_Position;
|
||||
uint32_t time_bar;
|
||||
uint32_t time_barBeat;
|
||||
uint32_t time_beatUnit;
|
||||
uint32_t time_beatsPerBar;
|
||||
uint32_t time_beatsPerMinute;
|
||||
uint32_t time_frame;
|
||||
uint32_t time_speed;
|
||||
uint32_t patch_Get;
|
||||
uint32_t patch_Set;
|
||||
uint32_t patch_property;
|
||||
uint32_t patch_value;
|
||||
};
|
||||
|
||||
URIDs urids;
|
||||
|
||||
private:
|
||||
typedef std::map<const std::string, uint32_t> Map;
|
||||
typedef std::map<uint32_t, const std::string> Unmap;
|
||||
|
@ -64,6 +100,10 @@ private:
|
|||
LV2_URID_Map _urid_map_feature_data;
|
||||
LV2_Feature _urid_unmap_feature;
|
||||
LV2_URID_Unmap _urid_unmap_feature_data;
|
||||
|
||||
mutable Glib::Threads::Mutex _lock;
|
||||
|
||||
static URIMap* uri_map;
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
#define __ardour_variant_h__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "ardour/libardour_visibility.h"
|
||||
|
@ -45,17 +47,62 @@ public:
|
|||
URI ///< URI string
|
||||
};
|
||||
|
||||
explicit Variant(bool value) : _type(BOOL) { _bool = value; }
|
||||
explicit Variant(double value) : _type(DOUBLE) { _double = value; }
|
||||
explicit Variant(float value) : _type(FLOAT) { _float = value; }
|
||||
explicit Variant(int value) : _type(INT) { _int = value; }
|
||||
explicit Variant(long value) : _type(LONG) { _long = value; }
|
||||
explicit Variant() : _type(VOID) { _long = 0; }
|
||||
explicit Variant(bool value) : _type(BOOL) { _bool = value; }
|
||||
explicit Variant(double value) : _type(DOUBLE) { _double = value; }
|
||||
explicit Variant(float value) : _type(FLOAT) { _float = value; }
|
||||
explicit Variant(int32_t value) : _type(INT) { _int = value; }
|
||||
explicit Variant(int64_t value) : _type(LONG) { _long = value; }
|
||||
|
||||
/** Make a variant of a specific string type (string types only) */
|
||||
Variant(Type type, const std::string& value)
|
||||
: _type(type)
|
||||
, _string(value)
|
||||
{}
|
||||
|
||||
/** Make a numeric variant from a double (numeric types only).
|
||||
*
|
||||
* If conversion is impossible, the variant will have type VOID.
|
||||
*/
|
||||
Variant(Type type, double value)
|
||||
: _type(type)
|
||||
{
|
||||
switch (type) {
|
||||
case BOOL:
|
||||
_bool = value != 0.0;
|
||||
break;
|
||||
case DOUBLE:
|
||||
_double = (double)value;
|
||||
break;
|
||||
case FLOAT:
|
||||
_float = (float)value;
|
||||
break;
|
||||
case INT:
|
||||
_int = (int32_t)lrint(std::max((double)INT32_MIN,
|
||||
std::min(value, (double)INT32_MAX)));
|
||||
break;
|
||||
case LONG:
|
||||
_long = (int64_t)lrint(std::max((double)INT64_MIN,
|
||||
std::min(value, (double)INT64_MAX)));
|
||||
break;
|
||||
default:
|
||||
_type = VOID;
|
||||
_long = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Convert a numeric variant to a double. */
|
||||
double to_double() const {
|
||||
switch (_type) {
|
||||
case BOOL: return _bool;
|
||||
case DOUBLE: return _double;
|
||||
case FLOAT: return _float;
|
||||
case INT: return _int;
|
||||
case LONG: return _long;
|
||||
default: return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
bool get_bool() const { ensure_type(BOOL); return _bool; }
|
||||
double get_double() const { ensure_type(DOUBLE); return _double; }
|
||||
float get_float() const { ensure_type(FLOAT); return _float; }
|
||||
|
@ -68,6 +115,15 @@ public:
|
|||
|
||||
Type type() const { return _type; }
|
||||
|
||||
static bool type_is_numeric(Type type) {
|
||||
switch (type) {
|
||||
case BOOL: case DOUBLE: case FLOAT: case INT: case LONG:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static const char* type_name(const Type type) {
|
||||
static const char* names[] = {
|
||||
|
|
|
@ -31,8 +31,10 @@
|
|||
#include "ardour/midi_track.h"
|
||||
#include "ardour/pan_controllable.h"
|
||||
#include "ardour/pannable.h"
|
||||
#include "ardour/plugin.h"
|
||||
#include "ardour/plugin_insert.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/uri_map.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
|
@ -146,9 +148,9 @@ Automatable::add_control(boost::shared_ptr<Evoral::Control> ac)
|
|||
}
|
||||
|
||||
ControlSet::add_control (ac);
|
||||
_can_automate_list.insert (param);
|
||||
|
||||
if (al) {
|
||||
_can_automate_list.insert (param);
|
||||
automation_list_automation_state_changed (param, al->automation_state ()); // sync everything up
|
||||
}
|
||||
}
|
||||
|
@ -170,6 +172,8 @@ Automatable::describe_parameter (Evoral::Parameter param)
|
|||
return string_compose("Bender [%1]", int(param.channel()) + 1);
|
||||
} else if (param.type() == MidiChannelPressureAutomation) {
|
||||
return string_compose("Pressure [%1]", int(param.channel()) + 1);
|
||||
} else if (param.type() == PluginPropertyAutomation) {
|
||||
return string_compose("Property %1", URIMap::instance().id_to_uri(param.id()));
|
||||
} else {
|
||||
return EventTypeMap::instance().to_symbol(param);
|
||||
}
|
||||
|
@ -251,7 +255,7 @@ Automatable::get_automation_xml_state ()
|
|||
|
||||
for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) {
|
||||
boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(li->second->list());
|
||||
if (!l->empty()) {
|
||||
if (l && !l->empty()) {
|
||||
node->add_child_nocopy (l->get_state ());
|
||||
}
|
||||
}
|
||||
|
@ -394,6 +398,7 @@ Automatable::control_factory(const Evoral::Parameter& param)
|
|||
{
|
||||
boost::shared_ptr<AutomationList> list(new AutomationList(param));
|
||||
Evoral::Control* control = NULL;
|
||||
ParameterDescriptor desc(param);
|
||||
if (param.type() >= MidiCCAutomation && param.type() <= MidiChannelPressureAutomation) {
|
||||
MidiTrack* mt = dynamic_cast<MidiTrack*>(this);
|
||||
if (mt) {
|
||||
|
@ -405,10 +410,24 @@ Automatable::control_factory(const Evoral::Parameter& param)
|
|||
} else if (param.type() == PluginAutomation) {
|
||||
PluginInsert* pi = dynamic_cast<PluginInsert*>(this);
|
||||
if (pi) {
|
||||
control = new PluginInsert::PluginControl(pi, param);
|
||||
pi->plugin(0)->get_parameter_descriptor(param.id(), desc);
|
||||
control = new PluginInsert::PluginControl(pi, param, desc);
|
||||
} else {
|
||||
warning << "PluginAutomation for non-Plugin" << endl;
|
||||
}
|
||||
} else if (param.type() == PluginPropertyAutomation) {
|
||||
PluginInsert* pi = dynamic_cast<PluginInsert*>(this);
|
||||
if (pi) {
|
||||
desc = pi->plugin(0)->get_property_descriptor(param.id());
|
||||
if (desc.datatype != Variant::VOID) {
|
||||
if (!Variant::type_is_numeric(desc.datatype)) {
|
||||
list.reset(); // Can't automate non-numeric data yet
|
||||
}
|
||||
control = new PluginInsert::PluginPropertyControl(pi, param, desc, list);
|
||||
}
|
||||
} else {
|
||||
warning << "PluginPropertyAutomation for non-Plugin" << endl;
|
||||
}
|
||||
} else if (param.type() == GainAutomation) {
|
||||
Amp* amp = dynamic_cast<Amp*>(this);
|
||||
if (amp) {
|
||||
|
@ -426,7 +445,7 @@ Automatable::control_factory(const Evoral::Parameter& param)
|
|||
}
|
||||
|
||||
if (!control) {
|
||||
control = new AutomationControl(_a_session, param);
|
||||
control = new AutomationControl(_a_session, param, desc);
|
||||
}
|
||||
|
||||
control->set_list(list);
|
||||
|
|
|
@ -29,14 +29,15 @@ using namespace std;
|
|||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
AutomationControl::AutomationControl(
|
||||
ARDOUR::Session& session,
|
||||
const Evoral::Parameter& parameter,
|
||||
boost::shared_ptr<ARDOUR::AutomationList> list,
|
||||
const string& name)
|
||||
AutomationControl::AutomationControl(ARDOUR::Session& session,
|
||||
const Evoral::Parameter& parameter,
|
||||
const ParameterDescriptor& desc,
|
||||
boost::shared_ptr<ARDOUR::AutomationList> list,
|
||||
const string& name)
|
||||
: Controllable (name.empty() ? EventTypeMap::instance().to_symbol(parameter) : name)
|
||||
, Evoral::Control(parameter, list)
|
||||
, _session(session)
|
||||
, _desc(desc)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "ardour/midi_buffer.h"
|
||||
#include "ardour/port.h"
|
||||
#include "ardour/port_set.h"
|
||||
#include "ardour/uri_map.h"
|
||||
#ifdef LV2_SUPPORT
|
||||
#include "ardour/lv2_plugin.h"
|
||||
#include "lv2_evbuf.h"
|
||||
|
@ -192,8 +193,8 @@ BufferSet::ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capac
|
|||
_lv2_buffers.push_back(
|
||||
std::make_pair(false, lv2_evbuf_new(buffer_capacity,
|
||||
LV2_EVBUF_EVENT,
|
||||
LV2Plugin::urids.atom_Chunk,
|
||||
LV2Plugin::urids.atom_Sequence)));
|
||||
URIMap::instance().urids.atom_Chunk,
|
||||
URIMap::instance().urids.atom_Sequence)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -267,8 +268,8 @@ BufferSet::ensure_lv2_bufsize(bool input, size_t i, size_t buffer_capacity)
|
|||
std::make_pair(false, lv2_evbuf_new(
|
||||
buffer_capacity,
|
||||
LV2_EVBUF_EVENT,
|
||||
LV2Plugin::urids.atom_Chunk,
|
||||
LV2Plugin::urids.atom_Sequence));
|
||||
URIMap::instance().urids.atom_Chunk,
|
||||
URIMap::instance().urids.atom_Sequence));
|
||||
}
|
||||
|
||||
LV2_Evbuf*
|
||||
|
@ -297,7 +298,7 @@ BufferSet::forward_lv2_midi(LV2_Evbuf* buf, size_t i, bool purge_ardour_buffer)
|
|||
uint32_t frames, subframes, type, size;
|
||||
uint8_t* data;
|
||||
lv2_evbuf_get(i, &frames, &subframes, &type, &size, &data);
|
||||
if (type == LV2Plugin::urids.midi_MidiEvent) {
|
||||
if (type == URIMap::instance().urids.midi_MidiEvent) {
|
||||
mbuf.push_back(frames, size, data);
|
||||
}
|
||||
}
|
||||
|
@ -326,7 +327,7 @@ BufferSet::flush_lv2_midi(bool input, size_t i)
|
|||
DEBUG_TRACE (PBD::DEBUG::LV2, string_compose ("\tByte[%1] = %2\n", x, (int) data[x]));
|
||||
}
|
||||
#endif
|
||||
if (type == LV2Plugin::urids.midi_MidiEvent) {
|
||||
if (type == URIMap::instance().urids.midi_MidiEvent) {
|
||||
// TODO: Make Ardour event buffers generic so plugins can communicate
|
||||
mbuf.push_back(frames, size, data);
|
||||
}
|
||||
|
|
|
@ -137,6 +137,7 @@ setup_enum_writer ()
|
|||
REGISTER_ENUM (PanElevationAutomation);
|
||||
REGISTER_ENUM (PanWidthAutomation);
|
||||
REGISTER_ENUM (PluginAutomation);
|
||||
REGISTER_ENUM (PluginPropertyAutomation);
|
||||
REGISTER_ENUM (SoloAutomation);
|
||||
REGISTER_ENUM (MuteAutomation);
|
||||
REGISTER_ENUM (MidiCCAutomation);
|
||||
|
|
|
@ -18,9 +18,12 @@
|
|||
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <cstdio>
|
||||
#include "ardour/types.h"
|
||||
#include "ardour/event_type_map.h"
|
||||
#include "ardour/parameter_types.h"
|
||||
#include "ardour/uri_map.h"
|
||||
#include "evoral/Parameter.hpp"
|
||||
#include "evoral/midi_events.h"
|
||||
#include "evoral/MIDIParameters.hpp"
|
||||
|
@ -31,44 +34,58 @@ using namespace std;
|
|||
|
||||
namespace ARDOUR {
|
||||
|
||||
EventTypeMap EventTypeMap::event_type_map;
|
||||
EventTypeMap* EventTypeMap::event_type_map;
|
||||
|
||||
EventTypeMap&
|
||||
EventTypeMap::instance()
|
||||
{
|
||||
if (!EventTypeMap::event_type_map) {
|
||||
EventTypeMap::event_type_map = new EventTypeMap(URIMap::instance());
|
||||
|
||||
// Initialize parameter metadata
|
||||
EventTypeMap::event_type_map->new_parameter(NullAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(GainAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(PanAzimuthAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(PanElevationAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(PanWidthAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(PluginAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(PluginPropertyAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(SoloAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(MuteAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(MidiCCAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(MidiPgmChangeAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(MidiPitchBenderAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(MidiChannelPressureAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(FadeInAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(FadeOutAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(EnvelopeAutomation);
|
||||
EventTypeMap::event_type_map->new_parameter(MidiCCAutomation);
|
||||
}
|
||||
return *EventTypeMap::event_type_map;
|
||||
}
|
||||
|
||||
bool
|
||||
EventTypeMap::type_is_midi(uint32_t type) const
|
||||
{
|
||||
return (type >= MidiCCAutomation) && (type <= MidiChannelPressureAutomation);
|
||||
return ARDOUR::parameter_is_midi((AutomationType)type);
|
||||
}
|
||||
|
||||
bool
|
||||
EventTypeMap::is_midi_parameter(const Evoral::Parameter& param)
|
||||
{
|
||||
return type_is_midi(param.type());
|
||||
return type_is_midi(param.type());
|
||||
}
|
||||
|
||||
uint8_t
|
||||
EventTypeMap::parameter_midi_type(const Evoral::Parameter& param) const
|
||||
{
|
||||
switch (param.type()) {
|
||||
case MidiCCAutomation: return MIDI_CMD_CONTROL; break;
|
||||
case MidiPgmChangeAutomation: return MIDI_CMD_PGM_CHANGE; break;
|
||||
case MidiChannelPressureAutomation: return MIDI_CMD_CHANNEL_PRESSURE; break;
|
||||
case MidiPitchBenderAutomation: return MIDI_CMD_BENDER; break;
|
||||
case MidiSystemExclusiveAutomation: return MIDI_CMD_COMMON_SYSEX; break;
|
||||
default: return 0;
|
||||
}
|
||||
return ARDOUR::parameter_midi_type((AutomationType)param.type());
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EventTypeMap::midi_event_type(uint8_t status) const
|
||||
{
|
||||
switch (status & 0xF0) {
|
||||
case MIDI_CMD_CONTROL: return MidiCCAutomation; break;
|
||||
case MIDI_CMD_PGM_CHANGE: return MidiPgmChangeAutomation; break;
|
||||
case MIDI_CMD_CHANNEL_PRESSURE: return MidiChannelPressureAutomation; break;
|
||||
case MIDI_CMD_BENDER: return MidiPitchBenderAutomation; break;
|
||||
case MIDI_CMD_COMMON_SYSEX: return MidiSystemExclusiveAutomation; break;
|
||||
default: return 0;
|
||||
}
|
||||
return (uint32_t)ARDOUR::midi_parameter_type(status);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -182,6 +199,8 @@ EventTypeMap::new_parameter(uint32_t type, uint8_t channel, uint32_t id) const
|
|||
Evoral::MIDI::bender_range(min, max, normal); break;
|
||||
case MidiSystemExclusiveAutomation:
|
||||
return p;
|
||||
case PluginPropertyAutomation:
|
||||
return p;
|
||||
}
|
||||
|
||||
p.set_range(type, min, max, normal, false);
|
||||
|
@ -220,6 +239,14 @@ EventTypeMap::new_parameter(const string& str) const
|
|||
} else if (str.length() > 10 && str.substr(0, 10) == "parameter-") {
|
||||
p_type = PluginAutomation;
|
||||
p_id = atoi(str.c_str()+10);
|
||||
} else if (str.length() > 9 && str.substr(0, 9) == "property-") {
|
||||
p_type = PluginPropertyAutomation;
|
||||
const char* name = str.c_str() + 9;
|
||||
if (isdigit(str.c_str()[0])) {
|
||||
p_id = atoi(name);
|
||||
} else {
|
||||
p_id = _uri_map.uri_to_id(name);
|
||||
}
|
||||
} else if (str.length() > 7 && str.substr(0, 7) == "midicc-") {
|
||||
p_type = MidiCCAutomation;
|
||||
uint32_t channel = 0;
|
||||
|
@ -286,6 +313,13 @@ EventTypeMap::to_symbol(const Evoral::Parameter& param) const
|
|||
return "envelope";
|
||||
} else if (t == PluginAutomation) {
|
||||
return string_compose("parameter-%1", param.id());
|
||||
} else if (t == PluginPropertyAutomation) {
|
||||
const char* uri = _uri_map.id_to_uri(param.id());
|
||||
if (uri) {
|
||||
return string_compose("property-%1", uri);
|
||||
} else {
|
||||
return string_compose("property-%1", param.id());
|
||||
}
|
||||
} else if (t == MidiCCAutomation) {
|
||||
return string_compose("midicc-%1-%2", int(param.channel()), param.id());
|
||||
} else if (t == MidiPgmChangeAutomation) {
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
#include "ardour/audioregion.h"
|
||||
#include "ardour/buffer_manager.h"
|
||||
#include "ardour/control_protocol_manager.h"
|
||||
#include "ardour/event_type_map.h"
|
||||
#include "ardour/filesystem_paths.h"
|
||||
#include "ardour/midi_region.h"
|
||||
#include "ardour/midiport_manager.h"
|
||||
|
@ -100,6 +101,7 @@
|
|||
#include "ardour/runtime_functions.h"
|
||||
#include "ardour/session_event.h"
|
||||
#include "ardour/source_factory.h"
|
||||
#include "ardour/uri_map.h"
|
||||
|
||||
#include "audiographer/routines.h"
|
||||
|
||||
|
@ -319,8 +321,10 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir
|
|||
SourceFactory::init ();
|
||||
Analyser::init ();
|
||||
|
||||
/* singleton - first object is "it" */
|
||||
/* singletons - first object is "it" */
|
||||
(void) PluginManager::instance();
|
||||
(void) URIMap::instance();
|
||||
(void) EventTypeMap::instance();
|
||||
|
||||
ProcessThread::init ();
|
||||
/* the + 4 is a bit of a handwave. i don't actually know
|
||||
|
@ -331,24 +335,6 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir
|
|||
|
||||
PannerManager::instance().discover_panners();
|
||||
|
||||
// Initialize parameter metadata
|
||||
EventTypeMap::instance().new_parameter(NullAutomation);
|
||||
EventTypeMap::instance().new_parameter(GainAutomation);
|
||||
EventTypeMap::instance().new_parameter(PanAzimuthAutomation);
|
||||
EventTypeMap::instance().new_parameter(PanElevationAutomation);
|
||||
EventTypeMap::instance().new_parameter(PanWidthAutomation);
|
||||
EventTypeMap::instance().new_parameter(PluginAutomation);
|
||||
EventTypeMap::instance().new_parameter(SoloAutomation);
|
||||
EventTypeMap::instance().new_parameter(MuteAutomation);
|
||||
EventTypeMap::instance().new_parameter(MidiCCAutomation);
|
||||
EventTypeMap::instance().new_parameter(MidiPgmChangeAutomation);
|
||||
EventTypeMap::instance().new_parameter(MidiPitchBenderAutomation);
|
||||
EventTypeMap::instance().new_parameter(MidiChannelPressureAutomation);
|
||||
EventTypeMap::instance().new_parameter(FadeInAutomation);
|
||||
EventTypeMap::instance().new_parameter(FadeOutAutomation);
|
||||
EventTypeMap::instance().new_parameter(EnvelopeAutomation);
|
||||
EventTypeMap::instance().new_parameter(MidiCCAutomation);
|
||||
|
||||
ARDOUR::AudioEngine::create ();
|
||||
|
||||
libardour_initialized = true;
|
||||
|
|
|
@ -97,34 +97,6 @@ using namespace std;
|
|||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
URIMap LV2Plugin::_uri_map;
|
||||
|
||||
LV2Plugin::URIDs LV2Plugin::urids = {
|
||||
_uri_map.uri_to_id(LV2_ATOM__Chunk),
|
||||
_uri_map.uri_to_id(LV2_ATOM__Path),
|
||||
_uri_map.uri_to_id(LV2_ATOM__Sequence),
|
||||
_uri_map.uri_to_id(LV2_ATOM__eventTransfer),
|
||||
_uri_map.uri_to_id(LV2_ATOM__URID),
|
||||
_uri_map.uri_to_id(LV2_ATOM__Blank),
|
||||
_uri_map.uri_to_id(LV2_ATOM__Object),
|
||||
_uri_map.uri_to_id(LV2_LOG__Error),
|
||||
_uri_map.uri_to_id(LV2_LOG__Note),
|
||||
_uri_map.uri_to_id(LV2_LOG__Warning),
|
||||
_uri_map.uri_to_id(LV2_MIDI__MidiEvent),
|
||||
_uri_map.uri_to_id(LV2_TIME__Position),
|
||||
_uri_map.uri_to_id(LV2_TIME__bar),
|
||||
_uri_map.uri_to_id(LV2_TIME__barBeat),
|
||||
_uri_map.uri_to_id(LV2_TIME__beatUnit),
|
||||
_uri_map.uri_to_id(LV2_TIME__beatsPerBar),
|
||||
_uri_map.uri_to_id(LV2_TIME__beatsPerMinute),
|
||||
_uri_map.uri_to_id(LV2_TIME__frame),
|
||||
_uri_map.uri_to_id(LV2_TIME__speed),
|
||||
_uri_map.uri_to_id(LV2_PATCH__Get),
|
||||
_uri_map.uri_to_id(LV2_PATCH__Set),
|
||||
_uri_map.uri_to_id(LV2_PATCH__property),
|
||||
_uri_map.uri_to_id(LV2_PATCH__value)
|
||||
};
|
||||
|
||||
class LV2World : boost::noncopyable {
|
||||
public:
|
||||
LV2World ();
|
||||
|
@ -151,6 +123,9 @@ public:
|
|||
LilvNode* lv2_freewheeling;
|
||||
LilvNode* lv2_inPlaceBroken;
|
||||
LilvNode* lv2_integer;
|
||||
LilvNode* lv2_default;
|
||||
LilvNode* lv2_minimum;
|
||||
LilvNode* lv2_maximum;
|
||||
LilvNode* lv2_reportsLatency;
|
||||
LilvNode* lv2_sampleRate;
|
||||
LilvNode* lv2_toggled;
|
||||
|
@ -220,11 +195,11 @@ log_vprintf(LV2_Log_Handle /*handle*/,
|
|||
{
|
||||
char* str = NULL;
|
||||
const int ret = g_vasprintf(&str, fmt, args);
|
||||
if (type == LV2Plugin::urids.log_Error) {
|
||||
if (type == URIMap::instance().urids.log_Error) {
|
||||
error << str << endmsg;
|
||||
} else if (type == LV2Plugin::urids.log_Warning) {
|
||||
} else if (type == URIMap::instance().urids.log_Warning) {
|
||||
warning << str << endmsg;
|
||||
} else if (type == LV2Plugin::urids.log_Note) {
|
||||
} else if (type == URIMap::instance().urids.log_Note) {
|
||||
info << str << endmsg;
|
||||
}
|
||||
// TODO: Toggleable log:Trace message support
|
||||
|
@ -278,6 +253,7 @@ LV2Plugin::LV2Plugin (AudioEngine& engine,
|
|||
, _insert_id("0")
|
||||
, _patch_port_in_index((uint32_t)-1)
|
||||
, _patch_port_out_index((uint32_t)-1)
|
||||
, _uri_map(URIMap::instance())
|
||||
{
|
||||
init(c_plugin, rate);
|
||||
}
|
||||
|
@ -291,6 +267,7 @@ LV2Plugin::LV2Plugin (const LV2Plugin& other)
|
|||
, _insert_id(other._insert_id)
|
||||
, _patch_port_in_index((uint32_t)-1)
|
||||
, _patch_port_out_index((uint32_t)-1)
|
||||
, _uri_map(URIMap::instance())
|
||||
{
|
||||
init(other._impl->plugin, other._sample_rate);
|
||||
|
||||
|
@ -613,6 +590,7 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
|
|||
}
|
||||
}
|
||||
|
||||
load_supported_properties(_property_descriptors);
|
||||
allocate_atom_event_buffers();
|
||||
latency_compute_run();
|
||||
}
|
||||
|
@ -1021,7 +999,7 @@ set_port_value(const char* port_symbol,
|
|||
uint32_t type)
|
||||
{
|
||||
LV2Plugin* self = (LV2Plugin*)user_data;
|
||||
if (type != 0 && type != self->_uri_map.uri_to_id(LV2_ATOM__Float)) {
|
||||
if (type != 0 && type != URIMap::instance().urids.atom_Float) {
|
||||
return; // TODO: Support non-float ports
|
||||
}
|
||||
|
||||
|
@ -1302,15 +1280,15 @@ LV2Plugin::set_property(uint32_t key, const Variant& value)
|
|||
|
||||
// Serialize patch:Set message to set property
|
||||
#ifdef HAVE_LV2_1_10_0
|
||||
lv2_atom_forge_object(forge, &frame, 1, LV2Plugin::urids.patch_Set);
|
||||
lv2_atom_forge_key(forge, LV2Plugin::urids.patch_property);
|
||||
lv2_atom_forge_object(forge, &frame, 1, _uri_map.urids.patch_Set);
|
||||
lv2_atom_forge_key(forge, _uri_map.urids.patch_property);
|
||||
lv2_atom_forge_urid(forge, key);
|
||||
lv2_atom_forge_key(forge, LV2Plugin::urids.patch_value);
|
||||
lv2_atom_forge_key(forge, _uri_map.urids.patch_value);
|
||||
#else
|
||||
lv2_atom_forge_blank(forge, &frame, 1, LV2Plugin::urids.patch_Set);
|
||||
lv2_atom_forge_property_head(forge, LV2Plugin::urids.patch_property, 0);
|
||||
lv2_atom_forge_blank(forge, &frame, 1, _uri_map.urids.patch_Set);
|
||||
lv2_atom_forge_property_head(forge, _uri_map.urids.patch_property, 0);
|
||||
lv2_atom_forge_urid(forge, key);
|
||||
lv2_atom_forge_property_head(forge, LV2Plugin::urids.patch_value, 0);
|
||||
lv2_atom_forge_property_head(forge, _uri_map.urids.patch_value, 0);
|
||||
#endif
|
||||
|
||||
forge_variant(forge, value);
|
||||
|
@ -1318,13 +1296,51 @@ LV2Plugin::set_property(uint32_t key, const Variant& value)
|
|||
// Write message to UI=>Plugin ring
|
||||
const LV2_Atom* const atom = (const LV2_Atom*)buf;
|
||||
write_from_ui(_patch_port_in_index,
|
||||
LV2Plugin::urids.atom_eventTransfer,
|
||||
_uri_map.urids.atom_eventTransfer,
|
||||
lv2_atom_total_size(atom),
|
||||
(const uint8_t*)atom);
|
||||
}
|
||||
|
||||
const ParameterDescriptor&
|
||||
LV2Plugin::get_property_descriptor(uint32_t id) const
|
||||
{
|
||||
PropertyDescriptors::const_iterator p = _property_descriptors.find(id);
|
||||
if (p != _property_descriptors.end()) {
|
||||
return p->second;
|
||||
}
|
||||
return Plugin::get_property_descriptor(id);
|
||||
}
|
||||
|
||||
static void
|
||||
set_parameter_descriptor(LV2World& world,
|
||||
ParameterDescriptor& desc,
|
||||
Variant::Type datatype,
|
||||
const LilvNode* subject)
|
||||
{
|
||||
LilvWorld* lworld = _world.world;
|
||||
LilvNode* label = lilv_world_get(lworld, subject, _world.rdfs_label, NULL);
|
||||
LilvNode* def = lilv_world_get(lworld, subject, _world.lv2_default, NULL);
|
||||
LilvNode* minimum = lilv_world_get(lworld, subject, _world.lv2_minimum, NULL);
|
||||
LilvNode* maximum = lilv_world_get(lworld, subject, _world.lv2_maximum, NULL);
|
||||
if (label) {
|
||||
desc.label = lilv_node_as_string(label);
|
||||
}
|
||||
if (def && lilv_node_is_float(def)) {
|
||||
desc.normal = lilv_node_as_float(def);
|
||||
}
|
||||
if (minimum && lilv_node_is_float(minimum)) {
|
||||
desc.lower = lilv_node_as_float(minimum);
|
||||
}
|
||||
if (maximum && lilv_node_is_float(maximum)) {
|
||||
desc.upper = lilv_node_as_float(maximum);
|
||||
}
|
||||
desc.datatype = datatype;
|
||||
desc.toggled |= datatype == Variant::BOOL;
|
||||
desc.integer_step |= datatype == Variant::INT || datatype == Variant::LONG;
|
||||
}
|
||||
|
||||
void
|
||||
LV2Plugin::get_supported_properties(std::vector<ParameterDescriptor>& descs)
|
||||
LV2Plugin::load_supported_properties(PropertyDescriptors& descs)
|
||||
{
|
||||
LilvWorld* lworld = _world.world;
|
||||
const LilvNode* subject = lilv_plugin_get_uri(_impl->plugin);
|
||||
|
@ -1333,27 +1349,28 @@ LV2Plugin::get_supported_properties(std::vector<ParameterDescriptor>& descs)
|
|||
LILV_FOREACH(nodes, p, properties) {
|
||||
// Get label and range
|
||||
const LilvNode* prop = lilv_nodes_get(properties, p);
|
||||
LilvNode* label = lilv_world_get(lworld, prop, _world.rdfs_label, NULL);
|
||||
LilvNode* range = lilv_world_get(lworld, prop, _world.rdfs_range, NULL);
|
||||
if (!range) {
|
||||
warning << string_compose(_("LV2: property <%1> has no range datatype, ignoring"),
|
||||
lilv_node_as_uri(prop)) << endmsg;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert range to variant type (TODO: support for multiple range types)
|
||||
Variant::Type datatype;
|
||||
if (!uri_to_variant_type(lilv_node_as_uri(range), datatype)) {
|
||||
error << string_compose(_("LV2: unknown variant datatype \"%1\""),
|
||||
lilv_node_as_uri(range));
|
||||
error << string_compose(_("LV2: property <%1> has unsupported datatype <%1>"),
|
||||
lilv_node_as_uri(prop), lilv_node_as_uri(range)) << endmsg;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add description to result
|
||||
ParameterDescriptor desc;
|
||||
desc.key = _uri_map.uri_to_id(lilv_node_as_uri(prop));
|
||||
desc.label = lilv_node_as_string(label);
|
||||
desc.datatype = datatype;
|
||||
desc.toggled = datatype == Variant::BOOL;
|
||||
desc.integer_step = datatype == Variant::INT || datatype == Variant::LONG;
|
||||
descs.push_back(desc);
|
||||
desc.key = _uri_map.uri_to_id(lilv_node_as_uri(prop));
|
||||
desc.datatype = datatype;
|
||||
set_parameter_descriptor(_world, desc, datatype, prop);
|
||||
descs.insert(std::make_pair(desc.key, desc));
|
||||
|
||||
lilv_node_free(label);
|
||||
lilv_node_free(range);
|
||||
}
|
||||
lilv_nodes_free(properties);
|
||||
|
@ -1375,15 +1392,15 @@ LV2Plugin::announce_property_values()
|
|||
|
||||
// Serialize patch:Get message with no subject (implicitly plugin instance)
|
||||
#ifdef HAVE_LV2_1_10_0
|
||||
lv2_atom_forge_object(forge, &frame, 1, LV2Plugin::urids.patch_Get);
|
||||
lv2_atom_forge_object(forge, &frame, 1, _uri_map.urids.patch_Get);
|
||||
#else
|
||||
lv2_atom_forge_blank(forge, &frame, 1, LV2Plugin::urids.patch_Get);
|
||||
lv2_atom_forge_blank(forge, &frame, 1, _uri_map.urids.patch_Get);
|
||||
#endif
|
||||
|
||||
// Write message to UI=>Plugin ring
|
||||
const LV2_Atom* const atom = (const LV2_Atom*)buf;
|
||||
write_from_ui(_patch_port_in_index,
|
||||
LV2Plugin::urids.atom_eventTransfer,
|
||||
_uri_map.urids.atom_eventTransfer,
|
||||
lv2_atom_total_size(atom),
|
||||
(const uint8_t*)atom);
|
||||
}
|
||||
|
@ -1532,6 +1549,11 @@ int
|
|||
LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) const
|
||||
{
|
||||
const LilvPort* port = lilv_plugin_get_port_by_index(_impl->plugin, which);
|
||||
if (!port) {
|
||||
error << string_compose("LV2: get descriptor of non-existent port %1", which)
|
||||
<< endmsg;
|
||||
return 1;
|
||||
}
|
||||
|
||||
LilvNodes* portunits;
|
||||
LilvNode *def, *min, *max;
|
||||
|
@ -1628,6 +1650,11 @@ LV2Plugin::automatable() const
|
|||
}
|
||||
}
|
||||
|
||||
for (PropertyDescriptors::const_iterator p = _property_descriptors.begin();
|
||||
p != _property_descriptors.end();
|
||||
++p) {
|
||||
ret.insert(ret.end(), Evoral::Parameter(PluginPropertyAutomation, 0, p->first));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1716,7 +1743,7 @@ LV2Plugin::allocate_atom_event_buffers()
|
|||
_atom_ev_buffers = (LV2_Evbuf**) malloc((total_atom_buffers + 1) * sizeof(LV2_Evbuf*));
|
||||
for (int i = 0; i < total_atom_buffers; ++i ) {
|
||||
_atom_ev_buffers[i] = lv2_evbuf_new(minimumSize, LV2_EVBUF_ATOM,
|
||||
LV2Plugin::urids.atom_Chunk, LV2Plugin::urids.atom_Sequence);
|
||||
_uri_map.urids.atom_Chunk, _uri_map.urids.atom_Sequence);
|
||||
}
|
||||
_atom_ev_buffers[total_atom_buffers] = 0;
|
||||
return;
|
||||
|
@ -1734,42 +1761,44 @@ write_position(LV2_Atom_Forge* forge,
|
|||
framepos_t position,
|
||||
framecnt_t offset)
|
||||
{
|
||||
const URIMap::URIDs& urids = URIMap::instance().urids;
|
||||
|
||||
uint8_t pos_buf[256];
|
||||
lv2_atom_forge_set_buffer(forge, pos_buf, sizeof(pos_buf));
|
||||
LV2_Atom_Forge_Frame frame;
|
||||
#ifdef HAVE_LV2_1_10_0
|
||||
lv2_atom_forge_object(forge, &frame, 1, LV2Plugin::urids.time_Position);
|
||||
lv2_atom_forge_key(forge, LV2Plugin::urids.time_frame);
|
||||
lv2_atom_forge_object(forge, &frame, 1, urids.time_Position);
|
||||
lv2_atom_forge_key(forge, urids.time_frame);
|
||||
lv2_atom_forge_long(forge, position);
|
||||
lv2_atom_forge_key(forge, LV2Plugin::urids.time_speed);
|
||||
lv2_atom_forge_key(forge, urids.time_speed);
|
||||
lv2_atom_forge_float(forge, speed);
|
||||
lv2_atom_forge_key(forge, LV2Plugin::urids.time_barBeat);
|
||||
lv2_atom_forge_key(forge, urids.time_barBeat);
|
||||
lv2_atom_forge_float(forge, bbt.beats - 1 +
|
||||
(bbt.ticks / Timecode::BBT_Time::ticks_per_beat));
|
||||
lv2_atom_forge_key(forge, LV2Plugin::urids.time_bar);
|
||||
lv2_atom_forge_key(forge, urids.time_bar);
|
||||
lv2_atom_forge_long(forge, bbt.bars - 1);
|
||||
lv2_atom_forge_key(forge, LV2Plugin::urids.time_beatUnit);
|
||||
lv2_atom_forge_key(forge, urids.time_beatUnit);
|
||||
lv2_atom_forge_int(forge, t.meter().note_divisor());
|
||||
lv2_atom_forge_key(forge, LV2Plugin::urids.time_beatsPerBar);
|
||||
lv2_atom_forge_key(forge, urids.time_beatsPerBar);
|
||||
lv2_atom_forge_float(forge, t.meter().divisions_per_bar());
|
||||
lv2_atom_forge_key(forge, LV2Plugin::urids.time_beatsPerMinute);
|
||||
lv2_atom_forge_key(forge, urids.time_beatsPerMinute);
|
||||
lv2_atom_forge_float(forge, t.tempo().beats_per_minute());
|
||||
#else
|
||||
lv2_atom_forge_blank(forge, &frame, 1, LV2Plugin::urids.time_Position);
|
||||
lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_frame, 0);
|
||||
lv2_atom_forge_blank(forge, &frame, 1, urids.time_Position);
|
||||
lv2_atom_forge_property_head(forge, urids.time_frame, 0);
|
||||
lv2_atom_forge_long(forge, position);
|
||||
lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_speed, 0);
|
||||
lv2_atom_forge_property_head(forge, urids.time_speed, 0);
|
||||
lv2_atom_forge_float(forge, speed);
|
||||
lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_barBeat, 0);
|
||||
lv2_atom_forge_property_head(forge, urids.time_barBeat, 0);
|
||||
lv2_atom_forge_float(forge, bbt.beats - 1 +
|
||||
(bbt.ticks / Timecode::BBT_Time::ticks_per_beat));
|
||||
lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_bar, 0);
|
||||
lv2_atom_forge_property_head(forge, urids.time_bar, 0);
|
||||
lv2_atom_forge_long(forge, bbt.bars - 1);
|
||||
lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatUnit, 0);
|
||||
lv2_atom_forge_property_head(forge, urids.time_beatUnit, 0);
|
||||
lv2_atom_forge_int(forge, t.meter().note_divisor());
|
||||
lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatsPerBar, 0);
|
||||
lv2_atom_forge_property_head(forge, urids.time_beatsPerBar, 0);
|
||||
lv2_atom_forge_float(forge, t.meter().divisions_per_bar());
|
||||
lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatsPerMinute, 0);
|
||||
lv2_atom_forge_property_head(forge, urids.time_beatsPerMinute, 0);
|
||||
lv2_atom_forge_float(forge, t.tempo().beats_per_minute());
|
||||
#endif
|
||||
|
||||
|
@ -1880,7 +1909,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||
: m;
|
||||
|
||||
// Now merge MIDI and any transport events into the buffer
|
||||
const uint32_t type = LV2Plugin::urids.midi_MidiEvent;
|
||||
const uint32_t type = _uri_map.urids.midi_MidiEvent;
|
||||
const framepos_t tend = _session.transport_frame() + nframes;
|
||||
++metric_i;
|
||||
while (m != m_end || (metric_i != tmap.metrics_end() &&
|
||||
|
@ -1932,7 +1961,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||
error << "Error reading from UI=>Plugin RingBuffer" << endmsg;
|
||||
break;
|
||||
}
|
||||
if (msg.protocol == urids.atom_eventTransfer) {
|
||||
if (msg.protocol == URIMap::instance().urids.atom_eventTransfer) {
|
||||
LV2_Evbuf* buf = _ev_buffers[msg.index];
|
||||
LV2_Evbuf_Iterator i = lv2_evbuf_end(buf);
|
||||
const LV2_Atom* const atom = (const LV2_Atom*)&body[0];
|
||||
|
@ -1998,20 +2027,20 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||
// Intercept patch change messages to emit PropertyChanged signal
|
||||
if ((flags & PORT_PATCHMSG)) {
|
||||
LV2_Atom* atom = (LV2_Atom*)(data - sizeof(LV2_Atom));
|
||||
if (atom->type == LV2Plugin::urids.atom_Blank ||
|
||||
atom->type == LV2Plugin::urids.atom_Object) {
|
||||
if (atom->type == _uri_map.urids.atom_Blank ||
|
||||
atom->type == _uri_map.urids.atom_Object) {
|
||||
LV2_Atom_Object* obj = (LV2_Atom_Object*)atom;
|
||||
if (obj->body.otype == LV2Plugin::urids.patch_Set) {
|
||||
if (obj->body.otype == _uri_map.urids.patch_Set) {
|
||||
const LV2_Atom* property = NULL;
|
||||
const LV2_Atom* value = NULL;
|
||||
lv2_atom_object_get(obj,
|
||||
LV2Plugin::urids.patch_property, &property,
|
||||
LV2Plugin::urids.patch_value, &value,
|
||||
_uri_map.urids.patch_property, &property,
|
||||
_uri_map.urids.patch_value, &value,
|
||||
0);
|
||||
|
||||
if (!property || !value ||
|
||||
property->type != LV2Plugin::urids.atom_URID ||
|
||||
value->type != LV2Plugin::urids.atom_Path) {
|
||||
property->type != _uri_map.urids.atom_URID ||
|
||||
value->type != _uri_map.urids.atom_Path) {
|
||||
std::cerr << "warning: patch:Set for unknown property" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
@ -2020,13 +2049,14 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||
const char* path = (const char*)LV2_ATOM_BODY_CONST(value);
|
||||
|
||||
// Emit PropertyChanged signal for UI
|
||||
// TODO: This should emit the control's Changed signal
|
||||
PropertyChanged(prop_id, Variant(Variant::PATH, path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_to_ui) continue;
|
||||
write_to_ui(port_index, urids.atom_eventTransfer,
|
||||
write_to_ui(port_index, URIMap::instance().urids.atom_eventTransfer,
|
||||
size + sizeof(LV2_Atom),
|
||||
data - sizeof(LV2_Atom));
|
||||
}
|
||||
|
@ -2227,6 +2257,9 @@ LV2World::LV2World()
|
|||
lv2_OutputPort = lilv_new_uri(world, LILV_URI_OUTPUT_PORT);
|
||||
lv2_inPlaceBroken = lilv_new_uri(world, LV2_CORE__inPlaceBroken);
|
||||
lv2_integer = lilv_new_uri(world, LV2_CORE__integer);
|
||||
lv2_default = lilv_new_uri(world, LV2_CORE__default);
|
||||
lv2_minimum = lilv_new_uri(world, LV2_CORE__minimum);
|
||||
lv2_maximum = lilv_new_uri(world, LV2_CORE__maximum);
|
||||
lv2_reportsLatency = lilv_new_uri(world, LV2_CORE__reportsLatency);
|
||||
lv2_sampleRate = lilv_new_uri(world, LV2_CORE__sampleRate);
|
||||
lv2_toggled = lilv_new_uri(world, LV2_CORE__toggled);
|
||||
|
|
|
@ -84,7 +84,8 @@ template<typename Time>
|
|||
struct EventsSortByTimeAndType {
|
||||
bool operator() (Evoral::Event<Time>* a, Evoral::Event<Time>* b) {
|
||||
if (a->time() == b->time()) {
|
||||
if (EventTypeMap::instance().type_is_midi (a->event_type()) && EventTypeMap::instance().type_is_midi (b->event_type())) {
|
||||
if (parameter_is_midi ((AutomationType)a->event_type()) &&
|
||||
parameter_is_midi ((AutomationType)b->event_type())) {
|
||||
/* negate return value since we must return whether
|
||||
* or not a should sort before b, not b before a
|
||||
*/
|
||||
|
|
|
@ -25,9 +25,9 @@
|
|||
#include "evoral/EventSink.hpp"
|
||||
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/event_type_map.h"
|
||||
#include "ardour/midi_source.h"
|
||||
#include "ardour/midi_state_tracker.h"
|
||||
#include "ardour/parameter_types.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
|
@ -162,7 +162,7 @@ MidiStateTracker::resolve_notes (Evoral::EventSink<framepos_t> &dst, framepos_t
|
|||
/* note that we do not care about failure from
|
||||
write() ... should we warn someone ?
|
||||
*/
|
||||
dst.write (time, EventTypeMap::instance().midi_event_type (buf[0]), 3, buf);
|
||||
dst.write (time, midi_parameter_type (buf[0]), 3, buf);
|
||||
_active_notes[note + 128 * channel]--;
|
||||
DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1: EVS-resolved note %2/%3 at %4\n",
|
||||
this, (int) note, (int) channel, time));
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "ardour/midi_playlist.h"
|
||||
#include "ardour/midi_port.h"
|
||||
#include "ardour/midi_track.h"
|
||||
#include "ardour/parameter_types.h"
|
||||
#include "ardour/port.h"
|
||||
#include "ardour/processor.h"
|
||||
#include "ardour/session.h"
|
||||
|
@ -618,7 +619,7 @@ MidiTrack::write_immediate_event(size_t size, const uint8_t* buf)
|
|||
cerr << "WARNING: Ignoring illegal immediate MIDI event" << endl;
|
||||
return false;
|
||||
}
|
||||
const uint32_t type = EventTypeMap::instance().midi_event_type(buf[0]);
|
||||
const uint32_t type = midi_parameter_type(buf[0]);
|
||||
return (_immediate_events.write (0, type, size, buf) == size);
|
||||
}
|
||||
|
||||
|
|
|
@ -256,7 +256,17 @@ PluginInsert::create_automatable_parameters ()
|
|||
param.set_range (desc.lower, desc.upper, _plugins.front()->default_value(i->id()), desc.toggled);
|
||||
can_automate (param);
|
||||
boost::shared_ptr<AutomationList> list(new AutomationList(param));
|
||||
add_control (boost::shared_ptr<AutomationControl> (new PluginControl(this, param, list)));
|
||||
add_control (boost::shared_ptr<AutomationControl> (new PluginControl(this, param, desc, list)));
|
||||
} else if (i->type() == PluginPropertyAutomation) {
|
||||
Evoral::Parameter param(*i);
|
||||
const ParameterDescriptor& desc = _plugins.front()->get_property_descriptor(param.id());
|
||||
if (desc.datatype != Variant::VOID) {
|
||||
boost::shared_ptr<AutomationList> list;
|
||||
if (Variant::type_is_numeric(desc.datatype)) {
|
||||
list = boost::shared_ptr<AutomationList>(new AutomationList(param));
|
||||
}
|
||||
add_control (boost::shared_ptr<AutomationControl> (new PluginPropertyControl(this, param, desc, list)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -368,7 +378,7 @@ PluginInsert::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t of
|
|||
boost::shared_ptr<AutomationControl> c
|
||||
= boost::dynamic_pointer_cast<AutomationControl>(li->second);
|
||||
|
||||
if (c->parameter().type() == PluginAutomation && c->automation_playback()) {
|
||||
if (c->list() && c->automation_playback()) {
|
||||
bool valid;
|
||||
|
||||
const float val = c->list()->rt_safe_eval (now, valid);
|
||||
|
@ -1167,11 +1177,15 @@ PluginInsert::set_parameter_state_2X (const XMLNode& node, int version)
|
|||
string
|
||||
PluginInsert::describe_parameter (Evoral::Parameter param)
|
||||
{
|
||||
if (param.type() != PluginAutomation) {
|
||||
return Automatable::describe_parameter(param);
|
||||
if (param.type() == PluginAutomation) {
|
||||
return _plugins[0]->describe_parameter (param);
|
||||
} else if (param.type() == PluginPropertyAutomation) {
|
||||
boost::shared_ptr<AutomationControl> c(automation_control(param));
|
||||
if (c && !c->desc().label.empty()) {
|
||||
return c->desc().label;
|
||||
}
|
||||
}
|
||||
|
||||
return _plugins[0]->describe_parameter (param);
|
||||
return Automatable::describe_parameter(param);
|
||||
}
|
||||
|
||||
ARDOUR::framecnt_t
|
||||
|
@ -1190,19 +1204,16 @@ PluginInsert::type ()
|
|||
return plugin()->get_info()->type;
|
||||
}
|
||||
|
||||
PluginInsert::PluginControl::PluginControl (PluginInsert* p, const Evoral::Parameter ¶m, boost::shared_ptr<AutomationList> list)
|
||||
: AutomationControl (p->session(), param, list, p->describe_parameter(param))
|
||||
PluginInsert::PluginControl::PluginControl (PluginInsert* p,
|
||||
const Evoral::Parameter& param,
|
||||
const ParameterDescriptor& desc,
|
||||
boost::shared_ptr<AutomationList> list)
|
||||
: AutomationControl (p->session(), param, desc, list, p->describe_parameter(param))
|
||||
, _plugin (p)
|
||||
{
|
||||
ParameterDescriptor desc;
|
||||
boost::shared_ptr<Plugin> plugin = p->plugin (0);
|
||||
|
||||
alist()->reset_default (plugin->default_value (param.id()));
|
||||
|
||||
plugin->get_parameter_descriptor (param.id(), desc);
|
||||
_logarithmic = desc.logarithmic;
|
||||
_sr_dependent = desc.sr_dependent;
|
||||
_toggled = desc.toggled;
|
||||
if (alist()) {
|
||||
alist()->reset_default (desc.normal);
|
||||
}
|
||||
|
||||
if (desc.toggled) {
|
||||
set_flags(Controllable::Toggle);
|
||||
|
@ -1232,7 +1243,7 @@ PluginInsert::PluginControl::internal_to_interface (double val) const
|
|||
{
|
||||
val = Controllable::internal_to_interface(val);
|
||||
|
||||
if (_logarithmic) {
|
||||
if (_desc.logarithmic) {
|
||||
if (val > 0) {
|
||||
val = pow (val, 1/1.5);
|
||||
} else {
|
||||
|
@ -1246,9 +1257,9 @@ PluginInsert::PluginControl::internal_to_interface (double val) const
|
|||
double
|
||||
PluginInsert::PluginControl::interface_to_internal (double val) const
|
||||
{
|
||||
if (_logarithmic) {
|
||||
if (_desc.logarithmic) {
|
||||
if (val <= 0) {
|
||||
val= 0;
|
||||
val = 0;
|
||||
} else {
|
||||
val = pow (val, 1.5);
|
||||
}
|
||||
|
@ -1279,6 +1290,62 @@ PluginInsert::PluginControl::get_value () const
|
|||
return _plugin->get_parameter (_list->parameter());
|
||||
}
|
||||
|
||||
PluginInsert::PluginPropertyControl::PluginPropertyControl (PluginInsert* p,
|
||||
const Evoral::Parameter& param,
|
||||
const ParameterDescriptor& desc,
|
||||
boost::shared_ptr<AutomationList> list)
|
||||
: AutomationControl (p->session(), param, desc, list)
|
||||
, _plugin (p)
|
||||
{
|
||||
if (alist()) {
|
||||
alist()->set_yrange (desc.lower, desc.upper);
|
||||
alist()->reset_default (desc.normal);
|
||||
}
|
||||
|
||||
if (desc.toggled) {
|
||||
set_flags(Controllable::Toggle);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginInsert::PluginPropertyControl::set_value (double user_val)
|
||||
{
|
||||
/* Old numeric set_value(), coerce to appropriate datatype if possible.
|
||||
This is lossy, but better than nothing until Ardour's automation system
|
||||
can handle various datatypes all the way down. */
|
||||
const Variant value(_desc.datatype, user_val);
|
||||
if (value.type() == Variant::VOID) {
|
||||
error << "set_value(double) called for non-numeric property" << endmsg;
|
||||
return;
|
||||
}
|
||||
|
||||
for (Plugins::iterator i = _plugin->_plugins.begin(); i != _plugin->_plugins.end(); ++i) {
|
||||
(*i)->set_property(_list->parameter().id(), value);
|
||||
}
|
||||
|
||||
_value = value;
|
||||
AutomationControl::set_value(user_val);
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
PluginInsert::PluginPropertyControl::get_state ()
|
||||
{
|
||||
stringstream ss;
|
||||
|
||||
XMLNode& node (AutomationControl::get_state());
|
||||
ss << parameter().id();
|
||||
node.add_property (X_("property"), ss.str());
|
||||
node.remove_property (X_("value"));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
double
|
||||
PluginInsert::PluginPropertyControl::get_value () const
|
||||
{
|
||||
return _value.to_double();
|
||||
}
|
||||
|
||||
boost::shared_ptr<Plugin>
|
||||
PluginInsert::get_impulse_analysis_plugin()
|
||||
{
|
||||
|
|
|
@ -3385,8 +3385,10 @@ Route::set_latency_compensation (framecnt_t longest_session_latency)
|
|||
}
|
||||
|
||||
Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr<Route> r)
|
||||
: AutomationControl (r->session(), Evoral::Parameter (SoloAutomation),
|
||||
boost::shared_ptr<AutomationList>(), name)
|
||||
: AutomationControl (r->session(),
|
||||
Evoral::Parameter (SoloAutomation),
|
||||
ParameterDescriptor(Evoral::Parameter (SoloAutomation)),
|
||||
boost::shared_ptr<AutomationList>(), name)
|
||||
, _route (r)
|
||||
{
|
||||
boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloAutomation)));
|
||||
|
@ -3430,8 +3432,11 @@ Route::SoloControllable::get_value () const
|
|||
}
|
||||
|
||||
Route::MuteControllable::MuteControllable (std::string name, boost::shared_ptr<Route> r)
|
||||
: AutomationControl (r->session(), Evoral::Parameter (MuteAutomation),
|
||||
boost::shared_ptr<AutomationList>(), name)
|
||||
: AutomationControl (r->session(),
|
||||
Evoral::Parameter (MuteAutomation),
|
||||
ParameterDescriptor (Evoral::Parameter (MuteAutomation)),
|
||||
boost::shared_ptr<AutomationList>(),
|
||||
name)
|
||||
, _route (r)
|
||||
{
|
||||
boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(MuteAutomation)));
|
||||
|
|
|
@ -37,10 +37,10 @@
|
|||
#include "evoral/Control.hpp"
|
||||
#include "evoral/SMF.hpp"
|
||||
|
||||
#include "ardour/event_type_map.h"
|
||||
#include "ardour/midi_model.h"
|
||||
#include "ardour/midi_ring_buffer.h"
|
||||
#include "ardour/midi_state_tracker.h"
|
||||
#include "ardour/parameter_types.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/smf_source.h"
|
||||
#include "ardour/debug.h"
|
||||
|
@ -263,7 +263,7 @@ SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination,
|
|||
continue;
|
||||
}
|
||||
|
||||
ev_type = EventTypeMap::instance().midi_event_type(ev_buffer[0]);
|
||||
ev_type = midi_parameter_type(ev_buffer[0]);
|
||||
|
||||
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked delta %1, time %2, buf[0] %3, type %4\n",
|
||||
ev_delta_t, time, ev_buffer[0], ev_type));
|
||||
|
@ -361,7 +361,7 @@ SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source,
|
|||
time -= position;
|
||||
|
||||
ev.set(buf, size, time);
|
||||
ev.set_event_type(EventTypeMap::instance().midi_event_type(ev.buffer()[0]));
|
||||
ev.set_event_type(midi_parameter_type(ev.buffer()[0]));
|
||||
ev.set_id(Evoral::next_event_id());
|
||||
|
||||
if (!(ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex())) {
|
||||
|
@ -645,7 +645,7 @@ SMFSource::load_model (bool lock, bool force_reload)
|
|||
if (!have_event_id) {
|
||||
event_id = Evoral::next_event_id();
|
||||
}
|
||||
uint32_t event_type = EventTypeMap::instance().midi_event_type(buf[0]);
|
||||
uint32_t event_type = midi_parameter_type(buf[0]);
|
||||
double event_time = time / (double) ppqn();
|
||||
#ifndef NDEBUG
|
||||
std::string ss;
|
||||
|
|
|
@ -178,7 +178,11 @@ Track::freeze_state() const
|
|||
}
|
||||
|
||||
Track::RecEnableControl::RecEnableControl (boost::shared_ptr<Track> t)
|
||||
: AutomationControl (t->session(), RecEnableAutomation, boost::shared_ptr<AutomationList>(), X_("recenable"))
|
||||
: AutomationControl (t->session(),
|
||||
RecEnableAutomation,
|
||||
ParameterDescriptor(Evoral::Parameter(RecEnableAutomation)),
|
||||
boost::shared_ptr<AutomationList>(),
|
||||
X_("recenable"))
|
||||
, track (t)
|
||||
{
|
||||
boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(RecEnableAutomation)));
|
||||
|
|
|
@ -30,6 +30,47 @@
|
|||
|
||||
namespace ARDOUR {
|
||||
|
||||
URIMap* URIMap::uri_map;
|
||||
|
||||
void
|
||||
URIMap::URIDs::init(URIMap& uri_map)
|
||||
{
|
||||
// Use string literals here instead of LV2 defines to avoid LV2 dependency
|
||||
atom_Chunk = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Chunk");
|
||||
atom_Path = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Path");
|
||||
atom_Sequence = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Sequence");
|
||||
atom_eventTransfer = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#eventTransfer");
|
||||
atom_URID = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#URID");
|
||||
atom_Blank = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Blank");
|
||||
atom_Object = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Object");
|
||||
atom_Float = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Float");
|
||||
log_Error = uri_map.uri_to_id("http://lv2plug.in/ns/ext/log#Error");
|
||||
log_Note = uri_map.uri_to_id("http://lv2plug.in/ns/ext/log#Note");
|
||||
log_Warning = uri_map.uri_to_id("http://lv2plug.in/ns/ext/log#Warning");
|
||||
midi_MidiEvent = uri_map.uri_to_id("http://lv2plug.in/ns/ext/midi#MidiEvent");
|
||||
time_Position = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#Position");
|
||||
time_bar = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#bar");
|
||||
time_barBeat = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#barBeat");
|
||||
time_beatUnit = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#beatUnit");
|
||||
time_beatsPerBar = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#beatsPerBar");
|
||||
time_beatsPerMinute = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#beatsPerMinute");
|
||||
time_frame = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#frame");
|
||||
time_speed = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#speed");
|
||||
patch_Get = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#Get");
|
||||
patch_Set = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#Set");
|
||||
patch_property = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#property");
|
||||
patch_value = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#value");
|
||||
}
|
||||
|
||||
URIMap&
|
||||
URIMap::instance()
|
||||
{
|
||||
if (!URIMap::uri_map) {
|
||||
URIMap::uri_map = new URIMap();
|
||||
}
|
||||
return *URIMap::uri_map;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
c_uri_map_uri_to_id(LV2_URI_Map_Callback_Data callback_data,
|
||||
const char* map,
|
||||
|
@ -62,7 +103,7 @@ c_urid_map(LV2_URID_Map_Handle handle,
|
|||
|
||||
static const char*
|
||||
c_urid_unmap(LV2_URID_Unmap_Handle handle,
|
||||
LV2_URID urid)
|
||||
LV2_URID urid)
|
||||
{
|
||||
URIMap* const me = (URIMap*)handle;
|
||||
return me->id_to_uri(urid);
|
||||
|
@ -84,11 +125,15 @@ URIMap::URIMap()
|
|||
_urid_unmap_feature_data.handle = this;
|
||||
_urid_unmap_feature.URI = LV2_URID_UNMAP_URI;
|
||||
_urid_unmap_feature.data = &_urid_unmap_feature_data;
|
||||
|
||||
urids.init(*this);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
URIMap::uri_to_id(const char* uri)
|
||||
{
|
||||
Glib::Threads::Mutex::Lock lm (_lock);
|
||||
|
||||
const std::string urimm(uri);
|
||||
const Map::const_iterator i = _map.find(urimm);
|
||||
if (i != _map.end()) {
|
||||
|
@ -103,6 +148,8 @@ URIMap::uri_to_id(const char* uri)
|
|||
const char*
|
||||
URIMap::id_to_uri(const uint32_t id) const
|
||||
{
|
||||
Glib::Threads::Mutex::Lock lm (_lock);
|
||||
|
||||
const Unmap::const_iterator i = _unmap.find(id);
|
||||
return (i != _unmap.end()) ? i->second.c_str() : NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user