summaryrefslogtreecommitdiff
path: root/libs/ardour/route.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour/route.cc')
-rw-r--r--libs/ardour/route.cc1428
1 files changed, 445 insertions, 983 deletions
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 6179af5028..931ae9a996 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -29,29 +29,30 @@
#include "evoral/Curve.hpp"
-#include "ardour/timestamps.h"
+#include "ardour/amp.h"
+#include "ardour/audio_port.h"
#include "ardour/audioengine.h"
-#include "ardour/route.h"
#include "ardour/buffer.h"
-#include "ardour/processor.h"
-#include "ardour/plugin_insert.h"
-#include "ardour/port_insert.h"
-#include "ardour/send.h"
-#include "ardour/session.h"
-#include "ardour/utils.h"
+#include "ardour/buffer_set.h"
#include "ardour/configuration.h"
+#include "ardour/control_outputs.h"
#include "ardour/cycle_timer.h"
-#include "ardour/route_group.h"
-#include "ardour/port.h"
-#include "ardour/audio_port.h"
-#include "ardour/ladspa_plugin.h"
-#include "ardour/panner.h"
#include "ardour/dB.h"
-#include "ardour/amp.h"
+#include "ardour/ladspa_plugin.h"
#include "ardour/meter.h"
-#include "ardour/buffer_set.h"
#include "ardour/mix.h"
+#include "ardour/panner.h"
+#include "ardour/plugin_insert.h"
+#include "ardour/port.h"
+#include "ardour/port_insert.h"
+#include "ardour/processor.h"
#include "ardour/profile.h"
+#include "ardour/route.h"
+#include "ardour/route_group.h"
+#include "ardour/send.h"
+#include "ardour/session.h"
+#include "ardour/timestamps.h"
+#include "ardour/utils.h"
#include "i18n.h"
@@ -62,21 +63,22 @@ using namespace PBD;
uint32_t Route::order_key_cnt = 0;
sigc::signal<void,const char*> Route::SyncOrderKeys;
-Route::Route (Session& sess, string name,
- int in_min, int in_max, int out_min, int out_max,
- Flag flg, DataType default_type)
- : IO (sess, name, in_min, in_max, out_min, out_max, default_type)
+Route::Route (Session& sess, string name, Flag flg,
+ DataType default_type, ChanCount in, ChanCount out)
+ : IO (sess, name, default_type, in, ChanCount::INFINITE, out, ChanCount::INFINITE)
, _flags (flg)
, _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl))
, _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl))
{
+ _configured_inputs = in;
+ _configured_outputs = out;
init ();
}
Route::Route (Session& sess, const XMLNode& node, DataType default_type)
: IO (sess, *node.child ("IO"), default_type)
- , _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl))
- , _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl))
+ , _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl))
+ , _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl))
{
init ();
_set_state (node, false);
@@ -104,6 +106,7 @@ Route::init ()
_declickable = false;
_pending_declick = true;
_remote_control_id = 0;
+ _in_configure_processors = false;
_edit_group = 0;
_mix_group = 0;
@@ -118,10 +121,13 @@ Route::init ()
mute_gain = 1.0;
desired_mute_gain = 1.0;
- _control_outs = 0;
-
input_changed.connect (mem_fun (this, &Route::input_change_handler));
output_changed.connect (mem_fun (this, &Route::output_change_handler));
+
+ _amp->set_sort_key (0);
+ _meter->set_sort_key (1);
+ add_processor (_amp, NULL);
+ add_processor (_meter, NULL);
}
Route::~Route ()
@@ -132,8 +138,6 @@ Route::~Route ()
for (OrderKeys::iterator i = order_keys.begin(); i != order_keys.end(); ++i) {
free ((void*)(i->first));
}
-
- delete _control_outs;
}
void
@@ -217,7 +221,6 @@ Route::ensure_track_or_route_name(string name, Session &session)
return newname;
}
-
void
Route::inc_gain (gain_t fraction, void *src)
{
@@ -291,21 +294,15 @@ Route::set_gain (gain_t val, void *src)
*/
void
Route::process_output_buffers (BufferSet& bufs,
- nframes_t start_frame, nframes_t end_frame, nframes_t nframes,
- bool with_processors, int declick, bool meter)
+ nframes_t start_frame, nframes_t end_frame, nframes_t nframes,
+ bool with_processors, int declick)
{
- // This is definitely very audio-only for now
- assert(_default_type == DataType::AUDIO);
-
ProcessorList::iterator i;
- bool post_fader_work = false;
bool mute_declick_applied = false;
gain_t dmg, dsg, dg;
- IO *co;
- bool mute_audible;
- bool solo_audible;
bool no_monitor;
- gain_t* gab = _session.gain_automation_buffer();
+
+ bufs.is_silent(false);
switch (Config->get_monitoring_model()) {
case HardwareMonitoring:
@@ -317,96 +314,89 @@ Route::process_output_buffers (BufferSet& bufs,
}
declick = _pending_declick;
-
- {
- Glib::Mutex::Lock cm (_control_outs_lock, Glib::TRY_LOCK);
-
- if (cm.locked()) {
- co = _control_outs;
- } else {
- co = 0;
- }
- }
+ const bool recording_without_monitoring = no_monitor && record_enabled()
+ && (!Config->get_auto_input() || _session.actively_recording());
+
+
+ /* -------------------------------------------------------------------------------------------
+ SET UP GAIN (FADER)
+ ----------------------------------------------------------------------------------------- */
+
{
Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
if (dm.locked()) {
dmg = desired_mute_gain;
dsg = desired_solo_gain;
- dg = _desired_gain;
+ dg = _gain_control->user_float();
} else {
dmg = mute_gain;
dsg = solo_gain;
dg = _gain;
}
}
+
+ // apply gain at the amp if...
+ _amp->apply_gain(
+ // we're not recording
+ !(record_enabled() && _session.actively_recording())
+ // or (we are recording, and) software monitoring is required
+ || Config->get_monitoring_model() == SoftwareMonitoring);
+
+ // mute at the amp if...
+ _amp->apply_mute(
+ !_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_post_fader,
+ mute_gain, dmg);
+
+ _amp->set_gain (_gain, dg);
+
+
+ /* -------------------------------------------------------------------------------------------
+ SET UP CONTROL OUTPUTS
+ ----------------------------------------------------------------------------------------- */
+
+ boost::shared_ptr<ControlOutputs> co = _control_outs;
+ if (co) {
+ // deliver control outputs unless we're ...
+ co->deliver (!(
+ dsg == 0 || // muted by solo of another track
+ (dmg == 0 && _mute_affects_control_outs) || // or muted by mute of this track
+ !recording_without_monitoring )); // or rec-enabled w/o s/w monitoring
+ }
+
/* -------------------------------------------------------------------------------------------
GLOBAL DECLICK (for transport changes etc.)
----------------------------------------------------------------------------------------- */
if (declick > 0) {
- Amp::run_in_place (bufs, nframes, 0.0, 1.0, false);
+ Amp::apply_gain (bufs, nframes, 0.0, 1.0, false);
_pending_declick = 0;
} else if (declick < 0) {
- Amp::run_in_place (bufs, nframes, 1.0, 0.0, false);
+ Amp::apply_gain (bufs, nframes, 1.0, 0.0, false);
_pending_declick = 0;
- } else {
-
- /* no global declick */
-
+ } else { // no global declick
if (solo_gain != dsg) {
- Amp::run_in_place (bufs, nframes, solo_gain, dsg, false);
+ Amp::apply_gain (bufs, nframes, solo_gain, dsg, false);
solo_gain = dsg;
}
}
/* -------------------------------------------------------------------------------------------
- INPUT METERING & MONITORING
+ PRE-FADER MUTING
----------------------------------------------------------------------------------------- */
- if (meter && (_meter_point == MeterInput)) {
- _meter->run_in_place(bufs, start_frame, end_frame, nframes);
- }
-
if (!_soloed && _mute_affects_pre_fader && (mute_gain != dmg)) {
- Amp::run_in_place (bufs, nframes, mute_gain, dmg, false);
+ Amp::apply_gain (bufs, nframes, mute_gain, dmg, false);
mute_gain = dmg;
mute_declick_applied = true;
}
+ if (mute_gain == 0.0f && dmg == 0.0f) {
+ bufs.is_silent(true);
+ }
- if ((_meter_point == MeterInput) && co) {
-
- solo_audible = dsg > 0;
- mute_audible = dmg > 0;// || !_mute_affects_pre_fader;
-
- if ( // muted by solo of another track
-
- !solo_audible ||
-
- // muted by mute of this track
-
- !mute_audible ||
-
- // rec-enabled but not s/w monitoring
-
- // TODO: this is probably wrong
-
- ( no_monitor && record_enabled()
- && (!Config->get_auto_input() || _session.actively_recording()) )
-
- ) {
-
- co->silence (nframes);
-
- } else {
-
- co->deliver_output (bufs, start_frame, end_frame, nframes);
-
- }
- }
/* -------------------------------------------------------------------------------------------
DENORMAL CONTROL
@@ -423,300 +413,78 @@ Route::process_output_buffers (BufferSet& bufs,
}
}
+
/* -------------------------------------------------------------------------------------------
- PRE-FADER REDIRECTS
+ PROCESSORS (including Amp (fader) and Meter)
----------------------------------------------------------------------------------------- */
if (with_processors) {
Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
if (rm.locked()) {
- if (mute_gain > 0 || !_mute_affects_pre_fader) {
+ //if (!bufs.is_silent()) {
for (i = _processors.begin(); i != _processors.end(); ++i) {
- switch ((*i)->placement()) {
- case PreFader:
- (*i)->run_in_place (bufs, start_frame, end_frame, nframes);
- break;
- case PostFader:
- post_fader_work = true;
- break;
- }
+ bufs.set_count(ChanCount::max(bufs.count(), (*i)->input_streams()));
+ (*i)->run_in_place (bufs, start_frame, end_frame, nframes);
+ bufs.set_count(ChanCount::max(bufs.count(), (*i)->output_streams()));
}
- } else {
+ /*} else {
for (i = _processors.begin(); i != _processors.end(); ++i) {
- switch ((*i)->placement()) {
- case PreFader:
- (*i)->silence (nframes);
- break;
- case PostFader:
- post_fader_work = true;
- break;
- }
+ (*i)->silence (nframes);
+ bufs.set_count(ChanCount::max(bufs.count(), (*i)->output_streams()));
}
- }
- }
- }
-
- /* When we entered this method, the number of bufs was set by n_process_buffers(), so
- * it may be larger than required. Consider e.g 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);
- mute_gain = dmg;
- mute_declick_applied = true;
- }
-
- /* -------------------------------------------------------------------------------------------
- PRE-FADER METERING & MONITORING
- ----------------------------------------------------------------------------------------- */
-
- if (meter && (_meter_point == MeterPreFader)) {
- _meter->run_in_place(bufs, start_frame, end_frame, nframes);
- }
-
-
- if ((_meter_point == MeterPreFader) && co) {
-
- solo_audible = dsg > 0;
- mute_audible = dmg > 0 || !_mute_affects_pre_fader;
-
- if ( // muted by solo of another track
-
- !solo_audible ||
-
- // muted by mute of this track
-
- !mute_audible ||
-
- // rec-enabled but not s/w monitoring
-
- ( no_monitor && record_enabled()
- && (!Config->get_auto_input() || _session.actively_recording()) )
-
- ) {
-
- co->silence (nframes);
-
- } else {
-
- co->deliver_output (bufs, start_frame, end_frame, nframes);
+ }*/
}
- }
-
- /* -------------------------------------------------------------------------------------------
- GAIN STAGE
- ----------------------------------------------------------------------------------------- */
-
- /* if not recording or recording and requiring any monitor signal, then apply gain */
-
- if ( // not recording
-
- !(record_enabled() && _session.actively_recording()) ||
-
- // OR recording
-
- // AND software monitoring required
- Config->get_monitoring_model() == SoftwareMonitoring) {
-
- if (apply_gain_automation) {
-
- if (_phase_invert) {
- 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) {
- sp[nx] *= -gab[nx];
- }
- }
- } else {
- 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) {
- sp[nx] *= gab[nx];
- }
- }
- }
-
- if (apply_gain_automation && _session.transport_rolling() && nframes > 0) {
- _effective_gain = gab[nframes-1];
- }
-
- } else {
-
- /* manual (scalar) gain */
-
- if (_gain != dg) {
-
- Amp::run_in_place (bufs, nframes, _gain, dg, _phase_invert);
- _gain = dg;
-
- } else if (_gain != 0 && (_phase_invert || _gain != 1.0)) {
-
- /* no need to interpolate current gain value,
- but its non-unity, so apply it. if the gain
- is zero, do nothing because we'll ship silence
- below.
- */
-
- gain_t this_gain;
-
- if (_phase_invert) {
- this_gain = -_gain;
- } else {
- this_gain = _gain;
- }
-
- for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
- Sample* const sp = i->data();
- apply_gain_to_buffer(sp,nframes,this_gain);
- }
-
- } else if (_gain == 0) {
- for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
- i->clear();
- }
- }
+ if (!_processors.empty()) {
+ bufs.set_count(ChanCount::max(bufs.count(), _processors.back()->output_streams()));
}
-
- } else {
-
- /* actively recording, no monitoring required; leave buffers as-is to save CPU cycles */
-
}
+
/* -------------------------------------------------------------------------------------------
- POST-FADER REDIRECTS
- ----------------------------------------------------------------------------------------- */
-
- /* note that post_fader_work cannot be true unless with_processors was also true,
- so don't test both
- */
-
- if (post_fader_work) {
-
- Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
- if (rm.locked()) {
- if (mute_gain > 0 || !_mute_affects_post_fader) {
- for (i = _processors.begin(); i != _processors.end(); ++i) {
- switch ((*i)->placement()) {
- case PreFader:
- break;
- case PostFader:
- (*i)->run_in_place (bufs, start_frame, end_frame, nframes);
- break;
- }
- }
- } else {
- for (i = _processors.begin(); i != _processors.end(); ++i) {
- switch ((*i)->placement()) {
- case PreFader:
- break;
- case PostFader:
- (*i)->silence (nframes);
- break;
- }
- }
- }
- }
- }
-
- if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_control_outs) {
- Amp::run_in_place (bufs, nframes, mute_gain, dmg, false);
- mute_gain = dmg;
- mute_declick_applied = true;
- }
-
- /* -------------------------------------------------------------------------------------------
- CONTROL OUTPUT STAGE
- ----------------------------------------------------------------------------------------- */
-
- if ((_meter_point == MeterPostFader) && co) {
-
- solo_audible = solo_gain > 0;
- mute_audible = dmg > 0 || !_mute_affects_control_outs;
-
- if ( // silent anyway
-
- (_gain == 0 && !apply_gain_automation) ||
-
- // muted by solo of another track
-
- !solo_audible ||
-
- // muted by mute of this track
-
- !mute_audible ||
-
- // recording but not s/w monitoring
-
- ( no_monitor && record_enabled()
- && (!Config->get_auto_input() || _session.actively_recording()) )
-
- ) {
-
- co->silence (nframes);
-
- } else {
-
- co->deliver_output (bufs, start_frame, end_frame, nframes);
- }
- }
-
- /* -------------------------------------------------------------------------------------------
- GLOBAL MUTE
+ POST-FADER MUTING
----------------------------------------------------------------------------------------- */
if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_main_outs) {
- Amp::run_in_place (bufs, nframes, mute_gain, dmg, false);
+ Amp::apply_gain (bufs, nframes, mute_gain, dmg, false);
mute_gain = dmg;
mute_declick_applied = true;
}
+ if (mute_gain == 0.0f && dmg == 0.0f) {
+ bufs.is_silent(true);
+ }
+
/* -------------------------------------------------------------------------------------------
MAIN OUTPUT STAGE
----------------------------------------------------------------------------------------- */
- solo_audible = dsg > 0;
- mute_audible = dmg > 0 || !_mute_affects_main_outs;
+ bool solo_audible = dsg > 0;
+ bool mute_audible = dmg > 0 || !_mute_affects_main_outs;
if (n_outputs().get(_default_type) == 0) {
/* relax */
- } else if (no_monitor && record_enabled()
- && (!Config->get_auto_input() || _session.actively_recording())) {
-
+ } else if (recording_without_monitoring) {
+
IO::silence (nframes);
-
- } else {
- if ( // silent anyway
+ } else {
- (_gain == 0 && !apply_gain_automation) ||
+ if ( // we're silent anyway
+ (_gain == 0 && !_amp->apply_gain_automation()) ||
- // muted by solo of another track, but not using control outs for solo
-
+ // or muted by solo of another track, but not using control outs for solo
(!solo_audible && (Config->get_solo_model() != SoloBus)) ||
- // muted by mute of this track
-
+ // or muted by mute of this track
!mute_audible
-
) {
/* don't use Route::silence() here, because that causes
all outputs (sends, port processors, etc. to be silent).
*/
-
- if (_meter_point == MeterPostFader) {
- peak_meter().reset();
- }
-
IO::silence (nframes);
} else {
@@ -731,321 +499,19 @@ Route::process_output_buffers (BufferSet& bufs,
POST-FADER METERING
----------------------------------------------------------------------------------------- */
+ /* TODO: Processor-list-ification needs to go further for this to be cleanly possible...
if (meter && (_meter_point == MeterPostFader)) {
if ((_gain == 0 && !apply_gain_automation) || dmg == 0) {
_meter->reset();
} else {
_meter->run_in_place(output_buffers(), start_frame, end_frame, nframes);
}
- }
-}
-
-#ifdef NEW_POB
-/** Process this route for one (sub) cycle (process thread)
- *
- * @param bufs Scratch buffers to use for the signal path
- * @param start_frame Initial transport frame
- * @param end_frame Final transport frame
- * @param nframes Number of frames to output (to ports)
- *
- * Note that (end_frame - start_frame) may not be equal to nframes when the
- * transport speed isn't 1.0 (eg varispeed).
- */
-void
-Route::process_output_buffers (BufferSet& bufs,
- nframes_t start_frame, nframes_t end_frame, nframes_t nframes,
- bool with_processors, int declick, bool meter)
-{
- // This is definitely very audio-only for now
- assert(_default_type == DataType::AUDIO);
-
- ProcessorList::iterator i;
- bool post_fader_work = false;
- bool mute_declick_applied = false;
- gain_t dmg, dsg, dg;
- IO *co;
- bool mute_audible;
- bool solo_audible;
- bool no_monitor;
- gain_t* gab = _session.gain_automation_buffer();
-
- switch (Config->get_monitoring_model()) {
- case HardwareMonitoring:
- case ExternalMonitoring:
- no_monitor = true;
- break;
- default:
- no_monitor = false;
- }
-
- declick = _pending_declick;
-
- {
- Glib::Mutex::Lock cm (_control_outs_lock, Glib::TRY_LOCK);
-
- if (cm.locked()) {
- co = _control_outs;
- } else {
- co = 0;
- }
- }
-
- {
- Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
-
- if (dm.locked()) {
- dmg = desired_mute_gain;
- dsg = desired_solo_gain;
- dg = _desired_gain;
- } else {
- dmg = mute_gain;
- dsg = solo_gain;
- dg = _gain;
- }
- }
-
- /* -------------------------------------------------------------------------------------------
- GLOBAL DECLICK (for transport changes etc.)
- input metering & monitoring (control outs)
- denormal control
- pre-fader redirects
- pre-fader metering & monitoring (control outs)
- gain stage
- post-fader redirects
- global mute
- main output
- post-fader metering & monitoring (control outs)
- ----------------------------------------------------------------------------------------- */
-
- {
- Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
- for (i = processors.begin(); i != processors.end(); ++i) {
- (*i)->run_in_place (bufs, start_frame, end_frame, nframes);
- }
- }
-
-
- /* -------------------------------------------------------------------------------------------
- INPUT METERING & MONITORING
- ----------------------------------------------------------------------------------------- */
-
- if (meter && (_meter_point == MeterInput)) {
- _meter->run_in_place(bufs, start_frame, end_frame, nframes);
- }
-
- if (!_soloed && _mute_affects_pre_fader && (mute_gain != dmg)) {
- Amp::run_in_place (bufs, nframes, mute_gain, dmg, false);
- mute_gain = dmg;
- mute_declick_applied = true;
- }
-
- /* -------------------------------------------------------------------------------------------
- PRE-FADER REDIRECTS
- ----------------------------------------------------------------------------------------- */
-
- // This really should already be true...
- bufs.set_count(pre_fader_streams());
-
-
- if ((_meter_point == MeterPreFader) && co) {
-
- solo_audible = dsg > 0;
- mute_audible = dmg > 0 || !_mute_affects_pre_fader;
-
- if ( // muted by solo of another track
-
- !solo_audible ||
-
- // muted by mute of this track
-
- !mute_audible ||
-
- // rec-enabled but not s/w monitoring
-
- ( no_monitor && record_enabled()
- && (!Config->get_auto_input() || _session.actively_recording()) )
-
- ) {
-
- co->silence (nframes);
-
- } else {
-
- co->deliver_output (bufs, start_frame, end_frame, nframes);
- }
- }
-
- /* -------------------------------------------------------------------------------------------
- GAIN STAGE
- ----------------------------------------------------------------------------------------- */
-
- /* if not recording or recording and requiring any monitor signal, then apply gain */
-
- if ( // not recording
-
- !(record_enabled() && _session.actively_recording()) ||
-
- // OR recording
-
- // AND software monitoring required
-
- Config->get_monitoring_model() == SoftwareMonitoring) {
-
- if (apply_gain_automation) {
-
- if (_phase_invert) {
- 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) {
- sp[nx] *= -gab[nx];
- }
- }
- } else {
- 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) {
- sp[nx] *= gab[nx];
- }
- }
- }
-
- if (apply_gain_automation && _session.transport_rolling() && nframes > 0) {
- _effective_gain = gab[nframes-1];
- }
-
- } else {
-
- /* manual (scalar) gain */
-
- if (_gain != dg) {
-
- Amp::run_in_place (bufs, nframes, _gain, dg, _phase_invert);
- _gain = dg;
-
- } else if (_gain != 0 && (_phase_invert || _gain != 1.0)) {
-
- /* no need to interpolate current gain value,
- but its non-unity, so apply it. if the gain
- is zero, do nothing because we'll ship silence
- below.
- */
-
- gain_t this_gain;
-
- if (_phase_invert) {
- this_gain = -_gain;
- } else {
- this_gain = _gain;
- }
-
- for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
- Sample* const sp = i->data();
- apply_gain_to_buffer(sp,nframes,this_gain);
- }
-
- } else if (_gain == 0) {
- for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
- i->clear();
- }
- }
- }
-
- } else {
-
- /* actively recording, no monitoring required; leave buffers as-is to save CPU cycles */
-
- }
-
- /* -------------------------------------------------------------------------------------------
- CONTROL OUTPUT STAGE
- ----------------------------------------------------------------------------------------- */
-
- if ((_meter_point == MeterPostFader) && co) {
-
- solo_audible = solo_gain > 0;
- mute_audible = dmg > 0 || !_mute_affects_control_outs;
-
- if ( // silent anyway
-
- (_gain == 0 && !apply_gain_automation) ||
-
- // muted by solo of another track
-
- !solo_audible ||
-
- // muted by mute of this track
-
- !mute_audible ||
-
- // recording but not s/w monitoring
-
- (no_monitor && record_enabled() && (!Config->get_auto_input() || _session.actively_recording()))
+ }*/
- ) {
-
- co->silence (nframes);
-
- } else {
-
- co->deliver_output (bufs, start_frame, end_frame, nframes);
- }
- }
-
- /* -------------------------------------------------------------------------------------------
- MAIN OUTPUT STAGE
- ----------------------------------------------------------------------------------------- */
-
- solo_audible = dsg > 0;
- mute_audible = dmg > 0 || !_mute_affects_main_outs;
-
- if (n_outputs().get(_default_type) == 0) {
-
- /* relax */
-
- } else if (no_monitor && record_enabled()
- && (!Config->get_auto_input() || _session.actively_recording())) {
-
- IO::silence (nframes);
-
- } else {
-
- if ( // silent anyway
-
- (_gain == 0 && !apply_gain_automation) ||
-
- // muted by solo of another track, but not using control outs for solo
-
- (!solo_audible && (Config->get_solo_model() != SoloBus)) ||
-
- // muted by mute of this track
-
- !mute_audible
-
- ) {
-
- /* don't use Route::silence() here, because that causes
- all outputs (sends, port processors, etc. to be silent).
- */
-
- if (_meter_point == MeterPostFader) {
- peak_meter().reset();
- }
-
- IO::silence (nframes);
-
- } else {
-
- deliver_output(bufs, start_frame, end_frame, nframes);
-
- }
-
- }
+ // at this point we've reached the desired mute gain regardless
+ mute_gain = dmg;
}
-#endif /* NEW_POB */
-
ChanCount
Route::n_process_buffers ()
{
@@ -1061,7 +527,7 @@ Route::setup_peak_meters()
}
void
-Route::passthru (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, int declick, bool meter_first)
+Route::passthru (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, int declick)
{
BufferSet& bufs = _session.get_scratch_buffers(n_process_buffers());
@@ -1069,20 +535,13 @@ Route::passthru (nframes_t start_frame, nframes_t end_frame, nframes_t nframes,
collect_input (bufs, nframes);
- if (meter_first) {
- _meter->run_in_place(bufs, start_frame, end_frame, nframes);
- meter_first = false;
- } else {
- meter_first = true;
- }
-
- process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick, meter_first);
+ process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick);
}
void
-Route::passthru_silence (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, int declick, bool meter)
+Route::passthru_silence (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, int declick)
{
- process_output_buffers (_session.get_silent_buffers (n_process_buffers()), start_frame, end_frame, nframes, true, declick, meter);
+ process_output_buffers (_session.get_silent_buffers (n_process_buffers()), start_frame, end_frame, nframes, true, declick);
}
void
@@ -1114,7 +573,6 @@ Route::catch_up_on_solo_mute_override ()
}
{
-
Glib::Mutex::Lock lm (declick_lock);
if (_muted) {
@@ -1166,7 +624,7 @@ Route::set_mute (bool yn, void *src)
Glib::Mutex::Lock lm (declick_lock);
- if (_soloed && Config->get_solo_mute_override()){
+ if (_soloed && Config->get_solo_mute_override()) {
desired_mute_gain = 1.0f;
} else {
desired_mute_gain = (yn?0.0f:1.0f);
@@ -1174,8 +632,24 @@ Route::set_mute (bool yn, void *src)
}
}
+static void
+dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& procs)
+{
+ cerr << name << " {" << endl;
+ for (list<boost::shared_ptr<Processor> >::const_iterator p = procs.begin();
+ p != procs.end(); ++p) {
+ cerr << "\t" << (*p)->sort_key() << ": " << (*p)->name() << endl;
+ }
+ cerr << "}" << endl;
+}
+
+/** Add a processor to the route.
+ * If @a iter is not NULL, it must point to an iterator in _processors and the new
+ * processor will be inserted immediately before this location. Otherwise,
+ * @a position is used.
+ */
int
-Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err)
+Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err, ProcessorList::iterator* iter, Placement placement)
{
ChanCount old_pms = processor_max_streams;
@@ -1189,18 +663,66 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
boost::shared_ptr<PluginInsert> pi;
boost::shared_ptr<PortInsert> porti;
- //processor->set_default_type(_default_type);
+ ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), processor);
+
+ if (processor == _amp || processor == _meter) {
+ // Ensure only one amp and one meter are in the list at any time
+ if (loc != _processors.end()) {
+ if (iter) {
+ if (*iter == loc) { // Already in place, do nothing
+ return 0;
+ } else { // New position given, relocate
+ _processors.erase(loc);
+ }
+ } else { // Insert at end
+ _processors.erase(loc);
+ loc = _processors.end();
+ }
+ }
+
+ } else {
+ if (loc != _processors.end()) {
+ cerr << "ERROR: Processor added to route twice!" << endl;
+ return 1;
+ }
+ }
+
+ // Use position given by user
+ if (iter) {
+ loc = *iter;
+
+ // Insert immediately before the amp
+ } else if (placement == PreFader) {
+ loc = find(_processors.begin(), _processors.end(), _amp);
+
+ // Insert at end
+ } else {
+ loc = _processors.end();
+ }
+
+ // Update sort keys
+ if (loc == _processors.end()) {
+ processor->set_sort_key(_processors.size());
+ } else {
+ processor->set_sort_key((*loc)->sort_key());
+ for (ProcessorList::iterator p = loc; p != _processors.end(); ++p) {
+ (*p)->set_sort_key((*p)->sort_key() + 1);
+ }
+ }
- _processors.push_back (processor);
+ _processors.insert(loc, processor);
// Set up processor list channels. This will set processor->[input|output]_streams(),
// configure redirect ports properly, etc.
- if (_reset_processor_counts (err)) {
- _processors.pop_back ();
- _reset_processor_counts (0); // it worked before we tried to add it ...
+ if (configure_processors_unlocked (err)) {
+ dump_processors(_name, _processors);
+ ProcessorList::iterator ploc = loc;
+ --ploc;
+ _processors.erase(ploc);
+ configure_processors_unlocked (0); // it worked before we tried to add it ...
return -1;
}
-
+
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(processor)) != 0) {
if (pi->natural_input_streams() == ChanCount::ZERO) {
@@ -1211,13 +733,8 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
}
// Ensure peak vector sizes before the plugin is activated
-
- ChanCount potential_max_streams;
-
- potential_max_streams.set (DataType::AUDIO, max (processor->input_streams().n_audio(),
- processor->output_streams().n_audio()));
- potential_max_streams.set (DataType::MIDI, max (processor->input_streams().n_midi(),
- processor->output_streams().n_midi()));
+ ChanCount potential_max_streams = ChanCount::max(
+ processor->input_streams(), processor->output_streams());
_meter->configure_io (potential_max_streams, potential_max_streams);
@@ -1232,13 +749,15 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
reset_panner ();
}
+ dump_processors (_name, _processors);
processors_changed (); /* EMIT SIGNAL */
+
return 0;
}
int
-Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
+Route::add_processors (const ProcessorList& others, ProcessorStreams* err, Placement placement)
{
/* NOTE: this is intended to be used ONLY when copying
processors from another Route. Hence the subtle
@@ -1257,10 +776,18 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
ProcessorList::iterator existing_end = _processors.end();
--existing_end;
- ChanCount potential_max_streams;
+ ChanCount potential_max_streams = ChanCount::max(input_minimum(), output_minimum());
for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) {
+ // Ensure meter only appears in the list once
+ if (*i == _meter) {
+ ProcessorList::iterator m = find(_processors.begin(), _processors.end(), *i);
+ if (m != _processors.end()) {
+ _processors.erase(m);
+ }
+ }
+
boost::shared_ptr<PluginInsert> pi;
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
@@ -1274,12 +801,16 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
// Ensure peak vector sizes before the plugin is activated
_meter->configure_io (potential_max_streams, potential_max_streams);
- _processors.push_back (*i);
+ ProcessorList::iterator loc = (placement == PreFader)
+ ? find(_processors.begin(), _processors.end(), _amp)
+ : _processors.end();
+
+ _processors.insert (loc, *i);
- if (_reset_processor_counts (err)) {
+ if (configure_processors_unlocked (err)) {
++existing_end;
_processors.erase (existing_end, _processors.end());
- _reset_processor_counts (0); // it worked before we tried to add it ...
+ configure_processors_unlocked (0); // it worked before we tried to add it ...
return -1;
}
@@ -1292,11 +823,26 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
if (processor_max_streams != old_pms || old_pms == ChanCount::ZERO) {
reset_panner ();
}
-
+
+ dump_processors (_name, _processors);
processors_changed (); /* EMIT SIGNAL */
+
return 0;
}
+void
+Route::placement_range(Placement p, ProcessorList::iterator& start, ProcessorList::iterator& end)
+{
+ if (p == PreFader) {
+ start = _processors.begin();
+ end = find(_processors.begin(), _processors.end(), _amp);
+ } else {
+ start = find(_processors.begin(), _processors.end(), _amp);
+ ++start;
+ end = _processors.end();
+ }
+}
+
/** Turn off all processors with a given placement
* @param p Placement of processors to disable
*/
@@ -1305,10 +851,11 @@ Route::disable_processors (Placement p)
{
Glib::RWLock::ReaderLock lm (_processor_lock);
- for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- if ((*i)->placement() == p) {
- (*i)->deactivate ();
- }
+ ProcessorList::iterator start, end;
+ placement_range(p, start, end);
+
+ for (ProcessorList::iterator i = start; i != end; ++i) {
+ (*i)->deactivate ();
}
_session.set_dirty ();
@@ -1336,8 +883,11 @@ Route::disable_plugins (Placement p)
{
Glib::RWLock::ReaderLock lm (_processor_lock);
- for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- if (boost::dynamic_pointer_cast<PluginInsert> (*i) && (*i)->placement() == p) {
+ ProcessorList::iterator start, end;
+ placement_range(p, start, end);
+
+ for (ProcessorList::iterator i = start; i != end; ++i) {
+ if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
(*i)->deactivate ();
}
}
@@ -1417,7 +967,10 @@ Route::pre_fader_streams() const
/* 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 && boost::dynamic_pointer_cast<Send> (*i) == 0) {
+ if ((*i) == _amp) {
+ break;
+ }
+ if (boost::dynamic_pointer_cast<Send> (*i) == 0) {
processor = *i;
}
}
@@ -1441,21 +994,38 @@ Route::clear_processors (Placement p)
if (!_session.engine().connected()) {
return;
}
+
+ bool already_deleting = _session.deletion_in_progress();
+ if (!already_deleting) {
+ _session.set_deletion_in_progress();
+ }
{
Glib::RWLock::WriterLock lm (_processor_lock);
ProcessorList new_list;
- for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- if ((*i)->placement() == p) {
- /* it's the placement we want to get rid of */
+ ProcessorList::iterator amp_loc = find(_processors.begin(), _processors.end(), _amp);
+ if (p == PreFader) {
+ // Get rid of PreFader processors
+ for (ProcessorList::iterator i = _processors.begin(); i != amp_loc; ++i) {
(*i)->drop_references ();
- } else {
- /* it's a different placement, so keep it */
+ }
+ // Keep the rest
+ for (ProcessorList::iterator i = amp_loc; i != _processors.end(); ++i) {
+ new_list.push_back (*i);
+ }
+ } else {
+ // Keep PreFader processors
+ for (ProcessorList::iterator i = _processors.begin(); i != amp_loc; ++i) {
new_list.push_back (*i);
}
+ new_list.push_back (_amp);
+ // Get rid of PostFader processors
+ for (ProcessorList::iterator i = amp_loc; i != _processors.end(); ++i) {
+ (*i)->drop_references ();
+ }
}
-
+
_processors = new_list;
}
@@ -1467,11 +1037,19 @@ Route::clear_processors (Placement p)
processor_max_streams.reset();
_have_internal_generator = false;
processors_changed (); /* EMIT SIGNAL */
+
+ if (!already_deleting) {
+ _session.clear_deletion_in_progress();
+ }
}
int
Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err)
{
+ if (processor == _amp || processor == _meter) {
+ return 0;
+ }
+
ChanCount old_pms = processor_max_streams;
if (!_session.engine().connected()) {
@@ -1490,7 +1068,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
ProcessorList::iterator tmp;
- /* move along, see failure case for reset_processor_counts()
+ /* move along, see failure case for configure_processors()
where we may need to reprocessor the processor.
*/
@@ -1524,11 +1102,11 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
return 1;
}
- if (_reset_processor_counts (err)) {
+ if (configure_processors_unlocked (err)) {
/* get back to where we where */
_processors.insert (i, processor);
/* we know this will work, because it worked before :) */
- _reset_processor_counts (0);
+ configure_processors_unlocked (0);
return -1;
}
@@ -1551,224 +1129,72 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
}
processor->drop_references ();
-
+
+ dump_processors (_name, _processors);
processors_changed (); /* EMIT SIGNAL */
- return 0;
-}
-int
-Route::reset_processor_counts (ProcessorStreams* err)
-{
- Glib::RWLock::WriterLock lm (_processor_lock);
- return _reset_processor_counts (err);
+ return 0;
}
-
int
-Route::_reset_processor_counts (ProcessorStreams* err)
-{
- ProcessorList::iterator r;
- uint32_t insert_cnt = 0;
- uint32_t send_cnt = 0;
- map<Placement,list<ProcessorCount> > proc_map;
- ProcessorList::iterator prev;
- ChanCount initial_streams = n_inputs ();
- ChanCount previous_initial_streams = n_inputs ();
- int ret = -1;
- uint32_t max_audio = 0;
- uint32_t max_midi = 0;
-
- processor_max_streams.reset ();
-
- /* Step 1: build a map that links each insert to an in/out channel count
-
- Divide inserts up by placement so we get the signal flow
- properly modelled. we need to do this because the _processors
- list is not sorted by placement, and because other reasons may
- exist now or in the future for this separate treatment.
- */
-
- /* ... but it should/will be... */
-
- for (r = _processors.begin(); r != _processors.end(); ++r) {
-
- boost::shared_ptr<PluginInsert> plugin_insert;
- boost::shared_ptr<PortInsert> port_insert;
-
- if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert>(*r)) != 0) {
-
- ++insert_cnt;
- proc_map[(*r)->placement()].push_back (ProcessorCount (*r));
-
- /* reset plugin counts back to one for now so
- that we have a predictable, controlled
- state to try to configure.
- */
-
- 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));
-
- } else if (boost::dynamic_pointer_cast<Send> (*r) != 0) {
- ++send_cnt;
- }
- }
-
- if (insert_cnt == 0) {
- if (send_cnt) {
- goto recompute;
- } else {
- ret = 0;
- goto streamcount;
- }
- }
-
- /* Now process each placement in order, checking to see if we
- can really do what has been requested.
- */
-
- /* A: PreFader */
-
- if (check_some_processor_counts (proc_map[PreFader], n_inputs (), err)) {
- goto streamcount;
- }
-
- 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) == false) {
- goto streamcount;
- }
- previous_initial_streams = initial_streams;
- }
- }
-
- /* B: PostFader */
-
- if (check_some_processor_counts (proc_map[PostFader], initial_streams, err)) {
- goto streamcount;
- }
-
- 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) == false) {
- goto streamcount;
- }
- previous_initial_streams = initial_streams;
- }
- }
-
- /* OK, everything can be set up correctly, so lets do it */
-
- apply_some_processor_counts (proc_map[PreFader]);
- apply_some_processor_counts (proc_map[PostFader]);
-
- /* recompute max outs of any processor */
-
- ret = 0;
-
- recompute:
-
- processor_max_streams.reset ();
- prev = _processors.end();
-
- for (r = _processors.begin(); r != _processors.end(); prev = r, ++r) {
- 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 {
- s->expect_inputs ((*prev)->output_streams());
- }
-
- } else {
-
- max_audio = max ((*r)->input_streams ().n_audio(), max_audio);
- max_midi = max ((*r)->input_streams ().n_midi(), max_midi);
- max_audio = max ((*r)->output_streams ().n_audio(), max_audio);
- max_midi = max ((*r)->output_streams ().n_midi(), max_midi);
- }
- }
-
- processor_max_streams.set (DataType::AUDIO, max_audio);
- processor_max_streams.set (DataType::MIDI, max_midi);
-
- /* we're done */
- return 0;
-
- streamcount:
- for (r = _processors.begin(); r != _processors.end(); ++r) {
- max_audio = max ((*r)->output_streams ().n_audio(), max_audio);
- max_midi = max ((*r)->output_streams ().n_midi(), max_midi);
- }
-
- processor_max_streams.set (DataType::AUDIO, max_audio);
- processor_max_streams.set (DataType::MIDI, max_midi);
-
- return ret;
-}
-
-int32_t
-Route::apply_some_processor_counts (list<ProcessorCount>& iclist)
+Route::configure_processors (ProcessorStreams* err)
{
- list<ProcessorCount>::iterator i;
-
- for (i = iclist.begin(); i != iclist.end(); ++i) {
-
- ProcessorCount& pc (*i);
-
- if (pc.processor->configure_io (pc.in, pc.out)) {
- return -1;
- }
-
- /* make sure that however many we have, they are all active */
-
- pc.processor->activate ();
+ if (!_in_configure_processors) {
+ Glib::RWLock::WriterLock lm (_processor_lock);
+ return configure_processors_unlocked (err);
}
-
return 0;
}
-/** Returns whether \a iclist can be configured and run starting with
- * \a required_inputs at the first processor's inputs.
- * If false is returned, \a iclist can not be run with \a required_inputs, and \a err is set.
- * Otherwise, \a err is set to the output of the list.
+/** Configure the input/output configuration of each processor in the processors list.
+ * Return 0 on success, otherwise configuration is impossible.
*/
-bool
-Route::check_some_processor_counts (list<ProcessorCount>& iclist, ChanCount required_inputs, ProcessorStreams* err)
+int
+Route::configure_processors_unlocked (ProcessorStreams* err)
{
- list<ProcessorCount>::iterator i;
- size_t index = 0;
-
- if (err) {
- err->index = 0;
- err->count = required_inputs;
+ if (_in_configure_processors) {
+ return 0;
}
- for (i = iclist.begin(); i != iclist.end(); ++i, ++index) {
+ _in_configure_processors = true;
- if (!(*i).processor->can_support_io_configuration (required_inputs, (*i).out)) {
+ // Check each processor in order to see if we can configure as requested
+ ChanCount in = _configured_inputs;
+ ChanCount out;
+ list< pair<ChanCount,ChanCount> > configuration;
+ uint32_t index = 0;
+ for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++index) {
+ (*p)->set_sort_key(index);
+ if ((*p)->can_support_io_configuration(in, out)) {
+ configuration.push_back(make_pair(in, out));
+ in = out;
+ } else {
if (err) {
err->index = index;
- err->count = required_inputs;
+ err->count = in;
}
- return true;
+ _in_configure_processors = false;
+ return -1;
}
-
- (*i).in = required_inputs;
- required_inputs = (*i).out;
+ }
+
+ // We can, so configure everything
+ list< pair<ChanCount,ChanCount> >::iterator c = configuration.begin();
+ for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++c) {
+ (*p)->configure_io(c->first, c->second);
+ (*p)->activate();
+ processor_max_streams = ChanCount::max(processor_max_streams, c->first);
+ processor_max_streams = ChanCount::max(processor_max_streams, c->second);
+ out = c->second;
}
- return false;
+ // Ensure route outputs match last processor's outputs
+ if (out != n_outputs()) {
+ ensure_io(_configured_inputs, out, false, this);
+ }
+
+ _in_configure_processors = false;
+ return 0;
}
void
@@ -1805,9 +1231,16 @@ Route::all_processors_active (Placement p, bool state)
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)->placement() == p) {
+ if ((*i) == _amp) {
+ before_amp = false;
+ continue;
+ }
+ if (p == PreFader && before_amp) {
if (state) {
(*i)->activate ();
} else {
@@ -1839,7 +1272,7 @@ Route::sort_processors (ProcessorStreams* err)
_processors.sort (comparator);
- if (_reset_processor_counts (err)) {
+ if (configure_processors_unlocked (err)) {
_processors = as_it_was_before;
processor_max_streams = old_pms;
return -1;
@@ -1925,7 +1358,7 @@ Route::state(bool full_state)
if (_control_outs) {
XMLNode* cnode = new XMLNode (X_("ControlOuts"));
- cnode->add_child_nocopy (_control_outs->state (full_state));
+ cnode->add_child_nocopy (_control_outs->io()->state (full_state));
node->add_child_nocopy (*cnode);
}
@@ -2033,8 +1466,8 @@ Route::set_deferred_state ()
deferred_state = 0;
}
-void
-Route::add_processor_from_xml (const XMLNode& node)
+bool
+Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator* iter)
{
const XMLProperty *prop;
@@ -2043,15 +1476,15 @@ Route::add_processor_from_xml (const XMLNode& node)
try {
boost::shared_ptr<Send> send (new Send (_session, node));
- add_processor (send);
+ add_processor (send, 0, iter);
+ return true;
}
catch (failed_constructor &err) {
error << _("Send construction failed") << endmsg;
- return;
+ return false;
}
- // use "Processor" in XML?
} else if (node.name() == "Processor") {
try {
@@ -2076,13 +1509,21 @@ Route::add_processor_from_xml (const XMLNode& node)
processor.reset (new Send (_session, node));
have_insert = true;
+
+ } else if (prop->value() == "meter") {
+
+ processor = _meter;
+
+ } else if (prop->value() == "amp") {
+
+ processor = _amp;
} else {
error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
}
- add_processor (processor);
+ return (add_processor (processor, 0, iter) == 0);
} else {
error << _("Processor XML node has no type property") << endmsg;
@@ -2091,9 +1532,10 @@ Route::add_processor_from_xml (const XMLNode& node)
catch (failed_constructor &err) {
warning << _("processor could not be created. Ignored.") << endmsg;
- return;
+ return false;
}
}
+ return false;
}
int
@@ -2238,6 +1680,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
}
XMLNodeList processor_nodes;
+ bool has_meter_processor = false; // legacy sessions don't
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
@@ -2245,12 +1688,18 @@ Route::_set_state (const XMLNode& node, bool call_base)
if (child->name() == X_("Send") || child->name() == X_("Processor")) {
processor_nodes.push_back(child);
+ if ((prop = child->property (X_("type"))) != 0 && prop->value() == "meter") {
+ has_meter_processor = true;
+ }
}
}
_set_processor_states(processor_nodes);
-
+ if (!has_meter_processor) {
+ set_meter_point(_meter_point, NULL);
+ }
+ processors_changed ();
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
@@ -2267,8 +1716,8 @@ Route::_set_state (const XMLNode& node, bool call_base)
string coutname = _name;
coutname += _("[control]");
- delete _control_outs;
- _control_outs = new IO (_session, coutname);
+ _control_outs = boost::shared_ptr<ControlOutputs> (
+ new ControlOutputs (_session, new IO (_session, coutname)));
/* fix up the control out name in the XML before setting it.
Otherwise track templates don't work because the control
@@ -2281,7 +1730,9 @@ Route::_set_state (const XMLNode& node, bool call_base)
prop->set_value (coutname);
}
- _control_outs->set_state (**(child->children().begin()));
+ _control_outs->io()->set_state (**(child->children().begin()));
+ _control_outs->set_sort_key (_meter->sort_key() + 1);
+ add_processor (_control_outs, 0);
} else if (child->name() == X_("Comment")) {
@@ -2303,8 +1754,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
_mute_control->set_state (*child);
_session.add_controllable (_mute_control);
}
- }
- else if (child->name() == X_("RemoteControl")) {
+ } else if (child->name() == X_("RemoteControl")) {
if ((prop = child->property (X_("id"))) != 0) {
int32_t x;
sscanf (prop->value().c_str(), "%d", &x);
@@ -2365,6 +1815,7 @@ Route::_set_processor_states(const XMLNodeList &nlist)
i = tmp;
}
+ Placement placement = PreFader;
// Iterate through state list and make sure all processors are on the track and in the correct order,
// set the state of existing processors according to the new state on the same go
@@ -2389,50 +1840,33 @@ Route::_set_processor_states(const XMLNodeList &nlist)
++o;
}
+ // If the processor (*niter) is not on the route,
+ // create it and move it to the correct location
if (o == _processors.end()) {
- // If the processor (*niter) is not on the route, we need to create it
- // and move it to the correct location
-
- ProcessorList::iterator prev_last = _processors.end();
- --prev_last; // We need this to check whether adding succeeded
-
- add_processor_from_xml (**niter);
-
- ProcessorList::iterator last = _processors.end();
- --last;
+ if (add_processor_from_xml (**niter, &i)) {
+ --i; // move iterator to the newly inserted processor
+ } else {
+ cerr << "Error restoring route: unable to restore processor" << endl;
+ }
- if (prev_last == last) {
- cerr << "Could not fully restore state as some processors were not possible to create" << endl;
- continue;
+ // Otherwise, we found the processor (*niter) on the route,
+ // ensure it is at the location provided in the XML state
+ } else {
+ if (i != o) {
+ boost::shared_ptr<Processor> tmp = (*o);
+ _processors.erase(o); // remove the old copy
+ _processors.insert(i, tmp); // insert the processor at the correct location
+ --i; // move iterator to the correct processor
}
- boost::shared_ptr<Processor> tmp = (*last);
- // remove the processor from the wrong location
- _processors.erase(last);
- // processor the new processor at the current location
- _processors.insert(i, tmp);
-
- --i; // move pointer to the newly processored processor
- continue;
+ (*i)->set_state((**niter));
}
- // We found the processor (*niter) on the route, first we must make sure the processor
- // is at the location provided in the XML state
- if (i != o) {
- boost::shared_ptr<Processor> tmp = (*o);
- // remove the old copy
- _processors.erase(o);
- // processor the processor at the correct location
- _processors.insert(i, tmp);
-
- --i; // move pointer so it points to the right processor
+ if (*i == _amp) {
+ placement = PostFader;
}
-
- (*i)->set_state( (**niter) );
}
-
- processors_changed ();
}
void
@@ -2450,7 +1884,7 @@ Route::silence (nframes_t nframes)
IO::silence (nframes);
if (_control_outs) {
- _control_outs->silence (nframes);
+ _control_outs->io()->silence (nframes);
}
{
@@ -2479,13 +1913,8 @@ Route::silence (nframes_t nframes)
int
Route::set_control_outs (const vector<string>& ports)
{
- Glib::Mutex::Lock lm (_control_outs_lock);
vector<string>::const_iterator i;
- size_t limit;
- delete _control_outs;
- _control_outs = 0;
-
if (is_control() || is_master()) {
/* no control outs for these two special busses */
return 0;
@@ -2498,28 +1927,31 @@ Route::set_control_outs (const vector<string>& ports)
string coutname = _name;
coutname += _("[control]");
- _control_outs = new IO (_session, coutname);
+ IO* out_io = new IO (_session, coutname);
+ boost::shared_ptr<ControlOutputs> out_proc(new ControlOutputs (_session, out_io));
- /* our control outs need as many outputs as we
- have audio outputs. we track the changes in ::output_change_handler().
- */
-
- // XXX its stupid that we have to get this value twice
-
- limit = n_outputs().n_audio();
-
- if (_control_outs->ensure_io (ChanCount::ZERO, ChanCount (DataType::AUDIO, n_outputs().get (DataType::AUDIO)), true, this)) {
+ /* As an IO, our control outs need as many IO outputs as we have outputs
+ * (we track the changes in ::output_change_handler()).
+ * As a processor, the control outs is an identity processor
+ * (i.e. it does not modify its input buffers whatsoever)
+ */
+ if (out_io->ensure_io (ChanCount::ZERO, n_outputs(), true, this)) {
return -1;
}
-
+
/* now connect to the named ports */
- for (size_t n = 0; n < limit; ++n) {
- if (_control_outs->connect_output (_control_outs->output (n), ports[n % ports.size()], this)) {
- error << string_compose (_("could not connect %1 to %2"), _control_outs->output(n)->name(), ports[n]) << endmsg;
+ for (size_t n = 0; n < n_outputs().n_total(); ++n) {
+ if (out_io->connect_output (out_io->output (n), ports[n % ports.size()], this)) {
+ error << string_compose (_("could not connect %1 to %2"),
+ out_io->output(n)->name(), ports[n]) << endmsg;
return -1;
}
}
+
+ _control_outs = out_proc;
+ _control_outs->set_sort_key (_meter->sort_key() + 1);
+ add_processor (_control_outs, NULL);
return 0;
}
@@ -2631,11 +2063,11 @@ Route::feeds (boost::shared_ptr<Route> other)
if (_control_outs) {
- no = _control_outs->n_outputs().n_total();
+ no = _control_outs->io()->n_outputs().n_total();
for (i = 0; i < no; ++i) {
for (j = 0; j < ni; ++j) {
- if (_control_outs->output(i)->connected_to (other->input (j)->name())) {
+ if (_control_outs->io()->output(i)->connected_to (other->input (j)->name())) {
return true;
}
}
@@ -2651,22 +2083,22 @@ Route::set_mute_config (mute_type t, bool onoff, void *src)
switch (t) {
case PRE_FADER:
_mute_affects_pre_fader = onoff;
- pre_fader_changed(src); /* EMIT SIGNAL */
+ pre_fader_changed(src); /* EMIT SIGNAL */
break;
case POST_FADER:
_mute_affects_post_fader = onoff;
- post_fader_changed(src); /* EMIT SIGNAL */
+ post_fader_changed(src); /* EMIT SIGNAL */
break;
case CONTROL_OUTS:
_mute_affects_control_outs = onoff;
- control_outs_changed(src); /* EMIT SIGNAL */
+ control_outs_changed(src); /* EMIT SIGNAL */
break;
case MAIN_OUTS:
_mute_affects_main_outs = onoff;
- main_outs_changed(src); /* EMIT SIGNAL */
+ main_outs_changed(src); /* EMIT SIGNAL */
break;
}
}
@@ -2723,22 +2155,22 @@ Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_f
}
void
-Route::input_change_handler (IOChange change, void *ignored)
+Route::input_change_handler (IOChange change, void *src)
{
- if (change & ConfigurationChanged) {
- reset_processor_counts (0);
+ if ((change & ConfigurationChanged)) {
+ configure_processors (0);
}
}
void
-Route::output_change_handler (IOChange change, void *ignored)
+Route::output_change_handler (IOChange change, void *src)
{
- if (change & ConfigurationChanged) {
+ if ((change & ConfigurationChanged)) {
if (_control_outs) {
- _control_outs->ensure_io (ChanCount::ZERO, ChanCount(DataType::AUDIO, n_outputs().n_audio()), true, this);
+ _control_outs->io()->ensure_io (ChanCount::ZERO, n_outputs(), true, this);
}
- reset_processor_counts (0);
+ configure_processors (0);
}
}
@@ -2765,10 +2197,10 @@ Route::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
return 0;
}
- apply_gain_automation = false;
+ _amp->apply_gain_automation(false);
- if (n_inputs().n_total()) {
- passthru (start_frame, end_frame, nframes, 0, false);
+ if (n_inputs() != ChanCount::ZERO) {
+ passthru (start_frame, end_frame, nframes, 0);
} else {
silence (nframes);
}
@@ -2829,7 +2261,7 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, int
_silent = false;
- apply_gain_automation = false;
+ _amp->apply_gain_automation(false);
{
Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
@@ -2837,13 +2269,14 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, int
if (am.locked() && _session.transport_rolling()) {
if (_gain_control->automation_playback()) {
- apply_gain_automation = _gain_control->list()->curve().rt_safe_get_vector (
- start_frame, end_frame, _session.gain_automation_buffer(), nframes);
+ _amp->apply_gain_automation(
+ _gain_control->list()->curve().rt_safe_get_vector (
+ start_frame, end_frame, _session.gain_automation_buffer(), nframes));
}
}
}
- passthru (start_frame, end_frame, nframes, declick, false);
+ passthru (start_frame, end_frame, nframes, declick);
return 0;
}
@@ -2912,7 +2345,35 @@ Route::set_meter_point (MeterPoint p, void *src)
{
if (_meter_point != p) {
_meter_point = p;
+
+ // Move meter in the processors list
+ ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), _meter);
+ _processors.erase(loc);
+ switch (p) {
+ case MeterInput:
+ loc = _processors.begin();
+ break;
+ case MeterPreFader:
+ loc = find(_processors.begin(), _processors.end(), _amp);
+ break;
+ case MeterPostFader:
+ loc = _processors.end();
+ break;
+ }
+ _processors.insert(loc, _meter);
+
+ // Update sort key
+ if (loc == _processors.end()) {
+ _meter->set_sort_key(_processors.size());
+ } else {
+ _meter->set_sort_key((*loc)->sort_key());
+ for (ProcessorList::iterator p = loc; p != _processors.end(); ++p) {
+ (*p)->set_sort_key((*p)->sort_key() + 1);
+ }
+ }
+
meter_change (src); /* EMIT SIGNAL */
+ processors_changed (); /* EMIT SIGNAL */
_session.set_dirty ();
}
}
@@ -3054,6 +2515,7 @@ Route::set_block_size (nframes_t nframes)
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->set_block_size (nframes);
}
+ _session.ensure_buffers(processor_max_streams);
}
void