db63c285f18802336a3d61068f6530e805c546e1
[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 #ifdef VST_SUPPORT
154         vst_refiller ();
155 #endif
156 }
157
158 void
159 PluginSelector::row_clicked(GdkEventButton* event)
160 {
161         if (event->type == GDK_2BUTTON_PRESS)
162                 btn_add_clicked();
163 }
164
165 void
166 PluginSelector::set_session (Session* s)
167 {
168         ENSURE_GUI_THREAD(bind (mem_fun(*this, &PluginSelector::set_session), s));
169         
170         session = s;
171
172         if (session) {
173                 session->going_away.connect (bind (mem_fun(*this, &PluginSelector::set_session), static_cast<Session*> (0)));
174         }
175 }
176
177 void
178 PluginSelector::_input_refiller (void *arg)
179 {
180         ((PluginSelector *) arg)->input_refiller ();
181 }
182
183 int compare(const void *left, const void *right)
184 {
185   return strcmp(*((char**)left), *((char**)right));
186 }
187
188 void
189 PluginSelector::input_refiller ()
190 {
191         guint row;
192         list<PluginInfo *> &plugs = manager->ladspa_plugin_info ();
193         list<PluginInfo *>::iterator i;
194         char ibuf[16], obuf[16];
195         lmodel->clear();
196 #ifdef VST_SUPPORT
197         vmodel->clear();
198 #endif
199
200 #ifdef HAVE_COREAUDIO
201         aumodel->clear();
202 #endif
203         // Insert into GTK list
204         for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) {
205                 snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs);
206                 snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs);         
207                 
208                 Gtk::TreeModel::Row newrow = *(lmodel->append());
209                 newrow[lcols.name] = (*i)->name.c_str();
210                 newrow[lcols.type] = (*i)->category.c_str();
211                 newrow[lcols.ins] = ibuf;
212                 newrow[lcols.outs] = obuf;
213                 newrow[lcols.plugin] = *i;
214         }
215
216         lmodel->set_sort_column (0, Gtk::SORT_ASCENDING);
217 }
218
219 #ifdef VST_SUPPORT
220
221 void
222 PluginSelector::_vst_refiller (void *arg)
223 {
224         ((PluginSelector *) arg)->vst_refiller ();
225 }
226
227 void
228 PluginSelector::vst_refiller ()
229 {
230         guint row;
231         list<PluginInfo *> &plugs = manager->vst_plugin_info ();
232         list<PluginInfo *>::iterator i;
233         char ibuf[16], obuf[16];
234         
235         // Insert into GTK list
236         for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) {
237
238                 snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs);
239                 snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs);         
240                 
241                 Gtk::TreeModel::Row newrow = *(vmodel->append());
242                 newrow[vcols.name] = (*i)->name.c_str();
243                 newrow[vcols.ins] = ibuf;
244                 newrow[vcols.outs] = obuf;
245                 newrow[vcols.plugin] = *i;
246         }
247         vmodel->set_sort_column (0, Gtk::SORT_ASCENDING);
248 }
249 #endif //VST_SUPPORT
250
251 #ifdef HAVE_COREAUDIO
252
253 void
254 PluginSelector::_au_refiller (void *arg)
255 {
256         ((PluginSelector *) arg)->au_refiller ();
257 }
258
259 void
260 PluginSelector::au_refiller ()
261 {
262         guint row;
263 //      list<PluginInfo *> &plugs = manager->au_plugin_info ();
264         list<PluginInfo *> &plugs;
265         list<PluginInfo *>::iterator i;
266         char ibuf[16], obuf[16];
267         
268         // Insert into GTK list
269         for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) {
270
271                 snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs);
272                 snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs);         
273                 
274                 Gtk::TreeModel::Row newrow = *(amodel->append());
275                 newrow[acols.name] = (*i)->name.c_str();
276                 newrow[acols.ins] = ibuf;
277                 newrow[acols.outs] = obuf;
278                 newrow[acols.plugin] = *i;
279         }
280         amodel->set_sort_column (0, Gtk::SORT_ASCENDING);
281 }
282 #endif //HAVE_COREAUDIO
283
284 void
285 PluginSelector::use_plugin (PluginInfo* pi)
286 {
287         list<PluginInfo *>::iterator i;
288
289         if (pi == 0 || session == 0) {
290                 return;
291         }
292
293         boost::shared_ptr<Plugin> plugin = manager->load (*session, pi);
294
295         if (plugin) {
296                 PluginCreated (plugin);
297         }
298 }
299
300 void
301 PluginSelector::btn_add_clicked()
302 {
303         // 0 = LADSPA, 1 = VST, 2 = AU
304         unsigned int page = notebook.get_current_page(); 
305         std::string name;
306         ARDOUR::PluginInfo *pi;
307         Gtk::TreeModel::Row newrow = *(amodel->append());
308         
309         Gtk::TreeModel::Row row;
310
311         switch (page) {
312                 case 0:
313                         row = *(ladspa_display.get_selection()->get_selected());
314                         name = row[lcols.name];
315                         pi = row[lcols.plugin];
316                         added_plugins.push_back (row[lcols.plugin]);
317                         break;
318                 case 1:
319 #ifdef VST_SUPPORT
320                         row = *(vst_display.get_selection()->get_selected());
321                         name = row[vcols.name];
322                         pi = row[vcols.plugin];
323                         added_plugins.push_back (row[vcols.plugin]);
324 #endif
325                         break;
326                 case 2:
327 #ifdef HAVE_COREAUDIO
328                         row = *(au_display.get_selection()->get_selected());
329                         name = row[aucols.name];
330                         pi = row[aucols.plugin];
331                         added_plugins.push_back (row[aucols.plugin]);
332 #endif
333                         break;
334         }
335
336         newrow[acols.text] = name;
337         newrow[acols.plugin] = pi;
338
339         if (!amodel->children().empty()) {
340                 set_response_sensitive (RESPONSE_APPLY, true);
341         }
342 }
343
344 void
345 PluginSelector::btn_remove_clicked()
346 {
347         list<PluginInfo*>::iterator i;
348         Gtk::TreeModel::iterator iter = added_list.get_selection()->get_selected();
349         for (i = added_plugins.begin(); (*i) != (*iter)[acols.plugin]; ++i);
350
351         added_plugins.erase(i); 
352         amodel->erase(iter);
353         if (amodel->children().empty()) {
354           set_response_sensitive (RESPONSE_APPLY, false);
355         }
356
357
358 }
359
360 void
361 PluginSelector::btn_update_clicked()
362 {
363         manager->refresh ();
364         input_refiller ();
365 #ifdef VST_SUPPORT
366         vst_refiller ();
367 #endif  
368 #ifdef HAVE_COREAUDIO
369 //      au_refiller ();
370 #endif
371 }
372
373 #ifdef VST_SUPPORT
374 void
375 PluginSelector::vst_display_selection_changed()
376 {
377   if (vst_display.get_selection()->count_selected_rows() != 0) {
378     btn_add->set_sensitive (true);
379   } else {
380     btn_add->set_sensitive (false);
381   }
382 }
383 #endif
384
385 #ifdef HAVE_COREAUDIO
386 void
387 PluginSelector::vst_display_selection_changed()
388 {
389   if (au_display.get_selection()->count_selected_rows() != 0) {
390     btn_add->set_sensitive (true);
391   } else {
392     btn_add->set_sensitive (false);
393   }
394 }
395 #endif
396
397 void
398 PluginSelector::ladspa_display_selection_changed()
399 {
400   if (ladspa_display.get_selection()->count_selected_rows() != 0) {
401     btn_add->set_sensitive (true);
402   } else {
403     btn_add->set_sensitive (false);
404   }
405 }
406
407 void
408 PluginSelector::added_list_selection_changed()
409 {
410   if (added_list.get_selection()->count_selected_rows() != 0) {
411     btn_remove->set_sensitive (true);
412   } else {
413     btn_remove->set_sensitive (false);
414   }
415 }
416
417 int
418 PluginSelector::run ()
419 {
420         ResponseType r;
421         list<PluginInfo*>::iterator i;
422
423         r = (ResponseType) Dialog::run ();
424
425         switch (r) {
426         case RESPONSE_APPLY:
427                 for (i = added_plugins.begin(); i != added_plugins.end(); ++i){
428                         use_plugin (*i);
429                 }
430                 break;
431
432         default:
433                 break;
434         }
435
436         cleanup ();
437
438         return (int) r;
439 }
440
441 void
442 PluginSelector::cleanup ()
443 {
444         hide();
445         added_plugins.clear();
446         amodel->clear();
447 }
448