#include <pbd/xml++.h>
#include <pbd/enumwriter.h>
#include <pbd/stacktrace.h>
+#include <pbd/memento_command.h>
#include <ardour/timestamps.h>
#include <ardour/audioengine.h>
using namespace PBD;
uint32_t Route::order_key_cnt = 0;
-sigc::signal<void> Route::SyncOrderKeys;
+sigc::signal<void,const char*> Route::SyncOrderKeys;
Route::Route (Session& sess, string name, int input_min, int input_max, int output_min, int output_max, Flag flg, DataType default_type)
: IO (sess, name, input_min, input_max, output_min, output_max, default_type),
free ((void*)(i->first));
}
- if (_control_outs) {
- delete _control_outs;
- }
+ delete _control_outs;
}
void
}
void
-Route::sync_order_keys ()
+Route::sync_order_keys (const char* base)
{
- uint32_t key;
-
if (order_keys.empty()) {
return;
}
-
- OrderKeys::iterator x = order_keys.begin();
- key = x->second;
- ++x;
- for (; x != order_keys.end(); ++x) {
- x->second = key;
+ OrderKeys::iterator i;
+ uint32_t key;
+
+ if ((i = order_keys.find (base)) == order_keys.end()) {
+ /* key doesn't exist, use the first existing
+ key (this is done during session initialization)
+ */
+ i = order_keys.begin();
+ key = i->second;
+ ++i;
+ } else {
+ /* key exists - use it and reset all others
+ (actually, itself included)
+ */
+ i = order_keys.begin();
+ key = i->second;
+ }
+
+ for (; i != order_keys.end(); ++i) {
+ i->second = key;
}
}
}
}
- // This really should already be true...
- bufs.set_count(pre_fader_streams());
+ /* When we entered this method, the number of bufs was set by n_process_buffers(), so
+ * it may be larger than required. Consider, for example, a mono track with two redirects A and B.
+ * If A has one input and three outputs, and B three inputs and one output, n_process_buffers()
+ * will be 3. In this case, now we've done pre-fader redirects, we can reset the number of bufs.
+ */
+ bufs.set_count (pre_fader_streams());
if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_post_fader) {
Amp::run_in_place (bufs, nframes, mute_gain, dmg, false);
_soloed = yn;
solo_changed (src); /* EMIT SIGNAL */
_solo_control->Changed (); /* EMIT SIGNAL */
+ }
+
+ catch_up_on_solo_mute_override ();
+}
+
+void
+Route::catch_up_on_solo_mute_override ()
+{
+ if (Config->get_solo_model() != InverseMute) {
+ return;
+ }
+
+ {
+
+ Glib::Mutex::Lock lm (declick_lock);
+
+ if (_muted) {
+ if (Config->get_solo_mute_override()) {
+ desired_mute_gain = (_soloed?1.0:0.0);
+ } else {
+ desired_mute_gain = 0.0;
+ }
+ } else {
+ desired_mute_gain = 1.0;
+ }
}
}
_mute_control->Changed (); /* EMIT SIGNAL */
Glib::Mutex::Lock lm (declick_lock);
- desired_mute_gain = (yn?0.0f:1.0f);
+
+ if (_soloed && Config->get_solo_mute_override()){
+ desired_mute_gain = 1.0f;
+ } else {
+ desired_mute_gain = (yn?0.0f:1.0f);
+ }
}
}
int
Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
{
+ /* NOTE: this is intended to be used ONLY when copying
+ processors from another Route. Hence the subtle
+ differences between this and ::add_processor()
+ */
+
ChanCount old_pmo = processor_max_outs;
if (!_session.engine().connected()) {
return -1;
}
- (*i)->activate ();
(*i)->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false));
}
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if ((*i)->placement() == p) {
- (*i)->set_active (false);
+ (*i)->deactivate ();
}
}
Glib::RWLock::ReaderLock lm (_processor_lock);
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- (*i)->set_active (false);
+ (*i)->deactivate ();
}
_session.set_dirty ();
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if (boost::dynamic_pointer_cast<PluginInsert> (*i) && (*i)->placement() == p) {
- (*i)->set_active (false);
+ (*i)->deactivate ();
}
}
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
- (*i)->set_active (false);
+ (*i)->deactivate ();
}
}
}
if ((*i)->active()) {
- (*i)->set_active (false);
+ (*i)->deactivate ();
(*i)->set_next_ab_is_active (true);
} else {
(*i)->set_next_ab_is_active (false);
}
if ((*i)->get_next_ab_is_active()) {
- (*i)->set_active (true);
+ (*i)->activate ();
} else {
- (*i)->set_active (false);
+ (*i)->deactivate ();
}
}
}
{
boost::shared_ptr<Processor> processor;
- // Find the last pre-fader redirect
+ /* Find the last pre-fader redirect that isn't a send; sends don't affect the number
+ * of streams. */
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
- if ((*i)->placement() == PreFader) {
+ if ((*i)->placement() == PreFader && boost::dynamic_pointer_cast<Send> (*i) == 0) {
processor = *i;
}
}
plugin_insert->set_count (1);
} else if ((port_insert = boost::dynamic_pointer_cast<PortInsert>(*r)) != 0) {
-
+
++insert_cnt;
proc_map[(*r)->placement()].push_back (ProcessorCount (*r));
++send_cnt;
}
}
-
+
if (insert_cnt == 0) {
if (send_cnt) {
goto recompute;
if (!proc_map[PreFader].empty()) {
previous_initial_streams = n_inputs ();
for (list<ProcessorCount>::iterator i = proc_map[PreFader].begin(); i != proc_map[PreFader].end(); i++) {
- if (i->processor->can_support_io_configuration (previous_initial_streams, initial_streams) < 0) {
+ if (i->processor->can_support_io_configuration (previous_initial_streams, initial_streams) == false) {
goto streamcount;
}
previous_initial_streams = initial_streams;
if (!proc_map[PostFader].empty()) {
for (list<ProcessorCount>::iterator i = proc_map[PostFader].begin(); i != proc_map[PostFader].end(); i++) {
- if (i->processor->can_support_io_configuration (previous_initial_streams, initial_streams) < 0) {
+ if (i->processor->can_support_io_configuration (previous_initial_streams, initial_streams) == false) {
goto streamcount;
}
previous_initial_streams = initial_streams;
boost::shared_ptr<Send> s;
if ((s = boost::dynamic_pointer_cast<Send> (*r)) != 0) {
+
+ /* don't pay any attention to send output configuration, since it doesn't
+ affect the route.
+ */
+
if (r == _processors.begin()) {
s->expect_inputs (n_inputs());
} else {
} else {
- /* don't pay any attention to send output configuration, since it doesn't
- affect the route.
- */
-
max_audio = max ((*r)->output_streams ().n_audio(), max_audio);
max_midi = max ((*r)->output_streams ().n_midi(), max_midi);
}
ProcessorCount& pc (*i);
- cerr << "now applying for " << (*i).processor->name() << " in = " << pc.in.n_audio() << " out = " << pc.out.n_audio() << endl;
-
if (pc.processor->configure_io (pc.in, pc.out)) {
return -1;
}
for (i = iclist.begin(); i != iclist.end(); ++i, ++index) {
- cerr << "Checking whether " << (*i).processor->name() << " can support " << required_inputs.n_audio() << " inputs\n";
-
if (!(*i).processor->can_support_io_configuration (required_inputs, (*i).out)) {
if (err) {
err->index = index;
return false;
}
-int
-Route::copy_processors (const Route& other, Placement placement, ProcessorStreams* err)
-{
- ChanCount old_pmo = processor_max_outs;
-
- ProcessorList to_be_deleted;
-
- {
- Glib::RWLock::WriterLock lm (_processor_lock);
- ProcessorList::iterator tmp;
- ProcessorList the_copy;
-
- the_copy = _processors;
-
- /* remove all relevant processors */
-
- for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ) {
- tmp = i;
- ++tmp;
-
- if ((*i)->placement() == placement) {
- to_be_deleted.push_back (*i);
- _processors.erase (i);
- }
-
- i = tmp;
- }
-
- /* now copy the relevant ones from "other" */
-
- for (ProcessorList::const_iterator i = other._processors.begin(); i != other._processors.end(); ++i) {
- if ((*i)->placement() == placement) {
- _processors.push_back (IOProcessor::clone (*i));
- }
- }
-
- /* reset plugin stream handling */
-
- if (_reset_processor_counts (err)) {
-
- /* FAILED COPY ATTEMPT: we have to restore order */
-
- /* delete all cloned processors */
-
- for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ) {
-
- tmp = i;
- ++tmp;
-
- if ((*i)->placement() == placement) {
- _processors.erase (i);
- }
-
- i = tmp;
- }
-
- /* restore the natural order */
-
- _processors = the_copy;
- processor_max_outs = old_pmo;
-
- /* we failed, even though things are OK again */
-
- return -1;
-
- } else {
-
- /* SUCCESSFUL COPY ATTEMPT: delete the processors we removed pre-copy */
- to_be_deleted.clear ();
- _user_latency = 0;
- }
- }
-
- if (processor_max_outs != old_pmo || old_pmo == ChanCount::ZERO) {
- reset_panner ();
- }
-
- processors_changed (); /* EMIT SIGNAL */
- return 0;
-}
-
void
Route::all_processors_flip ()
{
bool first_is_on = _processors.front()->active();
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- (*i)->set_active (!first_is_on);
+ if (first_is_on) {
+ (*i)->deactivate ();
+ } else {
+ (*i)->activate ();
+ }
}
_session.set_dirty ();
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if ((*i)->placement() == p) {
- (*i)->set_active (state);
+ if (state) {
+ (*i)->activate ();
+ } else {
+ (*i)->deactivate ();
+ }
}
}
node->add_property("mute-affects-pre-fader", _mute_affects_pre_fader?"yes":"no");
node->add_property("mute-affects-post-fader", _mute_affects_post_fader?"yes":"no");
node->add_property("mute-affects-control-outs", _mute_affects_control_outs?"yes":"no");
- node->add_property("mute-affects-main-outs", _mute_affects_main_outs?"yes":"no");
+ node->add_property("mute-affects-main-outs", _mute_affects_main_outs?"yes":"no");
+ node->add_property("meter-point", enum_2_string (_meter_point));
if (_edit_group) {
node->add_property("edit-group", _edit_group->name());
_mute_affects_main_outs = (prop->value()=="yes")?true:false;
}
+ if ((prop = node.property (X_("meter-point"))) != 0) {
+ _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point));
+ }
+
if ((prop = node.property (X_("edit-group"))) != 0) {
RouteGroup* edit_group = _session.edit_group_by_name(prop->value());
if(edit_group == 0) {
nlist = node.children();
- if (deferred_state) {
- delete deferred_state;
- }
-
+ delete deferred_state;
deferred_state = new XMLNode(X_("deferred state"));
/* set parent class properties before anything else */
string coutname = _name;
coutname += _("[control]");
+ delete _control_outs;
_control_outs = new IO (_session, coutname);
_control_outs->set_state (**(child->children().begin()));
vector<string>::const_iterator i;
size_t limit;
- if (_control_outs) {
- delete _control_outs;
- _control_outs = 0;
- }
+ delete _control_outs;
+ _control_outs = 0;
if (is_control() || is_master()) {
/* no control outs for these two special busses */
}
+/** Shift automation forwards from a particular place, thereby inserting time.
+ * Adds undo commands for any shifts that are performed.
+ *
+ * @param pos Position to start shifting from.
+ * @param frames Amount to shift forwards by.
+ */
+
+void
+Route::shift (nframes64_t pos, nframes64_t frames)
+{
+#ifdef THIS_NEEDS_FIXING_FOR_V3
+
+ /* gain automation */
+ XMLNode &before = _gain_control->get_state ();
+ _gain_control->shift (pos, frames);
+ XMLNode &after = _gain_control->get_state ();
+ _session.add_command (new MementoCommand<AutomationList> (_gain_automation_curve, &before, &after));
+
+ /* pan automation */
+ for (std::vector<StreamPanner*>::iterator i = _panner->begin (); i != _panner->end (); ++i) {
+ Curve & c = (*i)->automation ();
+ XMLNode &before = c.get_state ();
+ c.shift (pos, frames);
+ XMLNode &after = c.get_state ();
+ _session.add_command (new MementoCommand<AutomationList> (c, &before, &after));
+ }
+
+ /* redirect automation */
+ {
+ Glib::RWLock::ReaderLock lm (redirect_lock);
+ for (RedirectList::iterator i = _redirects.begin (); i != _redirects.end (); ++i) {
+
+ set<uint32_t> a;
+ (*i)->what_has_automation (a);
+
+ for (set<uint32_t>::const_iterator j = a.begin (); j != a.end (); ++j) {
+ AutomationList & al = (*i)->automation_list (*j);
+ XMLNode &before = al.get_state ();
+ al.shift (pos, frames);
+ XMLNode &after = al.get_state ();
+ _session.add_command (new MementoCommand<AutomationList> (al, &before, &after));
+ }
+ }
+ }
+#endif
+
+}