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_lv2_manager.h>
21 
22 #include <ags/plugin/ags_base_plugin.h>
23 #include <ags/plugin/ags_lv2_turtle_parser.h>
24 #include <ags/plugin/ags_lv2_turtle_scanner.h>
25 
26 #if defined(AGS_W32API)
27 #include <windows.h>
28 #else
29 #include <dlfcn.h>
30 #endif
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37 
38 #include <string.h>
39 #include <strings.h>
40 
41 #include <ags/config.h>
42 
43 void ags_lv2_manager_class_init(AgsLv2ManagerClass *lv2_manager);
44 void ags_lv2_manager_init (AgsLv2Manager *lv2_manager);
45 void ags_lv2_manager_set_property(GObject *gobject,
46 				  guint prop_id,
47 				  const GValue *value,
48 				  GParamSpec *param_spec);
49 void ags_lv2_manager_get_property(GObject *gobject,
50 				  guint prop_id,
51 				  GValue *value,
52 				  GParamSpec *param_spec);
53 void ags_lv2_manager_dispose(GObject *gobject);
54 void ags_lv2_manager_finalize(GObject *gobject);
55 
56 gint ags_lv2_manager_compare_strv(gconstpointer a,
57 				  gconstpointer b);
58 
59 /**
60  * SECTION:ags_lv2_manager
61  * @short_description: Singleton pattern to organize LV2
62  * @title: AgsLv2Manager
63  * @section_id:
64  * @include: ags/plugin/ags_lv2_manager.h
65  *
66  * The #AgsLv2Manager loads/unloads LV2 plugins.
67  */
68 
69 enum{
70   PROP_0,
71   PROP_LOCALE,
72 };
73 
74 static gpointer ags_lv2_manager_parent_class = NULL;
75 
76 AgsLv2Manager *ags_lv2_manager = NULL;
77 gchar **ags_lv2_default_path = NULL;
78 
79 static gboolean ags_lv2_manager_global_parse_names = TRUE;
80 static gboolean ags_lv2_manager_global_preserve_turtle = TRUE;
81 
82 GType
ags_lv2_manager_get_type(void)83 ags_lv2_manager_get_type (void)
84 {
85   static volatile gsize g_define_type_id__volatile = 0;
86 
87   if(g_once_init_enter (&g_define_type_id__volatile)){
88     GType ags_type_lv2_manager = 0;
89 
90     static const GTypeInfo ags_lv2_manager_info = {
91       sizeof (AgsLv2ManagerClass),
92       NULL, /* base_init */
93       NULL, /* base_finalize */
94       (GClassInitFunc) ags_lv2_manager_class_init,
95       NULL, /* class_finalize */
96       NULL, /* class_data */
97       sizeof (AgsLv2Manager),
98       0,    /* n_preallocs */
99       (GInstanceInitFunc) ags_lv2_manager_init,
100     };
101 
102     ags_type_lv2_manager = g_type_register_static(G_TYPE_OBJECT,
103 						  "AgsLv2Manager",
104 						  &ags_lv2_manager_info,
105 						  0);
106 
107     g_once_init_leave(&g_define_type_id__volatile, ags_type_lv2_manager);
108   }
109 
110   return g_define_type_id__volatile;
111 }
112 
113 void
ags_lv2_manager_class_init(AgsLv2ManagerClass * lv2_manager)114 ags_lv2_manager_class_init(AgsLv2ManagerClass *lv2_manager)
115 {
116   GObjectClass *gobject;
117   GParamSpec *param_spec;
118 
119   ags_lv2_manager_parent_class = g_type_class_peek_parent(lv2_manager);
120 
121   /* GObjectClass */
122   gobject = (GObjectClass *) lv2_manager;
123 
124   gobject->set_property = ags_lv2_manager_set_property;
125   gobject->get_property = ags_lv2_manager_get_property;
126 
127   gobject->dispose = ags_lv2_manager_dispose;
128   gobject->finalize = ags_lv2_manager_finalize;
129 
130   /* properties */
131   /**
132    * AgsLv2Manager:locale:
133    *
134    * The assigned locale.
135    *
136    * Since: 3.0.0
137    */
138   param_spec = g_param_spec_string("locale",
139 				   "locale of lv2 manager",
140 				   "The locale this lv2 manager is assigned to",
141 				   NULL,
142 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
143   g_object_class_install_property(gobject,
144 				  PROP_LOCALE,
145 				  param_spec);
146 }
147 
148 void
ags_lv2_manager_init(AgsLv2Manager * lv2_manager)149 ags_lv2_manager_init(AgsLv2Manager *lv2_manager)
150 {
151   /* lv2 manager mutex */
152   g_mutex_init(&(lv2_manager->obj_mutex));
153 
154   /* initialize lv2 plugin blacklist */
155   lv2_manager->lv2_plugin_blacklist = NULL;
156 
157   /* initialize lv2 plugin GList */
158   lv2_manager->lv2_plugin = NULL;
159 
160   /* current plugin node */
161   lv2_manager->current_plugin_node = NULL;
162 
163   /* initiliaze ags_lv2_default_path string vector */
164   if(ags_lv2_default_path == NULL){
165     gchar *lv2_env;
166 
167     if((lv2_env = getenv("LV2_PATH")) != NULL){
168       gchar *iter, *next;
169       guint i;
170 
171       ags_lv2_default_path = (gchar **) malloc(sizeof(gchar *));
172 
173       iter = lv2_env;
174       i = 0;
175 
176       while((next = strchr(iter, G_SEARCHPATH_SEPARATOR)) != NULL){
177 	ags_lv2_default_path = (gchar **) realloc(ags_lv2_default_path,
178 						  (i + 2) * sizeof(gchar *));
179 	ags_lv2_default_path[i] = g_strndup(iter,
180 					    next - iter);
181 
182 	iter = next + 1;
183 	i++;
184       }
185 
186       if(*iter != '\0'){
187 	ags_lv2_default_path = (gchar **) realloc(ags_lv2_default_path,
188 						  (i + 2) * sizeof(gchar *));
189 	ags_lv2_default_path[i] = g_strdup(iter);
190 
191 	i++;
192       }
193 
194       ags_lv2_default_path[i] = NULL;
195     }else{
196 #if defined(AGS_W32API)
197       AgsApplicationContext *application_context;
198 
199       gchar *app_dir;
200       gchar *path;
201 
202       guint i;
203 
204       i = 0;
205 
206       application_context = ags_application_context_get_instance();
207 
208       app_dir = NULL;
209 
210       if(strlen(application_context->argv[0]) > strlen("\\gsequencer.exe")){
211 	app_dir = g_strndup(application_context->argv[0],
212 			    strlen(application_context->argv[0]) - strlen("\\gsequencer.exe"));
213       }
214 
215       ags_lv2_default_path = (gchar **) malloc(2 * sizeof(gchar *));
216 
217       path = g_strdup_printf("%s\\lv2",
218 			     g_get_current_dir());
219 
220       if(g_file_test(path,
221 		     G_FILE_TEST_IS_DIR)){
222 	ags_lv2_default_path[i++] = path;
223       }else{
224 	g_free(path);
225 
226 	if(g_path_is_absolute(app_dir)){
227 	  ags_lv2_default_path[i++] = g_strdup_printf("%s\\lv2",
228 						      app_dir);
229 	}else{
230 	  ags_lv2_default_path[i++] = g_strdup_printf("%s\\%s\\lv2",
231 						      g_get_current_dir(),
232 						      app_dir);
233 	}
234       }
235 
236       ags_lv2_default_path[i++] = NULL;
237 
238       g_free(app_dir);
239 #else
240       gchar *home_dir;
241       guint i;
242 
243 #ifdef __APPLE__
244       if((home_dir = getenv("HOME")) != NULL){
245 	ags_lv2_default_path = (gchar **) malloc(5 * sizeof(gchar *));
246       }else{
247 	ags_lv2_default_path = (gchar **) malloc(4 * sizeof(gchar *));
248       }
249 
250       i = 0;
251 
252       ags_lv2_default_path[i++] = g_strdup("/Library/Audio/Plug-Ins/LV2");
253       ags_lv2_default_path[i++] = g_strdup("/usr/lib/lv2");
254       ags_lv2_default_path[i++] = g_strdup("/usr/local/lib/lv2");
255 
256       if(home_dir != NULL){
257 	ags_lv2_default_path[i++] = g_strdup_printf("%s/Library/Audio/Plug-Ins/LV2",
258 						    home_dir);
259       }
260 
261       ags_lv2_default_path[i++] = NULL;
262 #else
263       if((home_dir = getenv("HOME")) != NULL){
264 	ags_lv2_default_path = (gchar **) malloc(6 * sizeof(gchar *));
265       }else{
266 	ags_lv2_default_path = (gchar **) malloc(5 * sizeof(gchar *));
267       }
268 
269       i = 0;
270 
271       ags_lv2_default_path[i++] = g_strdup("/usr/lib64/lv2");
272       ags_lv2_default_path[i++] = g_strdup("/usr/local/lib64/lv2");
273       ags_lv2_default_path[i++] = g_strdup("/usr/lib/lv2");
274       ags_lv2_default_path[i++] = g_strdup("/usr/local/lib/lv2");
275 
276       if(home_dir != NULL){
277 	ags_lv2_default_path[i++] = g_strdup_printf("%s/.lv2",
278 						    home_dir);
279       }
280 
281       ags_lv2_default_path[i++] = NULL;
282 #endif
283 #endif
284     }
285   }
286 
287   /* quick scan filename and effect */
288   lv2_manager->quick_scan_plugin_filename = NULL;
289   lv2_manager->quick_scan_plugin_effect = NULL;
290 
291   lv2_manager->quick_scan_instrument_filename = NULL;
292   lv2_manager->quick_scan_instrument_effect = NULL;
293 }
294 
295 void
ags_lv2_manager_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)296 ags_lv2_manager_set_property(GObject *gobject,
297 			     guint prop_id,
298 			     const GValue *value,
299 			     GParamSpec *param_spec)
300 {
301   AgsLv2Manager *lv2_manager;
302 
303   lv2_manager = AGS_LV2_MANAGER(gobject);
304 
305   switch(prop_id){
306   case PROP_LOCALE:
307     {
308       gchar *locale;
309 
310       locale = (gchar *) g_value_get_string(value);
311 
312       if(lv2_manager->locale == locale){
313 	return;
314       }
315 
316       if(lv2_manager->locale != NULL){
317 	g_free(lv2_manager->locale);
318       }
319 
320       lv2_manager->locale = g_strdup(locale);
321     }
322     break;
323   default:
324     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
325     break;
326   }
327 }
328 
329 void
ags_lv2_manager_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)330 ags_lv2_manager_get_property(GObject *gobject,
331 			     guint prop_id,
332 			     GValue *value,
333 			     GParamSpec *param_spec)
334 {
335   AgsLv2Manager *lv2_manager;
336 
337   lv2_manager = AGS_LV2_MANAGER(gobject);
338 
339   switch(prop_id){
340   case PROP_LOCALE:
341     {
342       g_value_set_string(value, lv2_manager->locale);
343     }
344     break;
345   default:
346     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
347     break;
348   }
349 }
350 
351 void
ags_lv2_manager_dispose(GObject * gobject)352 ags_lv2_manager_dispose(GObject *gobject)
353 {
354   AgsLv2Manager *lv2_manager;
355 
356   lv2_manager = AGS_LV2_MANAGER(gobject);
357 
358   if(lv2_manager->lv2_plugin != NULL){
359     g_list_free_full(lv2_manager->lv2_plugin,
360 		     g_object_unref);
361 
362     lv2_manager->lv2_plugin = NULL;
363   }
364 
365   /* call parent */
366   G_OBJECT_CLASS(ags_lv2_manager_parent_class)->dispose(gobject);
367 }
368 
369 void
ags_lv2_manager_finalize(GObject * gobject)370 ags_lv2_manager_finalize(GObject *gobject)
371 {
372   AgsLv2Manager *lv2_manager;
373 
374   GList *lv2_plugin;
375 
376   lv2_manager = AGS_LV2_MANAGER(gobject);
377 
378   lv2_plugin = lv2_manager->lv2_plugin;
379 
380   g_list_free_full(lv2_plugin,
381 		   g_object_unref);
382 
383   if(lv2_manager == ags_lv2_manager){
384     ags_lv2_manager = NULL;
385   }
386 
387   /* call parent */
388   G_OBJECT_CLASS(ags_lv2_manager_parent_class)->finalize(gobject);
389 }
390 
391 /**
392  * ags_lv2_manager_global_get_parse_names:
393  *
394  * Get global config value parse names.
395  *
396  * Returns: if %TRUE parse only names, else not
397  *
398  * Since: 3.0.0
399  */
400 gboolean
ags_lv2_manager_global_get_parse_names()401 ags_lv2_manager_global_get_parse_names()
402 {
403   gboolean parse_names;
404 
405 //  g_rec_mutex_lock(ags_lv2_manager_get_class_mutex());
406 
407   parse_names = ags_lv2_manager_global_parse_names;
408 
409 //  g_rec_mutex_unlock(ags_lv2_manager_get_class_mutex());
410 
411   return(parse_names);
412 }
413 
414 /**
415  * ags_lv2_manager_global_get_preserve_turtle:
416  *
417  * Get global config value preserve turtle.
418  *
419  * Returns: if %TRUE preserve turtles, else not
420  *
421  * Since: 3.0.0
422  */
423 gboolean
ags_lv2_manager_global_get_preserve_turtle()424 ags_lv2_manager_global_get_preserve_turtle()
425 {
426   gboolean preserve_turtle;
427 
428 //  g_rec_mutex_lock(ags_lv2_manager_get_class_mutex());
429 
430   preserve_turtle = ags_lv2_manager_global_preserve_turtle;
431 
432 //  g_rec_mutex_unlock(ags_lv2_manager_get_class_mutex());
433 
434   return(preserve_turtle);
435 }
436 
437 /**
438  * ags_lv2_manager_get_default_path:
439  *
440  * Get lv2 manager default plugin path.
441  *
442  * Returns: (element-type utf8) (array zero-terminated=1) (transfer none): the plugin default search path as a string vector
443  *
444  * Since: 3.0.0
445  */
446 gchar**
ags_lv2_manager_get_default_path()447 ags_lv2_manager_get_default_path()
448 {
449   return(ags_lv2_default_path);
450 }
451 
452 /**
453  * ags_lv2_manager_set_default_path:
454  * @default_path: (element-type utf8) (array zero-terminated=1) (transfer full): the string vector array to use as default path
455  *
456  * Set lv2 manager default plugin path.
457  *
458  * Since: 3.0.0
459  */
460 void
ags_lv2_manager_set_default_path(gchar ** default_path)461 ags_lv2_manager_set_default_path(gchar** default_path)
462 {
463   ags_lv2_default_path = default_path;
464 }
465 
466 /**
467  * ags_lv2_manager_get_filenames:
468  * @lv2_manager: the #AgsLv2Manager
469  *
470  * Retrieve all filenames
471  *
472  * Returns: (element-type utf8) (array zero-terminated=1) (transfer full): a %NULL-terminated array of filenames
473  *
474  * Since: 3.0.0
475  */
476 gchar**
ags_lv2_manager_get_filenames(AgsLv2Manager * lv2_manager)477 ags_lv2_manager_get_filenames(AgsLv2Manager *lv2_manager)
478 {
479   GList *start_lv2_plugin, *lv2_plugin;
480 
481   gchar **filenames;
482 
483   guint i;
484   gboolean contains_filename;
485 
486   GRecMutex *lv2_manager_mutex;
487   GRecMutex *base_plugin_mutex;
488 
489   if(!AGS_IS_LV2_MANAGER(lv2_manager)){
490     return(NULL);
491   }
492 
493   /* get lv2 manager mutex */
494   lv2_manager_mutex = AGS_LV2_MANAGER_GET_OBJ_MUTEX(lv2_manager);
495 
496   /* collect */
497   g_rec_mutex_lock(lv2_manager_mutex);
498 
499   lv2_plugin =
500     start_lv2_plugin = g_list_copy(lv2_manager->lv2_plugin);
501 
502   g_rec_mutex_unlock(lv2_manager_mutex);
503 
504   filenames = NULL;
505 
506   for(i = 0; lv2_plugin != NULL;){
507     gchar *filename;
508 
509     /* get base plugin mutex */
510     base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(lv2_plugin->data);
511 
512     /* duplicate filename */
513     g_rec_mutex_lock(base_plugin_mutex);
514 
515     filename = g_strdup(AGS_BASE_PLUGIN(lv2_plugin->data)->filename);
516 
517     g_rec_mutex_unlock(base_plugin_mutex);
518 
519     if(filename == NULL){
520       lv2_plugin = lv2_plugin->next;
521 
522       continue;
523     }
524 
525     if(filenames == NULL){
526       filenames = (gchar **) malloc(2 * sizeof(gchar *));
527       filenames[i] = filename;
528       filenames[i + 1] = NULL;
529 
530       i++;
531     }else{
532 #ifdef HAVE_GLIB_2_44
533       contains_filename = g_strv_contains(filenames,
534 					  filename);
535 #else
536       contains_filename = ags_strv_contains(filenames,
537 					    filename);
538 #endif
539 
540       if(!contains_filename){
541 	filenames = (gchar **) realloc(filenames,
542 				       (i + 2) * sizeof(gchar *));
543 	filenames[i] = filename;
544 	filenames[i + 1] = NULL;
545 
546 	i++;
547       }else{
548 	g_free(filename);
549       }
550     }
551 
552     lv2_plugin = lv2_plugin->next;
553   }
554 
555   g_list_free(start_lv2_plugin);
556 
557   return(filenames);
558 }
559 
560 /**
561  * ags_lv2_manager_find_lv2_plugin:
562  * @lv2_manager: the #AgsLv2Manager
563  * @filename: the filename of the plugin
564  * @effect: the effect's name
565  *
566  * Lookup filename in loaded plugins.
567  *
568  * Returns: (transfer none): the #AgsLv2Plugin
569  *
570  * Since: 3.0.0
571  */
572 AgsLv2Plugin*
ags_lv2_manager_find_lv2_plugin(AgsLv2Manager * lv2_manager,gchar * filename,gchar * effect)573 ags_lv2_manager_find_lv2_plugin(AgsLv2Manager *lv2_manager,
574 				gchar *filename, gchar *effect)
575 {
576   AgsLv2Plugin *lv2_plugin;
577 
578   GList *start_list, *list;
579 
580   gboolean success;
581 
582   GRecMutex *lv2_manager_mutex;
583   GRecMutex *base_plugin_mutex;
584 
585   if(!AGS_IS_LV2_MANAGER(lv2_manager) ||
586      filename == NULL ||
587      effect == NULL){
588     return(NULL);
589   }
590 
591   /* get lv2 manager mutex */
592   lv2_manager_mutex = AGS_LV2_MANAGER_GET_OBJ_MUTEX(lv2_manager);
593 
594   /* collect */
595   g_rec_mutex_lock(lv2_manager_mutex);
596 
597   list =
598     start_list = g_list_copy(lv2_manager->lv2_plugin);
599 
600   g_rec_mutex_unlock(lv2_manager_mutex);
601 
602   success = FALSE;
603 
604   while(list != NULL){
605     lv2_plugin = AGS_LV2_PLUGIN(list->data);
606 
607     /* get base plugin mutex */
608     base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(lv2_plugin);
609 
610     /* check filename and effect */
611     g_rec_mutex_lock(base_plugin_mutex);
612 
613     success = (AGS_BASE_PLUGIN(lv2_plugin)->filename != NULL &&
614 	       AGS_BASE_PLUGIN(lv2_plugin)->effect != NULL &&
615 	       !g_strcmp0(AGS_BASE_PLUGIN(lv2_plugin)->filename,
616 			  filename) &&
617 	       !g_strcmp0(AGS_BASE_PLUGIN(lv2_plugin)->effect,
618 			  effect)) ? TRUE: FALSE;
619 
620     g_rec_mutex_unlock(base_plugin_mutex);
621 
622     if(success){
623       break;
624     }
625 
626     list = list->next;
627   }
628 
629   g_list_free(start_list);
630 
631   if(!success){
632     lv2_plugin = NULL;
633   }
634 
635   return(lv2_plugin);
636 }
637 
638 /**
639  * ags_lv2_manager_find_lv2_plugin_with_fallback:
640  * @lv2_manager: the #AgsLv2Manager
641  * @filename: the filename of the plugin
642  * @effect: the effect's name
643  *
644  * Lookup filename in loaded plugins.
645  *
646  * Returns: (transfer none): the #AgsLv2Plugin
647  *
648  * Since: 3.5.10
649  */
650 AgsLv2Plugin*
ags_lv2_manager_find_lv2_plugin_with_fallback(AgsLv2Manager * lv2_manager,gchar * filename,gchar * effect)651 ags_lv2_manager_find_lv2_plugin_with_fallback(AgsLv2Manager *lv2_manager,
652 					      gchar *filename, gchar *effect)
653 {
654   AgsLv2Plugin *lv2_plugin;
655 
656   GList *start_list, *list;
657 
658   gchar *filename_suffix;
659 
660   gboolean success;
661 
662   GRecMutex *lv2_manager_mutex;
663   GRecMutex *base_plugin_mutex;
664 
665   if(!AGS_IS_LV2_MANAGER(lv2_manager) ||
666      filename == NULL ||
667      effect == NULL){
668     return(NULL);
669   }
670 
671   /* get lv2 manager mutex */
672   lv2_manager_mutex = AGS_LV2_MANAGER_GET_OBJ_MUTEX(lv2_manager);
673 
674   lv2_plugin = ags_lv2_manager_find_lv2_plugin(lv2_manager,
675 					       filename, effect);
676 
677   if(lv2_plugin == NULL){
678     gchar *tmp;
679 
680     filename = g_strdup(filename);
681 
682     tmp = strrchr(filename, "/");
683 
684     if(tmp != NULL){
685       tmp[0] = '\0';
686     }
687 
688     filename_suffix = strrchr(tmp, "/");
689 
690     if(tmp != NULL){
691       tmp[0] = '/';
692     }
693 
694     /* collect */
695     g_rec_mutex_lock(lv2_manager_mutex);
696 
697     list =
698       start_list = g_list_copy(lv2_manager->lv2_plugin);
699 
700     g_rec_mutex_unlock(lv2_manager_mutex);
701 
702     success = FALSE;
703 
704     while(list != NULL){
705       lv2_plugin = AGS_LV2_PLUGIN(list->data);
706 
707       /* get base plugin mutex */
708       base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(lv2_plugin);
709 
710       /* check filename and effect */
711       g_rec_mutex_lock(base_plugin_mutex);
712 
713       success = (g_str_has_suffix(AGS_BASE_PLUGIN(lv2_plugin)->filename,
714 				  filename_suffix) &&
715 		 !g_strcmp0(AGS_BASE_PLUGIN(lv2_plugin)->effect,
716 			    effect)) ? TRUE: FALSE;
717 
718       g_rec_mutex_unlock(base_plugin_mutex);
719 
720       if(success){
721 	break;
722       }
723 
724       list = list->next;
725     }
726 
727     g_list_free(start_list);
728 
729     g_free(filename);
730 
731     if(!success){
732       lv2_plugin = NULL;
733     }
734   }
735 
736   return(lv2_plugin);
737 }
738 
739 /**
740  * ags_lv2_manager_load_blacklist:
741  * @lv2_manager: the #AgsLv2Manager
742  * @blacklist_filename: the filename as string
743  *
744  * Load blacklisted plugin filenames.
745  *
746  * Since: 3.0.0
747  */
748 void
ags_lv2_manager_load_blacklist(AgsLv2Manager * lv2_manager,gchar * blacklist_filename)749 ags_lv2_manager_load_blacklist(AgsLv2Manager *lv2_manager,
750 			       gchar *blacklist_filename)
751 {
752   GRecMutex *lv2_manager_mutex;
753 
754   if(!AGS_IS_LV2_MANAGER(lv2_manager) ||
755      blacklist_filename == NULL){
756     return;
757   }
758 
759   /* get lv2 manager mutex */
760   lv2_manager_mutex = AGS_LV2_MANAGER_GET_OBJ_MUTEX(lv2_manager);
761 
762   /* fill in */
763   g_rec_mutex_lock(lv2_manager_mutex);
764 
765   if(g_file_test(blacklist_filename,
766 		 (G_FILE_TEST_EXISTS |
767 		  G_FILE_TEST_IS_REGULAR))){
768     FILE *file;
769 
770     gchar *str;
771 
772     file = fopen(blacklist_filename,
773 		 "r");
774 
775 #ifndef AGS_W32API
776     while(getline(&str, NULL, file) != -1){
777       lv2_manager->lv2_plugin_blacklist = g_list_prepend(lv2_manager->lv2_plugin_blacklist,
778 							 str);
779     }
780 #endif
781   }
782 
783   g_rec_mutex_unlock(lv2_manager_mutex);
784 }
785 
786 /**
787  * ags_lv2_manager_load_file:
788  * @lv2_manager: the #AgsLv2Manager
789  * @manifest: the manifest
790  * @turtle: the loaded turtle
791  * @lv2_path: the lv2 path
792  * @filename: the filename of the plugin
793  *
794  * Load @filename specified plugin.
795  *
796  * Since: 3.0.0
797  */
798 void
ags_lv2_manager_load_file(AgsLv2Manager * lv2_manager,AgsTurtle * manifest,AgsTurtle * turtle,gchar * lv2_path,gchar * filename)799 ags_lv2_manager_load_file(AgsLv2Manager *lv2_manager,
800 			  AgsTurtle *manifest,
801 			  AgsTurtle *turtle,
802 			  gchar *lv2_path,
803 			  gchar *filename)
804 {
805   //TODO:JK: implement me
806 }
807 
808 /**
809  * ags_lv2_manager_load_preset:
810  * @lv2_manager: the #AgsLv2Manager
811  * @lv2_plugin: the #AgsLv2Plugin
812  * @preset: the #AgsTurtle
813  *
814  * Load preset.
815  *
816  * Since: 3.0.0
817  */
818 void
ags_lv2_manager_load_preset(AgsLv2Manager * lv2_manager,AgsLv2Plugin * lv2_plugin,AgsTurtle * preset)819 ags_lv2_manager_load_preset(AgsLv2Manager *lv2_manager,
820 			    AgsLv2Plugin *lv2_plugin,
821 			    AgsTurtle *preset)
822 {
823   //TODO:JK: implement me
824 }
825 
826 gint
ags_lv2_manager_compare_strv(gconstpointer a,gconstpointer b)827 ags_lv2_manager_compare_strv(gconstpointer a,
828 			     gconstpointer b)
829 {
830   return(g_strcmp0(((gchar **) a)[1], ((gchar **) b)[1]));
831 }
832 
833 /**
834  * ags_lv2_manager_quick_scan_default_directory:
835  * @lv2_manager: the #AgsLv2Manager
836  *
837  * Quick scan available plugins.
838  *
839  * Since: 3.2.7
840  */
841 void
ags_lv2_manager_quick_scan_default_directory(AgsLv2Manager * lv2_manager)842 ags_lv2_manager_quick_scan_default_directory(AgsLv2Manager *lv2_manager)
843 {
844   AgsLv2TurtleScanner *lv2_turtle_scanner;
845 
846   GDir *dir;
847 
848   GList *start_lv2_cache_turtle, *lv2_cache_turtle;
849 
850   GList *start_plugin;
851   GList *start_instrument;
852 
853   gchar **quick_scan_plugin_filename;
854   gchar **quick_scan_plugin_effect;
855 
856   gchar **quick_scan_instrument_filename;
857   gchar **quick_scan_instrument_effect;
858 
859   gchar **lv2_path;
860   gchar *path, *plugin_path;
861   gchar *str;
862 
863   GError *error;
864 
865   if(!AGS_IS_LV2_MANAGER(lv2_manager)){
866     return;
867   }
868 
869   lv2_turtle_scanner = ags_lv2_turtle_scanner_new();
870 
871   lv2_path = ags_lv2_default_path;
872 
873   while(*lv2_path != NULL){
874     if(!g_file_test(*lv2_path,
875 		    G_FILE_TEST_EXISTS)){
876       lv2_path++;
877 
878       continue;
879     }
880 
881     error = NULL;
882     dir = g_dir_open(*lv2_path,
883 		     0,
884 		     &error);
885 
886     if(error != NULL){
887       g_warning("%s", error->message);
888 
889       lv2_path++;
890 
891       g_error_free(error);
892 
893       continue;
894     }
895 
896     while((path = g_dir_read_name(dir)) != NULL){
897       if(!g_ascii_strncasecmp(path,
898 			      "..",
899 			      3) ||
900 	 !g_ascii_strncasecmp(path,
901 			      ".",
902 			      2)){
903 	continue;
904       }
905 
906       plugin_path = g_strdup_printf("%s%c%s",
907 				    *lv2_path,
908 				    G_DIR_SEPARATOR,
909 				    path);
910 
911       if(g_file_test(plugin_path,
912 		     G_FILE_TEST_IS_DIR)){
913 
914 	gchar *manifest_filename;
915 
916 	guint n_turtle;
917 
918 	manifest_filename = g_strdup_printf("%s%c%s",
919 					    plugin_path,
920 					    G_DIR_SEPARATOR,
921 					    "manifest.ttl");
922 
923 	if(!g_file_test(manifest_filename,
924 			G_FILE_TEST_EXISTS)){
925 	  g_free(manifest_filename);
926 
927 	  continue;
928 	}
929 
930 	g_message("quick scan turtle [Manifest] - %s", manifest_filename);
931 
932 	ags_lv2_turtle_scanner_quick_scan(lv2_turtle_scanner,
933 					  manifest_filename);
934 
935 	g_free(manifest_filename);
936       }
937     }
938 
939     lv2_path++;
940   }
941 
942   /* read plugins */
943   lv2_cache_turtle =
944     start_lv2_cache_turtle = g_list_reverse(g_list_copy(lv2_turtle_scanner->cache_turtle));
945 
946   start_plugin = NULL;
947   start_instrument = NULL;
948 
949   quick_scan_plugin_filename = NULL;
950   quick_scan_plugin_effect = NULL;
951 
952   quick_scan_instrument_filename = NULL;
953   quick_scan_instrument_effect = NULL;
954 
955   while(lv2_cache_turtle != NULL){
956     AgsLv2CacheTurtle *current;
957 
958     current = AGS_LV2_CACHE_TURTLE(lv2_cache_turtle->data);
959 
960     if(g_str_has_suffix(current->turtle_filename,
961 			"manifest.ttl")){
962       GList *start_list, *list;
963 
964       list =
965 	start_list = g_hash_table_get_keys(current->plugin_filename);
966 
967       while(list != NULL){
968 	gchar **strv;
969 
970 	gchar *filename;
971 	gchar *effect;
972 
973 	gboolean is_instrument;
974 
975 	filename = g_hash_table_lookup(current->plugin_filename,
976 				       list->data);
977 
978 	effect = g_hash_table_lookup(current->plugin_effect,
979 				     list->data);
980 
981 	is_instrument = FALSE;
982 
983 	if(g_hash_table_contains(current->is_instrument,
984 				 list->data)){
985 	  is_instrument = TRUE;
986 	}
987 
988 	strv = g_malloc(3 * sizeof(gchar *));
989 
990 	strv[0] = g_strdup(filename);
991 	strv[1] = g_strdup(effect);
992 	strv[2] = NULL;
993 
994 	if(!is_instrument){
995 	  start_plugin = g_list_insert_sorted(start_plugin,
996 					      strv,
997 					      (GCompareFunc) ags_lv2_manager_compare_strv);
998 	}else{
999 	  start_instrument = g_list_insert_sorted(start_instrument,
1000 						  strv,
1001 						  (GCompareFunc) ags_lv2_manager_compare_strv);
1002 	}
1003 
1004 	list = list->next;
1005       }
1006 
1007       g_list_free(start_list);
1008     }
1009 
1010     lv2_cache_turtle = lv2_cache_turtle->next;
1011   }
1012 
1013   g_list_free(start_lv2_cache_turtle);
1014 
1015   if(start_plugin != NULL){
1016     GList *plugin;
1017 
1018     guint length;
1019     guint i;
1020 
1021     plugin = start_plugin;
1022 
1023     length = g_list_length(start_plugin);
1024 
1025     quick_scan_plugin_filename = (gchar **) g_malloc((length + 1) * sizeof(gchar *));
1026     quick_scan_plugin_effect = (gchar **) g_malloc((length + 1) * sizeof(gchar *));
1027 
1028     for(i = 0; i < length; i++){
1029       quick_scan_plugin_filename[i] = ((gchar **) plugin->data)[0];
1030       quick_scan_plugin_effect[i] = ((gchar **) plugin->data)[1];
1031 
1032       plugin = plugin->next;
1033     }
1034 
1035     quick_scan_plugin_filename[i] = NULL;
1036     quick_scan_plugin_effect[i] = NULL;
1037   }
1038 
1039   if(start_instrument != NULL){
1040     GList *instrument;
1041 
1042     guint length;
1043     guint i;
1044 
1045     instrument = start_instrument;
1046 
1047     length = g_list_length(start_instrument);
1048 
1049     quick_scan_instrument_filename = (gchar **) g_malloc((length + 1) * sizeof(gchar *));
1050     quick_scan_instrument_effect = (gchar **) g_malloc((length + 1) * sizeof(gchar *));
1051 
1052     for(i = 0; i < length; i++){
1053       quick_scan_instrument_filename[i] = ((gchar **) instrument->data)[0];
1054       quick_scan_instrument_effect[i] = ((gchar **) instrument->data)[1];
1055 
1056       instrument = instrument->next;
1057     }
1058 
1059     quick_scan_instrument_filename[i] = NULL;
1060     quick_scan_instrument_effect[i] = NULL;
1061   }
1062 
1063   lv2_manager->quick_scan_plugin_filename = quick_scan_plugin_filename;
1064   lv2_manager->quick_scan_plugin_effect = quick_scan_plugin_effect;
1065 
1066   lv2_manager->quick_scan_instrument_filename = quick_scan_instrument_filename;
1067   lv2_manager->quick_scan_instrument_effect = quick_scan_instrument_effect;
1068 
1069   g_list_free_full(start_plugin,
1070 		   g_free);
1071 
1072   g_list_free_full(start_instrument,
1073 		   g_free);
1074 
1075   /* unref */
1076   g_object_unref(lv2_turtle_scanner);
1077 }
1078 
1079 /**
1080  * ags_lv2_manager_load_default_directory:
1081  * @lv2_manager: the #AgsLv2Manager
1082  *
1083  * Loads all available plugins.
1084  *
1085  * Since: 3.0.0
1086  */
1087 void
ags_lv2_manager_load_default_directory(AgsLv2Manager * lv2_manager)1088 ags_lv2_manager_load_default_directory(AgsLv2Manager *lv2_manager)
1089 {
1090   AgsTurtleManager *turtle_manager;
1091 
1092   GDir *dir;
1093 
1094   GList *start_list, *list;
1095 
1096   gchar **lv2_path;
1097   gchar *path, *plugin_path;
1098   gchar *str;
1099 
1100   GError *error;
1101 
1102   if(!AGS_IS_LV2_MANAGER(lv2_manager)){
1103     return;
1104   }
1105 
1106   turtle_manager = ags_turtle_manager_get_instance();
1107 
1108   xmlInitParser();
1109 
1110   lv2_path = ags_lv2_default_path;
1111 
1112   while(*lv2_path != NULL){
1113     if(!g_file_test(*lv2_path,
1114 		    G_FILE_TEST_EXISTS)){
1115       lv2_path++;
1116 
1117       continue;
1118     }
1119 
1120     error = NULL;
1121     dir = g_dir_open(*lv2_path,
1122 		     0,
1123 		     &error);
1124 
1125     if(error != NULL){
1126       g_warning("%s", error->message);
1127 
1128       lv2_path++;
1129 
1130       g_error_free(error);
1131 
1132       continue;
1133     }
1134 
1135     while((path = g_dir_read_name(dir)) != NULL){
1136       if(!g_ascii_strncasecmp(path,
1137 			      "..",
1138 			      3) ||
1139 	 !g_ascii_strncasecmp(path,
1140 			      ".",
1141 			      2)){
1142 	continue;
1143       }
1144 
1145       plugin_path = g_strdup_printf("%s%c%s",
1146 				    *lv2_path,
1147 				    G_DIR_SEPARATOR,
1148 				    path);
1149 
1150       if(g_file_test(plugin_path,
1151 		     G_FILE_TEST_IS_DIR)){
1152 	AgsLv2TurtleParser *lv2_turtle_parser;
1153 
1154 	AgsTurtle *manifest;
1155 	AgsTurtle **turtle;
1156 
1157 	gchar *manifest_filename;
1158 
1159 	guint n_turtle;
1160 
1161 	manifest_filename = g_strdup_printf("%s%c%s",
1162 					    plugin_path,
1163 					    G_DIR_SEPARATOR,
1164 					    "manifest.ttl");
1165 
1166 	if(!g_file_test(manifest_filename,
1167 			G_FILE_TEST_EXISTS)){
1168 	  g_free(manifest_filename);
1169 
1170 	  continue;
1171 	}
1172 
1173 	g_message("new turtle [Manifest] - %s", manifest_filename);
1174 
1175 	manifest = ags_turtle_new(manifest_filename);
1176 	ags_turtle_load(manifest,
1177 			NULL);
1178 	ags_turtle_manager_add(turtle_manager,
1179 			       (GObject *) manifest);
1180 
1181 	lv2_turtle_parser = ags_lv2_turtle_parser_new(manifest);
1182 
1183 	n_turtle = 1;
1184 	turtle = (AgsTurtle **) malloc(2 * sizeof(AgsTurtle *));
1185 
1186 	turtle[0] = manifest;
1187 	turtle[1] = NULL;
1188 
1189 	if(!ags_lv2_manager_global_get_preserve_turtle()){
1190 	  ags_lv2_turtle_parser_parse(lv2_turtle_parser,
1191 				      turtle, n_turtle);
1192 
1193 	  g_object_get(lv2_turtle_parser,
1194 		       "turtle", &start_list,
1195 		       NULL);
1196 
1197 	  list = start_list;
1198 
1199 	  while(list != NULL){
1200 	    turtle_manager->turtle = g_list_remove(turtle_manager->turtle,
1201 						   list->data);
1202 	    g_object_unref(list->data);
1203 
1204 	    list = list->next;
1205 	  }
1206 
1207 	  g_list_free_full(start_list,
1208 			   g_object_unref);
1209 	}else{
1210 	  if(!ags_lv2_manager_global_get_parse_names()){
1211 	    ags_lv2_turtle_parser_parse(lv2_turtle_parser,
1212 					turtle, n_turtle);
1213 	  }else{
1214 	    ags_lv2_turtle_parser_parse_names(lv2_turtle_parser,
1215 					      turtle, n_turtle);
1216 	  }
1217 	}
1218 
1219 	g_object_run_dispose(lv2_turtle_parser);
1220 	g_object_unref(lv2_turtle_parser);
1221 
1222 	g_object_unref(manifest);
1223 
1224 	g_free(manifest_filename);
1225 
1226 	free(turtle);
1227       }
1228     }
1229 
1230     lv2_path++;
1231   }
1232 }
1233 
1234 /**
1235  * ags_lv2_manager_get_lv2_plugin:
1236  * @lv2_manager: the #AgsLv2Manager
1237  *
1238  * Get lv2 plugin.
1239  *
1240  * Returns: (transfer full): the #GList-struct containing #AgsLv2Plugin
1241  *
1242  * Since: 3.5.15
1243  */
1244 GList*
ags_lv2_manager_get_lv2_plugin(AgsLv2Manager * lv2_manager)1245 ags_lv2_manager_get_lv2_plugin(AgsLv2Manager *lv2_manager)
1246 {
1247   GList *lv2_plugin;
1248 
1249   GRecMutex *lv2_manager_mutex;
1250 
1251   if(!AGS_IS_LV2_MANAGER(lv2_manager)){
1252     return(NULL);
1253   }
1254 
1255   /* get lv2 manager mutex */
1256   lv2_manager_mutex = AGS_LV2_MANAGER_GET_OBJ_MUTEX(lv2_manager);
1257 
1258   g_rec_mutex_lock(lv2_manager_mutex);
1259 
1260   lv2_plugin = g_list_copy_deep(lv2_manager->lv2_plugin,
1261 				(GCopyFunc) g_object_ref,
1262 				NULL);
1263 
1264   g_rec_mutex_unlock(lv2_manager_mutex);
1265 
1266   return(lv2_plugin);
1267 }
1268 
1269 /**
1270  * ags_lv2_manager_get_instance:
1271  *
1272  * Get instance.
1273  *
1274  * Returns: (transfer none): the #AgsLv2Manager
1275  *
1276  * Since: 3.0.0
1277  */
1278 AgsLv2Manager*
ags_lv2_manager_get_instance()1279 ags_lv2_manager_get_instance()
1280 {
1281   static GMutex mutex;
1282 
1283   g_mutex_lock(&mutex);
1284 
1285   if(ags_lv2_manager == NULL){
1286     ags_lv2_manager = ags_lv2_manager_new(AGS_LV2_MANAGER_DEFAULT_LOCALE);
1287   }
1288 
1289   g_mutex_unlock(&mutex);
1290 
1291   return(ags_lv2_manager);
1292 }
1293 
1294 /**
1295  * ags_lv2_manager_new:
1296  * @locale: the default locale
1297  *
1298  * Create a new instance of #AgsLv2Manager
1299  *
1300  * Returns: the new #AgsLv2Manager
1301  *
1302  * Since: 3.0.0
1303  */
1304 AgsLv2Manager*
ags_lv2_manager_new(gchar * locale)1305 ags_lv2_manager_new(gchar *locale)
1306 {
1307   AgsLv2Manager *lv2_manager;
1308 
1309   lv2_manager = (AgsLv2Manager *) g_object_new(AGS_TYPE_LV2_MANAGER,
1310 					       "locale", locale,
1311 					       NULL);
1312 
1313   return(lv2_manager);
1314 }
1315