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", ¤t_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", ¤t_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