#include "pbd/enumwriter.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/capturing_processor.h"
#include "ardour/debug.h"
#include "ardour/delivery.h"
+#include "ardour/event_type_map.h"
#include "ardour/gain_control.h"
#include "ardour/internal_return.h"
#include "ardour/internal_send.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)
processor_max_streams.reset();
}
+boost::weak_ptr<Route>
+Route::weakroute () {
+ return boost::weak_ptr<Route> (boost::dynamic_pointer_cast<Route> (shared_from_this ()));
+}
+
int
Route::init ()
{
_monitor_control->activate ();
}
- if (is_master() || is_monitor() || is_auditioner()) {
- _mute_master->set_solo_ignore (true);
- }
-
/* now that we have _meter, its safe to connect to this */
{
Route::set_listen (bool yn)
{
if (_monitor_send) {
+ if (_monitor_send->active() == yn) {
+ return;
+ }
if (yn) {
_monitor_send->activate ();
} else {
if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" ||
prop->value() == "windows-vst" ||
+ prop->value() == "mac-vst" ||
prop->value() == "lxvst" ||
prop->value() == "audiounit") {
//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();
Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor> before, ProcessorStreams* err)
{
ProcessorList::iterator loc;
+ boost::shared_ptr <PluginInsert> fanout;
+
+ if (g_atomic_int_get (&_pending_process_reorder)) {
+ /* we need to flush any pending re-order changes */
+ Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
+ apply_processor_changes_rt ();
+ }
if (before) {
loc = find(_processors.begin(), _processors.end(), before);
flags &= mask;
if (flags != None) {
- boost::optional<int> rv = PluginSetup (shared_from_this (), pi, flags); /* EMIT SIGNAL */
- switch (rv.get_value_or (0)) {
+ 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:
to_skip.push_back (*i); // don't add this one;
break;
default:
break;
}
+ if ((mode & 5) == 4) {
+ fanout = pi;
+ }
}
}
}
}
+ if (pi && pi->has_sidechain ()) {
+ pi->sidechain_input ()->changed.connect_same_thread (*this, boost::bind (&Route::sidechain_change_handler, this, _1, _2));
+ }
+
if ((*i)->active()) {
- // why? emit ActiveChanged() ??
+ // emit ActiveChanged() and latency_changed() if needed
(*i)->activate ();
}
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
set_processor_positions ();
+ if (fanout && fanout->configured ()
+ && fanout->output_streams().n_audio() > 2
+ && boost::dynamic_pointer_cast<PluginInsert> (the_instrument ()) == fanout) {
+ fan_out (); /* EMIT SIGNAL */
+ }
return 0;
}
if (!boost::dynamic_pointer_cast<PluginInsert> (*i)) {
continue;
}
+ if (!(*i)->display_to_user ()) {
+ continue;
+ }
+#ifdef MIXBUS
+ if (boost::dynamic_pointer_cast<PluginInsert> (*i)->is_channelstrip()) {
+ continue;
+ }
+#endif
if ((*i)->enabled ()) {
(*i)->enable (false);
/* backward = if the redirect was marked to go active on the next ab, do so */
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-
if (!boost::dynamic_pointer_cast<PluginInsert> (*i)) {
continue;
}
+ if (!(*i)->display_to_user ()) {
+ continue;
+ }
+#ifdef MIXBUS
+ if (boost::dynamic_pointer_cast<PluginInsert> (*i)->is_channelstrip()) {
+ continue;
+ }
+#endif
(*i)->enable ((*i)->get_next_ab_is_active ());
}
if (is_monitor()) {
// restriction for Monitor Section Processors
if (in.n_audio() != out.n_audio() || out.n_midi() > 0) {
- /* do not allow to add/remove channels (for now)
- * The Monitor follows the master-bus and has no panner (unpan)
- * but do allow processors with midi-in to be added (e.g VSTs with control that
- * will remain unconnected)
+ /* Note: The Monitor follows the master-bus and has no panner.
+ *
+ * The general idea is to only allow plugins that retain the channel-count
+ * and plugins with MIDI in (e.g VSTs with control that will remain unconnected).
+ * Then again 5.1 in, monitor stereo is a valid use-case.
+ *
+ * and worse: we only refuse adding plugins *here*.
+ *
+ * 1) stereo-master, stereo-mon, add a stereo-plugin, OK
+ * 2) change master-bus, add a channel
+ * 2a) monitor-secion follows
+ * 3) monitor processors fail to re-reconfigure (stereo plugin)
+ * 4) re-load session, monitor-processor remains unconfigured, crash.
*/
- DEBUG_TRACE (DEBUG::Processors, "Monitor: Channel configuration not allowed.\n");
- return list<pair<ChanCount, ChanCount> > ();
+ DEBUG_TRACE (DEBUG::Processors, "Monitor: Channel configuration change.\n");
}
if (boost::dynamic_pointer_cast<InternalSend> (*p)) {
// internal sends make no sense, only feedback
if (!(*i)->display_to_user() || boost::dynamic_pointer_cast<Amp> (*i)) {
continue;
}
+#ifdef MIXBUS
+ boost::shared_ptr<PluginInsert> pi;
+ if (0 != (pi = boost::dynamic_pointer_cast<PluginInsert>(*i))) {
+ if (pi->is_channelstrip ()) {
+ continue;
+ }
+ }
+#endif
(*i)->enable (state);
}
maybe_note_meter_position ();
}
+void
+Route::move_instrument_down (bool postfader)
+{
+ Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+ ProcessorList new_order;
+ boost::shared_ptr<Processor> instrument;
+ for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+ boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(*i);
+ if (pi && pi->plugin ()->get_info ()->is_instrument ()) {
+ instrument = *i;
+ } else if (instrument && *i == _amp) {
+ if (postfader) {
+ new_order.push_back (*i);
+ new_order.push_back (instrument);
+ } else {
+ new_order.push_back (instrument);
+ new_order.push_back (*i);
+ }
+ } else {
+ new_order.push_back (*i);
+ }
+ }
+ if (!instrument) {
+ return;
+ }
+ lm.release ();
+ reorder_processors (new_order, 0);
+}
+
int
Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err)
{
{
LocaleGuard lg;
if (!_session._template_state_dir.empty()) {
- assert (!full_state); // only for templates
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());
- }
-
- if (!can_solo()) {
- _mute_master->set_solo_ignore (true);
- }
+ 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);
}
} else {
warning << string_compose (_("Pannable state found for route (%1) without a panner!"), name()) << endmsg;
}
- } else if (child->name() == Controllable::xml_node_name) {
- if ((prop = child->property (X_("name"))) == 0) {
- continue;
- }
-
- if (prop->value() == _gain_control->name()) {
- _gain_control->set_state (*child, version);
- } else if (prop->value() == _solo_control->name()) {
- _solo_control->set_state (*child, version);
- } else if (prop->value() == _solo_safe_control->name()) {
- _solo_safe_control->set_state (*child, version);
- } else if (prop->value() == _solo_isolate_control->name()) {
- _solo_isolate_control->set_state (*child, version);
- } else if (prop->value() == _solo_control->name()) {
- _mute_control->set_state (*child, version);
- }
} else if (child->name() == Slavable::xml_node_name) {
Slavable::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 */
+ 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) {
XMLNode *cmt = *(child->children().begin());
_comment = cmt->content();
- } else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) {
- if (prop->value() == "solo") {
+ } else if (child->name() == Controllable::xml_node_name) {
+ std::string control_name;
+ if (!child->get_property (X_("name"), control_name)) {
+ continue;
+ }
+
+ if (control_name == _gain_control->name()) {
+ _gain_control->set_state (*child, version);
+ } else if (control_name == _solo_control->name()) {
_solo_control->set_state (*child, version);
- } else if (prop->value() == "mute") {
+ } else if (control_name == _solo_safe_control->name()) {
+ _solo_safe_control->set_state (*child, version);
+ } else if (control_name == _solo_isolate_control->name()) {
+ _solo_isolate_control->set_state (*child, version);
+ } else if (control_name == _mute_control->name()) {
_mute_control->set_state (*child, version);
+ } else if (control_name == _phase_control->name()) {
+ _phase_control->set_state (*child, version);
+ } else {
+ 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) {
+ ac->set_state (*child, version);
+ }
+ }
}
-
} else if (child->name() == MuteMaster::xml_node_name) {
_mute_master->set_state (*child, version);
Stripable::set_state (node, version);
- if (is_master() || is_monitor() || is_auditioner()) {
- _mute_master->set_solo_ignore (true);
- }
-
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);
}
} else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" ||
prop->value() == "windows-vst" ||
+ prop->value() == "mac-vst" ||
prop->value() == "lxvst" ||
prop->value() == "luaproc" ||
prop->value() == "audiounit") {
}
{
+ Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
Glib::Threads::RWLock::WriterLock lm (_processor_lock);
/* re-assign _processors w/o process-lock.
* if there's an IO-processor present in _processors but
* a process lock.
*/
_processors = new_order;
- Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
if (must_configure) {
configure_processors_unlocked (0, &lm);
{
Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
- boost::shared_ptr<Pannable> sendpan (new Pannable (_session));
- listener.reset (new InternalSend (_session, sendpan, _mute_master, boost::dynamic_pointer_cast<ARDOUR::Route>(shared_from_this()), route, Delivery::Aux));
+ listener.reset (new InternalSend (_session, _pannable, _mute_master, boost::dynamic_pointer_cast<ARDOUR::Route>(shared_from_this()), route, Delivery::Aux));
}
add_processor (listener, before);
if (iop != 0) {
boost::shared_ptr<const IO> iop_out = iop->output();
+ if (other.get() == this && iop_out && iop->input() && iop_out->connected_to (iop->input())) {
+ // TODO this needs a delaylines in the Insert to align connections (!)
+ DEBUG_TRACE (DEBUG::Graph, string_compose ("\tIOP %1 does feed its own return (%2)\n", iop->name(), other->name()));
+ continue;
+ }
if ((iop_out && other->all_inputs().fed_by (iop_out)) || iop->feeds (other)) {
DEBUG_TRACE (DEBUG::Graph, string_compose ("\tIOP %1 does feed %2\n", iop->name(), other->name()));
if (via_send_only) {
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 */
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;
io_changed (); /* EMIT SIGNAL */
}
- if (_solo_control->soloed_by_others_downstream()) {
- int sbod = 0;
- /* checking all all downstream routes for
- * explicit of implict solo is a rather drastic measure,
- * ideally the input_change_handler() of the other route
- * would propagate the change to us.
+ if ((change.type & IOChange::ConnectionsChanged)) {
+
+ /* do this ONLY if connections have changed. Configuration
+ * changes do not, by themselves alter solo upstream or
+ * downstream status.
*/
- boost::shared_ptr<RouteList> routes = _session.get_routes ();
- if (_output->connected()) {
- for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
- if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
- continue;
- }
- bool sends_only;
- bool does_feed = direct_feeds_according_to_reality (*i, &sends_only);
- if (does_feed && !sends_only) {
- if ((*i)->soloed()) {
- ++sbod;
- break;
+
+ if (_solo_control->soloed_by_others_downstream()) {
+ int sbod = 0;
+ /* checking all all downstream routes for
+ * explicit of implict solo is a rather drastic measure,
+ * ideally the input_change_handler() of the other route
+ * would propagate the change to us.
+ */
+ boost::shared_ptr<RouteList> routes = _session.get_routes ();
+ if (_output->connected()) {
+ for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
+ if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+ continue;
+ }
+ bool sends_only;
+ bool does_feed = direct_feeds_according_to_reality (*i, &sends_only);
+ if (does_feed && !sends_only) {
+ if ((*i)->soloed()) {
+ ++sbod;
+ break;
+ }
}
}
}
- }
- int delta = sbod - _solo_control->soloed_by_others_downstream();
- if (delta <= 0) {
- // do not allow new connections to change implicit solo (no propagation)
- _solo_control->mod_solo_by_others_downstream (delta);
- // Session::route_solo_changed() does not propagate indirect solo-changes
- // propagate upstream to tracks
- for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
- if ((*i).get() == this || !can_solo()) {
- continue;
- }
- bool sends_only;
- bool does_feed = (*i)->feeds (shared_from_this(), &sends_only);
- if (delta != 0 && does_feed && !sends_only) {
- (*i)->solo_control()->mod_solo_by_others_downstream (delta);
+
+ int delta = sbod - _solo_control->soloed_by_others_downstream();
+ if (delta <= 0) {
+ // do not allow new connections to change implicit solo (no propagation)
+ _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 = 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;
+ }
+ bool sends_only;
+ bool does_feed = (*i)->feeds (shared_this, &sends_only);
+ if (delta != 0 && does_feed && !sends_only) {
+ (*i)->solo_control()->mod_solo_by_others_downstream (delta);
+ }
}
- }
+ }
}
}
}
return 0;
}
- if (n_outputs().n_total() == 0) {
- return 0;
- }
-
- if (!_active || n_inputs() == ChanCount::ZERO) {
+ if (!_active) {
silence_unlocked (nframes);
return 0;
}
return 0;
}
- if (n_outputs().n_total() == 0) {
- return 0;
- }
-
- if (!_active || n_inputs().n_total() == 0) {
+ if (!_active) {
silence_unlocked (nframes);
return 0;
}
Route::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*end_frame*/, bool& /* need_butler */)
{
silence (nframes);
+ flush_processor_buffers_locked (nframes);
return 0;
}
void
Route::flush_processors ()
{
- /* XXX shouldn't really try to take this lock, since
- this is called from the RT audio thread.
- */
-
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
bool
Route::set_name (const string& str)
{
+ if (str.empty ()) {
+ return false;
+ }
+
if (str == name()) {
return true;
}
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);
}
}
_active = yn;
_input->set_active (yn);
_output->set_active (yn);
+ flush_processors ();
active_changed (); // EMIT SIGNAL
_session.set_dirty ();
}
new_processors.insert (amp, _monitor_control);
}
+ /* TRIM CONTROL */
+
+ if (_trim && _trim->active()) {
+ assert (!_trim->display_to_user ());
+ new_processors.push_front (_trim);
+ }
+
/* INTERNAL RETURN */
- /* doing this here means that any monitor control will come just after
- the return.
+ /* doing this here means that any monitor control will come after
+ the return and trim.
*/
if (_intreturn) {
new_processors.push_front (_intreturn);
}
- if (_trim && _trim->active()) {
- assert (!_trim->display_to_user ());
- new_processors.push_front (_trim);
- }
/* EXPORT PROCESSOR */
if (_capturing_processor) {
Route::pan_azimuth_control() const
{
#ifdef MIXBUS
+# undef MIXBUS_PORTS_H
+# include "../../gtk2_ardour/mixbus_ports.h"
boost::shared_ptr<ARDOUR::PluginInsert> plug = ch_post();
if (!plug) {
return boost::shared_ptr<AutomationControl>();
}
- const uint32_t port_channel_post_pan = 2; // gtk2_ardour/mixbus_ports.h
return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_channel_post_pan)));
#else
if (!_pannable || !panner()) {
boost::shared_ptr<AutomationControl>
Route::pan_width_control() const
{
+#ifdef MIXBUS
+ if (mixbus() && _ch_pre) {
+ //mono blend
+ return boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(_ch_pre->control(Evoral::Parameter(PluginAutomation, 0, 5)));
+ }
+#endif
if (Profile->get_mixbus() || !_pannable || !panner()) {
return boost::shared_ptr<AutomationControl>();
}
Route::eq_band_cnt () const
{
if (Profile->get_mixbus()) {
+#ifdef MIXBUS32C
+ if (is_master() || mixbus()) {
+ return 3;
+ } else {
+ return 4;
+ }
+#else
return 3;
+#endif
} else {
/* Ardour has no well-known EQ object */
return 0;
}
uint32_t port_number;
- switch (band) {
- case 0:
- if (is_master() || mixbus()) {
- port_number = 4;
- } else {
- port_number = 8;
+ if (is_master() || mixbus()) {
+ switch (band) {
+ case 0: port_number = 4; break;
+ case 1: port_number = 3; break;
+ case 2: port_number = 2; break;
+ default:
+ return boost::shared_ptr<AutomationControl>();
}
- break;
- case 1:
- if (is_master() || mixbus()) {
- port_number = 3;
- } else {
- port_number = 6;
+ } else {
+#ifdef MIXBUS32C
+ switch (band) {
+ case 0: port_number = 14; break;
+ case 1: port_number = 12; break;
+ case 2: port_number = 10; break;
+ case 3: port_number = 8; break;
+ default:
+ return boost::shared_ptr<AutomationControl>();
}
- break;
- case 2:
- if (is_master() || mixbus()) {
- port_number = 2;
- } else {
- port_number = 4;
+#else
+ switch (band) {
+ case 0: port_number = 8; break;
+ case 1: port_number = 6; break;
+ case 2: port_number = 4; break;
+ default:
+ return boost::shared_ptr<AutomationControl>();
}
- break;
- default:
- return boost::shared_ptr<AutomationControl>();
+#endif
}
return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_number)));
Route::eq_freq_controllable (uint32_t band) const
{
#ifdef MIXBUS
-
if (mixbus() || is_master()) {
/* no frequency controls for mixbusses or master */
return boost::shared_ptr<AutomationControl>();
}
uint32_t port_number;
+#ifdef MIXBUS32C
switch (band) {
- case 0:
- port_number = 7;
- break;
- case 1:
- port_number = 5;
- break;
- case 2:
- port_number = 3;
- break;
- default:
- return boost::shared_ptr<AutomationControl>();
+ case 0: port_number = 13; break;
+ case 1: port_number = 11; break;
+ case 2: port_number = 9; break;
+ case 3: port_number = 7; break;
+ default:
+ return boost::shared_ptr<AutomationControl>();
}
+#else
+ switch (band) {
+ case 0: port_number = 7; break;
+ case 1: port_number = 5; break;
+ case 2: port_number = 3; break;
+ default:
+ return boost::shared_ptr<AutomationControl>();
+ }
+#endif
return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_number)));
#else
#ifdef MIXBUS
boost::shared_ptr<PluginInsert> eq = ch_eq();
+ if (is_master() || mixbus() || !eq) {
+ return boost::shared_ptr<AutomationControl>();
+ }
+#ifdef MIXBUS32C
+ return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 3)));
+#else
+ return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 2)));
+#endif
+
+#else
+ return boost::shared_ptr<AutomationControl>();
+#endif
+}
+
+boost::shared_ptr<AutomationControl>
+Route::eq_lpf_controllable () const
+{
+#ifdef MIXBUS32C
+ boost::shared_ptr<PluginInsert> eq = ch_eq();
+
+ if (!eq) {
+ return boost::shared_ptr<AutomationControl>();
+ }
+
+ return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 6)));
+#else
+ return boost::shared_ptr<AutomationControl>();
+#endif
+}
+
+boost::shared_ptr<AutomationControl>
+Route::filter_enable_controllable () const
+{
+#ifdef MIXBUS32C
+ boost::shared_ptr<PluginInsert> eq = ch_eq();
+
if (!eq) {
return boost::shared_ptr<AutomationControl>();
}
string
Route::eq_band_name (uint32_t band) const
{
+#ifdef MIXBUS32C
+ if (is_master() || mixbus()) {
+#endif
if (Profile->get_mixbus()) {
switch (band) {
- case 0:
- return _("lo");
- case 1:
- return _("mid");
- case 2:
- return _("hi");
- default:
- return string();
+ case 0: return _("lo");
+ case 1: return _("mid");
+ case 2: return _("hi");
+ default: return string();
}
} else {
return string ();
}
+#ifdef MIXBUS32C
+ } else {
+ switch (band) {
+ case 0: return _("lo");
+ case 1: return _("lo mid");
+ case 2: return _("hi mid");
+ case 3: return _("hi");
+ default: return string();
+ }
+ }
+#endif
}
boost::shared_ptr<AutomationControl>
return boost::shared_ptr<AutomationControl>();
#endif
}
-boost::shared_ptr<AutomationControl>
+boost::shared_ptr<ReadOnlyControl>
Route::comp_redux_controllable () const
{
#ifdef MIXBUS
boost::shared_ptr<PluginInsert> comp = ch_comp();
if (!comp) {
- return boost::shared_ptr<AutomationControl>();
+ return boost::shared_ptr<ReadOnlyControl>();
+ }
+ if (is_master()) {
+ return comp->control_output (2);
+ } else {
+ return comp->control_output (6);
}
- return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (comp->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 6)));
#else
- return boost::shared_ptr<AutomationControl>();
+ return boost::shared_ptr<ReadOnlyControl>();
#endif
}
Route::send_level_controllable (uint32_t n) const
{
#ifdef MIXBUS
+# undef MIXBUS_PORTS_H
+# include "../../gtk2_ardour/mixbus_ports.h"
boost::shared_ptr<ARDOUR::PluginInsert> plug = ch_post();
- if (!plug) {
- return boost::shared_ptr<AutomationControl>();
- }
+ if (plug) {
+ uint32_t port_id = 0;
+ switch (n) {
+ case 0: port_id = port_channel_post_aux1_level; break;
+ case 1: port_id = port_channel_post_aux2_level; break;
+ case 2: port_id = port_channel_post_aux3_level; break;
+ case 3: port_id = port_channel_post_aux4_level; break;
+ case 4: port_id = port_channel_post_aux5_level; break;
+ case 5: port_id = port_channel_post_aux6_level; break;
+ case 6: port_id = port_channel_post_aux7_level; break;
+ case 7: port_id = port_channel_post_aux8_level; break;
+# ifdef MIXBUS32C
+ case 8: port_id = port_channel_post_aux9_level; break;
+ case 9: port_id = port_channel_post_aux10_level; break;
+ case 10: port_id = port_channel_post_aux11_level; break;
+ case 11: port_id = port_channel_post_aux12_level; break;
+# endif
+ default:
+ break;
+ }
- if (n >= 8) {
- /* no such bus */
- return boost::shared_ptr<AutomationControl>();
+ if (port_id > 0) {
+ return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_id)));
+ }
+# ifdef MIXBUS32C
+ assert (n > 11);
+ n -= 12;
+# else
+ assert (n > 7);
+ n -= 8;
+# endif
}
-
- const uint32_t port_id = port_channel_post_aux1_level + (2*n); // gtk2_ardour/mixbus_ports.h
- return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_id)));
-#else
+#endif
boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(nth_send (n));
if (!s) {
return boost::shared_ptr<AutomationControl>();
}
return s->gain_control ();
-#endif
}
boost::shared_ptr<AutomationControl>
Route::send_enable_controllable (uint32_t n) const
{
#ifdef MIXBUS
+# undef MIXBUS_PORTS_H
+# include "../../gtk2_ardour/mixbus_ports.h"
boost::shared_ptr<ARDOUR::PluginInsert> plug = ch_post();
- if (!plug) {
- return boost::shared_ptr<AutomationControl>();
- }
+ if (plug) {
+ uint32_t port_id = 0;
+ switch (n) {
+ case 0: port_id = port_channel_post_aux1_asgn; break;
+ case 1: port_id = port_channel_post_aux2_asgn; break;
+ case 2: port_id = port_channel_post_aux3_asgn; break;
+ case 3: port_id = port_channel_post_aux4_asgn; break;
+ case 4: port_id = port_channel_post_aux5_asgn; break;
+ case 5: port_id = port_channel_post_aux6_asgn; break;
+ case 6: port_id = port_channel_post_aux7_asgn; break;
+ case 7: port_id = port_channel_post_aux8_asgn; break;
+# ifdef MIXBUS32C
+ case 8: port_id = port_channel_post_aux9_asgn; break;
+ case 9: port_id = port_channel_post_aux10_asgn; break;
+ case 10: port_id = port_channel_post_aux11_asgn; break;
+ case 11: port_id = port_channel_post_aux12_asgn; break;
+# endif
+ default:
+ break;
+ }
- if (n >= 8) {
- /* no such bus */
- return boost::shared_ptr<AutomationControl>();
+ if (port_id > 0) {
+ return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_id)));
+ }
+# ifdef MIXBUS32C
+ assert (n > 11);
+ n -= 12;
+# else
+ assert (n > 7);
+ n -= 8;
+# endif
}
-
- const uint32_t port_id = port_channel_post_aux1_asgn + (2*n); // gtk2_ardour/mixbus_ports.h
- return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_id)));
-#else
+#endif
/* although Ardour sends have enable/disable as part of the Processor
- API, it is not exposed as a controllable.
-
- XXX: we should fix this.
- */
+ * API, it is not exposed as a controllable.
+ *
+ * XXX: we should fix this (make it click-free, automatable enable-control)
+ */
return boost::shared_ptr<AutomationControl>();
-#endif
}
string
Route::send_name (uint32_t n) const
{
#ifdef MIXBUS
- if (n >= 8) {
- return string();
+# ifdef MIXBUS32C
+ if (n < 12) {
+ return _session.get_mixbus (n)->name();
}
- boost::shared_ptr<Route> r = _session.get_mixbus (n);
- assert (r);
- return r->name();
+ n -= 12;
#else
+ if (n < 8) {
+ return _session.get_mixbus (n)->name();
+ }
+ n -= 8;
+# endif
+#endif
boost::shared_ptr<Processor> p = nth_send (n);
if (p) {
return p->name();
} else {
return string();
}
-#endif
}
boost::shared_ptr<AutomationControl>
if (!plug) {
return boost::shared_ptr<AutomationControl>();
}
+# undef MIXBUS_PORTS_H
+# include "../../gtk2_ardour/mixbus_ports.h"
return boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_channel_post_mstr_assign)));
#else
return boost::shared_ptr<AutomationControl>();
return false;
}
- return _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
+ return _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
}
void
Route::clear_all_solo_state ()
{
- double v = _solo_safe_control->get_value ();
-
_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);
- if (v != 0.0) {
- _solo_safe_control->set_value (v, Controllable::NoGroup);
+ for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+ if ((ac = (*i)->automation_control (id))) {
+ return ac;
+ }
}
+
+ return boost::shared_ptr<AutomationControl> ();
}