1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2021 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSequencer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/audio/ags_recall_channel_run.h>
21 
22 #include <ags/audio/ags_audio.h>
23 #include <ags/audio/ags_channel.h>
24 #include <ags/audio/ags_recycling.h>
25 #include <ags/audio/ags_recall_id.h>
26 #include <ags/audio/ags_recycling_context.h>
27 #include <ags/audio/ags_recall_audio.h>
28 #include <ags/audio/ags_recall_audio_run.h>
29 #include <ags/audio/ags_recall_channel.h>
30 #include <ags/audio/ags_recall_container.h>
31 #include <ags/audio/ags_recall_recycling.h>
32 
33 #include <ags/i18n.h>
34 
35 void ags_recall_channel_run_class_init(AgsRecallChannelRunClass *recall_channel_run);
36 void ags_recall_channel_run_connectable_interface_init(AgsConnectableInterface *connectable);
37 void ags_recall_channel_run_init(AgsRecallChannelRun *recall_channel_run);
38 void ags_recall_channel_run_set_property(GObject *gobject,
39 					 guint prop_id,
40 					 const GValue *value,
41 					 GParamSpec *param_spec);
42 void ags_recall_channel_run_get_property(GObject *gobject,
43 					 guint prop_id,
44 					 GValue *value,
45 					 GParamSpec *param_spec);
46 void ags_recall_channel_run_dispose(GObject *gobject);
47 void ags_recall_channel_run_finalize(GObject *gobject);
48 
49 void ags_recall_channel_run_notify_recall_container_callback(GObject *gobject,
50 							     GParamSpec *pspec,
51 							     gpointer user_data);
52 
53 void ags_recall_channel_run_connect(AgsConnectable *connectable);
54 void ags_recall_channel_run_disconnect(AgsConnectable *connectable);
55 
56 AgsRecall* ags_recall_channel_run_duplicate(AgsRecall *recall,
57 					    AgsRecallID *recall_id,
58 					    guint *n_params, gchar **parameter_name, GValue *value);
59 
60 void ags_recall_channel_run_map_recall_recycling(AgsRecallChannelRun *recall_channel_run);
61 
62 void ags_recall_channel_run_remap_child_source(AgsRecallChannelRun *recall_channel_run,
63 					       AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
64 					       AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region);
65 void ags_recall_channel_run_remap_child_destination(AgsRecallChannelRun *recall_channel_run,
66 						    AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
67 						    AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region);
68 void ags_recall_channel_run_source_recycling_changed_callback(AgsChannel *channel,
69 							      AgsRecycling *old_start_region, AgsRecycling *old_end_region,
70 							      AgsRecycling *new_start_region, AgsRecycling *new_end_region,
71 							      AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
72 							      AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region,
73 							      AgsRecallChannelRun *recall_channel_run);
74 
75 void ags_recall_channel_run_destination_recycling_changed_callback(AgsChannel *channel,
76 								   AgsRecycling *old_start_region, AgsRecycling *old_end_region,
77 								   AgsRecycling *new_start_region, AgsRecycling *new_end_region,
78 								   AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
79 								   AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region,
80 								   AgsRecallChannelRun *recall_channel_run);
81 
82 /**
83  * SECTION:ags_recall_channel_run
84  * @short_description: dynamic channel context of recall
85  * @title: AgsRecallChannelRun
86  * @section_id:
87  * @include: ags/audio/ags_recall_channel_run.h
88  *
89  * #AgsRecallChannelRun acts as channel recall run.
90  */
91 
92 enum{
93   PROP_0,
94   PROP_RECALL_AUDIO,
95   PROP_RECALL_AUDIO_RUN,
96   PROP_RECALL_CHANNEL,
97   PROP_DESTINATION,
98   PROP_SOURCE,
99 };
100 
101 static gpointer ags_recall_channel_run_parent_class = NULL;
102 static AgsConnectableInterface* ags_recall_channel_run_parent_connectable_interface;
103 
104 GType
ags_recall_channel_run_get_type()105 ags_recall_channel_run_get_type()
106 {
107   static volatile gsize g_define_type_id__volatile = 0;
108 
109   if(g_once_init_enter (&g_define_type_id__volatile)){
110     GType ags_type_recall_channel_run = 0;
111 
112     static const GTypeInfo ags_recall_channel_run_info = {
113       sizeof (AgsRecallChannelRunClass),
114       NULL, /* base_init */
115       NULL, /* base_finalize */
116       (GClassInitFunc) ags_recall_channel_run_class_init,
117       NULL, /* class_finalize */
118       NULL, /* class_data */
119       sizeof (AgsRecallChannelRun),
120       0,    /* n_preallocs */
121       (GInstanceInitFunc) ags_recall_channel_run_init,
122     };
123 
124     static const GInterfaceInfo ags_connectable_interface_info = {
125       (GInterfaceInitFunc) ags_recall_channel_run_connectable_interface_init,
126       NULL, /* interface_finalize */
127       NULL, /* interface_data */
128     };
129 
130     ags_type_recall_channel_run = g_type_register_static(AGS_TYPE_RECALL,
131 							 "AgsRecallChannelRun",
132 							 &ags_recall_channel_run_info,
133 							 0);
134 
135     g_type_add_interface_static(ags_type_recall_channel_run,
136 				AGS_TYPE_CONNECTABLE,
137 				&ags_connectable_interface_info);
138 
139     g_once_init_leave(&g_define_type_id__volatile, ags_type_recall_channel_run);
140   }
141 
142   return g_define_type_id__volatile;
143 }
144 
145 void
ags_recall_channel_run_class_init(AgsRecallChannelRunClass * recall_channel_run)146 ags_recall_channel_run_class_init(AgsRecallChannelRunClass *recall_channel_run)
147 {
148   GObjectClass *gobject;
149   AgsRecallClass *recall;
150   GParamSpec *param_spec;
151 
152   ags_recall_channel_run_parent_class = g_type_class_peek_parent(recall_channel_run);
153 
154   /* GObjectClass */
155   gobject = (GObjectClass *) recall_channel_run;
156 
157   gobject->set_property = ags_recall_channel_run_set_property;
158   gobject->get_property = ags_recall_channel_run_get_property;
159 
160   gobject->dispose = ags_recall_channel_run_dispose;
161   gobject->finalize = ags_recall_channel_run_finalize;
162 
163   /* properties */
164   /**
165    * AgsRecallChannelRun:recall-audio:
166    *
167    * The audio context of this recall.
168    *
169    * Since: 3.0.0
170    */
171   param_spec = g_param_spec_object("recall-audio",
172 				   i18n_pspec("AgsRecallAudio of this recall"),
173 				   i18n_pspec("The AgsRecallAudio which this recall needs"),
174 				   AGS_TYPE_RECALL_AUDIO,
175 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
176   g_object_class_install_property(gobject,
177 				  PROP_RECALL_AUDIO,
178 				  param_spec);
179 
180   /**
181    * AgsRecallChannelRun:recall-audio-run:
182    *
183    * The audio run context of this recall.
184    *
185    * Since: 3.0.0
186    */
187   param_spec = g_param_spec_object("recall-audio-run",
188 				   i18n_pspec("AgsRecallAudioRun of this recall"),
189 				   i18n_pspec("The AgsRecallAudioRun which this recall needs"),
190 				   AGS_TYPE_RECALL_AUDIO_RUN,
191 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
192   g_object_class_install_property(gobject,
193 				  PROP_RECALL_AUDIO_RUN,
194 				  param_spec);
195 
196   /**
197    * AgsRecallChannelRun:recall-channel:
198    *
199    * The channel context of this recall.
200    *
201    * Since: 3.0.0
202    */
203   param_spec = g_param_spec_object("recall-channel",
204 				   i18n_pspec("AsgRecallChannel of this recall"),
205 				   i18n_pspec("The AgsRecallChannel which this recall needs"),
206 				   AGS_TYPE_RECALL_CHANNEL,
207 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
208   g_object_class_install_property(gobject,
209 				  PROP_RECALL_CHANNEL,
210 				  param_spec);
211 
212   /**
213    * AgsRecallChannelRun:destination:
214    *
215    * The channel to do output to.
216    *
217    * Since: 3.0.0
218    */
219   param_spec = g_param_spec_object("destination",
220 				   i18n_pspec("destination of output"),
221 				   i18n_pspec("The destination AgsChannel where it will output to"),
222 				   AGS_TYPE_CHANNEL,
223 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
224   g_object_class_install_property(gobject,
225 				  PROP_DESTINATION,
226 				  param_spec);
227 
228   /**
229    * AgsRecallChannelRun:source:
230    *
231    * The channel to do input from.
232    *
233    * Since: 3.0.0
234    */
235   param_spec = g_param_spec_object("source",
236 				   i18n_pspec("source of input"),
237 				   i18n_pspec("The source AgsChannel where it will take the input from"),
238 				   AGS_TYPE_CHANNEL,
239 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
240   g_object_class_install_property(gobject,
241 				  PROP_SOURCE,
242 				  param_spec);
243 
244   /* AgsRecallClass */
245   recall = (AgsRecallClass *) recall_channel_run;
246 
247   recall->duplicate = ags_recall_channel_run_duplicate;
248 }
249 
250 void
ags_recall_channel_run_connectable_interface_init(AgsConnectableInterface * connectable)251 ags_recall_channel_run_connectable_interface_init(AgsConnectableInterface *connectable)
252 {
253   ags_recall_channel_run_parent_connectable_interface = g_type_interface_peek_parent(connectable);
254 
255   connectable->connect = ags_recall_channel_run_connect;
256   connectable->disconnect = ags_recall_channel_run_disconnect;
257 }
258 
259 void
ags_recall_channel_run_init(AgsRecallChannelRun * recall_channel_run)260 ags_recall_channel_run_init(AgsRecallChannelRun *recall_channel_run)
261 {
262   g_signal_connect_after(recall_channel_run, "notify::recall-container",
263 			 G_CALLBACK(ags_recall_channel_run_notify_recall_container_callback), NULL);
264 
265   recall_channel_run->recall_audio = NULL;
266   recall_channel_run->recall_audio_run = NULL;
267   recall_channel_run->recall_channel = NULL;
268 
269   recall_channel_run->source = NULL;
270   recall_channel_run->destination = NULL;
271 }
272 
273 
274 void
ags_recall_channel_run_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)275 ags_recall_channel_run_set_property(GObject *gobject,
276 				    guint prop_id,
277 				    const GValue *value,
278 				    GParamSpec *param_spec)
279 {
280   AgsRecallChannelRun *recall_channel_run;
281 
282   GRecMutex *recall_mutex;
283 
284   recall_channel_run = AGS_RECALL_CHANNEL_RUN(gobject);
285 
286   /* get recall mutex */
287   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall_channel_run);
288 
289   switch(prop_id){
290   case PROP_RECALL_AUDIO:
291     {
292       AgsRecallAudio *recall_audio;
293 
294       recall_audio = (AgsRecallAudio *) g_value_get_object(value);
295 
296       g_rec_mutex_lock(recall_mutex);
297 
298       if(recall_channel_run->recall_audio == recall_audio){
299 	g_rec_mutex_unlock(recall_mutex);
300 
301 	return;
302       }
303 
304       if(recall_channel_run->recall_audio != NULL){
305 	g_object_unref(recall_channel_run->recall_audio);
306       }
307 
308       if(recall_audio != NULL){
309 	g_object_ref(G_OBJECT(recall_audio));
310       }
311 
312       recall_channel_run->recall_audio = recall_audio;
313 
314       g_rec_mutex_unlock(recall_mutex);
315     }
316     break;
317   case PROP_RECALL_AUDIO_RUN:
318     {
319       AgsRecallAudioRun *recall_audio_run;
320 
321       recall_audio_run = (AgsRecallAudioRun *) g_value_get_object(value);
322 
323       g_rec_mutex_lock(recall_mutex);
324 
325       if(recall_channel_run->recall_audio_run == recall_audio_run){
326 	g_rec_mutex_unlock(recall_mutex);
327 
328 	return;
329       }
330 
331       if(recall_channel_run->recall_audio_run != NULL){
332 	g_object_unref(recall_channel_run->recall_audio_run);
333       }
334 
335       if(recall_audio_run != NULL){
336 	g_object_ref(G_OBJECT(recall_audio_run));
337       }
338 
339       recall_channel_run->recall_audio_run = recall_audio_run;
340 
341       g_rec_mutex_unlock(recall_mutex);
342     }
343     break;
344   case PROP_RECALL_CHANNEL:
345     {
346       AgsRecallChannel *recall_channel;
347 
348       recall_channel = (AgsRecallChannel *) g_value_get_object(value);
349 
350       g_rec_mutex_lock(recall_mutex);
351 
352       if(recall_channel_run->recall_channel == recall_channel){
353 	g_rec_mutex_unlock(recall_mutex);
354 
355 	return;
356       }
357 
358       if(recall_channel_run->recall_channel != NULL){
359 	g_object_unref(recall_channel_run->recall_channel);
360       }
361 
362       if(recall_channel != NULL){
363 	g_object_ref(G_OBJECT(recall_channel));
364       }
365 
366       recall_channel_run->recall_channel = recall_channel;
367 
368       g_rec_mutex_unlock(recall_mutex);
369     }
370     break;
371   case PROP_DESTINATION:
372     {
373       AgsChannel *destination;
374       AgsChannel *old_destination;
375 
376       destination = (AgsChannel *) g_value_get_object(value);
377 
378       g_rec_mutex_lock(recall_mutex);
379 
380       if(recall_channel_run->destination == destination){
381 	g_rec_mutex_unlock(recall_mutex);
382 
383 	return;
384       }
385 
386       old_destination = recall_channel_run->destination;
387 
388       if(destination != NULL){
389 	g_object_ref(G_OBJECT(destination));
390       }
391 
392       recall_channel_run->destination = destination;
393 
394       /* child destination */
395 #if 0
396       if(destination == recall_channel_run->source){
397 	g_warning("destination == recall_channel_run->source");
398       }
399 #endif
400 
401       if(old_destination != NULL){
402 	g_object_unref(G_OBJECT(old_destination));
403       }
404 
405       g_rec_mutex_unlock(recall_mutex);
406     }
407     break;
408   case PROP_SOURCE:
409     {
410       AgsChannel *source;
411       AgsChannel *old_source;
412 
413       source = (AgsChannel *) g_value_get_object(value);
414 
415       g_rec_mutex_lock(recall_mutex);
416 
417       if(recall_channel_run->source == source){
418 	g_rec_mutex_unlock(recall_mutex);
419 
420 	return;
421       }
422 
423       old_source = recall_channel_run->source;
424 
425       if(source != NULL){
426 	g_object_ref(G_OBJECT(source));
427       }
428 
429       recall_channel_run->source = source;
430 
431 #if 0
432       if(source == recall_channel_run->destination){
433 	g_warning("source == recall_channel_run->destination");
434       }
435 #endif
436 
437       if(old_source != NULL){
438 	g_object_unref(G_OBJECT(old_source));
439       }
440 
441       g_rec_mutex_unlock(recall_mutex);
442     }
443     break;
444   default:
445     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
446     break;
447   };
448 }
449 
450 void
ags_recall_channel_run_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)451 ags_recall_channel_run_get_property(GObject *gobject,
452 				    guint prop_id,
453 				    GValue *value,
454 				    GParamSpec *param_spec)
455 {
456   AgsRecallChannelRun *recall_channel_run;
457 
458   GRecMutex *recall_mutex;
459 
460   recall_channel_run = AGS_RECALL_CHANNEL_RUN(gobject);
461 
462   /* get recall mutex */
463   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall_channel_run);
464 
465   switch(prop_id){
466   case PROP_RECALL_AUDIO:
467     {
468       g_rec_mutex_lock(recall_mutex);
469 
470       g_value_set_object(value, recall_channel_run->recall_audio);
471 
472       g_rec_mutex_unlock(recall_mutex);
473     }
474     break;
475   case PROP_RECALL_AUDIO_RUN:
476     {
477       g_rec_mutex_lock(recall_mutex);
478 
479       g_value_set_object(value, recall_channel_run->recall_audio_run);
480 
481       g_rec_mutex_unlock(recall_mutex);
482     }
483     break;
484   case PROP_RECALL_CHANNEL:
485     {
486       g_rec_mutex_lock(recall_mutex);
487 
488       g_value_set_object(value, recall_channel_run->recall_channel);
489 
490       g_rec_mutex_unlock(recall_mutex);
491     }
492     break;
493   case PROP_DESTINATION:
494     {
495       g_rec_mutex_lock(recall_mutex);
496 
497       g_value_set_object(value, recall_channel_run->destination);
498 
499       g_rec_mutex_unlock(recall_mutex);
500     }
501     break;
502   case PROP_SOURCE:
503     {
504       g_rec_mutex_lock(recall_mutex);
505 
506       g_value_set_object(value, recall_channel_run->source);
507 
508       g_rec_mutex_unlock(recall_mutex);
509     }
510     break;
511   default:
512     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
513     break;
514   };
515 }
516 
517 void
ags_recall_channel_run_dispose(GObject * gobject)518 ags_recall_channel_run_dispose(GObject *gobject)
519 {
520   AgsRecallChannelRun *recall_channel_run;
521 
522   recall_channel_run = AGS_RECALL_CHANNEL_RUN(gobject);
523 
524   /* recall audio */
525   if(recall_channel_run->recall_audio != NULL){
526     gpointer tmp;
527 
528     tmp = recall_channel_run->recall_audio;
529 
530     recall_channel_run->recall_audio = NULL;
531 
532     g_object_unref(tmp);
533   }
534 
535   /* recall audio run */
536   if(recall_channel_run->recall_audio_run != NULL){
537     gpointer tmp;
538 
539     tmp = recall_channel_run->recall_audio_run;
540 
541     recall_channel_run->recall_audio_run = NULL;
542 
543     g_object_unref(tmp);
544   }
545 
546   /* recall channel */
547   if(recall_channel_run->recall_channel != NULL){
548     gpointer tmp;
549 
550     tmp = recall_channel_run->recall_channel;
551 
552     recall_channel_run->recall_channel = NULL;
553 
554     g_object_unref(tmp);
555   }
556 
557   /* destination */
558   if(recall_channel_run->destination != NULL){
559     gpointer tmp;
560 
561     tmp = recall_channel_run->destination;
562 
563     recall_channel_run->destination = NULL;
564 
565     g_object_unref(tmp);
566   }
567 
568   /* source */
569   if(recall_channel_run->source != NULL){
570     gpointer tmp;
571 
572     tmp = recall_channel_run->source;
573 
574     recall_channel_run->source = NULL;
575 
576     g_object_unref(tmp);
577   }
578 
579   /* call parent */
580   G_OBJECT_CLASS(ags_recall_channel_run_parent_class)->dispose(gobject);
581 }
582 
583 void
ags_recall_channel_run_finalize(GObject * gobject)584 ags_recall_channel_run_finalize(GObject *gobject)
585 {
586   AgsRecallChannelRun *recall_channel_run;
587 
588   recall_channel_run = AGS_RECALL_CHANNEL_RUN(gobject);
589 
590   /* recall audio */
591   if(recall_channel_run->recall_audio != NULL){
592     gpointer tmp;
593 
594     tmp = recall_channel_run->recall_audio;
595 
596     recall_channel_run->recall_audio = NULL;
597 
598     g_object_unref(G_OBJECT(recall_channel_run->recall_audio));
599   }
600 
601   /* recall audio run */
602   if(recall_channel_run->recall_audio_run != NULL){
603     gpointer tmp;
604 
605     tmp = recall_channel_run->recall_audio_run;
606 
607     recall_channel_run->recall_audio_run = NULL;
608 
609     g_object_unref(G_OBJECT(recall_channel_run->recall_audio_run));
610   }
611 
612   /* recall channel */
613   if(recall_channel_run->recall_channel != NULL){
614     gpointer tmp;
615 
616     tmp = recall_channel_run->recall_channel;
617 
618     recall_channel_run->recall_channel = NULL;
619 
620     g_object_unref(G_OBJECT(recall_channel_run->recall_channel));
621   }
622 
623   /* destination */
624   if(recall_channel_run->destination != NULL){
625     gpointer tmp;
626 
627     tmp = recall_channel_run->destination;
628 
629     recall_channel_run->destination = NULL;
630 
631     g_object_unref(recall_channel_run->destination);
632   }
633 
634   /* source */
635   if(recall_channel_run->source != NULL){
636     gpointer tmp;
637 
638     tmp = recall_channel_run->source;
639 
640     recall_channel_run->source = NULL;
641 
642     g_object_unref(recall_channel_run->source);
643   }
644 
645   /* call parent */
646   G_OBJECT_CLASS(ags_recall_channel_run_parent_class)->finalize(gobject);
647 }
648 
649 void
ags_recall_channel_run_notify_recall_container_callback(GObject * gobject,GParamSpec * pspec,gpointer user_data)650 ags_recall_channel_run_notify_recall_container_callback(GObject *gobject,
651 							GParamSpec *pspec,
652 							gpointer user_data)
653 {
654   AgsChannel *source;
655   AgsRecallContainer *recall_container;
656   AgsRecallChannelRun *recall_channel_run;
657 
658   recall_channel_run = AGS_RECALL_CHANNEL_RUN(gobject);
659 
660   /* get some fields */
661   g_object_get(recall_channel_run,
662 	       "recall-container", &recall_container,
663 	       NULL);
664 
665   if(recall_container != NULL){
666     AgsRecallAudio *recall_audio;
667     AgsRecallID *recall_id;
668 
669     GList *list_start, *list;
670 
671     g_object_get(recall_channel_run,
672 		 "source", &source,
673 		 "recall-id", &recall_id,
674 		 NULL);
675 
676     /* recall audio */
677     g_object_get(recall_container,
678 		 "recall-audio", &recall_audio,
679 		 NULL);
680 
681     g_object_set(recall_channel_run,
682 		 "recall-audio", recall_audio,
683 		 NULL);
684 
685     /* recall audio run */
686     g_object_get(recall_container,
687 		 "recall-audio-run", &list_start,
688 		 NULL);
689 
690     if(recall_id != NULL){
691       AgsRecyclingContext *recycling_context;
692 
693       g_object_get(recall_id,
694 		   "recycling-context", &recycling_context,
695 		   NULL);
696 
697       if((list = ags_recall_find_recycling_context(list_start,
698 						   (GObject *) recycling_context)) != NULL){
699 	g_object_set(recall_channel_run,
700 		     "recall-audio-run", list->data,
701 		     NULL);
702       }
703 
704       g_object_unref(recycling_context);
705     }else if(ags_recall_test_flags(recall_channel_run, AGS_RECALL_TEMPLATE)){
706       if((list = ags_recall_find_template(list_start)) != NULL){
707 	g_object_set(recall_channel_run,
708 		     "recall-audio-run", list->data,
709 		     NULL);
710       }
711     }
712 
713     g_list_free_full(list_start,
714 		     (GDestroyNotify) g_object_unref);
715 
716     /* recall channel */
717     g_object_get(recall_container,
718 		 "recall-channel", &list_start,
719 		 NULL);
720 
721     if((list = ags_recall_find_provider(list_start,
722 					(GObject *) source)) != NULL){
723       g_object_set(recall_channel_run,
724 		   "recall-channel", list->data,
725 		   NULL);
726     }
727 
728     g_list_free_full(list_start,
729 		     (GDestroyNotify) g_object_unref);
730 
731     if(recall_audio != NULL){
732       g_object_unref(recall_audio);
733     }
734 
735     /* unref */
736     if(source != NULL){
737       g_object_unref(source);
738     }
739 
740     g_object_unref(recall_container);
741 
742     if(recall_id != NULL){
743       g_object_unref(recall_id);
744     }
745   }else{
746     g_object_set(recall_channel_run,
747 		 "recall-audio", NULL,
748 		 "recall-audio-run", NULL,
749 		 "recall-channel", NULL,
750 		 NULL);
751   }
752 }
753 
754 void
ags_recall_channel_run_connect(AgsConnectable * connectable)755 ags_recall_channel_run_connect(AgsConnectable *connectable)
756 {
757   AgsChannel *destination, *source;
758   AgsRecallChannelRun *recall_channel_run;
759 
760   if(ags_connectable_is_connected(connectable)){
761     return;
762   }
763 
764   ags_recall_channel_run_parent_connectable_interface->connect(connectable);
765 
766   /* recall channel run */
767   recall_channel_run = AGS_RECALL_CHANNEL_RUN(connectable);
768 
769   /* get some fields */
770   g_object_get(recall_channel_run,
771 	       "destination", &destination,
772 	       "source", &source,
773 	       NULL);
774 
775   /* destination */
776   if(destination != NULL){
777     g_signal_connect(destination, "recycling-changed",
778 		     G_CALLBACK(ags_recall_channel_run_destination_recycling_changed_callback), recall_channel_run);
779 
780     g_object_unref(destination);
781   }
782 
783   /* source */
784   if(source != NULL){
785     g_signal_connect(source, "recycling-changed",
786 		     G_CALLBACK(ags_recall_channel_run_source_recycling_changed_callback), recall_channel_run);
787 
788     g_object_unref(source);
789   }
790 }
791 
792 void
ags_recall_channel_run_disconnect(AgsConnectable * connectable)793 ags_recall_channel_run_disconnect(AgsConnectable *connectable)
794 {
795   AgsChannel *destination, *source;
796   AgsRecallChannelRun *recall_channel_run;
797 
798   if(!ags_connectable_is_connected(connectable)){
799     return;
800   }
801 
802   ags_recall_channel_run_parent_connectable_interface->disconnect(connectable);
803 
804   /* recall channel run */
805   recall_channel_run = AGS_RECALL_CHANNEL_RUN(connectable);
806 
807   /* get some fields */
808   g_object_get(recall_channel_run,
809 	       "destination", &destination,
810 	       "source", &source,
811 	       NULL);
812 
813   /* destination */
814   if(destination != NULL){
815     g_object_disconnect(destination,
816 			"any_signal::recycling-changed",
817 			G_CALLBACK(ags_recall_channel_run_destination_recycling_changed_callback),
818 			recall_channel_run,
819 			NULL);
820 
821     g_object_unref(destination);
822   }
823 
824   /* source */
825   if(source != NULL){
826     g_object_disconnect(source,
827 			"any_signal::recycling-changed",
828 			G_CALLBACK(ags_recall_channel_run_source_recycling_changed_callback),
829 			recall_channel_run,
830 			NULL);
831 
832     g_object_unref(source);
833   }
834 }
835 
836 AgsRecall*
ags_recall_channel_run_duplicate(AgsRecall * recall,AgsRecallID * recall_id,guint * n_params,gchar ** parameter_name,GValue * value)837 ags_recall_channel_run_duplicate(AgsRecall *recall,
838 				 AgsRecallID *recall_id,
839 				 guint *n_params, gchar **parameter_name, GValue *value)
840 {
841   AgsChannel *destination, *source;
842   AgsRecallAudio *recall_audio;
843   AgsRecallAudioRun *recall_audio_run;
844   AgsRecallChannel *recall_channel;
845   AgsRecallChannelRun *recall_channel_run, *copy_recall_channel_run;
846   AgsRecyclingContext *parent_recycling_context, *recycling_context;
847   AgsRecyclingContext *next_recycling_context;
848 
849   GList *list_start, *list;
850 
851   GRecMutex *recall_mutex;
852 
853   recall_channel_run = AGS_RECALL_CHANNEL_RUN(recall);
854 
855   /* get recall mutex */
856   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
857 
858   /* get some fields */
859   g_rec_mutex_lock(recall_mutex);
860 
861   recall_audio = recall_channel_run->recall_audio;
862   //  recall_audio_run = recall_channel_run->recall_audio_run;
863   recall_channel = recall_channel_run->recall_channel;
864 
865   destination = recall_channel_run->destination;
866   source = recall_channel_run->source;
867 
868   g_rec_mutex_unlock(recall_mutex);
869 
870   next_recycling_context = NULL;
871 
872   if(destination != NULL){
873     g_object_get(destination,
874 		 "recall-id", &list_start,
875 		 NULL);
876 
877     next_recycling_context = (AgsRecyclingContext *) ags_recall_id_find_recycling_context(list_start,
878 											  recall_id->recycling_context->parent);
879     g_list_free_full(list_start,
880 		     (GDestroyNotify) g_object_unref);
881   }
882 
883   if(destination != NULL &&
884      next_recycling_context == NULL){
885     return(NULL);
886   }
887 
888   /* duplicate */
889   copy_recall_channel_run = (AgsRecallChannelRun *) AGS_RECALL_CLASS(ags_recall_channel_run_parent_class)->duplicate(recall,
890 														     recall_id,
891 														     n_params, parameter_name, value);
892   g_object_set(copy_recall_channel_run,
893 	       "recall-audio", recall_audio,
894 	       //	       "recall-audio-run", recall_audio_run,
895 	       "recall-channel", recall_channel,
896 	       "source", source,
897 	       "destination", destination,
898 	       NULL);
899 
900   /* remap */
901   if(destination != NULL){
902     AgsRecycling *first_recycling, *last_recycling;
903 
904     /* get some fields */
905     g_object_get(destination,
906 		 "first-recycling", &first_recycling,
907 		 "last-recycling", &last_recycling,
908 		 NULL);
909 
910     ags_recall_channel_run_remap_child_destination(copy_recall_channel_run,
911 						   NULL, NULL,
912 						   first_recycling, last_recycling);
913 
914     if(first_recycling != NULL){
915       g_object_unref(first_recycling);
916       g_object_unref(last_recycling);
917     }
918   }else if(source != NULL){
919     AgsRecycling *first_recycling, *last_recycling;
920 
921     /* get some fields */
922     g_object_get(source,
923 		 "first-recycling", &first_recycling,
924 		 "last-recycling", &last_recycling,
925 		 NULL);
926 
927     ags_recall_channel_run_remap_child_source(copy_recall_channel_run,
928 					      NULL, NULL,
929 					      first_recycling, last_recycling);
930 
931     if(first_recycling != NULL){
932       g_object_unref(first_recycling);
933       g_object_unref(last_recycling);
934     }
935   }
936 
937   return((AgsRecall *) copy_recall_channel_run);
938 }
939 
940 void
ags_recall_channel_run_map_recall_recycling(AgsRecallChannelRun * recall_channel_run)941 ags_recall_channel_run_map_recall_recycling(AgsRecallChannelRun *recall_channel_run)
942 {
943   AgsChannel *destination, *source;
944   AgsRecycling *destination_first_recycling, *destination_last_recycling;
945   AgsRecycling *destination_recycling, *destination_next_recycling, *destination_end_recycling;
946   AgsRecycling *source_first_recycling, *source_last_recycling;
947   AgsRecycling *source_recycling, *source_next_recycling, *source_end_recycling;
948   AgsRecallID *recall_id;
949 
950   GObject *output_soundcard, *input_soundcard;
951 
952   GType child_type;
953 
954   guint recall_flags;
955   guint ability_flags;
956   guint behaviour_flags;
957   gint sound_scope;
958   gint output_soundcard_channel, input_soundcard_channel;
959   guint samplerate;
960   guint buffer_size;
961   guint format;
962 
963   GRecMutex *recall_mutex;
964 
965   /* get recall mutex */
966   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall_channel_run);
967 
968   /* get some fields */
969   g_object_get(recall_channel_run,
970 	       "destination", &destination,
971 	       "source", &source,
972 	       NULL);
973 
974   g_rec_mutex_lock(recall_mutex);
975 
976   child_type = AGS_RECALL(recall_channel_run)->child_type;
977 
978   g_rec_mutex_unlock(recall_mutex);
979 
980   /* check instantiable child */
981   if(source == NULL ||
982      child_type == G_TYPE_NONE ||
983      ags_recall_test_flags(recall_channel_run, AGS_RECALL_TEMPLATE)){
984     if(destination != NULL){
985       g_object_unref(destination);
986     }
987 
988     if(source != NULL){
989       g_object_unref(source);
990     }
991 
992     return;
993   }
994 
995   /* AgsRecycling - source */
996   g_object_get(source,
997 	       "first-recycling", &source_first_recycling,
998 	       "last-recycling", &source_last_recycling,
999 	       NULL);
1000 
1001   /* AgsRecycling - destination*/
1002   destination_first_recycling = NULL;
1003   destination_last_recycling = NULL;
1004 
1005   if(destination != NULL){
1006     g_object_get(destination,
1007 		 "first-recycling", &destination_first_recycling,
1008 		 "last-recycling", &destination_last_recycling,
1009 		 NULL);
1010   }
1011 
1012   /* map */
1013   if(source_first_recycling != NULL){
1014     /* get some fields */
1015     g_object_get(source_first_recycling,
1016 		 "recall-id", &recall_id,
1017 		 "output-soundcard", &output_soundcard,
1018 		 "input-soundcard", &input_soundcard,
1019 		 NULL);
1020 
1021     g_rec_mutex_lock(recall_mutex);
1022 
1023     ability_flags = AGS_RECALL(recall_channel_run)->ability_flags;
1024     behaviour_flags = AGS_RECALL(recall_channel_run)->behaviour_flags;
1025     sound_scope = AGS_RECALL(recall_channel_run)->sound_scope;
1026 
1027     output_soundcard_channel = AGS_RECALL(recall_channel_run)->output_soundcard_channel;
1028 
1029     input_soundcard_channel = AGS_RECALL(recall_channel_run)->input_soundcard_channel;
1030 
1031     samplerate = AGS_RECALL(recall_channel_run)->samplerate;
1032     buffer_size = AGS_RECALL(recall_channel_run)->buffer_size;
1033     format =  AGS_RECALL(recall_channel_run)->format;
1034 
1035     g_rec_mutex_unlock(recall_mutex);
1036 
1037     /* get end recycling */
1038     source_end_recycling = ags_recycling_next(source_last_recycling);
1039 
1040     /*  */
1041     source_recycling = source_first_recycling;
1042     g_object_ref(source_recycling);
1043 
1044     while(source_recycling != source_end_recycling){
1045 #ifdef AGS_DEBUG
1046       g_message("ags_recall_channel_run_map_recall_recycling %d", source->line);
1047 #endif
1048 
1049       /*  */
1050       destination_recycling = destination_first_recycling;
1051 
1052       if(destination_first_recycling != NULL){
1053 	g_object_ref(destination_recycling);
1054 
1055 	/* get end recycling */
1056 	destination_end_recycling = ags_recycling_next(destination_last_recycling);
1057       }else{
1058 	destination_end_recycling = NULL;
1059       }
1060 
1061       do{
1062 	AgsRecallRecycling *recall_recycling;
1063 
1064 	/* instantiate */
1065 	recall_recycling = g_object_new(child_type,
1066 					"recall-id", recall_id,
1067 					"output-soundcard", output_soundcard,
1068 					"output-soundcard-channel", output_soundcard_channel,
1069 					"input-soundcard", input_soundcard,
1070 					"input-soundcard-channel", input_soundcard_channel,
1071 					"samplerate", samplerate,
1072 					"buffer-size", buffer_size,
1073 					"format", format,
1074 					"source", source_recycling,
1075 					"destination", destination_recycling,
1076 					NULL);
1077 
1078 	ags_recall_set_ability_flags((AgsRecall *) recall_recycling,
1079 				     ability_flags);
1080 	ags_recall_set_behaviour_flags((AgsRecall *) recall_recycling,
1081 				       behaviour_flags);
1082 	ags_recall_set_sound_scope((AgsRecall *) recall_recycling,
1083 				   sound_scope);
1084 
1085 	ags_recall_add_child((AgsRecall *) recall_channel_run,
1086 			     (AgsRecall *) recall_recycling);
1087 
1088 	if(destination_recycling != NULL){
1089 	  /* iterate */
1090 	  destination_next_recycling = ags_recycling_next(destination_recycling);
1091 
1092 	  g_object_unref(destination_recycling);
1093 
1094 	  destination_recycling = destination_next_recycling;
1095 	}
1096       }while(destination_recycling != destination_end_recycling);
1097 
1098       if(destination_recycling != NULL){
1099 	g_object_unref(destination_recycling);
1100       }
1101 
1102       if(destination_end_recycling != NULL){
1103 	g_object_unref(destination_end_recycling);
1104       }
1105 
1106       /* iterate */
1107       source_next_recycling = ags_recycling_next(source_recycling);
1108 
1109       g_object_unref(source_recycling);
1110 
1111       source_recycling = source_next_recycling;
1112     }
1113 
1114     /* unref */
1115     if(recall_id != NULL){
1116       g_object_unref(recall_id);
1117     }
1118 
1119     if(output_soundcard != NULL){
1120       g_object_unref(output_soundcard);
1121     }
1122 
1123      if(input_soundcard != NULL){
1124       g_object_unref(input_soundcard);
1125     }
1126 
1127     if(source_recycling != NULL){
1128       g_object_unref(source_recycling);
1129     }
1130 
1131     if(source_end_recycling != NULL){
1132       g_object_unref(source_end_recycling);
1133     }
1134   }
1135 
1136   /* unref */
1137   if(destination != NULL){
1138     g_object_unref(destination);
1139   }
1140 
1141   if(source != NULL){
1142     g_object_unref(source);
1143   }
1144 
1145   if(destination_first_recycling != NULL){
1146     g_object_unref(destination_first_recycling);
1147     g_object_unref(destination_last_recycling);
1148   }
1149 
1150   if(source_first_recycling != NULL){
1151     g_object_unref(source_first_recycling);
1152     g_object_unref(source_last_recycling);
1153   }
1154 }
1155 
1156 void
ags_recall_channel_run_remap_child_source(AgsRecallChannelRun * recall_channel_run,AgsRecycling * old_start_changed_region,AgsRecycling * old_end_changed_region,AgsRecycling * new_start_changed_region,AgsRecycling * new_end_changed_region)1157 ags_recall_channel_run_remap_child_source(AgsRecallChannelRun *recall_channel_run,
1158 					  AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
1159 					  AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region)
1160 {
1161   AgsChannel *destination, *source;
1162   AgsRecycling *destination_first_recycling;
1163   AgsRecycling *source_recycling, *source_next_recycling, *source_end_recycling;
1164   AgsRecallID *recall_id;
1165 
1166   GObject *output_soundcard, *input_soundcard;
1167 
1168   GList *list_start, *list;
1169 
1170   GType child_type;
1171 
1172   gint output_soundcard_channel, input_soundcard_channel;
1173   guint samplerate;
1174   guint buffer_size;
1175   guint format;
1176 
1177   GRecMutex *recall_mutex;
1178 
1179   /* get recall mutex */
1180   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall_channel_run);
1181 
1182   /* get some fields */
1183   g_object_get(recall_channel_run,
1184 	       "destination", &destination,
1185 	       "source", &source,
1186 	       NULL);
1187 
1188   g_rec_mutex_lock(recall_mutex);
1189 
1190   child_type = AGS_RECALL(recall_channel_run)->child_type;
1191 
1192   g_rec_mutex_unlock(recall_mutex);
1193 
1194   /* check instantiable child */
1195   if(source == NULL ||
1196      child_type == G_TYPE_NONE ||
1197      ags_recall_test_flags(recall_channel_run, AGS_RECALL_TEMPLATE)){
1198     if(destination != NULL){
1199       g_object_unref(destination);
1200     }
1201 
1202     if(source != NULL){
1203       g_object_unref(source);
1204     }
1205 
1206     return;
1207   }
1208 
1209   /* remove old */
1210   if(old_start_changed_region != NULL){
1211     /* get end recycling */
1212     source_end_recycling = ags_recycling_next(old_end_changed_region);
1213 
1214     /*  */
1215     source_recycling = old_start_changed_region;
1216     g_object_ref(source_recycling);
1217 
1218     while(source_recycling != source_end_recycling){
1219       /* get children */
1220       g_object_get(recall_channel_run,
1221 		   "child", &list_start,
1222 		   NULL);
1223 
1224       list = list_start;
1225 
1226       while(list != NULL){
1227 	AgsRecycling *current_source;
1228 	AgsRecall *current_recall;
1229 
1230 	current_recall = AGS_RECALL(list->data);
1231 
1232 	g_object_get(current_recall,
1233 		     "source", &current_source,
1234 		     NULL);
1235 
1236 	if(current_source == source_recycling){
1237 	  ags_recall_cancel(current_recall);
1238 	  ags_recall_remove_child((AgsRecall *) recall_channel_run,
1239 				  (AgsRecall *) current_recall);
1240 
1241 	  ags_connectable_disconnect(AGS_CONNECTABLE(current_recall));
1242 	  g_object_run_dispose((GObject *) current_recall);
1243 	  g_object_unref((GObject *) current_recall);
1244 	}
1245 
1246 	list = list->next;
1247       }
1248 
1249       g_list_free_full(list_start,
1250 		       (GDestroyNotify) g_object_unref);
1251 
1252       /* iterate */
1253       source_next_recycling = ags_recycling_next(source_recycling);
1254 
1255       g_object_unref(source_recycling);
1256 
1257       source_recycling = source_next_recycling;
1258     }
1259 
1260     /* unref */
1261     if(source_recycling != NULL){
1262       g_object_unref(source_recycling);
1263     }
1264 
1265     if(source_end_recycling != NULL){
1266       g_object_unref(source_end_recycling);
1267     }
1268   }
1269 
1270   /* add new */
1271   if(new_start_changed_region != NULL){
1272     /* get some fields */
1273     g_object_get(new_start_changed_region,
1274 		 "output-soundcard", &output_soundcard,
1275 		 "input-soundcard", &input_soundcard,
1276 		 NULL);
1277 
1278     g_object_get(recall_channel_run,
1279       		 "recall-id", &recall_id,
1280 		 NULL);
1281 
1282     g_rec_mutex_lock(recall_mutex);
1283 
1284     output_soundcard_channel = AGS_RECALL(recall_channel_run)->output_soundcard_channel;
1285 
1286     input_soundcard_channel = AGS_RECALL(recall_channel_run)->input_soundcard_channel;
1287 
1288     samplerate = AGS_RECALL(recall_channel_run)->samplerate;
1289     buffer_size = AGS_RECALL(recall_channel_run)->buffer_size;
1290     format =  AGS_RECALL(recall_channel_run)->format;
1291 
1292     g_rec_mutex_unlock(recall_mutex);
1293 
1294     if(destination != NULL){
1295       g_object_get(destination,
1296 		   "first-recycling", &destination_first_recycling,
1297 		   NULL);
1298     }else{
1299       destination_first_recycling = NULL;
1300     }
1301 
1302     /* get end recycling */
1303     source_end_recycling = ags_recycling_next(new_end_changed_region);
1304 
1305     /*  */
1306     source_recycling = new_start_changed_region;
1307     g_object_ref(source_recycling);
1308 
1309     while(source_recycling != source_end_recycling){
1310       AgsRecallRecycling *recall_recycling;
1311 
1312       //      g_message("%s[%d]", G_OBJECT_TYPE_NAME(recall_channel_run), recall_channel_run->source->line);
1313 
1314       recall_recycling = g_object_new(child_type,
1315 				      "recall-id", recall_id,
1316 				      "output-soundcard", output_soundcard,
1317 				      "output-soundcard-channel", output_soundcard_channel,
1318 				      "input-soundcard", input_soundcard,
1319 				      "input-soundcard-channel", input_soundcard_channel,
1320 				      "samplerate", samplerate,
1321 				      "buffer-size", buffer_size,
1322 				      "format", format,
1323 				      "source", source_recycling,
1324 				      "destination", destination_first_recycling,
1325 				      NULL);
1326 
1327       ags_recall_add_child((AgsRecall *) recall_channel_run,
1328 			   (AgsRecall *) recall_recycling);
1329       ags_connectable_connect(AGS_CONNECTABLE(recall_recycling));
1330 
1331       /* iterate */
1332       source_next_recycling = ags_recycling_next(source_recycling);
1333 
1334       g_object_unref(source_recycling);
1335 
1336       source_recycling = source_next_recycling;
1337     }
1338 
1339     /* unref */
1340     if(recall_id != NULL){
1341       g_object_unref(recall_id);
1342     }
1343 
1344     if(output_soundcard != NULL){
1345       g_object_unref(output_soundcard);
1346     }
1347 
1348      if(input_soundcard != NULL){
1349       g_object_unref(input_soundcard);
1350     }
1351 
1352      if(source_recycling != NULL){
1353       g_object_unref(source_recycling);
1354     }
1355 
1356     if(source_end_recycling != NULL){
1357       g_object_unref(source_end_recycling);
1358     }
1359   }
1360 
1361   /* unref */
1362   if(destination != NULL){
1363     g_object_unref(destination);
1364   }
1365 
1366   if(source != NULL){
1367     g_object_unref(source);
1368   }
1369 }
1370 
1371 void
ags_recall_channel_run_remap_child_destination(AgsRecallChannelRun * recall_channel_run,AgsRecycling * old_start_changed_region,AgsRecycling * old_end_changed_region,AgsRecycling * new_start_changed_region,AgsRecycling * new_end_changed_region)1372 ags_recall_channel_run_remap_child_destination(AgsRecallChannelRun *recall_channel_run,
1373 					       AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
1374 					       AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region)
1375 {
1376   AgsChannel *source;
1377   AgsRecycling *destination_first_recycling, *destination_last_recycling;
1378   AgsRecycling *destination_recycling, *destination_next_recycling, *destination_end_recycling;
1379   AgsRecycling *source_first_recycling, *source_last_recycling;
1380   AgsRecycling *source_recycling, *source_next_recycling, *source_end_recycling;
1381   AgsRecallID *recall_id;
1382 
1383   GObject *output_soundcard, *input_soundcard;
1384 
1385   GType child_type;
1386 
1387   gint output_soundcard_channel, input_soundcard_channel;
1388   guint samplerate;
1389   guint buffer_size;
1390   guint format;
1391 
1392   GRecMutex *recall_mutex;
1393 
1394   /* get recall mutex */
1395   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall_channel_run);
1396 
1397   /* get some fields */
1398   g_object_get(recall_channel_run,
1399 	       "source", &source,
1400 	       NULL);
1401 
1402   g_rec_mutex_lock(recall_mutex);
1403 
1404   child_type = AGS_RECALL(recall_channel_run)->child_type;
1405 
1406   g_rec_mutex_unlock(recall_mutex);
1407 
1408   /* check instantiable child */
1409   if(source == NULL ||
1410      child_type == G_TYPE_NONE ||
1411      ags_recall_test_flags(recall_channel_run, AGS_RECALL_TEMPLATE)){
1412     if(source != NULL){
1413       g_object_unref(source);
1414     }
1415 
1416     return;
1417   }
1418 
1419   /* remove old */
1420   if(old_start_changed_region != NULL){
1421     /* get end recycling */
1422     destination_end_recycling = ags_recycling_next(old_end_changed_region);
1423 
1424     /*  */
1425     destination_recycling = old_start_changed_region;
1426     g_object_ref(destination_recycling);
1427 
1428     while(destination_recycling != destination_end_recycling){
1429       GList *list_start, *list;
1430 
1431       /* get children */
1432       g_object_get(recall_channel_run,
1433 		   "child", &list_start,
1434 		   NULL);
1435 
1436       list = list_start;
1437 
1438       while(list != NULL){
1439 	AgsRecycling *current_destination;
1440 	AgsRecall *current_recall;
1441 
1442 	current_recall = AGS_RECALL(list->data);
1443 
1444 	g_object_get(current_recall,
1445 		     "destination", &current_destination,
1446 		     NULL);
1447 
1448 	if(current_destination == destination_recycling){
1449 	  ags_recall_cancel(current_recall);
1450 	  ags_recall_remove_child((AgsRecall *) recall_channel_run,
1451 				  (AgsRecall *) current_recall);
1452 
1453 	  ags_connectable_disconnect(AGS_CONNECTABLE(current_recall));
1454 	  g_object_run_dispose((GObject *) current_recall);
1455 	  g_object_unref((GObject *) current_recall);
1456 	}
1457 
1458 	list = list->next;
1459       }
1460 
1461       g_list_free_full(list_start,
1462 		       (GDestroyNotify) g_object_unref);
1463 
1464       /* iterate */
1465       destination_next_recycling = ags_recycling_next(destination_recycling);
1466 
1467       g_object_unref(destination_recycling);
1468 
1469       destination_recycling = destination_next_recycling;
1470     }
1471 
1472     if(destination_recycling != NULL){
1473       g_object_unref(destination_recycling);
1474     }
1475 
1476     if(destination_end_recycling != NULL){
1477       g_object_unref(destination_end_recycling);
1478     }
1479   }
1480 
1481   /* add new */
1482   if(new_start_changed_region == NULL ||
1483      source == NULL){
1484     return;
1485   }
1486 
1487   g_object_get(source,
1488 	       "first-recycling", &source_first_recycling,
1489 	       "last-recycling", &source_last_recycling,
1490 	       NULL);
1491 
1492   if(source_first_recycling != NULL){
1493     /* get some fields */
1494     g_rec_mutex_lock(recall_mutex);
1495 
1496     recall_id = AGS_RECALL(recall_channel_run)->recall_id;
1497 
1498     output_soundcard = AGS_RECALL(recall_channel_run)->output_soundcard;
1499     output_soundcard_channel = AGS_RECALL(recall_channel_run)->output_soundcard_channel;
1500 
1501     input_soundcard = AGS_RECALL(recall_channel_run)->input_soundcard;
1502     input_soundcard_channel = AGS_RECALL(recall_channel_run)->input_soundcard_channel;
1503 
1504     samplerate = AGS_RECALL(recall_channel_run)->samplerate;
1505     buffer_size = AGS_RECALL(recall_channel_run)->buffer_size;
1506     format =  AGS_RECALL(recall_channel_run)->format;
1507 
1508     g_rec_mutex_unlock(recall_mutex);
1509 
1510     /* get end recycling */
1511     destination_end_recycling = ags_recycling_next(new_end_changed_region);
1512 
1513     /*  */
1514     destination_recycling = new_start_changed_region;
1515     g_object_ref(destination_recycling);
1516 
1517     while(destination_recycling != destination_end_recycling){
1518       /* get end recycling */
1519       source_end_recycling = ags_recycling_next(source_last_recycling);
1520 
1521       /*  */
1522       source_recycling = source_first_recycling;
1523       g_object_ref(source_recycling);
1524 
1525       while(source_recycling != source_end_recycling){
1526 	AgsRecallRecycling *recall_recycling;
1527 
1528 	recall_recycling = g_object_new(child_type,
1529 					"recall-id", recall_id,
1530 					"output-soundcard", output_soundcard,
1531 					"output-soundcard-channel", output_soundcard_channel,
1532 					"input-soundcard", input_soundcard,
1533 					"input-soundcard-channel", input_soundcard_channel,
1534 					"samplerate", samplerate,
1535 					"buffer-size", buffer_size,
1536 					"format", format,
1537 					"source", source_recycling,
1538 					"destination", destination_recycling,
1539 					NULL);
1540 
1541 	ags_recall_add_child(AGS_RECALL(recall_channel_run), AGS_RECALL(recall_recycling));
1542 	ags_connectable_connect(AGS_CONNECTABLE(recall_recycling));
1543 
1544 	/* iterate */
1545 	source_next_recycling = ags_recycling_next(source_recycling);
1546 
1547 	g_object_unref(source_recycling);
1548 
1549 	source_recycling = source_next_recycling;
1550       }
1551 
1552       if(source_recycling != NULL){
1553 	g_object_unref(source_recycling);
1554       }
1555 
1556       /* iterate */
1557       destination_next_recycling = ags_recycling_next(destination_recycling);
1558 
1559       g_object_unref(destination_recycling);
1560 
1561       destination_recycling = destination_next_recycling;
1562     }
1563 
1564     if(destination_recycling != NULL){
1565       g_object_unref(destination_recycling);
1566     }
1567 
1568     if(destination_end_recycling != NULL){
1569       g_object_unref(destination_end_recycling);
1570     }
1571   }
1572 
1573   if(source != NULL){
1574     g_object_unref(source);
1575   }
1576 }
1577 
1578 void
ags_recall_channel_run_source_recycling_changed_callback(AgsChannel * channel,AgsRecycling * old_start_region,AgsRecycling * old_end_region,AgsRecycling * new_start_region,AgsRecycling * new_end_region,AgsRecycling * old_start_changed_region,AgsRecycling * old_end_changed_region,AgsRecycling * new_start_changed_region,AgsRecycling * new_end_changed_region,AgsRecallChannelRun * recall_channel_run)1579 ags_recall_channel_run_source_recycling_changed_callback(AgsChannel *channel,
1580 							 AgsRecycling *old_start_region, AgsRecycling *old_end_region,
1581 							 AgsRecycling *new_start_region, AgsRecycling *new_end_region,
1582 							 AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
1583 							 AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region,
1584 							 AgsRecallChannelRun *recall_channel_run)
1585 {
1586   AgsChannel *destination;
1587 
1588   g_object_get(recall_channel_run,
1589 	       "destination", &destination,
1590 	       NULL);
1591 
1592   if(destination != NULL){
1593     AgsRecycling *first_recycling, *last_recycling;
1594 
1595     g_object_get(destination,
1596 		 "first-recycling", &first_recycling,
1597 		 "last-recycling", &last_recycling,
1598 		 NULL);
1599 
1600     ags_recall_channel_run_remap_child_source(recall_channel_run,
1601 					      NULL, NULL,
1602 					      NULL, NULL);
1603     ags_recall_channel_run_remap_child_destination(recall_channel_run,
1604 						   NULL, NULL,
1605 						   first_recycling, last_recycling);
1606 
1607     if(first_recycling != NULL){
1608       g_object_unref(first_recycling);
1609       g_object_unref(last_recycling);
1610     }
1611   }else{
1612     ags_recall_channel_run_remap_child_source(recall_channel_run,
1613 					      old_start_changed_region, old_end_changed_region,
1614 					      new_start_changed_region, new_end_changed_region);
1615   }
1616 }
1617 
1618 void
ags_recall_channel_run_destination_recycling_changed_callback(AgsChannel * channel,AgsRecycling * old_start_region,AgsRecycling * old_end_region,AgsRecycling * new_start_region,AgsRecycling * new_end_region,AgsRecycling * old_start_changed_region,AgsRecycling * old_end_changed_region,AgsRecycling * new_start_changed_region,AgsRecycling * new_end_changed_region,AgsRecallChannelRun * recall_channel_run)1619 ags_recall_channel_run_destination_recycling_changed_callback(AgsChannel *channel,
1620 							      AgsRecycling *old_start_region, AgsRecycling *old_end_region,
1621 							      AgsRecycling *new_start_region, AgsRecycling *new_end_region,
1622 							      AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
1623 							      AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region,
1624 							      AgsRecallChannelRun *recall_channel_run)
1625 {
1626   /* empty */
1627 }
1628 
1629 /**
1630  * ags_recall_channel_run_get_recall_audio:
1631  * @recall_channel_run: the #AgsRecallChannelRun
1632  *
1633  * Get recall audio.
1634  *
1635  * Returns: (transfer full): the #AgsRecallAudio
1636  *
1637  * Since: 3.1.0
1638  */
1639 AgsRecallAudio*
ags_recall_channel_run_get_recall_audio(AgsRecallChannelRun * recall_channel_run)1640 ags_recall_channel_run_get_recall_audio(AgsRecallChannelRun *recall_channel_run)
1641 {
1642   AgsRecallAudio *recall_audio;
1643 
1644   if(!AGS_IS_RECALL_CHANNEL_RUN(recall_channel_run)){
1645     return(NULL);
1646   }
1647 
1648   g_object_get(recall_channel_run,
1649 	       "recall-audio", &recall_audio,
1650 	       NULL);
1651 
1652   return(recall_audio);
1653 }
1654 
1655 /**
1656  * ags_recall_channel_run_set_recall_audio:
1657  * @recall_channel_run: the #AgsRecallChannelRun
1658  * @recall_audio: the #AgsRecallAudio
1659  *
1660  * Set recall audio.
1661  *
1662  * Since: 3.1.0
1663  */
1664 void
ags_recall_channel_run_set_recall_audio(AgsRecallChannelRun * recall_channel_run,AgsRecallAudio * recall_audio)1665 ags_recall_channel_run_set_recall_audio(AgsRecallChannelRun *recall_channel_run, AgsRecallAudio *recall_audio)
1666 {
1667   if(!AGS_IS_RECALL_CHANNEL_RUN(recall_channel_run)){
1668     return;
1669   }
1670 
1671   g_object_set(recall_channel_run,
1672 	       "recall-audio", recall_audio,
1673 	       NULL);
1674 }
1675 
1676 /**
1677  * ags_recall_channel_run_get_recall_audio_run:
1678  * @recall_channel_run: the #AgsRecallChannelRun
1679  *
1680  * Get recall audio.
1681  *
1682  * Returns: (transfer full): the #AgsRecallAudioRun
1683  *
1684  * Since: 3.1.0
1685  */
1686 AgsRecallAudioRun*
ags_recall_channel_run_get_recall_audio_run(AgsRecallChannelRun * recall_channel_run)1687 ags_recall_channel_run_get_recall_audio_run(AgsRecallChannelRun *recall_channel_run)
1688 {
1689   AgsRecallAudioRun *recall_audio_run;
1690 
1691   if(!AGS_IS_RECALL_CHANNEL_RUN(recall_channel_run)){
1692     return(NULL);
1693   }
1694 
1695   g_object_get(recall_channel_run,
1696 	       "recall-audio-run", &recall_audio_run,
1697 	       NULL);
1698 
1699   return(recall_audio_run);
1700 }
1701 
1702 /**
1703  * ags_recall_channel_run_set_recall_audio_run:
1704  * @recall_channel_run: the #AgsRecallChannelRun
1705  * @recall_audio_run: the #AgsRecallAudioRun
1706  *
1707  * Set recall audio.
1708  *
1709  * Since: 3.1.0
1710  */
1711 void
ags_recall_channel_run_set_recall_audio_run(AgsRecallChannelRun * recall_channel_run,AgsRecallAudioRun * recall_audio_run)1712 ags_recall_channel_run_set_recall_audio_run(AgsRecallChannelRun *recall_channel_run, AgsRecallAudioRun *recall_audio_run)
1713 {
1714   if(!AGS_IS_RECALL_CHANNEL_RUN(recall_channel_run)){
1715     return;
1716   }
1717 
1718   g_object_set(recall_channel_run,
1719 	       "recall-audio-run", recall_audio_run,
1720 	       NULL);
1721 }
1722 
1723 /**
1724  * ags_recall_channel_run_get_recall_channel:
1725  * @recall_channel_run: the #AgsRecallChannelRun
1726  *
1727  * Get recall audio.
1728  *
1729  * Returns: (transfer full): the #AgsRecallChannel
1730  *
1731  * Since: 3.1.0
1732  */
1733 AgsRecallChannel*
ags_recall_channel_run_get_recall_channel(AgsRecallChannelRun * recall_channel_run)1734 ags_recall_channel_run_get_recall_channel(AgsRecallChannelRun *recall_channel_run)
1735 {
1736   AgsRecallChannel *recall_channel;
1737 
1738   if(!AGS_IS_RECALL_CHANNEL_RUN(recall_channel_run)){
1739     return(NULL);
1740   }
1741 
1742   g_object_get(recall_channel_run,
1743 	       "recall-channel", &recall_channel,
1744 	       NULL);
1745 
1746   return(recall_channel);
1747 }
1748 
1749 /**
1750  * ags_recall_channel_run_set_recall_channel:
1751  * @recall_channel_run: the #AgsRecallChannelRun
1752  * @recall_channel: the #AgsRecallChannel
1753  *
1754  * Set recall audio.
1755  *
1756  * Since: 3.1.0
1757  */
1758 void
ags_recall_channel_run_set_recall_channel(AgsRecallChannelRun * recall_channel_run,AgsRecallChannel * recall_channel)1759 ags_recall_channel_run_set_recall_channel(AgsRecallChannelRun *recall_channel_run, AgsRecallChannel *recall_channel)
1760 {
1761   if(!AGS_IS_RECALL_CHANNEL_RUN(recall_channel_run)){
1762     return;
1763   }
1764 
1765   g_object_set(recall_channel_run,
1766 	       "recall-channel", recall_channel,
1767 	       NULL);
1768 }
1769 
1770 /**
1771  * ags_recall_channel_run_get_destination:
1772  * @recall_channel_run: the #AgsRecallDestination
1773  *
1774  * Get destination.
1775  *
1776  * Returns: (transfer full): the #AgsDestination
1777  *
1778  * Since: 3.1.0
1779  */
1780 AgsChannel*
ags_recall_channel_run_get_destination(AgsRecallChannelRun * recall_channel_run)1781 ags_recall_channel_run_get_destination(AgsRecallChannelRun *recall_channel_run)
1782 {
1783   AgsChannel *destination;
1784 
1785   if(!AGS_IS_RECALL_CHANNEL_RUN(recall_channel_run)){
1786     return(NULL);
1787   }
1788 
1789   g_object_get(recall_channel_run,
1790 	       "destination", &destination,
1791 	       NULL);
1792 
1793   return(destination);
1794 }
1795 
1796 /**
1797  * ags_recall_channel_run_set_destination:
1798  * @recall_channel_run: the #AgsRecallChannelRun
1799  * @destination: the #AgsChannel
1800  *
1801  * Set destination.
1802  *
1803  * Since: 3.1.0
1804  */
1805 void
ags_recall_channel_run_set_destination(AgsRecallChannelRun * recall_channel_run,AgsChannel * destination)1806 ags_recall_channel_run_set_destination(AgsRecallChannelRun *recall_channel_run, AgsChannel *destination)
1807 {
1808   if(!AGS_IS_RECALL_CHANNEL_RUN(recall_channel_run)){
1809     return;
1810   }
1811 
1812   g_object_set(recall_channel_run,
1813 	       "destination", destination,
1814 	       NULL);
1815 }
1816 
1817 /**
1818  * ags_recall_channel_run_get_source:
1819  * @recall_channel_run: the #AgsRecallSource
1820  *
1821  * Get source.
1822  *
1823  * Returns: (transfer full): the #AgsSource
1824  *
1825  * Since: 3.1.0
1826  */
1827 AgsChannel*
ags_recall_channel_run_get_source(AgsRecallChannelRun * recall_channel_run)1828 ags_recall_channel_run_get_source(AgsRecallChannelRun *recall_channel_run)
1829 {
1830   AgsChannel *source;
1831 
1832   if(!AGS_IS_RECALL_CHANNEL_RUN(recall_channel_run)){
1833     return(NULL);
1834   }
1835 
1836   g_object_get(recall_channel_run,
1837 	       "source", &source,
1838 	       NULL);
1839 
1840   return(source);
1841 }
1842 
1843 /**
1844  * ags_recall_channel_run_set_source:
1845  * @recall_channel_run: the #AgsRecallChannelRun
1846  * @source: the #AgsChannel
1847  *
1848  * Set source.
1849  *
1850  * Since: 3.1.0
1851  */
1852 void
ags_recall_channel_run_set_source(AgsRecallChannelRun * recall_channel_run,AgsChannel * source)1853 ags_recall_channel_run_set_source(AgsRecallChannelRun *recall_channel_run, AgsChannel *source)
1854 {
1855   if(!AGS_IS_RECALL_CHANNEL_RUN(recall_channel_run)){
1856     return;
1857   }
1858 
1859   g_object_set(recall_channel_run,
1860 	       "source", source,
1861 	       NULL);
1862 }
1863 
1864 /**
1865  * ags_recall_channel_run_new:
1866  *
1867  * Creates an #AgsRecallChannelRun
1868  *
1869  * Returns: a new #AgsRecallChannelRun
1870  *
1871  * Since: 3.0.0
1872  */
1873 AgsRecallChannelRun*
ags_recall_channel_run_new()1874 ags_recall_channel_run_new()
1875 {
1876   AgsRecallChannelRun *recall_channel_run;
1877 
1878   recall_channel_run = (AgsRecallChannelRun *) g_object_new(AGS_TYPE_RECALL_CHANNEL_RUN,
1879 							    NULL);
1880 
1881   return(recall_channel_run);
1882 }
1883