Made plugin input/output counts multi-typed (towards MIDI plugins, instruments, etc).

Cleaning up/genericification of Insert interface.
Fixed meter count for pre-fader metering (was # inputs, not # channels at end of pre-fader redirect list).
Work on redirect list stream handling, better error reporting (towards automatically adding 'adaptors' in the future?).


git-svn-id: svn://localhost/ardour2/trunk@2025 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard
2007-06-20 03:05:16 +00:00
parent 996d59663f
commit 8ae5804279
11 changed files with 275 additions and 201 deletions

View File

@@ -425,10 +425,12 @@ GainMeter::setup_meters ()
if ((r = dynamic_cast<Route*> (_io.get())) != 0) {
switch (r->meter_point()) {
case MeterPreFader:
case MeterInput:
nmeters = r->n_inputs().n_total();
break;
case MeterPreFader:
nmeters = r->pre_fader_streams().n_total();
break;
case MeterPostFader:
nmeters = r->n_outputs().n_total();
break;

View File

@@ -270,8 +270,8 @@ PluginSelector::input_refiller ()
// Insert into GTK list
for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) {
snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs);
snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs);
snprintf (ibuf, sizeof(ibuf)-1, "%zu", (*i)->n_inputs.n_total());
snprintf (obuf, sizeof(obuf)-1, "%zu", (*i)->n_outputs.n_total());
Gtk::TreeModel::Row newrow = *(lmodel->append());
newrow[lcols.name] = (*i)->name.c_str();

View File

@@ -396,24 +396,24 @@ RedirectBox::insert_plugin_chosen (boost::shared_ptr<Plugin> plugin)
redirect->active_changed.connect (bind (mem_fun (*this, &RedirectBox::show_redirect_active_r), boost::weak_ptr<Redirect>(redirect)));
uint32_t err_streams;
Route::InsertStreams err;
if (_route->add_redirect (redirect, this, &err_streams)) {
weird_plugin_dialog (*plugin, err_streams, _route);
if (_route->add_redirect (redirect, this, &err)) {
weird_plugin_dialog (*plugin, err, _route);
// XXX SHAREDPTR delete plugin here .. do we even need to care?
}
}
}
void
RedirectBox::weird_plugin_dialog (Plugin& p, uint32_t streams, boost::shared_ptr<IO> io)
RedirectBox::weird_plugin_dialog (Plugin& p, Route::InsertStreams streams, boost::shared_ptr<IO> io)
{
ArdourDialog dialog (_("ardour: weird plugin dialog"));
Label label;
/* i hate this kind of code */
if (streams > p.get_info()->n_inputs) {
if (streams.count > p.get_info()->n_inputs) {
label.set_text (string_compose (_(
"You attempted to add a plugin (%1).\n"
"The plugin has %2 inputs\n"
@@ -423,9 +423,9 @@ RedirectBox::weird_plugin_dialog (Plugin& p, uint32_t streams, boost::shared_ptr
"This makes no sense - you are throwing away\n"
"part of the signal."),
p.name(),
p.get_info()->n_inputs,
streams));
} else if (streams < p.get_info()->n_inputs) {
p.get_info()->n_inputs.n_total(),
streams.count.n_total()));
} else if (streams.count < p.get_info()->n_inputs) {
label.set_text (string_compose (_(
"You attempted to add a plugin (%1).\n"
"The plugin has %2 inputs\n"
@@ -436,8 +436,8 @@ RedirectBox::weird_plugin_dialog (Plugin& p, uint32_t streams, boost::shared_ptr
"side-chain inputs. A future version of Ardour will\n"
"support this type of configuration."),
p.name(),
p.get_info()->n_inputs,
streams));
p.get_info()->n_inputs.n_total(),
streams.count.n_total()));
} else {
label.set_text (string_compose (_(
"You attempted to add a plugin (%1).\n"
@@ -450,11 +450,11 @@ RedirectBox::weird_plugin_dialog (Plugin& p, uint32_t streams, boost::shared_ptr
"\n"
"Ardour does not understand what to do in such situations.\n"),
p.name(),
p.get_info()->n_inputs,
p.get_info()->n_outputs,
p.get_info()->n_inputs.n_total(),
p.get_info()->n_outputs.n_total(),
io->n_inputs().n_total(),
io->n_outputs().n_total(),
streams));
streams.count.n_total()));
}
dialog.get_vbox()->pack_start (label);

