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