find a good match for variable i/o plugins
authorRobin Gareus <robin@gareus.org>
Fri, 15 Apr 2016 01:24:22 +0000 (03:24 +0200)
committerRobin Gareus <robin@gareus.org>
Fri, 15 Apr 2016 01:24:22 +0000 (03:24 +0200)
libs/ardour/audio_unit.cc
libs/ardour/luaproc.cc
libs/ardour/plugin_insert.cc

index 73a08fe7ac63dc63080cf2caab50b9d5c3db4f76..cab6a56c9275f14eb1844e83edfcf010dd906294 100644 (file)
@@ -1150,16 +1150,8 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha
        DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("%1 has %2 IO configurations, looking for %3 in, %4 out\n",
                                                        name(), io_configs.size(), in, out));
 
-       //Ardour expects the plugin to tell it the output
-       //configuration but AU plugins can have multiple I/O
-       //configurations in most cases. so first lets see
-       //if there's a configuration that keeps out==in
-
-       if (in.n_midi() > 0 && audio_in == 0) {
-               audio_out = 2; // prefer stereo version if available.
-       } else {
-               audio_out = audio_in;
-       }
+       // preferred setting (provided by plugin_insert)
+       audio_out = out.n_audio ();
 
        /* kAudioUnitProperty_SupportedNumChannels
         * https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html#//apple_ref/doc/uid/TP40003278-CH12-SW20
@@ -1208,6 +1200,21 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha
        audio_out = -1;
        bool found = false;
 
+       float penalty = 9999;
+       const int preferred_out = out.n_audio ();
+       int used_possible_in = 0;
+
+#define FOUNDCFG(nch) {                                  \
+       float p = fabsf ((float)(nch) - preferred_out);  \
+       if ((nch) > preferred_out) { p *= 1.1; }         \
+       if (p < penalty) {                               \
+               used_possible_in = possible_in;          \
+               audio_out = (nch);                       \
+               penalty = p;                             \
+               found = true;                            \
+       }                                                \
+}
+
        for (vector<pair<int,int> >::iterator i = io_configs.begin(); i != io_configs.end(); ++i) {
 
                int32_t possible_in = i->first;
@@ -1225,20 +1232,16 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha
                        /* no inputs, generators & instruments */
                        if (possible_out == -1) {
                                /* any configuration possible, provide stereo output */
-                               audio_out = 2;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out == -2) {
                                /* invalid, should be (0, -1) */
-                               audio_out = 2;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out < -2) {
-                               /* explicitly variable number of outputs. */
-                               audio_out = 2;
-                               found = true;
+                               /* variable number of outputs up to -N, */
+                               FOUNDCFG (min (-possible_out, preferred_out));
                        } else {
                                /* exact number of outputs */
-                               audio_out = possible_out;
-                               found = true;
+                               FOUNDCFG (possible_out);
                        }
                }
 
@@ -1246,40 +1249,35 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha
                        /* wildcard for input */
                        if (possible_out == -1) {
                                /* out must match in */
-                               audio_out = audio_in;
-                               found = true;
+                               FOUNDCFG (audio_in);
                        } else if (possible_out == -2) {
                                /* any configuration possible, pick matching */
-                               audio_out = audio_in;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out < -2) {
                                /* explicitly variable number of outputs, pick maximum */
-                               audio_out = -possible_out;
-                               found = true;
+                               FOUNDCFG (max (-possible_out, preferred_out));
+                               /* and try min, too, in case the penalty is lower */
+                               FOUNDCFG (min (-possible_out, preferred_out));
                        } else {
                                /* exact number of outputs */
-                               audio_out = possible_out;
-                               found = true;
+                               FOUNDCFG (possible_out);
                        }
                }
 
                if (possible_in == -2) {
                        if (possible_out == -1) {
                                /* any configuration possible, pick matching */
-                               audio_out = audio_in;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out == -2) {
                                /* invalid. interpret as (-1, -1) */
-                               audio_out = audio_in;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out < -2) {
-                               /* explicitly variable number of outputs, pick maximum */
-                               audio_out = -possible_out;
-                               found = true;
+                               /* invalid,  interpret as (<-2, <-2)
+                                * variable number of outputs up to -N, */
+                               FOUNDCFG (min (-possible_out, preferred_out));
                        } else {
                                /* exact number of outputs */
-                               audio_out = possible_out;
-                               found = true;
+                               FOUNDCFG (possible_out);
                        }
                }
 