View File

@@ -198,7 +198,7 @@ class RedirectBox : public Gtk::HBox
gint idle_delete_redirect (boost::weak_ptr<ARDOUR::Redirect>);
void weird_plugin_dialog (ARDOUR::Plugin& p, uint32_t streams, boost::shared_ptr<ARDOUR::IO> io);
void weird_plugin_dialog (ARDOUR::Plugin& p, ARDOUR::Route::InsertStreams streams, boost::shared_ptr<ARDOUR::IO> io);
static RedirectBox* _current_redirect_box;
static bool enter_box (GdkEventCrossing*, RedirectBox*);

View File

@@ -47,6 +47,8 @@ public:
// -1 is what to_index does. inlined for speed. this should maybe be changed..
inline size_t n_audio() const { return _counts[DataType::AUDIO-1]; }
inline size_t n_midi() const { return _counts[DataType::MIDI-1]; }
inline void set_audio(size_t a) { _counts[DataType::AUDIO-1] = a; }
inline void set_midi(size_t m) { _counts[DataType::MIDI-1] = m; }
size_t n_total() const
{

View File

@@ -55,9 +55,13 @@ class Insert : public Redirect
virtual void activate () {}
virtual void deactivate () {}
virtual int32_t can_support_input_configuration (int32_t in) const = 0;
virtual int32_t configure_io (int32_t magic, int32_t in, int32_t out) = 0;
virtual int32_t compute_output_streams (int32_t cnt) const = 0;
virtual bool can_support_input_configuration (ChanCount in) const = 0;
virtual ChanCount output_for_input_configuration (ChanCount in) const = 0;
virtual bool configure_io (ChanCount in, ChanCount out) = 0;
protected:
bool _configured;
ChanCount _configured_input;
};
class PortInsert : public Insert
@@ -81,9 +85,9 @@ class PortInsert : public Insert
ChanCount output_streams() const;
ChanCount input_streams() const;
int32_t can_support_input_configuration (int32_t) const;
int32_t configure_io (int32_t magic, int32_t in, int32_t out);
int32_t compute_output_streams (int32_t cnt) const;
virtual bool can_support_input_configuration (ChanCount in) const;
virtual ChanCount output_for_input_configuration (ChanCount in) const;
virtual bool configure_io (ChanCount in, ChanCount out);
uint32_t bit_slot() const { return bitslot; }
@@ -118,12 +122,12 @@ class PluginInsert : public Insert
ChanCount natural_output_streams() const;
ChanCount natural_input_streams() const;
int set_count (uint32_t num);
bool set_count (uint32_t num);
uint32_t get_count () const { return _plugins.size(); }
int32_t can_support_input_configuration (int32_t) const;
int32_t configure_io (int32_t magic, int32_t in, int32_t out);
int32_t compute_output_streams (int32_t cnt) const;
virtual bool can_support_input_configuration (ChanCount in) const;
virtual ChanCount output_for_input_configuration (ChanCount in) const;
virtual bool configure_io (ChanCount in, ChanCount out);
bool is_generator() const;
@@ -166,6 +170,8 @@ class PluginInsert : public Insert
void auto_state_changed (uint32_t which);
void automation_list_creation_callback (uint32_t, AutomationList&);
int32_t count_for_configuration (ChanCount in, ChanCount out) const;
boost::shared_ptr<Plugin> plugin_factory (boost::shared_ptr<Plugin>);
};

View File

