#include "ardour/meter.h"
#include "ardour/mix.h"
#include "ardour/monitor_processor.h"
+#include "ardour/pannable.h"
#include "ardour/panner.h"
+#include "ardour/panner_shell.h"
#include "ardour/plugin_insert.h"
#include "ardour/port.h"
#include "ardour/port_insert.h"
#include "ardour/utils.h"
#include "ardour/graph.h"
#include "ardour/unknown_processor.h"
+#include "ardour/capturing_processor.h"
#include "i18n.h"
int
Route::init ()
{
- /* add standard controls */
+ /* add standard controls */
_solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
- _mute_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
+ _mute_control->set_flags (Controllable::Flag (_mute_control->flags() | Controllable::Toggle));
add_control (_solo_control);
add_control (_mute_control);
+ /* panning */
+
+ _pannable.reset (new Pannable (_session));
+
/* input and output objects */
_input.reset (new IO (_session, _name, IO::Input, _default_type));
add_processor (_meter, PostFader);
- _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
+ _main_outs.reset (new Delivery (_session, _output, _pannable, _mute_master, _name, Delivery::Main));
add_processor (_main_outs, PostFader);
/* no panning on the monitor main outs */
+#ifdef PANNER_HACKS
_main_outs->panner()->set_bypassed (true);
+#endif
}
if (is_master() || is_monitor() || is_hidden()) {
}
}
- _route_group->apply (&Route::inc_gain, factor, _route_group);
+ _route_group->foreach_route (boost::bind (&Route::inc_gain, _1, factor, _route_group));
} else {
- _route_group->apply (&Route::set_gain, val, _route_group);
+ _route_group->foreach_route (boost::bind (&Route::set_gain, _1, val, _route_group));
}
return;
*/
void
Route::process_output_buffers (BufferSet& bufs,
- framepos_t start_frame, framepos_t end_frame, nframes_t nframes,
- bool /*with_processors*/, int declick)
+ framepos_t start_frame, framepos_t end_frame, pframes_t nframes,
+ bool /*with_processors*/, int declick,
+ bool gain_automation_ok)
{
bool monitor;
}
/* figure out if we're going to use gain automation */
- _amp->setup_gain_automation (start_frame, end_frame, nframes);
-
-
+ if (gain_automation_ok) {
+ _amp->setup_gain_automation (start_frame, end_frame, nframes);
+ } else {
+ _amp->apply_gain_automation (false);
+ }
+
/* tell main outs what to do about monitoring */
_main_outs->no_outs_cuz_we_no_monitor (!monitor);
Sample* const sp = i->data();
if (_phase_invert[chn]) {
- for (nframes_t nx = 0; nx < nframes; ++nx) {
+ for (pframes_t nx = 0; nx < nframes; ++nx) {
sp[nx] = -sp[nx];
sp[nx] += 1.0e-27f;
}
} else {
- for (nframes_t nx = 0; nx < nframes; ++nx) {
+ for (pframes_t nx = 0; nx < nframes; ++nx) {
sp[nx] += 1.0e-27f;
}
}
Sample* const sp = i->data();
if (_phase_invert[chn]) {
- for (nframes_t nx = 0; nx < nframes; ++nx) {
+ for (pframes_t nx = 0; nx < nframes; ++nx) {
sp[nx] = -sp[nx];
}
}
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
Sample* const sp = i->data();
- for (nframes_t nx = 0; nx < nframes; ++nx) {
+ for (pframes_t nx = 0; nx < nframes; ++nx) {
sp[nx] += 1.0e-27f;
}
}
}
void
-Route::passthru (framepos_t start_frame, framepos_t end_frame, nframes_t nframes, int declick)
+Route::passthru (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
{
BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
}
write_out_of_band_data (bufs, start_frame, end_frame, nframes);
- process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick);
+ process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick, true);
}
void
-Route::passthru_silence (framepos_t start_frame, framepos_t end_frame, nframes_t nframes, int declick)
+Route::passthru_silence (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
{
BufferSet& bufs (_session.get_silent_buffers (n_process_buffers()));
bufs.set_count (_input->n_ports());
write_out_of_band_data (bufs, start_frame, end_frame, nframes);
- process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick);
+ process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick, false);
}
void
}
if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_solo()) {
- _route_group->apply (&Route::set_solo, yn, _route_group);
+ _route_group->foreach_route (boost::bind (&Route::set_solo, _1, yn, _route_group));
return;
}
}
if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_solo()) {
- _route_group->apply (&Route::set_solo_isolated, yn, _route_group);
+ _route_group->foreach_route (boost::bind (&Route::set_solo_isolated, _1, yn, _route_group));
return;
}
if (_mute_master->muted_by_self()) {
mute_changed (this); /* EMIT SIGNAL */
+ _mute_control->Changed (); /* EMIT SIGNAL */
}
}
Route::set_mute (bool yn, void *src)
{
if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_mute()) {
- _route_group->apply (&Route::set_mute, yn, _route_group);
+ _route_group->foreach_route (boost::bind (&Route::set_mute, _1, yn, _route_group));
return;
}
if (muted() != yn) {
_mute_master->set_muted_by_self (yn);
mute_changed (src); /* EMIT SIGNAL */
+ _mute_control->Changed (); /* EMIT SIGNAL */
}
}
} else {
- processor.reset (new PortInsert (_session, _mute_master));
+ processor.reset (new PortInsert (_session, _pannable, _mute_master));
}
}
} else if (node.name() == "Send") {
- processor.reset (new Send (_session, _mute_master));
+ processor.reset (new Send (_session, _pannable, _mute_master));
} else {
node->add_child_nocopy (_input->state (full_state));
node->add_child_nocopy (_output->state (full_state));
node->add_child_nocopy (_solo_control->get_state ());
+ node->add_child_nocopy (_mute_control->get_state ());
node->add_child_nocopy (_mute_master->get_state ());
XMLNode* remote_control_node = new XMLNode (X_("RemoteControl"));
cmt->add_content (_comment);
}
+ node->add_child_nocopy (_pannable->state (full_state));
+
for (i = _processors.begin(); i != _processors.end(); ++i) {
node->add_child_nocopy((*i)->state (full_state));
}
if (child->name() == X_("Processor")) {
processor_state.add_child_copy (*child);
}
+
+
+ if (child->name() == X_("Pannable")) {
+ _pannable->set_state (*child, version);
+ }
}
set_processor_state (processor_state);
if ((prop = node.property (X_("active"))) != 0) {
bool yn = string_is_affirmative (prop->value());
_active = !yn; // force switch
- set_active (yn);
+ set_active (yn, this);
}
if ((prop = node.property (X_("meter-point"))) != 0) {
MeterPoint mp = MeterPoint (string_2_enum (prop->value (), _meter_point));
- set_meter_point (mp);
+ set_meter_point (mp, true);
if (_meter) {
_meter->set_display_to_user (_meter_point == MeterCustom);
}
_extra_xml = new XMLNode (*child);
- } else if (child->name() == X_("Controllable") && (prop = child->property("name")) != 0) {
-
+ } else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) {
if (prop->value() == "solo") {
_solo_control->set_state (*child, version);
- _session.add_controllable (_solo_control);
}
} else if (child->name() == X_("RemoteControl")) {
if ((prop = child->property (X_("active"))) != 0) {
bool yn = string_is_affirmative (prop->value());
_active = !yn; // force switch
- set_active (yn);
+ set_active (yn, this);
}
if ((prop = child->property (X_("gain"))) != 0) {
io_child = *io_niter;
if (io_child->name() == X_("Panner")) {
- _main_outs->panner()->set_state(*io_child, version);
+ _main_outs->panner_shell()->set_state(*io_child, version);
} else if (io_child->name() == X_("Automation")) {
/* IO's automation is for the fader */
_amp->set_automation_xml_state (*io_child, Evoral::Parameter (GainAutomation));
_extra_xml = new XMLNode (*child);
- } else if (child->name() == X_("Controllable") && (prop = child->property("name")) != 0) {
-
- if (prop->value() == "solo") {
+ } else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) {
+ if (prop->value() == X_("solo")) {
_solo_control->set_state (*child, version);
- _session.add_controllable (_solo_control);
- }
-
+ } else if (prop->value() == X_("mute")) {
+ _mute_control->set_state (*child, version);
+ }
+
} else if (child->name() == X_("RemoteControl")) {
if ((prop = child->property (X_("id"))) != 0) {
int32_t x;
if (prop->value() == "intsend") {
- processor.reset (new InternalSend (_session, _mute_master, boost::shared_ptr<Route>(), Delivery::Role (0)));
+ 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" ||
} else if (prop->value() == "port") {
- processor.reset (new PortInsert (_session, _mute_master));
+ processor.reset (new PortInsert (_session, _pannable, _mute_master));
} else if (prop->value() == "send") {
- processor.reset (new Send (_session, _mute_master));
+ processor.reset (new Send (_session, _pannable, _mute_master));
} else {
error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
}
void
-Route::silence (nframes_t nframes)
+Route::silence (framecnt_t nframes)
{
Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
if (!lm.locked()) {
}
void
-Route::silence_unlocked (nframes_t nframes)
+Route::silence_unlocked (framecnt_t nframes)
{
/* Must be called with the processor lock held */
/* master never sends to control outs */
return 0;
} else {
- listener.reset (new InternalSend (_session, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen)));
+ listener.reset (new InternalSend (_session, _pannable, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen)));
}
} else {
- listener.reset (new InternalSend (_session, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen)));
+ listener.reset (new InternalSend (_session, _pannable, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen)));
}
} catch (failed_constructor& err) {
_monitor_send = listener;
}
- if (placement == PostFader) {
- /* put it *really* at the end, not just after the panner (main outs)
- */
- add_processor (listener, _processors.end());
- } else {
- add_processor (listener, PreFader);
- }
+
+ if (aux) {
+
+ add_processor (listener, placement);
+
+ } else {
+
+ if (placement == PostFader) {
+ /* put it *really* at the end, not just after the panner (main outs)
+ */
+ add_processor (listener, _processors.end());
+ } else {
+ add_processor (listener, PreFader);
+ }
+
+ }
return 0;
}
return false;
}
+/** Called from the (non-realtime) butler thread when the transport is stopped */
void
-Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors)
+Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors)
{
framepos_t now = _session.transport_frame();
_roll_delay = _initial_delay;
}
-/** Called with the process lock held */
+/** Called with the process lock held if change contains ConfigurationChanged */
void
Route::input_change_handler (IOChange change, void * /*src*/)
{
}
}
-/** Called with the process lock held */
+/** Called with the process lock held if change contains ConfigurationChanged */
void
Route::output_change_handler (IOChange change, void * /*src*/)
{
}
int
-Route::no_roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame,
+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*/)
{
Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
return 0;
}
-nframes_t
-Route::check_initial_delay (nframes_t nframes, nframes_t& transport_frame)
+framecnt_t
+Route::check_initial_delay (framecnt_t nframes, framecnt_t& transport_frame)
{
if (_roll_delay > nframes) {
}
int
-Route::roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick,
+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 */)
{
Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
return 0;
}
- nframes_t unused = 0;
+ framecnt_t unused = 0;
if ((nframes = check_initial_delay (nframes, unused)) == 0) {
return 0;
}
int
-Route::silent_roll (nframes_t nframes, framepos_t /*start_frame*/, framepos_t /*end_frame*/,
+Route::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*end_frame*/,
bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */)
{
silence (nframes);
}
void
-Route::set_meter_point (MeterPoint p)
+Route::set_meter_point (MeterPoint p, bool force)
{
/* CAN BE CALLED FROM PROCESS CONTEXT */
- if (_meter_point == p) {
+ if (_meter_point == p && !force) {
return;
}
_meter->reflect_inputs (m_in);
_processors.insert (loc, _meter);
-
+
/* 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
_session.set_dirty ();
}
-nframes_t
+boost::shared_ptr<CapturingProcessor>
+Route::add_export_point()
+{
+ // Check if it exists already
+ boost::shared_ptr<CapturingProcessor> processor;
+ if ((processor = boost::dynamic_pointer_cast<CapturingProcessor> (*_processors.begin()))) {
+ return processor;
+ }
+
+ // ...else add it
+ processor.reset (new CapturingProcessor (_session));
+ add_processor (processor, _processors.begin());
+ return processor;
+}
+
+framecnt_t
Route::update_total_latency ()
{
- nframes_t old = _output->effective_latency();
- nframes_t own_latency = _output->user_latency();
+ framecnt_t old = _output->effective_latency();
+ framecnt_t own_latency = _output->user_latency();
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if ((*i)->active ()) {
}
void
-Route::set_user_latency (nframes_t nframes)
+Route::set_user_latency (framecnt_t nframes)
{
_output->set_user_latency (nframes);
_session.update_latency_compensation (false, false);
}
void
-Route::set_latency_delay (nframes_t longest_session_latency)
+Route::set_latency_delay (framecnt_t longest_session_latency)
{
- nframes_t old = _initial_delay;
+ framecnt_t old = _initial_delay;
if (_output->effective_latency() < longest_session_latency) {
_initial_delay = longest_session_latency - _output->effective_latency();
}
void
-Route::automation_snapshot (nframes_t now, bool force)
+Route::automation_snapshot (framepos_t now, bool force)
{
- panner()->automation_snapshot (now, force);
-
+ _pannable->automation_snapshot (now, force);
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->automation_snapshot (now, force);
}
}
void
-Route::set_block_size (nframes_t nframes)
+Route::set_block_size (pframes_t nframes)
{
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->set_block_size (nframes);
*/
void
-Route::shift (framepos_t /*pos*/, framecnt_t /*frames*/)
+Route::shift (framepos_t pos, framecnt_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));
+ {
+ boost::shared_ptr<AutomationControl> gc = _amp->gain_control();
+
+ XMLNode &before = gc->alist()->get_state ();
+ gc->alist()->shift (pos, frames);
+ XMLNode &after = gc->alist()->get_state ();
+ _session.add_command (new MementoCommand<AutomationList> (*gc->alist().get(), &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));
- }
+ {
+ ControlSet::Controls& c (_pannable->controls());
+
+ for (ControlSet::Controls::const_iterator ci = c.begin(); ci != c.end(); ++ci) {
+ boost::shared_ptr<AutomationControl> pc = boost::dynamic_pointer_cast<AutomationControl> (ci->second);
+ if (pc) {
+ boost::shared_ptr<AutomationList> al = pc->alist();
+ XMLNode& before = al->get_state ();
+ al->shift (pos, frames);
+ XMLNode& after = al->get_state ();
+ _session.add_command (new MementoCommand<AutomationList> (*al.get(), &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));
- }
- }
+ Glib::RWLock::ReaderLock lm (_processor_lock);
+ for (ProcessorList::iterator i = _processors.begin (); i != _processors.end (); ++i) {
+
+ set<Evoral::Parameter> parameters = (*i)->what_can_be_automated();
+
+ for (set<Evoral::Parameter>::const_iterator p = parameters.begin (); p != parameters.end (); ++p) {
+ boost::shared_ptr<AutomationControl> ac = (*i)->automation_control (*p);
+ if (ac) {
+ boost::shared_ptr<AutomationList> al = ac->alist();
+ XMLNode &before = al->get_state ();
+ al->shift (pos, frames);
+ XMLNode &after = al->get_state ();
+ _session.add_command (new MementoCommand<AutomationList> (*al.get(), &before, &after));
+ }
+ }
+ }
}
-#endif
-
}
}
void
-Route::set_active (bool yn)
+Route::set_active (bool yn, void* src)
{
+ if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_route_active()) {
+ _route_group->foreach_route (boost::bind (&Route::set_active, _1, yn, _route_group));
+ return;
+ }
+
if (_active != yn) {
_active = yn;
_input->set_active (yn);
}
}
+boost::shared_ptr<Pannable>
+Route::pannable() const
+{
+ return _pannable;
+}
+
boost::shared_ptr<Panner>
Route::panner() const
{
- return _main_outs->panner();
+ /* may be null ! */
+ return _main_outs->panner_shell()->panner();
+}
+
+boost::shared_ptr<PannerShell>
+Route::panner_shell() const
+{
+ return _main_outs->panner_shell();
}
boost::shared_ptr<AutomationControl>