diff --git a/gtk2_ardour/about.cc b/gtk2_ardour/about.cc index 2007f06749..771512f331 100644 --- a/gtk2_ardour/about.cc +++ b/gtk2_ardour/about.cc @@ -258,7 +258,8 @@ static const char* translators[] = { N_("Brazilian Portuguese:\n\tAlexander da Franca Fernandes \ \n\tChris Ross \n"), N_("Spanish:\n\t Alex Krohn \ -\n\tPablo Fernández \n"), +\n\tPablo Fernández \ +\n\tJuan Cruz Vardy Sabaté \n"), N_("Russian:\n\t Igor Blinov \ \n\tAleksandr Koltsov \ \n\tPetr Semiletov \ diff --git a/gtk2_ardour/plugin_pin_dialog.cc b/gtk2_ardour/plugin_pin_dialog.cc index fa62276515..7f4b8d132b 100644 --- a/gtk2_ardour/plugin_pin_dialog.cc +++ b/gtk2_ardour/plugin_pin_dialog.cc @@ -123,7 +123,7 @@ PluginPinWidget::PluginPinWidget (std::shared_ptr pi) _pm_size_group = SizeGroup::create (SIZE_GROUP_BOTH); _add_plugin.set_tweaks (ArdourButton::Square); _del_plugin.set_tweaks (ArdourButton::Square); - if (_pi->plugin (0)->get_info()->reconfigurable_io ()) { + if (_pi->plugin (0)->get_info()->reconfigurable_io () || _pi->plugin (0)->get_info()->variable_bus_layout ()) { _pm_size_group->add_widget (_add_input_audio); _pm_size_group->add_widget (_del_input_audio); _pm_size_group->add_widget (_add_input_midi); @@ -151,7 +151,7 @@ PluginPinWidget::PluginPinWidget (std::shared_ptr pi) /* left side */ tl->pack_start (_set_config, false, false); - if (_pi->plugin (0)->get_info()->reconfigurable_io ()) { + if (_pi->plugin (0)->get_info()->reconfigurable_io () || _pi->plugin (0)->get_info()->variable_bus_layout ()) { box = manage (new HBox ()); box->set_border_width (2); box->pack_start (_add_input_audio, true, false); diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h index bab471ddfa..0557c7cffd 100644 --- a/libs/ardour/ardour/plugin.h +++ b/libs/ardour/ardour/plugin.h @@ -315,6 +315,7 @@ public: virtual bool reconfigure_io (ChanCount /*in*/, ChanCount /*aux_in*/, ChanCount /*out*/) { return true; } virtual bool match_variable_io (ChanCount& /*in*/, ChanCount& /*aux_in*/, ChanCount& /*out*/) { return false; } + virtual void request_bus_layout (ChanCount const& /*in*/, ChanCount const& /*aux_in*/, ChanCount const& /*out*/) { } virtual ChanCount output_streams () const; virtual ChanCount input_streams () const; @@ -532,6 +533,11 @@ public: /* @return true if the plugin can change its inputs or outputs on demand. */ virtual bool reconfigurable_io () const { return false; } + /* @return true if the plugin has configurable busses but no AU style reconfigureable I/O (VST3) + * implies request_bus_layout () + */ + virtual bool variable_bus_layout () const { return false; } + /* max [re]configurable outputs (if finite, 0 otherwise) */ virtual uint32_t max_configurable_outputs () const { diff --git a/libs/ardour/ardour/vst3_plugin.h b/libs/ardour/ardour/vst3_plugin.h index 77facaa43b..2ea28375ad 100644 --- a/libs/ardour/ardour/vst3_plugin.h +++ b/libs/ardour/ardour/vst3_plugin.h @@ -202,6 +202,7 @@ public: void set_owner (ARDOUR::SessionObject* o); void set_non_realtime (bool); + void request_bus_layout (uint32_t main_in, uint32_t aux_in, uint32_t main_out); void enable_io (std::vector const&, std::vector const&, bool force = false); void process (float** ins, float** outs, uint32_t n_samples); @@ -242,8 +243,10 @@ private: bool disconnect_components (); bool update_processor (); + void query_io_config (); int32 count_channels (Vst::MediaType, Vst::BusDirection, Vst::BusType); + bool evoral_to_vst3 (Vst::Event&, Evoral::Event const&, int32_t); void update_shadow_data (); @@ -403,6 +406,12 @@ public: IOPortDescription describe_io_port (DataType dt, bool input, uint32_t id) const; PluginOutputConfiguration possible_output () const; + void request_bus_layout (ChanCount const& /*in*/, ChanCount const& /*aux_in*/, ChanCount const& /*out*/); + bool reconfigure_io (ChanCount /*in*/, ChanCount /*aux_in*/, ChanCount /*out*/); + + ChanCount output_streams () const; + ChanCount input_streams () const; + void set_automation_control (uint32_t, std::shared_ptr); std::string state_node_name () const @@ -487,6 +496,8 @@ public: bool is_instrument () const; PBD::Searchpath preset_search_path () const; + bool variable_bus_layout () const { return true; } + std::optional has_editor; std::shared_ptr m; diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index ebeea2d71e..e0d92f4331 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -46,6 +46,7 @@ #include "ardour/port.h" #include "ardour/session.h" #include "ardour/types.h" +#include "ardour/vst3_plugin.h" #include "pbd/i18n.h" @@ -2100,6 +2101,10 @@ PluginInsert::configure_io (ChanCount in, ChanCount out) /* NB. When resolving impossible matches, "replicate 1 time" is valid. * e.g. add a MIDI filter (1 MIDI in, 1 MIDI out) after some audio plugin */ assert (!_plugins.front()->get_info()->reconfigurable_io ()); + /* VST3 */ + for (auto const& p : _plugins) { + p->reconfigure_io (natural_input_streams (), aux_in, natural_output_streams ()); + } break; default: @@ -2260,6 +2265,24 @@ PluginInsert::configure_io (ChanCount in, ChanCount out) bool PluginInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) { + if (plugin()->get_info ()->variable_bus_layout ()) { + ChanCount input_streams = natural_input_streams (); + ChanCount sc; + if (_sidechain) { + _sidechain->can_support_io_configuration (sc, sc); + } + for (auto const& p : _plugins) { + if (_custom_cfg) { + p->request_bus_layout (_custom_sinks, sc, _custom_sinks); + } else { + p->request_bus_layout (in, sc, in); + } + } + if (input_streams != natural_input_streams ()) { + mapping_changed (); + } + } + if (_sidechain) { _sidechain->can_support_io_configuration (in, out); // never fails, sets "out" } diff --git a/libs/ardour/region_fx_plugin.cc b/libs/ardour/region_fx_plugin.cc index 431cf1f011..87c5b59de4 100644 --- a/libs/ardour/region_fx_plugin.cc +++ b/libs/ardour/region_fx_plugin.cc @@ -32,6 +32,7 @@ #include "ardour/readonly_control.h" #include "ardour/region_fx_plugin.h" #include "ardour/session.h" +#include "ardour/vst3_plugin.h" using namespace std; using namespace ARDOUR; @@ -835,6 +836,12 @@ RegionFxPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& ou out = ChanCount::min (in, out); return true; } + if (plugin()->get_info ()->variable_bus_layout ()) { + ChanCount sc; + for (auto const& p : _plugins) { + p->request_bus_layout (in, sc, in); + } + } return private_can_support_io_configuration (in, out).method != Impossible; } diff --git a/libs/ardour/vst3_plugin.cc b/libs/ardour/vst3_plugin.cc index c881cdad92..a97cf5cbbc 100644 --- a/libs/ardour/vst3_plugin.cc +++ b/libs/ardour/vst3_plugin.cc @@ -16,13 +16,16 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#ifdef WAF_BUILD +#include "libardour-config.h" +#endif + #include #include "pbd/gstdio_compat.h" #include #include "pbd/basename.h" -#include "pbd/compose.h" #include "pbd/convert.h" #include "pbd/debug.h" #include "pbd/error.h" @@ -98,22 +101,6 @@ VST3Plugin::init () _plug->OnResizeView.connect_same_thread (_connections, std::bind (&VST3Plugin::forward_resize_view, this, _1, _2)); _plug->OnParameterChange.connect_same_thread (_connections, std::bind (&VST3Plugin::parameter_change_handler, this, _1, _2, _3)); _plug->OnProcessorChange.connect_same_thread (_connections, [&](ARDOUR::RouteProcessorChange const& rpc) { Plugin::send_processors_changed (rpc); }); - - /* assume only default active busses are connected */ - for (auto const& abi : _plug->bus_info_in ()) { - for (int32_t i = 0; i < abi.second.n_chn; ++i) { - _connected_inputs.push_back (abi.second.dflt); - } - } - - for (auto const& abi : _plug->bus_info_out ()) { - for (int32_t i = 0; i < abi.second.n_chn; ++i) { - _connected_outputs.push_back (abi.second.dflt); - } - } - - /* pre-configure from GUI thread */ - _plug->enable_io (_connected_inputs, _connected_outputs, true); } void @@ -337,6 +324,47 @@ VST3Plugin::possible_output () const #endif } +ChanCount +VST3Plugin::input_streams () const +{ + ChanCount cc; + cc.set_audio (_plug->n_audio_inputs (true)); + cc.set_midi (_plug->n_midi_inputs ()); + return cc; +} + +ChanCount +VST3Plugin::output_streams () const +{ + ChanCount cc; + cc.set_audio (_plug->n_audio_outputs (true)); + cc.set_midi (_plug->n_midi_outputs ()); + return cc; +} + +void +VST3Plugin::request_bus_layout (ChanCount const& in, ChanCount const& aux_in, ChanCount const& out) +{ + _plug->request_bus_layout (in.n_audio (), aux_in.n_audio (), out.n_audio ()); +} + +bool +VST3Plugin::reconfigure_io (ChanCount in, ChanCount aux_in, ChanCount out) +{ + _connected_inputs.clear (); + _connected_inputs.resize (in.n_audio () + aux_in.n_audio ()); + _connected_inputs.flip (); + + _connected_outputs.clear (); + _connected_outputs.resize (out.n_audio ()); + _connected_outputs.flip (); + + DEBUG_TRACE (DEBUG::VST3Config, string_compose ("VST3Plugin::reconfigure_io %1 %2 %3\n", in, aux_in, out)); + + _plug->enable_io (_connected_inputs, _connected_outputs); + return true; +} + /* **************************************************************************** * Plugin UI */ @@ -838,7 +866,7 @@ VST3Plugin::connect_and_run (BufferSet& bufs, } } - _plug->enable_io (_connected_inputs, _connected_outputs); + //_plug->enable_io (_connected_inputs, _connected_outputs); // XXX _plug->process (ins, outs, n_samples); @@ -1303,13 +1331,13 @@ VST3PI::VST3PI (std::shared_ptr m, std::string unique_ _busbuf_in.resize (_n_bus_in); _busbuf_out.resize (_n_bus_out); - /* do not re-order, _io_name is build in sequence */ - _n_inputs = count_channels (Vst::kAudio, Vst::kInput, Vst::kMain); - _n_aux_inputs = count_channels (Vst::kAudio, Vst::kInput, Vst::kAux); - _n_outputs = count_channels (Vst::kAudio, Vst::kOutput, Vst::kMain); - _n_aux_outputs = count_channels (Vst::kAudio, Vst::kOutput, Vst::kAux); - _n_midi_inputs = count_channels (Vst::kEvent, Vst::kInput, Vst::kMain); - _n_midi_outputs = count_channels (Vst::kEvent, Vst::kOutput, Vst::kMain); + query_io_config (); + + if (n_audio_inputs () == 0 && n_audio_outputs () == 0 && n_midi_inputs () == 0 && n_midi_outputs () == 0) { + /* see also vst3_scan discover_vst3 -- assume stereo by default */ + request_bus_layout (2, 0, 2); + query_io_config (); + } if (!connect_components ()) { //_controller->terminate(); // XXX ? @@ -1547,6 +1575,26 @@ VST3PI::queryInterface (const TUID _iid, void** obj) return kNoInterface; } +void +VST3PI::query_io_config () +{ + _io_name[Vst::kAudio][Vst::kInput].clear (); + _io_name[Vst::kAudio][Vst::kOutput].clear (); + _io_name[Vst::kEvent][Vst::kInput].clear (); + _io_name[Vst::kEvent][Vst::kOutput].clear (); + _bus_info_in.clear (); + _bus_info_out.clear (); + + /* do not re-order, _io_name is build in sequence */ + _n_inputs = count_channels (Vst::kAudio, Vst::kInput, Vst::kMain); + _n_aux_inputs = count_channels (Vst::kAudio, Vst::kInput, Vst::kAux); + _n_outputs = count_channels (Vst::kAudio, Vst::kOutput, Vst::kMain); + _n_aux_outputs = count_channels (Vst::kAudio, Vst::kOutput, Vst::kAux); + _n_midi_inputs = count_channels (Vst::kEvent, Vst::kInput, Vst::kMain); + _n_midi_outputs = count_channels (Vst::kEvent, Vst::kOutput, Vst::kMain); + +} + tresult VST3PI::restartComponent (int32 flags) { @@ -2253,6 +2301,72 @@ VST3PI::set_event_bus_state (bool enable) } } +void +VST3PI::request_bus_layout (uint32_t in, uint32_t aux_in, uint32_t out) +{ + // TODO only if changed .. and if plugin doesn't have defaults + + DEBUG_TRACE (DEBUG::VST3Config, string_compose ("VST3PI::request_bus_layout: in = %1 aux-in = %2 out = %3\n", in, aux_in, out)); + + bool was_active = _is_processing; + if (!deactivate ()) { + DEBUG_TRACE (DEBUG::VST3Config, "VST3PI::request_bus_layout failed to deactivate plugin\n"); + } + + typedef std::vector VSTSpeakerArrangements; + VSTSpeakerArrangements sa_in; + VSTSpeakerArrangements sa_out; + + Vst::SpeakerArrangement sa = ((uint64_t)1 << in) - 1; + if (in == 1 /*Vst::SpeakerArr::kSpeakerL */ && !_no_kMono) { + sa = Vst::SpeakerArr::kMono; /* 1 << 19 */ + } + + if (_n_bus_in > 0) { + sa_in.push_back (sa); + } + + sa = ((uint64_t)1 << out) - 1; + if (out == 1 /*Vst::SpeakerArr::kSpeakerL */ && !_no_kMono) { + sa = Vst::SpeakerArr::kMono; /* 1 << 19 */ + } + + if (_n_bus_out > 0) { + sa_out.push_back (sa); + } + + sa = ((uint64_t)1 << aux_in) - 1; + + if (_n_bus_in > 1) { + sa_in.push_back (sa); + } + + sa = 0; + while (sa_in.size () < (VSTSpeakerArrangements::size_type) _n_bus_in) { + sa_in.push_back (sa); + } + + while (sa_out.size () < (VSTSpeakerArrangements::size_type) _n_bus_out) { + sa_out.push_back (sa); + } + + Vst::SpeakerArrangement null_arrangement = {}; +#ifndef NDEBUG + tresult rv = +#endif + _processor->setBusArrangements (sa_in.size () > 0 ? &sa_in[0] : &null_arrangement, sa_in.size (), + sa_out.size () > 0 ? &sa_out[0] : &null_arrangement, sa_out.size ()); + + DEBUG_TRACE (DEBUG::VST3Config, string_compose ("VST3PI::request_bus_layout setBusArrangements ins = %1 outs = %2 | rv = %3\n", sa_in.size (), sa_out.size (), rv)); + + query_io_config (); + + if (was_active) { + activate (); + } + +} + void VST3PI::enable_io (std::vector const& ins, std::vector const& outs, bool force) { @@ -2273,8 +2387,8 @@ VST3PI::enable_io (std::vector const& ins, std::vector const& outs, _enabled_audio_in = ins; _enabled_audio_out = outs; - assert (_enabled_audio_in.size () == n_audio_inputs ()); - assert (_enabled_audio_out.size () == n_audio_outputs ()); + //assert (_enabled_audio_in.size () == n_audio_inputs ()); + //assert (_enabled_audio_out.size () == n_audio_outputs ()); /* check that settings have not changed */ assert (_n_bus_in == _component->getBusCount (Vst::kAudio, Vst::kInput)); assert (_n_bus_out == _component->getBusCount (Vst::kAudio, Vst::kOutput)); diff --git a/libs/ardour/vst3_scan.cc b/libs/ardour/vst3_scan.cc index ed8a62fa45..919ef92ba2 100644 --- a/libs/ardour/vst3_scan.cc +++ b/libs/ardour/vst3_scan.cc @@ -74,7 +74,7 @@ static const char* fmt_type (Vst::BusType t) { } static int32 -count_channels (Vst::IComponent* c, Vst::MediaType media, Vst::BusDirection dir, Vst::BusType type, bool verbose = false) +count_channels (Vst::IComponent* c, Vst::MediaType media, Vst::BusDirection dir, Vst::BusType type, bool verbose = false, bool can_fail = true) { /* see also libs/ardour/vst3_plugin.cc VST3PI::count_channels */ int32 n_busses = c->getBusCount (media, dir); @@ -100,13 +100,57 @@ count_channels (Vst::IComponent* c, Vst::MediaType media, Vst::BusDirection dir, } else { n_channels += bus.channelCount; } - } else if (verbose && rv != kResultTrue) { - PBD::info << "VST3: \\ error getting busInfo for bus: " << i << " rv: " << rv << ", got type: " << fmt_type (bus.busType) << endmsg; + } else if (rv != kResultTrue) { + if (verbose) { + PBD::info << "VST3: \\ error getting busInfo for bus: " << i << " rv: " << rv << ", got type: " << fmt_type (bus.busType) << endmsg; + } + if (!can_fail) { + return -1; + } } } return n_channels; } +static bool +count_all_count_channels (ARDOUR::VST3Info& nfo, Vst::IComponent* c, bool verbose, bool require_result) +{ + nfo.n_inputs = count_channels (c, Vst::kAudio, Vst::kInput, Vst::kMain, verbose, require_result); + nfo.n_aux_inputs = count_channels (c, Vst::kAudio, Vst::kInput, Vst::kAux, verbose); + nfo.n_outputs = count_channels (c, Vst::kAudio, Vst::kOutput, Vst::kMain, verbose, require_result); + nfo.n_aux_outputs = count_channels (c, Vst::kAudio, Vst::kOutput, Vst::kAux, verbose); + nfo.n_midi_inputs = count_channels (c, Vst::kEvent, Vst::kInput, Vst::kMain, verbose); + nfo.n_midi_outputs = count_channels (c, Vst::kEvent, Vst::kOutput, Vst::kMain, verbose); + + return nfo.n_inputs < 0 || nfo.n_outputs < 0; +} + +static void +set_speaker_arrangement (Vst::IComponent* c, IPtr p) +{ + Vst::SpeakerArrangement null_arrangement = {}; + typedef std::vector VSTSpeakerArrangements; + VSTSpeakerArrangements sa_in; + VSTSpeakerArrangements sa_out; + + /* assume stereo by default */ + int n_bus_in = c->getBusCount (Vst::kAudio, Vst::kInput); + int n_bus_out = c->getBusCount (Vst::kAudio, Vst::kOutput); + + while (sa_in.size () < (VSTSpeakerArrangements::size_type) n_bus_in) { + Vst::SpeakerArrangement sa = Vst::SpeakerArr::kStereo; + sa_in.push_back (sa); + } + while (sa_out.size () < (VSTSpeakerArrangements::size_type) n_bus_out) { + Vst::SpeakerArrangement sa = Vst::SpeakerArr::kStereo; + sa_out.push_back (sa); + } + + p->setBusArrangements (sa_in.size () > 0 ? &sa_in[0] : &null_arrangement, sa_in.size (), + sa_out.size () > 0 ? &sa_out[0] : &null_arrangement, sa_out.size ()); + +} + static bool discover_vst3 (std::shared_ptr m, std::vector& rv, bool verbose) { @@ -209,12 +253,12 @@ discover_vst3 (std::shared_ptr m, std::vectorsetProcessing (false); component->setActive (false);