From 424cacfbc83516d9e935bd93135e58b34dcfc002 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 15 Apr 2016 17:57:40 +0200 Subject: [PATCH] variable plugin port config. * extend plugin API (query IO ports) * collect possible variable plugin configurations (AU, Lua) * prepare semi-automatic configuration (presets: mono, stereo, N) --- libs/ardour/ardour/audio_unit.h | 3 + libs/ardour/ardour/luaproc.h | 3 + libs/ardour/ardour/lv2_plugin.h | 2 +- libs/ardour/ardour/plugin.h | 5 +- libs/ardour/ardour/plugin_insert.h | 6 +- libs/ardour/ardour/route.h | 1 + libs/ardour/audio_unit.cc | 90 +++++++++++++++++++----------- libs/ardour/luaproc.cc | 76 ++++++++++++++++--------- libs/ardour/lv2_plugin.cc | 2 +- libs/ardour/plugin.cc | 14 ++++- libs/ardour/plugin_insert.cc | 37 +++++++++++- libs/ardour/route.cc | 39 +++++++++++++ 12 files changed, 211 insertions(+), 67 deletions(-) diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h index b83798fd3e..63bd05b50d 100644 --- a/libs/ardour/ardour/audio_unit.h +++ b/libs/ardour/ardour/audio_unit.h @@ -74,6 +74,8 @@ class LIBARDOUR_API AUPlugin : public ARDOUR::Plugin void set_parameter (uint32_t which, float val); float get_parameter (uint32_t which) const; + PluginOutputConfiguration possible_output () const { return _output_configs; } + int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const; uint32_t nth_parameter (uint32_t which, bool& ok) const; void activate (); @@ -172,6 +174,7 @@ class LIBARDOUR_API AUPlugin : public ARDOUR::Plugin AudioBufferList* buffers; bool _has_midi_input; bool _has_midi_output; + PluginOutputConfiguration _output_configs; /* despite all the cool work that apple did on their AU preset system, they left factory presets and user presets as two diff --git a/libs/ardour/ardour/luaproc.h b/libs/ardour/ardour/luaproc.h index 0f4f8d7d6d..a0f49d61bb 100644 --- a/libs/ardour/ardour/luaproc.h +++ b/libs/ardour/ardour/luaproc.h @@ -63,6 +63,8 @@ public: std::string get_docs () const { return _docs; } std::string get_parameter_docs (uint32_t) const; + PluginOutputConfiguration possible_output () const { return _output_configs; } + std::set automatable() const; void activate () { } @@ -140,6 +142,7 @@ private: ChanCount _configured_in; ChanCount _configured_out; + PluginOutputConfiguration _output_configs; bool _has_midi_input; bool _has_midi_output; diff --git a/libs/ardour/ardour/lv2_plugin.h b/libs/ardour/ardour/lv2_plugin.h index f1907e80ae..34e68fdc7f 100644 --- a/libs/ardour/ardour/lv2_plugin.h +++ b/libs/ardour/ardour/lv2_plugin.h @@ -80,7 +80,7 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const; uint32_t nth_parameter (uint32_t port, bool& ok) const; - IOPortDescription describe_io_port (DataType dt, bool input, uint32_t id); + IOPortDescription describe_io_port (DataType dt, bool input, uint32_t id) const; const void* extension_data (const char* uri) const; diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h index ec749281af..d284c2620d 100644 --- a/libs/ardour/ardour/plugin.h +++ b/libs/ardour/ardour/plugin.h @@ -22,6 +22,7 @@ #include #include +#include #include "pbd/statefuldestructible.h" #include "pbd/controllable.h" @@ -54,6 +55,7 @@ class AutomationControl; typedef boost::shared_ptr PluginPtr; typedef boost::shared_ptr PluginInfoPtr; typedef std::list PluginInfoList; +typedef std::set PluginOutputConfiguration; /** A plugin is an external module (usually 3rd party provided) loaded into Ardour * for the purpose of digital signal processing. @@ -124,7 +126,8 @@ class LIBARDOUR_API Plugin : public PBD::StatefulDestructible, public Latent bool is_sidechain; }; - virtual IOPortDescription describe_io_port (DataType dt, bool input, uint32_t id); + virtual IOPortDescription describe_io_port (DataType dt, bool input, uint32_t id) const; + virtual PluginOutputConfiguration possible_output () const; virtual void set_automation_control (uint32_t /*port_index*/, boost::shared_ptr) { } diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h index aa1164187d..c8f0a84222 100644 --- a/libs/ardour/ardour/plugin_insert.h +++ b/libs/ardour/ardour/plugin_insert.h @@ -134,7 +134,8 @@ class LIBARDOUR_API PluginInsert : public Processor } } - ChanCount required_buffers () const { return _required_buffers; } + const ChanCount& required_buffers () const { return _required_buffers; } + const ChanCount& preset_out () const { return _preset_out; } // allow to override output_streams(), implies "Custom Mode" @@ -144,6 +145,7 @@ class LIBARDOUR_API PluginInsert : public Processor void set_outputs (const ChanCount&); void set_strict_io (bool b); void set_custom_cfg (bool b); + bool set_preset_out (const ChanCount&); bool add_sidechain (uint32_t n_audio = 1); bool del_sidechain (); boost::shared_ptr sidechain () const { return _sidechain; } @@ -306,6 +308,7 @@ class LIBARDOUR_API PluginInsert : public Processor ChanCount _configured_internal; // with side-chain ChanCount _configured_out; ChanCount _custom_out; + ChanCount _preset_out; ChanCount _cached_sidechain_pins; ChanCount _required_buffers; @@ -317,6 +320,7 @@ class LIBARDOUR_API PluginInsert : public Processor bool _mapping_changed; Match private_can_support_io_configuration (ChanCount const &, ChanCount &) const; + Match internal_can_support_io_configuration (ChanCount const &, ChanCount &) const; Match automatic_can_support_io_configuration (ChanCount const &, ChanCount &) const; /** details of the match currently being used */ diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 7e7d5d55d4..c8f6005872 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -313,6 +313,7 @@ class LIBARDOUR_API Route : public SessionObject, public Automatable, public Rou */ bool customize_plugin_insert (boost::shared_ptr proc, uint32_t count, ChanCount outs); bool add_remove_sidechain (boost::shared_ptr proc, bool); + bool plugin_preset_output (boost::shared_ptr proc, ChanCount outs); /* enable sidechain input for a given processor * diff --git a/libs/ardour/audio_unit.cc b/libs/ardour/audio_unit.cc index 2ded196f52..2746f76330 100644 --- a/libs/ardour/audio_unit.cc +++ b/libs/ardour/audio_unit.cc @@ -1133,8 +1133,7 @@ AUPlugin::output_streams() const bool AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, ChanCount* imprecise) { - // Note: We never attempt to multiply-instantiate plugins to meet io configurations. - + _output_configs.clear (); const int32_t audio_in = in.n_audio(); int32_t audio_out; AUPluginInfoPtr pinfo = boost::dynamic_pointer_cast(get_info()); @@ -1151,7 +1150,10 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha name(), io_configs.size(), in, out)); // preferred setting (provided by plugin_insert) + const int preferred_out = out.n_audio (); audio_out = out.n_audio (); + bool found = false; + bool exact_match = false; /* kAudioUnitProperty_SupportedNumChannels * https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html#//apple_ref/doc/uid/TP40003278-CH12-SW20 @@ -1184,35 +1186,43 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha int32_t possible_in = i->first; int32_t possible_out = i->second; - if ((possible_in == audio_in) && (possible_out == audio_out)) { + if ((possible_in == audio_in) && (possible_out == preferred_out)) { DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tCHOSEN: %1 in %2 out to match in %3 out %4\n", - possible_in, possible_out, - in, out)); + possible_in, possible_out, + in, out)); - out.set (DataType::MIDI, 0); - out.set (DataType::AUDIO, audio_out); - - return true; + // exact match + _output_configs.insert (preferred_out); + exact_match = true; + found = true; + break; } } /* now allow potentially "imprecise" matches */ - audio_out = -1; - bool found = false; - + int32_t audio_out = -1; 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; \ - } \ +#define FOUNDCFG(nch) { \ + float p = fabsf ((float)(nch) - preferred_out); \ + _output_configs.insert (nch); \ + if ((nch) > preferred_out) { p *= 1.1; } \ + if (p < penalty) { \ + used_possible_in = possible_in; \ + audio_out = (nch); \ + penalty = p; \ + found = true; \ + } \ +} + +#define ANYTHINGGOES \ + _output_configs.insert (0); + +#define UPTO(nch) { \ + for (int n = 1; n < nch; ++n) { \ + _output_configs.insert (n); \ + } \ } for (vector >::iterator i = io_configs.begin(); i != io_configs.end(); ++i) { @@ -1233,12 +1243,15 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha if (possible_out == -1) { /* any configuration possible, provide stereo output */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out == -2) { /* invalid, should be (0, -1) */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { /* variable number of outputs up to -N, */ FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out); } else { /* exact number of outputs */ FOUNDCFG (possible_out); @@ -1253,11 +1266,13 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha } else if (possible_out == -2) { /* any configuration possible, pick matching */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { /* explicitly variable number of outputs, pick maximum */ FOUNDCFG (max (-possible_out, preferred_out)); /* and try min, too, in case the penalty is lower */ FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out) } else { /* exact number of outputs */ FOUNDCFG (possible_out); @@ -1268,13 +1283,16 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha if (possible_out == -1) { /* any configuration possible, pick matching */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out == -2) { /* invalid. interpret as (-1, -1) */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { /* invalid, interpret as (<-2, <-2) * variable number of outputs up to -N, */ FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out) } else { /* exact number of outputs */ FOUNDCFG (possible_out); @@ -1291,14 +1309,17 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha if (audio_in > -possible_in && imprecise == NULL) { /* request is too large */ } else if (possible_out == -1) { - /* any output configuration possible, provide stereo out */ + /* any output configuration possible */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out == -2) { /* invalid. interpret as (<-2, -1) */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { /* variable number of outputs up to -N, */ FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out) } else { /* exact number of outputs */ FOUNDCFG (possible_out); @@ -1310,15 +1331,16 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha if (possible_out == -1) { /* any output configuration possible */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out == -2) { - /* plugins shouldn't really use (>0,-2) but might. - * interpret as (>0,-1): - */ + /* plugins shouldn't really use (>0,-2), interpret as (>0,-1) */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { /* > 0, < -2 is not specified * interpret as up to -N */ FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out) } else { /* exact number of outputs */ FOUNDCFG (possible_out); @@ -1350,20 +1372,24 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, Cha } } - if (found) { + if (!found) { + DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tFAIL: no io configs match %1\n", in)); + return false; + } + + if (exact_match) { + out.set (DataType::MIDI, 0); // currently always zero + out.set (DataType::AUDIO, preferred_out); + } else { 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)); - } else { - DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tFAIL: no io configs match %1\n", in)); - return false; } + DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tCHOSEN: in %1 out %2\n", in, out)); return true; } diff --git a/libs/ardour/luaproc.cc b/libs/ardour/luaproc.cc index 31a5dd8785..baeb9409f4 100644 --- a/libs/ardour/luaproc.cc +++ b/libs/ardour/luaproc.cc @@ -311,6 +311,7 @@ bool LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, ChanCount* imprecise) { // caller must hold process lock (no concurrent calls to interpreter + _output_configs.clear (); if (in.n_midi() > 0 && !_has_midi_input && !imprecise) { return false; @@ -322,14 +323,9 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan return false; } - luabridge::LuaRef table = luabridge::getGlobal (L, "table"); //lua std lib - luabridge::LuaRef tablesort = table["sort"]; - assert (tablesort.isFunction ()); - luabridge::LuaRef *_iotable = NULL; // can't use reference :( try { luabridge::LuaRef iotable = ioconfig (); - tablesort (iotable); if (iotable.isTable ()) { _iotable = new luabridge::LuaRef (iotable); } @@ -349,13 +345,14 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan return false; } + bool found = false; + bool exact_match = false; const int32_t audio_in = in.n_audio (); - int32_t audio_out; int32_t midi_out = 0; // TODO handle _has_midi_output // preferred setting (provided by plugin_insert) assert (out.n_audio () > 0); - audio_out = out.n_audio (); + const int preferred_out = out.n_audio (); for (luabridge::Iterator i (iotable); !i.isNil (); ++i) { assert (i.value ().type () == LUA_TTABLE); @@ -365,28 +362,36 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan int possible_out = io["audio_out"]; // exact match - if ((possible_in == audio_in) && (possible_out == audio_out)) { - out.set (DataType::MIDI, 0); - out.set (DataType::AUDIO, audio_out); - return true; + if ((possible_in == audio_in) && (possible_out == preferred_out)) { + _output_configs.insert (preferred_out); + exact_match = true; + found = true; + break; } } /* now allow potentially "imprecise" matches */ - audio_out = -1; - bool found = false; - + int32_t audio_out = -1; 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; \ - } \ +#define FOUNDCFG(nch) { \ + float p = fabsf ((float)(nch) - preferred_out); \ + _output_configs.insert (nch); \ + if ((nch) > preferred_out) { p *= 1.1; } \ + if (p < penalty) { \ + audio_out = (nch); \ + penalty = p; \ + found = true; \ + } \ +} + +#define ANYTHINGGOES \ + _output_configs.insert (0); + +#define UPTO(nch) { \ + for (int n = 1; n < nch; ++n) { \ + _output_configs.insert (n); \ + } \ } for (luabridge::Iterator i (iotable); !i.isNil (); ++i) { @@ -404,12 +409,15 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan if (possible_out == -1) { /* any configuration possible, stereo output */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out == -2) { /* invalid, should be (0, -1) */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { /* variable number of outputs up to -N, */ FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out); } else { /* exact number of outputs */ FOUNDCFG (possible_out); @@ -424,11 +432,13 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan } else if (possible_out == -2) { /* any configuration possible, pick matching */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { /* explicitly variable number of outputs, pick maximum */ FOUNDCFG (max (-possible_out, preferred_out)); /* and try min, too, in case the penalty is lower */ FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out) } else { /* exact number of outputs */ FOUNDCFG (possible_out); @@ -436,17 +446,19 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan } if (possible_in == -2) { - if (possible_out == -1) { /* any configuration possible, pick matching */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out == -2) { /* invalid. interpret as (-1, -1) */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { /* invalid, interpret as (<-2, <-2) * variable number of outputs up to -N, */ FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out) } else { /* exact number of outputs */ FOUNDCFG (possible_out); @@ -465,12 +477,15 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan } else if (possible_out == -1) { /* any output configuration possible */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out == -2) { /* invalid. interpret as (<-2, -1) */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { /* variable number of outputs up to -N, */ FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out) } else { /* exact number of outputs */ FOUNDCFG (possible_out); @@ -482,13 +497,16 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan if (possible_out == -1) { /* any output configuration possible */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out == -2) { /* invalid. interpret as (>0, -1) */ FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { /* > 0, < -2 is not specified * interpret as up to -N */ FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out) } else { /* exact number of outputs */ FOUNDCFG (possible_out); @@ -523,13 +541,17 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan } } - if (!found) { return false; } - out.set (DataType::MIDI, midi_out); // currently always zero - out.set (DataType::AUDIO, audio_out); + if (exact_match) { + out.set (DataType::MIDI, midi_out); // currently always zero + out.set (DataType::AUDIO, preferred_out); + } else { + out.set (DataType::MIDI, midi_out); // currently always zero + out.set (DataType::AUDIO, audio_out); + } return true; } diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index e13328b97b..43a4901ca7 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -1934,7 +1934,7 @@ LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) c } Plugin::IOPortDescription -LV2Plugin::describe_io_port (ARDOUR::DataType dt, bool input, uint32_t id) +LV2Plugin::describe_io_port (ARDOUR::DataType dt, bool input, uint32_t id) const { PortFlags match = 0; switch (dt) { diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc index 61141301cb..babc3e441f 100644 --- a/libs/ardour/plugin.cc +++ b/libs/ardour/plugin.cc @@ -258,7 +258,7 @@ Plugin::input_streams () const } Plugin::IOPortDescription -Plugin::describe_io_port (ARDOUR::DataType dt, bool input, uint32_t id) +Plugin::describe_io_port (ARDOUR::DataType dt, bool input, uint32_t id) const { std::stringstream ss; switch (dt) { @@ -278,12 +278,22 @@ Plugin::describe_io_port (ARDOUR::DataType dt, bool input, uint32_t id) ss << _("Out") << " "; } - ss << id; + ss << (id + 1); Plugin::IOPortDescription iod (ss.str()); return iod; } +PluginOutputConfiguration +Plugin::possible_output () const +{ + PluginOutputConfiguration oc; + if (_info) { + oc.insert (_info->n_outputs.n_audio ()); + } + return oc; +} + const Plugin::PresetRecord * Plugin::preset_by_label (const string& label) { diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index 2005d5b2e2..646bf5e63a 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -159,6 +159,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) { @@ -1383,6 +1394,8 @@ PluginInsert::configure_io (ChanCount in, ChanCount out) 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); } @@ -1390,7 +1403,6 @@ PluginInsert::configure_io (ChanCount in, ChanCount out) ChanCount useins; bool const r = _plugins.front()->can_support_io_configuration (in, dout, &useins); assert (r); - assert (dout.n_audio() <= out.n_audio()); // sans midi bypass if (useins.n_audio() == 0) { useins = in; } @@ -1529,12 +1541,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(); @@ -1848,6 +1877,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"); @@ -2121,6 +2151,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()) { diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 51fc33a395..7ef2a62a24 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -2505,6 +2505,45 @@ Route::add_remove_sidechain (boost::shared_ptr proc, bool add) return true; } +bool +Route::plugin_preset_output (boost::shared_ptr proc, ChanCount outs) +{ + boost::shared_ptr pi; + if ((pi = boost::dynamic_pointer_cast(proc)) == 0) { + return false; + } + + { + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); + ProcessorList::iterator i = find (_processors.begin(), _processors.end(), proc); + if (i == _processors.end ()) { + return false; + } + } + + { + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); + + const ChanCount& old (pi->preset_out ()); + if (!pi->set_preset_out (outs)) { + return true; // no change, OK + } + + list > c = try_configure_processors_unlocked (n_inputs (), 0); + if (c.empty()) { + /* not possible */ + pi->set_preset_out (old); + return false; + } + configure_processors_unlocked (0); + } + + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + _session.set_dirty (); + return true; +} + bool Route::reset_plugin_insert (boost::shared_ptr proc) { -- 2.30.2