#include "ardour/session.h"
#include "ardour/unknown_processor.h"
#include "ardour/utils.h"
+#include "ardour/vca.h"
#include "i18n.h"
PBD::Signal0<void> Route::SyncOrderKeys;
PBD::Signal0<void> Route::RemoteControlIDChange;
+PBD::Signal3<int,boost::shared_ptr<Route>, boost::shared_ptr<PluginInsert>, Route::PluginSetupOptions > Route::PluginSetup;
/** Base class for all routable/mixable objects (tracks and busses) */
Route::Route (Session& sess, string name, Flag flg, DataType default_type)
- : SessionObject (sess, name)
+ : Stripable (sess, name)
, Automatable (sess)
, GraphNode (sess._process_graph)
, _active (true)
_output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2));
_output->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::output_port_count_changing, this, _1));
-#if 0 // not used - just yet
- if (!is_master() && !is_monitor() && !is_auditioner()) {
- _delayline.reset (new DelayLine (_session, _name));
- add_processor (_delayline, PreFader);
- }
-#endif
-
- /* add amp processor */
+ /* add the amp/fader processor.
+ * it should be the first processor to be added on every route.
+ */
_gain_control = boost::shared_ptr<GainControllable> (new GainControllable (_session, GainAutomation, shared_from_this ()));
add_control (_gain_control);
_amp->set_display_name (_("Monitor"));
}
+#if 0 // not used - just yet
+ if (!is_master() && !is_monitor() && !is_auditioner()) {
+ _delayline.reset (new DelayLine (_session, _name));
+ add_processor (_delayline, PreFader);
+ }
+#endif
+
/* and input trim */
_trim_control = boost::shared_ptr<GainControllable> (new GainControllable (_session, TrimAutomation, shared_from_this ()));
}
}
+
+inline Route::PluginSetupOptions operator|= (Route::PluginSetupOptions& a, const Route::PluginSetupOptions& b) {
+ return a = static_cast<Route::PluginSetupOptions> (static_cast <int>(a) | static_cast<int> (b));
+}
+
+inline Route::PluginSetupOptions operator&= (Route::PluginSetupOptions& a, const Route::PluginSetupOptions& b) {
+ return a = static_cast<Route::PluginSetupOptions> (static_cast <int>(a) & static_cast<int> (b));
+}
+
int
Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor> before, ProcessorStreams* err)
{
return 0;
}
+ ProcessorList to_skip;
+
+ // check if there's an instrument to replace or configure
+ for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) {
+ boost::shared_ptr<PluginInsert> pi;
+ if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) == 0) {
+ continue;
+ }
+ if (!pi->plugin ()->get_info ()->is_instrument ()) {
+ continue;
+ }
+ boost::shared_ptr<Processor> instrument = the_instrument ();
+ ChanCount in (DataType::MIDI, 1);
+ ChanCount out (DataType::AUDIO, 2); // XXX route's out?!
+
+ PluginSetupOptions flags = None;
+ if (instrument) {
+ flags |= CanReplace;
+ in = instrument->input_streams ();
+ out = instrument->output_streams ();
+ }
+ if (pi->has_output_presets (in, out)) {
+ flags |= MultiOut;
+ }
+
+ pi->set_strict_io (_strict_io);
+
+ PluginSetupOptions mask = None;
+ if (Config->get_ask_replace_instrument ()) {
+ mask |= CanReplace;
+ }
+ if (Config->get_ask_setup_instrument ()) {
+ mask |= MultiOut;
+ }
+
+ flags &= mask;
+
+ if (flags != None) {
+ boost::optional<int> rv = PluginSetup (shared_from_this (), pi, flags); /* EMIT SIGNAL */
+ switch (rv.get_value_or (0)) {
+ case 1:
+ to_skip.push_back (*i); // don't add this one;
+ break;
+ case 2:
+ replace_processor (instrument, *i, err);
+ to_skip.push_back (*i);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
{
Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
Glib::Threads::RWLock::WriterLock lm (_processor_lock);
if (*i == _meter) {
continue;
}
+ ProcessorList::iterator check = find (to_skip.begin(), to_skip.end(), *i);
+ if (check != to_skip.end()) {
+ continue;
+ }
boost::shared_ptr<PluginInsert> pi;
node->add_child_nocopy (_pannable->state (full_state));
}
- for (i = _processors.begin(); i != _processors.end(); ++i) {
- if (!full_state) {
- /* template save: do not include internal sends functioning as
- aux sends because the chance of the target ID
- in the session where this template is used
- is not very likely.
-
- similarly, do not save listen sends which connect to
- the monitor section, because these will always be
- added if necessary.
- */
- boost::shared_ptr<InternalSend> is;
+ {
+ Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+ for (i = _processors.begin(); i != _processors.end(); ++i) {
+ if (!full_state) {
+ /* template save: do not include internal sends functioning as
+ aux sends because the chance of the target ID
+ in the session where this template is used
+ is not very likely.
+
+ similarly, do not save listen sends which connect to
+ the monitor section, because these will always be
+ added if necessary.
+ */
+ boost::shared_ptr<InternalSend> is;
- if ((is = boost::dynamic_pointer_cast<InternalSend> (*i)) != 0) {
- if (is->role() == Delivery::Listen) {
- continue;
+ if ((is = boost::dynamic_pointer_cast<InternalSend> (*i)) != 0) {
+ if (is->role() == Delivery::Listen) {
+ continue;
+ }
}
}
+ node->add_child_nocopy((*i)->state (full_state));
}
- node->add_child_nocopy((*i)->state (full_state));
}
if (_extra_xml) {
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
- XMLProperty const * prop = (*niter)->property ("type");
+ XMLProperty* prop = (*niter)->property ("type");
if (prop->value() == "amp") {
_amp->set_state (**niter, Stateful::current_state_version);
return _gain_control;
}
-boost::shared_ptr<GainControl>
+boost::shared_ptr<AutomationControl>
Route::trim_control() const
{
return _trim_control;
}
-boost::shared_ptr<Route::PhaseControllable>
+boost::shared_ptr<AutomationControl>
Route::phase_control() const
{
if (phase_invert().size()) {
/* find the amp */
- ProcessorList::iterator amp = new_processors.begin ();
- while (amp != new_processors.end() && *amp != _amp) {
- ++amp;
- }
+ ProcessorList::iterator amp = find (new_processors.begin(), new_processors.end(), _amp);
- assert (amp != new_processors.end ());
+ if (amp == new_processors.end ()) {
+ error << string_compose (_("Amp/Fader on Route '%1' went AWOL. Re-added."), name()) << endmsg;
+ new_processors.push_front (_amp);
+ amp = find (new_processors.begin(), new_processors.end(), _amp);
+ }
/* and the processor after the amp */
return boost::shared_ptr<AutomationControl>();
#endif
}
+
+bool
+Route::slaved_to (boost::shared_ptr<VCA> vca) const
+{
+ if (!vca || !_gain_control) {
+ return false;
+ }
+
+ return _gain_control->slaved_to (vca);
+}
+
+void
+Route::vca_assign (boost::shared_ptr<VCA> vca)
+{
+ _gain_control->add_master (vca);
+ vca->add_solo_target (shared_from_this());
+ vca->add_mute_target (shared_from_this());
+}
+
+void
+Route::vca_unassign (boost::shared_ptr<VCA> vca)
+{
+ if (!vca) {
+ /* unassign from all */
+ _gain_control->clear_masters ();
+ /* XXXX need to remove from solo/mute target lists */
+ } else {
+ _gain_control->remove_master (vca);
+ vca->remove_solo_target (shared_from_this());
+ vca->remove_mute_target (shared_from_this());
+ }
+}