copy plugin state to all instances when instantiating.
[ardour.git] / libs / ardour / plugin_insert.cc
index 94f5ba62c0d687b3d75ce9e994072f324483c916..19c661287fba38d1e25dd9a070c90f999eb31a48 100644 (file)
@@ -117,12 +117,14 @@ PluginInsert::set_count (uint32_t num)
                for (uint32_t n = 0; n < diff; ++n) {
                        boost::shared_ptr<Plugin> p = plugin_factory (_plugins[0]);
                        add_plugin (p);
-                       if (active ()) {
-                               p->activate ();
-                       }
 
                        if (require_state) {
-                               /* XXX do something */
+                               XMLNode& state = _plugins[0]->get_state ();
+                               p->set_state (state, Stateful::loading_state_version);
+                       }
+
+                       if (active ()) {
+                               p->activate ();
                        }
                }
                PluginConfigChanged (); /* EMIT SIGNAL */
@@ -159,6 +161,17 @@ PluginInsert::set_custom_cfg (bool b)
        }
 }
 
+bool
+PluginInsert::set_preset_out (const ChanCount& c)
+{
+       bool changed = _preset_out != c;
+       _preset_out = c;
+       if (changed && !_custom_cfg) {
+               PluginConfigChanged (); /* EMIT SIGNAL */
+       }
+       return changed;
+}
+
 bool
 PluginInsert::add_sidechain (uint32_t n_audio)
 {
@@ -258,7 +271,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;
@@ -341,15 +353,13 @@ PluginInsert::plugin_latency () const {
 }
 
 bool
-PluginInsert::is_midi_instrument() const
+PluginInsert::needs_midi_input() const
 {
-       /* XXX more finesse is possible here. VST plugins have a
-          a specific "instrument" flag, for example.
-        */
-       PluginInfoPtr pi = _plugins[0]->get_info();
-
-       return pi->n_inputs.n_midi() != 0 &&
-               pi->n_outputs.n_audio() > 0;
+       PluginInfoPtr pip = _plugins[0]->get_info();
+       if (pip->needs_midi_input ()) {
+               return true;
+       }
+       return pip->n_inputs.n_midi() != 0 && pip->n_outputs.n_audio() != 0;
 }
 
 void
@@ -1164,7 +1174,7 @@ PluginInsert::sanitize_maps ()
        /* strip dead wood */
        PinMappings new_ins;
        PinMappings new_outs;
-       ChanMapping new_thru (_thru_map);
+       ChanMapping new_thru;
 
        for (uint32_t pc = 0; pc < get_count(); ++pc) {
                ChanMapping new_in;
@@ -1208,6 +1218,17 @@ PluginInsert::sanitize_maps ()
                }
        }
 
+       /* remove excess thru */
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+               for (uint32_t o = 0; o < _configured_out.get (*t); ++o) {
+                       bool valid;
+                       uint32_t idx = _thru_map.get (*t, o, &valid);
+                       if (valid && idx < _configured_internal.get (*t)) {
+                               new_thru.set (*t, o, idx);
+                       }
+               }
+       }
+
        /* prevent out + thru,  existing plugin outputs override thru */
        for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
                for (uint32_t o = 0; o < _configured_out.get (*t); ++o) {
@@ -1282,13 +1303,19 @@ PluginInsert::reset_map (bool emit)
                                } else {
                                        if (_match.method == Split) {
                                                if (cend == 0) { continue; }
+                                               if (_strict_io && ic + stride * pc >= cend) {
+                                                       break;
+                                               }
                                                /* connect *no* sidechain sinks in round-robin fashion */
                                                _in_map[pc].set (*t, in, ic + stride * pc);
+                                               if (_strict_io && (ic + 1) == cend) {
+                                                       break;
+                                               }
                                                ic = (ic + 1) % cend;
                                        } else {
                                                uint32_t s = in - shift;
                                                if (stride * pc + s < cend) {
-                                                       _in_map[pc].set (*t, in, stride * pc + s);
+                                                       _in_map[pc].set (*t, in, s + stride * pc);
                                                }
                                        }
                                }