@@ -28,6 +28,7 @@
#include <jack/types.h>
#include <ardour/types.h>
#include <ardour/chan_count.h>
#include <ardour/plugin_state.h>
#include <ardour/cycles.h>
@@ -60,8 +61,8 @@ class PluginInfo {
string name;
string category;
uint32_t n_inputs;
uint32_t n_outputs;
ChanCount n_inputs;
ChanCount n_outputs;
ARDOUR::PluginType type;
long unique_id;

View File

@@ -159,15 +159,23 @@ class Route : public IO
}
ChanCount max_redirect_outs () const { return redirect_max_outs; }
ChanCount pre_fader_streams() const;
// FIXME: remove/replace err_streams parameters with something appropriate
// they are used by 'wierd_plugin_dialog'(sic) to display the number of input streams
// at the insertion point if the insert fails
int add_redirect (boost::shared_ptr<Redirect>, void *src, uint32_t* err_streams = 0);
int add_redirects (const RedirectList&, void *src, uint32_t* err_streams = 0);
int remove_redirect (boost::shared_ptr<Redirect>, void *src, uint32_t* err_streams = 0);
int copy_redirects (const Route&, Placement, uint32_t* err_streams = 0);
int sort_redirects (uint32_t* err_streams = 0);
/** A record of the stream configuration at some point in the redirect list.
* Used to return where and why a redirect list configuration request failed.
*/
struct InsertStreams {
InsertStreams(size_t i=0, ChanCount c=ChanCount()) : index(i), count(c) {}
size_t index; ///< Index of redirect where configuration failed
ChanCount count; ///< Input requested of redirect
};
int add_redirect (boost::shared_ptr<Redirect>, void *src, InsertStreams* err = 0);
int add_redirects (const RedirectList&, void *src, InsertStreams* err = 0);
int remove_redirect (boost::shared_ptr<Redirect>, void *src, InsertStreams* err = 0);
int copy_redirects (const Route&, Placement, InsertStreams* err = 0);
int sort_redirects (InsertStreams* err = 0);
void disable_redirects (Placement);
void disable_redirects ();
void disable_plugins (Placement);
@@ -347,22 +355,21 @@ class Route : public IO
void output_change_handler (IOChange, void *src);
bool legal_redirect (Redirect&);
int reset_plugin_counts (uint32_t*); /* locked */
int _reset_plugin_counts (uint32_t*); /* unlocked */
int reset_plugin_counts (InsertStreams*); /* locked */
int _reset_plugin_counts (InsertStreams*); /* unlocked */
/* plugin count handling */
/* insert I/O channels and plugin count handling */
struct InsertCount {
boost::shared_ptr<ARDOUR::Insert> insert;
int32_t cnt;
int32_t in;
int32_t out;
ChanCount in;
ChanCount out;
InsertCount (boost::shared_ptr<ARDOUR::Insert> ins) : insert (ins), cnt (-1) {}
InsertCount (boost::shared_ptr<ARDOUR::Insert> ins) : insert(ins) {}
};
int32_t apply_some_plugin_counts (std::list<InsertCount>& iclist);
int32_t check_some_plugin_counts (std::list<InsertCount>& iclist, int32_t required_inputs, uint32_t* err_streams);
bool check_some_plugin_counts (std::list<InsertCount>& iclist, ChanCount required_inputs, InsertStreams* err_streams);
void set_deferred_state ();
void add_redirect_from_xml (const XMLNode&);

View File

