#include "ardour/capturing_processor.h"
#include "ardour/debug.h"
#include "ardour/delivery.h"
+#include "ardour/gain_control.h"
#include "ardour/internal_return.h"
#include "ardour/internal_send.h"
#include "ardour/meter.h"
#include "ardour/pannable.h"
#include "ardour/panner.h"
#include "ardour/panner_shell.h"
+#include "ardour/parameter_descriptor.h"
#include "ardour/plugin_insert.h"
#include "ardour/port.h"
#include "ardour/port_insert.h"
_mute_control.reset (new MuteControllable (X_("mute"), shared_from_this ()));
_phase_control.reset (new PhaseControllable (X_("phase"), shared_from_this ()));
+ _solo_isolate_control.reset (new SoloIsolateControllable (X_("solo-iso"), shared_from_this ()));
+ _solo_safe_control.reset (new SoloSafeControllable (X_("solo-safe"), shared_from_this ()));
+
_solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
_mute_control->set_flags (Controllable::Flag (_mute_control->flags() | Controllable::Toggle));
_phase_control->set_flags (Controllable::Flag (_phase_control->flags() | Controllable::Toggle));
/* add amp processor */
- _amp.reset (new Amp (_session));
+ _gain_control = boost::shared_ptr<GainControllable> (new GainControllable (_session, GainAutomation, shared_from_this ()));
+ add_control (_gain_control);
+
+ _amp.reset (new Amp (_session, X_("Fader"), _gain_control, true));
add_processor (_amp, PostFader);
- // amp should exist before amp controls
- _group_gain_control.reset (new GroupGainControllable (X_("groupgain"), shared_from_this ()));
- _group_gain_control->set_flags (Controllable::Flag (_group_gain_control->flags() | Controllable::GainLike));
- add_control (_group_gain_control);
+ if (is_monitor ()) {
+ _amp->set_display_name (_("Monitor"));
+ }
/* and input trim */
- _trim.reset (new Amp (_session, "trim"));
+
+ _trim_control = boost::shared_ptr<GainControllable> (new GainControllable (_session, TrimAutomation, shared_from_this ()));
+ add_control (_trim_control);
+
+ _trim.reset (new Amp (_session, X_("Trim"), _trim_control, false));
_trim->set_display_to_user (false);
if (dynamic_cast<AudioTrack*>(this)) {
}
void
-Route::inc_gain (gain_t fraction, void *src)
+Route::inc_gain (gain_t factor)
{
- _amp->inc_gain (fraction, src);
+ /* To be used ONLY when doing group-relative gain adjustment, from
+ * ::set_gain()
+ */
+
+ float desired_gain = _gain_control->user_double();
+
+ if (fabsf (desired_gain) < GAIN_COEFF_SMALL) {
+ // really?! what's the idea here?
+ _gain_control->route_set_value (0.000001f + (0.000001f * factor));
+ } else {
+ _gain_control->route_set_value (desired_gain + (desired_gain * factor));
+ }
}
void
-Route::set_gain (gain_t val, void *src)
+Route::set_gain (gain_t val, Controllable::GroupControlDisposition group_override)
{
- if (src != 0 && _route_group && src != _route_group && _route_group->is_active() && _route_group->is_gain()) {
+ if (use_group (group_override, &RouteGroup::is_gain)) {
if (_route_group->is_relative()) {
- gain_t usable_gain = _amp->gain();
+ gain_t usable_gain = _gain_control->get_value();
if (usable_gain < 0.000001f) {
usable_gain = 0.000001f;
}
}
}
- _route_group->foreach_route (boost::bind (&Route::inc_gain, _1, factor, _route_group));
+ _route_group->foreach_route (boost::bind (&Route::inc_gain, _1, factor));
} else {
- _route_group->foreach_route (boost::bind (&Route::set_gain, _1, val, _route_group));
+ _route_group->foreach_route (boost::bind (&Route::set_gain, _1, val, Controllable::NoGroup));
}
return;
}
- if (val == _amp->gain()) {
+ if (val == _gain_control->get_value()) {
return;
}
- _amp->set_gain (val, src);
-}
-
-void
-Route::inc_trim (gain_t fraction, void *src)
-{
- _trim->inc_gain (fraction, src);
+ _gain_control->route_set_value (val);
}
void
-Route::set_trim (gain_t val, void * /* src */)
+Route::set_trim (gain_t val, Controllable::GroupControlDisposition /* group override */)
{
// TODO route group, see set_gain()
- _trim->set_gain (val, 0);
+ _trim_control->route_set_value (val);
}
void
}
void
-Route::set_listen (bool yn, void* src, bool group_override)
+Route::set_listen (bool yn, Controllable::GroupControlDisposition group_override)
{
if (_solo_safe) {
return;
}
- bool group_active = _route_group && _route_group->is_active() && _route_group->is_solo();
- if (group_override && _route_group) {
- group_active = !group_active;
- }
-
- if (_route_group && src != _route_group && group_active) {
- _route_group->foreach_route (boost::bind (&Route::set_listen, _1, yn, _route_group, group_override));
+ if (use_group (group_override, &RouteGroup::is_solo)) {
+ _route_group->foreach_route (boost::bind (&Route::set_listen, _1, yn, Controllable::NoGroup));
return;
}
}
_mute_master->set_soloed_by_others (false);
- listen_changed (src, group_override); /* EMIT SIGNAL */
+ listen_changed (group_override); /* EMIT SIGNAL */
}
}
}
}
void
-Route::set_solo_safe (bool yn, void *src)
+Route::set_solo_safe (bool yn, Controllable::GroupControlDisposition /* group_override */)
{
if (_solo_safe != yn) {
_solo_safe = yn;
- solo_safe_changed (src);
+ solo_safe_changed (); /* EMIT SIGNAL */
+ _solo_safe_control->Changed(); /* EMIT SIGNAL */
}
}
{
PBD::Unwinder<bool> uw (_solo_safe, false);
- set_solo (false, this);
+ set_solo (false, Controllable::NoGroup);
}
if (emit_changed) {
set_mute_master_solo ();
- solo_changed (false, this, false); /* EMIT SIGNAL */
+ solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
}
}
void
-Route::set_solo (bool yn, void *src, bool group_override)
+Route::set_solo (bool yn, Controllable::GroupControlDisposition group_override)
{
if (_solo_safe) {
DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo change due to solo-safe\n", name()));
return;
}
- bool group_active = _route_group && _route_group->is_active() && _route_group->is_solo();
- if (group_override && _route_group) {
- group_active = !group_active;
- }
- if (_route_group && src != _route_group && group_active) {
- _route_group->foreach_route (boost::bind (&Route::set_solo, _1, yn, _route_group, group_override));
+ if (use_group (group_override, &RouteGroup::is_solo)) {
+ _route_group->foreach_route (boost::bind (&Route::set_solo, _1, yn, Controllable::NoGroup));
return;
}
- DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set solo => %2, src: %3 grp ? %4 currently self-soloed ? %5\n",
- name(), yn, src, (src == _route_group), self_soloed()));
+ DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set solo => %2, grp ? %3 currently self-soloed ? %4\n",
+ name(), yn, enum_2_string(group_override), self_soloed()));
if (self_soloed() != yn) {
set_self_solo (yn);
- solo_changed (true, src, group_override); /* EMIT SIGNAL */
+ solo_changed (true, group_override); /* EMIT SIGNAL */
_solo_control->Changed (); /* EMIT SIGNAL */
}
*/
if (yn && Profile->get_trx()) {
- set_mute (false, src);
+ set_mute (false, Controllable::UseGroup);
}
}
}
set_mute_master_solo ();
- solo_changed (false, this, false); /* EMIT SIGNAL */
+ solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
}
void
DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbD delta %2 = %3\n", name(), delta, _soloed_by_others_downstream));
set_mute_master_solo ();
- solo_changed (false, this, false); /* EMIT SIGNAL */
+ solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
}
void
}
void
-Route::mod_solo_isolated_by_upstream (bool yn, void* src)
+Route::mod_solo_isolated_by_upstream (bool yn)
{
bool old = solo_isolated ();
DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod_solo_isolated_by_upstream cur: %2 d: %3\n",
if (solo_isolated() != old) {
/* solo isolated status changed */
_mute_master->set_solo_ignore (solo_isolated());
- solo_isolated_changed (src); /* EMIT SIGNAL */
+ solo_isolated_changed (); /* EMIT SIGNAL */
}
}
void
-Route::set_solo_isolated (bool yn, void *src)
+Route::set_solo_isolated (bool yn, Controllable::GroupControlDisposition group_override)
{
if (is_master() || is_monitor() || is_auditioner()) {
return;
}
- if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_solo()) {
- _route_group->foreach_route (boost::bind (&Route::set_solo_isolated, _1, yn, _route_group));
+ if (use_group (group_override, &RouteGroup::is_solo)) {
+ _route_group->foreach_route (boost::bind (&Route::set_solo_isolated, _1, yn, Controllable::NoGroup));
return;
}
bool does_feed = feeds (*i, &sends_only);
if (does_feed && !sends_only) {
- (*i)->mod_solo_isolated_by_upstream (yn, src);
+ (*i)->mod_solo_isolated_by_upstream (yn);
}
}
/* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */
- solo_isolated_changed (src); /* EMIT SIGNAL */
+ solo_isolated_changed (); /* EMIT SIGNAL */
+ _solo_isolate_control->Changed(); /* EMIT SIGNAL */
}
bool
mute_points_changed (); /* EMIT SIGNAL */
if (_mute_master->muted_by_self()) {
- mute_changed (this); /* EMIT SIGNAL */
+ mute_changed (); /* EMIT SIGNAL */
_mute_control->Changed (); /* EMIT SIGNAL */
}
}
void
-Route::set_mute (bool yn, void *src)
+Route::set_mute (bool yn, Controllable::GroupControlDisposition group_override)
{
- if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_mute()) {
- _route_group->foreach_route (boost::bind (&Route::set_mute, _1, yn, _route_group));
+ if (use_group (group_override, &RouteGroup::is_mute)) {
+ _route_group->foreach_route (boost::bind (&Route::set_mute, _1, yn, Controllable::NoGroup));
return;
}
*/
act_on_mute ();
/* tell everyone else */
- mute_changed (src); /* EMIT SIGNAL */
+ mute_changed (); /* EMIT SIGNAL */
_mute_control->Changed (); /* EMIT SIGNAL */
}
}
if ((*p)->can_support_io_configuration(in, out)) {
DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1 ID=%2 in=%3 out=%4\n",(*p)->name(), (*p)->id(), in, out));
configuration.push_back(make_pair(in, out));
+
+ 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)
+ */
+ DEBUG_TRACE (DEBUG::Processors, "Monitor: Channel configuration not allowed.\n");
+ return list<pair<ChanCount, ChanCount> > ();
+ }
+ if (boost::dynamic_pointer_cast<InternalSend> (*p)) {
+ // internal sends make no sense, only feedback
+ DEBUG_TRACE (DEBUG::Processors, "Monitor: No Sends allowed.\n");
+ return list<pair<ChanCount, ChanCount> > ();
+ }
+ if (boost::dynamic_pointer_cast<PortInsert> (*p)) {
+ /* External Sends can be problematic. one can add/remove ports
+ * there signal leaves the DAW to external monitors anyway, so there's
+ * no real use for allowing them here anyway.
+ */
+ DEBUG_TRACE (DEBUG::Processors, "Monitor: No External Sends allowed.\n");
+ return list<pair<ChanCount, ChanCount> > ();
+ }
+ if (boost::dynamic_pointer_cast<Send> (*p)) {
+ // ditto
+ DEBUG_TRACE (DEBUG::Processors, "Monitor: No Sends allowed.\n");
+ return list<pair<ChanCount, ChanCount> > ();
+ }
+ }
in = out;
} else {
if (err) {
XMLNode&
Route::state(bool full_state)
{
+ 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];
}
}
+ if (!_session._template_state_dir.empty()) {
+ foreach_processor (sigc::bind (sigc::mem_fun (*this, &Route::set_plugin_state_dir), ""));
+ }
+
return *node;
}
}
if ((prop = node.property ("solo-isolated")) != 0) {
- set_solo_isolated (string_is_affirmative (prop->value()), this);
+ set_solo_isolated (string_is_affirmative (prop->value()), Controllable::NoGroup);
}
if ((prop = node.property ("solo-safe")) != 0) {
- set_solo_safe (string_is_affirmative (prop->value()), this);
+ set_solo_safe (string_is_affirmative (prop->value()), Controllable::NoGroup);
}
if ((prop = node.property (X_("phase-invert"))) != 0) {
/* XXX force reset of solo status */
- set_solo (yn, this);
+ set_solo (yn);
}
if ((prop = node.property (X_("muted"))) != 0) {
gain_t val;
if (sscanf (prop->value().c_str(), "%f", &val) == 1) {
- _amp->gain_control()->set_value (val);
+ _amp->gain_control()->set_value (val, Controllable::NoGroup);
}
}
Route::set_comment (string cmt, void *src)
{
_comment = cmt;
- comment_changed (src);
+ comment_changed ();
_session.set_dirty ();
}
if (_solo_isolated_by_upstream) {
// solo-isolate currently only propagates downstream
if (idelta < 0) {
- mod_solo_isolated_by_upstream (false, this);
+ mod_solo_isolated_by_upstream (false);
}
// TODO think: mod_solo_isolated_by_upstream() does not take delta arg,
// but idelta can't be smaller than -1, can it?
}
if (idelta < 0 && does_feed && !sends_only) {
- (*i)->mod_solo_isolated_by_upstream (false, this);
+ (*i)->mod_solo_isolated_by_upstream (false);
}
}
}
}
}
-Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr<Route> r)
- : 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)));
- gl->set_interpolation(Evoral::ControlList::Discrete);
- set_list (gl);
-}
-
-void
-Route::SoloControllable::set_value (double val)
-{
- if (writable()) {
- set_value_unchecked (val);
- }
-}
-
-void
-Route::SoloControllable::set_value_unchecked (double val)
-{
- const bool bval = ((val >= 0.5) ? true : false);
-
- boost::shared_ptr<RouteList> rl (new RouteList);
-
- boost::shared_ptr<Route> r = _route.lock ();
- if (!r) {
- return;
- }
-
- rl->push_back (r);
-
- if (Config->get_solo_control_is_listen_control()) {
- _session.set_listen (rl, bval);
- } else {
- _session.set_solo (rl, bval);
- }
-}
-
-double
-Route::SoloControllable::get_value () const
-{
- boost::shared_ptr<Route> r = _route.lock ();
- if (!r) {
- return 0;
- }
-
- if (Config->get_solo_control_is_listen_control()) {
- return r->listening_via_monitor() ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
- } else {
- return r->self_soloed() ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
- }
-}
-
-Route::MuteControllable::MuteControllable (std::string name, boost::shared_ptr<Route> r)
- : 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)));
- gl->set_interpolation(Evoral::ControlList::Discrete);
- set_list (gl);
-}
-
-void
-Route::MuteControllable::set_superficial_value(bool muted)
-{
- /* Note we can not use AutomationControl::set_value here since it will emit
- Changed(), but the value will not be correct to the observer. */
-
- const bool to_list = _list && ((AutomationList*)_list.get ())->automation_write ();
- const double where = _session.audible_frame ();
- if (to_list) {
- /* Note that we really need this:
- * if (as == Touch && _list->in_new_write_pass ()) {
- * alist->start_write_pass (_session.audible_frame ());
- * }
- * here in the case of the user calling from a GUI or whatever.
- * Without the ability to distinguish between user and
- * automation-initiated changes, we lose the "touch mute"
- * behaviour we have in AutomationController::toggled ().
- */
- _list->set_in_write_pass (true, false, where);
- }
-
- Control::set_double (muted, where, to_list);
-}
-
-void
-Route::MuteControllable::set_value (double val)
-{
- if (writable()) {
- set_value_unchecked (val);
- }
-}
-
-void
-Route::MuteControllable::set_value_unchecked (double val)
-{
- const bool bval = ((val >= 0.5) ? true : false);
-
- boost::shared_ptr<Route> r = _route.lock ();
- if (!r) {
- return;
- }
-
- if (_list && ((AutomationList*)_list.get())->automation_playback()) {
- // Set superficial/automation value to drive controller (and possibly record)
- set_superficial_value (bval);
- // Playing back automation, set route mute directly
- r->set_mute (bval, this);
- } else {
- // Set from user, queue mute event
- boost::shared_ptr<RouteList> rl (new RouteList);
- rl->push_back (r);
- _session.set_mute (rl, bval, Session::rt_cleanup);
- }
-}
-
-double
-Route::MuteControllable::get_value () const
-{
- if (_list && ((AutomationList*)_list.get())->automation_playback()) {
- // Playing back automation, get the value from the list
- return AutomationControl::get_value();
- }
-
- // Not playing back automation, get the actual route mute value
- boost::shared_ptr<Route> r = _route.lock ();
- return (r && r->muted()) ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
-}
-
-Route::GroupGainControllable::GroupGainControllable (std::string name, boost::shared_ptr<Route> r)
- : AutomationControl (r->session(),
- Evoral::Parameter (GainAutomation),
- ParameterDescriptor (Evoral::Parameter (GainAutomation)),
- boost::shared_ptr<AutomationList>(),
- name)
- , _route (r)
-{
- boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(GainAutomation)));
- gl->set_interpolation(Evoral::ControlList::Discrete);
- set_list (gl);
-}
-
-void
-Route::GroupGainControllable::set_value (double val)
-{
- boost::shared_ptr<Route> r = _route.lock ();
- // I am not sure why I need the * .5 to make this work
- float normalized_position = r->gain_control()->interface_to_internal (val * 0.5);
- r->set_gain ((gain_t)normalized_position, this);
-}
-
-double
-Route::GroupGainControllable::get_value () const
-{
- boost::shared_ptr<Route> r = _route.lock ();
- return 2.0 * r->gain_control()->internal_to_interface (r->gain_control()->get_value ());
-}
-
-Route::PhaseControllable::PhaseControllable (std::string name, boost::shared_ptr<Route> r)
- : AutomationControl (r->session(),
- Evoral::Parameter (PhaseAutomation),
- ParameterDescriptor (Evoral::Parameter (PhaseAutomation)),
- boost::shared_ptr<AutomationList>(),
- name)
- , _route (r)
-{
- boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(PhaseAutomation)));
- gl->set_interpolation(Evoral::ControlList::Discrete);
- set_list (gl);
-}
-
-void
-Route::PhaseControllable::set_value (double v)
-{
- boost::shared_ptr<Route> r = _route.lock ();
- if (r->phase_invert().size()) {
- if (v == 0 || (v < 1 && v > 0.9) ) {
- r->set_phase_invert (_current_phase, false);
- } else {
- r->set_phase_invert (_current_phase, true);
- }
- }
-}
-
-double
-Route::PhaseControllable::get_value () const
-{
- boost::shared_ptr<Route> r = _route.lock ();
- return (double) r->phase_invert (_current_phase);
-}
-
-void
-Route::PhaseControllable::set_channel (uint32_t c)
-{
- _current_phase = c;
-}
-
-uint32_t
-Route::PhaseControllable::channel () const
-{
- return _current_phase;
-}
-
void
Route::set_block_size (pframes_t nframes)
{
}
}
+void
+Route::set_plugin_state_dir (boost::weak_ptr<Processor> p, const std::string& d)
+{
+ boost::shared_ptr<Processor> processor (p.lock ());
+ boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
+ if (!pi) {
+ return;
+ }
+ pi->set_state_dir (d);
+}
int
Route::save_as_template (const string& path, const string& name)
{
- {
- // would be nice to use foreach_processor()
- Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
- std::string state_dir = path.substr (0, path.find_last_of ('.')); // strip template_suffix
- 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->set_state_dir (state_dir);
- }
- }
- }
+ 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));
- {
- Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
- 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->set_state_dir ();
- }
- }
- }
-
XMLTree tree;
IO::set_name_in_state (*node.children().front(), name);
tree.set_root (&node);
- // TODO: special case LV2 plugin state
- // copy of serialize it. Alternatively:
- // create a plugin-preset (which can be loaded separately)
/* return zero on success, non-zero otherwise */
return !tree.write (path.c_str());
if (_phase_invert[c] != yn) {
_phase_invert[c] = yn;
phase_invert_changed (); /* EMIT SIGNAL */
+ _phase_control->Changed(); /* EMIT SIGNAL */
_session.set_dirty ();
}
}
return _main_outs->panner_shell();
}
-boost::shared_ptr<AutomationControl>
+boost::shared_ptr<GainControl>
Route::gain_control() const
{
- return _amp->gain_control();
+ return _gain_control;
}
-boost::shared_ptr<AutomationControl>
+boost::shared_ptr<GainControl>
Route::trim_control() const
{
- return _trim->gain_control();
+ return _trim_control;
+}
+
+boost::shared_ptr<Route::PhaseControllable>
+Route::phase_control() const
+{
+ if (phase_invert().size()) {
+ return _phase_control;
+ } else {
+ return boost::shared_ptr<PhaseControllable>();
+ }
}
boost::shared_ptr<AutomationControl>
}
boost::shared_ptr<Processor>
-Route::nth_plugin (uint32_t n)
+Route::nth_plugin (uint32_t n) const
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
- ProcessorList::iterator i;
+ ProcessorList::const_iterator i;
for (i = _processors.begin(); i != _processors.end(); ++i) {
if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
}
boost::shared_ptr<Processor>
-Route::nth_send (uint32_t n)
+Route::nth_send (uint32_t n) const
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
- ProcessorList::iterator i;
+ ProcessorList::const_iterator i;
for (i = _processors.begin(); i != _processors.end(); ++i) {
if (boost::dynamic_pointer_cast<Send> (*i)) {
+
+ if ((*i)->name().find (_("Monitor")) == 0) {
+ /* send to monitor section is not considered
+ to be an accessible send.
+ */
+ continue;
+ }
+
if (n-- == 0) {
return *i;
}
if (_monitor_control && is_monitor ()) {
assert (!_monitor_control->display_to_user ());
- new_processors.push_front (_monitor_control);
+ new_processors.insert (amp, _monitor_control);
}
/* INTERNAL RETURN */
{
#ifdef MIXBUS
boost::shared_ptr<ARDOUR::PluginInsert> plug = ch_post();
- assert (plug);
+ 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
return _("Compressor");
case 2:
return _("Limiter");
+ case 3:
+ return mixbus() ? _("Sidechain") : _("Limiter");
}
return _("???");
case 1:
return _("Ratio");
case 2:
+ case 3:
return _("Rels");
}
return _("???");
return _("???");
#endif
}
+
+boost::shared_ptr<AutomationControl>
+Route::send_level_controllable (uint32_t n) const
+{
+#ifdef MIXBUS
+ boost::shared_ptr<ARDOUR::PluginInsert> plug = ch_post();
+ if (!plug) {
+ return boost::shared_ptr<AutomationControl>();
+ }
+
+ if (n >= 8) {
+ /* no such bus */
+ return boost::shared_ptr<AutomationControl>();
+ }
+
+ 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
+ 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
+ boost::shared_ptr<ARDOUR::PluginInsert> plug = ch_post();
+ if (!plug) {
+ return boost::shared_ptr<AutomationControl>();
+ }
+
+ if (n >= 8) {
+ /* no such bus */
+ return boost::shared_ptr<AutomationControl>();
+ }
+
+ 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
+ /* although Ardour sends have enable/disable as part of the Processor
+ API, it is not exposed as a controllable.
+
+ XXX: we should fix this.
+ */
+ return boost::shared_ptr<AutomationControl>();
+#endif
+}
+
+string
+Route::send_name (uint32_t n) const
+{
+#ifdef MIXBUS
+ if (n >= 8) {
+ return string();
+ }
+ boost::shared_ptr<Route> r = _session.get_mixbus (n);
+ assert (r);
+ return r->name();
+#else
+ boost::shared_ptr<Processor> p = nth_send (n);
+ if (p) {
+ return p->name();
+ } else {
+ return string();
+ }
+#endif
+}
+
+boost::shared_ptr<AutomationControl>
+Route::master_send_enable_controllable () const
+{
+#ifdef MIXBUS
+ boost::shared_ptr<ARDOUR::PluginInsert> plug = ch_post();
+ if (!plug) {
+ return boost::shared_ptr<AutomationControl>();
+ }
+ 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>();
+#endif
+}