1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2019 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/audio/recall/ags_play_lv2_audio.h>
21 
22 #include <ags/plugin/ags_lv2_manager.h>
23 #include <ags/plugin/ags_lv2_plugin.h>
24 #include <ags/plugin/ags_lv2_conversion.h>
25 #include <ags/plugin/ags_plugin_port.h>
26 
27 #include <ags/audio/ags_port.h>
28 
29 #if defined(AGS_W32API)
30 #include <windows.h>
31 #else
32 #include <dlfcn.h>
33 #endif
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 
41 #include <libxml/tree.h>
42 
43 #include <ags/i18n.h>
44 
45 void ags_play_lv2_audio_class_init(AgsPlayLv2AudioClass *play_lv2_audio);
46 void ags_play_lv2_audio_init(AgsPlayLv2Audio *play_lv2_audio);
47 void ags_play_lv2_audio_set_property(GObject *gobject,
48 				     guint prop_id,
49 				     const GValue *value,
50 				     GParamSpec *param_spec);
51 void ags_play_lv2_audio_get_property(GObject *gobject,
52 				     guint prop_id,
53 				     GValue *value,
54 				     GParamSpec *param_spec);
55 void ags_play_lv2_audio_dispose(GObject *gobject);
56 void ags_play_lv2_audio_finalize(GObject *gobject);
57 
58 /**
59  * SECTION:ags_play_lv2_audio
60  * @short_description: play audio lv2
61  * @title: AgsPlayLv2Audio
62  * @section_id:
63  * @include: ags/audio/recall/ags_play_lv2_audio.h
64  *
65  * The #AgsPlayLv2Audio class provides ports to the effect processor.
66  */
67 
68 enum{
69   PROP_0,
70   PROP_TURTLE,
71   PROP_URI,
72   PROP_PLUGIN,
73   PROP_INPUT_LINES,
74   PROP_OUTPUT_LINES,
75 };
76 
77 static gpointer ags_play_lv2_audio_parent_class = NULL;
78 
79 const gchar *ags_play_lv2_audio_plugin_name = "ags-play-lv2";
80 const gchar *ags_play_lv2_audio_specifier[] = {
81 };
82 const gchar *ags_play_lv2_audio_control_port[] = {
83 };
84 
85 GType
ags_play_lv2_audio_get_type()86 ags_play_lv2_audio_get_type()
87 {
88   static volatile gsize g_define_type_id__volatile = 0;
89 
90   if(g_once_init_enter (&g_define_type_id__volatile)){
91     GType ags_type_play_lv2_audio;
92 
93     static const GTypeInfo ags_play_lv2_audio_info = {
94       sizeof (AgsPlayLv2AudioClass),
95       NULL, /* base_init */
96       NULL, /* base_finalize */
97       (GClassInitFunc) ags_play_lv2_audio_class_init,
98       NULL, /* class_finalize */
99       NULL, /* class_audio */
100       sizeof (AgsPlayLv2Audio),
101       0,    /* n_preallocs */
102       (GInstanceInitFunc) ags_play_lv2_audio_init,
103     };
104 
105     ags_type_play_lv2_audio = g_type_register_static(AGS_TYPE_RECALL_AUDIO,
106 						     "AgsPlayLv2Audio",
107 						     &ags_play_lv2_audio_info,
108 						     0);
109 
110     g_once_init_leave (&g_define_type_id__volatile, ags_type_play_lv2_audio);
111   }
112 
113   return g_define_type_id__volatile;
114 }
115 
116 void
ags_play_lv2_audio_class_init(AgsPlayLv2AudioClass * play_lv2_audio)117 ags_play_lv2_audio_class_init(AgsPlayLv2AudioClass *play_lv2_audio)
118 {
119   GObjectClass *gobject;
120   GParamSpec *param_spec;
121 
122   ags_play_lv2_audio_parent_class = g_type_class_peek_parent(play_lv2_audio);
123 
124   /* GObjectClass */
125   gobject = (GObjectClass *) play_lv2_audio;
126 
127   gobject->set_property = ags_play_lv2_audio_set_property;
128   gobject->get_property = ags_play_lv2_audio_get_property;
129 
130   gobject->dispose = ags_play_lv2_audio_dispose;
131   gobject->finalize = ags_play_lv2_audio_finalize;
132 
133   /* properties */
134   /**
135    * AgsPlayLv2Audio:turtle:
136    *
137    * The assigned turtle.
138    *
139    * Since: 3.0.0
140    */
141   param_spec = g_param_spec_object("turtle",
142 				   i18n_pspec("turtle of recall lv2"),
143 				   i18n_pspec("The turtle which this recall lv2 is described by"),
144 				   AGS_TYPE_TURTLE,
145 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
146   g_object_class_install_property(gobject,
147 				  PROP_TURTLE,
148 				  param_spec);
149 
150   /**
151    * AgsPlayLv2Audio:uri:
152    *
153    * The uri's name.
154    *
155    * Since: 3.0.0
156    */
157   param_spec =  g_param_spec_string("uri",
158 				    i18n_pspec("the uri"),
159 				    i18n_pspec("The uri's string representation"),
160 				    NULL,
161 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
162   g_object_class_install_property(gobject,
163 				  PROP_URI,
164 				  param_spec);
165 
166   /**
167    * AgsPlayLv2Audio:plugin:
168    *
169    * The plugin's plugin object.
170    *
171    * Since: 3.0.0
172    */
173   param_spec =  g_param_spec_object("plugin",
174 				    i18n_pspec("the plugin"),
175 				    i18n_pspec("The plugin as plugin object"),
176 				    AGS_TYPE_LV2_PLUGIN,
177 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
178   g_object_class_install_property(gobject,
179 				  PROP_PLUGIN,
180 				  param_spec);
181 
182   /**
183    * AgsPlayLv2Audio:input-lines:
184    *
185    * The effect's input lines count.
186    *
187    * Since: 3.0.0
188    */
189   param_spec =  g_param_spec_ulong("input-lines",
190 				   i18n_pspec("input lines of effect"),
191 				   i18n_pspec("The effect's count of input lines"),
192 				   0,
193 				   65535,
194 				   0,
195 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
196   g_object_class_install_property(gobject,
197 				  PROP_INPUT_LINES,
198 				  param_spec);
199 
200   /**
201    * AgsPlayLv2Audio:output-lines:
202    *
203    * The effect's output lines count.
204    *
205    * Since: 3.0.0
206    */
207   param_spec =  g_param_spec_ulong("output-lines",
208 				   i18n_pspec("output lines of effect"),
209 				   i18n_pspec("The effect's count of output lines"),
210 				   0,
211 				   65535,
212 				   0,
213 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
214   g_object_class_install_property(gobject,
215 				  PROP_OUTPUT_LINES,
216 				  param_spec);
217 }
218 
219 void
ags_play_lv2_audio_init(AgsPlayLv2Audio * play_lv2_audio)220 ags_play_lv2_audio_init(AgsPlayLv2Audio *play_lv2_audio)
221 {
222   GList *port;
223 
224   AGS_RECALL(play_lv2_audio)->name = "ags-play-lv2";
225   AGS_RECALL(play_lv2_audio)->version = AGS_RECALL_DEFAULT_VERSION;
226   AGS_RECALL(play_lv2_audio)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
227   AGS_RECALL(play_lv2_audio)->xml_type = "ags-play-lv2-audio";
228 
229   play_lv2_audio->turtle = NULL;
230 
231   play_lv2_audio->uri = NULL;
232 
233   play_lv2_audio->plugin = NULL;
234   play_lv2_audio->plugin_descriptor = NULL;
235 
236   play_lv2_audio->input_port = NULL;
237   play_lv2_audio->input_lines = 0;
238 
239   play_lv2_audio->output_port = NULL;
240   play_lv2_audio->output_lines = 0;
241 
242   play_lv2_audio->event_port = 0;
243   play_lv2_audio->atom_port = 0;
244 
245   play_lv2_audio->bank = 0;
246   play_lv2_audio->program = 0;
247 }
248 
249 void
ags_play_lv2_audio_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)250 ags_play_lv2_audio_set_property(GObject *gobject,
251 				guint prop_id,
252 				const GValue *value,
253 				GParamSpec *param_spec)
254 {
255   AgsPlayLv2Audio *play_lv2_audio;
256 
257   GRecMutex *recall_mutex;
258 
259   play_lv2_audio = AGS_PLAY_LV2_AUDIO(gobject);
260 
261   /* get recall mutex */
262   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_lv2_audio);
263 
264   switch(prop_id){
265   case PROP_TURTLE:
266     {
267       AgsTurtle *turtle;
268 
269       turtle = (AgsTurtle *) g_value_get_object(value);
270 
271       g_rec_mutex_lock(recall_mutex);
272 
273       if(play_lv2_audio->turtle == turtle){
274 	g_rec_mutex_unlock(recall_mutex);
275 
276 	return;
277       }
278 
279       if(play_lv2_audio->turtle != NULL){
280 	g_object_unref(play_lv2_audio->turtle);
281       }
282 
283       if(turtle != NULL){
284 	g_object_ref(turtle);
285       }
286 
287       play_lv2_audio->turtle = turtle;
288 
289       g_rec_mutex_unlock(recall_mutex);
290     }
291     break;
292   case PROP_URI:
293     {
294       gchar *uri;
295 
296       uri = g_value_get_string(value);
297 
298       g_rec_mutex_lock(recall_mutex);
299 
300       if(uri == play_lv2_audio->uri){
301 	g_rec_mutex_unlock(recall_mutex);
302 
303 	return;
304       }
305 
306       if(play_lv2_audio->uri != NULL){
307 	g_free(play_lv2_audio->uri);
308       }
309 
310       play_lv2_audio->uri = g_strdup(uri);
311 
312       g_rec_mutex_unlock(recall_mutex);
313     }
314     break;
315   case PROP_PLUGIN:
316     {
317       AgsLv2Plugin *lv2_plugin;
318 
319       lv2_plugin = g_value_get_object(value);
320 
321       g_rec_mutex_lock(recall_mutex);
322 
323       if(play_lv2_audio->plugin == lv2_plugin){
324 	g_rec_mutex_unlock(recall_mutex);
325 
326 	return;
327       }
328 
329       if(play_lv2_audio->plugin != NULL){
330 	g_object_unref(play_lv2_audio->plugin);
331       }
332 
333       if(lv2_plugin != NULL){
334 	g_object_ref(lv2_plugin);
335       }
336 
337       play_lv2_audio->plugin = lv2_plugin;
338 
339       g_rec_mutex_unlock(recall_mutex);
340     }
341     break;
342   case PROP_INPUT_LINES:
343     {
344       unsigned long effect_input_lines;
345 
346       effect_input_lines = g_value_get_ulong(value);
347 
348       g_rec_mutex_lock(recall_mutex);
349 
350       if(effect_input_lines == play_lv2_audio->input_lines){
351 	g_rec_mutex_unlock(recall_mutex);
352 
353 	return;
354       }
355 
356       play_lv2_audio->input_lines = effect_input_lines;
357 
358       g_rec_mutex_unlock(recall_mutex);
359     }
360     break;
361   case PROP_OUTPUT_LINES:
362     {
363       unsigned long effect_output_lines;
364 
365       effect_output_lines = g_value_get_ulong(value);
366 
367       g_rec_mutex_lock(recall_mutex);
368 
369       if(effect_output_lines == play_lv2_audio->output_lines){
370 	g_rec_mutex_unlock(recall_mutex);
371 
372 	return;
373       }
374 
375       play_lv2_audio->output_lines = effect_output_lines;
376 
377       g_rec_mutex_unlock(recall_mutex);
378     }
379     break;
380   default:
381     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
382     break;
383   };
384 }
385 
386 void
ags_play_lv2_audio_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)387 ags_play_lv2_audio_get_property(GObject *gobject,
388 				guint prop_id,
389 				GValue *value,
390 				GParamSpec *param_spec)
391 {
392   AgsPlayLv2Audio *play_lv2_audio;
393 
394   GRecMutex *recall_mutex;
395 
396   play_lv2_audio = AGS_PLAY_LV2_AUDIO(gobject);
397 
398   /* get recall mutex */
399   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_lv2_audio);
400 
401   switch(prop_id){
402   case PROP_TURTLE:
403     {
404       g_rec_mutex_lock(recall_mutex);
405 
406       g_value_set_object(value, play_lv2_audio->turtle);
407 
408       g_rec_mutex_unlock(recall_mutex);
409     }
410     break;
411   case PROP_URI:
412     {
413       g_rec_mutex_lock(recall_mutex);
414 
415       g_value_set_string(value, play_lv2_audio->uri);
416 
417       g_rec_mutex_unlock(recall_mutex);
418     }
419     break;
420   case PROP_PLUGIN:
421     {
422       g_rec_mutex_lock(recall_mutex);
423 
424       g_value_set_object(value, play_lv2_audio->plugin);
425 
426       g_rec_mutex_unlock(recall_mutex);
427     }
428     break;
429   case PROP_INPUT_LINES:
430     {
431       g_rec_mutex_lock(recall_mutex);
432 
433       g_value_set_ulong(value, play_lv2_audio->input_lines);
434 
435       g_rec_mutex_unlock(recall_mutex);
436     }
437     break;
438   case PROP_OUTPUT_LINES:
439     {
440       g_rec_mutex_lock(recall_mutex);
441 
442       g_value_set_ulong(value, play_lv2_audio->output_lines);
443 
444       g_rec_mutex_unlock(recall_mutex);
445     }
446     break;
447   default:
448     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
449     break;
450   }
451 }
452 
453 void
ags_play_lv2_audio_dispose(GObject * gobject)454 ags_play_lv2_audio_dispose(GObject *gobject)
455 {
456   AgsPlayLv2Audio *play_lv2_audio;
457 
458   play_lv2_audio = AGS_PLAY_LV2_AUDIO(gobject);
459 
460   /* turtle */
461   if(play_lv2_audio->turtle != NULL){
462     g_object_unref(play_lv2_audio->turtle);
463 
464     play_lv2_audio->turtle = NULL;
465   }
466 
467   /* plugin */
468   if(play_lv2_audio->plugin != NULL){
469     g_object_unref(play_lv2_audio->plugin);
470 
471     play_lv2_audio->plugin = NULL;
472   }
473 
474   /* call parent */
475   G_OBJECT_CLASS(ags_play_lv2_audio_parent_class)->dispose(gobject);
476 }
477 
478 void
ags_play_lv2_audio_finalize(GObject * gobject)479 ags_play_lv2_audio_finalize(GObject *gobject)
480 {
481   AgsPlayLv2Audio *play_lv2_audio;
482 
483   play_lv2_audio = AGS_PLAY_LV2_AUDIO(gobject);
484 
485   /* turtle */
486   if(play_lv2_audio->turtle != NULL){
487     g_object_unref(play_lv2_audio->turtle);
488   }
489 
490   /* plugin */
491   if(play_lv2_audio->plugin != NULL){
492     g_object_unref(play_lv2_audio->plugin);
493   }
494 
495   /* filename, effect and uri */
496   g_free(play_lv2_audio->uri);
497 
498   /* call parent */
499   G_OBJECT_CLASS(ags_play_lv2_audio_parent_class)->finalize(gobject);
500 }
501 
502 /**
503  * ags_play_lv2_audio_test_flags:
504  * @play_lv2_audio: the #AgsPlayLv2Audio
505  * @flags: the flags
506  *
507  * Test @flags to be set on @play_lv2_audio.
508  *
509  * Returns: %TRUE if flags are set, else %FALSE
510  *
511  * Since: 3.0.0
512  */
513 gboolean
ags_play_lv2_audio_test_flags(AgsPlayLv2Audio * play_lv2_audio,guint flags)514 ags_play_lv2_audio_test_flags(AgsPlayLv2Audio *play_lv2_audio, guint flags)
515 {
516   gboolean retval;
517 
518   GRecMutex *recall_mutex;
519 
520   if(!AGS_IS_PLAY_LV2_AUDIO(play_lv2_audio)){
521     return(FALSE);
522   }
523 
524   /* get play_lv2_audio mutex */
525   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_lv2_audio);
526 
527   /* test */
528   g_rec_mutex_lock(recall_mutex);
529 
530   retval = (flags & (play_lv2_audio->flags)) ? TRUE: FALSE;
531 
532   g_rec_mutex_unlock(recall_mutex);
533 
534   return(retval);
535 }
536 
537 /**
538  * ags_play_lv2_audio_set_flags:
539  * @play_lv2_audio: the #AgsPlayLv2Audio
540  * @flags: the flags
541  *
542  * Set flags.
543  *
544  * Since: 3.0.0
545  */
546 void
ags_play_lv2_audio_set_flags(AgsPlayLv2Audio * play_lv2_audio,guint flags)547 ags_play_lv2_audio_set_flags(AgsPlayLv2Audio *play_lv2_audio, guint flags)
548 {
549   GRecMutex *recall_mutex;
550 
551   if(!AGS_IS_PLAY_LV2_AUDIO(play_lv2_audio)){
552     return;
553   }
554 
555   /* get play_lv2_audio mutex */
556   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_lv2_audio);
557 
558   /* set flags */
559   g_rec_mutex_lock(recall_mutex);
560 
561   play_lv2_audio->flags |= flags;
562 
563   g_rec_mutex_unlock(recall_mutex);
564 }
565 
566 /**
567  * ags_play_lv2_audio_unset_flags:
568  * @play_lv2_audio: the #AgsPlayLv2Audio
569  * @flags: the flags
570  *
571  * Unset flags.
572  *
573  * Since: 3.0.0
574  */
575 void
ags_play_lv2_audio_unset_flags(AgsPlayLv2Audio * play_lv2_audio,guint flags)576 ags_play_lv2_audio_unset_flags(AgsPlayLv2Audio *play_lv2_audio, guint flags)
577 {
578   GRecMutex *recall_mutex;
579 
580   if(!AGS_IS_PLAY_LV2_AUDIO(play_lv2_audio)){
581     return;
582   }
583 
584   /* get play_lv2_audio mutex */
585   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_lv2_audio);
586 
587   /* set flags */
588   g_rec_mutex_lock(recall_mutex);
589 
590   play_lv2_audio->flags &= (~flags);
591 
592   g_rec_mutex_unlock(recall_mutex);
593 }
594 
595 /**
596  * ags_play_lv2_audio_load:
597  * @play_lv2_audio: the #AgsPlayLv2Audio
598  *
599  * Set up LV2 handle.
600  *
601  * Since: 3.0.0
602  */
603 void
ags_play_lv2_audio_load(AgsPlayLv2Audio * play_lv2_audio)604 ags_play_lv2_audio_load(AgsPlayLv2Audio *play_lv2_audio)
605 {
606   AgsLv2Plugin *lv2_plugin;
607 
608   gchar *filename, *effect;
609 
610   guint effect_index;
611   guint i;
612 
613   void *plugin_so;
614   LV2_Descriptor_Function lv2_descriptor;
615   LV2_Descriptor *plugin_descriptor;
616 
617   GRecMutex *recall_mutex;
618 
619   if(!AGS_IS_PLAY_LV2_AUDIO(play_lv2_audio)){
620     return;
621   }
622 
623   /* get recall mutex */
624   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_lv2_audio);
625 
626   /* get filename and effect */
627   g_rec_mutex_lock(recall_mutex);
628 
629   filename = g_strdup(AGS_RECALL(play_lv2_audio)->filename);
630   effect = g_strdup(AGS_RECALL(play_lv2_audio)->effect);
631 
632   g_rec_mutex_unlock(recall_mutex);
633 
634   /* find AgsLv2Plugin */
635   lv2_plugin = ags_lv2_manager_find_lv2_plugin(ags_lv2_manager_get_instance(),
636 					       filename, effect);
637 
638   g_object_get(lv2_plugin,
639 	       "plugin-so", &plugin_so,
640 	       NULL);
641 
642   if(plugin_so == NULL){
643     g_message("open %s", filename);
644 
645 #ifdef AGS_W32API
646     plugin_so = LoadLibrary(filename);
647 #else
648     plugin_so = dlopen(filename,
649 		       RTLD_NOW);
650 #endif
651 
652     g_object_set(lv2_plugin,
653 		 "plugin-so", plugin_so,
654 		 NULL);
655   }
656 
657   /* get some fields */
658   play_lv2_audio->plugin = lv2_plugin;
659 
660   if(plugin_so != NULL){
661     gboolean success;
662 
663     success = FALSE;
664 
665 #ifdef AGS_W32API
666     lv2_descriptor = (LV2_Descriptor_Function) GetProcAddress(plugin_so,
667 							      "lv2_descriptor");
668 
669     success = (!lv2_descriptor) ? FALSE: TRUE;
670 #else
671     lv2_descriptor = (LV2_Descriptor_Function) dlsym(plugin_so,
672 						     "lv2_descriptor");
673 
674     success = (dlerror() == NULL) ? TRUE: FALSE;
675 #endif
676 
677     if(success && lv2_descriptor){
678       effect_index = 0;
679 
680       for(i = 0; (plugin_descriptor = lv2_descriptor((unsigned long) i)) != NULL; i++){
681 	 if(!g_ascii_strcasecmp(plugin_descriptor->URI,
682 				lv2_plugin->uri)){
683 	   effect_index = i;
684 
685 	   g_object_set(lv2_plugin,
686 			"effect-index", effect_index,
687 			NULL);
688 
689 	   break;
690 	 }
691       }
692 
693       g_rec_mutex_lock(recall_mutex);
694 
695       play_lv2_audio->plugin_descriptor = plugin_descriptor;
696 
697       g_rec_mutex_unlock(recall_mutex);
698 
699       if(ags_lv2_plugin_test_flags(lv2_plugin, AGS_LV2_PLUGIN_NEEDS_WORKER)){
700 	ags_play_lv2_audio_set_flags(play_lv2_audio, AGS_PLAY_LV2_AUDIO_HAS_WORKER);
701       }
702     }
703   }
704 
705   /* free */
706   g_free(filename);
707   g_free(effect);
708 }
709 
710 /**
711  * ags_play_lv2_audio_load_ports:
712  * @play_lv2_audio: the #AgsPlayLv2Audio
713  *
714  * Set up LV2 ports.
715  *
716  * Returns: (element-type AgsAudio.Port) (transfer full): the #GList-struct containing #AgsPort
717  *
718  * Since: 3.0.0
719  */
720 GList*
ags_play_lv2_audio_load_ports(AgsPlayLv2Audio * play_lv2_audio)721 ags_play_lv2_audio_load_ports(AgsPlayLv2Audio *play_lv2_audio)
722 {
723   AgsPort *current;
724 
725   AgsLv2Plugin *lv2_plugin;
726 
727   GList *start_port;
728   GList *start_plugin_port, *plugin_port;
729 
730   gchar *filename, *effect;
731   gchar *plugin_name;
732 
733   uint32_t port_count;
734   uint32_t i;
735 
736   GRecMutex *recall_mutex;
737   GRecMutex *base_plugin_mutex;
738 
739   if(!AGS_IS_PLAY_LV2_AUDIO(play_lv2_audio)){
740     return(NULL);
741   }
742 
743   /* get recall mutex */
744   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_lv2_audio);
745 
746   /* get filename and effect */
747   g_rec_mutex_lock(recall_mutex);
748 
749   filename = g_strdup(AGS_RECALL(play_lv2_audio)->filename);
750   effect = g_strdup(AGS_RECALL(play_lv2_audio)->effect);
751 
752   g_rec_mutex_unlock(recall_mutex);
753 
754   /* find AgsLv2Plugin */
755   lv2_plugin = ags_lv2_manager_find_lv2_plugin(ags_lv2_manager_get_instance(),
756 						  filename, effect);
757 
758   play_lv2_audio->plugin = lv2_plugin;
759 
760   /* get plugin port */
761   g_object_get(lv2_plugin,
762 	       "plugin-port", &start_plugin_port,
763 	       NULL);
764 
765   /* get base plugin mutex */
766   base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(lv2_plugin);
767 
768   /* get plugin name */
769   g_rec_mutex_lock(base_plugin_mutex);
770 
771   plugin_name = g_strdup_printf("lv2-<%s>", lv2_plugin->uri);
772 
773   g_rec_mutex_unlock(base_plugin_mutex);
774 
775   plugin_port = start_plugin_port;
776   start_port = NULL;
777 
778   if(plugin_port != NULL){
779     port_count = g_list_length(plugin_port);
780 
781     for(i = 0; i < port_count; i++){
782       gchar *specifier;
783 
784       GValue *value;
785 
786       GRecMutex *plugin_port_mutex;
787 
788       /* get plugin port mutex */
789       plugin_port_mutex = AGS_PLUGIN_PORT_GET_OBJ_MUTEX(plugin_port->data);
790 
791       if(ags_plugin_port_test_flags((AgsPluginPort *) plugin_port->data, AGS_PLUGIN_PORT_INPUT)){
792 	if(ags_plugin_port_test_flags((AgsPluginPort *) plugin_port->data, AGS_PLUGIN_PORT_EVENT)){
793 	  play_lv2_audio->flags |= AGS_PLAY_LV2_AUDIO_HAS_EVENT_PORT;
794 	  play_lv2_audio->event_port = AGS_PLUGIN_PORT(plugin_port->data)->port_index;
795 	}
796 
797 	if(ags_plugin_port_test_flags((AgsPluginPort *) plugin_port->data, AGS_PLUGIN_PORT_ATOM)){
798 	  play_lv2_audio->flags |= AGS_PLAY_LV2_AUDIO_HAS_ATOM_PORT;
799 	  play_lv2_audio->atom_port = AGS_PLUGIN_PORT(plugin_port->data)->port_index;
800 	}
801       }
802 
803       if(ags_plugin_port_test_flags((AgsPluginPort *) plugin_port->data, AGS_PLUGIN_PORT_CONTROL) &&
804 	 (ags_plugin_port_test_flags((AgsPluginPort *) plugin_port->data, AGS_PLUGIN_PORT_INPUT) ||
805 	  ags_plugin_port_test_flags((AgsPluginPort *) plugin_port->data, AGS_PLUGIN_PORT_OUTPUT))){
806 	gchar *specifier;
807 
808 	/* get specifier */
809 	g_rec_mutex_lock(plugin_port_mutex);
810 
811 	specifier = g_strdup(AGS_PLUGIN_PORT(plugin_port->data)->port_name);
812 
813 	g_rec_mutex_unlock(plugin_port_mutex);
814 
815 	if(specifier == NULL){
816 	  plugin_port = plugin_port->next;
817 
818 	  continue;
819 	}
820 
821 	current = g_object_new(AGS_TYPE_PORT,
822 			       "plugin-name", plugin_name,
823 			       "specifier", specifier,
824 			       "control-port", g_strdup_printf("%u/%u",
825 								 i,
826 								 port_count),
827 			       "port-value-is-pointer", FALSE,
828 			       "port-value-type", G_TYPE_FLOAT,
829 			       NULL);
830 	g_object_ref(current);
831 
832 	if(ags_plugin_port_test_flags((AgsPluginPort *) plugin_port->data, AGS_PLUGIN_PORT_OUTPUT)){
833 	  ags_recall_set_flags((AgsRecall *) play_lv2_audio,
834 			       AGS_RECALL_HAS_OUTPUT_PORT);
835 
836 	  ags_port_set_flags((AgsPort *) current,
837 			     AGS_PORT_IS_OUTPUT);
838 	}else{
839 	  gint scale_steps;
840 
841 	  g_object_get(plugin_port->data,
842 		       "scale-steps", &scale_steps,
843 		       NULL);
844 
845 	  if(!ags_plugin_port_test_flags((AgsPluginPort *) plugin_port->data, AGS_PLUGIN_PORT_INTEGER) &&
846 	     !ags_plugin_port_test_flags((AgsPluginPort *) plugin_port->data, AGS_PLUGIN_PORT_TOGGLED) &&
847 	     scale_steps == -1){
848 	    ags_port_set_flags((AgsPort *) current,
849 			       AGS_PORT_INFINITE_RANGE);
850 	  }
851 	}
852 
853 	g_object_set(current,
854 		     "plugin-port", plugin_port->data,
855 		     NULL);
856 
857 	ags_play_lv2_audio_load_conversion(play_lv2_audio,
858 					   (GObject *) current,
859 					   (GObject *) plugin_port->data);
860 
861 	g_object_get(plugin_port->data,
862 		     "default-value", &value,
863 		      NULL);
864 
865 	current->port_value.ags_port_ladspa = g_value_get_float(value);
866 
867 #ifdef AGS_DEBUG
868 	g_message("connecting port: %s %d/%d", specifier, i, port_count);
869 #endif
870 
871 	start_port = g_list_prepend(start_port,
872 				    current);
873       }else if(ags_plugin_port_test_flags((AgsPluginPort *) plugin_port->data, AGS_PLUGIN_PORT_AUDIO)){
874 	guint port_index;
875 
876 	g_object_get(plugin_port->data,
877 		     "port-index", &port_index,
878 		     NULL);
879 
880 	if(ags_plugin_port_test_flags((AgsPluginPort *) plugin_port->data, AGS_PLUGIN_PORT_INPUT)){
881 	  g_rec_mutex_lock(recall_mutex);
882 
883 	  if(play_lv2_audio->input_port == NULL){
884 	    play_lv2_audio->input_port = (uint32_t *) malloc(sizeof(uint32_t));
885 	    play_lv2_audio->input_port[0] = port_index;
886 	  }else{
887 	    play_lv2_audio->input_port = (uint32_t *) realloc(play_lv2_audio->input_port,
888 							      (play_lv2_audio->input_lines + 1) * sizeof(uint32_t));
889 	    play_lv2_audio->input_port[play_lv2_audio->input_lines] = port_index;
890 	  }
891 
892 	  play_lv2_audio->input_lines += 1;
893 
894 	  g_rec_mutex_unlock(recall_mutex);
895 	}else if(ags_plugin_port_test_flags((AgsPluginPort *) plugin_port->data, AGS_PLUGIN_PORT_OUTPUT)){
896 	  g_rec_mutex_lock(recall_mutex);
897 
898 	  if(play_lv2_audio->output_port == NULL){
899 	    play_lv2_audio->output_port = (uint32_t *) malloc(sizeof(uint32_t));
900 	    play_lv2_audio->output_port[0] = port_index;
901 	  }else{
902 	    play_lv2_audio->output_port = (uint32_t *) realloc(play_lv2_audio->output_port,
903 							       (play_lv2_audio->output_lines + 1) * sizeof(uint32_t));
904 	    play_lv2_audio->output_port[play_lv2_audio->output_lines] = port_index;
905 	  }
906 
907 	  play_lv2_audio->output_lines += 1;
908 
909 	  g_rec_mutex_unlock(recall_mutex);
910 	}
911       }
912 
913       /* iterate */
914       plugin_port = plugin_port->next;
915     }
916 
917     start_port = g_list_reverse(start_port);
918     AGS_RECALL(play_lv2_audio)->port = g_list_copy(start_port);
919   }
920 
921   /* unref/free */
922   g_list_free_full(start_plugin_port,
923 		   g_object_unref);
924 
925   g_free(filename);
926   g_free(effect);
927 
928   g_free(plugin_name);
929 
930 #ifdef AGS_DEBUG
931   g_message("output lines: %d", play_lv2_audio->output_lines);
932 #endif
933 
934   return(start_port);
935 }
936 
937 /**
938  * ags_play_lv2_audio_load_conversion:
939  * @play_lv2_audio: the #AgsPlayLv2Audio
940  * @port: the #AgsPort
941  * @plugin_port: the #AgsPluginPort
942  *
943  * Loads conversion object by using @plugin_port and sets in on @port.
944  *
945  * Since: 3.0.0
946  */
947 void
ags_play_lv2_audio_load_conversion(AgsPlayLv2Audio * play_lv2_audio,GObject * port,GObject * plugin_port)948 ags_play_lv2_audio_load_conversion(AgsPlayLv2Audio *play_lv2_audio,
949 				   GObject *port,
950 				   GObject *plugin_port)
951 {
952   AgsLv2Conversion *lv2_conversion;
953 
954   if(!AGS_IS_PLAY_LV2_AUDIO(play_lv2_audio) ||
955      !AGS_IS_PORT(port) ||
956      !AGS_PLUGIN_PORT(plugin_port)){
957     return;
958   }
959 
960   lv2_conversion = NULL;
961 
962   if(ags_plugin_port_test_flags((AgsPluginPort *) plugin_port, AGS_PLUGIN_PORT_LOGARITHMIC)){
963     lv2_conversion = ags_lv2_conversion_new();
964     lv2_conversion->flags |= AGS_LV2_CONVERSION_LOGARITHMIC;
965 
966     g_object_set(port,
967 		 "conversion", lv2_conversion,
968 		 NULL);
969   }
970 }
971 
972 /**
973  * ags_play_lv2_audio_find:
974  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
975  * @filename: plugin's filename
976  * @uri: plugin's uri
977  *
978  * Retrieve LV2 recall.
979  *
980  * Returns: (element-type AgsAudio.Recall) (transfer none): Next match.
981  *
982  * Since: 3.0.0
983  */
984 GList*
ags_play_lv2_audio_find(GList * recall,gchar * filename,gchar * uri)985 ags_play_lv2_audio_find(GList *recall,
986 			gchar *filename, gchar *uri)
987 {
988   while(recall != NULL){
989     if(AGS_IS_PLAY_LV2_AUDIO(recall->data)){
990       gboolean success;
991 
992       GRecMutex *recall_mutex;
993 
994       /* get recall mutex */
995       recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall->data);
996 
997       /* check current filename and effect */
998       g_rec_mutex_lock(recall_mutex);
999 
1000       success = (!g_strcmp0(AGS_RECALL(recall->data)->filename,
1001 			    filename) &&
1002 		 !g_strcmp0(AGS_PLAY_LV2_AUDIO(recall->data)->uri,
1003 			    uri)) ? TRUE: FALSE;
1004 
1005       g_rec_mutex_unlock(recall_mutex);
1006 
1007       if(success){
1008 	break;
1009       }
1010     }
1011 
1012     /* iterate */
1013     recall = recall->next;
1014   }
1015 
1016   return(recall);
1017 }
1018 
1019 /**
1020  * ags_play_lv2_audio_new:
1021  * @audio: the #AgsAudio
1022  *
1023  * Create a new instance of #AgsPlayLv2Audio
1024  *
1025  * Returns: the new #AgsPlayLv2Audio
1026  *
1027  * Since: 3.0.0
1028  */
1029 AgsPlayLv2Audio*
ags_play_lv2_audio_new(AgsAudio * audio)1030 ags_play_lv2_audio_new(AgsAudio *audio)
1031 {
1032   AgsPlayLv2Audio *play_lv2_audio;
1033 
1034   play_lv2_audio = (AgsPlayLv2Audio *) g_object_new(AGS_TYPE_PLAY_LV2_AUDIO,
1035 						    "audio", audio,
1036 						    NULL);
1037 
1038   return(play_lv2_audio);
1039 }
1040