#include "pbd/xml++.h"
#include "pbd/enumwriter.h"
+#include "pbd/locale_guard.h"
#include "pbd/memento_command.h"
#include "pbd/stacktrace.h"
-#include "pbd/convert.h"
+#include "pbd/types_convert.h"
#include "pbd/unwind.h"
#include "ardour/amp.h"
#include "ardour/session.h"
#include "ardour/solo_control.h"
#include "ardour/solo_isolate_control.h"
+#include "ardour/types_convert.h"
#include "ardour/unknown_processor.h"
#include "ardour/utils.h"
#include "ardour/vca.h"
: Stripable (sess, name, PresentationInfo (flag))
, GraphNode (sess._process_graph)
, Muteable (sess, name)
- , Automatable (sess)
, _active (true)
, _signal_latency (0)
, _signal_latency_at_amp_position (0)
, _strict_io (false)
, _custom_meter_position_noted (false)
, _pinmgr_proxy (0)
+ , _patch_selector_dialog (0)
{
processor_max_streams.reset();
}
boost::weak_ptr<Route>
Route::weakroute () {
- return boost::weak_ptr<Route> (shared_from_this ());
+ return boost::weak_ptr<Route> (boost::dynamic_pointer_cast<Route> (shared_from_this ()));
}
int
/* add standard controls */
_gain_control.reset (new GainControl (_session, GainAutomation));
- add_control (_gain_control);
-
_trim_control.reset (new GainControl (_session, TrimAutomation));
- add_control (_trim_control);
+ /* While the route has-a gain-control for consistency with Stripable and VCA
+ * ownership is handed over to the Amp Processor which manages the
+ * state of the Control and AutomationList as part of its
+ * Automatable API. -- Don't call add_control () here.
+ */
_solo_control.reset (new SoloControl (_session, X_("solo"), *this, *this));
add_control (_solo_control);
return;
}
- _mute_control->automation_run (start_frame, nframes);
+ automation_run (start_frame, nframes);
/* figure out if we're going to use gain automation */
if (gain_automation_ok) {
//A2 uses the "active" flag in the toplevel redirect node, not in the child plugin/IO
if (i != children.end()) {
if ((prop = (*i)->property (X_("active"))) != 0) {
- if ( string_is_affirmative (prop->value()) && (!_session.get_bypass_all_loaded_plugins () || !processor->display_to_user () ) )
+ if ( string_to<bool> (prop->value()) && (!_session.get_bypass_all_loaded_plugins () || !processor->display_to_user () ) )
processor->activate();
else
processor->deactivate();
loc = _processors.end ();
}
- if (!AudioEngine::instance()->connected()) {
- return 1;
- }
-
if (others.empty()) {
return 0;
}
flags &= mask;
if (flags != None) {
- boost::optional<int> rv = PluginSetup (shared_from_this (), pi, flags); /* EMIT SIGNAL */
+ boost::optional<int> rv = PluginSetup (boost::dynamic_pointer_cast<Route>(shared_from_this ()), pi, flags); /* EMIT SIGNAL */
int mode = rv.get_value_or (0);
switch (mode & 3) {
case 1:
_session.set_deletion_in_progress();
}
+ ProcessorList old_list = _processors;
{
Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
Glib::Threads::RWLock::WriterLock lm (_processor_lock);
_processors = new_list;
configure_processors_unlocked (&err, &lm); // this can't fail
}
+ /* drop references w/o process-lock (I/O procs may re-take it in ~IO() */
+ old_list.clear ();
processor_max_streams.reset();
_have_internal_generator = false;
XMLNode&
Route::state(bool full_state)
{
- LocaleGuard lg;
if (!_session._template_state_dir.empty()) {
foreach_processor (sigc::bind (sigc::mem_fun (*this, &Route::set_plugin_state_dir), _session._template_state_dir));
}
XMLNode *node = new XMLNode("Route");
ProcessorList::iterator i;
- char buf[32];
- id().print (buf, sizeof (buf));
- node->add_property("id", buf);
- node->add_property ("name", _name);
- node->add_property("default-type", _default_type.to_string());
- node->add_property ("strict-io", _strict_io);
+ node->set_property ("id", id ());
+ node->set_property ("name", name());
+ node->set_property ("default-type", _default_type);
+ node->set_property ("strict-io", _strict_io);
node->add_child_nocopy (_presentation_info.get_state());
- node->add_property("active", _active?"yes":"no");
- string p;
- node->add_property("denormal-protection", _denormal_protection?"yes":"no");
- node->add_property("meter-point", enum_2_string (_meter_point));
+ node->set_property ("active", _active);
+ node->set_property ("denormal-protection", _denormal_protection);
+ node->set_property ("meter-point", _meter_point);
- node->add_property("meter-type", enum_2_string (_meter_type));
+ node->set_property ("meter-type", _meter_type);
if (_route_group) {
- node->add_property("route-group", _route_group->name());
+ node->set_property ("route-group", _route_group->name());
}
node->add_child_nocopy (_solo_control->get_state ());
if (_custom_meter_position_noted) {
boost::shared_ptr<Processor> after = _processor_after_last_custom_meter.lock ();
if (after) {
- after->id().print (buf, sizeof (buf));
- node->add_property (X_("processor-after-last-custom-meter"), buf);
+ node->set_property (X_("processor-after-last-custom-meter"), after->id());
}
}
XMLNodeList nlist;
XMLNodeConstIterator niter;
XMLNode *child;
- XMLProperty const * prop;
if (node.name() != "Route"){
error << string_compose(_("Bad node sent to Route::set_state() [%1]"), node.name()) << endmsg;
return -1;
}
- if ((prop = node.property (X_("name"))) != 0) {
- Route::set_name (prop->value());
+ std::string route_name;
+ if (node.get_property (X_("name"), route_name)) {
+ Route::set_name (route_name);
}
set_id (node);
Stripable::set_state (node, version);
- if ((prop = node.property (X_("strict-io"))) != 0) {
- _strict_io = string_is_affirmative (prop->value());
- }
+ node.get_property (X_("strict-io"), _strict_io);
if (is_monitor()) {
/* monitor bus does not get a panner, but if (re)created
child = *niter;
if (child->name() == IO::state_node_name) {
- if ((prop = child->property (X_("direction"))) == 0) {
+ std::string direction;
+ if (!child->get_property (X_("direction"), direction)) {
continue;
}
- if (prop->value() == "Input") {
+ if (direction == "Input") {
_input->set_state (*child, version);
- } else if (prop->value() == "Output") {
+ } else if (direction == "Output") {
_output->set_state (*child, version);
}
}
}
- if ((prop = node.property (X_("meter-point"))) != 0) {
- MeterPoint mp = MeterPoint (string_2_enum (prop->value (), _meter_point));
+ MeterPoint mp;
+ if (node.get_property (X_("meter-point"), mp)) {
set_meter_point (mp, true);
if (_meter) {
_meter->set_display_to_user (_meter_point == MeterCustom);
}
}
- if ((prop = node.property (X_("meter-type"))) != 0) {
- _meter_type = MeterType (string_2_enum (prop->value (), _meter_type));
- }
+ node.get_property (X_("meter-type"), _meter_type);
_initial_io_setup = false;
// this looks up the internal instrument in processors
reset_instrument_info();
- if ((prop = node.property (X_("denormal-protection"))) != 0) {
- set_denormal_protection (string_is_affirmative (prop->value()));
+ bool denormal_protection;
+ if (node.get_property (X_("denormal-protection"), denormal_protection)) {
+ set_denormal_protection (denormal_protection);
}
/* convert old 3001 state */
- if ((prop = node.property (X_("phase-invert"))) != 0) {
- _phase_control->set_phase_invert (boost::dynamic_bitset<> (prop->value ()));
+ std::string phase_invert_str;
+ if (node.get_property (X_("phase-invert"), phase_invert_str)) {
+ _phase_control->set_phase_invert (boost::dynamic_bitset<> (phase_invert_str));
}
- if ((prop = node.property (X_("active"))) != 0) {
- bool yn = string_is_affirmative (prop->value());
- set_active (yn, this);
+ bool is_active;
+ if (node.get_property (X_("active"), is_active)) {
+ set_active (is_active, this);
}
- if ((prop = node.property (X_("processor-after-last-custom-meter"))) != 0) {
- PBD::ID id (prop->value ());
+ std::string id_string;
+ if (node.get_property (X_("processor-after-last-custom-meter"), id_string)) {
+ PBD::ID id (id_string);
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
ProcessorList::const_iterator i = _processors.begin ();
while (i != _processors.end() && (*i)->id() != id) {
_comment = cmt->content();
} else if (child->name() == Controllable::xml_node_name) {
- if ((prop = child->property (X_("name"))) == 0) {
+ std::string control_name;
+ if (!child->get_property (X_("name"), control_name)) {
continue;
}
- if (prop->value() == _gain_control->name()) {
- _gain_control->set_state (*child, version);
- } else if (prop->value() == _solo_control->name()) {
+ if (control_name == _solo_control->name()) {
_solo_control->set_state (*child, version);
- } else if (prop->value() == _solo_safe_control->name()) {
+ } else if (control_name == _solo_safe_control->name()) {
_solo_safe_control->set_state (*child, version);
- } else if (prop->value() == _solo_isolate_control->name()) {
+ } else if (control_name == _solo_isolate_control->name()) {
_solo_isolate_control->set_state (*child, version);
- } else if (prop->value() == _mute_control->name()) {
+ } else if (control_name == _mute_control->name()) {
_mute_control->set_state (*child, version);
- } else if (prop->value() == _phase_control->name()) {
+ } else if (control_name == _phase_control->name()) {
_phase_control->set_state (*child, version);
} else {
- Evoral::Parameter p = EventTypeMap::instance().from_symbol (prop->value());
+ Evoral::Parameter p = EventTypeMap::instance().from_symbol (control_name);
if (p.type () >= MidiCCAutomation && p.type () < MidiSystemExclusiveAutomation) {
boost::shared_ptr<AutomationControl> ac = automation_control (p, true);
if (ac) {
Stripable::set_state (node, version);
if ((prop = node.property (X_("denormal-protection"))) != 0) {
- set_denormal_protection (string_is_affirmative (prop->value()));
+ set_denormal_protection (string_to<bool> (prop->value()));
}
if ((prop = node.property (X_("muted"))) != 0) {
bool first = true;
- bool muted = string_is_affirmative (prop->value());
+ bool muted = string_to<bool> (prop->value());
if (muted) {
if ((prop = node.property (X_("mute-affects-pre-fader"))) != 0) {
- if (string_is_affirmative (prop->value())){
+ if (string_to<bool> (prop->value())){
mute_point = mute_point + "PreFader";
first = false;
}
if ((prop = node.property (X_("mute-affects-post-fader"))) != 0) {
- if (string_is_affirmative (prop->value())){
+ if (string_to<bool> (prop->value())){
if (!first) {
mute_point = mute_point + ",";
if ((prop = node.property (X_("mute-affects-control-outs"))) != 0) {
- if (string_is_affirmative (prop->value())){
+ if (string_to<bool> (prop->value())){
if (!first) {
mute_point = mute_point + ",";
if ((prop = node.property (X_("mute-affects-main-outs"))) != 0) {
- if (string_is_affirmative (prop->value())){
+ if (string_to<bool> (prop->value())){
if (!first) {
mute_point = mute_point + ",";
set_id (*child);
if ((prop = child->property (X_("active"))) != 0) {
- bool yn = string_is_affirmative (prop->value());
+ bool yn = string_to<bool> (prop->value());
_active = !yn; // force switch
set_active (yn, this);
}
}
}
+ ProcessorList old_list = _processors; // keep a copy
{
Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
Glib::Threads::RWLock::WriterLock lm (_processor_lock);
}
}
}
+ /* drop references w/o process-lock (I/O procs may re-take it in ~IO() */
+ old_list.clear ();
reset_instrument_info ();
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
_output->silence (nframes);
+ // update owned automated controllables
+ automation_run (now, nframes);
+
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
boost::shared_ptr<PluginInsert> pi;
if (!_active && (pi = boost::dynamic_pointer_cast<PluginInsert> (*i)) != 0) {
- // skip plugins, they don't need anything when we're not active
+ /* evaluate automated automation controls */
+ pi->automation_run (now, nframes);
+ /* skip plugins, they don't need anything when we're not active */
continue;
}
bool
Route::direct_feeds_according_to_graph (boost::shared_ptr<Route> other, bool* via_send_only)
{
- return _session._current_route_graph.has (shared_from_this (), other, via_send_only);
+ return _session._current_route_graph.has (boost::dynamic_pointer_cast<Route> (shared_from_this ()), other, via_send_only);
}
bool
Route::feeds_according_to_graph (boost::shared_ptr<Route> other)
{
- return _session._current_route_graph.feeds (shared_from_this (), other);
+ return _session._current_route_graph.feeds (boost::dynamic_pointer_cast<Route> (shared_from_this ()), other);
}
/** Called from the (non-realtime) butler thread when the transport is stopped */
void
-Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool /*did_locate*/, bool can_flush_processors)
+Route::non_realtime_transport_stop (framepos_t now, bool flush)
{
- framepos_t now = _session.transport_frame();
-
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
- Automatable::transport_stopped (now);
+ Automatable::non_realtime_transport_stop (now, flush);
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- if (!_have_internal_generator && (Config->get_plugins_stop_with_transport() && can_flush_processors)) {
+ if (!_have_internal_generator && (Config->get_plugins_stop_with_transport() && flush)) {
(*i)->flush ();
}
- (*i)->transport_stopped (now);
+ (*i)->non_realtime_transport_stop (now, flush);
}
}
continue;
}
bool sends_only;
- bool does_feed = (*i)->direct_feeds_according_to_reality (shared_from_this(), &sends_only);
+ bool does_feed = (*i)->direct_feeds_according_to_reality (boost::dynamic_pointer_cast<Route> (shared_from_this()), &sends_only);
if (does_feed && !sends_only) {
if ((*i)->soloed()) {
++sbou;
_solo_control->mod_solo_by_others_downstream (delta);
// Session::route_solo_changed() does not propagate indirect solo-changes
// propagate upstream to tracks
- boost::shared_ptr<Route> shared_this = shared_from_this();
+ boost::shared_ptr<Route> shared_this = boost::dynamic_pointer_cast<Route> (shared_from_this());
for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
if ((*i).get() == this || !can_solo()) {
continue;
}
int
-Route::save_as_template (const string& path, const string& name)
+Route::save_as_template (const string& path, const string& name, const string& description)
{
std::string state_dir = path.substr (0, path.find_last_of ('.')); // strip template_suffix
PBD::Unwinder<std::string> uw (_session._template_state_dir, state_dir);
XMLNode& node (state (false));
+ node.set_property (X_("name"), name);
+
+ node.remove_nodes (X_("description"));
+ if (!description.empty()) {
+ XMLNode* desc = new XMLNode(X_("description"));
+ XMLNode* desc_cont = new XMLNode(X_("content"), description);
+ desc->add_child_nocopy (*desc_cont);
+
+ node.add_child_nocopy (*desc);
+ }
XMLTree tree;
void
Route::set_name_in_state (XMLNode& node, string const & name, bool rename_playlist)
{
- node.add_property (X_("name"), name);
+ node.set_property (X_("name"), name);
XMLNodeList children = node.children();
for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) {
} else if ((*i)->name() == X_("Processor")) {
- XMLProperty const * role = (*i)->property (X_("role"));
- if (role && role->value() == X_("Main")) {
- (*i)->add_property (X_("name"), name);
+ std::string str;
+ if ((*i)->get_property (X_("role"), str) && str == X_("Main")) {
+ (*i)->set_property (X_("name"), name);
}
} else if ((*i)->name() == X_("Diskstream")) {
if (rename_playlist) {
- (*i)->add_property (X_("playlist"), string_compose ("%1.1", name).c_str());
+ (*i)->set_property (X_("playlist"), name + ".1");
}
- (*i)->add_property (X_("name"), name);
+ (*i)->set_property (X_("name"), name);
}
}
void
Route::non_realtime_locate (framepos_t pos)
{
+ Automatable::non_realtime_locate (pos);
+
if (_pannable) {
- _pannable->transport_located (pos);
+ _pannable->non_realtime_locate (pos);
}
if (_delayline.get()) {
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- (*i)->transport_located (pos);
+ (*i)->non_realtime_locate (pos);
}
}
_roll_delay = _initial_delay;
uint32_t port_number;
#ifdef MIXBUS32C
switch (band) {
- case 0: port_number = 13; break;
- case 1: port_number = 11; break;
- case 2: port_number = 9; break;
- case 3: port_number = 7; break;
+ case 0: port_number = 13; break; // lo
+ case 1: port_number = 11; break; // lo mid
+ case 2: port_number = 9; break; // hi mid
+ case 3: port_number = 7; break; // hi
default:
return boost::shared_ptr<AutomationControl>();
}
boost::shared_ptr<AutomationControl>
Route::eq_shape_controllable (uint32_t band) const
{
+#ifdef MIXBUS32C
+ boost::shared_ptr<PluginInsert> eq = ch_eq();
+ if (is_master() || mixbus() || !eq) {
+ return boost::shared_ptr<AutomationControl>();
+ }
+ switch (band) {
+ case 0:
+ return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 4))); // lo bell
+ break;
+ case 3:
+ return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 3))); // hi bell
+ break;
+ default:
+ break;
+ }
+#endif
return boost::shared_ptr<AutomationControl>();
}
}
boost::shared_ptr<AutomationControl>
-Route::eq_hpf_controllable () const
+Route::filter_freq_controllable (bool hpf) const
{
#ifdef MIXBUS
boost::shared_ptr<PluginInsert> eq = ch_eq();
if (is_master() || mixbus() || !eq) {
return boost::shared_ptr<AutomationControl>();
}
+ if (hpf) {
#ifdef MIXBUS32C
- return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 3)));
+ return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 5))); // HPF freq
#else
- return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 2)));
+ return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 2)));
+#endif
+ } else {
+#ifdef MIXBUS32C
+ return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 6))); // LPF freq
+#else
+ return boost::shared_ptr<AutomationControl>();
+#endif
+ }
+
+#else
+ return boost::shared_ptr<AutomationControl>();
#endif
+}
+
+boost::shared_ptr<AutomationControl>
+Route::filter_slope_controllable (bool) const
+{
+ return boost::shared_ptr<AutomationControl>();
+}
+
+boost::shared_ptr<AutomationControl>
+Route::filter_enable_controllable (bool) const
+{
+#ifdef MIXBUS32C
+ boost::shared_ptr<PluginInsert> eq = ch_eq();
+
+ if (is_master() || mixbus() || !eq) {
+ return boost::shared_ptr<AutomationControl>();
+ }
+ return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 2)));
#else
return boost::shared_ptr<AutomationControl>();
#endif
# undef MIXBUS_PORTS_H
# include "../../gtk2_ardour/mixbus_ports.h"
boost::shared_ptr<ARDOUR::PluginInsert> plug = ch_post();
- if (plug) {
+ if (plug && !mixbus()) {
uint32_t port_id = 0;
switch (n) {
case 0: port_id = port_channel_post_aux1_level; break;
# undef MIXBUS_PORTS_H
# include "../../gtk2_ardour/mixbus_ports.h"
boost::shared_ptr<ARDOUR::PluginInsert> plug = ch_post();
- if (plug) {
+ if (plug && !mixbus()) {
uint32_t port_id = 0;
switch (n) {
case 0: port_id = port_channel_post_aux1_asgn; break;
Route::send_name (uint32_t n) const
{
#ifdef MIXBUS
+ boost::shared_ptr<ARDOUR::PluginInsert> plug = ch_post();
+ if (plug && !mixbus()) {
# ifdef MIXBUS32C
- if (n < 12) {
- return _session.get_mixbus (n)->name();
- }
- n -= 12;
+ if (n < 12) {
+ return _session.get_mixbus (n)->name();
+ }
+ n -= 12;
#else
- if (n < 8) {
- return _session.get_mixbus (n)->name();
- }
- n -= 8;
+ if (n < 8) {
+ return _session.get_mixbus (n)->name();
+ }
+ n -= 8;
# endif
+ }
#endif
boost::shared_ptr<Processor> p = nth_send (n);
if (p) {
{
_solo_control->clear_all_solo_state ();
}
+
+boost::shared_ptr<AutomationControl>
+Route::automation_control_recurse (PBD::ID const & id) const
+{
+ boost::shared_ptr<AutomationControl> ac = Automatable::automation_control (id);
+
+ if (ac) {
+ return ac;
+ }
+
+ Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+
+ for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+ if ((ac = (*i)->automation_control (id))) {
+ return ac;
+ }
+ }
+
+ return boost::shared_ptr<AutomationControl> ();
+}
+
+SlavableControlList
+Route::slavables () const
+{
+ SlavableControlList rv;
+ rv.push_back (_gain_control);
+ rv.push_back (_mute_control);
+ rv.push_back (_solo_control);
+ return rv;
+}