@@ -1294,57 +1292,40 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha
                                /* request is too large */
                        } else if (possible_out == -1) {
                                /* any output configuration possible, provide stereo out */
-                               audio_out = 2;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out == -2) {
                                /* invalid. interpret as (<-2, -1) */
-                               audio_out = 2;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out < -2) {
-                               /* explicitly variable number of outputs, pick stereo */
-                               audio_out = 2;
-                               found = true;
+                               /* variable number of outputs up to -N, */
+                               FOUNDCFG (min (-possible_out, preferred_out));
                        } else {
                                /* exact number of outputs */
-                               audio_out = possible_out;
-                               found = true;
+                               FOUNDCFG (possible_out);
                        }
                }
 
                if (possible_in && (possible_in == audio_in)) {
                        /* exact number of inputs ... must match obviously */
                        if (possible_out == -1) {
-                               /* any output configuration possible, provide stereo output */
-                               audio_out = 2;
-                               found = true;
+                               /* any output configuration possible */
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out == -2) {
                                /* plugins shouldn't really use (>0,-2) but might.
-                                  interpret as (>0,-1):
-                                  any output configuration possible, provide stereo output
-                               */
-                               audio_out = 2;
-                               found = true;
+                                * interpret as (>0,-1):
+                                */
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out < -2) {
-                               /* explicitly variable number of outputs, pick maximum */
-                               audio_out = -possible_out;
-                               found = true;
+                               /* > 0, < -2 is not specified
+                                * interpret as up to -N */
+                               FOUNDCFG (min (-possible_out, preferred_out));
                        } else {
                                /* exact number of outputs */
-                               audio_out = possible_out;
-                               found = true;
-                       }
-               }
-
-               if (found) {
-                       if (possible_in < -2 && audio_in == 0) {
-                               // input-port count cannot be zero, use as many ports
-                               // as outputs, but at most abs(possible_in)
-                               audio_input_cnt = max (1, min (audio_out, -possible_in));
+                               FOUNDCFG (possible_out);
                        }
-                       break;
                }
-
        }
