Robin Gareus
b8551eed7e
The InstrumentSelector keeps a PluginPtr reference to all instruments. By default Ardour does not destroy the editor at exit, So 3 instances of Instrument Selector can remain * TriggerClipPicker in the editor sidebar (owned by _editor) * TriggerClipPicker on the TriggerPage (owned by trigger_page) * SoundFileOmega (sfbrowser owned by Editor) If a shared_ptr reference is retained, VST3 Module is not unloaded at exit. This leads to issues with various plugins. eg. Reason Rack does not terminate, Ardour hangs at exit.
227 lines
6.2 KiB
C++
227 lines
6.2 KiB
C++
/*
|
|
* Copyright (C) 2016-2018 Robin Gareus <robin@gareus.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "pbd/convert.h"
|
|
#include "pbd/enumwriter.h"
|
|
|
|
#include "ardour/plugin_manager.h"
|
|
#include "gtkmm2ext/gui_thread.h"
|
|
|
|
#include "instrument_selector.h"
|
|
|
|
#include "pbd/i18n.h"
|
|
|
|
using namespace Gtk;
|
|
using namespace ARDOUR;
|
|
|
|
sigc::signal<void> InstrumentSelector::DropPluginInfoPtr;
|
|
|
|
InstrumentSelector::InstrumentSelector (InstrumentListDisposition disp)
|
|
: _reasonable_synth_id (0)
|
|
, _gmsynth_id (UINT32_MAX)
|
|
, _disposition (disp)
|
|
{
|
|
refill ();
|
|
|
|
PluginManager::instance ().PluginListChanged.connect (_update_connection, invalidator (*this), boost::bind (&InstrumentSelector::refill, this), gui_context());
|
|
DropPluginInfoPtr.connect (sigc::mem_fun (*this, &InstrumentSelector::drop_plugin_ptr));
|
|
}
|
|
|
|
void
|
|
InstrumentSelector::drop_plugin_ptr()
|
|
{
|
|
unset_model ();
|
|
clear ();
|
|
_instrument_list->clear ();
|
|
}
|
|
|
|
void
|
|
InstrumentSelector::refill()
|
|
{
|
|
TreeModel::iterator iter = get_active();
|
|
std::string selected;
|
|
if (iter) {
|
|
const TreeModel::Row& row = (*iter);
|
|
selected = row[_instrument_list_columns.name];
|
|
}
|
|
|
|
unset_model ();
|
|
clear ();
|
|
build_instrument_list();
|
|
set_model(_instrument_list);
|
|
pack_start(_instrument_list_columns.name);
|
|
if (selected.empty ()) {
|
|
if (_gmsynth_id != UINT32_MAX) {
|
|
set_active(_gmsynth_id);
|
|
} else {
|
|
set_active(_reasonable_synth_id);
|
|
}
|
|
} else {
|
|
TreeModel::Children rows = _instrument_list->children();
|
|
TreeModel::Children::iterator i;
|
|
for (i = rows.begin(); i != rows.end(); ++i) {
|
|
std::string cn = (*i)[_instrument_list_columns.name];
|
|
if (cn == selected) {
|
|
set_active(*i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
set_button_sensitivity(Gtk::SENSITIVITY_AUTO);
|
|
}
|
|
|
|
static bool
|
|
pluginsort (const PluginInfoPtr& a, const PluginInfoPtr& b)
|
|
{
|
|
return PBD::downcase(a->name) < PBD::downcase(b->name);
|
|
}
|
|
|
|
static bool
|
|
invalid_instrument (PluginInfoPtr p) {
|
|
const PluginManager& manager = PluginManager::instance();
|
|
if (manager.get_status(p) == PluginManager::Hidden) {
|
|
return true;
|
|
}
|
|
if (manager.get_status(p) == PluginManager::Concealed) {
|
|
return true;
|
|
}
|
|
return !p->is_instrument();
|
|
}
|
|
|
|
void
|
|
InstrumentSelector::build_instrument_list()
|
|
{
|
|
PluginManager& manager = PluginManager::instance();
|
|
|
|
PluginInfoList all_plugs;
|
|
all_plugs.insert(all_plugs.end(), manager.ladspa_plugin_info().begin(), manager.ladspa_plugin_info().end());
|
|
all_plugs.insert(all_plugs.end(), manager.lua_plugin_info().begin(), manager.lua_plugin_info().end());
|
|
all_plugs.insert(all_plugs.end(), manager.lv2_plugin_info().begin(), manager.lv2_plugin_info().end());
|
|
#ifdef WINDOWS_VST_SUPPORT
|
|
all_plugs.insert(all_plugs.end(), manager.windows_vst_plugin_info().begin(), manager.windows_vst_plugin_info().end());
|
|
#endif
|
|
#ifdef LXVST_SUPPORT
|
|
all_plugs.insert(all_plugs.end(), manager.lxvst_plugin_info().begin(), manager.lxvst_plugin_info().end());
|
|
#endif
|
|
#ifdef MACVST_SUPPORT
|
|
all_plugs.insert(all_plugs.end(), manager.mac_vst_plugin_info().begin(), manager.mac_vst_plugin_info().end());
|
|
#endif
|
|
#ifdef AUDIOUNIT_SUPPORT
|
|
all_plugs.insert(all_plugs.end(), manager.au_plugin_info().begin(), manager.au_plugin_info().end());
|
|
#endif
|
|
#ifdef VST3_SUPPORT
|
|
all_plugs.insert(all_plugs.end(), manager.vst3_plugin_info().begin(), manager.vst3_plugin_info().end());
|
|
#endif
|
|
|
|
all_plugs.remove_if (invalid_instrument);
|
|
all_plugs.sort (pluginsort);
|
|
|
|
_instrument_list = ListStore::create(_instrument_list_columns);
|
|
|
|
if (_disposition==ForTrackSelector) {
|
|
TreeModel::Row row = *(_instrument_list->append());
|
|
row[_instrument_list_columns.info_ptr] = PluginInfoPtr();
|
|
row[_instrument_list_columns.name] = _("-none-");
|
|
}
|
|
|
|
_longest_instrument_name = "";
|
|
|
|
uint32_t n = (_disposition==ForTrackSelector) ? 1 : 0;
|
|
std::string prev;
|
|
for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i, ++n) {
|
|
PluginInfoPtr p = *i;
|
|
|
|
if (p->name.length() > _longest_instrument_name.length()) {
|
|
_longest_instrument_name = p->name;
|
|
}
|
|
|
|
std::string suffix;
|
|
|
|
#ifdef MIXBUS
|
|
uint32_t n_outs = p->max_configurable_outputs ();
|
|
if (n_outs > 2) {
|
|
if (p->reconfigurable_io ()) {
|
|
suffix = string_compose(_(u8"\u2264 %1 outs"), n_outs);
|
|
} else {
|
|
suffix = string_compose(_("%1 outs"), n_outs);
|
|
}
|
|
}
|
|
#else
|
|
if (p->multichannel_name_ambiguity) {
|
|
uint32_t n_outs = p->max_configurable_outputs ();
|
|
if (n_outs > 2) {
|
|
if (p->reconfigurable_io ()) {
|
|
suffix = string_compose(_(u8"\u2264 %1 outs"), n_outs);
|
|
} else {
|
|
suffix = string_compose(_("%1 outs"), n_outs);
|
|
}
|
|
} else if (n_outs == 2) {
|
|
suffix = _("stereo");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (p->plugintype_name_ambiguity) {
|
|
std::string pt = PluginManager::plugin_type_name (p->type);
|
|
if (!suffix.empty ()) {
|
|
suffix += ", ";
|
|
}
|
|
suffix += pt;
|
|
}
|
|
|
|
std::string name = p->name;
|
|
if (!suffix.empty ()) {
|
|
name += " (" + suffix + ")";
|
|
}
|
|
|
|
TreeModel::Row row = *(_instrument_list->append());
|
|
row[_instrument_list_columns.name] = name;
|
|
|
|
row[_instrument_list_columns.info_ptr] = p;
|
|
if (p->unique_id == "https://community.ardour.org/node/7596") {
|
|
_reasonable_synth_id = n;
|
|
}
|
|
if (p->unique_id == "http://gareus.org/oss/lv2/gmsynth") {
|
|
_gmsynth_id = n;
|
|
}
|
|
prev = p->name;
|
|
}
|
|
}
|
|
|
|
PluginInfoPtr
|
|
InstrumentSelector::selected_instrument() const
|
|
{
|
|
TreeModel::iterator iter = get_active();
|
|
if (!iter) {
|
|
return PluginInfoPtr();
|
|
}
|
|
|
|
const TreeModel::Row& row = (*iter);
|
|
return row[_instrument_list_columns.info_ptr];
|
|
}
|
|
|
|
std::string
|
|
InstrumentSelector::selected_instrument_name () const
|
|
{
|
|
PluginInfoPtr pip = selected_instrument ();
|
|
if (!pip) {
|
|
return "";
|
|
}
|
|
return pip->name;
|
|
}
|