/* panning */
- Pannable* p = new Pannable (_session);
+ if (!(_flags & Route::MonitorOut)) {
+ Pannable* p = new Pannable (_session);
#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
- boost_debug_shared_ptr_mark_interesting (p, "Pannable");
+ boost_debug_shared_ptr_mark_interesting (p, "Pannable");
#endif
- _pannable.reset (p);
+ _pannable.reset (p);
+ }
/* input and output objects */
_output.reset (new IO (_session, _name, IO::Output, _default_type));
_input->changed.connect_same_thread (*this, boost::bind (&Route::input_change_handler, this, _1, _2));
- _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2));
-
_input->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::input_port_count_changing, this, _1));
/* add amp processor */
_intreturn.reset (new InternalReturn (_session));
_intreturn->activate ();
- /* the thing that provides proper control over a control/monitor/listen bus
+ /* the thing that provides proper control over a control/monitor/listen bus
(such as per-channel cut, dim, solo, invert, etc).
*/
_monitor_control.reset (new MonitorProcessor (_session));
{
DEBUG_TRACE (DEBUG::Destruction, string_compose ("route %1 destructor\n", _name));
- /* do this early so that we don't get incoming signals as we are going through destruction
+ /* do this early so that we don't get incoming signals as we are going through destruction
*/
drop_connections ();
/* don't use clear_processors here, as it depends on the session which may
- be half-destroyed by now
+ be half-destroyed by now
*/
Glib::RWLock::WriterLock lm (_processor_lock);
}
bool changed = false;
-
+
for (; i != order_keys.end(); ++i) {
if (i->second != key) {
i->second = key;
abort ();
}
}
-#endif
+#endif
/* should we NOT run plugins here if the route is inactive?
do we catch route != active somewhere higher?
*/
return;
}
+ if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_solo()) {
+ _route_group->foreach_route (boost::bind (&Route::set_listen, _1, yn, _route_group));
+ return;
+ }
+
if (_monitor_send) {
if (yn != _monitor_send->active()) {
if (yn) {
if (_solo_safe != yn) {
_solo_safe = yn;
solo_safe_changed (src);
- }
+ }
}
bool
DEBUG_TRACE (DEBUG::Solo, string_compose (
"%1 SbU delta %2 = %3 old = %4 sbd %5 ss %6 exclusive %7\n",
- name(), delta, _soloed_by_others_upstream, old_sbu,
+ name(), delta, _soloed_by_others_upstream, old_sbu,
_soloed_by_others_downstream, _self_solo, Config->get_exclusive_solo()));
- /* push the inverse solo change to everything that feeds us.
+ /* push the inverse solo change to everything that feeds us.
This is important for solo-within-group. When we solo 1 track out of N that
feed a bus, that track will cause mod_solo_by_upstream (+1) to be called
on the bus. The bus then needs to call mod_solo_by_downstream (-1) on all
tracks that feed it. This will silence them if they were audible because
- of a bus solo, but the newly soloed track will still be audible (because
+ of a bus solo, but the newly soloed track will still be audible (because
it is self-soloed).
but .. do this only when we are being told to solo-by-upstream (i.e delta = +1),
*/
if ((_self_solo || _soloed_by_others_downstream) &&
- ((old_sbu == 0 && _soloed_by_others_upstream > 0) ||
+ ((old_sbu == 0 && _soloed_by_others_upstream > 0) ||
(old_sbu > 0 && _soloed_by_others_upstream == 0))) {
if (delta > 0 || !Config->get_exclusive_solo()) {
sr->mod_solo_by_others_downstream (-delta);
}
}
- }
+ }
}
set_mute_master_solo ();
_route_group->foreach_route (boost::bind (&Route::set_solo_isolated, _1, yn, _route_group));
return;
}
-
+
/* forward propagate solo-isolate status to everything fed by this route, but not those via sends only */
boost::shared_ptr<RouteList> routes = _session.get_routes ();
bool sends_only;
bool does_feed = direct_feeds (*i, &sends_only); // we will recurse anyway, so don't use ::feeds()
-
+
if (does_feed && !sends_only) {
(*i)->set_solo_isolated (yn, (*i)->route_group());
}
cerr << name << " {" << endl;
for (list<boost::shared_ptr<Processor> >::const_iterator p = procs.begin();
p != procs.end(); ++p) {
- cerr << "\t" << (*p)->name() << " ID = " << (*p)->id() << endl;
+ cerr << "\t" << (*p)->name() << " ID = " << (*p)->id() << " @ " << (*p) << endl;
}
cerr << "}" << endl;
}
#endif
int
-Route::add_processor (boost::shared_ptr<Processor> processor, Placement placement, ProcessorStreams* err)
+Route::add_processor (boost::shared_ptr<Processor> processor, Placement placement, ProcessorStreams* err, bool activation_allowed)
{
ProcessorList::iterator loc;
loc = find (_processors.begin(), _processors.end(), _main_outs);
}
- return add_processor (processor, loc, err);
+ return add_processor (processor, loc, err, activation_allowed);
}
+/** Add a processor to a route such that it ends up with a given index into the visible processors.
+ * @param index Index to add the processor at, or -1 to add at the end of the list.
+ */
+
+int
+Route::add_processor_by_index (boost::shared_ptr<Processor> processor, int index, ProcessorStreams* err, bool activation_allowed)
+{
+ /* XXX this is not thread safe - we don't hold the lock across determining the iter
+ to add before and actually doing the insertion. dammit.
+ */
+
+ if (index == -1) {
+ return add_processor (processor, _processors.end(), err, activation_allowed);
+ }
+
+ ProcessorList::iterator i = _processors.begin ();
+ int j = 0;
+ while (i != _processors.end() && j < index) {
+ if ((*i)->display_to_user()) {
+ ++j;
+ }
+
+ ++i;
+ }
+
+ return add_processor (processor, i, err, activation_allowed);
+}
+
/** Add a processor to the route.
* @param iter an iterator in _processors; the new processor will be inserted immediately before this location.
*/
DEBUG_TRACE (DEBUG::Processors, string_compose (
"%1 adding processor %2\n", name(), processor->name()));
-
- ChanCount old_pms = processor_max_streams;
if (!_session.engine().connected() || !processor) {
return 1;
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(processor)) != 0) {
- if (pi->natural_input_streams() == ChanCount::ZERO) {
+ if (pi->has_no_inputs ()) {
/* generator plugin */
_have_internal_generator = true;
}
XMLNodeList const & children = node.children ();
XMLNodeList::const_iterator i = children.begin ();
-
+
while (i != children.end() && (*i)->name() != X_("Redirect")) {
++i;
}
if ((prop = node.property ("type")) != 0) {
- if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
+ if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" ||
prop->value() == "vst" ||
+ prop->value() == "lxvst" ||
prop->value() == "audiounit") {
processor.reset (new PluginInsert (_session));
loc = _processors.end ();
}
- ChanCount old_pms = processor_max_streams;
-
if (!_session.engine().connected()) {
return 1;
}
pi->set_count (1);
}
- ProcessorList::iterator inserted = _processors.insert (loc, *i);
+ _processors.insert (loc, *i);
if ((*i)->active()) {
(*i)->activate ();
boost::shared_ptr<PluginInsert> pi;
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
- if (pi->is_generator()) {
+ if (pi->has_no_inputs ()) {
_have_internal_generator = true;
break;
}
void
Route::clear_processors (Placement p)
{
- const ChanCount old_pms = processor_max_streams;
-
if (!_session.engine().connected()) {
return;
}
return 0;
}
- ChanCount old_pms = processor_max_streams;
-
if (!_session.engine().connected()) {
return 1;
}
{
Glib::RWLock::WriterLock lm (_processor_lock);
ProcessorState pstate (this);
-
+
ProcessorList::iterator i;
bool removed = false;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-
+
if (configure_processors_unlocked (err)) {
pstate.restore ();
/* we know this will work, because it worked before :) */
boost::shared_ptr<PluginInsert> pi;
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
- if (pi->is_generator()) {
+ if (pi->has_no_inputs ()) {
_have_internal_generator = true;
break;
}
{
Glib::RWLock::WriterLock lm (_processor_lock);
ProcessorState pstate (this);
-
+
ProcessorList::iterator i;
boost::shared_ptr<Processor> processor;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-
+
if (configure_processors_unlocked (err)) {
pstate.restore ();
/* we know this will work, because it worked before :) */
boost::shared_ptr<PluginInsert> pi;
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
- if (pi->is_generator()) {
+ if (pi->has_no_inputs ()) {
_have_internal_generator = true;
break;
}
Route::configure_processors (ProcessorStreams* err)
{
assert (!AudioEngine::instance()->process_lock().trylock());
-
+
if (!_in_configure_processors) {
Glib::RWLock::WriterLock lm (_processor_lock);
return configure_processors_unlocked (err);
}
-
+
return 0;
}
DEBUG_TRACE (DEBUG::Processors, "--- CONFIGURE ABORTED due to unknown processor.\n");
break;
}
-
+
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));
}
DEBUG_TRACE (DEBUG::Processors, "}\n");
-
+
return configuration;
}
if (boost::dynamic_pointer_cast<UnknownProcessor> (*p)) {
break;
}
-
+
(*p)->configure_io(c->first, c->second);
processor_max_streams = ChanCount::max(processor_max_streams, c->first);
processor_max_streams = ChanCount::max(processor_max_streams, c->second);
}
/* make sure we have sufficient scratch buffers to cope with the new processor
- configuration */
+ configuration
+ */
_session.ensure_buffers (n_process_buffers ());
DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configuration complete\n", _name));
if (_processors.empty()) {
return;
}
+
ProcessorList::iterator start, end;
placement_range(p, start, end);
- bool before_amp = true;
- for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- if ((*i) == _amp) {
- before_amp = false;
- continue;
- }
- if (p == PreFader && before_amp) {
- if (state) {
- (*i)->activate ();
- } else {
- (*i)->deactivate ();
- }
+ for (ProcessorList::iterator i = start; i != end; ++i) {
+ if (state) {
+ (*i)->activate ();
+ } else {
+ (*i)->deactivate ();
}
}
{
Glib::RWLock::WriterLock lm (_processor_lock);
ProcessorState pstate (this);
-
+
ProcessorList::iterator oiter;
ProcessorList::const_iterator niter;
ProcessorList as_it_will_be;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-
+
if (configure_processors_unlocked (err)) {
pstate.restore ();
return -1;
cmt->add_content (_comment);
}
- node->add_child_nocopy (_pannable->state (full_state));
+ if (_pannable) {
+ node->add_child_nocopy (_pannable->state (full_state));
+ }
for (i = _processors.begin(); i != _processors.end(); ++i) {
node->add_child_nocopy((*i)->state (full_state));
Route::set_name (prop->value());
}
- if ((prop = node.property ("id")) != 0) {
- _id = prop->value ();
- }
+ set_id (node);
if ((prop = node.property (X_("flags"))) != 0) {
_flags = Flag (string_2_enum (prop->value(), _flags));
_mute_master->set_solo_ignore (true);
}
+ if (is_monitor()) {
+ /* monitor bus does not get a panner, but if (re)created
+ via XML, it will already have one by the time we
+ call ::set_state(). so ... remove it.
+ */
+ unpan ();
+ }
+
/* add all processors (except amp, which is always present) */
nlist = node.children();
XMLNode processor_state (X_("processor_state"));
+ Stateful::save_extra_xml (node);
+
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
if (child->name() == X_("Pannable")) {
- _pannable->set_state (*child, version);
+ if (_pannable) {
+ _pannable->set_state (*child, version);
+ } else {
+ warning << string_compose (_("Pannable state found for route (%1) without a panner!"), name()) << endmsg;
+ }
}
}
XMLNode *cmt = *(child->children().begin());
_comment = cmt->content();
- } else if (child->name() == X_("Extra")) {
-
- _extra_xml = new XMLNode (*child);
-
} else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) {
if (prop->value() == "solo") {
_solo_control->set_state (*child, version);
} else {
_flags = Flag (0);
}
-
+
if ((prop = node.property (X_("phase-invert"))) != 0) {
boost::dynamic_bitset<> p (_input->n_ports().n_audio ());
if (string_is_affirmative (prop->value ())) {
p.set ();
- }
+ }
set_phase_invert (p);
}
}
if ((prop = node.property (X_("muted"))) != 0) {
-
+
bool first = true;
bool muted = string_is_affirmative (prop->value());
-
+
if (muted) {
string mute_point;
-
+
if ((prop = node.property (X_("mute-affects-pre-fader"))) != 0) {
-
+
if (string_is_affirmative (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 (!first) {
mute_point = mute_point + ",";
}
-
+
mute_point = mute_point + "PostFader";
first = false;
}
}
if ((prop = node.property (X_("mute-affects-control-outs"))) != 0) {
-
+
if (string_is_affirmative (prop->value())){
-
+
if (!first) {
mute_point = mute_point + ",";
}
-
+
mute_point = mute_point + "Listen";
first = false;
}
}
if ((prop = node.property (X_("mute-affects-main-outs"))) != 0) {
-
+
if (string_is_affirmative (prop->value())){
-
+
if (!first) {
mute_point = mute_point + ",";
}
-
+
mute_point = mute_point + "Main";
}
}
-
+
_mute_master->set_mute_points (mute_point);
_mute_master->set_muted_by_self (true);
}
Route::set_name (prop->value ());
}
- if ((prop = child->property (X_("id"))) != 0) {
- _id = prop->value ();
- }
+ set_id (*child);
if ((prop = child->property (X_("active"))) != 0) {
bool yn = string_is_affirmative (prop->value());
_active = !yn; // force switch
set_active (yn, this);
}
-
+
if ((prop = child->property (X_("gain"))) != 0) {
gain_t val;
_amp->gain_control()->set_value (val);
}
}
-
+
/* Set up Panners in the IO */
XMLNodeList io_nlist = child->children ();
-
+
XMLNodeConstIterator io_niter;
XMLNode *io_child;
-
+
for (io_niter = io_nlist.begin(); io_niter != io_nlist.end(); ++io_niter) {
io_child = *io_niter;
-
+
if (io_child->name() == X_("Panner")) {
_main_outs->panner_shell()->set_state(*io_child, version);
} else if (io_child->name() == X_("Automation")) {
set_processor_state_2X (redirect_nodes, version);
+ Stateful::save_extra_xml (node);
+
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
XMLNode *cmt = *(child->children().begin());
_comment = cmt->content();
- } else if (child->name() == X_("extra")) {
-
- _extra_xml = new XMLNode (*child);
-
} else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) {
if (prop->value() == X_("solo")) {
_solo_control->set_state (*child, version);
set_remote_control_id (x);
}
- }
+ }
}
return 0;
}
}
- // If the processor (*niter) is not on the route then create it
+ // If the processor (*niter) is not on the route then create it
if (o == _processors.end()) {
if (prop->value() == "intsend") {
processor.reset (new InternalSend (_session, _pannable, _mute_master, boost::shared_ptr<Route>(), Delivery::Role (0)));
+
} else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" ||
prop->value() == "vst" ||
+ prop->value() == "lxvst" ||
prop->value() == "audiounit") {
processor.reset (new PluginInsert(_session));
boost::shared_ptr<PluginInsert> pi;
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
- if (pi->is_generator()) {
+ if (pi->has_no_inputs ()) {
_have_internal_generator = true;
break;
}
Route::silence_unlocked (framecnt_t nframes)
{
/* Must be called with the processor lock held */
-
+
if (!_silent) {
_output->silence (nframes);
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
boost::shared_ptr<PluginInsert> pi;
-
+
if (!_active && (pi = boost::dynamic_pointer_cast<PluginInsert> (*i)) != 0) {
// skip plugins, they don't need anything when we're not active
continue;
}
-
+
(*i)->silence (nframes);
}
-
+
if (nframes == _session.get_block_size()) {
// _silent = true;
}
{
/* master never sends to control outs */
assert (!is_master ());
-
+
/* make sure we have one */
if (!_monitor_send) {
_monitor_send.reset (new InternalSend (_session, _pannable, _mute_master, _session.monitor_out(), Delivery::Listen));
_monitor_send->set_display_to_user (false);
}
-
+
/* set it up */
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
configure_processors (0);
return 0;
}
-/** Add an internal send to a route.
+/** Add an internal send to a route.
* @param route route to send to.
* @param placement placement for the send.
*/
Route::listen_via (boost::shared_ptr<Route> route, Placement placement)
{
assert (route != _session.monitor_out ());
-
+
{
Glib::RWLock::ReaderLock rm (_processor_lock);
return true;
}
-
+
for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); ++r) {
boost::shared_ptr<IOProcessor> iop;
} else {
DEBUG_TRACE (DEBUG::Graph, string_compose ("\tPROC %1 is not an IOP\n", (*r)->name()));
}
-
+
}
DEBUG_TRACE (DEBUG::Graph, string_compose ("\tdoes NOT feed %1\n", other->name()));
}
}
-/** Called with the process lock held if change contains ConfigurationChanged */
-void
-Route::output_change_handler (IOChange change, void * /*src*/)
-{
- if ((change.type & IOChange::ConfigurationChanged)) {
-
- /* XXX resize all listeners to match _main_outs? */
-
- /* Auto-connect newly-created outputs, unless we're auto-connecting to master
- and we are master (as an auto-connect in this situation would cause a
- feedback loop)
- */
-
- AutoConnectOption ac = Config->get_output_auto_connect ();
-
- if (ac == AutoConnectPhysical || (ac == AutoConnectMaster && !is_master ())) {
-
- ChanCount start = change.before;
-
- for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
- if (change.before.get(*i) < change.after.get(*i)) {
- /* the existing ChanCounts don't matter for this call as they are only
- to do with matching input and output indices, and we are only changing
- outputs here.
- */
- ChanCount dummy;
-
- /* only auto-connect the newly-created outputs, not the ones that were
- already there
- */
- start.set (*i, start.get (*i) + 1);
-
- _session.auto_connect_route (this, dummy, dummy, false, false, ChanCount(), change.before);
- }
- }
- }
-
- // configure_processors (0);
- }
-}
-
uint32_t
Route::pans_required () const
{
int
Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
- bool session_state_changing, bool /*can_record*/, bool /*rec_monitors_input*/)
+ bool session_state_changing, bool /*can_record*/)
{
Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
if (!lm.locked()) {
if (_session.transport_speed() != 0.0f) {
/* we're rolling but some state is changing (e.g. our diskstream contents)
so we cannot use them. Be silent till this is over.
-
+
XXX note the absurdity of ::no_roll() being called when we ARE rolling!
*/
silence_unlocked (nframes);
return 0;
}
-framecnt_t
-Route::check_initial_delay (framecnt_t nframes, framecnt_t& transport_frame)
-{
- if (_roll_delay > nframes) {
-
- _roll_delay -= nframes;
- silence_unlocked (nframes);
- /* transport frame is not legal for caller to use */
- return 0;
-
- } else if (_roll_delay > 0) {
-
- nframes -= _roll_delay;
- silence_unlocked (_roll_delay);
- transport_frame += _roll_delay;
-
- /* shuffle all the port buffers for things that lead "out" of this Route
- to reflect that we just wrote _roll_delay frames of silence.
- */
-
- Glib::RWLock::ReaderLock lm (_processor_lock);
- for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor> (*i);
- if (iop) {
- iop->increment_port_buffer_offset (_roll_delay);
- }
- }
- _output->increment_port_buffer_offset (_roll_delay);
-
- _roll_delay = 0;
-
- }
-
- return nframes;
-}
-
int
Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick,
- bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */)
+ bool /*can_record*/, bool& /* need_butler */)
{
Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
if (!lm.locked()) {
return 0;
}
-
+
automation_snapshot (_session.transport_frame(), false);
if (n_outputs().n_total() == 0) {
int
Route::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*end_frame*/,
- bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */)
+ bool /*can_record*/, bool& /* need_butler */)
{
silence (nframes);
return 0;
}
_meter_point = p;
-
+
bool meter_was_visible_to_user = _meter->display_to_user ();
{
Glib::RWLock::WriterLock lm (_processor_lock);
-
+
if (_meter_point != MeterCustom) {
_meter->set_display_to_user (false);
-
+
setup_invisible_processors ();
-
+
ProcessorList::iterator loc = find (_processors.begin(), _processors.end(), _meter);
ChanCount m_in;
-
+
if (loc == _processors.begin()) {
m_in = _input->n_ports();
} else {
--before;
m_in = (*before)->output_streams ();
}
-
+
_meter->reflect_inputs (m_in);
-
+
/* we do not need to reconfigure the processors, because the meter
(a) is always ready to handle processor_max_streams
(b) is always an N-in/N-out processor, and thus moving
it doesn't require any changes to the other processors.
*/
-
+
} else {
-
+
// just make it visible and let the user move it
-
+
_meter->set_display_to_user (true);
}
}
meter_change (); /* EMIT SIGNAL */
bool const meter_visibly_changed = (_meter->display_to_user() != meter_was_visible_to_user);
-
+
processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, meter_visibly_changed)); /* EMIT SIGNAL */
}
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-
+
if (configure_processors_unlocked (0)) {
pstate.restore ();
configure_processors_unlocked (0); // it worked before we tried to add it ...
Route::add_export_point()
{
if (!_capturing_processor) {
-
+
_capturing_processor.reset (new CapturingProcessor (_session));
_capturing_processor->activate ();
}
}
-
+
return _capturing_processor;
}
void
Route::automation_snapshot (framepos_t now, bool force)
{
- _pannable->automation_snapshot (now, force);
+ if (_pannable) {
+ _pannable->automation_snapshot (now, force);
+ }
+
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->automation_snapshot (now, force);
}
if (!r) {
return;
}
-
+
rl->push_back (r);
if (Config->get_solo_control_is_listen_control()) {
if (!r) {
return 0;
}
-
+
if (Config->get_solo_control_is_listen_control()) {
return r->listening_via_monitor() ? 1.0f : 0.0f;
} else {
if (!r) {
return;
}
-
+
rl->push_back (r);
_session.set_mute (rl, bval);
}
if (!r) {
return 0;
}
-
+
return r->muted() ? 1.0f : 0.0f;
}
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->set_block_size (nframes);
}
-
+
_session.ensure_buffers (n_process_buffers ());
}
}
/* pan automation */
- {
+ if (_pannable) {
ControlSet::Controls& c (_pannable->controls());
for (ControlSet::Controls::const_iterator ci = c.begin(); ci != c.end(); ++ci) {
ret = (_input->set_name(name) && _output->set_name(name));
if (ret) {
-
- Glib::RWLock::ReaderLock lm (_processor_lock);
-
- for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-
- /* rename all I/O processors that have inputs or outputs */
-
- boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor> (*i);
-
- if (iop && (iop->output() || iop->input())) {
- if (!iop->set_name (name)) {
- ret = false;
- }
+ /* rename the main outs. Leave other IO processors
+ * with whatever name they already have, because its
+ * just fine as it is (it will not contain the route
+ * name if its a port insert, port send or port return).
+ */
+
+ if (_main_outs) {
+ if (_main_outs->set_name (name)) {
+ /* XXX returning false here is stupid because
+ we already changed the route name.
+ */
+ return false;
}
}
-
}
return ret;
_route_group->foreach_route (boost::bind (&Route::set_active, _1, yn, _route_group));
return;
}
-
+
if (_active != yn) {
_active = yn;
_input->set_active (yn);
if (n-- == 0) {
return *i;
}
- }
+ }
}
return boost::shared_ptr<Processor> ();
Route::unknown_processors () const
{
list<string> p;
-
+
Glib::RWLock::ReaderLock lm (_processor_lock);
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
if (boost::dynamic_pointer_cast<UnknownProcessor const> (*i)) {
jack_latency_range_t all_connections;
- all_connections.min = ~((jack_nframes_t) 0);
- all_connections.max = 0;
-
- /* iterate over all "from" ports and determine the latency range for all of their
- connections to the "outside" (outside of this Route).
- */
-
- for (PortSet::iterator p = from.begin(); p != from.end(); ++p) {
-
- jack_latency_range_t range;
-
- p->get_connected_latency_range (range, playback);
-
- all_connections.min = min (all_connections.min, range.min);
- all_connections.max = max (all_connections.max, range.max);
+ if (from.empty()) {
+ all_connections.min = 0;
+ all_connections.max = 0;
+ } else {
+ all_connections.min = ~((jack_nframes_t) 0);
+ all_connections.max = 0;
+
+ /* iterate over all "from" ports and determine the latency range for all of their
+ connections to the "outside" (outside of this Route).
+ */
+
+ for (PortSet::iterator p = from.begin(); p != from.end(); ++p) {
+
+ jack_latency_range_t range;
+
+ p->get_connected_latency_range (range, playback);
+
+ all_connections.min = min (all_connections.min, range.min);
+ all_connections.max = max (all_connections.max, range.max);
+ }
}
/* set the "from" port latencies to the max/min range of all their connections */
}
/* we'll build this new list here and then use it */
-
+
ProcessorList new_processors;
/* find visible processors */
-
+
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if ((*i)->display_to_user ()) {
new_processors.push_back (*i);
new_processors.insert (amp, _monitor_send);
break;
}
+ _monitor_send->set_can_pan (false);
break;
case AfterFaderListen:
switch (Config->get_afl_position ()) {
new_processors.insert (new_processors.end(), _monitor_send);
break;
}
+ _monitor_send->set_can_pan (true);
break;
}
} else {
new_processors.insert (new_processors.end(), _monitor_send);
+ _monitor_send->set_can_pan (false);
}
}
assert (!_monitor_control->display_to_user ());
new_processors.push_front (_monitor_control);
}
-
+
/* INTERNAL RETURN */
/* doing this here means that any monitor control will come just after
}
/* EXPORT PROCESSOR */
-
+
if (_capturing_processor) {
assert (!_capturing_processor->display_to_user ());
new_processors.push_front (_capturing_processor);
return true;
}
+void
+Route::unpan ()
+{
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+ Glib::RWLock::ReaderLock lp (_processor_lock);
+
+ _pannable.reset ();
+
+ for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+ boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery>(*i);
+ if (d) {
+ d->unpan ();
+ }
+ }
+}