+
        if (!found && imprecise) {
                /* try harder */
                for (vector<pair<int,int> >::iterator i = io_configs.begin(); i != io_configs.end(); ++i) {
@@ -1356,29 +1337,26 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha
 
                        imprecise->set (DataType::AUDIO, possible_in);
                        if (possible_out == -1 || possible_out == -2) {
-                               audio_out = 2;
-                               found = true;
+                               FOUNDCFG (2);
                        } else if (possible_out < -2) {
                                /* explicitly variable number of outputs, pick maximum */
-                               audio_out = -possible_out;
-                               found = true;
+                               FOUNDCFG (min (-possible_out, preferred_out));
                        } else {
                                /* exact number of outputs */
-                               audio_out = possible_out;
-                               found = true;
-                       }
-
-                       if (found) {
-                               // ideally we'll keep iterating and take the "best match"
-                               // whatever "best" means:
-                               // least unconnected inputs, least silenced inputs,
-                               // closest match of inputs == outputs
-                               break;
+                               FOUNDCFG (possible_out);
                        }
+                       // ideally we'll also find the closest, best matching
+                       // input configuration with minimal output penalty...
                }
        }
 
        if (found) {
+               if (used_possible_in < -2 && audio_in == 0) {
+                       // input-port count cannot be zero, use as many ports
+                       // as outputs, but at most abs(possible_in)
+                       audio_input_cnt = max (1, min (audio_out, -used_possible_in));
+               }
+
                out.set (DataType::MIDI, 0); /// XXX
                out.set (DataType::AUDIO, audio_out);
                DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tCHOSEN: in %1 out %2\n", in, out));
index 7af6f587a428e443eeaa3b0916938632cac274a3..fc9e5de537db860cbaa2b910ae55374e0cc780d1 100644 (file)
@@ -354,12 +354,9 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
        int32_t audio_out;
        int32_t midi_out = 0; // TODO handle  _has_midi_output
 
-       if (in.n_midi() > 0 && audio_in == 0) {
-               audio_out = 2; // prefer stereo version if available.
-       } else {
-               audio_out = audio_in;
-       }
-
+       // preferred setting (provided by plugin_insert)
+       assert (out.n_audio () > 0);
+       audio_out = out.n_audio ();
 
        for (luabridge::Iterator i (iotable); !i.isNil (); ++i) {
                assert (i.value ().type () == LUA_TTABLE);
@@ -380,6 +377,19 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
        audio_out = -1;
        bool found = false;
 
+       float penalty = 9999;
+       const int preferred_out = out.n_audio ();
+
+#define FOUNDCFG(nch) {                                  \
+       float p = fabsf ((float)(nch) - preferred_out);  \
+       if ((nch) > preferred_out) { p *= 1.1; }         \
+       if (p < penalty) {                               \
+               audio_out = (nch);                       \
+               penalty = p;                             \
+               found = true;                            \
+       }                                                \
+}
+
        for (luabridge::Iterator i (iotable); !i.isNil (); ++i) {
                assert (i.value ().type () == LUA_TTABLE);
                luabridge::LuaRef io (i.value ());
@@ -393,21 +403,17 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
                if (possible_in == 0) {
                        /* no inputs, generators & instruments */
                        if (possible_out == -1) {
-                               /* any configuration possible, provide stereo output */
-                               audio_out = 2;
-                               found = true;
+                               /* any configuration possible, stereo output */
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out == -2) {
                                /* invalid, should be (0, -1) */
-                               audio_out = 2;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out < -2) {
-                               /* variable number of outputs. -> whatever */
-                               audio_out = 2;
-                               found = true;
+                               /* variable number of outputs up to -N, */
+                               FOUNDCFG (min (-possible_out, preferred_out));
                        } else {
                                /* exact number of outputs */
-                               audio_out = possible_out;
-                               found = true;
+                               FOUNDCFG (possible_out);
                        }
                }
 
@@ -415,20 +421,18 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
                        /* wildcard for input */
                        if (possible_out == -1) {
                                /* out must match in */
-                               audio_out = audio_in;
-                               found = true;
+                               FOUNDCFG (audio_in);
                        } else if (possible_out == -2) {
                                /* any configuration possible, pick matching */
-                               audio_out = audio_in;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out < -2) {
                                /* explicitly variable number of outputs, pick maximum */
-                               audio_out = -possible_out;
-                               found = true;
+                               FOUNDCFG (max (-possible_out, preferred_out));
+                               /* and try min, too, in case the penalty is lower */
+                               FOUNDCFG (min (-possible_out, preferred_out));
                        } else {
                                /* exact number of outputs */
-                               audio_out = possible_out;
-                               found = true;
+                               FOUNDCFG (possible_out);
                        }
                }
 
@@ -436,20 +440,17 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
 
                        if (possible_out == -1) {
                                /* any configuration possible, pick matching */
-                               audio_out = audio_in;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out == -2) {
                                /* invalid. interpret as (-1, -1) */
-                               audio_out = audio_in;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out < -2) {
-                               /* explicitly variable number of outputs, pick maximum */
-                               audio_out = -possible_out;
-                               found = true;
+                               /* invalid,  interpret as (<-2, <-2)
+                                * variable number of outputs up to -N, */
+                               FOUNDCFG (min (-possible_out, preferred_out));
                        } else {
                                /* exact number of outputs */
-                               audio_out = possible_out;
-                               found = true;
+                               FOUNDCFG (possible_out);
                        }
                }
 
@@ -463,48 +464,37 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
                        if (audio_in > -possible_in && imprecise == NULL) {
                                /* request is too large */
                        } else if (possible_out == -1) {
-                               /* any output configuration possible, provide stereo out */
-                               audio_out = 2;
-                               found = true;
+                               /* any output configuration possible */
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out == -2) {
                                /* invalid. interpret as (<-2, -1) */
-                               audio_out = 2;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out < -2) {
-                               /* explicitly variable number of outputs, pick stereo */
-                               audio_out = 2;
-                               found = true;
+                               /* variable number of outputs up to -N, */
+                               FOUNDCFG (min (-possible_out, preferred_out));
                        } else {
                                /* exact number of outputs */
-                               audio_out = possible_out;
-                               found = true;
+                               FOUNDCFG (possible_out);
                        }
                }
 
                if (possible_in && (possible_in == audio_in)) {
                        /* exact number of inputs ... must match obviously */
                        if (possible_out == -1) {
-                               /* any output configuration possible, provide stereo output */
-                               audio_out = 2;
-                               found = true;
+                               /* any output configuration possible */
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out == -2) {
                                /* invalid. interpret as (>0, -1) */
-                               audio_out = 2;
-                               found = true;
+                               FOUNDCFG (preferred_out);
                        } else if (possible_out < -2) {
-                               /* explicitly variable number of outputs, pick maximum */
-                               audio_out = -possible_out;
-                               found = true;
+                               /* > 0, < -2 is not specified
+                                * interpret as up to -N */
+                               FOUNDCFG (min (-possible_out, preferred_out));
                        } else {
                                /* exact number of outputs */
-                               audio_out = possible_out;
-                               found = true;
+                               FOUNDCFG (possible_out);
                        }
                }
