1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2020 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/plugin/ags_lv2ui_plugin.h>
21 
22 #include <ags/plugin/ags_lv2_plugin.h>
23 #include <ags/plugin/ags_lv2_event_manager.h>
24 #include <ags/plugin/ags_lv2_uri_map_manager.h>
25 #include <ags/plugin/ags_lv2_log_manager.h>
26 #include <ags/plugin/ags_lv2_urid_manager.h>
27 
28 #if defined(AGS_W32API)
29 #include <windows.h>
30 #else
31 #include <dlfcn.h>
32 #endif
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 
40 #include <math.h>
41 
42 #include <lv2.h>
43 #include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
44 #include <lv2/lv2plug.in/ns/ext/instance-access/instance-access.h>
45 
46 #include <ags/i18n.h>
47 
48 void ags_lv2ui_plugin_class_init(AgsLv2uiPluginClass *lv2ui_plugin);
49 void ags_lv2ui_plugin_init (AgsLv2uiPlugin *lv2ui_plugin);
50 void ags_lv2ui_plugin_set_property(GObject *gobject,
51 				   guint prop_id,
52 				   const GValue *value,
53 				   GParamSpec *param_spec);
54 void ags_lv2ui_plugin_get_property(GObject *gobject,
55 				   guint prop_id,
56 				   GValue *value,
57 				   GParamSpec *param_spec);
58 void ags_lv2ui_plugin_dispose(GObject *gobject);
59 void ags_lv2ui_plugin_finalize(GObject *gobject);
60 
61 gpointer ags_lv2ui_plugin_instantiate_with_params(AgsBasePlugin *base_plugin,
62 						  guint *n_params,
63 						  gchar ***parameter_name,
64 						  GValue **value);
65 
66 void ags_lv2ui_plugin_connect_port(AgsBasePlugin *base_plugin,
67 				   gpointer plugin_handle,
68 				   guint port_index,
69 				   gpointer data_location);
70 void ags_lv2ui_plugin_activate(AgsBasePlugin *base_plugin,
71 			       gpointer plugin_handle);
72 void ags_lv2ui_plugin_deactivate(AgsBasePlugin *base_plugin,
73 				 gpointer plugin_handle);
74 void ags_lv2ui_plugin_run(AgsBasePlugin *base_plugin,
75 			  gpointer plugin_handle,
76 			  snd_seq_event_t *seq_event,
77 			  guint frame_count);
78 void ags_lv2ui_plugin_load_plugin(AgsBasePlugin *base_plugin);
79 
80 /**
81  * SECTION:ags_lv2ui_plugin
82  * @short_description: The lv2ui plugin class
83  * @title: AgsLv2uiPlugin
84  * @section_id:
85  * @include: ags/plugin/ags_lv2ui_plugin.h
86  *
87  * The #AgsLv2uiPlugin loads/unloads a Lv2ui plugin.
88  */
89 
90 enum{
91   PROP_0,
92   PROP_GUI_FILENAME,
93   PROP_GUI_URI,
94   PROP_MANIFEST,
95   PROP_GUI_TURTLE,
96   PROP_LV2_PLUGIN,
97 };
98 
99 static gpointer ags_lv2ui_plugin_parent_class = NULL;
100 
101 GType
ags_lv2ui_plugin_get_type(void)102 ags_lv2ui_plugin_get_type (void)
103 {
104   static volatile gsize g_define_type_id__volatile = 0;
105 
106   if(g_once_init_enter (&g_define_type_id__volatile)){
107     GType ags_type_lv2ui_plugin = 0;
108 
109     static const GTypeInfo ags_lv2ui_plugin_info = {
110       sizeof (AgsLv2uiPluginClass),
111       NULL, /* lv2ui_init */
112       NULL, /* lv2ui_finalize */
113       (GClassInitFunc) ags_lv2ui_plugin_class_init,
114       NULL, /* class_finalize */
115       NULL, /* class_data */
116       sizeof (AgsLv2uiPlugin),
117       0,    /* n_preallocs */
118       (GInstanceInitFunc) ags_lv2ui_plugin_init,
119     };
120 
121     ags_type_lv2ui_plugin = g_type_register_static(AGS_TYPE_BASE_PLUGIN,
122 						   "AgsLv2uiPlugin",
123 						   &ags_lv2ui_plugin_info,
124 						   0);
125 
126     g_once_init_leave(&g_define_type_id__volatile, ags_type_lv2ui_plugin);
127   }
128 
129   return g_define_type_id__volatile;
130 }
131 
132 GType
ags_lv2ui_plugin_flags_get_type()133 ags_lv2ui_plugin_flags_get_type()
134 {
135   static volatile gsize g_flags_type_id__volatile;
136 
137   if(g_once_init_enter (&g_flags_type_id__volatile)){
138     static const GFlagsValue values[] = {
139       { AGS_LV2UI_PLUGIN_IS_SYNTHESIZER, "AGS_LV2UI_PLUGIN_IS_SYNTHESIZER", "lv2ui-plugin-is-synthesizer" },
140       { AGS_LV2UI_PLUGIN_GTK2, "AGS_LV2UI_PLUGIN_GTK2", "lv2ui-plugin-gtk2" },
141       { AGS_LV2UI_PLUGIN_GTK3, "AGS_LV2UI_PLUGIN_GTK3", "lv2ui-plugin-gtk3" },
142       { AGS_LV2UI_PLUGIN_QT4, "AGS_LV2UI_PLUGIN_QT4", "lv2ui-plugin-qt4" },
143       { AGS_LV2UI_PLUGIN_QT5, "AGS_LV2UI_PLUGIN_QT5", "lv2ui-plugin-qt5" },
144       { 0, NULL, NULL }
145     };
146 
147     GType g_flags_type_id = g_flags_register_static(g_intern_static_string("AgsLv2uiPluginFlags"), values);
148 
149     g_once_init_leave (&g_flags_type_id__volatile, g_flags_type_id);
150   }
151 
152   return g_flags_type_id__volatile;
153 }
154 
155 void
ags_lv2ui_plugin_class_init(AgsLv2uiPluginClass * lv2ui_plugin)156 ags_lv2ui_plugin_class_init(AgsLv2uiPluginClass *lv2ui_plugin)
157 {
158   AgsBasePluginClass *base_plugin;
159 
160   GObjectClass *gobject;
161   GParamSpec *param_spec;
162 
163   ags_lv2ui_plugin_parent_class = g_type_class_peek_parent(lv2ui_plugin);
164 
165   /* GObjectClass */
166   gobject = (GObjectClass *) lv2ui_plugin;
167 
168   gobject->set_property = ags_lv2ui_plugin_set_property;
169   gobject->get_property = ags_lv2ui_plugin_get_property;
170 
171   gobject->dispose = ags_lv2ui_plugin_dispose;
172   gobject->finalize = ags_lv2ui_plugin_finalize;
173 
174   /* properties */
175   /**
176    * AgsLv2uiPlugin:gui-uri:
177    *
178    * The assigned GUI URI.
179    *
180    * Since: 3.0.0
181    */
182   param_spec = g_param_spec_string("gui-uri",
183 				   i18n_pspec("GUI URI of the plugin"),
184 				   i18n_pspec("The GUI URI this plugin is located in"),
185 				   NULL,
186 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
187   g_object_class_install_property(gobject,
188 				  PROP_GUI_URI,
189 				  param_spec);
190 
191   /**
192    * AgsLv2uiPlugin:manifest:
193    *
194    * The assigned manifest.
195    *
196    * Since: 3.0.0
197    */
198   param_spec = g_param_spec_object("manifest",
199 				   i18n_pspec("manifest of the plugin"),
200 				   i18n_pspec("The manifest this plugin is located in"),
201 				   AGS_TYPE_TURTLE,
202 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
203   g_object_class_install_property(gobject,
204 				  PROP_MANIFEST,
205 				  param_spec);
206 
207   /**
208    * AgsLv2uiPlugin:gui-turtle:
209    *
210    * The assigned GUI turtle.
211    *
212    * Since: 3.0.0
213    */
214   param_spec = g_param_spec_object("gui-turtle",
215 				   i18n_pspec("GUI turtle of the plugin"),
216 				   i18n_pspec("The GUI turtle this plugin is located in"),
217 				   AGS_TYPE_TURTLE,
218 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
219   g_object_class_install_property(gobject,
220 				  PROP_GUI_TURTLE,
221 				  param_spec);
222 
223   /**
224    * AgsLv2uiPlugin:lv2-plugin:
225    *
226    * The assigned LV2 plugin.
227    *
228    * Since: 3.0.0
229    */
230   param_spec = g_param_spec_object("lv2-plugin",
231 				   i18n_pspec("LV2 plugin of the plugin"),
232 				   i18n_pspec("The LV2 plugin this plugin is located in"),
233 				   AGS_TYPE_LV2_PLUGIN,
234 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
235   g_object_class_install_property(gobject,
236 				  PROP_LV2_PLUGIN,
237 				  param_spec);
238 
239   /* AgsBasePluginClass */
240   base_plugin = (AgsBasePluginClass *) lv2ui_plugin;
241 
242   base_plugin->instantiate_with_params = ags_lv2ui_plugin_instantiate_with_params;
243   base_plugin->load_plugin = ags_lv2ui_plugin_load_plugin;
244 }
245 
246 void
ags_lv2ui_plugin_init(AgsLv2uiPlugin * lv2ui_plugin)247 ags_lv2ui_plugin_init(AgsLv2uiPlugin *lv2ui_plugin)
248 {
249   lv2ui_plugin->flags = 0;
250 
251   lv2ui_plugin->gui_uri = NULL;
252 
253   lv2ui_plugin->manifest = NULL;
254   lv2ui_plugin->gui_turtle = NULL;
255 
256   lv2ui_plugin->lv2_plugin = NULL;
257 
258   lv2ui_plugin->feature = NULL;
259 }
260 
261 void
ags_lv2ui_plugin_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)262 ags_lv2ui_plugin_set_property(GObject *gobject,
263 			      guint prop_id,
264 			      const GValue *value,
265 			      GParamSpec *param_spec)
266 {
267   AgsLv2uiPlugin *lv2ui_plugin;
268 
269   GRecMutex *base_plugin_mutex;
270 
271   lv2ui_plugin = AGS_LV2UI_PLUGIN(gobject);
272 
273   /* get base plugin mutex */
274   base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(lv2ui_plugin);
275 
276   switch(prop_id){
277   case PROP_GUI_URI:
278     {
279       gchar *gui_uri;
280 
281       gui_uri = (gchar *) g_value_get_string(value);
282 
283       g_rec_mutex_lock(base_plugin_mutex);
284 
285       if(lv2ui_plugin->gui_uri == gui_uri){
286 	g_rec_mutex_unlock(base_plugin_mutex);
287 
288 	return;
289       }
290 
291       if(lv2ui_plugin->gui_uri != NULL){
292 	g_free(lv2ui_plugin->gui_uri);
293       }
294 
295       lv2ui_plugin->gui_uri = g_strdup(gui_uri);
296 
297       g_rec_mutex_unlock(base_plugin_mutex);
298     }
299     break;
300   case PROP_MANIFEST:
301     {
302       AgsTurtle *manifest;
303 
304       manifest = (AgsTurtle *) g_value_get_object(value);
305 
306       g_rec_mutex_lock(base_plugin_mutex);
307 
308       if(lv2ui_plugin->manifest == manifest){
309 	g_rec_mutex_unlock(base_plugin_mutex);
310 
311 	return;
312       }
313 
314       if(lv2ui_plugin->manifest != NULL){
315 	g_object_unref(lv2ui_plugin->manifest);
316       }
317 
318       if(manifest != NULL){
319 	g_object_ref(manifest);
320       }
321 
322       lv2ui_plugin->manifest = manifest;
323 
324       g_rec_mutex_unlock(base_plugin_mutex);
325     }
326     break;
327   case PROP_GUI_TURTLE:
328     {
329       AgsTurtle *gui_turtle;
330 
331       gui_turtle = (AgsTurtle *) g_value_get_object(value);
332 
333       g_rec_mutex_lock(base_plugin_mutex);
334 
335       if(lv2ui_plugin->gui_turtle == gui_turtle){
336 	g_rec_mutex_unlock(base_plugin_mutex);
337 
338 	return;
339       }
340 
341       if(lv2ui_plugin->gui_turtle != NULL){
342 	g_object_unref(lv2ui_plugin->gui_turtle);
343       }
344 
345       if(gui_turtle != NULL){
346 	g_object_ref(gui_turtle);
347       }
348 
349       lv2ui_plugin->gui_turtle = gui_turtle;
350 
351       g_rec_mutex_unlock(base_plugin_mutex);
352     }
353     break;
354   case PROP_LV2_PLUGIN:
355     {
356       GObject *lv2_plugin;
357 
358       lv2_plugin = (GObject *) g_value_get_object(value);
359 
360       g_rec_mutex_lock(base_plugin_mutex);
361 
362       if(lv2ui_plugin->lv2_plugin == lv2_plugin){
363 	g_rec_mutex_unlock(base_plugin_mutex);
364 
365 	return;
366       }
367 
368       if(lv2ui_plugin->lv2_plugin != NULL){
369 	g_object_unref(lv2ui_plugin->lv2_plugin);
370       }
371 
372       if(lv2_plugin != NULL){
373 	g_object_ref(lv2_plugin);
374       }
375 
376       lv2ui_plugin->lv2_plugin = lv2_plugin;
377 
378       g_rec_mutex_unlock(base_plugin_mutex);
379     }
380     break;
381   default:
382     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
383     break;
384   }
385 }
386 
387 void
ags_lv2ui_plugin_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)388 ags_lv2ui_plugin_get_property(GObject *gobject,
389 			      guint prop_id,
390 			      GValue *value,
391 			      GParamSpec *param_spec)
392 {
393   AgsLv2uiPlugin *lv2ui_plugin;
394 
395   GRecMutex *base_plugin_mutex;
396 
397   lv2ui_plugin = AGS_LV2UI_PLUGIN(gobject);
398 
399   /* get base plugin mutex */
400   base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(lv2ui_plugin);
401 
402   switch(prop_id){
403   case PROP_GUI_URI:
404     {
405       g_rec_mutex_lock(base_plugin_mutex);
406 
407       g_value_set_string(value, lv2ui_plugin->gui_uri);
408 
409       g_rec_mutex_unlock(base_plugin_mutex);
410     }
411     break;
412   case PROP_MANIFEST:
413     {
414       g_rec_mutex_lock(base_plugin_mutex);
415 
416       g_value_set_object(value, lv2ui_plugin->manifest);
417 
418       g_rec_mutex_unlock(base_plugin_mutex);
419     }
420     break;
421   case PROP_GUI_TURTLE:
422     {
423       g_rec_mutex_lock(base_plugin_mutex);
424 
425       g_value_set_object(value, lv2ui_plugin->gui_turtle);
426 
427       g_rec_mutex_unlock(base_plugin_mutex);
428     }
429     break;
430   case PROP_LV2_PLUGIN:
431     {
432       g_rec_mutex_lock(base_plugin_mutex);
433 
434       g_value_set_object(value, lv2ui_plugin->lv2_plugin);
435 
436       g_rec_mutex_unlock(base_plugin_mutex);
437     }
438     break;
439   default:
440     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
441     break;
442   }
443 }
444 
445 void
ags_lv2ui_plugin_dispose(GObject * gobject)446 ags_lv2ui_plugin_dispose(GObject *gobject)
447 {
448   AgsLv2uiPlugin *lv2ui_plugin;
449 
450   lv2ui_plugin = AGS_LV2UI_PLUGIN(gobject);
451 
452   if(lv2ui_plugin->manifest != NULL){
453     g_object_unref(lv2ui_plugin->manifest);
454 
455     lv2ui_plugin->manifest = NULL;
456   }
457 
458   if(lv2ui_plugin->gui_turtle != NULL){
459     g_object_unref(lv2ui_plugin->gui_turtle);
460 
461     lv2ui_plugin->gui_turtle = NULL;
462   }
463 
464   if(lv2ui_plugin->lv2_plugin != NULL){
465     g_object_unref(lv2ui_plugin->lv2_plugin);
466 
467     lv2ui_plugin->lv2_plugin = NULL;
468   }
469 
470   /* call parent */
471   G_OBJECT_CLASS(ags_lv2ui_plugin_parent_class)->dispose(gobject);
472 }
473 
474 void
ags_lv2ui_plugin_finalize(GObject * gobject)475 ags_lv2ui_plugin_finalize(GObject *gobject)
476 {
477   AgsLv2uiPlugin *lv2ui_plugin;
478 
479   lv2ui_plugin = AGS_LV2UI_PLUGIN(gobject);
480 
481   g_free(lv2ui_plugin->gui_uri);
482 
483   if(lv2ui_plugin->manifest != NULL){
484     g_object_unref(lv2ui_plugin->manifest);
485   }
486 
487   if(lv2ui_plugin->gui_turtle != NULL){
488     g_object_unref(lv2ui_plugin->gui_turtle);
489   }
490 
491   if(lv2ui_plugin->lv2_plugin != NULL){
492     g_object_unref(lv2ui_plugin->lv2_plugin);
493   }
494 
495   /* call parent */
496   G_OBJECT_CLASS(ags_lv2ui_plugin_parent_class)->finalize(gobject);
497 }
498 
499 void
ags_lv2ui_plugin_load_plugin(AgsBasePlugin * base_plugin)500 ags_lv2ui_plugin_load_plugin(AgsBasePlugin *base_plugin)
501 {
502   //NOTE:JK: deprecated
503 }
504 
505 gpointer
ags_lv2ui_plugin_instantiate_with_params(AgsBasePlugin * base_plugin,guint * n_params,gchar *** parameter_name,GValue ** value)506 ags_lv2ui_plugin_instantiate_with_params(AgsBasePlugin *base_plugin,
507 					 guint *n_params,
508 					 gchar ***parameter_name,
509 					 GValue **value)
510 {
511   AgsLv2uiPlugin *lv2ui_plugin;
512 
513   LV2UI_Controller controller;
514   LV2UI_Widget widget;
515 
516   void *ui_plugin_so;
517   LV2UI_DescriptorFunction lv2ui_descriptor;
518   LV2UI_Descriptor *plugin_descriptor;
519 
520   LV2_Handle *lv2_handle;
521   LV2UI_Handle *ui_handle;
522 
523   LV2_URI_Map_Feature *uri_map_feature;
524 
525   LV2_Log_Log *log_feature;
526 
527   LV2_Event_Feature *event_feature;
528 
529   LV2_URID_Map *urid_map;
530   LV2_URID_Unmap *urid_unmap;
531 
532   LV2UI_Write_Function write_function;
533 
534   LV2_Feature **feature;
535 
536   gchar *uri;
537   gchar *filename;
538   char *path;
539   gchar *str;
540 
541   float *ptr_samplerate;
542   float *ptr_buffer_size;
543 
544   uint32_t ui_effect_index;
545   guint local_n_params;
546   guint total_feature;
547   guint nth;
548   guint i;
549   gboolean initial_call;
550 
551   LV2UI_Handle (*instantiate)(const struct _LV2UI_Descriptor* descriptor,
552 			      const char *plugin_uri,
553 			      const char *bundle_path,
554 			      LV2UI_Write_Function write_function,
555 			      LV2UI_Controller controller,
556 			      LV2UI_Widget *widget,
557 			      const LV2_Feature *const *features);
558 
559   GRecMutex *base_plugin_mutex;
560 
561   lv2ui_plugin = AGS_LV2UI_PLUGIN(base_plugin);
562 
563   /* get base plugin mutex */
564   base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(base_plugin);
565 
566   local_n_params = 0;
567 
568   if(n_params == NULL){
569     n_params = &local_n_params;
570   }
571 
572   /* get some fields */
573   g_rec_mutex_lock(base_plugin_mutex);
574 
575   ui_plugin_so = base_plugin->ui_plugin_so;
576   ui_effect_index = 0;
577 
578   if(ui_plugin_so == NULL){
579     gboolean success;
580 
581     g_message("open %s", base_plugin->ui_filename);
582 
583 #ifdef AGS_W32API
584     ui_plugin_so = LoadLibrary(base_plugin->filename);
585 #else
586     ui_plugin_so = dlopen(base_plugin->filename,
587 			  RTLD_NOW);
588 #endif
589 
590     g_object_set(lv2ui_plugin,
591 		 "ui-plugin-so", ui_plugin_so,
592 		 NULL);
593 
594     success = FALSE;
595 
596 #ifdef AGS_W32API
597     base_plugin->ui_plugin_handle =
598       lv2ui_descriptor = (LV2_Descriptor_Function) GetProcAddress(ui_plugin_so,
599 								  "lv2ui_descriptor");
600 
601     success = (!lv2_descriptor) ? FALSE: TRUE;
602 #else
603     base_plugin->ui_plugin_handle =
604       lv2ui_descriptor = (LV2_Descriptor_Function) dlsym(ui_plugin_so,
605 							 "lv2ui_descriptor");
606 
607     success = (dlerror() == NULL) ? TRUE: FALSE;
608 #endif
609 
610     if(success && lv2_descriptor){
611       for(i = 0; (plugin_descriptor = lv2ui_descriptor((uint32_t) i)) != NULL; i++){
612 	if(!g_ascii_strcasecmp(plugin_descriptor->URI,
613 			       lv2ui_plugin->gui_uri)){
614 	  base_plugin->ui_plugin_descriptor = plugin_descriptor;
615 	  ui_effect_index = i;
616 
617 	  g_object_set(lv2ui_plugin,
618 		       "ui-effect-index", ui_effect_index,
619 		       NULL);
620 
621 	  break;
622 	}
623       }
624     }
625   }
626 
627   lv2ui_descriptor = base_plugin->ui_plugin_handle;
628   plugin_descriptor = base_plugin->ui_plugin_descriptor;
629 
630   feature = lv2ui_plugin->feature;
631 
632   path = g_path_get_dirname(base_plugin->ui_filename);
633 
634   ui_effect_index = base_plugin->ui_effect_index;
635 
636   g_rec_mutex_unlock(base_plugin_mutex);
637 
638   if(ui_plugin_so == NULL){
639     g_free(path);
640 
641     return(NULL);
642   }
643 
644   /* check args */
645   uri = NULL;
646 
647   controller = NULL;
648   widget = NULL;
649 
650   write_function = NULL;
651 
652   lv2_handle = NULL;
653 
654   if(n_params != NULL &&
655      parameter_name != NULL &&
656      parameter_name[0] != NULL &&
657      value != NULL &&
658      value[0] != NULL){
659     for(i = 0; i < n_params[0] && parameter_name[0][i] != NULL; i++){
660       if(!g_ascii_strncasecmp(parameter_name[0][i],
661 			      "uri",
662 			      4)){
663 	uri = g_value_get_pointer(&(value[0][i]));
664       }else if(!g_ascii_strncasecmp(parameter_name[0][i],
665 			      "controller",
666 			      11)){
667 	controller = g_value_get_pointer(&(value[0][i]));
668       }else if(!g_ascii_strncasecmp(parameter_name[0][i],
669 				    "write-function",
670 				    15)){
671 	write_function = g_value_get_pointer(&(value[0][i]));
672       }else if(!g_ascii_strncasecmp(parameter_name[0][i],
673 				    "instance",
674 				    9)){
675 	lv2_handle = g_value_get_pointer(&(value[0][i]));
676       }
677     }
678   }
679 
680   /* features */
681   initial_call = FALSE;
682 
683   if(feature == NULL){
684     initial_call = TRUE;
685 
686     /**/
687     total_feature = 9;
688     nth = 0;
689 
690     feature = (LV2_Feature **) malloc(total_feature * sizeof(LV2_Feature *));
691 
692     /* idle interface */
693     feature[nth] = (LV2_Feature *) malloc(sizeof(LV2_Feature));
694     feature[nth]->URI = LV2_UI__idleInterface;
695     feature[nth]->data = NULL;
696 
697     nth++;
698 
699     /* show interface */
700     feature[nth] = (LV2_Feature *) malloc(sizeof(LV2_Feature));
701     feature[nth]->URI = LV2_UI__showInterface;
702     feature[nth]->data = NULL;
703 
704     nth++;
705 
706     /* instance access */
707     feature[nth] = (LV2_Feature *) malloc(sizeof(LV2_Feature));
708     feature[nth]->URI = LV2_INSTANCE_ACCESS_URI;
709     feature[nth]->data = NULL;
710 
711     if(lv2_handle != NULL){
712       feature[nth]->data = lv2_handle[0];
713     }
714 
715     nth++;
716 
717     /* URI map feature */
718     uri_map_feature = (LV2_URI_Map_Feature *) malloc(sizeof(LV2_URI_Map_Feature));
719     uri_map_feature->callback_data = NULL;
720     uri_map_feature->uri_to_id = ags_lv2_uri_map_manager_uri_to_id;
721 
722     feature[nth] = (LV2_Feature *) malloc(sizeof(LV2_Feature));
723     feature[nth]->URI = LV2_URI_MAP_URI;
724     feature[nth]->data = uri_map_feature;
725 
726     nth++;
727 
728     /* log feature */
729 #if 0
730     log_feature = (LV2_Log_Log *) malloc(sizeof(LV2_Log_Log));
731 
732     log_feature->handle = NULL;
733     log_feature->printf = ags_lv2_log_manager_printf;
734     log_feature->vprintf = ags_lv2_log_manager_vprintf;
735 
736     feature[nth] = (LV2_Feature *) malloc(sizeof(LV2_Feature));
737     feature[nth]->URI = LV2_LOG__log;
738     feature[nth]->data = log_feature;
739 
740     nth++;
741 #endif
742 
743     /* event feature */
744     event_feature = (LV2_Event_Feature *) malloc(sizeof(LV2_Event_Feature));
745 
746     event_feature->callback_data = NULL;
747     event_feature->lv2_event_ref = ags_lv2_event_manager_lv2_event_ref;
748     event_feature->lv2_event_unref = ags_lv2_event_manager_lv2_event_unref;
749 
750     feature[nth] = (LV2_Feature *) malloc(sizeof(LV2_Feature));
751     feature[nth]->URI = LV2_EVENT_URI;
752     feature[nth]->data = event_feature;
753 
754     nth++;
755 
756     /* URID map feature */
757     urid_map = (LV2_URID_Map *) malloc(sizeof(LV2_URID_Map));
758     urid_map->handle = NULL;
759     urid_map->map = ags_lv2_urid_manager_map;
760 
761     feature[nth] = (LV2_Feature *) malloc(sizeof(LV2_Feature));
762     feature[nth]->URI = LV2_URID_MAP_URI;
763     feature[nth]->data = urid_map;
764 
765     nth++;
766 
767     /* URID unmap feature */
768     urid_unmap = (LV2_URID_Unmap *) malloc(sizeof(LV2_URID_Unmap));
769     urid_unmap->handle = NULL;
770     urid_unmap->unmap = ags_lv2_urid_manager_unmap;
771 
772     feature[nth] = (LV2_Feature *) malloc(sizeof(LV2_Feature));
773     feature[nth]->URI = LV2_URID_UNMAP_URI;
774     feature[nth]->data = urid_unmap;
775 
776     nth++;
777 
778     /* terminate */
779     for(; nth < total_feature; nth++){
780       feature[nth] = NULL;
781     }
782 
783     g_rec_mutex_lock(base_plugin_mutex);
784 
785     lv2ui_plugin->feature = feature;
786 
787     g_rec_mutex_unlock(base_plugin_mutex);
788   }
789 
790   instantiate = NULL;
791 
792   if(plugin_descriptor != NULL){
793     g_rec_mutex_lock(base_plugin_mutex);
794 
795     instantiate = plugin_descriptor->instantiate;
796 
797     g_rec_mutex_unlock(base_plugin_mutex);
798   }
799 
800   /* instantiate */
801   ui_handle = (LV2UI_Handle *) malloc(sizeof(LV2UI_Handle));
802 
803   ui_handle[0] = NULL;
804 
805   if(instantiate != NULL){
806     ui_handle[0] = instantiate(plugin_descriptor,
807 			       uri,
808 			       path,
809 			       write_function,
810 			       controller,
811 			       &widget,
812 			       feature);
813   }
814 
815   g_message("LV2UI handle = %p", ui_handle[0]);
816 
817   if(parameter_name != NULL &&
818      value != NULL){
819     if(n_params[0] == 0){
820       parameter_name[0] = (gchar **) malloc(2 * sizeof(gchar *));
821       value[0] = g_new0(GValue,
822 			1);
823     }else{
824       parameter_name[0] = (gchar **) realloc(parameter_name[0],
825 					     (n_params[0] + 2) * sizeof(gchar *));
826       value[0] = g_renew(GValue,
827 			 value[0],
828 			 n_params[0] + 1);
829     }
830 
831     parameter_name[0][n_params[0]] = g_strdup("widget");
832     g_value_init(&(value[0][n_params[0]]),
833 		 G_TYPE_POINTER);
834     g_value_set_pointer(&(value[0][n_params[0]]), widget);
835 
836     parameter_name[0][n_params[0] + 1] = NULL;
837 
838     n_params[0] += 1;
839   }
840 
841   return(ui_handle);
842 }
843 
844 /**
845  * ags_lv2ui_plugin_test_flags:
846  * @lv2ui_plugin: the #AgsLv2uiPlugin
847  * @flags: the flags
848  *
849  * Test @flags to be set on @recall.
850  *
851  * Returns: %TRUE if flags are set, else %FALSE
852  *
853  * Since: 3.0.0
854  */
855 gboolean
ags_lv2ui_plugin_test_flags(AgsLv2uiPlugin * lv2ui_plugin,guint flags)856 ags_lv2ui_plugin_test_flags(AgsLv2uiPlugin *lv2ui_plugin, guint flags)
857 {
858   gboolean retval;
859 
860   GRecMutex *base_plugin_mutex;
861 
862   if(!AGS_IS_LV2UI_PLUGIN(lv2ui_plugin)){
863     return(FALSE);
864   }
865 
866   /* get base plugin mutex */
867   base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(lv2ui_plugin);
868 
869   /* test flags */
870   g_rec_mutex_lock(base_plugin_mutex);
871 
872   retval = ((flags & (lv2ui_plugin->flags)) != 0) ? TRUE: FALSE;
873 
874   g_rec_mutex_unlock(base_plugin_mutex);
875 
876   return(retval);
877 }
878 
879 /**
880  * ags_lv2ui_plugin_set_flags:
881  * @lv2ui_plugin: the #AgsLv2uiPlugin
882  * @flags: the flags
883  *
884  * Set flags.
885  *
886  * Since: 3.0.0
887  */
888 void
ags_lv2ui_plugin_set_flags(AgsLv2uiPlugin * lv2ui_plugin,guint flags)889 ags_lv2ui_plugin_set_flags(AgsLv2uiPlugin *lv2ui_plugin, guint flags)
890 {
891   GRecMutex *base_plugin_mutex;
892 
893   if(!AGS_IS_LV2UI_PLUGIN(lv2ui_plugin)){
894     return;
895   }
896 
897   /* get base plugin mutex */
898   base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(lv2ui_plugin);
899 
900   /* set flags */
901   g_rec_mutex_lock(base_plugin_mutex);
902 
903   lv2ui_plugin->flags |= flags;
904 
905   g_rec_mutex_unlock(base_plugin_mutex);
906 }
907 
908 /**
909  * ags_lv2ui_plugin_unset_flags:
910  * @lv2ui_plugin: the #AgsLv2uiPlugin
911  * @flags: the flags
912  *
913  * Unset flags.
914  *
915  * Since: 3.0.0
916  */
917 void
ags_lv2ui_plugin_unset_flags(AgsLv2uiPlugin * lv2ui_plugin,guint flags)918 ags_lv2ui_plugin_unset_flags(AgsLv2uiPlugin *lv2ui_plugin, guint flags)
919 {
920   GRecMutex *base_plugin_mutex;
921 
922   if(!AGS_IS_LV2UI_PLUGIN(lv2ui_plugin)){
923     return;
924   }
925 
926   /* get base plugin mutex */
927   base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(lv2ui_plugin);
928 
929   /* unset flags */
930   g_rec_mutex_lock(base_plugin_mutex);
931 
932   lv2ui_plugin->flags &= (~flags);
933 
934   g_rec_mutex_unlock(base_plugin_mutex);
935 }
936 
937 /**
938  * ags_lv2ui_plugin_find_gui_uri:
939  * @lv2ui_plugin: (element-type AgsAudio.Lv2uiPlugin) (transfer none): the #GList-struct containing #AgsLv2uiPlugin
940  * @gui_uri: the gui-uri as string
941  *
942  * Find next matching gui-uri in @lv2ui_plugin.
943  *
944  * Returns: (element-type AgsAudio.Lv2uiPlugin) (transfer none): the next matching #GList-struct
945  *
946  * Since: 3.0.0
947  */
948 GList*
ags_lv2ui_plugin_find_gui_uri(GList * lv2ui_plugin,gchar * gui_uri)949 ags_lv2ui_plugin_find_gui_uri(GList *lv2ui_plugin,
950 			      gchar *gui_uri)
951 {
952   if(gui_uri == NULL){
953     return(NULL);
954   }
955 
956   while(lv2ui_plugin != NULL){
957     if(AGS_LV2UI_PLUGIN(lv2ui_plugin->data)->gui_uri != NULL &&
958        !g_ascii_strcasecmp(AGS_LV2UI_PLUGIN(lv2ui_plugin->data)->gui_uri,
959 			   gui_uri)){
960       return(lv2ui_plugin);
961     }
962 
963     lv2ui_plugin = lv2ui_plugin->next;
964   }
965 
966   return(NULL);
967 }
968 
969 /**
970  * ags_lv2ui_plugin_new:
971  * @gui_turtle: the #AgsTurtle
972  * @filename: the plugin .so
973  * @effect: the effect's string representation
974  * @gui_uri: the effect's gui_uri
975  * @effect_index: the effect's index
976  *
977  * Creates an #AgsLv2uiPlugin
978  *
979  * Returns: a new #AgsLv2uiPlugin
980  *
981  * Since: 3.0.0
982  */
983 AgsLv2uiPlugin*
ags_lv2ui_plugin_new(AgsTurtle * gui_turtle,gchar * filename,gchar * effect,gchar * gui_uri,guint effect_index)984 ags_lv2ui_plugin_new(AgsTurtle *gui_turtle,
985 		     gchar *filename,
986 		     gchar *effect,
987 		     gchar *gui_uri,
988 		     guint effect_index)
989 {
990   AgsLv2uiPlugin *lv2ui_plugin;
991 
992   lv2ui_plugin = (AgsLv2uiPlugin *) g_object_new(AGS_TYPE_LV2UI_PLUGIN,
993 						 "gui-turtle", gui_turtle,
994 						 "filename", filename,
995 						 "effect", effect,
996 						 "gui-uri", gui_uri,
997 						 "effect-index", effect_index,
998 						 NULL);
999 
1000   return(lv2ui_plugin);
1001 }
1002