+ if (_plugins.empty()) {
+ return Match();
+ }
+
+ /* if a user specified a custom cfg, so be it. */
+ if (_custom_cfg) {
+ out = _custom_out;
+ return Match (ExactMatch, get_count(), false, true); // XXX
+ }
+
+ /* try automatic configuration */
+ Match m = PluginInsert::automatic_can_support_io_configuration (inx, out);
+
+ PluginInfoPtr info = _plugins.front()->get_info();
+ ChanCount inputs = info->n_inputs;
+ ChanCount outputs = info->n_outputs;
+ ChanCount midi_bypass;
+ if (inx.get(DataType::MIDI) == 1 && outputs.get(DataType::MIDI) == 0) {
+ midi_bypass.set (DataType::MIDI, 1);
+ }
+
+ /* handle case strict-i/o */
+ if (_strict_io && m.method != Impossible) {
+ m.strict_io = true;
+
+ /* special case MIDI instruments */
+ if (is_midi_instrument()) {
+ // output = midi-bypass + at most master-out channels.
+ ChanCount max_out (DataType::AUDIO, 2); // TODO use master-out
+ max_out.set (DataType::MIDI, out.get(DataType::MIDI));
+ out = ChanCount::min (out, max_out);
+ return m;
+ }
+
+ switch (m.method) {
+ case NoInputs:
+ if (inx.n_audio () != out.n_audio ()) { // ignore midi bypass
+ /* replicate processor to match output count (generators and such)
+ * at least enough to feed every output port. */
+ uint32_t f = 1; // at least one. e.g. control data filters, no in, no out.
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ uint32_t nin = inputs.get (*t);
+ if (nin == 0 || inx.get(*t) == 0) { continue; }
+ f = max (f, (uint32_t) ceil (inx.get(*t) / (float)nin));
+ }
+ out = inx + midi_bypass;
+ return Match (Replicate, f);
+ }
+ break;
+ case Split:
+ break;
+ default:
+ break;
+ }
+
+ out = inx + midi_bypass;
+ if (inx.get(DataType::MIDI) == 1
+ && out.get (DataType::MIDI) == 0
+ && outputs.get(DataType::MIDI) == 0) {
+ out += ChanCount (DataType::MIDI, 1);
+ }
+ return m;
+ }
+
+ if (m.method != Impossible) {
+ return m;
+ }
+
+ if (info->reconfigurable_io()) {
+ ChanCount useins;
+ bool const r = _plugins.front()->can_support_io_configuration (inx, out, &useins);
+ if (!r) {
+ // houston, we have a problem.
+ return Match (Impossible, 0);
+ }
+ return Match (Delegate, 1);
+ }
+
+ // add at least as many plugins so that output count matches input count
+ uint32_t f = 0;
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ uint32_t nin = inputs.get (*t);
+ uint32_t nout = outputs.get (*t);
+ if (nin == 0 || inx.get(*t) == 0) { continue; }
+ // prefer floor() so the count won't overly increase IFF (nin < nout)
+ f = max (f, (uint32_t) floor (inx.get(*t) / (float)nout));
+ }
+ if (f > 0 && outputs * f >= _configured_out) {
+ out = outputs * f + midi_bypass;
+ return Match (Replicate, f);
+ }
+
+ // add at least as many plugins needed to connect all inputs
+ f = 1;
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ uint32_t nin = inputs.get (*t);
+ if (nin == 0 || inx.get(*t) == 0) { continue; }
+ f = max (f, (uint32_t) ceil (inx.get(*t) / (float)nin));
+ }
+ out = outputs * f + midi_bypass;
+ return Match (Replicate, f);
+}
+
+/* this is the original Ardour 3/4 behavior, mainly for backwards compatibility */
+PluginInsert::Match
+PluginInsert::automatic_can_support_io_configuration (ChanCount const & inx, ChanCount& out) const
+{
+ if (_plugins.empty()) {
+ return Match();
+ }
+