@@ -53,11 +53,13 @@ using namespace PBD;
* Inserts are still definitely audio only */
Insert::Insert(Session& s, string name, Placement p)
: Redirect (s, name, p)
, _configured(false)
{
}
Insert::Insert(Session& s, string name, Placement p, int imin, int imax, int omin, int omax)
: Redirect (s, name, p, imin, imax, omin, omax)
, _configured(false)
{
}
@@ -121,7 +123,7 @@ PluginInsert::PluginInsert (const PluginInsert& other)
RedirectCreated (this); /* EMIT SIGNAL */
}
int
bool
PluginInsert::set_count (uint32_t num)
{
bool require_state = !_plugins.empty();
@@ -131,7 +133,7 @@ PluginInsert::set_count (uint32_t num)
*/
if (num == 0) {
return -1;
return false;
} else if (num > _plugins.size()) {
uint32_t diff = num - _plugins.size();
@@ -150,7 +152,7 @@ PluginInsert::set_count (uint32_t num)
}
}
return 0;
return true;
}
void
@@ -185,29 +187,31 @@ PluginInsert::auto_state_changed (uint32_t which)
ChanCount
PluginInsert::output_streams() const
{
// FIXME: TYPE
return ChanCount(DataType::AUDIO, _plugins[0]->get_info()->n_outputs * _plugins.size());
if (_configured)
return output_for_input_configuration(_configured_input);
else
return natural_output_streams();
}
ChanCount
PluginInsert::input_streams() const
{
// FIXME: TYPE
return ChanCount(DataType::AUDIO, _plugins[0]->get_info()->n_inputs * _plugins.size());
if (_configured)
return _configured_input;
else
return natural_input_streams();
}
ChanCount
PluginInsert::natural_output_streams() const
{
// FIXME: TYPE
return ChanCount(DataType::AUDIO, _plugins[0]->get_info()->n_outputs);
return _plugins[0]->get_info()->n_outputs;
}
ChanCount
PluginInsert::natural_input_streams() const
{
// FIXME: TYPE
return ChanCount(DataType::AUDIO, _plugins[0]->get_info()->n_inputs);
return _plugins[0]->get_info()->n_inputs;
}
bool
@@ -217,7 +221,7 @@ PluginInsert::is_generator() const
a specific "instrument" flag, for example.
*/
return _plugins[0]->get_info()->n_inputs == 0;
return _plugins[0]->get_info()->n_inputs.n_audio() == 0;
}
void
@@ -349,12 +353,9 @@ PluginInsert::silence (nframes_t nframes, nframes_t offset)
uint32_t in_index = 0;
uint32_t out_index = 0;
uint32_t n;
if (active()) {
for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
n = (*i) -> get_info()->n_inputs;
(*i)->connect_and_run (_session.get_silent_buffers (ChanCount(DataType::AUDIO, n)), in_index, out_index, nframes, offset);
(*i)->connect_and_run (_session.get_silent_buffers ((*i)->get_info()->n_inputs), in_index, out_index, nframes, offset);
}
}
}
@@ -370,8 +371,8 @@ PluginInsert::run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
connect_and_run (bufs, nframes, offset, false);
}
} else {
uint32_t in = _plugins[0]->get_info()->n_inputs;
uint32_t out = _plugins[0]->get_info()->n_outputs;
uint32_t in = _plugins[0]->get_info()->n_inputs.n_audio();
uint32_t out = _plugins[0]->get_info()->n_outputs.n_audio();
if (out > in) {
@@ -382,7 +383,7 @@ PluginInsert::run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
}
}
bufs.count().set(DataType::AUDIO, out);
bufs.count().set(_default_type, out);
}
}
@@ -534,36 +535,98 @@ PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
return boost::shared_ptr<Plugin> ((Plugin*) 0);
}
int32_t
PluginInsert::compute_output_streams (int32_t cnt) const
bool
PluginInsert::configure_io (ChanCount in, ChanCount out)
{
return _plugins[0]->get_info()->n_outputs * cnt;
ChanCount matching_out = output_for_input_configuration(out);
if (matching_out != out) {
_configured = false;
return false;
} else {
bool success = set_count (count_for_configuration(in, out));
if (success) {
_configured = true;
_configured_input = in;
}
return success;
}
}
int32_t
PluginInsert::configure_io (int32_t magic, int32_t in, int32_t out)
bool
PluginInsert::can_support_input_configuration (ChanCount in_count) const
{
return set_count (magic);
int32_t outputs = _plugins[0]->get_info()->n_outputs.get(_default_type);
int32_t inputs = _plugins[0]->get_info()->n_inputs.get(_default_type);
int32_t in = in_count.get(_default_type);
/* see output_for_input_configuration below */
if ((inputs == 0)
|| (outputs == 1 && inputs == 1)
|| (inputs == in)
|| ((inputs < in) && (inputs % in == 0))) {
return true;
} else {
return false;
}
}
int32_t
PluginInsert::can_support_input_configuration (int32_t in) const
ChanCount
PluginInsert::output_for_input_configuration (ChanCount in) const
{
int32_t outputs = _plugins[0]->get_info()->n_outputs;
int32_t inputs = _plugins[0]->get_info()->n_inputs;
ChanCount outputs = _plugins[0]->get_info()->n_outputs;
ChanCount inputs = _plugins[0]->get_info()->n_inputs;
if (inputs == 0) {
if (inputs.n_total() == 0) {
/* instrument plugin, always legal, but throws away any existing streams */
return outputs;
}
/* instrument plugin, always legal, but it throws
away any existing active streams.
if (inputs.n_total() == 1 && outputs == inputs) {
/* mono plugin, replicate as needed to match in */
return in;
}
if (inputs == in) {
/* exact match */
return outputs;
}
// FIXME: single type plugins only. can we do this for instruments?
if ((inputs.n_total() == inputs.get(_default_type))
&& ((in.n_total() == in.get(_default_type))
&& (inputs.n_total() < in.n_total())
&& (inputs.n_total() % in.n_total() == 0))) {
/* number of inputs is a factor of the requested input
configuration, so we can replicate.
*/
return ChanCount(_default_type, in.n_total() / inputs.n_total());
}
/* sorry */
return ChanCount();
}
/* Number of plugin instances required to support a given channel configuration.
* (private helper)
*/
int32_t
PluginInsert::count_for_configuration (ChanCount in, ChanCount out) const
{
// FIXME: take 'out' into consideration
ChanCount outputs = _plugins[0]->get_info()->n_outputs;
ChanCount inputs = _plugins[0]->get_info()->n_inputs;
if (inputs.n_total() == 0) {
/* instrument plugin, always legal, but throws away any existing streams */
return 1;
}
if (outputs == 1 && inputs == 1) {
/* mono plugin, replicate as needed */
return in;
if (inputs.n_total() == 1 && outputs == inputs) {
/* mono plugin, replicate as needed to match in */
return in.n_total();
}
if (inputs == in) {
@@ -571,18 +634,21 @@ PluginInsert::can_support_input_configuration (int32_t in) const
return 1;
}
if ((inputs < in) && (inputs % in == 0)) {
// FIXME: single type plugins only. can we do this for instruments?
if ((inputs.n_total() == inputs.get(_default_type))
&& ((in.n_total() == in.get(_default_type))
&& (inputs.n_total() < in.n_total())
&& (inputs.n_total() % in.n_total() == 0))) {
/* number of inputs is a factor of the requested input
configuration, so we can replicate.
*/
return in/inputs;
return in.n_total() / inputs.n_total();
}
/* sorry */
return -1;
return 0;
}
XMLNode&
@@ -970,14 +1036,14 @@ PortInsert::latency()
return _session.engine().frames_per_cycle() + input_latency();
}
int32_t
PortInsert::can_support_input_configuration (int32_t in) const
bool
PortInsert::can_support_input_configuration (ChanCount in) const
{
if (input_maximum() == ChanCount::INFINITE && output_maximum() == ChanCount::INFINITE) {
/* not configured yet */
return 1; /* we can support anything the first time we're asked */
return true; /* we can support anything the first time we're asked */
} else {
@@ -985,16 +1051,23 @@ PortInsert::can_support_input_configuration (int32_t in) const
many output ports it will have.
*/
if (output_maximum().get(_default_type) == static_cast<uint32_t>(in)) {
return 1;
if (output_maximum() == in) {
return true;
}
}
return -1;
return false;
}
int32_t
PortInsert::configure_io (int32_t ignored_magic, int32_t in, int32_t out)
ChanCount
PortInsert::output_for_input_configuration (ChanCount in) const
{
return in;
}
bool
PortInsert::configure_io (ChanCount in, ChanCount out)
{
/* do not allow configuration to be changed outside the range of
the last request config. or something like that.
@@ -1010,27 +1083,12 @@ PortInsert::configure_io (int32_t ignored_magic, int32_t in, int32_t out)
to the number of input ports we need.
*/
set_output_maximum (ChanCount(_default_type, in));
set_output_minimum (ChanCount(_default_type, in));
set_input_maximum (ChanCount(_default_type, out));
set_input_minimum (ChanCount(_default_type, out));
set_output_maximum (in);
set_output_minimum (in);
set_input_maximum (out);
set_input_minimum (out);
if (in < 0) {
in = n_outputs ().get(_default_type);
}
if (out < 0) {
out = n_inputs ().get(_default_type);
}
return ensure_io (ChanCount(_default_type, out), ChanCount(_default_type, in), false, this);
}
int32_t
PortInsert::compute_output_streams (int32_t cnt) const
{
/* puzzling, eh? think about it ... */
return n_inputs ().get(_default_type);
return (ensure_io (out, in, false, this) == 0);
}
ChanCount

View File

@@ -253,18 +253,18 @@ PluginManager::ladspa_discover (string path)
info->category = get_ladspa_category(descriptor->UniqueID);
info->path = path;
info->index = i;
info->n_inputs = 0;
info->n_outputs = 0;
info->n_inputs = ChanCount();
info->n_outputs = ChanCount();
info->type = ARDOUR::LADSPA;
info->unique_id = descriptor->UniqueID;
for (uint32_t n=0; n < descriptor->PortCount; ++n) {
if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
if ( LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n]) ) {
info->n_inputs++;
info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
}
else if ( LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n]) ) {
info->n_outputs++;
info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
}
}
}

