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_channel.h>
21 
22 #include <ags/libags.h>
23 
24 #include <ags/plugin/ags_ladspa_manager.h>
25 #include <ags/plugin/ags_dssi_manager.h>
26 #include <ags/plugin/ags_lv2_manager.h>
27 
28 #include <ags/audio/ags_audio.h>
29 #include <ags/audio/ags_output.h>
30 #include <ags/audio/ags_input.h>
31 #include <ags/audio/ags_audio_signal.h>
32 #include <ags/audio/ags_automation.h>
33 #include <ags/audio/ags_pattern.h>
34 #include <ags/audio/ags_playback_domain.h>
35 #include <ags/audio/ags_playback.h>
36 #include <ags/audio/ags_recall.h>
37 #include <ags/audio/ags_recall_audio.h>
38 #include <ags/audio/ags_recall_audio_run.h>
39 #include <ags/audio/ags_recall_channel.h>
40 #include <ags/audio/ags_recall_channel_run.h>
41 #include <ags/audio/ags_recall_container.h>
42 #include <ags/audio/ags_generic_recall_channel_run.h>
43 #include <ags/audio/ags_generic_recall_recycling.h>
44 #include <ags/audio/ags_recall_ladspa.h>
45 #include <ags/audio/ags_recall_ladspa_run.h>
46 #include <ags/audio/ags_recall_dssi.h>
47 #include <ags/audio/ags_recall_dssi_run.h>
48 #include <ags/audio/ags_recall_lv2.h>
49 #include <ags/audio/ags_recall_lv2_run.h>
50 #include <ags/audio/ags_port.h>
51 #include <ags/audio/ags_recall_id.h>
52 
53 #include <ags/audio/thread/ags_audio_loop.h>
54 #include <ags/audio/thread/ags_audio_thread.h>
55 #include <ags/audio/thread/ags_channel_thread.h>
56 
57 #include <ags/audio/task/ags_cancel_channel.h>
58 
59 #include <ags/audio/file/ags_audio_file_link.h>
60 #include <ags/audio/file/ags_audio_file.h>
61 
62 #include <ags/audio/recall/ags_play_channel_run.h>
63 
64 #include <ags/audio/fx/ags_fx_playback_channel_processor.h>
65 
66 #include <stdlib.h>
67 #include <stdio.h>
68 
69 #include <ladspa.h>
70 #include <dssi.h>
71 #include <lv2.h>
72 
73 #include <ags/i18n.h>
74 
75 /**
76  * SECTION:ags_channel
77  * @short_description: Acts as entry point to the audio tree.
78  * @title: AgsChannel
79  * @section_id:
80  * @include: ags/audio/ags_channel.h
81  *
82  * #AgsChannel is the entry point to the entire audio tree and its nested
83  * recycling tree.
84  *
85  * Every channel has its own #AgsRecallID. As modifying link a new #AgsRecyclingContext
86  * is indicated, since it acts as a kind of recall id tree context.
87  */
88 
89 void ags_channel_class_init(AgsChannelClass *channel_class);
90 void ags_channel_connectable_interface_init(AgsConnectableInterface *connectable);
91 void ags_channel_init(AgsChannel *channel);
92 void ags_channel_set_property(GObject *gobject,
93 			      guint prop_id,
94 			      const GValue *value,
95 			      GParamSpec *param_spec);
96 void ags_channel_get_property(GObject *gobject,
97 			      guint prop_id,
98 			      GValue *value,
99 			      GParamSpec *param_spec);
100 void ags_channel_dispose(GObject *gobject);
101 void ags_channel_finalize(GObject *gobject);
102 
103 AgsUUID* ags_channel_get_uuid(AgsConnectable *connectable);
104 gboolean ags_channel_has_resource(AgsConnectable *connectable);
105 gboolean ags_channel_is_ready(AgsConnectable *connectable);
106 void ags_channel_add_to_registry(AgsConnectable *connectable);
107 void ags_channel_remove_from_registry(AgsConnectable *connectable);
108 xmlNode* ags_channel_list_resource(AgsConnectable *connectable);
109 xmlNode* ags_channel_xml_compose(AgsConnectable *connectable);
110 void ags_channel_xml_parse(AgsConnectable *connectable,
111 			   xmlNode *node);
112 gboolean ags_channel_is_connected(AgsConnectable *connectable);
113 void ags_channel_connect(AgsConnectable *connectable);
114 void ags_channel_disconnect(AgsConnectable *connectable);
115 
116 void ags_channel_real_set_output_soundcard(AgsChannel *channel, GObject *output_soundcard);
117 
118 void ags_channel_real_set_input_soundcard(AgsChannel *channel, GObject *input_soundcard);
119 
120 void ags_channel_real_set_samplerate(AgsChannel *channel, guint samplerate);
121 
122 void ags_channel_real_set_buffer_size(AgsChannel *channel, guint buffer_size);
123 
124 void ags_channel_real_set_format(AgsChannel *channel, guint format);
125 
126 gboolean ags_channel_check_loop(AgsChannel *output,
127 				AgsAudio *audio,
128 				guint level);
129 
130 gboolean ags_channel_reset_recycling_recursive_input(AgsChannel *input,
131 						     AgsAudio **found_next, AgsAudio **found_prev,
132 						     AgsChannel **next_channel, AgsChannel **prev_channel,
133 						     AgsRecycling **replace_with_first_recycling, AgsRecycling **replace_with_last_recycling,
134 						     guint *complete_level_first, guint *complete_level_last,
135 						     gboolean *find_next, gboolean *find_prev,
136 						     gboolean *replace_first, gboolean *replace_last);
137 void ags_channel_reset_recycling_recursive_output(AgsChannel *output,
138 						  AgsAudio **found_next, AgsAudio **found_prev,
139 						  AgsChannel **next_channel, AgsChannel **prev_channel,
140 						  AgsRecycling **replace_with_first_recycling, AgsRecycling **replace_with_last_recycling,
141 						  guint *complete_level_first, guint *complete_level_last,
142 						  gboolean *find_next, gboolean *find_prev,
143 						  gboolean *replace_first, gboolean *replace_last);
144 void ags_channel_reset_recycling_recursive(AgsChannel *input,
145 					   AgsAudio **found_next, AgsAudio **found_prev,
146 					   AgsChannel **next_channel, AgsChannel **prev_channel,
147 					   AgsRecycling **replace_with_first_recycling, AgsRecycling **replace_with_last_recycling,
148 					   guint *complete_level_first, guint *complete_level_last,
149 					   gboolean *find_next, gboolean *find_prev,
150 					   gboolean *replace_first, gboolean *replace_last);
151 
152 void ags_channel_reset_recycling_reset_recycling_context_up(AgsChannel *current);
153 void ags_channel_reset_recycling_reset_recycling_context_down(AgsChannel *current_output,
154 							      AgsRecyclingContext *new_recycling_context, AgsRecyclingContext *old_recycling_context);
155 void ags_channel_reset_recycling_reset_recycling_context_down_input(AgsChannel *current_output,
156 								    AgsRecyclingContext *new_recycling_context, AgsRecyclingContext *old_recycling_context);
157 
158 void ags_channel_reset_recycling_emit_changed_input(AgsChannel *start_channel, AgsChannel *input,
159 						    AgsRecycling *changed_old_first_recycling, AgsRecycling *changed_old_last_recycling,
160 						    AgsRecycling *old_first_recycling, AgsRecycling *old_last_recycling,
161 						    AgsRecycling *first_recycling, AgsRecycling *last_recycling);
162 void ags_channel_reset_recycling_emit_changed_output(AgsChannel *start_channel, AgsChannel *output,
163 						     AgsRecycling *changed_old_first_recycling, AgsRecycling *changed_old_last_recycling,
164 						     AgsRecycling *old_first_recycling, AgsRecycling *old_last_recycling,
165 						     AgsRecycling *first_recycling, AgsRecycling *last_recycling);
166 void ags_channel_reset_recycling_emit_changed(AgsChannel *start_channel, AgsChannel *input,
167 					      AgsRecycling *changed_old_first_recycling, AgsRecycling *changed_old_last_recycling,
168 					      AgsRecycling *old_first_recycling, AgsRecycling *old_last_recycling,
169 					      AgsRecycling *first_recycling, AgsRecycling *last_recycling);
170 
171 void ags_channel_real_recycling_changed(AgsChannel *channel,
172 					AgsRecycling *old_start_region, AgsRecycling *old_end_region,
173 					AgsRecycling *new_start_region, AgsRecycling *new_end_region,
174 					AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
175 					AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region);
176 
177 GList* ags_channel_add_ladspa_effect(AgsChannel *channel,
178 				     gchar *filename,
179 				     gchar *effect);
180 GList* ags_channel_add_dssi_effect(AgsChannel *channel,
181 				   gchar *filename,
182 				   gchar *effect);
183 GList* ags_channel_add_lv2_effect(AgsChannel *channel,
184 				  gchar *filename,
185 				  gchar *effect);
186 GList* ags_channel_real_add_effect(AgsChannel *channel,
187 				   gchar *filename,
188 				   gchar *effect);
189 void ags_channel_real_remove_effect(AgsChannel *channel,
190 				    guint nth);
191 
192 void ags_channel_real_duplicate_recall(AgsChannel *channel,
193 				       AgsRecallID *recall_id);
194 void ags_channel_real_resolve_recall(AgsChannel *channel,
195 				     AgsRecallID *recall_id);
196 void ags_channel_real_init_recall(AgsChannel *channel,
197 				  AgsRecallID *recall_id, guint staging_flags);
198 void ags_channel_real_play_recall(AgsChannel *channel,
199 				  AgsRecallID *recall_id, guint staging_flags);
200 void ags_channel_real_done_recall(AgsChannel *channel,
201 				  AgsRecallID *recall_id);
202 void ags_channel_real_cancel_recall(AgsChannel *channel,
203 				    AgsRecallID *recall_id);
204 
205 void ags_channel_real_cleanup_recall(AgsChannel *channel,
206 				     AgsRecallID *recall_id);
207 
208 void ags_channel_recall_done_callback(AgsRecall *recall,
209 				      AgsChannel *channel);
210 
211 GList* ags_channel_real_start(AgsChannel *channel,
212 			      gint sound_scope);
213 void ags_channel_real_stop(AgsChannel *channel,
214 			   GList *recall_id, gint sound_scope);
215 
216 GList* ags_channel_real_check_scope(AgsChannel *channel, gint sound_scope);
217 
218 void ags_channel_recursive_set_property_setv(AgsChannel *channel,
219 					     gint n_params,
220 					     gchar **parameter_name, GValue *value);
221 void ags_channel_recursive_set_property_down(AgsChannel *channel,
222 					     gint n_params,
223 					     gchar **parameter_name, GValue *value);
224 void ags_channel_recursive_set_property_down_input(AgsChannel *channel,
225 						   gint n_params,
226 						   gchar **parameter_name, GValue *value);
227 
228 void ags_channel_recursive_setup_run_stage_up(AgsChannel *channel,
229 					      AgsRecyclingContext *recycling_context,
230 					      gint sound_scope, guint local_staging_flags);
231 void ags_channel_recursive_setup_run_stage_down(AgsChannel *channel,
232 						AgsRecyclingContext *recycling_context,
233 						gint sound_scope, guint local_staging_flags);
234 void ags_channel_recursive_setup_run_stage_down_input(AgsChannel *channel,
235 						      AgsRecyclingContext *recycling_context,
236 						      gint sound_scope, guint local_staging_flags);
237 void ags_channel_recursive_prepare_run_stage_up(AgsChannel *channel,
238 						AgsRecyclingContext *recycling_context,
239 						gint sound_scope, guint local_staging_flags);
240 void ags_channel_recursive_prepare_run_stage_down(AgsChannel *channel,
241 						  AgsRecyclingContext *recycling_context,
242 						  gint sound_scope, guint local_staging_flags);
243 void ags_channel_recursive_prepare_run_stage_down_input(AgsChannel *channel,
244 							AgsRecyclingContext *recycling_context,
245 							gint sound_scope, guint local_staging_flags);
246 void ags_channel_recursive_do_run_stage_up(AgsChannel *channel,
247 					   AgsRecyclingContext *recycling_context,
248 					   gint sound_scope, guint staging_flags);
249 void ags_channel_recursive_do_run_stage_down(AgsChannel *channel,
250 					     AgsRecyclingContext *recycling_context,
251 					     gint sound_scope, guint staging_flags);
252 void ags_channel_recursive_do_run_stage_down_input(AgsChannel *channel,
253 						   AgsRecyclingContext *recycling_context,
254 						   gint sound_scope, guint staging_flags);
255 void ags_channel_recursive_cleanup_run_stage_up(AgsChannel *channel,
256 						AgsRecyclingContext *recycling_context,
257 						gint sound_scope, guint local_staging_flags);
258 void ags_channel_recursive_cleanup_run_stage_down(AgsChannel *channel,
259 						  AgsRecyclingContext *recycling_context,
260 						  gint sound_scope, guint local_staging_flags);
261 void ags_channel_recursive_cleanup_run_stage_down_input(AgsChannel *channel,
262 							AgsRecyclingContext *recycling_context,
263 							gint sound_scope, guint local_staging_flags);
264 
265 void ags_channel_real_recursive_run_stage(AgsChannel *channel,
266 					  gint sound_scope, guint staging_flags);
267 
268 enum{
269   ADD_EFFECT,
270   REMOVE_EFFECT,
271   RECYCLING_CHANGED,
272   DUPLICATE_RECALL,
273   RESOLVE_RECALL,
274   INIT_RECALL,
275   PLAY_RECALL,
276   DONE_RECALL,
277   CANCEL_RECALL,
278   CLEANUP_RECALL,
279   START,
280   STOP,
281   CHECK_SCOPE,
282   RECURSIVE_RUN_STAGE,
283   LAST_SIGNAL,
284 };
285 
286 enum{
287   PROP_0,
288   PROP_AUDIO,
289   PROP_OUTPUT_SOUNDCARD,
290   PROP_OUTPUT_SOUNDCARD_CHANNEL,
291   PROP_INPUT_SOUNDCARD,
292   PROP_INPUT_SOUNDCARD_CHANNEL,
293   PROP_SAMPLERATE,
294   PROP_BUFFER_SIZE,
295   PROP_FORMAT,
296   PROP_PAD,
297   PROP_AUDIO_CHANNEL,
298   PROP_LINE,
299   PROP_OCTAVE,
300   PROP_KEY,
301   PROP_ABSOLUTE_KEY,
302   PROP_NOTE_FREQUENCY,
303   PROP_NOTE_KEY,
304   PROP_MIDI_NOTE,
305   PROP_PREV,
306   PROP_PREV_PAD,
307   PROP_NEXT,
308   PROP_NEXT_PAD,
309   PROP_LINK,
310   PROP_FIRST_RECYCLING,
311   PROP_LAST_RECYCLING,
312   PROP_PLAYBACK,
313   PROP_PATTERN,
314   PROP_RECALL_ID,
315   PROP_RECYCLING_CONTEXT,
316   PROP_RECALL_CONTAINER,
317   PROP_PLAY,
318   PROP_RECALL,
319 };
320 
321 enum{
322   AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_ADD_RECALL_ID      = 1,
323   AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE          = 1 <<  1,
324   AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE            = 1 <<  2,
325 }AgsChannelRecursivePrepareStagingFlags;
326 
327 enum{
328   AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL      = 1,
329   AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL      = 1 <<  1,
330   AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE                      = 1 <<  2,
331 }AgsChannelRecursiveCleanupStagingFlags;
332 
333 static gpointer ags_channel_parent_class = NULL;
334 static guint channel_signals[LAST_SIGNAL];
335 
336 GType
ags_channel_get_type(void)337 ags_channel_get_type (void)
338 {
339   static volatile gsize g_define_type_id__volatile = 0;
340 
341   if(g_once_init_enter (&g_define_type_id__volatile)){
342     GType ags_type_channel = 0;
343 
344     static const GTypeInfo ags_channel_info = {
345       sizeof (AgsChannelClass),
346       NULL, /* base_init */
347       NULL, /* base_finalize */
348       (GClassInitFunc) ags_channel_class_init,
349       NULL, /* class_finalize */
350       NULL, /* class_data */
351       sizeof (AgsChannel),
352       0,    /* n_preallocs */
353       (GInstanceInitFunc) ags_channel_init,
354     };
355 
356     static const GInterfaceInfo ags_connectable_interface_info = {
357       (GInterfaceInitFunc) ags_channel_connectable_interface_init,
358       NULL, /* interface_finalize */
359       NULL, /* interface_data */
360     };
361 
362     ags_type_channel = g_type_register_static(G_TYPE_OBJECT,
363 					      "AgsChannel",
364 					      &ags_channel_info, 0);
365 
366     g_type_add_interface_static(ags_type_channel,
367 				AGS_TYPE_CONNECTABLE,
368 				&ags_connectable_interface_info);
369 
370     g_once_init_leave(&g_define_type_id__volatile, ags_type_channel);
371   }
372 
373   return g_define_type_id__volatile;
374 }
375 
376 GType
ags_channel_flags_get_type()377 ags_channel_flags_get_type()
378 {
379   static volatile gsize g_flags_type_id__volatile;
380 
381   if(g_once_init_enter (&g_flags_type_id__volatile)){
382     static const GFlagsValue values[] = {
383       { AGS_CHANNEL_ADDED_TO_REGISTRY, "AGS_CHANNEL_ADDED_TO_REGISTRY", "channel-added-to-registry" },
384       { AGS_CHANNEL_CONNECTED, "AGS_CHANNEL_CONNECTED", "channel-connected" },
385       { AGS_CHANNEL_BYPASS, "AGS_CHANNEL_BYPASS", "channel-bypass" },
386       { 0, NULL, NULL }
387     };
388 
389     GType g_flags_type_id = g_flags_register_static(g_intern_static_string("AgsChannelFlags"), values);
390 
391     g_once_init_leave (&g_flags_type_id__volatile, g_flags_type_id);
392   }
393 
394   return g_flags_type_id__volatile;
395 }
396 
397 void
ags_channel_class_init(AgsChannelClass * channel)398 ags_channel_class_init(AgsChannelClass *channel)
399 {
400   GObjectClass *gobject;
401 
402   GParamSpec *param_spec;
403 
404   ags_channel_parent_class = g_type_class_peek_parent(channel);
405 
406   /* GObjectClass */
407   gobject = (GObjectClass *) channel;
408 
409   gobject->set_property = ags_channel_set_property;
410   gobject->get_property = ags_channel_get_property;
411 
412   gobject->dispose = ags_channel_dispose;
413   gobject->finalize = ags_channel_finalize;
414 
415   /* properties */
416   /**
417    * AgsChannel:audio:
418    *
419    * The assigned #AgsAudio aligning channels.
420    *
421    * Since: 3.0.0
422    */
423   param_spec = g_param_spec_object("audio",
424 				   i18n_pspec("assigned audio"),
425 				   i18n_pspec("The audio it is assigned with"),
426 				   AGS_TYPE_AUDIO,
427 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
428   g_object_class_install_property(gobject,
429 				  PROP_AUDIO,
430 				  param_spec);
431 
432   /**
433    * AgsChannel:output-soundcard:
434    *
435    * The assigned output #AgsSoundcard.
436    *
437    * Since: 3.0.0
438    */
439   param_spec = g_param_spec_object("output-soundcard",
440 				   i18n_pspec("assigned output soundcard"),
441 				   i18n_pspec("The output soundcard it is assigned with"),
442 				   G_TYPE_OBJECT,
443 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
444   g_object_class_install_property(gobject,
445 				  PROP_OUTPUT_SOUNDCARD,
446 				  param_spec);
447 
448   /**
449    * AgsChannel:output-soundcard-channel:
450    *
451    * The output soundcard channel.
452    *
453    * Since: 3.0.0
454    */
455   param_spec =  g_param_spec_int("output-soundcard-channel",
456 				 i18n_pspec("output soundcard channel"),
457 				 i18n_pspec("The output soundcard channel"),
458 				 -1,
459 				 G_MAXINT32,
460 				 0,
461 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
462   g_object_class_install_property(gobject,
463 				  PROP_OUTPUT_SOUNDCARD_CHANNEL,
464 				  param_spec);
465 
466   /**
467    * AgsChannel:input-soundcard:
468    *
469    * The assigned input #AgsSoundcard.
470    *
471    * Since: 3.0.0
472    */
473   param_spec = g_param_spec_object("input-soundcard",
474 				   i18n_pspec("assigned input soundcard"),
475 				   i18n_pspec("The input soundcard it is assigned with"),
476 				   G_TYPE_OBJECT,
477 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
478   g_object_class_install_property(gobject,
479 				  PROP_INPUT_SOUNDCARD,
480 				  param_spec);
481 
482   /**
483    * AgsChannel:input-soundcard-channel:
484    *
485    * The input soundcard channel.
486    *
487    * Since: 3.0.0
488    */
489   param_spec =  g_param_spec_int("input-soundcard-channel",
490 				 i18n_pspec("input soundcard channel"),
491 				 i18n_pspec("The input soundcard channel"),
492 				 -1,
493 				 G_MAXINT32,
494 				 0,
495 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
496   g_object_class_install_property(gobject,
497 				  PROP_INPUT_SOUNDCARD_CHANNEL,
498 				  param_spec);
499 
500   /**
501    * AgsChannel:samplerate:
502    *
503    * The samplerate.
504    *
505    * Since: 3.0.0
506    */
507   param_spec =  g_param_spec_uint("samplerate",
508 				  i18n_pspec("samplerate"),
509 				  i18n_pspec("The samplerate"),
510 				  0,
511 				  G_MAXUINT32,
512 				  0,
513 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
514   g_object_class_install_property(gobject,
515 				  PROP_SAMPLERATE,
516 				  param_spec);
517 
518   /**
519    * AgsChannel:buffer-size:
520    *
521    * The buffer size.
522    *
523    * Since: 3.0.0
524    */
525   param_spec =  g_param_spec_uint("buffer-size",
526 				  i18n_pspec("buffer size"),
527 				  i18n_pspec("The buffer size"),
528 				  0,
529 				  G_MAXUINT32,
530 				  0,
531 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
532   g_object_class_install_property(gobject,
533 				  PROP_BUFFER_SIZE,
534 				  param_spec);
535 
536   /**
537    * AgsChannel:format:
538    *
539    * The format.
540    *
541    * Since: 3.0.0
542    */
543   param_spec =  g_param_spec_uint("format",
544 				  i18n_pspec("format"),
545 				  i18n_pspec("The format"),
546 				  0,
547 				  G_MAXUINT32,
548 				  0,
549 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
550   g_object_class_install_property(gobject,
551 				  PROP_FORMAT,
552 				  param_spec);
553 
554   /**
555    * AgsChannel:pad:
556    *
557    * The nth pad.
558    *
559    * Since: 3.0.0
560    */
561   param_spec =  g_param_spec_uint("pad",
562 				  i18n_pspec("nth pad"),
563 				  i18n_pspec("The nth pad"),
564 				  0,
565 				  G_MAXUINT32,
566 				  0,
567 				  G_PARAM_READABLE);
568   g_object_class_install_property(gobject,
569 				  PROP_PAD,
570 				  param_spec);
571 
572   /**
573    * AgsChannel:audio-channel:
574    *
575    * The nth audio channel.
576    *
577    * Since: 3.0.0
578    */
579   param_spec =  g_param_spec_uint("audio-channel",
580 				  i18n_pspec("nth audio channel"),
581 				  i18n_pspec("The nth audio channel"),
582 				  0,
583 				  G_MAXUINT32,
584 				  0,
585 				  G_PARAM_READABLE);
586   g_object_class_install_property(gobject,
587 				  PROP_AUDIO_CHANNEL,
588 				  param_spec);
589 
590   /**
591    * AgsChannel:line:
592    *
593    * The nth line.
594    *
595    * Since: 3.0.0
596    */
597   param_spec =  g_param_spec_uint("line",
598 				  i18n_pspec("nth line"),
599 				  i18n_pspec("The nth line"),
600 				  0,
601 				  G_MAXUINT32,
602 				  0,
603 				  G_PARAM_READABLE);
604   g_object_class_install_property(gobject,
605 				  PROP_LINE,
606 				  param_spec);
607 
608   /**
609    * AgsChannel:octave:
610    *
611    * The nth octave.
612    *
613    * Since: 3.0.0
614    */
615   param_spec =  g_param_spec_int("octave",
616 				 i18n_pspec("nth octave"),
617 				 i18n_pspec("The nth octave"),
618 				 AGS_CHANNEL_MINIMUM_OCTAVE,
619 				 AGS_CHANNEL_MAXIMUM_OCTAVE,
620 				 AGS_CHANNEL_DEFAULT_OCTAVE,
621 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
622   g_object_class_install_property(gobject,
623 				  PROP_OCTAVE,
624 				  param_spec);
625 
626   /**
627    * AgsChannel:key:
628    *
629    * The nth key.
630    *
631    * Since: 3.0.0
632    */
633   param_spec =  g_param_spec_uint("key",
634 				  i18n_pspec("nth key"),
635 				  i18n_pspec("The nth key"),
636 				  AGS_CHANNEL_MINIMUM_OCTAVE_SEMITONE,
637 				  AGS_CHANNEL_MAXIMUM_OCTAVE_SEMITONE,
638 				  AGS_CHANNEL_DEFAULT_OCTAVE_SEMITONE,
639 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
640   g_object_class_install_property(gobject,
641 				  PROP_KEY,
642 				  param_spec);
643 
644   /**
645    * AgsChannel:absolute-key:
646    *
647    * The nth absolute key.
648    *
649    * Since: 3.0.0
650    */
651   param_spec =  g_param_spec_int("absolute-key",
652 				 i18n_pspec("nth absolute key"),
653 				 i18n_pspec("The nth absolute key"),
654 				 AGS_CHANNEL_MINIMUM_SEMITONE,
655 				 AGS_CHANNEL_MAXIMUM_SEMITONE,
656 				 AGS_CHANNEL_DEFAULT_SEMITONE,
657 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
658   g_object_class_install_property(gobject,
659 				  PROP_ABSOLUTE_KEY,
660 				  param_spec);
661 
662   /**
663    * AgsChannel:note-frequency:
664    *
665    * The note frequency.
666    *
667    * Since: 3.0.0
668    */
669   param_spec =  g_param_spec_double("note-frequency",
670 				    i18n_pspec("note frequency"),
671 				    i18n_pspec("The note frequency"),
672 				    AGS_CHANNEL_MINIMUM_NOTE_FREQUENCY,
673 				    AGS_CHANNEL_MAXIMUM_NOTE_FREQUENCY,
674 				    AGS_CHANNEL_DEFAULT_NOTE_FREQUENCY,
675 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
676   g_object_class_install_property(gobject,
677 				  PROP_NOTE_FREQUENCY,
678 				  param_spec);
679 
680   /**
681    * AgsChannel:note-key:
682    *
683    * The assigned note key representing this channel.
684    *
685    * Since: 3.0.0
686    */
687   param_spec = g_param_spec_string("note-key",
688 				   i18n_pspec("assigned note key"),
689 				   i18n_pspec("The note key it is assigned with"),
690 				   NULL,
691 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
692   g_object_class_install_property(gobject,
693 				  PROP_NOTE_KEY,
694 				  param_spec);
695 
696   /**
697    * AgsChannel:midi-note:
698    *
699    * The nth midi note.
700    *
701    * Since: 3.0.0
702    */
703   param_spec =  g_param_spec_uint("midi-note",
704 				  i18n_pspec("nth midi note"),
705 				  i18n_pspec("The nth midi note"),
706 				  AGS_CHANNEL_MINIMUM_MIDI_NOTE,
707 				  AGS_CHANNEL_MAXIMUM_MIDI_NOTE,
708 				  AGS_CHANNEL_DEFAULT_MIDI_NOTE,
709 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
710   g_object_class_install_property(gobject,
711 				  PROP_MIDI_NOTE,
712 				  param_spec);
713 
714   /**
715    * AgsChannel:prev:
716    *
717    * The assigned prev #AgsChannel.
718    *
719    * Since: 3.0.0
720    */
721   param_spec = g_param_spec_object("prev",
722 				   "assigned prev",
723 				   "The prev it is assigned with",
724 				   AGS_TYPE_CHANNEL,
725 				   G_PARAM_READABLE);
726   g_object_class_install_property(gobject,
727 				  PROP_PREV,
728 				  param_spec);
729 
730   /**
731    * AgsChannel:prev-pad:
732    *
733    * The assigned prev pad #AgsChannel.
734    *
735    * Since: 3.0.0
736    */
737   param_spec = g_param_spec_object("prev-pad",
738 				   "assigned prev pad",
739 				   "The prev pad it is assigned with",
740 				   AGS_TYPE_CHANNEL,
741 				   G_PARAM_READABLE);
742   g_object_class_install_property(gobject,
743 				  PROP_PREV_PAD,
744 				  param_spec);
745 
746   /**
747    * AgsChannel:next:
748    *
749    * The assigned next #AgsChannel.
750    *
751    * Since: 3.0.0
752    */
753   param_spec = g_param_spec_object("next",
754 				   "assigned next",
755 				   "The next it is assigned with",
756 				   AGS_TYPE_CHANNEL,
757 				   G_PARAM_READABLE);
758   g_object_class_install_property(gobject,
759 				  PROP_NEXT,
760 				  param_spec);
761 
762   /**
763    * AgsChannel:next-pad:
764    *
765    * The assigned next pad #AgsChannel.
766    *
767    * Since: 3.0.0
768    */
769   param_spec = g_param_spec_object("next-pad",
770 				   "assigned next pad",
771 				   "The next it is assigned with",
772 				   AGS_TYPE_CHANNEL,
773 				   G_PARAM_READABLE);
774   g_object_class_install_property(gobject,
775 				  PROP_NEXT_PAD,
776 				  param_spec);
777 
778   /**
779    * AgsChannel:link:
780    *
781    * The assigned link as #AgsChannel.
782    *
783    * Since: 3.0.0
784    */
785   param_spec = g_param_spec_object("link",
786 				   i18n_pspec("assigned link"),
787 				   i18n_pspec("The link it is assigned with"),
788 				   AGS_TYPE_CHANNEL,
789 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
790   g_object_class_install_property(gobject,
791 				  PROP_LINK,
792 				  param_spec);
793 
794   /**
795    * AgsChannel:first-recycling:
796    *
797    * The containing #AgsRecycling it takes it #AgsAudioSignal from.
798    *
799    * Since: 3.0.0
800    */
801   param_spec = g_param_spec_object("first-recycling",
802 				   i18n_pspec("containing first recycling"),
803 				   i18n_pspec("The first recycling it contains"),
804 				   AGS_TYPE_RECYCLING,
805 				   G_PARAM_READABLE);
806   g_object_class_install_property(gobject,
807 				  PROP_FIRST_RECYCLING,
808 				  param_spec);
809 
810   /**
811    * AgsChannel:last-recycling:
812    *
813    * The containing #AgsRecycling it takes it #AgsAudioSignal from.
814    *
815    * Since: 3.0.0
816    */
817   param_spec = g_param_spec_object("last-recycling",
818 				   i18n_pspec("containing last recycling"),
819 				   i18n_pspec("The last recycling it contains"),
820 				   AGS_TYPE_RECYCLING,
821 				   G_PARAM_READABLE);
822   g_object_class_install_property(gobject,
823 				  PROP_LAST_RECYCLING,
824 				  param_spec);
825 
826   /**
827    * AgsChannel:playback:
828    *
829    * The assigned #AgsPlayback.
830    *
831    * Since: 3.0.0
832    */
833   param_spec = g_param_spec_object("playback",
834 				   i18n_pspec("assigned playback"),
835 				   i18n_pspec("The playback it is assigned with"),
836 				   AGS_TYPE_PLAYBACK,
837 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
838   g_object_class_install_property(gobject,
839 				  PROP_PLAYBACK,
840 				  param_spec);
841 
842   /**
843    * AgsChannel:pattern: (type GList(AgsPatter)) (transfer full)
844    *
845    * The containing #AgsPattern.
846    *
847    * Since: 3.0.0
848    */
849   param_spec = g_param_spec_pointer("pattern",
850 				    i18n_pspec("containing pattern"),
851 				    i18n_pspec("The pattern it contains"),
852 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
853   g_object_class_install_property(gobject,
854 				  PROP_PATTERN,
855 				  param_spec);
856 
857   /**
858    * AgsChannel:recall-id: (type GList(AgsRecallID)) (transfer full)
859    *
860    * The assigned #AgsRecallID.
861    *
862    * Since: 3.0.0
863    */
864   param_spec = g_param_spec_pointer("recall-id",
865 				    i18n_pspec("assigned recall id"),
866 				    i18n_pspec("The recall id it is assigned with"),
867 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
868   g_object_class_install_property(gobject,
869 				  PROP_RECALL_ID,
870 				  param_spec);
871 
872   /**
873    * AgsChannel:recycling-context: (type GList(AgsRecyclingContext)) (transfer full)
874    *
875    * The containing #AgsRecyclingContext.
876    *
877    * Since: 3.0.0
878    */
879   param_spec = g_param_spec_pointer("recycling-context",
880 				    i18n_pspec("containing recycling-context"),
881 				    i18n_pspec("The recycling context it contains"),
882 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
883   g_object_class_install_property(gobject,
884 				  PROP_RECYCLING_CONTEXT,
885 				  param_spec);
886 
887   /**
888    * AgsChannel:recall-container: (type GList(AgsRecallContainer)) (transfer full)
889    *
890    * The containing #AgsRecallContainer.
891    *
892    * Since: 3.0.0
893    */
894   param_spec = g_param_spec_pointer("recall-container",
895 				    i18n_pspec("containing recall-container"),
896 				    i18n_pspec("The recall container it contains"),
897 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
898   g_object_class_install_property(gobject,
899 				  PROP_RECALL_CONTAINER,
900 				  param_spec);
901 
902   /**
903    * AgsChannel:recall: (type GList(AgsRecall)) (transfer full)
904    *
905    * The containing #AgsRecall in recall-context.
906    *
907    * Since: 3.0.0
908    */
909   param_spec = g_param_spec_pointer("recall",
910 				    i18n_pspec("containing recall"),
911 				    i18n_pspec("The recall it contains"),
912 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
913   g_object_class_install_property(gobject,
914 				  PROP_RECALL,
915 				  param_spec);
916 
917   /**
918    * AgsChannel:play: (type GList(AgsRecall)) (transfer full)
919    *
920    * The containing #AgsRecall in play-context.
921    *
922    * Since: 3.0.0
923    */
924   param_spec = g_param_spec_pointer("play",
925 				    i18n_pspec("containing play"),
926 				    i18n_pspec("The play it contains"),
927 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
928   g_object_class_install_property(gobject,
929 				  PROP_PLAY,
930 				  param_spec);
931 
932   /* AgsChannelClass */
933   channel->recycling_changed = NULL;
934 
935   channel->add_effect = ags_channel_real_add_effect;
936   channel->remove_effect = ags_channel_real_remove_effect;
937 
938   channel->duplicate_recall = ags_channel_real_duplicate_recall;
939   channel->resolve_recall = ags_channel_real_resolve_recall;
940 
941   channel->init_recall = ags_channel_real_init_recall;
942   channel->play_recall = ags_channel_real_play_recall;
943 
944   channel->done_recall = ags_channel_real_done_recall;
945   channel->cancel_recall = ags_channel_real_cancel_recall;
946 
947   channel->cleanup_recall = ags_channel_real_cleanup_recall;
948 
949   channel->start = ags_channel_real_start;
950   channel->stop = ags_channel_real_stop;
951 
952   channel->check_scope = ags_channel_real_check_scope;
953   channel->recursive_run_stage = ags_channel_real_recursive_run_stage;
954 
955   /* signals */
956   /**
957    * AgsChannel::recycling-changed:
958    * @channel: the #AgsChannel recycling changed
959    * @old_start_region: first #AgsRecycling
960    * @old_end_region: last #AgsRecycling
961    * @new_start_region: new first #AgsRecycling
962    * @new_end_region: new last #AgsRecycling
963    * @old_start_changed_region: modified link #AgsRecycling start
964    * @old_end_changed_region: modified link #AgsRecyclig end
965    * @new_start_changed_region: replacing link #AgsRecycling start
966    * @new_end_changed_region: replacing link #AgsRecycling end
967    *
968    * The ::recycling-changed signal is invoked to notify modified recycling tree.
969    *
970    * Since: 3.0.0
971    */
972   channel_signals[RECYCLING_CHANGED] =
973     g_signal_new("recycling-changed",
974 		 G_TYPE_FROM_CLASS (channel),
975 		 G_SIGNAL_RUN_LAST,
976 		 G_STRUCT_OFFSET (AgsChannelClass, recycling_changed),
977 		 NULL, NULL,
978 		 ags_cclosure_marshal_VOID__OBJECT_OBJECT_OBJECT_OBJECT_OBJECT_OBJECT_OBJECT_OBJECT,
979 		 G_TYPE_NONE, 8,
980 		 G_TYPE_OBJECT, G_TYPE_OBJECT,
981 		 G_TYPE_OBJECT, G_TYPE_OBJECT,
982 		 G_TYPE_OBJECT, G_TYPE_OBJECT,
983 		 G_TYPE_OBJECT, G_TYPE_OBJECT);
984 
985   /**
986    * AgsChannel::add-effect:
987    * @channel: the #AgsChannel to modify
988    * @filename: the effect's filename
989    * @effect: the effect's name
990    *
991    * The ::add-effect signal notifies about added effect.
992    *
993    * Since: 3.0.0
994    */
995   channel_signals[ADD_EFFECT] =
996     g_signal_new("add-effect",
997 		 G_TYPE_FROM_CLASS(channel),
998 		 G_SIGNAL_RUN_LAST,
999 		 G_STRUCT_OFFSET(AgsChannelClass, add_effect),
1000 		 NULL, NULL,
1001 		 ags_cclosure_marshal_POINTER__STRING_STRING,
1002 		 G_TYPE_POINTER, 2,
1003 		 G_TYPE_STRING,
1004 		 G_TYPE_STRING);
1005 
1006   /**
1007    * AgsChannel::remove-effect:
1008    * @channel: the #AgsChannel to modify
1009    * @nth: the nth effect
1010    *
1011    * The ::remove-effect signal notifies about removed effect.
1012    *
1013    * Since: 3.0.0
1014    */
1015   channel_signals[REMOVE_EFFECT] =
1016     g_signal_new("remove-effect",
1017 		 G_TYPE_FROM_CLASS(channel),
1018 		 G_SIGNAL_RUN_LAST,
1019 		 G_STRUCT_OFFSET(AgsChannelClass, remove_effect),
1020 		 NULL, NULL,
1021 		 g_cclosure_marshal_VOID__UINT,
1022 		 G_TYPE_NONE, 1,
1023 		 G_TYPE_UINT);
1024 
1025   /**
1026    * AgsChannel::duplicate-recall:
1027    * @channel: the #AgsChannel
1028    * @recall_id: the appropriate #AgsRecallID
1029    *
1030    * The ::duplicate-recall signal is invoked during playback initialization.
1031    *
1032    * Since: 3.0.0
1033    */
1034   channel_signals[DUPLICATE_RECALL] =
1035     g_signal_new("duplicate-recall",
1036 		 G_TYPE_FROM_CLASS(channel),
1037 		 G_SIGNAL_RUN_LAST,
1038 		 G_STRUCT_OFFSET(AgsChannelClass, duplicate_recall),
1039 		 NULL, NULL,
1040 		 g_cclosure_marshal_VOID__OBJECT,
1041 		 G_TYPE_NONE, 1,
1042 		 G_TYPE_OBJECT);
1043 
1044   /**
1045    * AgsChannel::resolve-recall:
1046    * @channel: the #AgsChannel
1047    * @recall_id: the appropriate #AgsRecallID
1048    *
1049    * The ::resolve-recall signal is invoked during playback initialization.
1050    *
1051    * Since: 3.0.0
1052    */
1053   channel_signals[RESOLVE_RECALL] =
1054     g_signal_new("resolve-recall",
1055 		 G_TYPE_FROM_CLASS(channel),
1056 		 G_SIGNAL_RUN_LAST,
1057 		 G_STRUCT_OFFSET(AgsChannelClass, resolve_recall),
1058 		 NULL, NULL,
1059 		 g_cclosure_marshal_VOID__OBJECT,
1060 		 G_TYPE_NONE, 1,
1061 		 G_TYPE_OBJECT);
1062 
1063   /**
1064    * AgsChannel::init-recall:
1065    * @channel: the #AgsChannel
1066    * @recall_id: the appropriate #AgsRecallID
1067    * @staging_flags: the staging flags
1068    *
1069    * The ::init-recall signal is invoked during playback initialization.
1070    *
1071    * Since: 3.0.0
1072    */
1073   channel_signals[INIT_RECALL] =
1074     g_signal_new("init-recall",
1075 		 G_TYPE_FROM_CLASS(channel),
1076 		 G_SIGNAL_RUN_LAST,
1077 		 G_STRUCT_OFFSET(AgsChannelClass, init_recall),
1078 		 NULL, NULL,
1079 		 ags_cclosure_marshal_VOID__OBJECT_UINT,
1080 		 G_TYPE_NONE, 2,
1081 		 G_TYPE_OBJECT, G_TYPE_UINT);
1082 
1083   /**
1084    * AgsChannel::play-recall:
1085    * @channel: the #AgsChannel
1086    * @recall_id: the appropriate #AgsRecallID
1087    * @staging_flags: the staging flags
1088    *
1089    * The ::play-recall signal is invoked during playback run.
1090    *
1091    * Since: 3.0.0
1092    */
1093   channel_signals[PLAY_RECALL] =
1094     g_signal_new("play-recall",
1095 		 G_TYPE_FROM_CLASS(channel),
1096 		 G_SIGNAL_RUN_LAST,
1097 		 G_STRUCT_OFFSET(AgsChannelClass, play_recall),
1098 		 NULL, NULL,
1099 		 ags_cclosure_marshal_VOID__OBJECT_UINT,
1100 		 G_TYPE_NONE, 2,
1101 		 G_TYPE_OBJECT,
1102 		 G_TYPE_UINT);
1103 
1104   /**
1105    * AgsChannel::done-recall:
1106    * @channel: the #AgsChannel
1107    * @recall_id: the appropriate #AgsRecallID
1108    *
1109    * The ::done-recall signal is invoked during termination of playback.
1110    *
1111    * Since: 3.0.0
1112    */
1113   channel_signals[DONE_RECALL] =
1114     g_signal_new("done-recall",
1115 		 G_TYPE_FROM_CLASS(channel),
1116 		 G_SIGNAL_RUN_LAST,
1117 		 G_STRUCT_OFFSET(AgsChannelClass, done_recall),
1118 		 NULL, NULL,
1119 		 g_cclosure_marshal_VOID__OBJECT,
1120 		 G_TYPE_NONE, 1,
1121 		 G_TYPE_OBJECT);
1122 
1123   /**
1124    * AgsChannel::cancel-recall:
1125    * @channel: the #AgsChannel
1126    * @recall_id: the appropriate #AgsRecallID
1127    *
1128    * The ::cancel-recall signal is invoked during termination of playback.
1129    *
1130    * Since: 3.0.0
1131    */
1132   channel_signals[CANCEL_RECALL] =
1133     g_signal_new("cancel-recall",
1134 		 G_TYPE_FROM_CLASS(channel),
1135 		 G_SIGNAL_RUN_LAST,
1136 		 G_STRUCT_OFFSET(AgsChannelClass, cancel_recall),
1137 		 NULL, NULL,
1138 		 g_cclosure_marshal_VOID__OBJECT,
1139 		 G_TYPE_NONE, 1,
1140 		 G_TYPE_OBJECT);
1141 
1142   /**
1143    * AgsChannel::cleanup-recall:
1144    * @channel: the #AgsChannel
1145    * @recall_id: the appropriate #AgsRecallID
1146    *
1147    * The ::cleanup-recall signal is invoked during termination of playback.
1148    *
1149    * Since: 3.0.0
1150    */
1151   channel_signals[CLEANUP_RECALL] =
1152     g_signal_new("cleanup-recall",
1153 		 G_TYPE_FROM_CLASS(channel),
1154 		 G_SIGNAL_RUN_LAST,
1155 		 G_STRUCT_OFFSET(AgsChannelClass, cleanup_recall),
1156 		 NULL, NULL,
1157 		 g_cclosure_marshal_VOID__OBJECT,
1158 		 G_TYPE_NONE, 1,
1159 		 G_TYPE_OBJECT);
1160 
1161   /**
1162    * AgsChannel::start:
1163    * @channel: the #AgsChannel
1164    * @sound_scope: the sound scope
1165    *
1166    * The ::start signal is invoked as playback starts.
1167    *
1168    * Returns: (type GLib.List) (element-type AgsAudio.RecallID) (transfer full): the #GList-struct containing #AgsRecallID
1169    *
1170    * Since: 3.0.0
1171    */
1172   channel_signals[START] =
1173     g_signal_new("start",
1174 		 G_TYPE_FROM_CLASS(channel),
1175 		 G_SIGNAL_RUN_LAST,
1176 		 G_STRUCT_OFFSET(AgsChannelClass, start),
1177 		 NULL, NULL,
1178 		 ags_cclosure_marshal_POINTER__INT,
1179 		 G_TYPE_POINTER, 1,
1180 		 G_TYPE_INT);
1181 
1182   /**
1183    * AgsChannel::stop:
1184    * @channel: the #AgsChannel
1185    * @recall_id: the #GList-struct containing #AgsRecallID
1186    * @sound_scope: the sound scope
1187    *
1188    * The ::stop signal is invoked as playback stops.
1189    *
1190    * Since: 3.0.0
1191    */
1192   channel_signals[STOP] =
1193     g_signal_new("stop",
1194 		 G_TYPE_FROM_CLASS(channel),
1195 		 G_SIGNAL_RUN_LAST,
1196 		 G_STRUCT_OFFSET(AgsChannelClass, stop),
1197 		 NULL, NULL,
1198 		 ags_cclosure_marshal_VOID__POINTER_INT,
1199 		 G_TYPE_NONE, 2,
1200 		 G_TYPE_POINTER,
1201 		 G_TYPE_INT);
1202 
1203   /**
1204    * AgsChannel::check-scope:
1205    * @channel: the #AgsChannel
1206    * @sound_scope: the sound scope
1207    *
1208    * The ::check-scope signal gives you control of checking scope.
1209    *
1210    * Returns: the #GList-struct containing #AgsRecallID
1211    *
1212    * Since: 3.0.0
1213    */
1214   channel_signals[CHECK_SCOPE] =
1215     g_signal_new("check-scope",
1216 		 G_TYPE_FROM_CLASS(channel),
1217 		 G_SIGNAL_RUN_LAST,
1218 		 G_STRUCT_OFFSET(AgsChannelClass, check_scope),
1219 		 NULL, NULL,
1220 		 ags_cclosure_marshal_POINTER__INT,
1221 		 G_TYPE_POINTER, 1,
1222 		 G_TYPE_INT);
1223 
1224   /**
1225    * AgsChannel::recursive-run-stage:
1226    * @channel: the #AgsChannel
1227    * @sound_scope: the sound scope
1228    * @staging_flags: the staging flags
1229    *
1230    * The ::recursive-run-stage signal gives you control of checking scope.
1231    *
1232    * Since: 3.0.0
1233    */
1234   channel_signals[RECURSIVE_RUN_STAGE] =
1235     g_signal_new("recursive-run-stage",
1236 		 G_TYPE_FROM_CLASS(channel),
1237 		 G_SIGNAL_RUN_LAST,
1238 		 G_STRUCT_OFFSET(AgsChannelClass, recursive_run_stage),
1239 		 NULL, NULL,
1240 		 ags_cclosure_marshal_VOID__INT_UINT,
1241 		 G_TYPE_NONE, 2,
1242 		 G_TYPE_INT,
1243 		 G_TYPE_UINT);
1244 }
1245 
1246 void
ags_channel_connectable_interface_init(AgsConnectableInterface * connectable)1247 ags_channel_connectable_interface_init(AgsConnectableInterface *connectable)
1248 {
1249   connectable->get_uuid = ags_channel_get_uuid;
1250   connectable->has_resource = ags_channel_has_resource;
1251 
1252   connectable->is_ready = ags_channel_is_ready;
1253   connectable->add_to_registry = ags_channel_add_to_registry;
1254   connectable->remove_from_registry = ags_channel_remove_from_registry;
1255 
1256   connectable->list_resource = ags_channel_list_resource;
1257   connectable->xml_compose = ags_channel_xml_compose;
1258   connectable->xml_parse = ags_channel_xml_parse;
1259 
1260   connectable->is_connected = ags_channel_is_connected;
1261   connectable->connect = ags_channel_connect;
1262   connectable->disconnect = ags_channel_disconnect;
1263 
1264   connectable->connect_connection = NULL;
1265   connectable->disconnect_connection = NULL;
1266 }
1267 
1268 GQuark
ags_channel_error_quark()1269 ags_channel_error_quark()
1270 {
1271   return(g_quark_from_static_string("ags-channel-error-quark"));
1272 }
1273 
1274 void
ags_channel_init(AgsChannel * channel)1275 ags_channel_init(AgsChannel *channel)
1276 {
1277   AgsConfig *config;
1278 
1279   gchar *str;
1280 
1281   channel->flags = 0;
1282   channel->ability_flags = 0;
1283   channel->behaviour_flags = 0;
1284   memset(channel->staging_flags, 0, AGS_SOUND_SCOPE_LAST * sizeof(guint));
1285 
1286   memset(channel->staging_completed, FALSE, AGS_SOUND_SCOPE_LAST * sizeof(gboolean));
1287 
1288   /* channel mutex */
1289   g_rec_mutex_init(&(channel->obj_mutex));
1290 
1291   /* uuid */
1292   channel->uuid = ags_uuid_alloc();
1293   ags_uuid_generate(channel->uuid);
1294 
1295   /* config */
1296   config = ags_config_get_instance();
1297 
1298   /* base init */
1299   channel->audio = NULL;
1300 
1301   channel->output_soundcard = NULL;
1302   channel->output_soundcard_channel = -1;
1303 
1304   channel->input_soundcard = NULL;
1305   channel->input_soundcard_channel = 0;
1306 
1307   /* presets */
1308   channel->samplerate = ags_soundcard_helper_config_get_samplerate(config);
1309   channel->buffer_size = ags_soundcard_helper_config_get_buffer_size(config);
1310   channel->format = ags_soundcard_helper_config_get_format(config);
1311 
1312   /* allocation info */
1313   channel->pad = 0;
1314   channel->audio_channel = 0;
1315   channel->line = 0;
1316 
1317   channel->octave = AGS_CHANNEL_DEFAULT_OCTAVE;
1318   channel->key = AGS_CHANNEL_DEFAULT_OCTAVE_SEMITONE;
1319   channel->absolute_key = AGS_CHANNEL_DEFAULT_SEMITONE;
1320 
1321   channel->note_frequency = AGS_CHANNEL_DEFAULT_NOTE_FREQUENCY;
1322   channel->note_key = NULL;
1323 
1324   channel->midi_note = AGS_CHANNEL_DEFAULT_MIDI_NOTE;
1325 
1326   /* inter-connected channels */
1327   channel->prev = NULL;
1328   channel->prev_pad = NULL;
1329   channel->next = NULL;
1330   channel->next_pad = NULL;
1331 
1332   /* link and recycling */
1333   channel->link = NULL;
1334 
1335   channel->first_recycling = NULL;
1336   channel->last_recycling = NULL;
1337 
1338   /* playback */
1339   channel->playback = (GObject *) ags_playback_new((GObject *) channel);
1340   g_object_ref(channel->playback);
1341 
1342   /* pattern */
1343   channel->pattern = NULL;
1344 
1345   /* recall id and recycling context */
1346   channel->recall_id = NULL;
1347   channel->recycling_context = NULL;
1348 
1349   /* recall container */
1350   channel->recall_container = NULL;
1351 
1352   /* play */
1353   g_rec_mutex_init(&(channel->play_mutex));
1354 
1355   channel->play = NULL;
1356 
1357   /* recall */
1358   g_rec_mutex_init(&(channel->recall_mutex));
1359 
1360   channel->recall = NULL;
1361 
1362   /* data */
1363   channel->line_widget = NULL;
1364   channel->file_data = NULL;
1365 }
1366 
1367 void
ags_channel_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)1368 ags_channel_set_property(GObject *gobject,
1369 			 guint prop_id,
1370 			 const GValue *value,
1371 			 GParamSpec *param_spec)
1372 {
1373   AgsChannel *channel;
1374 
1375   GRecMutex *channel_mutex;
1376 
1377   channel = AGS_CHANNEL(gobject);
1378 
1379   /* get channel mutex */
1380   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
1381 
1382   switch(prop_id){
1383   case PROP_AUDIO:
1384   {
1385     AgsAudio *audio;
1386 
1387     audio = (AgsAudio *) g_value_get_object(value);
1388 
1389     g_rec_mutex_lock(channel_mutex);
1390 
1391     if((AgsAudio *) channel->audio == audio){
1392       g_rec_mutex_unlock(channel_mutex);
1393 
1394       return;
1395     }
1396 
1397     if(channel->audio != NULL){
1398       g_object_unref(G_OBJECT(channel->audio));
1399     }
1400 
1401     if(audio != NULL){
1402       g_object_ref(G_OBJECT(audio));
1403     }
1404 
1405     channel->audio = (GObject *) audio;
1406 
1407     g_rec_mutex_unlock(channel_mutex);
1408   }
1409   break;
1410   case PROP_OUTPUT_SOUNDCARD:
1411   {
1412     GObject *output_soundcard;
1413 
1414     output_soundcard = (GObject *) g_value_get_object(value);
1415 
1416     ags_channel_real_set_output_soundcard(channel,
1417 					  output_soundcard);
1418   }
1419   break;
1420   case PROP_OUTPUT_SOUNDCARD_CHANNEL:
1421   {
1422     g_rec_mutex_lock(channel_mutex);
1423 
1424     channel->output_soundcard_channel = g_value_get_int(value);
1425 
1426     g_rec_mutex_unlock(channel_mutex);
1427   }
1428   break;
1429   case PROP_INPUT_SOUNDCARD:
1430   {
1431     GObject *input_soundcard;
1432 
1433     input_soundcard = (GObject *) g_value_get_object(value);
1434 
1435     ags_channel_real_set_input_soundcard(channel,
1436 					 input_soundcard);
1437   }
1438   break;
1439   case PROP_INPUT_SOUNDCARD_CHANNEL:
1440   {
1441     g_rec_mutex_lock(channel_mutex);
1442 
1443     channel->input_soundcard_channel = g_value_get_int(value);
1444 
1445     g_rec_mutex_unlock(channel_mutex);
1446   }
1447   break;
1448   case PROP_SAMPLERATE:
1449   {
1450     guint samplerate;
1451 
1452     samplerate = g_value_get_uint(value);
1453 
1454     ags_channel_real_set_samplerate(channel,
1455 				    samplerate);
1456   }
1457   break;
1458   case PROP_BUFFER_SIZE:
1459   {
1460     guint buffer_size;
1461 
1462     buffer_size = g_value_get_uint(value);
1463 
1464     ags_channel_real_set_buffer_size(channel,
1465 				     buffer_size);
1466   }
1467   break;
1468   case PROP_FORMAT:
1469   {
1470     guint format;
1471 
1472     format = g_value_get_uint(value);
1473 
1474     ags_channel_real_set_format(channel,
1475 				format);
1476   }
1477   break;
1478   case PROP_PAD:
1479   {
1480     g_rec_mutex_lock(channel_mutex);
1481 
1482     channel->pad = g_value_get_uint(value);
1483 
1484     g_rec_mutex_unlock(channel_mutex);
1485   }
1486   break;
1487   case PROP_AUDIO_CHANNEL:
1488   {
1489     g_rec_mutex_lock(channel_mutex);
1490 
1491     channel->audio_channel = g_value_get_uint(value);
1492 
1493     g_rec_mutex_unlock(channel_mutex);
1494   }
1495   break;
1496   case PROP_LINE:
1497   {
1498     g_rec_mutex_lock(channel_mutex);
1499 
1500     channel->line = g_value_get_uint(value);
1501 
1502     g_rec_mutex_unlock(channel_mutex);
1503   }
1504   break;
1505   case PROP_OCTAVE:
1506   {
1507     g_rec_mutex_lock(channel_mutex);
1508 
1509     channel->octave = g_value_get_int(value);
1510 
1511     g_rec_mutex_unlock(channel_mutex);
1512   }
1513   break;
1514   case PROP_KEY:
1515   {
1516     g_rec_mutex_lock(channel_mutex);
1517 
1518     channel->key = g_value_get_uint(value);
1519 
1520     g_rec_mutex_unlock(channel_mutex);
1521   }
1522   break;
1523   case PROP_ABSOLUTE_KEY:
1524   {
1525     g_rec_mutex_lock(channel_mutex);
1526 
1527     channel->absolute_key = g_value_get_int(value);
1528 
1529     g_rec_mutex_unlock(channel_mutex);
1530   }
1531   break;
1532   case PROP_NOTE_FREQUENCY:
1533   {
1534     g_rec_mutex_lock(channel_mutex);
1535 
1536     channel->note_frequency = g_value_get_double(value);
1537 
1538     g_rec_mutex_unlock(channel_mutex);
1539   }
1540   break;
1541   case PROP_NOTE_KEY:
1542   {
1543     gchar *note_key;
1544 
1545     note_key = g_value_get_string(value);
1546 
1547     g_rec_mutex_lock(channel_mutex);
1548 
1549     if(channel->note_key == note_key){
1550       g_rec_mutex_unlock(channel_mutex);
1551 
1552       return;
1553     }
1554 
1555     if(channel->note_key != NULL){
1556       g_free(channel->note_key);
1557     }
1558 
1559     channel->note_key = g_strdup(note_key);
1560 
1561     g_rec_mutex_unlock(channel_mutex);
1562   }
1563   break;
1564   case PROP_MIDI_NOTE:
1565   {
1566     g_rec_mutex_lock(channel_mutex);
1567 
1568     channel->midi_note = g_value_get_uint(value);
1569 
1570     g_rec_mutex_unlock(channel_mutex);
1571   }
1572   break;
1573   case PROP_LINK:
1574   {
1575     AgsChannel *link;
1576 
1577     link = (AgsChannel *) g_value_get_object(value);
1578 
1579     g_rec_mutex_lock(channel_mutex);
1580 
1581     if(channel->link == link){
1582       g_rec_mutex_unlock(channel_mutex);
1583 
1584       return;
1585     }
1586 
1587     g_rec_mutex_unlock(channel_mutex);
1588 
1589     ags_channel_set_link(channel,
1590 			 link,
1591 			 NULL);
1592   }
1593   break;
1594   case PROP_PLAYBACK:
1595   {
1596     AgsPlayback *playback;
1597 
1598     playback = (AgsPlayback *) g_value_get_object(value);
1599 
1600     g_rec_mutex_lock(channel_mutex);
1601 
1602     if(channel->playback == (GObject *) playback){
1603       g_rec_mutex_unlock(channel_mutex);
1604 
1605       return;
1606     }
1607 
1608     if(channel->playback != NULL){
1609       g_object_unref(channel->playback);
1610     }
1611 
1612     if(playback != NULL){
1613       g_object_ref(playback);
1614     }
1615 
1616     channel->playback = (GObject *) playback;
1617 
1618     g_rec_mutex_unlock(channel_mutex);
1619   }
1620   break;
1621   case PROP_PATTERN:
1622   {
1623     AgsPattern *pattern;
1624 
1625     pattern = (AgsPattern *) g_value_get_pointer(value);
1626 
1627     ags_channel_add_pattern(channel,
1628 			    (GObject *) pattern);
1629   }
1630   break;
1631   case PROP_RECALL_ID:
1632   {
1633     AgsRecallID *recall_id;
1634 
1635     recall_id = (AgsRecallID *) g_value_get_pointer(value);
1636 
1637     ags_channel_add_recall_id(channel,
1638 			      recall_id);
1639   }
1640   break;
1641   case PROP_RECYCLING_CONTEXT:
1642   {
1643     AgsRecyclingContext *recycling_context;
1644 
1645     recycling_context = (AgsRecyclingContext *) g_value_get_pointer(value);
1646 
1647     g_rec_mutex_lock(channel_mutex);
1648 
1649     if(recycling_context == NULL ||
1650        g_list_find(channel->recycling_context, recycling_context) != NULL){
1651       g_rec_mutex_unlock(channel_mutex);
1652 
1653       return;
1654     }
1655 
1656     channel->recycling_context = g_list_prepend(channel->recycling_context,
1657 						recycling_context);
1658     g_object_ref(recycling_context);
1659 
1660     g_rec_mutex_unlock(channel_mutex);
1661   }
1662   break;
1663   case PROP_RECALL_CONTAINER:
1664   {
1665     AgsRecallContainer *recall_container;
1666 
1667     recall_container = (AgsRecallContainer *) g_value_get_pointer(value);
1668 
1669     ags_channel_add_recall_container(channel,
1670 				     (GObject *) recall_container);
1671   }
1672   break;
1673   case PROP_PLAY:
1674   {
1675     AgsRecall *play;
1676 
1677     play = (AgsRecall *) g_value_get_pointer(value);
1678 
1679     ags_channel_add_recall(channel,
1680 			   (GObject *) play,
1681 			   TRUE);
1682   }
1683   break;
1684   case PROP_RECALL:
1685   {
1686     AgsRecall *recall;
1687 
1688     /*  */
1689     recall = (AgsRecall *) g_value_get_pointer(value);
1690 
1691     ags_channel_add_recall(channel,
1692 			   (GObject *) recall,
1693 			   FALSE);
1694   }
1695   break;
1696   default:
1697     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
1698     break;
1699   }
1700 }
1701 
1702 void
ags_channel_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)1703 ags_channel_get_property(GObject *gobject,
1704 			 guint prop_id,
1705 			 GValue *value,
1706 			 GParamSpec *param_spec)
1707 {
1708   AgsChannel *channel;
1709 
1710   GRecMutex *channel_mutex;
1711 
1712   channel = AGS_CHANNEL(gobject);
1713 
1714   /* get channel mutex */
1715   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
1716 
1717   switch(prop_id){
1718   case PROP_AUDIO:
1719   {
1720     g_rec_mutex_lock(channel_mutex);
1721 
1722     g_value_set_object(value, channel->audio);
1723 
1724     g_rec_mutex_unlock(channel_mutex);
1725   }
1726   break;
1727   case PROP_OUTPUT_SOUNDCARD:
1728   {
1729     g_rec_mutex_lock(channel_mutex);
1730 
1731     g_value_set_object(value, channel->output_soundcard);
1732 
1733     g_rec_mutex_unlock(channel_mutex);
1734   }
1735   break;
1736   case PROP_OUTPUT_SOUNDCARD_CHANNEL:
1737   {
1738     g_rec_mutex_lock(channel_mutex);
1739 
1740     g_value_set_int(value, channel->output_soundcard_channel);
1741 
1742     g_rec_mutex_unlock(channel_mutex);
1743   }
1744   break;
1745   case PROP_INPUT_SOUNDCARD:
1746   {
1747     g_rec_mutex_lock(channel_mutex);
1748 
1749     g_value_set_object(value,
1750 		       channel->input_soundcard);
1751 
1752     g_rec_mutex_unlock(channel_mutex);
1753   }
1754   break;
1755   case PROP_INPUT_SOUNDCARD_CHANNEL:
1756   {
1757     g_rec_mutex_lock(channel_mutex);
1758 
1759     g_value_set_int(value, channel->input_soundcard_channel);
1760 
1761     g_rec_mutex_unlock(channel_mutex);
1762   }
1763   break;
1764   case PROP_SAMPLERATE:
1765   {
1766     g_rec_mutex_lock(channel_mutex);
1767 
1768     g_value_set_uint(value, channel->samplerate);
1769 
1770     g_rec_mutex_unlock(channel_mutex);
1771   }
1772   break;
1773   case PROP_BUFFER_SIZE:
1774   {
1775     g_rec_mutex_lock(channel_mutex);
1776 
1777     g_value_set_uint(value, channel->buffer_size);
1778 
1779     g_rec_mutex_unlock(channel_mutex);
1780   }
1781   break;
1782   case PROP_FORMAT:
1783   {
1784     g_rec_mutex_lock(channel_mutex);
1785 
1786     g_value_set_uint(value, channel->format);
1787 
1788     g_rec_mutex_unlock(channel_mutex);
1789   }
1790   break;
1791   case PROP_PAD:
1792   {
1793     g_rec_mutex_lock(channel_mutex);
1794 
1795     g_value_set_uint(value, channel->pad);
1796 
1797     g_rec_mutex_unlock(channel_mutex);
1798   }
1799   break;
1800   case PROP_AUDIO_CHANNEL:
1801   {
1802     g_rec_mutex_lock(channel_mutex);
1803 
1804     g_value_set_uint(value, channel->audio_channel);
1805 
1806     g_rec_mutex_unlock(channel_mutex);
1807   }
1808   break;
1809   case PROP_LINE:
1810   {
1811     g_rec_mutex_lock(channel_mutex);
1812 
1813     g_value_set_uint(value, channel->line);
1814 
1815     g_rec_mutex_unlock(channel_mutex);
1816   }
1817   break;
1818   case PROP_ABSOLUTE_KEY:
1819   {
1820     g_rec_mutex_lock(channel_mutex);
1821 
1822     g_value_set_int(value, channel->absolute_key);
1823 
1824     g_rec_mutex_unlock(channel_mutex);
1825   }
1826   break;
1827   case PROP_NOTE_FREQUENCY:
1828   {
1829     g_rec_mutex_lock(channel_mutex);
1830 
1831     g_value_set_double(value, channel->note_frequency);
1832 
1833     g_rec_mutex_unlock(channel_mutex);
1834   }
1835   break;
1836   case PROP_NOTE_KEY:
1837   {
1838     g_rec_mutex_lock(channel_mutex);
1839 
1840     g_value_set_string(value, channel->note_key);
1841 
1842     g_rec_mutex_unlock(channel_mutex);
1843   }
1844   break;
1845   case PROP_MIDI_NOTE:
1846   {
1847     g_rec_mutex_lock(channel_mutex);
1848 
1849     g_value_set_uint(value, channel->midi_note);
1850 
1851     g_rec_mutex_unlock(channel_mutex);
1852   }
1853   break;
1854   case PROP_PREV:
1855   {
1856     g_rec_mutex_lock(channel_mutex);
1857 
1858     g_value_set_object(value, channel->prev);
1859 
1860     g_rec_mutex_unlock(channel_mutex);
1861   }
1862   break;
1863   case PROP_PREV_PAD:
1864   {
1865     g_rec_mutex_lock(channel_mutex);
1866 
1867     g_value_set_object(value, channel->prev_pad);
1868 
1869     g_rec_mutex_unlock(channel_mutex);
1870   }
1871   break;
1872   case PROP_NEXT:
1873   {
1874     g_rec_mutex_lock(channel_mutex);
1875 
1876     g_value_set_object(value, channel->next);
1877 
1878     g_rec_mutex_unlock(channel_mutex);
1879   }
1880   break;
1881   case PROP_NEXT_PAD:
1882   {
1883     g_rec_mutex_lock(channel_mutex);
1884 
1885     g_value_set_object(value, channel->next_pad);
1886 
1887     g_rec_mutex_unlock(channel_mutex);
1888   }
1889   break;
1890   case PROP_LINK:
1891   {
1892     g_rec_mutex_lock(channel_mutex);
1893 
1894     g_value_set_object(value, channel->link);
1895 
1896     g_rec_mutex_unlock(channel_mutex);
1897   }
1898   break;
1899   case PROP_FIRST_RECYCLING:
1900   {
1901     g_rec_mutex_lock(channel_mutex);
1902 
1903     g_value_set_object(value, channel->first_recycling);
1904 
1905     g_rec_mutex_unlock(channel_mutex);
1906   }
1907   break;
1908   case PROP_LAST_RECYCLING:
1909   {
1910     g_rec_mutex_lock(channel_mutex);
1911 
1912     g_value_set_object(value, channel->last_recycling);
1913 
1914     g_rec_mutex_unlock(channel_mutex);
1915   }
1916   break;
1917   case PROP_PLAYBACK:
1918   {
1919     g_rec_mutex_lock(channel_mutex);
1920 
1921     g_value_set_object(value, channel->playback);
1922 
1923     g_rec_mutex_unlock(channel_mutex);
1924   }
1925   break;
1926   case PROP_PATTERN:
1927   {
1928     g_rec_mutex_lock(channel_mutex);
1929 
1930     g_value_set_pointer(value, g_list_copy_deep(channel->pattern,
1931 						(GCopyFunc) g_object_ref,
1932 						NULL));
1933 
1934     g_rec_mutex_unlock(channel_mutex);
1935   }
1936   break;
1937   case PROP_RECALL_ID:
1938   {
1939     g_rec_mutex_lock(channel_mutex);
1940 
1941     g_value_set_pointer(value, g_list_copy_deep(channel->recall_id,
1942 						(GCopyFunc) g_object_ref,
1943 						NULL));
1944 
1945     g_rec_mutex_unlock(channel_mutex);
1946   }
1947   break;
1948   case PROP_RECYCLING_CONTEXT:
1949   {
1950     g_rec_mutex_lock(channel_mutex);
1951 
1952     g_value_set_pointer(value, g_list_copy_deep(channel->recycling_context,
1953 						(GCopyFunc) g_object_ref,
1954 						NULL));
1955 
1956     g_rec_mutex_unlock(channel_mutex);
1957   }
1958   break;
1959   case PROP_RECALL_CONTAINER:
1960   {
1961     g_rec_mutex_lock(channel_mutex);
1962 
1963     g_value_set_pointer(value, g_list_copy_deep(channel->recall_container,
1964 						(GCopyFunc) g_object_ref,
1965 						NULL));
1966 
1967     g_rec_mutex_unlock(channel_mutex);
1968   }
1969   break;
1970   case PROP_PLAY:
1971   {
1972     GRecMutex *play_mutex;
1973 
1974     /* get play mutex */
1975     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
1976 
1977     /*  */
1978     g_rec_mutex_lock(play_mutex);
1979 
1980     g_value_set_pointer(value,
1981 			g_list_copy_deep(channel->play,
1982 					 (GCopyFunc) g_object_ref,
1983 					 NULL));
1984 
1985     g_rec_mutex_unlock(play_mutex);
1986   }
1987   break;
1988   case PROP_RECALL:
1989   {
1990     GRecMutex *recall_mutex;
1991 
1992     /* get recall mutex */
1993     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
1994 
1995     /*  */
1996     g_rec_mutex_lock(recall_mutex);
1997 
1998     g_value_set_pointer(value,
1999 			g_list_copy_deep(channel->recall,
2000 					 (GCopyFunc) g_object_ref,
2001 					 NULL));
2002 
2003     g_rec_mutex_unlock(recall_mutex);
2004   }
2005   break;
2006   default:
2007     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
2008     break;
2009   }
2010 }
2011 
2012 void
ags_channel_dispose(GObject * gobject)2013 ags_channel_dispose(GObject *gobject)
2014 {
2015   AgsChannel *channel;
2016   AgsRecycling *first_recycling, *last_recycling;
2017   AgsRecycling *recycling, *recycling_next;
2018   AgsRecycling *end_region;
2019 
2020   GList *start_list;
2021   GList *list, *list_next;
2022 
2023   gboolean dispose_recycling;
2024 
2025   GRecMutex *play_mutex;
2026   GRecMutex *recall_mutex;
2027 
2028   channel = AGS_CHANNEL(gobject);
2029 
2030   ags_connectable_disconnect(AGS_CONNECTABLE(channel));
2031 
2032   /* audio */
2033   dispose_recycling = FALSE;
2034 
2035   if(channel->audio != NULL){
2036     AgsAudio *audio;
2037 
2038     audio = AGS_AUDIO(channel->audio);
2039 
2040     channel->audio = NULL;
2041 
2042     if((ags_audio_test_flags(audio, AGS_AUDIO_INPUT_HAS_RECYCLING) &&
2043 	AGS_IS_INPUT(channel) &&
2044 	channel->link == NULL) ||
2045        (ags_audio_test_flags(audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING) &&
2046 	AGS_IS_OUTPUT(channel))){
2047       dispose_recycling = TRUE;
2048     }
2049 
2050     g_object_unref(audio);
2051   }
2052 
2053   /* soundcard */
2054   if(channel->output_soundcard != NULL){
2055     gpointer tmp;
2056 
2057     tmp = channel->output_soundcard;
2058 
2059     channel->output_soundcard = NULL;
2060 
2061     g_object_unref(tmp);
2062   }
2063 
2064   if(channel->input_soundcard != NULL){
2065     gpointer tmp;
2066 
2067     tmp = channel->input_soundcard;
2068 
2069     channel->input_soundcard = NULL;
2070 
2071     g_object_unref(tmp);
2072   }
2073 
2074   /* recycling */
2075   recycling =
2076     first_recycling = channel->first_recycling;
2077 
2078   last_recycling = channel->last_recycling;
2079 
2080   channel->first_recycling = NULL;
2081   channel->last_recycling = NULL;
2082 
2083   if(recycling != NULL){
2084     end_region = last_recycling->next;
2085 
2086     while(recycling != end_region){
2087       recycling_next = recycling->next;
2088 
2089       if(dispose_recycling){
2090 	g_object_run_dispose((GObject *) recycling);
2091 	g_object_unref((GObject *) recycling);
2092       }
2093 
2094       recycling = recycling_next;
2095     }
2096   }
2097 
2098   /* playback */
2099   if(channel->playback != NULL){
2100     AgsPlayback *playback;
2101 
2102     playback = (AgsPlayback *) channel->playback;
2103 
2104     channel->playback = NULL;
2105 
2106     //TODO:JK: stop threads
2107     g_object_run_dispose(playback);
2108   }
2109 
2110   /* recall id */
2111   if(channel->recall_id != NULL){
2112     list =
2113       start_list = channel->recall_id;
2114 
2115     channel->recall_id = NULL;
2116 
2117     while(list != NULL){
2118       list_next = list->next;
2119 
2120       g_object_run_dispose(list->data);
2121 
2122       list = list_next;
2123     }
2124 
2125     g_list_free_full(start_list,
2126 		     g_object_unref);
2127   }
2128 
2129   /* recall container */
2130   if(channel->recall_container != NULL){
2131     list =
2132       start_list = channel->recall_container;
2133 
2134     channel->recall_container = NULL;
2135 
2136     while(list != NULL){
2137       AgsRecall *recall_audio;
2138 
2139       GList *recall_audio_run;
2140 
2141       list_next = list->next;
2142 
2143       g_object_get(list->data,
2144 		   "recall-audio", &recall_audio,
2145 		   "recall-audio-run", &recall_audio_run,
2146 		   NULL);
2147 
2148       if(recall_audio == NULL &&
2149 	 recall_audio_run == NULL){
2150 	g_object_run_dispose((GObject *) list->data);
2151       }
2152 
2153       if(recall_audio != NULL){
2154 	g_object_unref(recall_audio);
2155       }
2156 
2157       g_list_free_full(recall_audio_run,
2158 		       g_object_unref);
2159 
2160       list = list_next;
2161     }
2162 
2163     g_list_free_full(start_list,
2164 		     g_object_unref);
2165   }
2166 
2167   /* play */
2168   if(channel->play != NULL){
2169     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
2170 
2171     /* run dispose and unref */
2172     g_rec_mutex_lock(play_mutex);
2173 
2174     list =
2175       start_list = channel->play;
2176 
2177     channel->play = NULL;
2178 
2179     g_rec_mutex_unlock(play_mutex);
2180 
2181     while(list != NULL){
2182       list_next = list->next;
2183 
2184       g_object_run_dispose(list->data);
2185 
2186       list = list_next;
2187     }
2188 
2189     g_list_free_full(start_list,
2190 		     g_object_unref);
2191   }
2192 
2193   /* recall */
2194   if(channel->recall != NULL){
2195     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
2196 
2197     /* run dispose and unref */
2198     g_rec_mutex_lock(recall_mutex);
2199 
2200     list =
2201       start_list = channel->recall;
2202 
2203     channel->recall = NULL;
2204 
2205     while(list != NULL){
2206       list_next = list->next;
2207 
2208       g_object_run_dispose(list->data);
2209 
2210       list = list_next;
2211     }
2212 
2213     g_list_free_full(start_list,
2214 		     g_object_unref);
2215 
2216     g_rec_mutex_unlock(recall_mutex);
2217   }
2218 
2219   /* pattern */
2220   if(channel->pattern != NULL){
2221     list =
2222       start_list = channel->pattern;
2223 
2224     channel->pattern = NULL;
2225 
2226     while(list != NULL){
2227       list_next = list->next;
2228 
2229       g_object_run_dispose((GObject *) list->data);
2230 
2231       list = list_next;
2232     }
2233 
2234     g_list_free_full(start_list,
2235 		     g_object_unref);
2236   }
2237 
2238   /* call parent */
2239   G_OBJECT_CLASS(ags_channel_parent_class)->dispose(gobject);
2240 }
2241 
2242 void
ags_channel_finalize(GObject * gobject)2243 ags_channel_finalize(GObject *gobject)
2244 {
2245   AgsChannel *channel;
2246   AgsRecycling *first_recycling, *last_recycling;
2247   AgsRecycling *recycling, *recycling_next;
2248   AgsRecycling *end_region;
2249 
2250   GList *start_list;
2251   GList *list, *list_next;
2252 
2253   gboolean dispose_recycling;
2254 
2255   GRecMutex *play_mutex;
2256   GRecMutex *recall_mutex;
2257 
2258   channel = AGS_CHANNEL(gobject);
2259 
2260   /* audio */
2261   dispose_recycling = FALSE;
2262 
2263   if(channel->audio != NULL){
2264     AgsAudio *audio;
2265 
2266     audio = channel->audio;
2267 
2268     channel->audio = NULL;
2269 
2270     if((ags_audio_test_flags(audio, AGS_AUDIO_INPUT_HAS_RECYCLING) &&
2271 	AGS_IS_INPUT(channel) &&
2272 	channel->link == NULL) ||
2273        (ags_audio_test_flags(audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING) &&
2274 	AGS_IS_OUTPUT(channel))){
2275       dispose_recycling = TRUE;
2276     }
2277 
2278     g_object_unref(audio);
2279   }
2280 
2281   /* soundcard */
2282   if(channel->output_soundcard != NULL){
2283     gpointer tmp;
2284 
2285     tmp = channel->output_soundcard;
2286 
2287     channel->output_soundcard = NULL;
2288 
2289     g_object_unref(tmp);
2290   }
2291 
2292   if(channel->input_soundcard != NULL){
2293     gpointer tmp;
2294 
2295     tmp = channel->input_soundcard;
2296 
2297     channel->input_soundcard = NULL;
2298 
2299     g_object_unref(tmp);
2300   }
2301 
2302   /* recycling */
2303   recycling =
2304     first_recycling = channel->first_recycling;
2305 
2306   last_recycling = channel->last_recycling;
2307 
2308   channel->first_recycling = NULL;
2309   channel->last_recycling = NULL;
2310 
2311   if(recycling != NULL){
2312     end_region = last_recycling->next;
2313 
2314     while(recycling != end_region){
2315       recycling_next = recycling->next;
2316 
2317       if(dispose_recycling){
2318 	g_object_run_dispose((GObject *) recycling);
2319 	g_object_unref((GObject *) recycling);
2320       }
2321 
2322       recycling = recycling_next;
2323     }
2324   }
2325 
2326   /* key string */
2327   if(channel->note_key != NULL){
2328     free(channel->note_key);
2329   }
2330 
2331   /* playback */
2332   if(channel->playback != NULL){
2333     g_object_unref(channel->playback);
2334   }
2335 
2336   /* recall id */
2337   if(channel->playback != NULL){
2338     AgsPlayback *playback;
2339 
2340     playback = (AgsPlayback *) channel->playback;
2341 
2342     channel->playback = NULL;
2343 
2344     //TODO:JK: stop threads
2345     g_object_run_dispose(playback);
2346   }
2347 
2348   /* recall id */
2349   if(channel->recall_id != NULL){
2350     list =
2351       start_list = channel->recall_id;
2352 
2353     channel->recall_id = NULL;
2354 
2355     while(list != NULL){
2356       list_next = list->next;
2357 
2358       g_object_run_dispose(list->data);
2359 
2360       list = list_next;
2361     }
2362 
2363     g_list_free_full(start_list,
2364 		     g_object_unref);
2365   }
2366 
2367   /* recall container */
2368   if(channel->recall_container != NULL){
2369     list =
2370       start_list = channel->recall_container;
2371 
2372     channel->recall_container = NULL;
2373 
2374     while(list != NULL){
2375       AgsRecall *recall_audio;
2376 
2377       GList *recall_audio_run;
2378 
2379       list_next = list->next;
2380 
2381       g_object_get(list->data,
2382 		   "recall-audio", &recall_audio,
2383 		   "recall-audio-run", &recall_audio_run,
2384 		   NULL);
2385 
2386       if(recall_audio == NULL &&
2387 	 recall_audio_run == NULL){
2388 	g_object_run_dispose((GObject *) list->data);
2389       }
2390 
2391       if(recall_audio != NULL){
2392 	g_object_unref(recall_audio);
2393       }
2394 
2395       g_list_free_full(recall_audio_run,
2396 		       g_object_unref);
2397 
2398       list = list_next;
2399     }
2400 
2401     g_list_free_full(start_list,
2402 		     g_object_unref);
2403   }
2404 
2405   /* play */
2406   if(channel->play != NULL){
2407     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
2408 
2409     /* run dispose and unref */
2410     g_rec_mutex_lock(play_mutex);
2411 
2412     list =
2413       start_list = channel->play;
2414 
2415     channel->play = NULL;
2416 
2417     g_rec_mutex_unlock(play_mutex);
2418 
2419     while(list != NULL){
2420       list_next = list->next;
2421 
2422       g_object_run_dispose(list->data);
2423 
2424       list = list_next;
2425     }
2426 
2427     g_list_free_full(start_list,
2428 		     g_object_unref);
2429   }
2430 
2431   /* recall */
2432   if(channel->recall != NULL){
2433     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
2434 
2435     /* run dispose and unref */
2436     g_rec_mutex_lock(recall_mutex);
2437 
2438     list =
2439       start_list = channel->recall;
2440 
2441     channel->recall = NULL;
2442 
2443     while(list != NULL){
2444       list_next = list->next;
2445 
2446       g_object_run_dispose(list->data);
2447 
2448       list = list_next;
2449     }
2450 
2451     g_list_free_full(start_list,
2452 		     g_object_unref);
2453 
2454     g_rec_mutex_unlock(recall_mutex);
2455   }
2456 
2457   /* pattern */
2458   if(channel->pattern != NULL){
2459     list =
2460       start_list = channel->pattern;
2461 
2462     channel->pattern = NULL;
2463 
2464     while(list != NULL){
2465       list_next = list->next;
2466 
2467       g_object_run_dispose((GObject *) list->data);
2468 
2469       list = list_next;
2470     }
2471 
2472     g_list_free_full(start_list,
2473 		     g_object_unref);
2474   }
2475 
2476   /* call parent class */
2477   G_OBJECT_CLASS(ags_channel_parent_class)->finalize(gobject);
2478 }
2479 
2480 AgsUUID*
ags_channel_get_uuid(AgsConnectable * connectable)2481 ags_channel_get_uuid(AgsConnectable *connectable)
2482 {
2483   AgsChannel *channel;
2484 
2485   AgsUUID *ptr;
2486 
2487   GRecMutex *channel_mutex;
2488 
2489   channel = AGS_CHANNEL(connectable);
2490 
2491   /* get channel signal mutex */
2492   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
2493 
2494   /* get UUID */
2495   g_rec_mutex_lock(channel_mutex);
2496 
2497   ptr = channel->uuid;
2498 
2499   g_rec_mutex_unlock(channel_mutex);
2500 
2501   return(ptr);
2502 }
2503 
2504 gboolean
ags_channel_has_resource(AgsConnectable * connectable)2505 ags_channel_has_resource(AgsConnectable *connectable)
2506 {
2507   return(TRUE);
2508 }
2509 
2510 gboolean
ags_channel_is_ready(AgsConnectable * connectable)2511 ags_channel_is_ready(AgsConnectable *connectable)
2512 {
2513   AgsChannel *channel;
2514 
2515   gboolean is_ready;
2516 
2517   channel = AGS_CHANNEL(connectable);
2518 
2519   /* check is added */
2520   is_ready = ags_channel_test_flags(channel, AGS_CHANNEL_ADDED_TO_REGISTRY);
2521 
2522   return(is_ready);
2523 }
2524 
2525 void
ags_channel_add_to_registry(AgsConnectable * connectable)2526 ags_channel_add_to_registry(AgsConnectable *connectable)
2527 {
2528   AgsChannel *channel;
2529   AgsRecycling *first_recycling, *last_recycling;
2530   AgsRecycling *recycling, *next_recycling, *end_recycling;
2531 
2532   AgsRegistry *registry;
2533   AgsRegistryEntry *entry;
2534 
2535   AgsApplicationContext *application_context;
2536 
2537   GList *start_list, *list;
2538 
2539   if(ags_connectable_is_ready(connectable)){
2540     return;
2541   }
2542 
2543   channel = AGS_CHANNEL(connectable);
2544 
2545   ags_channel_set_flags(channel, AGS_CHANNEL_ADDED_TO_REGISTRY);
2546 
2547   application_context = ags_application_context_get_instance();
2548 
2549   registry = (AgsRegistry *) ags_service_provider_get_registry(AGS_SERVICE_PROVIDER(application_context));
2550 
2551   if(registry != NULL){
2552     entry = ags_registry_entry_alloc(registry);
2553     g_value_set_object(entry->entry,
2554 		       (gpointer) channel);
2555     ags_registry_add_entry(registry,
2556 			   entry);
2557   }
2558 
2559   /* get some fields */
2560   g_object_get(channel,
2561 	       "first-recycling", &first_recycling,
2562 	       "last-recycling", &last_recycling,
2563 	       NULL);
2564 
2565   /* add recycling */
2566   if(first_recycling != NULL){
2567     recycling = first_recycling;
2568     g_object_ref(recycling);
2569 
2570     /* get end recycling */
2571     end_recycling = ags_recycling_next(last_recycling);
2572 
2573     while(recycling != end_recycling){
2574       /* add */
2575       ags_connectable_add_to_registry(AGS_CONNECTABLE(recycling));
2576 
2577       /* iterate */
2578       next_recycling = ags_recycling_next(recycling);
2579 
2580       g_object_unref(recycling);
2581 
2582       recycling = next_recycling;
2583     }
2584 
2585     g_object_unref(first_recycling);
2586     g_object_unref(last_recycling);
2587 
2588     if(end_recycling != NULL){
2589       g_object_unref(end_recycling);
2590     }
2591   }
2592 
2593   /* add play */
2594   g_object_get(channel,
2595 	       "play", &start_list,
2596 	       NULL);
2597 
2598   list = start_list;
2599 
2600   while(list != NULL){
2601     ags_connectable_add_to_registry(AGS_CONNECTABLE(list->data));
2602 
2603     list = list->next;
2604   }
2605 
2606   g_list_free_full(start_list,
2607 		   g_object_unref);
2608 
2609   /* add recall */
2610   g_object_get(channel,
2611 	       "recall", &start_list,
2612 	       NULL);
2613 
2614   list = start_list;
2615 
2616   while(list != NULL){
2617     ags_connectable_add_to_registry(AGS_CONNECTABLE(list->data));
2618 
2619     list = list->next;
2620   }
2621 
2622   g_list_free_full(start_list,
2623 		   g_object_unref);
2624 }
2625 
2626 void
ags_channel_remove_from_registry(AgsConnectable * connectable)2627 ags_channel_remove_from_registry(AgsConnectable *connectable)
2628 {
2629   if(!ags_connectable_is_ready(connectable)){
2630     return;
2631   }
2632 
2633   //TODO:JK: implement me
2634 }
2635 
2636 xmlNode*
ags_channel_list_resource(AgsConnectable * connectable)2637 ags_channel_list_resource(AgsConnectable *connectable)
2638 {
2639   xmlNode *node;
2640 
2641   node = NULL;
2642 
2643   //TODO:JK: implement me
2644 
2645   return(node);
2646 }
2647 
2648 xmlNode*
ags_channel_xml_compose(AgsConnectable * connectable)2649 ags_channel_xml_compose(AgsConnectable *connectable)
2650 {
2651   xmlNode *node;
2652 
2653   node = NULL;
2654 
2655   //TODO:JK: implement me
2656 
2657   return(node);
2658 }
2659 
2660 void
ags_channel_xml_parse(AgsConnectable * connectable,xmlNode * node)2661 ags_channel_xml_parse(AgsConnectable *connectable,
2662 		      xmlNode *node)
2663 {
2664   //TODO:JK: implement me
2665 }
2666 
2667 gboolean
ags_channel_is_connected(AgsConnectable * connectable)2668 ags_channel_is_connected(AgsConnectable *connectable)
2669 {
2670   AgsChannel *channel;
2671 
2672   gboolean is_connected;
2673 
2674   channel = AGS_CHANNEL(connectable);
2675 
2676   /* check is connected */
2677   is_connected = ags_channel_test_flags(channel, AGS_CHANNEL_CONNECTED);
2678 
2679   return(is_connected);
2680 }
2681 
2682 void
ags_channel_connect(AgsConnectable * connectable)2683 ags_channel_connect(AgsConnectable *connectable)
2684 {
2685   AgsChannel *channel;
2686   AgsChannel *link;
2687   AgsRecycling *first_recycling, *last_recycling;
2688   AgsRecycling *recycling, *next_recycling, *end_recycling;
2689 
2690   GList *start_list, *list;
2691 
2692   if(ags_connectable_is_connected(connectable)){
2693     return;
2694   }
2695 
2696   channel = AGS_CHANNEL(connectable);
2697 
2698   ags_channel_set_flags(channel, AGS_CHANNEL_CONNECTED);
2699 
2700 #ifdef AGS_DEBUG
2701   g_message("connecting channel");
2702 #endif
2703 
2704   /* get some fields */
2705   g_object_get(channel,
2706 	       "link", &link,
2707 	       "first-recycling", &first_recycling,
2708 	       "last-recycling", &last_recycling,
2709 	       NULL);
2710 
2711   /* connect recycling */
2712   if(first_recycling != NULL &&
2713      (AGS_IS_OUTPUT(channel) ||
2714       (AGS_IS_INPUT(channel) && link == NULL))){
2715     recycling = first_recycling;
2716     g_object_ref(recycling);
2717 
2718     /* get end recycling */
2719     end_recycling = ags_recycling_next(last_recycling);
2720 
2721     while(recycling != end_recycling){
2722       /* connect */
2723       ags_connectable_connect(AGS_CONNECTABLE(recycling));
2724 
2725       /* iterate */
2726       next_recycling = ags_recycling_next(recycling);
2727 
2728       g_object_unref(recycling);
2729 
2730       recycling = next_recycling;
2731     }
2732 
2733     if(end_recycling != NULL){
2734       g_object_unref(end_recycling);
2735     }
2736   }
2737 
2738   if(link != NULL){
2739     g_object_unref(link);
2740   }
2741 
2742   if(first_recycling != NULL){
2743     g_object_unref(first_recycling);
2744   }
2745 
2746   if(last_recycling != NULL){
2747     g_object_unref(last_recycling);
2748   }
2749 
2750   //NOTE:JK: playback connected by playback domain
2751 
2752   /* connect pattern */
2753   g_object_get(channel,
2754 	       "pattern", &start_list,
2755 	       NULL);
2756 
2757   list = start_list;
2758 
2759   while(list != NULL){
2760     ags_connectable_connect(AGS_CONNECTABLE(list->data));
2761 
2762     list = list->next;
2763   }
2764 
2765   g_list_free_full(start_list,
2766 		   g_object_unref);
2767 
2768   /* connect recall container */
2769   g_object_get(channel,
2770 	       "recall-container", &start_list,
2771 	       NULL);
2772 
2773   list = start_list;
2774 
2775   while(list != NULL){
2776     ags_connectable_connect(AGS_CONNECTABLE(list->data));
2777 
2778     list = list->next;
2779   }
2780 
2781   g_list_free_full(start_list,
2782 		   g_object_unref);
2783 
2784   /* connect recall - play context */
2785   g_object_get(channel,
2786 	       "play", &start_list,
2787 	       NULL);
2788 
2789   list = start_list;
2790 
2791   while(list != NULL){
2792     ags_connectable_connect(AGS_CONNECTABLE(list->data));
2793 
2794     list = list->next;
2795   }
2796 
2797   g_list_free_full(start_list,
2798 		   g_object_unref);
2799 
2800   /* connect recall - recall context */
2801   g_object_get(channel,
2802 	       "recall", &start_list,
2803 	       NULL);
2804 
2805   list = start_list;
2806 
2807   while(list != NULL){
2808     ags_connectable_connect(AGS_CONNECTABLE(list->data));
2809 
2810     list = list->next;
2811   }
2812 
2813   g_list_free_full(start_list,
2814 		   g_object_unref);
2815 }
2816 
2817 void
ags_channel_disconnect(AgsConnectable * connectable)2818 ags_channel_disconnect(AgsConnectable *connectable)
2819 {
2820   AgsChannel *channel;
2821   AgsChannel *link;
2822   AgsRecycling *first_recycling, *last_recycling;
2823   AgsRecycling *recycling, *next_recycling, *end_recycling;
2824 
2825   GList *start_list, *list;
2826 
2827   if(!ags_connectable_is_connected(connectable)){
2828     return;
2829   }
2830 
2831   channel = AGS_CHANNEL(connectable);
2832 
2833   ags_channel_unset_flags(channel, AGS_CHANNEL_CONNECTED);
2834 
2835 #ifdef AGS_DEBUG
2836   g_message("disconnecting channel");
2837 #endif
2838 
2839   /* get some fields */
2840   g_object_get(channel,
2841 	       "link", &link,
2842 	       "first-recycling", &first_recycling,
2843 	       "last-recycling", &last_recycling,
2844 	       NULL);
2845 
2846   /* disconnect recycling */
2847   if(first_recycling != NULL &&
2848      (AGS_IS_OUTPUT(channel) ||
2849       (AGS_IS_INPUT(channel) && link == NULL))){
2850     recycling = first_recycling;
2851     g_object_ref(recycling);
2852 
2853     /* get end recycling */
2854     end_recycling = ags_recycling_next(last_recycling);
2855 
2856     while(recycling != end_recycling){
2857       /* disconnect */
2858       ags_connectable_disconnect(AGS_CONNECTABLE(recycling));
2859 
2860       /* iterate */
2861       next_recycling = ags_recycling_next(recycling);
2862 
2863       g_object_unref(recycling);
2864 
2865       recycling = next_recycling;
2866     }
2867 
2868     if(end_recycling != NULL){
2869       g_object_unref(end_recycling);
2870     }
2871   }
2872 
2873   if(link != NULL){
2874     g_object_unref(link);
2875   }
2876 
2877   if(first_recycling != NULL){
2878     g_object_unref(first_recycling);
2879   }
2880 
2881   if(last_recycling != NULL){
2882     g_object_unref(last_recycling);
2883   }
2884 
2885   /* disconnect pattern */
2886   g_object_get(channel,
2887 	       "pattern", &start_list,
2888 	       NULL);
2889 
2890   list = start_list;
2891 
2892   while(list != NULL){
2893     ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
2894 
2895     list = list->next;
2896   }
2897 
2898   g_list_free_full(start_list,
2899 		   g_object_unref);
2900 
2901   /* disconnect recall container */
2902   g_object_get(channel,
2903 	       "recall-container", &start_list,
2904 	       NULL);
2905 
2906   list = start_list;
2907 
2908   while(list != NULL){
2909     ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
2910 
2911     list = list->next;
2912   }
2913 
2914   g_list_free_full(start_list,
2915 		   g_object_unref);
2916 
2917   /* disconnect recall - play context */
2918   g_object_get(channel,
2919 	       "play", &start_list,
2920 	       NULL);
2921 
2922   list = start_list;
2923 
2924   while(list != NULL){
2925     ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
2926 
2927     list = list->next;
2928   }
2929 
2930   g_list_free_full(start_list,
2931 		   g_object_unref);
2932 
2933   /* disconnect recall - recall context */
2934   g_object_get(channel,
2935 	       "recall", &start_list,
2936 	       NULL);
2937 
2938   list = start_list;
2939 
2940   while(list != NULL){
2941     ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
2942 
2943     list = list->next;
2944   }
2945 
2946   g_list_free_full(start_list,
2947 		   g_object_unref);
2948 }
2949 
2950 /**
2951  * ags_channel_get_obj_mutex:
2952  * @channel: the #AgsChannel
2953  *
2954  * Get object mutex.
2955  *
2956  * Returns: the #GRecMutex to lock @channel
2957  *
2958  * Since: 3.1.0
2959  */
2960 GRecMutex*
ags_channel_get_obj_mutex(AgsChannel * channel)2961 ags_channel_get_obj_mutex(AgsChannel *channel)
2962 {
2963   if(!AGS_IS_CHANNEL(channel)){
2964     return(NULL);
2965   }
2966 
2967   return(AGS_CHANNEL_GET_OBJ_MUTEX(channel));
2968 }
2969 
2970 /**
2971  * ags_channel_get_play_mutex:
2972  * @channel: the #AgsChannel
2973  *
2974  * Get play mutex.
2975  *
2976  * Returns: the #GRecMutex to lock @channel's play property
2977  *
2978  * Since: 3.1.0
2979  */
2980 GRecMutex*
ags_channel_get_play_mutex(AgsChannel * channel)2981 ags_channel_get_play_mutex(AgsChannel *channel)
2982 {
2983   if(!AGS_IS_CHANNEL(channel)){
2984     return(NULL);
2985   }
2986 
2987   return(AGS_CHANNEL_GET_PLAY_MUTEX(channel));
2988 }
2989 
2990 /**
2991  * ags_channel_get_recall_mutex:
2992  * @channel: the #AgsChannel
2993  *
2994  * Get recall mutex.
2995  *
2996  * Returns: the #GRecMutex to lock @channel's recall property
2997  *
2998  * Since: 3.1.0
2999  */
3000 GRecMutex*
ags_channel_get_recall_mutex(AgsChannel * channel)3001 ags_channel_get_recall_mutex(AgsChannel *channel)
3002 {
3003   if(!AGS_IS_CHANNEL(channel)){
3004     return(NULL);
3005   }
3006 
3007   return(AGS_CHANNEL_GET_RECALL_MUTEX(channel));
3008 }
3009 
3010 /**
3011  * ags_channel_test_flags:
3012  * @channel: the #AgsChannel
3013  * @flags: the flags
3014  *
3015  * Test @flags to be set on @channel.
3016  *
3017  * Returns: %TRUE if flags are set, else %FALSE
3018  *
3019  * Since: 3.0.0
3020  */
3021 gboolean
ags_channel_test_flags(AgsChannel * channel,guint flags)3022 ags_channel_test_flags(AgsChannel *channel, guint flags)
3023 {
3024   gboolean retval;
3025 
3026   GRecMutex *channel_mutex;
3027 
3028   if(!AGS_IS_CHANNEL(channel)){
3029     return(FALSE);
3030   }
3031 
3032   /* get channel mutex */
3033   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3034 
3035   /* test */
3036   g_rec_mutex_lock(channel_mutex);
3037 
3038   retval = (flags & (channel->flags)) ? TRUE: FALSE;
3039 
3040   g_rec_mutex_unlock(channel_mutex);
3041 
3042   return(retval);
3043 }
3044 
3045 /**
3046  * ags_channel_set_flags:
3047  * @channel: the #AgsChannel
3048  * @flags: see #AgsChannelFlags-enum
3049  *
3050  * Enable a feature of @channel.
3051  *
3052  * Since: 3.0.0
3053  */
3054 void
ags_channel_set_flags(AgsChannel * channel,guint flags)3055 ags_channel_set_flags(AgsChannel *channel, guint flags)
3056 {
3057   GRecMutex *channel_mutex;
3058 
3059   if(!AGS_IS_CHANNEL(channel)){
3060     return;
3061   }
3062 
3063   /* get channel mutex */
3064   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3065 
3066   //TODO:JK: add more?
3067 
3068   /* set flags */
3069   g_rec_mutex_lock(channel_mutex);
3070 
3071   channel->flags |= flags;
3072 
3073   g_rec_mutex_unlock(channel_mutex);
3074 }
3075 
3076 /**
3077  * ags_channel_unset_flags:
3078  * @channel: the #AgsChannel
3079  * @flags: see #AgsChannelFlags-enum
3080  *
3081  * Disable a feature of @channel.
3082  *
3083  * Since: 3.0.0
3084  */
3085 void
ags_channel_unset_flags(AgsChannel * channel,guint flags)3086 ags_channel_unset_flags(AgsChannel *channel, guint flags)
3087 {
3088   GRecMutex *channel_mutex;
3089 
3090   if(!AGS_IS_CHANNEL(channel)){
3091     return;
3092   }
3093 
3094   /* get channel mutex */
3095   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3096 
3097   //TODO:JK: add more?
3098 
3099   /* unset flags */
3100   g_rec_mutex_lock(channel_mutex);
3101 
3102   channel->flags &= (~flags);
3103 
3104   g_rec_mutex_unlock(channel_mutex);
3105 }
3106 
3107 /**
3108  * ags_channel_test_ability_flags:
3109  * @channel: the #AgsChannel
3110  * @ability_flags: the ability flags
3111  *
3112  * Test @ability_flags to be set on @channel.
3113  *
3114  * Returns: %TRUE if flags are set, else %FALSE
3115  *
3116  * Since: 3.0.0
3117  */
3118 gboolean
ags_channel_test_ability_flags(AgsChannel * channel,guint ability_flags)3119 ags_channel_test_ability_flags(AgsChannel *channel, guint ability_flags)
3120 {
3121   gboolean retval;
3122 
3123   GRecMutex *channel_mutex;
3124 
3125   if(!AGS_IS_CHANNEL(channel)){
3126     return(FALSE);
3127   }
3128 
3129   /* get channel mutex */
3130   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3131 
3132   /* test */
3133   g_rec_mutex_lock(channel_mutex);
3134 
3135   retval = (ability_flags & (channel->ability_flags)) ? TRUE: FALSE;
3136 
3137   g_rec_mutex_unlock(channel_mutex);
3138 
3139   return(retval);
3140 }
3141 
3142 /**
3143  * ags_channel_set_ability_flags:
3144  * @channel: the #AgsChannel
3145  * @ability_flags: see enum AgsSoundAbilityFlags
3146  *
3147  * Enable an ability of AgsChannel.
3148  *
3149  * Since: 3.0.0
3150  */
3151 void
ags_channel_set_ability_flags(AgsChannel * channel,guint ability_flags)3152 ags_channel_set_ability_flags(AgsChannel *channel, guint ability_flags)
3153 {
3154   AgsAudio *audio;
3155   AgsPlaybackDomain *playback_domain;
3156   AgsPlayback *playback;
3157 
3158   GObject *output_soundcard;
3159 
3160   guint samplerate, buffer_size;
3161   guint channel_ability_flags;
3162   gboolean super_threaded_channel;
3163 
3164   GRecMutex *channel_mutex;
3165 
3166   if(!AGS_IS_CHANNEL(channel)){
3167     return;
3168   }
3169 
3170   /* get channel mutex */
3171   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3172 
3173   /* get channel fields */
3174   g_rec_mutex_lock(channel_mutex);
3175 
3176   channel_ability_flags = channel->ability_flags;
3177 
3178   samplerate = channel->samplerate;
3179   buffer_size = channel->buffer_size;
3180 
3181   g_rec_mutex_unlock(channel_mutex);
3182 
3183   audio = NULL;
3184 
3185   g_object_get(channel,
3186 	       "audio", &audio,
3187 	       "output-soundcard", &output_soundcard,
3188 	       "playback", &playback,
3189 	       NULL);
3190 
3191   /* get playback fields */
3192   super_threaded_channel = ags_playback_test_flags(playback, AGS_PLAYBACK_SUPER_THREADED_CHANNEL);
3193 
3194   g_object_get(playback,
3195 	       "playback-domain", &playback_domain,
3196 	       NULL);
3197 
3198   if(super_threaded_channel){
3199     /* playback ability */
3200     if((AGS_SOUND_ABILITY_PLAYBACK & (ability_flags)) != 0 &&
3201        (AGS_SOUND_ABILITY_PLAYBACK & (channel_ability_flags)) == 0){
3202       AgsAudioThread *audio_thread;
3203       AgsChannelThread *channel_thread;
3204 
3205       channel_thread = ags_channel_thread_new(output_soundcard,
3206 					      (GObject *) channel);
3207       ags_channel_thread_set_sound_scope(channel_thread,
3208 					 AGS_SOUND_SCOPE_PLAYBACK);
3209 
3210       g_object_set(channel_thread,
3211 		   "frequency", ceil((gdouble) samplerate / (gdouble) buffer_size) + AGS_SOUNDCARD_DEFAULT_OVERCLOCK,
3212 		   NULL);
3213 
3214       ags_playback_set_channel_thread(playback,
3215 				      (AgsThread *) channel_thread,
3216 				      AGS_SOUND_SCOPE_PLAYBACK);
3217 
3218       /* set thread child */
3219       audio_thread = (AgsAudioThread *) ags_playback_domain_get_audio_thread(playback_domain,
3220 									     AGS_SOUND_SCOPE_PLAYBACK);
3221 
3222       ags_thread_add_child_extended((AgsThread *) audio_thread,
3223 				    (AgsThread *) channel_thread,
3224 				    TRUE, TRUE);
3225     }
3226 
3227     /* sequencer ability */
3228     if((AGS_SOUND_ABILITY_SEQUENCER & (ability_flags)) != 0 &&
3229        (AGS_SOUND_ABILITY_SEQUENCER & (channel_ability_flags)) == 0){
3230       AgsAudioThread *audio_thread;
3231       AgsChannelThread *channel_thread;
3232 
3233       channel_thread = ags_channel_thread_new(output_soundcard,
3234 					      (GObject *) channel);
3235       ags_channel_thread_set_sound_scope(channel_thread,
3236 					 AGS_SOUND_SCOPE_SEQUENCER);
3237 
3238       g_object_set(channel_thread,
3239 		   "frequency", ceil((gdouble) samplerate / (gdouble) buffer_size) + AGS_SOUNDCARD_DEFAULT_OVERCLOCK,
3240 		   NULL);
3241 
3242       ags_playback_set_channel_thread(playback,
3243 				      (AgsThread *) channel_thread,
3244 				      AGS_SOUND_SCOPE_SEQUENCER);
3245 
3246       /* set thread child */
3247       audio_thread = (AgsAudioThread *) ags_playback_domain_get_audio_thread(playback_domain,
3248 									     AGS_SOUND_SCOPE_SEQUENCER);
3249 
3250       ags_thread_add_child_extended((AgsThread *) audio_thread,
3251 				    (AgsThread *) channel_thread,
3252 				    TRUE, TRUE);
3253     }
3254 
3255     /* notation ability */
3256     if((AGS_SOUND_ABILITY_NOTATION & (ability_flags)) != 0 &&
3257        (AGS_SOUND_ABILITY_NOTATION & (channel_ability_flags)) == 0){
3258       AgsAudioThread *audio_thread;
3259       AgsChannelThread *channel_thread;
3260 
3261       channel_thread = ags_channel_thread_new(output_soundcard,
3262 					      (GObject *) channel);
3263       ags_channel_thread_set_sound_scope(channel_thread,
3264 					 AGS_SOUND_SCOPE_NOTATION);
3265 
3266       g_object_set(channel_thread,
3267 		   "frequency", ceil((gdouble) samplerate / (gdouble) buffer_size) + AGS_SOUNDCARD_DEFAULT_OVERCLOCK,
3268 		   NULL);
3269 
3270       ags_playback_set_channel_thread(playback,
3271 				      (AgsThread *) channel_thread,
3272 				      AGS_SOUND_SCOPE_NOTATION);
3273 
3274       /* set thread child */
3275       audio_thread = (AgsAudioThread *) ags_playback_domain_get_audio_thread(playback_domain,
3276 									     AGS_SOUND_SCOPE_NOTATION);
3277       ags_thread_add_child_extended((AgsThread *) audio_thread,
3278 				    (AgsThread *) channel_thread,
3279 				    TRUE, TRUE);
3280     }
3281 
3282     /* wave ability */
3283     if((AGS_SOUND_ABILITY_WAVE & (ability_flags)) != 0 &&
3284        (AGS_SOUND_ABILITY_WAVE & (channel_ability_flags)) == 0){
3285       AgsAudioThread *audio_thread;
3286       AgsChannelThread *channel_thread;
3287 
3288       channel_thread = ags_channel_thread_new(output_soundcard,
3289 					      (GObject *) channel);
3290       ags_channel_thread_set_sound_scope(channel_thread,
3291 					 AGS_SOUND_SCOPE_WAVE);
3292 
3293       g_object_set(channel_thread,
3294 		   "frequency", ceil((gdouble) samplerate / (gdouble) buffer_size) + AGS_SOUNDCARD_DEFAULT_OVERCLOCK,
3295 		   NULL);
3296 
3297       ags_playback_set_channel_thread(playback,
3298 				      (AgsThread *) channel_thread,
3299 				      AGS_SOUND_SCOPE_WAVE);
3300 
3301       /* set thread child */
3302       audio_thread = (AgsAudioThread *) ags_playback_domain_get_audio_thread(playback_domain,
3303 									     AGS_SOUND_SCOPE_WAVE);
3304 
3305       ags_thread_add_child_extended((AgsThread *) audio_thread,
3306 				    (AgsThread *) channel_thread,
3307 				    TRUE, TRUE);
3308     }
3309 
3310     /* midi ability */
3311     if((AGS_SOUND_ABILITY_MIDI & (ability_flags)) != 0 &&
3312        (AGS_SOUND_ABILITY_MIDI & (channel_ability_flags)) == 0){
3313       AgsAudioThread *audio_thread;
3314       AgsChannelThread *channel_thread;
3315 
3316       channel_thread = ags_channel_thread_new(output_soundcard,
3317 					      (GObject *) channel);
3318       ags_channel_thread_set_sound_scope(channel_thread,
3319 					 AGS_SOUND_SCOPE_MIDI);
3320 
3321       g_object_set(channel_thread,
3322 		   "frequency", ceil((gdouble) samplerate / (gdouble) buffer_size) + AGS_SOUNDCARD_DEFAULT_OVERCLOCK,
3323 		   NULL);
3324 
3325       ags_playback_set_channel_thread(playback,
3326 				      (AgsThread *) channel_thread,
3327 				      AGS_SOUND_SCOPE_MIDI);
3328 
3329       /* set thread child */
3330       audio_thread = (AgsAudioThread *) ags_playback_domain_get_audio_thread(playback_domain,
3331 									     AGS_SOUND_SCOPE_MIDI);
3332 
3333       ags_thread_add_child_extended((AgsThread *) audio_thread,
3334 				    (AgsThread *) channel_thread,
3335 				    TRUE, TRUE);
3336     }
3337   }
3338 
3339   /* unref */
3340   if(audio != NULL){
3341     g_object_unref(audio);
3342   }
3343 
3344   if(output_soundcard != NULL){
3345     g_object_unref(output_soundcard);
3346   }
3347 
3348   if(playback_domain != NULL){
3349     g_object_unref(playback_domain);
3350   }
3351 
3352   if(playback != NULL){
3353     g_object_unref(playback);
3354   }
3355 
3356   /* set flags */
3357   g_rec_mutex_lock(channel_mutex);
3358 
3359   channel->ability_flags |= ability_flags;
3360 
3361   g_rec_mutex_unlock(channel_mutex);
3362 }
3363 
3364 /**
3365  * ags_channel_unset_ability_flags:
3366  * @channel: the #AgsChannel
3367  * @ability_flags: see enum AgsSoundAbilityFlags
3368  *
3369  * Disable an ability of AgsChannel.
3370  *
3371  * Since: 3.0.0
3372  */
3373 void
ags_channel_unset_ability_flags(AgsChannel * channel,guint ability_flags)3374 ags_channel_unset_ability_flags(AgsChannel *channel, guint ability_flags)
3375 {
3376   AgsPlaybackDomain *playback_domain;
3377   AgsPlayback *playback;
3378 
3379   guint channel_ability_flags;
3380 
3381   GRecMutex *channel_mutex;
3382 
3383   if(!AGS_IS_CHANNEL(channel)){
3384     return;
3385   }
3386 
3387   /* get channel mutex */
3388   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3389 
3390   /* get channel fields */
3391   g_rec_mutex_lock(channel_mutex);
3392 
3393   channel_ability_flags = channel->ability_flags;
3394 
3395   g_rec_mutex_unlock(channel_mutex);
3396 
3397   g_object_get(channel,
3398 	       "playback", &playback,
3399 	       NULL);
3400 
3401   /* get playback fields */
3402   g_object_get(playback,
3403 	       "playback-domain", &playback_domain,
3404 	       NULL);
3405 
3406   /* playback ability */
3407   if((AGS_SOUND_ABILITY_PLAYBACK & (ability_flags)) == 0 &&
3408      (AGS_SOUND_ABILITY_PLAYBACK & (channel_ability_flags)) != 0){
3409     AgsAudioThread *audio_thread;
3410     AgsChannelThread *channel_thread;
3411 
3412     audio_thread = (AgsAudioThread *) ags_playback_domain_get_audio_thread(playback_domain,
3413 									   AGS_SOUND_SCOPE_PLAYBACK);
3414     channel_thread = (AgsChannelThread *) ags_playback_get_channel_thread(playback,
3415 									  AGS_SOUND_SCOPE_PLAYBACK);
3416     ags_thread_remove_child((AgsThread *) audio_thread,
3417 			    (AgsThread *) channel_thread);
3418 
3419     ags_playback_set_channel_thread(playback,
3420 				    NULL,
3421 				    AGS_SOUND_SCOPE_PLAYBACK);
3422   }
3423 
3424   /* notation ability */
3425   if((AGS_SOUND_ABILITY_NOTATION & (ability_flags)) == 0 &&
3426      (AGS_SOUND_ABILITY_NOTATION & (channel_ability_flags)) != 0){
3427     AgsAudioThread *audio_thread;
3428     AgsChannelThread *channel_thread;
3429 
3430     audio_thread = (AgsAudioThread *) ags_playback_domain_get_audio_thread(playback_domain,
3431 									   AGS_SOUND_SCOPE_NOTATION);
3432     channel_thread = (AgsChannelThread *) ags_playback_get_channel_thread(playback,
3433 									  AGS_SOUND_SCOPE_NOTATION);
3434     ags_thread_remove_child((AgsThread *) audio_thread,
3435 			    (AgsThread *) channel_thread);
3436 
3437     ags_playback_set_channel_thread(playback,
3438 				    NULL,
3439 				    AGS_SOUND_SCOPE_NOTATION);
3440   }
3441 
3442   /* sequencer ability */
3443   if((AGS_SOUND_ABILITY_SEQUENCER & (ability_flags)) == 0 &&
3444      (AGS_SOUND_ABILITY_SEQUENCER & (channel_ability_flags)) != 0){
3445     AgsAudioThread *audio_thread;
3446     AgsChannelThread *channel_thread;
3447 
3448     audio_thread = (AgsAudioThread *) ags_playback_domain_get_audio_thread(playback_domain,
3449 									   AGS_SOUND_SCOPE_SEQUENCER);
3450     channel_thread = (AgsChannelThread *) ags_playback_get_channel_thread(playback,
3451 									  AGS_SOUND_SCOPE_SEQUENCER);
3452     ags_thread_remove_child((AgsThread *) audio_thread,
3453 			    (AgsThread *) channel_thread);
3454 
3455     ags_playback_set_channel_thread(playback,
3456 				    NULL,
3457 				    AGS_SOUND_SCOPE_SEQUENCER);
3458   }
3459 
3460   /* wave ability */
3461   if((AGS_SOUND_ABILITY_WAVE & (ability_flags)) == 0 &&
3462      (AGS_SOUND_ABILITY_WAVE & (channel_ability_flags)) != 0){
3463     AgsAudioThread *audio_thread;
3464     AgsChannelThread *channel_thread;
3465 
3466     audio_thread = (AgsAudioThread *) ags_playback_domain_get_audio_thread(playback_domain,
3467 									   AGS_SOUND_SCOPE_WAVE);
3468     channel_thread = (AgsChannelThread *) ags_playback_get_channel_thread(playback,
3469 									  AGS_SOUND_SCOPE_WAVE);
3470     ags_thread_remove_child((AgsThread *) audio_thread,
3471 			    (AgsThread *) channel_thread);
3472 
3473     ags_playback_set_channel_thread(playback,
3474 				    NULL,
3475 				    AGS_SOUND_SCOPE_WAVE);
3476   }
3477 
3478   /* midi ability */
3479   if((AGS_SOUND_ABILITY_MIDI & (ability_flags)) == 0 &&
3480      (AGS_SOUND_ABILITY_MIDI & (channel_ability_flags)) != 0){
3481     AgsAudioThread *audio_thread;
3482     AgsChannelThread *channel_thread;
3483 
3484     audio_thread = (AgsAudioThread *) ags_playback_domain_get_audio_thread(playback_domain,
3485 									   AGS_SOUND_SCOPE_MIDI);
3486     channel_thread = (AgsChannelThread *) ags_playback_get_channel_thread(playback,
3487 									  AGS_SOUND_SCOPE_MIDI);
3488     ags_thread_remove_child((AgsThread *) audio_thread,
3489 			    (AgsThread *) channel_thread);
3490 
3491     ags_playback_set_channel_thread(playback,
3492 				    NULL,
3493 				    AGS_SOUND_SCOPE_MIDI);
3494   }
3495 
3496   if(playback_domain != NULL){
3497     g_object_unref(playback_domain);
3498   }
3499 
3500   if(playback != NULL){
3501     g_object_unref(playback);
3502   }
3503 
3504   /* unset flags */
3505   g_rec_mutex_lock(channel_mutex);
3506 
3507   channel->ability_flags &= (~ability_flags);
3508 
3509   g_rec_mutex_unlock(channel_mutex);
3510 }
3511 
3512 /**
3513  * ags_channel_test_behaviour_flags:
3514  * @channel: the #AgsChannel
3515  * @behaviour_flags: the behaviour flags
3516  *
3517  * Test @behaviour_flags to be set on @channel.
3518  *
3519  * Returns: %TRUE if flags are set, else %FALSE
3520  *
3521  * Since: 3.0.0
3522  */
3523 gboolean
ags_channel_test_behaviour_flags(AgsChannel * channel,guint behaviour_flags)3524 ags_channel_test_behaviour_flags(AgsChannel *channel, guint behaviour_flags)
3525 {
3526   gboolean retval;
3527 
3528   GRecMutex *channel_mutex;
3529 
3530   if(!AGS_IS_CHANNEL(channel)){
3531     return(FALSE);
3532   }
3533 
3534   /* get channel mutex */
3535   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3536 
3537   /* test */
3538   g_rec_mutex_lock(channel_mutex);
3539 
3540   retval = (behaviour_flags & (channel->behaviour_flags)) ? TRUE: FALSE;
3541 
3542   g_rec_mutex_unlock(channel_mutex);
3543 
3544   return(retval);
3545 }
3546 
3547 /**
3548  * ags_channel_set_behaviour_flags:
3549  * @channel: the #AgsChannel
3550  * @behaviour_flags: the behaviour flags
3551  *
3552  * Set behaviour flags.
3553  *
3554  * Since: 3.0.0
3555  */
3556 void
ags_channel_set_behaviour_flags(AgsChannel * channel,guint behaviour_flags)3557 ags_channel_set_behaviour_flags(AgsChannel *channel, guint behaviour_flags)
3558 {
3559   GRecMutex *channel_mutex;
3560 
3561   if(!AGS_IS_CHANNEL(channel)){
3562     return;
3563   }
3564 
3565   /* get channel mutex */
3566   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3567 
3568   /* set flags */
3569   g_rec_mutex_lock(channel_mutex);
3570 
3571   channel->behaviour_flags |= behaviour_flags;
3572 
3573   g_rec_mutex_unlock(channel_mutex);
3574 }
3575 
3576 /**
3577  * ags_channel_unset_behaviour_flags:
3578  * @channel: the #AgsChannel
3579  * @behaviour_flags: the behaviour flags
3580  *
3581  * Unset behaviour flags.
3582  *
3583  * Since: 3.0.0
3584  */
3585 void
ags_channel_unset_behaviour_flags(AgsChannel * channel,guint behaviour_flags)3586 ags_channel_unset_behaviour_flags(AgsChannel *channel, guint behaviour_flags)
3587 {
3588   GRecMutex *channel_mutex;
3589 
3590   if(!AGS_IS_CHANNEL(channel)){
3591     return;
3592   }
3593 
3594   /* get channel mutex */
3595   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3596 
3597   /* unset flags */
3598   g_rec_mutex_lock(channel_mutex);
3599 
3600   channel->behaviour_flags &= (~behaviour_flags);
3601 
3602   g_rec_mutex_unlock(channel_mutex);
3603 }
3604 
3605 /**
3606  * ags_channel_test_staging_flags:
3607  * @channel: the #AgsChannel
3608  * @sound_scope: the #AgsSoundScope to test
3609  * @staging_flags: the staging flags
3610  *
3611  * Test @staging_flags to be set on @channel.
3612  *
3613  * Returns: %TRUE if flags are set, else %FALSE
3614  *
3615  * Since: 3.0.0
3616  */
3617 gboolean
ags_channel_test_staging_flags(AgsChannel * channel,gint sound_scope,guint staging_flags)3618 ags_channel_test_staging_flags(AgsChannel *channel, gint sound_scope,
3619 			       guint staging_flags)
3620 {
3621   gboolean retval;
3622 
3623   GRecMutex *channel_mutex;
3624 
3625   if(!AGS_IS_CHANNEL(channel)){
3626     return(FALSE);
3627   }
3628 
3629   /* get channel mutex */
3630   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3631 
3632   /* test */
3633   g_rec_mutex_lock(channel_mutex);
3634 
3635   retval = (staging_flags & (channel->staging_flags[sound_scope])) ? TRUE: FALSE;
3636 
3637   g_rec_mutex_unlock(channel_mutex);
3638 
3639   return(retval);
3640 }
3641 
3642 /**
3643  * ags_channel_set_staging_flags:
3644  * @channel: the #AgsChannel
3645  * @sound_scope: the #AgsSoundScope to apply, or -1 to apply to all
3646  * @staging_flags: the staging flags
3647  *
3648  * Set staging flags.
3649  *
3650  * Since: 3.0.0
3651  */
3652 void
ags_channel_set_staging_flags(AgsChannel * channel,gint sound_scope,guint staging_flags)3653 ags_channel_set_staging_flags(AgsChannel *channel, gint sound_scope,
3654 			      guint staging_flags)
3655 {
3656   guint i;
3657 
3658   GRecMutex *channel_mutex;
3659 
3660   if(!AGS_IS_CHANNEL(channel)){
3661     return;
3662   }
3663 
3664   /* get channel mutex */
3665   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3666 
3667   /* set flags */
3668   g_rec_mutex_lock(channel_mutex);
3669 
3670   if(sound_scope < 0){
3671     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
3672       channel->staging_flags[i] |= staging_flags;
3673     }
3674   }else if(sound_scope < AGS_SOUND_SCOPE_LAST){
3675     channel->staging_flags[sound_scope] |= staging_flags;
3676   }
3677 
3678   g_rec_mutex_unlock(channel_mutex);
3679 }
3680 
3681 /**
3682  * ags_channel_unset_staging_flags:
3683  * @channel: the #AgsChannel
3684  * @sound_scope: the #AgsSoundScope to apply, or -1 to apply to all
3685  * @staging_flags: the staging flags
3686  *
3687  * Unset staging flags.
3688  *
3689  * Since: 3.0.0
3690  */
3691 void
ags_channel_unset_staging_flags(AgsChannel * channel,gint sound_scope,guint staging_flags)3692 ags_channel_unset_staging_flags(AgsChannel *channel, gint sound_scope,
3693 				guint staging_flags)
3694 {
3695   guint i;
3696 
3697   GRecMutex *channel_mutex;
3698 
3699   if(!AGS_IS_CHANNEL(channel)){
3700     return;
3701   }
3702 
3703   /* get channel mutex */
3704   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3705 
3706   /* unset flags */
3707   g_rec_mutex_lock(channel_mutex);
3708 
3709   if(sound_scope < 0){
3710     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
3711       channel->staging_flags[i] &= (~staging_flags);
3712     }
3713   }else if(sound_scope < AGS_SOUND_SCOPE_LAST){
3714     channel->staging_flags[sound_scope] &= (~staging_flags);
3715   }
3716 
3717   g_rec_mutex_unlock(channel_mutex);
3718 }
3719 
3720 /**
3721  * ags_channel_test_staging_completed:
3722  * @channel: the #AgsChannel
3723  * @sound_scope: the #AgsSoundScope to test
3724  *
3725  * Test @sound_scope to be completed on @channel.
3726  *
3727  * Returns: %TRUE if completed, otherwise %FALSE
3728  *
3729  * Since: 3.3.0
3730  */
3731 gboolean
ags_channel_test_staging_completed(AgsChannel * channel,gint sound_scope)3732 ags_channel_test_staging_completed(AgsChannel *channel, gint sound_scope)
3733 {
3734   guint i;
3735   gboolean success;
3736 
3737   GRecMutex *channel_mutex;
3738 
3739   if(!AGS_IS_CHANNEL(channel)){
3740     return(FALSE);
3741   }
3742 
3743   /* get channel mutex */
3744   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3745 
3746   /* test staging completed */
3747   success = FALSE;
3748 
3749   g_rec_mutex_lock(channel_mutex);
3750 
3751   if(sound_scope < 0){
3752     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
3753       if(!channel->staging_completed[i]){
3754 	break;
3755       }
3756     }
3757 
3758     if(i == AGS_SOUND_SCOPE_LAST){
3759       success = TRUE;
3760     }
3761   }else if(sound_scope < AGS_SOUND_SCOPE_LAST){
3762     success = channel->staging_completed[sound_scope];
3763   }
3764 
3765   g_rec_mutex_unlock(channel_mutex);
3766 
3767   return(success);
3768 }
3769 
3770 /**
3771  * ags_channel_set_staging_completed:
3772  * @channel: the #AgsChannel
3773  * @sound_scope: the #AgsSoundScope to apply, or -1 to apply to all
3774  *
3775  * Set @sound_scope to be completed.
3776  *
3777  * Since: 3.3.0
3778  */
3779 void
ags_channel_set_staging_completed(AgsChannel * channel,gint sound_scope)3780 ags_channel_set_staging_completed(AgsChannel *channel, gint sound_scope)
3781 {
3782   guint i;
3783 
3784   GRecMutex *channel_mutex;
3785 
3786   if(!AGS_IS_CHANNEL(channel)){
3787     return;
3788   }
3789 
3790   /* get channel mutex */
3791   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3792 
3793   /* test staging completed */
3794   g_rec_mutex_lock(channel_mutex);
3795 
3796   if(sound_scope < 0){
3797     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
3798       channel->staging_completed[i] = TRUE;
3799     }
3800   }else if(sound_scope < AGS_SOUND_SCOPE_LAST){
3801     channel->staging_completed[sound_scope] = TRUE;
3802   }
3803 
3804   g_rec_mutex_unlock(channel_mutex);
3805 }
3806 
3807 /**
3808  * ags_channel_unset_staging_completed:
3809  * @channel: the #AgsChannel
3810  * @sound_scope: the #AgsSoundScope to apply, or -1 to apply to all
3811  *
3812  * Unset @sound_scope to be completed.
3813  *
3814  * Since: 3.3.0
3815  */
3816 void
ags_channel_unset_staging_completed(AgsChannel * channel,gint sound_scope)3817 ags_channel_unset_staging_completed(AgsChannel *channel, gint sound_scope)
3818 {
3819   guint i;
3820 
3821   GRecMutex *channel_mutex;
3822 
3823   if(!AGS_IS_CHANNEL(channel)){
3824     return;
3825   }
3826 
3827   /* get channel mutex */
3828   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3829 
3830   /* test staging completed */
3831   g_rec_mutex_lock(channel_mutex);
3832 
3833   if(sound_scope < 0){
3834     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
3835       channel->staging_completed[i] = FALSE;
3836     }
3837   }else if(sound_scope < AGS_SOUND_SCOPE_LAST){
3838     channel->staging_completed[sound_scope] = FALSE;
3839   }
3840 
3841   g_rec_mutex_unlock(channel_mutex);
3842 }
3843 
3844 /**
3845  * ags_channel_get_audio:
3846  * @channel: the #AgsChannel
3847  *
3848  * Get audio.
3849  *
3850  * Returns: (transfer full): the #AgsAudio
3851  *
3852  * Since: 3.1.0
3853  */
3854 GObject*
ags_channel_get_audio(AgsChannel * channel)3855 ags_channel_get_audio(AgsChannel *channel)
3856 {
3857   GObject *audio;
3858 
3859   if(!AGS_IS_CHANNEL(channel)){
3860     return(NULL);
3861   }
3862 
3863   g_object_get(channel,
3864 	       "audio", &audio,
3865 	       NULL);
3866 
3867   return(audio);
3868 }
3869 
3870 /**
3871  * ags_channel_set_audio:
3872  * @channel: the #AgsChannel
3873  * @audio: the #AgsAudio
3874  *
3875  * Set audio.
3876  *
3877  * Since: 3.1.0
3878  */
3879 void
ags_channel_set_audio(AgsChannel * channel,GObject * audio)3880 ags_channel_set_audio(AgsChannel *channel, GObject *audio)
3881 {
3882   if(!AGS_IS_CHANNEL(channel)){
3883     return;
3884   }
3885 
3886   g_object_set(channel,
3887 	       "audio", audio,
3888 	       NULL);
3889 }
3890 
3891 /**
3892  * ags_channel_next:
3893  * @channel: the #AgsChannel
3894  *
3895  * Iterate @channel.
3896  *
3897  * Returns: (transfer full): the next of #AgsChannel if available, otherwise %NULL
3898  *
3899  * Since: 3.0.0
3900  */
3901 AgsChannel*
ags_channel_next(AgsChannel * channel)3902 ags_channel_next(AgsChannel *channel)
3903 {
3904   AgsChannel *next;
3905 
3906   GRecMutex *channel_mutex;
3907 
3908   if(!AGS_IS_CHANNEL(channel)){
3909     return(NULL);
3910   }
3911 
3912   /* get channel mutex */
3913   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3914 
3915   /* get next */
3916   g_rec_mutex_lock(channel_mutex);
3917 
3918   next = channel->next;
3919 
3920   if(next != NULL){
3921     g_object_ref(next);
3922   }
3923 
3924   g_rec_mutex_unlock(channel_mutex);
3925 
3926   return(next);
3927 }
3928 
3929 /**
3930  * ags_channel_prev:
3931  * @channel: the #AgsChannel
3932  *
3933  * Iterate @channel.
3934  *
3935  * Returns: (transfer full): the prev of #AgsChannel if available, otherwise %NULL
3936  *
3937  * Since: 3.0.0
3938  */
3939 AgsChannel*
ags_channel_prev(AgsChannel * channel)3940 ags_channel_prev(AgsChannel *channel)
3941 {
3942   AgsChannel *prev;
3943 
3944   GRecMutex *channel_mutex;
3945 
3946   if(!AGS_IS_CHANNEL(channel)){
3947     return(NULL);
3948   }
3949 
3950   /* get channel mutex */
3951   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3952 
3953   /* get prev */
3954   g_rec_mutex_lock(channel_mutex);
3955 
3956   prev = channel->prev;
3957 
3958   if(prev != NULL){
3959     g_object_ref(prev);
3960   }
3961 
3962   g_rec_mutex_unlock(channel_mutex);
3963 
3964   return(prev);
3965 }
3966 
3967 /**
3968  * ags_channel_next_pad:
3969  * @channel: the #AgsChannel
3970  *
3971  * Iterate @channel.
3972  *
3973  * Returns: (transfer full): the next pad of #AgsChannel if available, otherwise %NULL
3974  *
3975  * Since: 3.0.0
3976  */
3977 AgsChannel*
ags_channel_next_pad(AgsChannel * channel)3978 ags_channel_next_pad(AgsChannel *channel)
3979 {
3980   AgsChannel *next_pad;
3981 
3982   GRecMutex *channel_mutex;
3983 
3984   if(!AGS_IS_CHANNEL(channel)){
3985     return(NULL);
3986   }
3987 
3988   /* get channel mutex */
3989   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
3990 
3991   /* get next pad */
3992   g_rec_mutex_lock(channel_mutex);
3993 
3994   next_pad = channel->next_pad;
3995 
3996   if(next_pad != NULL){
3997     g_object_ref(next_pad);
3998   }
3999 
4000   g_rec_mutex_unlock(channel_mutex);
4001 
4002   return(next_pad);
4003 }
4004 
4005 /**
4006  * ags_channel_prev_pad:
4007  * @channel: the #AgsChannel
4008  *
4009  * Iterate @channel.
4010  *
4011  * Returns: (transfer full): the prev pad of #AgsChannel if available, otherwise %NULL
4012  *
4013  * Since: 3.0.0
4014  */
4015 AgsChannel*
ags_channel_prev_pad(AgsChannel * channel)4016 ags_channel_prev_pad(AgsChannel *channel)
4017 {
4018   AgsChannel *prev_pad;
4019 
4020   GRecMutex *channel_mutex;
4021 
4022   if(!AGS_IS_CHANNEL(channel)){
4023     return(NULL);
4024   }
4025 
4026   /* get channel mutex */
4027   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4028 
4029   /* get prev pad */
4030   g_rec_mutex_lock(channel_mutex);
4031 
4032   prev_pad = channel->prev_pad;
4033 
4034   if(prev_pad != NULL){
4035     g_object_ref(prev_pad);
4036   }
4037 
4038   g_rec_mutex_unlock(channel_mutex);
4039 
4040   return(prev_pad);
4041 }
4042 
4043 /**
4044  * ags_channel_first:
4045  * @channel: an #AgsChannel
4046  *
4047  * Iterates until the first #AgsChannel was found.
4048  *
4049  * Returns: (transfer full): the first #AgsChannel
4050  *
4051  * Since: 3.0.0
4052  */
4053 AgsChannel*
ags_channel_first(AgsChannel * channel)4054 ags_channel_first(AgsChannel *channel)
4055 {
4056   AgsChannel *prev;
4057 
4058   gboolean has_prev;
4059 
4060   GRecMutex *channel_mutex;
4061 
4062   if(!AGS_IS_CHANNEL(channel)){
4063     return(NULL);
4064   }
4065 
4066   /* first */
4067   channel = ags_channel_pad_first(channel);
4068 
4069   while(channel != NULL){
4070     /* get channel mutex */
4071     channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4072 
4073     /* check prev */
4074     has_prev = TRUE;
4075 
4076     g_rec_mutex_lock(channel_mutex);
4077 
4078     prev = channel->prev;
4079 
4080     if(prev == NULL){
4081       has_prev = FALSE;
4082     }else{
4083       g_object_ref(prev);
4084     }
4085 
4086     g_rec_mutex_unlock(channel_mutex);
4087 
4088     if(!has_prev){
4089       break;
4090     }
4091 
4092     /* iterate */
4093     g_object_unref(channel);
4094 
4095     channel = prev;
4096   }
4097 
4098   return(channel);
4099 }
4100 
4101 /**
4102  * ags_channel_last:
4103  * @channel: an #AgsChannel
4104  *
4105  * Iterates until the last #AgsChannel was found.
4106  *
4107  * Returns: (transfer full): the last #AgsChannel
4108  *
4109  * Since: 3.0.0
4110  */
4111 AgsChannel*
ags_channel_last(AgsChannel * channel)4112 ags_channel_last(AgsChannel *channel)
4113 {
4114   AgsChannel *next;
4115 
4116   gboolean has_next;
4117 
4118   GRecMutex *channel_mutex;
4119 
4120   if(!AGS_IS_CHANNEL(channel)){
4121     return(NULL);
4122   }
4123 
4124   /* last */
4125   channel = ags_channel_pad_last(channel);
4126 
4127   while(channel != NULL){
4128     /* get channel mutex */
4129     channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4130 
4131     /* check next */
4132     has_next = TRUE;
4133 
4134     g_rec_mutex_lock(channel_mutex);
4135 
4136     next = channel->next;
4137 
4138     if(next == NULL){
4139       has_next = FALSE;
4140     }else{
4141       g_object_ref(next);
4142     }
4143 
4144     g_rec_mutex_unlock(channel_mutex);
4145 
4146     if(!has_next){
4147       break;
4148     }
4149 
4150     /* iterate */
4151     g_object_unref(channel);
4152 
4153     channel = next;
4154   }
4155 
4156   return(channel);
4157 }
4158 
4159 /**
4160  * ags_channel_nth:
4161  * @channel: an #AgsChannel
4162  * @nth: the count to iterate
4163  *
4164  * Iterates @nth times forward.
4165  *
4166  * Returns: (transfer full): the nth #AgsChannel
4167  *
4168  * Since: 3.0.0
4169  */
4170 AgsChannel*
ags_channel_nth(AgsChannel * channel,guint nth)4171 ags_channel_nth(AgsChannel *channel, guint nth)
4172 {
4173   AgsChannel *next;
4174 
4175   guint i;
4176 
4177   GRecMutex *channel_mutex;
4178 
4179   if(!AGS_IS_CHANNEL(channel)){
4180     return(NULL);
4181   }
4182 
4183   g_object_ref(channel);
4184 
4185   for(i = 0; i < nth && channel != NULL; i++){
4186     /* get channel mutex */
4187     channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4188 
4189     /* prepare */
4190     g_rec_mutex_lock(channel_mutex);
4191 
4192     next = channel->next;
4193 
4194     if(next != NULL){
4195       g_object_ref(next);
4196     }
4197 
4198     g_rec_mutex_unlock(channel_mutex);
4199 
4200     /* iterate */
4201     g_object_unref(channel);
4202 
4203     channel = next;
4204   }
4205 
4206 #ifdef AGS_DEBUG
4207   if((nth != 0 && i != nth) || channel == NULL){
4208     g_message("ags_channel_nth:\n  nth channel does not exist\n  `- stopped @: i = %u; nth = %u\n", i, nth);
4209   }
4210 #endif
4211 
4212   return(channel);
4213 }
4214 
4215 /**
4216  * ags_channel_pad_first:
4217  * @channel: an #AgsChannel
4218  *
4219  * Iterates until the first pad has been reached.
4220  *
4221  * Returns: (transfer full): the first #AgsChannel with the same audio channel as @channel
4222  *
4223  * Since: 3.0.0
4224  */
4225 AgsChannel*
ags_channel_pad_first(AgsChannel * channel)4226 ags_channel_pad_first(AgsChannel *channel)
4227 {
4228   AgsChannel *prev_pad;
4229 
4230   gboolean has_prev_pad;
4231 
4232   GRecMutex *channel_mutex;
4233 
4234   if(!AGS_IS_CHANNEL(channel)){
4235     return(NULL);
4236   }
4237 
4238   /* pad first */
4239   g_object_ref(channel);
4240 
4241   while(channel != NULL){
4242     /* get channel mutex */
4243     channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4244 
4245     /* check has prev pad */
4246     has_prev_pad = TRUE;
4247 
4248     g_rec_mutex_lock(channel_mutex);
4249 
4250     prev_pad = channel->prev_pad;
4251 
4252     if(prev_pad == NULL){
4253       has_prev_pad = FALSE;
4254     }else{
4255       g_object_ref(prev_pad);
4256     }
4257 
4258     g_rec_mutex_unlock(channel_mutex);
4259 
4260     if(!has_prev_pad){
4261       break;
4262     }
4263 
4264     /* iterate */
4265     g_object_unref(channel);
4266 
4267     channel = prev_pad;
4268   }
4269 
4270   return(channel);
4271 }
4272 
4273 /**
4274  * ags_channel_pad_last:
4275  * @channel: an #AgsChannel
4276  *
4277  * Iterates until the last pad has been reached.
4278  *
4279  * Returns: (transfer full): the last #AgsChannel with the same audio channel as @channel
4280  *
4281  * Since: 3.0.0
4282  */
4283 AgsChannel*
ags_channel_pad_last(AgsChannel * channel)4284 ags_channel_pad_last(AgsChannel *channel)
4285 {
4286   AgsChannel *next_pad;
4287 
4288   gboolean has_next_pad;
4289 
4290   GRecMutex *channel_mutex;
4291 
4292   if(!AGS_IS_CHANNEL(channel)){
4293     return(NULL);
4294   }
4295 
4296   g_object_ref(channel);
4297 
4298   while(channel != NULL){
4299     /* get channel mutex */
4300     channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4301 
4302     /* check has next pad */
4303     has_next_pad = TRUE;
4304 
4305     g_rec_mutex_lock(channel_mutex);
4306 
4307     next_pad = channel->next_pad;
4308 
4309     if(next_pad == NULL){
4310       has_next_pad = FALSE;
4311     }else{
4312       g_object_ref(next_pad);
4313     }
4314 
4315     g_rec_mutex_unlock(channel_mutex);
4316 
4317     if(!has_next_pad){
4318       break;
4319     }
4320 
4321     /* iterate */
4322     g_object_unref(channel);
4323 
4324     channel = next_pad;
4325   }
4326 
4327   return(channel);
4328 }
4329 
4330 /**
4331  * ags_channel_pad_nth:
4332  * @channel: an #AgsChannel
4333  * @nth: the count of pads to step
4334  *
4335  * Iterates nth times.
4336  *
4337  * Returns: (transfer full): the nth pad
4338  *
4339  * Since: 3.0.0
4340  */
4341 AgsChannel*
ags_channel_pad_nth(AgsChannel * channel,guint nth)4342 ags_channel_pad_nth(AgsChannel *channel, guint nth)
4343 {
4344   AgsChannel *next_pad;
4345 
4346   guint i;
4347 
4348   GRecMutex *channel_mutex;
4349 
4350   if(!AGS_IS_CHANNEL(channel)){
4351     return(NULL);
4352   }
4353 
4354   g_object_ref(channel);
4355 
4356   for(i = 0; i < nth && channel != NULL; i++){
4357     /* get channel mutex */
4358     channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4359 
4360     /* prepare */
4361     g_rec_mutex_lock(channel_mutex);
4362 
4363     next_pad = channel->next_pad;
4364 
4365     if(next_pad != NULL){
4366       g_object_ref(next_pad);
4367     }
4368 
4369     g_rec_mutex_unlock(channel_mutex);
4370 
4371     /* iterate */
4372     g_object_unref(channel);
4373 
4374     channel = next_pad;
4375   }
4376 
4377 #ifdef AGS_DEBUG
4378   if(channel == NULL){
4379     g_message("ags_channel_nth_pad:\n  nth pad does not exist\n  `- stopped @: i = %u; nth = %u", i, nth);
4380   }
4381 #endif
4382 
4383   return(channel);
4384 }
4385 
4386 /**
4387  * ags_channel_first_with_recycling:
4388  * @channel: an #AgsChannel
4389  *
4390  * Find first recycling related to @channel.
4391  *
4392  * Returns: (transfer full): the first channel with an #AgsRecycling
4393  *
4394  * Since: 3.0.0
4395  */
4396 AgsChannel*
ags_channel_first_with_recycling(AgsChannel * channel)4397 ags_channel_first_with_recycling(AgsChannel *channel)
4398 {
4399   AgsChannel *next_pad;
4400 
4401   gboolean has_recycling;
4402 
4403   GRecMutex *channel_mutex;
4404 
4405   if(!AGS_IS_CHANNEL(channel)){
4406     return(NULL);
4407   }
4408 
4409   channel = ags_channel_pad_first(channel);
4410 
4411   /* first with recycling */
4412   while(channel != NULL){
4413     /* get channel mutex */
4414     channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4415 
4416     /* check has recycling */
4417     has_recycling = FALSE;
4418 
4419     g_rec_mutex_lock(channel_mutex);
4420 
4421     next_pad = channel->next_pad;
4422 
4423     if(channel->first_recycling != NULL){
4424       has_recycling = TRUE;
4425     }else{
4426       if(next_pad != NULL){
4427 	g_object_ref(next_pad);
4428       }
4429     }
4430 
4431     g_rec_mutex_unlock(channel_mutex);
4432 
4433     if(has_recycling){
4434       break;
4435     }
4436 
4437     /* iterate */
4438     g_object_unref(channel);
4439 
4440     channel = next_pad;
4441   }
4442 
4443   return(channel);
4444 }
4445 
4446 /**
4447  * ags_channel_last_with_recycling:
4448  * @channel: an #AgsChannel
4449  *
4450  * Find last recycling related to @channel.
4451  *
4452  * Returns: (transfer full): the last channel with an #AgsRecycling
4453  *
4454  * Since: 3.0.0
4455  */
4456 AgsChannel*
ags_channel_last_with_recycling(AgsChannel * channel)4457 ags_channel_last_with_recycling(AgsChannel *channel)
4458 {
4459   AgsChannel *prev_pad;
4460 
4461   gboolean has_recycling;
4462 
4463   GRecMutex *channel_mutex;
4464 
4465   if(!AGS_IS_CHANNEL(channel)){
4466     return(NULL);
4467   }
4468 
4469   channel = ags_channel_pad_last(channel);
4470 
4471   while(channel != NULL){
4472     /* get channel mutex */
4473     channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4474 
4475     /* check has recycling */
4476     has_recycling = FALSE;
4477 
4478     g_rec_mutex_lock(channel_mutex);
4479 
4480     prev_pad = channel->prev_pad;
4481 
4482     if(channel->first_recycling != NULL){
4483       has_recycling = TRUE;
4484     }else{
4485       if(prev_pad != NULL){
4486 	g_object_ref(prev_pad);
4487       }
4488     }
4489 
4490     g_rec_mutex_unlock(channel_mutex);
4491 
4492     if(has_recycling){
4493       break;
4494     }
4495 
4496     /* iterate */
4497     g_object_unref(channel);
4498 
4499     channel = prev_pad;
4500   }
4501 
4502   return(channel);
4503 }
4504 
4505 /**
4506  * ags_channel_prev_with_recycling:
4507  * @channel: an #AgsChannel
4508  *
4509  * Find previous #AgsRecycling of @channel.
4510  *
4511  * Returns: (transfer full): the prev channel with an #AgsRecycling
4512  *
4513  * Since: 3.0.0
4514  */
4515 AgsChannel*
ags_channel_prev_with_recycling(AgsChannel * channel)4516 ags_channel_prev_with_recycling(AgsChannel *channel)
4517 {
4518   AgsChannel *current, *prev_pad;
4519   AgsRecycling *recycling;
4520 
4521   GRecMutex *channel_mutex;
4522 
4523   if(!AGS_IS_CHANNEL(channel)){
4524     return(NULL);
4525   }
4526 
4527   /* get channel mutex */
4528   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4529 
4530   /* prev with recycling */
4531   g_rec_mutex_lock(channel_mutex);
4532 
4533   prev_pad = channel->prev_pad;
4534 
4535   if(prev_pad != NULL){
4536     g_object_ref(prev_pad);
4537   }
4538 
4539   g_rec_mutex_unlock(channel_mutex);
4540 
4541   current = prev_pad;
4542 
4543   while(current != NULL && current != channel){
4544     /* get channel mutex */
4545     channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4546 
4547     /* check has recycling */
4548     g_rec_mutex_lock(channel_mutex);
4549 
4550     recycling = current->last_recycling;
4551 
4552     prev_pad = current->prev_pad;
4553 
4554     if(prev_pad != NULL){
4555       g_object_ref(prev_pad);
4556     }
4557 
4558     g_rec_mutex_unlock(channel_mutex);
4559 
4560     if(recycling != NULL){
4561       break;
4562     }
4563 
4564     /* iterate */
4565     g_object_unref(current);
4566 
4567     current = prev_pad;
4568   }
4569 
4570   return(current);
4571 }
4572 
4573 /**
4574  * ags_channel_next_with_recycling:
4575  * @channel: an #AgsChannel
4576  *
4577  * Find next #AgsRecycling of @channel.
4578  *
4579  * Returns: (transfer full): the next channel with an #AgsRecycling
4580  *
4581  * Since: 3.0.0
4582  */
4583 AgsChannel*
ags_channel_next_with_recycling(AgsChannel * channel)4584 ags_channel_next_with_recycling(AgsChannel *channel)
4585 {
4586   AgsChannel *current, *next_pad;
4587   AgsRecycling *recycling;
4588 
4589   GRecMutex *channel_mutex;
4590 
4591   if(!AGS_IS_CHANNEL(channel)){
4592     return(NULL);
4593   }
4594 
4595   /* get channel mutex */
4596   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4597 
4598   /* next with recycling */
4599   g_rec_mutex_lock(channel_mutex);
4600 
4601   next_pad = channel->next_pad;
4602 
4603   if(next_pad != NULL){
4604     g_object_ref(next_pad);
4605   }
4606 
4607   g_rec_mutex_unlock(channel_mutex);
4608 
4609   current = next_pad;
4610 
4611   while(current != NULL){
4612     /* get channel mutex */
4613     channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4614 
4615     /* check has recycling */
4616     g_rec_mutex_lock(channel_mutex);
4617 
4618     recycling = current->first_recycling;
4619 
4620     next_pad = current->next_pad;
4621 
4622     if(next_pad != NULL){
4623       g_object_ref(next_pad);
4624     }
4625 
4626     g_rec_mutex_unlock(channel_mutex);
4627 
4628     if(recycling != NULL){
4629       break;
4630     }
4631 
4632     /* iterate */
4633     g_object_unref(current);
4634 
4635     current = next_pad;
4636   }
4637 
4638   return(current);
4639 }
4640 
4641 /**
4642  * ags_channel_get_link:
4643  * @channel: the #AgsChannel
4644  *
4645  * Ascend/descend @channel.
4646  *
4647  * Returns: (transfer full): the link of #AgsChannel if available, otherwise %NULL
4648  *
4649  * Since: 3.0.0
4650  */
4651 AgsChannel*
ags_channel_get_link(AgsChannel * channel)4652 ags_channel_get_link(AgsChannel *channel)
4653 {
4654   AgsChannel *link;
4655 
4656   GRecMutex *channel_mutex;
4657 
4658   if(!AGS_IS_CHANNEL(channel)){
4659     return(NULL);
4660   }
4661 
4662   /* get channel mutex */
4663   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4664 
4665   /* get next pad */
4666   g_rec_mutex_lock(channel_mutex);
4667 
4668   link = channel->link;
4669 
4670   if(link != NULL){
4671     g_object_ref(link);
4672   }
4673 
4674   g_rec_mutex_unlock(channel_mutex);
4675 
4676   return(link);
4677 }
4678 
4679 gboolean
ags_channel_check_loop(AgsChannel * output,AgsAudio * audio,guint level)4680 ags_channel_check_loop(AgsChannel *output,
4681 		       AgsAudio *audio,
4682 		       guint level)
4683 {
4684   AgsAudio *current_audio;
4685   AgsChannel *link;
4686 
4687   guint current_audio_channel;
4688   guint current_line;
4689   gboolean audio_matches;
4690 
4691   if(output == NULL ||
4692      audio == NULL){
4693     return(FALSE);
4694   }
4695 
4696   current_audio = NULL;
4697 
4698   link = NULL;
4699 
4700   g_object_get(output,
4701 	       "link", &link,
4702 	       NULL);
4703 
4704   if(link == NULL){
4705     return(FALSE);
4706   }
4707 
4708   g_object_get(link,
4709 	       "audio", &current_audio,
4710 	       "audio-channel", &current_audio_channel,
4711 	       "line", &current_line,
4712 	       NULL);
4713 
4714   audio_matches = (audio == current_audio) ? TRUE: FALSE;
4715 
4716   if(!audio_matches){
4717     AgsChannel *current_start_output, *current_output;
4718 
4719     current_start_output = NULL;
4720 
4721     g_object_get(current_audio,
4722 		 "output", &current_start_output,
4723 		 NULL);
4724 
4725     if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
4726       current_output = ags_channel_nth(current_start_output,
4727 				       current_audio_channel);
4728 
4729       while(current_output != NULL){
4730 	AgsChannel *next_pad;
4731 
4732 	audio_matches = ags_channel_check_loop(current_output,
4733 					       audio,
4734 					       level + 1);
4735 
4736 	if(audio_matches){
4737 	  break;
4738 	}
4739 
4740 	/* iterate */
4741 	next_pad = ags_channel_next_pad(current_output);
4742 
4743 	g_object_unref(current_output);
4744 
4745 	current_output = next_pad;
4746       }
4747 
4748       if(current_output != NULL){
4749 	g_object_unref(current_output);
4750       }
4751     }else{
4752       current_output = ags_channel_nth(current_start_output,
4753 				       current_line);
4754 
4755       audio_matches = ags_channel_check_loop(current_output,
4756 					     audio,
4757 					     level + 1);
4758 
4759       if(current_output != NULL){
4760 	g_object_unref(current_output);
4761       }
4762     }
4763 
4764     if(current_start_output != NULL){
4765       g_object_unref(current_start_output);
4766     }
4767   }
4768 
4769   if(current_audio != NULL){
4770     g_object_unref(current_audio);
4771   }
4772 
4773   if(link != NULL){
4774     g_object_unref(link);
4775   }
4776 
4777   return(audio_matches);
4778 }
4779 
4780 /**
4781  * ags_channel_set_link:
4782  * @channel: an #AgsChannel to link
4783  * @link: an other #AgsChannel to link with
4784  * @error: you may retrieve a AGS_CHANNEL_ERROR_LOOP_IN_LINK error
4785  *
4786  * Change the linking of #AgsChannel objects. Sets link, calls ags_channel_reset_recycling().
4787  * Further it does loop detection and makes your machine running.
4788  *
4789  * Since: 3.0.0
4790  */
4791 void
ags_channel_set_link(AgsChannel * channel,AgsChannel * link,GError ** error)4792 ags_channel_set_link(AgsChannel *channel, AgsChannel *link,
4793 		     GError **error)
4794 {
4795   AgsChannel *old_channel_link, *old_link_link;
4796   AgsChannel *old_channel_level, *old_link_level;
4797 
4798   GError *this_error;
4799 
4800   GRecMutex *channel_mutex;
4801   GRecMutex *link_mutex;
4802   GRecMutex *old_channel_link_mutex;
4803   GRecMutex *old_link_link_mutex;
4804 
4805 #ifdef AGS_DEBUG
4806   g_message("set link %x %x", channel, link);
4807 #endif
4808 
4809   if(channel == NULL &&
4810      link == NULL){
4811     return;
4812   }
4813 
4814   if(channel != NULL &&
4815      !AGS_IS_CHANNEL(channel)){
4816     g_warning("ags_channel_set_link() - unsupported type");
4817 
4818     return;
4819   }
4820 
4821   if(link != NULL &&
4822      !AGS_IS_CHANNEL(link)){
4823     g_warning("ags_channel_set_link() - unsupported type");
4824 
4825     return;
4826   }
4827 
4828   /* get channel and link mutex */
4829   channel_mutex = NULL;
4830   link_mutex = NULL;
4831 
4832   if(channel != NULL){
4833     channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
4834   }
4835 
4836   if(link != NULL){
4837     link_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(link);
4838   }
4839 
4840   /* get some fields */
4841   old_channel_link = NULL;
4842   old_link_link = NULL;
4843 
4844   if(channel != NULL){
4845     g_object_get(channel,
4846 		 "link", &old_channel_link,
4847 		 NULL);
4848   }
4849 
4850   if(link != NULL){
4851     g_object_get(link,
4852 		 "link", &old_link_link,
4853 		 NULL);
4854   }
4855 
4856   old_channel_link_mutex = NULL;
4857 
4858   if(old_channel_link != NULL){
4859     old_channel_link_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(old_channel_link);
4860   }
4861 
4862   old_link_link_mutex = NULL;
4863 
4864   if(old_link_link != NULL){
4865     old_link_link_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(old_link_link);
4866   }
4867 
4868   /* check no change */
4869   if(old_channel_link == link){
4870     if(old_channel_link != NULL){
4871       g_object_unref(old_channel_link);
4872     }
4873 
4874     if(old_link_link != NULL){
4875       g_object_unref(old_link_link);
4876     }
4877 
4878     return;
4879   }
4880 
4881   if(old_link_link == channel){
4882     if(old_channel_link != NULL){
4883       g_object_unref(old_channel_link);
4884     }
4885 
4886     if(old_link_link != NULL){
4887       g_object_unref(old_link_link);
4888     }
4889 
4890     return;
4891   }
4892 
4893   /* check for a loop */
4894   if(channel != NULL &&
4895      link != NULL){
4896     AgsAudio *audio;
4897     AgsChannel *start_iter;
4898 
4899     guint level;
4900     gboolean audio_matches;
4901 
4902     audio = NULL;
4903 
4904     start_iter = NULL;
4905 
4906     if(AGS_IS_OUTPUT(channel)){
4907       start_iter = channel;
4908     }else{
4909       start_iter = link;
4910     }
4911 
4912     g_object_ref(start_iter);
4913 
4914     g_object_get(start_iter,
4915 		 "audio", &audio,
4916 		 NULL);
4917 
4918     level = 0;
4919 
4920     audio_matches = ags_channel_check_loop(start_iter,
4921 					   audio,
4922 					   level);
4923 
4924     if(start_iter != NULL){
4925       g_object_unref(start_iter);
4926     }
4927 
4928     if(audio != NULL){
4929       g_object_unref(audio);
4930     }
4931 
4932     if(audio_matches){
4933       if(error != NULL){
4934 	g_set_error(error,
4935 		    AGS_CHANNEL_ERROR,
4936 		    AGS_CHANNEL_ERROR_LOOP_IN_LINK,
4937 		    "failed to link channel");
4938       }
4939 
4940       if(old_channel_link != NULL){
4941 	g_object_unref(old_channel_link);
4942       }
4943 
4944       if(old_link_link != NULL){
4945 	g_object_unref(old_link_link);
4946       }
4947 
4948       return;
4949     }
4950   }
4951 
4952   /* temporary set channel link */
4953   if(channel != NULL){
4954     g_rec_mutex_lock(channel_mutex);
4955 
4956     channel->link = NULL;
4957 
4958     g_rec_mutex_unlock(channel_mutex);
4959   }
4960 
4961   /* temporary set link link */
4962   if(link != NULL){
4963     g_rec_mutex_lock(link_mutex);
4964 
4965     link->link = NULL;
4966 
4967     g_rec_mutex_unlock(link_mutex);
4968   }
4969 
4970   if(channel != NULL &&
4971      old_channel_link != NULL){
4972     /* reset link */
4973     g_rec_mutex_lock(old_channel_link_mutex);
4974 
4975     old_channel_link->link = NULL;
4976 
4977     g_rec_mutex_unlock(old_channel_link_mutex);
4978 
4979     /* emit */
4980     this_error = NULL;
4981 
4982     ags_channel_set_link(old_channel_link,
4983 			 NULL,
4984 			 &this_error);
4985 
4986     g_object_unref(channel);
4987     g_object_unref(old_channel_link);
4988   }
4989 
4990   /* ref count */
4991   if(link != NULL &&
4992      old_link_link != NULL){
4993     /* reset link */
4994     g_rec_mutex_lock(old_link_link_mutex);
4995 
4996     old_link_link->link = NULL;
4997 
4998     g_rec_mutex_unlock(old_link_link_mutex);
4999 
5000     /* emit */
5001     this_error = NULL;
5002 
5003     ags_channel_set_link(old_link_link,
5004 			 NULL,
5005 			 &this_error);
5006 
5007     g_object_unref(link);
5008     g_object_unref(old_link_link);
5009   }
5010 
5011   /* set channel link */
5012   if(channel != NULL){
5013     g_rec_mutex_lock(channel_mutex);
5014 
5015     channel->link = link;
5016 
5017     if(link != NULL){
5018       g_object_ref(link);
5019     }
5020 
5021     g_rec_mutex_unlock(channel_mutex);
5022   }
5023 
5024   /* set link link */
5025   if(link != NULL){
5026     g_rec_mutex_lock(link_mutex);
5027 
5028     link->link = channel;
5029 
5030     if(channel != NULL){
5031       g_object_ref(channel);
5032     }
5033 
5034     g_rec_mutex_unlock(link_mutex);
5035   }
5036 
5037   /* notify link */
5038   if(channel != NULL &&
5039      link != NULL){
5040     ags_channel_set_link(link,
5041 			 channel,
5042 			 &this_error);
5043   }
5044 
5045   /* reset recycling */
5046   if(AGS_IS_OUTPUT(channel)){
5047     if(link != NULL){
5048       AgsRecycling *first_recycling, *last_recycling;
5049 
5050       /* get some fields */
5051       g_rec_mutex_lock(channel_mutex);
5052 
5053       first_recycling = channel->first_recycling;
5054       last_recycling = channel->last_recycling;
5055 
5056       g_rec_mutex_unlock(channel_mutex);
5057 
5058       /* reset */
5059       ags_channel_reset_recycling(link,
5060 				  first_recycling, last_recycling);
5061     }
5062   }
5063 
5064   if(AGS_IS_OUTPUT(link)){
5065     if(channel != NULL){
5066       AgsRecycling *first_recycling, *last_recycling;
5067 
5068       /* get some fields */
5069       g_rec_mutex_lock(link_mutex);
5070 
5071       first_recycling = link->first_recycling;
5072       last_recycling = link->last_recycling;
5073 
5074       g_rec_mutex_unlock(link_mutex);
5075 
5076       /* reset */
5077       ags_channel_reset_recycling(channel,
5078 				  first_recycling, last_recycling);
5079     }
5080   }
5081 
5082   if(AGS_IS_INPUT(channel)){
5083     if(link == NULL){
5084       AgsAudio *audio;
5085       AgsRecycling *first_recycling, *last_recycling;
5086 
5087       GObject *output_soundcard;
5088       GObject *input_soundcard;
5089 
5090       gint output_soundcard_channel;
5091       gint input_soundcard_channel;
5092       guint samplerate;
5093       guint buffer_size;
5094       guint format;
5095 
5096       audio = NULL;
5097 
5098       output_soundcard = NULL;
5099       input_soundcard = NULL;
5100 
5101       output_soundcard_channel = 0;
5102       input_soundcard_channel = 0;
5103 
5104       samplerate = AGS_SOUNDCARD_DEFAULT_SAMPLERATE;
5105       buffer_size = AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE;
5106       format = AGS_SOUNDCARD_DEFAULT_FORMAT;
5107 
5108       g_object_get(channel,
5109 		   "audio", &audio,
5110 		   "output-soundcard", &output_soundcard,
5111 		   "output-soundcard-channel", &output_soundcard_channel,
5112 		   "input-soundcard", &input_soundcard,
5113 		   "input-soundcard-channel", &input_soundcard_channel,
5114 		   "samplerate", &samplerate,
5115 		   "buffer-size", &buffer_size,
5116 		   "format", &format,
5117 		   NULL);
5118 
5119       first_recycling = NULL;
5120       last_recycling = NULL;
5121 
5122       if(ags_audio_test_flags(audio, AGS_AUDIO_INPUT_HAS_RECYCLING)){
5123 	first_recycling =
5124 	  last_recycling = g_object_new(AGS_TYPE_RECYCLING,
5125 					"channel", channel,
5126 					"output-soundcard", output_soundcard,
5127 					"output-soundcard-channel", output_soundcard_channel,
5128 					"input-soundcard", input_soundcard,
5129 					"input-soundcard-channel", input_soundcard_channel,
5130 					"samplerate", samplerate,
5131 					"buffer-size", buffer_size,
5132 					"format", format,
5133 					NULL);
5134       }
5135 
5136       /* reset */
5137       ags_channel_reset_recycling(channel,
5138 				  first_recycling, last_recycling);
5139 
5140       if(audio != NULL){
5141 	g_object_unref(audio);
5142       }
5143 
5144       if(output_soundcard != NULL){
5145 	g_object_unref(output_soundcard);
5146       }
5147 
5148       if(input_soundcard != NULL){
5149 	g_object_unref(input_soundcard);
5150       }
5151     }
5152   }
5153 
5154   if(AGS_IS_INPUT(link)){
5155     if(channel == NULL){
5156       AgsAudio *audio;
5157       AgsRecycling *first_recycling, *last_recycling;
5158 
5159       GObject *output_soundcard;
5160       GObject *input_soundcard;
5161 
5162       gint output_soundcard_channel;
5163       gint input_soundcard_channel;
5164       guint samplerate;
5165       guint buffer_size;
5166       guint format;
5167 
5168       audio = NULL;
5169 
5170       output_soundcard = NULL;
5171       input_soundcard = NULL;
5172 
5173       output_soundcard_channel = 0;
5174       input_soundcard_channel = 0;
5175 
5176       samplerate = AGS_SOUNDCARD_DEFAULT_SAMPLERATE;
5177       buffer_size = AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE;
5178       format = AGS_SOUNDCARD_DEFAULT_FORMAT;
5179 
5180       g_object_get(link,
5181 		   "audio", &audio,
5182 		   "output-soundcard", &output_soundcard,
5183 		   "output-soundcard-channel", &output_soundcard_channel,
5184 		   "input-soundcard", &input_soundcard,
5185 		   "input-soundcard-channel", &input_soundcard_channel,
5186 		   "samplerate", &samplerate,
5187 		   "buffer-size", &buffer_size,
5188 		   "format", &format,
5189 		   NULL);
5190 
5191       first_recycling = NULL;
5192       last_recycling = NULL;
5193 
5194       if(ags_audio_test_flags(audio, AGS_AUDIO_INPUT_HAS_RECYCLING)){
5195 	first_recycling =
5196 	  last_recycling = g_object_new(AGS_TYPE_RECYCLING,
5197 					"channel", link,
5198 					"output-soundcard", output_soundcard,
5199 					"output-soundcard-channel", output_soundcard_channel,
5200 					"input-soundcard", input_soundcard,
5201 					"input-soundcard-channel", input_soundcard_channel,
5202 					"samplerate", samplerate,
5203 					"buffer-size", buffer_size,
5204 					"format", format,
5205 					NULL);
5206       }
5207 
5208       /* reset */
5209       ags_channel_reset_recycling(link,
5210 				  first_recycling, last_recycling);
5211 
5212       if(audio != NULL){
5213 	g_object_unref(audio);
5214       }
5215 
5216       if(output_soundcard != NULL){
5217 	g_object_unref(output_soundcard);
5218       }
5219 
5220       if(input_soundcard != NULL){
5221 	g_object_unref(input_soundcard);
5222       }
5223     }
5224   }
5225 
5226   if(old_channel_link != NULL){
5227     if(AGS_IS_OUTPUT(old_channel_link)){
5228       AgsRecycling *first_recycling, *last_recycling;
5229 
5230       /* get some fields */
5231       g_rec_mutex_lock(old_channel_link_mutex);
5232 
5233       first_recycling = old_channel_link->first_recycling;
5234       last_recycling = old_channel_link->last_recycling;
5235 
5236       g_rec_mutex_unlock(old_channel_link_mutex);
5237 
5238       /* reset */
5239       ags_channel_reset_recycling(old_channel_link,
5240 				  first_recycling, last_recycling);
5241     }else{
5242       AgsAudio *audio;
5243       AgsRecycling *first_recycling, *last_recycling;
5244 
5245       GObject *output_soundcard;
5246       GObject *input_soundcard;
5247 
5248       gint output_soundcard_channel;
5249       gint input_soundcard_channel;
5250       guint samplerate;
5251       guint buffer_size;
5252       guint format;
5253 
5254       audio = NULL;
5255 
5256       output_soundcard = NULL;
5257       input_soundcard = NULL;
5258 
5259       output_soundcard_channel = 0;
5260       input_soundcard_channel = 0;
5261 
5262       samplerate = AGS_SOUNDCARD_DEFAULT_SAMPLERATE;
5263       buffer_size = AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE;
5264       format = AGS_SOUNDCARD_DEFAULT_FORMAT;
5265 
5266       g_object_get(old_channel_link,
5267 		   "audio", &audio,
5268 		   "output-soundcard", &output_soundcard,
5269 		   "output-soundcard-channel", &output_soundcard_channel,
5270 		   "input-soundcard", &input_soundcard,
5271 		   "input-soundcard-channel", &input_soundcard_channel,
5272 		   "samplerate", &samplerate,
5273 		   "buffer-size", &buffer_size,
5274 		   "format", &format,
5275 		   NULL);
5276 
5277       first_recycling = NULL;
5278       last_recycling = NULL;
5279 
5280       if(ags_audio_test_flags(audio, AGS_AUDIO_INPUT_HAS_RECYCLING)){
5281 	first_recycling =
5282 	  last_recycling = g_object_new(AGS_TYPE_RECYCLING,
5283 					"channel", old_channel_link,
5284 					"output-soundcard", output_soundcard,
5285 					"output-soundcard-channel", output_soundcard_channel,
5286 					"input-soundcard", input_soundcard,
5287 					"input-soundcard-channel", input_soundcard_channel,
5288 					"samplerate", samplerate,
5289 					"buffer-size", buffer_size,
5290 					"format", format,
5291 					NULL);
5292       }
5293 
5294       /* reset */
5295       ags_channel_reset_recycling(old_channel_link,
5296 				  first_recycling, last_recycling);
5297 
5298       if(audio != NULL){
5299 	g_object_unref(audio);
5300       }
5301 
5302       if(output_soundcard != NULL){
5303 	g_object_unref(output_soundcard);
5304       }
5305 
5306       if(input_soundcard != NULL){
5307 	g_object_unref(input_soundcard);
5308       }
5309     }
5310   }
5311 
5312   if(old_link_link != NULL){
5313     if(AGS_IS_OUTPUT(old_link_link)){
5314       AgsRecycling *first_recycling, *last_recycling;
5315 
5316       /* get some fields */
5317       g_rec_mutex_lock(old_link_link_mutex);
5318 
5319       first_recycling = old_link_link->first_recycling;
5320       last_recycling = old_link_link->last_recycling;
5321 
5322       g_rec_mutex_unlock(old_link_link_mutex);
5323 
5324       /* reset */
5325       ags_channel_reset_recycling(old_link_link,
5326 				  first_recycling, last_recycling);
5327     }else{
5328       AgsAudio *audio;
5329       AgsRecycling *first_recycling, *last_recycling;
5330 
5331       GObject *output_soundcard;
5332       GObject *input_soundcard;
5333 
5334       gint output_soundcard_channel;
5335       gint input_soundcard_channel;
5336       guint samplerate;
5337       guint buffer_size;
5338       guint format;
5339 
5340       audio = NULL;
5341 
5342       output_soundcard = NULL;
5343       input_soundcard = NULL;
5344 
5345       output_soundcard_channel = 0;
5346       input_soundcard_channel = 0;
5347 
5348       samplerate = AGS_SOUNDCARD_DEFAULT_SAMPLERATE;
5349       buffer_size = AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE;
5350       format = AGS_SOUNDCARD_DEFAULT_FORMAT;
5351 
5352       g_object_get(old_link_link,
5353 		   "audio", &audio,
5354 		   "output-soundcard", &output_soundcard,
5355 		   "output-soundcard-channel", &output_soundcard_channel,
5356 		   "input-soundcard", &input_soundcard,
5357 		   "input-soundcard-channel", &input_soundcard_channel,
5358 		   "samplerate", &samplerate,
5359 		   "buffer-size", &buffer_size,
5360 		   "format", &format,
5361 		   NULL);
5362 
5363       first_recycling = NULL;
5364       last_recycling = NULL;
5365 
5366       if(ags_audio_test_flags(audio, AGS_AUDIO_INPUT_HAS_RECYCLING)){
5367 	first_recycling =
5368 	  last_recycling = g_object_new(AGS_TYPE_RECYCLING,
5369 					"channel", old_link_link,
5370 					"output-soundcard", output_soundcard,
5371 					"output-soundcard-channel", output_soundcard_channel,
5372 					"input-soundcard", input_soundcard,
5373 					"input-soundcard-channel", input_soundcard_channel,
5374 					"samplerate", samplerate,
5375 					"buffer-size", buffer_size,
5376 					"format", format,
5377 					NULL);
5378       }
5379 
5380       /* reset */
5381       ags_channel_reset_recycling(old_link_link,
5382 				  first_recycling, last_recycling);
5383 
5384       if(audio != NULL){
5385 	g_object_unref(audio);
5386       }
5387 
5388       if(output_soundcard != NULL){
5389 	g_object_unref(output_soundcard);
5390       }
5391 
5392       if(input_soundcard != NULL){
5393 	g_object_unref(input_soundcard);
5394       }
5395     }
5396   }
5397 
5398   /* reset soundcard */
5399   if((AGS_IS_OUTPUT(channel) &&
5400       AGS_IS_INPUT(link)) ||
5401      (AGS_IS_INPUT(channel) &&
5402       AGS_IS_OUTPUT(link))){
5403     AgsChannel *current, *current_link;
5404 
5405     GObject *output_soundcard;
5406 
5407     gint output_soundcard_channel;
5408     guint n_params;
5409 
5410     GValue *value;
5411 
5412     static const gchar* parameter_name[] = {
5413       "output-soundcard",
5414       "output-soundcard-channel",
5415       NULL,
5416     };
5417 
5418 
5419     if(AGS_IS_INPUT(channel)){
5420       current = channel;
5421       current_link = link;
5422     }else{
5423       current = link;
5424       current_link = channel;
5425     }
5426 
5427     /* get some fields */
5428     output_soundcard = NULL;
5429 
5430     output_soundcard_channel = 0;
5431 
5432     g_object_get(current,
5433 		 "output-soundcard", &output_soundcard,
5434 		 "output-soundcard-channel", &output_soundcard_channel,
5435 		 NULL);
5436 
5437     /* allocate parameter name and value */
5438     n_params = 2;
5439 
5440     value = g_new0(GValue,
5441 		   n_params);
5442 
5443     /* output soundcard */
5444     g_value_init(&(value[0]),
5445 		 G_TYPE_OBJECT);
5446     g_value_set_object(&(value[0]),
5447 		       output_soundcard);
5448 
5449     /* output soundcard channel */
5450     g_value_init(&(value[1]),
5451 		 G_TYPE_INT);
5452     g_value_set_int(&(value[1]),
5453 		    output_soundcard_channel);
5454 
5455     /* recursive set property */
5456     ags_channel_recursive_set_property(current_link,
5457 				       n_params,
5458 				       parameter_name, value);
5459 
5460     if(output_soundcard != NULL){
5461       g_object_unref(output_soundcard);
5462     }
5463   }
5464 
5465   /* unset recall id - old channel */
5466   if(AGS_IS_INPUT(old_channel_link)){
5467     old_channel_level = ags_channel_get_level(old_channel_link);
5468 
5469     if(old_channel_level == NULL){
5470       gint i;
5471 
5472       for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
5473 	GList *recall_id;
5474 
5475 	recall_id = ags_channel_check_scope(old_channel_link, i);
5476 
5477 	if(recall_id != NULL){
5478 	  ags_channel_recursive_run_stage(old_channel_link,
5479 					  i, (AGS_SOUND_STAGING_CANCEL |
5480 					      AGS_SOUND_STAGING_DONE |
5481 					      AGS_SOUND_STAGING_REMOVE));
5482 
5483 	  g_list_free_full(recall_id,
5484 			   g_object_unref);
5485 	}
5486       }
5487     }else{
5488       g_object_unref(old_channel_level);
5489     }
5490   }
5491 
5492   /* unset recall id - old link */
5493   if(AGS_IS_INPUT(old_link_link)){
5494     old_link_level = ags_channel_get_level(old_link_link);
5495 
5496     if(old_link_level == NULL){
5497       gint i;
5498 
5499       for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
5500 	GList *recall_id;
5501 
5502 	recall_id = ags_channel_check_scope(old_link_link, i);
5503 
5504 	if(recall_id != NULL){
5505 	  ags_channel_recursive_run_stage(old_link_link,
5506 					  i, (AGS_SOUND_STAGING_CANCEL |
5507 					      AGS_SOUND_STAGING_DONE |
5508 					      AGS_SOUND_STAGING_REMOVE));
5509 
5510 	  g_list_free_full(recall_id,
5511 			   g_object_unref);
5512 	}
5513       }
5514     }else{
5515       g_object_unref(old_link_level);
5516     }
5517   }
5518 
5519   /* reset recall id */
5520   if(channel != NULL){
5521     gint i;
5522 
5523     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
5524       GList *recall_id;
5525 
5526       recall_id = ags_channel_check_scope(channel, i);
5527 
5528       if(recall_id != NULL){
5529 	ags_channel_recursive_run_stage(link,
5530 					i, (AGS_SOUND_STAGING_CHECK_RT_DATA |
5531 					    AGS_SOUND_STAGING_RUN_INIT_PRE |
5532 					    AGS_SOUND_STAGING_RUN_INIT_INTER |
5533 					    AGS_SOUND_STAGING_RUN_INIT_POST));
5534 
5535 	g_list_free_full(recall_id,
5536 			 g_object_unref);
5537       }
5538     }
5539   }
5540 
5541   if(link != NULL){
5542     gint i;
5543 
5544     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
5545       GList *recall_id;
5546 
5547       recall_id = ags_channel_check_scope(link, i);
5548 
5549       if(recall_id != NULL){
5550 	ags_channel_recursive_run_stage(channel,
5551 					i, (AGS_SOUND_STAGING_CHECK_RT_DATA |
5552 					    AGS_SOUND_STAGING_RUN_INIT_PRE |
5553 					    AGS_SOUND_STAGING_RUN_INIT_INTER |
5554 					    AGS_SOUND_STAGING_RUN_INIT_POST));
5555 
5556 	g_list_free_full(recall_id,
5557 			 g_object_unref);
5558       }
5559     }
5560   }
5561 
5562   if(old_channel_link != NULL){
5563     g_object_unref(old_channel_link);
5564   }
5565 
5566   if(old_link_link != NULL){
5567     g_object_unref(old_link_link);
5568   }
5569 }
5570 
5571 gboolean
ags_channel_reset_recycling_recursive_input(AgsChannel * input,AgsAudio ** found_next,AgsAudio ** found_prev,AgsChannel ** next_channel,AgsChannel ** prev_channel,AgsRecycling ** replace_with_first_recycling,AgsRecycling ** replace_with_last_recycling,guint * complete_level_first,guint * complete_level_last,gboolean * find_next,gboolean * find_prev,gboolean * replace_first,gboolean * replace_last)5572 ags_channel_reset_recycling_recursive_input(AgsChannel *input,
5573 					    AgsAudio **found_next, AgsAudio **found_prev,
5574 					    AgsChannel **next_channel, AgsChannel **prev_channel,
5575 					    AgsRecycling **replace_with_first_recycling, AgsRecycling **replace_with_last_recycling,
5576 					    guint *complete_level_first, guint *complete_level_last,
5577 					    gboolean *find_next, gboolean *find_prev,
5578 					    gboolean *replace_first, gboolean *replace_last)
5579 {
5580   AgsAudio *audio;
5581   AgsChannel *nth_channel_prev, *nth_channel_next;
5582 
5583   guint audio_flags;
5584 
5585   GRecMutex *audio_mutex;
5586   GRecMutex *input_mutex;
5587   GRecMutex *next_channel_mutex;
5588   GRecMutex *prev_channel_mutex;
5589 
5590   if(input == NULL){
5591     return(TRUE);
5592   }
5593 
5594   /* get input mutex */
5595   input_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(input);
5596 
5597   /* check done */
5598   g_rec_mutex_lock(input_mutex);
5599 
5600   if((input->first_recycling == replace_with_first_recycling[0] &&
5601       input->last_recycling == replace_with_last_recycling[0])){
5602     g_rec_mutex_unlock(input_mutex);
5603 
5604     return(TRUE);
5605   }
5606 
5607   /* set recycling */
5608   if(replace_first[0]){
5609     input->first_recycling = replace_with_first_recycling[0];
5610   }
5611 
5612   if(replace_last[0]){
5613     input->last_recycling = replace_with_last_recycling[0];
5614   }
5615 
5616   g_rec_mutex_unlock(input_mutex);
5617 
5618   /* search for neighboor recyclings */
5619   audio = NULL;
5620 
5621   g_object_get(input,
5622 	       "audio", &audio,
5623 	       NULL);
5624 
5625   /* get audio mutex */
5626   audio_mutex = AGS_AUDIO_GET_OBJ_MUTEX(audio);
5627 
5628   /* audio flags */
5629   g_rec_mutex_lock(audio_mutex);
5630 
5631   audio_flags = audio->flags;
5632 
5633   g_rec_mutex_unlock(audio_mutex);
5634 
5635   if((AGS_AUDIO_ASYNC & (audio_flags)) != 0){
5636     if(find_prev[0]){
5637       nth_channel_prev = ags_channel_prev_with_recycling(input);
5638 
5639       if(nth_channel_prev != NULL){
5640 #ifdef AGS_DEBUG
5641 	g_message("found prev");
5642 #endif
5643 	find_prev[0] = FALSE;
5644 	replace_first[0] = FALSE;
5645 
5646 	if(complete_level_first[0] == 0){
5647 	  found_prev[0] = audio;
5648 	  prev_channel[0] = nth_channel_prev;
5649 
5650 	  complete_level_first[0] = 1;
5651 	}
5652 
5653 	g_object_unref(nth_channel_prev);
5654       }
5655     }else{
5656       nth_channel_prev = ags_channel_prev_with_recycling(input);
5657 
5658       if(nth_channel_prev != NULL){
5659 	g_object_unref(nth_channel_prev);
5660       }
5661     }
5662 
5663     if(find_next[0]){
5664       nth_channel_next = ags_channel_next_with_recycling(input);
5665 
5666       if(nth_channel_next != NULL){
5667 #ifdef AGS_DEBUG
5668 	g_message("found next");
5669 #endif
5670 
5671 	find_next[0] = FALSE;
5672 	replace_last[0] = FALSE;
5673 
5674 	if(complete_level_last[0] == 0){
5675 	  found_next[0] = audio;
5676 	  next_channel[0] = nth_channel_next;
5677 
5678 	  complete_level_last[0] = 1;
5679 	}
5680 
5681 	g_object_unref(nth_channel_next);
5682       }
5683     }else{
5684       nth_channel_next = ags_channel_next_with_recycling(input);
5685 
5686       if(nth_channel_next != NULL){
5687 	g_object_unref(nth_channel_next);
5688       }
5689     }
5690 
5691     if(prev_channel[0] != NULL){
5692       if(next_channel[0] == NULL){
5693 	if(replace_with_last_recycling[0] == NULL){
5694 	  /* get prev channel mutex */
5695 	  prev_channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(prev_channel[0]);
5696 
5697 	  /* prev channel */
5698 	  g_rec_mutex_lock(prev_channel_mutex);
5699 
5700 	  replace_with_last_recycling[0] = prev_channel[0]->last_recycling;
5701 
5702 	  g_rec_mutex_unlock(prev_channel_mutex);
5703 
5704 	  /* continues flag */
5705 	  find_next[0] = FALSE;
5706 	}
5707       }else{
5708 	/* get prev and next channel mutex */
5709 	prev_channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(prev_channel[0]);
5710 	next_channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(next_channel[0]);
5711 
5712 	/* prev channel */
5713 	g_rec_mutex_lock(prev_channel_mutex);
5714 
5715 	replace_with_last_recycling[0] = prev_channel[0]->last_recycling;
5716 
5717 	g_rec_mutex_unlock(prev_channel_mutex);
5718 
5719 	/* next channel */
5720 	g_rec_mutex_lock(next_channel_mutex);
5721 
5722 	replace_with_first_recycling[0] = next_channel[0]->first_recycling;
5723 
5724 	g_rec_mutex_unlock(next_channel_mutex);
5725       }
5726     }else{
5727       if(next_channel[0] != NULL){
5728 	if(replace_with_first_recycling[0] == NULL){
5729 	  /* get prev and next channel mutex */
5730 	  next_channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(next_channel[0]);
5731 
5732 	  /* next channel */
5733 	  g_rec_mutex_lock(next_channel_mutex);
5734 
5735 	  replace_with_first_recycling[0] = next_channel[0]->first_recycling;
5736 
5737 	  g_rec_mutex_unlock(next_channel_mutex);
5738 
5739 	  /* continues flag */
5740 	  find_prev[0] = FALSE;
5741 	}
5742       }
5743     }
5744   }
5745 
5746   if(audio != NULL){
5747     g_object_unref(audio);
5748   }
5749 
5750   if(replace_first[0] || replace_last[0]){
5751     return(FALSE);
5752   }else{
5753     return(TRUE);
5754   }
5755 }
5756 
5757 void
ags_channel_reset_recycling_recursive_output(AgsChannel * output,AgsAudio ** found_next,AgsAudio ** found_prev,AgsChannel ** next_channel,AgsChannel ** prev_channel,AgsRecycling ** replace_with_first_recycling,AgsRecycling ** replace_with_last_recycling,guint * complete_level_first,guint * complete_level_last,gboolean * find_next,gboolean * find_prev,gboolean * replace_first,gboolean * replace_last)5758 ags_channel_reset_recycling_recursive_output(AgsChannel *output,
5759 					     AgsAudio **found_next, AgsAudio **found_prev,
5760 					     AgsChannel **next_channel, AgsChannel **prev_channel,
5761 					     AgsRecycling **replace_with_first_recycling, AgsRecycling **replace_with_last_recycling,
5762 					     guint *complete_level_first, guint *complete_level_last,
5763 					     gboolean *find_next, gboolean *find_prev,
5764 					     gboolean *replace_first, gboolean *replace_last)
5765 {
5766   AgsAudio *audio;
5767   AgsChannel *input;
5768   AgsChannel *link;
5769   AgsChannel *nth_channel_prev, *nth_channel_next;
5770   AgsRecycling *first_recycling, *last_recycling;
5771 
5772   guint audio_flags;
5773   guint audio_channel;
5774 
5775   GRecMutex *audio_mutex;
5776   GRecMutex *output_mutex;
5777 
5778   if(output == NULL){
5779     return;
5780   }
5781 
5782   /* get output mutex */
5783   output_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(output);
5784 
5785   /* get audio and audio channel */
5786   g_rec_mutex_lock(output_mutex);
5787 
5788   audio_channel = output->audio_channel;
5789 
5790   g_rec_mutex_unlock(output_mutex);
5791 
5792   audio = NULL;
5793 
5794   g_object_get(output,
5795 	       "audio", &audio,
5796 	       NULL);
5797 
5798   if(audio == NULL){
5799     return;
5800   }
5801 
5802   /* get audio mutex */
5803   audio_mutex = AGS_AUDIO_GET_OBJ_MUTEX(audio);
5804 
5805   /* get input and flags */
5806   g_rec_mutex_lock(audio_mutex);
5807 
5808   input = audio->input;
5809   audio_flags = audio->flags;
5810 
5811   g_rec_mutex_unlock(audio_mutex);
5812 
5813   /* replace */
5814   if(replace_last[0]){
5815     /* do it so */
5816     g_rec_mutex_lock(output_mutex);
5817 
5818     output->last_recycling = replace_with_last_recycling[0];
5819 
5820     g_rec_mutex_unlock(output_mutex);
5821   }
5822 
5823   /* last recycling */
5824   if(replace_first[0]){
5825     /* do it so */
5826     g_rec_mutex_lock(output_mutex);
5827 
5828     output->first_recycling = replace_with_first_recycling[0];
5829 
5830     g_rec_mutex_unlock(output_mutex);
5831   }
5832 
5833   /* deeper level */
5834   g_rec_mutex_lock(output_mutex);
5835 
5836   link = output->link;
5837 
5838   g_rec_mutex_unlock(output_mutex);
5839 
5840   if(link != NULL){
5841     g_object_ref(link);
5842 
5843     ags_channel_reset_recycling_recursive(link,
5844 					  found_next, found_prev,
5845 					  next_channel, prev_channel,
5846 					  replace_with_first_recycling, replace_with_last_recycling,
5847 					  complete_level_first, complete_level_last,
5848 					  find_next, find_prev,
5849 					  replace_first, replace_last);
5850 
5851     g_object_unref(link);
5852   }
5853 
5854   if(audio != NULL){
5855     g_object_unref(audio);
5856   }
5857 }
5858 
5859 void
ags_channel_reset_recycling_recursive(AgsChannel * input,AgsAudio ** found_next,AgsAudio ** found_prev,AgsChannel ** next_channel,AgsChannel ** prev_channel,AgsRecycling ** replace_with_first_recycling,AgsRecycling ** replace_with_last_recycling,guint * complete_level_first,guint * complete_level_last,gboolean * find_next,gboolean * find_prev,gboolean * replace_first,gboolean * replace_last)5860 ags_channel_reset_recycling_recursive(AgsChannel *input,
5861 				      AgsAudio **found_next, AgsAudio **found_prev,
5862 				      AgsChannel **next_channel, AgsChannel **prev_channel,
5863 				      AgsRecycling **replace_with_first_recycling, AgsRecycling **replace_with_last_recycling,
5864 				      guint *complete_level_first, guint *complete_level_last,
5865 				      gboolean *find_next, gboolean *find_prev,
5866 				      gboolean *replace_first, gboolean *replace_last)
5867 {
5868   AgsAudio *audio;
5869   AgsChannel *output;
5870   AgsChannel *nth_output;
5871 
5872   guint audio_channel, line;
5873   gboolean completed;
5874 
5875   if(input == NULL){
5876     return;
5877   }
5878 
5879   /* get audio and audio channel */
5880   audio = NULL;
5881 
5882   audio_channel = 0;
5883   line = 0;
5884 
5885   g_object_get(input,
5886 	       "audio", &audio,
5887 	       "audio-channel", &audio_channel,
5888 	       "line", &line,
5889 	       NULL);
5890 
5891   /* get output */
5892   output = NULL;
5893 
5894   g_object_get(audio,
5895 	       "output", &output,
5896 	       NULL);
5897 
5898   /* AgsInput */
5899   completed = ags_channel_reset_recycling_recursive_input(input,
5900 							  found_next, found_prev,
5901 							  next_channel, prev_channel,
5902 							  replace_with_first_recycling, replace_with_last_recycling,
5903 							  complete_level_first, complete_level_last,
5904 							  find_next, find_prev,
5905 							  replace_first, replace_last);
5906 
5907   if(completed){
5908     if(audio != NULL){
5909       g_object_unref(audio);
5910     }
5911 
5912     if(output != NULL){
5913       g_object_unref(output);
5914     }
5915 
5916     return;
5917   }
5918 
5919   /* AgsOutput */
5920   if(!ags_audio_test_flags(audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING)){
5921     if(ags_audio_test_flags(audio, AGS_AUDIO_ASYNC)){
5922       nth_output = ags_channel_nth(output, audio_channel);
5923 
5924       if(output != NULL){
5925 	g_object_unref(output);
5926       }
5927 
5928       output = nth_output;
5929     }else{
5930       nth_output = ags_channel_nth(output, line);
5931 
5932       if(output != NULL){
5933 	g_object_unref(output);
5934       }
5935 
5936       output = nth_output;
5937     }
5938 
5939     ags_channel_reset_recycling_recursive_output(output,
5940 						 found_next, found_prev,
5941 						 next_channel, prev_channel,
5942 						 replace_with_first_recycling, replace_with_last_recycling,
5943 						 complete_level_first, complete_level_last,
5944 						 find_next, find_prev,
5945 						 replace_first, replace_last);
5946   }
5947 
5948   if(audio != NULL){
5949     g_object_unref(audio);
5950   }
5951 
5952   if(output != NULL){
5953     g_object_unref(output);
5954   }
5955 }
5956 
5957 void
ags_channel_reset_recycling_reset_recycling_context_up(AgsChannel * current)5958 ags_channel_reset_recycling_reset_recycling_context_up(AgsChannel *current)
5959 {
5960   //NOTE:JK: actually handled by ags_channel_set_link()
5961 #if 0
5962   gint i;
5963 
5964   if(!AGS_IS_CHANNEL(current)){
5965     return;
5966   }
5967 
5968   for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
5969     GList *recall_id;
5970 
5971     recall_id = ags_channel_check_scope(current, i);
5972 
5973     if(recall_id != NULL){
5974       ags_channel_recursive_run_stage(current,
5975 				      i, (AGS_SOUND_STAGING_CANCEL));
5976 
5977       g_list_free_full(recall_id,
5978 		       g_object_unref);
5979     }
5980   }
5981 #endif
5982 }
5983 
5984 void
ags_channel_reset_recycling_reset_recycling_context_down(AgsChannel * current_output,AgsRecyclingContext * new_recycling_context,AgsRecyclingContext * old_recycling_context)5985 ags_channel_reset_recycling_reset_recycling_context_down(AgsChannel *current_output,
5986 							 AgsRecyclingContext *new_recycling_context, AgsRecyclingContext *old_recycling_context)
5987 {
5988   AgsAudio *current_audio;
5989 
5990   GList *recall_id_start, *recall_id;
5991 
5992   guint current_audio_flags;
5993 
5994   GRecMutex *current_audio_mutex;
5995   GRecMutex *current_output_mutex;
5996 
5997   if(!AGS_IS_CHANNEL(current_output)){
5998     return;
5999   }
6000 
6001   /* get current output mutex */
6002   current_output_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(current_output);
6003 
6004   /* get current audio */
6005   g_rec_mutex_lock(current_output_mutex);
6006 
6007   current_audio = (AgsAudio *) current_output->audio;
6008 
6009   g_rec_mutex_unlock(current_output_mutex);
6010 
6011   /* get current audio mutex */
6012   current_audio_mutex = AGS_AUDIO_GET_OBJ_MUTEX(current_audio);
6013 
6014   /* get recall id - output */
6015   g_rec_mutex_lock(current_output_mutex);
6016 
6017   recall_id =
6018     recall_id_start = g_list_copy(current_output->recall_id);
6019 
6020   g_rec_mutex_unlock(current_output_mutex);
6021 
6022   /* reset - output */
6023   while(recall_id != NULL){
6024     AgsRecallID *current_recall_id;
6025     AgsRecyclingContext *current_recycling_context;
6026 
6027     GRecMutex *recall_id_mutex;
6028 
6029     current_recall_id = recall_id->data;
6030 
6031     /* get recall id mutex */
6032     recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(current_recall_id);
6033 
6034     /* get some fields */
6035     g_rec_mutex_lock(recall_id_mutex);
6036 
6037     current_recycling_context = current_recall_id->recycling_context;
6038 
6039     g_rec_mutex_unlock(recall_id_mutex);
6040 
6041     if(current_recycling_context == old_recycling_context){
6042       g_object_set(current_recall_id,
6043 		   "recycling-context", new_recycling_context,
6044 		   NULL);
6045     }
6046 
6047     recall_id = recall_id->next;
6048   }
6049 
6050   g_list_free(recall_id_start);
6051 
6052   /* get recall id - audio */
6053   g_rec_mutex_lock(current_audio_mutex);
6054 
6055   current_audio_flags = current_audio->flags;
6056 
6057   recall_id = g_list_copy(current_audio->recall_id);
6058 
6059   g_rec_mutex_unlock(current_audio_mutex);
6060 
6061   /* reset - audio */
6062   while(recall_id != NULL){
6063     AgsRecallID *current_recall_id;
6064     AgsRecyclingContext *current_recycling_context;
6065 
6066     GRecMutex *recall_id_mutex;
6067 
6068     current_recall_id = recall_id->data;
6069 
6070     /* get recall id mutex */
6071     recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(current_recall_id);
6072 
6073     /* get some fields */
6074     g_rec_mutex_lock(recall_id_mutex);
6075 
6076     current_recycling_context = current_recall_id->recycling_context;
6077 
6078     g_rec_mutex_unlock(recall_id_mutex);
6079 
6080     if(current_recycling_context == old_recycling_context){
6081       g_object_set(current_recall_id,
6082 		   "recycling-context", new_recycling_context,
6083 		   NULL);
6084     }
6085 
6086     recall_id = recall_id->next;
6087   }
6088 
6089   g_list_free(recall_id_start);
6090 
6091   /* check completed */
6092   if((AGS_AUDIO_OUTPUT_HAS_RECYCLING & (current_audio_flags)) != 0){
6093     return;
6094   }
6095 
6096   /* traverse the tree */
6097   ags_channel_reset_recycling_reset_recycling_context_down_input(current_output,
6098 								 new_recycling_context, old_recycling_context);
6099 }
6100 
6101 void
ags_channel_reset_recycling_reset_recycling_context_down_input(AgsChannel * current_output,AgsRecyclingContext * new_recycling_context,AgsRecyclingContext * old_recycling_context)6102 ags_channel_reset_recycling_reset_recycling_context_down_input(AgsChannel *current_output,
6103 							       AgsRecyclingContext *new_recycling_context, AgsRecyclingContext *old_recycling_context)
6104 {
6105   AgsAudio *current_audio;
6106   AgsChannel *current_input, *next_pad, *nth_input;
6107   AgsChannel *current_link;
6108 
6109   GList *start_recall_id, *recall_id;
6110 
6111   guint audio_flags;
6112   guint audio_channel, line;
6113 
6114   if(!AGS_IS_CHANNEL(current_output)){
6115     return;
6116   }
6117 
6118   /* get current audio */
6119   current_audio = NULL;
6120 
6121   audio_channel = 0;
6122   line = 0;
6123 
6124   g_object_get(current_output,
6125 	       "audio", &current_audio,
6126 	       "audio-channel", &audio_channel,
6127 	       "line", &line,
6128 	       NULL);
6129 
6130   /* get some fields */
6131   current_input = NULL;
6132 
6133   g_object_get(current_audio,
6134 	       "input", &current_input,
6135 	       NULL);
6136 
6137   /* reset and traverse */
6138   if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
6139     nth_input = ags_channel_nth(current_input, audio_channel);
6140 
6141     g_object_unref(current_input);
6142 
6143     current_input = nth_input;
6144 
6145     while(current_input != NULL){
6146       /* get recall id - input */
6147       start_recall_id = NULL;
6148 
6149       g_object_get(current_input,
6150 		   "recall-id", &start_recall_id,
6151 		   NULL);
6152 
6153       current_link = ags_channel_get_link(current_input);
6154 
6155       /* reset - input */
6156       recall_id = start_recall_id;
6157 
6158       while(recall_id != NULL){
6159 	AgsRecallID *current_recall_id;
6160 	AgsRecyclingContext *current_recycling_context;
6161 
6162 	current_recall_id = recall_id->data;
6163 
6164 	current_recycling_context = NULL;
6165 
6166 	g_object_get(current_recall_id,
6167 		     "recycling-context", &current_recycling_context,
6168 		     NULL);
6169 
6170 	if(current_recycling_context == old_recycling_context){
6171 	  g_object_set(current_recall_id,
6172 		       "recycling-context", new_recycling_context,
6173 		       NULL);
6174 	}
6175 
6176 	if(current_recycling_context != NULL){
6177 	  g_object_unref(current_recycling_context);
6178 	}
6179 
6180 	recall_id = recall_id->next;
6181       }
6182 
6183       g_list_free_full(start_recall_id,
6184 		       g_object_unref);
6185 
6186       /* traverse the tree */
6187       ags_channel_reset_recycling_reset_recycling_context_down_input(current_link,
6188 								     new_recycling_context, old_recycling_context);
6189 
6190       /* unref */
6191       if(current_link != NULL){
6192 	g_object_unref(current_link);
6193       }
6194 
6195       /* iterate */
6196       next_pad = ags_channel_next_pad(current_input);
6197 
6198       g_object_unref(current_input);
6199 
6200       current_input = next_pad;
6201     }
6202   }else{
6203     nth_input = ags_channel_nth(current_input, line);
6204 
6205     g_object_unref(current_input);
6206 
6207     current_input = nth_input;
6208 
6209     /* get recall id - input */
6210     start_recall_id = NULL;
6211 
6212     g_object_get(current_input,
6213 		 "recall-id", &start_recall_id,
6214 		 NULL);
6215 
6216     current_link = ags_channel_get_link(current_input);
6217 
6218     /* reset - input */
6219     recall_id = start_recall_id;
6220 
6221     while(recall_id != NULL){
6222       AgsRecallID *current_recall_id;
6223       AgsRecyclingContext *current_recycling_context;
6224 
6225       current_recall_id = recall_id->data;
6226 
6227       current_recycling_context = NULL;
6228 
6229       g_object_get(current_recall_id,
6230 		   "recycling-context", &current_recycling_context,
6231 		   NULL);
6232 
6233       if(current_recycling_context == old_recycling_context){
6234 	g_object_set(current_recall_id,
6235 		     "recycling-context", new_recycling_context,
6236 		     NULL);
6237       }
6238 
6239       if(current_recycling_context != NULL){
6240 	g_object_unref(current_recycling_context);
6241       }
6242 
6243       recall_id = recall_id->next;
6244     }
6245 
6246     g_list_free_full(start_recall_id,
6247 		     g_object_unref);
6248 
6249     /* traverse the tree */
6250     ags_channel_reset_recycling_reset_recycling_context_down_input(current_link,
6251 								   new_recycling_context, old_recycling_context);
6252 
6253     /* unref */
6254     if(current_link != NULL){
6255       g_object_unref(current_link);
6256     }
6257   }
6258 
6259   if(current_audio != NULL){
6260     g_object_unref(current_audio);
6261   }
6262 }
6263 
6264 void
ags_channel_reset_recycling_emit_changed_input(AgsChannel * start_channel,AgsChannel * input,AgsRecycling * changed_old_first_recycling,AgsRecycling * changed_old_last_recycling,AgsRecycling * old_first_recycling,AgsRecycling * old_last_recycling,AgsRecycling * first_recycling,AgsRecycling * last_recycling)6265 ags_channel_reset_recycling_emit_changed_input(AgsChannel *start_channel, AgsChannel *input,
6266 					       AgsRecycling *changed_old_first_recycling, AgsRecycling *changed_old_last_recycling,
6267 					       AgsRecycling *old_first_recycling, AgsRecycling *old_last_recycling,
6268 					       AgsRecycling *first_recycling, AgsRecycling *last_recycling)
6269 {
6270   AgsRecycling *input_first_recycling, *input_last_recycling;
6271 
6272   GRecMutex *input_mutex;
6273 
6274   if(input == NULL){
6275     return;
6276   }
6277 
6278   /* get input mutex */
6279   input_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(input);
6280 
6281   /* get current recycling */
6282   g_rec_mutex_lock(input_mutex);
6283 
6284   input_first_recycling = input->first_recycling;
6285   input_last_recycling = input->last_recycling;
6286 
6287   g_rec_mutex_unlock(input_mutex);
6288 
6289   /* emit changed */
6290   if(input != start_channel){
6291     ags_channel_recycling_changed(input,
6292 				  changed_old_first_recycling, changed_old_last_recycling,
6293 				  input_first_recycling, input_last_recycling,
6294 				  old_first_recycling, old_last_recycling,
6295 				  first_recycling, last_recycling);
6296   }
6297 }
6298 
6299 void
ags_channel_reset_recycling_emit_changed_output(AgsChannel * start_channel,AgsChannel * output,AgsRecycling * changed_old_first_recycling,AgsRecycling * changed_old_last_recycling,AgsRecycling * old_first_recycling,AgsRecycling * old_last_recycling,AgsRecycling * first_recycling,AgsRecycling * last_recycling)6300 ags_channel_reset_recycling_emit_changed_output(AgsChannel *start_channel, AgsChannel *output,
6301 						AgsRecycling *changed_old_first_recycling, AgsRecycling *changed_old_last_recycling,
6302 						AgsRecycling *old_first_recycling, AgsRecycling *old_last_recycling,
6303 						AgsRecycling *first_recycling, AgsRecycling *last_recycling)
6304 {
6305   AgsChannel *link;
6306   AgsRecycling *output_first_recycling, *output_last_recycling;
6307 
6308   GRecMutex *output_mutex;
6309 
6310   if(output == NULL){
6311     return;
6312   }
6313 
6314   /* get output mutex */
6315   output_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(output);
6316 
6317   /* get current recycling */
6318   g_rec_mutex_lock(output_mutex);
6319 
6320   link = output->link;
6321 
6322   output_first_recycling = output->first_recycling;
6323   output_last_recycling = output->last_recycling;
6324 
6325   g_rec_mutex_unlock(output_mutex);
6326 
6327   /* emit changed */
6328   if(output != start_channel){
6329     ags_channel_recycling_changed(output,
6330 				  changed_old_first_recycling, changed_old_last_recycling,
6331 				  output_first_recycling, output_last_recycling,
6332 				  old_first_recycling, old_last_recycling,
6333 				  first_recycling, last_recycling);
6334   }
6335 
6336   if(link != NULL){
6337     ags_channel_reset_recycling_emit_changed(start_channel, link,
6338 					     changed_old_first_recycling, changed_old_last_recycling,
6339 					     old_first_recycling, old_last_recycling,
6340 					     first_recycling, last_recycling);
6341   }
6342 }
6343 
6344 void
ags_channel_reset_recycling_emit_changed(AgsChannel * start_channel,AgsChannel * input,AgsRecycling * changed_old_first_recycling,AgsRecycling * changed_old_last_recycling,AgsRecycling * old_first_recycling,AgsRecycling * old_last_recycling,AgsRecycling * first_recycling,AgsRecycling * last_recycling)6345 ags_channel_reset_recycling_emit_changed(AgsChannel *start_channel, AgsChannel *input,
6346 					 AgsRecycling *changed_old_first_recycling, AgsRecycling *changed_old_last_recycling,
6347 					 AgsRecycling *old_first_recycling, AgsRecycling *old_last_recycling,
6348 					 AgsRecycling *first_recycling, AgsRecycling *last_recycling)
6349 {
6350   AgsAudio *audio;
6351   AgsChannel *output, *nth_output;
6352 
6353   guint audio_channel, line;
6354 
6355   if(input == NULL){
6356     return;
6357   }
6358 
6359   /* get audio and audio channel */
6360   audio = NULL;
6361 
6362   audio_channel = 0;
6363   line = 0;
6364 
6365   g_object_get(input,
6366 	       "audio", &audio,
6367 	       "audio-channel", &audio_channel,
6368 	       "line", &line,
6369 	       NULL);
6370 
6371   /* get output */
6372   output = NULL;
6373 
6374   g_object_get(audio,
6375 	       "output", &output,
6376 	       NULL);
6377 
6378   /* AgsInput */
6379   ags_channel_reset_recycling_emit_changed_input(start_channel, input,
6380 						 changed_old_first_recycling, changed_old_last_recycling,
6381 						 old_first_recycling, old_last_recycling,
6382 						 first_recycling, last_recycling);
6383 
6384   /* higher level */
6385   if(!ags_audio_test_flags(audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING)){
6386     if(ags_audio_test_flags(audio, AGS_AUDIO_ASYNC)){
6387       nth_output = ags_channel_nth(output, audio_channel);
6388 
6389       if(output != NULL){
6390 	g_object_unref(output);
6391       }
6392 
6393       output = nth_output;
6394     }else{
6395       nth_output = ags_channel_nth(output, line);
6396 
6397       if(output != NULL){
6398 	g_object_unref(output);
6399       }
6400 
6401       output = nth_output;
6402     }
6403 
6404     ags_channel_reset_recycling_emit_changed_output(start_channel, output,
6405 						    changed_old_first_recycling, changed_old_last_recycling,
6406 						    old_first_recycling, old_last_recycling,
6407 						    first_recycling, last_recycling);
6408   }
6409 
6410   if(audio != NULL){
6411     g_object_unref(audio);
6412   }
6413 
6414   if(output != NULL){
6415     g_object_unref(output);
6416   }
6417 }
6418 
6419 /**
6420  * ags_channel_reset_recycling:
6421  * @channel: the channel to reset
6422  * @first_recycling: the recycling to set for channel->first_recycling
6423  * @last_recycling: the recycling to set for channel->last_recycling
6424  *
6425  * Called by ags_channel_set_link() to handle outdated #AgsRecycling references.
6426  * Invoke only by a task.
6427  *
6428  * Since: 3.0.0
6429  */
6430 void
ags_channel_reset_recycling(AgsChannel * channel,AgsRecycling * first_recycling,AgsRecycling * last_recycling)6431 ags_channel_reset_recycling(AgsChannel *channel,
6432 			    AgsRecycling *first_recycling, AgsRecycling *last_recycling)
6433 {
6434   AgsAudio *audio;
6435   AgsAudio *found_prev, *found_next;
6436   AgsAudio *level_audio;
6437   AgsChannel *prev_channel, *next_channel, *current;
6438   AgsChannel *level_channel, *level_link;
6439   AgsRecycling *parent;
6440   AgsRecycling *old_first_recycling, *old_last_recycling;
6441   AgsRecycling *replace_with_first_recycling, *replace_with_last_recycling;
6442   AgsRecycling *changed_old_first_recycling, *changed_old_last_recycling;
6443   AgsRecycling *nth_recycling, *next_recycling, *stop_recycling;
6444   AgsRecycling *next_first_recycling, *prev_last_recycling;
6445 
6446   guint audio_flags;
6447   guint level_audio_flags;
6448   guint complete_level_first, complete_level_last;
6449   gboolean is_output;
6450   gboolean replace_first, replace_last;
6451   gboolean find_prev, find_next;
6452   gboolean change_old_last, change_old_first;
6453 
6454   GRecMutex *audio_mutex;
6455   GRecMutex *level_audio_mutex;
6456   GRecMutex *channel_mutex;
6457   GRecMutex *current_mutex;
6458   GRecMutex *nth_channel_mutex;
6459   GRecMutex *level_channel_mutex;
6460   GRecMutex *recycling_mutex;
6461   GRecMutex *nth_recycling_mutex;
6462 
6463   /* entry point */
6464   if(!AGS_IS_CHANNEL(channel)){
6465     return;
6466   }
6467 
6468   /* get channel mutex */
6469   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
6470 
6471   /*  */
6472   audio = NULL;
6473 
6474   g_object_get(channel,
6475 	       "audio", &audio,
6476 	       NULL);
6477 
6478   /* fix first or last recycling if needed */
6479   if(first_recycling == NULL && last_recycling != NULL){
6480     first_recycling = last_recycling;
6481   }
6482 
6483   if(last_recycling == NULL && first_recycling != NULL){
6484     last_recycling = first_recycling;
6485   }
6486 
6487   /* set old recycling */
6488   old_first_recycling = channel->first_recycling;
6489   old_last_recycling = channel->last_recycling;
6490 
6491   /* initialising */
6492   found_prev = NULL;
6493   found_next = NULL;
6494 
6495   parent = NULL;
6496 
6497   prev_channel = NULL;
6498   next_channel = NULL;
6499 
6500   replace_with_first_recycling = first_recycling;
6501   replace_with_last_recycling = last_recycling;
6502 
6503   changed_old_first_recycling = NULL;
6504   changed_old_last_recycling = NULL;
6505 
6506   complete_level_first = 0;
6507   complete_level_last = 0;
6508 
6509   replace_first = TRUE;
6510   replace_last = TRUE;
6511 
6512   find_next = TRUE;
6513   find_prev = TRUE;
6514 
6515   change_old_first = TRUE;
6516   change_old_last = TRUE;
6517 
6518   if((old_first_recycling == first_recycling)){
6519     replace_first = FALSE;
6520   }
6521 
6522   if((old_last_recycling == last_recycling)){
6523     replace_last = FALSE;
6524   }
6525 
6526   /* set recycling - update AgsChannel */
6527   if(AGS_IS_INPUT(channel)){
6528     ags_channel_reset_recycling_recursive(channel,
6529 					  &found_next, &found_prev,
6530 					  &next_channel, &prev_channel,
6531 					  &replace_with_first_recycling, &replace_with_last_recycling,
6532 					  &complete_level_first, &complete_level_last,
6533 					  &find_next, &find_prev,
6534 					  &replace_first, &replace_last);
6535   }else{
6536     ags_channel_reset_recycling_recursive_output(channel,
6537 						 &found_next, &found_prev,
6538 						 &next_channel, &prev_channel,
6539 						 &replace_with_first_recycling, &replace_with_last_recycling,
6540 						 &complete_level_first, &complete_level_last,
6541 						 &find_next, &find_prev,
6542 						 &replace_first, &replace_last);
6543   }
6544 
6545   g_rec_mutex_lock(channel_mutex);
6546 
6547   channel->first_recycling = first_recycling;
6548   channel->last_recycling = last_recycling;
6549 
6550   g_rec_mutex_unlock(channel_mutex);
6551 
6552   /* get audio mutex */
6553   audio_mutex = AGS_AUDIO_GET_OBJ_MUTEX(audio);
6554 
6555   /* audio flags */
6556   g_rec_mutex_lock(audio_mutex);
6557 
6558   audio_flags = audio->flags;
6559 
6560   g_rec_mutex_unlock(audio_mutex);
6561 
6562   /* join now the retrieved recyclings */
6563   next_first_recycling = NULL;
6564   prev_last_recycling = NULL;
6565 
6566   if(!(AGS_IS_INPUT(channel) &&
6567        (AGS_AUDIO_OUTPUT_HAS_RECYCLING & (audio_flags)) != 0)){
6568     if(first_recycling != NULL){
6569       if(prev_channel != NULL){
6570 	/* get prev channel mutex */
6571 	nth_channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(prev_channel);
6572 
6573 	/* get prev channel last recycling */
6574 	g_rec_mutex_lock(nth_channel_mutex);
6575 
6576 	prev_last_recycling = prev_channel->last_recycling;
6577 
6578 	g_rec_mutex_unlock(nth_channel_mutex);
6579 
6580 	if(prev_last_recycling != NULL){
6581 	  /* get nth recycling mutex */
6582 	  nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(prev_last_recycling);
6583 
6584 	  /* prev channel last recycling next */
6585 	  g_object_set(prev_last_recycling,
6586 		       "next", first_recycling,
6587 		       NULL);
6588 
6589 	  /* get nth recycling mutex */
6590 	  nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(first_recycling);
6591 
6592 	  /* first recycling prev */
6593 	  g_object_set(first_recycling,
6594 		       "prev", prev_last_recycling,
6595 		       NULL);
6596 	}else{
6597 	  /* get nth recycling mutex */
6598 	  nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(first_recycling);
6599 
6600 	  /* first recycling prev */
6601 	  g_object_set(first_recycling,
6602 		       "prev", NULL,
6603 		       NULL);
6604 	}
6605       }else{
6606 	/* get nth recycling mutex */
6607 	nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(first_recycling);
6608 
6609 	/* first recycling prev */
6610 	g_object_set(first_recycling,
6611 		     "prev", NULL,
6612 		     NULL);
6613       }
6614 
6615       if(next_channel != NULL){
6616 	/* get next channel mutex */
6617 	nth_channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(next_channel);
6618 
6619 	/* get prev channel last recycling */
6620 	g_rec_mutex_lock(nth_channel_mutex);
6621 
6622 	next_first_recycling = next_channel->first_recycling;
6623 
6624 	g_rec_mutex_unlock(nth_channel_mutex);
6625 
6626 	if(next_first_recycling != NULL){
6627 	  /* get nth recycling mutex */
6628 	  nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(next_first_recycling);
6629 
6630 	  /* next channel first recycling next */
6631 	  g_object_set(next_first_recycling,
6632 		       "prev", last_recycling,
6633 		       NULL);
6634 
6635 	  /* get nth recycling mutex */
6636 	  nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(last_recycling);
6637 
6638 	  /* last recycling next */
6639 	  g_object_set(last_recycling,
6640 		       "next", next_first_recycling,
6641 		       NULL);
6642 	}else{
6643 	  /* get nth recycling mutex */
6644 	  nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(last_recycling);
6645 
6646 	  /* last recycling next */
6647 	  g_object_set(last_recycling,
6648 		       "next", NULL,
6649 		       NULL);
6650 	}
6651       }else{
6652 	/* get nth recycling mutex */
6653 	nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(last_recycling);
6654 
6655 	/* last recycling next */
6656 	g_object_set(last_recycling,
6657 		     "next", NULL,
6658 		     NULL);
6659       }
6660     }else{
6661       gboolean link_next, link_prev;
6662 
6663       if(prev_channel != NULL){
6664 	/* get prev channel mutex */
6665 	nth_channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(prev_channel);
6666 
6667 	/*  */
6668 	g_rec_mutex_lock(nth_channel_mutex);
6669 
6670 	prev_last_recycling = prev_channel->last_recycling;
6671 
6672 	g_rec_mutex_unlock(nth_channel_mutex);
6673 
6674 	if(prev_last_recycling != NULL){
6675 	  link_next = TRUE;
6676 	}else{
6677 	  link_next = FALSE;
6678 	}
6679       }else{
6680 	link_next = FALSE;
6681       }
6682 
6683       if(next_channel != NULL){
6684 	/* get prev channel mutex */
6685 	nth_channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(next_channel);
6686 
6687 	/*  */
6688 	g_rec_mutex_lock(nth_channel_mutex);
6689 
6690 	next_first_recycling = next_channel->first_recycling;
6691 
6692 	g_rec_mutex_unlock(nth_channel_mutex);
6693 
6694 	if(next_first_recycling != NULL){
6695 	  link_prev = TRUE;
6696 	}else{
6697 	  link_prev = FALSE;
6698 	}
6699       }else{
6700 	link_prev = FALSE;
6701       }
6702 
6703       if(link_next){
6704 	if(link_prev){
6705 	  AgsRecycling *first_recycling, *last_recycling;
6706 
6707 	  /* get first recycling mutex */
6708 	  nth_channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(next_channel);
6709 
6710 	  g_rec_mutex_lock(nth_channel_mutex);
6711 
6712 	  first_recycling = next_channel->first_recycling;
6713 
6714 	  g_rec_mutex_unlock(nth_channel_mutex);
6715 
6716 	  /* get last recycling mutex */
6717 	  nth_channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(prev_channel);
6718 
6719 	  g_rec_mutex_lock(nth_channel_mutex);
6720 
6721 	  last_recycling = prev_channel->last_recycling;
6722 
6723 	  g_rec_mutex_unlock(nth_channel_mutex);
6724 
6725 	  /*
6726 	   *
6727 	   */
6728 	  /* get nth recycling mutex */
6729 	  nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(next_first_recycling);
6730 
6731 	  /* next channel first recycling next */
6732 	  g_object_set(next_first_recycling,
6733 		       "prev", last_recycling,
6734 		       NULL);
6735 
6736 	  /*
6737 	   *
6738 	   */
6739 	  /* get nth recycling mutex */
6740 	  nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(prev_last_recycling);
6741 
6742 	  /* prev channel last recycling next */
6743 	  g_object_set(prev_last_recycling,
6744 		       "next", first_recycling,
6745 		       NULL);
6746 	}else{
6747 	  /* get nth recycling mutex */
6748 	  nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(prev_last_recycling);
6749 
6750 	  /* prev channel last recycling next */
6751 	  g_object_set(prev_last_recycling,
6752 		       "next", NULL,
6753 		       NULL);
6754 	}
6755       }else if(link_prev){
6756 	/* get nth recycling mutex */
6757 	nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(next_first_recycling);
6758 
6759 	/* next channel first recycling next */
6760 	g_object_set(next_first_recycling,
6761 		     "prev", NULL,
6762 		     NULL);
6763       }
6764     }
6765   }
6766 
6767   /* find and set parent */
6768   if(first_recycling != NULL){
6769     /* find parent */
6770     parent = NULL;
6771 
6772     if(AGS_IS_OUTPUT(channel)){
6773       g_rec_mutex_lock(channel_mutex);
6774 
6775       current = channel->link;
6776 
6777       g_rec_mutex_unlock(channel_mutex);
6778     }else{
6779       current = channel;
6780     }
6781 
6782     if(current != NULL){
6783       g_object_ref(current);
6784     }
6785 
6786     while(current != NULL &&
6787 	  parent == NULL){
6788       AgsAudio *audio;
6789       AgsChannel *output;
6790 
6791       guint audio_channel, line;
6792 
6793       GRecMutex *audio_mutex;
6794 
6795       guint audio_flags;
6796 
6797       /* get current mutex */
6798       current_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(current);
6799 
6800       /* get audio */
6801       audio = NULL;
6802 
6803       g_object_get(current,
6804 		   "audio", &audio,
6805 		   NULL);
6806 
6807       g_rec_mutex_lock(current_mutex);
6808 
6809       audio_channel = current->audio_channel;
6810       line = current->line;
6811 
6812       g_rec_mutex_unlock(current_mutex);
6813 
6814       /* get audio mutex */
6815       audio_mutex = AGS_AUDIO_GET_OBJ_MUTEX(audio);
6816 
6817       /* get nth */
6818       output = NULL;
6819 
6820       g_object_get(audio,
6821 		   "output", &output,
6822 		   NULL);
6823 
6824       g_rec_mutex_lock(audio_mutex);
6825 
6826       audio_flags = audio->flags;
6827 
6828       g_rec_mutex_unlock(audio_mutex);
6829 
6830       /* get current */
6831       if(current != NULL){
6832 	g_object_unref(current);
6833       }
6834 
6835       if((AGS_AUDIO_ASYNC & (audio_flags)) != 0){
6836 	current = ags_channel_nth(output,
6837 				  audio_channel);
6838       }else{
6839 	current = ags_channel_nth(output,
6840 				  line);
6841       }
6842 
6843       if(current != NULL){
6844 	AgsChannel *link;
6845 
6846 	/* get current mutex */
6847 	current_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(current);
6848 
6849 	/* check if parent found */
6850 	g_rec_mutex_lock(current_mutex);
6851 
6852 	if((AGS_AUDIO_OUTPUT_HAS_RECYCLING & (audio_flags)) != 0){
6853 	  /* set parent */
6854 	  parent = current->first_recycling;
6855 	}
6856 
6857 	link = current->link;
6858 
6859 	if(current != NULL){
6860 	  g_object_unref(current);
6861 	}
6862 
6863 	if(link != NULL){
6864 	  g_object_ref(link);
6865 	}
6866 
6867 	current = link;
6868 
6869 	g_rec_mutex_unlock(current_mutex);
6870       }
6871 
6872       if(audio != NULL){
6873 	g_object_unref(audio);
6874       }
6875     }
6876 
6877     if(current != NULL){
6878       g_object_unref(current);
6879     }
6880 
6881     /* apply parent */
6882     nth_recycling = first_recycling;
6883 
6884     /* get recycling mutex */
6885     recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(last_recycling);
6886 
6887     /*  */
6888     g_rec_mutex_lock(recycling_mutex);
6889 
6890     stop_recycling = last_recycling->next;
6891 
6892     g_rec_mutex_unlock(recycling_mutex);
6893 
6894     /* parent - do it so */
6895     while(nth_recycling != stop_recycling){
6896       /* get nth recycling mutex */
6897       nth_recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(nth_recycling);
6898 
6899       /* set parent and iterate */
6900       g_object_set(nth_recycling,
6901 		   "parent", parent,
6902 		   NULL);
6903 
6904       g_rec_mutex_lock(nth_recycling_mutex);
6905 
6906       nth_recycling = nth_recycling->next;
6907 
6908       g_rec_mutex_unlock(nth_recycling_mutex);
6909     }
6910   }
6911 
6912   /* reset recycling context */
6913   level_channel = ags_channel_get_level(channel);
6914   level_audio = NULL;
6915 
6916   if(level_channel != NULL){
6917     /* get level channel mutex */
6918     level_channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(level_channel);
6919 
6920     /* get level audio */
6921     level_audio = NULL;
6922 
6923     level_link = NULL;
6924 
6925     g_object_get(level_channel,
6926 		 "audio", &level_audio,
6927 		 "link", &level_link,
6928 		 NULL);
6929 
6930     /* get level audio mutex */
6931     level_audio_mutex = AGS_AUDIO_GET_OBJ_MUTEX(level_audio);
6932 
6933     /* get some fields */
6934     g_rec_mutex_lock(level_audio_mutex);
6935 
6936     level_audio_flags = level_audio->flags;
6937 
6938     g_rec_mutex_unlock(level_audio_mutex);
6939 
6940     if(AGS_IS_INPUT(level_channel)){
6941       gboolean reset_recycling_context;
6942 
6943       reset_recycling_context = FALSE;
6944 
6945       if((AGS_AUDIO_INPUT_HAS_RECYCLING & (level_audio_flags)) != 0){
6946 	reset_recycling_context = TRUE;
6947       }
6948 
6949       if(reset_recycling_context){
6950 	gint i;
6951 
6952 	for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
6953 	  GList *recall_id_start, *recall_id;
6954 
6955 	  recall_id =
6956 	    recall_id_start = ags_channel_check_scope(level_channel, i);
6957 
6958 	  while(recall_id != NULL){
6959 	    AgsRecallID *current_recall_id;
6960 	    AgsRecyclingContext *recycling_context, *new_recycling_context;
6961 
6962 	    GRecMutex *recall_id_mutex;
6963 
6964 	    current_recall_id = AGS_RECALL_ID(recall_id->data);
6965 
6966 	    /* get recall id mutex */
6967 	    recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(current_recall_id);
6968 
6969 	    /* get recycling context */
6970 	    g_rec_mutex_lock(recall_id_mutex);
6971 
6972 	    recycling_context = current_recall_id->recycling_context;
6973 
6974 	    g_rec_mutex_unlock(recall_id_mutex);
6975 
6976 	    /* reset recycling context */
6977 	    new_recycling_context = ags_recycling_context_reset_recycling(recycling_context,
6978 									  old_first_recycling, old_last_recycling,
6979 									  first_recycling, last_recycling);
6980 
6981 	    /* add/remove recycling context */
6982 	    ags_audio_remove_recycling_context(level_audio,
6983 					       (GObject *) recycling_context);
6984 
6985 	    ags_audio_add_recycling_context(level_audio,
6986 					    (GObject *) new_recycling_context);
6987 
6988 	    /* traverse the tree */
6989 	    ags_channel_reset_recycling_reset_recycling_context_down(level_link,
6990 								     new_recycling_context, recycling_context);
6991 
6992 	    /* iterate */
6993 	    recall_id = recall_id->next;
6994 	  }
6995 
6996 	  g_list_free_full(recall_id_start,
6997 			   g_object_unref);
6998 	}
6999       }
7000     }else{
7001 #ifdef AGS_DEBUG
7002       g_message("unexpected result as retrieving level: !AGS_IS_INPUT(level)");
7003 #endif
7004     }
7005 
7006     if(level_audio != NULL){
7007       g_object_unref(level_audio);
7008     }
7009 
7010     g_object_unref(level_channel);
7011 
7012     if(level_link != NULL){
7013       g_object_unref(level_link);
7014     }
7015   }else{
7016     if(first_recycling == NULL){
7017       /* reset recycling context */
7018       ags_channel_reset_recycling_reset_recycling_context_up(channel);
7019     }else{
7020 #ifdef AGS_DEBUG
7021       g_message("unexpected result: level_channel == NULL && first_recycling != NULL");
7022 #endif
7023     }
7024   }
7025 
7026   /* emit changed */
7027   changed_old_first_recycling = NULL;
7028   changed_old_last_recycling = NULL;
7029 
7030   is_output = AGS_IS_OUTPUT(channel);
7031 
7032   if(!is_output){
7033     if(old_first_recycling != NULL){
7034       changed_old_first_recycling = old_first_recycling;
7035       changed_old_last_recycling = old_last_recycling;
7036     }
7037 
7038     ags_channel_reset_recycling_emit_changed_input(channel, channel,
7039 						   changed_old_first_recycling, changed_old_last_recycling,
7040 						   old_first_recycling, old_last_recycling,
7041 						   first_recycling, last_recycling);
7042 
7043     if((AGS_AUDIO_OUTPUT_HAS_RECYCLING & (audio_flags)) == 0){
7044       AgsChannel *output, *nth_channel;
7045 
7046       g_object_get(audio,
7047 		   "output", &output,
7048 		   NULL);
7049 
7050       /* get matching output */
7051       if((AGS_AUDIO_ASYNC & (audio_flags)) != 0){
7052 	guint audio_channel;
7053 
7054 	g_rec_mutex_lock(channel_mutex);
7055 
7056 	audio_channel = channel->audio_channel;
7057 
7058 	g_rec_mutex_unlock(channel_mutex);
7059 
7060 	nth_channel = ags_channel_nth(output, audio_channel);
7061 
7062 	if(output != NULL){
7063 	  g_object_unref(output);
7064 	}
7065 
7066 	output = nth_channel;
7067       }else{
7068 	guint line;
7069 
7070 	g_rec_mutex_lock(channel_mutex);
7071 
7072 	line = channel->line;
7073 
7074 	g_rec_mutex_unlock(channel_mutex);
7075 
7076 	nth_channel = ags_channel_nth(output, line);
7077 
7078 	if(output != NULL){
7079 	  g_object_unref(output);
7080 	}
7081 
7082 	output = nth_channel;
7083       }
7084 
7085       /* emit */
7086       ags_channel_reset_recycling_emit_changed_output(channel, output,
7087 						      changed_old_first_recycling, changed_old_last_recycling,
7088 						      old_first_recycling, old_last_recycling,
7089 						      first_recycling, last_recycling);
7090 
7091       if(output != NULL){
7092 	g_object_unref(output);
7093       }
7094     }
7095   }else{
7096     ags_channel_reset_recycling_emit_changed_output(channel, channel,
7097 						    changed_old_first_recycling, changed_old_last_recycling,
7098 						    old_first_recycling, old_last_recycling,
7099 						    first_recycling, last_recycling);
7100   }
7101 
7102   if(audio != NULL){
7103     g_object_unref(audio);
7104   }
7105 }
7106 
7107 /**
7108  * ags_channel_recycling_changed:
7109  * @channel: the object recycling changed
7110  * @old_start_region: first recycling
7111  * @old_end_region: last recycling
7112  * @new_start_region: new first recycling
7113  * @new_end_region: new last recycling
7114  * @old_start_changed_region: modified link recycling start
7115  * @old_end_changed_region: modified link recyclig end
7116  * @new_start_changed_region: replacing link recycling start
7117  * @new_end_changed_region: replacing link recycling end
7118  *
7119  * Modify recycling. Asynchronously only.
7120  *
7121  * Since: 3.0.0
7122  */
7123 void
ags_channel_recycling_changed(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)7124 ags_channel_recycling_changed(AgsChannel *channel,
7125 			      AgsRecycling *old_start_region, AgsRecycling *old_end_region,
7126 			      AgsRecycling *new_start_region, AgsRecycling *new_end_region,
7127 			      AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
7128 			      AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region)
7129 {
7130   g_return_if_fail(AGS_IS_CHANNEL(channel));
7131 
7132   g_object_ref(G_OBJECT(channel));
7133   g_signal_emit(G_OBJECT(channel),
7134 		channel_signals[RECYCLING_CHANGED], 0,
7135 		old_start_region, old_end_region,
7136 		new_start_region, new_end_region,
7137 		old_start_changed_region, old_end_changed_region,
7138 		new_start_changed_region, new_end_changed_region);
7139   g_object_unref(G_OBJECT(channel));
7140 }
7141 
7142 /**
7143  * ags_channel_get_output_soundcard:
7144  * @channel: the #AgsChannel
7145  *
7146  * Get the output soundcard object of @channel.
7147  *
7148  * Returns: (transfer full): the output soundcard
7149  *
7150  * Since: 3.1.0
7151  */
7152 GObject*
ags_channel_get_output_soundcard(AgsChannel * channel)7153 ags_channel_get_output_soundcard(AgsChannel *channel)
7154 {
7155   GObject *output_soundcard;
7156 
7157   if(!AGS_IS_CHANNEL(channel)){
7158     return(NULL);
7159   }
7160 
7161   g_object_get(channel,
7162 	       "output-soundcard", &output_soundcard,
7163 	       NULL);
7164 
7165   return(output_soundcard);
7166 }
7167 
7168 void
ags_channel_real_set_output_soundcard(AgsChannel * channel,GObject * output_soundcard)7169 ags_channel_real_set_output_soundcard(AgsChannel *channel,
7170 				      GObject *output_soundcard)
7171 {
7172   AgsRecycling *recycling;
7173   AgsPlayback *playback;
7174 
7175   AgsThread *channel_thread;
7176 
7177   GObject *old_soundcard;
7178 
7179   GList *list;
7180 
7181   guint samplerate;
7182   guint buffer_size;
7183   guint format;
7184   gint i;
7185   gboolean reset_recycling;
7186 
7187   GRecMutex *channel_mutex;
7188   GRecMutex *playback_mutex;
7189   GRecMutex *play_mutex, *recall_mutex;
7190 
7191   if(!AGS_IS_CHANNEL(channel)){
7192     return;
7193   }
7194 
7195   /* get channel mutex */
7196   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
7197 
7198   /* old soundcard */
7199   g_rec_mutex_lock(channel_mutex);
7200 
7201   old_soundcard = channel->output_soundcard;
7202 
7203   g_rec_mutex_unlock(channel_mutex);
7204 
7205   if(old_soundcard == output_soundcard){
7206     return;
7207   }
7208 
7209   /* ref and set new soundcard */
7210   if(output_soundcard != NULL){
7211     g_object_ref(output_soundcard);
7212   }
7213 
7214   g_rec_mutex_lock(channel_mutex);
7215 
7216   channel->output_soundcard = (GObject *) output_soundcard;
7217 
7218   g_rec_mutex_unlock(channel_mutex);
7219 
7220   if(output_soundcard != NULL){
7221     /* get presets */
7222     ags_soundcard_get_presets(AGS_SOUNDCARD(output_soundcard),
7223 			      NULL,
7224 			      &samplerate,
7225 			      &buffer_size,
7226 			      &format);
7227 
7228     /* apply presets */
7229     g_object_set(channel,
7230 		 "samplerate", samplerate,
7231 		 "buffer-size", buffer_size,
7232 		 "format", format,
7233 		 NULL);
7234   }
7235 
7236   /* AgsRecycling */
7237   reset_recycling = FALSE;
7238 
7239   g_rec_mutex_lock(channel_mutex);
7240 
7241   if((AGS_IS_OUTPUT(channel) ||
7242       channel->link == NULL) &&
7243      channel->first_recycling != NULL){
7244     reset_recycling = TRUE;
7245   }
7246 
7247   g_rec_mutex_unlock(channel_mutex);
7248 
7249   if(reset_recycling){
7250     g_rec_mutex_lock(channel_mutex);
7251 
7252     recycling = channel->first_recycling;
7253 
7254     g_rec_mutex_unlock(channel_mutex);
7255 
7256     g_object_set(G_OBJECT(recycling),
7257 		 "output-soundcard", output_soundcard,
7258 		 NULL);
7259   }
7260 
7261   /* playback - channel thread */
7262   g_rec_mutex_lock(channel_mutex);
7263 
7264   playback = AGS_PLAYBACK(channel->playback);
7265 
7266   g_rec_mutex_unlock(channel_mutex);
7267 
7268   /* get playback domain mutex */
7269   playback_mutex = AGS_PLAYBACK_GET_OBJ_MUTEX(playback);
7270 
7271   /* channel thread - output soundcard */
7272   for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
7273     g_rec_mutex_lock(playback_mutex);
7274 
7275     channel_thread = playback->channel_thread[i];
7276 
7277     g_rec_mutex_unlock(playback_mutex);
7278 
7279     if(channel_thread != NULL){
7280       /* set output soundcard */
7281       g_object_set(channel_thread,
7282 		   "default-output-soundcard", output_soundcard,
7283 		   NULL);
7284     }
7285   }
7286 
7287   /* get play mutex */
7288   play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
7289 
7290   /* play context */
7291   g_rec_mutex_lock(play_mutex);
7292 
7293   list = channel->play;
7294 
7295   while(list != NULL){
7296     g_object_set(G_OBJECT(list->data),
7297 		 "output-soundcard", output_soundcard,
7298 		 NULL);
7299 
7300     list = list->next;
7301   }
7302 
7303   g_rec_mutex_unlock(play_mutex);
7304 
7305   /* get recall mutex */
7306   recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
7307 
7308   /* recall context */
7309   g_rec_mutex_lock(recall_mutex);
7310 
7311   list = channel->recall;
7312 
7313   while(list != NULL){
7314     g_object_set(G_OBJECT(list->data),
7315 		 "output-soundcard", output_soundcard,
7316 		 NULL);
7317 
7318     list = list->next;
7319   }
7320 
7321   g_rec_mutex_unlock(recall_mutex);
7322 
7323   /* unref old soundcard */
7324   if(old_soundcard != NULL){
7325     g_object_unref(old_soundcard);
7326   }
7327 }
7328 
7329 /**
7330  * ags_channel_set_output_soundcard:
7331  * @channel: an #AgsChannel
7332  * @output_soundcard: the #GObject implementing #AgsSoundcard
7333  *
7334  * Set the output soundcard object of @channel.
7335  *
7336  * Since: 3.0.0
7337  */
7338 void
ags_channel_set_output_soundcard(AgsChannel * channel,GObject * output_soundcard)7339 ags_channel_set_output_soundcard(AgsChannel *channel, GObject *output_soundcard)
7340 {
7341   if(!AGS_IS_CHANNEL(channel)){
7342     return;
7343   }
7344 
7345   g_object_set(channel,
7346 	       "output-soundcard", output_soundcard,
7347 	       NULL);
7348 }
7349 
7350 /**
7351  * ags_channel_get_input_soundcard:
7352  * @channel: the #AgsChannel
7353  *
7354  * Get the input soundcard object of @channel.
7355  *
7356  * Returns: (transfer full): the input soundcard
7357  *
7358  * Since: 3.1.0
7359  */
7360 GObject*
ags_channel_get_input_soundcard(AgsChannel * channel)7361 ags_channel_get_input_soundcard(AgsChannel *channel)
7362 {
7363   GObject *input_soundcard;
7364 
7365   if(!AGS_IS_CHANNEL(channel)){
7366     return(NULL);
7367   }
7368 
7369   g_object_get(channel,
7370 	       "input-soundcard", &input_soundcard,
7371 	       NULL);
7372 
7373   return(input_soundcard);
7374 }
7375 
7376 void
ags_channel_real_set_input_soundcard(AgsChannel * channel,GObject * input_soundcard)7377 ags_channel_real_set_input_soundcard(AgsChannel *channel,
7378 				     GObject *input_soundcard)
7379 {
7380   AgsRecycling *recycling;
7381 
7382   GObject *old_soundcard;
7383 
7384   GList *list;
7385 
7386   gboolean reset_recycling;
7387 
7388   GRecMutex *channel_mutex;
7389   GRecMutex *play_mutex, *recall_mutex;
7390 
7391   if(!AGS_IS_CHANNEL(channel)){
7392     return;
7393   }
7394 
7395   /* get channel mutex */
7396   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
7397 
7398   /* old soundcard */
7399   g_rec_mutex_lock(channel_mutex);
7400 
7401   old_soundcard = channel->input_soundcard;
7402 
7403   g_rec_mutex_unlock(channel_mutex);
7404 
7405   if(old_soundcard == input_soundcard){
7406     return;
7407   }
7408 
7409   /* ref and set new soundcard */
7410   if(input_soundcard != NULL){
7411     g_object_ref(input_soundcard);
7412   }
7413 
7414   g_rec_mutex_lock(channel_mutex);
7415 
7416   channel->input_soundcard = (GObject *) input_soundcard;
7417 
7418   g_rec_mutex_unlock(channel_mutex);
7419 
7420   /* AgsRecycling */
7421   reset_recycling = FALSE;
7422 
7423   g_rec_mutex_lock(channel_mutex);
7424 
7425   if((AGS_IS_OUTPUT(channel) ||
7426       channel->link == NULL) &&
7427      channel->first_recycling != NULL){
7428     reset_recycling = TRUE;
7429   }
7430 
7431   g_rec_mutex_unlock(channel_mutex);
7432 
7433   if(reset_recycling){
7434     g_rec_mutex_lock(channel_mutex);
7435 
7436     recycling = channel->first_recycling;
7437 
7438     g_rec_mutex_unlock(channel_mutex);
7439 
7440     g_object_set(G_OBJECT(recycling),
7441 		 "input-soundcard", input_soundcard,
7442 		 NULL);
7443   }
7444 
7445   /* get play mutex */
7446   play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
7447 
7448   /* play context */
7449   g_rec_mutex_lock(play_mutex);
7450 
7451   list = channel->play;
7452 
7453   while(list != NULL){
7454     g_object_set(G_OBJECT(list->data),
7455 		 "input-soundcard", input_soundcard,
7456 		 NULL);
7457 
7458     list = list->next;
7459   }
7460 
7461   g_rec_mutex_unlock(play_mutex);
7462 
7463   /* get recall mutex */
7464   recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
7465 
7466   /* recall context */
7467   g_rec_mutex_lock(recall_mutex);
7468 
7469   list = channel->recall;
7470 
7471   while(list != NULL){
7472     g_object_set(G_OBJECT(list->data),
7473 		 "input-soundcard", input_soundcard,
7474 		 NULL);
7475 
7476     list = list->next;
7477   }
7478 
7479   g_rec_mutex_unlock(recall_mutex);
7480 
7481   /* unref old soundcard */
7482   if(old_soundcard != NULL){
7483     g_object_unref(old_soundcard);
7484   }
7485 }
7486 
7487 /**
7488  * ags_channel_set_input_soundcard:
7489  * @channel: an #AgsChannel
7490  * @input_soundcard: the #GObject implementing #AgsSoundcard
7491  *
7492  * Set the input soundcard object of @channel.
7493  *
7494  * Since: 3.0.0
7495  */
7496 void
ags_channel_set_input_soundcard(AgsChannel * channel,GObject * input_soundcard)7497 ags_channel_set_input_soundcard(AgsChannel *channel, GObject *input_soundcard)
7498 {
7499   if(!AGS_IS_CHANNEL(channel)){
7500     return;
7501   }
7502 
7503   g_object_set(channel,
7504 	       "input-soundcard", input_soundcard,
7505 	       NULL);
7506 }
7507 
7508 /**
7509  * ags_channel_get_samplerate:
7510  * @channel: the #AgsChannel
7511  *
7512  * Gets samplerate.
7513  *
7514  * Returns: the samplerate
7515  *
7516  * Since: 3.1.0
7517  */
7518 guint
ags_channel_get_samplerate(AgsChannel * channel)7519 ags_channel_get_samplerate(AgsChannel *channel)
7520 {
7521   guint samplerate;
7522 
7523   if(!AGS_IS_CHANNEL(channel)){
7524     return(0);
7525   }
7526 
7527   g_object_get(channel,
7528 	       "samplerate", &samplerate,
7529 	       NULL);
7530 
7531   return(samplerate);
7532 }
7533 
7534 void
ags_channel_real_set_samplerate(AgsChannel * channel,guint samplerate)7535 ags_channel_real_set_samplerate(AgsChannel *channel, guint samplerate)
7536 {
7537   AgsChannel *link;
7538   AgsRecycling *recycling;
7539   AgsPlayback *playback;
7540 
7541   AgsThread *channel_thread;
7542   AgsMessageDelivery *message_delivery;
7543 
7544   GList *start_message_queue;
7545 
7546   gdouble frequency;
7547   guint old_samplerate;
7548   gint i;
7549 
7550   GRecMutex *channel_mutex;
7551   GRecMutex *playback_mutex;
7552 
7553   if(!AGS_IS_CHANNEL(channel)){
7554     return;
7555   }
7556 
7557   /* get channel mutex */
7558   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
7559 
7560   /* set samplerate */
7561   g_rec_mutex_lock(channel_mutex);
7562 
7563   old_samplerate = channel->samplerate;
7564 
7565   channel->samplerate = samplerate;
7566 
7567   link = channel->link;
7568   recycling = channel->first_recycling;
7569 
7570   playback = (AgsPlayback *) channel->playback;
7571 
7572   frequency = ceil((gdouble) channel->samplerate / (gdouble) channel->buffer_size) + AGS_SOUNDCARD_DEFAULT_OVERCLOCK;
7573 
7574   g_rec_mutex_unlock(channel_mutex);
7575 
7576   if(playback != NULL){
7577     /* get playback domain mutex */
7578     playback_mutex = AGS_PLAYBACK_GET_OBJ_MUTEX(playback);
7579 
7580     /* channel thread - frequency */
7581     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
7582       g_rec_mutex_lock(playback_mutex);
7583 
7584       channel_thread = playback->channel_thread[i];
7585 
7586       g_rec_mutex_unlock(playback_mutex);
7587 
7588       if(channel_thread != NULL){
7589 	/* apply new frequency */
7590 	g_object_set(channel_thread,
7591 		     "frequency", frequency,
7592 		     NULL);
7593       }
7594     }
7595   }
7596 
7597   if(link == NULL &&
7598      recycling != NULL){
7599     g_object_set(recycling,
7600 		 "samplerate", samplerate,
7601 		 NULL);
7602   }
7603 
7604   /* emit message */
7605   message_delivery = ags_message_delivery_get_instance();
7606 
7607   start_message_queue = ags_message_delivery_find_sender_namespace(message_delivery,
7608 								   "libags-audio");
7609 
7610   if(start_message_queue != NULL){
7611     AgsMessageEnvelope *message;
7612 
7613     xmlDoc *doc;
7614     xmlNode *root_node;
7615 
7616     /* specify message body */
7617     doc = xmlNewDoc("1.0");
7618 
7619     root_node = xmlNewNode(NULL,
7620 			   "ags-command");
7621     xmlDocSetRootElement(doc, root_node);
7622 
7623     xmlNewProp(root_node,
7624 	       "method",
7625 	       "AgsChannel::set-samplerate");
7626 
7627     /* add message */
7628     message = ags_message_envelope_new((GObject *) channel,
7629 				       NULL,
7630 				       doc);
7631 
7632     /* set parameter */
7633     message->n_params = 2;
7634 
7635     message->parameter_name = (gchar **) malloc(3 * sizeof(gchar *));
7636     message->value = g_new0(GValue,
7637 			    2);
7638 
7639     /* samplerate */
7640     message->parameter_name[0] = "samplerate";
7641 
7642     g_value_init(&(message->value[0]),
7643 		 G_TYPE_UINT);
7644     g_value_set_uint(&(message->value[0]),
7645 		     samplerate);
7646 
7647     /* old samplerate */
7648     message->parameter_name[1] = "old-samplerate";
7649 
7650     g_value_init(&(message->value[1]),
7651 		 G_TYPE_UINT);
7652     g_value_set_uint(&(message->value[1]),
7653 		     old_samplerate);
7654 
7655     /* terminate string vector */
7656     message->parameter_name[2] = NULL;
7657 
7658     /* add message */
7659     ags_message_delivery_add_message_envelope(message_delivery,
7660 					      "libags-audio",
7661 					      message);
7662 
7663     g_list_free_full(start_message_queue,
7664 		     (GDestroyNotify) g_object_unref);
7665   }
7666 }
7667 
7668 /**
7669  * ags_channel_set_samplerate:
7670  * @channel: the #AgsChannel
7671  * @samplerate: the samplerate
7672  *
7673  * Set samplerate.
7674  *
7675  * Since: 3.0.0
7676  */
7677 void
ags_channel_set_samplerate(AgsChannel * channel,guint samplerate)7678 ags_channel_set_samplerate(AgsChannel *channel, guint samplerate)
7679 {
7680   if(!AGS_IS_CHANNEL(channel)){
7681     return;
7682   }
7683 
7684   g_object_set(channel,
7685 	       "samplerate", samplerate,
7686 	       NULL);
7687 }
7688 
7689 /**
7690  * ags_channel_get_buffer_size:
7691  * @channel: the #AgsChannel
7692  *
7693  * Gets buffer size.
7694  *
7695  * Returns: the buffer size
7696  *
7697  * Since: 3.1.0
7698  */
7699 guint
ags_channel_get_buffer_size(AgsChannel * channel)7700 ags_channel_get_buffer_size(AgsChannel *channel)
7701 {
7702   guint buffer_size;
7703 
7704   if(!AGS_IS_CHANNEL(channel)){
7705     return(0);
7706   }
7707 
7708   g_object_get(channel,
7709 	       "buffer-size", &buffer_size,
7710 	       NULL);
7711 
7712   return(buffer_size);
7713 }
7714 
7715 void
ags_channel_real_set_buffer_size(AgsChannel * channel,guint buffer_size)7716 ags_channel_real_set_buffer_size(AgsChannel *channel, guint buffer_size)
7717 {
7718   AgsChannel *link;
7719   AgsRecycling *recycling;
7720   AgsPlayback *playback;
7721 
7722   AgsThread *channel_thread;
7723   AgsMessageDelivery *message_delivery;
7724 
7725   GList *start_message_queue;
7726 
7727   gdouble frequency;
7728   guint old_buffer_size;
7729   gint i;
7730 
7731   GRecMutex *channel_mutex;
7732   GRecMutex *playback_mutex;
7733 
7734   if(!AGS_IS_CHANNEL(channel)){
7735     return;
7736   }
7737 
7738   /* get channel mutex */
7739   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
7740 
7741   /* set buffer size */
7742   g_rec_mutex_lock(channel_mutex);
7743 
7744   old_buffer_size = channel->buffer_size;
7745 
7746   channel->buffer_size = buffer_size;
7747 
7748   link = channel->link;
7749   recycling = channel->first_recycling;
7750 
7751   playback = (AgsPlayback *) channel->playback;
7752 
7753   frequency = ceil((gdouble) channel->samplerate / (gdouble) channel->buffer_size) + AGS_SOUNDCARD_DEFAULT_OVERCLOCK;
7754 
7755   g_rec_mutex_unlock(channel_mutex);
7756 
7757   if(playback != NULL){
7758     /* get playback domain mutex */
7759     playback_mutex = AGS_PLAYBACK_GET_OBJ_MUTEX(playback);
7760 
7761     /* channel thread - frequency */
7762     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
7763       g_rec_mutex_lock(playback_mutex);
7764 
7765       channel_thread = playback->channel_thread[i];
7766 
7767       g_rec_mutex_unlock(playback_mutex);
7768 
7769       if(channel_thread != NULL){
7770 	/* apply new frequency */
7771 	g_object_set(channel_thread,
7772 		     "frequency", frequency,
7773 		     NULL);
7774       }
7775     }
7776   }
7777 
7778   if(link == NULL &&
7779      recycling != NULL){
7780     g_object_set(recycling,
7781 		 "buffer-size", buffer_size,
7782 		 NULL);
7783   }
7784 
7785   /* emit message */
7786   message_delivery = ags_message_delivery_get_instance();
7787 
7788   start_message_queue = ags_message_delivery_find_sender_namespace(message_delivery,
7789 								   "libags-audio");
7790 
7791   if(start_message_queue != NULL){
7792     AgsMessageEnvelope *message;
7793 
7794     xmlDoc *doc;
7795     xmlNode *root_node;
7796 
7797     /* specify message body */
7798     doc = xmlNewDoc("1.0");
7799 
7800     root_node = xmlNewNode(NULL,
7801 			   "ags-command");
7802     xmlDocSetRootElement(doc, root_node);
7803 
7804     xmlNewProp(root_node,
7805 	       "method",
7806 	       "AgsChannel::set-buffer-size");
7807 
7808     /* add message */
7809     message = ags_message_envelope_new((GObject *) channel,
7810 				       NULL,
7811 				       doc);
7812 
7813     /* set parameter */
7814     message->n_params = 2;
7815 
7816     message->parameter_name = (gchar **) malloc(3 * sizeof(gchar *));
7817     message->value = g_new0(GValue,
7818 			    2);
7819 
7820     /* buffer_size */
7821     message->parameter_name[0] = "buffer-size";
7822 
7823     g_value_init(&(message->value[0]),
7824 		 G_TYPE_UINT);
7825     g_value_set_uint(&(message->value[0]),
7826 		     buffer_size);
7827 
7828     /* old buffer_size */
7829     message->parameter_name[1] = "old-buffer-size";
7830 
7831     g_value_init(&(message->value[1]),
7832 		 G_TYPE_UINT);
7833     g_value_set_uint(&(message->value[1]),
7834 		     old_buffer_size);
7835 
7836     /* terminate string vector */
7837     message->parameter_name[2] = NULL;
7838 
7839     /* add message */
7840     ags_message_delivery_add_message_envelope(message_delivery,
7841 					      "libags-audio",
7842 					      message);
7843 
7844     g_list_free_full(start_message_queue,
7845 		     (GDestroyNotify) g_object_unref);
7846   }
7847 }
7848 
7849 /**
7850  * ags_channel_set_buffer_size:
7851  * @channel: the #AgsChannel
7852  * @buffer_size: the buffer_size
7853  *
7854  * Set buffer-size.
7855  *
7856  * Since: 3.0.0
7857  */
7858 void
ags_channel_set_buffer_size(AgsChannel * channel,guint buffer_size)7859 ags_channel_set_buffer_size(AgsChannel *channel, guint buffer_size)
7860 {
7861   if(!AGS_IS_CHANNEL(channel)){
7862     return;
7863   }
7864 
7865   g_object_set(channel,
7866 	       "buffer-size", buffer_size,
7867 	       NULL);
7868 }
7869 
7870 /**
7871  * ags_channel_get_format:
7872  * @channel: the #AgsChannel
7873  *
7874  * Gets format.
7875  *
7876  * Returns: the format
7877  *
7878  * Since: 3.1.0
7879  */
7880 guint
ags_channel_get_format(AgsChannel * channel)7881 ags_channel_get_format(AgsChannel *channel)
7882 {
7883   guint format;
7884 
7885   if(!AGS_IS_CHANNEL(channel)){
7886     return(0);
7887   }
7888 
7889   g_object_get(channel,
7890 	       "format", &format,
7891 	       NULL);
7892 
7893   return(format);
7894 }
7895 
7896 void
ags_channel_real_set_format(AgsChannel * channel,guint format)7897 ags_channel_real_set_format(AgsChannel *channel, guint format)
7898 {
7899   AgsChannel *link;
7900   AgsRecycling *recycling;
7901 
7902   AgsMessageDelivery *message_delivery;
7903 
7904   GList *start_message_queue;
7905 
7906   guint old_format;
7907 
7908   GRecMutex *channel_mutex;
7909 
7910   if(!AGS_IS_CHANNEL(channel)){
7911     return;
7912   }
7913 
7914   /* get channel mutex */
7915   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
7916 
7917   /* set buffer size */
7918   g_rec_mutex_lock(channel_mutex);
7919 
7920   old_format = channel->format;
7921 
7922   channel->format = format;
7923 
7924   link = channel->link;
7925   recycling = channel->first_recycling;
7926 
7927   g_rec_mutex_unlock(channel_mutex);
7928 
7929   if(link == NULL &&
7930      recycling != NULL){
7931     g_object_set(recycling,
7932 		 "format", format,
7933 		 NULL);
7934   }
7935 
7936   /* emit message */
7937   message_delivery = ags_message_delivery_get_instance();
7938 
7939   start_message_queue = ags_message_delivery_find_sender_namespace(message_delivery,
7940 								   "libags-audio");
7941 
7942   if(start_message_queue != NULL){
7943     AgsMessageEnvelope *message;
7944 
7945     xmlDoc *doc;
7946     xmlNode *root_node;
7947 
7948     /* specify message body */
7949     doc = xmlNewDoc("1.0");
7950 
7951     root_node = xmlNewNode(NULL,
7952 			   "ags-command");
7953     xmlDocSetRootElement(doc, root_node);
7954 
7955     xmlNewProp(root_node,
7956 	       "method",
7957 	       "AgsChannel::set-format");
7958 
7959     /* add message */
7960     message = ags_message_envelope_new((GObject *) channel,
7961 				       NULL,
7962 				       doc);
7963 
7964     /* set parameter */
7965     message->n_params = 2;
7966 
7967     message->parameter_name = (gchar **) malloc(3 * sizeof(gchar *));
7968     message->value = g_new0(GValue,
7969 			    2);
7970 
7971     /* format */
7972     message->parameter_name[0] = "format";
7973 
7974     g_value_init(&(message->value[0]),
7975 		 G_TYPE_UINT);
7976     g_value_set_uint(&(message->value[0]),
7977 		     format);
7978 
7979     /* old format */
7980     message->parameter_name[1] = "old-format";
7981 
7982     g_value_init(&(message->value[1]),
7983 		 G_TYPE_UINT);
7984     g_value_set_uint(&(message->value[1]),
7985 		     old_format);
7986 
7987     /* terminate string vector */
7988     message->parameter_name[2] = NULL;
7989 
7990     /* add message */
7991     ags_message_delivery_add_message_envelope(message_delivery,
7992 					      "libags-audio",
7993 					      message);
7994 
7995     g_list_free_full(start_message_queue,
7996 		     (GDestroyNotify) g_object_unref);
7997   }
7998 }
7999 
8000 /**
8001  * ags_channel_set_format:
8002  * @channel: the #AgsChannel
8003  * @format: the format
8004  *
8005  * Set format.
8006  *
8007  * Since: 3.0.0
8008  */
8009 void
ags_channel_set_format(AgsChannel * channel,guint format)8010 ags_channel_set_format(AgsChannel *channel, guint format)
8011 {
8012   if(!AGS_IS_CHANNEL(channel)){
8013     return;
8014   }
8015 
8016   g_object_set(channel,
8017 	       "format", format,
8018 	       NULL);
8019 }
8020 
8021 /**
8022  * ags_channel_get_pad:
8023  * @channel: the #AgsChannel
8024  *
8025  * Gets pad.
8026  *
8027  * Returns: the pad
8028  *
8029  * Since: 3.1.0
8030  */
8031 guint
ags_channel_get_pad(AgsChannel * channel)8032 ags_channel_get_pad(AgsChannel *channel)
8033 {
8034   guint pad;
8035 
8036   if(!AGS_IS_CHANNEL(channel)){
8037     return(0);
8038   }
8039 
8040   g_object_get(channel,
8041 	       "pad", &pad,
8042 	       NULL);
8043 
8044   return(pad);
8045 }
8046 
8047 /**
8048  * ags_channel_set_pad:
8049  * @channel: the #AgsChannel
8050  * @pad: the pad
8051  *
8052  * Set pad.
8053  *
8054  * Since: 3.0.0
8055  */
8056 void
ags_channel_set_pad(AgsChannel * channel,guint pad)8057 ags_channel_set_pad(AgsChannel *channel, guint pad)
8058 {
8059   if(!AGS_IS_CHANNEL(channel)){
8060     return;
8061   }
8062 
8063 
8064   g_object_set(channel,
8065 	       "pad", pad,
8066 	       NULL);
8067 }
8068 
8069 /**
8070  * ags_channel_get_audio_channel:
8071  * @channel: the #AgsChannel
8072  *
8073  * Gets audio_channel.
8074  *
8075  * Returns: the audio_channel
8076  *
8077  * Since: 3.1.0
8078  */
8079 guint
ags_channel_get_audio_channel(AgsChannel * channel)8080 ags_channel_get_audio_channel(AgsChannel *channel)
8081 {
8082   guint audio_channel;
8083 
8084   if(!AGS_IS_CHANNEL(channel)){
8085     return(0);
8086   }
8087 
8088   g_object_get(channel,
8089 	       "audio-channel", &audio_channel,
8090 	       NULL);
8091 
8092   return(audio_channel);
8093 }
8094 
8095 /**
8096  * ags_channel_set_audio_channel:
8097  * @channel: the #AgsChannel
8098  * @audio_channel: the audio_channel
8099  *
8100  * Set audio_channel.
8101  *
8102  * Since: 3.0.0
8103  */
8104 void
ags_channel_set_audio_channel(AgsChannel * channel,guint audio_channel)8105 ags_channel_set_audio_channel(AgsChannel *channel, guint audio_channel)
8106 {
8107   if(!AGS_IS_CHANNEL(channel)){
8108     return;
8109   }
8110 
8111 
8112   g_object_set(channel,
8113 	       "audio-channel", audio_channel,
8114 	       NULL);
8115 }
8116 
8117 /**
8118  * ags_channel_get_line:
8119  * @channel: the #AgsChannel
8120  *
8121  * Gets line.
8122  *
8123  * Returns: the line
8124  *
8125  * Since: 3.1.0
8126  */
8127 guint
ags_channel_get_line(AgsChannel * channel)8128 ags_channel_get_line(AgsChannel *channel)
8129 {
8130   guint line;
8131 
8132   if(!AGS_IS_CHANNEL(channel)){
8133     return(0);
8134   }
8135 
8136   g_object_get(channel,
8137 	       "line", &line,
8138 	       NULL);
8139 
8140   return(line);
8141 }
8142 
8143 /**
8144  * ags_channel_set_line:
8145  * @channel: the #AgsChannel
8146  * @line: the line
8147  *
8148  * Set line.
8149  *
8150  * Since: 3.0.0
8151  */
8152 void
ags_channel_set_line(AgsChannel * channel,guint line)8153 ags_channel_set_line(AgsChannel *channel, guint line)
8154 {
8155   if(!AGS_IS_CHANNEL(channel)){
8156     return;
8157   }
8158 
8159 
8160   g_object_set(channel,
8161 	       "line", line,
8162 	       NULL);
8163 }
8164 
8165 /**
8166  * ags_channel_get_octave:
8167  * @channel: the #AgsChannel
8168  *
8169  * Gets octave.
8170  *
8171  * Returns: the octave
8172  *
8173  * Since: 3.1.0
8174  */
8175 gint
ags_channel_get_octave(AgsChannel * channel)8176 ags_channel_get_octave(AgsChannel *channel)
8177 {
8178   gint octave;
8179 
8180   if(!AGS_IS_CHANNEL(channel)){
8181     return(0);
8182   }
8183 
8184   g_object_get(channel,
8185 	       "octave", &octave,
8186 	       NULL);
8187 
8188   return(octave);
8189 }
8190 
8191 /**
8192  * ags_channel_set_octave:
8193  * @channel: the #AgsChannel
8194  * @octave: the octave
8195  *
8196  * Sets octave.
8197  *
8198  * Since: 3.1.0
8199  */
8200 void
ags_channel_set_octave(AgsChannel * channel,gint octave)8201 ags_channel_set_octave(AgsChannel *channel, gint octave)
8202 {
8203   if(!AGS_IS_CHANNEL(channel)){
8204     return;
8205   }
8206 
8207   g_object_set(channel,
8208 	       "octave", octave,
8209 	       NULL);
8210 }
8211 
8212 /**
8213  * ags_channel_get_key:
8214  * @channel: the #AgsChannel
8215  *
8216  * Gets key.
8217  *
8218  * Returns: the key
8219  *
8220  * Since: 3.1.0
8221  */
8222 guint
ags_channel_get_key(AgsChannel * channel)8223 ags_channel_get_key(AgsChannel *channel)
8224 {
8225   guint key;
8226 
8227   if(!AGS_IS_CHANNEL(channel)){
8228     return(0);
8229   }
8230 
8231   g_object_get(channel,
8232 	       "key", &key,
8233 	       NULL);
8234 
8235   return(key);
8236 }
8237 
8238 /**
8239  * ags_channel_set_key:
8240  * @channel: the #AgsChannel
8241  * @key: the key
8242  *
8243  * Sets key.
8244  *
8245  * Since: 3.1.0
8246  */
8247 void
ags_channel_set_key(AgsChannel * channel,guint key)8248 ags_channel_set_key(AgsChannel *channel, guint key)
8249 {
8250   if(!AGS_IS_CHANNEL(channel)){
8251     return;
8252   }
8253 
8254   g_object_set(channel,
8255 	       "key", key,
8256 	       NULL);
8257 }
8258 
8259 /**
8260  * ags_channel_get_absolute_key:
8261  * @channel: the #AgsChannel
8262  *
8263  * Gets absolute key.
8264  *
8265  * Returns: the absolute key
8266  *
8267  * Since: 3.1.0
8268  */
8269 gint
ags_channel_get_absolute_key(AgsChannel * channel)8270 ags_channel_get_absolute_key(AgsChannel *channel)
8271 {
8272   gint absolute_key;
8273 
8274   if(!AGS_IS_CHANNEL(channel)){
8275     return(0);
8276   }
8277 
8278   g_object_get(channel,
8279 	       "absolute-key", &absolute_key,
8280 	       NULL);
8281 
8282   return(absolute_key);
8283 }
8284 
8285 /**
8286  * ags_channel_set_absolute_key:
8287  * @channel: the #AgsChannel
8288  * @absolute_key: the absolute key
8289  *
8290  * Sets absolute key.
8291  *
8292  * Since: 3.1.0
8293  */
8294 void
ags_channel_set_absolute_key(AgsChannel * channel,gint absolute_key)8295 ags_channel_set_absolute_key(AgsChannel *channel, gint absolute_key)
8296 {
8297   if(!AGS_IS_CHANNEL(channel)){
8298     return;
8299   }
8300 
8301   g_object_set(channel,
8302 	       "absolute-key", absolute_key,
8303 	       NULL);
8304 }
8305 
8306 /**
8307  * ags_channel_get_pattern:
8308  * @channel: the #AgsChannel
8309  *
8310  * Get pattern.
8311  *
8312  * Returns: (element-type AgsAudio.Pattern) (transfer full): the #GList-struct containig #AgsPattern
8313  *
8314  * Since: 3.1.0
8315  */
8316 GList*
ags_channel_get_pattern(AgsChannel * channel)8317 ags_channel_get_pattern(AgsChannel *channel)
8318 {
8319   GList *pattern;
8320 
8321   if(!AGS_IS_CHANNEL(channel)){
8322     return(NULL);
8323   }
8324 
8325   g_object_get(channel,
8326 	       "pattern", &pattern,
8327 	       NULL);
8328 
8329   return(pattern);
8330 }
8331 
8332 /**
8333  * ags_channel_set_pattern:
8334  * @channel: the #AgsChannel
8335  * @pattern: (element-type AgsAudio.Pattern) (transfer full): the #GList-struct containing #AgsPattern
8336  *
8337  * Set pattern by replacing existing.
8338  *
8339  * Since: 3.1.0
8340  */
8341 void
ags_channel_set_pattern(AgsChannel * channel,GList * pattern)8342 ags_channel_set_pattern(AgsChannel *channel, GList *pattern)
8343 {
8344   GList *start_pattern;
8345 
8346   GRecMutex *channel_mutex;
8347 
8348   if(!AGS_IS_CHANNEL(channel)){
8349     return;
8350   }
8351 
8352   /* get channel mutex */
8353   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8354 
8355   g_rec_mutex_lock(channel_mutex);
8356 
8357   start_pattern = channel->pattern;
8358   channel->pattern = pattern;
8359 
8360   g_rec_mutex_unlock(channel_mutex);
8361 
8362   g_list_free_full(start_pattern,
8363 		   (GDestroyNotify) g_object_unref);
8364 }
8365 
8366 /**
8367  * ags_channel_add_pattern:
8368  * @channel: an #AgsChannel
8369  * @pattern: the #AgsPattern
8370  *
8371  * Removes a pattern.
8372  *
8373  * Since: 3.0.0
8374  */
8375 void
ags_channel_add_pattern(AgsChannel * channel,GObject * pattern)8376 ags_channel_add_pattern(AgsChannel *channel, GObject *pattern)
8377 {
8378   GRecMutex *channel_mutex;
8379 
8380   if(!AGS_IS_CHANNEL(channel) ||
8381      !AGS_IS_PATTERN(pattern)){
8382     return;
8383   }
8384 
8385   /* get channel mutex */
8386   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8387 
8388   /*  add pattern */
8389   g_rec_mutex_lock(channel_mutex);
8390 
8391   if(g_list_find(channel->pattern, pattern) == NULL){
8392     g_object_ref(pattern);
8393     channel->pattern = g_list_prepend(channel->pattern,
8394 				      pattern);
8395   }
8396 
8397   g_rec_mutex_unlock(channel_mutex);
8398 }
8399 
8400 /**
8401  * ags_channel_remove_pattern:
8402  * @channel: an #AgsChannel
8403  * @pattern: the #AgsPattern
8404  *
8405  * Removes a pattern.
8406  *
8407  * Since: 3.0.0
8408  */
8409 void
ags_channel_remove_pattern(AgsChannel * channel,GObject * pattern)8410 ags_channel_remove_pattern(AgsChannel *channel, GObject *pattern)
8411 {
8412   GRecMutex *channel_mutex;
8413 
8414   if(!AGS_IS_CHANNEL(channel) ||
8415      !AGS_IS_PATTERN(pattern)){
8416     return;
8417   }
8418 
8419   /* get channel mutex */
8420   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8421 
8422   /* remove pattern */
8423   g_rec_mutex_lock(channel_mutex);
8424 
8425   if(g_list_find(channel->pattern, pattern) != NULL){
8426     channel->pattern = g_list_remove(channel->pattern,
8427 				     pattern);
8428     g_object_unref(G_OBJECT(pattern));
8429   }
8430 
8431   g_rec_mutex_unlock(channel_mutex);
8432 }
8433 
8434 /**
8435  * ags_channel_get_playback:
8436  * @channel: the #AgsChannel
8437  *
8438  * Get playback.
8439  *
8440  * Returns: (transfer full): the #AgsPlayback
8441  *
8442  * Since: 3.1.0
8443  */
8444 GObject*
ags_channel_get_playback(AgsChannel * channel)8445 ags_channel_get_playback(AgsChannel *channel)
8446 {
8447   GObject *playback;
8448 
8449   if(!AGS_IS_CHANNEL(channel)){
8450     return(NULL);
8451   }
8452 
8453   g_object_get(channel,
8454 	       "playback", &playback,
8455 	       NULL);
8456 
8457   return(playback);
8458 }
8459 
8460 /**
8461  * ags_channel_set_playback:
8462  * @channel: the #AgsChannel
8463  * @playback: the #AgsPlayback
8464  *
8465  * Set playback.
8466  *
8467  * Since: 3.1.0
8468  */
8469 void
ags_channel_set_playback(AgsChannel * channel,GObject * playback)8470 ags_channel_set_playback(AgsChannel *channel, GObject *playback)
8471 {
8472   if(!AGS_IS_CHANNEL(channel)){
8473     return;
8474   }
8475 
8476   g_object_set(channel,
8477 	       "playback", playback,
8478 	       NULL);
8479 }
8480 
8481 /**
8482  * ags_channel_get_recall_id:
8483  * @channel: the #AgsChannel
8484  *
8485  * Get recall id.
8486  *
8487  * Returns: (element-type AgsAudio.RecallID) (transfer full): the #GList-struct containig #AgsRecallID
8488  *
8489  * Since: 3.1.0
8490  */
8491 GList*
ags_channel_get_recall_id(AgsChannel * channel)8492 ags_channel_get_recall_id(AgsChannel *channel)
8493 {
8494   GList *recall_id;
8495 
8496   if(!AGS_IS_CHANNEL(channel)){
8497     return(NULL);
8498   }
8499 
8500   g_object_get(channel,
8501 	       "recall_id", &recall_id,
8502 	       NULL);
8503 
8504   return(recall_id);
8505 }
8506 
8507 /**
8508  * ags_channel_set_recall_id:
8509  * @channel: the #AgsChannel
8510  * @recall_id: (element-type AgsAudio.RecallID) (transfer full): the #GList-struct containing #AgsRecallID
8511  *
8512  * Set recall id by replacing existing.
8513  *
8514  * Since: 3.1.0
8515  */
8516 void
ags_channel_set_recall_id(AgsChannel * channel,GList * recall_id)8517 ags_channel_set_recall_id(AgsChannel *channel, GList *recall_id)
8518 {
8519   GList *start_recall_id;
8520 
8521   GRecMutex *channel_mutex;
8522 
8523   if(!AGS_IS_CHANNEL(channel)){
8524     return;
8525   }
8526 
8527   /* get channel mutex */
8528   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8529 
8530   g_rec_mutex_lock(channel_mutex);
8531 
8532   start_recall_id = channel->recall_id;
8533   channel->recall_id = recall_id;
8534 
8535   g_rec_mutex_unlock(channel_mutex);
8536 
8537   g_list_free_full(start_recall_id,
8538 		   (GDestroyNotify) g_object_unref);
8539 }
8540 
8541 /**
8542  * ags_channel_add_recall_id:
8543  * @channel: an #AgsChannel
8544  * @recall_id: the #AgsRecallID
8545  *
8546  * Adds a recall id.
8547  *
8548  * Since: 3.0.0
8549  */
8550 void
ags_channel_add_recall_id(AgsChannel * channel,AgsRecallID * recall_id)8551 ags_channel_add_recall_id(AgsChannel *channel, AgsRecallID *recall_id)
8552 {
8553   GRecMutex *channel_mutex;
8554 
8555   if(!AGS_IS_CHANNEL(channel) ||
8556      !AGS_IS_RECALL_ID(recall_id)){
8557     return;
8558   }
8559 
8560   /* get channel mutex */
8561   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8562 
8563   /* add recall id */
8564   g_rec_mutex_lock(channel_mutex);
8565 
8566   if(g_list_find(channel->recall_id, recall_id) == NULL){
8567     g_object_ref(G_OBJECT(recall_id));
8568     channel->recall_id = g_list_prepend(channel->recall_id,
8569 					recall_id);
8570   }
8571 
8572   g_rec_mutex_unlock(channel_mutex);
8573 }
8574 
8575 /**
8576  * ags_channel_remove_recall_id:
8577  * @channel: an #AgsChannel
8578  * @recall_id: the #AgsRecallID
8579  *
8580  * Removes a recall id.
8581  *
8582  * Since: 3.0.0
8583  */
8584 void
ags_channel_remove_recall_id(AgsChannel * channel,AgsRecallID * recall_id)8585 ags_channel_remove_recall_id(AgsChannel *channel, AgsRecallID *recall_id)
8586 {
8587   GRecMutex *channel_mutex;
8588 
8589   if(!AGS_IS_CHANNEL(channel) ||
8590      !AGS_IS_RECALL_ID(recall_id)){
8591     return;
8592   }
8593 
8594   /* get channel mutex */
8595   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8596 
8597   /* remove recall id */
8598   g_rec_mutex_lock(channel_mutex);
8599 
8600   if(g_list_find(channel->recall_id, recall_id) != NULL){
8601     channel->recall_id = g_list_remove(channel->recall_id,
8602 				       recall_id);
8603     g_object_unref(G_OBJECT(recall_id));
8604   }
8605 
8606   g_rec_mutex_unlock(channel_mutex);
8607 }
8608 
8609 /**
8610  * ags_channel_get_recall_container:
8611  * @channel: the #AgsChannel
8612  *
8613  * Get recall_container.
8614  *
8615  * Returns: (element-type AgsAudio.RecallContainer) (transfer full): the #GList-struct containig #AgsRecallContainer
8616  *
8617  * Since: 3.1.0
8618  */
8619 GList*
ags_channel_get_recall_container(AgsChannel * channel)8620 ags_channel_get_recall_container(AgsChannel *channel)
8621 {
8622   GList *recall_container;
8623 
8624   if(!AGS_IS_CHANNEL(channel)){
8625     return(NULL);
8626   }
8627 
8628   g_object_get(channel,
8629 	       "recall-container", &recall_container,
8630 	       NULL);
8631 
8632   return(recall_container);
8633 }
8634 
8635 /**
8636  * ags_channel_set_recall_container:
8637  * @channel: the #AgsChannel
8638  * @recall_container: (element-type AgsAudio.RecallContainer) (transfer full): the #GList-struct containing #AgsRecallContainer
8639  *
8640  * Set recall_container by replacing existing.
8641  *
8642  * Since: 3.1.0
8643  */
8644 void
ags_channel_set_recall_container(AgsChannel * channel,GList * recall_container)8645 ags_channel_set_recall_container(AgsChannel *channel, GList *recall_container)
8646 {
8647   GList *start_recall_container;
8648 
8649   GRecMutex *channel_mutex;
8650 
8651   if(!AGS_IS_CHANNEL(channel)){
8652     return;
8653   }
8654 
8655   /* get channel mutex */
8656   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8657 
8658   g_rec_mutex_lock(channel_mutex);
8659 
8660   start_recall_container = channel->recall_container;
8661   channel->recall_container = recall_container;
8662 
8663   g_rec_mutex_unlock(channel_mutex);
8664 
8665   g_list_free_full(start_recall_container,
8666 		   (GDestroyNotify) g_object_unref);
8667 }
8668 
8669 /**
8670  * ags_channel_add_recall_container:
8671  * @channel: an #AgsChannel
8672  * @recall_container: the #AgsRecallContainer
8673  *
8674  * Adds a recall container.
8675  *
8676  * Since: 3.0.0
8677  */
8678 void
ags_channel_add_recall_container(AgsChannel * channel,GObject * recall_container)8679 ags_channel_add_recall_container(AgsChannel *channel, GObject *recall_container)
8680 {
8681   GRecMutex *channel_mutex;
8682 
8683   if(!AGS_IS_CHANNEL(channel) ||
8684      !AGS_IS_RECALL_CONTAINER(recall_container)){
8685     return;
8686   }
8687 
8688   /* get channel mutex */
8689   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8690 
8691   /* add recall container */
8692   g_rec_mutex_lock(channel_mutex);
8693 
8694   if(g_list_find(channel->recall_container, recall_container) == NULL){
8695     g_object_ref(G_OBJECT(recall_container));
8696     channel->recall_container = g_list_prepend(channel->recall_container,
8697 					       recall_container);
8698   }
8699 
8700   g_rec_mutex_unlock(channel_mutex);
8701 }
8702 
8703 /**
8704  * ags_channel_remove_recall_container:
8705  * @channel: an #AgsChannel
8706  * @recall_container: the #AgsRecallContainer
8707  *
8708  * Removes a recall container.
8709  *
8710  * Since: 3.0.0
8711  */
8712 void
ags_channel_remove_recall_container(AgsChannel * channel,GObject * recall_container)8713 ags_channel_remove_recall_container(AgsChannel *channel, GObject *recall_container)
8714 {
8715   GRecMutex *channel_mutex;
8716 
8717   if(!AGS_IS_CHANNEL(channel) ||
8718      !AGS_IS_RECALL_CONTAINER(recall_container)){
8719     return;
8720   }
8721 
8722   /* get channel mutex */
8723   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8724 
8725   /* remove recall container */
8726   g_rec_mutex_lock(channel_mutex);
8727 
8728   if(g_list_find(channel->recall_container, recall_container) != NULL){
8729     channel->recall_container = g_list_remove(channel->recall_container,
8730 					      recall_container);
8731     g_object_unref(G_OBJECT(recall_container));
8732   }
8733 
8734   g_rec_mutex_unlock(channel_mutex);
8735 }
8736 
8737 /**
8738  * ags_channel_get_play:
8739  * @channel: the #AgsChannel
8740  *
8741  * Get play.
8742  *
8743  * Returns: (element-type AgsAudio.Recall) (transfer full): the #GList-struct containig #AgsRecall
8744  *
8745  * Since: 3.1.0
8746  */
8747 GList*
ags_channel_get_play(AgsChannel * channel)8748 ags_channel_get_play(AgsChannel *channel)
8749 {
8750   GList *play;
8751 
8752   if(!AGS_IS_CHANNEL(channel)){
8753     return(NULL);
8754   }
8755 
8756   g_object_get(channel,
8757 	       "play", &play,
8758 	       NULL);
8759 
8760   return(play);
8761 }
8762 
8763 /**
8764  * ags_channel_set_play:
8765  * @channel: the #AgsChannel
8766  * @play: (element-type AgsAudio.Recall) (transfer full): the #GList-struct containing #AgsRecall
8767  *
8768  * Set play by replacing existing.
8769  *
8770  * Since: 3.1.0
8771  */
8772 void
ags_channel_set_play(AgsChannel * channel,GList * play)8773 ags_channel_set_play(AgsChannel *channel, GList *play)
8774 {
8775   GList *start_play;
8776 
8777   GRecMutex *channel_mutex;
8778 
8779   if(!AGS_IS_CHANNEL(channel)){
8780     return;
8781   }
8782 
8783   /* get channel mutex */
8784   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8785 
8786   g_rec_mutex_lock(channel_mutex);
8787 
8788   start_play = channel->play;
8789   channel->play = play;
8790 
8791   g_rec_mutex_unlock(channel_mutex);
8792 
8793   g_list_free_full(start_play,
8794 		   (GDestroyNotify) g_object_unref);
8795 }
8796 
8797 /**
8798  * ags_channel_get_recall:
8799  * @channel: the #AgsChannel
8800  *
8801  * Get recall.
8802  *
8803  * Returns: (element-type AgsAudio.Recall) (transfer full): the #GList-struct containig #AgsRecall
8804  *
8805  * Since: 3.1.0
8806  */
8807 GList*
ags_channel_get_recall(AgsChannel * channel)8808 ags_channel_get_recall(AgsChannel *channel)
8809 {
8810   GList *recall;
8811 
8812   if(!AGS_IS_CHANNEL(channel)){
8813     return(NULL);
8814   }
8815 
8816   g_object_get(channel,
8817 	       "recall", &recall,
8818 	       NULL);
8819 
8820   return(recall);
8821 }
8822 
8823 /**
8824  * ags_channel_set_recall:
8825  * @channel: the #AgsChannel
8826  * @recall: (element-type AgsAudio.Recall) (transfer full): the #GList-struct containing #AgsRecall
8827  *
8828  * Set recall by replacing existing.
8829  *
8830  * Since: 3.1.0
8831  */
8832 void
ags_channel_set_recall(AgsChannel * channel,GList * recall)8833 ags_channel_set_recall(AgsChannel *channel, GList *recall)
8834 {
8835   GList *start_recall;
8836 
8837   GRecMutex *channel_mutex;
8838 
8839   if(!AGS_IS_CHANNEL(channel)){
8840     return;
8841   }
8842 
8843   /* get channel mutex */
8844   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8845 
8846   g_rec_mutex_lock(channel_mutex);
8847 
8848   start_recall = channel->recall;
8849   channel->recall = recall;
8850 
8851   g_rec_mutex_unlock(channel_mutex);
8852 
8853   g_list_free_full(start_recall,
8854 		   (GDestroyNotify) g_object_unref);
8855 }
8856 
8857 /**
8858  * ags_channel_add_recall:
8859  * @channel: an #AgsChannel
8860  * @recall: the #AgsRecall
8861  * @play_context: %TRUE if play context, else if %FALSE recall context
8862  *
8863  * Adds a recall.
8864  *
8865  * Since: 3.0.0
8866  */
8867 void
ags_channel_add_recall(AgsChannel * channel,GObject * recall,gboolean play_context)8868 ags_channel_add_recall(AgsChannel *channel, GObject *recall,
8869 		       gboolean play_context)
8870 {
8871   GObject *output_soundcard, *input_soundcard;
8872 
8873   gint output_soundcard_channel, input_soundcard_channel;
8874   guint samplerate;
8875   guint buffer_size;
8876   guint format;
8877   gboolean success;
8878 
8879   GRecMutex *channel_mutex;
8880 
8881   if(!AGS_IS_CHANNEL(channel) ||
8882      !AGS_IS_RECALL(recall)){
8883     return;
8884   }
8885 
8886   /* get channel mutex */
8887   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8888 
8889   /* get some fields */
8890   g_rec_mutex_lock(channel_mutex);
8891 
8892   output_soundcard = channel->output_soundcard;
8893   output_soundcard_channel = channel->output_soundcard_channel;
8894 
8895   input_soundcard = channel->input_soundcard;
8896   input_soundcard_channel = channel->input_soundcard_channel;
8897 
8898   samplerate = channel->samplerate;
8899   buffer_size = channel->buffer_size;
8900   format = channel->format;
8901 
8902   g_rec_mutex_unlock(channel_mutex);
8903 
8904   success = FALSE;
8905   g_object_set(recall,
8906 	       "output-soundcard", output_soundcard,
8907 	       "output-soundcard-channel", output_soundcard_channel,
8908 	       "input-soundcard", input_soundcard,
8909 	       "input-soundcard-channel", input_soundcard_channel,
8910 	       "samplerate", samplerate,
8911 	       "buffer-size", buffer_size,
8912 	       "format", format,
8913 	       NULL);
8914 
8915   if(play_context){
8916     GRecMutex *play_mutex;
8917 
8918     /* get play mutex */
8919     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
8920 
8921     /* add recall */
8922     g_rec_mutex_lock(play_mutex);
8923 
8924     if(g_list_find(channel->play, recall) == NULL){
8925       g_object_ref(G_OBJECT(recall));
8926 
8927       channel->play = g_list_prepend(channel->play,
8928 				     recall);
8929     }
8930 
8931     g_rec_mutex_unlock(play_mutex);
8932   }else{
8933     GRecMutex *recall_mutex;
8934 
8935     /* get recall mutex */
8936     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
8937 
8938     /* add recall */
8939     g_rec_mutex_lock(recall_mutex);
8940 
8941     if(g_list_find(channel->recall, recall) == NULL){
8942       g_object_ref(G_OBJECT(recall));
8943 
8944       channel->recall = g_list_prepend(channel->recall,
8945 				       recall);
8946     }
8947 
8948     g_rec_mutex_unlock(recall_mutex);
8949   }
8950 
8951   if(success){
8952     if(AGS_IS_RECALL_CHANNEL(recall) ||
8953        AGS_IS_RECALL_CHANNEL_RUN(recall)){
8954       g_object_set(recall,
8955 		   "source", channel,
8956 		   NULL);
8957     }
8958   }
8959 }
8960 
8961 /**
8962  * ags_channel_insert_recall:
8963  * @channel: an #AgsChannel
8964  * @recall: the #AgsRecall
8965  * @play_context: %TRUE if play context, else if %FALSE recall context
8966  * @position: the position
8967  *
8968  * Insert @recall at @position in @channel's @play_context.
8969  *
8970  * Since: 3.3.0
8971  */
8972 void
ags_channel_insert_recall(AgsChannel * channel,GObject * recall,gboolean play_context,gint position)8973 ags_channel_insert_recall(AgsChannel *channel, GObject *recall,
8974 			  gboolean play_context,
8975 			  gint position)
8976 {
8977   GObject *output_soundcard, *input_soundcard;
8978 
8979   gint output_soundcard_channel, input_soundcard_channel;
8980   guint samplerate;
8981   guint buffer_size;
8982   guint format;
8983   gboolean success;
8984 
8985   GRecMutex *channel_mutex;
8986 
8987   if(!AGS_IS_CHANNEL(channel) ||
8988      !AGS_IS_RECALL(recall)){
8989     return;
8990   }
8991 
8992   /* get channel mutex */
8993   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
8994 
8995   /* get some fields */
8996   g_rec_mutex_lock(channel_mutex);
8997 
8998   output_soundcard = channel->output_soundcard;
8999   output_soundcard_channel = channel->output_soundcard_channel;
9000 
9001   input_soundcard = channel->input_soundcard;
9002   input_soundcard_channel = channel->input_soundcard_channel;
9003 
9004   samplerate = channel->samplerate;
9005   buffer_size = channel->buffer_size;
9006   format = channel->format;
9007 
9008   g_rec_mutex_unlock(channel_mutex);
9009 
9010   success = FALSE;
9011   g_object_set(recall,
9012 	       "output-soundcard", output_soundcard,
9013 	       "output-soundcard-channel", output_soundcard_channel,
9014 	       "input-soundcard", input_soundcard,
9015 	       "input-soundcard-channel", input_soundcard_channel,
9016 	       "samplerate", samplerate,
9017 	       "buffer-size", buffer_size,
9018 	       "format", format,
9019 	       NULL);
9020 
9021   if(play_context){
9022     GRecMutex *play_mutex;
9023 
9024     /* get play mutex */
9025     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
9026 
9027     /* insert recall */
9028     g_rec_mutex_lock(play_mutex);
9029 
9030     if(g_list_find(channel->play, recall) == NULL){
9031       g_object_ref(G_OBJECT(recall));
9032 
9033       channel->play = g_list_insert(channel->play,
9034 				    recall,
9035 				    position);
9036     }
9037 
9038     g_rec_mutex_unlock(play_mutex);
9039   }else{
9040     GRecMutex *recall_mutex;
9041 
9042     /* get recall mutex */
9043     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
9044 
9045     /* insert recall */
9046     g_rec_mutex_lock(recall_mutex);
9047 
9048     if(g_list_find(channel->recall, recall) == NULL){
9049       g_object_ref(G_OBJECT(recall));
9050 
9051       channel->recall = g_list_insert(channel->recall,
9052 				      recall,
9053 				      position);
9054     }
9055 
9056     g_rec_mutex_unlock(recall_mutex);
9057   }
9058 
9059   if(success){
9060     if(AGS_IS_RECALL_CHANNEL(recall) ||
9061        AGS_IS_RECALL_CHANNEL_RUN(recall)){
9062       g_object_set(recall,
9063 		   "source", channel,
9064 		   NULL);
9065     }
9066   }
9067 }
9068 
9069 /**
9070  * ags_channel_remove_recall:
9071  * @channel: an #AgsChannel
9072  * @recall: the #AgsRecall
9073  * @play_context: %TRUE if play context, else if %FALSE recall context
9074  *
9075  * Removes a recall.
9076  *
9077  * Since: 3.0.0
9078  */
9079 void
ags_channel_remove_recall(AgsChannel * channel,GObject * recall,gboolean play_context)9080 ags_channel_remove_recall(AgsChannel *channel, GObject *recall,
9081 			  gboolean play_context)
9082 {
9083   gboolean success;
9084 
9085   if(!AGS_IS_CHANNEL(channel) ||
9086      !AGS_IS_RECALL(recall)){
9087     return;
9088   }
9089 
9090   success = FALSE;
9091 
9092   if(play_context){
9093     GRecMutex *play_mutex;
9094 
9095     /* get play mutex */
9096     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
9097 
9098     /* remove recall */
9099     g_rec_mutex_lock(play_mutex);
9100 
9101     if(g_list_find(channel->play, recall) != NULL){
9102       success = TRUE;
9103 
9104       channel->play = g_list_remove(channel->play,
9105 				    recall);
9106     }
9107 
9108     g_rec_mutex_unlock(play_mutex);
9109   }else{
9110     GRecMutex *recall_mutex;
9111 
9112     /* get recall mutex */
9113     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
9114 
9115     /* remove recall */
9116     g_rec_mutex_lock(recall_mutex);
9117 
9118     if(g_list_find(channel->recall, recall) != NULL){
9119       success = TRUE;
9120 
9121       channel->recall = g_list_remove(channel->recall,
9122 				      recall);
9123     }
9124 
9125     g_rec_mutex_unlock(recall_mutex);
9126   }
9127 
9128   if(success){
9129 #if 0
9130     if(AGS_IS_RECALL_CHANNEL(recall) ||
9131        AGS_IS_RECALL_CHANNEL_RUN(recall)){
9132       g_object_set(recall,
9133 		   "source", NULL,
9134 		   "destination", NULL,
9135 		   NULL);
9136     }
9137 #endif
9138 
9139     g_object_unref(G_OBJECT(recall));
9140   }
9141 }
9142 
9143 GList*
ags_channel_add_ladspa_effect(AgsChannel * channel,gchar * filename,gchar * effect)9144 ags_channel_add_ladspa_effect(AgsChannel *channel,
9145 			      gchar *filename,
9146 			      gchar *effect)
9147 {
9148   AgsAudio *audio;
9149   AgsRecallContainer *recall_container;
9150   AgsGenericRecallChannelRun *generic_recall_channel_run;
9151   AgsRecallLadspa *recall_ladspa;
9152 
9153   AgsLadspaManager *ladspa_manager;
9154   AgsLadspaPlugin *ladspa_plugin;
9155 
9156   GObject *output_soundcard, *input_soundcard;
9157 
9158   GList *recall_list;
9159 
9160   gint output_soundcard_channel, input_soundcard_channel;
9161 
9162   void *plugin_so;
9163   LADSPA_Descriptor_Function ladspa_descriptor;
9164   LADSPA_Descriptor *plugin_descriptor;
9165   unsigned long effect_index;
9166 
9167   GRecMutex *channel_mutex;
9168 
9169   if(!AGS_IS_CHANNEL(channel)){
9170     return(NULL);
9171   }
9172 
9173   /* get channel mutex */
9174   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
9175 
9176   /* get some fields */
9177   g_rec_mutex_lock(channel_mutex);
9178 
9179   audio = (AgsAudio *) channel->audio;
9180 
9181   output_soundcard = channel->output_soundcard;
9182   output_soundcard_channel = channel->output_soundcard_channel;
9183 
9184   input_soundcard = channel->input_soundcard;
9185   input_soundcard_channel = channel->input_soundcard_channel;
9186 
9187   g_rec_mutex_unlock(channel_mutex);
9188 
9189   /* initialize return value */
9190   recall_list = NULL;
9191 
9192   /* load plugin */
9193   ladspa_manager = ags_ladspa_manager_get_instance();
9194   ladspa_plugin = ags_ladspa_manager_find_ladspa_plugin(ladspa_manager,
9195 							filename, effect);
9196 
9197   effect_index = AGS_BASE_PLUGIN(ladspa_plugin)->effect_index;
9198 
9199   /* ladspa play */
9200   recall_container = ags_recall_container_new();
9201   ags_channel_add_recall_container(channel,
9202 				   (GObject *) recall_container);
9203 
9204   recall_ladspa = ags_recall_ladspa_new(channel,
9205 					filename,
9206 					effect,
9207 					effect_index);
9208   AGS_RECALL(recall_ladspa)->flags |= AGS_RECALL_TEMPLATE;
9209   g_object_set(G_OBJECT(recall_ladspa),
9210 	       "output-soundcard", output_soundcard,
9211 	       "output-soundcard-channel", output_soundcard_channel,
9212 	       "input-soundcard", input_soundcard,
9213 	       "input-soundcard-channel", input_soundcard_channel,
9214 	       "recall-container", recall_container,
9215 	       NULL);
9216   ags_channel_add_recall(channel,
9217 			 (GObject *) recall_ladspa,
9218 			 TRUE);
9219 
9220   recall_list = g_list_prepend(recall_list,
9221 			       recall_ladspa);
9222 
9223   /* load */
9224   ags_recall_ladspa_load(recall_ladspa);
9225   ags_recall_ladspa_load_ports(recall_ladspa);
9226 
9227   /* generic */
9228   generic_recall_channel_run = ags_generic_recall_channel_run_new(channel,
9229 								  AGS_TYPE_GENERIC_RECALL_RECYCLING,
9230 								  AGS_TYPE_RECALL_LADSPA_RUN);
9231   AGS_RECALL(generic_recall_channel_run)->flags |= AGS_RECALL_TEMPLATE;
9232   g_object_set(G_OBJECT(generic_recall_channel_run),
9233 	       "output-soundcard", output_soundcard,
9234 	       "output-soundcard-channel", output_soundcard_channel,
9235 	       "input-soundcard", input_soundcard,
9236 	       "input-soundcard-channel", input_soundcard_channel,
9237 	       "recall-container", recall_container,
9238 	       "recall-channel", recall_ladspa,
9239 	       NULL);
9240   ags_channel_add_recall(channel,
9241 			 (GObject *) generic_recall_channel_run,
9242 			 TRUE);
9243 
9244   recall_list = g_list_prepend(recall_list,
9245 			       generic_recall_channel_run);
9246 
9247   /* check if connected or running */
9248   if(ags_connectable_is_connected(AGS_CONNECTABLE(channel))){
9249     AgsRecall *current;
9250 
9251     GList *recall_id_start, *recall_id;
9252 
9253     GRecMutex *recall_id_mutex;
9254 
9255     ags_connectable_connect(AGS_CONNECTABLE(recall_container));
9256     ags_connectable_connect(AGS_CONNECTABLE(recall_ladspa));
9257     ags_connectable_connect(AGS_CONNECTABLE(generic_recall_channel_run));
9258 
9259     /* get recall id */
9260     g_rec_mutex_lock(channel_mutex);
9261 
9262     recall_id =
9263       recall_id_start = g_list_copy(channel->recall_id);
9264 
9265     g_rec_mutex_unlock(channel_mutex);
9266 
9267     while(recall_id != NULL){
9268       if(AGS_RECALL_ID(recall_id->data)->recycling_context != NULL &&
9269 	 AGS_RECALL_ID(recall_id->data)->recycling_context->parent == NULL){
9270 	if(ags_recall_id_check_staging_flags(recall_id->data,
9271 					     (AGS_SOUND_STATE_IS_WAITING |
9272 					      AGS_SOUND_STATE_IS_ACTIVE))){
9273 	  gint sound_scope;
9274 	  guint staging_flags;
9275 
9276 	  current = ags_recall_duplicate((AgsRecall *) generic_recall_channel_run,
9277 					 (AgsRecallID *) recall_id->data,
9278 					 NULL, NULL, NULL);
9279 
9280 	  /* get recall id mutex */
9281 	  recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id->data);
9282 
9283 	  /* set appropriate scope */
9284 	  g_rec_mutex_lock(recall_id_mutex);
9285 
9286 	  sound_scope = AGS_RECALL_ID(recall_id->data)->sound_scope;
9287 	  staging_flags = AGS_RECALL_ID(recall_id->data)->staging_flags;
9288 
9289 	  g_rec_mutex_unlock(recall_id_mutex);
9290 
9291 	  ags_recall_set_sound_scope(current,
9292 				     sound_scope);
9293 
9294 	  /* append to AgsChannel */
9295 	  ags_channel_add_recall(channel,
9296 				 (GObject *) current,
9297 				 TRUE);
9298 
9299 	  /* connect */
9300 	  ags_connectable_connect(AGS_CONNECTABLE(current));
9301 
9302 	  /* notify run and resolve dependencies */
9303 	  ags_recall_notify_dependency(current, AGS_RECALL_NOTIFY_RUN, 1);
9304 
9305 	  ags_recall_resolve_dependency(current);
9306 
9307 	  /* set staging flags */
9308 	  ags_recall_set_staging_flags(current,
9309 				       staging_flags);
9310 	}
9311       }
9312 
9313       /* iterate */
9314       recall_id = recall_id->next;
9315     }
9316 
9317     /* free GList */
9318     g_list_free(recall_id_start);
9319   }
9320 
9321   /* ladspa recall */
9322   recall_container = ags_recall_container_new();
9323   ags_channel_add_recall_container(channel,
9324 				   (GObject *) recall_container);
9325 
9326   recall_ladspa = ags_recall_ladspa_new(channel,
9327 					filename,
9328 					effect,
9329 					effect_index);
9330   AGS_RECALL(recall_ladspa)->flags |= AGS_RECALL_TEMPLATE;
9331   g_object_set(G_OBJECT(recall_ladspa),
9332 	       "output-soundcard", output_soundcard,
9333 	       "output-soundcard-channel", output_soundcard_channel,
9334 	       "input-soundcard", input_soundcard,
9335 	       "input-soundcard-channel", input_soundcard_channel,
9336 	       "recall-container", recall_container,
9337 	       NULL);
9338   ags_channel_add_recall(channel,
9339 			 (GObject *) recall_ladspa,
9340 			 FALSE);
9341 
9342   recall_list = g_list_prepend(recall_list,
9343 			       recall_ladspa);
9344 
9345   /* load */
9346   ags_recall_ladspa_load(recall_ladspa);
9347   ags_recall_ladspa_load_ports(recall_ladspa);
9348 
9349   /* generic recall */
9350   generic_recall_channel_run = ags_generic_recall_channel_run_new(channel,
9351 								  AGS_TYPE_GENERIC_RECALL_RECYCLING,
9352 								  AGS_TYPE_RECALL_LADSPA_RUN);
9353   AGS_RECALL(generic_recall_channel_run)->flags |= AGS_RECALL_TEMPLATE;
9354   g_object_set(G_OBJECT(generic_recall_channel_run),
9355 	       "output-soundcard", output_soundcard,
9356 	       "output-soundcard-channel", output_soundcard_channel,
9357 	       "input-soundcard", input_soundcard,
9358 	       "input-soundcard-channel", input_soundcard_channel,
9359 	       "recall-container", recall_container,
9360 	       "recall-channel", recall_ladspa,
9361 	       NULL);
9362   ags_channel_add_recall(channel,
9363 			 (GObject *) generic_recall_channel_run,
9364 			 FALSE);
9365 
9366   recall_list = g_list_prepend(recall_list,
9367 			       generic_recall_channel_run);
9368 
9369   /* check if connected or running */
9370   if(ags_connectable_is_connected(AGS_CONNECTABLE(channel))){
9371     AgsRecall *current;
9372 
9373     GList *recall_id_start, *recall_id;
9374 
9375     ags_connectable_connect(AGS_CONNECTABLE(recall_container));
9376     ags_connectable_connect(AGS_CONNECTABLE(recall_ladspa));
9377     ags_connectable_connect(AGS_CONNECTABLE(generic_recall_channel_run));
9378 
9379     /* get recall id */
9380     g_rec_mutex_lock(channel_mutex);
9381 
9382     recall_id =
9383       recall_id_start = g_list_copy(channel->recall_id);
9384 
9385     g_rec_mutex_unlock(channel_mutex);
9386 
9387     while(recall_id != NULL){
9388       if(AGS_RECALL_ID(recall_id->data)->recycling_context != NULL &&
9389 	 AGS_RECALL_ID(recall_id->data)->recycling_context->parent != NULL){
9390 	if(ags_recall_id_check_staging_flags(recall_id->data,
9391 					     (AGS_SOUND_STATE_IS_WAITING |
9392 					      AGS_SOUND_STATE_IS_ACTIVE))){
9393 
9394 	  gint sound_scope;
9395 	  guint staging_flags;
9396 
9397 	  GRecMutex *recall_id_mutex;
9398 
9399 	  current = ags_recall_duplicate((AgsRecall *) generic_recall_channel_run,
9400 					 (AgsRecallID *) recall_id->data,
9401 					 NULL, NULL, NULL);
9402 
9403 
9404 	  /* get recall id mutex */
9405 	  recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id->data);
9406 
9407 	  /* set appropriate scope */
9408 	  g_rec_mutex_lock(recall_id_mutex);
9409 
9410 	  sound_scope = AGS_RECALL_ID(recall_id->data)->sound_scope;
9411 	  staging_flags = AGS_RECALL_ID(recall_id->data)->staging_flags;
9412 
9413 	  g_rec_mutex_unlock(recall_id_mutex);
9414 
9415 	  ags_recall_set_sound_scope(current,
9416 				     sound_scope);
9417 
9418 	  /* append to AgsChannel */
9419 	  ags_channel_add_recall(channel,
9420 				 (GObject *) current,
9421 				 FALSE);
9422 
9423 	  /* connect */
9424 	  ags_connectable_connect(AGS_CONNECTABLE(current));
9425 
9426 	  /* notify run and resolve dependencies */
9427 	  ags_recall_notify_dependency(current, AGS_RECALL_NOTIFY_RUN, 1);
9428 
9429 	  ags_recall_resolve_dependency(current);
9430 
9431 	  /* set staging flags */
9432 	  ags_recall_set_staging_flags(current,
9433 				       staging_flags);
9434 	}
9435       }
9436 
9437       /* iterate */
9438       recall_id = recall_id->next;
9439     }
9440 
9441     /* free GList */
9442     g_list_free(recall_id_start);
9443   }
9444 
9445   return(recall_list);
9446 }
9447 
9448 GList*
ags_channel_add_dssi_effect(AgsChannel * channel,gchar * filename,gchar * effect)9449 ags_channel_add_dssi_effect(AgsChannel *channel,
9450 			    gchar *filename,
9451 			    gchar *effect)
9452 {
9453   AgsAudio *audio;
9454   AgsRecallContainer *recall_container;
9455   AgsGenericRecallChannelRun *generic_recall_channel_run;
9456   AgsRecallDssi *recall_dssi;
9457 
9458   AgsDssiManager *dssi_manager;
9459   AgsDssiPlugin *dssi_plugin;
9460 
9461   GObject *output_soundcard, *input_soundcard;
9462 
9463   GList *recall_list;
9464 
9465   gint output_soundcard_channel, input_soundcard_channel;
9466 
9467   void *plugin_so;
9468   DSSI_Descriptor_Function dssi_descriptor;
9469   DSSI_Descriptor *plugin_descriptor;
9470   unsigned long effect_index;
9471 
9472   GRecMutex *channel_mutex;
9473 
9474   if(!AGS_IS_CHANNEL(channel)){
9475     return(NULL);
9476   }
9477 
9478   /* get channel mutex */
9479   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
9480 
9481   /* get some fields */
9482   g_rec_mutex_lock(channel_mutex);
9483 
9484   audio = (AgsAudio *) channel->audio;
9485 
9486   output_soundcard = channel->output_soundcard;
9487   output_soundcard_channel = channel->output_soundcard_channel;
9488 
9489   input_soundcard = channel->input_soundcard;
9490   input_soundcard_channel = channel->input_soundcard_channel;
9491 
9492   g_rec_mutex_unlock(channel_mutex);
9493 
9494   recall_list = NULL;
9495 
9496   /* load plugin */
9497   dssi_manager = ags_dssi_manager_get_instance();
9498   dssi_plugin = ags_dssi_manager_find_dssi_plugin(dssi_manager,
9499 						  filename, effect);
9500 
9501   effect_index = AGS_BASE_PLUGIN(dssi_plugin)->effect_index;
9502 
9503   /* dssi play */
9504   recall_container = ags_recall_container_new();
9505   ags_channel_add_recall_container(channel,
9506 				   (GObject *) recall_container);
9507 
9508   recall_dssi = ags_recall_dssi_new(channel,
9509 				    filename,
9510 				    effect,
9511 				    effect_index);
9512   AGS_RECALL(recall_dssi)->flags |= AGS_RECALL_TEMPLATE;
9513   g_object_set(G_OBJECT(recall_dssi),
9514 	       "output-soundcard", output_soundcard,
9515 	       "output-soundcard-channel", output_soundcard_channel,
9516 	       "input-soundcard", input_soundcard,
9517 	       "input-soundcard-channel", input_soundcard_channel,
9518 	       "recall-container", recall_container,
9519 	       NULL);
9520   ags_channel_add_recall(channel,
9521 			 (GObject *) recall_dssi,
9522 			 TRUE);
9523 
9524   recall_list = g_list_prepend(recall_list,
9525 			       recall_dssi);
9526 
9527   /* load */
9528   ags_recall_dssi_load(recall_dssi);
9529   ags_recall_dssi_load_ports(recall_dssi);
9530 
9531   /* generic */
9532   generic_recall_channel_run = ags_generic_recall_channel_run_new(channel,
9533 								  AGS_TYPE_GENERIC_RECALL_RECYCLING,
9534 								  AGS_TYPE_RECALL_DSSI_RUN);
9535   AGS_RECALL(generic_recall_channel_run)->flags |= AGS_RECALL_TEMPLATE;
9536   g_object_set(G_OBJECT(generic_recall_channel_run),
9537 	       "output-soundcard", output_soundcard,
9538 	       "output-soundcard-channel", output_soundcard_channel,
9539 	       "input-soundcard", input_soundcard,
9540 	       "input-soundcard-channel", input_soundcard_channel,
9541 	       "recall-container", recall_container,
9542 	       "recall-channel", recall_dssi,
9543 	       NULL);
9544   ags_channel_add_recall(channel,
9545 			 (GObject *) generic_recall_channel_run,
9546 			 TRUE);
9547 
9548   recall_list = g_list_prepend(recall_list,
9549 			       generic_recall_channel_run);
9550 
9551   /* check if connected or running */
9552   if(ags_connectable_is_connected(AGS_CONNECTABLE(channel))){
9553     AgsRecall *current;
9554 
9555     GList *recall_id_start, *recall_id;
9556 
9557     GRecMutex *recall_id_mutex;
9558 
9559     ags_connectable_connect(AGS_CONNECTABLE(recall_container));
9560     ags_connectable_connect(AGS_CONNECTABLE(recall_dssi));
9561     ags_connectable_connect(AGS_CONNECTABLE(generic_recall_channel_run));
9562 
9563     /* get recall id */
9564     g_rec_mutex_lock(channel_mutex);
9565 
9566     recall_id =
9567       recall_id_start = g_list_copy(channel->recall_id);
9568 
9569     g_rec_mutex_unlock(channel_mutex);
9570 
9571     while(recall_id != NULL){
9572       if(AGS_RECALL_ID(recall_id->data)->recycling_context != NULL &&
9573 	 AGS_RECALL_ID(recall_id->data)->recycling_context->parent == NULL){
9574 	if(ags_recall_id_check_staging_flags(recall_id->data,
9575 					     (AGS_SOUND_STATE_IS_WAITING |
9576 					      AGS_SOUND_STATE_IS_ACTIVE))){
9577 	  gint sound_scope;
9578 	  guint staging_flags;
9579 
9580 	  current = ags_recall_duplicate((AgsRecall *) generic_recall_channel_run,
9581 					 (AgsRecallID *) recall_id->data,
9582 					 NULL, NULL, NULL);
9583 
9584 	  /* get recall id mutex */
9585 	  recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id->data);
9586 
9587 	  /* set appropriate scope */
9588 	  g_rec_mutex_lock(recall_id_mutex);
9589 
9590 	  sound_scope = AGS_RECALL_ID(recall_id->data)->sound_scope;
9591 	  staging_flags = AGS_RECALL_ID(recall_id->data)->staging_flags;
9592 
9593 	  g_rec_mutex_unlock(recall_id_mutex);
9594 
9595 	  ags_recall_set_sound_scope(current,
9596 				     sound_scope);
9597 
9598 	  /* append to AgsChannel */
9599 	  ags_channel_add_recall(channel,
9600 				 (GObject *) current,
9601 				 TRUE);
9602 
9603 	  /* connect */
9604 	  ags_connectable_connect(AGS_CONNECTABLE(current));
9605 
9606 	  /* notify run and resolve dependencies */
9607 	  ags_recall_notify_dependency(current, AGS_RECALL_NOTIFY_RUN, 1);
9608 
9609 	  ags_recall_resolve_dependency(current);
9610 
9611 	  /* set staging flags */
9612 	  ags_recall_set_staging_flags(current,
9613 				       staging_flags);
9614 	}
9615       }
9616 
9617       /* iterate */
9618       recall_id = recall_id->next;
9619     }
9620 
9621     /* free GList */
9622     g_list_free(recall_id_start);
9623   }
9624 
9625   /* dssi recall */
9626   recall_container = ags_recall_container_new();
9627   ags_channel_add_recall_container(channel,
9628 				   (GObject *) recall_container);
9629 
9630   recall_dssi = ags_recall_dssi_new(channel,
9631 				    filename,
9632 				    effect,
9633 				    effect_index);
9634   AGS_RECALL(recall_dssi)->flags |= AGS_RECALL_TEMPLATE;
9635   g_object_set(G_OBJECT(recall_dssi),
9636 	       "output-soundcard", output_soundcard,
9637 	       "output-soundcard-channel", output_soundcard_channel,
9638 	       "input-soundcard", input_soundcard,
9639 	       "input-soundcard-channel", input_soundcard_channel,
9640 	       "recall-container", recall_container,
9641 	       NULL);
9642   ags_channel_add_recall(channel,
9643 			 (GObject *) recall_dssi,
9644 			 FALSE);
9645 
9646   recall_list = g_list_prepend(recall_list,
9647 			       recall_dssi);
9648 
9649   /* load */
9650   ags_recall_dssi_load(recall_dssi);
9651   ags_recall_dssi_load_ports(recall_dssi);
9652 
9653   /* generic */
9654   generic_recall_channel_run = ags_generic_recall_channel_run_new(channel,
9655 								  AGS_TYPE_GENERIC_RECALL_RECYCLING,
9656 								  AGS_TYPE_RECALL_DSSI_RUN);
9657   AGS_RECALL(generic_recall_channel_run)->flags |= AGS_RECALL_TEMPLATE;
9658   g_object_set(G_OBJECT(generic_recall_channel_run),
9659 	       "output-soundcard", output_soundcard,
9660 	       "output-soundcard-channel", output_soundcard_channel,
9661 	       "input-soundcard", input_soundcard,
9662 	       "input-soundcard-channel", input_soundcard_channel,
9663 	       "recall-container", recall_container,
9664 	       "recall-channel", recall_dssi,
9665 	       NULL);
9666   ags_channel_add_recall(channel,
9667 			 (GObject *) generic_recall_channel_run,
9668 			 FALSE);
9669 
9670   recall_list = g_list_prepend(recall_list,
9671 			       generic_recall_channel_run);
9672 
9673   /* check if connected or running */
9674   if(ags_connectable_is_connected(AGS_CONNECTABLE(channel))){
9675     AgsRecall *current;
9676 
9677     GList *recall_id_start, *recall_id;
9678 
9679     ags_connectable_connect(AGS_CONNECTABLE(recall_container));
9680     ags_connectable_connect(AGS_CONNECTABLE(recall_dssi));
9681     ags_connectable_connect(AGS_CONNECTABLE(generic_recall_channel_run));
9682 
9683     /* get recall id */
9684     g_rec_mutex_lock(channel_mutex);
9685 
9686     recall_id =
9687       recall_id_start = g_list_copy(channel->recall_id);
9688 
9689     g_rec_mutex_unlock(channel_mutex);
9690 
9691     while(recall_id != NULL){
9692       if(AGS_RECALL_ID(recall_id->data)->recycling_context != NULL &&
9693 	 AGS_RECALL_ID(recall_id->data)->recycling_context->parent != NULL){
9694 	if(ags_recall_id_check_staging_flags(recall_id->data,
9695 					     (AGS_SOUND_STATE_IS_WAITING |
9696 					      AGS_SOUND_STATE_IS_ACTIVE))){
9697 
9698 	  gint sound_scope;
9699 	  guint staging_flags;
9700 
9701 	  GRecMutex *recall_id_mutex;
9702 
9703 	  current = ags_recall_duplicate((AgsRecall *) generic_recall_channel_run,
9704 					 (AgsRecallID *) recall_id->data,
9705 					 NULL, NULL, NULL);
9706 
9707 
9708 	  /* get recall id mutex */
9709 	  recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id->data);
9710 
9711 	  /* set appropriate scope */
9712 	  g_rec_mutex_lock(recall_id_mutex);
9713 
9714 	  sound_scope = AGS_RECALL_ID(recall_id->data)->sound_scope;
9715 	  staging_flags = AGS_RECALL_ID(recall_id->data)->staging_flags;
9716 
9717 	  g_rec_mutex_unlock(recall_id_mutex);
9718 
9719 	  ags_recall_set_sound_scope(current,
9720 				     sound_scope);
9721 
9722 	  /* append to AgsChannel */
9723 	  ags_channel_add_recall(channel,
9724 				 (GObject *) current,
9725 				 FALSE);
9726 
9727 	  /* connect */
9728 	  ags_connectable_connect(AGS_CONNECTABLE(current));
9729 
9730 	  /* notify run and resolve dependencies */
9731 	  ags_recall_notify_dependency(current, AGS_RECALL_NOTIFY_RUN, 1);
9732 
9733 	  ags_recall_resolve_dependency(current);
9734 
9735 	  /* set staging flags */
9736 	  ags_recall_set_staging_flags(current,
9737 				       staging_flags);
9738 	}
9739       }
9740 
9741       /* iterate */
9742       recall_id = recall_id->next;
9743     }
9744 
9745     /* free GList */
9746     g_list_free(recall_id_start);
9747   }
9748 
9749   return(recall_list);
9750 }
9751 
9752 GList*
ags_channel_add_lv2_effect(AgsChannel * channel,gchar * filename,gchar * effect)9753 ags_channel_add_lv2_effect(AgsChannel *channel,
9754 			   gchar *filename,
9755 			   gchar *effect)
9756 {
9757   AgsAudio *audio;
9758   AgsRecallContainer *recall_container;
9759   AgsGenericRecallChannelRun *generic_recall_channel_run;
9760   AgsRecallLv2 *recall_lv2;
9761 
9762   AgsLv2Manager *lv2_manager;
9763   AgsLv2Plugin *lv2_plugin;
9764 
9765   GObject *output_soundcard, *input_soundcard;
9766 
9767   GList *uri_node;
9768   GList *recall_list;
9769 
9770   gchar *uri;
9771   gchar *str;
9772 
9773   gint output_soundcard_channel, input_soundcard_channel;
9774 
9775   void *plugin_so;
9776   LV2_Descriptor_Function lv2_descriptor;
9777   LV2_Descriptor *plugin_descriptor;
9778   uint32_t effect_index;
9779 
9780   GRecMutex *channel_mutex;
9781 
9782   if(!AGS_IS_CHANNEL(channel)){
9783     return(NULL);
9784   }
9785 
9786   /* get channel mutex */
9787   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
9788 
9789   /* get some fields */
9790   g_rec_mutex_lock(channel_mutex);
9791 
9792   audio = (AgsAudio *) channel->audio;
9793 
9794   output_soundcard = channel->output_soundcard;
9795   output_soundcard_channel = channel->output_soundcard_channel;
9796 
9797   input_soundcard = channel->input_soundcard;
9798   input_soundcard_channel = channel->input_soundcard_channel;
9799 
9800   g_rec_mutex_unlock(channel_mutex);
9801 
9802   recall_list = NULL;
9803 
9804   /* load plugin */
9805   lv2_manager = ags_lv2_manager_get_instance();
9806   lv2_plugin = ags_lv2_manager_find_lv2_plugin(lv2_manager,
9807 					       filename, effect);
9808 
9809   effect_index = AGS_BASE_PLUGIN(lv2_plugin)->effect_index;
9810   uri = lv2_plugin->uri;
9811 
9812   /* lv2 play */
9813   recall_container = ags_recall_container_new();
9814   ags_channel_add_recall_container(channel,
9815 				   (GObject *) recall_container);
9816 
9817   recall_lv2 = ags_recall_lv2_new(channel,
9818 				  lv2_plugin->turtle,
9819 				  filename,
9820 				  effect,
9821 				  uri,
9822 				  effect_index);
9823   AGS_RECALL(recall_lv2)->flags |= AGS_RECALL_TEMPLATE;
9824   g_object_set(G_OBJECT(recall_lv2),
9825 	       "output-soundcard", output_soundcard,
9826 	       "output-soundcard-channel", output_soundcard_channel,
9827 	       "input-soundcard", input_soundcard,
9828 	       "input-soundcard-channel", input_soundcard_channel,
9829 	       "recall-container", recall_container,
9830 	       NULL);
9831   ags_channel_add_recall(channel,
9832 			 (GObject *) recall_lv2,
9833 			 TRUE);
9834 
9835   recall_list = g_list_prepend(recall_list,
9836 			       recall_lv2);
9837 
9838   /* load */
9839   ags_recall_lv2_load(recall_lv2);
9840   ags_recall_lv2_load_ports(recall_lv2);
9841 
9842   /* generic */
9843   generic_recall_channel_run = ags_generic_recall_channel_run_new(channel,
9844 								  AGS_TYPE_GENERIC_RECALL_RECYCLING,
9845 								  AGS_TYPE_RECALL_LV2_RUN);
9846   AGS_RECALL(generic_recall_channel_run)->flags |= AGS_RECALL_TEMPLATE;
9847   g_object_set(G_OBJECT(generic_recall_channel_run),
9848 	       "output-soundcard", output_soundcard,
9849 	       "output-soundcard-channel", output_soundcard_channel,
9850 	       "input-soundcard", input_soundcard,
9851 	       "input-soundcard-channel", input_soundcard_channel,
9852 	       "recall-container", recall_container,
9853 	       "recall-channel", recall_lv2,
9854 	       NULL);
9855   ags_channel_add_recall(channel,
9856 			 (GObject *) generic_recall_channel_run,
9857 			 TRUE);
9858 
9859   recall_list = g_list_prepend(recall_list,
9860 			       generic_recall_channel_run);
9861 
9862   /* check if connected or running */
9863   if(ags_connectable_is_connected(AGS_CONNECTABLE(channel))){
9864     AgsRecall *current;
9865 
9866     GList *recall_id_start, *recall_id;
9867 
9868     GRecMutex *recall_id_mutex;
9869 
9870     ags_connectable_connect(AGS_CONNECTABLE(recall_container));
9871     ags_connectable_connect(AGS_CONNECTABLE(recall_lv2));
9872     ags_connectable_connect(AGS_CONNECTABLE(generic_recall_channel_run));
9873 
9874     /* get recall id */
9875     g_rec_mutex_lock(channel_mutex);
9876 
9877     recall_id =
9878       recall_id_start = g_list_copy(channel->recall_id);
9879 
9880     g_rec_mutex_unlock(channel_mutex);
9881 
9882     while(recall_id != NULL){
9883       if(AGS_RECALL_ID(recall_id->data)->recycling_context != NULL &&
9884 	 AGS_RECALL_ID(recall_id->data)->recycling_context->parent == NULL){
9885 	if(ags_recall_id_check_staging_flags(recall_id->data,
9886 					     (AGS_SOUND_STATE_IS_WAITING |
9887 					      AGS_SOUND_STATE_IS_ACTIVE))){
9888 	  gint sound_scope;
9889 	  guint staging_flags;
9890 
9891 	  current = ags_recall_duplicate((AgsRecall *) generic_recall_channel_run,
9892 					 (AgsRecallID *) recall_id->data,
9893 					 NULL, NULL, NULL);
9894 
9895 	  /* get recall id mutex */
9896 	  recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id->data);
9897 
9898 	  /* set appropriate scope */
9899 	  g_rec_mutex_lock(recall_id_mutex);
9900 
9901 	  sound_scope = AGS_RECALL_ID(recall_id->data)->sound_scope;
9902 	  staging_flags = AGS_RECALL_ID(recall_id->data)->staging_flags;
9903 
9904 	  g_rec_mutex_unlock(recall_id_mutex);
9905 
9906 	  ags_recall_set_sound_scope(current,
9907 				     sound_scope);
9908 
9909 	  /* append to AgsChannel */
9910 	  ags_channel_add_recall(channel,
9911 				 (GObject *) current,
9912 				 TRUE);
9913 
9914 	  /* connect */
9915 	  ags_connectable_connect(AGS_CONNECTABLE(current));
9916 
9917 	  /* notify run and resolve dependencies */
9918 	  ags_recall_notify_dependency(current, AGS_RECALL_NOTIFY_RUN, 1);
9919 
9920 	  ags_recall_resolve_dependency(current);
9921 
9922 	  /* set staging flags */
9923 	  ags_recall_set_staging_flags(current,
9924 				       staging_flags);
9925 	}
9926       }
9927 
9928       /* iterate */
9929       recall_id = recall_id->next;
9930     }
9931 
9932     /* free GList */
9933     g_list_free(recall_id_start);
9934   }
9935 
9936   /* lv2 recall */
9937   recall_container = ags_recall_container_new();
9938   ags_channel_add_recall_container(channel,
9939 				   (GObject *) recall_container);
9940 
9941   recall_lv2 = ags_recall_lv2_new(channel,
9942 				  lv2_plugin->turtle,
9943 				  filename,
9944 				  effect,
9945 				  uri,
9946 				  effect_index);
9947   AGS_RECALL(recall_lv2)->flags |= AGS_RECALL_TEMPLATE;
9948   g_object_set(G_OBJECT(recall_lv2),
9949 	       "output-soundcard", output_soundcard,
9950 	       "output-soundcard-channel", output_soundcard_channel,
9951 	       "input-soundcard", input_soundcard,
9952 	       "input-soundcard-channel", input_soundcard_channel,
9953 	       "recall-container", recall_container,
9954 	       NULL);
9955   ags_channel_add_recall(channel,
9956 			 (GObject *) recall_lv2,
9957 			 FALSE);
9958 
9959   recall_list = g_list_prepend(recall_list,
9960 			       recall_lv2);
9961 
9962   /* load */
9963   ags_recall_lv2_load(recall_lv2);
9964   ags_recall_lv2_load_ports(recall_lv2);
9965 
9966   /* generic */
9967   generic_recall_channel_run = ags_generic_recall_channel_run_new(channel,
9968 								  AGS_TYPE_GENERIC_RECALL_RECYCLING,
9969 								  AGS_TYPE_RECALL_LV2_RUN);
9970   AGS_RECALL(generic_recall_channel_run)->flags |= AGS_RECALL_TEMPLATE;
9971   g_object_set(G_OBJECT(generic_recall_channel_run),
9972 	       "output-soundcard", output_soundcard,
9973 	       "output-soundcard-channel", output_soundcard_channel,
9974 	       "input-soundcard", input_soundcard,
9975 	       "input-soundcard-channel", input_soundcard_channel,
9976 	       "recall-container", recall_container,
9977 	       "recall-channel", recall_lv2,
9978 	       NULL);
9979   ags_channel_add_recall(channel,
9980 			 (GObject *) generic_recall_channel_run,
9981 			 FALSE);
9982 
9983   recall_list = g_list_prepend(recall_list,
9984 			       generic_recall_channel_run);
9985 
9986   /* check if connected or running */
9987   if(ags_connectable_is_connected(AGS_CONNECTABLE(channel))){
9988     AgsRecall *current;
9989 
9990     GList *recall_id_start, *recall_id;
9991 
9992     GRecMutex *recall_id_mutex;
9993 
9994     ags_connectable_connect(AGS_CONNECTABLE(recall_container));
9995     ags_connectable_connect(AGS_CONNECTABLE(recall_lv2));
9996     ags_connectable_connect(AGS_CONNECTABLE(generic_recall_channel_run));
9997 
9998     /* get recall id */
9999     g_rec_mutex_lock(channel_mutex);
10000 
10001     recall_id =
10002       recall_id_start = g_list_copy(channel->recall_id);
10003 
10004     g_rec_mutex_unlock(channel_mutex);
10005 
10006     while(recall_id != NULL){
10007       if(AGS_RECALL_ID(recall_id->data)->recycling_context != NULL &&
10008 	 AGS_RECALL_ID(recall_id->data)->recycling_context->parent == NULL){
10009 	if(ags_recall_id_check_staging_flags(recall_id->data,
10010 					     (AGS_SOUND_STATE_IS_WAITING |
10011 					      AGS_SOUND_STATE_IS_ACTIVE))){
10012 	  gint sound_scope;
10013 	  guint staging_flags;
10014 
10015 	  current = ags_recall_duplicate((AgsRecall *) generic_recall_channel_run,
10016 					 (AgsRecallID *) recall_id->data,
10017 					 NULL, NULL, NULL);
10018 
10019 	  /* get recall id mutex */
10020 	  recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id->data);
10021 
10022 	  /* set appropriate scope */
10023 	  g_rec_mutex_lock(recall_id_mutex);
10024 
10025 	  sound_scope = AGS_RECALL_ID(recall_id->data)->sound_scope;
10026 	  staging_flags = AGS_RECALL_ID(recall_id->data)->staging_flags;
10027 
10028 	  g_rec_mutex_unlock(recall_id_mutex);
10029 
10030 	  ags_recall_set_sound_scope(current,
10031 				     sound_scope);
10032 
10033 	  /* append to AgsChannel */
10034 	  ags_channel_add_recall(channel,
10035 				 (GObject *) current,
10036 				 FALSE);
10037 
10038 	  /* connect */
10039 	  ags_connectable_connect(AGS_CONNECTABLE(current));
10040 
10041 	  /* notify run and resolve dependencies */
10042 	  ags_recall_notify_dependency(current, AGS_RECALL_NOTIFY_RUN, 1);
10043 
10044 	  ags_recall_resolve_dependency(current);
10045 
10046 	  /* set staging flags */
10047 	  ags_recall_set_staging_flags(current,
10048 				       staging_flags);
10049 	}
10050       }
10051 
10052       /* iterate */
10053       recall_id = recall_id->next;
10054     }
10055 
10056     /* free GList */
10057     g_list_free(recall_id_start);
10058   }
10059 
10060   return(recall_list);
10061 }
10062 
10063 GList*
ags_channel_real_add_effect(AgsChannel * channel,gchar * filename,gchar * effect)10064 ags_channel_real_add_effect(AgsChannel *channel,
10065 			    gchar *filename,
10066 			    gchar *effect)
10067 {
10068   AgsLadspaPlugin *ladspa_plugin;
10069   AgsDssiPlugin *dssi_plugin;
10070   AgsLv2Plugin *lv2_plugin;
10071 
10072   AgsMessageDelivery *message_delivery;
10073 
10074   GList *start_message_queue;
10075   GList *recall_list;
10076 
10077   /* load plugin */
10078   ladspa_plugin = ags_ladspa_manager_find_ladspa_plugin(ags_ladspa_manager_get_instance(),
10079 							filename, effect);
10080   recall_list = NULL;
10081 
10082   if(ladspa_plugin != NULL){
10083     recall_list = ags_channel_add_ladspa_effect(channel,
10084 						filename,
10085 						effect);
10086   }
10087 
10088   if(ladspa_plugin == NULL){
10089     dssi_plugin = ags_dssi_manager_find_dssi_plugin(ags_dssi_manager_get_instance(),
10090 						    filename, effect);
10091 
10092     if(dssi_plugin != NULL){
10093       recall_list = ags_channel_add_dssi_effect(channel,
10094 						filename,
10095 						effect);
10096     }
10097   }
10098 
10099   if(ladspa_plugin == NULL &&
10100      dssi_plugin == NULL){
10101     lv2_plugin = ags_lv2_manager_find_lv2_plugin(ags_lv2_manager_get_instance(),
10102 						 filename, effect);
10103 
10104     if(lv2_plugin != NULL){
10105       recall_list = ags_channel_add_lv2_effect(channel,
10106 					       filename,
10107 					       effect);
10108     }
10109   }
10110 
10111   /* emit message */
10112   message_delivery = ags_message_delivery_get_instance();
10113 
10114   start_message_queue = ags_message_delivery_find_sender_namespace(message_delivery,
10115 								   "libags-audio");
10116 
10117   if(start_message_queue != NULL){
10118     AgsMessageEnvelope *message;
10119 
10120     xmlDoc *doc;
10121     xmlNode *root_node;
10122 
10123     /* specify message body */
10124     doc = xmlNewDoc("1.0");
10125 
10126     root_node = xmlNewNode(NULL,
10127 			   "ags-command");
10128     xmlDocSetRootElement(doc, root_node);
10129 
10130     xmlNewProp(root_node,
10131 	       "method",
10132 	       "AgsChannel::add-effect");
10133 
10134     /* add message */
10135     message = ags_message_envelope_new((GObject *) channel,
10136 				       NULL,
10137 				       doc);
10138 
10139     /* set parameter */
10140     message->n_params = 2;
10141 
10142     message->parameter_name = (gchar **) malloc(3 * sizeof(gchar *));
10143     message->value = g_new0(GValue,
10144 			    2);
10145 
10146     /* filename */
10147     message->parameter_name[0] = "filename";
10148     g_value_init(&(message->value[0]),
10149 		 G_TYPE_STRING);
10150     g_value_set_string(&(message->value[0]),
10151 		       filename);
10152 
10153     /* effect */
10154     message->parameter_name[1] = "effect";
10155     g_value_init(&(message->value[1]),
10156 		 G_TYPE_STRING);
10157     g_value_set_string(&(message->value[1]),
10158 		       effect);
10159 
10160     /* terminate string vector */
10161     message->parameter_name[2] = NULL;
10162 
10163     /* add message */
10164     ags_message_delivery_add_message_envelope(message_delivery,
10165 					      "libags-audio",
10166 					      message);
10167 
10168     g_list_free_full(start_message_queue,
10169 		     (GDestroyNotify) g_object_unref);
10170   }
10171 
10172   return(recall_list);
10173 }
10174 
10175 /**
10176  * ags_channel_add_effect:
10177  * @channel: the #AgsChannel
10178  * @filename: the filename
10179  * @effect: the effect
10180  *
10181  * Add specified effect to @channel.
10182  *
10183  * Returns: (element-type AgsAudio.Recall) (transfer full): the #GList-struct containing #AgsRecall
10184  *
10185  * Since: 3.0.0
10186  */
10187 GList*
ags_channel_add_effect(AgsChannel * channel,gchar * filename,gchar * effect)10188 ags_channel_add_effect(AgsChannel *channel,
10189 		       gchar *filename,
10190 		       gchar *effect)
10191 {
10192   GList *recall_list;
10193 
10194   g_return_val_if_fail(AGS_IS_CHANNEL(channel), NULL);
10195 
10196   recall_list = NULL;
10197 
10198   g_object_ref((GObject *) channel);
10199   g_signal_emit(G_OBJECT(channel),
10200 		channel_signals[ADD_EFFECT], 0,
10201 		filename,
10202 		effect,
10203 		&recall_list);
10204   g_object_unref((GObject *) channel);
10205 
10206   return(recall_list);
10207 }
10208 
10209 void
ags_channel_real_remove_effect(AgsChannel * channel,guint nth)10210 ags_channel_real_remove_effect(AgsChannel *channel,
10211 			       guint nth)
10212 {
10213   AgsAudio *audio;
10214   AgsRecall *recall_channel, *recall_channel_run;
10215   AgsRecallContainer *recall_container;
10216 
10217   AgsMessageDelivery *message_delivery;
10218 
10219   GList *start_message_queue;
10220   GList *automation_start, *automation;
10221   GList *port;
10222   GList *list_start, *list;
10223 
10224   GList *play_start, *play;
10225   GList *recall_start, *recall;
10226   GList *task;
10227 
10228   gchar *specifier;
10229 
10230   guint nth_effect;
10231 
10232   GRecMutex *audio_mutex;
10233   GRecMutex *channel_mutex;
10234   GRecMutex *play_mutex, *recall_mutex;
10235 
10236   /* get channel mutex */
10237   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
10238 
10239   play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
10240   recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
10241 
10242   /* get some fields */
10243   g_rec_mutex_lock(channel_mutex);
10244 
10245   audio = (AgsAudio *) channel->audio;
10246 
10247   g_rec_mutex_unlock(channel_mutex);
10248 
10249   /* get audio mutex */
10250   audio_mutex = AGS_AUDIO_GET_OBJ_MUTEX(audio);
10251 
10252   /* play */
10253   nth_effect = 0;
10254 
10255   g_rec_mutex_lock(play_mutex);
10256 
10257   play =
10258     play_start = g_list_copy(channel->play);
10259 
10260   while((play = ags_recall_template_find_all_type(play,
10261 						  AGS_TYPE_RECALL_LADSPA,
10262 						  AGS_TYPE_RECALL_LV2,
10263 						  G_TYPE_NONE)) != NULL){
10264     if((AGS_RECALL_TEMPLATE & (AGS_RECALL(play->data)->flags)) != 0){
10265       nth_effect++;
10266     }
10267 
10268     if(nth_effect == nth + 1){
10269       break;
10270     }
10271 
10272     play = play->next;
10273   }
10274 
10275   g_rec_mutex_unlock(play_mutex);
10276 
10277   /* recall */
10278   nth_effect = 0;
10279 
10280   g_rec_mutex_lock(recall_mutex);
10281 
10282   recall =
10283     recall_start = g_list_copy(channel->recall);
10284 
10285   while((recall = ags_recall_template_find_all_type(recall,
10286 						    AGS_TYPE_RECALL_LADSPA,
10287 						    AGS_TYPE_RECALL_LV2,
10288 						    G_TYPE_NONE)) != NULL){
10289     if((AGS_RECALL_TEMPLATE & (AGS_RECALL(recall->data)->flags)) != 0){
10290       nth_effect++;
10291     }
10292 
10293     if(nth_effect == nth + 1){
10294       break;
10295     }
10296 
10297     recall = recall->next;
10298   }
10299 
10300   g_rec_mutex_unlock(recall_mutex);
10301 
10302   /* play context */
10303   /* automation */
10304   port = NULL;
10305 
10306   if(play != NULL){
10307     g_rec_mutex_lock(play_mutex);
10308 
10309     port = AGS_RECALL(play->data)->port;
10310 
10311     g_rec_mutex_unlock(play_mutex);
10312   }
10313 
10314   while(port != NULL){
10315     specifier = AGS_PORT(port->data)->specifier;
10316 
10317     /* get automation */
10318     g_rec_mutex_lock(audio_mutex);
10319 
10320     automation =
10321       automation_start = g_list_copy(audio->automation);
10322 
10323     g_rec_mutex_unlock(audio_mutex);
10324 
10325     while((automation = ags_automation_find_specifier(automation,
10326 						      specifier)) != NULL){
10327       /* remove automation  */
10328       ags_audio_remove_automation(audio,
10329 				  automation->data);
10330 
10331       /* run dispose and unref */
10332       g_object_run_dispose(automation->data);
10333       g_object_unref(automation->data);
10334 
10335       /* iterate */
10336       automation = automation->next;
10337     }
10338 
10339     g_list_free(automation_start);
10340 
10341     /* iterate */
10342     port = port->next;
10343   }
10344 
10345   /* remove - recall channel run */
10346   recall_container = (AgsRecallContainer *) AGS_RECALL(play->data)->recall_container;
10347   recall_channel = (AgsRecall *) play->data;
10348   recall_channel_run = (AgsRecall *) ags_recall_find_template(recall_container->recall_channel_run)->data;
10349 
10350   list =
10351     list_start = g_list_copy(recall_container->recall_channel_run);
10352 
10353   while(list != NULL){
10354     ags_channel_remove_recall(channel,
10355 			      (GObject *) list->data,
10356 			      TRUE);
10357 
10358     /* iterate */
10359     list = list->next;
10360   }
10361 
10362   g_list_free(list_start);
10363 
10364   /* remove - recall channel */
10365   ags_channel_remove_recall(channel,
10366 			    (GObject *) recall_channel,
10367 			    TRUE);
10368 
10369   /* remove recal container */
10370   ags_channel_remove_recall_container(channel,
10371 				      (GObject *) recall_container);
10372 
10373   /* recall context */
10374   /* automation */
10375   port = NULL;
10376 
10377   if(recall != NULL){
10378     g_rec_mutex_lock(recall_mutex);
10379 
10380     port = AGS_RECALL(recall->data)->port;
10381 
10382     g_rec_mutex_unlock(recall_mutex);
10383   }
10384 
10385   while(port != NULL){
10386     specifier = AGS_PORT(port->data)->specifier;
10387 
10388     /* get automation */
10389     g_rec_mutex_lock(audio_mutex);
10390 
10391     automation =
10392       automation_start = g_list_copy(audio->automation);
10393 
10394     g_rec_mutex_unlock(audio_mutex);
10395 
10396     while((automation = ags_automation_find_specifier(automation,
10397 						      specifier)) != NULL){
10398       /* remove automation  */
10399       ags_audio_remove_automation(audio,
10400 				  automation->data);
10401 
10402       /* run dispose and unref */
10403       g_object_run_dispose(automation->data);
10404       g_object_unref(automation->data);
10405 
10406       /* iterate */
10407       automation = automation->next;
10408     }
10409 
10410     g_list_free(automation_start);
10411 
10412     /* iterate */
10413     port = port->next;
10414   }
10415 
10416   /* remove - recall channel */
10417   recall_container = (AgsRecallContainer *) AGS_RECALL(recall->data)->recall_container;
10418   recall_channel = (AgsRecall *) recall->data;
10419   recall_channel_run = (AgsRecall *) ags_recall_find_template(recall_container->recall_channel_run)->data;
10420 
10421   list =
10422     list_start = g_list_copy(recall_container->recall_channel_run);
10423 
10424   while(list != NULL){
10425     ags_channel_remove_recall(channel,
10426 			      (GObject *) list->data,
10427 			      FALSE);
10428 
10429     /* iterate */
10430     list = list->next;
10431   }
10432 
10433   g_list_free(list_start);
10434 
10435   /* remove - recall channel */
10436   ags_channel_remove_recall(channel,
10437 			    (GObject *) recall_channel,
10438 			    FALSE);
10439 
10440   /* remove recal container */
10441   ags_channel_remove_recall_container(channel,
10442 				      (GObject *) recall_container);
10443 
10444 
10445   /* free lists */
10446   g_list_free(play_start);
10447   g_list_free(recall_start);
10448 
10449   /* emit message */
10450   message_delivery = ags_message_delivery_get_instance();
10451 
10452   start_message_queue = ags_message_delivery_find_sender_namespace(message_delivery,
10453 								   "libags-audio");
10454 
10455   if(start_message_queue != NULL){
10456     AgsMessageEnvelope *message;
10457 
10458     xmlDoc *doc;
10459     xmlNode *root_node;
10460 
10461     /* specify message body */
10462     doc = xmlNewDoc("1.0");
10463 
10464     root_node = xmlNewNode(NULL,
10465 			   "ags-command");
10466     xmlDocSetRootElement(doc, root_node);
10467 
10468     xmlNewProp(root_node,
10469 	       "method",
10470 	       "AgsChannel::remove-effect");
10471 
10472     /* add message */
10473     message = ags_message_envelope_new((GObject *) channel,
10474 				       NULL,
10475 				       doc);
10476 
10477     /* set parameter */
10478     message->n_params = 1;
10479 
10480     message->parameter_name = (gchar **) malloc(2 * sizeof(gchar *));
10481     message->value = g_new0(GValue,
10482 			    1);
10483 
10484     /* nth */
10485     message->parameter_name[0] = "nth";
10486     g_value_init(&(message->value[0]),
10487 		 G_TYPE_UINT);
10488     g_value_set_uint(&(message->value[0]),
10489 		     nth);
10490 
10491     /* terminate string vector */
10492     message->parameter_name[1] = NULL;
10493 
10494     /* add message */
10495     ags_message_delivery_add_message_envelope(message_delivery,
10496 					      "libags-audio",
10497 					      message);
10498 
10499     g_list_free_full(start_message_queue,
10500 		     (GDestroyNotify) g_object_unref);
10501   }
10502 }
10503 
10504 /**
10505  * ags_channel_remove_effect:
10506  * @channel: the #AgsChannel
10507  * @nth: nth effect
10508  *
10509  * Remove specified effect of @channel.
10510  *
10511  * Since: 3.0.0
10512  */
10513 void
ags_channel_remove_effect(AgsChannel * channel,guint nth)10514 ags_channel_remove_effect(AgsChannel *channel,
10515 			  guint nth)
10516 {
10517   g_return_if_fail(AGS_IS_CHANNEL(channel));
10518 
10519   g_object_ref((GObject *) channel);
10520   g_signal_emit(G_OBJECT(channel),
10521 		channel_signals[REMOVE_EFFECT], 0,
10522 		nth);
10523   g_object_unref((GObject *) channel);
10524 }
10525 
10526 void
ags_channel_real_duplicate_recall(AgsChannel * channel,AgsRecallID * recall_id)10527 ags_channel_real_duplicate_recall(AgsChannel *channel,
10528 				  AgsRecallID *recall_id)
10529 {
10530   AgsRecall *recall, *copy_recall;
10531   AgsRecyclingContext *parent_recycling_context, *recycling_context;
10532 
10533   GList *list_start, *list;
10534 
10535   guint sound_scope;
10536   guint current_staging_flags;
10537   gboolean play_context;
10538 
10539   GRecMutex *channel_mutex;
10540   GRecMutex *recall_id_mutex;
10541   GRecMutex *recycling_context_mutex;
10542 
10543   if(!AGS_IS_RECALL_ID(recall_id)){
10544     return;
10545   }
10546 
10547   //  g_message("dup");
10548 
10549   /* get recall id mutex */
10550   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
10551 
10552   /* get some fields */
10553   g_rec_mutex_lock(recall_id_mutex);
10554 
10555   sound_scope = recall_id->sound_scope;
10556 
10557   g_rec_mutex_unlock(recall_id_mutex);
10558 
10559   if(sound_scope == -1){
10560     g_critical("can only duplicate for specific sound scope");
10561 
10562     return;
10563   }
10564 
10565   recycling_context = NULL;
10566 
10567   g_object_get(recall_id,
10568 	       "recycling-context", &recycling_context,
10569 	       NULL);
10570 
10571   /* get channel mutex */
10572   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
10573 
10574   /* get staging flags */
10575   g_rec_mutex_lock(channel_mutex);
10576 
10577   current_staging_flags = channel->staging_flags[sound_scope];
10578 
10579   g_rec_mutex_unlock(channel_mutex);
10580 
10581   if(!AGS_IS_RECYCLING_CONTEXT(recycling_context) ||
10582      (AGS_SOUND_STAGING_RUN_INIT_PRE & (current_staging_flags)) != 0){
10583     if(recycling_context != NULL){
10584       g_object_unref(recycling_context);
10585     }
10586 
10587     return;
10588   }
10589 
10590   /* get recycling context mutex */
10591   recycling_context_mutex = AGS_RECYCLING_CONTEXT_GET_OBJ_MUTEX(recycling_context);
10592 
10593   /* get parent recycling context */
10594   parent_recycling_context = NULL;
10595 
10596   g_object_get(recycling_context,
10597 	       "parent", &parent_recycling_context,
10598 	       NULL);
10599 
10600   /* get the appropriate list */
10601   if(parent_recycling_context == NULL){
10602     GRecMutex *play_mutex;
10603 
10604     play_context = TRUE;
10605 
10606     /* get play mutex */
10607     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
10608 
10609     /* copy play context */
10610     g_rec_mutex_lock(play_mutex);
10611 
10612     list_start = g_list_copy_deep(channel->play,
10613 				  (GCopyFunc) g_object_ref,
10614 				  NULL);
10615 
10616     g_rec_mutex_unlock(play_mutex);
10617 
10618     /* reverse play context */
10619     list =
10620       list_start = g_list_reverse(list_start);
10621   }else{
10622     GRecMutex *recall_mutex;
10623 
10624     play_context = FALSE;
10625 
10626     /* get recall mutex */
10627     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
10628 
10629     /* copy recall context */
10630     g_rec_mutex_lock(recall_mutex);
10631 
10632     list_start = g_list_copy_deep(channel->recall,
10633 				  (GCopyFunc) g_object_ref,
10634 				  NULL);
10635 
10636     g_rec_mutex_unlock(recall_mutex);
10637 
10638     /* reverse recall context */
10639     list =
10640       list_start = g_list_reverse(list_start);
10641   }
10642 
10643   /* notify run */
10644   //  ags_recall_notify_dependency(AGS_RECALL(list->data), AGS_RECALL_NOTIFY_RUN, 1);
10645 
10646   /* return if already played */
10647   g_rec_mutex_lock(recall_id_mutex);
10648 
10649   if(ags_recall_id_check_state_flags(recall_id, AGS_SOUND_STATE_IS_WAITING) ||
10650      ags_recall_id_check_state_flags(recall_id, AGS_SOUND_STATE_IS_ACTIVE) ||
10651      ags_recall_id_check_state_flags(recall_id, AGS_SOUND_STATE_IS_PROCESSING) ||
10652      ags_recall_id_check_state_flags(recall_id, AGS_SOUND_STATE_IS_TERMINATING)){
10653     g_list_free_full(list_start,
10654 		     g_object_unref);
10655 
10656     if(parent_recycling_context != NULL){
10657       g_object_unref(parent_recycling_context);
10658     }
10659 
10660     if(recycling_context != NULL){
10661       g_object_unref(recycling_context);
10662     }
10663 
10664     g_rec_mutex_unlock(recall_id_mutex);
10665 
10666     return;
10667   }
10668 
10669   ags_recall_id_set_state_flags(recall_id,
10670 				AGS_SOUND_STATE_IS_WAITING);
10671 
10672   g_rec_mutex_unlock(recall_id_mutex);
10673 
10674   /* duplicate */
10675   while(list != NULL){
10676     GRecMutex *current_recall_mutex;
10677 
10678     recall = AGS_RECALL(list->data);
10679 
10680     /* get current recall mutex */
10681     current_recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
10682 
10683     /* some checks */
10684     g_rec_mutex_lock(current_recall_mutex);
10685 
10686     if(AGS_IS_RECALL_CHANNEL(recall) ||
10687        (AGS_RECALL_TEMPLATE & (recall->flags)) == 0 ||
10688        recall->recall_id != NULL ||
10689        !ags_recall_match_ability_flags_to_scope(recall,
10690 						sound_scope)){
10691       list = list->next;
10692 
10693       g_rec_mutex_unlock(current_recall_mutex);
10694 
10695       continue;
10696     }
10697 
10698     g_rec_mutex_unlock(current_recall_mutex);
10699 
10700     /* duplicate the recall */
10701     copy_recall = ags_recall_duplicate(recall,
10702 				       recall_id,
10703 				       NULL, NULL, NULL);
10704 
10705     if(copy_recall == NULL){
10706       /* iterate */
10707       list = list->next;
10708 
10709       continue;
10710     }
10711 
10712 #ifdef AGS_DEBUG
10713     g_message("recall duplicated: %s %s", G_OBJECT_TYPE_NAME(channel), G_OBJECT_TYPE_NAME(copy_recall));
10714 #endif
10715 
10716     /* set appropriate sound scope */
10717     ags_recall_set_sound_scope(copy_recall, sound_scope);
10718 
10719     /* append to AgsChannel */
10720     ags_channel_add_recall(channel,
10721 			   (GObject *) copy_recall,
10722 			   play_context);
10723     g_signal_connect(copy_recall, "done",
10724 		     G_CALLBACK(ags_channel_recall_done_callback), channel);
10725 
10726     /* connect */
10727     ags_connectable_connect(AGS_CONNECTABLE(copy_recall));
10728 
10729     /* notify run */
10730     ags_recall_notify_dependency(copy_recall, AGS_RECALL_NOTIFY_RUN, 1);
10731 
10732     /* iterate */
10733     list = list->next;
10734   }
10735 
10736   g_list_free_full(list_start,
10737 		   g_object_unref);
10738 
10739   if(parent_recycling_context != NULL){
10740     g_object_unref(parent_recycling_context);
10741   }
10742 
10743   if(recycling_context != NULL){
10744     g_object_unref(recycling_context);
10745   }
10746 }
10747 
10748 /**
10749  * ags_channel_duplicate_recall:
10750  * @channel: the #AgsChannel
10751  * @recall_id: the #AgsRecallID
10752  *
10753  * Duplicate #AgsRecall template and assign @recall_id to it.
10754  *
10755  * Since: 3.0.0
10756  */
10757 void
ags_channel_duplicate_recall(AgsChannel * channel,AgsRecallID * recall_id)10758 ags_channel_duplicate_recall(AgsChannel *channel,
10759 			     AgsRecallID *recall_id)
10760 {
10761   g_return_if_fail(AGS_IS_CHANNEL(channel) && AGS_IS_RECALL_ID(recall_id));
10762 
10763   g_object_ref((GObject *) channel);
10764   g_signal_emit(G_OBJECT(channel),
10765 		channel_signals[DUPLICATE_RECALL], 0,
10766 		recall_id);
10767   g_object_unref((GObject *) channel);
10768 }
10769 
10770 void
ags_channel_real_resolve_recall(AgsChannel * channel,AgsRecallID * recall_id)10771 ags_channel_real_resolve_recall(AgsChannel *channel,
10772 				AgsRecallID *recall_id)
10773 {
10774   AgsRecall *recall;
10775   AgsRecyclingContext *parent_recycling_context, *recycling_context;
10776 
10777   GList *list_start, *list;
10778 
10779   guint sound_scope;
10780   guint current_staging_flags;
10781 
10782   GRecMutex *channel_mutex;
10783   GRecMutex *recall_id_mutex;
10784   GRecMutex *recycling_context_mutex;
10785 
10786   if(!AGS_IS_RECALL_ID(recall_id)){
10787     return;
10788   }
10789 
10790   /* get recall id mutex */
10791   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
10792 
10793   /* get some fields */
10794   g_rec_mutex_lock(recall_id_mutex);
10795 
10796   sound_scope = recall_id->sound_scope;
10797 
10798   g_rec_mutex_unlock(recall_id_mutex);
10799 
10800   if(sound_scope == -1){
10801     g_critical("can only resolve for specific sound scope");
10802 
10803     return;
10804   }
10805 
10806   recycling_context = NULL;
10807 
10808   g_object_get(recall_id,
10809 	       "recycling-context", &recycling_context,
10810 	       NULL);
10811 
10812   /* get channel mutex */
10813   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
10814 
10815   /* get staging flags */
10816   g_rec_mutex_lock(channel_mutex);
10817 
10818   current_staging_flags = channel->staging_flags[sound_scope];
10819 
10820   g_rec_mutex_unlock(channel_mutex);
10821 
10822   if(!AGS_IS_RECYCLING_CONTEXT(recycling_context) ||
10823      (AGS_SOUND_STAGING_RUN_INIT_PRE & (current_staging_flags)) != 0){
10824     if(recycling_context != NULL){
10825       g_object_unref(recycling_context);
10826     }
10827 
10828     return;
10829   }
10830 
10831   /* get recycling context mutex */
10832   recycling_context_mutex = AGS_RECYCLING_CONTEXT_GET_OBJ_MUTEX(recycling_context);
10833 
10834   /* get parent recycling context */
10835   parent_recycling_context = NULL;
10836 
10837   g_object_get(recycling_context,
10838 	       "parent", &parent_recycling_context,
10839 	       NULL);
10840 
10841   /* get the appropriate lists */
10842   if(parent_recycling_context == NULL){
10843     GRecMutex *play_mutex;
10844 
10845     /* get play mutex */
10846     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
10847 
10848     /* copy play context */
10849     g_rec_mutex_lock(play_mutex);
10850 
10851     list =
10852       list_start = g_list_copy_deep(channel->play,
10853 				    (GCopyFunc) g_object_ref,
10854 				    NULL);
10855 
10856     g_rec_mutex_unlock(play_mutex);
10857 
10858     /* reverse play context */
10859     list =
10860       list_start = g_list_reverse(list_start);
10861   }else{
10862     GRecMutex *recall_mutex;
10863 
10864     /* get recall mutex */
10865     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
10866 
10867     /* copy recall context */
10868     g_rec_mutex_lock(recall_mutex);
10869 
10870     list =
10871       list_start = g_list_copy_deep(channel->recall,
10872 				    (GCopyFunc) g_object_ref,
10873 				    NULL);
10874 
10875     g_rec_mutex_unlock(recall_mutex);
10876 
10877     /* reverse recall context */
10878     list =
10879       list_start = g_list_reverse(list_start);
10880   }
10881 
10882   /* resolve */
10883   while((list = ags_recall_find_recycling_context(list,
10884 						  (GObject *) recycling_context)) != NULL){
10885     recall = AGS_RECALL(list->data);
10886 
10887     ags_recall_resolve_dependency(recall);
10888 
10889     list = list->next;
10890   }
10891 
10892   g_list_free_full(list_start,
10893 		   g_object_unref);
10894 
10895   if(parent_recycling_context != NULL){
10896     g_object_unref(parent_recycling_context);
10897   }
10898 
10899   if(recycling_context != NULL){
10900     g_object_unref(recycling_context);
10901   }
10902 }
10903 
10904 /**
10905  * ags_channel_resolve_recall:
10906  * @channel: an #AgsChannel
10907  * @recall_id: appropriate #AgsRecallID
10908  *
10909  * Resolve step of initialization.
10910  *
10911  * Since: 3.0.0
10912  */
10913 void
ags_channel_resolve_recall(AgsChannel * channel,AgsRecallID * recall_id)10914 ags_channel_resolve_recall(AgsChannel *channel,
10915 			   AgsRecallID *recall_id)
10916 {
10917   g_return_if_fail(AGS_IS_CHANNEL(channel) && AGS_IS_RECALL_ID(recall_id));
10918 
10919   g_object_ref((GObject *) channel);
10920   g_signal_emit(G_OBJECT(channel),
10921 		channel_signals[RESOLVE_RECALL], 0,
10922 		recall_id);
10923   g_object_unref((GObject *) channel);
10924 }
10925 
10926 void
ags_channel_real_init_recall(AgsChannel * channel,AgsRecallID * recall_id,guint staging_flags)10927 ags_channel_real_init_recall(AgsChannel *channel,
10928 			     AgsRecallID *recall_id, guint staging_flags)
10929 {
10930   AgsRecall *recall;
10931   AgsRecyclingContext *parent_recycling_context, *recycling_context;
10932 
10933   GList *list_start, *list;
10934 
10935   guint sound_scope;
10936   guint current_staging_flags;
10937   static const guint staging_mask = (AGS_SOUND_STAGING_CHECK_RT_DATA |
10938 				     AGS_SOUND_STAGING_RUN_INIT_PRE |
10939 				     AGS_SOUND_STAGING_RUN_INIT_INTER |
10940 				     AGS_SOUND_STAGING_RUN_INIT_POST);
10941 
10942   GRecMutex *channel_mutex;
10943   GRecMutex *recall_id_mutex;
10944   GRecMutex *recycling_context_mutex;
10945 
10946   if(!AGS_IS_RECALL_ID(recall_id)){
10947     return;
10948   }
10949 
10950   /* get recall id mutex */
10951   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
10952 
10953   /* get some fields */
10954   g_rec_mutex_lock(recall_id_mutex);
10955 
10956   sound_scope = recall_id->sound_scope;
10957 
10958   g_rec_mutex_unlock(recall_id_mutex);
10959 
10960   if(sound_scope == -1){
10961     g_critical("can only init for specific sound scope");
10962 
10963     return;
10964   }
10965 
10966   recycling_context = NULL;
10967 
10968   g_object_get(recall_id,
10969 	       "recycling-context", &recycling_context,
10970 	       NULL);
10971 
10972   /* get channel mutex */
10973   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
10974 
10975   /* get staging flags */
10976   g_rec_mutex_lock(channel_mutex);
10977 
10978   current_staging_flags = channel->staging_flags[sound_scope];
10979 
10980   g_rec_mutex_unlock(channel_mutex);
10981 
10982   if(!AGS_IS_RECYCLING_CONTEXT(recycling_context) ||
10983      (AGS_SOUND_STAGING_RUN_INIT_PRE & (current_staging_flags)) != 0){
10984     if(recycling_context != NULL){
10985       g_object_unref(recycling_context);
10986     }
10987 
10988     return;
10989   }
10990 
10991   /* get recycling context mutex */
10992   recycling_context_mutex = AGS_RECYCLING_CONTEXT_GET_OBJ_MUTEX(recycling_context);
10993 
10994   /* get parent recycling context */
10995   parent_recycling_context = NULL;
10996 
10997   g_object_get(recycling_context,
10998 	       "parent", &parent_recycling_context,
10999 	       NULL);
11000 
11001   /* get the appropriate lists */
11002   if(parent_recycling_context == NULL){
11003     GRecMutex *play_mutex;
11004 
11005     /* get play mutex */
11006     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
11007 
11008     /* copy play context */
11009     g_rec_mutex_lock(play_mutex);
11010 
11011     list =
11012       list_start = g_list_copy_deep(channel->play,
11013 				    (GCopyFunc) g_object_ref,
11014 				    NULL);
11015 
11016     g_rec_mutex_unlock(play_mutex);
11017 
11018     /* reverse play context */
11019     list =
11020       list_start = g_list_reverse(list_start);
11021   }else{
11022     GRecMutex *recall_mutex;
11023 
11024     /* get recall mutex */
11025     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
11026 
11027     /* copy recall context */
11028     g_rec_mutex_lock(recall_mutex);
11029 
11030     list =
11031       list_start = g_list_copy_deep(channel->recall,
11032 				    (GCopyFunc) g_object_ref,
11033 				    NULL);
11034 
11035     g_rec_mutex_unlock(recall_mutex);
11036 
11037     /* reverse recall context */
11038     list =
11039       list_start = g_list_reverse(list_start);
11040   }
11041 
11042   /* init  */
11043   staging_flags = staging_mask & staging_flags;
11044 
11045   while((list = ags_recall_find_recycling_context(list,
11046 						  (GObject *) recycling_context)) != NULL){
11047     recall = AGS_RECALL(list->data);
11048 
11049     /* run init stages */
11050     ags_recall_set_state_flags(recall,
11051 			       AGS_SOUND_STATE_IS_ACTIVE);
11052 
11053     ags_recall_set_staging_flags(recall,
11054 				 staging_flags);
11055 
11056     list = list->next;
11057   }
11058 
11059   g_list_free_full(list_start,
11060 		   g_object_unref);
11061 
11062 #if 0
11063   ags_channel_set_staging_flags(channel, sound_scope,
11064 				staging_flags);
11065 #endif
11066 
11067   if(parent_recycling_context != NULL){
11068     g_object_unref(parent_recycling_context);
11069   }
11070 
11071   if(recycling_context != NULL){
11072     g_object_unref(recycling_context);
11073   }
11074 }
11075 
11076 /**
11077  * ags_channel_init_recall:
11078  * @channel: the #AgsChannel
11079  * @recall_id: the #AgsRecallID
11080  * @staging_flags: the stages to invoke
11081  *
11082  * Prepare #AgsRecall objects and invoke #AgsRecall::run-init-pre, #AgsRecall::run-init-inter or
11083  * #AgsRecall::run-init-post as specified by @staging_flags.
11084  *
11085  * Since: 3.0.0
11086  */
11087 void
ags_channel_init_recall(AgsChannel * channel,AgsRecallID * recall_id,guint staging_flags)11088 ags_channel_init_recall(AgsChannel *channel,
11089 			AgsRecallID *recall_id, guint staging_flags)
11090 {
11091   g_return_if_fail(AGS_IS_CHANNEL(channel) && AGS_IS_RECALL_ID(recall_id));
11092 
11093   g_object_ref((GObject *) channel);
11094   g_signal_emit(G_OBJECT(channel),
11095 		channel_signals[INIT_RECALL], 0,
11096 		recall_id, staging_flags);
11097   g_object_unref((GObject *) channel);
11098 }
11099 
11100 void
ags_channel_real_play_recall(AgsChannel * channel,AgsRecallID * recall_id,guint staging_flags)11101 ags_channel_real_play_recall(AgsChannel *channel,
11102 			     AgsRecallID *recall_id, guint staging_flags)
11103 {
11104   AgsRecall *recall;
11105   AgsRecyclingContext *parent_recycling_context, *recycling_context;
11106 
11107   GList *list_start, *list;
11108 
11109   guint sound_scope;
11110   guint current_staging_flags;
11111   static const guint staging_mask = (AGS_SOUND_STAGING_RUN_INIT_PRE |
11112 				     AGS_SOUND_STAGING_RUN_INIT_INTER |
11113 				     AGS_SOUND_STAGING_RUN_INIT_POST |
11114 				     AGS_SOUND_STAGING_FEED_INPUT_QUEUE |
11115 				     AGS_SOUND_STAGING_AUTOMATE |
11116 				     AGS_SOUND_STAGING_RUN_PRE |
11117 				     AGS_SOUND_STAGING_RUN_INTER |
11118 				     AGS_SOUND_STAGING_RUN_POST |
11119 				     AGS_SOUND_STAGING_DO_FEEDBACK |
11120 				     AGS_SOUND_STAGING_FEED_OUTPUT_QUEUE |
11121 				     AGS_SOUND_STAGING_FINI);
11122 
11123   GRecMutex *channel_mutex;
11124   GRecMutex *recall_id_mutex;
11125   GRecMutex *recycling_context_mutex;
11126 
11127   if(!AGS_IS_RECALL_ID(recall_id)){
11128     return;
11129   }
11130 
11131 //  g_message("recall ID 0x%x", recall_id);
11132 
11133   if(ags_recall_id_check_state_flags(recall_id, AGS_SOUND_STATE_IS_TERMINATING)){
11134 //    g_message("`⁻ term");
11135 
11136     return;
11137   }
11138 
11139   /* get recall id mutex */
11140   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
11141 
11142   /* get some fields */
11143   g_rec_mutex_lock(recall_id_mutex);
11144 
11145   sound_scope = recall_id->sound_scope;
11146 
11147   g_rec_mutex_unlock(recall_id_mutex);
11148 
11149   recycling_context = NULL;
11150 
11151   g_object_get(recall_id,
11152 	       "recycling-context", &recycling_context,
11153 	       NULL);
11154 
11155   /* get channel mutex */
11156   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
11157 
11158   /* get staging flags */
11159   g_rec_mutex_lock(channel_mutex);
11160 
11161   current_staging_flags = channel->staging_flags[sound_scope];
11162 
11163   g_rec_mutex_unlock(channel_mutex);
11164 
11165 #if 0
11166   if(!AGS_IS_RECYCLING_CONTEXT(recycling_context) ||
11167      (AGS_SOUND_STAGING_RUN_INIT_PRE & (current_staging_flags)) == 0 ||
11168      (AGS_SOUND_STAGING_RUN_INIT_INTER & (current_staging_flags)) == 0 ||
11169      (AGS_SOUND_STAGING_RUN_INIT_POST & (current_staging_flags)) == 0){
11170     return;
11171   }
11172 #endif
11173 
11174   /* get recycling context mutex */
11175   recycling_context_mutex = AGS_RECYCLING_CONTEXT_GET_OBJ_MUTEX(recycling_context);
11176 
11177   /* get parent recycling context */
11178   parent_recycling_context = NULL;
11179 
11180   g_object_get(recycling_context,
11181 	       "parent", &parent_recycling_context,
11182 	       NULL);
11183 
11184   /* get the appropriate lists */
11185   if(parent_recycling_context == NULL){
11186     GRecMutex *play_mutex;
11187 
11188     /* get play mutex */
11189     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
11190 
11191     /* copy play context */
11192     g_rec_mutex_lock(play_mutex);
11193 
11194     list_start = g_list_copy_deep(channel->play,
11195 				  (GCopyFunc) g_object_ref,
11196 				  NULL);
11197 
11198     g_rec_mutex_unlock(play_mutex);
11199 
11200     /* reverse play context */
11201     list =
11202       list_start = g_list_reverse(list_start);
11203   }else{
11204     GRecMutex *recall_mutex;
11205 
11206     /* get recall mutex */
11207     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
11208 
11209     /* copy recall context */
11210     g_rec_mutex_lock(recall_mutex);
11211 
11212     list_start = g_list_copy_deep(channel->recall,
11213 				  (GCopyFunc) g_object_ref,
11214 				  NULL);
11215 
11216     g_rec_mutex_unlock(recall_mutex);
11217 
11218     /* reverse recall context */
11219     list =
11220       list_start = g_list_reverse(list_start);
11221   }
11222 
11223   /* automate and play  */
11224   if((AGS_SOUND_STAGING_FX & (staging_flags)) == 0){
11225     staging_flags = staging_flags & staging_mask;
11226 
11227     if((AGS_SOUND_STAGING_AUTOMATE & (staging_flags)) != 0){
11228       while(list != NULL){
11229 	recall = AGS_RECALL(list->data);
11230 
11231 	/* play stages */
11232 	if(AGS_IS_RECALL_CHANNEL(recall)){
11233 	  ags_recall_set_staging_flags(recall,
11234 				       AGS_SOUND_STAGING_AUTOMATE);
11235 	  ags_recall_unset_staging_flags(recall,
11236 					 AGS_SOUND_STAGING_AUTOMATE);
11237 	}
11238 
11239 	list = list->next;
11240       }
11241     }
11242 
11243     staging_flags = staging_flags & (~AGS_SOUND_STAGING_AUTOMATE);
11244   }
11245 
11246   list = list_start;
11247 
11248   while((list = ags_recall_find_recycling_context(list,
11249 						  (GObject *) recycling_context)) != NULL){
11250     recall = AGS_RECALL(list->data);
11251 
11252     /* play stages */
11253     ags_recall_set_staging_flags(recall,
11254 				 staging_flags);
11255     ags_recall_unset_staging_flags(recall,
11256 				   staging_flags);
11257 
11258     list = list->next;
11259   }
11260 
11261   g_list_free_full(list_start,
11262 		   g_object_unref);
11263 
11264   if(parent_recycling_context != NULL){
11265     g_object_unref(parent_recycling_context);
11266   }
11267 
11268   if(recycling_context != NULL){
11269     g_object_unref(recycling_context);
11270   }
11271 
11272   //FIXME:JK: uncomment
11273   //  ags_channel_set_staging_flags(channel, sound_scope,
11274   //				staging_flags);
11275 }
11276 
11277 /**
11278  * ags_channel_play_recall:
11279  * @channel: the #AgsChannel
11280  * @recall_id: the #AgsRecallID
11281  * @staging_flags: the stages to invoke
11282  *
11283  * Run the specified steps by @recall_id of @channel.
11284  *
11285  * Since: 3.0.0
11286  */
11287 void
ags_channel_play_recall(AgsChannel * channel,AgsRecallID * recall_id,guint staging_flags)11288 ags_channel_play_recall(AgsChannel *channel,
11289 			AgsRecallID *recall_id, guint staging_flags)
11290 {
11291   g_return_if_fail(AGS_IS_CHANNEL(channel) && AGS_IS_RECALL_ID(recall_id));
11292 
11293   g_object_ref((GObject *) channel);
11294   g_signal_emit(G_OBJECT(channel),
11295 		channel_signals[PLAY_RECALL], 0,
11296 		recall_id, staging_flags);
11297   g_object_unref((GObject *) channel);
11298 }
11299 
11300 void
ags_channel_real_done_recall(AgsChannel * channel,AgsRecallID * recall_id)11301 ags_channel_real_done_recall(AgsChannel *channel,
11302 			     AgsRecallID *recall_id)
11303 {
11304   AgsRecall *recall;
11305   AgsRecyclingContext *parent_recycling_context, *recycling_context;
11306 
11307   GList *list_start, *list;
11308 
11309   guint sound_scope;
11310   guint current_staging_flags;
11311   static const guint staging_flags = (AGS_SOUND_STAGING_DONE);
11312 
11313   GRecMutex *channel_mutex;
11314   GRecMutex *recall_id_mutex;
11315   GRecMutex *recycling_context_mutex;
11316 
11317   if(!AGS_IS_RECALL_ID(recall_id)){
11318     return;
11319   }
11320 
11321   /* get recall id mutex */
11322   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
11323 
11324   /* get some fields */
11325   g_rec_mutex_lock(recall_id_mutex);
11326 
11327   sound_scope = recall_id->sound_scope;
11328 
11329   g_rec_mutex_unlock(recall_id_mutex);
11330 
11331   recycling_context = NULL;
11332 
11333   g_object_get(recall_id,
11334 	       "recycling-context", &recycling_context,
11335 	       NULL);
11336 
11337   /* get channel mutex */
11338   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
11339 
11340   /* get staging flags */
11341   g_rec_mutex_lock(channel_mutex);
11342 
11343   current_staging_flags = channel->staging_flags[sound_scope];
11344 
11345   g_rec_mutex_unlock(channel_mutex);
11346 
11347   if(!AGS_IS_RECYCLING_CONTEXT(recycling_context) ||
11348      (AGS_SOUND_STAGING_RUN_INIT_PRE & (current_staging_flags)) == 0 ||
11349      (AGS_SOUND_STAGING_RUN_INIT_INTER & (current_staging_flags)) == 0 ||
11350      (AGS_SOUND_STAGING_RUN_INIT_POST & (current_staging_flags)) == 0){
11351     if(recycling_context != NULL){
11352       g_object_unref(recycling_context);
11353     }
11354 
11355     return;
11356   }
11357 
11358   /* get recycling context mutex */
11359   recycling_context_mutex = AGS_RECYCLING_CONTEXT_GET_OBJ_MUTEX(recycling_context);
11360 
11361   /* get parent recycling context */
11362   parent_recycling_context = NULL;
11363 
11364   g_object_get(recycling_context,
11365 	       "parent", &parent_recycling_context,
11366 	       NULL);
11367 
11368   /* get the appropriate lists */
11369   if(parent_recycling_context == NULL){
11370     GRecMutex *play_mutex;
11371 
11372     /* get play mutex */
11373     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
11374 
11375     /* copy play context */
11376     g_rec_mutex_lock(play_mutex);
11377 
11378     list =
11379       list_start = g_list_copy_deep(channel->play,
11380 				    (GCopyFunc) g_object_ref,
11381 				    NULL);
11382 
11383     g_rec_mutex_unlock(play_mutex);
11384 
11385     /* reverse play context */
11386     list =
11387       list_start = g_list_reverse(list_start);
11388   }else{
11389     GRecMutex *recall_mutex;
11390 
11391     /* get recall mutex */
11392     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
11393 
11394     /* copy recall context */
11395     g_rec_mutex_lock(recall_mutex);
11396 
11397     list =
11398       list_start = g_list_copy_deep(channel->recall,
11399 				    (GCopyFunc) g_object_ref,
11400 				    NULL);
11401 
11402     g_rec_mutex_unlock(recall_mutex);
11403 
11404     /* reverse recall context */
11405     list =
11406       list_start = g_list_reverse(list_start);
11407   }
11408 
11409   /* done  */
11410   while((list = ags_recall_find_recycling_context(list,
11411 						  (GObject *) recycling_context)) != NULL){
11412     recall = AGS_RECALL(list->data);
11413 
11414     /* done stages */
11415     ags_recall_set_staging_flags(recall,
11416 				 staging_flags);
11417 
11418     list = list->next;
11419   }
11420 
11421   g_list_free_full(list_start,
11422 		   g_object_unref);
11423 
11424   ags_channel_set_staging_flags(channel, sound_scope,
11425 				staging_flags);
11426 
11427   if(parent_recycling_context != NULL){
11428     g_object_unref(parent_recycling_context);
11429   }
11430 
11431   if(recycling_context != NULL){
11432     g_object_unref(recycling_context);
11433   }
11434 }
11435 
11436 /**
11437  * ags_channel_done_recall:
11438  * @channel: the #AgsChannel
11439  * @recall_id: the #AgsRecallID
11440  *
11441  * Done processing specified by @recall_id.
11442  *
11443  * Since: 3.0.0
11444  */
11445 void
ags_channel_done_recall(AgsChannel * channel,AgsRecallID * recall_id)11446 ags_channel_done_recall(AgsChannel *channel,
11447 			AgsRecallID *recall_id)
11448 {
11449   g_return_if_fail(AGS_IS_CHANNEL(channel) && AGS_IS_RECALL_ID(recall_id));
11450 
11451   g_object_ref(G_OBJECT(channel));
11452   g_signal_emit(G_OBJECT(channel),
11453 		channel_signals[DONE_RECALL], 0,
11454 		recall_id);
11455   g_object_unref(G_OBJECT(channel));
11456 }
11457 
11458 void
ags_channel_real_cancel_recall(AgsChannel * channel,AgsRecallID * recall_id)11459 ags_channel_real_cancel_recall(AgsChannel *channel,
11460 			       AgsRecallID *recall_id)
11461 {
11462   AgsRecall *recall;
11463   AgsRecyclingContext *parent_recycling_context, *recycling_context;
11464 
11465   GList *list_start, *list;
11466 
11467   guint sound_scope;
11468   guint current_staging_flags;
11469   static const guint staging_flags = (AGS_SOUND_STAGING_CANCEL);
11470 
11471   GRecMutex *channel_mutex;
11472   GRecMutex *recall_id_mutex;
11473   GRecMutex *recycling_context_mutex;
11474 
11475   if(!AGS_IS_RECALL_ID(recall_id)){
11476     return;
11477   }
11478 
11479   /* get recall id mutex */
11480   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
11481 
11482   /* get some fields */
11483   g_rec_mutex_lock(recall_id_mutex);
11484 
11485   sound_scope = recall_id->sound_scope;
11486 
11487   g_rec_mutex_unlock(recall_id_mutex);
11488 
11489   recycling_context = NULL;
11490 
11491   g_object_get(recall_id,
11492 	       "recycling-context", &recycling_context,
11493 	       NULL);
11494 
11495   /* get channel mutex */
11496   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
11497 
11498   /* get staging flags */
11499   g_rec_mutex_lock(channel_mutex);
11500 
11501   current_staging_flags = channel->staging_flags[sound_scope];
11502 
11503   g_rec_mutex_unlock(channel_mutex);
11504 
11505   if(!AGS_IS_RECYCLING_CONTEXT(recycling_context) ||
11506      (AGS_SOUND_STAGING_RUN_INIT_PRE & (current_staging_flags)) == 0 ||
11507      (AGS_SOUND_STAGING_RUN_INIT_INTER & (current_staging_flags)) == 0 ||
11508      (AGS_SOUND_STAGING_RUN_INIT_POST & (current_staging_flags)) == 0){
11509     if(recycling_context != NULL){
11510       g_object_unref(recycling_context);
11511     }
11512 
11513     return;
11514   }
11515 
11516   /* get recycling context mutex */
11517   recycling_context_mutex = AGS_RECYCLING_CONTEXT_GET_OBJ_MUTEX(recycling_context);
11518 
11519   /* get parent recycling context */
11520   parent_recycling_context = NULL;
11521 
11522   g_object_get(recycling_context,
11523 	       "parent", &parent_recycling_context,
11524 	       NULL);
11525 
11526   /* get the appropriate lists */
11527   if(parent_recycling_context == NULL){
11528     GRecMutex *play_mutex;
11529 
11530     /* get play mutex */
11531     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
11532 
11533     /* copy play context */
11534     g_rec_mutex_lock(play_mutex);
11535 
11536     list =
11537       list_start = g_list_copy_deep(channel->play,
11538 				    (GCopyFunc) g_object_ref,
11539 				    NULL);
11540 
11541     g_rec_mutex_unlock(play_mutex);
11542 
11543     /* reverse play context */
11544     list =
11545       list_start = g_list_reverse(list_start);
11546   }else{
11547     GRecMutex *recall_mutex;
11548 
11549     /* get recall mutex */
11550     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
11551 
11552     /* copy recall context */
11553     g_rec_mutex_lock(recall_mutex);
11554 
11555     list =
11556       list_start = g_list_copy_deep(channel->recall,
11557 				    (GCopyFunc) g_object_ref,
11558 				    NULL);
11559 
11560     g_rec_mutex_unlock(recall_mutex);
11561 
11562     /* reverse recall context */
11563     list =
11564       list_start = g_list_reverse(list_start);
11565   }
11566 
11567   /* cancel  */
11568   while((list = ags_recall_find_recycling_context(list,
11569 						  (GObject *) recycling_context)) != NULL){
11570     recall = AGS_RECALL(list->data);
11571 
11572     /* cancel stages */
11573     ags_recall_set_staging_flags(recall,
11574 				 staging_flags);
11575 
11576     ags_recall_unset_state_flags(recall,
11577 				 AGS_SOUND_STATE_IS_ACTIVE);
11578 
11579     list = list->next;
11580   }
11581 
11582   g_list_free_full(list_start,
11583 		   g_object_unref);
11584 
11585   ags_channel_set_staging_flags(channel, sound_scope,
11586 				staging_flags);
11587 
11588   if(parent_recycling_context != NULL){
11589     g_object_unref(parent_recycling_context);
11590   }
11591 
11592   if(recycling_context != NULL){
11593     g_object_unref(recycling_context);
11594   }
11595 }
11596 
11597 /**
11598  * ags_channel_cancel_recall:
11599  * @channel: the #AgsChannel
11600  * @recall_id: the #AgsRecallID
11601  *
11602  * Cancel processing specified by @recall_id.
11603  *
11604  * Since: 3.0.0
11605  */
11606 void
ags_channel_cancel_recall(AgsChannel * channel,AgsRecallID * recall_id)11607 ags_channel_cancel_recall(AgsChannel *channel,
11608 			  AgsRecallID *recall_id)
11609 {
11610   g_return_if_fail(AGS_IS_CHANNEL(channel) && AGS_IS_RECALL_ID(recall_id));
11611 
11612   g_object_ref((GObject *) channel);
11613   g_signal_emit(G_OBJECT(channel),
11614 		channel_signals[CANCEL_RECALL], 0,
11615 		recall_id);
11616   g_object_unref((GObject *) channel);
11617 }
11618 
11619 void
ags_channel_real_cleanup_recall(AgsChannel * channel,AgsRecallID * recall_id)11620 ags_channel_real_cleanup_recall(AgsChannel *channel,
11621 				AgsRecallID *recall_id)
11622 {
11623   AgsRecall *recall;
11624   AgsRecyclingContext *parent_recycling_context, *recycling_context;
11625 
11626   GList *list_start, *list;
11627   GList *match_start, *match;
11628 
11629   gint sound_scope;
11630   guint current_staging_flags;
11631   gboolean play_context;
11632 
11633   GRecMutex *channel_mutex;
11634   GRecMutex *recall_id_mutex;
11635   GRecMutex *recycling_context_mutex;
11636 
11637   if(!AGS_IS_RECALL_ID(recall_id)){
11638     return;
11639   }
11640 
11641   /* get recall id mutex */
11642   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
11643 
11644   /* get some fields */
11645   g_rec_mutex_lock(recall_id_mutex);
11646 
11647   sound_scope = recall_id->sound_scope;
11648 
11649   g_rec_mutex_unlock(recall_id_mutex);
11650 
11651   recycling_context = NULL;
11652 
11653   g_object_get(recall_id,
11654 	       "recycling-context", &recycling_context,
11655 	       NULL);
11656 
11657   /* get channel mutex */
11658   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
11659 
11660   /* get staging flags */
11661   g_rec_mutex_lock(channel_mutex);
11662 
11663   current_staging_flags = channel->staging_flags[sound_scope];
11664 
11665   g_rec_mutex_unlock(channel_mutex);
11666 
11667   /* get recycling context mutex */
11668   recycling_context_mutex = AGS_RECYCLING_CONTEXT_GET_OBJ_MUTEX(recycling_context);
11669 
11670   /* get parent recycling context */
11671   parent_recycling_context = NULL;
11672 
11673   g_object_get(recycling_context,
11674 	       "parent", &parent_recycling_context,
11675 	       NULL);
11676 
11677   /* get the appropriate lists */
11678   if(parent_recycling_context == NULL){
11679     GRecMutex *play_mutex;
11680 
11681     play_context = TRUE;
11682 
11683     /* get play mutex */
11684     play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
11685 
11686     /* copy play context */
11687     g_rec_mutex_lock(play_mutex);
11688 
11689     list =
11690       list_start = g_list_copy_deep(channel->play,
11691 				    (GCopyFunc) g_object_ref,
11692 				    NULL);
11693 
11694     g_rec_mutex_unlock(play_mutex);
11695 
11696     /* reverse play context */
11697     list =
11698       list_start = g_list_reverse(list_start);
11699   }else{
11700     GRecMutex *recall_mutex;
11701 
11702     play_context = FALSE;
11703 
11704     /* get recall mutex */
11705     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
11706 
11707     /* copy recall context */
11708     g_rec_mutex_lock(recall_mutex);
11709 
11710     list =
11711       list_start = g_list_copy_deep(channel->recall,
11712 				    (GCopyFunc) g_object_ref,
11713 				    NULL);
11714 
11715     g_rec_mutex_unlock(recall_mutex);
11716 
11717     /* reverse recall context */
11718     list =
11719       list_start = g_list_reverse(list_start);
11720   }
11721 
11722   /* cleanup  */
11723   match_start = NULL;
11724 
11725   while((list = ags_recall_find_recycling_context(list,
11726 						  (GObject *) recycling_context)) != NULL){
11727     recall = AGS_RECALL(list->data);
11728 
11729     /* remove recall */
11730     ags_channel_remove_recall(channel, (GObject *) recall, play_context);
11731     match_start = g_list_prepend(match_start,
11732 				 recall);
11733 
11734     list = list->next;
11735   }
11736 
11737   g_list_free_full(list_start,
11738 		   g_object_unref);
11739 
11740   /* destroy  */
11741   match = match_start;
11742 
11743   while(match != NULL){
11744     recall = AGS_RECALL(match->data);
11745 
11746     /* destroy */
11747     ags_connectable_disconnect(AGS_CONNECTABLE(recall));
11748     g_object_run_dispose((GObject *) recall);
11749 
11750     match = match->next;
11751   }
11752 
11753   g_list_free_full(match_start,
11754 		   g_object_unref);
11755 
11756   if(parent_recycling_context != NULL){
11757     g_object_unref(parent_recycling_context);
11758   }
11759 
11760   if(recycling_context != NULL){
11761     g_object_unref(recycling_context);
11762   }
11763 }
11764 
11765 /**
11766  * ags_channel_cleanup_recall:
11767  * @channel: the #AgsChannel
11768  * @recall_id: the #AgsRecallID
11769  *
11770  * Cleanup processing specified by @recall_id.
11771  *
11772  * Since: 3.0.0
11773  */
11774 void
ags_channel_cleanup_recall(AgsChannel * channel,AgsRecallID * recall_id)11775 ags_channel_cleanup_recall(AgsChannel *channel,
11776 			   AgsRecallID *recall_id)
11777 {
11778   g_return_if_fail(AGS_IS_CHANNEL(channel) && AGS_IS_RECALL_ID(recall_id));
11779 
11780   g_object_ref((GObject *) channel);
11781   g_signal_emit(G_OBJECT(channel),
11782 		channel_signals[CLEANUP_RECALL], 0,
11783 		recall_id);
11784   g_object_unref((GObject *) channel);
11785 }
11786 
11787 void
ags_channel_recall_done_callback(AgsRecall * recall,AgsChannel * channel)11788 ags_channel_recall_done_callback(AgsRecall *recall,
11789 				 AgsChannel *channel)
11790 {
11791   AgsCancelChannel *cancel_channel;
11792 
11793   AgsTaskLauncher *task_launcher;
11794 
11795   AgsApplicationContext *application_context;
11796 
11797   gint sound_scope;
11798 
11799   if(!ags_recall_test_state_flags(recall, AGS_SOUND_STATE_IS_TERMINATING) &&
11800      (AGS_IS_PLAY_CHANNEL_RUN(recall) ||
11801       AGS_IS_FX_PLAYBACK_CHANNEL_PROCESSOR(recall))){
11802     sound_scope = ags_recall_get_sound_scope(recall);
11803 
11804     if(sound_scope == AGS_SOUND_SCOPE_PLAYBACK){
11805       application_context = ags_application_context_get_instance();
11806 
11807       task_launcher = ags_concurrency_provider_get_task_launcher(AGS_CONCURRENCY_PROVIDER(application_context));
11808 
11809       cancel_channel = ags_cancel_channel_new(channel,
11810 					      sound_scope);
11811 
11812       ags_task_launcher_add_task(task_launcher,
11813 				 cancel_channel);
11814 
11815       g_object_unref(cancel_channel);
11816     }
11817   }
11818 }
11819 
11820 GList*
ags_channel_real_start(AgsChannel * channel,gint sound_scope)11821 ags_channel_real_start(AgsChannel *channel,
11822 		       gint sound_scope)
11823 {
11824   AgsAudio *audio;
11825   AgsRecycling *first_recycling;
11826   AgsPlaybackDomain *playback_domain;
11827   AgsPlayback *playback;
11828   AgsRecallID *audio_recall_id;
11829   AgsRecallID *channel_recall_id;
11830   AgsRecallID *current_recall_id;
11831   AgsRecyclingContext *recycling_context;
11832 
11833   AgsThread *audio_loop;
11834   AgsThread *audio_thread;
11835   AgsThread *channel_thread;
11836   AgsMessageDelivery *message_delivery;
11837 
11838   AgsApplicationContext *application_context;
11839 
11840   GList *start_message_queue;
11841   GList *start_recall_id;
11842   GList *start_wait_thread, *wait_thread;
11843 
11844   gint64 start_wait_timeout;
11845   gint i;
11846 
11847   static const guint staging_flags = (AGS_SOUND_STAGING_CHECK_RT_DATA |
11848 				      AGS_SOUND_STAGING_RUN_INIT_PRE |
11849 				      AGS_SOUND_STAGING_RUN_INIT_INTER |
11850 				      AGS_SOUND_STAGING_RUN_INIT_POST);
11851 
11852   if(!AGS_IS_INPUT(channel) ||
11853      sound_scope >= AGS_SOUND_SCOPE_LAST){
11854     return(NULL);
11855   }
11856 
11857   /* get some fields */
11858   audio = NULL;
11859 
11860   g_object_get(channel,
11861 	       "audio", &audio,
11862 	       NULL);
11863 
11864   /* test input has recycling */
11865   if(!ags_audio_test_flags(audio, AGS_AUDIO_INPUT_HAS_RECYCLING)){
11866     if(audio != NULL){
11867       g_object_unref(audio);
11868     }
11869 
11870     return(NULL);
11871   }
11872 
11873   application_context = ags_application_context_get_instance();
11874 
11875   audio_loop = ags_concurrency_provider_get_main_loop(AGS_CONCURRENCY_PROVIDER(application_context));
11876 
11877   /* add channel to AgsAudioLoop */
11878   ags_audio_loop_add_channel(AGS_AUDIO_LOOP(audio_loop),
11879 			     (GObject *) channel);
11880 
11881   ags_audio_loop_set_flags(audio_loop, AGS_AUDIO_LOOP_PLAY_CHANNEL);
11882 
11883   /* get playback domain */
11884   g_object_get(audio,
11885 	       "playback-domain", &playback_domain,
11886 	       NULL);
11887 
11888   /* get recycling and playback */
11889   g_object_get(channel,
11890 	       "first-recycling", &first_recycling,
11891 	       "playback", &playback,
11892 	       NULL);
11893 
11894   /* run stage */
11895   start_recall_id = NULL;
11896 
11897   if(sound_scope >= 0){
11898     current_recall_id = ags_playback_get_recall_id(playback,
11899 						   sound_scope);
11900 
11901     if(current_recall_id == NULL){
11902       /* recycling context */
11903       recycling_context = ags_recycling_context_new(1);
11904       ags_audio_add_recycling_context(audio,
11905 				      (GObject *) recycling_context);
11906 
11907       /* set recycling */
11908       ags_recycling_context_replace(recycling_context,
11909 				    first_recycling,
11910 				    0);
11911 
11912       /* create audio recall id */
11913       audio_recall_id = g_object_new(AGS_TYPE_RECALL_ID,
11914 				     "recycling-context", recycling_context,
11915 				     NULL);
11916       ags_recall_id_set_sound_scope(audio_recall_id, sound_scope);
11917       ags_audio_add_recall_id(audio,
11918 			      (GObject *) audio_recall_id);
11919 
11920       g_object_set(recycling_context,
11921 		   "recall-id", audio_recall_id,
11922 		   NULL);
11923 
11924       /* create channel recall id */
11925       channel_recall_id = g_object_new(AGS_TYPE_RECALL_ID,
11926 				       "recycling-context", recycling_context,
11927 				       NULL);
11928       ags_recall_id_set_sound_scope(channel_recall_id, sound_scope);
11929       ags_channel_add_recall_id(channel,
11930 				(GObject *) channel_recall_id);
11931 
11932       /* prepend recall id */
11933       start_recall_id = g_list_prepend(start_recall_id,
11934 				       channel_recall_id);
11935 
11936       /* set playback's recall id */
11937       if(AGS_SOUND_SCOPE_PLAYBACK == sound_scope){
11938 //	ags_recall_id_set_state_flags(channel_recall_id, AGS_SOUND_STATE_IS_WAITING);
11939       }
11940 
11941       ags_playback_set_recall_id(playback,
11942 				 channel_recall_id,
11943 				 sound_scope);
11944     }else{
11945       start_recall_id = g_list_prepend(start_recall_id,
11946 				       current_recall_id);
11947     }
11948 
11949     /* run stage */
11950     ags_channel_recursive_run_stage(channel,
11951 				    sound_scope, staging_flags);
11952 
11953     /* add to start queue */
11954     audio_thread = NULL;
11955     channel_thread = NULL;
11956 
11957     start_wait_thread = NULL;
11958 
11959     if(AGS_SOUND_SCOPE_PLAYBACK != sound_scope){
11960       if(ags_playback_domain_test_flags(playback_domain, AGS_PLAYBACK_DOMAIN_SUPER_THREADED_AUDIO)){
11961 	audio_thread = ags_playback_domain_get_audio_thread(playback_domain,
11962 							    sound_scope);
11963 
11964 	if(audio_thread != NULL){
11965 	  start_wait_thread = g_list_prepend(start_wait_thread,
11966 					     audio_thread);
11967 
11968 #if 1
11969 	  ags_thread_add_start_queue(audio_loop,
11970 				     audio_thread);
11971 #else
11972 	  ags_thread_start(audio_thread);
11973 #endif
11974 	}
11975       }
11976 
11977       if(ags_playback_test_flags(playback, AGS_PLAYBACK_SUPER_THREADED_CHANNEL)){
11978 	channel_thread = ags_playback_get_channel_thread(playback,
11979 							 sound_scope);
11980 
11981 	if(channel_thread != NULL){
11982 	  start_wait_thread = g_list_prepend(start_wait_thread,
11983 					     channel_thread);
11984 
11985 #if 1
11986 	  ags_thread_add_start_queue(audio_loop,
11987 				     channel_thread);
11988 #else
11989 	  ags_thread_start(channel_thread);
11990 #endif
11991 	}
11992       }
11993     }
11994 
11995     /* unref */
11996 #if 0
11997     wait_thread = start_wait_thread;
11998 
11999     start_wait_timeout = g_get_monotonic_time() + 5 * G_USEC_PER_SEC;
12000 
12001     while(wait_thread != NULL){
12002       /* wait thread */
12003       g_mutex_lock(AGS_THREAD_GET_START_MUTEX(wait_thread->data));
12004 
12005       if(!ags_thread_test_status_flags(wait_thread->data, AGS_THREAD_STATUS_START_DONE)){
12006 	ags_thread_set_status_flags(wait_thread->data, AGS_THREAD_STATUS_START_WAIT);
12007 
12008 	while(ags_thread_test_status_flags(wait_thread->data, AGS_THREAD_STATUS_START_WAIT) &&
12009 	      !ags_thread_test_status_flags(wait_thread->data, AGS_THREAD_STATUS_START_DONE) &&
12010 	      g_get_monotonic_time() < start_wait_timeout){
12011 	  g_cond_wait_until(AGS_THREAD_GET_START_COND(wait_thread->data),
12012 			    AGS_THREAD_GET_START_MUTEX(wait_thread->data),
12013 			    start_wait_timeout);
12014 	}
12015       }
12016 
12017       g_mutex_unlock(AGS_THREAD_GET_START_MUTEX(wait_thread->data));
12018 
12019       if(g_get_monotonic_time() > start_wait_timeout){
12020 	g_critical("sync timeout");
12021 
12022 	goto ags_channel_real_start_ONE_SCOPE_TIMEOUT;
12023       }
12024 
12025       wait_thread = wait_thread->next;
12026     }
12027 #endif
12028 
12029   ags_channel_real_start_ONE_SCOPE_TIMEOUT:
12030     g_list_free_full(start_wait_thread,
12031 		     g_object_unref);
12032 
12033     start_wait_thread = NULL;
12034   }else{
12035     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
12036       current_recall_id = ags_playback_get_recall_id(playback,
12037 						     i);
12038 
12039       if(current_recall_id == NULL){
12040 	/* recycling context */
12041 	recycling_context = ags_recycling_context_new(1);
12042 	ags_audio_add_recycling_context(audio,
12043 					(GObject *) recycling_context);
12044 
12045 	/* set recycling */
12046 	ags_recycling_context_replace(recycling_context,
12047 				      first_recycling,
12048 				      0);
12049 
12050 	/* create audio recall id */
12051 	audio_recall_id = g_object_new(AGS_TYPE_RECALL_ID,
12052 				       "recycling-context", recycling_context,
12053 				       NULL);
12054 	ags_recall_id_set_sound_scope(audio_recall_id, i);
12055 	ags_audio_add_recall_id(audio,
12056 				(GObject *) audio_recall_id);
12057 
12058 	g_object_set(recycling_context,
12059 		     "recall-id", audio_recall_id,
12060 		     NULL);
12061 
12062 	/* create channel recall id */
12063 	channel_recall_id = g_object_new(AGS_TYPE_RECALL_ID,
12064 					 "recycling-context", recycling_context,
12065 					 NULL);
12066 	ags_recall_id_set_sound_scope(channel_recall_id, i);
12067 	ags_channel_add_recall_id(channel,
12068 				  (GObject *) channel_recall_id);
12069 
12070 	/* prepend recall id */
12071 	start_recall_id = g_list_prepend(start_recall_id,
12072 					 channel_recall_id);
12073 
12074 	/* set playback's recall id */
12075 	if(AGS_SOUND_SCOPE_PLAYBACK == i){
12076 //	  ags_recall_id_set_state_flags(channel_recall_id, AGS_SOUND_STATE_IS_WAITING);
12077 	}
12078 
12079 	ags_playback_set_recall_id(playback,
12080 				   channel_recall_id,
12081 				   i);
12082       }else{
12083 	start_recall_id = g_list_prepend(start_recall_id,
12084 					 current_recall_id);
12085       }
12086 
12087       /* run stage */
12088       ags_channel_recursive_run_stage(channel,
12089 				      i, staging_flags);
12090 
12091       /* add to start queue */
12092       audio_thread = NULL;
12093       channel_thread = NULL;
12094 
12095       start_wait_thread = NULL;
12096 
12097       if(AGS_SOUND_SCOPE_PLAYBACK != i){
12098 	if(ags_playback_domain_test_flags(playback_domain, AGS_PLAYBACK_DOMAIN_SUPER_THREADED_AUDIO)){
12099 	  audio_thread = ags_playback_domain_get_audio_thread(playback_domain,
12100 							      i);
12101 
12102 	  if(audio_thread != NULL){
12103 	    start_wait_thread = g_list_prepend(start_wait_thread,
12104 					       audio_thread);
12105 
12106 #if 1
12107 	    ags_thread_add_start_queue(audio_loop,
12108 				       audio_thread);
12109 #else
12110 	    ags_thread_start(audio_thread);
12111 #endif
12112 	  }
12113 	}
12114 
12115 	if(ags_playback_test_flags(playback, AGS_PLAYBACK_SUPER_THREADED_CHANNEL)){
12116 	  channel_thread = ags_playback_get_channel_thread(playback,
12117 							   i);
12118 
12119 	  if(channel_thread != NULL){
12120 	    start_wait_thread = g_list_prepend(start_wait_thread,
12121 					       channel_thread);
12122 
12123 #if 1
12124 	    ags_thread_add_start_queue(audio_loop,
12125 				       channel_thread);
12126 #else
12127 	    ags_thread_start(channel_thread);
12128 #endif
12129 	  }
12130 	}
12131       }
12132 
12133       /* unref */
12134 #if 0
12135       wait_thread = start_wait_thread;
12136 
12137       start_wait_timeout = g_get_monotonic_time() + 5 * G_USEC_PER_SEC;
12138 
12139       while(wait_thread != NULL){
12140 	/* wait thread */
12141 	g_mutex_lock(AGS_THREAD_GET_START_MUTEX(wait_thread->data));
12142 
12143 	if(!ags_thread_test_status_flags(wait_thread->data, AGS_THREAD_STATUS_START_DONE)){
12144 	  ags_thread_set_status_flags(wait_thread->data, AGS_THREAD_STATUS_START_WAIT);
12145 
12146 	  while(ags_thread_test_status_flags(wait_thread->data, AGS_THREAD_STATUS_START_WAIT) &&
12147 		!ags_thread_test_status_flags(wait_thread->data, AGS_THREAD_STATUS_START_DONE) &&
12148 		g_get_monotonic_time() < start_wait_timeout){
12149 	    g_cond_wait_until(AGS_THREAD_GET_START_COND(wait_thread->data),
12150 			      AGS_THREAD_GET_START_MUTEX(wait_thread->data),
12151 			      start_wait_timeout);
12152 	  }
12153 	}
12154 
12155 	g_mutex_unlock(AGS_THREAD_GET_START_MUTEX(wait_thread->data));
12156 
12157 	if(g_get_monotonic_time() > start_wait_timeout){
12158 	  g_critical("sync timeout");
12159 
12160 	  goto ags_channel_real_start_ALL_SCOPE_TIMEOUT;
12161 	}
12162 
12163 	wait_thread = wait_thread->next;
12164       }
12165 #endif
12166 
12167     ags_channel_real_start_ALL_SCOPE_TIMEOUT:
12168       g_list_free_full(start_wait_thread,
12169 		       g_object_unref);
12170 
12171       start_wait_thread = NULL;
12172     }
12173   }
12174 
12175   if(audio != NULL){
12176     g_object_unref(audio);
12177   }
12178 
12179   g_object_unref(playback_domain);
12180 
12181   g_object_unref(first_recycling);
12182   g_object_unref(playback);
12183 
12184   start_recall_id = g_list_reverse(start_recall_id);
12185 
12186   /* emit message */
12187   message_delivery = ags_message_delivery_get_instance();
12188 
12189   start_message_queue = ags_message_delivery_find_sender_namespace(message_delivery,
12190 								   "libags-audio");
12191 
12192   if(start_message_queue != NULL){
12193     AgsMessageEnvelope *message;
12194 
12195     xmlDoc *doc;
12196     xmlNode *root_node;
12197 
12198     /* specify message body */
12199     doc = xmlNewDoc("1.0");
12200 
12201     root_node = xmlNewNode(NULL,
12202 			   "ags-command");
12203     xmlDocSetRootElement(doc, root_node);
12204 
12205     xmlNewProp(root_node,
12206 	       "method",
12207 	       "AgsChannel::start");
12208 
12209     /* add message */
12210     message = ags_message_envelope_new((GObject *) channel,
12211 				       NULL,
12212 				       doc);
12213 
12214     /* set parameter */
12215     message->n_params = 2;
12216 
12217     message->parameter_name = (gchar **) malloc(3 * sizeof(gchar *));
12218     message->value = g_new0(GValue,
12219 			    2);
12220 
12221     /* sound scope */
12222     message->parameter_name[0] = "sound-scope";
12223     g_value_init(&(message->value[0]),
12224 		 G_TYPE_INT);
12225     g_value_set_int(&(message->value[0]),
12226 		    sound_scope);
12227 
12228     /* recall id */
12229     message->parameter_name[1] = "recall-id";
12230     g_value_init(&(message->value[1]),
12231 		 G_TYPE_POINTER);
12232     g_value_set_pointer(&(message->value[1]),
12233 			g_list_copy_deep(start_recall_id,
12234 					 (GCopyFunc) g_object_ref,
12235 					 NULL));
12236 
12237     /* terminate string vector */
12238     message->parameter_name[2] = NULL;
12239 
12240     /* add message */
12241     ags_message_delivery_add_message_envelope(message_delivery,
12242 					      "libags-audio",
12243 					      message);
12244 
12245     g_list_free_full(start_message_queue,
12246 		     (GDestroyNotify) g_object_unref);
12247   }
12248 
12249   return(start_recall_id);
12250 }
12251 
12252 /**
12253  * ags_channel_start:
12254  * @channel: the #AgsChannel
12255  * @sound_scope: the sound scope
12256  *
12257  * Start @channel's @sound_scope to do playback.
12258  *
12259  * Returns: (element-type AgsAudio.RecallID) (transfer full): the #GList-struct containing #AgsRecallID
12260  *
12261  * Since: 3.0.0
12262  */
12263 GList*
ags_channel_start(AgsChannel * channel,gint sound_scope)12264 ags_channel_start(AgsChannel *channel,
12265 		  gint sound_scope)
12266 {
12267   GList *recall_id;
12268 
12269   g_return_val_if_fail(AGS_IS_CHANNEL(channel), NULL);
12270 
12271   recall_id = NULL;
12272 
12273   g_object_ref((GObject *) channel);
12274   g_signal_emit(G_OBJECT(channel),
12275 		channel_signals[START], 0,
12276 		sound_scope,
12277 		&recall_id);
12278   g_object_unref((GObject *) channel);
12279 
12280   return(recall_id);
12281 }
12282 
12283 void
ags_channel_real_stop(AgsChannel * channel,GList * recall_id,gint sound_scope)12284 ags_channel_real_stop(AgsChannel *channel,
12285 		      GList *recall_id, gint sound_scope)
12286 {
12287   AgsPlaybackDomain *playback_domain;
12288   AgsPlayback *playback;
12289 
12290   AgsThread *audio_loop;
12291   AgsThread *audio_thread;
12292   AgsThread *channel_thread;
12293   AgsMessageDelivery *message_delivery;
12294 
12295   AgsApplicationContext *application_context;
12296 
12297   GList *list;
12298   GList *start_message_queue;
12299 
12300   gint i;
12301 
12302   static const guint staging_flags = (AGS_SOUND_STAGING_CANCEL |
12303 				      AGS_SOUND_STAGING_REMOVE);
12304 
12305   if(recall_id == NULL ||
12306      sound_scope >= AGS_SOUND_SCOPE_LAST){
12307     return;
12308   }
12309 
12310   list = recall_id;
12311 
12312   while(list != NULL){
12313     ags_recall_id_set_state_flags(list->data, AGS_SOUND_STATE_IS_TERMINATING);
12314 
12315     list = list->next;
12316   }
12317 
12318   application_context = ags_application_context_get_instance();
12319 
12320   audio_loop = ags_concurrency_provider_get_main_loop(AGS_CONCURRENCY_PROVIDER(application_context));
12321 
12322   /* get some fields */
12323   g_object_get(channel,
12324 	       "playback", &playback,
12325 	       NULL);
12326 
12327   g_object_get(playback,
12328 	       "playback-domain", &playback_domain,
12329 	       NULL);
12330 
12331   if(sound_scope >= 0){
12332     /* stop thread */
12333     audio_thread = ags_playback_domain_get_audio_thread(playback_domain,
12334 							sound_scope);
12335 
12336     channel_thread = ags_playback_get_channel_thread(playback,
12337 						     sound_scope);
12338 
12339     if(audio_thread != NULL){
12340       ags_thread_stop(audio_thread);
12341 
12342       g_object_unref(audio_thread);
12343     }
12344 
12345     if(channel_thread != NULL){
12346       ags_thread_stop(channel_thread);
12347 
12348       g_object_unref(channel_thread);
12349     }
12350 
12351     /* cancel */
12352     ags_channel_recursive_run_stage(channel,
12353 				    sound_scope, staging_flags);
12354 
12355     /* clean - fini */
12356     ags_channel_recursive_run_stage(channel,
12357 				    sound_scope, AGS_SOUND_STAGING_FINI);
12358 
12359     ags_playback_set_recall_id(playback,
12360 			       NULL,
12361 			       sound_scope);
12362   }else{
12363     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
12364       /* stop thread */
12365       audio_thread = ags_playback_domain_get_audio_thread(playback_domain,
12366 							  i);
12367 
12368       channel_thread = ags_playback_get_channel_thread(playback,
12369 						       i);
12370 
12371       if(audio_thread != NULL){
12372 	ags_thread_stop(audio_thread);
12373 
12374 	g_object_unref(audio_thread);
12375       }
12376 
12377       if(channel_thread != NULL){
12378 	ags_thread_stop(channel_thread);
12379 
12380 	g_object_unref(channel_thread);
12381       }
12382     }
12383 
12384     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
12385       /* cancel */
12386       ags_channel_recursive_run_stage(channel,
12387 				      i, staging_flags);
12388 
12389       /* clean - fini */
12390       ags_channel_recursive_run_stage(channel,
12391 				      i, AGS_SOUND_STAGING_FINI);
12392 
12393       ags_playback_set_recall_id(playback,
12394 				 NULL,
12395 				 i);
12396     }
12397   }
12398 
12399   /* remove channel from AgsAudioLoop */
12400   ags_audio_loop_remove_channel(audio_loop,
12401 				(GObject *) channel);
12402 
12403   /* emit message */
12404   message_delivery = ags_message_delivery_get_instance();
12405 
12406   start_message_queue = ags_message_delivery_find_sender_namespace(message_delivery,
12407 								   "libags-audio");
12408 
12409   if(start_message_queue != NULL){
12410     AgsMessageEnvelope *message;
12411 
12412     xmlDoc *doc;
12413     xmlNode *root_node;
12414 
12415     /* specify message body */
12416     doc = xmlNewDoc("1.0");
12417 
12418     root_node = xmlNewNode(NULL,
12419 			   "ags-command");
12420     xmlDocSetRootElement(doc, root_node);
12421 
12422     xmlNewProp(root_node,
12423 	       "method",
12424 	       "AgsChannel::stop");
12425 
12426     /* add message */
12427     message = ags_message_envelope_new((GObject *) channel,
12428 				       NULL,
12429 				       doc);
12430 
12431     /* set parameter */
12432     message->n_params = 2;
12433 
12434     message->parameter_name = (gchar **) malloc(3 * sizeof(gchar *));
12435     message->value = g_new0(GValue,
12436 			    2);
12437 
12438     /* recall id */
12439     message->parameter_name[0] = "recall-id";
12440     g_value_init(&(message->value[0]),
12441 		 G_TYPE_POINTER);
12442     g_value_set_pointer(&(message->value[0]),
12443 			recall_id);
12444 
12445     /* sound scope */
12446     message->parameter_name[1] = "sound-scope";
12447     g_value_init(&(message->value[1]),
12448 		 G_TYPE_INT);
12449     g_value_set_int(&(message->value[1]),
12450 		    sound_scope);
12451 
12452     /* terminate string vector */
12453     message->parameter_name[2] = NULL;
12454 
12455     /* add message */
12456     ags_message_delivery_add_message_envelope(message_delivery,
12457 					      "libags-audio",
12458 					      message);
12459 
12460     g_list_free_full(start_message_queue,
12461 		     (GDestroyNotify) g_object_unref);
12462   }
12463 }
12464 
12465 /**
12466  * ags_channel_stop:
12467  * @channel: the #AgsChannel
12468  * @recall_id: (element-type AgsAudio.RecallID) (transfer none): the #GList-struct containing #AgsRecallID
12469  * @sound_scope: the sound scope
12470  *
12471  * Stop @channel's @sound_scope playback specified by @recall_id.
12472  *
12473  * Since: 3.0.0
12474  */
12475 void
ags_channel_stop(AgsChannel * channel,GList * recall_id,gint sound_scope)12476 ags_channel_stop(AgsChannel *channel,
12477 		 GList *recall_id, gint sound_scope)
12478 {
12479   g_return_if_fail(AGS_IS_CHANNEL(channel));
12480 
12481   g_object_ref((GObject *) channel);
12482   g_signal_emit(G_OBJECT(channel),
12483 		channel_signals[STOP], 0,
12484 		recall_id, sound_scope);
12485   g_object_unref((GObject *) channel);
12486 }
12487 
12488 GList*
ags_channel_real_check_scope(AgsChannel * channel,gint sound_scope)12489 ags_channel_real_check_scope(AgsChannel *channel, gint sound_scope)
12490 {
12491   GList *list_start, *list;
12492   GList *recall_id;
12493 
12494   gint i;
12495 
12496   /* get recall id */
12497   g_object_get(channel,
12498 	       "recall-id", &list_start,
12499 	       NULL);
12500 
12501   /* iterate recall id */
12502   list = list_start;
12503 
12504   recall_id = NULL;
12505 
12506   if(sound_scope >= 0){
12507     while(list != NULL){
12508       /* check sound scope */
12509       if(ags_recall_id_check_sound_scope(list->data, sound_scope)){
12510 	recall_id = g_list_prepend(recall_id,
12511 				   list->data);
12512       }
12513 
12514       /* iterate */
12515       list = list->next;
12516     }
12517   }else{
12518     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
12519       list = list_start;
12520 
12521       while(list != NULL){
12522 	/* check sound scope */
12523 	if(ags_recall_id_check_sound_scope(list->data, i)){
12524 	  recall_id = g_list_prepend(recall_id,
12525 				     list->data);
12526 	}
12527 
12528 	/* iterate */
12529 	list = list->next;
12530       }
12531     }
12532   }
12533 
12534   /* reverse recall id */
12535   recall_id = g_list_reverse(recall_id);
12536 
12537   g_list_foreach(recall_id,
12538 		 (GFunc) g_object_ref,
12539 		 NULL);
12540 
12541   /* unref */
12542   g_list_free_full(list_start,
12543 		   g_object_unref);
12544 
12545   return(recall_id);
12546 }
12547 
12548 /**
12549  * ags_channel_check_scope:
12550  * @channel: the #AgsChannel
12551  * @sound_scope: the sound scope
12552  *
12553  * Check @channel's @sound_scope.
12554  *
12555  * Returns: (element-type AgsAudio.RecallID) (transfer full): the #GList-struct containing #AgsRecallID or %NULL if not playing
12556  *
12557  * Since: 3.0.0
12558  */
12559 GList*
ags_channel_check_scope(AgsChannel * channel,gint sound_scope)12560 ags_channel_check_scope(AgsChannel *channel, gint sound_scope)
12561 {
12562   GList *recall_id;
12563 
12564   g_return_val_if_fail(AGS_IS_CHANNEL(channel), NULL);
12565 
12566   recall_id = NULL;
12567 
12568   g_object_ref((GObject *) channel);
12569   g_signal_emit(G_OBJECT(channel),
12570 		channel_signals[CHECK_SCOPE], 0,
12571 		sound_scope,
12572 		&recall_id);
12573   g_object_unref((GObject *) channel);
12574 
12575   return(recall_id);
12576 }
12577 
12578 /**
12579  * ags_channel_collect_all_channel_ports:
12580  * @channel: the #AgsChannel
12581  *
12582  * Retrieve all ports of #AgsChannel.
12583  *
12584  * Returns: (element-type AgsAudio.Port) (transfer full): a new #GList containing #AgsPort
12585  *
12586  * Since: 3.0.0
12587  */
12588 GList*
ags_channel_collect_all_channel_ports(AgsChannel * channel)12589 ags_channel_collect_all_channel_ports(AgsChannel *channel)
12590 {
12591   GList *recall_start, *recall;
12592   GList *list;
12593 
12594   GRecMutex *recall_mutex, *play_mutex;
12595   GRecMutex *mutex;
12596 
12597   if(!AGS_IS_CHANNEL(channel)){
12598     return(NULL);
12599   }
12600 
12601   list = NULL;
12602 
12603   /* get play mutex */
12604   play_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
12605 
12606   /* collect port of playing recall */
12607   g_rec_mutex_lock(play_mutex);
12608 
12609   recall =
12610     recall_start = g_list_copy_deep(channel->play,
12611 				    (GCopyFunc) g_object_ref,
12612 				    NULL);
12613 
12614   g_rec_mutex_unlock(play_mutex);
12615 
12616   while(recall != NULL){
12617     AgsRecall *current;
12618 
12619     current = AGS_RECALL(recall->data);
12620 
12621     /* get mutex */
12622     mutex = AGS_RECALL_GET_OBJ_MUTEX(current);
12623 
12624     /* concat port */
12625     g_rec_mutex_lock(mutex);
12626 
12627     if(current->port != NULL){
12628       if(list == NULL){
12629 	list = g_list_copy_deep(current->port,
12630 				(GCopyFunc) g_object_ref,
12631 				NULL);
12632       }else{
12633 	if(current->port != NULL){
12634 	  list = g_list_concat(list,
12635 			       g_list_copy_deep(current->port,
12636 						(GCopyFunc) g_object_ref,
12637 						NULL));
12638 	}
12639       }
12640     }
12641 
12642     g_rec_mutex_unlock(mutex);
12643 
12644     /* iterate */
12645     recall = recall->next;
12646   }
12647 
12648   g_list_free_full(recall_start,
12649 		   g_object_unref);
12650 
12651   /* get recall mutex */
12652   recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
12653 
12654   /* the same for true recall */
12655   g_rec_mutex_lock(recall_mutex);
12656 
12657   recall =
12658     recall_start = g_list_copy_deep(channel->recall,
12659 				    (GCopyFunc) g_object_ref,
12660 				    NULL);
12661 
12662   g_rec_mutex_unlock(recall_mutex);
12663 
12664   while(recall != NULL){
12665     AgsRecall *current;
12666 
12667     current = AGS_RECALL(recall->data);
12668 
12669     /* get mutex */
12670     mutex = AGS_RECALL_GET_OBJ_MUTEX(current);
12671 
12672     /* concat port */
12673     g_rec_mutex_lock(mutex);
12674 
12675     if(current->port != NULL){
12676       if(list == NULL){
12677 	list = g_list_copy_deep(current->port,
12678 				(GCopyFunc) g_object_ref,
12679 				NULL);
12680       }else{
12681 	if(current->port != NULL){
12682 	  list = g_list_concat(list,
12683 			       g_list_copy_deep(current->port,
12684 						(GCopyFunc) g_object_ref,
12685 						NULL));
12686 	}
12687       }
12688     }
12689 
12690     g_rec_mutex_unlock(mutex);
12691 
12692     /* iterate */
12693     recall = recall->next;
12694   }
12695 
12696   g_list_free_full(recall_start,
12697 		   g_object_unref);
12698 
12699   /*  */
12700   list = g_list_reverse(list);
12701 
12702   return(list);
12703 }
12704 
12705 /**
12706  * ags_channel_collect_all_channel_ports_by_specifier_and_context:
12707  * @channel: an #AgsChannel
12708  * @specifier: the port's name
12709  * @play_context: either %TRUE for play or %FALSE for recall
12710  *
12711  * Retrieve specified port of #AgsChannel
12712  *
12713  * Returns: (element-type AgsAudio.Port) (transfer full): a #GList-struct of #AgsPort if found, otherwise %NULL
12714  *
12715  * Since: 3.0.0
12716  */
12717 GList*
ags_channel_collect_all_channel_ports_by_specifier_and_context(AgsChannel * channel,gchar * specifier,gboolean play_context)12718 ags_channel_collect_all_channel_ports_by_specifier_and_context(AgsChannel *channel,
12719 							       gchar *specifier,
12720 							       gboolean play_context)
12721 {
12722   GList *recall_start, *recall;
12723   GList *port_start, *port;
12724   GList *list;
12725 
12726   GRecMutex *recall_mutex;
12727 
12728   if(!AGS_IS_CHANNEL(channel)){
12729     return(NULL);
12730   }
12731 
12732   if(play_context){
12733     /* get play mutex */
12734     recall_mutex = AGS_CHANNEL_GET_PLAY_MUTEX(channel);
12735 
12736     /* get recall */
12737     g_rec_mutex_lock(recall_mutex);
12738 
12739     recall =
12740       recall_start = g_list_copy_deep(channel->play,
12741 				      (GCopyFunc) g_object_ref,
12742 				      NULL);
12743 
12744     g_rec_mutex_unlock(recall_mutex);
12745   }else{
12746     /* get recall mutex */
12747     recall_mutex = AGS_CHANNEL_GET_RECALL_MUTEX(channel);
12748 
12749     /* get recall */
12750     g_rec_mutex_lock(recall_mutex);
12751 
12752     recall =
12753       recall_start = g_list_copy_deep(channel->recall,
12754 				      (GCopyFunc) g_object_ref,
12755 				      NULL);
12756 
12757     g_rec_mutex_unlock(recall_mutex);
12758   }
12759 
12760   /* collect port of playing recall */
12761   list = NULL;
12762 
12763   while(recall != NULL){
12764     AgsRecall *current;
12765 
12766     GRecMutex *mutex;
12767 
12768     current = AGS_RECALL(recall->data);
12769 
12770     /* get mutex */
12771     mutex = AGS_RECALL_GET_OBJ_MUTEX(current);
12772 
12773     /* get port */
12774     g_rec_mutex_lock(mutex);
12775 
12776     port =
12777       port_start = g_list_copy_deep(current->port,
12778 				    (GCopyFunc) g_object_ref,
12779 				    NULL);
12780 
12781     g_rec_mutex_unlock(mutex);
12782 
12783     /* check specifier */
12784     while((port = ags_port_find_specifier(port, specifier)) != NULL){
12785       AgsPort *current;
12786 
12787       current = AGS_PORT(port->data);
12788 
12789       g_object_ref(current);
12790       list = g_list_prepend(list,
12791 			    current);
12792 
12793       /* iterate - port */
12794       port = port->next;
12795     }
12796 
12797     g_list_free_full(port_start,
12798 		     g_object_unref);
12799 
12800     /* iterate - recall */
12801     recall = recall->next;
12802   }
12803 
12804   g_list_free_full(recall_start,
12805 		   g_object_unref);
12806 
12807   /* reverse result */
12808   list = g_list_reverse(list);
12809 
12810   return(list);
12811 }
12812 
12813 /**
12814  * ags_channel_get_level:
12815  * @channel: the #AgsChannel
12816  *
12817  * Get level.
12818  *
12819  * Returns: (transfer full): the level of @channel as #AgsChannel or %NULL if no parent recycling.
12820  *
12821  * Since: 3.0.0
12822  */
12823 AgsChannel*
ags_channel_get_level(AgsChannel * channel)12824 ags_channel_get_level(AgsChannel *channel)
12825 {
12826   AgsAudio *audio;
12827   AgsChannel *start_output, *nth_output;
12828   AgsChannel *level, *next_level;
12829 
12830   guint audio_channel;
12831   guint input_line;
12832 
12833   /* check above recycling */
12834   level = channel;
12835 
12836   if(level != NULL){
12837     g_object_ref(level);
12838   }
12839 
12840   audio = NULL;
12841 
12842   if(AGS_IS_OUTPUT(channel)){
12843     goto ags_channel_get_level_ITERATE;
12844   }
12845 
12846   while(level != NULL){
12847     /* get some fields */
12848     g_object_get(level,
12849 		 "audio", &audio,
12850 		 "audio-channel", &audio_channel,
12851 		 "line", &input_line,
12852 		 NULL);
12853 
12854     if(ags_audio_test_flags(audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING)){
12855       if(audio != NULL){
12856 	g_object_unref(audio);
12857       }
12858 
12859       break;
12860     }
12861 
12862     /* get some fields */
12863     g_object_get(audio,
12864 		 "output", &start_output,
12865 		 NULL);
12866 
12867     if(ags_audio_test_flags(audio, AGS_AUDIO_ASYNC)){
12868       nth_output = ags_channel_nth(start_output,
12869 				   audio_channel);
12870 
12871       if(level != NULL){
12872 	g_object_unref(level);
12873       }
12874 
12875       level = nth_output;
12876     }else{
12877       nth_output = ags_channel_nth(start_output,
12878 				   input_line);
12879 
12880       if(level != NULL){
12881 	g_object_unref(level);
12882       }
12883 
12884       level = nth_output;
12885     }
12886 
12887     if(audio != NULL){
12888       g_object_unref(audio);
12889     }
12890 
12891     if(level == NULL){
12892       break;
12893     }
12894 
12895   ags_channel_get_level_ITERATE:
12896 
12897     /* iterate */
12898     next_level = ags_channel_get_link(level);
12899 
12900     g_object_unref(level);
12901 
12902     level = next_level;
12903   }
12904 
12905   return(level);
12906 }
12907 
12908 void
ags_channel_recursive_set_property_setv(AgsChannel * channel,gint n_params,gchar ** parameter_name,GValue * value)12909 ags_channel_recursive_set_property_setv(AgsChannel *channel,
12910 					gint n_params,
12911 					gchar **parameter_name, GValue *value)
12912 {
12913 #if HAVE_GLIB_2_54
12914   g_object_setv((GObject *) channel,
12915 		n_params,
12916 		parameter_name, value);
12917 #else
12918   guint i;
12919 
12920   for(i = 0; i < n_params; i++){
12921     g_object_set_property((GObject *) channel,
12922 			  parameter_name[i], &(value[i]));
12923   }
12924 #endif
12925 }
12926 
12927 void
ags_channel_recursive_set_property_down(AgsChannel * channel,gint n_params,gchar ** parameter_name,GValue * value)12928 ags_channel_recursive_set_property_down(AgsChannel *channel,
12929 					gint n_params,
12930 					gchar **parameter_name, GValue *value)
12931 {
12932   if(channel == NULL){
12933     return;
12934   }
12935 
12936   ags_channel_recursive_set_property_setv(channel,
12937 					  n_params,
12938 					  parameter_name, value);
12939 
12940   ags_channel_recursive_set_property_down_input(channel,
12941 						n_params,
12942 						parameter_name, value);
12943 }
12944 
12945 void
ags_channel_recursive_set_property_down_input(AgsChannel * channel,gint n_params,gchar ** parameter_name,GValue * value)12946 ags_channel_recursive_set_property_down_input(AgsChannel *channel,
12947 					      gint n_params,
12948 					      gchar **parameter_name, GValue *value)
12949 {
12950   AgsAudio *audio;
12951   AgsChannel *start_input;
12952   AgsChannel *input, *next_pad, *nth_input;
12953   AgsChannel *link;
12954 
12955   guint audio_channel, line;
12956 
12957   if(channel == NULL){
12958     return;
12959   }
12960 
12961   /* get some fields */
12962   g_object_get(channel,
12963 	       "audio", &audio,
12964 	       "audio-channel", &audio_channel,
12965 	       "line", &line,
12966 	       NULL);
12967 
12968   if(audio == NULL){
12969     return;
12970   }
12971 
12972   /* get some fields */
12973   g_object_get(audio,
12974 	       "input", &start_input,
12975 	       NULL);
12976 
12977   /* sync/async */
12978   if(ags_audio_test_flags(audio, AGS_AUDIO_ASYNC)){
12979     nth_input = ags_channel_nth(start_input,
12980 				audio_channel);
12981 
12982     input = nth_input;
12983 
12984     next_pad = NULL;
12985 
12986     while(input != NULL){
12987       /* get some fields */
12988       link = ags_channel_get_link(input);
12989 
12990       /* set property */
12991       ags_channel_recursive_set_property_setv(input,
12992 					      n_params,
12993 					      parameter_name, value);
12994 
12995       ags_channel_recursive_set_property_down(link,
12996 					      n_params,
12997 					      parameter_name, value);
12998 
12999       /* unref */
13000       if(link != NULL){
13001 	g_object_unref(link);
13002       }
13003 
13004       /* iterate */
13005       next_pad = ags_channel_next_pad(input);
13006 
13007       g_object_unref(input);
13008 
13009       input = next_pad;
13010     }
13011 
13012     if(next_pad != NULL){
13013       g_object_unref(next_pad);
13014     }
13015   }else{
13016     nth_input = ags_channel_nth(start_input,
13017 				line);
13018 
13019     input = nth_input;
13020 
13021     /* get some fields */
13022     link = ags_channel_get_link(input);
13023 
13024     /* set property */
13025     ags_channel_recursive_set_property_setv(input,
13026 					    n_params,
13027 					    parameter_name, value);
13028 
13029     ags_channel_recursive_set_property_down(link,
13030 					    n_params,
13031 					    parameter_name, value);
13032 
13033     /* unref */
13034     if(link != NULL){
13035       g_object_unref(link);
13036     }
13037 
13038     if(input != NULL){
13039       g_object_unref(input);
13040     }
13041   }
13042 
13043   if(audio != NULL){
13044     g_object_unref(audio);
13045   }
13046 
13047   if(start_input != NULL){
13048     g_object_unref(start_input);
13049   }
13050 }
13051 
13052 /**
13053  * ags_channel_recursive_set_property:
13054  * @channel: the #AgsChannel
13055  * @n_params: the count of paramter name and value pairs
13056  * @parameter_name: a string vector containing parameter names
13057  * @value: the value array
13058  *
13059  * Recursive set property for #AgsChannel.
13060  *
13061  * Since: 3.0.0
13062  */
13063 void
ags_channel_recursive_set_property(AgsChannel * channel,gint n_params,gchar ** parameter_name,GValue * value)13064 ags_channel_recursive_set_property(AgsChannel *channel,
13065 				   gint n_params,
13066 				   gchar **parameter_name, GValue *value)
13067 {
13068   AgsChannel *link;
13069 
13070   if(!AGS_IS_CHANNEL(channel)){
13071     return;
13072   }
13073 
13074   /* get some fields */
13075   link = ags_channel_get_link(channel);
13076 
13077   if(AGS_IS_INPUT(channel)){
13078     ags_channel_recursive_set_property_setv(channel,
13079 					    n_params,
13080 					    parameter_name, value);
13081 
13082     ags_channel_recursive_set_property_down(link,
13083 					    n_params,
13084 					    parameter_name, value);
13085   }else{
13086     ags_channel_recursive_set_property_down(channel,
13087 					    n_params,
13088 					    parameter_name, value);
13089   }
13090 
13091   if(link != NULL){
13092     g_object_unref(link);
13093   }
13094 }
13095 
13096 void
ags_channel_recursive_setup_run_stage_up(AgsChannel * channel,AgsRecyclingContext * recycling_context,gint sound_scope,guint local_staging_flags)13097 ags_channel_recursive_setup_run_stage_up(AgsChannel *channel,
13098 					 AgsRecyclingContext *recycling_context,
13099 					 gint sound_scope, guint local_staging_flags)
13100 {
13101   AgsAudio *current_audio;
13102   AgsChannel *current_channel, *nth_channel;
13103   AgsChannel *current_link;
13104   AgsRecallID *current_recall_id;
13105 
13106   GList *start_recall_id, *recall_id;
13107 
13108   guint pad, audio_channel;
13109   guint line;
13110 
13111   if(!AGS_IS_CHANNEL(channel) ||
13112      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
13113     return;
13114   }
13115 
13116   current_audio = NULL;
13117 
13118   current_channel = channel;
13119 
13120   if(current_channel != NULL){
13121     g_object_ref(current_channel);
13122   }
13123 
13124   current_link = NULL;
13125 
13126   if(AGS_IS_OUTPUT(channel)){
13127     g_object_get(channel,
13128 		 "audio", &current_audio,
13129 		 NULL);
13130 
13131     goto ags_channel_recursive_setup_run_stage_up_OUTPUT;
13132   }
13133 
13134   while(current_channel != NULL){
13135     /* check scope - input */
13136     recall_id =
13137       start_recall_id = ags_channel_check_scope(current_channel, sound_scope);
13138 
13139     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
13140 							     recycling_context);
13141 
13142     if(current_recall_id == NULL){
13143       current_recall_id = g_object_new(AGS_TYPE_RECALL_ID,
13144 				       "recycling-context", recycling_context,
13145 				       NULL);
13146       ags_recall_id_set_sound_scope(current_recall_id, sound_scope);
13147 
13148       ags_channel_add_recall_id(current_channel,
13149 				current_recall_id);
13150     }
13151 
13152     /* free recall id */
13153     g_list_free_full(start_recall_id,
13154 		     g_object_unref);
13155 
13156     /* get current audio */
13157     current_audio = NULL;
13158 
13159     g_object_get(current_channel,
13160 		 "audio", &current_audio,
13161 		 NULL);
13162 
13163     /* check scope - audio */
13164     recall_id =
13165       start_recall_id = ags_audio_check_scope(current_audio, sound_scope);
13166 
13167     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
13168 							     recycling_context);
13169 
13170     if(current_recall_id == NULL){
13171       current_recall_id = g_object_new(AGS_TYPE_RECALL_ID,
13172 				       "recycling-context", recycling_context,
13173 				       NULL);
13174       ags_recall_id_set_sound_scope(current_recall_id, sound_scope);
13175 
13176       ags_audio_add_recall_id(current_audio,
13177 			      (GObject *) current_recall_id);
13178     }
13179 
13180     /* free recall id */
13181     g_list_free_full(start_recall_id,
13182 		     g_object_unref);
13183 
13184     /* get some fields */
13185     audio_channel = 0;
13186     line = 0;
13187 
13188     g_object_get(current_channel,
13189 		 "audio-channel", &audio_channel,
13190 		 "line", &line,
13191 		 NULL);
13192 
13193     /* move up */
13194     if(current_channel != NULL){
13195       g_object_unref(current_channel);
13196     }
13197 
13198     current_channel = NULL;
13199 
13200     g_object_get(current_audio,
13201 		 "output", &current_channel,
13202 		 NULL);
13203 
13204     if(ags_audio_test_flags(current_audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING)){
13205       /* unref current audio */
13206       if(current_audio != NULL){
13207 	g_object_unref(current_audio);
13208       }
13209 
13210       if(current_channel != NULL){
13211 	g_object_unref(current_channel);
13212       }
13213 
13214       break;
13215     }
13216 
13217     if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
13218       nth_channel = ags_channel_nth(current_channel,
13219 				    audio_channel);
13220 
13221       g_object_unref(current_channel);
13222 
13223       current_channel = nth_channel;
13224     }else{
13225       nth_channel = ags_channel_nth(current_channel,
13226 				    line);
13227 
13228       g_object_unref(current_channel);
13229 
13230       current_channel = nth_channel;
13231     }
13232 
13233   ags_channel_recursive_setup_run_stage_up_OUTPUT:
13234 
13235     /* check scope - output */
13236     recall_id =
13237       start_recall_id = ags_channel_check_scope(current_channel, sound_scope);
13238 
13239     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
13240 							     recycling_context);
13241 
13242     if(current_recall_id == NULL){
13243       current_recall_id = g_object_new(AGS_TYPE_RECALL_ID,
13244 				       "recycling-context", recycling_context,
13245 				       NULL);
13246       ags_recall_id_set_sound_scope(current_recall_id, sound_scope);
13247 
13248       ags_channel_add_recall_id(current_channel,
13249 				current_recall_id);
13250     }
13251 
13252     /* free recall id */
13253     g_list_free_full(start_recall_id,
13254 		     g_object_unref);
13255 
13256     /* unref current audio */
13257     if(current_audio != NULL){
13258       g_object_unref(current_audio);
13259     }
13260 
13261     /* iterate */
13262     current_link = ags_channel_get_link(current_channel);
13263 
13264     g_object_unref(current_channel);
13265 
13266     current_channel = current_link;
13267   }
13268 
13269   if(current_channel != NULL){
13270     g_object_unref(current_channel);
13271   }
13272 }
13273 
13274 void
ags_channel_recursive_setup_run_stage_down(AgsChannel * channel,AgsRecyclingContext * recycling_context,gint sound_scope,guint local_staging_flags)13275 ags_channel_recursive_setup_run_stage_down(AgsChannel *channel,
13276 					   AgsRecyclingContext *recycling_context,
13277 					   gint sound_scope, guint local_staging_flags)
13278 {
13279   AgsAudio *current_audio;
13280   AgsChannel *start_input;
13281   AgsChannel *current_input, *next_pad, *next_channel, *nth_input;
13282   AgsRecallID *current_recall_id, *next_recall_id;
13283   AgsRecyclingContext *next_recycling_context;
13284 
13285   GList *start_recall_id, *recall_id;
13286 
13287   guint audio_channel, line;
13288   gboolean play_context;
13289 
13290   static const guint staging_mask = (AGS_SOUND_STAGING_CHECK_RT_DATA |
13291 				     AGS_SOUND_STAGING_RUN_INIT_PRE |
13292 				     AGS_SOUND_STAGING_RUN_INIT_INTER |
13293 				     AGS_SOUND_STAGING_RUN_INIT_POST);
13294 
13295   if(!AGS_IS_CHANNEL(channel) ||
13296      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
13297     return;
13298   }
13299 
13300   /* setup */
13301   next_recycling_context = recycling_context;
13302 
13303   /* check scope - output */
13304   recall_id =
13305     start_recall_id = ags_channel_check_scope(channel, sound_scope);
13306 
13307   current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
13308 							   recycling_context);
13309 
13310   if(current_recall_id == NULL){
13311     current_recall_id = g_object_new(AGS_TYPE_RECALL_ID,
13312 				     "recycling-context", recycling_context,
13313 				     NULL);
13314     ags_recall_id_set_sound_scope(current_recall_id, sound_scope);
13315 
13316     ags_channel_add_recall_id(channel,
13317 			      current_recall_id);
13318   }
13319 
13320   /* free recall id */
13321   g_list_free_full(start_recall_id,
13322 		   g_object_unref);
13323 
13324   /* get current audio */
13325   current_audio = NULL;
13326 
13327   audio_channel = 0;
13328   line = 0;
13329 
13330   g_object_get(channel,
13331 	       "audio", &current_audio,
13332 	       "audio-channel", &audio_channel,
13333 	       "line", &line,
13334 	       NULL);
13335 
13336   /* check scope - audio */
13337   recall_id =
13338     start_recall_id = ags_audio_check_scope(current_audio, sound_scope);
13339 
13340   current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
13341 							   recycling_context);
13342 
13343   if(current_recall_id == NULL){
13344     current_recall_id = g_object_new(AGS_TYPE_RECALL_ID,
13345 				     "recycling-context", recycling_context,
13346 				     NULL);
13347     ags_recall_id_set_sound_scope(current_recall_id, sound_scope);
13348 
13349     ags_audio_add_recall_id(current_audio,
13350 			    (GObject *) current_recall_id);
13351   }
13352 
13353   g_list_free_full(start_recall_id,
13354 		   g_object_unref);
13355 
13356   /* get some fields */
13357   start_input = NULL;
13358 
13359   g_object_get(current_audio,
13360 	       "input", &start_input,
13361 	       NULL);
13362 
13363   /* check next recycling context */
13364   current_input = NULL;
13365 
13366   if(ags_audio_test_flags(current_audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING)){
13367     AgsRecycling *first_recycling;
13368     AgsRecycling *recycling;
13369 
13370     gint position;
13371 
13372     next_recycling_context = NULL;
13373 
13374     if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
13375       AgsChannel *first_with_recycling;
13376 
13377       nth_input = ags_channel_nth(start_input,
13378 				  audio_channel);
13379 
13380       current_input = nth_input;
13381 
13382       first_with_recycling = ags_channel_first_with_recycling(current_input);
13383 
13384       first_recycling = NULL;
13385 
13386       g_object_get(first_with_recycling,
13387 		   "first-recycling", &first_recycling,
13388 		   NULL);
13389 
13390       g_object_unref(first_with_recycling);
13391 
13392       if(current_input != NULL){
13393 	g_object_unref(current_input);
13394       }
13395     }else{
13396       nth_input = ags_channel_nth(start_input,
13397 				  line);
13398 
13399       current_input = nth_input;
13400 
13401       first_recycling = NULL;
13402 
13403       g_object_get(current_input,
13404 		   "first-recycling", &first_recycling,
13405 		   NULL);
13406 
13407       if(current_input != NULL){
13408 	g_object_unref(current_input);
13409       }
13410     }
13411 
13412     if(first_recycling != NULL){
13413       position = ags_recycling_context_find_child(recycling_context,
13414 						  first_recycling);
13415 
13416       if(position >= 0){
13417 	GList *child_start;
13418 
13419 	child_start = NULL;
13420 
13421 	g_object_get(recycling_context,
13422 		     "child", &child_start,
13423 		     NULL);
13424 
13425 	next_recycling_context = g_list_nth_data(child_start, position);
13426 	g_list_free_full(child_start,
13427 			 g_object_unref);
13428       }
13429 
13430       g_object_unref(first_recycling);
13431     }
13432   }
13433 
13434   if(next_recycling_context == NULL){
13435     AgsRecycling *first_recycling, *last_recycling;
13436     AgsRecycling *end_region;
13437     AgsRecycling *recycling, *next_recycling;
13438 
13439     guint64 length;
13440     guint64 i;
13441 
13442     current_input = NULL;
13443 
13444     length = 0;
13445 
13446     if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
13447       nth_input = ags_channel_nth(start_input,
13448 				  audio_channel);
13449 
13450       current_input = nth_input;
13451 
13452       if(current_input != NULL){
13453 	g_object_ref(current_input);
13454       }
13455 
13456       next_pad = NULL;
13457 
13458       while(current_input != NULL){
13459 	gint position;
13460 
13461 	first_recycling = NULL;
13462 	last_recycling = NULL;
13463 
13464 	g_object_get(current_input,
13465 		     "first-recycling", &first_recycling,
13466 		     "last-recycling", &last_recycling,
13467 		     NULL);
13468 
13469 	end_region = ags_recycling_next(last_recycling);
13470 
13471 	position = ags_recycling_position(first_recycling, end_region,
13472 					  last_recycling);
13473 	length += (position + 1);
13474 
13475 	/* unref */
13476 	if(first_recycling != NULL){
13477 	  g_object_unref(first_recycling);
13478 	  g_object_unref(last_recycling);
13479 	}
13480 
13481 	if(end_region != NULL){
13482 	  g_object_unref(end_region);
13483 	}
13484 
13485 	/* iterate */
13486 	next_pad = ags_channel_next_pad(current_input);
13487 
13488 	g_object_unref(current_input);
13489 
13490 	current_input = next_pad;
13491       }
13492 
13493       if(next_pad != NULL){
13494 	g_object_unref(next_pad);
13495       }
13496     }else{
13497       nth_input = ags_channel_nth(start_input,
13498 				  line);
13499 
13500       current_input = nth_input;
13501 
13502       if(current_input != NULL){
13503 	g_object_ref(current_input);
13504       }
13505 
13506       next_pad = NULL;
13507 
13508       first_recycling = NULL;
13509       last_recycling = NULL;
13510 
13511       g_object_get(current_input,
13512 		   "first-recycling", &first_recycling,
13513 		   "last-recycling", &last_recycling,
13514 		   NULL);
13515 
13516       if(first_recycling != NULL){
13517 	end_region = ags_recycling_next(last_recycling);
13518 
13519 	length = ags_recycling_position(first_recycling, end_region,
13520 					last_recycling);
13521 	length++;
13522 
13523 	g_object_unref(first_recycling);
13524 	g_object_unref(last_recycling);
13525 
13526 	if(end_region != NULL){
13527 	  g_object_unref(end_region);
13528 	}
13529       }else{
13530 	length = 0;
13531       }
13532 
13533       if(current_input != NULL){
13534 	g_object_unref(current_input);
13535       }
13536     }
13537 
13538     /* instantiate next recycling context */
13539     if(length > 0){
13540       next_recycling_context = ags_recycling_context_new(length);
13541       g_object_set(recycling_context,
13542 		   "child", next_recycling_context,
13543 		   NULL);
13544 
13545       ags_audio_add_recycling_context(current_audio,
13546 				      (GObject *) next_recycling_context);
13547 
13548       current_input = nth_input;
13549 
13550       for(i = 0; i < length;){
13551 	first_recycling = NULL;
13552 
13553 	g_object_get(current_input,
13554 		     "first-recycling", &first_recycling,
13555 		     NULL);
13556 
13557 	recycling = first_recycling;
13558 	g_object_ref(recycling);
13559 
13560 	next_recycling = NULL;
13561 
13562 	for(; i < length && recycling != NULL; i++){
13563 	  /* set recycling */
13564 	  ags_recycling_context_replace(next_recycling_context,
13565 					recycling,
13566 					i);
13567 
13568 	  /* iterate */
13569 	  i++;
13570 
13571 	  next_recycling = ags_recycling_next(recycling);
13572 
13573 	  g_object_unref(recycling);
13574 
13575 	  recycling = next_recycling;
13576 	}
13577 
13578 	/* unref */
13579 	if(first_recycling != NULL){
13580 	  g_object_unref(first_recycling);
13581 	}
13582 
13583 	if(next_recycling != NULL){
13584 	  g_object_unref(next_recycling);
13585 	}
13586 
13587 	/* iterate */
13588 	next_pad = ags_channel_next_pad(current_input);
13589 
13590 	g_object_unref(current_input);
13591 
13592 	current_input = next_pad;
13593       }
13594 
13595       if(next_pad != NULL){
13596 	g_object_unref(next_pad);
13597       }
13598     }
13599   }
13600 
13601   if(next_recycling_context != NULL &&
13602      next_recycling_context != recycling_context){
13603     /* check scope - audio */
13604     recall_id =
13605       start_recall_id = ags_audio_check_scope(current_audio, sound_scope);
13606 
13607     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
13608 							     next_recycling_context);
13609 
13610     if(current_recall_id == NULL){
13611       current_recall_id = g_object_new(AGS_TYPE_RECALL_ID,
13612 				       "recycling-context", next_recycling_context,
13613 				       NULL);
13614       ags_recall_id_set_sound_scope(current_recall_id, sound_scope);
13615 
13616       ags_audio_add_recall_id(current_audio,
13617 			      (GObject *) current_recall_id);
13618     }
13619 
13620     /* free recall id */
13621     g_list_free_full(start_recall_id,
13622 		     g_object_unref);
13623   }
13624 
13625   ags_channel_recursive_setup_run_stage_down_input(channel,
13626 						   next_recycling_context,
13627 						   sound_scope, local_staging_flags);
13628 
13629   /* unref */
13630   if(current_audio != NULL){
13631     g_object_unref(current_audio);
13632   }
13633 
13634   if(start_input != NULL){
13635     g_object_unref(start_input);
13636   }
13637 }
13638 
13639 void
ags_channel_recursive_setup_run_stage_down_input(AgsChannel * channel,AgsRecyclingContext * recycling_context,gint sound_scope,guint local_staging_flags)13640 ags_channel_recursive_setup_run_stage_down_input(AgsChannel *channel,
13641 						 AgsRecyclingContext *recycling_context,
13642 						 gint sound_scope, guint local_staging_flags)
13643 {
13644   AgsAudio *current_audio;
13645   AgsChannel *start_input;
13646   AgsChannel *current_input, *next_pad, *nth_input;
13647   AgsChannel *current_link;
13648   AgsRecallID *current_recall_id;
13649 
13650   GList *start_recall_id, *recall_id;
13651 
13652   guint audio_channel, line;
13653 
13654   static const guint staging_mask = (AGS_SOUND_STAGING_CHECK_RT_DATA |
13655 				     AGS_SOUND_STAGING_RUN_INIT_PRE |
13656 				     AGS_SOUND_STAGING_RUN_INIT_INTER |
13657 				     AGS_SOUND_STAGING_RUN_INIT_POST);
13658 
13659   if(!AGS_IS_CHANNEL(channel) ||
13660      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
13661     return;
13662   }
13663 
13664   /* get some fields */
13665   current_audio = NULL;
13666 
13667   audio_channel = 0;
13668   line = 0;
13669 
13670   g_object_get(channel,
13671 	       "audio", &current_audio,
13672 	       "line", &line,
13673 	       "audio-channel", &audio_channel,
13674 	       NULL);
13675 
13676   if(current_audio == NULL){
13677     return;
13678   }
13679 
13680   /* get some fields */
13681   start_input = NULL;
13682 
13683   g_object_get(current_audio,
13684 	       "input", &start_input,
13685 	       NULL);
13686 
13687   /* sync/async */
13688   if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
13689     nth_input = ags_channel_nth(start_input,
13690 				audio_channel);
13691 
13692     current_input = nth_input;
13693 
13694     next_pad = NULL;
13695 
13696     while(current_input != NULL){
13697       /* get some fields */
13698       current_link = ags_channel_get_link(current_input);
13699 
13700       /* check scope - input */
13701       recall_id =
13702 	start_recall_id = ags_channel_check_scope(current_input, sound_scope);
13703 
13704       current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
13705 							       recycling_context);
13706 
13707       if(current_recall_id == NULL){
13708 	current_recall_id = g_object_new(AGS_TYPE_RECALL_ID,
13709 					 "recycling-context", recycling_context,
13710 					 NULL);
13711 	ags_recall_id_set_sound_scope(current_recall_id, sound_scope);
13712 
13713 	ags_channel_add_recall_id(current_input,
13714 				  current_recall_id);
13715       }
13716 
13717       /* free recall id */
13718       g_list_free_full(start_recall_id,
13719 		       g_object_unref);
13720 
13721       /* traverse the tree */
13722       ags_channel_recursive_setup_run_stage_down(current_link,
13723 						 recycling_context,
13724 						 sound_scope, local_staging_flags);
13725 
13726       if(current_link != NULL){
13727 	g_object_unref(current_link);
13728       }
13729 
13730       /* iterate */
13731       next_pad = ags_channel_next_pad(current_input);
13732 
13733       g_object_unref(current_input);
13734 
13735       current_input = next_pad;
13736     }
13737 
13738     if(next_pad != NULL){
13739       g_object_unref(next_pad);
13740     }
13741   }else{
13742     nth_input = ags_channel_nth(start_input,
13743 				line);
13744 
13745     current_input = nth_input;
13746 
13747     /* get some fields */
13748     current_link = ags_channel_get_link(current_input);
13749 
13750     /* check scope - input */
13751     recall_id =
13752       start_recall_id = ags_channel_check_scope(current_input, sound_scope);
13753 
13754     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
13755 							     recycling_context);
13756 
13757     if(current_recall_id == NULL){
13758       current_recall_id = g_object_new(AGS_TYPE_RECALL_ID,
13759 				       "recycling-context", recycling_context,
13760 				       NULL);
13761       ags_recall_id_set_sound_scope(current_recall_id, sound_scope);
13762 
13763       ags_channel_add_recall_id(current_input,
13764 				current_recall_id);
13765     }
13766 
13767     /* free recall id */
13768     g_list_free_full(start_recall_id,
13769 		     g_object_unref);
13770 
13771     /* traverse the tree */
13772     ags_channel_recursive_setup_run_stage_down(current_link,
13773 					       recycling_context,
13774 					       sound_scope, local_staging_flags);
13775 
13776     if(current_link != NULL){
13777       g_object_unref(current_link);
13778     }
13779 
13780     if(current_input != NULL){
13781       g_object_unref(current_input);
13782     }
13783   }
13784 
13785   /* unref */
13786   if(current_audio != NULL){
13787     g_object_unref(current_audio);
13788   }
13789 
13790   if(start_input != NULL){
13791     g_object_unref(start_input);
13792   }
13793 }
13794 
13795 void
ags_channel_recursive_prepare_run_stage_up(AgsChannel * channel,AgsRecyclingContext * recycling_context,gint sound_scope,guint local_staging_flags)13796 ags_channel_recursive_prepare_run_stage_up(AgsChannel *channel,
13797 					   AgsRecyclingContext *recycling_context,
13798 					   gint sound_scope, guint local_staging_flags)
13799 {
13800   AgsAudio *current_audio;
13801   AgsChannel *current_channel, *nth_channel;
13802   AgsChannel *current_link;
13803   AgsRecallID *current_recall_id;
13804 
13805   GList *start_recall_id, *recall_id;
13806 
13807   guint pad, audio_channel;
13808   guint line;
13809 
13810   if(!AGS_IS_CHANNEL(channel) ||
13811      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
13812     return;
13813   }
13814 
13815   current_audio = NULL;
13816 
13817   current_channel = channel;
13818 
13819   if(current_channel != NULL){
13820     g_object_ref(current_channel);
13821   }
13822 
13823   current_link = NULL;
13824 
13825   if(AGS_IS_OUTPUT(channel)){
13826     g_object_get(channel,
13827 		 "audio", &current_audio,
13828 		 NULL);
13829 
13830     goto ags_channel_recursive_prepare_run_stage_up_OUTPUT;
13831   }
13832 
13833   while(current_channel != NULL){
13834     /* check scope - input */
13835     recall_id =
13836       start_recall_id = ags_channel_check_scope(current_channel, sound_scope);
13837 
13838     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
13839 							     recycling_context);
13840 
13841     /* duplicate */
13842     if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE & (local_staging_flags)) != 0){
13843       if(current_recall_id != NULL){
13844 	ags_channel_duplicate_recall(current_channel,
13845 				     current_recall_id);
13846       }
13847     }
13848 
13849     /* resolve */
13850     if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE & (local_staging_flags)) != 0){
13851       if(current_recall_id != NULL){
13852 	ags_channel_resolve_recall(current_channel,
13853 				   current_recall_id);
13854       }
13855     }
13856 
13857     /* free recall id */
13858     g_list_free_full(start_recall_id,
13859 		     g_object_unref);
13860 
13861     /* get current audio */
13862     current_audio = NULL;
13863 
13864     g_object_get(current_channel,
13865 		 "audio", &current_audio,
13866 		 NULL);
13867 
13868     /* check scope - audio */
13869     recall_id =
13870       start_recall_id = ags_audio_check_scope(current_audio, sound_scope);
13871 
13872     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
13873 							     recycling_context);
13874 
13875     /* duplicate */
13876     pad = 0;
13877     audio_channel = 0;
13878     line = 0;
13879 
13880     g_object_get(current_channel,
13881 		 "pad", &pad,
13882 		 "audio-channel", &audio_channel,
13883 		 "line", &line,
13884 		 NULL);
13885 
13886     if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE & (local_staging_flags)) != 0){
13887       if(current_recall_id != NULL){
13888 	ags_audio_duplicate_recall(current_audio,
13889 				   current_recall_id,
13890 				   pad, audio_channel,
13891 				   line);
13892       }
13893     }
13894 
13895     /* resolve */
13896     if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE & (local_staging_flags)) != 0){
13897       if(current_recall_id != NULL){
13898 	ags_audio_resolve_recall(current_audio,
13899 				 current_recall_id);
13900       }
13901     }
13902 
13903     /* free recall id */
13904     g_list_free_full(start_recall_id,
13905 		     g_object_unref);
13906 
13907     /* get some fields */
13908     audio_channel = 0;
13909     line = 0;
13910 
13911     g_object_get(current_channel,
13912 		 "audio-channel", &audio_channel,
13913 		 "line", &line,
13914 		 NULL);
13915 
13916     /* move up */
13917     if(current_channel != NULL){
13918       g_object_unref(current_channel);
13919     }
13920 
13921     current_channel = NULL;
13922 
13923     g_object_get(current_audio,
13924 		 "output", &current_channel,
13925 		 NULL);
13926 
13927     if(ags_audio_test_flags(current_audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING)){
13928       /* unref current audio */
13929       if(current_audio != NULL){
13930 	g_object_unref(current_audio);
13931       }
13932 
13933       if(current_channel != NULL){
13934 	g_object_unref(current_channel);
13935       }
13936 
13937       break;
13938     }
13939 
13940     if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
13941       nth_channel = ags_channel_nth(current_channel,
13942 				    audio_channel);
13943 
13944       g_object_unref(current_channel);
13945 
13946       current_channel = nth_channel;
13947     }else{
13948       nth_channel = ags_channel_nth(current_channel,
13949 				    line);
13950 
13951       g_object_unref(current_channel);
13952 
13953       current_channel = nth_channel;
13954     }
13955 
13956   ags_channel_recursive_prepare_run_stage_up_OUTPUT:
13957 
13958     /* check scope - output */
13959     recall_id =
13960       start_recall_id = ags_channel_check_scope(current_channel, sound_scope);
13961 
13962     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
13963 							     recycling_context);
13964 
13965     /* duplicate */
13966     if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE & (local_staging_flags)) != 0){
13967       if(current_recall_id != NULL){
13968 	ags_channel_duplicate_recall(current_channel,
13969 				     current_recall_id);
13970       }
13971     }
13972 
13973     /* resolve */
13974     if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE & (local_staging_flags)) != 0){
13975       if(current_recall_id != NULL){
13976 	ags_channel_resolve_recall(current_channel,
13977 				   current_recall_id);
13978       }
13979     }
13980 
13981     /* free recall id */
13982     g_list_free_full(start_recall_id,
13983 		     g_object_unref);
13984 
13985     /* unref current audio */
13986     g_object_unref(current_audio);
13987 
13988     /* iterate */
13989     current_link = ags_channel_get_link(current_channel);
13990 
13991     g_object_unref(current_channel);
13992 
13993     current_channel = current_link;
13994   }
13995 
13996   if(current_link != NULL){
13997     g_object_unref(current_link);
13998   }
13999 }
14000 
14001 void
ags_channel_recursive_prepare_run_stage_down(AgsChannel * channel,AgsRecyclingContext * recycling_context,gint sound_scope,guint local_staging_flags)14002 ags_channel_recursive_prepare_run_stage_down(AgsChannel *channel,
14003 					     AgsRecyclingContext *recycling_context,
14004 					     gint sound_scope, guint local_staging_flags)
14005 {
14006   AgsAudio *current_audio;
14007   AgsChannel *start_input;
14008   AgsChannel *current_input, *next_pad, *next_channel, *nth_input;
14009   AgsRecallID *current_recall_id, *next_recall_id;
14010   AgsRecyclingContext *next_recycling_context;
14011 
14012   GList *start_recall_id, *recall_id;
14013 
14014   guint pad, audio_channel;
14015   guint line;
14016 
14017   if(!AGS_IS_CHANNEL(channel) ||
14018      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
14019     return;
14020   }
14021 
14022   /* prepare */
14023   next_recycling_context = recycling_context;
14024 
14025   /* check scope - output */
14026   recall_id =
14027     start_recall_id = ags_channel_check_scope(channel, sound_scope);
14028 
14029   current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14030 							   recycling_context);
14031 
14032   /* duplicate */
14033   if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE & (local_staging_flags)) != 0){
14034     if(current_recall_id != NULL){
14035       ags_channel_duplicate_recall(channel,
14036 				   current_recall_id);
14037     }
14038   }
14039 
14040   /* resolve */
14041   if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE & (local_staging_flags)) != 0){
14042     if(current_recall_id != NULL){
14043       ags_channel_resolve_recall(channel,
14044 				 current_recall_id);
14045     }
14046   }
14047 
14048   /* free recall id */
14049   g_list_free_full(start_recall_id,
14050 		   g_object_unref);
14051 
14052   /* get current audio */
14053   current_audio = NULL;
14054 
14055   audio_channel = 0;
14056   line = 0;
14057 
14058   g_object_get(channel,
14059 	       "audio", &current_audio,
14060 	       "audio-channel", &audio_channel,
14061 	       "line", &line,
14062 	       NULL);
14063 
14064   /* check scope - audio */
14065   recall_id =
14066     start_recall_id = ags_audio_check_scope(current_audio, sound_scope);
14067 
14068   current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14069 							   recycling_context);
14070 
14071   /* duplicate - audio */
14072   pad = 0;
14073   audio_channel = 0;
14074   line = 0;
14075 
14076   g_object_get(channel,
14077 	       "pad", &pad,
14078 	       "audio-channel", &audio_channel,
14079 	       "line", &line,
14080 	       NULL);
14081 
14082   if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE & (local_staging_flags)) != 0){
14083     if(current_recall_id != NULL){
14084       ags_audio_duplicate_recall(current_audio,
14085 				 current_recall_id,
14086 				 pad, audio_channel,
14087 				 line);
14088     }
14089   }
14090 
14091   /* resolve - audio */
14092   if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE & (local_staging_flags)) != 0){
14093     if(current_recall_id != NULL){
14094       ags_audio_resolve_recall(current_audio,
14095 			       current_recall_id);
14096     }
14097   }
14098 
14099   /* free recall id */
14100   g_list_free_full(start_recall_id,
14101 		   g_object_unref);
14102 
14103   /* get some fields */
14104   start_input = NULL;
14105 
14106   g_object_get(current_audio,
14107 	       "input", &start_input,
14108 	       NULL);
14109 
14110   /* check next recycling context */
14111   if(ags_audio_test_flags(current_audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING)){
14112     AgsRecycling *first_recycling;
14113 
14114     gint position;
14115 
14116     next_recycling_context = NULL;
14117 
14118     if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
14119       AgsChannel *first_with_recycling;
14120 
14121       nth_input = ags_channel_nth(start_input,
14122 				  audio_channel);
14123 
14124       current_input = nth_input;
14125 
14126       first_with_recycling = ags_channel_first_with_recycling(current_input);
14127 
14128       first_recycling = NULL;
14129 
14130       g_object_get(first_with_recycling,
14131 		   "first-recycling", &first_recycling,
14132 		   NULL);
14133 
14134       g_object_unref(first_with_recycling);
14135 
14136       if(current_input != NULL){
14137 	g_object_unref(current_input);
14138       }
14139     }else{
14140       nth_input = ags_channel_nth(start_input,
14141 				  line);
14142 
14143       current_input = nth_input;
14144 
14145       first_recycling = NULL;
14146 
14147       g_object_get(current_input,
14148 		   "first-recycling", &first_recycling,
14149 		   NULL);
14150 
14151       if(current_input != NULL){
14152 	g_object_unref(current_input);
14153       }
14154     }
14155 
14156     if(first_recycling != NULL){
14157       position = ags_recycling_context_find_child(recycling_context,
14158 						  first_recycling);
14159 
14160       if(position >= 0){
14161 	GList *child_start;
14162 
14163 	child_start = NULL;
14164 
14165 	g_object_get(recycling_context,
14166 		     "child", &child_start,
14167 		     NULL);
14168 
14169 	next_recycling_context = g_list_nth_data(child_start, position);
14170 	g_list_free_full(child_start,
14171 			 g_object_unref);
14172       }
14173 
14174       g_object_unref(first_recycling);
14175     }
14176   }
14177 
14178   if(next_recycling_context != NULL &&
14179      next_recycling_context != recycling_context){
14180     /* check scope - audio */
14181     recall_id =
14182       start_recall_id = ags_audio_check_scope(current_audio, sound_scope);
14183 
14184     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14185 							     next_recycling_context);
14186 
14187     /* duplicate - audio */
14188     if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE & (local_staging_flags)) != 0){
14189       if(current_recall_id != NULL){
14190 	ags_audio_duplicate_recall(current_audio,
14191 				   current_recall_id,
14192 				   pad, audio_channel,
14193 				   line);
14194       }
14195     }
14196 
14197     /* resolve - audio */
14198     if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE & (local_staging_flags)) != 0){
14199       if(current_recall_id != NULL){
14200 	ags_audio_resolve_recall(current_audio,
14201 				 current_recall_id);
14202       }
14203     }
14204 
14205     /* free recall id */
14206     g_list_free_full(start_recall_id,
14207 		     g_object_unref);
14208   }
14209 
14210   /* unref */
14211   if(start_input != NULL){
14212     g_object_unref(start_input);
14213   }
14214 
14215   /* traverse the tree */
14216   ags_channel_recursive_prepare_run_stage_down_input(channel,
14217 						     next_recycling_context,
14218 						     sound_scope, local_staging_flags);
14219 
14220   /* unref */
14221   if(current_audio != NULL){
14222     g_object_unref(current_audio);
14223   }
14224 }
14225 
14226 void
ags_channel_recursive_prepare_run_stage_down_input(AgsChannel * channel,AgsRecyclingContext * recycling_context,gint sound_scope,guint local_staging_flags)14227 ags_channel_recursive_prepare_run_stage_down_input(AgsChannel *channel,
14228 						   AgsRecyclingContext *recycling_context,
14229 						   gint sound_scope, guint local_staging_flags)
14230 {
14231   AgsAudio *current_audio;
14232   AgsChannel *start_input;
14233   AgsChannel *current_input, *next_pad, *nth_input;
14234   AgsChannel *current_link;
14235   AgsRecallID *current_recall_id;
14236 
14237   GList *start_recall_id, *recall_id;
14238 
14239   guint audio_channel, line;
14240 
14241   if(!AGS_IS_CHANNEL(channel) ||
14242      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
14243     return;
14244   }
14245 
14246   /* get some fields */
14247   current_audio = NULL;
14248 
14249   audio_channel = 0;
14250   line = 0;
14251 
14252   g_object_get(channel,
14253 	       "audio", &current_audio,
14254 	       "line", &line,
14255 	       "audio-channel", &audio_channel,
14256 	       NULL);
14257 
14258   if(current_audio == NULL){
14259     return;
14260   }
14261 
14262   /* get some fields */
14263   g_object_get(current_audio,
14264 	       "input", &start_input,
14265 	       NULL);
14266 
14267   /* sync/async */
14268   if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
14269     nth_input = ags_channel_nth(start_input,
14270 				audio_channel);
14271 
14272     current_input = nth_input;
14273 
14274     next_pad = NULL;
14275 
14276     while(current_input != NULL){
14277       /* get some fields */
14278       current_link = ags_channel_get_link(current_input);
14279 
14280       /* check scope - input */
14281       recall_id =
14282 	start_recall_id = ags_channel_check_scope(current_input, sound_scope);
14283 
14284       current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14285 							       recycling_context);
14286 
14287       /* duplicate */
14288       if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE & (local_staging_flags)) != 0){
14289 	if(current_recall_id != NULL){
14290 	  ags_channel_duplicate_recall(current_input,
14291 				       current_recall_id);
14292 	}
14293       }
14294 
14295       /* resolve */
14296       if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE & (local_staging_flags)) != 0){
14297 
14298 	if(current_recall_id){
14299 	  ags_channel_resolve_recall(current_input,
14300 				     current_recall_id);
14301 	}
14302       }
14303 
14304       /* free recall id */
14305       g_list_free_full(start_recall_id,
14306 		       g_object_unref);
14307 
14308       /* traverse the tree */
14309       ags_channel_recursive_prepare_run_stage_down(current_link,
14310 						   recycling_context,
14311 						   sound_scope, local_staging_flags);
14312 
14313       if(current_link != NULL){
14314 	g_object_unref(current_link);
14315       }
14316 
14317       /* iterate */
14318       next_pad = ags_channel_next_pad(current_input);
14319 
14320       g_object_unref(current_input);
14321 
14322       current_input = next_pad;
14323     }
14324 
14325     if(next_pad != NULL){
14326       g_object_unref(next_pad);
14327     }
14328   }else{
14329     nth_input = ags_channel_nth(start_input,
14330 				line);
14331 
14332     current_input = nth_input;
14333 
14334     /* get some fields */
14335     current_link = ags_channel_get_link(current_input);
14336 
14337     /* check scope - input */
14338     recall_id =
14339       start_recall_id = ags_channel_check_scope(current_input, sound_scope);
14340 
14341     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14342 							     recycling_context);
14343 
14344     /* duplicate */
14345     if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE & (local_staging_flags)) != 0){
14346       if(current_recall_id != NULL){
14347 	ags_channel_duplicate_recall(current_input,
14348 				     current_recall_id);
14349       }
14350     }
14351 
14352     /* resolve */
14353     if((AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE & (local_staging_flags)) != 0){
14354       if(current_recall_id != NULL){
14355 	ags_channel_resolve_recall(current_input,
14356 				   current_recall_id);
14357       }
14358     }
14359 
14360     /* free recall id */
14361     g_list_free_full(start_recall_id,
14362 		     g_object_unref);
14363 
14364     /* traverse the tree */
14365     ags_channel_recursive_prepare_run_stage_down(current_link,
14366 						 recycling_context,
14367 						 sound_scope, local_staging_flags);
14368 
14369     if(current_link != NULL){
14370       g_object_unref(current_link);
14371     }
14372 
14373     if(current_input != NULL){
14374       g_object_unref(current_input);
14375     }
14376   }
14377 
14378   /* unref */
14379   if(current_audio != NULL){
14380     g_object_unref(current_audio);
14381   }
14382 
14383   if(start_input != NULL){
14384     g_object_unref(start_input);
14385   }
14386 }
14387 
14388 void
ags_channel_recursive_do_run_stage_up(AgsChannel * channel,AgsRecyclingContext * recycling_context,gint sound_scope,guint staging_flags)14389 ags_channel_recursive_do_run_stage_up(AgsChannel *channel,
14390 				      AgsRecyclingContext *recycling_context,
14391 				      gint sound_scope, guint staging_flags)
14392 {
14393   AgsAudio *current_audio;
14394   AgsChannel *current_channel, *nth_channel;
14395   AgsChannel *current_link;
14396   AgsRecallID *current_recall_id;
14397 
14398   GList *start_recall_id, *recall_id;
14399 
14400   guint audio_channel;
14401   guint line;
14402 
14403   if(!AGS_IS_CHANNEL(channel) ||
14404      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
14405     return;
14406   }
14407 
14408   current_audio = NULL;
14409 
14410   current_channel = channel;
14411 
14412   if(current_channel != NULL){
14413     g_object_ref(current_channel);
14414   }
14415 
14416   current_link = NULL;
14417 
14418   if(AGS_IS_OUTPUT(channel)){
14419     g_object_get(channel,
14420 		 "audio", &current_audio,
14421 		 NULL);
14422 
14423     goto ags_channel_recursive_do_run_stage_up_OUTPUT;
14424   }
14425 
14426   while(current_channel != NULL){
14427     /* check scope - input */
14428     recall_id =
14429       start_recall_id = ags_channel_check_scope(current_channel, sound_scope);
14430 
14431     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14432 							     recycling_context);
14433 
14434     /* init recall */
14435     if((AGS_SOUND_STAGING_CHECK_RT_DATA & (staging_flags)) != 0 ||
14436        (AGS_SOUND_STAGING_RUN_INIT_PRE & (staging_flags)) != 0 ||
14437        (AGS_SOUND_STAGING_RUN_INIT_INTER & (staging_flags)) != 0 ||
14438        (AGS_SOUND_STAGING_RUN_INIT_POST & (staging_flags)) != 0){
14439       if(current_recall_id != NULL){
14440 	ags_channel_init_recall(current_channel,
14441 				current_recall_id, staging_flags);
14442       }
14443     }
14444 
14445     /* play recall */
14446     if(current_recall_id != NULL){
14447       ags_channel_play_recall(current_channel,
14448 			      current_recall_id, staging_flags);
14449     }
14450 
14451     /* free recall id */
14452     g_list_free_full(start_recall_id,
14453 		     g_object_unref);
14454 
14455     /* get current audio */
14456     current_audio = NULL;
14457 
14458     g_object_get(current_channel,
14459 		 "audio", &current_audio,
14460 		 NULL);
14461 
14462     /* check scope - audio */
14463     recall_id =
14464       start_recall_id = ags_audio_check_scope(current_audio, sound_scope);
14465 
14466     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14467 							     recycling_context);
14468 
14469     /* init recall */
14470     if((AGS_SOUND_STAGING_CHECK_RT_DATA & (staging_flags)) != 0 ||
14471        (AGS_SOUND_STAGING_RUN_INIT_PRE & (staging_flags)) != 0 ||
14472        (AGS_SOUND_STAGING_RUN_INIT_INTER & (staging_flags)) != 0 ||
14473        (AGS_SOUND_STAGING_RUN_INIT_POST & (staging_flags)) != 0){
14474       if(current_recall_id != NULL){
14475 	ags_audio_init_recall(current_audio,
14476 			      current_recall_id, staging_flags);
14477       }
14478     }
14479 
14480     /* play recall */
14481     if(current_recall_id != NULL){
14482       ags_audio_play_recall(current_audio,
14483 			    current_recall_id, staging_flags);
14484     }
14485 
14486     /* free recall id */
14487     g_list_free_full(start_recall_id,
14488 		     g_object_unref);
14489 
14490     /* get some fields */
14491     audio_channel = 0;
14492     line = 0;
14493 
14494     g_object_get(current_channel,
14495 		 "audio-channel", &audio_channel,
14496 		 "line", &line,
14497 		 NULL);
14498 
14499     /* move up */
14500     if(current_channel != NULL){
14501       g_object_unref(current_channel);
14502     }
14503 
14504     current_channel = NULL;
14505 
14506     g_object_get(current_audio,
14507 		 "output", &current_channel,
14508 		 NULL);
14509 
14510     if(ags_audio_test_flags(current_audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING)){
14511       /* unref current audio */
14512       if(current_audio != NULL){
14513 	g_object_unref(current_audio);
14514       }
14515 
14516       if(current_channel != NULL){
14517 	g_object_unref(current_channel);
14518       }
14519 
14520       break;
14521     }
14522 
14523     if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
14524       nth_channel = ags_channel_nth(current_channel,
14525 				    audio_channel);
14526 
14527       g_object_unref(current_channel);
14528 
14529       current_channel = nth_channel;
14530     }else{
14531       nth_channel = ags_channel_nth(current_channel,
14532 				    line);
14533 
14534       g_object_unref(current_channel);
14535 
14536       current_channel = nth_channel;
14537     }
14538 
14539   ags_channel_recursive_do_run_stage_up_OUTPUT:
14540 
14541     /* check scope - output */
14542     recall_id =
14543       start_recall_id = ags_channel_check_scope(current_channel, sound_scope);
14544 
14545     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14546 							     recycling_context);
14547 
14548     /* init recall */
14549     if((AGS_SOUND_STAGING_CHECK_RT_DATA & (staging_flags)) != 0 ||
14550        (AGS_SOUND_STAGING_RUN_INIT_PRE & (staging_flags)) != 0 ||
14551        (AGS_SOUND_STAGING_RUN_INIT_INTER & (staging_flags)) != 0 ||
14552        (AGS_SOUND_STAGING_RUN_INIT_POST & (staging_flags)) != 0){
14553       if(current_recall_id != NULL){
14554 	ags_channel_init_recall(current_channel,
14555 				current_recall_id, staging_flags);
14556       }
14557     }
14558 
14559     /* play recall */
14560     if(current_recall_id != NULL){
14561       ags_channel_play_recall(current_channel,
14562 			      current_recall_id, staging_flags);
14563     }
14564 
14565     /* free recall id */
14566     g_list_free_full(start_recall_id,
14567 		     g_object_unref);
14568 
14569     /* unref current audio */
14570     g_object_unref(current_audio);
14571 
14572     /* iterate */
14573     current_link = ags_channel_get_link(current_channel);
14574 
14575     g_object_unref(current_channel);
14576 
14577     current_channel = current_link;
14578   }
14579 
14580   if(current_link != NULL){
14581     g_object_unref(current_link);
14582   }
14583 }
14584 
14585 void
ags_channel_recursive_do_run_stage_down(AgsChannel * channel,AgsRecyclingContext * recycling_context,gint sound_scope,guint staging_flags)14586 ags_channel_recursive_do_run_stage_down(AgsChannel *channel,
14587 					AgsRecyclingContext *recycling_context,
14588 					gint sound_scope, guint staging_flags)
14589 {
14590   AgsAudio *current_audio;
14591   AgsChannel *start_input;
14592   AgsChannel *current_input, *next_pad, *next_channel, *nth_input;
14593   AgsRecallID *current_recall_id, *next_recall_id;
14594   AgsRecyclingContext *next_recycling_context;
14595 
14596   GList *start_recall_id, *recall_id;
14597 
14598   guint audio_channel, line;
14599 
14600   if(!AGS_IS_CHANNEL(channel) ||
14601      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
14602     return;
14603   }
14604 
14605   /* do */
14606   next_recycling_context = recycling_context;
14607 
14608   /* check scope - output */
14609   recall_id =
14610     start_recall_id = ags_channel_check_scope(channel, sound_scope);
14611 
14612   current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14613 							   recycling_context);
14614 
14615   /* init recall */
14616   if((AGS_SOUND_STAGING_CHECK_RT_DATA & (staging_flags)) != 0 ||
14617      (AGS_SOUND_STAGING_RUN_INIT_PRE & (staging_flags)) != 0 ||
14618      (AGS_SOUND_STAGING_RUN_INIT_INTER & (staging_flags)) != 0 ||
14619      (AGS_SOUND_STAGING_RUN_INIT_POST & (staging_flags)) != 0){
14620     if(current_recall_id != NULL){
14621       ags_channel_init_recall(channel,
14622 			      current_recall_id, staging_flags);
14623     }
14624   }
14625 
14626   /* play recall */
14627   if(current_recall_id != NULL){
14628     ags_channel_play_recall(channel,
14629 			    current_recall_id, staging_flags);
14630   }
14631 
14632   /* free recall id */
14633   g_list_free_full(start_recall_id,
14634 		   g_object_unref);
14635 
14636   /* get current audio */
14637   current_audio = NULL;
14638 
14639   audio_channel = 0;
14640   line = 0;
14641 
14642   g_object_get(channel,
14643 	       "audio", &current_audio,
14644 	       "audio-channel", &audio_channel,
14645 	       "line", &line,
14646 	       NULL);
14647 
14648   /* check scope - audio */
14649   recall_id =
14650     start_recall_id = ags_audio_check_scope(current_audio, sound_scope);
14651 
14652   current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14653 							   recycling_context);
14654 
14655   /* init recall */
14656   if((AGS_SOUND_STAGING_CHECK_RT_DATA & (staging_flags)) != 0 ||
14657      (AGS_SOUND_STAGING_RUN_INIT_PRE & (staging_flags)) != 0 ||
14658      (AGS_SOUND_STAGING_RUN_INIT_INTER & (staging_flags)) != 0 ||
14659      (AGS_SOUND_STAGING_RUN_INIT_POST & (staging_flags)) != 0){
14660     if(current_recall_id != NULL){
14661       ags_audio_init_recall(current_audio,
14662 			    current_recall_id, staging_flags);
14663     }
14664   }
14665 
14666   /* play recall */
14667   if(current_recall_id != NULL){
14668     ags_audio_play_recall(current_audio,
14669 			  current_recall_id, staging_flags);
14670   }
14671 
14672   /* free recall id */
14673   g_list_free_full(start_recall_id,
14674 		   g_object_unref);
14675 
14676   /* get some fields */
14677   start_input = NULL;
14678 
14679   g_object_get(current_audio,
14680 	       "input", &start_input,
14681 	       NULL);
14682 
14683   /* check next recycling context */
14684   if(ags_audio_test_flags(current_audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING)){
14685     AgsRecycling *first_recycling;
14686 
14687     gint position;
14688 
14689     next_recycling_context = NULL;
14690 
14691     if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
14692       AgsChannel *first_with_recycling;
14693 
14694       nth_input = ags_channel_nth(start_input,
14695 				  audio_channel);
14696 
14697       current_input = nth_input;
14698 
14699       first_with_recycling = ags_channel_first_with_recycling(current_input);
14700 
14701       first_recycling = NULL;
14702 
14703       g_object_get(first_with_recycling,
14704 		   "first-recycling", &first_recycling,
14705 		   NULL);
14706 
14707       g_object_unref(first_with_recycling);
14708 
14709       if(current_input != NULL){
14710 	g_object_unref(current_input);
14711       }
14712     }else{
14713       nth_input = ags_channel_nth(start_input,
14714 				  line);
14715 
14716       current_input = nth_input;
14717 
14718       first_recycling = NULL;
14719 
14720       g_object_get(current_input,
14721 		   "first-recycling", &first_recycling,
14722 		   NULL);
14723 
14724       if(current_input != NULL){
14725 	g_object_unref(current_input);
14726       }
14727     }
14728 
14729     if(first_recycling != NULL){
14730       position = ags_recycling_context_find_child(recycling_context,
14731 						  first_recycling);
14732 
14733       if(position >= 0){
14734 	GList *child_start;
14735 
14736 	child_start = NULL;
14737 
14738 	g_object_get(recycling_context,
14739 		     "child", &child_start,
14740 		     NULL);
14741 
14742 	next_recycling_context = g_list_nth_data(child_start, position);
14743 	g_list_free_full(child_start,
14744 			 g_object_unref);
14745       }
14746 
14747       g_object_unref(first_recycling);
14748     }
14749   }
14750 
14751   if(next_recycling_context != NULL &&
14752      next_recycling_context != recycling_context){
14753     /* check scope - audio */
14754     recall_id =
14755       start_recall_id = ags_audio_check_scope(current_audio, sound_scope);
14756 
14757     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14758 							     next_recycling_context);
14759 
14760     /* init recall */
14761     if((AGS_SOUND_STAGING_CHECK_RT_DATA & (staging_flags)) != 0 ||
14762        (AGS_SOUND_STAGING_RUN_INIT_PRE & (staging_flags)) != 0 ||
14763        (AGS_SOUND_STAGING_RUN_INIT_INTER & (staging_flags)) != 0 ||
14764        (AGS_SOUND_STAGING_RUN_INIT_POST & (staging_flags)) != 0){
14765       if(current_recall_id != NULL){
14766 	ags_audio_init_recall(current_audio,
14767 			      current_recall_id, staging_flags);
14768       }
14769     }
14770 
14771     /* play recall */
14772     if(current_recall_id != NULL){
14773       ags_audio_play_recall(current_audio,
14774 			    current_recall_id, staging_flags);
14775     }
14776 
14777     /* free recall id */
14778     g_list_free_full(start_recall_id,
14779 		     g_object_unref);
14780   }
14781 
14782   /* unref */
14783   if(start_input != NULL){
14784     g_object_unref(start_input);
14785   }
14786 
14787   /* traverse the tree */
14788   ags_channel_recursive_do_run_stage_down_input(channel,
14789 						next_recycling_context,
14790 						sound_scope, staging_flags);
14791 
14792   /* unref */
14793   if(current_audio != NULL){
14794     g_object_unref(current_audio);
14795   }
14796 }
14797 
14798 void
ags_channel_recursive_do_run_stage_down_input(AgsChannel * channel,AgsRecyclingContext * recycling_context,gint sound_scope,guint staging_flags)14799 ags_channel_recursive_do_run_stage_down_input(AgsChannel *channel,
14800 					      AgsRecyclingContext *recycling_context,
14801 					      gint sound_scope, guint staging_flags)
14802 {
14803   AgsAudio *current_audio;
14804   AgsChannel *start_input;
14805   AgsChannel *current_input, *next_pad, *nth_input;
14806   AgsChannel *current_link;
14807   AgsRecallID *current_recall_id;
14808 
14809   GList *start_recall_id, *recall_id;
14810 
14811   guint audio_channel, line;
14812 
14813   if(!AGS_IS_CHANNEL(channel) ||
14814      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
14815     return;
14816   }
14817 
14818   /* get some fields */
14819   current_audio = NULL;
14820 
14821   audio_channel = 0;
14822   line = 0;
14823 
14824   g_object_get(channel,
14825 	       "audio", &current_audio,
14826 	       "line", &line,
14827 	       "audio-channel", &audio_channel,
14828 	       NULL);
14829 
14830   if(current_audio == NULL){
14831     return;
14832   }
14833 
14834   /* get some fields */
14835   start_input = NULL;
14836 
14837   g_object_get(current_audio,
14838 	       "input", &start_input,
14839 	       NULL);
14840 
14841   /* sync/async */
14842   if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
14843     nth_input = ags_channel_nth(start_input,
14844 				audio_channel);
14845 
14846     current_input = nth_input;
14847 
14848     next_pad = NULL;
14849 
14850     while(current_input != NULL){
14851       /* get some fields */
14852       current_link = ags_channel_get_link(current_input);
14853 
14854       /* check scope - input */
14855       recall_id =
14856 	start_recall_id = ags_channel_check_scope(current_input, sound_scope);
14857 
14858       current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14859 							       recycling_context);
14860 
14861       /* init recall */
14862       if((AGS_SOUND_STAGING_CHECK_RT_DATA & (staging_flags)) != 0 ||
14863 	 (AGS_SOUND_STAGING_RUN_INIT_PRE & (staging_flags)) != 0 ||
14864 	 (AGS_SOUND_STAGING_RUN_INIT_INTER & (staging_flags)) != 0 ||
14865 	 (AGS_SOUND_STAGING_RUN_INIT_POST & (staging_flags)) != 0){
14866 	if(current_recall_id != NULL){
14867 	  ags_channel_init_recall(current_input,
14868 				  current_recall_id, staging_flags);
14869 	}
14870       }
14871 
14872       /* play recall */
14873       if(current_recall_id != NULL){
14874 	ags_channel_play_recall(current_input,
14875 				current_recall_id, staging_flags);
14876       }
14877 
14878       /* free recall id */
14879       g_list_free_full(start_recall_id,
14880 		       g_object_unref);
14881 
14882       /* traverse the tree */
14883       ags_channel_recursive_do_run_stage_down(current_link,
14884 					      recycling_context,
14885 					      sound_scope, staging_flags);
14886 
14887       if(current_link != NULL){
14888 	g_object_unref(current_link);
14889       }
14890 
14891       /* iterate */
14892       next_pad = ags_channel_next_pad(current_input);
14893 
14894       g_object_unref(current_input);
14895 
14896       current_input = next_pad;
14897     }
14898 
14899     if(next_pad != NULL){
14900       g_object_unref(next_pad);
14901     }
14902   }else{
14903     nth_input = ags_channel_nth(start_input,
14904 				line);
14905 
14906     current_input = nth_input;
14907 
14908     /* get some fields */
14909     current_link = ags_channel_get_link(current_input);
14910 
14911     /* check scope - input */
14912     recall_id =
14913       start_recall_id = ags_channel_check_scope(current_input, sound_scope);
14914 
14915     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
14916 							     recycling_context);
14917 
14918     /* init recall */
14919     if((AGS_SOUND_STAGING_CHECK_RT_DATA & (staging_flags)) != 0 ||
14920        (AGS_SOUND_STAGING_RUN_INIT_PRE & (staging_flags)) != 0 ||
14921        (AGS_SOUND_STAGING_RUN_INIT_INTER & (staging_flags)) != 0 ||
14922        (AGS_SOUND_STAGING_RUN_INIT_POST & (staging_flags)) != 0){
14923       if(current_recall_id != NULL){
14924 	ags_channel_init_recall(current_input,
14925 				current_recall_id, staging_flags);
14926       }
14927     }
14928 
14929     /* play recall */
14930     if(current_recall_id != NULL){
14931       ags_channel_play_recall(current_input,
14932 			      current_recall_id, staging_flags);
14933     }
14934 
14935     /* free recall id */
14936     g_list_free_full(start_recall_id,
14937 		     g_object_unref);
14938 
14939     /* traverse the tree */
14940     ags_channel_recursive_do_run_stage_down(current_link,
14941 					    recycling_context,
14942 					    sound_scope, staging_flags);
14943 
14944     if(current_link != NULL){
14945       g_object_unref(current_link);
14946     }
14947 
14948     if(current_input != NULL){
14949       g_object_unref(current_input);
14950     }
14951   }
14952 
14953   /* unref */
14954   if(current_audio != NULL){
14955     g_object_unref(current_audio);
14956   }
14957 
14958   if(start_input != NULL){
14959     g_object_unref(start_input);
14960   }
14961 }
14962 
14963 void
ags_channel_recursive_cleanup_run_stage_up(AgsChannel * channel,AgsRecyclingContext * recycling_context,gint sound_scope,guint local_staging_flags)14964 ags_channel_recursive_cleanup_run_stage_up(AgsChannel *channel,
14965 					   AgsRecyclingContext *recycling_context,
14966 					   gint sound_scope, guint local_staging_flags)
14967 {
14968   AgsAudio *current_audio;
14969   AgsChannel *current_channel, *nth_channel;
14970   AgsChannel *current_link;
14971   AgsRecallID *current_recall_id;
14972 
14973   GList *start_recall_id, *recall_id;
14974 
14975   guint audio_channel;
14976   guint line;
14977 
14978   static const guint staging_mask = (AGS_SOUND_STAGING_CHECK_RT_DATA |
14979 				     AGS_SOUND_STAGING_RUN_INIT_PRE |
14980 				     AGS_SOUND_STAGING_RUN_INIT_INTER |
14981 				     AGS_SOUND_STAGING_RUN_INIT_POST);
14982 
14983   if(!AGS_IS_CHANNEL(channel) ||
14984      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
14985     return;
14986   }
14987 
14988   current_audio = NULL;
14989 
14990   current_channel = channel;
14991 
14992   if(current_channel != NULL){
14993     g_object_ref(current_channel);
14994   }
14995 
14996   current_link = NULL;
14997 
14998   if(AGS_IS_OUTPUT(channel)){
14999     g_object_get(channel,
15000 		 "audio", &current_audio,
15001 		 NULL);
15002 
15003     goto ags_channel_recursive_cleanup_run_stage_up_OUTPUT;
15004   }
15005 
15006   while(current_channel != NULL){
15007     /* check scope - input */
15008     recall_id =
15009       start_recall_id = ags_channel_check_scope(current_channel, sound_scope);
15010 
15011     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
15012 							     recycling_context);
15013 
15014     /* cancel */
15015     if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL & (local_staging_flags)) != 0){
15016       if(current_recall_id != NULL){
15017 	ags_channel_cancel_recall(current_channel,
15018 				  current_recall_id);
15019       }
15020     }
15021 
15022     /* remove */
15023     if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL & (local_staging_flags)) != 0){
15024       if(current_recall_id != NULL){
15025 	ags_channel_cleanup_recall(current_channel,
15026 				   current_recall_id);
15027       }
15028     }
15029 
15030     /* fini - clean */
15031     if((AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE & (local_staging_flags)) != 0){
15032       if(current_recall_id != NULL){
15033 	ags_channel_remove_recall_id(current_channel,
15034 				     current_recall_id);
15035 
15036 	ags_channel_unset_staging_flags(current_channel, sound_scope,
15037 					staging_mask);
15038       }
15039     }
15040 
15041     /* free recall id */
15042     g_list_free_full(start_recall_id,
15043 		     g_object_unref);
15044 
15045     /* get current audio */
15046     current_audio = NULL;
15047 
15048     g_object_get(current_channel,
15049 		 "audio", &current_audio,
15050 		 NULL);
15051 
15052     /* check scope - audio */
15053     recall_id =
15054       start_recall_id = ags_audio_check_scope(current_audio, sound_scope);
15055 
15056     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
15057 							     recycling_context);
15058 
15059     /* cancel */
15060     if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL & (local_staging_flags)) != 0){
15061       if(current_recall_id != NULL){
15062 	ags_audio_cancel_recall(current_audio,
15063 				current_recall_id);
15064       }
15065     }
15066 
15067     /* remove */
15068     if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL & (local_staging_flags)) != 0){
15069       if(current_recall_id){
15070 	ags_audio_cleanup_recall(current_audio,
15071 				 current_recall_id);
15072       }
15073     }
15074 
15075     /* fini - clean */
15076     if((AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE & (local_staging_flags)) != 0){
15077       if(current_recall_id != NULL){
15078 	ags_audio_remove_recall_id(current_audio,
15079 				   (GObject *) current_recall_id);
15080 
15081 	ags_audio_unset_staging_flags(current_audio, sound_scope,
15082 				      staging_mask);
15083       }
15084     }
15085 
15086     /* free recall id */
15087     g_list_free_full(start_recall_id,
15088 		     g_object_unref);
15089 
15090     /* get some fields */
15091     audio_channel = 0;
15092     line = 0;
15093 
15094     g_object_get(current_channel,
15095 		 "audio-channel", &audio_channel,
15096 		 "line", &line,
15097 		 NULL);
15098 
15099     /* move up */
15100     if(current_channel != NULL){
15101       g_object_unref(current_channel);
15102     }
15103 
15104     current_channel = NULL;
15105 
15106     g_object_get(current_audio,
15107 		 "output", &current_channel,
15108 		 NULL);
15109 
15110     if(ags_audio_test_flags(current_audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING)){
15111       /* fini - clean */
15112       if((AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE & (local_staging_flags)) != 0){
15113 	ags_audio_remove_recycling_context(current_audio, (GObject *) recycling_context);
15114       }
15115 
15116       /* unref current audio */
15117       if(current_audio != NULL){
15118 	g_object_unref(current_audio);
15119       }
15120 
15121       if(current_channel != NULL){
15122 	g_object_unref(current_channel);
15123       }
15124 
15125       break;
15126     }
15127 
15128     if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
15129       nth_channel = ags_channel_nth(current_channel,
15130 				    audio_channel);
15131 
15132       g_object_unref(current_channel);
15133 
15134       current_channel = nth_channel;
15135     }else{
15136       nth_channel = ags_channel_nth(current_channel,
15137 				    line);
15138 
15139       g_object_unref(current_channel);
15140 
15141       current_channel = nth_channel;
15142     }
15143 
15144   ags_channel_recursive_cleanup_run_stage_up_OUTPUT:
15145 
15146     /* check scope - output */
15147     recall_id =
15148       start_recall_id = ags_channel_check_scope(current_channel, sound_scope);
15149 
15150     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
15151 							     recycling_context);
15152 
15153     /* cancel */
15154     if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL & (local_staging_flags)) != 0){
15155       if(current_recall_id != NULL){
15156 	ags_channel_cancel_recall(current_channel,
15157 				  current_recall_id);
15158       }
15159     }
15160 
15161     /* remove */
15162     if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL & (local_staging_flags)) != 0){
15163       if(current_recall_id != NULL){
15164 	ags_channel_cleanup_recall(current_channel,
15165 				   current_recall_id);
15166       }
15167     }
15168 
15169     /* fini - clean */
15170     if((AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE & (local_staging_flags)) != 0){
15171       if(current_recall_id){
15172 	ags_channel_remove_recall_id(current_channel,
15173 				     current_recall_id);
15174 
15175 	ags_channel_unset_staging_flags(current_channel, sound_scope,
15176 					staging_mask);
15177       }
15178     }
15179 
15180     /* free recall id */
15181     g_list_free_full(start_recall_id,
15182 		     g_object_unref);
15183 
15184     /* fini - clean */
15185     if((AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE & (local_staging_flags)) != 0){
15186       ags_audio_remove_recycling_context(current_audio, (GObject *) recycling_context);
15187     }
15188 
15189     /* unref current audio */
15190     if(current_audio != NULL){
15191       g_object_unref(current_audio);
15192     }
15193 
15194     /* iterate */
15195     current_link = ags_channel_get_link(current_channel);
15196 
15197     g_object_unref(current_channel);
15198 
15199     current_channel = current_link;
15200   }
15201 
15202   if(current_link != NULL){
15203     g_object_unref(current_link);
15204   }
15205 }
15206 
15207 void
ags_channel_recursive_cleanup_run_stage_down(AgsChannel * channel,AgsRecyclingContext * recycling_context,gint sound_scope,guint local_staging_flags)15208 ags_channel_recursive_cleanup_run_stage_down(AgsChannel *channel,
15209 					     AgsRecyclingContext *recycling_context,
15210 					     gint sound_scope, guint local_staging_flags)
15211 {
15212   AgsAudio *current_audio;
15213   AgsChannel *start_input;
15214   AgsChannel *current_input, *next_pad, *next_channel, *nth_input;
15215   AgsRecallID *current_recall_id, *next_recall_id;
15216   AgsRecyclingContext *next_recycling_context;
15217 
15218   GList *start_recall_id, *recall_id;
15219 
15220   guint audio_channel, line;
15221   gboolean play_context;
15222 
15223   static const guint staging_mask = (AGS_SOUND_STAGING_CHECK_RT_DATA |
15224 				     AGS_SOUND_STAGING_RUN_INIT_PRE |
15225 				     AGS_SOUND_STAGING_RUN_INIT_INTER |
15226 				     AGS_SOUND_STAGING_RUN_INIT_POST);
15227 
15228   if(!AGS_IS_CHANNEL(channel) ||
15229      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
15230     return;
15231   }
15232 
15233   /* cleanup */
15234   next_recycling_context = recycling_context;
15235 
15236   /* check scope - output */
15237   recall_id =
15238     start_recall_id = ags_channel_check_scope(channel, sound_scope);
15239 
15240   current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
15241 							   recycling_context);
15242 
15243   /* cancel */
15244   if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL & (local_staging_flags)) != 0){
15245     if(current_recall_id != NULL){
15246       ags_channel_cancel_recall(channel,
15247 				current_recall_id);
15248     }
15249   }
15250 
15251   /* remove */
15252   if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL & (local_staging_flags)) != 0){
15253     if(current_recall_id != NULL){
15254       ags_channel_cleanup_recall(channel,
15255 				 current_recall_id);
15256     }
15257   }
15258 
15259   /* fini - clean */
15260   if((AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE & (local_staging_flags)) != 0){
15261     if(current_recall_id != NULL){
15262       ags_channel_remove_recall_id(channel,
15263 				   current_recall_id);
15264 
15265       ags_channel_unset_staging_flags(channel, sound_scope,
15266 				      staging_mask);
15267     }
15268   }
15269 
15270   /* free recall id */
15271   g_list_free_full(start_recall_id,
15272 		   g_object_unref);
15273 
15274   /* get current audio */
15275   current_audio = NULL;
15276 
15277   audio_channel = 0;
15278   line = 0;
15279 
15280   g_object_get(channel,
15281 	       "audio", &current_audio,
15282 	       "audio-channel", &audio_channel,
15283 	       "line", &line,
15284 	       NULL);
15285 
15286   /* check scope - audio */
15287   recall_id =
15288     start_recall_id = ags_audio_check_scope(current_audio, sound_scope);
15289 
15290   current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
15291 							   recycling_context);
15292 
15293   /* cancel */
15294   if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL & (local_staging_flags)) != 0){
15295     if(current_recall_id != NULL){
15296       ags_audio_cancel_recall(current_audio,
15297 			      current_recall_id);
15298     }
15299   }
15300 
15301   /* remove */
15302   if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL & (local_staging_flags)) != 0){
15303     if(current_recall_id){
15304       ags_audio_cleanup_recall(current_audio,
15305 			       current_recall_id);
15306     }
15307   }
15308 
15309   /* fini - clean */
15310   if((AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE & (local_staging_flags)) != 0){
15311     if(current_recall_id != NULL){
15312       ags_audio_remove_recall_id(current_audio,
15313 				 (GObject *) current_recall_id);
15314 
15315       ags_audio_unset_staging_flags(current_audio, sound_scope,
15316 				    staging_mask);
15317     }
15318   }
15319 
15320   /* free recall id */
15321   g_list_free_full(start_recall_id,
15322 		   g_object_unref);
15323 
15324   /* get some fields */
15325   start_input = NULL;
15326 
15327   g_object_get(current_audio,
15328 	       "input", &start_input,
15329 	       NULL);
15330 
15331   /* check next recycling context */
15332   if(ags_audio_test_flags(current_audio, AGS_AUDIO_OUTPUT_HAS_RECYCLING)){
15333     AgsRecycling *first_recycling;
15334 
15335     gint position;
15336 
15337     next_recycling_context = NULL;
15338     first_recycling = NULL;
15339 
15340     if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
15341       AgsChannel *first_with_recycling;
15342 
15343       nth_input = ags_channel_nth(start_input,
15344 				  audio_channel);
15345 
15346       current_input = nth_input;
15347 
15348       first_with_recycling = ags_channel_first_with_recycling(current_input);
15349 
15350       first_recycling = NULL;
15351 
15352       g_object_get(first_with_recycling,
15353 		   "first-recycling", &first_recycling,
15354 		   NULL);
15355 
15356       g_object_unref(first_with_recycling);
15357 
15358       if(current_input != NULL){
15359 	g_object_unref(current_input);
15360       }
15361     }else{
15362       nth_input = ags_channel_nth(start_input,
15363 				  line);
15364 
15365       current_input = nth_input;
15366 
15367       first_recycling = NULL;
15368 
15369       g_object_get(current_input,
15370 		   "first-recycling", &first_recycling,
15371 		   NULL);
15372 
15373       if(current_input != NULL){
15374 	g_object_unref(current_input);
15375       }
15376     }
15377 
15378     if(first_recycling != NULL){
15379       position = ags_recycling_context_find_child(recycling_context,
15380 						  first_recycling);
15381 
15382       if(position >= 0){
15383 	GList *child_start;
15384 
15385 	child_start = NULL;
15386 
15387 	g_object_get(recycling_context,
15388 		     "child", &child_start,
15389 		     NULL);
15390 
15391 	next_recycling_context = g_list_nth_data(child_start, position);
15392 	g_list_free_full(child_start,
15393 			 g_object_unref);
15394       }
15395 
15396       g_object_unref(first_recycling);
15397     }
15398   }
15399 
15400   if(next_recycling_context != NULL &&
15401      next_recycling_context != recycling_context){
15402     /* check scope - audio */
15403     recall_id =
15404       start_recall_id = ags_audio_check_scope(current_audio, sound_scope);
15405 
15406     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
15407 							     next_recycling_context);
15408 
15409     /* cancel */
15410     if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL & (local_staging_flags)) != 0){
15411       if(current_recall_id != NULL){
15412 	ags_audio_cancel_recall(current_audio,
15413 				current_recall_id);
15414       }
15415     }
15416 
15417     /* remove */
15418     if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL & (local_staging_flags)) != 0){
15419       if(current_recall_id != NULL){
15420 	ags_audio_cleanup_recall(current_audio,
15421 				 current_recall_id);
15422       }
15423     }
15424 
15425     /* fini - clean */
15426     if((AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE & (local_staging_flags)) != 0){
15427       if(current_recall_id != NULL){
15428 	ags_audio_remove_recall_id(current_audio,
15429 				   (GObject *) current_recall_id);
15430 
15431 	ags_audio_unset_staging_flags(current_audio, sound_scope,
15432 				      staging_mask);
15433       }
15434     }
15435 
15436     g_list_free_full(start_recall_id,
15437 		     g_object_unref);
15438   }
15439 
15440   /* free recall id */
15441   ags_channel_recursive_cleanup_run_stage_down_input(channel,
15442 						     next_recycling_context,
15443 						     sound_scope, local_staging_flags);
15444 
15445   /* unref */
15446   if(start_input != NULL){
15447     g_object_unref(start_input);
15448   }
15449 
15450   /* fini - clean */
15451   if((AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE & (local_staging_flags)) != 0){
15452     ags_audio_remove_recycling_context(current_audio, (GObject *) recycling_context);
15453     ags_audio_remove_recycling_context(current_audio, (GObject *) next_recycling_context);
15454   }
15455 
15456   /* unref */
15457   if(current_audio != NULL){
15458     g_object_unref(current_audio);
15459   }
15460 }
15461 
15462 void
ags_channel_recursive_cleanup_run_stage_down_input(AgsChannel * channel,AgsRecyclingContext * recycling_context,gint sound_scope,guint local_staging_flags)15463 ags_channel_recursive_cleanup_run_stage_down_input(AgsChannel *channel,
15464 						   AgsRecyclingContext *recycling_context,
15465 						   gint sound_scope, guint local_staging_flags)
15466 {
15467   AgsAudio *current_audio;
15468   AgsChannel *start_input;
15469   AgsChannel *current_input, *next_pad, *nth_input;
15470   AgsChannel *current_link;
15471   AgsRecallID *current_recall_id;
15472 
15473   GList *start_recall_id, *recall_id;
15474 
15475   guint audio_channel, line;
15476 
15477   static const guint staging_mask = (AGS_SOUND_STAGING_CHECK_RT_DATA |
15478 				     AGS_SOUND_STAGING_RUN_INIT_PRE |
15479 				     AGS_SOUND_STAGING_RUN_INIT_INTER |
15480 				     AGS_SOUND_STAGING_RUN_INIT_POST);
15481 
15482   if(!AGS_IS_CHANNEL(channel) ||
15483      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
15484     return;
15485   }
15486 
15487   /* get some fields */
15488   current_audio = NULL;
15489 
15490   audio_channel = 0;
15491   line = 0;
15492 
15493   g_object_get(channel,
15494 	       "audio", &current_audio,
15495 	       "line", &line,
15496 	       "audio-channel", &audio_channel,
15497 	       NULL);
15498 
15499   if(current_audio == NULL){
15500     return;
15501   }
15502 
15503   /* get some fields */
15504   start_input = NULL;
15505 
15506   g_object_get(current_audio,
15507 	       "input", &start_input,
15508 	       NULL);
15509 
15510   /* sync/async */
15511   if(ags_audio_test_flags(current_audio, AGS_AUDIO_ASYNC)){
15512     nth_input = ags_channel_nth(start_input,
15513 				audio_channel);
15514 
15515     current_input = nth_input;
15516 
15517     next_pad = NULL;
15518 
15519     while(current_input != NULL){
15520       /* get some fields */
15521       current_link = ags_channel_get_link(current_input);
15522 
15523       /* check scope - input */
15524       recall_id =
15525 	start_recall_id = ags_channel_check_scope(current_input, sound_scope);
15526 
15527       current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
15528 							       recycling_context);
15529 
15530       /* cancel */
15531       if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL & (local_staging_flags)) != 0){
15532 	if(current_recall_id != NULL){
15533 	  ags_channel_cancel_recall(current_input,
15534 				    current_recall_id);
15535 	}
15536       }
15537 
15538       /* remove */
15539       if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL & (local_staging_flags)) != 0){
15540 	if(current_recall_id != NULL){
15541 	  ags_channel_cleanup_recall(current_input,
15542 				     current_recall_id);
15543 	}
15544       }
15545 
15546       /* fini - clean */
15547       if((AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE & (local_staging_flags)) != 0){
15548 	if(current_recall_id != NULL){
15549 	  ags_channel_remove_recall_id(current_input,
15550 				       current_recall_id);
15551 
15552 	  ags_channel_unset_staging_flags(current_input, sound_scope,
15553 					  staging_mask);
15554 	}
15555       }
15556 
15557       /* free recall id */
15558       g_list_free_full(start_recall_id,
15559 		       g_object_unref);
15560 
15561       /* traverse the tree */
15562       ags_channel_recursive_cleanup_run_stage_down(current_link,
15563 						   recycling_context,
15564 						   sound_scope, local_staging_flags);
15565 
15566       if(current_link != NULL){
15567 	g_object_unref(current_link);
15568       }
15569 
15570       /* iterate */
15571       next_pad = ags_channel_next_pad(current_input);
15572 
15573       g_object_unref(current_input);
15574 
15575       current_input = next_pad;
15576     }
15577 
15578     if(next_pad != NULL){
15579       g_object_unref(next_pad);
15580     }
15581   }else{
15582     nth_input = ags_channel_nth(start_input,
15583 				line);
15584 
15585     current_input = nth_input;
15586 
15587     /* get some fields */
15588     current_link = ags_channel_get_link(current_input);
15589 
15590     /* check scope - input */
15591     start_recall_id = ags_channel_check_scope(current_input, sound_scope);
15592 
15593     current_recall_id = ags_recall_id_find_recycling_context(start_recall_id,
15594 							     recycling_context);
15595 
15596     /* cancel */
15597     if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL & (local_staging_flags)) != 0){
15598       if(current_recall_id != NULL){
15599 	ags_channel_cancel_recall(current_input,
15600 				  current_recall_id);
15601       }
15602     }
15603 
15604     /* remove */
15605     if((AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL & (local_staging_flags)) != 0){
15606       if(current_recall_id != NULL){
15607 	ags_channel_cleanup_recall(current_input,
15608 				   current_recall_id);
15609       }
15610     }
15611 
15612     /* fini - clean */
15613     if((AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE & (local_staging_flags)) != 0){
15614       if(current_recall_id != NULL){
15615 	ags_channel_remove_recall_id(current_input,
15616 				     current_recall_id);
15617 
15618 	ags_channel_unset_staging_flags(current_input, sound_scope,
15619 					staging_mask);
15620       }
15621     }
15622 
15623     /* free recall id */
15624     g_list_free_full(start_recall_id,
15625 		     g_object_unref);
15626 
15627     /* traverse the tree */
15628     ags_channel_recursive_cleanup_run_stage_down(current_link,
15629 						 recycling_context,
15630 						 sound_scope, local_staging_flags);
15631 
15632     if(current_link != NULL){
15633       g_object_unref(current_link);
15634     }
15635 
15636     if(current_input != NULL){
15637       g_object_unref(current_input);
15638     }
15639   }
15640 
15641   if(current_audio != NULL){
15642     g_object_unref(current_audio);
15643   }
15644 
15645   if(start_input != NULL){
15646     g_object_unref(start_input);
15647   }
15648 }
15649 
15650 void
ags_channel_real_recursive_run_stage(AgsChannel * channel,gint sound_scope,guint staging_flags)15651 ags_channel_real_recursive_run_stage(AgsChannel *channel,
15652 				     gint sound_scope, guint staging_flags)
15653 {
15654   AgsChannel *link;
15655   AgsRecyclingContext *recycling_context;
15656 
15657   GList *recall_id, *recall_id_iter;
15658 
15659   guint pad;
15660   gint i;
15661 
15662   GRecMutex *channel_mutex;
15663   GRecMutex *recall_id_mutex;
15664 
15665   if(sound_scope < 0 ||
15666      sound_scope >= AGS_SOUND_SCOPE_LAST){
15667     return;
15668   }
15669 
15670   pad = 0;
15671 
15672   /* check scope - input */
15673   recall_id = ags_channel_check_scope(channel, sound_scope);
15674 
15675   recycling_context = NULL;
15676 
15677   if(recall_id != NULL){
15678     AgsRecycling *recycling;
15679 
15680     GList *iter;
15681 
15682     recycling = NULL;
15683 
15684     g_object_get(channel,
15685 		 "first-recycling", &recycling,
15686 		 NULL);
15687 
15688     iter = recall_id;
15689 
15690     while(iter != NULL){
15691       AgsRecallID *current_recall_id;
15692       AgsRecyclingContext *current_recycling_context;
15693 
15694       current_recall_id = iter->data;
15695 
15696       /* get recall id mutex */
15697       recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(current_recall_id);
15698 
15699       /* get recycling context */
15700       g_rec_mutex_lock(recall_id_mutex);
15701 
15702       current_recycling_context = current_recall_id->recycling_context;
15703 
15704       g_rec_mutex_unlock(recall_id_mutex);
15705 
15706       if(ags_recycling_context_find(current_recycling_context, recycling) >= 0){
15707 	recycling_context = current_recycling_context;
15708 
15709 	break;
15710       }
15711 
15712       /* iterate */
15713       iter = iter->next;
15714     }
15715 
15716     g_object_unref(recycling);
15717 
15718     g_list_free_full(recall_id,
15719 		     g_object_unref);
15720   }
15721 
15722   /* get channel mutex */
15723   channel_mutex = AGS_CHANNEL_GET_OBJ_MUTEX(channel);
15724 
15725   /* get link and pad */
15726   g_rec_mutex_lock(channel_mutex);
15727 
15728   link = channel->link;
15729 
15730   pad = channel->pad;
15731 
15732   g_rec_mutex_unlock(channel_mutex);
15733 
15734   if((AGS_SOUND_STAGING_CHECK_RT_DATA & (staging_flags)) != 0 ||
15735      (AGS_SOUND_STAGING_RUN_INIT_PRE & (staging_flags)) != 0){
15736     if(AGS_IS_OUTPUT(channel)){
15737       if(pad == 0){
15738 	/* add recall id */
15739 	ags_channel_recursive_setup_run_stage_down(channel,
15740 						   recycling_context,
15741 						   sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_ADD_RECALL_ID);
15742 
15743 	ags_channel_recursive_setup_run_stage_up(link,
15744 						 recycling_context,
15745 						 sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_ADD_RECALL_ID);
15746 
15747 	/* duplicate */
15748 	ags_channel_recursive_prepare_run_stage_down(channel,
15749 						     recycling_context,
15750 						     sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE);
15751 
15752 	ags_channel_recursive_prepare_run_stage_up(link,
15753 						   recycling_context,
15754 						   sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE);
15755 
15756 	/* resolve */
15757 	ags_channel_recursive_prepare_run_stage_down(channel,
15758 						     recycling_context,
15759 						     sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE);
15760 
15761 	ags_channel_recursive_prepare_run_stage_up(link,
15762 						   recycling_context,
15763 						   sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE);
15764       }else{
15765 	/* add recall id */
15766 	ags_channel_recursive_setup_run_stage_up(channel,
15767 						 recycling_context,
15768 						 sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_ADD_RECALL_ID);
15769 
15770 	/* duplicate */
15771 	ags_channel_recursive_prepare_run_stage_up(channel,
15772 						   recycling_context,
15773 						   sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE);
15774 
15775 	/* resolve */
15776 	ags_channel_recursive_prepare_run_stage_up(channel,
15777 						   recycling_context,
15778 						   sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE);
15779       }
15780     }else{
15781       /* add recall id */
15782       ags_channel_recursive_prepare_run_stage_down(link,
15783 						   recycling_context,
15784 						   sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_ADD_RECALL_ID);
15785       ags_channel_recursive_prepare_run_stage_up(channel,
15786 						 recycling_context,
15787 						 sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_ADD_RECALL_ID);
15788 
15789       /* duplicate */
15790       ags_channel_recursive_prepare_run_stage_down(link,
15791 						   recycling_context,
15792 						   sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE);
15793       ags_channel_recursive_prepare_run_stage_up(channel,
15794 						 recycling_context,
15795 						 sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_DUPLICATE);
15796 
15797       /* resolve */
15798       ags_channel_recursive_prepare_run_stage_down(link,
15799 						   recycling_context,
15800 						   sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE);
15801       ags_channel_recursive_prepare_run_stage_up(channel,
15802 						 recycling_context,
15803 						 sound_scope, AGS_CHANNEL_RECURSIVE_PREPARE_STAGING_RESOLVE);
15804     }
15805   }
15806 
15807   if(AGS_IS_OUTPUT(channel)){
15808     /* do run stage - init/play recall */
15809     if(pad == 0){
15810       AgsAudio *audio;
15811       AgsChannel *start_output;
15812       AgsChannel *output, *next;
15813 
15814       ags_channel_recursive_do_run_stage_down(channel,
15815 					      recycling_context,
15816 					      sound_scope, staging_flags);
15817 
15818       audio = NULL;
15819 
15820       g_object_get(channel,
15821 		   "audio", &audio,
15822 		   NULL);
15823 
15824       output =
15825 	start_output = NULL;
15826 
15827       g_object_get(audio,
15828 		   "output", &start_output,
15829 		   NULL);
15830 
15831       if(start_output != NULL){
15832 	output = start_output;
15833 	g_object_ref(output);
15834 
15835 	while(output != NULL){
15836 	  ags_channel_set_staging_completed(output, sound_scope);
15837 
15838 	  /* iterate */
15839 	  next = ags_channel_next(output);
15840 
15841 	  g_object_unref(output);
15842 
15843 	  output = next;
15844 	}
15845       }
15846 
15847       ags_channel_recursive_do_run_stage_up(link,
15848 					    recycling_context,
15849 					    sound_scope, staging_flags);
15850 
15851       if(audio != NULL){
15852 	g_object_unref(audio);
15853       }
15854 
15855       if(start_output != NULL){
15856 	g_object_unref(start_output);
15857       }
15858     }else{
15859       while(!ags_channel_test_staging_completed(channel, sound_scope));
15860 
15861       ags_channel_recursive_do_run_stage_up(channel,
15862 					    recycling_context,
15863 					    sound_scope, staging_flags);
15864     }
15865   }else{
15866     /* do run stage - init/play recall */
15867     ags_channel_recursive_do_run_stage_down(link,
15868 					    recycling_context,
15869 					    sound_scope, staging_flags);
15870     ags_channel_recursive_do_run_stage_up(channel,
15871 					  recycling_context,
15872 					  sound_scope, staging_flags);
15873   }
15874 
15875   if((AGS_SOUND_STAGING_CANCEL & (staging_flags)) != 0){
15876     if(AGS_IS_OUTPUT(channel)){
15877       /* cancel */
15878       if(pad == 0){
15879 	ags_channel_recursive_cleanup_run_stage_down(channel,
15880 						     recycling_context,
15881 						     sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL);
15882 
15883 	ags_channel_recursive_cleanup_run_stage_up(link,
15884 						   recycling_context,
15885 						   sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL);
15886       }else{
15887 	ags_channel_recursive_cleanup_run_stage_up(channel,
15888 						   recycling_context,
15889 						   sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL);
15890       }
15891     }else{
15892       /* cancel */
15893       ags_channel_recursive_cleanup_run_stage_down(link,
15894 						   recycling_context,
15895 						   sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL);
15896       ags_channel_recursive_cleanup_run_stage_up(channel,
15897 						 recycling_context,
15898 						 sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_CANCEL_RECALL);
15899     }
15900   }
15901 
15902   if((AGS_SOUND_STAGING_REMOVE & (staging_flags)) != 0){
15903     if(AGS_IS_OUTPUT(channel)){
15904       /* remove */
15905       if(pad == 0){
15906 	ags_channel_recursive_cleanup_run_stage_down(channel,
15907 						     recycling_context,
15908 						     sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL);
15909 
15910 	ags_channel_recursive_cleanup_run_stage_up(link,
15911 						   recycling_context,
15912 						   sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL);
15913       }else{
15914 	ags_channel_recursive_cleanup_run_stage_up(channel,
15915 						   recycling_context,
15916 						   sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL);
15917       }
15918     }else{
15919       /* remove */
15920       ags_channel_recursive_cleanup_run_stage_down(link,
15921 						   recycling_context,
15922 						   sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL);
15923       ags_channel_recursive_cleanup_run_stage_up(channel,
15924 						 recycling_context,
15925 						 sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_STAGING_REMOVE_RECALL);
15926     }
15927   }
15928 
15929   if((AGS_SOUND_STAGING_FINI & (staging_flags)) != 0){
15930     if(AGS_IS_OUTPUT(channel)){
15931       if(pad == 0){
15932 	ags_channel_recursive_cleanup_run_stage_down(channel,
15933 						     recycling_context,
15934 						     sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE);
15935 
15936 	ags_channel_recursive_cleanup_run_stage_up(link,
15937 						   recycling_context,
15938 						   sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE);
15939       }else{
15940 	ags_channel_recursive_cleanup_run_stage_up(channel,
15941 						   recycling_context,
15942 						   sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE);
15943       }
15944     }else{
15945       ags_channel_recursive_cleanup_run_stage_down(link,
15946 						   recycling_context,
15947 						   sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE);
15948       ags_channel_recursive_cleanup_run_stage_up(channel,
15949 						 recycling_context,
15950 						 sound_scope, AGS_CHANNEL_RECURSIVE_CLEANUP_SCOPE);
15951     }
15952   }
15953 }
15954 
15955 /**
15956  * ags_channel_recursive_run_stage:
15957  * @channel: the #AgsChannel
15958  * @sound_scope: the sound scope
15959  * @staging_flags: the staging flags
15960  *
15961  * Recursive run stage specified by @staging_flags for matching @sound_scope.
15962  *
15963  * Since: 3.0.0
15964  */
15965 void
ags_channel_recursive_run_stage(AgsChannel * channel,gint sound_scope,guint staging_flags)15966 ags_channel_recursive_run_stage(AgsChannel *channel,
15967 				gint sound_scope, guint staging_flags)
15968 {
15969   g_return_if_fail(AGS_IS_CHANNEL(channel));
15970 
15971   g_object_ref(G_OBJECT(channel));
15972   g_signal_emit(G_OBJECT(channel),
15973 		channel_signals[RECURSIVE_RUN_STAGE], 0,
15974 		sound_scope, staging_flags);
15975   g_object_unref(G_OBJECT(channel));
15976 }
15977 
15978 /**
15979  * ags_channel_new:
15980  * @audio: the #AgsAudio
15981  *
15982  * Creates a new instance of #AgsChannel, linking tree to @audio.
15983  *
15984  * Returns: a new #AgsChannel
15985  *
15986  * Since: 3.0.0
15987  */
15988 AgsChannel*
ags_channel_new(GObject * audio)15989 ags_channel_new(GObject *audio)
15990 {
15991   AgsChannel *channel;
15992 
15993   channel = (AgsChannel *) g_object_new(AGS_TYPE_CHANNEL,
15994 					"audio", audio,
15995 					NULL);
15996 
15997   return(channel);
15998 }
15999