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/X/ags_effect_line.h>
21 #include <ags/X/ags_effect_line_callbacks.h>
22 
23 #include <ags/X/ags_ui_provider.h>
24 #include <ags/X/ags_window.h>
25 #include <ags/X/ags_machine.h>
26 #include <ags/X/ags_effect_pad.h>
27 #include <ags/X/ags_line_member.h>
28 #include <ags/X/ags_effect_separator.h>
29 #include <ags/X/ags_machine_editor.h>
30 #include <ags/X/ags_pad_editor.h>
31 #include <ags/X/ags_line_editor.h>
32 #include <ags/X/ags_line_member_editor.h>
33 #include <ags/X/ags_plugin_browser.h>
34 #include <ags/X/ags_ladspa_browser.h>
35 #include <ags/X/ags_dssi_browser.h>
36 #include <ags/X/ags_lv2_browser.h>
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43 
44 #include <ladspa.h>
45 
46 #include <ags/i18n.h>
47 
48 void ags_effect_line_class_init(AgsEffectLineClass *effect_line);
49 void ags_effect_line_connectable_interface_init(AgsConnectableInterface *connectable);
50 void ags_effect_line_init(AgsEffectLine *effect_line);
51 void ags_effect_line_set_property(GObject *gobject,
52 				  guint prop_id,
53 				  const GValue *value,
54 				  GParamSpec *param_spec);
55 void ags_effect_line_get_property(GObject *gobject,
56 				  guint prop_id,
57 				  GValue *value,
58 				  GParamSpec *param_spec);
59 void ags_effect_line_dispose(GObject *gobject);
60 void ags_effect_line_finalize(GObject *gobject);
61 
62 void ags_effect_line_connect(AgsConnectable *connectable);
63 void ags_effect_line_disconnect(AgsConnectable *connectable);
64 
65 void ags_effect_line_real_set_channel(AgsEffectLine *effect_line, AgsChannel *channel);
66 
67 void ags_effect_line_add_ladspa_plugin(AgsEffectLine *effect_line,
68 				       GList *control_type_name,
69 				       AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
70 				       gchar *plugin_name,
71 				       gchar *filename,
72 				       gchar *effect,
73 				       guint start_audio_channel, guint stop_audio_channel,
74 				       guint start_pad, guint stop_pad,
75 				       gint position,
76 				       guint create_flags, guint recall_flags);
77 void ags_effect_line_add_dssi_plugin(AgsEffectLine *effect_line,
78 				     GList *control_type_name,
79 				     AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
80 				     gchar *plugin_name,
81 				     gchar *filename,
82 				     gchar *effect,
83 				     guint start_audio_channel, guint stop_audio_channel,
84 				     guint start_pad, guint stop_pad,
85 				     gint position,
86 				     guint create_flags, guint recall_flags);
87 void ags_effect_line_add_lv2_plugin(AgsEffectLine *effect_line,
88 				    GList *control_type_name,
89 				    AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
90 				    gchar *plugin_name,
91 				    gchar *filename,
92 				    gchar *effect,
93 				    guint start_audio_channel, guint stop_audio_channel,
94 				    guint start_pad, guint stop_pad,
95 				    gint position,
96 				    guint create_flags, guint recall_flags);
97 void ags_effect_line_real_add_plugin(AgsEffectLine *effect_line,
98 				     GList *control_type_name,
99 				     AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
100 				     gchar *plugin_name,
101 				     gchar *filename,
102 				     gchar *effect,
103 				     guint start_audio_channel, guint stop_audio_channel,
104 				     guint start_pad, guint stop_pad,
105 				     gint position,
106 				     guint create_flags, guint recall_flags);
107 void ags_effect_line_real_remove_plugin(AgsEffectLine *effect_line,
108 					guint nth);
109 
110 void ags_effect_line_real_map_recall(AgsEffectLine *effect_line,
111 				     guint output_pad_start);
112 GList* ags_effect_line_real_find_port(AgsEffectLine *effect_line);
113 
114 /**
115  * SECTION:ags_effect_line
116  * @short_description: A composite widget to visualize a bunch of #AgsChannel
117  * @title: AgsEffectLine
118  * @section_id:
119  * @include: ags/X/ags_effect_line.h
120  *
121  * #AgsEffectLine is a composite widget to visualize one #AgsChannel. It should be
122  * packed by an #AgsEffectLine.
123  */
124 
125 enum{
126   SAMPLERATE_CHANGED,
127   BUFFER_SIZE_CHANGED,
128   FORMAT_CHANGED,
129   SET_CHANNEL,
130   ADD_PLUGIN,
131   REMOVE_PLUGIN,
132   MAP_RECALL,
133   FIND_PORT,
134   DONE,
135   LAST_SIGNAL,
136 };
137 
138 enum{
139   PROP_0,
140   PROP_SAMPLERATE,
141   PROP_BUFFER_SIZE,
142   PROP_FORMAT,
143   PROP_CHANNEL,
144 };
145 
146 static gpointer ags_effect_line_parent_class = NULL;
147 static guint effect_line_signals[LAST_SIGNAL];
148 
149 GHashTable *ags_effect_line_indicator_queue_draw = NULL;
150 
151 GType
ags_effect_line_get_type(void)152 ags_effect_line_get_type(void)
153 {
154   static volatile gsize g_define_type_id__volatile = 0;
155 
156   if(g_once_init_enter (&g_define_type_id__volatile)){
157     GType ags_type_effect_line = 0;
158 
159     static const GTypeInfo ags_effect_line_info = {
160       sizeof(AgsEffectLineClass),
161       NULL, /* base_init */
162       NULL, /* base_finalize */
163       (GClassInitFunc) ags_effect_line_class_init,
164       NULL, /* class_finalize */
165       NULL, /* class_data */
166       sizeof(AgsEffectLine),
167       0,    /* n_preallocs */
168       (GInstanceInitFunc) ags_effect_line_init,
169     };
170 
171     static const GInterfaceInfo ags_connectable_interface_info = {
172       (GInterfaceInitFunc) ags_effect_line_connectable_interface_init,
173       NULL, /* interface_finalize */
174       NULL, /* interface_data */
175     };
176 
177     ags_type_effect_line = g_type_register_static(GTK_TYPE_BOX,
178 						  "AgsEffectLine", &ags_effect_line_info,
179 						  0);
180 
181     g_type_add_interface_static(ags_type_effect_line,
182 				AGS_TYPE_CONNECTABLE,
183 				&ags_connectable_interface_info);
184 
185     g_once_init_leave(&g_define_type_id__volatile, ags_type_effect_line);
186   }
187 
188   return g_define_type_id__volatile;
189 }
190 
191 void
ags_effect_line_class_init(AgsEffectLineClass * effect_line)192 ags_effect_line_class_init(AgsEffectLineClass *effect_line)
193 {
194   GObjectClass *gobject;
195   GParamSpec *param_spec;
196 
197   ags_effect_line_parent_class = g_type_class_peek_parent(effect_line);
198 
199   /* GObjectClass */
200   gobject = G_OBJECT_CLASS(effect_line);
201 
202   gobject->set_property = ags_effect_line_set_property;
203   gobject->get_property = ags_effect_line_get_property;
204 
205   gobject->dispose = ags_effect_line_dispose;
206   gobject->finalize = ags_effect_line_finalize;
207 
208   /* properties */
209   /**
210    * AgsEffectLine:samplerate:
211    *
212    * The samplerate.
213    *
214    * Since: 3.0.0
215    */
216   param_spec = g_param_spec_uint("samplerate",
217 				 i18n_pspec("samplerate"),
218 				 i18n_pspec("The samplerate"),
219 				 0,
220 				 G_MAXUINT32,
221 				 AGS_SOUNDCARD_DEFAULT_SAMPLERATE,
222 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
223   g_object_class_install_property(gobject,
224 				  PROP_SAMPLERATE,
225 				  param_spec);
226 
227   /**
228    * AgsEffectLine:buffer-size:
229    *
230    * The buffer length.
231    *
232    * Since: 3.0.0
233    */
234   param_spec = g_param_spec_uint("buffer-size",
235 				 i18n_pspec("buffer size"),
236 				 i18n_pspec("The buffer size"),
237 				 0,
238 				 G_MAXUINT32,
239 				 AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE,
240 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
241   g_object_class_install_property(gobject,
242 				  PROP_BUFFER_SIZE,
243 				  param_spec);
244 
245   /**
246    * AgsEffectLine:format:
247    *
248    * The format.
249    *
250    * Since: 3.0.0
251    */
252   param_spec = g_param_spec_uint("format",
253 				 i18n_pspec("format"),
254 				 i18n_pspec("The format"),
255 				 0,
256 				 G_MAXUINT32,
257 				 AGS_SOUNDCARD_DEFAULT_FORMAT,
258 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
259   g_object_class_install_property(gobject,
260 				  PROP_FORMAT,
261 				  param_spec);
262 
263   /**
264    * AgsEffectLine:channel:
265    *
266    * The start of a bunch of #AgsChannel to visualize.
267    *
268    * Since: 3.0.0
269    */
270   param_spec = g_param_spec_object("channel",
271 				   i18n_pspec("assigned channel"),
272 				   i18n_pspec("The channel it is assigned with"),
273 				   AGS_TYPE_CHANNEL,
274 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
275   g_object_class_install_property(gobject,
276 				  PROP_CHANNEL,
277 				  param_spec);
278 
279   /* AgsEffectLineClass */
280   effect_line->samplerate_changed = NULL;
281   effect_line->buffer_size_changed = NULL;
282   effect_line->format_changed = NULL;
283 
284   effect_line->set_channel = ags_effect_line_real_set_channel;
285 
286   effect_line->add_plugin = ags_effect_line_real_add_plugin;
287   effect_line->remove_plugin = ags_effect_line_real_remove_plugin;
288 
289   effect_line->map_recall = ags_effect_line_real_map_recall;
290   effect_line->find_port = ags_effect_line_real_find_port;
291 
292   effect_line->done = NULL;
293 
294   /* signals */
295   /**
296    * AgsEffectLine::samplerate-changed:
297    * @effect_line: the #AgsEffectLine
298    * @samplerate: the samplerate
299    * @old_samplerate: the old samplerate
300    *
301    * The ::samplerate-changed signal notifies about changed samplerate.
302    *
303    * Since: 3.0.0
304    */
305   effect_line_signals[SAMPLERATE_CHANGED] =
306     g_signal_new("samplerate-changed",
307 		 G_TYPE_FROM_CLASS(effect_line),
308 		 G_SIGNAL_RUN_LAST,
309 		 G_STRUCT_OFFSET(AgsEffectLineClass, samplerate_changed),
310 		 NULL, NULL,
311 		 ags_cclosure_marshal_VOID__UINT_UINT,
312 		 G_TYPE_NONE, 2,
313 		 G_TYPE_UINT,
314 		 G_TYPE_UINT);
315 
316   /**
317    * AgsEffectLine::buffer-size-changed:
318    * @effect_line: the #AgsEffectLine
319    * @buffer_size: the buffer size
320    * @old_buffer_size: the old buffer size
321    *
322    * The ::buffer-size-changed signal notifies about changed buffer size.
323    *
324    * Since: 3.0.0
325    */
326   effect_line_signals[BUFFER_SIZE_CHANGED] =
327     g_signal_new("buffer-size-changed",
328 		 G_TYPE_FROM_CLASS(effect_line),
329 		 G_SIGNAL_RUN_LAST,
330 		 G_STRUCT_OFFSET(AgsEffectLineClass, buffer_size_changed),
331 		 NULL, NULL,
332 		 ags_cclosure_marshal_VOID__UINT_UINT,
333 		 G_TYPE_NONE, 2,
334 		 G_TYPE_UINT,
335 		 G_TYPE_UINT);
336 
337   /**
338    * AgsEffectLine::format-changed:
339    * @effect_line: the #AgsEffectLine
340    * @format: the format
341    * @old_format: the old format
342    *
343    * The ::format-changed signal notifies about changed format.
344    *
345    * Since: 3.0.0
346    */
347   effect_line_signals[FORMAT_CHANGED] =
348     g_signal_new("format-changed",
349 		 G_TYPE_FROM_CLASS(effect_line),
350 		 G_SIGNAL_RUN_LAST,
351 		 G_STRUCT_OFFSET(AgsEffectLineClass, format_changed),
352 		 NULL, NULL,
353 		 ags_cclosure_marshal_VOID__UINT_UINT,
354 		 G_TYPE_NONE, 2,
355 		 G_TYPE_UINT,
356 		 G_TYPE_UINT);
357 
358   /**
359    * AgsEffectLine::set-channel:
360    * @effect_line: the #AgsEffectLine to modify
361    * @channel: the #AgsChannel to set
362    *
363    * The ::set-channel signal notifies about changed channel.
364    *
365    * Since: 3.0.0
366    */
367   effect_line_signals[SET_CHANNEL] =
368     g_signal_new("set-channel",
369 		 G_TYPE_FROM_CLASS(effect_line),
370 		 G_SIGNAL_RUN_LAST,
371 		 G_STRUCT_OFFSET(AgsEffectLineClass, set_channel),
372 		 NULL, NULL,
373 		 g_cclosure_marshal_VOID__OBJECT,
374 		 G_TYPE_NONE, 1,
375 		 G_TYPE_OBJECT);
376 
377   /**
378    * AgsEffectLine::add-plugin:
379    * @effect_line: the #AgsEffectLine to modify
380    * @effect: the effect's name
381    *
382    * The ::add-plugin signal notifies about added effect.
383    *
384    * Since: 3.3.0
385    */
386   effect_line_signals[ADD_PLUGIN] =
387     g_signal_new("add-plugin",
388 		 G_TYPE_FROM_CLASS(effect_line),
389 		 G_SIGNAL_RUN_LAST,
390 		 G_STRUCT_OFFSET(AgsEffectLineClass, add_plugin),
391 		 NULL, NULL,
392 		 ags_cclosure_marshal_VOID__POINTER_OBJECT_OBJECT_STRING_STRING_STRING_UINT_UINT_UINT_UINT_INT_UINT_UINT,
393 		 G_TYPE_NONE, 13,
394 		 G_TYPE_POINTER,
395 		 G_TYPE_OBJECT,
396 		 G_TYPE_OBJECT,
397 		 G_TYPE_STRING,
398 		 G_TYPE_STRING,
399 		 G_TYPE_STRING,
400 		 G_TYPE_UINT,
401 		 G_TYPE_UINT,
402 		 G_TYPE_UINT,
403 		 G_TYPE_UINT,
404 		 G_TYPE_INT,
405 		 G_TYPE_UINT,
406 		 G_TYPE_UINT);
407 
408   /**
409    * AgsEffectLine::remove-plugin:
410    * @effect_line: the #AgsEffectLine to modify
411    * @nth: the nth effect
412    *
413    * The ::remove-plugin signal notifies about removed effect.
414    *
415    * Since: 3.3.0
416    */
417   effect_line_signals[REMOVE_PLUGIN] =
418     g_signal_new("remove-plugin",
419 		 G_TYPE_FROM_CLASS(effect_line),
420 		 G_SIGNAL_RUN_LAST,
421 		 G_STRUCT_OFFSET(AgsEffectLineClass, remove_plugin),
422 		 NULL, NULL,
423 		 g_cclosure_marshal_VOID__UINT,
424 		 G_TYPE_NONE, 1,
425 		 G_TYPE_UINT);
426 
427   /**
428    * AgsEffectLine::map-recall:
429    * @effect_line: the #AgsEffectLine
430    * @output_pad_start: the channel's start pad
431    *
432    * The ::map-recall should be used to add the effect_line's default recall. This function
433    * may call ags_effect_line_find_port().
434    *
435    * Since: 3.0.0
436    */
437   effect_line_signals[MAP_RECALL] =
438     g_signal_new("map-recall",
439                  G_TYPE_FROM_CLASS (effect_line),
440                  G_SIGNAL_RUN_LAST,
441 		 G_STRUCT_OFFSET (AgsEffectLineClass, map_recall),
442                  NULL, NULL,
443                  g_cclosure_marshal_VOID__UINT,
444                  G_TYPE_NONE, 1,
445 		 G_TYPE_UINT);
446 
447   /**
448    * AgsEffectLine::find-port:
449    * @effect_line: the #AgsEffectLine to resize
450    *
451    * The ::find-port as recall should be mapped
452    *
453    * Returns: an #GList-struct containing all related #AgsPort
454    *
455    * Since: 3.0.0
456    */
457   effect_line_signals[FIND_PORT] =
458     g_signal_new("find-port",
459 		 G_TYPE_FROM_CLASS(effect_line),
460 		 G_SIGNAL_RUN_LAST,
461 		 G_STRUCT_OFFSET(AgsEffectLineClass, find_port),
462 		 NULL, NULL,
463 		 ags_cclosure_marshal_POINTER__VOID,
464 		 G_TYPE_POINTER, 0);
465 
466   /**
467    * AgsEffectLine::done:
468    * @effect_line: the #AgsEffectLine
469    * @recall_id: the #AgsRecallID
470    *
471    * The ::done signal gets emited as audio stops playback.
472    *
473    * Since: 3.0.0
474    */
475   effect_line_signals[DONE] =
476     g_signal_new("done",
477                  G_TYPE_FROM_CLASS(effect_line),
478                  G_SIGNAL_RUN_LAST,
479 		 G_STRUCT_OFFSET(AgsEffectLineClass, done),
480                  NULL, NULL,
481                  g_cclosure_marshal_VOID__OBJECT,
482                  G_TYPE_NONE, 1,
483 		 G_TYPE_OBJECT);
484 }
485 
486 void
ags_effect_line_connectable_interface_init(AgsConnectableInterface * connectable)487 ags_effect_line_connectable_interface_init(AgsConnectableInterface *connectable)
488 {
489   connectable->is_ready = NULL;
490   connectable->is_connected = NULL;
491   connectable->connect = ags_effect_line_connect;
492   connectable->disconnect = ags_effect_line_disconnect;
493 }
494 
495 void
ags_effect_line_init(AgsEffectLine * effect_line)496 ags_effect_line_init(AgsEffectLine *effect_line)
497 {
498   AgsApplicationContext *application_context;
499   AgsConfig *config;
500 
501   gtk_orientable_set_orientation(GTK_ORIENTABLE(effect_line),
502 				 GTK_ORIENTATION_VERTICAL);
503 
504   application_context = ags_application_context_get_instance();
505 
506   g_signal_connect(application_context, "check-message",
507 		   G_CALLBACK(ags_effect_line_check_message_callback), effect_line);
508 
509   if(ags_effect_line_indicator_queue_draw == NULL){
510     ags_effect_line_indicator_queue_draw = g_hash_table_new_full(g_direct_hash, g_direct_equal,
511 								 NULL,
512 								 NULL);
513   }
514 
515   effect_line->flags = 0;
516 
517   effect_line->name = NULL;
518 
519   effect_line->version = AGS_EFFECT_LINE_DEFAULT_VERSION;
520   effect_line->build_id = AGS_EFFECT_LINE_DEFAULT_BUILD_ID;
521 
522   config = ags_config_get_instance();
523 
524   effect_line->samplerate = ags_soundcard_helper_config_get_samplerate(config);
525   effect_line->buffer_size = ags_soundcard_helper_config_get_buffer_size(config);
526   effect_line->format = ags_soundcard_helper_config_get_format(config);
527 
528   effect_line->channel = NULL;
529 
530   effect_line->label = (GtkLabel *) g_object_new(GTK_TYPE_LABEL,
531 						 NULL);
532   gtk_box_pack_start(GTK_BOX(effect_line),
533 		     GTK_WIDGET(effect_line->label),
534 		     FALSE, FALSE,
535 		     0);
536 
537   effect_line->group = (GtkToggleButton *) gtk_toggle_button_new_with_label(i18n("group"));
538   gtk_box_pack_start((GtkBox *) effect_line,
539 		     (GtkWidget *) effect_line->group,
540 		     FALSE, FALSE,
541 		     0);
542 
543   effect_line->grid = (GtkGrid *) gtk_grid_new();
544   gtk_box_pack_start((GtkBox *) effect_line,
545 		     (GtkWidget *) effect_line->grid,
546 		     FALSE, FALSE,
547 		     0);
548 
549   effect_line->plugin = NULL;
550 
551   effect_line->queued_drawing = NULL;
552 }
553 
554 void
ags_effect_line_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)555 ags_effect_line_set_property(GObject *gobject,
556 			     guint prop_id,
557 			     const GValue *value,
558 			     GParamSpec *param_spec)
559 {
560   AgsEffectLine *effect_line;
561 
562   effect_line = AGS_EFFECT_LINE(gobject);
563 
564   switch(prop_id){
565   case PROP_SAMPLERATE:
566     {
567       guint samplerate, old_samplerate;
568 
569       samplerate = g_value_get_uint(value);
570       old_samplerate = effect_line->samplerate;
571 
572       if(samplerate == old_samplerate){
573 	return;
574       }
575 
576       effect_line->samplerate = samplerate;
577 
578       ags_effect_line_samplerate_changed(effect_line,
579 					 samplerate, old_samplerate);
580     }
581     break;
582   case PROP_BUFFER_SIZE:
583     {
584       guint buffer_size, old_buffer_size;
585 
586       buffer_size = g_value_get_uint(value);
587       old_buffer_size = effect_line->buffer_size;
588 
589       if(buffer_size == old_buffer_size){
590 	return;
591       }
592 
593       effect_line->buffer_size = buffer_size;
594 
595       ags_effect_line_buffer_size_changed(effect_line,
596 					  buffer_size, old_buffer_size);
597     }
598     break;
599   case PROP_FORMAT:
600     {
601       guint format, old_format;
602 
603       format = g_value_get_uint(value);
604       old_format = effect_line->format;
605 
606       if(format == old_format){
607 	return;
608       }
609 
610       effect_line->format = format;
611 
612       ags_effect_line_format_changed(effect_line,
613 				     format, old_format);
614     }
615     break;
616   case PROP_CHANNEL:
617     {
618       AgsChannel *channel;
619 
620       channel = (AgsChannel *) g_value_get_object(value);
621 
622       ags_effect_line_set_channel(effect_line, channel);
623     }
624     break;
625   default:
626     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
627     break;
628   }
629 }
630 
631 void
ags_effect_line_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)632 ags_effect_line_get_property(GObject *gobject,
633 			     guint prop_id,
634 			     GValue *value,
635 			     GParamSpec *param_spec)
636 {
637   AgsEffectLine *effect_line;
638 
639   effect_line = AGS_EFFECT_LINE(gobject);
640 
641   switch(prop_id){
642   case PROP_SAMPLERATE:
643     {
644       g_value_set_uint(value,
645 		       effect_line->samplerate);
646     }
647     break;
648   case PROP_BUFFER_SIZE:
649     {
650       g_value_set_uint(value,
651 		       effect_line->buffer_size);
652     }
653     break;
654   case PROP_FORMAT:
655     {
656       g_value_set_uint(value,
657 		       effect_line->format);
658     }
659     break;
660   case PROP_CHANNEL:
661     {
662       g_value_set_object(value,
663 			 effect_line->channel);
664     }
665     break;
666   default:
667     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
668     break;
669   }
670 }
671 
672 void
ags_effect_line_dispose(GObject * gobject)673 ags_effect_line_dispose(GObject *gobject)
674 {
675   AgsEffectLine *effect_line;
676 
677   effect_line = AGS_EFFECT_LINE(gobject);
678 
679   if(effect_line->channel != NULL){
680     g_object_unref(effect_line->channel);
681 
682     effect_line->channel = NULL;
683   }
684 
685   /* call parent */
686   G_OBJECT_CLASS(ags_effect_line_parent_class)->dispose(gobject);
687 }
688 
689 void
ags_effect_line_finalize(GObject * gobject)690 ags_effect_line_finalize(GObject *gobject)
691 {
692   AgsEffectLine *effect_line;
693 
694   AgsApplicationContext *application_context;
695 
696   GList *list;
697 
698   effect_line = AGS_EFFECT_LINE(gobject);
699 
700   application_context = ags_application_context_get_instance();
701 
702   g_object_disconnect(application_context,
703 		      "any_signal::check-message",
704 		      G_CALLBACK(ags_effect_line_check_message_callback),
705 		      effect_line,
706 		      NULL);
707 
708   /* remove of the queued drawing hash */
709   list = effect_line->queued_drawing;
710 
711   while(list != NULL){
712     g_hash_table_remove(ags_effect_line_indicator_queue_draw,
713 			list->data);
714 
715     list = list->next;
716   }
717 
718   /* channel */
719   if(effect_line->channel != NULL){
720     g_object_unref(effect_line->channel);
721   }
722 
723   /* call parent */
724   G_OBJECT_CLASS(ags_effect_line_parent_class)->finalize(gobject);
725 }
726 
727 void
ags_effect_line_connect(AgsConnectable * connectable)728 ags_effect_line_connect(AgsConnectable *connectable)
729 {
730   AgsEffectLine *effect_line;
731 
732   GList *list, *start_list;
733 
734   effect_line = AGS_EFFECT_LINE(connectable);
735 
736   if((AGS_EFFECT_LINE_CONNECTED & (effect_line->flags)) == 0){
737     return;
738   }
739 
740   effect_line->flags &= (~AGS_EFFECT_LINE_CONNECTED);
741 
742   if((AGS_EFFECT_LINE_PREMAPPED_RECALL & (effect_line->flags)) == 0){
743     if((AGS_EFFECT_LINE_MAPPED_RECALL & (effect_line->flags)) == 0){
744       ags_effect_line_map_recall(effect_line,
745 				 0);
746     }
747   }else{
748     ags_effect_line_find_port(effect_line);
749   }
750 
751   /* connect line members */
752   list =
753     start_list = gtk_container_get_children(GTK_CONTAINER(effect_line->grid));
754 
755   while(list != NULL){
756     if(AGS_IS_CONNECTABLE(list->data)){
757       ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
758     }
759 
760     list = list->next;
761   }
762 
763   g_list_free(start_list);
764 }
765 
766 void
ags_effect_line_disconnect(AgsConnectable * connectable)767 ags_effect_line_disconnect(AgsConnectable *connectable)
768 {
769   AgsEffectLine *effect_line;
770 
771   GList *start_list, *list;
772 
773   effect_line = AGS_EFFECT_LINE(connectable);
774 
775   if((AGS_EFFECT_LINE_CONNECTED & (effect_line->flags)) == 0){
776     return;
777   }
778 
779   /* unset connected flag */
780   effect_line->flags &= (~AGS_EFFECT_LINE_CONNECTED);
781 
782   /* disconnect line members */
783   list =
784     start_list = gtk_container_get_children(GTK_CONTAINER(effect_line->grid));
785 
786   while(list != NULL){
787     if(AGS_IS_CONNECTABLE(list->data)){
788       ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
789     }
790 
791     list = list->next;
792   }
793 
794   g_list_free(start_list);
795 }
796 
797 /**
798  * ags_effect_line_plugin_alloc:
799  * @play_container: the #AgsRecallContainer
800  * @recall_container: the #AgsRecallContainer
801  * @plugin_name: the plugin name
802  * @filename: the filename as string
803  * @effect: the effect as string
804  *
805  * Allocate #AgsEffectLinePlugin-struct.
806  *
807  * Returns: the newly allocated #AgsEffectLinePlugin-struct
808  *
809  * Since: 3.3.0
810  */
811 AgsEffectLinePlugin*
ags_effect_line_plugin_alloc(AgsRecallContainer * play_container,AgsRecallContainer * recall_container,gchar * plugin_name,gchar * filename,gchar * effect)812 ags_effect_line_plugin_alloc(AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
813 			     gchar *plugin_name,
814 			     gchar *filename,
815 			     gchar *effect)
816 {
817   AgsEffectLinePlugin *effect_line_plugin;
818 
819   effect_line_plugin = (AgsEffectLinePlugin *) g_malloc(sizeof(AgsEffectLinePlugin));
820 
821   if(play_container != NULL){
822     g_object_ref(play_container);
823   }
824 
825   effect_line_plugin->play_container = play_container;
826 
827   if(recall_container != NULL){
828     g_object_ref(recall_container);
829   }
830 
831   effect_line_plugin->recall_container = recall_container;
832 
833   effect_line_plugin->plugin_name = g_strdup(plugin_name);
834 
835   effect_line_plugin->filename = g_strdup(filename);
836   effect_line_plugin->effect = g_strdup(effect);
837 
838   effect_line_plugin->control_type_name = NULL;
839 
840   effect_line_plugin->control_count = 0;
841 
842   return(effect_line_plugin);
843 }
844 
845 /**
846  * ags_effect_line_plugin_free:
847  * @effect_line_plugin: the #AgsEffectLinePlugin-struct
848  *
849  * Free @effect_line_plugin.
850  *
851  * Since: 3.3.0
852  */
853 void
ags_effect_line_plugin_free(AgsEffectLinePlugin * effect_line_plugin)854 ags_effect_line_plugin_free(AgsEffectLinePlugin *effect_line_plugin)
855 {
856   if(effect_line_plugin == NULL){
857     return;
858   }
859 
860   if(effect_line_plugin->play_container != NULL){
861     g_object_unref(effect_line_plugin->play_container);
862   }
863 
864   if(effect_line_plugin->recall_container != NULL){
865     g_object_unref(effect_line_plugin->recall_container);
866   }
867 
868   if(effect_line_plugin->filename != NULL){
869     g_free(effect_line_plugin->filename);
870   }
871 
872   if(effect_line_plugin->effect != NULL){
873     g_free(effect_line_plugin->effect);
874   }
875 
876   if(effect_line_plugin->control_type_name != NULL){
877     g_list_free(effect_line_plugin->control_type_name);
878   }
879 
880   g_free(effect_line_plugin);
881 }
882 
883 /**
884  * ags_effect_line_samplerate_changed:
885  * @effect_line: the #AgsEffectLine
886  * @samplerate: the samplerate
887  * @old_samplerate: the old samplerate
888  *
889  * Notify about samplerate changed.
890  *
891  * Since: 3.0.0
892  */
893 void
ags_effect_line_samplerate_changed(AgsEffectLine * effect_line,guint samplerate,guint old_samplerate)894 ags_effect_line_samplerate_changed(AgsEffectLine *effect_line,
895 				   guint samplerate, guint old_samplerate)
896 {
897   g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
898 
899   g_object_ref((GObject *) effect_line);
900   g_signal_emit(G_OBJECT(effect_line),
901 		effect_line_signals[SAMPLERATE_CHANGED], 0,
902 		samplerate,
903 		old_samplerate);
904   g_object_unref((GObject *) effect_line);
905 }
906 
907 /**
908  * ags_effect_line_buffer_size_changed:
909  * @effect_line: the #AgsEffectLine
910  * @buffer_size: the buffer_size
911  * @old_buffer_size: the old buffer_size
912  *
913  * Notify about buffer_size changed.
914  *
915  * Since: 3.0.0
916  */
917 void
ags_effect_line_buffer_size_changed(AgsEffectLine * effect_line,guint buffer_size,guint old_buffer_size)918 ags_effect_line_buffer_size_changed(AgsEffectLine *effect_line,
919 				    guint buffer_size, guint old_buffer_size)
920 {
921   g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
922 
923   g_object_ref((GObject *) effect_line);
924   g_signal_emit(G_OBJECT(effect_line),
925 		effect_line_signals[BUFFER_SIZE_CHANGED], 0,
926 		buffer_size,
927 		old_buffer_size);
928   g_object_unref((GObject *) effect_line);
929 }
930 
931 /**
932  * ags_effect_line_format_changed:
933  * @effect_line: the #AgsEffectLine
934  * @format: the format
935  * @old_format: the old format
936  *
937  * Notify about format changed.
938  *
939  * Since: 3.0.0
940  */
941 void
ags_effect_line_format_changed(AgsEffectLine * effect_line,guint format,guint old_format)942 ags_effect_line_format_changed(AgsEffectLine *effect_line,
943 			       guint format, guint old_format)
944 {
945   g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
946 
947   g_object_ref((GObject *) effect_line);
948   g_signal_emit(G_OBJECT(effect_line),
949 		effect_line_signals[FORMAT_CHANGED], 0,
950 		format,
951 		old_format);
952   g_object_unref((GObject *) effect_line);
953 }
954 
955 void
ags_effect_line_real_set_channel(AgsEffectLine * effect_line,AgsChannel * channel)956 ags_effect_line_real_set_channel(AgsEffectLine *effect_line, AgsChannel *channel)
957 {
958   gchar *str;
959 
960   if(effect_line->channel == channel){
961     return;
962   }
963 
964   if(effect_line->channel != NULL){
965     g_object_unref(G_OBJECT(effect_line->channel));
966   }
967 
968   if(channel != NULL){
969     g_object_ref(G_OBJECT(channel));
970   }
971 
972   if(effect_line->channel != NULL){
973     effect_line->flags &= (~AGS_EFFECT_LINE_PREMAPPED_RECALL);
974   }
975 
976   if(channel != NULL){
977     effect_line->samplerate = channel->samplerate;
978     effect_line->buffer_size = channel->buffer_size;
979     effect_line->format = channel->format;
980   }
981 
982   effect_line->channel = channel;
983 
984   if(channel != NULL){
985     guint audio_channel;
986 
987     /* get audio channel */
988     g_object_get(channel,
989 		 "audio-channel", &audio_channel,
990 		 NULL);
991 
992     /* set label */
993     str = g_strdup_printf("%s %d", i18n("channel"), audio_channel + 1);
994     gtk_label_set_label(effect_line->label,
995 			str);
996 
997     g_free(str);
998   }else{
999     str = g_strdup_printf("%s (null)", i18n("channel"));
1000     gtk_label_set_label(effect_line->label,
1001 			str);
1002 
1003     g_free(str);
1004   }
1005 }
1006 
1007 /**
1008  * ags_effect_line_set_channel:
1009  * @effect_line: the #AgsEffectLine
1010  * @channel: the #AgsChannel to set
1011  *
1012  * Is emitted as channel gets modified.
1013  *
1014  * Since: 3.0.0
1015  */
1016 void
ags_effect_line_set_channel(AgsEffectLine * effect_line,AgsChannel * channel)1017 ags_effect_line_set_channel(AgsEffectLine *effect_line, AgsChannel *channel)
1018 {
1019   g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
1020 
1021   g_object_ref((GObject *) effect_line);
1022   g_signal_emit(G_OBJECT(effect_line),
1023 		effect_line_signals[SET_CHANNEL], 0,
1024 		channel);
1025   g_object_unref((GObject *) effect_line);
1026 }
1027 
1028 void
ags_effect_line_add_ladspa_plugin(AgsEffectLine * effect_line,GList * control_type_name,AgsRecallContainer * play_container,AgsRecallContainer * recall_container,gchar * plugin_name,gchar * filename,gchar * effect,guint start_audio_channel,guint stop_audio_channel,guint start_pad,guint stop_pad,gint position,guint create_flags,guint recall_flags)1029 ags_effect_line_add_ladspa_plugin(AgsEffectLine *effect_line,
1030 				  GList *control_type_name,
1031 				  AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
1032 				  gchar *plugin_name,
1033 				  gchar *filename,
1034 				  gchar *effect,
1035 				  guint start_audio_channel, guint stop_audio_channel,
1036 				  guint start_pad, guint stop_pad,
1037 				  gint position,
1038 				  guint create_flags, guint recall_flags)
1039 {
1040   AgsLineMember *line_member;
1041   AgsEffectSeparator *separator;
1042 
1043   AgsEffectLinePlugin *effect_line_plugin;
1044 
1045   AgsAudio *audio;
1046   AgsChannel *channel;
1047 
1048   AgsLadspaPlugin *ladspa_plugin;
1049 
1050   GList *start_recall;
1051   GList *start_list, *list;
1052   GList *start_plugin_port, *plugin_port;
1053 
1054   guint audio_channel;
1055   guint pad;
1056   gdouble page, step;
1057   guint port_count;
1058   guint control_count;
1059 
1060   guint x, y;
1061   guint k;
1062 
1063   audio = NULL;
1064   channel = NULL;
1065 
1066   audio_channel = 0;
1067 
1068   pad = 0;
1069 
1070   g_object_get(effect_line,
1071 	       "channel", &channel,
1072 	       NULL);
1073 
1074   /* alloc effect_line plugin */
1075   effect_line_plugin = ags_effect_line_plugin_alloc(play_container, recall_container,
1076 						    plugin_name,
1077 						    filename,
1078 						    effect);
1079   effect_line_plugin->control_type_name = control_type_name;
1080 
1081   effect_line->plugin = g_list_append(effect_line->plugin,
1082 				      effect_line_plugin);
1083 
1084   g_object_get(channel,
1085 	       "audio", &audio,
1086 	       "audio-channel", &audio_channel,
1087 	       "pad", &pad,
1088 	       NULL);
1089 
1090   /* load plugin */
1091   ladspa_plugin = ags_ladspa_manager_find_ladspa_plugin(ags_ladspa_manager_get_instance(),
1092 							filename, effect);
1093 
1094   /* ags-fx-ladspa */
1095   start_recall = ags_fx_factory_create(audio,
1096 				       effect_line_plugin->play_container, effect_line_plugin->recall_container,
1097 				       plugin_name,
1098 				       filename,
1099 				       effect,
1100 				       audio_channel, audio_channel + 1,
1101 				       pad, pad + 1,
1102 				       position,
1103 				       create_flags | (AGS_IS_OUTPUT(channel) ? AGS_FX_FACTORY_OUTPUT: AGS_FX_FACTORY_INPUT), recall_flags);
1104 
1105   g_list_free_full(start_recall,
1106 		   (GDestroyNotify) g_object_unref);
1107 
1108   /* retrieve position within table  */
1109   x = 0;
1110   y = 0;
1111 
1112   list =
1113     start_list = gtk_container_get_children(effect_line->grid);
1114 
1115   while(list != NULL){
1116     guint top_attach;
1117 
1118     gtk_container_child_get(GTK_CONTAINER(effect_line->grid),
1119 			    list->data,
1120 			    "top-attach", &top_attach,
1121 			    NULL);
1122 
1123     if(y <= top_attach){
1124       y = top_attach + 1;
1125     }
1126 
1127     list = list->next;
1128   }
1129 
1130   g_list_free(start_list);
1131 
1132   /* add separator */
1133   separator = ags_effect_separator_new();
1134 
1135   separator->play_container = play_container;
1136   separator->recall_container = recall_container;
1137 
1138   g_object_set(separator,
1139 	       "text", effect,
1140 	       "filename", filename,
1141 	       "effect", effect,
1142 	       NULL);
1143 
1144   gtk_widget_set_valign(separator,
1145 			GTK_ALIGN_FILL);
1146   gtk_widget_set_halign(separator,
1147 			GTK_ALIGN_FILL);
1148 
1149   gtk_grid_attach(effect_line->grid,
1150 		  (GtkWidget *) separator,
1151 		  0, y,
1152 		  AGS_EFFECT_LINE_COLUMNS_COUNT, 1);
1153   gtk_widget_show_all(GTK_WIDGET(separator));
1154 
1155   y++;
1156 
1157   /* load ports */
1158   g_object_get(ladspa_plugin,
1159 	       "plugin-port", &start_plugin_port,
1160 	       NULL);
1161 
1162   plugin_port = start_plugin_port;
1163 
1164   port_count = g_list_length(start_plugin_port);
1165 
1166   control_count = 0;
1167 
1168   k = 0;
1169 
1170   while(plugin_port != NULL){
1171     if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_CONTROL)){
1172       GtkWidget *child_widget;
1173 
1174       AgsLadspaConversion *ladspa_conversion;
1175 
1176       GType widget_type;
1177 
1178       gchar *plugin_name;
1179       gchar *control_port;
1180       gchar *port_name;
1181 
1182       guint unique_id;
1183       guint scale_precision;
1184       gdouble step_count;
1185       gboolean disable_seemless;
1186       gboolean do_step_conversion;
1187 
1188       GRecMutex *plugin_port_mutex;
1189 
1190       control_count++;
1191 
1192       disable_seemless = FALSE;
1193       do_step_conversion = FALSE;
1194 
1195       if(x == AGS_EFFECT_LINE_COLUMNS_COUNT){
1196 	x = 0;
1197 	y++;
1198       }
1199 
1200       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_TOGGLED)){
1201 	disable_seemless = TRUE;
1202 
1203 	if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_OUTPUT)){
1204 	  widget_type = AGS_TYPE_LED;
1205 	}else{
1206 	  widget_type = GTK_TYPE_TOGGLE_BUTTON;
1207 	}
1208       }else{
1209 	if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_OUTPUT)){
1210 	  widget_type = AGS_TYPE_HINDICATOR;
1211 	}else{
1212 	  widget_type = AGS_TYPE_DIAL;
1213 	}
1214       }
1215 
1216       if(control_type_name != NULL){
1217 	widget_type = g_type_from_name(control_type_name->data);
1218 
1219 	control_type_name = control_type_name->next;
1220       }
1221 
1222       scale_precision = AGS_DIAL_DEFAULT_PRECISION;
1223       step_count = AGS_LADSPA_CONVERSION_DEFAULT_STEP_COUNT;
1224 
1225       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_INTEGER)){
1226 	guint scale_steps;
1227 
1228 	g_object_get(plugin_port->data,
1229 		     "scale-steps", &scale_steps,
1230 		     NULL);
1231 
1232 	step_count =
1233 	  scale_precision = (gdouble) scale_steps;
1234 
1235 	disable_seemless = TRUE;
1236       }
1237 
1238       /* get plugin port mutex */
1239       plugin_port_mutex = AGS_PLUGIN_PORT_GET_OBJ_MUTEX(plugin_port->data);
1240 
1241       /* get port name */
1242       g_rec_mutex_lock(plugin_port_mutex);
1243 
1244       port_name = g_strdup(AGS_PLUGIN_PORT(plugin_port->data)->port_name);
1245 
1246       g_rec_mutex_unlock(plugin_port_mutex);
1247 
1248       /* add line member */
1249       g_object_get(ladspa_plugin,
1250 		   "unique-id", &unique_id,
1251 		   NULL);
1252 
1253       plugin_name = g_strdup_printf("ladspa-%u",
1254 				    unique_id);
1255 
1256       control_port = g_strdup_printf("%u/%u",
1257 				     k + 1,
1258 				     port_count);
1259 
1260       line_member = (AgsLineMember *) g_object_new(AGS_TYPE_LINE_MEMBER,
1261 						   "widget-type", widget_type,
1262 						   "widget-label", AGS_PLUGIN_PORT(plugin_port->data)->port_name,
1263 						   "play-container", play_container,
1264 						   "recall-container", recall_container,
1265 						   "plugin-name", plugin_name,
1266 						   "filename", filename,
1267 						   "effect", effect,
1268 						   "specifier", AGS_PLUGIN_PORT(plugin_port->data)->port_name,
1269 						   "control-port", control_port,
1270 						   "scale-precision", scale_precision,
1271 						   "step-count", step_count,
1272 						   NULL);
1273       child_widget = ags_line_member_get_widget(line_member);
1274 
1275       g_free(plugin_name);
1276       g_free(control_port);
1277       g_free(port_name);
1278 
1279       /* ladspa conversion */
1280       ladspa_conversion = NULL;
1281 
1282       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_BOUNDED_BELOW)){
1283 	if(ladspa_conversion == NULL ||
1284 	   !AGS_IS_LADSPA_CONVERSION(ladspa_conversion)){
1285 	  ladspa_conversion = ags_ladspa_conversion_new();
1286 	}
1287 
1288 	ladspa_conversion->flags |= AGS_LADSPA_CONVERSION_BOUNDED_BELOW;
1289       }
1290 
1291       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_BOUNDED_ABOVE)){
1292 	if(ladspa_conversion == NULL ||
1293 	   !AGS_IS_LADSPA_CONVERSION(ladspa_conversion)){
1294 	  ladspa_conversion = ags_ladspa_conversion_new();
1295 	}
1296 
1297 	ladspa_conversion->flags |= AGS_LADSPA_CONVERSION_BOUNDED_ABOVE;
1298       }
1299       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_SAMPLERATE)){
1300 	if(ladspa_conversion == NULL ||
1301 	   !AGS_IS_LADSPA_CONVERSION(ladspa_conversion)){
1302 	  ladspa_conversion = ags_ladspa_conversion_new();
1303 	}
1304 
1305 	ladspa_conversion->flags |= AGS_LADSPA_CONVERSION_SAMPLERATE;
1306       }
1307 
1308       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_LOGARITHMIC)){
1309 	if(ladspa_conversion == NULL ||
1310 	   !AGS_IS_LADSPA_CONVERSION(ladspa_conversion)){
1311 	  ladspa_conversion = ags_ladspa_conversion_new();
1312 	}
1313 
1314 	ladspa_conversion->flags |= AGS_LADSPA_CONVERSION_LOGARITHMIC;
1315 
1316 	do_step_conversion = TRUE;
1317       }
1318 
1319       g_object_set(line_member,
1320 		   "conversion", ladspa_conversion,
1321 		   NULL);
1322 
1323       /* child widget */
1324       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_TOGGLED)){
1325 	line_member->port_flags = AGS_LINE_MEMBER_PORT_BOOLEAN;
1326       }
1327 
1328       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_INTEGER)){
1329 	line_member->port_flags = AGS_LINE_MEMBER_PORT_INTEGER;
1330       }
1331 
1332       if(AGS_IS_DIAL(child_widget)){
1333 	AgsDial *dial;
1334 	GtkAdjustment *adjustment;
1335 
1336 	float lower_bound, upper_bound;
1337 	float default_value;
1338 	gdouble lower, upper;
1339 	gdouble control_value;
1340 
1341 	dial = (AgsDial *) child_widget;
1342 
1343 	if(disable_seemless){
1344 	  dial->flags &= (~AGS_DIAL_SEEMLESS_MODE);
1345 	}
1346 
1347 	/* add controls of ports and apply range  */
1348 	g_rec_mutex_lock(plugin_port_mutex);
1349 
1350 	lower_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->lower_value);
1351 	upper_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->upper_value);
1352 
1353 	g_rec_mutex_unlock(plugin_port_mutex);
1354 
1355 	if(do_step_conversion){
1356 	  g_object_set(ladspa_conversion,
1357 		       "lower", lower_bound,
1358 		       "upper", upper_bound,
1359 		       NULL);
1360 
1361 	  lower = 0.0;
1362 	  upper = AGS_LADSPA_CONVERSION_DEFAULT_STEP_COUNT - 1.0;
1363 
1364 #if 0
1365 	  if(!disable_seemless){
1366 	    g_object_get(ladspa_conversion,
1367 			 "step-count", &step_count,
1368 			 NULL);
1369 	  }
1370 #endif
1371 	}else{
1372 	  lower = lower_bound;
1373 	  upper = upper_bound;
1374 	}
1375 
1376 	adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.1, 0.1, 0.0);
1377 	g_object_set(dial,
1378 		     "adjustment", adjustment,
1379 		     NULL);
1380 
1381 	if(upper >= 0.0 && lower >= 0.0){
1382 	  step = (upper - lower) / step_count;
1383 	}else if(upper < 0.0 && lower < 0.0){
1384 	  step = -1.0 * (lower - upper) / step_count;
1385 	}else{
1386 	  step = (upper - lower) / step_count;
1387 	}
1388 
1389 	if(step_count > 8){
1390 	  if(upper >= 0.0 && lower >= 0.0){
1391 	    page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
1392 	  }else if(upper < 0.0 && lower < 0.0){
1393 	    page = -1.0 * (lower - upper) / AGS_DIAL_DEFAULT_PRECISION;
1394 	  }else{
1395 	    page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
1396 	  }
1397 	}else{
1398 	  page = step;
1399 	}
1400 
1401 	gtk_adjustment_set_step_increment(adjustment,
1402 					  step);
1403 	gtk_adjustment_set_page_increment(adjustment,
1404 					  page);
1405 	gtk_adjustment_set_lower(adjustment,
1406 				 lower);
1407 	gtk_adjustment_set_upper(adjustment,
1408 				 upper);
1409 
1410 	/* get/set default value */
1411 	g_rec_mutex_lock(plugin_port_mutex);
1412 
1413 	default_value = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->default_value);
1414 
1415 	g_rec_mutex_unlock(plugin_port_mutex);
1416 
1417 	control_value = default_value;
1418 
1419 	if(ladspa_conversion != NULL){
1420 	  control_value = ags_conversion_convert((AgsConversion *) ladspa_conversion,
1421 						 default_value,
1422 						 TRUE);
1423 	}
1424 
1425 	gtk_adjustment_set_value(adjustment,
1426 				 control_value);
1427       }else if(GTK_IS_RANGE(child_widget)){
1428 	GtkRange *range;
1429 	GtkAdjustment *adjustment;
1430 
1431 	float lower_bound, upper_bound;
1432 	gdouble lower, upper;
1433 	float default_value;
1434 	gdouble control_value;
1435 
1436 	range = (GtkRange *) child_widget;
1437 
1438 	/* add controls of ports and apply range  */
1439 	g_rec_mutex_lock(plugin_port_mutex);
1440 
1441 	lower_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->lower_value);
1442 	upper_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->upper_value);
1443 
1444 	g_rec_mutex_unlock(plugin_port_mutex);
1445 
1446 	if(do_step_conversion){
1447 	  g_object_set(ladspa_conversion,
1448 		       "lower", lower_bound,
1449 		       "upper", upper_bound,
1450 		       NULL);
1451 
1452 	  lower = 0.0;
1453 	  upper = AGS_LADSPA_CONVERSION_DEFAULT_STEP_COUNT - 1.0;
1454 
1455 #if 0
1456 	  if(!disable_seemless){
1457 	    g_object_get(ladspa_conversion,
1458 			 "step-count", &step_count,
1459 			 NULL);
1460 	  }
1461 #endif
1462 	}else{
1463 	  lower = lower_bound;
1464 	  upper = upper_bound;
1465 	}
1466 
1467 	g_object_get(range,
1468 		     "adjustment", &adjustment,
1469 		     NULL);
1470 
1471 	if(upper >= 0.0 && lower >= 0.0){
1472 	  step = (upper - lower) / step_count;
1473 	}else if(upper < 0.0 && lower < 0.0){
1474 	  step = -1.0 * (lower - upper) / step_count;
1475 	}else{
1476 	  step = (upper - lower) / step_count;
1477 	}
1478 
1479 	if(step_count > 8){
1480 	  if(upper >= 0.0 && lower >= 0.0){
1481 	    page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
1482 	  }else if(upper < 0.0 && lower < 0.0){
1483 	    page = -1.0 * (lower - upper) / AGS_DIAL_DEFAULT_PRECISION;
1484 	  }else{
1485 	    page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
1486 	  }
1487 	}else{
1488 	  page = step;
1489 	}
1490 
1491 	gtk_adjustment_set_step_increment(adjustment,
1492 					  step);
1493 	gtk_adjustment_set_page_increment(adjustment,
1494 					  page);
1495 	gtk_adjustment_set_lower(adjustment,
1496 				 lower);
1497 	gtk_adjustment_set_upper(adjustment,
1498 				 upper);
1499 
1500 	/* get/set default value */
1501 	g_rec_mutex_lock(plugin_port_mutex);
1502 
1503 	default_value = (float) g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->default_value);
1504 
1505 	g_rec_mutex_unlock(plugin_port_mutex);
1506 
1507 	control_value = default_value;
1508 
1509 	if(ladspa_conversion != NULL){
1510 	  control_value = ags_conversion_convert((AgsConversion *) ladspa_conversion,
1511 						 default_value,
1512 						 TRUE);
1513 	}
1514 
1515 	gtk_adjustment_set_value(adjustment,
1516 				 control_value);
1517       }else if(GTK_IS_SPIN_BUTTON(child_widget)){
1518 	GtkSpinButton *spin_button;
1519 	GtkAdjustment *adjustment;
1520 
1521 	float lower_bound, upper_bound;
1522 	gdouble lower, upper;
1523 	float default_value;
1524 	gdouble control_value;
1525 
1526 	spin_button = (GtkSpinButton *) child_widget;
1527 
1528 	/* add controls of ports and apply range  */
1529 	g_rec_mutex_lock(plugin_port_mutex);
1530 
1531 	lower_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->lower_value);
1532 	upper_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->upper_value);
1533 
1534 	g_rec_mutex_unlock(plugin_port_mutex);
1535 
1536 	if(do_step_conversion){
1537 	  g_object_set(ladspa_conversion,
1538 		       "lower", lower_bound,
1539 		       "upper", upper_bound,
1540 		       NULL);
1541 
1542 	  lower = 0.0;
1543 	  upper = AGS_LADSPA_CONVERSION_DEFAULT_STEP_COUNT - 1.0;
1544 
1545 #if 0
1546 	  if(!disable_seemless){
1547 	    g_object_get(ladspa_conversion,
1548 			 "step-count", &step_count,
1549 			 NULL);
1550 	  }
1551 #endif
1552 	}else{
1553 	  lower = lower_bound;
1554 	  upper = upper_bound;
1555 	}
1556 
1557 	g_object_get(spin_button,
1558 		     "adjustment", &adjustment,
1559 		     NULL);
1560 
1561 	if(upper >= 0.0 && lower >= 0.0){
1562 	  step = (upper - lower) / step_count;
1563 	}else if(upper < 0.0 && lower < 0.0){
1564 	  step = -1.0 * (lower - upper) / step_count;
1565 	}else{
1566 	  step = (upper - lower) / step_count;
1567 	}
1568 
1569 	if(step_count > 8){
1570 	  if(upper >= 0.0 && lower >= 0.0){
1571 	    page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
1572 	  }else if(upper < 0.0 && lower < 0.0){
1573 	    page = -1.0 * (lower - upper) / AGS_DIAL_DEFAULT_PRECISION;
1574 	  }else{
1575 	    page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
1576 	  }
1577 	}else{
1578 	  page = step;
1579 	}
1580 
1581 	gtk_adjustment_set_step_increment(adjustment,
1582 					  step);
1583 	gtk_adjustment_set_page_increment(adjustment,
1584 					  page);
1585 	gtk_adjustment_set_lower(adjustment,
1586 				 lower);
1587 	gtk_adjustment_set_upper(adjustment,
1588 				 upper);
1589 
1590 	/* get/set default value */
1591 	g_rec_mutex_lock(plugin_port_mutex);
1592 
1593 	default_value = (float) g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->default_value);
1594 
1595 	g_rec_mutex_unlock(plugin_port_mutex);
1596 
1597 	control_value = default_value;
1598 
1599 	if(ladspa_conversion != NULL){
1600 	  control_value = ags_conversion_convert((AgsConversion *) ladspa_conversion,
1601 						 default_value,
1602 						 TRUE);
1603 	}
1604 
1605 	gtk_adjustment_set_value(adjustment,
1606 				 control_value);
1607       }else if(AGS_IS_INDICATOR(child_widget) ||
1608 	       AGS_IS_LED(child_widget)){
1609 	g_hash_table_insert(ags_effect_line_indicator_queue_draw,
1610 			    child_widget, ags_effect_line_indicator_queue_draw_timeout);
1611 
1612 	effect_line->queued_drawing = g_list_prepend(effect_line->queued_drawing,
1613 						     child_widget);
1614 
1615 	g_timeout_add(AGS_UI_PROVIDER_DEFAULT_TIMEOUT * 1000.0,
1616 		      (GSourceFunc) ags_effect_line_indicator_queue_draw_timeout,
1617 		      (gpointer) child_widget);
1618       }
1619 
1620 #ifdef AGS_DEBUG
1621       g_message("ladspa bounds: %f %f", lower, upper);
1622 #endif
1623 
1624       gtk_widget_set_valign(line_member,
1625 			    GTK_ALIGN_FILL);
1626       gtk_widget_set_halign(line_member,
1627 			    GTK_ALIGN_FILL);
1628 
1629       gtk_grid_attach(effect_line->grid,
1630 		      (GtkWidget *) line_member,
1631 		      (x % AGS_EFFECT_LINE_COLUMNS_COUNT), y,
1632 		      1, 1);
1633 
1634       ags_connectable_connect(AGS_CONNECTABLE(line_member));
1635       gtk_widget_show_all((GtkWidget *) line_member);
1636 
1637       /* iterate */
1638       x++;
1639 
1640       if(x % AGS_EFFECT_LINE_COLUMNS_COUNT == 0){
1641 	y++;
1642       }
1643     }
1644 
1645     /* iterate */
1646     plugin_port = plugin_port->next;
1647     k++;
1648   }
1649 
1650   effect_line_plugin->control_count = control_count;
1651 
1652   if(audio != NULL){
1653     g_object_unref(audio);
1654   }
1655 
1656   if(channel != NULL){
1657     g_object_unref(channel);
1658   }
1659 
1660   g_list_free_full(start_plugin_port,
1661 		   g_object_unref);
1662 }
1663 
1664 void
ags_effect_line_add_lv2_plugin(AgsEffectLine * effect_line,GList * control_type_name,AgsRecallContainer * play_container,AgsRecallContainer * recall_container,gchar * plugin_name,gchar * filename,gchar * effect,guint start_audio_channel,guint stop_audio_channel,guint start_pad,guint stop_pad,gint position,guint create_flags,guint recall_flags)1665 ags_effect_line_add_lv2_plugin(AgsEffectLine *effect_line,
1666 			       GList *control_type_name,
1667 			       AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
1668 			       gchar *plugin_name,
1669 			       gchar *filename,
1670 			       gchar *effect,
1671 			       guint start_audio_channel, guint stop_audio_channel,
1672 			       guint start_pad, guint stop_pad,
1673 			       gint position,
1674 			       guint create_flags, guint recall_flags)
1675 {
1676   AgsLineMember *line_member;
1677   AgsEffectSeparator *separator;
1678 
1679   AgsEffectLinePlugin *effect_line_plugin;
1680 
1681   AgsAudio *audio;
1682   AgsChannel *channel;
1683 
1684   AgsLv2Manager *lv2_manager;
1685   AgsLv2Plugin *lv2_plugin;
1686 
1687   GList *start_recall;
1688   GList *start_list, *list;
1689   GList *start_plugin_port, *plugin_port;
1690 
1691   gchar *uri;
1692 
1693   gboolean is_lv2_plugin;
1694 
1695   guint audio_channel;
1696   guint pad;
1697   gdouble page, step;
1698   guint port_count;
1699   guint control_count;
1700 
1701   guint x, y;
1702   guint k;
1703 
1704   GRecMutex *lv2_manager_mutex;
1705   GRecMutex *base_plugin_mutex;
1706 
1707   lv2_manager = ags_lv2_manager_get_instance();
1708 
1709   lv2_manager_mutex = AGS_LV2_MANAGER_GET_OBJ_MUTEX(lv2_manager);
1710 
1711   audio = NULL;
1712   channel = NULL;
1713 
1714   pad = 0;
1715   audio_channel = 0;
1716 
1717   g_object_get(effect_line,
1718 	       "channel", &channel,
1719 	       NULL);
1720 
1721   /* make sure turtle is parsed */
1722   g_rec_mutex_lock(lv2_manager_mutex);
1723 
1724   is_lv2_plugin = ((lv2_manager->quick_scan_plugin_filename != NULL &&
1725 		    g_strv_contains(lv2_manager->quick_scan_plugin_filename,
1726 				    filename)) ||
1727 		   (lv2_manager->quick_scan_instrument_filename != NULL &&
1728 		    g_strv_contains(lv2_manager->quick_scan_instrument_filename,
1729 				    filename))) ? TRUE: FALSE;
1730 
1731   g_rec_mutex_unlock(lv2_manager_mutex);
1732 
1733   if(filename != NULL &&
1734      effect != NULL &&
1735      is_lv2_plugin){
1736     AgsTurtle *manifest;
1737     AgsTurtleManager *turtle_manager;
1738 
1739     gchar *path;
1740     gchar *manifest_filename;
1741 
1742     turtle_manager = ags_turtle_manager_get_instance();
1743 
1744     path = g_path_get_dirname(filename);
1745 
1746     manifest_filename = g_strdup_printf("%s%c%s",
1747 					path,
1748 					G_DIR_SEPARATOR,
1749 					"manifest.ttl");
1750 
1751     manifest = (AgsTurtle *) ags_turtle_manager_find(turtle_manager,
1752 						     manifest_filename);
1753 
1754     if(manifest == NULL){
1755       AgsLv2TurtleParser *lv2_turtle_parser;
1756 
1757       AgsTurtle **turtle;
1758 
1759       guint n_turtle;
1760 
1761       g_message("new turtle [Manifest] - %s", manifest_filename);
1762 
1763       manifest = ags_turtle_new(manifest_filename);
1764       ags_turtle_load(manifest,
1765 		      NULL);
1766       ags_turtle_manager_add(turtle_manager,
1767 			     (GObject *) manifest);
1768 
1769       lv2_turtle_parser = ags_lv2_turtle_parser_new(manifest);
1770 
1771       n_turtle = 1;
1772       turtle = (AgsTurtle **) malloc(2 * sizeof(AgsTurtle *));
1773 
1774       turtle[0] = manifest;
1775       turtle[1] = NULL;
1776 
1777       ags_lv2_turtle_parser_parse(lv2_turtle_parser,
1778 				  turtle, n_turtle);
1779 
1780       g_object_run_dispose((GObject *) lv2_turtle_parser);
1781       g_object_unref(lv2_turtle_parser);
1782 
1783       g_object_unref(manifest);
1784 
1785       free(turtle);
1786     }
1787 
1788     g_free(manifest_filename);
1789   }
1790 
1791   /* alloc effect line plugin */
1792   effect_line_plugin = ags_effect_line_plugin_alloc(play_container, recall_container,
1793 						    plugin_name,
1794 						    filename,
1795 						    effect);
1796   effect_line_plugin->control_type_name = control_type_name;
1797 
1798   effect_line->plugin = g_list_append(effect_line->plugin,
1799 			       effect_line_plugin);
1800 
1801   g_object_get(channel,
1802 	       "audio", &audio,
1803 	       "audio-channel", &audio_channel,
1804 	       "pad", &pad,
1805 	       NULL);
1806 
1807   /* load plugin */
1808   lv2_plugin = ags_lv2_manager_find_lv2_plugin(ags_lv2_manager_get_instance(),
1809 					       filename, effect);
1810 
1811   /* get base plugin mutex */
1812   base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(lv2_plugin);
1813 
1814   /* get uri */
1815   g_rec_mutex_lock(base_plugin_mutex);
1816 
1817   uri = g_strdup(lv2_plugin->uri);
1818 
1819   g_rec_mutex_unlock(base_plugin_mutex);
1820 
1821   /* ags-fx-lv2 */
1822   start_recall = ags_fx_factory_create(audio,
1823 				       effect_line_plugin->play_container, effect_line_plugin->recall_container,
1824 				       plugin_name,
1825 				       filename,
1826 				       effect,
1827 				       audio_channel, audio_channel + 1,
1828 				       pad, pad + 1,
1829 				       position,
1830 				       create_flags | (AGS_IS_OUTPUT(channel) ? AGS_FX_FACTORY_OUTPUT: AGS_FX_FACTORY_INPUT), recall_flags);
1831 
1832   g_list_free_full(start_recall,
1833 		   (GDestroyNotify) g_object_unref);
1834 
1835   /* retrieve position within table  */
1836   x = 0;
1837   y = 0;
1838 
1839   list =
1840     start_list = gtk_container_get_children(effect_line->grid);
1841 
1842   while(list != NULL){
1843     guint top_attach;
1844 
1845     gtk_container_child_get(GTK_CONTAINER(effect_line->grid),
1846 			    list->data,
1847 			    "top-attach", &top_attach,
1848 			    NULL);
1849 
1850     if(y <= top_attach){
1851       y = top_attach + 1;
1852     }
1853 
1854     list = list->next;
1855   }
1856 
1857   g_list_free(start_list);
1858 
1859   /* add separator */
1860   separator = ags_effect_separator_new();
1861 
1862   separator->play_container = play_container;
1863   separator->recall_container = recall_container;
1864 
1865   g_object_set(separator,
1866 	       "text", effect,
1867 	       "filename", filename,
1868 	       "effect", effect,
1869 	       NULL);
1870 
1871   gtk_widget_set_valign(separator,
1872 			GTK_ALIGN_FILL);
1873   gtk_widget_set_halign(separator,
1874 			GTK_ALIGN_FILL);
1875 
1876   gtk_grid_attach(effect_line->grid,
1877 		  (GtkWidget *) separator,
1878 		  0, y,
1879 		  AGS_EFFECT_LINE_COLUMNS_COUNT, 1);
1880   gtk_widget_show_all(GTK_WIDGET(separator));
1881 
1882   y++;
1883 
1884   /* load ports */
1885   g_object_get(lv2_plugin,
1886 	       "plugin-port", &start_plugin_port,
1887 	       NULL);
1888 
1889   plugin_port = start_plugin_port;
1890 
1891   port_count = g_list_length(start_plugin_port);
1892 
1893   control_count = 0;
1894 
1895   k = 0;
1896 
1897   while(plugin_port != NULL){
1898     if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_CONTROL)){
1899       GtkWidget *child_widget;
1900 
1901       AgsLv2Conversion *lv2_conversion;
1902 
1903       GType widget_type;
1904 
1905       gchar *plugin_name;
1906       gchar *control_port;
1907       gchar *port_name;
1908 
1909       guint scale_precision;
1910       gdouble step_count;
1911       gboolean disable_seemless;
1912       gboolean do_step_conversion;
1913 
1914       GRecMutex *plugin_port_mutex;
1915 
1916       control_count++;
1917 
1918       disable_seemless = FALSE;
1919       do_step_conversion = FALSE;
1920 
1921       if(x == AGS_EFFECT_LINE_COLUMNS_COUNT){
1922 	x = 0;
1923 	y++;
1924       }
1925 
1926       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_TOGGLED)){
1927 	disable_seemless = TRUE;
1928 
1929 	if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_OUTPUT)){
1930 	  widget_type = AGS_TYPE_LED;
1931 	}else{
1932 	  widget_type = GTK_TYPE_TOGGLE_BUTTON;
1933 	}
1934       }else{
1935 	if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_OUTPUT)){
1936 	  widget_type = AGS_TYPE_HINDICATOR;
1937 	}else{
1938 	  widget_type = AGS_TYPE_DIAL;
1939 	}
1940       }
1941 
1942       if(control_type_name != NULL){
1943 	widget_type = g_type_from_name(control_type_name->data);
1944 
1945 	control_type_name = control_type_name->next;
1946       }
1947 
1948       scale_precision = AGS_DIAL_DEFAULT_PRECISION;
1949       step_count = AGS_LV2_CONVERSION_DEFAULT_STEP_COUNT;
1950 
1951       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_INTEGER)){
1952 	guint scale_steps;
1953 
1954 	g_object_get(plugin_port->data,
1955 		     "scale-steps", &scale_steps,
1956 		     NULL);
1957 
1958 	step_count =
1959 	  scale_precision = (gdouble) scale_steps;
1960 
1961 	disable_seemless = TRUE;
1962       }
1963 
1964       /* get plugin port mutex */
1965       plugin_port_mutex = AGS_PLUGIN_PORT_GET_OBJ_MUTEX(plugin_port->data);
1966 
1967       /* get port name */
1968       g_rec_mutex_lock(plugin_port_mutex);
1969 
1970       port_name = g_strdup(AGS_PLUGIN_PORT(plugin_port->data)->port_name);
1971 
1972       g_rec_mutex_unlock(plugin_port_mutex);
1973 
1974       /* add line member */
1975       plugin_name = g_strdup_printf("lv2-<%s>",
1976 				    uri);
1977 
1978       control_port = g_strdup_printf("%u/%u",
1979 				     k + 1,
1980 				     port_count);
1981 
1982       line_member = (AgsLineMember *) g_object_new(AGS_TYPE_LINE_MEMBER,
1983 						   "widget-type", widget_type,
1984 						   "widget-label", port_name,
1985 						   "plugin-name", plugin_name,
1986 						   "filename", filename,
1987 						   "effect", effect,
1988 						   "specifier", port_name,
1989 						   "control-port", control_port,
1990 						   "scale-precision", scale_precision,
1991 						   "step-count", step_count,
1992 						   NULL);
1993       child_widget = ags_line_member_get_widget(line_member);
1994 
1995       g_free(plugin_name);
1996       g_free(control_port);
1997       g_free(port_name);
1998 
1999       /* lv2 conversion */
2000       lv2_conversion = NULL;
2001 
2002       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_LOGARITHMIC)){
2003 	if(lv2_conversion == NULL ||
2004 	   !AGS_IS_LV2_CONVERSION(lv2_conversion)){
2005 	  lv2_conversion = ags_lv2_conversion_new();
2006 	}
2007 
2008 	lv2_conversion->flags |= AGS_LV2_CONVERSION_LOGARITHMIC;
2009 
2010 	do_step_conversion = TRUE;
2011       }
2012 
2013       g_object_set(line_member,
2014 		   "conversion", lv2_conversion,
2015 		   NULL);
2016 
2017       /* child widget */
2018       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_TOGGLED)){
2019 	line_member->port_flags = AGS_LINE_MEMBER_PORT_BOOLEAN;
2020       }
2021 
2022       if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_INTEGER)){
2023 	line_member->port_flags = AGS_LINE_MEMBER_PORT_INTEGER;
2024       }
2025 
2026       if(AGS_IS_DIAL(child_widget)){
2027 	AgsDial *dial;
2028 	GtkAdjustment *adjustment;
2029 
2030 	float lower_bound, upper_bound;
2031 	gdouble lower, upper;
2032 	float default_value;
2033 	gdouble control_value;
2034 
2035 	dial = (AgsDial *) child_widget;
2036 
2037 	if(disable_seemless){
2038 	  dial->flags &= (~AGS_DIAL_SEEMLESS_MODE);
2039 	}
2040 
2041 	/* add controls of ports and apply range  */
2042 	g_rec_mutex_lock(plugin_port_mutex);
2043 
2044 	lower_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->lower_value);
2045 	upper_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->upper_value);
2046 
2047 	g_rec_mutex_unlock(plugin_port_mutex);
2048 
2049 	if(do_step_conversion){
2050 	  g_object_set(lv2_conversion,
2051 		       "lower", lower_bound,
2052 		       "upper", upper_bound,
2053 		       NULL);
2054 
2055 	  lower = 0.0;
2056 	  upper = AGS_LV2_CONVERSION_DEFAULT_STEP_COUNT - 1.0;
2057 
2058 #if 0
2059 	  if(!disable_seemless){
2060 	    g_object_get(lv2_conversion,
2061 			 "step-count", &step_count,
2062 			 NULL);
2063 	  }
2064 #endif
2065 	}else{
2066 	  lower = lower_bound;
2067 	  upper = upper_bound;
2068 	}
2069 
2070 	adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.1, 0.1, 0.0);
2071 	g_object_set(dial,
2072 		     "adjustment", adjustment,
2073 		     NULL);
2074 
2075 	if(upper >= 0.0 && lower >= 0.0){
2076 	  step = (upper - lower) / step_count;
2077 	}else if(upper < 0.0 && lower < 0.0){
2078 	  step = -1.0 * (lower - upper) / step_count;
2079 	}else{
2080 	  step = (upper - lower) / step_count;
2081 	}
2082 
2083 	if(step_count > 8){
2084 	  if(upper >= 0.0 && lower >= 0.0){
2085 	    page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
2086 	  }else if(upper < 0.0 && lower < 0.0){
2087 	    page = -1.0 * (lower - upper) / AGS_DIAL_DEFAULT_PRECISION;
2088 	  }else{
2089 	    page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
2090 	  }
2091 	}else{
2092 	  page = step;
2093 	}
2094 
2095 	gtk_adjustment_set_step_increment(adjustment,
2096 					  step);
2097 	gtk_adjustment_set_page_increment(adjustment,
2098 					  page);
2099 	gtk_adjustment_set_lower(adjustment,
2100 				 lower);
2101 	gtk_adjustment_set_upper(adjustment,
2102 				 upper);
2103 
2104 	/* get/set default value */
2105 	g_rec_mutex_lock(plugin_port_mutex);
2106 
2107 	default_value = (float) g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->default_value);
2108 
2109 	g_rec_mutex_unlock(plugin_port_mutex);
2110 
2111 	control_value = default_value;
2112 
2113 	if(lv2_conversion != NULL){
2114 	  control_value = ags_conversion_convert((AgsConversion *) lv2_conversion,
2115 						 default_value,
2116 						 TRUE);
2117 	}
2118 
2119 	gtk_adjustment_set_value(adjustment,
2120 				 control_value);
2121       }else if(GTK_IS_RANGE(child_widget)){
2122 	GtkRange *range;
2123 	GtkAdjustment *adjustment;
2124 
2125 	float lower_bound, upper_bound;
2126 	gdouble lower, upper;
2127 	float default_value;
2128 	gdouble control_value;
2129 
2130 	range = (GtkRange *) child_widget;
2131 
2132 	/* add controls of ports and apply range  */
2133 	g_rec_mutex_lock(plugin_port_mutex);
2134 
2135 	lower_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->lower_value);
2136 	upper_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->upper_value);
2137 
2138 	g_rec_mutex_unlock(plugin_port_mutex);
2139 
2140 	if(do_step_conversion){
2141 	  g_object_set(lv2_conversion,
2142 		       "lower", lower_bound,
2143 		       "upper", upper_bound,
2144 		       NULL);
2145 
2146 	  lower = 0.0;
2147 	  upper = AGS_LV2_CONVERSION_DEFAULT_STEP_COUNT - 1.0;
2148 
2149 #if 0
2150 	  if(!disable_seemless){
2151 	    g_object_get(lv2_conversion,
2152 			 "step-count", &step_count,
2153 			 NULL);
2154 	  }
2155 #endif
2156 	}else{
2157 	  lower = lower_bound;
2158 	  upper = upper_bound;
2159 	}
2160 
2161 	g_object_get(range,
2162 		     "adjustment", &adjustment,
2163 		     NULL);
2164 
2165 	if(upper >= 0.0 && lower >= 0.0){
2166 	  step = (upper - lower) / step_count;
2167 	}else if(upper < 0.0 && lower < 0.0){
2168 	  step = -1.0 * (lower - upper) / step_count;
2169 	}else{
2170 	  step = (upper - lower) / step_count;
2171 	}
2172 
2173 	if(step_count > 8){
2174 	  if(upper >= 0.0 && lower >= 0.0){
2175 	    page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
2176 	  }else if(upper < 0.0 && lower < 0.0){
2177 	    page = -1.0 * (lower - upper) / AGS_DIAL_DEFAULT_PRECISION;
2178 	  }else{
2179 	    page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
2180 	  }
2181 	}else{
2182 	  page = step;
2183 	}
2184 
2185 	gtk_adjustment_set_step_increment(adjustment,
2186 					  step);
2187 	gtk_adjustment_set_page_increment(adjustment,
2188 					  page);
2189 	gtk_adjustment_set_lower(adjustment,
2190 				 lower);
2191 	gtk_adjustment_set_upper(adjustment,
2192 				 upper);
2193 
2194 	/* get/set default value */
2195 	g_rec_mutex_lock(plugin_port_mutex);
2196 
2197 	default_value = (float) g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->default_value);
2198 
2199 	g_rec_mutex_unlock(plugin_port_mutex);
2200 
2201 	control_value = default_value;
2202 
2203 	if(lv2_conversion != NULL){
2204 	  control_value = ags_conversion_convert((AgsConversion *) lv2_conversion,
2205 						 default_value,
2206 						 TRUE);
2207 	}
2208 
2209 	gtk_adjustment_set_value(adjustment,
2210 				 control_value);
2211       }else if(GTK_IS_SPIN_BUTTON(child_widget)){
2212 	GtkSpinButton *spin_button;
2213 	GtkAdjustment *adjustment;
2214 
2215 	float lower_bound, upper_bound;
2216 	gdouble lower, upper;
2217 	float default_value;
2218 	gdouble control_value;
2219 
2220 	spin_button = (GtkSpinButton *) child_widget;
2221 
2222 	/* add controls of ports and apply range  */
2223 	g_rec_mutex_lock(plugin_port_mutex);
2224 
2225 	lower_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->lower_value);
2226 	upper_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->upper_value);
2227 
2228 	g_rec_mutex_unlock(plugin_port_mutex);
2229 
2230 	if(do_step_conversion){
2231 	  g_object_set(lv2_conversion,
2232 		       "lower", lower_bound,
2233 		       "upper", upper_bound,
2234 		       NULL);
2235 
2236 	  lower = 0.0;
2237 	  upper = AGS_LV2_CONVERSION_DEFAULT_STEP_COUNT - 1.0;
2238 
2239 #if 0
2240 	  if(!disable_seemless){
2241 	    g_object_get(lv2_conversion,
2242 			 "step-count", &step_count,
2243 			 NULL);
2244 	  }
2245 #endif
2246 	}else{
2247 	  lower = lower_bound;
2248 	  upper = upper_bound;
2249 	}
2250 
2251 	g_object_get(spin_button,
2252 		     "adjustment", &adjustment,
2253 		     NULL);
2254 
2255 	if(upper >= 0.0 && lower >= 0.0){
2256 	  step = (upper - lower) / step_count;
2257 	}else if(upper < 0.0 && lower < 0.0){
2258 	  step = -1.0 * (lower - upper) / step_count;
2259 	}else{
2260 	  step = (upper - lower) / step_count;
2261 	}
2262 
2263 	if(step_count > 8){
2264 	  if(upper >= 0.0 && lower >= 0.0){
2265 	    page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
2266 	  }else if(upper < 0.0 && lower < 0.0){
2267 	    page = -1.0 * (lower - upper) / AGS_DIAL_DEFAULT_PRECISION;
2268 	  }else{
2269 	    page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
2270 	  }
2271 	}else{
2272 	  page = step;
2273 	}
2274 
2275 	gtk_adjustment_set_step_increment(adjustment,
2276 					  step);
2277 	gtk_adjustment_set_page_increment(adjustment,
2278 					  page);
2279 	gtk_adjustment_set_lower(adjustment,
2280 				 lower);
2281 	gtk_adjustment_set_upper(adjustment,
2282 				 upper);
2283 
2284 	/* get/set default value */
2285 	g_rec_mutex_lock(plugin_port_mutex);
2286 
2287 	default_value = (float) g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->default_value);
2288 
2289 	g_rec_mutex_unlock(plugin_port_mutex);
2290 
2291 	control_value = default_value;
2292 
2293 	if(lv2_conversion != NULL){
2294 	  control_value = ags_conversion_convert((AgsConversion *) lv2_conversion,
2295 						 default_value,
2296 						 TRUE);
2297 	}
2298 
2299 	gtk_adjustment_set_value(adjustment,
2300 				 control_value);
2301       }else if(AGS_IS_INDICATOR(child_widget) ||
2302 	       AGS_IS_LED(child_widget)){
2303 	g_hash_table_insert(ags_effect_line_indicator_queue_draw,
2304 			    child_widget,
2305 			    ags_effect_line_indicator_queue_draw_timeout);
2306 
2307 	effect_line->queued_drawing = g_list_prepend(effect_line->queued_drawing,
2308 						     child_widget);
2309 
2310 	g_timeout_add(AGS_UI_PROVIDER_DEFAULT_TIMEOUT * 1000.0,
2311 		      (GSourceFunc) ags_effect_line_indicator_queue_draw_timeout,
2312 		      (gpointer) child_widget);
2313       }
2314 
2315 #ifdef AGS_DEBUG
2316       g_message("lv2 bounds: %f %f", lower, upper);
2317 #endif
2318 
2319       gtk_widget_set_valign(line_member,
2320 			    GTK_ALIGN_FILL);
2321       gtk_widget_set_halign(line_member,
2322 			    GTK_ALIGN_FILL);
2323 
2324       gtk_grid_attach(effect_line->grid,
2325 		      (GtkWidget *) line_member,
2326 		      (x % AGS_EFFECT_LINE_COLUMNS_COUNT), y,
2327 		      1, 1);
2328 
2329       ags_connectable_connect(AGS_CONNECTABLE(line_member));
2330       gtk_widget_show_all((GtkWidget *) line_member);
2331 
2332       /* iterate */
2333       x++;
2334 
2335       if(x % AGS_EFFECT_LINE_COLUMNS_COUNT == 0){
2336 	y++;
2337       }
2338     }
2339 
2340     /* iterate */
2341     plugin_port = plugin_port->next;
2342     k++;
2343   }
2344 
2345   effect_line_plugin->control_count = control_count;
2346 
2347   if(audio != NULL){
2348     g_object_unref(audio);
2349   }
2350 
2351   if(channel != NULL){
2352     g_object_unref(channel);
2353   }
2354 
2355   g_list_free_full(start_plugin_port,
2356 		   g_object_unref);
2357 
2358   g_free(uri);
2359 }
2360 
2361 void
ags_effect_line_real_add_plugin(AgsEffectLine * effect_line,GList * control_type_name,AgsRecallContainer * play_container,AgsRecallContainer * recall_container,gchar * plugin_name,gchar * filename,gchar * effect,guint start_audio_channel,guint stop_audio_channel,guint start_pad,guint stop_pad,gint position,guint create_flags,guint recall_flags)2362 ags_effect_line_real_add_plugin(AgsEffectLine *effect_line,
2363 				GList *control_type_name,
2364 				AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
2365 				gchar *plugin_name,
2366 				gchar *filename,
2367 				gchar *effect,
2368 				guint start_audio_channel, guint stop_audio_channel,
2369 				guint start_pad, guint stop_pad,
2370 				gint position,
2371 				guint create_flags, guint recall_flags)
2372 {
2373   AgsBasePlugin *base_plugin;
2374 
2375   gchar *fallback_filename;
2376 
2377   base_plugin = NULL;
2378 
2379   fallback_filename = NULL;
2380 
2381   if(!g_ascii_strncasecmp(plugin_name,
2382 			  "ags-fx-ladspa",
2383 			  14)){
2384     base_plugin = (AgsBasePlugin *) ags_ladspa_manager_find_ladspa_plugin_with_fallback(ags_ladspa_manager_get_instance(),
2385 											filename, effect);
2386   }else if(!g_ascii_strncasecmp(plugin_name,
2387 				"ags-fx-lv2",
2388 				11)){
2389     base_plugin = (AgsBasePlugin *) ags_lv2_manager_find_lv2_plugin_with_fallback(ags_lv2_manager_get_instance(),
2390 										  filename, effect);
2391   }
2392 
2393   if(base_plugin != NULL){
2394     g_object_get(base_plugin,
2395 		 "filename", &fallback_filename,
2396 		 NULL);
2397   }else{
2398     fallback_filename = g_strdup(filename);
2399   }
2400 
2401   if((AGS_FX_FACTORY_ADD & (create_flags)) != 0){
2402     if(!g_ascii_strncasecmp(plugin_name,
2403 			    "ags-fx-ladspa",
2404 			    14)){
2405       ags_effect_line_add_ladspa_plugin(effect_line,
2406 					control_type_name,
2407 					play_container, recall_container,
2408 					plugin_name,
2409 					fallback_filename,
2410 					effect,
2411 					start_audio_channel, stop_audio_channel,
2412 					start_pad, stop_pad,
2413 					position,
2414 					create_flags, recall_flags);
2415     }else if(!g_ascii_strncasecmp(plugin_name,
2416 				  "ags-fx-lv2",
2417 				  11)){
2418       ags_effect_line_add_lv2_plugin(effect_line,
2419 				     control_type_name,
2420 				     play_container, recall_container,
2421 				     plugin_name,
2422 				     fallback_filename,
2423 				     effect,
2424 				     start_audio_channel, stop_audio_channel,
2425 				     start_pad, stop_pad,
2426 				     position,
2427 				     create_flags, recall_flags);
2428     }
2429   }
2430 
2431   g_free(fallback_filename);
2432 }
2433 
2434 /**
2435  * ags_effect_line_add_plugin:
2436  * @effect_line: the #AgsEffectLine to modify
2437  * @control_type_name: the #GList-struct containing string representation of a #GType
2438  * @play_container: an #AgsRecallContainer to indetify what recall to use
2439  * @recall_container: an #AgsRecallContainer to indetify what recall to use
2440  * @plugin_name: the plugin identifier
2441  * @filename: the effect's filename
2442  * @effect: the effect's name
2443  * @start_audio_channel: the first audio channel to apply
2444  * @stop_audio_channel: the last audio channel to apply
2445  * @start_pad: the first pad to apply
2446  * @stop_pad: the last pad to apply
2447  * @position: the position to insert the recall
2448  * @create_flags: modify the behaviour of this function
2449  * @recall_flags: flags to be set for #AgsRecall
2450  *
2451  * Add an effect by its filename and effect specifier.
2452  *
2453  * Since: 3.3.0
2454  */
2455 void
ags_effect_line_add_plugin(AgsEffectLine * effect_line,GList * control_type_name,AgsRecallContainer * play_container,AgsRecallContainer * recall_container,gchar * plugin_name,gchar * filename,gchar * effect,guint start_audio_channel,guint stop_audio_channel,guint start_pad,guint stop_pad,gint position,guint create_flags,guint recall_flags)2456 ags_effect_line_add_plugin(AgsEffectLine *effect_line,
2457 			   GList *control_type_name,
2458 			   AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
2459 			   gchar *plugin_name,
2460 			   gchar *filename,
2461 			   gchar *effect,
2462 			   guint start_audio_channel, guint stop_audio_channel,
2463 			   guint start_pad, guint stop_pad,
2464 			   gint position,
2465 			   guint create_flags, guint recall_flags)
2466 {
2467   g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
2468 
2469   g_object_ref((GObject *) effect_line);
2470   g_signal_emit(G_OBJECT(effect_line),
2471 		effect_line_signals[ADD_PLUGIN], 0,
2472 		control_type_name,
2473 		play_container, recall_container,
2474 		plugin_name,
2475 		filename,
2476 		effect,
2477 		start_audio_channel, stop_audio_channel,
2478 		start_pad, stop_pad,
2479 		position,
2480 		create_flags, recall_flags);
2481   g_object_unref((GObject *) effect_line);
2482 }
2483 
2484 void
ags_effect_line_real_remove_plugin(AgsEffectLine * effect_line,guint nth)2485 ags_effect_line_real_remove_plugin(AgsEffectLine *effect_line,
2486 				   guint nth)
2487 {
2488   AgsEffectLinePlugin *effect_line_plugin;
2489 
2490   AgsAudio *audio;
2491 
2492   GList *start_list, *list;
2493   GList *start_recall, *recall;
2494 
2495   if(!AGS_IS_EFFECT_LINE(effect_line)){
2496     return;
2497   }
2498 
2499   audio = NULL;
2500 
2501   list = g_list_nth(effect_line->plugin,
2502 		    nth);
2503 
2504   if(list == NULL){
2505     return;
2506   }
2507 
2508   effect_line_plugin = list->data;
2509 
2510   g_object_get(effect_line->channel,
2511 	       "audio", &audio,
2512 	       NULL);
2513 
2514   /*  */
2515   effect_line->plugin = g_list_remove(effect_line->plugin,
2516 				      effect_line_plugin);
2517 
2518   /* AgsRecallAudio */
2519   ags_audio_remove_recall(audio, (GObject *) ags_recall_container_get_recall_audio(effect_line_plugin->play_container),
2520 			  TRUE);
2521 
2522   ags_audio_remove_recall(audio, (GObject *) ags_recall_container_get_recall_audio(effect_line_plugin->recall_container),
2523 			  FALSE);
2524 
2525   /* AgsRecallAudioRun - play context */
2526   g_object_get(effect_line_plugin->play_container,
2527 	       "recall-audio-run", &start_recall,
2528 	       NULL);
2529 
2530   recall = start_recall;
2531 
2532   while(recall != NULL){
2533     ags_audio_remove_recall(audio, recall->data,
2534 			    TRUE);
2535 
2536     recall = recall->next;
2537   }
2538 
2539   g_list_free_full(start_recall,
2540 		   (GDestroyNotify) g_object_unref);
2541 
2542   /* AgsRecallAudioRun - recall context */
2543   g_object_get(effect_line_plugin->recall_container,
2544 	       "recall-audio-run", &start_recall,
2545 	       NULL);
2546 
2547   recall = start_recall;
2548 
2549   while(recall != NULL){
2550     ags_audio_remove_recall(audio, (GObject *) recall->data,
2551 			    FALSE);
2552 
2553     recall = recall->next;
2554   }
2555 
2556   g_list_free_full(start_recall,
2557 		   (GDestroyNotify) g_object_unref);
2558 
2559   /* AgsRecallChannel - play context */
2560   g_object_get(effect_line_plugin->play_container,
2561 	       "recall-channel", &start_recall,
2562 	       NULL);
2563 
2564   recall = start_recall;
2565 
2566   while(recall != NULL){
2567     AgsChannel *channel;
2568 
2569     g_object_get(recall->data,
2570 		 "source", &channel,
2571 		 NULL);
2572 
2573     ags_channel_remove_recall(channel, (GObject *) recall->data,
2574 			      TRUE);
2575 
2576     if(channel != NULL){
2577       g_object_unref(channel);
2578     }
2579 
2580     recall = recall->next;
2581   }
2582 
2583   g_list_free_full(start_recall,
2584 		   (GDestroyNotify) g_object_unref);
2585 
2586   /* AgsRecallChannel - recall context */
2587   g_object_get(effect_line_plugin->recall_container,
2588 	       "recall-channel", &start_recall,
2589 	       NULL);
2590 
2591   recall = start_recall;
2592 
2593   while(recall != NULL){
2594     AgsChannel *channel;
2595 
2596     g_object_get(recall->data,
2597 		 "source", &channel,
2598 		 NULL);
2599 
2600     ags_channel_remove_recall(channel, (GObject *) recall->data,
2601 			      FALSE);
2602 
2603 
2604     if(channel != NULL){
2605       g_object_unref(channel);
2606     }
2607 
2608     recall = recall->next;
2609   }
2610 
2611   g_list_free_full(start_recall,
2612 		   (GDestroyNotify) g_object_unref);
2613 
2614   /* AgsRecallChannelRun - play context */
2615   g_object_get(effect_line_plugin->play_container,
2616 	       "recall-channel-run", &start_recall,
2617 	       NULL);
2618 
2619   recall = start_recall;
2620 
2621   while(recall != NULL){
2622     AgsChannel *channel;
2623 
2624     g_object_get(recall->data,
2625 		 "source", &channel,
2626 		 NULL);
2627 
2628     ags_channel_remove_recall(channel, (GObject *) recall->data,
2629 			      TRUE);
2630 
2631     if(channel != NULL){
2632       g_object_unref(channel);
2633     }
2634 
2635     recall = recall->next;
2636   }
2637 
2638   g_list_free_full(start_recall,
2639 		   (GDestroyNotify) g_object_unref);
2640 
2641   /* AgsRecallChannelRun - recall context */
2642   g_object_get(effect_line_plugin->recall_container,
2643 	       "recall-channel-run", &start_recall,
2644 	       NULL);
2645 
2646   recall = start_recall;
2647 
2648   while(recall != NULL){
2649     AgsChannel *channel;
2650 
2651     g_object_get(recall->data,
2652 		 "source", &channel,
2653 		 NULL);
2654 
2655     ags_channel_remove_recall(channel, (GObject *) recall->data,
2656 			      FALSE);
2657 
2658     if(channel != NULL){
2659       g_object_unref(channel);
2660     }
2661 
2662     recall = recall->next;
2663   }
2664 
2665   g_list_free_full(start_recall,
2666 		   (GDestroyNotify) g_object_unref);
2667 
2668   /* recall container */
2669   ags_audio_remove_recall_container(audio, (GObject *) effect_line_plugin->play_container);
2670   ags_audio_remove_recall_container(audio, (GObject *) effect_line_plugin->recall_container);
2671 
2672   ags_channel_remove_recall_container(effect_line->channel, (GObject *) effect_line_plugin->play_container);
2673   ags_channel_remove_recall_container(effect_line->channel, (GObject *) effect_line_plugin->recall_container);
2674 
2675   /* destroy controls - expander table */
2676   start_list = gtk_container_get_children((GtkContainer *) effect_line->grid);
2677 
2678   list = start_list;
2679 
2680   while(list != NULL){
2681     if(AGS_IS_LINE_MEMBER(list->data) &&
2682        AGS_LINE_MEMBER(list->data)->play_container == effect_line_plugin->play_container){
2683       if(AGS_IS_INDICATOR(list->data) ||
2684 	 AGS_IS_LED(list->data)){
2685 	g_hash_table_remove(ags_effect_line_indicator_queue_draw,
2686 			    list->data);
2687       }
2688 
2689       gtk_widget_destroy(list->data);
2690     }else if(AGS_IS_EFFECT_SEPARATOR(list->data) &&
2691 	     AGS_EFFECT_SEPARATOR(list->data)->play_container == effect_line_plugin->play_container){
2692       gtk_widget_destroy(list->data);
2693     }
2694 
2695     list = list->next;
2696   }
2697 
2698   g_list_free(start_list);
2699 
2700   /* unref */
2701   if(audio != NULL){
2702     g_object_unref(audio);
2703   }
2704 
2705   /* free AgsEffectLinePlugin */
2706   ags_effect_line_plugin_free(effect_line_plugin);
2707 }
2708 
2709 /**
2710  * ags_effect_line_remove_plugin:
2711  * @effect_line: the #AgsEffectLine to modify
2712  * @nth: the nth effect to remove
2713  *
2714  * Remove an effect by its position.
2715  *
2716  * Since: 3.3.0
2717  */
2718 void
ags_effect_line_remove_plugin(AgsEffectLine * effect_line,guint nth)2719 ags_effect_line_remove_plugin(AgsEffectLine *effect_line,
2720 			      guint nth)
2721 {
2722   g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
2723 
2724   g_object_ref((GObject *) effect_line);
2725   g_signal_emit(G_OBJECT(effect_line),
2726 		effect_line_signals[REMOVE_PLUGIN], 0,
2727 		nth);
2728   g_object_unref((GObject *) effect_line);
2729 }
2730 
2731 void
ags_effect_line_real_map_recall(AgsEffectLine * effect_line,guint ouput_pad_start)2732 ags_effect_line_real_map_recall(AgsEffectLine *effect_line,
2733 				guint ouput_pad_start)
2734 {
2735   if((AGS_EFFECT_LINE_MAPPED_RECALL & (effect_line->flags)) != 0){
2736     return;
2737   }
2738 
2739   effect_line->flags |= AGS_EFFECT_LINE_MAPPED_RECALL;
2740 
2741   ags_effect_line_find_port(effect_line);
2742 }
2743 
2744 /**
2745  * ags_effect_line_map_recall:
2746  * @effect_line: the #AgsEffectLine to add its default recall.
2747  * @output_pad_start: the start channel's index
2748  *
2749  * You may want the @effect_line to add its default recall. This function
2750  * may call ags_effect_line_find_port().
2751  *
2752  * Since: 3.0.0
2753  */
2754 void
ags_effect_line_map_recall(AgsEffectLine * effect_line,guint output_pad_start)2755 ags_effect_line_map_recall(AgsEffectLine *effect_line,
2756 			   guint output_pad_start)
2757 {
2758   g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
2759 
2760   g_object_ref((GObject *) effect_line);
2761   g_signal_emit((GObject *) effect_line,
2762 		effect_line_signals[MAP_RECALL], 0,
2763 		output_pad_start);
2764   g_object_unref((GObject *) effect_line);
2765 }
2766 
2767 GList*
ags_effect_line_real_find_port(AgsEffectLine * effect_line)2768 ags_effect_line_real_find_port(AgsEffectLine *effect_line)
2769 {
2770   GList *port, *tmp_port;
2771   GList *line_member, *line_member_start;
2772 
2773   if(effect_line == NULL ||
2774      effect_line->grid == NULL){
2775     return(NULL);
2776   }
2777 
2778   line_member_start =
2779     line_member = gtk_container_get_children(GTK_CONTAINER(effect_line->grid));
2780 
2781   port = NULL;
2782 
2783   if(line_member != NULL){
2784     while(line_member != NULL){
2785       if(AGS_IS_LINE_MEMBER(line_member->data)){
2786 	tmp_port = ags_line_member_find_port(AGS_LINE_MEMBER(line_member->data));
2787 
2788 	if(port != NULL){
2789 	  port = g_list_concat(port,
2790 			       tmp_port);
2791 	}else{
2792 	  port = tmp_port;
2793 	}
2794       }
2795 
2796       line_member = line_member->next;
2797     }
2798 
2799     g_list_free(line_member_start);
2800   }
2801 
2802   return(port);
2803 }
2804 
2805 /**
2806  * ags_effect_line_find_port:
2807  * @effect_line: the #AgsEffectLine
2808  *
2809  * Lookup ports of associated recalls.
2810  *
2811  * Returns: a #GList-struct containing all related #AgsPort
2812  *
2813  * Since: 3.0.0
2814  */
2815 GList*
ags_effect_line_find_port(AgsEffectLine * effect_line)2816 ags_effect_line_find_port(AgsEffectLine *effect_line)
2817 {
2818   GList *list;
2819 
2820   list = NULL;
2821   g_return_val_if_fail(AGS_IS_EFFECT_LINE(effect_line),
2822 		       NULL);
2823 
2824   g_object_ref((GObject *) effect_line);
2825   g_signal_emit((GObject *) effect_line,
2826 		effect_line_signals[FIND_PORT], 0,
2827 		&list);
2828   g_object_unref((GObject *) effect_line);
2829 
2830   return(list);
2831 }
2832 
2833 /**
2834  * ags_effect_line_done:
2835  * @effect_line: the #AgsEffectLine
2836  * @recall_id: the #AgsRecallID
2837  *
2838  * Notify about to stop playback of @recall_id.
2839  *
2840  * Since: 3.0.0
2841  */
2842 void
ags_effect_line_done(AgsEffectLine * effect_line,GObject * recall_id)2843 ags_effect_line_done(AgsEffectLine *effect_line, GObject *recall_id)
2844 {
2845   g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
2846 
2847   g_object_ref((GObject *) effect_line);
2848   g_signal_emit((GObject *) effect_line,
2849 		effect_line_signals[DONE], 0,
2850 		recall_id);
2851   g_object_unref((GObject *) effect_line);
2852 }
2853 
2854 /**
2855  * ags_effect_line_find_next_grouped:
2856  * @effect_line: a #GList-struct of #AgsEffectLine objects
2857  *
2858  * Retrieve next grouped effect_line.
2859  *
2860  * Returns: next matching #GList-struct containing #AgsEffectLine
2861  *
2862  * Since: 3.0.0
2863  */
2864 GList*
ags_effect_line_find_next_grouped(GList * effect_line)2865 ags_effect_line_find_next_grouped(GList *effect_line)
2866 {
2867   while(effect_line != NULL && !gtk_toggle_button_get_active(AGS_EFFECT_LINE(effect_line->data)->group)){
2868     effect_line = effect_line->next;
2869   }
2870 
2871   return(effect_line);
2872 }
2873 
2874 /**
2875  * ags_effect_line_check_message:
2876  * @effect_line: the #AgsEffectLine
2877  *
2878  * Check message queue for message envelopes.
2879  *
2880  * Since: 3.0.0
2881  */
2882 void
ags_effect_line_check_message(AgsEffectLine * effect_line)2883 ags_effect_line_check_message(AgsEffectLine *effect_line)
2884 {
2885   AgsChannel *channel;
2886 
2887   AgsMessageDelivery *message_delivery;
2888 
2889   GList *start_message_envelope, *message_envelope;
2890 
2891   if(!AGS_IS_EFFECT_LINE(effect_line)){
2892     return;
2893   }
2894 
2895   /* retrieve message */
2896   message_delivery = ags_message_delivery_get_instance();
2897 
2898   channel = effect_line->channel;
2899 
2900   message_envelope =
2901     start_message_envelope = ags_message_delivery_find_sender(message_delivery,
2902 							      "libgsequencer",
2903 							      (GObject *) channel);
2904 
2905   while(message_envelope != NULL){
2906     xmlNode *root_node;
2907 
2908     root_node = xmlDocGetRootElement(AGS_MESSAGE_ENVELOPE(message_envelope->data)->doc);
2909 
2910     if(!xmlStrncmp(root_node->name,
2911 		   "ags-command",
2912 		   12)){
2913       if(!xmlStrncmp(xmlGetProp(root_node,
2914 				"method"),
2915 		     BAD_CAST "AgsChannel::set-samplerate",
2916 		     27)){
2917 	guint samplerate;
2918 	gint position;
2919 
2920 	position = ags_strv_index(AGS_MESSAGE_ENVELOPE(message_envelope->data)->parameter_name,
2921 				  "samplerate");
2922 	samplerate = g_value_get_uint(&(AGS_MESSAGE_ENVELOPE(message_envelope->data)->value[position]));
2923 
2924 	/* set samplerate */
2925 	g_object_set(effect_line,
2926 		     "samplerate", samplerate,
2927 		     NULL);
2928       }else if(!xmlStrncmp(xmlGetProp(root_node,
2929 				      "method"),
2930 			   BAD_CAST "AgsChannel::set-buffer-size",
2931 			   28)){
2932 	guint buffer_size;
2933 	gint position;
2934 
2935 	position = ags_strv_index(AGS_MESSAGE_ENVELOPE(message_envelope->data)->parameter_name,
2936 				  "buffer-size");
2937 	buffer_size = g_value_get_uint(&(AGS_MESSAGE_ENVELOPE(message_envelope->data)->value[position]));
2938 
2939 	/* set buffer size */
2940 	g_object_set(effect_line,
2941 		     "buffer-size", buffer_size,
2942 		     NULL);
2943       }else if(!xmlStrncmp(xmlGetProp(root_node,
2944 				      "method"),
2945 			   BAD_CAST "AgsChannel::set-format",
2946 			   23)){
2947 	guint format;
2948 	gint position;
2949 
2950 	position = ags_strv_index(AGS_MESSAGE_ENVELOPE(message_envelope->data)->parameter_name,
2951 				  "format");
2952 	format = g_value_get_uint(&(AGS_MESSAGE_ENVELOPE(message_envelope->data)->value[position]));
2953 
2954 	/* set format */
2955 	g_object_set(effect_line,
2956 		     "format", format,
2957 		     NULL);
2958       }else if(!xmlStrncmp(xmlGetProp(root_node,
2959 				      "method"),
2960 			   BAD_CAST "AgsChannel::done",
2961 			   16)){
2962 	AgsRecallID *recall_id;
2963 
2964 	gint position;
2965 
2966 	position = ags_strv_index(AGS_MESSAGE_ENVELOPE(message_envelope->data)->parameter_name,
2967 				  "recall-id");
2968 
2969 	recall_id = g_value_get_object(&(AGS_MESSAGE_ENVELOPE(message_envelope->data)->value[position]));
2970 
2971 	/* done */
2972 	ags_effect_line_done(effect_line,
2973 			     (GObject *) recall_id);
2974       }
2975     }
2976 
2977     message_envelope = message_envelope->next;
2978   }
2979 
2980   g_list_free_full(start_message_envelope,
2981 		   g_object_unref);
2982 }
2983 
2984 /**
2985  * ags_effect_line_indicator_queue_draw_timeout:
2986  * @widget: the indicator widgt
2987  *
2988  * Queue draw widget
2989  *
2990  * Returns: %TRUE if proceed with redraw, otherwise %FALSE
2991  *
2992  * Since: 3.0.0
2993  */
2994 gboolean
ags_effect_line_indicator_queue_draw_timeout(GtkWidget * widget)2995 ags_effect_line_indicator_queue_draw_timeout(GtkWidget *widget)
2996 {
2997   AgsEffectLine *effect_line;
2998 
2999   if(g_hash_table_lookup(ags_effect_line_indicator_queue_draw,
3000 			 widget) != NULL){
3001     GList *list, *list_start;
3002 
3003     effect_line = (AgsEffectLine *) gtk_widget_get_ancestor(widget,
3004 							    AGS_TYPE_EFFECT_LINE);
3005 
3006     list_start =
3007       list = gtk_container_get_children((GtkContainer *) AGS_EFFECT_LINE(effect_line)->grid);
3008 
3009     /* check members */
3010     while(list != NULL){
3011       if(AGS_IS_LINE_MEMBER(list->data) &&
3012 	 (AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_VINDICATOR ||
3013 	  AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_HINDICATOR ||
3014 	  AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_LED)){
3015 	AgsLineMember *line_member;
3016 	GtkAdjustment *adjustment;
3017 	GtkWidget *child;
3018 
3019 	AgsPort *current;
3020 
3021 	AgsPluginPort *plugin_port;
3022 
3023 	gdouble average_peak;
3024 	gdouble lower, upper;
3025 	gdouble range;
3026 	gdouble peak;
3027 	gboolean success;
3028 
3029 	GValue value = {0,};
3030 
3031 	GRecMutex *port_mutex;
3032 	GRecMutex *plugin_port_mutex;
3033 
3034 	line_member = AGS_LINE_MEMBER(list->data);
3035 	child = gtk_bin_get_child(GTK_BIN(line_member));
3036 
3037 	average_peak = 0.0;
3038 
3039 	/* play port */
3040 	current = line_member->port;
3041 
3042 	if(current == NULL){
3043 	  list = list->next;
3044 
3045 	  continue;
3046 	}
3047 
3048 	/* check if output port and specifier matches */
3049 	if(!ags_port_test_flags(current, AGS_PORT_IS_OUTPUT)){
3050 	  list = list->next;
3051 
3052 	  continue;
3053 	}
3054 
3055 	g_object_get(current,
3056 		     "plugin-port", &plugin_port,
3057 		     NULL);
3058 
3059 	if(plugin_port == NULL){
3060 	  list = list->next;
3061 
3062 	  continue;
3063 	}
3064 
3065 	g_object_unref(plugin_port);
3066 
3067 	/* get port mutex */
3068 	port_mutex = AGS_PORT_GET_OBJ_MUTEX(current);
3069 
3070 	/* match specifier */
3071 	g_rec_mutex_lock(port_mutex);
3072 
3073 	success = (!g_ascii_strcasecmp(current->specifier,
3074 				       line_member->specifier)) ? TRUE: FALSE;
3075 
3076 	g_rec_mutex_unlock(port_mutex);
3077 
3078 	if(!success){
3079 	  list = list->next;
3080 
3081 	  continue;
3082 	}
3083 
3084 	/* get plugin port mutex */
3085 	plugin_port_mutex = AGS_PLUGIN_PORT_GET_OBJ_MUTEX(plugin_port);
3086 
3087 	/* lower and upper */
3088 	g_rec_mutex_lock(plugin_port_mutex);
3089 
3090 	lower = g_value_get_float(plugin_port->lower_value);
3091 	upper = g_value_get_float(plugin_port->upper_value);
3092 
3093 	g_rec_mutex_unlock(plugin_port_mutex);
3094 
3095 	/* get range */
3096 	if(line_member->conversion != NULL){
3097 	  lower = ags_conversion_convert(line_member->conversion,
3098 					 lower,
3099 					 TRUE);
3100 
3101 	  upper = ags_conversion_convert(line_member->conversion,
3102 					 upper,
3103 					 TRUE);
3104 	}
3105 
3106 	range = upper - lower;
3107 
3108 	/* play port - read value */
3109 	g_value_init(&value, G_TYPE_FLOAT);
3110 	ags_port_safe_read(current,
3111 			   &value);
3112 
3113 	peak = g_value_get_float(&value);
3114 	g_value_unset(&value);
3115 
3116 	if(line_member->conversion != NULL){
3117 	  peak = ags_conversion_convert(line_member->conversion,
3118 					peak,
3119 					TRUE);
3120 	}
3121 
3122 	/* calculate peak */
3123 	if(range == 0.0 ||
3124 	   current->port_value_type == G_TYPE_BOOLEAN){
3125 	  if(peak != 0.0){
3126 	    average_peak = 10.0;
3127 	  }
3128 	}else{
3129 	  average_peak += ((1.0 / (range / peak)) * 10.0);
3130 	}
3131 
3132 	/* recall port */
3133 	current = line_member->recall_port;
3134 
3135 	/* recall port - read value */
3136 	g_value_init(&value, G_TYPE_FLOAT);
3137 	ags_port_safe_read(current,
3138 			   &value);
3139 
3140 	peak = g_value_get_float(&value);
3141 	g_value_unset(&value);
3142 
3143 	if(line_member->conversion != NULL){
3144 	  peak = ags_conversion_convert(line_member->conversion,
3145 					peak,
3146 					TRUE);
3147 	}
3148 
3149 	/* calculate peak */
3150 	if(range == 0.0 ||
3151 	   current->port_value_type == G_TYPE_BOOLEAN){
3152 	  if(peak != 0.0){
3153 	    average_peak = 10.0;
3154 	  }
3155 	}else{
3156 	  average_peak += ((1.0 / (range / peak)) * 10.0);
3157 	}
3158 
3159 	/* apply */
3160 	if(AGS_IS_LED(child)){
3161 	  if(average_peak != 0.0){
3162 	    ags_led_set_active((AgsLed *) child);
3163 	  }
3164 	}else{
3165 	  g_object_get(child,
3166 		       "adjustment", &adjustment,
3167 		       NULL);
3168 
3169 	  gtk_adjustment_set_value(adjustment,
3170 				   average_peak);
3171 	}
3172       }
3173 
3174       list = list->next;
3175     }
3176 
3177     g_list_free(list_start);
3178 
3179     /* queue draw */
3180     gtk_widget_queue_draw(widget);
3181 
3182     return(TRUE);
3183   }else{
3184     return(FALSE);
3185   }
3186 }
3187 
3188 /**
3189  * ags_effect_line_new:
3190  * @channel: the #AgsChannel to visualize
3191  *
3192  * Create a new instance of #AgsEffectLine
3193  *
3194  * Returns: the new #AgsEffectLine
3195  *
3196  * Since: 3.0.0
3197  */
3198 AgsEffectLine*
ags_effect_line_new(AgsChannel * channel)3199 ags_effect_line_new(AgsChannel *channel)
3200 {
3201   AgsEffectLine *effect_line;
3202 
3203   effect_line = (AgsEffectLine *) g_object_new(AGS_TYPE_EFFECT_LINE,
3204 					       "channel", channel,
3205 					       NULL);
3206 
3207   return(effect_line);
3208 }
3209