-
-               if (found) {
-                       break;
-               }
        }
 
        if (!found && imprecise) {
@@ -521,25 +511,16 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
 
                        imprecise->set (DataType::AUDIO, possible_in);
                        if (possible_out == -1 || possible_out == -2) {
-                               audio_out = 2;
-                               found = true;
+                               FOUNDCFG (2);
                        } else if (possible_out < -2) {
                                /* explicitly variable number of outputs, pick maximum */
-                               audio_out = -possible_out;
-                               found = true;
+                               FOUNDCFG (min (-possible_out, preferred_out));
                        } else {
                                /* exact number of outputs */
-                               audio_out = possible_out;
-                               found = true;
-                       }
-
-                       if (found) {
-                               // ideally we'll keep iterating and take the "best match"
-                               // whatever "best" means:
-                               // least unconnected inputs, least silenced inputs,
-                               // closest match of inputs == outputs
-                               break;
+                               FOUNDCFG (possible_out);
                        }
+                       // ideally we'll also find the closest, best matching
+                       // input configuration with minimal output penalty...
                }
        }
 
index 74c169196d25854c60892f573a1c5ef4c0fdbcec..2005d5b2e20f8c86b260de7c874479c211b9616c 100644 (file)
@@ -258,7 +258,6 @@ PluginInsert::internal_input_streams() const
        PluginInfoPtr info = _plugins.front()->get_info();
 
        if (info->reconfigurable_io()) {
-               assert (_plugins.size() == 1);
                in = _plugins.front()->input_streams();
        } else {
                in = info->n_inputs;
@@ -1381,14 +1380,22 @@ PluginInsert::configure_io (ChanCount in, ChanCount out)
                break;
        case Delegate:
                {
-                       ChanCount dout;
+                       ChanCount dout (in); // hint
+                       if (_custom_cfg) { 
+                               dout = _custom_out;
+                       } else if (dout.n_midi () > 0 && dout.n_audio () == 0) {
+                               dout.set (DataType::AUDIO, 2);
+                       }
+                       if (out.n_audio () == 0) { out.set (DataType::AUDIO, 1); }
                        ChanCount useins;
                        bool const r = _plugins.front()->can_support_io_configuration (in, dout, &useins);
                        assert (r);
-                       assert (_match.strict_io || dout.n_audio() == out.n_audio()); // sans midi bypass
+                       assert (dout.n_audio() <= out.n_audio()); // sans midi bypass
                        if (useins.n_audio() == 0) {
                                useins = in;
                        }
+                       DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("Delegate configuration: %1 %2 %3\n", name(), useins, dout));
+
                        if (_plugins.front()->configure_io (useins, dout) == false) {
                                PluginIoReConfigure (); /* EMIT SIGNAL */
                                _configured = false;
@@ -1542,8 +1549,13 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanC
 
        /* if a user specified a custom cfg, so be it. */
        if (_custom_cfg) {
+               PluginInfoPtr info = _plugins.front()->get_info();
                out = _custom_out;
-               return Match (ExactMatch, get_count(), _strict_io, true); // XXX
+               if (info->reconfigurable_io()) {
+                       return Match (Delegate, get_count(), _strict_io, true);
+               } else {
+                       return Match (ExactMatch, get_count(), _strict_io, true);
+               }
        }
 
        /* try automatic configuration */
@@ -1601,7 +1613,9 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanC
 
        if (info->reconfigurable_io()) {
                ChanCount useins;
-               // TODO add sidechains here
+               out = inx; // hint
+               if (out.n_midi () > 0 && out.n_audio () == 0) { out.set (DataType::AUDIO, 2); }
+               if (out.n_audio () == 0) { out.set (DataType::AUDIO, 1); }
                bool const r = _plugins.front()->can_support_io_configuration (inx, out, &useins);
                if (!r) {
                        // houston, we have a problem.
@@ -1665,7 +1679,12 @@ PluginInsert::automatic_can_support_io_configuration (ChanCount const & inx, Cha
        ChanCount midi_bypass;
 
        if (info->reconfigurable_io()) {
-               /* Plugin has flexible I/O, so delegate to it */
+               /* Plugin has flexible I/O, so delegate to it
+                * pre-seed outputs, plugin tries closest match
+                */
+               out = in; // hint
+               if (out.n_midi () > 0 && out.n_audio () == 0) { out.set (DataType::AUDIO, 2); }
+               if (out.n_audio () == 0) { out.set (DataType::AUDIO, 1); }
                bool const r = _plugins.front()->can_support_io_configuration (in, out);
                if (!r) {
                        return Match (Impossible, 0);