, _no_inplace (false)
, _strict_io (false)
, _custom_cfg (false)
- , _pending_no_inplace (false)
+ , _maps_from_state (false)
{
/* the first is the master */
{
}
+void
+PluginInsert::set_strict_io (bool b)
+{
+ bool changed = _strict_io != b;
+ _strict_io = b;
+ if (changed) {
+ PluginConfigChanged (); /* EMIT SIGNAL */
+ }
+}
+
bool
PluginInsert::set_count (uint32_t num)
{
/* XXX do something */
}
}
+ PluginConfigChanged (); /* EMIT SIGNAL */
} else if (num < _plugins.size()) {
uint32_t diff = _plugins.size() - num;
for (uint32_t n= 0; n < diff; ++n) {
_plugins.pop_back();
}
+ PluginConfigChanged (); /* EMIT SIGNAL */
}
return true;
void
PluginInsert::set_outputs (const ChanCount& c)
{
+ bool changed = (_custom_out != c) && _custom_cfg;
_custom_out = c;
+ if (changed) {
+ PluginConfigChanged (); /* EMIT SIGNAL */
+ }
+}
+
+void
+PluginInsert::set_custom_cfg (bool b)
+{
+ bool changed = _custom_cfg != b;
+ _custom_cfg = b;
+ if (changed) {
+ PluginConfigChanged (); /* EMIT SIGNAL */
+ }
}
void
PinMappings in_map (_in_map);
PinMappings out_map (_out_map);
-#if 1
- // auto-detect if inplace processing is possible
- // TODO: do this once. during configure_io and every time the
- // plugin-count or mapping changes.
- bool inplace_ok = true;
- for (uint32_t pc = 0; pc < get_count() && inplace_ok ; ++pc) {
- if (!in_map[pc].is_monotonic ()) {
- inplace_ok = false;
- }
- if (!out_map[pc].is_monotonic ()) {
- inplace_ok = false;
- }
- }
-
- if (_pending_no_inplace != !inplace_ok) {
-#ifndef NDEBUG // this 'cerr' needs to go ASAP.
- cerr << name () << " automatically set : " << (inplace_ok ? "Use Inplace" : "No Inplace") << "\n"; // XXX
-#endif
- _pending_no_inplace = !inplace_ok;
- }
-#endif
-
- _no_inplace = _pending_no_inplace || _plugins.front()->inplace_broken ();
-
-
#if 1
// TODO optimize special case.
// Currently this never triggers because the in_map for "Split" triggeres no_inplace.
if (num < _in_map.size()) {
bool changed = _in_map[num] != m;
_in_map[num] = m;
+ sanitize_maps ();
if (changed) {
PluginMapChanged (); /* EMIT SIGNAL */
}
if (num < _out_map.size()) {
bool changed = _out_map[num] != m;
_out_map[num] = m;
+ sanitize_maps ();
if (changed) {
PluginMapChanged (); /* EMIT SIGNAL */
}
return false;
}
+bool
+PluginInsert::sanitize_maps ()
+{
+ bool changed = false;
+ /* strip dead wood */
+ PinMappings new_ins;
+ PinMappings new_outs;
+ for (uint32_t pc = 0; pc < get_count(); ++pc) {
+ ChanMapping new_in;
+ ChanMapping new_out;
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ for (uint32_t i = 0; i < natural_input_streams().get (*t); ++i) {
+ bool valid;
+ uint32_t idx = _in_map[pc].get (*t, i, &valid);
+ if (valid && idx < _configured_in.get (*t)) {
+ new_in.set (*t, i, idx);
+ }
+ }
+ for (uint32_t o = 0; o < natural_output_streams().get (*t); ++o) {
+ bool valid;
+ uint32_t idx = _out_map[pc].get (*t, o, &valid);
+ if (valid && idx < _configured_out.get (*t)) {
+ new_out.set (*t, o, idx);
+ }
+ }
+ }
+ if (_in_map[pc] != new_in || _out_map[pc] != new_out) {
+ changed = true;
+ }
+ new_ins[pc] = new_in;
+ new_outs[pc] = new_out;
+ }
+ /* prevent dup output assignments */
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ for (uint32_t o = 0; o < _configured_out.get (*t); ++o) {
+ bool mapped = false;
+ for (uint32_t pc = 0; pc < get_count(); ++pc) {
+ bool valid;
+ uint32_t idx = new_outs[pc].get_src (*t, o, &valid);
+ if (valid && mapped) {
+ new_outs[pc].unset (*t, idx);
+ } else if (valid) {
+ mapped = true;
+ }
+ }
+ }
+ }
+
+ if (_in_map != new_ins || _out_map != new_outs) {
+ changed = true;
+ }
+ _in_map = new_ins;
+ _out_map = new_outs;
+
+ return changed;
+}
+
+bool
+PluginInsert::reset_map (bool emit)
+{
+ uint32_t pc = 0;
+ const PinMappings old_in (_in_map);
+ const PinMappings old_out (_out_map);
+
+ _in_map.clear ();
+ _out_map.clear ();
+ for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
+ if (_match.method == Split) {
+ _in_map[pc] = ChanMapping ();
+ /* connect inputs in round-robin fashion */
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ const uint32_t cend = _configured_in.get (*t);
+ if (cend == 0) { continue; }
+ uint32_t c = 0;
+ for (uint32_t in = 0; in < natural_input_streams().get (*t); ++in) {
+ _in_map[pc].set (*t, in, c);
+ c = c + 1 % cend;
+ }
+ }
+ } else {
+ _in_map[pc] = ChanMapping (ChanCount::min (natural_input_streams (), _configured_in));
+ }
+ _out_map[pc] = ChanMapping (ChanCount::min (natural_output_streams(), _configured_out));
+
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ _in_map[pc].offset_to(*t, pc * natural_input_streams().get(*t));
+ _out_map[pc].offset_to(*t, pc * natural_output_streams().get(*t));
+ }
+ }
+ sanitize_maps ();
+ if (old_in == _in_map && old_out == _out_map) {
+ return false;
+ }
+ if (emit) {
+ PluginMapChanged (); /* EMIT SIGNAL */
+ }
+ return true;
+}
+
bool
PluginInsert::configure_io (ChanCount in, ChanCount out)
{
/* get plugin configuration */
_match = private_can_support_io_configuration (in, out);
-#ifndef NDEBUG // XXX
- cout << "Match '" << name() << "': " << _match;
+#ifndef NDEBUG
+ if (DEBUG_ENABLED(DEBUG::ChanMapping)) {
+ DEBUG_STR_DECL(a);
+ DEBUG_STR_APPEND(a, string_compose ("Match '%1':", name()));
+ DEBUG_STR_APPEND(a, _match);
+ DEBUG_TRACE (DEBUG::ChanMapping, DEBUG_STR(a).str());
+ }
#endif
/* set the matching method and number of plugins that we will use to meet this configuration */
) {
/* If the configuraton has not changed, keep the mapping */
} else if (_match.custom_cfg && _configured) {
- /* strip dead wood */
- for (uint32_t pc = 0; pc < get_count(); ++pc) {
- ChanMapping new_in;
- ChanMapping new_out;
- for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
- for (uint32_t i = 0; i < natural_input_streams().get (*t); ++i) {
- bool valid;
- uint32_t idx = _in_map[pc].get (*t, i, &valid);
- if (valid && idx <= in.get (*t)) {
- new_in.set (*t, i, idx);
- }
- }
- for (uint32_t o = 0; o < natural_output_streams().get (*t); ++o) {
- bool valid;
- uint32_t idx = _out_map[pc].get (*t, o, &valid);
- if (valid && idx <= out.get (*t)) {
- new_out.set (*t, o, idx);
- }
- }
- }
- if (_in_map[pc] != new_in || _out_map[pc] != new_out) {
- mapping_changed = true;
- }
- _in_map[pc] = new_in;
- _out_map[pc] = new_out;
- }
+ mapping_changed = sanitize_maps ();
} else {
- /* generate a new mapping */
- uint32_t pc = 0;
- _in_map.clear ();
- _out_map.clear ();
- for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
- if (_match.method == Split) {
- _in_map[pc] = ChanMapping ();
- /* connect inputs in round-robin fashion */
- for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
- const uint32_t cend = _configured_in.get (*t);
- if (cend == 0) { continue; }
- uint32_t c = 0;
- for (uint32_t in = 0; in < natural_input_streams().get (*t); ++in) {
- _in_map[pc].set (*t, in, c);
- c = c + 1 % cend;
- }
- }
- } else {
- _in_map[pc] = ChanMapping (ChanCount::min (natural_input_streams (), in));
- }
- _out_map[pc] = ChanMapping (ChanCount::min (natural_output_streams(), out));
-
- for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
- _in_map[pc].offset_to(*t, pc * natural_input_streams().get(*t));
- _out_map[pc].offset_to(*t, pc * natural_output_streams().get(*t));
- }
+ if (_maps_from_state) {
+ _maps_from_state = false;
mapping_changed = true;
+ sanitize_maps ();
+ } else {
+ /* generate a new mapping */
+ mapping_changed = reset_map (false);
}
}
if (mapping_changed) {
PluginMapChanged (); /* EMIT SIGNAL */
-#ifndef NDEBUG // XXX
- uint32_t pc = 0;
- cout << "----<<----\n";
- for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
- cout << "Channel Map for " << name() << " plugin " << pc << "\n";
- cout << " * Inputs:\n" << _in_map[pc];
- cout << " * Outputs:\n" << _out_map[pc];
+
+#ifndef NDEBUG
+ if (DEBUG_ENABLED(DEBUG::ChanMapping)) {
+ uint32_t pc = 0;
+ DEBUG_STR_DECL(a);
+ DEBUG_STR_APPEND(a, "\n--------<<--------\n");
+ for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
+ if (pc > 0) {
+ DEBUG_STR_APPEND(a, "----><----\n");
+ }
+ DEBUG_STR_APPEND(a, string_compose ("Channel Map for %1 plugin %2\n", name(), pc));
+ DEBUG_STR_APPEND(a, " * Inputs:\n");
+ DEBUG_STR_APPEND(a, _in_map[pc]);
+ DEBUG_STR_APPEND(a, " * Outputs:\n");
+ DEBUG_STR_APPEND(a, _out_map[pc]);
+ }
+ DEBUG_STR_APPEND(a, "-------->>--------\n");
+ DEBUG_TRACE (DEBUG::ChanMapping, DEBUG_STR(a).str());
}
- cout << "---->>----\n";
#endif
}
+ // auto-detect if inplace processing is possible
+ bool inplace_ok = true;
+ for (uint32_t pc = 0; pc < get_count() && inplace_ok ; ++pc) {
+ if (!_in_map[pc].is_monotonic ()) {
+ inplace_ok = false;
+ }
+ if (!_out_map[pc].is_monotonic ()) {
+ inplace_ok = false;
+ }
+ }
+ _no_inplace = !inplace_ok || _plugins.front()->inplace_broken ();
+
if (old_in != in || old_out != out
|| (old_match.method != _match.method && (old_match.method == Split || _match.method == Split))
) {
ChanCount outputs = info->n_outputs;
if (in.get(DataType::MIDI) == 1 && outputs.get(DataType::MIDI) == 0) {
- DEBUG_TRACE ( DEBUG::Processors, string_compose ("bypassing midi-data around %1\n", name()));
+ DEBUG_TRACE ( DEBUG::ChanMapping, string_compose ("bypassing midi-data around %1\n", name()));
midi_bypass.set (DataType::MIDI, 1);
}
if (in.get(DataType::MIDI) == 1 && inputs.get(DataType::MIDI) == 0) {
- DEBUG_TRACE ( DEBUG::Processors, string_compose ("hiding midi-port from plugin %1\n", name()));
+ DEBUG_TRACE ( DEBUG::ChanMapping, string_compose ("hiding midi-port from plugin %1\n", name()));
in.set(DataType::MIDI, 0);
}
/* save custom i/o config */
node.add_property("custom", _custom_cfg ? "yes" : "no");
- if (_custom_cfg) {
- assert (_custom_out == _configured_out); // redundant
- for (uint32_t pc = 0; pc < get_count(); ++pc) {
- // TODO save _in_map[pc], _out_map[pc]
- }
+ for (uint32_t pc = 0; pc < get_count(); ++pc) {
+ char tmp[128];
+ snprintf (tmp, sizeof(tmp), "InputMap-%d", pc);
+ node.add_child_nocopy (* _in_map[pc].state (tmp));
+ snprintf (tmp, sizeof(tmp), "OutputMap-%d", pc);
+ node.add_child_nocopy (* _out_map[pc].state (tmp));
}
_plugins[0]->set_insert_id(this->id());
_custom_cfg = string_is_affirmative (prop->value());
}
+ uint32_t in_maps = 0;
+ uint32_t out_maps = 0;
XMLNodeList kids = node.children ();
for (XMLNodeIterator i = kids.begin(); i != kids.end(); ++i) {
if ((*i)->name() == X_("ConfiguredOutput")) {
_custom_out = ChanCount(**i);
}
- // TODO restore mappings for all 0 .. count.
+ if (strncmp ((*i)->name().c_str(), X_("InputMap-"), 9) == 0) {
+ long pc = atol (&((*i)->name().c_str()[9]));
+ if (pc >=0 && pc <= get_count()) {
+ _in_map[pc] = ChanMapping (**i);
+ ++in_maps;
+ }
+ }
+ if (strncmp ((*i)->name().c_str(), X_("OutputMap-"), 10) == 0) {
+ long pc = atol (&((*i)->name().c_str()[10]));
+ if (pc >=0 && pc <= get_count()) {
+ _out_map[pc] = ChanMapping (**i);
+ ++out_maps;
+ }
+ }
+ }
+ if (in_maps == out_maps && out_maps >0 && out_maps == get_count()) {
+ _maps_from_state = true;
}
-
-
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
if (active()) {