the return of VST support
[ardour.git] / gtk2_ardour / plugin_selector.cc
1 /*
2     Copyright (C) 2000 Paul Davis 
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
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <cstdio>
21 #include <lrdf.h>
22
23 #include <gtkmm/table.h>
24 #include <gtkmm/stock.h>
25 #include <gtkmm/button.h>
26 #include <gtkmm/notebook.h>
27
28 #include <ardour/plugin_manager.h>
29 #include <ardour/plugin.h>
30 #include <ardour/configuration.h>
31
32 #include "ardour_ui.h"
33 #include "plugin_selector.h"
34 #include "gui_thread.h"
35
36 #include "i18n.h"
37
38 using namespace ARDOUR;
39 using namespace PBD;
40 using namespace Gtk;
41
42 PluginSelector::PluginSelector (PluginManager *mgr)
43         : ArdourDialog (_("ardour: plugins"), true, false)
44 {
45         set_position (Gtk::WIN_POS_MOUSE);
46         set_name ("PluginSelectorWindow");
47         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
48
49         manager = mgr;
50         session = 0;
51         o_selected_plug = -1;
52         i_selected_plug = 0;
53
54         lmodel = Gtk::ListStore::create(lcols);
55         ladspa_display.set_model (lmodel);
56         ladspa_display.append_column (_("Available LADSPA Plugins"), lcols.name);
57         ladspa_display.append_column (_("Type"), lcols.type);
58         ladspa_display.append_column (_("# Inputs"),lcols.ins);
59         ladspa_display.append_column (_("# Outputs"), lcols.outs);
60         ladspa_display.set_headers_visible (true);
61         ladspa_display.set_reorderable (false);
62         lscroller.set_border_width(10);
63         lscroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
64         lscroller.add(ladspa_display);
65
66         amodel = Gtk::ListStore::create(acols);
67         added_list.set_model (amodel);
68         added_list.append_column (_("Plugins to be Connected to Insert"), acols.text);
69         added_list.set_headers_visible (true);
70         added_list.set_reorderable (false);
71
72         for (int i = 0; i <=3; i++) {
73                 Gtk::TreeView::Column* column = ladspa_display.get_column(i);
74                 column->set_sort_column(i);
75         }
76
77 #ifdef VST_SUPPORT
78         vmodel = ListStore::create(vcols);
79         vst_display.set_model (vmodel);
80         vst_display.append_column (_("Available plugins"), vcols.name);
81         vst_display.append_column (_("# Inputs"), vcols.ins);
82         vst_display.append_column (_("# Outputs"), vcols.outs);
83         vst_display.set_headers_visible (true);
84         vst_display.set_reorderable (false);
85         vscroller.set_border_width(10);
86         vscroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
87         vscroller.add(vst_display);
88
89         for (int i = 0; i <=2; i++) {
90                 Gtk::TreeView::Column* column = vst_display.get_column(i);
91                 column->set_sort_column(i);
92         }
93 #endif
94         ascroller.set_border_width(10);
95         ascroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
96         ascroller.add(added_list);
97         btn_add = manage(new Gtk::Button(Stock::ADD));
98         ARDOUR_UI::instance()->tooltips().set_tip(*btn_add, _("Add a plugin to the effect list"));
99         btn_add->set_sensitive (false);
100         btn_remove = manage(new Gtk::Button(Stock::REMOVE));
101         btn_remove->set_sensitive (false);
102         ARDOUR_UI::instance()->tooltips().set_tip(*btn_remove, _("Remove a plugin from the effect list"));
103         Gtk::Button *btn_update = manage(new Gtk::Button(Stock::REFRESH));
104         ARDOUR_UI::instance()->tooltips().set_tip(*btn_update, _("Update available plugins"));
105
106         btn_add->set_name("PluginSelectorButton");
107         btn_remove->set_name("PluginSelectorButton");
108
109         Gtk::Table* table = manage(new Gtk::Table(7, 10));
110         table->set_size_request(750, 500);
111         table->attach(notebook, 0, 7, 0, 5);
112
113         table->attach(*btn_add, 1, 2, 5, 6, Gtk::FILL, Gtk::FILL, 5, 5);
114         table->attach(*btn_remove, 3, 4, 5, 6, Gtk::FILL, Gtk::FILL, 5, 5);
115         table->attach(*btn_update, 5, 6, 5, 6, Gtk::FILL, Gtk::FILL, 5, 5);
116
117         table->attach(ascroller, 0, 7, 7, 9);
118
119         add_button (Stock::CANCEL, RESPONSE_CANCEL);
120         add_button (Stock::CONNECT, RESPONSE_APPLY);
121         set_default_response (RESPONSE_APPLY);
122         set_response_sensitive (RESPONSE_APPLY, false);
123         get_vbox()->pack_start (*table);
124
125         using namespace Gtk::Notebook_Helpers;
126         notebook.pages().push_back (TabElem (lscroller, _("LADSPA")));
127 #ifdef VST_SUPPORT
128         if (Config->get_use_vst()) {
129                 notebook.pages().push_back (TabElem (vscroller, _("VST")));
130         }
131 #endif
132
133         table->set_name("PluginSelectorTable");
134         ladspa_display.set_name("PluginSelectorDisplay");
135         //ladspa_display.set_name("PluginSelectorList");
136         added_list.set_name("PluginSelectorList");
137
138         ladspa_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked));
139 #ifdef VST_SUPPORT
140         if (Config->get_use_vst()) {
141                 vst_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked));
142                 vst_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::vst_display_selection_changed));
143         }
144 #endif
145         
146         btn_update->signal_clicked().connect (mem_fun(*this, &PluginSelector::btn_update_clicked));
147         btn_add->signal_clicked().connect(mem_fun(*this, &PluginSelector::btn_add_clicked));
148         btn_remove->signal_clicked().connect(mem_fun(*this, &PluginSelector::btn_remove_clicked));
149         ladspa_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::ladspa_display_selection_changed));
150         added_list.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::added_list_selection_changed));
151
152         input_refiller ();
153         vst_refiller ();
154 }
155
156 void
157 PluginSelector::row_clicked(GdkEventButton* event)
158 {
159         if (event->type == GDK_2BUTTON_PRESS)
160                 btn_add_clicked();
161 }
162
163 void
164 PluginSelector::set_session (Session* s)
165 {
166         ENSURE_GUI_THREAD(bind (mem_fun(*this, &PluginSelector::set_session), s));
167         
168         session = s;
169
170         if (session) {
171                 session->going_away.connect (bind (mem_fun(*this, &PluginSelector::set_session), static_cast<Session*> (0)));
172         }
173 }
174
175 void
176 PluginSelector::_input_refiller (void *arg)
177 {
178         ((PluginSelector *) arg)->input_refiller ();
179 }
180
181 int compare(const void *left, const void *right)
182 {
183   return strcmp(*((char**)left), *((char**)right));
184 }
185
186 void
187 PluginSelector::input_refiller ()
188 {
189         guint row;
190         list<PluginInfo *> &plugs = manager->ladspa_plugin_info ();
191         list<PluginInfo *>::iterator i;
192         char ibuf[16], obuf[16];
193         lmodel->clear();
194 #ifdef VST_SUPPORT
195         vmodel->clear();
196 #endif
197         // Insert into GTK list
198         for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) {
199                 snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs);
200                 snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs);         
201                 
202                 Gtk::TreeModel::Row newrow = *(lmodel->append());
203                 newrow[lcols.name] = (*i)->name.c_str();
204                 newrow[lcols.type] = (*i)->category.c_str();
205                 newrow[lcols.ins] = ibuf;
206                 newrow[lcols.outs] = obuf;
207                 newrow[lcols.plugin] = *i;
208         }
209
210         lmodel->set_sort_column (0, Gtk::SORT_ASCENDING);
211 }
212
213 #ifdef VST_SUPPORT
214
215 void
216 PluginSelector::_vst_refiller (void *arg)
217 {
218         ((PluginSelector *) arg)->vst_refiller ();
219 }
220
221 void
222 PluginSelector::vst_refiller ()
223 {
224         guint row;
225         list<PluginInfo *> &plugs = manager->vst_plugin_info ();
226         list<PluginInfo *>::iterator i;
227         char ibuf[16], obuf[16];
228         
229         // Insert into GTK list
230         for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) {
231
232                 snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs);
233                 snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs);         
234                 
235                 Gtk::TreeModel::Row newrow = *(vmodel->append());
236                 newrow[vcols.name] = (*i)->name.c_str();
237                 newrow[vcols.ins] = ibuf;
238                 newrow[vcols.outs] = obuf;
239                 newrow[vcols.plugin] = *i;
240         }
241         vmodel->set_sort_column (0, Gtk::SORT_ASCENDING);
242 }
243 #endif
244
245 void
246 PluginSelector::use_plugin (PluginInfo* pi)
247 {
248         list<PluginInfo *>::iterator i;
249
250         if (pi == 0 || session == 0) {
251                 return;
252         }
253
254         Plugin *plugin = manager->load (*session, pi);
255
256         if (plugin) {
257                 PluginCreated (plugin);
258         }
259 }
260
261 void
262 PluginSelector::btn_add_clicked()
263 {
264         bool vst = notebook.get_current_page(); // 0 = LADSPA, 1 = VST
265         std::string name;
266         ARDOUR::PluginInfo *pi;
267         Gtk::TreeModel::Row newrow = *(amodel->append());
268         
269         if (vst) {
270 #ifdef VST_SUPPORT
271                 Gtk::TreeModel::Row row = *(vst_display.get_selection()->get_selected());
272                 name = row[vcols.name];
273                 pi = row[vcols.plugin];
274                 added_plugins.push_back (row[vcols.plugin]);
275 #endif
276         } else {
277                 Gtk::TreeModel::Row row = *(ladspa_display.get_selection()->get_selected());
278                 name = row[lcols.name];
279                 pi = row[lcols.plugin];
280                 added_plugins.push_back (row[lcols.plugin]);
281         }
282         newrow[acols.text] = name;
283         newrow[acols.plugin] = pi;
284
285         if (!amodel->children().empty()) {
286           set_response_sensitive (RESPONSE_APPLY, true);
287         }
288 }
289
290 void
291 PluginSelector::btn_remove_clicked()
292 {
293         list<PluginInfo*>::iterator i;
294         Gtk::TreeModel::iterator iter = added_list.get_selection()->get_selected();
295         for (i = added_plugins.begin(); (*i) != (*iter)[acols.plugin]; ++i);
296
297         added_plugins.erase(i); 
298         amodel->erase(iter);
299         if (amodel->children().empty()) {
300           set_response_sensitive (RESPONSE_APPLY, false);
301         }
302
303
304 }
305
306 void
307 PluginSelector::btn_update_clicked()
308 {
309         manager->refresh ();
310         input_refiller ();
311         vst_refiller ();
312 }
313
314 #ifdef VST_SUPPORT
315 void
316 PluginSelector::vst_display_selection_changed()
317 {
318   if (vst_display.get_selection()->count_selected_rows() != 0) {
319     btn_add->set_sensitive (true);
320   } else {
321     btn_add->set_sensitive (false);
322   }
323 }
324 #endif
325
326 void
327 PluginSelector::ladspa_display_selection_changed()
328 {
329   if (ladspa_display.get_selection()->count_selected_rows() != 0) {
330     btn_add->set_sensitive (true);
331   } else {
332     btn_add->set_sensitive (false);
333   }
334 }
335
336 void
337 PluginSelector::added_list_selection_changed()
338 {
339   if (added_list.get_selection()->count_selected_rows() != 0) {
340     btn_remove->set_sensitive (true);
341   } else {
342     btn_remove->set_sensitive (false);
343   }
344 }
345
346 int
347 PluginSelector::run ()
348 {
349         ResponseType r;
350         list<PluginInfo*>::iterator i;
351
352         r = (ResponseType) Dialog::run ();
353
354         switch (r) {
355         case RESPONSE_APPLY:
356                 for (i = added_plugins.begin(); i != added_plugins.end(); ++i){
357                         use_plugin (*i);
358                 }
359                 break;
360
361         default:
362                 break;
363         }
364
365         cleanup ();
366
367         return (int) r;
368 }
369
370 void
371 PluginSelector::cleanup ()
372 {
373         hide();
374         added_plugins.clear();
375         amodel->clear();
376 }
377