View File

@@ -773,7 +773,7 @@ Route::set_mute (bool yn, void *src)
}
int
Route::add_redirect (boost::shared_ptr<Redirect> redirect, void *src, uint32_t* err_streams)
Route::add_redirect (boost::shared_ptr<Redirect> redirect, void *src, InsertStreams* err)
{
ChanCount old_rmo = redirect_max_outs;
@@ -792,7 +792,7 @@ Route::add_redirect (boost::shared_ptr<Redirect> redirect, void *src, uint32_t*
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(redirect)) != 0) {
pi->set_count (1);
if (pi->input_streams() == ChanCount::ZERO) {
if (pi->natural_input_streams() == ChanCount::ZERO) {
/* generator plugin */
_have_internal_generator = true;
}
@@ -814,18 +814,19 @@ Route::add_redirect (boost::shared_ptr<Redirect> redirect, void *src, uint32_t*
porti->ensure_io (n_outputs (), n_inputs(), false, this);
}
// Ensure peak vector sizes before the plugin is activated
ChanCount potential_max_streams = max(redirect->input_streams(), redirect->output_streams());
_meter->setup(potential_max_streams);
_redirects.push_back (redirect);
if (_reset_plugin_counts (err_streams)) {
// Set up redirect list channels. This will set redirect->[input|output]_streams()
if (_reset_plugin_counts (err)) {
_redirects.pop_back ();
_reset_plugin_counts (0); // it worked before we tried to add it ...
return -1;
}
// Ensure peak vector sizes before the plugin is activated
ChanCount potential_max_streams = max(redirect->input_streams(), redirect->output_streams());
_meter->setup(potential_max_streams);
redirect->activate ();
redirect->active_changed.connect (mem_fun (*this, &Route::redirect_active_proxy));
}
@@ -840,7 +841,7 @@ Route::add_redirect (boost::shared_ptr<Redirect> redirect, void *src, uint32_t*
}
int
Route::add_redirects (const RedirectList& others, void *src, uint32_t* err_streams)
Route::add_redirects (const RedirectList& others, void *src, InsertStreams* err)
{
ChanCount old_rmo = redirect_max_outs;
@@ -873,7 +874,7 @@ Route::add_redirects (const RedirectList& others, void *src, uint32_t* err_strea
_redirects.push_back (*i);
if (_reset_plugin_counts (err_streams)) {
if (_reset_plugin_counts (err)) {
++existing_end;
_redirects.erase (existing_end, _redirects.end());
_reset_plugin_counts (0); // it worked before we tried to add it ...
@@ -996,6 +997,28 @@ Route::ab_plugins (bool forward)
}
}
}
/* Figure out the streams that will feed into PreFader */
ChanCount
Route::pre_fader_streams() const
{
boost::shared_ptr<Redirect> redirect;
// Find the last pre-fader redirect
for (RedirectList::const_iterator r = _redirects.begin(); r != _redirects.end(); ++r) {
if ((*r)->placement() == PreFader) {
redirect = *r;
}
}
if (redirect) {
return redirect->output_streams();
} else {
return n_inputs ();
}
}
/** Remove redirects with a given placement.
* @param p Placement of redirects to remove.
@@ -1037,7 +1060,7 @@ Route::clear_redirects (Placement p, void *src)
}
int
Route::remove_redirect (boost::shared_ptr<Redirect> redirect, void *src, uint32_t* err_streams)
Route::remove_redirect (boost::shared_ptr<Redirect> redirect, void *src, InsertStreams* err)
{
ChanCount old_rmo = redirect_max_outs;
@@ -1093,7 +1116,7 @@ Route::remove_redirect (boost::shared_ptr<Redirect> redirect, void *src, uint32_
return 1;
}
if (_reset_plugin_counts (err_streams)) {
if (_reset_plugin_counts (err)) {
/* get back to where we where */
_redirects.insert (i, redirect);
/* we know this will work, because it worked before :) */
@@ -1127,92 +1150,52 @@ Route::remove_redirect (boost::shared_ptr<Redirect> redirect, void *src, uint32_
}
int
Route::reset_plugin_counts (uint32_t* lpc)
Route::reset_plugin_counts (InsertStreams* err)
{
Glib::RWLock::WriterLock lm (redirect_lock);
return _reset_plugin_counts (lpc);
return _reset_plugin_counts (err);
}
int
Route::_reset_plugin_counts (uint32_t* err_streams)
Route::_reset_plugin_counts (InsertStreams* err)
{
RedirectList::iterator r;
uint32_t i_cnt;
uint32_t s_cnt;
map<Placement,list<InsertCount> > insert_map;
nframes_t initial_streams;
redirect_max_outs.reset();
i_cnt = 0;
s_cnt = 0;
ChanCount initial_streams;
/* Process each placement in order, checking to see if we
can really do what has been requested.
*/
/* divide inserts up by placement so we get the signal flow
properly modelled. we need to do this because the _redirects
list is not sorted by placement, and because other reasons may
exist now or in the future for this separate treatment.
list is not sorted by placement
*/
/* ... but it should/will be... */
for (r = _redirects.begin(); r != _redirects.end(); ++r) {
boost::shared_ptr<Insert> insert;
/* do this here in case we bomb out before we get to the end of
this function.
*/
redirect_max_outs = max ((*r)->output_streams (), redirect_max_outs);
if ((insert = boost::dynamic_pointer_cast<Insert>(*r)) != 0) {
++i_cnt;
insert_map[insert->placement()].push_back (InsertCount (insert));
/* reset plugin counts back to one for now so
that we have a predictable, controlled
state to try to configure.
*/
boost::shared_ptr<PluginInsert> pi;
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(insert)) != 0) {
pi->set_count (1);
}
} else if (boost::dynamic_pointer_cast<Send> (*r) != 0) {
++s_cnt;
}
}
if (i_cnt == 0) {
if (s_cnt) {
goto recompute;
} else {
return 0;
}
}
/* Now process each placement in order, checking to see if we
can really do what has been requested.
*/
/* A: PreFader */
if (check_some_plugin_counts (insert_map[PreFader], n_inputs ().get(_default_type), err_streams)) {
if ( ! check_some_plugin_counts (insert_map[PreFader], n_inputs (), err)) {
return -1;
}
/* figure out the streams that will feed into PreFader */
if (!insert_map[PreFader].empty()) {
InsertCount& ic (insert_map[PreFader].back());
initial_streams = ic.insert->compute_output_streams (ic.cnt);
} else {
initial_streams = n_inputs ().get(_default_type);
}
ChanCount post_fader_input = (err ? err->count : n_inputs());
/* B: PostFader */
if (check_some_plugin_counts (insert_map[PostFader], initial_streams, err_streams)) {
if ( ! check_some_plugin_counts (insert_map[PostFader], post_fader_input, err)) {
return -1;
}
@@ -1223,8 +1206,6 @@ Route::_reset_plugin_counts (uint32_t* err_streams)
/* recompute max outs of any redirect */
recompute:
redirect_max_outs.reset();
RedirectList::iterator prev = _redirects.end();
@@ -1261,7 +1242,7 @@ Route::apply_some_plugin_counts (list<InsertCount>& iclist)
for (i = iclist.begin(); i != iclist.end(); ++i) {
if ((*i).insert->configure_io ((*i).cnt, (*i).in, (*i).out)) {
if ((*i).insert->configure_io ((*i).in, (*i).out)) {
return -1;
}
/* make sure that however many we have, they are all active */
@@ -1271,38 +1252,55 @@ Route::apply_some_plugin_counts (list<InsertCount>& iclist)
return 0;
}
int32_t
Route::check_some_plugin_counts (list<InsertCount>& iclist, int32_t required_inputs, uint32_t* err_streams)
/** Returns whether \a iclist can be configured and run starting with
* \a required_inputs at the first insert'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.
*/
bool
Route::check_some_plugin_counts (list<InsertCount>& iclist, ChanCount required_inputs, InsertStreams* err)
{
list<InsertCount>::iterator i;
size_t index = 0;
if (err) {
err->index = 0;
err->count = required_inputs;
}
for (i = iclist.begin(); i != iclist.end(); ++i) {
if (((*i).cnt = (*i).insert->can_support_input_configuration (required_inputs)) < 0) {
if (err_streams) {
*err_streams = required_inputs;
if ((*i).insert->can_support_input_configuration (required_inputs) < 0) {
if (err) {
err->index = index;
err->count = required_inputs;
}
return -1;
return false;
}
(*i).in = required_inputs;
(*i).out = (*i).insert->compute_output_streams ((*i).cnt);
(*i).out = (*i).insert->output_for_input_configuration (required_inputs);
required_inputs = (*i).out;
++index;
}
if (err) {
if (!iclist.empty()) {
err->index = index;
err->count = iclist.back().insert->output_for_input_configuration(required_inputs);
}
}
return 0;
return true;
}
int
Route::copy_redirects (const Route& other, Placement placement, uint32_t* err_streams)
Route::copy_redirects (const Route& other, Placement placement, InsertStreams* err)
{
ChanCount old_rmo = redirect_max_outs;
if (err_streams) {
*err_streams = 0;
}
RedirectList to_be_deleted;
{
@@ -1336,7 +1334,7 @@ Route::copy_redirects (const Route& other, Placement placement, uint32_t* err_st
/* reset plugin stream handling */
if (_reset_plugin_counts (err_streams)) {
if (_reset_plugin_counts (err)) {
/* FAILED COPY ATTEMPT: we have to restore order */
@@ -1421,7 +1419,7 @@ struct RedirectSorter {
};
int
Route::sort_redirects (uint32_t* err_streams)
Route::sort_redirects (InsertStreams* err)
{
{
RedirectSorter comparator;
@@ -1434,7 +1432,7 @@ Route::sort_redirects (uint32_t* err_streams)
_redirects.sort (comparator);
if (_reset_plugin_counts (err_streams)) {
if (_reset_plugin_counts (err)) {
_redirects = as_it_was_before;
redirect_max_outs = old_rmo;
return -1;