plugin-pin-map:
authorRobin Gareus <robin@gareus.org>
Thu, 31 Mar 2016 18:28:48 +0000 (20:28 +0200)
committerRobin Gareus <robin@gareus.org>
Thu, 31 Mar 2016 18:28:48 +0000 (20:28 +0200)
* fix MIDI-bypass
* prepare combined channel-map report (for GUI)
* fix route failed config return

libs/ardour/ardour/chan_mapping.h
libs/ardour/ardour/plugin_insert.h
libs/ardour/chan_mapping.cc
libs/ardour/plugin_insert.cc
libs/ardour/route.cc

index 730ecadc7258443dde1e157d67f8222f6bc0d6f0..f73408baec7071b423038b3cc0622534ac385ba9 100644 (file)
 namespace ARDOUR {
 
 
-/** A mapping from one set of channels to another
- * (e.g. how to 'connect' two BufferSets).
+/** A mapping from one set of channels to another.
+ * The general form is  1 source (from), many sinks (to).
+ * numeric IDs are used to identify sources and sinks.
  *
- * for plugins the form is  "pin" -> "buffer"
+ * for plugins this is used to map "plugin-pin" to "audio-buffer"
  */
 class LIBARDOUR_API ChanMapping {
 public:
@@ -44,15 +45,24 @@ public:
 
        uint32_t get(DataType t, uint32_t from, bool* valid) const;
 
+       /** reverse lookup
+        * @param type data type
+        * @param to pin
+        * @param valid pointer to a boolean. If not NULL it is set to true if the mapping is found, and false otherwise.
+        * @returns first "from" that matches given "to"
+        */
+       uint32_t get_src(DataType t, uint32_t to, bool* valid) const;
+
        /** get buffer mapping for given data type and pin
         * @param type data type
-        * @param from pin
+        * @param from numeric source id
         * @returns mapped buffer number (or ChanMapping::Invalid)
         */
-       uint32_t get(DataType t, uint32_t from) const { return get (t, from, NULL); }
+       uint32_t get (DataType t, uint32_t from) const { return get (t, from, NULL); }
+
        /** set buffer mapping for given data type
         * @param type data type
-        * @param from pin
+        * @param from numeric source id
         * @param to buffer
         */
        void     set(DataType t, uint32_t from, uint32_t to);
@@ -61,7 +71,7 @@ public:
 
        /** remove mapping
         * @param type data type
-        * @param from source to remove from mapping
+        * @param from numeric source to remove from mapping
         */
        void     unset(DataType t, uint32_t from);
 
@@ -76,7 +86,6 @@ public:
         */
        bool     is_monotonic () const;
 
-
        /** Test if this mapping is a subset
         * @param superset to test against
         * @returns true if all mapping are also present in the superset
@@ -97,20 +106,6 @@ public:
                return ! (*this == other);
        }
 
-       ChanMapping operator+=(const ChanMapping& other) {
-               const ChanMapping::Mappings& mp (other.mappings());
-               for (Mappings::const_iterator tm = mp.begin(); tm != mp.end(); ++tm) {
-                       for (TypeMapping::const_iterator i = tm->second.begin(); i != tm->second.end(); ++i) {
-#if 0
-                               bool valid; uint32_t x = get (tm->first, i->first, &valid);
-                               assert (!valid || x == i->second);
-#endif
-                               set (tm->first, i->first, i->second);
-                       }
-               }
-               return *this;
-       }
-
 private:
        Mappings _mappings;
 };
index d64ee8f31da7705bbb5b3291a7e8cbf296797441..291dda42316407844b9ecbe5be14fd931bb5178e 100644 (file)
@@ -85,21 +85,9 @@ class LIBARDOUR_API PluginInsert : public Processor
                }
        }
 
-       ChanMapping input_map () const {
-               ChanMapping rv;
-               for (PinMappings::const_iterator i = _in_map.begin (); i != _in_map.end (); ++i) {
-                       rv += i->second;
-               }
-               return rv;
-       }
-
-       ChanMapping output_map () const {
-               ChanMapping rv;
-               for (PinMappings::const_iterator i = _out_map.begin (); i != _out_map.end (); ++i) {
-                       rv += i->second;
-               }
-               return rv;
-       }
+       ChanMapping input_map () const;
+       ChanMapping output_map () const;
+       bool has_midi_bypass () const;
 
        void set_input_map (uint32_t, ChanMapping);
        void set_output_map (uint32_t, ChanMapping);
index 0ca79af505d1f69ccf58b1008e8f77c84ea0be24..6386c2863b264a668121631b1bdf1c71071d9cb6 100644 (file)
@@ -67,6 +67,26 @@ ChanMapping::get(DataType t, uint32_t from, bool* valid) const
        return m->second;
 }
 
+uint32_t
+ChanMapping::get_src(DataType t, uint32_t to, bool* valid) const
+{
+       Mappings::const_iterator tm = _mappings.find(t);
+       if (tm == _mappings.end()) {
+               if (valid) { *valid = false; }
+               return -1;
+       }
+       for (TypeMapping::const_iterator i = tm->second.begin(); i != tm->second.end(); ++i) {
+               if (i->second == to) {
+                       if (valid) { *valid = true; }
+                       return i->first;
+               }
+       }
+       if (valid) { *valid = false; }
+       return -1;
+}
+
+
+
 void
 ChanMapping::set(DataType t, uint32_t from, uint32_t to)
 {
index 9d7276e73299ec09e3a592800efdf2060360411a..08a3d8326f2466009e0800002ac94a14cff85f97 100644 (file)
@@ -567,7 +567,7 @@ PluginInsert::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t of
                /* all instances have completed, now clear outputs that have not been written to.
                 * (except midi bypass)
                 */
-               if (bufs.count().n_midi() == 1 && natural_output_streams().get(DataType::MIDI) == 0) {
+               if (has_midi_bypass ()) {
                        used_outputs.set (DataType::MIDI, 0, 1); // Midi bypass.
                }
                for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
@@ -592,6 +592,9 @@ PluginInsert::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t of
                for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
                        for (uint32_t out = 0; out < bufs.count().get (*t); ++out) {
                                bool mapped = false;
+                               if (*t == DataType::MIDI && out == 0 && has_midi_bypass ()) {
+                                       mapped = true; // in-place Midi bypass
+                               }
                                for (uint32_t pc = 0; pc < get_count() && !mapped; ++pc) {
                                        for (uint32_t o = 0; o < natural_output_streams().get (*t); ++o) {
                                                bool valid;
@@ -892,6 +895,53 @@ PluginInsert::set_output_map (uint32_t num, ChanMapping m) {
        }
 }
 
+ChanMapping
+PluginInsert::input_map () const
+{
+       ChanMapping rv;
+       uint32_t pc = 0;
+       for (PinMappings::const_iterator i = _in_map.begin (); i != _in_map.end (); ++i, ++pc) {
+               ChanMapping m (i->second);
+               const ChanMapping::Mappings& mp ((*i).second.mappings());
+               for (ChanMapping::Mappings::const_iterator tm = mp.begin(); tm != mp.end(); ++tm) {
+                       for (ChanMapping::TypeMapping::const_iterator i = tm->second.begin(); i != tm->second.end(); ++i) {
+                               rv.set (tm->first, i->first + pc * natural_input_streams().get(tm->first), i->second);
+                       }
+               }
+       }
+       return rv;
+}
+
+ChanMapping
+PluginInsert::output_map () const
+{
+       ChanMapping rv;
+       uint32_t pc = 0;
+       for (PinMappings::const_iterator i = _out_map.begin (); i != _out_map.end (); ++i, ++pc) {
+               ChanMapping m (i->second);
+               const ChanMapping::Mappings& mp ((*i).second.mappings());
+               for (ChanMapping::Mappings::const_iterator tm = mp.begin(); tm != mp.end(); ++tm) {
+                       for (ChanMapping::TypeMapping::const_iterator i = tm->second.begin(); i != tm->second.end(); ++i) {
+                               rv.set (tm->first, i->first + pc * natural_output_streams().get(tm->first), i->second);
+                       }
+               }
+       }
+       if (has_midi_bypass ()) {
+               rv.set (DataType::MIDI, 0, 0);
+       }
+
+       return rv;
+}
+
+bool
+PluginInsert::has_midi_bypass () const
+{
+       if (_configured_in.n_midi () == 1 && _configured_out.n_midi () == 1 && natural_output_streams ().n_midi () == 0) {
+               return true;
+       }
+       return false;
+}
+
 bool
 PluginInsert::configure_io (ChanCount in, ChanCount out)
 {
@@ -1088,14 +1138,16 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanC
                return Match (ExactMatch, get_count(), false, true); // XXX
        }
 
-       /* try automatic configuration next */
+       /* 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) {
@@ -1112,7 +1164,7 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanC
 
                switch (m.method) {
                        case NoInputs:
-                               if (inx != out) {
+                               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.
@@ -1121,7 +1173,7 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanC
                                                if (nin == 0 || inx.get(*t) == 0) { continue; }
                                                f = max (f, (uint32_t) ceil (inx.get(*t) / (float)nin));
                                        }
-                                       out = inx;
+                                       out = inx + midi_bypass;
                                        return Match (Replicate, f);
                                }
                                break;
@@ -1130,9 +1182,8 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanC
                        default:
                                break;
                }
-               if (inx == out) { return m; }
 
-               out = inx;
+               out = inx + midi_bypass;
                if (inx.get(DataType::MIDI) == 1
                                && out.get (DataType::MIDI) == 0
                                && outputs.get(DataType::MIDI) == 0) {
@@ -1165,7 +1216,7 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanC
                f = max (f, (uint32_t) floor (inx.get(*t) / (float)nout));
        }
        if (f > 0 && outputs * f >= _configured_out) {
-               out = outputs * f;
+               out = outputs * f + midi_bypass;
                return Match (Replicate, f);
        }
 
@@ -1176,7 +1227,7 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanC
                if (nin == 0 || inx.get(*t) == 0) { continue; }
                f = max (f, (uint32_t) ceil (inx.get(*t) / (float)nin));
        }
-       out = outputs * f;
+       out = outputs * f + midi_bypass;
        return Match (Replicate, f);
 }
 
@@ -1206,7 +1257,7 @@ PluginInsert::automatic_can_support_io_configuration (ChanCount const & inx, Cha
 
        if (in.get(DataType::MIDI) == 1 && outputs.get(DataType::MIDI) == 0) {
                DEBUG_TRACE ( DEBUG::Processors, string_compose ("bypassing midi-data around %1\n", name()));
-               midi_bypass.set(DataType::MIDI, 1);
+               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()));
@@ -1267,7 +1318,7 @@ PluginInsert::automatic_can_support_io_configuration (ChanCount const & inx, Cha
                }
        }
 
-       if (can_replicate) {
+       if (can_replicate && f > 0) {
                for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
                        out.set (*t, outputs.get(*t) * f);
                }
@@ -1323,7 +1374,6 @@ PluginInsert::automatic_can_support_io_configuration (ChanCount const & inx, Cha
                return Match (Hide, 1, false, false, hide_channels);
        }
 
-       midi_bypass.reset();
        return Match (Impossible, 0);
 }
 
index de854e7d269d5755df83c8add4bb9774392def1e..990ab14e2856c5532b369894bf60ce55c314dffd 100644 (file)
@@ -2155,6 +2155,7 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
 
                if (!(*p)->configure_io(c->first, c->second)) {
                        DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configuration failed\n", _name));
+                       _in_configure_processors = false;
                        return -1;
                }
                processor_max_streams = ChanCount::max(processor_max_streams, c->first);