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_bridge.h>
21 #include <ags/X/ags_effect_bridge_callbacks.h>
22 
23 #include <ags/X/ags_machine.h>
24 #include <ags/X/ags_effect_pad.h>
25 #include <ags/X/ags_effect_bulk.h>
26 
27 #include <ags/i18n.h>
28 
29 void ags_effect_bridge_class_init(AgsEffectBridgeClass *effect_bridge);
30 void ags_effect_bridge_connectable_interface_init(AgsConnectableInterface *connectable);
31 void ags_effect_bridge_init(AgsEffectBridge *effect_bridge);
32 void ags_effect_bridge_set_property(GObject *gobject,
33 				    guint prop_id,
34 				    const GValue *value,
35 				    GParamSpec *param_spec);
36 void ags_effect_bridge_get_property(GObject *gobject,
37 				    guint prop_id,
38 				    GValue *value,
39 				    GParamSpec *param_spec);
40 void ags_effect_bridge_connect(AgsConnectable *connectable);
41 void ags_effect_bridge_disconnect(AgsConnectable *connectable);
42 
43 void ags_effect_bridge_real_resize_audio_channels(AgsEffectBridge *effect_bridge,
44 						  guint new_size, guint old_size);
45 void ags_effect_bridge_real_resize_pads(AgsEffectBridge *effect_bridge,
46 					GType channel_type,
47 					guint new_size, guint old_size);
48 void ags_effect_bridge_real_map_recall(AgsEffectBridge *effect_bridge);
49 GList* ags_effect_bridge_real_find_port(AgsEffectBridge *effect_bridge);
50 
51 /**
52  * SECTION:ags_effect_bridge
53  * @short_description: A composite widget to visualize a bunch of #AgsChannel
54  * @title: AgsEffectBridge
55  * @section_id:
56  * @include: ags/X/ags_effect_bridge.h
57  *
58  * #AgsEffectBridge is a composite widget containing #AgsEffectBulk or #AgsEffectPad. It should be
59  * packed by an #AgsMachine.
60  */
61 
62 enum{
63   SAMPLERATE_CHANGED,
64   BUFFER_SIZE_CHANGED,
65   FORMAT_CHANGED,
66   RESIZE_AUDIO_CHANNELS,
67   RESIZE_PADS,
68   MAP_RECALL,
69   FIND_PORT,
70   LAST_SIGNAL,
71 };
72 
73 enum{
74   PROP_0,
75   PROP_SAMPLERATE,
76   PROP_BUFFER_SIZE,
77   PROP_FORMAT,
78   PROP_AUDIO,
79 };
80 
81 static gpointer ags_effect_bridge_parent_class = NULL;
82 static guint effect_bridge_signals[LAST_SIGNAL];
83 
84 GType
ags_effect_bridge_get_type(void)85 ags_effect_bridge_get_type(void)
86 {
87   static volatile gsize g_define_type_id__volatile = 0;
88 
89   if(g_once_init_enter (&g_define_type_id__volatile)){
90     GType ags_type_effect_bridge = 0;
91 
92     static const GTypeInfo ags_effect_bridge_info = {
93       sizeof(AgsEffectBridgeClass),
94       NULL, /* base_init */
95       NULL, /* base_finalize */
96       (GClassInitFunc) ags_effect_bridge_class_init,
97       NULL, /* class_finalize */
98       NULL, /* class_data */
99       sizeof(AgsEffectBridge),
100       0,    /* n_preallocs */
101       (GInstanceInitFunc) ags_effect_bridge_init,
102     };
103 
104     static const GInterfaceInfo ags_connectable_interface_info = {
105       (GInterfaceInitFunc) ags_effect_bridge_connectable_interface_init,
106       NULL, /* interface_finalize */
107       NULL, /* interface_data */
108     };
109 
110     ags_type_effect_bridge = g_type_register_static(GTK_TYPE_BOX,
111 						    "AgsEffectBridge", &ags_effect_bridge_info,
112 						    0);
113 
114     g_type_add_interface_static(ags_type_effect_bridge,
115 				AGS_TYPE_CONNECTABLE,
116 				&ags_connectable_interface_info);
117 
118     g_once_init_leave(&g_define_type_id__volatile, ags_type_effect_bridge);
119   }
120 
121   return g_define_type_id__volatile;
122 }
123 
124 void
ags_effect_bridge_class_init(AgsEffectBridgeClass * effect_bridge)125 ags_effect_bridge_class_init(AgsEffectBridgeClass *effect_bridge)
126 {
127   GObjectClass *gobject;
128   GParamSpec *param_spec;
129 
130   ags_effect_bridge_parent_class = g_type_class_peek_parent(effect_bridge);
131 
132   /* GObjectClass */
133   gobject = (GObjectClass *) effect_bridge;
134 
135   gobject->set_property = ags_effect_bridge_set_property;
136   gobject->get_property = ags_effect_bridge_get_property;
137 
138   /* properties */
139   /**
140    * AgsEffectBridge:samplerate:
141    *
142    * The samplerate.
143    *
144    * Since: 3.0.0
145    */
146   param_spec = g_param_spec_uint("samplerate",
147 				 i18n_pspec("samplerate"),
148 				 i18n_pspec("The samplerate"),
149 				 0,
150 				 G_MAXUINT32,
151 				 AGS_SOUNDCARD_DEFAULT_SAMPLERATE,
152 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
153   g_object_class_install_property(gobject,
154 				  PROP_SAMPLERATE,
155 				  param_spec);
156 
157   /**
158    * AgsEffectBridge:buffer-size:
159    *
160    * The buffer length.
161    *
162    * Since: 3.0.0
163    */
164   param_spec = g_param_spec_uint("buffer-size",
165 				 i18n_pspec("buffer size"),
166 				 i18n_pspec("The buffer size"),
167 				 0,
168 				 G_MAXUINT32,
169 				 AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE,
170 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
171   g_object_class_install_property(gobject,
172 				  PROP_BUFFER_SIZE,
173 				  param_spec);
174 
175   /**
176    * AgsEffectBridge:format:
177    *
178    * The format.
179    *
180    * Since: 3.0.0
181    */
182   param_spec = g_param_spec_uint("format",
183 				 i18n_pspec("format"),
184 				 i18n_pspec("The format"),
185 				 0,
186 				 G_MAXUINT32,
187 				 AGS_SOUNDCARD_DEFAULT_FORMAT,
188 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
189   g_object_class_install_property(gobject,
190 				  PROP_FORMAT,
191 				  param_spec);
192 
193   /**
194    * AgsEffectBridge:audio:
195    *
196    * The start of a bunch of #AgsAudio to visualize.
197    *
198    * Since: 3.0.0
199    */
200   param_spec = g_param_spec_object("audio",
201 				   i18n_pspec("assigned audio"),
202 				   i18n_pspec("The audio it is assigned with"),
203 				   AGS_TYPE_AUDIO,
204 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
205   g_object_class_install_property(gobject,
206 				  PROP_AUDIO,
207 				  param_spec);
208 
209   /* AgsEffectBridgeClass */
210   effect_bridge->samplerate_changed = NULL;
211   effect_bridge->buffer_size_changed = NULL;
212   effect_bridge->format_changed = NULL;
213 
214   effect_bridge->resize_pads = ags_effect_bridge_real_resize_pads;
215   effect_bridge->resize_audio_channels = ags_effect_bridge_real_resize_audio_channels;
216 
217   effect_bridge->map_recall = ags_effect_bridge_real_map_recall;
218   effect_bridge->find_port = ags_effect_bridge_real_find_port;
219 
220   /* signals */
221   /**
222    * AgsEffectBridge::samplerate-changed:
223    * @effect_bridge: the #AgsEffectBridge
224    * @samplerate: the samplerate
225    * @old_samplerate: the old samplerate
226    *
227    * The ::samplerate-changed signal notifies about changed samplerate.
228    *
229    * Since: 3.0.0
230    */
231   effect_bridge_signals[SAMPLERATE_CHANGED] =
232     g_signal_new("samplerate-changed",
233 		 G_TYPE_FROM_CLASS(effect_bridge),
234 		 G_SIGNAL_RUN_LAST,
235 		 G_STRUCT_OFFSET(AgsEffectBridgeClass, samplerate_changed),
236 		 NULL, NULL,
237 		 ags_cclosure_marshal_VOID__UINT_UINT,
238 		 G_TYPE_NONE, 2,
239 		 G_TYPE_UINT,
240 		 G_TYPE_UINT);
241 
242   /**
243    * AgsEffectBridge::buffer-size-changed:
244    * @effect_bridge: the #AgsEffectBridge
245    * @buffer_size: the buffer size
246    * @old_buffer_size: the old buffer size
247    *
248    * The ::buffer-size-changed signal notifies about changed buffer size.
249    *
250    * Since: 3.0.0
251    */
252   effect_bridge_signals[BUFFER_SIZE_CHANGED] =
253     g_signal_new("buffer-size-changed",
254 		 G_TYPE_FROM_CLASS(effect_bridge),
255 		 G_SIGNAL_RUN_LAST,
256 		 G_STRUCT_OFFSET(AgsEffectBridgeClass, buffer_size_changed),
257 		 NULL, NULL,
258 		 ags_cclosure_marshal_VOID__UINT_UINT,
259 		 G_TYPE_NONE, 2,
260 		 G_TYPE_UINT,
261 		 G_TYPE_UINT);
262 
263   /**
264    * AgsEffectBridge::format-changed:
265    * @effect_bridge: the #AgsEffectBridge
266    * @format: the format
267    * @old_format: the old format
268    *
269    * The ::format-changed signal notifies about changed format.
270    *
271    * Since: 3.0.0
272    */
273   effect_bridge_signals[FORMAT_CHANGED] =
274     g_signal_new("format-changed",
275 		 G_TYPE_FROM_CLASS(effect_bridge),
276 		 G_SIGNAL_RUN_LAST,
277 		 G_STRUCT_OFFSET(AgsEffectBridgeClass, format_changed),
278 		 NULL, NULL,
279 		 ags_cclosure_marshal_VOID__UINT_UINT,
280 		 G_TYPE_NONE, 2,
281 		 G_TYPE_UINT,
282 		 G_TYPE_UINT);
283 
284   /**
285    * AgsEffectBridge::resize-audio-channels:
286    * @effect_bridge: the #AgsEffectBridge to modify
287    * @channel: the #AgsChannel to set
288    * @new_size: the new size
289    * @old_size: the old size
290    *
291    * The ::resize-audio-channels signal notifies about changed channel allocation within
292    * audio.
293    *
294    * Since: 3.0.0
295    */
296   effect_bridge_signals[RESIZE_AUDIO_CHANNELS] =
297     g_signal_new("resize-audio-channels",
298 		 G_TYPE_FROM_CLASS(effect_bridge),
299 		 G_SIGNAL_RUN_LAST,
300 		 G_STRUCT_OFFSET(AgsEffectBridgeClass, resize_audio_channels),
301 		 NULL, NULL,
302 		 ags_cclosure_marshal_VOID__UINT_UINT,
303 		 G_TYPE_NONE, 2,
304 		 G_TYPE_UINT,
305 		 G_TYPE_UINT);
306 
307   /**
308    * AgsEffectBridge::resize-pads:
309    * @effect_bridge: the #AgsEffectBridge to modify
310    * @channel: the #AgsChannel to set
311    * @channel_type: either %AGS_TYPE_INPUT or %AGS_TYPE_OUTPUT
312    * @new_size: the new size
313    * @old_size: the old size
314    *
315    * The ::resize-pads signal notifies about changed channel allocation within
316    * audio.
317    *
318    * Since: 3.0.0
319    */
320   effect_bridge_signals[RESIZE_PADS] =
321     g_signal_new("resize-pads",
322 		 G_TYPE_FROM_CLASS(effect_bridge),
323 		 G_SIGNAL_RUN_LAST,
324 		 G_STRUCT_OFFSET(AgsEffectBridgeClass, resize_pads),
325 		 NULL, NULL,
326 		 ags_cclosure_marshal_VOID__ULONG_UINT_UINT,
327 		 G_TYPE_NONE, 3,
328 		 G_TYPE_ULONG,
329 		 G_TYPE_UINT,
330 		 G_TYPE_UINT);
331 
332   /**
333    * AgsEffectBridge::map-recall:
334    * @effect_bridge: the #AgsEffectBridge
335    *
336    * The ::map-recall should be used to add the effect_bridge's default recall.
337    *
338    * Since: 3.0.0
339    */
340   effect_bridge_signals[MAP_RECALL] =
341     g_signal_new("map-recall",
342                  G_TYPE_FROM_CLASS (effect_bridge),
343                  G_SIGNAL_RUN_LAST,
344 		 G_STRUCT_OFFSET (AgsEffectBridgeClass, map_recall),
345                  NULL, NULL,
346                  g_cclosure_marshal_VOID__UINT,
347                  G_TYPE_NONE, 0);
348 
349   /**
350    * AgsEffectBridge::find-port:
351    * @effect_bridge: the #AgsEffectBridge to resize
352    * Returns: a #GList with associated ports
353    *
354    * The ::find-port as recall should be mapped
355    *
356    * Since: 3.0.0
357    */
358   effect_bridge_signals[FIND_PORT] =
359     g_signal_new("find-port",
360 		 G_TYPE_FROM_CLASS(effect_bridge),
361 		 G_SIGNAL_RUN_LAST,
362 		 G_STRUCT_OFFSET(AgsEffectBridgeClass, find_port),
363 		 NULL, NULL,
364 		 ags_cclosure_marshal_POINTER__VOID,
365 		 G_TYPE_POINTER, 0);
366 }
367 
368 void
ags_effect_bridge_connectable_interface_init(AgsConnectableInterface * connectable)369 ags_effect_bridge_connectable_interface_init(AgsConnectableInterface *connectable)
370 {
371   connectable->is_ready = NULL;
372   connectable->is_connected = NULL;
373   connectable->connect = ags_effect_bridge_connect;
374   connectable->disconnect = ags_effect_bridge_disconnect;
375 }
376 
377 void
ags_effect_bridge_init(AgsEffectBridge * effect_bridge)378 ags_effect_bridge_init(AgsEffectBridge *effect_bridge)
379 {
380   gtk_orientable_set_orientation(GTK_ORIENTABLE(effect_bridge),
381 				 GTK_ORIENTATION_VERTICAL);
382 
383   effect_bridge->flags = 0;
384 
385   effect_bridge->name = NULL;
386 
387   effect_bridge->version = AGS_EFFECT_BRIDGE_DEFAULT_VERSION;
388   effect_bridge->build_id = AGS_EFFECT_BRIDGE_DEFAULT_BUILD_ID;
389 
390   effect_bridge->samplerate = AGS_SOUNDCARD_DEFAULT_SAMPLERATE;
391   effect_bridge->buffer_size = AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE;
392   effect_bridge->format = AGS_SOUNDCARD_DEFAULT_FORMAT;
393 
394   effect_bridge->audio_channels = 0;
395 
396   effect_bridge->output_pads = 0;
397   effect_bridge->input_pads = 0;
398 
399   effect_bridge->audio = NULL;
400 
401   /* output */
402   effect_bridge->output_pad_type = G_TYPE_NONE;
403   effect_bridge->output_line_type = G_TYPE_NONE;
404 
405   effect_bridge->bulk_output_type = G_TYPE_NONE;
406 
407   effect_bridge->bulk_output = NULL;
408 
409   effect_bridge->output = NULL;
410 
411   /* input */
412   effect_bridge->input_pad_type = G_TYPE_NONE;
413   effect_bridge->input_line_type = G_TYPE_NONE;
414 
415   effect_bridge->bulk_input_type = G_TYPE_NONE;
416 
417   effect_bridge->bulk_input = NULL;
418 
419   effect_bridge->input = NULL;
420 }
421 
422 void
ags_effect_bridge_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)423 ags_effect_bridge_set_property(GObject *gobject,
424 			       guint prop_id,
425 			       const GValue *value,
426 			       GParamSpec *param_spec)
427 {
428   AgsEffectBridge *effect_bridge;
429 
430   effect_bridge = AGS_EFFECT_BRIDGE(gobject);
431 
432   switch(prop_id){
433   case PROP_SAMPLERATE:
434     {
435       GList *start_list, *list;
436 
437       guint samplerate, old_samplerate;
438 
439       samplerate = g_value_get_uint(value);
440       old_samplerate = effect_bridge->samplerate;
441 
442       if(samplerate == old_samplerate){
443 	return;
444       }
445 
446       effect_bridge->samplerate = samplerate;
447 
448       ags_effect_bridge_samplerate_changed(effect_bridge,
449 					   samplerate, old_samplerate);
450 
451       if(effect_bridge->output != NULL){
452 	list =
453 	  start_list = gtk_container_get_children(GTK_CONTAINER(effect_bridge->output));
454 
455 	while(list != NULL){
456 	  if(AGS_IS_EFFECT_PAD(list->data)){
457 	    g_object_set(list->data,
458 			 "samplerate", samplerate,
459 			 NULL);
460 	  }
461 
462 	  list = list->next;
463 	}
464 
465 	g_list_free(start_list);
466       }
467 
468       if(effect_bridge->input != NULL){
469 	list =
470 	  start_list = gtk_container_get_children(GTK_CONTAINER(effect_bridge->input));
471 
472 	while(list != NULL){
473 	  if(AGS_IS_EFFECT_PAD(list->data)){
474 	    g_object_set(list->data,
475 			 "samplerate", samplerate,
476 			 NULL);
477 	  }
478 
479 	  list = list->next;
480 	}
481 
482 	g_list_free(start_list);
483       }
484     }
485     break;
486   case PROP_BUFFER_SIZE:
487     {
488       GList *start_list, *list;
489 
490       guint buffer_size, old_buffer_size;
491 
492       buffer_size = g_value_get_uint(value);
493       old_buffer_size = effect_bridge->buffer_size;
494 
495       if(buffer_size == old_buffer_size){
496 	return;
497       }
498 
499       effect_bridge->buffer_size = buffer_size;
500 
501       ags_effect_bridge_buffer_size_changed(effect_bridge,
502 					    buffer_size, old_buffer_size);
503 
504       if(effect_bridge->output != NULL){
505 	list =
506 	  start_list = gtk_container_get_children(GTK_CONTAINER(effect_bridge->output));
507 
508 	while(list != NULL){
509 	  if(AGS_IS_EFFECT_PAD(list->data)){
510 	    g_object_set(list->data,
511 			 "buffer-size", buffer_size,
512 			 NULL);
513 	  }
514 
515 	  list = list->next;
516 	}
517 
518 	g_list_free(start_list);
519       }
520 
521       if(effect_bridge->input != NULL){
522 	list =
523 	  start_list = gtk_container_get_children(GTK_CONTAINER(effect_bridge->input));
524 
525 	while(list != NULL){
526 	  if(AGS_IS_EFFECT_PAD(list->data)){
527 	    g_object_set(list->data,
528 			 "buffer-size", buffer_size,
529 			 NULL);
530 	  }
531 
532 	  list = list->next;
533 	}
534 
535 	g_list_free(start_list);
536       }
537     }
538     break;
539   case PROP_FORMAT:
540     {
541       GList *start_list, *list;
542 
543       guint format, old_format;
544 
545       format = g_value_get_uint(value);
546       old_format = effect_bridge->format;
547 
548       if(format == old_format){
549 	return;
550       }
551 
552       effect_bridge->format = format;
553 
554       ags_effect_bridge_format_changed(effect_bridge,
555 				       format, old_format);
556 
557       if(effect_bridge->output != NULL){
558 	list =
559 	  start_list = gtk_container_get_children(GTK_CONTAINER(effect_bridge->output));
560 
561 	while(list != NULL){
562 	  if(AGS_IS_EFFECT_PAD(list->data)){
563 	    g_object_set(list->data,
564 			 "format", format,
565 			 NULL);
566 	  }
567 
568 	  list = list->next;
569 	}
570 
571 	g_list_free(start_list);
572       }
573 
574       if(effect_bridge->input != NULL){
575 	list =
576 	  start_list = gtk_container_get_children(GTK_CONTAINER(effect_bridge->input));
577 
578 	while(list != NULL){
579 	  if(AGS_IS_EFFECT_PAD(list->data)){
580 	    g_object_set(list->data,
581 			 "format", format,
582 			 NULL);
583 	  }
584 
585 	  list = list->next;
586 	}
587 
588 	g_list_free(start_list);
589       }
590     }
591     break;
592   case PROP_AUDIO:
593     {
594       AgsAudio *audio;
595 
596       audio = (AgsAudio *) g_value_get_object(value);
597 
598       if(effect_bridge->audio == audio){
599 	return;
600       }
601 
602       if(effect_bridge->audio != NULL){
603 	GList *effect_pad;
604 
605 	g_object_unref(effect_bridge->audio);
606 
607 	if(audio == NULL){
608 	  /* destroy pad */
609 	  effect_pad = gtk_container_get_children((GtkContainer *) effect_bridge->output);
610 
611 	  while(effect_pad != NULL){
612 	    gtk_widget_destroy(effect_pad->data);
613 
614 	    effect_pad = effect_pad->next;
615 	  }
616 
617 	  effect_pad = gtk_container_get_children((GtkContainer *) effect_bridge->input);
618 
619 	  while(effect_pad != NULL){
620 	    gtk_widget_destroy(GTK_WIDGET(effect_pad->data));
621 
622 	    effect_pad = effect_pad->next;
623 	  }
624 	}
625       }
626 
627       if(audio != NULL){
628 	AgsChannel *input, *output;
629 
630 	GList *start_effect_pad, *effect_pad;
631 	GList *start_effect_line, *effect_line;
632 
633 	guint audio_channels;
634 	guint output_pads, input_pads;
635 	guint i;
636 
637 	g_object_ref(audio);
638 	g_object_get(audio,
639 		     "output", &output,
640 		     "input", &input,
641 		     "audio-channels", &audio_channels,
642 		     "output-pads", &output_pads,
643 		     "input-pads", &input_pads,
644 		     NULL);
645 
646 	effect_bridge->samplerate = audio->samplerate;
647 	effect_bridge->buffer_size = audio->buffer_size;
648 	effect_bridge->format = audio->format;
649 
650 	if(output != NULL){
651 	  g_object_unref(output);
652 	}
653 
654 	if(input != NULL){
655 	  g_object_unref(input);
656 	}
657 
658 	/* set channel and resize for AgsOutput */
659 	if(effect_bridge->output_pad_type != G_TYPE_NONE){
660 	  effect_pad =
661 	    start_effect_pad = gtk_container_get_children((GtkContainer *) effect_bridge->output);
662 
663 	  /* reset */
664 	  i = 0;
665 
666 	  while(effect_pad != NULL && output != NULL){
667 	    effect_line =
668 	      start_effect_line = gtk_container_get_children((GtkContainer *) AGS_EFFECT_PAD(effect_pad->data)->grid);
669 
670 	    g_object_set(G_OBJECT(effect_pad->data),
671 			 "channel", output,
672 			 NULL);
673 
674 	    ags_effect_pad_resize_lines(AGS_EFFECT_PAD(effect_pad->data), effect_bridge->output_line_type,
675 					audio_channels, g_list_length(effect_line));
676 
677 	    g_list_free(start_effect_line);
678 
679 	    /* iterate */
680 	    g_object_get(output,
681 			 "next-pad", &output,
682 			 NULL);
683 
684 	    if(output != NULL){
685 	      g_object_unref(output);
686 	    }
687 
688 	    effect_pad = effect_pad->next;
689 	    i++;
690 	  }
691 
692 	  if(output != NULL){
693 	    AgsEffectPad *effect_pad;
694 
695 	    /* add effect pad */
696 	    for(; i < output_pads; i++){
697 	      effect_pad = g_object_new(effect_bridge->output_pad_type,
698 					"channel", output,
699 					NULL);
700 
701 	      gtk_container_add((GtkContainer *) effect_bridge->output,
702 				GTK_WIDGET(effect_pad));
703 
704 	      ags_effect_pad_resize_lines(effect_pad, effect_bridge->output_line_type,
705 					  audio_channels, 0);
706 
707 	      /* iterate */
708 	      g_object_get(output,
709 			   "next-pad", &output,
710 			   NULL);
711 
712 	      if(output != NULL){
713 		g_object_unref(output);
714 	      }
715 	    }
716 
717 	    g_list_free(start_effect_pad);
718 	  }else{
719 	    /* destroy effect pad */
720 	    effect_pad =
721 	      start_effect_pad = gtk_container_get_children((GtkContainer *) effect_bridge->output);
722 	    effect_pad = g_list_nth(effect_pad,
723 				    output_pads);
724 
725 	    while(effect_pad != NULL){
726 	      gtk_widget_destroy(effect_pad->data);
727 
728 	      effect_pad = effect_pad->next;
729 	    }
730 
731 	    g_list_free(start_effect_pad);
732 	  }
733 	}
734 
735 	/* set channel and resize for AgsInput */
736 	if(effect_bridge->input_pad_type != G_TYPE_NONE){
737 	  effect_pad =
738 	    start_effect_pad = gtk_container_get_children((GtkContainer *) effect_bridge->input);
739 
740 	  i = 0;
741 
742 	  while(effect_pad != NULL && input != NULL){
743 	    effect_line =
744 	      start_effect_line = gtk_container_get_children((GtkContainer *) AGS_EFFECT_PAD(effect_pad->data)->grid);
745 
746 	    g_object_set(G_OBJECT(effect_pad->data),
747 			 "channel", input,
748 			 NULL);
749 
750 	    ags_effect_pad_resize_lines(AGS_EFFECT_PAD(effect_pad->data), effect_bridge->input_line_type,
751 					audio_channels, g_list_length(effect_line));
752 
753 	    g_list_free(start_effect_line);
754 
755 	    /* iterate */
756 	    g_object_get(input,
757 			 "next-pad", &input,
758 			 NULL);
759 
760 	    if(input != NULL){
761 	      g_object_unref(input);
762 	    }
763 
764 	    effect_pad = effect_pad->next;
765 	    i++;
766 	  }
767 
768 	  if(input != NULL){
769 	    AgsEffectPad *effect_pad;
770 
771 	    /* add effect pad */
772 	    for(; i < input_pads; i++){
773 	      effect_pad = g_object_new(effect_bridge->input_pad_type,
774 					"channel", input,
775 					NULL);
776 	      gtk_container_add((GtkContainer *) effect_bridge->input,
777 				GTK_WIDGET(effect_pad));
778 
779 	      ags_effect_pad_resize_lines(effect_pad, effect_bridge->input_line_type,
780 					  audio_channels, 0);
781 
782 	      /* iterate */
783 	      g_object_get(input,
784 			   "next-pad", &input,
785 			   NULL);
786 
787 	      if(input != NULL){
788 		g_object_unref(input);
789 	      }
790 	    }
791 
792 	    g_list_free(start_effect_pad);
793 	  }else{
794 	    /* destroy effect pad */
795 	    effect_pad =
796 	      start_effect_pad = gtk_container_get_children((GtkContainer *) effect_bridge->input);
797 	    effect_pad = g_list_nth(effect_pad,
798 				    input_pads);
799 
800 	    while(effect_pad != NULL){
801 	      gtk_widget_destroy(effect_pad->data);
802 
803 	      effect_pad = effect_pad->next;
804 	    }
805 
806 	    g_list_free(start_effect_pad);
807 	  }
808 	}
809       }
810 
811       effect_bridge->audio = audio;
812 
813       if(effect_bridge->bulk_output != NULL){
814 	g_object_set(effect_bridge->bulk_output,
815 		     "audio", audio,
816 		     NULL);
817       }
818 
819       if(effect_bridge->bulk_input != NULL){
820 	g_object_set(effect_bridge->bulk_input,
821 		     "audio", audio,
822 		     NULL);
823       }
824     }
825     break;
826   default:
827     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
828     break;
829   }
830 }
831 
832 void
ags_effect_bridge_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)833 ags_effect_bridge_get_property(GObject *gobject,
834 			       guint prop_id,
835 			       GValue *value,
836 			       GParamSpec *param_spec)
837 {
838   AgsEffectBridge *effect_bridge;
839 
840   effect_bridge = AGS_EFFECT_BRIDGE(gobject);
841 
842   switch(prop_id){
843   case PROP_SAMPLERATE:
844     {
845       g_value_set_uint(value,
846 		       effect_bridge->samplerate);
847     }
848     break;
849   case PROP_BUFFER_SIZE:
850     {
851       g_value_set_uint(value,
852 		       effect_bridge->buffer_size);
853     }
854     break;
855   case PROP_FORMAT:
856     {
857       g_value_set_uint(value,
858 		       effect_bridge->format);
859     }
860     break;
861   case PROP_AUDIO:
862     {
863       g_value_set_object(value, effect_bridge->audio);
864     }
865     break;
866   default:
867     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
868     break;
869   }
870 }
871 
872 void
ags_effect_bridge_connect(AgsConnectable * connectable)873 ags_effect_bridge_connect(AgsConnectable *connectable)
874 {
875   AgsMachine *machine;
876   AgsEffectBridge *effect_bridge;
877 
878   GList *effect_pad_list, *effect_pad_list_start;
879 
880   effect_bridge = AGS_EFFECT_BRIDGE(connectable);
881 
882   if((AGS_EFFECT_BRIDGE_CONNECTED & (effect_bridge->flags)) != 0){
883     return;
884   }
885 
886   effect_bridge->flags |= AGS_EFFECT_BRIDGE_CONNECTED;
887 
888   machine = (AgsMachine *) gtk_widget_get_ancestor(GTK_WIDGET(effect_bridge),
889 						   AGS_TYPE_MACHINE);
890 
891   g_signal_connect_after(machine, "resize-audio-channels",
892 			 G_CALLBACK(ags_effect_bridge_resize_audio_channels_callback), effect_bridge);
893 
894   g_signal_connect_after(machine, "resize-pads",
895 			 G_CALLBACK(ags_effect_bridge_resize_pads_callback), effect_bridge);
896 
897   /* AgsEffectBulk - input */
898   if(effect_bridge->bulk_input != NULL){
899     ags_connectable_connect(AGS_CONNECTABLE(effect_bridge->bulk_input));
900   }
901 
902   /* AgsEffectBulk - output */
903   if(effect_bridge->bulk_output != NULL){
904     ags_connectable_connect(AGS_CONNECTABLE(effect_bridge->bulk_output));
905   }
906 
907   /* AgsEffectPad - input */
908   if(effect_bridge->input != NULL){
909     effect_pad_list_start =
910       effect_pad_list = gtk_container_get_children((GtkContainer *) effect_bridge->input);
911 
912     while(effect_pad_list != NULL){
913       ags_connectable_connect(AGS_CONNECTABLE(effect_pad_list->data));
914 
915       effect_pad_list = effect_pad_list->next;
916     }
917 
918     g_list_free(effect_pad_list_start);
919   }
920 
921   /* AgsEffectPad - output */
922   if(effect_bridge->output != NULL){
923     effect_pad_list_start =
924       effect_pad_list = gtk_container_get_children((GtkContainer *) effect_bridge->output);
925 
926     while(effect_pad_list != NULL){
927       ags_connectable_connect(AGS_CONNECTABLE(effect_pad_list->data));
928 
929       effect_pad_list = effect_pad_list->next;
930     }
931 
932     g_list_free(effect_pad_list_start);
933   }
934 }
935 
936 void
ags_effect_bridge_disconnect(AgsConnectable * connectable)937 ags_effect_bridge_disconnect(AgsConnectable *connectable)
938 {
939   AgsMachine *machine;
940   AgsEffectBridge *effect_bridge;
941 
942   GList *effect_pad_list, *effect_pad_list_start;
943 
944   effect_bridge = AGS_EFFECT_BRIDGE(connectable);
945 
946   if((AGS_EFFECT_BRIDGE_CONNECTED & (effect_bridge->flags)) == 0){
947     return;
948   }
949 
950   effect_bridge->flags &= (~AGS_EFFECT_BRIDGE_CONNECTED);
951 
952   machine = (AgsMachine *) gtk_widget_get_ancestor(GTK_WIDGET(effect_bridge),
953 						   AGS_TYPE_MACHINE);
954 
955   g_object_disconnect(G_OBJECT(machine),
956 		      "any_signal::resize-audio-channels",
957 		      G_CALLBACK(ags_effect_bridge_resize_audio_channels_callback),
958 		      effect_bridge,
959 		      "any_signal::resize-pads",
960 		      G_CALLBACK(ags_effect_bridge_resize_pads_callback),
961 		      effect_bridge,
962 		      NULL);
963 
964   /* AgsEffectBulk - input */
965   if(effect_bridge->bulk_input != NULL){
966     ags_connectable_disconnect(AGS_CONNECTABLE(effect_bridge->bulk_input));
967   }
968 
969   /* AgsEffectBulk - output */
970   if(effect_bridge->bulk_output != NULL){
971     ags_connectable_disconnect(AGS_CONNECTABLE(effect_bridge->bulk_output));
972   }
973 
974   /* AgsEffectPad - input */
975   if(effect_bridge->input != NULL){
976     effect_pad_list_start =
977       effect_pad_list = gtk_container_get_children((GtkContainer *) effect_bridge->input);
978 
979     while(effect_pad_list != NULL){
980       ags_connectable_disconnect(AGS_CONNECTABLE(effect_pad_list->data));
981 
982       effect_pad_list = effect_pad_list->next;
983     }
984 
985     g_list_free(effect_pad_list_start);
986   }
987 
988   /* AgsEffectPad - output */
989   if(effect_bridge->output != NULL){
990     effect_pad_list_start =
991       effect_pad_list = gtk_container_get_children((GtkContainer *) effect_bridge->output);
992 
993     while(effect_pad_list != NULL){
994       ags_connectable_disconnect(AGS_CONNECTABLE(effect_pad_list->data));
995 
996       effect_pad_list = effect_pad_list->next;
997     }
998 
999     g_list_free(effect_pad_list_start);
1000   }
1001 }
1002 
1003 /**
1004  * ags_effect_bridge_samplerate_changed:
1005  * @effect_bridge: the #AgsEffectBridge
1006  * @samplerate: the samplerate
1007  * @old_samplerate: the old samplerate
1008  *
1009  * Notify about samplerate changed.
1010  *
1011  * Since: 3.0.0
1012  */
1013 void
ags_effect_bridge_samplerate_changed(AgsEffectBridge * effect_bridge,guint samplerate,guint old_samplerate)1014 ags_effect_bridge_samplerate_changed(AgsEffectBridge *effect_bridge,
1015 				     guint samplerate, guint old_samplerate)
1016 {
1017   g_return_if_fail(AGS_IS_EFFECT_BRIDGE(effect_bridge));
1018 
1019   g_object_ref((GObject *) effect_bridge);
1020   g_signal_emit(G_OBJECT(effect_bridge),
1021 		effect_bridge_signals[SAMPLERATE_CHANGED], 0,
1022 		samplerate,
1023 		old_samplerate);
1024   g_object_unref((GObject *) effect_bridge);
1025 }
1026 
1027 /**
1028  * ags_effect_bridge_buffer_size_changed:
1029  * @effect_bridge: the #AgsEffectBridge
1030  * @buffer_size: the buffer_size
1031  * @old_buffer_size: the old buffer_size
1032  *
1033  * Notify about buffer_size changed.
1034  *
1035  * Since: 3.0.0
1036  */
1037 void
ags_effect_bridge_buffer_size_changed(AgsEffectBridge * effect_bridge,guint buffer_size,guint old_buffer_size)1038 ags_effect_bridge_buffer_size_changed(AgsEffectBridge *effect_bridge,
1039 				      guint buffer_size, guint old_buffer_size)
1040 {
1041   g_return_if_fail(AGS_IS_EFFECT_BRIDGE(effect_bridge));
1042 
1043   g_object_ref((GObject *) effect_bridge);
1044   g_signal_emit(G_OBJECT(effect_bridge),
1045 		effect_bridge_signals[BUFFER_SIZE_CHANGED], 0,
1046 		buffer_size,
1047 		old_buffer_size);
1048   g_object_unref((GObject *) effect_bridge);
1049 }
1050 
1051 /**
1052  * ags_effect_bridge_format_changed:
1053  * @effect_bridge: the #AgsEffectBridge
1054  * @format: the format
1055  * @old_format: the old format
1056  *
1057  * Notify about format changed.
1058  *
1059  * Since: 3.0.0
1060  */
1061 void
ags_effect_bridge_format_changed(AgsEffectBridge * effect_bridge,guint format,guint old_format)1062 ags_effect_bridge_format_changed(AgsEffectBridge *effect_bridge,
1063 				 guint format, guint old_format)
1064 {
1065   g_return_if_fail(AGS_IS_EFFECT_BRIDGE(effect_bridge));
1066 
1067   g_object_ref((GObject *) effect_bridge);
1068   g_signal_emit(G_OBJECT(effect_bridge),
1069 		effect_bridge_signals[FORMAT_CHANGED], 0,
1070 		format,
1071 		old_format);
1072   g_object_unref((GObject *) effect_bridge);
1073 }
1074 
1075 void
ags_effect_bridge_real_resize_audio_channels(AgsEffectBridge * effect_bridge,guint new_size,guint old_size)1076 ags_effect_bridge_real_resize_audio_channels(AgsEffectBridge *effect_bridge,
1077 					     guint new_size,
1078 					     guint old_size)
1079 {
1080   AgsAudio *audio;
1081 
1082   GList *start_list, *list;
1083 
1084   audio = effect_bridge->audio;
1085 
1086   if(audio == NULL ||
1087      new_size == old_size){
1088     return;
1089   }
1090 
1091   /* output */
1092   if(effect_bridge->output != NULL){
1093     list =
1094       start_list = gtk_container_get_children((GtkContainer *) effect_bridge->output);
1095 
1096     while(list != NULL){
1097       ags_effect_pad_resize_lines(AGS_EFFECT_PAD(list->data), effect_bridge->output_line_type,
1098 				  new_size, old_size);
1099 
1100       list = list->next;
1101     }
1102 
1103     g_list_free(start_list);
1104   }
1105 
1106   /* input */
1107   if(effect_bridge->input != NULL){
1108     list =
1109       start_list = gtk_container_get_children((GtkContainer *) effect_bridge->input);
1110 
1111     while(list != NULL){
1112       ags_effect_pad_resize_lines(AGS_EFFECT_PAD(list->data), effect_bridge->input_line_type,
1113 				  new_size, old_size);
1114 
1115       list = list->next;
1116     }
1117 
1118     g_list_free(start_list);
1119   }
1120 
1121   effect_bridge->audio_channels = new_size;
1122 }
1123 
1124 /**
1125  * ags_effect_bridge_resize_audio_channels:
1126  * @effect_bridge: the #AgsEffectBridge
1127  * @new_size: new allocation
1128  * @old_size: old allocation
1129  *
1130  * Resize audio channel allocation.
1131  *
1132  * Since: 3.0.0
1133  */
1134 void
ags_effect_bridge_resize_audio_channels(AgsEffectBridge * effect_bridge,guint new_size,guint old_size)1135 ags_effect_bridge_resize_audio_channels(AgsEffectBridge *effect_bridge,
1136 					guint new_size,
1137 					guint old_size)
1138 {
1139   g_return_if_fail(AGS_IS_EFFECT_BRIDGE(effect_bridge));
1140 
1141   g_object_ref((GObject *) effect_bridge);
1142   g_signal_emit(G_OBJECT(effect_bridge),
1143 		effect_bridge_signals[RESIZE_AUDIO_CHANNELS], 0,
1144 		new_size,
1145 		old_size);
1146   g_object_unref((GObject *) effect_bridge);
1147 }
1148 
1149 void
ags_effect_bridge_real_resize_pads(AgsEffectBridge * effect_bridge,GType channel_type,guint new_size,guint old_size)1150 ags_effect_bridge_real_resize_pads(AgsEffectBridge *effect_bridge,
1151 				   GType channel_type,
1152 				   guint new_size,
1153 				   guint old_size)
1154 {
1155   AgsEffectPad *effect_pad;
1156 
1157   AgsAudio *audio;
1158   AgsChannel *start_output, *start_input;
1159   AgsChannel *current;
1160 
1161   guint audio_channels;
1162   guint audio_audio_channels;
1163   guint audio_input_pads, audio_output_pads;
1164   guint i;
1165 
1166   audio = effect_bridge->audio;
1167 
1168   if(audio == NULL){
1169     return;
1170   }
1171 
1172   audio_channels = effect_bridge->audio_channels;
1173 
1174   start_output = NULL;
1175   start_input = NULL;
1176 
1177   audio_audio_channels = 0;
1178 
1179   audio_input_pads = 0;
1180   audio_output_pads = 0;
1181 
1182   if(audio != NULL){
1183     g_object_get(audio,
1184 		 "output", &start_output,
1185 		 "input", &start_input,
1186 		 "audio-channels", &audio_audio_channels,
1187 		 "input-pads", &audio_input_pads,
1188 		 "output-pads", &audio_output_pads,
1189 		 NULL);
1190   }
1191 
1192   if(new_size > old_size){
1193     for(i = old_size; i < new_size; i++){
1194       if(g_type_is_a(channel_type, AGS_TYPE_OUTPUT)){
1195 	if(audio_audio_channels > 0 &&
1196 	   i < new_size){
1197 	  current = ags_channel_nth(start_output, i * audio_audio_channels);
1198 	}else{
1199 	  current = NULL;
1200 	}
1201 
1202 	if(effect_bridge->output_pad_type != G_TYPE_NONE){
1203 	  effect_pad = g_object_new(effect_bridge->output_pad_type,
1204 				    "channel", current,
1205 				    NULL);
1206 	  ags_effect_pad_resize_lines(effect_pad, effect_bridge->output_line_type,
1207 				      audio_channels, 0);
1208 	  gtk_container_add((GtkContainer *) effect_bridge->output,
1209 			    GTK_WIDGET(effect_pad));
1210 	}
1211       }else{
1212 	if(audio_audio_channels > 0 &&
1213 	   i < audio_input_pads){
1214 	  current = ags_channel_nth(start_input, i * audio_audio_channels);
1215 	}else{
1216 	  current = NULL;
1217 	}
1218 
1219 	if(effect_bridge->input_pad_type != G_TYPE_NONE){
1220 	  effect_pad = g_object_new(effect_bridge->input_pad_type,
1221 				    "channel", current,
1222 				    NULL);
1223 	  ags_effect_pad_resize_lines(effect_pad, effect_bridge->input_line_type,
1224 				      audio_channels, 0);
1225 	  gtk_container_add((GtkContainer *) effect_bridge->input,
1226 			    GTK_WIDGET(effect_pad));
1227 	}
1228       }
1229     }
1230 
1231     if(start_output != NULL){
1232       g_object_unref(start_output);
1233     }
1234 
1235     if(start_input != NULL){
1236       g_object_unref(start_input);
1237     }
1238 
1239     /* connect and show */
1240     if((AGS_EFFECT_BRIDGE_CONNECTED & (effect_bridge->flags)) != 0){
1241       GtkContainer *container;
1242 
1243       GList *start_list, *list;
1244 
1245       container = (GtkContainer *) ((channel_type == AGS_TYPE_OUTPUT) ? effect_bridge->output: effect_bridge->input);
1246 
1247       if(container != NULL){
1248 	start_list = gtk_container_get_children(container);
1249 	list = g_list_nth(start_list,
1250 			  old_size);
1251 
1252 	while(list != NULL){
1253 	  ags_connectable_connect(AGS_CONNECTABLE(list->data));
1254 	  gtk_widget_show_all(list->data);
1255 
1256 	  list = list->next;
1257 	}
1258 
1259 	g_list_free(start_list);
1260       }
1261     }
1262   }else{
1263     GList *start_list, *list;
1264 
1265     list =
1266       start_list = NULL;
1267 
1268     if(channel_type == AGS_TYPE_OUTPUT){
1269       if(effect_bridge->output != NULL){
1270 	start_list = gtk_container_get_children((GtkContainer *) effect_bridge->output);
1271 	list = g_list_nth(start_list,
1272 			  new_size);
1273       }
1274     }else{
1275       if(effect_bridge->input != NULL){
1276 	start_list = gtk_container_get_children((GtkContainer *) effect_bridge->input);
1277 	list = g_list_nth(start_list,
1278 			  new_size);
1279       }
1280     }
1281 
1282     for(i = 0; list != NULL && i < new_size - old_size; i++){
1283       gtk_widget_destroy(list->data);
1284 
1285       list = list->next;
1286     }
1287 
1288     g_list_free(start_list);
1289   }
1290 
1291   if(start_output != NULL){
1292     g_object_unref(start_output);
1293   }
1294 
1295   if(start_input != NULL){
1296     g_object_unref(start_input);
1297   }
1298 
1299   if(g_type_is_a(channel_type, AGS_TYPE_OUTPUT)){
1300     effect_bridge->output_pads = new_size;
1301   }else{
1302     effect_bridge->input_pads = new_size;
1303   }
1304 }
1305 
1306 /**
1307  * ags_effect_bridge_resize_pads:
1308  * @effect_bridge: the #AgsEffectBridge
1309  * @channel_type: the channel #GType
1310  * @new_size: new allocation
1311  * @old_size: old allocation
1312  *
1313  * Resize pad allocation.
1314  *
1315  * Since: 3.0.0
1316  */
1317 void
ags_effect_bridge_resize_pads(AgsEffectBridge * effect_bridge,GType channel_type,guint new_size,guint old_size)1318 ags_effect_bridge_resize_pads(AgsEffectBridge *effect_bridge,
1319 			      GType channel_type,
1320 			      guint new_size,
1321 			      guint old_size)
1322 {
1323   g_return_if_fail(AGS_IS_EFFECT_BRIDGE(effect_bridge));
1324 
1325   g_object_ref((GObject *) effect_bridge);
1326   g_signal_emit(G_OBJECT(effect_bridge),
1327 		effect_bridge_signals[RESIZE_PADS], 0,
1328 		channel_type,
1329 		new_size,
1330 		old_size);
1331   g_object_unref((GObject *) effect_bridge);
1332 }
1333 
1334 void
ags_effect_bridge_real_map_recall(AgsEffectBridge * effect_bridge)1335 ags_effect_bridge_real_map_recall(AgsEffectBridge *effect_bridge)
1336 {
1337   if((AGS_EFFECT_BRIDGE_MAPPED_RECALL & (effect_bridge->flags)) != 0){
1338     return;
1339   }
1340 
1341   effect_bridge->flags |= AGS_EFFECT_BRIDGE_MAPPED_RECALL;
1342 
1343   ags_effect_bridge_find_port(effect_bridge);
1344 }
1345 
1346 /**
1347  * ags_effect_bridge_map_recall:
1348  * @effect_bridge: the #AgsEffectBridge to add its default recall.
1349  *
1350  * You may want the @effect_bridge to add its default recall.
1351  *
1352  * Since: 3.0.0
1353  */
1354 void
ags_effect_bridge_map_recall(AgsEffectBridge * effect_bridge)1355 ags_effect_bridge_map_recall(AgsEffectBridge *effect_bridge)
1356 {
1357   g_return_if_fail(AGS_IS_EFFECT_BRIDGE(effect_bridge));
1358 
1359   g_object_ref((GObject *) effect_bridge);
1360   g_signal_emit((GObject *) effect_bridge,
1361 		effect_bridge_signals[MAP_RECALL], 0);
1362   g_object_unref((GObject *) effect_bridge);
1363 }
1364 
1365 GList*
ags_effect_bridge_real_find_port(AgsEffectBridge * effect_bridge)1366 ags_effect_bridge_real_find_port(AgsEffectBridge *effect_bridge)
1367 {
1368   GList *effect_pad, *effect_pad_start;
1369 
1370   GList *port, *tmp_port;
1371 
1372   port = NULL;
1373 
1374   /* find output ports */
1375   if(effect_bridge->output != NULL){
1376     effect_pad_start =
1377       effect_pad = gtk_container_get_children((GtkContainer *) effect_bridge->output);
1378 
1379     while(effect_pad != NULL){
1380       tmp_port = ags_effect_pad_find_port(AGS_EFFECT_PAD(effect_pad->data));
1381 
1382       if(port != NULL){
1383 	port = g_list_concat(port,
1384 			     tmp_port);
1385       }else{
1386 	port = tmp_port;
1387       }
1388 
1389       effect_pad = effect_pad->next;
1390     }
1391 
1392     g_list_free(effect_pad_start);
1393   }
1394 
1395   /* find input ports */
1396   if(effect_bridge->input != NULL){
1397     effect_pad_start =
1398       effect_pad = gtk_container_get_children((GtkContainer *) effect_bridge->input);
1399 
1400     while(effect_pad != NULL){
1401       tmp_port = ags_effect_pad_find_port(AGS_EFFECT_PAD(effect_pad->data));
1402 
1403       if(port != NULL){
1404 	port = g_list_concat(port,
1405 			     tmp_port);
1406       }else{
1407 	port = tmp_port;
1408       }
1409 
1410       effect_pad = effect_pad->next;
1411     }
1412 
1413     g_list_free(effect_pad_start);
1414   }
1415 
1416   /* find output bulk ports */
1417   if(effect_bridge->bulk_output != NULL){
1418     tmp_port = ags_effect_bulk_find_port((AgsEffectBulk *) effect_bridge->bulk_output);
1419 
1420     if(port != NULL){
1421       port = g_list_concat(port,
1422 			   tmp_port);
1423     }else{
1424       port = tmp_port;
1425     }
1426   }
1427 
1428   /* find input bulk ports */
1429   if(effect_bridge->bulk_output != NULL){
1430     tmp_port = ags_effect_bulk_find_port((AgsEffectBulk *) effect_bridge->bulk_output);
1431 
1432     if(port != NULL){
1433       port = g_list_concat(port,
1434 			   tmp_port);
1435     }else{
1436       port = tmp_port;
1437     }
1438   }
1439 
1440   return(port);
1441 }
1442 
1443 /**
1444  * ags_effect_bridge_find_port:
1445  * @effect_bridge: the #AgsEffectBridge
1446  * Returns: an #GList containing all related #AgsPort
1447  *
1448  * Lookup ports of associated recalls.
1449  *
1450  * Since: 3.0.0
1451  */
1452 GList*
ags_effect_bridge_find_port(AgsEffectBridge * effect_bridge)1453 ags_effect_bridge_find_port(AgsEffectBridge *effect_bridge)
1454 {
1455   GList *list;
1456 
1457   list = NULL;
1458   g_return_val_if_fail(AGS_IS_EFFECT_BRIDGE(effect_bridge),
1459 		       NULL);
1460 
1461   g_object_ref((GObject *) effect_bridge);
1462   g_signal_emit((GObject *) effect_bridge,
1463 		effect_bridge_signals[FIND_PORT], 0,
1464 		&list);
1465   g_object_unref((GObject *) effect_bridge);
1466 
1467   return(list);
1468 }
1469 
1470 /**
1471  * ags_effect_bridge_new:
1472  * @audio: the #AgsAudio to visualize
1473  *
1474  * Creates an #AgsEffectBridge
1475  *
1476  * Returns: a new #AgsEffectBridge
1477  *
1478  * Since: 3.0.0
1479  */
1480 AgsEffectBridge*
ags_effect_bridge_new(AgsAudio * audio)1481 ags_effect_bridge_new(AgsAudio *audio)
1482 {
1483   AgsEffectBridge *effect_bridge;
1484 
1485   effect_bridge = (AgsEffectBridge *) g_object_new(AGS_TYPE_EFFECT_BRIDGE,
1486 						   "audio", audio,
1487 						   NULL);
1488 
1489   return(effect_bridge);
1490 }
1491