Added LADSPA_PATH to ardev_common.sh
[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         current_selection = PluginInfo::LADSPA;
55
56         lmodel = Gtk::ListStore::create(lcols);
57         ladspa_display.set_model (lmodel);
58         ladspa_display.append_column (_("Available LADSPA Plugins"), lcols.name);
59         ladspa_display.append_column (_("Type"), lcols.type);
60         ladspa_display.append_column (_("# Inputs"),lcols.ins);
61         ladspa_display.append_column (_("# Outputs"), lcols.outs);
62         ladspa_display.set_headers_visible (true);
63         ladspa_display.set_reorderable (false);
64         lscroller.set_border_width(10);
65         lscroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
66         lscroller.add(ladspa_display);
67
68         amodel = Gtk::ListStore::create(acols);
69         added_list.set_model (amodel);
70         added_list.append_column (_("Plugins to be Connected to Insert"), acols.text);
71         added_list.set_headers_visible (true);
72         added_list.set_reorderable (false);
73
74         for (int i = 0; i <=3; i++) {
75                 Gtk::TreeView::Column* column = ladspa_display.get_column(i);
76                 column->set_sort_column(i);
77         }
78
79 #ifdef VST_SUPPORT
80         vmodel = ListStore::create(vcols);
81         vst_display.set_model (vmodel);
82         vst_display.append_column (_("Available plugins"), vcols.name);
83         vst_display.append_column (_("# Inputs"), vcols.ins);
84         vst_display.append_column (_("# Outputs"), vcols.outs);
85         vst_display.set_headers_visible (true);
86         vst_display.set_reorderable (false);
87         vscroller.set_border_width(10);
88         vscroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
89         vscroller.add(vst_display);
90
91         for (int i = 0; i <=2; i++) {
92                 Gtk::TreeView::Column* column = vst_display.get_column(i);
93                 column->set_sort_column(i);
94         }
95 #endif
96
97 #ifdef HAVE_COREAUDIO
98         aumodel = ListStore::create(aucols);
99         au_display.set_model (aumodel);
100         au_display.append_column (_("Available plugins"), aucols.name);
101         au_display.append_column (_("# Inputs"), aucols.ins);
102         au_display.append_column (_("# Outputs"), aucols.outs);
103         au_display.set_headers_visible (true);
104         au_display.set_reorderable (false);
105         auscroller.set_border_width(10);
106         auscroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
107         auscroller.add(au_display);
108
109         for (int i = 0; i <=2; i++) {
110                 Gtk::TreeView::Column* column = au_display.get_column(i);
111                 column->set_sort_column(i);
112         }
113 #endif
114
115         ascroller.set_border_width(10);
116         ascroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
117         ascroller.add(added_list);
118         btn_add = manage(new Gtk::Button(Stock::ADD));
119         ARDOUR_UI::instance()->tooltips().set_tip(*btn_add, _("Add a plugin to the effect list"));
120         btn_add->set_sensitive (false);
121         btn_remove = manage(new Gtk::Button(Stock::REMOVE));
122         btn_remove->set_sensitive (false);
123         ARDOUR_UI::instance()->tooltips().set_tip(*btn_remove, _("Remove a plugin from the effect list"));
124         Gtk::Button *btn_update = manage(new Gtk::Button(Stock::REFRESH));
125         ARDOUR_UI::instance()->tooltips().set_tip(*btn_update, _("Update available plugins"));
126
127         btn_add->set_name("PluginSelectorButton");
128         btn_remove->set_name("PluginSelectorButton");
129
130         Gtk::Table* table = manage(new Gtk::Table(7, 10));
131         table->set_size_request(750, 500);
132         table->attach(notebook, 0, 7, 0, 5);
133
134         table->attach(*btn_add, 1, 2, 5, 6, Gtk::FILL, Gtk::FILL, 5, 5);
135         table->attach(*btn_remove, 3, 4, 5, 6, Gtk::FILL, Gtk::FILL, 5, 5);
136         table->attach(*btn_update, 5, 6, 5, 6, Gtk::FILL, Gtk::FILL, 5, 5);
137
138         table->attach(ascroller, 0, 7, 7, 9);
139
140         add_button (Stock::CANCEL, RESPONSE_CANCEL);
141         add_button (Stock::CONNECT, RESPONSE_APPLY);
142         set_default_response (RESPONSE_APPLY);
143         set_response_sensitive (RESPONSE_APPLY, false);
144         get_vbox()->pack_start (*table);
145
146         using namespace Gtk::Notebook_Helpers;
147         notebook.pages().push_back (TabElem (lscroller, _("LADSPA")));
148
149 #ifdef VST_SUPPORT
150         if (Config->get_use_vst()) {
151                 notebook.pages().push_back (TabElem (vscroller, _("VST")));
152         }
153 #endif
154
155 #ifdef HAVE_COREAUDIO
156         notebook.pages().push_back (TabElem (auscroller, _("AudioUnit")));
157 #endif
158
159         table->set_name("PluginSelectorTable");
160         ladspa_display.set_name("PluginSelectorDisplay");
161         //ladspa_display.set_name("PluginSelectorList");
162         added_list.set_name("PluginSelectorList");
163
164         ladspa_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked));
165         ladspa_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::ladspa_display_selection_changed));
166         
167 #ifdef VST_SUPPORT
168         if (Config->get_use_vst()) {
169                 vst_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked));
170                 vst_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::vst_display_selection_changed));
171         }
172 #endif
173
174 #ifdef HAVE_COREAUDIO
175         au_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked));
176         au_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::au_display_selection_changed));
177 #endif
178
179         btn_update->signal_clicked().connect (mem_fun(*this, &PluginSelector::btn_update_clicked));
180         btn_add->signal_clicked().connect(mem_fun(*this, &PluginSelector::btn_add_clicked));
181         btn_remove->signal_clicked().connect(mem_fun(*this, &PluginSelector::btn_remove_clicked));
182         added_list.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::added_list_selection_changed));
183
184         input_refiller ();
185         
186 #ifdef VST_SUPPORT
187         vst_refiller ();
188 #endif
189
190 #ifdef HAVE_COREAUDIO
191         au_refiller ();
192 #endif
193 }
194
195 void
196 PluginSelector::row_clicked(GdkEventButton* event)
197 {
198         if (event->type == GDK_2BUTTON_PRESS)
199                 btn_add_clicked();
200 }
201
202 void
203 PluginSelector::set_session (Session* s)
204 {
205         ENSURE_GUI_THREAD(bind (mem_fun(*this, &PluginSelector::set_session), s));
206         
207         session = s;
208
209         if (session) {
210                 session->going_away.connect (bind (mem_fun(*this, &PluginSelector::set_session), static_cast<Session*> (0)));
211         }
212 }
213
214 void
215 PluginSelector::_input_refiller (void *arg)
216 {
217         ((PluginSelector *) arg)->input_refiller ();
218 }
219
220 int compare(const void *left, const void *right)
221 {
222   return strcmp(*((char**)left), *((char**)right));
223 }
224
225 void
226 PluginSelector::input_refiller ()
227 {
228         guint row;
229         PluginInfoList &plugs = manager->ladspa_plugin_info ();
230         PluginInfoList::iterator i;
231         char ibuf[16], obuf[16];
232         lmodel->clear();
233
234         // Insert into GTK list
235         for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) {
236                 snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs);
237                 snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs);         
238                 
239                 Gtk::TreeModel::Row newrow = *(lmodel->append());
240                 newrow[lcols.name] = (*i)->name.c_str();
241                 newrow[lcols.type] = (*i)->category.c_str();
242                 newrow[lcols.ins] = ibuf;
243                 newrow[lcols.outs] = obuf;
244                 newrow[lcols.plugin] = *i;
245         }
246
247         lmodel->set_sort_column (0, Gtk::SORT_ASCENDING);
248 }
249
250 #ifdef VST_SUPPORT
251
252 void
253 PluginSelector::_vst_refiller (void *arg)
254 {
255         ((PluginSelector *) arg)->vst_refiller ();
256 }
257
258 void
259 PluginSelector::vst_refiller ()
260 {
261         guint row;
262         PluginInfoList &plugs = manager->vst_plugin_info ();
263         PluginInfoList::iterator i;
264         char ibuf[16], obuf[16];
265         vmodel->clear();
266         
267         // Insert into GTK list
268         for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) {
269
270                 snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs);
271                 snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs);         
272                 
273                 Gtk::TreeModel::Row newrow = *(vmodel->append());
274                 newrow[vcols.name] = (*i)->name.c_str();
275                 newrow[vcols.ins] = ibuf;
276                 newrow[vcols.outs] = obuf;
277                 newrow[vcols.plugin] = *i;
278         }
279         vmodel->set_sort_column (0, Gtk::SORT_ASCENDING);
280 }
281
282 void
283 PluginSelector::vst_display_selection_changed()
284 {
285         if (vst_display.get_selection()->count_selected_rows() != 0) {
286                 btn_add->set_sensitive (true);
287         } else {
288                 btn_add->set_sensitive (false);
289         }
290
291         current_selection = PluginInfo::VST;
292 }
293
294 #endif //VST_SUPPORT
295
296 #ifdef HAVE_COREAUDIO
297
298 void
299 PluginSelector::_au_refiller (void *arg)
300 {
301         ((PluginSelector *) arg)->au_refiller ();
302 }
303
304 void
305 PluginSelector::au_refiller ()
306 {
307         guint row;
308         PluginInfoList &plugs = manager->au_plugin_info ();
309         PluginInfoList::iterator i;
310         char ibuf[16], obuf[16];
311         aumodel->clear();
312         
313         // Insert into GTK list
314         for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) {
315
316                 snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs);
317                 snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs);         
318                 
319                 Gtk::TreeModel::Row newrow = *(aumodel->append());
320                 newrow[aucols.name] = (*i)->name.c_str();
321                 newrow[aucols.ins] = ibuf;
322                 newrow[aucols.outs] = obuf;
323                 newrow[aucols.plugin] = *i;
324         }
325         aumodel->set_sort_column (0, Gtk::SORT_ASCENDING);
326 }
327
328 void
329 PluginSelector::au_display_selection_changed()
330 {
331         if (au_display.get_selection()->count_selected_rows() != 0) {
332                 btn_add->set_sensitive (true);
333         } else {
334                 btn_add->set_sensitive (false);
335         }
336         
337         current_selection = PluginInfo::AudioUnit;
338 }
339
340 #endif //HAVE_COREAUDIO
341
342 void
343 PluginSelector::use_plugin (PluginInfoPtr pi)
344 {
345         if (session == 0) {
346                 return;
347         }
348
349         boost::shared_ptr<Plugin> plugin = manager->load (*session, pi);
350
351         if (plugin) {
352                 PluginCreated (plugin);
353         }
354 }
355
356 void
357 PluginSelector::btn_add_clicked()
358 {
359         std::string name;
360         PluginInfoPtr pi;
361         Gtk::TreeModel::Row newrow = *(amodel->append());
362         
363         Gtk::TreeModel::Row row;
364
365         switch (current_selection) {
366                 case PluginInfo::LADSPA:
367                         row = *(ladspa_display.get_selection()->get_selected());
368                         name = row[lcols.name];
369                         pi = row[lcols.plugin];
370                         break;
371                 case PluginInfo::VST:
372 #ifdef VST_SUPPORT
373                         row = *(vst_display.get_selection()->get_selected());
374                         name = row[vcols.name];
375                         pi = row[vcols.plugin];
376 #endif
377                         break;
378                 case PluginInfo::AudioUnit:
379 #ifdef HAVE_COREAUDIO
380                         row = *(au_display.get_selection()->get_selected());
381                         name = row[aucols.name];
382                         pi = row[aucols.plugin];
383 #endif
384                         break;
385                 default:
386                         error << "Programming error.  Unknown plugin selected." << endmsg;
387                         return;
388         }
389
390         newrow[acols.text] = name;
391         newrow[acols.plugin] = pi;
392
393         if (!amodel->children().empty()) {
394                 set_response_sensitive (RESPONSE_APPLY, true);
395         }
396 }
397
398 void
399 PluginSelector::btn_remove_clicked()
400 {
401         Gtk::TreeModel::iterator iter = added_list.get_selection()->get_selected();
402         
403         amodel->erase(iter);
404         if (amodel->children().empty()) {
405                 set_response_sensitive (RESPONSE_APPLY, false);
406         }
407 }
408
409 void
410 PluginSelector::btn_update_clicked()
411 {
412         manager->refresh ();
413         input_refiller ();
414 #ifdef VST_SUPPORT
415         vst_refiller ();
416 #endif  
417 #ifdef HAVE_COREAUDIO
418         au_refiller ();
419 #endif
420 }
421
422 void
423 PluginSelector::ladspa_display_selection_changed()
424 {
425         if (ladspa_display.get_selection()->count_selected_rows() != 0) {
426                 btn_add->set_sensitive (true);
427         } else {
428                 btn_add->set_sensitive (false);
429         }
430         
431         current_selection = PluginInfo::LADSPA;
432 }
433
434 void
435 PluginSelector::added_list_selection_changed()
436 {
437   if (added_list.get_selection()->count_selected_rows() != 0) {
438     btn_remove->set_sensitive (true);
439   } else {
440     btn_remove->set_sensitive (false);
441   }
442 }
443
444 int
445 PluginSelector::run ()
446 {
447         ResponseType r;
448         TreeModel::Children::iterator i;
449
450         r = (ResponseType) Dialog::run ();
451
452         switch (r) {
453         case RESPONSE_APPLY:
454                 for (i = amodel->children().begin(); i != amodel->children().end(); ++i) {
455                         use_plugin ((*i)[acols.plugin]);
456                 }
457                 break;
458
459         default:
460                 break;
461         }
462
463         cleanup ();
464
465         return (int) r;
466 }
467
468 void
469 PluginSelector::cleanup ()
470 {
471         hide();
472         amodel->clear();
473 }