@@ -1377,14 +1404,23 @@ PluginInsert::configure_io (ChanCount in, ChanCount out)
                break;
        case Delegate:
                {
-                       ChanCount dout;
+                       ChanCount dout (in); // hint
+                       if (_custom_cfg) { 
+                               dout = _custom_out;
+                       } else if (_preset_out.n_audio () > 0) {
+                               dout.set (DataType::AUDIO, _preset_out.n_audio ());
+                       } 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
                        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;
@@ -1457,6 +1493,25 @@ PluginInsert::configure_io (ChanCount in, ChanCount out)
        _no_inplace = check_inplace ();
        _mapping_changed = false;
 
+       /* only the "noinplace_buffers" thread buffers need to be this large,
+        * this can be optimized. other buffers are fine with
+        * ChanCount::max (natural_input_streams (), natural_output_streams())
+        * and route.cc's max (configured_in, configured_out)
+        *
+        * no-inplace copies "thru" outputs (to emulate in-place) for
+        * all outputs (to prevent overwrite) into a temporary space
+        * which also holds input buffers (in case the plugin does process
+        * in-place and overwrites those).
+        *
+        * this buffers need to be at least as
+        *   natural_input_streams () + possible outputs.
+        *
+        * sidechain inputs add a constraint on the input:
+        * configured input + sidechain (=_configured_internal)
+        */
+       _required_buffers =ChanCount::max (_configured_internal,
+                       natural_input_streams () + ChanCount::max (_configured_out, natural_output_streams () * get_count ()));
+
        if (old_in != in || old_out != out || old_internal != _configured_internal
                        || (old_match.method != _match.method && (old_match.method == Split || _match.method == Split))
                 ) {
@@ -1499,12 +1554,29 @@ PluginInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out)
        return private_can_support_io_configuration (in, out).method != Impossible;
 }
 
+PluginInsert::Match
+PluginInsert::private_can_support_io_configuration (ChanCount const& in, ChanCount& out) const
+{
+       if (!_custom_cfg && _preset_out.n_audio () > 0) {
+               // preseed hint (for variable i/o)
+               out.set (DataType::AUDIO, _preset_out.n_audio ());
+       }
+
+       Match rv = internal_can_support_io_configuration (in, out);
+
+       if (!_custom_cfg && _preset_out.n_audio () > 0) {
+               DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("using output preset: %1 %2\n", name(), _preset_out));
+               out.set (DataType::AUDIO, _preset_out.n_audio ());
+       }
+       return rv;
+}
+
 /** A private version of can_support_io_configuration which returns the method
  *  by which the configuration can be matched, rather than just whether or not
  *  it can be.
  */
 PluginInsert::Match
-PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanCount& out) const
+PluginInsert::internal_can_support_io_configuration (ChanCount const & inx, ChanCount& out) const
 {
        if (_plugins.empty()) {
                return Match();
@@ -1519,8 +1591,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 */
@@ -1535,7 +1612,7 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanC
                m.strict_io = true;
 
                /* special case MIDI instruments */
-               if (is_midi_instrument()) {
+               if (needs_midi_input ()) {
                        // 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));
@@ -1578,7 +1655,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.
@@ -1642,7 +1721,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);
@@ -1806,6 +1890,7 @@ PluginInsert::state (bool full)
         * in case the plugin goes missing) */
        node.add_child_nocopy (* _configured_in.state (X_("ConfiguredInput")));
        node.add_child_nocopy (* _configured_out.state (X_("ConfiguredOutput")));
+       node.add_child_nocopy (* _preset_out.state (X_("PresetOutput")));
 
        /* save custom i/o config */
        node.add_property("custom", _custom_cfg ? "yes" : "no");
@@ -2079,6 +2164,9 @@ PluginInsert::set_state(const XMLNode& node, int version)
                if ((*i)->name() == X_("ConfiguredOutput")) {
                        _custom_out = ChanCount(**i);
                }
+               if ((*i)->name() == X_("PresetOutput")) {
+                       _preset_out = ChanCount(**i);
+               }
                if (strncmp ((*i)->name ().c_str(), X_("InputMap-"), 9) == 0) {
                        long pc = atol (&((*i)->name().c_str()[9]));
                        if (pc >=0 && pc <= get_count()) {