1 /*
2  * Copyright (C) 2016-2018 Robin Gareus <robin@gareus.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #include "pbd/convert.h"
20 #include "pbd/enumwriter.h"
21 
22 #include "ardour/plugin_manager.h"
23 #include "gtkmm2ext/gui_thread.h"
24 
25 #include "instrument_selector.h"
26 
27 #include "pbd/i18n.h"
28 
29 using namespace Gtk;
30 using namespace ARDOUR;
31 
InstrumentSelector(bool allow_none)32 InstrumentSelector::InstrumentSelector (bool allow_none)
33 	: _reasonable_synth_id (0)
34 	, _gmsynth_id (UINT32_MAX)
35 	, _allow_none (allow_none)
36 {
37 	refill ();
38 
39 	PluginManager::instance ().PluginListChanged.connect (_update_connection, invalidator (*this), boost::bind (&InstrumentSelector::refill, this), gui_context());
40 }
41 
42 void
refill()43 InstrumentSelector::refill()
44 {
45 	TreeModel::iterator iter = get_active();
46 	std::string selected;
47 	if (iter) {
48 		const TreeModel::Row& row = (*iter);
49 		selected = row[_instrument_list_columns.name];
50 	}
51 
52 	unset_model ();
53 	clear ();
54 	build_instrument_list();
55 	set_model(_instrument_list);
56 	pack_start(_instrument_list_columns.name);
57 	if (selected.empty ()) {
58 		if (_gmsynth_id != UINT32_MAX) {
59 			set_active(_gmsynth_id);
60 		} else {
61 			set_active(_reasonable_synth_id);
62 		}
63 	} else {
64 		TreeModel::Children rows = _instrument_list->children();
65 		TreeModel::Children::iterator i;
66 		for (i = rows.begin(); i != rows.end(); ++i) {
67 			std::string cn = (*i)[_instrument_list_columns.name];
68 			if (cn == selected) {
69 				set_active(*i);
70 				break;
71 			}
72 		}
73 	}
74 	set_button_sensitivity(Gtk::SENSITIVITY_AUTO);
75 }
76 
77 static bool
pluginsort(const PluginInfoPtr & a,const PluginInfoPtr & b)78 pluginsort (const PluginInfoPtr& a, const PluginInfoPtr& b)
79 {
80 	return PBD::downcase(a->name) < PBD::downcase(b->name);
81 }
82 
83 static bool
invalid_instrument(PluginInfoPtr p)84 invalid_instrument (PluginInfoPtr p) {
85 	const PluginManager& manager = PluginManager::instance();
86 	if (manager.get_status(p) == PluginManager::Hidden) {
87 		return true;
88 	}
89 	if (manager.get_status(p) == PluginManager::Concealed) {
90 		return true;
91 	}
92 	return !p->is_instrument();
93 }
94 
95 void
build_instrument_list()96 InstrumentSelector::build_instrument_list()
97 {
98 	PluginManager& manager = PluginManager::instance();
99 
100 	PluginInfoList all_plugs;
101 	all_plugs.insert(all_plugs.end(), manager.ladspa_plugin_info().begin(), manager.ladspa_plugin_info().end());
102 	all_plugs.insert(all_plugs.end(), manager.lua_plugin_info().begin(), manager.lua_plugin_info().end());
103 	all_plugs.insert(all_plugs.end(), manager.lv2_plugin_info().begin(), manager.lv2_plugin_info().end());
104 #ifdef WINDOWS_VST_SUPPORT
105 	all_plugs.insert(all_plugs.end(), manager.windows_vst_plugin_info().begin(), manager.windows_vst_plugin_info().end());
106 #endif
107 #ifdef LXVST_SUPPORT
108 	all_plugs.insert(all_plugs.end(), manager.lxvst_plugin_info().begin(), manager.lxvst_plugin_info().end());
109 #endif
110 #ifdef MACVST_SUPPORT
111 	all_plugs.insert(all_plugs.end(), manager.mac_vst_plugin_info().begin(), manager.mac_vst_plugin_info().end());
112 #endif
113 #ifdef AUDIOUNIT_SUPPORT
114 	all_plugs.insert(all_plugs.end(), manager.au_plugin_info().begin(), manager.au_plugin_info().end());
115 #endif
116 #ifdef VST3_SUPPORT
117 	all_plugs.insert(all_plugs.end(), manager.vst3_plugin_info().begin(), manager.vst3_plugin_info().end());
118 #endif
119 
120 	all_plugs.remove_if (invalid_instrument);
121 	all_plugs.sort (pluginsort);
122 
123 	_instrument_list = ListStore::create(_instrument_list_columns);
124 
125 	if (_allow_none) {
126 		TreeModel::Row row = *(_instrument_list->append());
127 		row[_instrument_list_columns.info_ptr] = PluginInfoPtr();
128 		row[_instrument_list_columns.name]     = _("-none-");
129 	}
130 
131 	uint32_t n = _allow_none ? 1 : 0;
132 	std::string prev;
133 	for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i, ++n) {
134 		PluginInfoPtr p = *i;
135 
136 		std::string suffix;
137 
138 #ifdef MIXBUS
139 		uint32_t n_outs = p->max_configurable_ouputs ();
140 		if (n_outs > 2) {
141 			if (p->reconfigurable_io ()) {
142 				suffix = string_compose(_("\u2264 %1 outs"), n_outs);
143 			} else {
144 				suffix = string_compose(_("%1 outs"), n_outs);
145 			}
146 		}
147 #else
148 		if (p->multichannel_name_ambiguity) {
149 			uint32_t n_outs = p->max_configurable_ouputs ();
150 			if (n_outs > 2) {
151 				if (p->reconfigurable_io ()) {
152 					suffix = string_compose(_("\u2264 %1 outs"), n_outs);
153 				} else {
154 					suffix = string_compose(_("%1 outs"), n_outs);
155 				}
156 			} else if (n_outs == 2) {
157 				suffix = _("stereo");
158 			}
159 		}
160 #endif
161 
162 		if (p->plugintype_name_ambiguity) {
163 			std::string pt = PluginManager::plugin_type_name (p->type);
164 			if (!suffix.empty ()) {
165 				suffix += ", ";
166 			}
167 			suffix += pt;
168 		}
169 
170 		std::string name = p->name;
171 		if (!suffix.empty ()) {
172 			name += " (" + suffix + ")";
173 		}
174 
175 		TreeModel::Row row = *(_instrument_list->append());
176 		row[_instrument_list_columns.name] = name;
177 
178 		row[_instrument_list_columns.info_ptr] = p;
179 		if (p->unique_id == "https://community.ardour.org/node/7596") {
180 			_reasonable_synth_id = n;
181 		}
182 		if (p->unique_id == "http://gareus.org/oss/lv2/gmsynth") {
183 			_gmsynth_id = n;
184 		}
185 		prev = p->name;
186 	}
187 }
188 
189 PluginInfoPtr
selected_instrument() const190 InstrumentSelector::selected_instrument() const
191 {
192 	TreeModel::iterator iter = get_active();
193 	if (!iter) {
194 		return PluginInfoPtr();
195 	}
196 
197 	const TreeModel::Row& row = (*iter);
198 	return row[_instrument_list_columns.info_ptr];
199 }
200 
201 std::string
selected_instrument_name() const202 InstrumentSelector::selected_instrument_name () const
203 {
204 	PluginInfoPtr pip = selected_instrument ();
205 	if (!pip) {
206 		return "";
207 	}
208 	return pip->name;
209 }
210