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