X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Froute.cc;h=74b3a87fcf96985adacca1b9981f8236f1cac14e;hb=420cc9b4478059cfeabd8da5b2a25595a1de29fb;hp=caae7af43a5f2189d94e17d3f168b690009a0d08;hpb=9cddc7cda09997fd45bd6aae61be94f4337f617e;p=ardour.git diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index caae7af43a..74b3a87fcf 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -46,6 +46,7 @@ #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" @@ -56,6 +57,7 @@ #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" @@ -137,6 +139,9 @@ Route::init () _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)); @@ -171,16 +176,22 @@ Route::init () /* add amp processor */ - _amp.reset (new Amp (_session)); + _gain_control = boost::shared_ptr (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 (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(this)) { @@ -380,19 +391,30 @@ Route::ensure_track_or_route_name(string name, Session &session) } 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; } @@ -423,34 +445,28 @@ Route::set_gain (gain_t val, void *src) } } - _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); + _gain_control->route_set_value (val); } void -Route::inc_trim (gain_t fraction, void *src) -{ - _trim->inc_gain (fraction, src); -} - -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 @@ -647,7 +663,7 @@ Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes, break; } - /* if we're not exporting, stop processing if we come across a routing processor. */ + /* if we're *not* exporting, stop processing if we come across a routing processor. */ if (!for_export && boost::dynamic_pointer_cast(*i)) { break; } @@ -655,8 +671,20 @@ Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes, break; } - /* don't run any processors that does routing. - * oh, and don't bother with the peak meter either. + /* special case the panner (export outputs) + * Ideally we'd only run the panner, not the delivery itself... + * but panners need separate input/output buffers and some context + * (panshell, panner type, etc). AFAICT there is no ill side effect + * of re-using the main delivery when freewheeling/exporting a region. + */ + if ((*i) == _main_outs) { + assert ((*i)->does_routing()); + (*i)->run (buffers, start - latency, start - latency + nframes, nframes, true); + buffers.set_count ((*i)->output_streams()); + } + + /* don't run any processors that do routing. + * Also don't bother with metering. */ if (!(*i)->does_routing() && !boost::dynamic_pointer_cast(*i)) { (*i)->run (buffers, start - latency, start - latency + nframes, nframes, true); @@ -772,19 +800,14 @@ Route::passthru_silence (framepos_t start_frame, framepos_t end_frame, pframes_t } 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::ForGroup)); return; } @@ -799,7 +822,7 @@ Route::set_listen (bool yn, void* src, bool group_override) } _mute_master->set_soloed_by_others (false); - listen_changed (src, group_override); /* EMIT SIGNAL */ + listen_changed (group_override); /* EMIT SIGNAL */ } } } @@ -815,11 +838,12 @@ Route::listening_via_monitor () const } 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 */ } } @@ -856,18 +880,21 @@ Route::clear_all_solo_state () { PBD::Unwinder 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) { + 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 (_solo_safe) { DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo change due to solo-safe\n", name())); return; @@ -878,21 +905,14 @@ Route::set_solo (bool yn, void *src, bool group_override) 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::ForGroup)); 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())); - 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 */ } @@ -903,7 +923,7 @@ Route::set_solo (bool yn, void *src, bool group_override) */ if (yn && Profile->get_trx()) { - set_mute (false, src); + set_mute (false, Controllable::UseGroup); } } @@ -970,7 +990,7 @@ Route::mod_solo_by_others_upstream (int32_t delta) } set_mute_master_solo (); - solo_changed (false, this, false); /* EMIT SIGNAL */ + solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */ } void @@ -992,7 +1012,7 @@ Route::mod_solo_by_others_downstream (int32_t delta) 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 @@ -1003,7 +1023,7 @@ Route::set_mute_master_solo () } 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", @@ -1022,19 +1042,19 @@ Route::mod_solo_isolated_by_upstream (bool yn, void* src) 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::ForGroup)); return; } @@ -1072,13 +1092,14 @@ Route::set_solo_isolated (bool yn, void *src) 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 @@ -1094,16 +1115,16 @@ Route::set_mute_points (MuteMaster::MutePoint mp) 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::ForGroup)); return; } @@ -1114,7 +1135,7 @@ Route::set_mute (bool yn, void *src) */ act_on_mute (); /* tell everyone else */ - mute_changed (src); /* EMIT SIGNAL */ + mute_changed (); /* EMIT SIGNAL */ _mute_control->Changed (); /* EMIT SIGNAL */ } } @@ -2502,11 +2523,11 @@ Route::set_state (const XMLNode& node, int version) } 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) { @@ -2661,7 +2682,7 @@ Route::set_state_2X (const XMLNode& node, int version) /* XXX force reset of solo status */ - set_solo (yn, this); + set_solo (yn); } if ((prop = node.property (X_("muted"))) != 0) { @@ -2800,7 +2821,7 @@ Route::set_state_2X (const XMLNode& node, int version) 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); } } @@ -2963,7 +2984,8 @@ Route::set_processor_state (const XMLNode& node) } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" || prop->value() == "lv2" || prop->value() == "windows-vst" || - prop->value() == "lxvst" || + prop->value() == "lxvst" || + prop->value() == "luaproc" || prop->value() == "audiounit") { if (_session.get_disable_all_loaded_plugins ()) { @@ -3228,7 +3250,7 @@ void Route::set_comment (string cmt, void *src) { _comment = cmt; - comment_changed (src); + comment_changed (); _session.set_dirty (); } @@ -3402,7 +3424,7 @@ Route::input_change_handler (IOChange change, void * /*src*/) 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? @@ -3422,7 +3444,7 @@ Route::input_change_handler (IOChange change, void * /*src*/) } if (idelta < 0 && does_feed && !sends_only) { - (*i)->mod_solo_isolated_by_upstream (false, this); + (*i)->mod_solo_isolated_by_upstream (false); } } } @@ -3881,217 +3903,6 @@ Route::set_latency_compensation (framecnt_t longest_session_latency) } } -Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr r) - : AutomationControl (r->session(), - Evoral::Parameter (SoloAutomation), - ParameterDescriptor(Evoral::Parameter (SoloAutomation)), - boost::shared_ptr(), name) - , _route (r) -{ - boost::shared_ptr 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 rl (new RouteList); - - boost::shared_ptr 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 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 r) - : AutomationControl (r->session(), - Evoral::Parameter (MuteAutomation), - ParameterDescriptor (Evoral::Parameter (MuteAutomation)), - boost::shared_ptr(), - name) - , _route (r) -{ - boost::shared_ptr 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 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 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 r = _route.lock (); - return (r && r->muted()) ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO; -} - -Route::GroupGainControllable::GroupGainControllable (std::string name, boost::shared_ptr r) - : AutomationControl (r->session(), - Evoral::Parameter (GainAutomation), - ParameterDescriptor (Evoral::Parameter (GainAutomation)), - boost::shared_ptr(), - name) - , _route (r) -{ - boost::shared_ptr 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 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 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 r) - : AutomationControl (r->session(), - Evoral::Parameter (PhaseAutomation), - ParameterDescriptor (Evoral::Parameter (PhaseAutomation)), - boost::shared_ptr(), - name) - , _route (r) -{ - boost::shared_ptr 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 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 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) { @@ -4317,6 +4128,7 @@ Route::set_phase_invert (uint32_t c, bool yn) if (_phase_invert[c] != yn) { _phase_invert[c] = yn; phase_invert_changed (); /* EMIT SIGNAL */ + _phase_control->Changed(); /* EMIT SIGNAL */ _session.set_dirty (); } } @@ -4398,16 +4210,26 @@ Route::panner_shell() const return _main_outs->panner_shell(); } -boost::shared_ptr +boost::shared_ptr Route::gain_control() const { - return _amp->gain_control(); + return _gain_control; } -boost::shared_ptr +boost::shared_ptr Route::trim_control() const { - return _trim->gain_control(); + return _trim_control; +} + +boost::shared_ptr +Route::phase_control() const +{ + if (phase_invert().size()) { + return _phase_control; + } else { + return boost::shared_ptr(); + } } boost::shared_ptr @@ -4441,10 +4263,10 @@ Route::get_control (const Evoral::Parameter& param) } boost::shared_ptr -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 (*i)) { @@ -4458,13 +4280,21 @@ Route::nth_plugin (uint32_t n) } boost::shared_ptr -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 (*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; } @@ -5093,7 +4923,9 @@ Route::pan_azimuth_control() const { #ifdef MIXBUS boost::shared_ptr plug = ch_post(); - assert (plug); + if (!plug) { + return boost::shared_ptr(); + } const uint32_t port_channel_post_pan = 2; // gtk2_ardour/mixbus_ports.h return boost::dynamic_pointer_cast (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_channel_post_pan))); #else @@ -5421,6 +5253,8 @@ Route::comp_mode_name (uint32_t mode) const return _("Compressor"); case 2: return _("Limiter"); + case 3: + return mixbus() ? _("Sidechain") : _("Limiter"); } return _("???"); @@ -5439,6 +5273,7 @@ Route::comp_speed_name (uint32_t mode) const case 1: return _("Ratio"); case 2: + case 3: return _("Rels"); } return _("???"); @@ -5446,3 +5281,88 @@ Route::comp_speed_name (uint32_t mode) const return _("???"); #endif } + +boost::shared_ptr +Route::send_level_controllable (uint32_t n) const +{ +#ifdef MIXBUS + boost::shared_ptr plug = ch_post(); + if (!plug) { + return boost::shared_ptr(); + } + + if (n >= 8) { + /* no such bus */ + return boost::shared_ptr(); + } + + const uint32_t port_id = port_channel_post_aux1_level + (2*n); // gtk2_ardour/mixbus_ports.h + return boost::dynamic_pointer_cast (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_id))); +#else + boost::shared_ptr s = boost::dynamic_pointer_cast(nth_send (n)); + if (!s) { + return boost::shared_ptr(); + } + return s->gain_control (); +#endif +} + +boost::shared_ptr +Route::send_enable_controllable (uint32_t n) const +{ +#ifdef MIXBUS + boost::shared_ptr plug = ch_post(); + if (!plug) { + return boost::shared_ptr(); + } + + if (n >= 8) { + /* no such bus */ + return boost::shared_ptr(); + } + + const uint32_t port_id = port_channel_post_aux1_asgn + (2*n); // gtk2_ardour/mixbus_ports.h + return boost::dynamic_pointer_cast (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(); +#endif +} + +string +Route::send_name (uint32_t n) const +{ +#ifdef MIXBUS + if (n >= 8) { + return string(); + } + boost::shared_ptr r = _session.get_mixbus (n); + assert (r); + return r->name(); +#else + boost::shared_ptr p = nth_send (n); + if (p) { + return p->name(); + } else { + return string(); + } +#endif +} + +boost::shared_ptr +Route::master_send_enable_controllable () const +{ +#ifdef MIXBUS + boost::shared_ptr plug = ch_post(); + if (!plug) { + return boost::shared_ptr(); + } + return boost::dynamic_pointer_cast (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_channel_post_mstr_assign))); +#else + return boost::shared_ptr(); +#endif +}