1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2021 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSequencer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/X/machine/ags_lv2_bridge.h>
21 #include <ags/X/machine/ags_lv2_bridge_callbacks.h>
22 
23 #include <lv2/lv2plug.in/ns/lv2ext/lv2_programs.h>
24 
25 #include <ags/X/ags_ui_provider.h>
26 #include <ags/X/ags_window.h>
27 #include <ags/X/ags_navigation.h>
28 #include <ags/X/ags_effect_bridge.h>
29 #include <ags/X/ags_effect_bulk.h>
30 #include <ags/X/ags_bulk_member.h>
31 
32 #include <ags/i18n.h>
33 
34 void ags_lv2_bridge_class_init(AgsLv2BridgeClass *lv2_bridge);
35 void ags_lv2_bridge_connectable_interface_init(AgsConnectableInterface *connectable);
36 void ags_lv2_bridge_init(AgsLv2Bridge *lv2_bridge);
37 void ags_lv2_bridge_set_property(GObject *gobject,
38 				 guint prop_id,
39 				 const GValue *value,
40 				 GParamSpec *param_spec);
41 void ags_lv2_bridge_get_property(GObject *gobject,
42 				 guint prop_id,
43 				 GValue *value,
44 				 GParamSpec *param_spec);
45 void ags_lv2_bridge_finalize(GObject *gobject);
46 
47 void ags_lv2_bridge_connect(AgsConnectable *connectable);
48 void ags_lv2_bridge_disconnect(AgsConnectable *connectable);
49 
50 void ags_lv2_bridge_resize_audio_channels(AgsMachine *machine,
51 				       guint audio_channels, guint audio_channels_old,
52 				       gpointer data);
53 void ags_lv2_bridge_resize_pads(AgsMachine *machine, GType channel_type,
54 				guint pads, guint pads_old,
55 				gpointer data);
56 
57 void ags_lv2_bridge_map_recall(AgsMachine *machine);
58 
59 /**
60  * SECTION:ags_lv2_bridge
61  * @short_description: A composite widget to visualize a bunch of #AgsChannel
62  * @title: AgsLv2Bridge
63  * @section_id:
64  * @include: ags/X/ags_lv2_bridge.h
65  *
66  * #AgsLv2Bridge is a composite widget to visualize all #AgsChannel. It should be
67  * packed by an #AgsMachine.
68  */
69 
70 enum{
71   PROP_0,
72   PROP_FILENAME,
73   PROP_EFFECT,
74   PROP_URI,
75   PROP_INDEX,
76   PROP_HAS_MIDI,
77   PROP_HAS_GUI,
78   PROP_GUI_FILENAME,
79   PROP_GUI_URI,
80 };
81 
82 static gpointer ags_lv2_bridge_parent_class = NULL;
83 static AgsConnectableInterface* ags_lv2_bridge_parent_connectable_interface;
84 
85 GHashTable *ags_lv2_bridge_lv2ui_handle = NULL;
86 GHashTable *ags_lv2_bridge_lv2ui_idle = NULL;
87 
88 GType
ags_lv2_bridge_get_type(void)89 ags_lv2_bridge_get_type(void)
90 {
91   static volatile gsize g_define_type_id__volatile = 0;
92 
93   if(g_once_init_enter (&g_define_type_id__volatile)){
94     GType ags_type_lv2_bridge = 0;
95 
96     static const GTypeInfo ags_lv2_bridge_info = {
97       sizeof(AgsLv2BridgeClass),
98       NULL, /* base_init */
99       NULL, /* base_finalize */
100       (GClassInitFunc) ags_lv2_bridge_class_init,
101       NULL, /* class_finalize */
102       NULL, /* class_data */
103       sizeof(AgsLv2Bridge),
104       0,    /* n_preallocs */
105       (GInstanceInitFunc) ags_lv2_bridge_init,
106     };
107 
108     static const GInterfaceInfo ags_connectable_interface_info = {
109       (GInterfaceInitFunc) ags_lv2_bridge_connectable_interface_init,
110       NULL, /* interface_finalize */
111       NULL, /* interface_data */
112     };
113 
114     ags_type_lv2_bridge = g_type_register_static(AGS_TYPE_MACHINE,
115 						 "AgsLv2Bridge", &ags_lv2_bridge_info,
116 						 0);
117 
118     g_type_add_interface_static(ags_type_lv2_bridge,
119 				AGS_TYPE_CONNECTABLE,
120 				&ags_connectable_interface_info);
121 
122     g_once_init_leave(&g_define_type_id__volatile, ags_type_lv2_bridge);
123   }
124 
125   return g_define_type_id__volatile;
126 }
127 
128 void
ags_lv2_bridge_class_init(AgsLv2BridgeClass * lv2_bridge)129 ags_lv2_bridge_class_init(AgsLv2BridgeClass *lv2_bridge)
130 {
131   AgsMachineClass *machine;
132   GObjectClass *gobject;
133 
134   GParamSpec *param_spec;
135 
136   ags_lv2_bridge_parent_class = g_type_class_peek_parent(lv2_bridge);
137 
138   /* GObjectClass */
139   gobject = G_OBJECT_CLASS(lv2_bridge);
140 
141   gobject->set_property = ags_lv2_bridge_set_property;
142   gobject->get_property = ags_lv2_bridge_get_property;
143 
144   gobject->finalize = ags_lv2_bridge_finalize;
145 
146   /* properties */
147   /**
148    * AgsRecallLv2:filename:
149    *
150    * The plugin's filename.
151    *
152    * Since: 3.0.0
153    */
154   param_spec =  g_param_spec_string("filename",
155 				    i18n_pspec("the object file"),
156 				    i18n_pspec("The filename as string of object file"),
157 				    NULL,
158 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
159   g_object_class_install_property(gobject,
160 				  PROP_FILENAME,
161 				  param_spec);
162 
163   /**
164    * AgsRecallLv2:effect:
165    *
166    * The effect's name.
167    *
168    * Since: 3.0.0
169    */
170   param_spec =  g_param_spec_string("effect",
171 				    i18n_pspec("the effect"),
172 				    i18n_pspec("The effect's string representation"),
173 				    NULL,
174 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
175   g_object_class_install_property(gobject,
176 				  PROP_EFFECT,
177 				  param_spec);
178 
179   /**
180    * AgsRecallLv2:uri:
181    *
182    * The uri's name.
183    *
184    * Since: 3.0.0
185    */
186   param_spec =  g_param_spec_string("uri",
187 				    i18n_pspec("the uri"),
188 				    i18n_pspec("The uri's string representation"),
189 				    NULL,
190 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
191   g_object_class_install_property(gobject,
192 				  PROP_URI,
193 				  param_spec);
194 
195   /**
196    * AgsRecallLv2:index:
197    *
198    * The uri's index.
199    *
200    * Since: 3.0.0
201    */
202   param_spec =  g_param_spec_ulong("index",
203 				   i18n_pspec("index of uri"),
204 				   i18n_pspec("The numerical index of uri"),
205 				   0,
206 				   65535,
207 				   0,
208 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
209   g_object_class_install_property(gobject,
210 				  PROP_INDEX,
211 				  param_spec);
212 
213   /**
214    * AgsRecallLv2:has-midi:
215    *
216    * If has-midi is set to %TRUE appropriate flag is set
217    * to audio in order to become a sequencer.
218    *
219    * Since: 3.0.0
220    */
221   param_spec =  g_param_spec_boolean("has-midi",
222 				     i18n_pspec("has-midi"),
223 				     i18n_pspec("If effect has-midi"),
224 				     FALSE,
225 				     G_PARAM_READABLE | G_PARAM_WRITABLE);
226   g_object_class_install_property(gobject,
227 				  PROP_HAS_MIDI,
228 				  param_spec);
229 
230   /**
231    * AgsRecallLv2:has-gui:
232    *
233    * If has-gui is set to %TRUE 128 inputs are allocated and appropriate flag is set
234    * to audio in order to become a sequencer.
235    *
236    * Since: 3.0.0
237    */
238   param_spec =  g_param_spec_boolean("has-gui",
239 				     i18n_pspec("has-gui"),
240 				     i18n_pspec("If effect has-gui"),
241 				     FALSE,
242 				     G_PARAM_READABLE | G_PARAM_WRITABLE);
243   g_object_class_install_property(gobject,
244 				  PROP_HAS_GUI,
245 				  param_spec);
246 
247   /**
248    * AgsRecallLv2:gui-filename:
249    *
250    * The plugin's GUI filename.
251    *
252    * Since: 3.0.0
253    */
254   param_spec =  g_param_spec_string("gui-filename",
255 				    i18n_pspec("the GUI object file"),
256 				    i18n_pspec("The filename as string of GUI object file"),
257 				    NULL,
258 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
259   g_object_class_install_property(gobject,
260 				  PROP_GUI_FILENAME,
261 				  param_spec);
262 
263   /**
264    * AgsRecallLv2:gui-uri:
265    *
266    * The GUI's uri name.
267    *
268    * Since: 3.0.0
269    */
270   param_spec =  g_param_spec_string("gui-uri",
271 				    i18n_pspec("the gui-uri"),
272 				    i18n_pspec("The gui-uri's string representation"),
273 				    NULL,
274 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
275   g_object_class_install_property(gobject,
276 				  PROP_GUI_URI,
277 				  param_spec);
278 
279   /* AgsMachine */
280   machine = (AgsMachineClass *) lv2_bridge;
281 
282   machine->map_recall = ags_lv2_bridge_map_recall;
283 }
284 
285 void
ags_lv2_bridge_connectable_interface_init(AgsConnectableInterface * connectable)286 ags_lv2_bridge_connectable_interface_init(AgsConnectableInterface *connectable)
287 {
288   ags_lv2_bridge_parent_connectable_interface = g_type_interface_peek_parent(connectable);
289 
290   connectable->is_ready = NULL;
291   connectable->is_connected = NULL;
292   connectable->connect = ags_lv2_bridge_connect;
293   connectable->disconnect = ags_lv2_bridge_disconnect;
294 }
295 
296 void
ags_lv2_bridge_init(AgsLv2Bridge * lv2_bridge)297 ags_lv2_bridge_init(AgsLv2Bridge *lv2_bridge)
298 {
299   GtkGrid *grid;
300   GtkMenuItem *item;
301 
302   AgsAudio *audio;
303 
304   g_signal_connect_after((GObject *) lv2_bridge, "parent-set",
305 			 G_CALLBACK(ags_lv2_bridge_parent_set_callback), (gpointer) lv2_bridge);
306 
307   if(ags_lv2_bridge_lv2ui_handle == NULL){
308     ags_lv2_bridge_lv2ui_handle = g_hash_table_new_full(g_direct_hash, g_direct_equal,
309 						      NULL,
310 						      NULL);
311   }
312 
313   if(ags_lv2_bridge_lv2ui_idle == NULL){
314     ags_lv2_bridge_lv2ui_idle = g_hash_table_new_full(g_direct_hash, g_direct_equal,
315 						      NULL,
316 						      NULL);
317   }
318 
319   audio = AGS_MACHINE(lv2_bridge)->audio;
320   ags_audio_set_flags(audio, (AGS_AUDIO_SYNC));
321   g_object_set(audio,
322 	       "min-audio-channels", 1,
323 	       "min-output-pads", 1,
324 	       "min-input-pads", 1,
325 	       NULL);
326 
327   g_signal_connect_after(G_OBJECT(lv2_bridge), "resize-audio-channels",
328 			 G_CALLBACK(ags_lv2_bridge_resize_audio_channels), NULL);
329 
330   g_signal_connect_after(G_OBJECT(lv2_bridge), "resize-pads",
331 			 G_CALLBACK(ags_lv2_bridge_resize_pads), NULL);
332 
333   lv2_bridge->flags = 0;
334 
335   lv2_bridge->name = NULL;
336 
337   lv2_bridge->version = AGS_LV2_BRIDGE_DEFAULT_VERSION;
338   lv2_bridge->build_id = AGS_LV2_BRIDGE_DEFAULT_BUILD_ID;
339 
340   lv2_bridge->xml_type = "ags-lv2-bridge";
341 
342   lv2_bridge->mapped_output_pad = 0;
343   lv2_bridge->mapped_input_pad = 0;
344 
345   lv2_bridge->lv2_play_container = ags_recall_container_new();
346   lv2_bridge->lv2_recall_container = ags_recall_container_new();
347 
348   lv2_bridge->envelope_play_container = ags_recall_container_new();
349   lv2_bridge->envelope_recall_container = ags_recall_container_new();
350 
351   lv2_bridge->buffer_play_container = ags_recall_container_new();
352   lv2_bridge->buffer_recall_container = ags_recall_container_new();
353 
354   lv2_bridge->filename = NULL;
355   lv2_bridge->effect = NULL;
356   lv2_bridge->uri = NULL;
357   lv2_bridge->uri_index = 0;
358 
359   lv2_bridge->has_midi = FALSE;
360 
361   lv2_bridge->lv2_plugin = NULL;
362 
363   lv2_bridge->lv2_descriptor = NULL;
364   lv2_bridge->lv2_handle = NULL;
365   lv2_bridge->port_value = NULL;
366 
367   lv2_bridge->has_gui = FALSE;
368   lv2_bridge->gui_filename = NULL;
369   lv2_bridge->gui_uri = NULL;
370 
371   lv2_bridge->lv2ui_plugin = NULL;
372 
373   lv2_bridge->ui_descriptor = NULL;
374 
375   lv2_bridge->ui_feature = (LV2_Feature **) malloc(3 * sizeof(LV2_Feature *));
376 
377   lv2_bridge->ui_feature[0] = (LV2_Feature *) malloc(sizeof(LV2_Feature));
378   lv2_bridge->ui_feature[0]->data = NULL;
379 
380   lv2_bridge->ui_feature[1] = (LV2_Feature *) malloc(sizeof(LV2_Feature));
381   lv2_bridge->ui_feature[1]->data = NULL;
382 
383   lv2_bridge->ui_feature[2] = NULL;
384 
385   lv2_bridge->ui_handle = NULL;
386 
387   /**/
388   lv2_bridge->vbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_VERTICAL,
389 					    0);
390   gtk_container_add((GtkContainer *) gtk_bin_get_child((GtkBin *) lv2_bridge),
391 		    (GtkWidget *) lv2_bridge->vbox);
392 
393   lv2_bridge->program = NULL;
394   lv2_bridge->preset = NULL;
395 
396   /* effect bridge */
397   AGS_MACHINE(lv2_bridge)->bridge = (GtkContainer *) ags_effect_bridge_new(audio);
398   gtk_box_pack_start(lv2_bridge->vbox,
399 		     (GtkWidget *) AGS_MACHINE(lv2_bridge)->bridge,
400 		     FALSE, FALSE,
401 		     0);
402 
403   grid = (GtkGrid *) gtk_grid_new();
404   gtk_box_pack_start((GtkBox *) AGS_EFFECT_BRIDGE(AGS_MACHINE(lv2_bridge)->bridge),
405 		     (GtkWidget *) grid,
406 		     FALSE, FALSE,
407 		     0);
408 
409   AGS_EFFECT_BRIDGE(AGS_MACHINE(lv2_bridge)->bridge)->bulk_input = (GtkWidget *) ags_effect_bulk_new(audio,
410 												     AGS_TYPE_INPUT);
411   AGS_EFFECT_BULK(AGS_EFFECT_BRIDGE(AGS_MACHINE(lv2_bridge)->bridge)->bulk_input)->flags |= (AGS_EFFECT_BULK_HIDE_BUTTONS |
412 											     AGS_EFFECT_BULK_HIDE_ENTRIES |
413 											     AGS_EFFECT_BULK_SHOW_LABELS);
414 
415   gtk_widget_set_valign((GtkWidget *) AGS_EFFECT_BRIDGE(AGS_MACHINE(lv2_bridge)->bridge)->bulk_input,
416 			GTK_ALIGN_FILL);
417   gtk_widget_set_halign((GtkWidget *) AGS_EFFECT_BRIDGE(AGS_MACHINE(lv2_bridge)->bridge)->bulk_input,
418 			GTK_ALIGN_FILL);
419 
420   gtk_grid_attach(grid,
421 		  (GtkWidget *) AGS_EFFECT_BRIDGE(AGS_MACHINE(lv2_bridge)->bridge)->bulk_input,
422 		  0, 0,
423 		  1, 1);
424 
425   /* lv2 menu */
426   item = (GtkMenuItem *) gtk_menu_item_new_with_label("Lv2");
427   gtk_menu_shell_append((GtkMenuShell *) AGS_MACHINE(lv2_bridge)->popup,
428 			(GtkWidget *) item);
429   gtk_widget_show((GtkWidget *) item);
430 
431   lv2_bridge->lv2_menu = (GtkMenu *) gtk_menu_new();
432   gtk_menu_item_set_submenu((GtkMenuItem *) item,
433 			    (GtkWidget *) lv2_bridge->lv2_menu);
434 
435   item = (GtkMenuItem *) gtk_menu_item_new_with_label(i18n("show GUI"));
436   gtk_menu_shell_append((GtkMenuShell *) lv2_bridge->lv2_menu,
437 			(GtkWidget *) item);
438 
439   gtk_widget_show_all((GtkWidget *) lv2_bridge->lv2_menu);
440 
441   /* plugin widget */
442   lv2_bridge->lv2_gui = NULL;
443   lv2_bridge->ui_widget = NULL;
444 
445   lv2_bridge->lv2_window = NULL;
446 }
447 
448 void
ags_lv2_bridge_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)449 ags_lv2_bridge_set_property(GObject *gobject,
450 			    guint prop_id,
451 			    const GValue *value,
452 			    GParamSpec *param_spec)
453 {
454   AgsLv2Bridge *lv2_bridge;
455 
456   lv2_bridge = AGS_LV2_BRIDGE(gobject);
457 
458   switch(prop_id){
459   case PROP_FILENAME:
460     {
461       gchar *filename;
462 
463       filename = g_value_get_string(value);
464 
465       if(filename == lv2_bridge->filename){
466 	return;
467       }
468 
469       if(lv2_bridge->filename != NULL){
470 	g_free(lv2_bridge->filename);
471       }
472 
473       if(filename != NULL){
474 	if(!g_file_test(filename,
475 			G_FILE_TEST_EXISTS)){
476 	  AgsWindow *window;
477 
478 	  window = (AgsWindow *) gtk_widget_get_toplevel((GtkWidget *) lv2_bridge);
479 
480 	  ags_window_show_error(window,
481 				g_strdup_printf("Plugin file not present %s",
482 						filename));
483 	}
484       }
485 
486       lv2_bridge->filename = g_strdup(filename);
487     }
488     break;
489   case PROP_EFFECT:
490     {
491       gchar *effect;
492 
493       effect = g_value_get_string(value);
494 
495       if(effect == lv2_bridge->effect){
496 	return;
497       }
498 
499       if(lv2_bridge->effect != NULL){
500 	g_free(lv2_bridge->effect);
501       }
502 
503       lv2_bridge->effect = g_strdup(effect);
504     }
505     break;
506   case PROP_URI:
507     {
508       gchar *uri;
509 
510       uri = g_value_get_string(value);
511 
512       if(uri == lv2_bridge->uri){
513 	return;
514       }
515 
516       if(lv2_bridge->uri != NULL){
517 	g_free(lv2_bridge->uri);
518       }
519 
520       lv2_bridge->uri = g_strdup(uri);
521     }
522     break;
523   case PROP_INDEX:
524     {
525       unsigned long uri_index;
526 
527       uri_index = g_value_get_ulong(value);
528 
529       if(uri_index == lv2_bridge->uri_index){
530 	return;
531       }
532 
533       lv2_bridge->uri_index = uri_index;
534     }
535     break;
536   case PROP_HAS_MIDI:
537     {
538       gboolean has_midi;
539 
540       has_midi = g_value_get_boolean(value);
541 
542       if(lv2_bridge->has_midi == has_midi){
543 	return;
544       }
545 
546       lv2_bridge->has_midi = has_midi;
547     }
548     break;
549   case PROP_HAS_GUI:
550     {
551       gboolean has_gui;
552 
553       has_gui = g_value_get_boolean(value);
554 
555       if(lv2_bridge->has_gui == has_gui){
556 	return;
557       }
558 
559       lv2_bridge->has_gui = has_gui;
560     }
561     break;
562   case PROP_GUI_FILENAME:
563     {
564       gchar *gui_filename;
565 
566       gui_filename = g_value_get_string(value);
567 
568       if(lv2_bridge->gui_filename == gui_filename){
569 	return;
570       }
571 
572       lv2_bridge->gui_filename = g_strdup(gui_filename);
573     }
574     break;
575   case PROP_GUI_URI:
576     {
577       gchar *gui_uri;
578 
579       gui_uri = g_value_get_string(value);
580 
581       if(gui_uri == lv2_bridge->gui_uri){
582 	return;
583       }
584 
585       if(lv2_bridge->gui_uri != NULL){
586 	g_free(lv2_bridge->gui_uri);
587       }
588 
589       lv2_bridge->gui_uri = g_strdup(gui_uri);
590     }
591     break;
592   default:
593     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
594     break;
595   }
596 }
597 
598 void
ags_lv2_bridge_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)599 ags_lv2_bridge_get_property(GObject *gobject,
600 			    guint prop_id,
601 			    GValue *value,
602 			    GParamSpec *param_spec)
603 {
604   AgsLv2Bridge *lv2_bridge;
605 
606   lv2_bridge = AGS_LV2_BRIDGE(gobject);
607 
608   switch(prop_id){
609   case PROP_FILENAME:
610     {
611       g_value_set_string(value, lv2_bridge->filename);
612     }
613     break;
614   case PROP_EFFECT:
615     {
616       g_value_set_string(value, lv2_bridge->effect);
617     }
618     break;
619   case PROP_URI:
620     {
621       g_value_set_string(value, lv2_bridge->uri);
622     }
623     break;
624   case PROP_INDEX:
625     {
626       g_value_set_ulong(value, lv2_bridge->uri_index);
627     }
628     break;
629   case PROP_HAS_MIDI:
630     {
631       g_value_set_boolean(value, lv2_bridge->has_midi);
632     }
633     break;
634   case PROP_HAS_GUI:
635     {
636       g_value_set_boolean(value, lv2_bridge->has_gui);
637     }
638     break;
639   case PROP_GUI_FILENAME:
640     {
641       g_value_set_string(value, lv2_bridge->gui_filename);
642     }
643     break;
644   case PROP_GUI_URI:
645     {
646       g_value_set_string(value, lv2_bridge->gui_uri);
647     }
648     break;
649   default:
650     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
651     break;
652   }
653 }
654 
655 void
ags_lv2_bridge_finalize(GObject * gobject)656 ags_lv2_bridge_finalize(GObject *gobject)
657 {
658   AgsLv2Bridge *lv2_bridge;
659 
660   lv2_bridge = AGS_LV2_BRIDGE(gobject);
661 
662   g_object_disconnect(G_OBJECT(lv2_bridge),
663 		      "any_signal::resize-audio-channels",
664 		      G_CALLBACK(ags_lv2_bridge_resize_audio_channels),
665 		      NULL,
666 		      "any_signal::resize-pads",
667 		      G_CALLBACK(ags_lv2_bridge_resize_pads),
668 		      NULL,
669 		      NULL);
670 
671   /* lv2 plugin */
672   if(lv2_bridge->lv2_plugin != NULL){
673     g_object_unref(lv2_bridge->lv2_plugin);
674   }
675 
676   /* lv2ui plugin */
677   if(lv2_bridge->lv2ui_plugin != NULL){
678     g_object_unref(lv2_bridge->lv2ui_plugin);
679   }
680 
681   /* plugin widget */
682   if(lv2_bridge->ui_handle != NULL){
683     lv2_bridge->ui_descriptor->cleanup(lv2_bridge->ui_handle[0]);
684 
685     g_hash_table_remove(ags_lv2_bridge_lv2ui_handle,
686 			lv2_bridge->ui_handle);
687 
688     g_hash_table_remove(ags_lv2_bridge_lv2ui_idle,
689 			lv2_bridge->ui_handle);
690   }
691 
692   if(lv2_bridge->lv2_window != NULL){
693     gtk_widget_destroy(lv2_bridge->lv2_window);
694   }
695 
696   /* call parent */
697   G_OBJECT_CLASS(ags_lv2_bridge_parent_class)->finalize(gobject);
698 }
699 
700 void
ags_lv2_bridge_connect(AgsConnectable * connectable)701 ags_lv2_bridge_connect(AgsConnectable *connectable)
702 {
703   AgsLv2Bridge *lv2_bridge;
704   AgsEffectBridge *effect_bridge;
705   AgsBulkMember *bulk_member;
706   GtkWidget *control;
707 
708   GList *list, *list_start;
709 
710   if((AGS_MACHINE_CONNECTED & (AGS_MACHINE(connectable)->flags)) != 0){
711     return;
712   }
713 
714   ags_lv2_bridge_parent_connectable_interface->connect(connectable);
715 
716   lv2_bridge = AGS_LV2_BRIDGE(connectable);
717 
718   /* menu */
719   list =
720     list_start = gtk_container_get_children((GtkContainer *) lv2_bridge->lv2_menu);
721 
722   g_signal_connect(G_OBJECT(list->data), "activate",
723 		   G_CALLBACK(ags_lv2_bridge_show_gui_callback), lv2_bridge);
724 
725   g_list_free(list_start);
726 
727   /* program */
728   if(lv2_bridge->program != NULL){
729     g_signal_connect_after(G_OBJECT(lv2_bridge->program), "changed",
730 			   G_CALLBACK(ags_lv2_bridge_program_changed_callback), lv2_bridge);
731   }
732 
733   /* bulk member */
734   effect_bridge = AGS_EFFECT_BRIDGE(AGS_MACHINE(lv2_bridge)->bridge);
735 
736   list =
737     list_start = gtk_container_get_children((GtkContainer *) AGS_EFFECT_BULK(effect_bridge->bulk_input)->grid);
738 
739   while(list != NULL){
740     bulk_member = list->data;
741 
742     control = gtk_bin_get_child(GTK_BIN(bulk_member));
743 
744     if(bulk_member->widget_type == AGS_TYPE_DIAL){
745       g_signal_connect_after(GTK_WIDGET(control), "value-changed",
746 			     G_CALLBACK(ags_lv2_bridge_dial_changed_callback), lv2_bridge);
747     }else if(bulk_member->widget_type == GTK_TYPE_SCALE){
748       g_signal_connect_after(GTK_WIDGET(control), "value-changed",
749 			     G_CALLBACK(ags_lv2_bridge_scale_changed_callback), lv2_bridge);
750     }else if(bulk_member->widget_type == GTK_TYPE_SPIN_BUTTON){
751       g_signal_connect_after(GTK_WIDGET(control), "value-changed",
752 			     G_CALLBACK(ags_lv2_bridge_spin_button_changed_callback), lv2_bridge);
753     }else if(bulk_member->widget_type == GTK_TYPE_CHECK_BUTTON){
754       g_signal_connect_after(GTK_WIDGET(control), "clicked",
755 			     G_CALLBACK(ags_lv2_bridge_check_button_clicked_callback), lv2_bridge);
756     }else if(bulk_member->widget_type == GTK_TYPE_TOGGLE_BUTTON){
757       g_signal_connect_after(GTK_WIDGET(control), "clicked",
758 			     G_CALLBACK(ags_lv2_bridge_toggle_button_clicked_callback), lv2_bridge);
759     }else if(bulk_member->widget_type == GTK_TYPE_BUTTON){
760       g_signal_connect_after(GTK_WIDGET(control), "clicked",
761 			     G_CALLBACK(ags_lv2_bridge_button_clicked_callback), lv2_bridge);
762     }
763 
764     list = list->next;
765   }
766 
767   g_list_free(list_start);
768 }
769 
770 void
ags_lv2_bridge_disconnect(AgsConnectable * connectable)771 ags_lv2_bridge_disconnect(AgsConnectable *connectable)
772 {
773   AgsLv2Bridge *lv2_bridge;
774   AgsEffectBridge *effect_bridge;
775   AgsBulkMember *bulk_member;
776   GtkWidget *control;
777 
778   GList *list, *list_start;
779 
780   if((AGS_MACHINE_CONNECTED & (AGS_MACHINE(connectable)->flags)) == 0){
781     return;
782   }
783 
784   ags_lv2_bridge_parent_connectable_interface->disconnect(connectable);
785 
786   lv2_bridge = AGS_LV2_BRIDGE(connectable);
787 
788   /* menu */
789   list =
790     list_start = gtk_container_get_children((GtkContainer *) lv2_bridge->lv2_menu);
791 
792   g_object_disconnect(G_OBJECT(list->data),
793 		      "any_signal::activate",
794 		      G_CALLBACK(ags_lv2_bridge_show_gui_callback),
795 		      lv2_bridge,
796 		      NULL);
797 
798   g_list_free(list_start);
799 
800   /* program */
801   if(lv2_bridge->program != NULL){
802     g_object_disconnect(G_OBJECT(lv2_bridge->program),
803 			"any_signal::changed",
804 			G_CALLBACK(ags_lv2_bridge_program_changed_callback),
805 			lv2_bridge,
806 			NULL);
807   }
808 
809   /* bulk member */
810   effect_bridge = AGS_EFFECT_BRIDGE(AGS_MACHINE(lv2_bridge)->bridge);
811 
812   list =
813     list_start = gtk_container_get_children((GtkContainer *) AGS_EFFECT_BULK(effect_bridge->bulk_input)->grid);
814 
815   while(list != NULL){
816     bulk_member = list->data;
817 
818     control = gtk_bin_get_child(GTK_BIN(bulk_member));
819 
820     if(bulk_member->widget_type == AGS_TYPE_DIAL){
821       g_object_disconnect(GTK_WIDGET(control),
822 			  "any_signal::value-changed",
823 			  G_CALLBACK(ags_lv2_bridge_dial_changed_callback),
824 			  lv2_bridge,
825 			  NULL);
826     }else if(bulk_member->widget_type == GTK_TYPE_VSCALE){
827       g_object_disconnect(GTK_WIDGET(control),
828 			  "any_signal::value-changed",
829 			  G_CALLBACK(ags_lv2_bridge_scale_changed_callback),
830 			  lv2_bridge,
831 			  NULL);
832     }else if(bulk_member->widget_type == GTK_TYPE_HSCALE){
833       g_object_disconnect(GTK_WIDGET(control),
834 			  "any_signal::value-changed",
835 			  G_CALLBACK(ags_lv2_bridge_scale_changed_callback),
836 			  lv2_bridge,
837 			  NULL);
838     }else if(bulk_member->widget_type == GTK_TYPE_SPIN_BUTTON){
839       g_object_disconnect(GTK_WIDGET(control),
840 			  "any_signal::value-changed",
841 			  G_CALLBACK(ags_lv2_bridge_spin_button_changed_callback),
842 			  lv2_bridge,
843 			  NULL);
844     }else if(bulk_member->widget_type == GTK_TYPE_CHECK_BUTTON){
845       g_object_disconnect(GTK_WIDGET(control),
846 			  "any_signal::clicked",
847 			  G_CALLBACK(ags_lv2_bridge_check_button_clicked_callback),
848 			  lv2_bridge,
849 			  NULL);
850     }else if(bulk_member->widget_type == GTK_TYPE_TOGGLE_BUTTON){
851       g_object_disconnect(GTK_WIDGET(control),
852 			  "any_signal::clicked",
853 			  G_CALLBACK(ags_lv2_bridge_toggle_button_clicked_callback),
854 			  lv2_bridge,
855 			  NULL);
856     }else if(bulk_member->widget_type == GTK_TYPE_BUTTON){
857       g_object_disconnect(GTK_WIDGET(control),
858 			  "any_signal::clicked",
859 			  G_CALLBACK(ags_lv2_bridge_button_clicked_callback),
860 			  lv2_bridge,
861 			  NULL);
862     }
863 
864     list = list->next;
865   }
866 
867   g_list_free(list_start);
868 }
869 
870 void
ags_lv2_bridge_resize_audio_channels(AgsMachine * machine,guint audio_channels,guint audio_channels_old,gpointer data)871 ags_lv2_bridge_resize_audio_channels(AgsMachine *machine,
872 				     guint audio_channels, guint audio_channels_old,
873 				     gpointer data)
874 {
875   AgsLv2Bridge *lv2_bridge;
876 
877   lv2_bridge = (AgsLv2Bridge *) machine;
878 
879   if(audio_channels > audio_channels_old){
880     /* recall */
881     if((AGS_MACHINE_MAPPED_RECALL & (machine->flags)) != 0){
882       ags_lv2_bridge_input_map_recall(lv2_bridge,
883 				      audio_channels_old,
884 				      0);
885 
886       ags_lv2_bridge_output_map_recall(lv2_bridge,
887 				       audio_channels_old,
888 				       0);
889     }
890   }
891 }
892 
893 void
ags_lv2_bridge_resize_pads(AgsMachine * machine,GType channel_type,guint pads,guint pads_old,gpointer data)894 ags_lv2_bridge_resize_pads(AgsMachine *machine, GType channel_type,
895 			   guint pads, guint pads_old,
896 			   gpointer data)
897 {
898   AgsLv2Bridge *lv2_bridge;
899 
900   gboolean grow;
901 
902   lv2_bridge = (AgsLv2Bridge *) machine;
903 
904   if(pads_old < pads){
905     grow = TRUE;
906   }else{
907     grow = FALSE;
908   }
909 
910   if(g_type_is_a(channel_type, AGS_TYPE_INPUT)){
911     if(grow){
912       /* recall */
913       if((AGS_MACHINE_MAPPED_RECALL & (machine->flags)) != 0){
914 	ags_lv2_bridge_input_map_recall(lv2_bridge,
915 					0,
916 					pads_old);
917       }
918     }else{
919       lv2_bridge->mapped_input_pad = pads;
920     }
921   }else{
922     if(grow){
923       /* recall */
924       if((AGS_MACHINE_MAPPED_RECALL & (machine->flags)) != 0){
925 	ags_lv2_bridge_output_map_recall(lv2_bridge,
926 					 0,
927 					 pads_old);
928       }
929     }else{
930       lv2_bridge->mapped_output_pad = pads;
931     }
932   }
933 }
934 
935 void
ags_lv2_bridge_map_recall(AgsMachine * machine)936 ags_lv2_bridge_map_recall(AgsMachine *machine)
937 {
938   AgsNavigation *navigation;
939   AgsLv2Bridge *lv2_bridge;
940 
941   AgsAudio *audio;
942 
943   AgsApplicationContext *application_context;
944 
945   GList *start_play, *start_recall;
946   GList *start_list, *list;
947 
948   gint position;
949 
950   if((AGS_MACHINE_MAPPED_RECALL & (machine->flags)) != 0 ||
951      (AGS_MACHINE_PREMAPPED_RECALL & (machine->flags)) != 0){
952     return;
953   }
954 
955   application_context = ags_application_context_get_instance();
956 
957   navigation = (AgsNavigation *) ags_ui_provider_get_navigation(AGS_UI_PROVIDER(application_context));
958 
959   lv2_bridge = (AgsLv2Bridge *) machine;
960 
961   audio = machine->audio;
962 
963   position = 0;
964 
965   /* add new controls */
966   ags_effect_bulk_add_plugin(AGS_EFFECT_BULK(AGS_EFFECT_BRIDGE(machine->bridge)->bulk_input),
967 			     NULL,
968 			     lv2_bridge->lv2_play_container, lv2_bridge->lv2_recall_container,
969 			     "ags-fx-lv2",
970 			     lv2_bridge->filename,
971 			     lv2_bridge->effect,
972 			     0, 0,
973 			     0, 0,
974 			     position,
975 			     (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT), 0);
976 
977 
978 
979   if((AGS_MACHINE_IS_SYNTHESIZER & (machine->flags)) != 0){
980     start_play = ags_audio_get_play(audio);
981     start_recall = ags_audio_get_recall(audio);
982 
983     list =
984       start_list = NULL;
985 
986     if(start_play != NULL &&
987        start_recall != NULL){
988       list =
989 	start_list = g_list_concat(start_play,
990 				   start_recall);
991     }
992 
993     while((list = ags_recall_template_find_type(list, AGS_TYPE_FX_NOTATION_AUDIO)) != NULL){
994       AgsPort *port;
995 
996       GValue value = G_VALUE_INIT;
997 
998       /* loop */
999       port = NULL;
1000 
1001       g_object_get(list->data,
1002 		   "loop", &port,
1003 		   NULL);
1004 
1005       g_value_init(&value,
1006 		   G_TYPE_BOOLEAN);
1007 
1008       g_value_set_boolean(&value,
1009 			  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(navigation->loop)));
1010 
1011       ags_port_safe_write(port,
1012 			  &value);
1013 
1014       if(port != NULL){
1015 	g_object_unref(port);
1016       }
1017 
1018       /* loop start */
1019       port = NULL;
1020 
1021       g_object_get(list->data,
1022 		   "loop-start", &port,
1023 		   NULL);
1024 
1025       g_value_unset(&value);
1026       g_value_init(&value,
1027 		   G_TYPE_UINT64);
1028 
1029       g_value_set_uint64(&value,
1030 			 16 * gtk_spin_button_get_value_as_int(navigation->loop_left_tact));
1031 
1032       ags_port_safe_write(port,
1033 			  &value);
1034 
1035       if(port != NULL){
1036 	g_object_unref(port);
1037       }
1038 
1039       /* loop end */
1040       port = NULL;
1041 
1042       g_object_get(list->data,
1043 		   "loop-end", &port,
1044 		   NULL);
1045 
1046       g_value_unset(&value);
1047       g_value_init(&value,
1048 		   G_TYPE_UINT64);
1049 
1050       g_value_set_uint64(&value,
1051 			 16 * gtk_spin_button_get_value_as_int(navigation->loop_right_tact));
1052 
1053       ags_port_safe_write(port,
1054 			  &value);
1055 
1056       if(port != NULL){
1057 	g_object_unref(port);
1058       }
1059 
1060       /* iterate */
1061       list = list->next;
1062     }
1063 
1064     g_list_free_full(start_list,
1065 		     (GDestroyNotify) g_object_unref);
1066 
1067     /* ags-fx-envelope */
1068     start_recall = ags_fx_factory_create(audio,
1069 					 lv2_bridge->envelope_play_container, lv2_bridge->envelope_recall_container,
1070 					 "ags-fx-envelope",
1071 					 NULL,
1072 					 NULL,
1073 					 0, 0,
1074 					 0, 0,
1075 					 position,
1076 					 (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT), 0);
1077 
1078     g_list_free_full(start_recall,
1079 		     (GDestroyNotify) g_object_unref);
1080 
1081     /* ags-fx-buffer */
1082     start_recall = ags_fx_factory_create(audio,
1083 					 lv2_bridge->buffer_play_container, lv2_bridge->buffer_recall_container,
1084 					 "ags-fx-buffer",
1085 					 NULL,
1086 					 NULL,
1087 					 0, 0,
1088 					 0, 0,
1089 					 position,
1090 					 (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT), 0);
1091 
1092     g_list_free_full(start_recall,
1093 		     (GDestroyNotify) g_object_unref);
1094   }
1095 
1096   /* depending on destination */
1097   ags_lv2_bridge_input_map_recall(lv2_bridge,
1098 				  0,
1099 				  0);
1100 
1101   /* depending on destination */
1102   ags_lv2_bridge_output_map_recall(lv2_bridge,
1103 				   0,
1104 				   0);
1105 
1106   /* call parent */
1107   AGS_MACHINE_CLASS(ags_lv2_bridge_parent_class)->map_recall(machine);
1108 }
1109 
1110 void
ags_lv2_bridge_input_map_recall(AgsLv2Bridge * lv2_bridge,guint audio_channel_start,guint input_pad_start)1111 ags_lv2_bridge_input_map_recall(AgsLv2Bridge *lv2_bridge,
1112 				guint audio_channel_start,
1113 				guint input_pad_start)
1114 {
1115   AgsAudio *audio;
1116 
1117   GList *start_recall;
1118 
1119   gint position;
1120   guint input_pads;
1121   guint audio_channels;
1122 
1123   if(lv2_bridge->mapped_input_pad > input_pad_start){
1124     return;
1125   }
1126 
1127   audio = AGS_MACHINE(lv2_bridge)->audio;
1128 
1129   position = 0;
1130 
1131   input_pads = 0;
1132   audio_channels = 0;
1133 
1134   /* get some fields */
1135   g_object_get(audio,
1136 	       "input-pads", &input_pads,
1137 	       "audio-channels", &audio_channels,
1138 	       NULL);
1139 
1140   /* add to effect bridge */
1141   ags_effect_bulk_add_plugin((AgsEffectBulk *) AGS_EFFECT_BRIDGE(AGS_MACHINE(lv2_bridge)->bridge)->bulk_input,
1142 			     NULL,
1143 			     lv2_bridge->lv2_play_container, lv2_bridge->lv2_recall_container,
1144 			     "ags-fx-lv2",
1145 			     lv2_bridge->filename,
1146 			     lv2_bridge->effect,
1147 			     audio_channel_start, audio_channels,
1148 			     input_pad_start, input_pads,
1149 			     position,
1150 			     (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
1151 
1152   /* source */
1153   if((AGS_MACHINE_IS_SYNTHESIZER & (AGS_MACHINE(lv2_bridge)->flags)) != 0){
1154     /* ags-fx-envelope */
1155     start_recall = ags_fx_factory_create(audio,
1156 					 lv2_bridge->envelope_play_container, lv2_bridge->envelope_recall_container,
1157 					 "ags-fx-envelope",
1158 					 NULL,
1159 					 NULL,
1160 					 audio_channel_start, audio_channels,
1161 					 input_pad_start, input_pads,
1162 					 position,
1163 					 (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
1164 
1165     g_list_free_full(start_recall,
1166 		     (GDestroyNotify) g_object_unref);
1167 
1168     /* ags-fx-buffer */
1169     start_recall = ags_fx_factory_create(audio,
1170 					 lv2_bridge->buffer_play_container, lv2_bridge->buffer_recall_container,
1171 					 "ags-fx-buffer",
1172 					 NULL,
1173 					 NULL,
1174 					 audio_channel_start, audio_channels,
1175 					 input_pad_start, input_pads,
1176 					 position,
1177 					 (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
1178 
1179     g_list_free_full(start_recall,
1180 		     (GDestroyNotify) g_object_unref);
1181   }
1182 
1183   lv2_bridge->mapped_input_pad = input_pads;
1184 }
1185 
1186 void
ags_lv2_bridge_output_map_recall(AgsLv2Bridge * lv2_bridge,guint audio_channel_start,guint output_pad_start)1187 ags_lv2_bridge_output_map_recall(AgsLv2Bridge *lv2_bridge,
1188 				 guint audio_channel_start,
1189 				 guint output_pad_start)
1190 {
1191   AgsAudio *audio;
1192 
1193   guint output_pads;
1194 
1195   if(lv2_bridge->mapped_output_pad > output_pad_start){
1196     return;
1197   }
1198 
1199   audio = AGS_MACHINE(lv2_bridge)->audio;
1200 
1201   output_pads = 0;
1202 
1203   /* get some fields */
1204   g_object_get(audio,
1205 	       "output-pads", &output_pads,
1206 	       NULL);
1207 
1208   lv2_bridge->mapped_output_pad = output_pads;
1209 }
1210 
1211 void
ags_lv2_bridge_load_program(AgsLv2Bridge * lv2_bridge)1212 ags_lv2_bridge_load_program(AgsLv2Bridge *lv2_bridge)
1213 {
1214   AgsLv2Plugin *lv2_plugin;
1215 
1216   LV2_Descriptor *plugin_descriptor;
1217   LV2_Programs_Interface *program_interface;
1218 
1219   /* retrieve lv2 plugin */
1220   lv2_plugin = lv2_bridge->lv2_plugin;
1221 
1222   if(lv2_plugin == NULL){
1223     lv2_plugin =
1224       lv2_bridge->lv2_plugin = ags_lv2_manager_find_lv2_plugin(ags_lv2_manager_get_instance(),
1225 							       lv2_bridge->filename,
1226 							       lv2_bridge->effect);
1227     g_object_ref(lv2_plugin);
1228 
1229     lv2_bridge->lv2_descriptor = AGS_BASE_PLUGIN(lv2_plugin)->plugin_descriptor;
1230   }
1231 
1232   if(lv2_plugin == NULL){
1233     return;
1234   }
1235 
1236   plugin_descriptor = lv2_bridge->lv2_descriptor;
1237 
1238   if(plugin_descriptor != NULL &&
1239      plugin_descriptor->extension_data != NULL &&
1240      (program_interface = plugin_descriptor->extension_data(LV2_PROGRAMS__Interface)) != NULL){
1241     GtkListStore *model;
1242 
1243     GtkTreeIter iter;
1244 
1245     LV2_Program_Descriptor *program_descriptor;
1246 
1247     uint32_t i;
1248 
1249     if(lv2_bridge->lv2_handle == NULL){
1250       guint samplerate;
1251       guint buffer_size;
1252 
1253       g_object_get(AGS_MACHINE(lv2_bridge)->audio,
1254 		   "samplerate", &samplerate,
1255 		   "buffer-size", &buffer_size,
1256 		   NULL);
1257 
1258       lv2_bridge->lv2_handle = ags_base_plugin_instantiate((AgsBasePlugin *) lv2_plugin,
1259 							   samplerate, buffer_size);
1260     }
1261 
1262     if(lv2_bridge->lv2_handle != NULL){
1263       if(lv2_bridge->port_value == NULL){
1264 	GList *start_plugin_port, *plugin_port;
1265 
1266 	guint port_count;
1267 
1268 	g_object_get(lv2_plugin,
1269 		     "plugin-port", &start_plugin_port,
1270 		     NULL);
1271 
1272 	plugin_port = start_plugin_port;
1273 	port_count = g_list_length(start_plugin_port);
1274 
1275 	if(port_count > 0){
1276 	  lv2_bridge->port_value = (float *) malloc(port_count * sizeof(float));
1277 	}
1278 
1279 	while(plugin_port != NULL){
1280 	  if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_CONTROL)){
1281 	    if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_INPUT)){
1282 	      plugin_descriptor->connect_port(lv2_bridge->lv2_handle[0],
1283 					      AGS_PLUGIN_PORT(plugin_port->data)->port_index,
1284 					      &(lv2_bridge->port_value[AGS_PLUGIN_PORT(plugin_port->data)->port_index]));
1285 	    }
1286 	  }
1287 
1288 	  /* iterate */
1289 	  plugin_port = plugin_port->next;
1290 	}
1291 
1292 	g_list_free_full(start_plugin_port,
1293 			 g_object_unref);
1294       }
1295 
1296       if(lv2_bridge->program == NULL){
1297 	GtkBox *hbox;
1298 	GtkLabel *label;
1299 
1300 	/* program */
1301 	hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
1302 				      0);
1303 	gtk_box_pack_start(lv2_bridge->vbox,
1304 			   (GtkWidget *) hbox,
1305 			   FALSE, FALSE,
1306 			   0);
1307 	gtk_box_reorder_child(lv2_bridge->vbox,
1308 			      (GtkWidget *) hbox,
1309 			      0);
1310 
1311 	label = (GtkLabel *) gtk_label_new(i18n("program"));
1312 	gtk_box_pack_start(hbox,
1313 			   (GtkWidget *) label,
1314 			   FALSE, FALSE,
1315 			   0);
1316 
1317 	lv2_bridge->program = (GtkComboBoxText *) gtk_combo_box_text_new();
1318 	gtk_box_pack_start(hbox,
1319 			   (GtkWidget *) lv2_bridge->program,
1320 			   FALSE, FALSE,
1321 			   0);
1322 
1323 	if((AGS_MACHINE_CONNECTED & (AGS_MACHINE(lv2_bridge)->flags)) != 0){
1324 	  g_signal_connect_after(G_OBJECT(lv2_bridge->program), "changed",
1325 				 G_CALLBACK(ags_lv2_bridge_program_changed_callback), lv2_bridge);
1326 	}
1327 
1328 	model = gtk_list_store_new(3,
1329 				   G_TYPE_STRING,
1330 				   G_TYPE_ULONG,
1331 				   G_TYPE_ULONG);
1332 
1333 	gtk_combo_box_set_model(GTK_COMBO_BOX(lv2_bridge->program),
1334 				GTK_TREE_MODEL(model));
1335       }else{
1336 	model = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(lv2_bridge->program)));
1337 
1338 	gtk_list_store_clear(GTK_LIST_STORE(model));
1339       }
1340 
1341       for(i = 0; (program_descriptor = program_interface->get_program(lv2_bridge->lv2_handle[0], i)) != NULL; i++){
1342 	gtk_list_store_append(model, &iter);
1343 	gtk_list_store_set(model, &iter,
1344 			   0, program_descriptor->name,
1345 			   1, program_descriptor->bank,
1346 			   2, program_descriptor->program,
1347 			   -1);
1348       }
1349     }
1350   }
1351 }
1352 
1353 void
ags_lv2_bridge_load_preset(AgsLv2Bridge * lv2_bridge)1354 ags_lv2_bridge_load_preset(AgsLv2Bridge *lv2_bridge)
1355 {
1356   GtkBox *hbox;
1357   GtkLabel *label;
1358 
1359   AgsLv2Plugin *lv2_plugin;
1360 
1361   GList *list;
1362 
1363   /* retrieve lv2 plugin */
1364   lv2_plugin = lv2_bridge->lv2_plugin;
1365 
1366   if(lv2_plugin == NULL){
1367     lv2_plugin =
1368       lv2_bridge->lv2_plugin = ags_lv2_manager_find_lv2_plugin(ags_lv2_manager_get_instance(),
1369 							       lv2_bridge->filename,
1370 							       lv2_bridge->effect);
1371     g_object_ref(lv2_plugin);
1372 
1373     lv2_bridge->lv2_descriptor = AGS_BASE_PLUGIN(lv2_plugin)->plugin_descriptor;
1374   }
1375 
1376   if(lv2_plugin == NULL){
1377     return;
1378   }
1379 
1380   /* preset */
1381   hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
1382 				0);
1383   gtk_box_pack_start(lv2_bridge->vbox,
1384 		     (GtkWidget *) hbox,
1385 		     FALSE, FALSE,
1386 		     0);
1387   gtk_box_reorder_child(lv2_bridge->vbox,
1388   			(GtkWidget *) hbox,
1389   			0);
1390 
1391   label = (GtkLabel *) gtk_label_new(i18n("preset"));
1392   gtk_box_pack_start(hbox,
1393 		     (GtkWidget *) label,
1394 		     FALSE, FALSE,
1395 		     0);
1396 
1397   lv2_bridge->preset = (GtkComboBoxText *) gtk_combo_box_text_new();
1398   gtk_box_pack_start(hbox,
1399 		     (GtkWidget *) lv2_bridge->preset,
1400 		     FALSE, FALSE,
1401 		     0);
1402 
1403   /* preset */
1404   list = lv2_plugin->preset;
1405 
1406   while(list != NULL){
1407     if(AGS_LV2_PRESET(list->data)->preset_label != NULL){
1408       gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(lv2_bridge->preset),
1409 				     AGS_LV2_PRESET(list->data)->preset_label);
1410     }
1411 
1412     list = list->next;
1413   }
1414 
1415   gtk_widget_show_all((GtkWidget *) hbox);
1416 
1417   /* connect preset */
1418   g_signal_connect_after(G_OBJECT(lv2_bridge->preset), "changed",
1419 			 G_CALLBACK(ags_lv2_bridge_preset_changed_callback), lv2_bridge);
1420 }
1421 
1422 void
ags_lv2_bridge_load_midi(AgsLv2Bridge * lv2_bridge)1423 ags_lv2_bridge_load_midi(AgsLv2Bridge *lv2_bridge)
1424 {
1425   //TODO:JK: implement me
1426 }
1427 
1428 void
ags_lv2_bridge_load_gui(AgsLv2Bridge * lv2_bridge)1429 ags_lv2_bridge_load_gui(AgsLv2Bridge *lv2_bridge)
1430 {
1431   AgsLv2Plugin *lv2_plugin;
1432   AgsLv2uiPlugin *lv2ui_plugin;
1433 
1434   GList *list;
1435 
1436   /* retrieve lv2 plugin */
1437   lv2_plugin = lv2_bridge->lv2_plugin;
1438 
1439   if(lv2_plugin == NULL){
1440     lv2_plugin =
1441       lv2_bridge->lv2_plugin = ags_lv2_manager_find_lv2_plugin(ags_lv2_manager_get_instance(),
1442 							       lv2_bridge->filename,
1443 							       lv2_bridge->effect);
1444     g_object_ref(lv2_plugin);
1445 
1446     lv2_bridge->lv2_descriptor = AGS_BASE_PLUGIN(lv2_plugin)->plugin_descriptor;
1447   }
1448 
1449   if(lv2_plugin == NULL ||
1450      lv2_plugin->ui_uri == NULL){
1451     return;
1452   }
1453 
1454   /* retrieve lv2ui plugin */
1455   lv2ui_plugin = lv2_bridge->lv2ui_plugin;
1456 
1457   if(lv2ui_plugin == NULL){
1458     list = ags_lv2ui_plugin_find_gui_uri(ags_lv2ui_manager_get_instance()->lv2ui_plugin,
1459 					 lv2_plugin->ui_uri);
1460 
1461     if(list == NULL){
1462       return;
1463     }
1464 
1465     lv2ui_plugin =
1466       lv2_bridge->lv2ui_plugin = list->data;
1467     g_object_ref(lv2ui_plugin);
1468 
1469     lv2_bridge->ui_descriptor = AGS_BASE_PLUGIN(lv2ui_plugin)->ui_plugin_descriptor;
1470   }
1471 
1472 #ifdef AGS_DEBUG
1473   g_message("ui filename - %s, %s", AGS_BASE_PLUGIN(lv2ui_plugin)->ui_filename, lv2_plugin->ui_uri);
1474 #endif
1475 
1476   /* apply ui */
1477   g_object_set(lv2_bridge,
1478 	       "has-gui", TRUE,
1479 	       "gui-uri", lv2_plugin->ui_uri,
1480 	       "gui-filename", AGS_BASE_PLUGIN(lv2ui_plugin)->ui_filename,
1481 	       NULL);
1482 }
1483 
1484 void
ags_lv2_bridge_load(AgsLv2Bridge * lv2_bridge)1485 ags_lv2_bridge_load(AgsLv2Bridge *lv2_bridge)
1486 {
1487   AgsLv2Plugin *lv2_plugin;
1488 
1489   guint samplerate;
1490   guint buffer_size;
1491 
1492   /* retrieve lv2 plugin */
1493   lv2_plugin = lv2_bridge->lv2_plugin;
1494 
1495   if(lv2_plugin == NULL){
1496     lv2_plugin =
1497       lv2_bridge->lv2_plugin = ags_lv2_manager_find_lv2_plugin(ags_lv2_manager_get_instance(),
1498 							       lv2_bridge->filename,
1499 							       lv2_bridge->effect);
1500     g_object_ref(lv2_plugin);
1501 
1502     lv2_bridge->lv2_descriptor = AGS_BASE_PLUGIN(lv2_plugin)->plugin_descriptor;
1503   }
1504 
1505   if(lv2_plugin == NULL){
1506     return;
1507   }
1508 
1509   /* URI */
1510   g_object_set(lv2_bridge,
1511 	       "uri", lv2_plugin->uri,
1512 	       NULL);
1513 
1514   /* samplerate and buffer size */
1515   samplerate = ags_soundcard_helper_config_get_samplerate(ags_config_get_instance());
1516   buffer_size = ags_soundcard_helper_config_get_buffer_size(ags_config_get_instance());
1517 
1518   /* program */
1519   lv2_bridge->lv2_handle = ags_base_plugin_instantiate((AgsBasePlugin *) lv2_plugin,
1520 						       samplerate, buffer_size);
1521 
1522   if((AGS_LV2_PLUGIN_HAS_PROGRAM_INTERFACE & (lv2_plugin->flags)) != 0){
1523     ags_lv2_bridge_load_program(lv2_bridge);
1524   }
1525 
1526   /* preset */
1527   if(lv2_plugin->preset != NULL){
1528     ags_lv2_bridge_load_preset(lv2_bridge);
1529   }
1530 
1531   /* load gui */
1532   ags_lv2_bridge_load_gui(lv2_bridge);
1533 }
1534 
1535 /**
1536  * ags_lv2_bridge_lv2ui_idle_timeout:
1537  * @widget: LV2UI_Handle
1538  *
1539  * Idle lv2 ui.
1540  *
1541  * Returns: %TRUE if proceed with redraw, otherwise %FALSE
1542  *
1543  * Since: 3.0.0
1544  */
1545 gboolean
ags_lv2_bridge_lv2ui_idle_timeout(GtkWidget * widget)1546 ags_lv2_bridge_lv2ui_idle_timeout(GtkWidget *widget)
1547 {
1548   AgsLv2Bridge *lv2_bridge;
1549 
1550   AgsLv2uiPlugin *lv2ui_plugin;
1551 
1552   int retval;
1553 
1554   /* retrieve lv2ui plugin */
1555   if((lv2_bridge = g_hash_table_lookup(ags_lv2_bridge_lv2ui_idle,
1556 				       widget)) != NULL){
1557     lv2ui_plugin = lv2_bridge->lv2ui_plugin;
1558 
1559     if(lv2ui_plugin->feature != NULL &&
1560        lv2ui_plugin->feature[0]->data != NULL){
1561       retval = ((LV2UI_Idle_Interface *) lv2ui_plugin->feature[0]->data)->idle(lv2_bridge->ui_handle[0]);
1562 
1563       if(retval != 0){
1564 	g_hash_table_remove(ags_lv2_bridge_lv2ui_handle,
1565 			    lv2_bridge->ui_handle);
1566 
1567 	lv2_bridge->ui_handle = NULL;
1568 
1569 	return(FALSE);
1570       }
1571     }
1572 
1573     return(TRUE);
1574   }else{
1575     return(FALSE);
1576   }
1577 }
1578 
1579 /**
1580  * ags_lv2_bridge_new:
1581  * @soundcard: the assigned soundcard.
1582  * @filename: the plugin.so
1583  * @effect: the effect
1584  *
1585  * Create a new instance of #AgsLv2Bridge
1586  *
1587  * Returns: the new #AgsLv2Bridge
1588  *
1589  * Since: 3.0.0
1590  */
1591 AgsLv2Bridge*
ags_lv2_bridge_new(GObject * soundcard,gchar * filename,gchar * effect)1592 ags_lv2_bridge_new(GObject *soundcard,
1593 		   gchar *filename,
1594 		   gchar *effect)
1595 {
1596   AgsLv2Bridge *lv2_bridge;
1597 
1598   lv2_bridge = (AgsLv2Bridge *) g_object_new(AGS_TYPE_LV2_BRIDGE,
1599 					     NULL);
1600 
1601   g_object_set(AGS_MACHINE(lv2_bridge)->audio,
1602 	       "output-soundcard", soundcard,
1603 	       NULL);
1604 
1605   g_object_set(lv2_bridge,
1606 	       "filename", filename,
1607 	       "effect", effect,
1608 	       NULL);
1609 
1610   return(lv2_bridge);
1611 }
1612