1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2021 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSequencer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/audio/ags_recall.h>
21 
22 #include <ags/plugin/ags_ladspa_manager.h>
23 #include <ags/plugin/ags_dssi_manager.h>
24 #include <ags/plugin/ags_lv2_manager.h>
25 
26 #include <ags/audio/ags_sound_enums.h>
27 #include <ags/audio/ags_audio.h>
28 #include <ags/audio/ags_channel.h>
29 #include <ags/audio/ags_recycling.h>
30 #include <ags/audio/ags_audio_signal.h>
31 #include <ags/audio/ags_port.h>
32 #include <ags/audio/ags_recall_id.h>
33 #include <ags/audio/ags_recycling_context.h>
34 #include <ags/audio/ags_recall_container.h>
35 #include <ags/audio/ags_recall_dependency.h>
36 #include <ags/audio/ags_recall_audio.h>
37 #include <ags/audio/ags_recall_audio_run.h>
38 #include <ags/audio/ags_recall_channel.h>
39 #include <ags/audio/ags_recall_channel_run.h>
40 #include <ags/audio/ags_recall_ladspa.h>
41 #include <ags/audio/ags_recall_dssi.h>
42 #include <ags/audio/ags_recall_lv2.h>
43 #include <ags/audio/ags_recall_recycling.h>
44 #include <ags/audio/ags_recall_audio_signal.h>
45 
46 #include <libxml/tree.h>
47 
48 #include <string.h>
49 
50 #include <ags/i18n.h>
51 
52 void ags_recall_class_init(AgsRecallClass *recall_class);
53 void ags_recall_connectable_interface_init(AgsConnectableInterface *connectable);
54 void ags_recall_init(AgsRecall *recall);
55 void ags_recall_set_property(GObject *gobject,
56 			     guint prop_id,
57 			     const GValue *value,
58 			     GParamSpec *param_spec);
59 void ags_recall_get_property(GObject *gobject,
60 			     guint prop_id,
61 			     GValue *value,
62 			     GParamSpec *param_spec);
63 void ags_recall_dispose(GObject *gobject);
64 void ags_recall_finalize(GObject *gobject);
65 
66 AgsUUID* ags_recall_get_uuid(AgsConnectable *connectable);
67 gboolean ags_recall_has_resource(AgsConnectable *connectable);
68 gboolean ags_recall_is_ready(AgsConnectable *connectable);
69 void ags_recall_add_to_registry(AgsConnectable *connectable);
70 void ags_recall_remove_from_registry(AgsConnectable *connectable);
71 xmlNode* ags_recall_list_resource(AgsConnectable *connectable);
72 xmlNode* ags_recall_xml_compose(AgsConnectable *connectable);
73 void ags_recall_xml_parse(AgsConnectable *connectable,
74 			  xmlNode *node);
75 gboolean ags_recall_is_connected(AgsConnectable *connectable);
76 void ags_recall_connect(AgsConnectable *connectable);
77 void ags_recall_disconnect(AgsConnectable *connectable);
78 
79 void ags_recall_real_resolve_dependency(AgsRecall *recall);
80 void ags_recall_real_check_rt_data(AgsRecall *recall);
81 
82 void ags_recall_real_run_init_pre(AgsRecall *recall);
83 void ags_recall_real_run_init_inter(AgsRecall *recall);
84 void ags_recall_real_run_init_post(AgsRecall *recall);
85 
86 void ags_recall_real_feed_input_queue(AgsRecall *recall);
87 void ags_recall_real_automate(AgsRecall *recall);
88 
89 void ags_recall_real_run_pre(AgsRecall *recall);
90 void ags_recall_real_run_inter(AgsRecall *recall);
91 void ags_recall_real_run_post(AgsRecall *recall);
92 
93 void ags_recall_real_do_feedback(AgsRecall *recall);
94 void ags_recall_real_feed_output_queue(AgsRecall *recall);
95 
96 void ags_recall_real_stop_persistent(AgsRecall *recall);
97 void ags_recall_real_cancel(AgsRecall *recall);
98 void ags_recall_real_done(AgsRecall *recall);
99 
100 AgsRecall* ags_recall_real_duplicate(AgsRecall *reall,
101 				     AgsRecallID *recall_id,
102 				     guint *n_params, gchar **parameter_name, GValue *value);
103 
104 void ags_recall_child_done(AgsRecall *child,
105 			   AgsRecall *parent);
106 
107 /**
108  * SECTION:ags_recall
109  * @short_description: The recall base class
110  * @title: AgsRecall
111  * @section_id:
112  * @include: ags/audio/ags_recall.h
113  *
114  * #AgsRecall acts as effect processor.
115  */
116 
117 enum{
118   PLAY_RESOLVE_DEPENDENCY,
119   PLAY_CHECK_RT_DATA,
120   PLAY_RUN_INIT_PRE,
121   PLAY_RUN_INIT_INTER,
122   PLAY_RUN_INIT_POST,
123   PLAY_FEED_INPUT_QUEUE,
124   PLAY_AUTOMATE,
125   PLAY_RUN_PRE,
126   PLAY_RUN_INTER,
127   PLAY_RUN_POST,
128   PLAY_DO_FEEDBACK,
129   PLAY_FEED_OUTPUT_QUEUE,
130   PLAY_STOP_PERSISTENT,
131   PLAY_CANCEL,
132   PLAY_DONE,
133   PLAY_DUPLICATE,
134   PLAY_NOTIFY_DEPENDENCY,
135   CHILD_ADDED,
136   LAST_SIGNAL,
137 };
138 
139 enum{
140   PROP_0,
141   PROP_FILENAME,
142   PROP_EFFECT,
143   PROP_EFFECT_INDEX,
144   PROP_RECALL_CONTAINER,
145   PROP_OUTPUT_SOUNDCARD,
146   PROP_OUTPUT_SOUNDCARD_CHANNEL,
147   PROP_INPUT_SOUNDCARD,
148   PROP_INPUT_SOUNDCARD_CHANNEL,
149   PROP_SAMPLERATE,
150   PROP_BUFFER_SIZE,
151   PROP_FORMAT,
152   PROP_PAD,
153   PROP_AUDIO_CHANNEL,
154   PROP_LINE,
155   PROP_PORT,
156   PROP_AUTOMATION_PORT,
157   PROP_RECALL_ID,
158   PROP_RECALL_DEPENDENCY,
159   PROP_PARENT,
160   PROP_CHILD_TYPE,
161   PROP_CHILD,
162 };
163 
164 static gpointer ags_recall_parent_class = NULL;
165 static guint recall_signals[LAST_SIGNAL];
166 
167 static gboolean ags_recall_global_children_lock_free = FALSE;
168 static gboolean ags_recall_global_omit_event = TRUE;
169 static gboolean ags_recall_global_performance_mode = FALSE;
170 static gboolean ags_recall_global_rt_safe = FALSE;
171 
172 GType
ags_recall_get_type(void)173 ags_recall_get_type(void)
174 {
175   static volatile gsize g_define_type_id__volatile = 0;
176 
177   if(g_once_init_enter (&g_define_type_id__volatile)){
178     GType ags_type_recall = 0;
179 
180     static const GTypeInfo ags_recall_info = {
181       sizeof (AgsRecallClass),
182       NULL, /* base_init */
183       NULL, /* base_finalize */
184       (GClassInitFunc) ags_recall_class_init,
185       NULL, /* class_finalize */
186       NULL, /* class_data */
187       sizeof (AgsRecall),
188       0,    /* n_preallocs */
189       (GInstanceInitFunc) ags_recall_init,
190     };
191 
192     static const GInterfaceInfo ags_connectable_interface_info = {
193       (GInterfaceInitFunc) ags_recall_connectable_interface_init,
194       NULL, /* interface_finalize */
195       NULL, /* interface_data */
196     };
197 
198     ags_type_recall = g_type_register_static(G_TYPE_OBJECT,
199 					     "AgsRecall",
200 					     &ags_recall_info,
201 					     0);
202 
203     g_type_add_interface_static(ags_type_recall,
204 				AGS_TYPE_CONNECTABLE,
205 				&ags_connectable_interface_info);
206 
207     g_once_init_leave(&g_define_type_id__volatile, ags_type_recall);
208   }
209 
210   return g_define_type_id__volatile;
211 }
212 
213 GType
ags_recall_flags_get_type()214 ags_recall_flags_get_type()
215 {
216   static volatile gsize g_flags_type_id__volatile;
217 
218   if(g_once_init_enter (&g_flags_type_id__volatile)){
219     static const GFlagsValue values[] = {
220       { AGS_RECALL_ADDED_TO_REGISTRY, "AGS_RECALL_ADDED_TO_REGISTRY", "recall-added-to-registry" },
221       { AGS_RECALL_CONNECTED, "AGS_RECALL_CONNECTED", "recall-connected" },
222       { AGS_RECALL_TEMPLATE, "AGS_RECALL_TEMPLATE", "recall-template" },
223       { AGS_RECALL_DEFAULT_TEMPLATE, "AGS_RECALL_DEFAULT_TEMPLATE", "recall-default-template" },
224       { AGS_RECALL_HAS_OUTPUT_PORT, "AGS_RECALL_HAS_OUTPUT_PORT", "recall-has-output-port" },
225       { AGS_RECALL_BYPASS, "AGS_RECALL_BYPASS", "recall-bypass" },
226       { AGS_RECALL_INITIAL_RUN, "AGS_RECALL_INITIAL_RUN", "recall-initial-run" },
227       { 0, NULL, NULL }
228     };
229 
230     GType g_flags_type_id = g_flags_register_static(g_intern_static_string("AgsRecallFlags"), values);
231 
232     g_once_init_leave (&g_flags_type_id__volatile, g_flags_type_id);
233   }
234 
235   return g_flags_type_id__volatile;
236 }
237 
238 GType
ags_recall_notify_dependency_mode_get_type()239 ags_recall_notify_dependency_mode_get_type()
240 {
241   static volatile gsize g_flags_type_id__volatile;
242 
243   if(g_once_init_enter (&g_flags_type_id__volatile)){
244     static const GFlagsValue values[] = {
245       { AGS_RECALL_NOTIFY_RUN, "AGS_RECALL_NOTIFY_RUN", "recall-notify-run" },
246       { AGS_RECALL_NOTIFY_AUDIO, "AGS_RECALL_NOTIFY_AUDIO", "recall-notify-audio" },
247       { AGS_RECALL_NOTIFY_AUDIO_RUN, "AGS_RECALL_NOTIFY_AUDIO_RUN", "recall-notify-audio-run" },
248       { AGS_RECALL_NOTIFY_CHANNEL, "AGS_RECALL_NOTIFY_CHANNEL", "recall-notify-channel" },
249       { AGS_RECALL_NOTIFY_CHANNEL_RUN, "AGS_RECALL_NOTIFY_CHANNEL_RUN", "recall-notify-channel-run" },
250       { AGS_RECALL_NOTIFY_RECALL, "AGS_RECALL_NOTIFY_RECALL", "recall-notify-recall" },
251       { 0, NULL, NULL }
252     };
253 
254     GType g_flags_type_id = g_flags_register_static(g_intern_static_string("AgsRecallNotifyDependencyMode"), values);
255 
256     g_once_init_leave (&g_flags_type_id__volatile, g_flags_type_id);
257   }
258 
259   return g_flags_type_id__volatile;
260 }
261 
262 void
ags_recall_class_init(AgsRecallClass * recall)263 ags_recall_class_init(AgsRecallClass *recall)
264 {
265   GObjectClass *gobject;
266 
267   GParamSpec *param_spec;
268 
269   ags_recall_parent_class = g_type_class_peek_parent(recall);
270 
271   /* GObjectClass */
272   gobject = (GObjectClass *) recall;
273 
274   gobject->set_property = ags_recall_set_property;
275   gobject->get_property = ags_recall_get_property;
276 
277   gobject->dispose = ags_recall_dispose;
278   gobject->finalize = ags_recall_finalize;
279 
280   /* properties */
281   /**
282    * AgsRecall:filename:
283    *
284    * The plugin's filename.
285    *
286    * Since: 3.0.0
287    */
288   param_spec = g_param_spec_string("filename",
289 				   i18n_pspec("the object file"),
290 				   i18n_pspec("The filename as string of object file"),
291 				   NULL,
292 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
293   g_object_class_install_property(gobject,
294 				  PROP_FILENAME,
295 				  param_spec);
296 
297   /**
298    * AgsRecall:effect:
299    *
300    * The plugin's effect.
301    *
302    * Since: 3.0.0
303    */
304   param_spec = g_param_spec_string("effect",
305 				   i18n_pspec("the effect"),
306 				   i18n_pspec("The effect's string representation"),
307 				   NULL,
308 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
309   g_object_class_install_property(gobject,
310 				  PROP_EFFECT,
311 				  param_spec);
312 
313   /**
314    * AgsRecall:effect-index:
315    *
316    * The effect's index.
317    *
318    * Since: 3.0.0
319    */
320   param_spec = g_param_spec_uint("effect-index",
321 				 i18n_pspec("index of effect"),
322 				 i18n_pspec("The numerical index of effect"),
323 				 0,
324 				 G_MAXUINT32,
325 				 0,
326 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
327   g_object_class_install_property(gobject,
328 				  PROP_EFFECT_INDEX,
329 				  param_spec);
330 
331   /**
332    * AgsRecall:recall-container:
333    *
334    * The #AgsRecallContainer packed into.
335    *
336    * Since: 3.0.0
337    */
338   param_spec = g_param_spec_object("recall-container",
339 				   i18n_pspec("container of recall"),
340 				   i18n_pspec("The container which this recall is packed into"),
341 				   AGS_TYPE_RECALL_CONTAINER,
342 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
343   g_object_class_install_property(gobject,
344 				  PROP_RECALL_CONTAINER,
345 				  param_spec);
346 
347   /**
348    * AgsRecall:output-soundcard:
349    *
350    * The assigned soundcard.
351    *
352    * Since: 3.0.0
353    */
354   param_spec = g_param_spec_object("output-soundcard",
355 				   i18n_pspec("output soundcard"),
356 				   i18n_pspec("The output soundcard which this recall is packed into"),
357 				   G_TYPE_OBJECT,
358 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
359   g_object_class_install_property(gobject,
360 				  PROP_OUTPUT_SOUNDCARD,
361 				  param_spec);
362 
363   /**
364    * AgsRecall:output-soundcard-channel:
365    *
366    * The output soundcard channel.
367    *
368    * Since: 3.0.0
369    */
370   param_spec = g_param_spec_int("output-soundcard-channel",
371 				i18n_pspec("output soundcard channel"),
372 				i18n_pspec("The output soundcard channel"),
373 				-1,
374 				G_MAXINT32,
375 				-1,
376 				G_PARAM_READABLE | G_PARAM_WRITABLE);
377   g_object_class_install_property(gobject,
378 				  PROP_OUTPUT_SOUNDCARD_CHANNEL,
379 				  param_spec);
380 
381   /**
382    * AgsRecall:input-soundcard:
383    *
384    * The assigned soundcard.
385    *
386    * Since: 3.0.0
387    */
388   param_spec = g_param_spec_object("input-soundcard",
389 				   i18n_pspec("input soundcard"),
390 				   i18n_pspec("The input soundcard which this recall is packed into"),
391 				   G_TYPE_OBJECT,
392 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
393   g_object_class_install_property(gobject,
394 				  PROP_INPUT_SOUNDCARD,
395 				  param_spec);
396 
397   /**
398    * AgsRecall:input-soundcard-channel:
399    *
400    * The input soundcard channel.
401    *
402    * Since: 3.0.0
403    */
404   param_spec = g_param_spec_int("input-soundcard-channel",
405 				i18n_pspec("input soundcard channel"),
406 				i18n_pspec("The input soundcard channel"),
407 				-1,
408 				G_MAXINT32,
409 				-1,
410 				G_PARAM_READABLE | G_PARAM_WRITABLE);
411   g_object_class_install_property(gobject,
412 				  PROP_INPUT_SOUNDCARD_CHANNEL,
413 				  param_spec);
414 
415   /**
416    * AgsRecall:samplerate:
417    *
418    * The samplerate.
419    *
420    * Since: 3.0.0
421    */
422   param_spec = g_param_spec_uint("samplerate",
423 				 i18n_pspec("samplerate"),
424 				 i18n_pspec("The samplerate"),
425 				 0,
426 				 G_MAXUINT32,
427 				 0,
428 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
429   g_object_class_install_property(gobject,
430 				  PROP_SAMPLERATE,
431 				  param_spec);
432 
433   /**
434    * AgsRecall:buffer-size:
435    *
436    * The buffer size.
437    *
438    * Since: 3.0.0
439    */
440   param_spec = g_param_spec_uint("buffer-size",
441 				 i18n_pspec("buffer size"),
442 				 i18n_pspec("The buffer size"),
443 				 0,
444 				 G_MAXUINT32,
445 				 0,
446 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
447   g_object_class_install_property(gobject,
448 				  PROP_BUFFER_SIZE,
449 				  param_spec);
450 
451   /**
452    * AgsRecall:format:
453    *
454    * The format.
455    *
456    * Since: 3.0.0
457    */
458   param_spec = g_param_spec_uint("format",
459 				 i18n_pspec("format"),
460 				 i18n_pspec("The format"),
461 				 0,
462 				 G_MAXUINT32,
463 				 0,
464 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
465   g_object_class_install_property(gobject,
466 				  PROP_FORMAT,
467 				  param_spec);
468 
469   /**
470    * AgsRecall:pad:
471    *
472    * The nth pad.
473    *
474    * Since: 3.0.0
475    */
476   param_spec =  g_param_spec_uint("pad",
477 				  i18n_pspec("nth pad"),
478 				  i18n_pspec("The nth pad"),
479 				  0,
480 				  G_MAXUINT32,
481 				  0,
482 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
483   g_object_class_install_property(gobject,
484 				  PROP_PAD,
485 				  param_spec);
486 
487   /**
488    * AgsRecall:audio-channel:
489    *
490    * The nth audio channel.
491    *
492    * Since: 3.0.0
493    */
494   param_spec =  g_param_spec_uint("audio-channel",
495 				  i18n_pspec("nth audio channel"),
496 				  i18n_pspec("The nth audio channel"),
497 				  0,
498 				  G_MAXUINT32,
499 				  0,
500 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
501   g_object_class_install_property(gobject,
502 				  PROP_AUDIO_CHANNEL,
503 				  param_spec);
504 
505   /**
506    * AgsRecall:line:
507    *
508    * The nth line.
509    *
510    * Since: 3.0.0
511    */
512   param_spec =  g_param_spec_uint("line",
513 				  i18n_pspec("nth line"),
514 				  i18n_pspec("The nth line"),
515 				  0,
516 				  G_MAXUINT32,
517 				  0,
518 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
519   g_object_class_install_property(gobject,
520 				  PROP_LINE,
521 				  param_spec);
522 
523   /**
524    * AgsRecall:port: (type GList(AgsPort)) (transfer full)
525    *
526    * The assigned #AgsPort
527    *
528    * Since: 3.0.0
529    */
530   param_spec = g_param_spec_pointer("port",
531 				    i18n_pspec("port of recall"),
532 				    i18n_pspec("The port of recall"),
533 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
534   g_object_class_install_property(gobject,
535 				  PROP_PORT,
536 				  param_spec);
537 
538   /**
539    * AgsRecall:automation-port: (type GList(AgsPort)) (transfer full)
540    *
541    * The #AgsPort doing automation.
542    *
543    * Since: 3.0.0
544    */
545   param_spec = g_param_spec_pointer("automation-port",
546 				    i18n_pspec("automation port"),
547 				    i18n_pspec("The port doing automation"),
548 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
549   g_object_class_install_property(gobject,
550 				  PROP_AUTOMATION_PORT,
551 				  param_spec);
552 
553   /**
554    * AgsRecall:recall-id:
555    *
556    * The #AgsRecallID running in.
557    *
558    * Since: 3.0.0
559    */
560   param_spec = g_param_spec_object("recall-id",
561 				   i18n_pspec("run id of recall"),
562 				   i18n_pspec("The recall id of the recall"),
563 				   AGS_TYPE_RECALL_ID,
564 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
565   g_object_class_install_property(gobject,
566 				  PROP_RECALL_ID,
567 				  param_spec);
568 
569   /**
570    * AgsRecall:recall-dependency: (type GList(AgsRecallDependency)) (transfer full)
571    *
572    * The #AgsRecallDependency.
573    *
574    * Since: 3.0.0
575    */
576   param_spec = g_param_spec_pointer("recall-dependency",
577 				    i18n_pspec("recall dependency"),
578 				    i18n_pspec("The assigned recall dependency"),
579 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
580   g_object_class_install_property(gobject,
581 				  PROP_RECALL_DEPENDENCY,
582 				  param_spec);
583 
584   /**
585    * AgsRecall:parent:
586    *
587    * The parent #AgsRecall.
588    *
589    * Since: 3.0.0
590    */
591   param_spec = g_param_spec_object("parent",
592 				   i18n_pspec("parent recall of this recall"),
593 				   i18n_pspec("The recall should be the parent instance of this recall"),
594 				   AGS_TYPE_RECALL,
595 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
596   g_object_class_install_property(gobject,
597 				  PROP_PARENT,
598 				  param_spec);
599 
600   /**
601    * AgsRecall:child-type:
602    *
603    * The type of child #AgsRecall.
604    *
605    * Since: 3.0.0
606    */
607   param_spec = g_param_spec_gtype("child-type",
608 				  i18n_pspec("child type"),
609 				  i18n_pspec("The type of child that can be added"),
610 				  G_TYPE_NONE,
611 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
612   g_object_class_install_property(gobject,
613 				  PROP_CHILD_TYPE,
614 				  param_spec);
615 
616   /**
617    * AgsRecall:child: (type GList(AgsRecall)) (transfer full)
618    *
619    * The child #AgsRecall.
620    *
621    * Since: 3.0.0
622    */
623   param_spec = g_param_spec_pointer("child",
624 				    i18n_pspec("child of recall"),
625 				    i18n_pspec("The child that can be added"),
626 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
627   g_object_class_install_property(gobject,
628 				  PROP_CHILD,
629 				  param_spec);
630 
631   /* AgsRecallClass */
632   recall->resolve_dependency = ags_recall_real_resolve_dependency;
633   recall->check_rt_data = ags_recall_real_check_rt_data;
634 
635   recall->run_init_pre = ags_recall_real_run_init_pre;
636   recall->run_init_inter = ags_recall_real_run_init_inter;
637   recall->run_init_post = ags_recall_real_run_init_post;
638 
639   recall->feed_input_queue = ags_recall_real_feed_input_queue;
640   recall->automate = ags_recall_real_automate;
641 
642   recall->run_pre = ags_recall_real_run_pre;
643   recall->run_inter = ags_recall_real_run_inter;
644   recall->run_post = ags_recall_real_run_post;
645 
646   recall->do_feedback = ags_recall_real_do_feedback;
647   recall->feed_output_queue = ags_recall_real_feed_output_queue;
648 
649   recall->stop_persistent = ags_recall_real_stop_persistent;
650   recall->cancel = ags_recall_real_cancel;
651   recall->done = ags_recall_real_done;
652 
653   recall->duplicate = ags_recall_real_duplicate;
654 
655   recall->notify_dependency = NULL;
656 
657   recall->child_added = NULL;
658 
659   /* signals */
660   /**
661    * AgsRecall::resolve-dependency:
662    * @recall: the #AgsRecall to resolve
663    *
664    * The ::resolve-dependency signal notifies about resolving
665    * dependency.
666    *
667    * Since: 3.0.0
668    */
669   recall_signals[PLAY_RESOLVE_DEPENDENCY] =
670     g_signal_new("resolve-dependency",
671 		 G_TYPE_FROM_CLASS(recall),
672 		 G_SIGNAL_RUN_LAST,
673 		 G_STRUCT_OFFSET(AgsRecallClass, resolve_dependency),
674 		 NULL, NULL,
675 		 g_cclosure_marshal_VOID__VOID,
676 		 G_TYPE_NONE, 0);
677 
678   /**
679    * AgsRecall::check-rt-data:
680    * @recall: the #AgsRecall to initialize
681    *
682    * The ::check-rt-data signal notifies about initializing
683    * stage 0.
684    *
685    * Since: 3.0.0
686    */
687   recall_signals[PLAY_CHECK_RT_DATA] =
688     g_signal_new("check-rt-data",
689 		 G_TYPE_FROM_CLASS(recall),
690 		 G_SIGNAL_RUN_LAST,
691 		 G_STRUCT_OFFSET(AgsRecallClass, check_rt_data),
692 		 NULL, NULL,
693 		 g_cclosure_marshal_VOID__VOID,
694 		 G_TYPE_NONE, 0);
695 
696   /**
697    * AgsRecall::run-init-pre:
698    * @recall: the #AgsRecall to initialize
699    *
700    * The ::run-init-pre signal notifies about initializing
701    * stage 0.
702    *
703    * Since: 3.0.0
704    */
705   recall_signals[PLAY_RUN_INIT_PRE] =
706     g_signal_new("run-init-pre",
707 		 G_TYPE_FROM_CLASS(recall),
708 		 G_SIGNAL_RUN_LAST,
709 		 G_STRUCT_OFFSET(AgsRecallClass, run_init_pre),
710 		 NULL, NULL,
711 		 g_cclosure_marshal_VOID__VOID,
712 		 G_TYPE_NONE, 0);
713 
714   /**
715    * AgsRecall::run-init-inter:
716    * @recall: the #AgsRecall to initialize
717    *
718    * The ::run-init-inter signal notifies about initializing
719    * stage 1.
720    *
721    * Since: 3.0.0
722    */
723   recall_signals[PLAY_RUN_INIT_INTER] =
724     g_signal_new("run-init-inter",
725 		 G_TYPE_FROM_CLASS(recall),
726 		 G_SIGNAL_RUN_LAST,
727 		 G_STRUCT_OFFSET(AgsRecallClass, run_init_inter),
728 		 NULL, NULL,
729 		 g_cclosure_marshal_VOID__VOID,
730 		 G_TYPE_NONE, 0);
731 
732   /**
733    * AgsRecall::run-init-post:
734    * @recall: the #AgsRecall to initialize
735    *
736    * The ::run-init-post signal notifies about initializing
737    * stage 2.
738    *
739    * Since: 3.0.0
740    */
741   recall_signals[PLAY_RUN_INIT_POST] =
742     g_signal_new("run-init-post",
743 		 G_TYPE_FROM_CLASS(recall),
744 		 G_SIGNAL_RUN_LAST,
745 		 G_STRUCT_OFFSET(AgsRecallClass, run_init_post),
746 		 NULL, NULL,
747 		 g_cclosure_marshal_VOID__VOID,
748 		 G_TYPE_NONE, 0);
749 
750   /**
751    * AgsRecall::feed-input-queue:
752    * @recall: the #AgsRecall to play
753    *
754    * The ::feed-input-queue signal notifies about running
755    * feed input queue.
756    *
757    * Since: 3.0.0
758    */
759   recall_signals[PLAY_FEED_INPUT_QUEUE] =
760     g_signal_new("feed-input-queue",
761 		 G_TYPE_FROM_CLASS(recall),
762 		 G_SIGNAL_RUN_LAST,
763 		 G_STRUCT_OFFSET(AgsRecallClass, feed_input_queue),
764 		 NULL, NULL,
765 		 g_cclosure_marshal_VOID__VOID,
766 		 G_TYPE_NONE, 0);
767 
768   /**
769    * AgsRecall::automate:
770    * @recall: the #AgsRecall to play
771    *
772    * The ::automate signal notifies about running
773    * automation and is normally called during ::run-pre.
774    *
775    * Since: 3.0.0
776    */
777   recall_signals[PLAY_AUTOMATE] =
778     g_signal_new("automate",
779 		 G_TYPE_FROM_CLASS(recall),
780 		 G_SIGNAL_RUN_LAST,
781 		 G_STRUCT_OFFSET(AgsRecallClass, automate),
782 		 NULL, NULL,
783 		 g_cclosure_marshal_VOID__VOID,
784 		 G_TYPE_NONE, 0);
785 
786   /**
787    * AgsRecall::run-pre:
788    * @recall: the #AgsRecall to play
789    *
790    * The ::run-pre signal notifies about running
791    * stage 0.
792    *
793    * Since: 3.0.0
794    */
795   recall_signals[PLAY_RUN_PRE] =
796     g_signal_new("run-pre",
797 		 G_TYPE_FROM_CLASS(recall),
798 		 G_SIGNAL_RUN_LAST,
799 		 G_STRUCT_OFFSET(AgsRecallClass, run_pre),
800 		 NULL, NULL,
801 		 g_cclosure_marshal_VOID__VOID,
802 		 G_TYPE_NONE, 0);
803 
804   /**
805    * AgsRecall::run-inter:
806    * @recall: the #AgsRecall to play
807    *
808    * The ::run-inter signal notifies about running
809    * stage 1.
810    *
811    * Since: 3.0.0
812    */
813   recall_signals[PLAY_RUN_INTER] =
814     g_signal_new("run-inter",
815 		 G_TYPE_FROM_CLASS(recall),
816 		 G_SIGNAL_RUN_LAST,
817 		 G_STRUCT_OFFSET(AgsRecallClass, run_inter),
818 		 NULL, NULL,
819 		 g_cclosure_marshal_VOID__VOID,
820 		 G_TYPE_NONE, 0);
821 
822   /**
823    * AgsRecall::run-post:
824    * @recall: the #AgsRecall to play
825    *
826    * The ::run-post signal notifies about running
827    * stage 2.
828    *
829    * Since: 3.0.0
830    */
831   recall_signals[PLAY_RUN_POST] =
832     g_signal_new("run-post",
833 		 G_TYPE_FROM_CLASS(recall),
834 		 G_SIGNAL_RUN_LAST,
835 		 G_STRUCT_OFFSET(AgsRecallClass, run_post),
836 		 NULL, NULL,
837 		 g_cclosure_marshal_VOID__VOID,
838 		 G_TYPE_NONE, 0);
839 
840   /**
841    * AgsRecall::do-feedback:
842    * @recall: the #AgsRecall to play
843    *
844    * The ::do-feedback signal notifies about running
845    * stage 2.
846    *
847    * Since: 3.0.0
848    */
849   recall_signals[PLAY_DO_FEEDBACK] =
850     g_signal_new("do-feedback",
851 		 G_TYPE_FROM_CLASS(recall),
852 		 G_SIGNAL_RUN_LAST,
853 		 G_STRUCT_OFFSET(AgsRecallClass, do_feedback),
854 		 NULL, NULL,
855 		 g_cclosure_marshal_VOID__VOID,
856 		 G_TYPE_NONE, 0);
857 
858   /**
859    * AgsRecall::feed-output-queue:
860    * @recall: the #AgsRecall to play
861    *
862    * The ::feed-output-queue signal notifies about running
863    * feed output queue.
864    *
865    * Since: 3.0.0
866    */
867   recall_signals[PLAY_FEED_OUTPUT_QUEUE] =
868     g_signal_new("feed-output-queue",
869 		 G_TYPE_FROM_CLASS(recall),
870 		 G_SIGNAL_RUN_LAST,
871 		 G_STRUCT_OFFSET(AgsRecallClass, feed_output_queue),
872 		 NULL, NULL,
873 		 g_cclosure_marshal_VOID__VOID,
874 		 G_TYPE_NONE, 0);
875 
876   /**
877    * AgsRecall::stop-persistent:
878    * @recall: the #AgsRecall stop playback
879    *
880    * The ::stop-persistent signal notifies about definitively
881    * stopping playback.
882    *
883    * Since: 3.0.0
884    */
885   recall_signals[PLAY_STOP_PERSISTENT] =
886     g_signal_new("stop_persistent",
887 		 G_TYPE_FROM_CLASS(recall),
888 		 G_SIGNAL_RUN_LAST,
889 		 G_STRUCT_OFFSET(AgsRecallClass, stop_persistent),
890 		 NULL, NULL,
891 		 g_cclosure_marshal_VOID__VOID,
892 		 G_TYPE_NONE, 0);
893 
894   /**
895    * AgsRecall::cancel:
896    * @recall: the #AgsRecall to cancel playback
897    *
898    * The ::cancel signal notifies about cancelling playback.
899    *
900    * Since: 3.0.0
901    */
902   recall_signals[PLAY_CANCEL] =
903     g_signal_new("cancel",
904 		 G_TYPE_FROM_CLASS(recall),
905 		 G_SIGNAL_RUN_LAST,
906 		 G_STRUCT_OFFSET(AgsRecallClass, cancel),
907 		 NULL, NULL,
908 		 g_cclosure_marshal_VOID__VOID,
909 		 G_TYPE_NONE, 0);
910 
911   /**
912    * AgsRecall::done:
913    * @recall: the #AgsRecall to finish playback
914    *
915    * The ::done signal notifies about stopping playback.
916    *
917    * Since: 3.0.0
918    */
919   recall_signals[PLAY_DONE] =
920     g_signal_new("done",
921 		 G_TYPE_FROM_CLASS(recall),
922 		 G_SIGNAL_RUN_LAST,
923 		 G_STRUCT_OFFSET(AgsRecallClass, done),
924 		 NULL, NULL,
925 		 g_cclosure_marshal_VOID__VOID,
926 		 G_TYPE_NONE, 0);
927 
928   /**
929    * AgsRecall::duplicate:
930    * @recall: the #AgsRecall to duplicate
931    * @recall_id: the assigned #AgsRecallID
932    * @n_params: pointer to array length
933    * @parameter_name: parameter name string vector
934    * @value: the #GValue-struct array
935    *
936    * The ::duplicate signal notifies about instantiating.
937    *
938    * Returns: (transfer full): the new #AgsRecall instance
939    *
940    * Since: 3.0.0
941    */
942   recall_signals[PLAY_DUPLICATE] =
943     g_signal_new("duplicate",
944 		 G_TYPE_FROM_CLASS(recall),
945 		 G_SIGNAL_RUN_LAST,
946 		 G_STRUCT_OFFSET(AgsRecallClass, duplicate),
947 		 NULL, NULL,
948 		 ags_cclosure_marshal_OBJECT__OBJECT_POINTER_POINTER_POINTER,
949 		 G_TYPE_OBJECT, 4,
950 		 G_TYPE_OBJECT,
951 		 G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
952 
953   /**
954    * AgsRecall::notify-dependency:
955    * @recall: the #AgsRecall to notify
956    * @dependency: the kind of dependency
957    * @increase: if %TRUE increase dependency count, else if %FALSE decrease
958    *
959    * The ::notify-dependency signal notifies about dependency
960    * added.
961    *
962    * Since: 3.0.0
963    */
964   recall_signals[PLAY_NOTIFY_DEPENDENCY] =
965     g_signal_new("notify-dependency",
966 		 G_TYPE_FROM_CLASS(recall),
967 		 G_SIGNAL_RUN_LAST,
968 		 G_STRUCT_OFFSET(AgsRecallClass, notify_dependency),
969 		 NULL, NULL,
970 		 ags_cclosure_marshal_VOID__UINT_BOOLEAN,
971 		 G_TYPE_NONE, 2,
972 		 G_TYPE_UINT, G_TYPE_BOOLEAN);
973 
974   /**
975    * AgsRecall::child-added:
976    * @recall: the #AgsRecall to add the child
977    * @child: the #AgsRecall to add
978    *
979    * The ::child-added signal notifies about children
980    * added.
981    *
982    * Since: 3.0.0
983    */
984   recall_signals[CHILD_ADDED] =
985     g_signal_new("child-added",
986 		 G_TYPE_FROM_CLASS(recall),
987 		 G_SIGNAL_RUN_LAST,
988 		 G_STRUCT_OFFSET(AgsRecallClass, child_added),
989 		 NULL, NULL,
990 		 g_cclosure_marshal_VOID__OBJECT,
991 		 G_TYPE_NONE, 1,
992 		 G_TYPE_OBJECT);
993 }
994 
995 void
ags_recall_connectable_interface_init(AgsConnectableInterface * connectable)996 ags_recall_connectable_interface_init(AgsConnectableInterface *connectable)
997 {
998   connectable->get_uuid = ags_recall_get_uuid;
999   connectable->has_resource = ags_recall_has_resource;
1000 
1001   connectable->is_ready = ags_recall_is_ready;
1002   connectable->add_to_registry = ags_recall_add_to_registry;
1003   connectable->remove_from_registry = ags_recall_remove_from_registry;
1004 
1005   connectable->list_resource = ags_recall_list_resource;
1006   connectable->xml_compose = ags_recall_xml_compose;
1007   connectable->xml_parse = ags_recall_xml_parse;
1008 
1009   connectable->is_connected = ags_recall_is_connected;
1010   connectable->connect = ags_recall_connect;
1011   connectable->disconnect = ags_recall_disconnect;
1012 
1013   connectable->connect_connection = NULL;
1014   connectable->disconnect_connection = NULL;
1015 }
1016 
1017 void
ags_recall_init(AgsRecall * recall)1018 ags_recall_init(AgsRecall *recall)
1019 {
1020   recall->flags = 0;
1021   recall->ability_flags = 0;
1022   recall->behaviour_flags = 0;
1023   recall->sound_scope = -1;
1024   recall->staging_flags = 0;
1025   recall->state_flags = 0;
1026 
1027   /* add recall mutex */
1028   g_rec_mutex_init(&(recall->obj_mutex));
1029 
1030   /* uuid */
1031 #if 0
1032   recall->uuid = ags_uuid_alloc();
1033   ags_uuid_generate(recall->uuid);
1034 #else
1035   recall->uuid = NULL;
1036 #endif
1037 
1038   /* version and build id */
1039   recall->version = NULL;
1040   recall->build_id = NULL;
1041 
1042   /* name */
1043   recall->name = NULL;
1044 
1045   /* filename and effect */
1046   recall->filename = NULL;
1047   recall->effect = NULL;
1048   recall->effect_index = 0;
1049 
1050   /* xml type  */
1051   recall->xml_type = NULL;
1052 
1053   /* base init */
1054   recall->recall_container = NULL;
1055 
1056   recall->output_soundcard = NULL;
1057   recall->output_soundcard_channel = 0;
1058 
1059   recall->input_soundcard = NULL;
1060   recall->input_soundcard_channel = 0;
1061 
1062 #if 0
1063   /* config */
1064   config = ags_config_get_instance();
1065 
1066   /* presets */
1067   recall->samplerate = ags_soundcard_helper_config_get_samplerate(config);
1068   recall->buffer_size = ags_soundcard_helper_config_get_buffer_size(config);
1069   recall->format = ags_soundcard_helper_config_get_format(config);
1070 #else
1071   /* presets */
1072   recall->samplerate = AGS_SOUNDCARD_DEFAULT_SAMPLERATE;
1073   recall->buffer_size = AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE;
1074   recall->format = AGS_SOUNDCARD_DEFAULT_FORMAT;
1075 #endif
1076 
1077   recall->pad = 0;
1078   recall->audio_channel = 0;
1079 
1080   recall->line = 0;
1081 
1082   /* port and automation port */
1083   recall->port = NULL;
1084   recall->automation_port = NULL;
1085 
1086   /* recall id */
1087   recall->recall_id = NULL;
1088 
1089   /* recall dependency */
1090   recall->recall_dependency = NULL;
1091 
1092   /* recall handler */
1093   recall->recall_handler = NULL;
1094 
1095   /* nested recall */
1096   recall->parent = NULL;
1097 
1098   recall->child_type = G_TYPE_NONE;
1099 
1100   recall->n_child_params = 0;
1101   recall->child_parameter_name = NULL;
1102   recall->child_value = NULL;
1103 
1104   recall->children = NULL;
1105 }
1106 
1107 void
ags_recall_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)1108 ags_recall_set_property(GObject *gobject,
1109 			guint prop_id,
1110 			const GValue *value,
1111 			GParamSpec *param_spec)
1112 {
1113   AgsRecall *recall;
1114 
1115   GRecMutex *recall_mutex;
1116 
1117   recall = AGS_RECALL(gobject);
1118 
1119   /* get recall mutex */
1120   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
1121 
1122   switch(prop_id){
1123   case PROP_FILENAME:
1124     {
1125       gchar *filename;
1126 
1127       filename = g_value_get_string(value);
1128 
1129       g_rec_mutex_lock(recall_mutex);
1130 
1131       if(filename == recall->filename){
1132 	g_rec_mutex_unlock(recall_mutex);
1133 
1134 	return;
1135       }
1136 
1137       if(recall->filename != NULL){
1138 	g_free(recall->filename);
1139       }
1140 
1141       recall->filename = g_strdup(filename);
1142 
1143       g_rec_mutex_unlock(recall_mutex);
1144     }
1145     break;
1146   case PROP_EFFECT:
1147     {
1148       gchar *effect;
1149 
1150       effect = g_value_get_string(value);
1151 
1152       g_rec_mutex_lock(recall_mutex);
1153 
1154       if(effect == recall->effect){
1155 	g_rec_mutex_unlock(recall_mutex);
1156 
1157 	return;
1158       }
1159 
1160       if(recall->effect != NULL){
1161 	g_free(recall->effect);
1162       }
1163 
1164       recall->effect = g_strdup(effect);
1165 
1166       g_rec_mutex_unlock(recall_mutex);
1167     }
1168     break;
1169   case PROP_EFFECT_INDEX:
1170     {
1171       g_rec_mutex_lock(recall_mutex);
1172 
1173       recall->effect_index = g_value_get_uint(value);
1174 
1175       g_rec_mutex_unlock(recall_mutex);
1176     }
1177     break;
1178   case PROP_RECALL_CONTAINER:
1179     {
1180       AgsRecallContainer *recall_container;
1181 
1182       recall_container = (AgsRecallContainer *) g_value_get_object(value);
1183 
1184       g_rec_mutex_lock(recall_mutex);
1185 
1186       if(recall->recall_container == (GObject *) recall_container){
1187 	g_rec_mutex_unlock(recall_mutex);
1188 
1189 	return;
1190       }
1191 
1192       if(recall->recall_container != NULL){
1193 	g_object_unref(G_OBJECT(recall->recall_container));
1194 
1195 	recall->recall_container = NULL;
1196       }
1197 
1198       if(recall_container != NULL){
1199 	g_object_ref(recall_container);
1200       }
1201 
1202       recall->recall_container = (GObject *) recall_container;
1203 
1204       g_rec_mutex_unlock(recall_mutex);
1205     }
1206     break;
1207   case PROP_OUTPUT_SOUNDCARD:
1208     {
1209       GObject *output_soundcard;
1210 
1211       output_soundcard = (GObject *) g_value_get_object(value);
1212 
1213       ags_recall_set_output_soundcard(recall,
1214 				      output_soundcard);
1215     }
1216     break;
1217   case PROP_OUTPUT_SOUNDCARD_CHANNEL:
1218     {
1219       g_rec_mutex_lock(recall_mutex);
1220 
1221       recall->output_soundcard_channel = g_value_get_int(value);
1222 
1223       g_rec_mutex_unlock(recall_mutex);
1224     }
1225     break;
1226   case PROP_INPUT_SOUNDCARD:
1227     {
1228       GObject *input_soundcard;
1229 
1230       input_soundcard = (GObject *) g_value_get_object(value);
1231 
1232       ags_recall_set_input_soundcard(recall,
1233 				     input_soundcard);
1234     }
1235     break;
1236   case PROP_INPUT_SOUNDCARD_CHANNEL:
1237     {
1238       g_rec_mutex_lock(recall_mutex);
1239 
1240       recall->input_soundcard_channel = g_value_get_int(value);
1241 
1242       g_rec_mutex_unlock(recall_mutex);
1243     }
1244     break;
1245   case PROP_SAMPLERATE:
1246     {
1247       guint samplerate;
1248 
1249       samplerate = g_value_get_uint(value);
1250 
1251       ags_recall_set_samplerate(recall,
1252 				samplerate);
1253     }
1254     break;
1255   case PROP_BUFFER_SIZE:
1256     {
1257       guint buffer_size;
1258 
1259       buffer_size = g_value_get_uint(value);
1260 
1261       ags_recall_set_buffer_size(recall,
1262 				 buffer_size);
1263     }
1264     break;
1265   case PROP_FORMAT:
1266     {
1267       guint format;
1268 
1269       format = g_value_get_uint(value);
1270 
1271       ags_recall_set_format(recall,
1272 			    format);
1273     }
1274     break;
1275   case PROP_PAD:
1276     {
1277       g_rec_mutex_lock(recall_mutex);
1278 
1279       recall->pad = g_value_get_uint(value);
1280 
1281       g_rec_mutex_unlock(recall_mutex);
1282     }
1283     break;
1284   case PROP_AUDIO_CHANNEL:
1285     {
1286       g_rec_mutex_lock(recall_mutex);
1287 
1288       recall->audio_channel = g_value_get_uint(value);
1289 
1290       g_rec_mutex_unlock(recall_mutex);
1291     }
1292     break;
1293   case PROP_LINE:
1294     {
1295       g_rec_mutex_lock(recall_mutex);
1296 
1297       recall->line = g_value_get_uint(value);
1298 
1299       g_rec_mutex_unlock(recall_mutex);
1300     }
1301     break;
1302   case PROP_PORT:
1303     {
1304       AgsPort *port;
1305 
1306       port = (AgsPort *) g_value_get_pointer(value);
1307 
1308       g_rec_mutex_lock(recall_mutex);
1309 
1310       if(!AGS_IS_PORT(port) ||
1311 	 g_list_find(recall->port, port) != NULL){
1312 	g_rec_mutex_unlock(recall_mutex);
1313 
1314 	return;
1315       }
1316 
1317       g_object_ref(port);
1318       recall->port = g_list_prepend(recall->port,
1319 				    port);
1320 
1321       g_rec_mutex_unlock(recall_mutex);
1322     }
1323     break;
1324   case PROP_AUTOMATION_PORT:
1325     {
1326       AgsPort *automation_port;
1327 
1328       automation_port = (AgsPort *) g_value_get_pointer(value);
1329 
1330       g_rec_mutex_lock(recall_mutex);
1331 
1332       if(!AGS_IS_PORT(automation_port) ||
1333 	 g_list_find(recall->automation_port, automation_port) != NULL){
1334 	g_rec_mutex_unlock(recall_mutex);
1335 
1336 	return;
1337       }
1338 
1339       g_object_ref(automation_port);
1340       recall->port = g_list_prepend(recall->automation_port,
1341 				    automation_port);
1342 
1343       g_rec_mutex_unlock(recall_mutex);
1344     }
1345     break;
1346   case PROP_RECALL_ID:
1347     {
1348       AgsRecallID *recall_id;
1349 
1350       recall_id = (AgsRecallID *) g_value_get_object(value);
1351 
1352       g_rec_mutex_lock(recall_mutex);
1353 
1354       if(recall->recall_id == recall_id){
1355 	g_rec_mutex_unlock(recall_mutex);
1356 
1357 	return;
1358       }
1359 
1360       g_rec_mutex_unlock(recall_mutex);
1361 
1362       ags_recall_set_recall_id(recall, recall_id);
1363     }
1364     break;
1365   case PROP_RECALL_DEPENDENCY:
1366     {
1367       AgsRecallDependency *recall_dependency;
1368 
1369       recall_dependency = (AgsRecallDependency *) g_value_get_pointer(value);
1370 
1371       g_rec_mutex_lock(recall_mutex);
1372 
1373       if(!AGS_IS_RECALL_DEPENDENCY(recall_dependency) ||
1374 	 g_list_find(recall->recall_dependency, recall_dependency) != NULL){
1375 	g_rec_mutex_unlock(recall_mutex);
1376 
1377 	return;
1378       }
1379 
1380       g_rec_mutex_unlock(recall_mutex);
1381 
1382       ags_recall_add_recall_dependency(recall, recall_dependency);
1383     }
1384     break;
1385   case PROP_PARENT:
1386     {
1387       AgsRecall *parent;
1388 
1389       parent = (AgsRecall *) g_value_get_object(value);
1390 
1391       g_rec_mutex_lock(recall_mutex);
1392 
1393       if(recall->parent == parent){
1394 	g_rec_mutex_unlock(recall_mutex);
1395 
1396 	return;
1397       }
1398 
1399       if(recall->parent != NULL){
1400 	g_object_unref(recall->parent);
1401       }
1402 
1403       if(parent != NULL){
1404 	g_object_ref(parent);
1405       }
1406 
1407       recall->parent = parent;
1408 
1409       g_rec_mutex_unlock(recall_mutex);
1410     }
1411     break;
1412   case PROP_CHILD_TYPE:
1413     {
1414       g_rec_mutex_lock(recall_mutex);
1415 
1416       recall->child_type = g_value_get_gtype(value);
1417 
1418       g_rec_mutex_unlock(recall_mutex);
1419     }
1420     break;
1421   case PROP_CHILD:
1422     {
1423       AgsRecall *child;
1424 
1425       child = (AgsRecall *) g_value_get_pointer(value);
1426 
1427       g_rec_mutex_lock(recall_mutex);
1428 
1429       if(!AGS_IS_RECALL(child) ||
1430 	 g_list_find(recall->children, child) != NULL){
1431 	g_rec_mutex_unlock(recall_mutex);
1432 
1433 	return;
1434       }
1435 
1436       g_rec_mutex_unlock(recall_mutex);
1437 
1438       ags_recall_add_child(recall, child);
1439     }
1440     break;
1441   default:
1442     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
1443     break;
1444   }
1445 }
1446 
1447 void
ags_recall_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)1448 ags_recall_get_property(GObject *gobject,
1449 			guint prop_id,
1450 			GValue *value,
1451 			GParamSpec *param_spec)
1452 {
1453   AgsRecall *recall;
1454 
1455   GRecMutex *recall_mutex;
1456 
1457   recall = AGS_RECALL(gobject);
1458 
1459   /* get recall mutex */
1460   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
1461 
1462   switch(prop_id){
1463   case PROP_FILENAME:
1464     {
1465       g_rec_mutex_lock(recall_mutex);
1466 
1467       g_value_set_string(value, recall->filename);
1468 
1469       g_rec_mutex_unlock(recall_mutex);
1470     }
1471     break;
1472   case PROP_EFFECT:
1473     {
1474       g_rec_mutex_lock(recall_mutex);
1475 
1476       g_value_set_string(value, recall->effect);
1477 
1478       g_rec_mutex_unlock(recall_mutex);
1479     }
1480     break;
1481   case PROP_EFFECT_INDEX:
1482     {
1483       g_rec_mutex_lock(recall_mutex);
1484 
1485       g_value_set_uint(value, recall->effect_index);
1486 
1487       g_rec_mutex_unlock(recall_mutex);
1488     }
1489     break;
1490   case PROP_RECALL_CONTAINER:
1491     {
1492       g_rec_mutex_lock(recall_mutex);
1493 
1494       g_value_set_object(value, recall->recall_container);
1495 
1496       g_rec_mutex_unlock(recall_mutex);
1497     }
1498     break;
1499   case PROP_OUTPUT_SOUNDCARD:
1500     {
1501       g_rec_mutex_lock(recall_mutex);
1502 
1503       g_value_set_object(value, recall->output_soundcard);
1504 
1505       g_rec_mutex_unlock(recall_mutex);
1506     }
1507     break;
1508   case PROP_OUTPUT_SOUNDCARD_CHANNEL:
1509     {
1510       g_rec_mutex_lock(recall_mutex);
1511 
1512       g_value_set_int(value, recall->output_soundcard_channel);
1513 
1514       g_rec_mutex_unlock(recall_mutex);
1515     }
1516     break;
1517   case PROP_INPUT_SOUNDCARD:
1518     {
1519       g_rec_mutex_lock(recall_mutex);
1520 
1521       g_value_set_object(value,
1522 			 recall->input_soundcard);
1523 
1524       g_rec_mutex_unlock(recall_mutex);
1525     }
1526     break;
1527   case PROP_INPUT_SOUNDCARD_CHANNEL:
1528     {
1529       g_rec_mutex_lock(recall_mutex);
1530 
1531       g_value_set_int(value, recall->input_soundcard_channel);
1532 
1533       g_rec_mutex_unlock(recall_mutex);
1534     }
1535     break;
1536   case PROP_SAMPLERATE:
1537     {
1538       g_rec_mutex_lock(recall_mutex);
1539 
1540       g_value_set_uint(value, recall->samplerate);
1541 
1542       g_rec_mutex_unlock(recall_mutex);
1543     }
1544     break;
1545   case PROP_BUFFER_SIZE:
1546     {
1547       g_rec_mutex_lock(recall_mutex);
1548 
1549       g_value_set_uint(value, recall->buffer_size);
1550 
1551       g_rec_mutex_unlock(recall_mutex);
1552     }
1553     break;
1554   case PROP_FORMAT:
1555     {
1556       g_rec_mutex_lock(recall_mutex);
1557 
1558       g_value_set_uint(value, recall->format);
1559 
1560       g_rec_mutex_unlock(recall_mutex);
1561     }
1562     break;
1563   case PROP_PAD:
1564     {
1565       g_rec_mutex_lock(recall_mutex);
1566 
1567       g_value_set_uint(value, recall->pad);
1568 
1569       g_rec_mutex_unlock(recall_mutex);
1570     }
1571     break;
1572   case PROP_AUDIO_CHANNEL:
1573     {
1574       g_rec_mutex_lock(recall_mutex);
1575 
1576       g_value_set_uint(value, recall->audio_channel);
1577 
1578       g_rec_mutex_unlock(recall_mutex);
1579     }
1580     break;
1581   case PROP_LINE:
1582     {
1583       g_rec_mutex_lock(recall_mutex);
1584 
1585       g_value_set_uint(value, recall->line);
1586 
1587       g_rec_mutex_unlock(recall_mutex);
1588     }
1589     break;
1590   case PROP_PORT:
1591     {
1592       g_rec_mutex_lock(recall_mutex);
1593 
1594       g_value_set_pointer(value, g_list_copy_deep(recall->port,
1595 						  (GCopyFunc) g_object_ref,
1596 						  NULL));
1597 
1598       g_rec_mutex_unlock(recall_mutex);
1599     }
1600     break;
1601   case PROP_AUTOMATION_PORT:
1602     {
1603       g_rec_mutex_lock(recall_mutex);
1604 
1605       g_value_set_pointer(value, g_list_copy_deep(recall->automation_port,
1606 						  (GCopyFunc) g_object_ref,
1607 						  NULL));
1608 
1609       g_rec_mutex_unlock(recall_mutex);
1610     }
1611     break;
1612   case PROP_RECALL_ID:
1613     {
1614       g_rec_mutex_lock(recall_mutex);
1615 
1616       g_value_set_object(value, recall->recall_id);
1617 
1618       g_rec_mutex_unlock(recall_mutex);
1619     }
1620     break;
1621   case PROP_RECALL_DEPENDENCY:
1622     {
1623       g_rec_mutex_lock(recall_mutex);
1624 
1625       g_value_set_pointer(value, g_list_copy_deep(recall->recall_dependency,
1626 						  (GCopyFunc) g_object_ref,
1627 						  NULL));
1628 
1629       g_rec_mutex_unlock(recall_mutex);
1630     }
1631     break;
1632   case PROP_PARENT:
1633     {
1634       g_rec_mutex_lock(recall_mutex);
1635 
1636       g_value_set_object(value, recall->parent);
1637 
1638       g_rec_mutex_unlock(recall_mutex);
1639     }
1640     break;
1641   case PROP_CHILD:
1642     {
1643       g_rec_mutex_lock(recall_mutex);
1644 
1645       g_value_set_pointer(value, g_list_copy_deep(recall->children,
1646 						  (GCopyFunc) g_object_ref,
1647 						  NULL));
1648 
1649       g_rec_mutex_unlock(recall_mutex);
1650     }
1651     break;
1652   case PROP_CHILD_TYPE:
1653     {
1654       g_rec_mutex_lock(recall_mutex);
1655 
1656       g_value_set_gtype(value,
1657 			recall->child_type);
1658 
1659       g_rec_mutex_unlock(recall_mutex);
1660     }
1661     break;
1662   default:
1663     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
1664     break;
1665   }
1666 }
1667 
1668 void
ags_recall_dispose(GObject * gobject)1669 ags_recall_dispose(GObject *gobject)
1670 {
1671   AgsRecall *recall;
1672 
1673   GList *start_list, *list;
1674 
1675   recall = AGS_RECALL(gobject);
1676 
1677   ags_connectable_disconnect(AGS_CONNECTABLE(recall));
1678 
1679   /* recall container */
1680   if(recall->recall_container != NULL){
1681     ags_recall_container_remove(recall->recall_container,
1682 				recall);
1683   }
1684 
1685   /* soundcard */
1686   if(recall->output_soundcard != NULL){
1687     gpointer tmp;
1688 
1689     tmp = recall->output_soundcard;
1690 
1691     recall->output_soundcard = NULL;
1692 
1693     g_object_unref(tmp);
1694   }
1695 
1696   if(recall->input_soundcard != NULL){
1697     gpointer tmp;
1698 
1699     tmp = recall->input_soundcard;
1700 
1701     recall->input_soundcard = NULL;
1702 
1703     g_object_unref(tmp);
1704   }
1705 
1706   /* port */
1707   if(recall->port != NULL){
1708     start_list = recall->port;
1709 
1710     recall->port = NULL;
1711 
1712     g_list_free_full(start_list,
1713 		     (GDestroyNotify) g_object_unref);
1714   }
1715 
1716   /* automation port */
1717   if(recall->automation_port != NULL){
1718     start_list = recall->automation_port;
1719 
1720     recall->automation_port = NULL;
1721 
1722     g_list_free_full(start_list,
1723 		     g_object_unref);
1724   }
1725 
1726   /* recall id */
1727   if(recall->recall_id != NULL){
1728     g_object_unref(recall->recall_id);
1729 
1730     recall->recall_id = NULL;
1731   }
1732 
1733   /* recall dependency */
1734   if(recall->recall_dependency != NULL){
1735     g_list_free_full(recall->recall_dependency,
1736 		     g_object_unref);
1737 
1738     recall->recall_dependency = NULL;
1739   }
1740 
1741   /* parent */
1742   if(recall->parent != NULL){
1743     ags_recall_remove_child(recall->parent,
1744 			    recall);
1745 
1746     recall->parent = NULL;
1747   }
1748 
1749   /* children */
1750   if(recall->children != NULL){
1751     list =
1752       start_list = recall->children;
1753 
1754     recall->children = NULL;
1755 
1756     while(list != NULL){
1757       g_object_run_dispose(G_OBJECT(list->data));
1758 
1759       list = list->next;
1760     }
1761 
1762     g_list_free_full(start_list,
1763 		     g_object_unref);
1764   }
1765 
1766   /* call parent */
1767   G_OBJECT_CLASS(ags_recall_parent_class)->dispose(gobject);
1768 }
1769 
1770 void
ags_recall_finalize(GObject * gobject)1771 ags_recall_finalize(GObject *gobject)
1772 {
1773   AgsRecall *recall;
1774 
1775   GList *start_list, *list;
1776 
1777   guint i;
1778 
1779   recall = AGS_RECALL(gobject);
1780 
1781 #ifdef AGS_DEBUG
1782   g_message("finalize %s", G_OBJECT_TYPE_NAME(gobject));
1783 #endif
1784 
1785   ags_uuid_free(recall->uuid);
1786 
1787   //TODO:JK: check removal
1788 #if 0
1789   guint *ids;
1790   guint i, n_ids;
1791 
1792   ids = g_signal_list_ids(AGS_TYPE_RECALL,
1793 			  &n_ids);
1794 
1795   for(i = 0; i < n_ids; i++){
1796     g_signal_handlers_disconnect_matched(gobject,
1797 					 G_SIGNAL_MATCH_ID,
1798 					 ids[i],
1799 					 0,
1800 					 NULL,
1801 					 NULL,
1802 					 NULL);
1803   }
1804 
1805   g_free(ids);
1806 #endif
1807 
1808   g_free(recall->filename);
1809   g_free(recall->effect);
1810 
1811   /* recall container */
1812   if(recall->recall_container != NULL){
1813     ags_recall_container_remove(recall->recall_container,
1814 				recall);
1815   }
1816 
1817   /* soundcard */
1818   if(recall->output_soundcard != NULL){
1819     gpointer tmp;
1820 
1821     tmp = recall->output_soundcard;
1822 
1823     recall->output_soundcard = NULL;
1824 
1825     g_object_unref(tmp);
1826   }
1827 
1828   if(recall->input_soundcard != NULL){
1829     gpointer tmp;
1830 
1831     tmp = recall->input_soundcard;
1832 
1833     recall->input_soundcard = NULL;
1834 
1835     g_object_unref(tmp);
1836   }
1837 
1838   /* port */
1839   if(recall->port != NULL){
1840     start_list = recall->port;
1841 
1842     recall->port = NULL;
1843 
1844     g_list_free_full(start_list,
1845 		     (GDestroyNotify) g_object_unref);
1846   }
1847 
1848   /* automation port */
1849   if(recall->automation_port != NULL){
1850     start_list = recall->automation_port;
1851 
1852     recall->automation_port = NULL;
1853 
1854     g_list_free_full(start_list,
1855 		     g_object_unref);
1856   }
1857 
1858   /* recall id */
1859   if(recall->recall_id != NULL){
1860     g_object_unref(recall->recall_id);
1861 
1862     recall->recall_id = NULL;
1863   }
1864 
1865   /* recall dependency */
1866   if(recall->recall_dependency != NULL){
1867     g_list_free_full(recall->recall_dependency,
1868 		     g_object_unref);
1869 
1870     recall->recall_dependency = NULL;
1871   }
1872 
1873   /* parent */
1874   if(recall->parent != NULL){
1875     ags_recall_remove_child(recall->parent,
1876 			    recall);
1877 
1878     recall->parent = NULL;
1879   }
1880 
1881   /* recall handler */
1882   g_list_free_full(recall->recall_handler,
1883 		   (GDestroyNotify) ags_recall_handler_free);
1884 
1885   /* children */
1886   if(recall->child_parameter_name != NULL){
1887     g_strfreev(recall->child_parameter_name);
1888 
1889     recall->child_parameter_name = NULL;
1890   }
1891 
1892   if(recall->child_value != NULL){
1893     for(i = 0; i < recall->n_child_params; i++){
1894       g_value_unset(&(recall->child_value[i]));
1895     }
1896 
1897     g_free(recall->child_value);
1898 
1899     recall->child_value = NULL;
1900   }
1901 
1902   if(recall->children != NULL){
1903     list =
1904       start_list = recall->children;
1905 
1906     recall->children = NULL;
1907 
1908     while(list != NULL){
1909       g_object_run_dispose(G_OBJECT(list->data));
1910 
1911       list = list->next;
1912     }
1913 
1914     g_list_free_full(start_list,
1915 		     g_object_unref);
1916   }
1917 
1918   /* call parent */
1919   G_OBJECT_CLASS(ags_recall_parent_class)->finalize(gobject);
1920 }
1921 
1922 AgsUUID*
ags_recall_get_uuid(AgsConnectable * connectable)1923 ags_recall_get_uuid(AgsConnectable *connectable)
1924 {
1925   AgsRecall *recall;
1926 
1927   AgsUUID *ptr;
1928 
1929   GRecMutex *recall_mutex;
1930 
1931   recall = AGS_RECALL(connectable);
1932 
1933   /* get recall mutex */
1934   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
1935 
1936   /* get UUID */
1937   g_rec_mutex_lock(recall_mutex);
1938 
1939   ptr = recall->uuid;
1940 
1941   g_rec_mutex_unlock(recall_mutex);
1942 
1943   return(ptr);
1944 }
1945 
1946 gboolean
ags_recall_has_resource(AgsConnectable * connectable)1947 ags_recall_has_resource(AgsConnectable *connectable)
1948 {
1949   return(TRUE);
1950 }
1951 
1952 gboolean
ags_recall_is_ready(AgsConnectable * connectable)1953 ags_recall_is_ready(AgsConnectable *connectable)
1954 {
1955   AgsRecall *recall;
1956 
1957   gboolean is_ready;
1958 
1959   recall = AGS_RECALL(connectable);
1960 
1961   /* check is added */
1962   is_ready = ags_recall_test_flags(recall, AGS_RECALL_ADDED_TO_REGISTRY);
1963 
1964   return(is_ready);
1965 }
1966 
1967 void
ags_recall_add_to_registry(AgsConnectable * connectable)1968 ags_recall_add_to_registry(AgsConnectable *connectable)
1969 {
1970   AgsRecall *recall;
1971 
1972   AgsRegistry *registry;
1973   AgsRegistryEntry *entry;
1974 
1975   AgsApplicationContext *application_context;
1976 
1977   GList *list;
1978 
1979   if(ags_connectable_is_ready(connectable)){
1980     return;
1981   }
1982 
1983   recall = AGS_RECALL(connectable);
1984 
1985   ags_recall_set_flags(recall, AGS_RECALL_ADDED_TO_REGISTRY);
1986 
1987   application_context = ags_application_context_get_instance();
1988 
1989   registry = (AgsRegistry *) ags_service_provider_get_registry(AGS_SERVICE_PROVIDER(application_context));
1990 
1991   if(registry != NULL){
1992     entry = ags_registry_entry_alloc(registry);
1993     g_value_set_object(entry->entry,
1994 		       (gpointer) recall);
1995     ags_registry_add_entry(registry,
1996 			   entry);
1997   }
1998 
1999   //TODO:JK: implement me
2000 }
2001 
2002 void
ags_recall_remove_from_registry(AgsConnectable * connectable)2003 ags_recall_remove_from_registry(AgsConnectable *connectable)
2004 {
2005   if(!ags_connectable_is_ready(connectable)){
2006     return;
2007   }
2008 
2009   //TODO:JK: implement me
2010 }
2011 
2012 xmlNode*
ags_recall_list_resource(AgsConnectable * connectable)2013 ags_recall_list_resource(AgsConnectable *connectable)
2014 {
2015   xmlNode *node;
2016 
2017   node = NULL;
2018 
2019   //TODO:JK: implement me
2020 
2021   return(node);
2022 }
2023 
2024 xmlNode*
ags_recall_xml_compose(AgsConnectable * connectable)2025 ags_recall_xml_compose(AgsConnectable *connectable)
2026 {
2027   xmlNode *node;
2028 
2029   node = NULL;
2030 
2031   //TODO:JK: implement me
2032 
2033   return(node);
2034 }
2035 
2036 void
ags_recall_xml_parse(AgsConnectable * connectable,xmlNode * node)2037 ags_recall_xml_parse(AgsConnectable *connectable,
2038 		     xmlNode *node)
2039 {
2040   //TODO:JK: implement me
2041 }
2042 
2043 gboolean
ags_recall_is_connected(AgsConnectable * connectable)2044 ags_recall_is_connected(AgsConnectable *connectable)
2045 {
2046   AgsRecall *recall;
2047 
2048   gboolean is_connected;
2049 
2050   recall = AGS_RECALL(connectable);
2051 
2052   /* check is connected */
2053   is_connected = ags_recall_test_flags(recall, AGS_RECALL_CONNECTED);
2054 
2055   return(is_connected);
2056 }
2057 
2058 void
ags_recall_connect(AgsConnectable * connectable)2059 ags_recall_connect(AgsConnectable *connectable)
2060 {
2061   AgsRecall *recall;
2062 
2063   GList *list_start, *list, *next;
2064 
2065   gboolean children_lock_free;
2066 
2067   GRecMutex *recall_mutex;
2068 
2069   if(ags_connectable_is_connected(connectable)){
2070     return;
2071   }
2072 
2073   recall = AGS_RECALL(connectable);
2074 
2075   ags_recall_set_flags(recall, AGS_RECALL_CONNECTED);
2076 
2077   /* get recall mutex */
2078   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2079 
2080   children_lock_free = ags_recall_global_get_children_lock_free();
2081 
2082   /* connect children */
2083   if(!children_lock_free){
2084     g_rec_mutex_lock(recall_mutex);
2085 
2086     list =
2087       list_start = g_list_copy(recall->children);
2088 
2089     g_rec_mutex_unlock(recall_mutex);
2090   }else{
2091     list =
2092       list_start = recall->children;
2093   }
2094 
2095   while(list != NULL){
2096     next = list->next;
2097 
2098     ags_connectable_connect(AGS_CONNECTABLE(list->data));
2099 
2100     list = next;
2101   }
2102 
2103   if(!children_lock_free){
2104     g_list_free(list_start);
2105   }
2106 
2107   /* recall handler */
2108   g_rec_mutex_lock(recall_mutex);
2109 
2110   list =
2111     list_start = g_list_copy(recall->recall_handler);
2112 
2113   g_rec_mutex_unlock(recall_mutex);
2114 
2115   while(list != NULL){
2116     AgsRecallHandler *recall_handler;
2117 
2118     recall_handler = AGS_RECALL_HANDLER(list->data);
2119     g_signal_connect_after(G_OBJECT(recall), recall_handler->signal_name,
2120 			   G_CALLBACK(recall_handler->callback), recall_handler->data);
2121 
2122     list = list->next;
2123   }
2124 
2125   g_list_free(list_start);
2126 }
2127 
2128 void
ags_recall_disconnect(AgsConnectable * connectable)2129 ags_recall_disconnect(AgsConnectable *connectable)
2130 {
2131   AgsRecall *recall;
2132 
2133   GList *list_start, *list, *next;
2134 
2135   gboolean children_lock_free;
2136 
2137   GRecMutex *recall_mutex;
2138 
2139   if(!ags_connectable_is_connected(connectable)){
2140     return;
2141   }
2142 
2143   recall = AGS_RECALL(connectable);
2144 
2145   ags_recall_unset_flags(recall, AGS_RECALL_CONNECTED);
2146 
2147   /* get recall mutex */
2148   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2149 
2150   children_lock_free = ags_recall_global_get_children_lock_free();
2151 
2152   /* connect children */
2153   if(!children_lock_free){
2154     g_rec_mutex_lock(recall_mutex);
2155 
2156     list =
2157       list_start = g_list_copy(recall->children);
2158 
2159     g_rec_mutex_unlock(recall_mutex);
2160   }else{
2161     list =
2162       list_start = recall->children;
2163   }
2164 
2165   while(list != NULL){
2166     ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
2167 
2168     list = list->next;
2169   }
2170 
2171   if(!children_lock_free){
2172     g_list_free(list_start);
2173   }
2174 
2175   /* recall handler */
2176   g_rec_mutex_lock(recall_mutex);
2177 
2178   list =
2179     list_start = g_list_copy(recall->recall_handler);
2180 
2181   g_rec_mutex_unlock(recall_mutex);
2182 
2183   while(list != NULL){
2184     AgsRecallHandler *recall_handler;
2185 
2186     gchar *signal_name;
2187 
2188     next = list->next;
2189 
2190     recall_handler = AGS_RECALL_HANDLER(list->data);
2191 
2192     signal_name = g_strdup_printf("any_signal::%s",
2193 				  recall_handler->signal_name);
2194     g_object_disconnect(G_OBJECT(recall),
2195 			signal_name,
2196 			G_CALLBACK(recall_handler->callback),
2197 			recall_handler->data,
2198 			NULL);
2199 
2200     g_free(signal_name);
2201 
2202     list = next;
2203   }
2204 
2205   g_list_free(list_start);
2206 }
2207 
2208 /**
2209  * ags_recall_global_set_omit_event:
2210  * @omit_event: %TRUE if omit event, otherwise %FALSE
2211  *
2212  * Set global config value omit event.
2213  *
2214  * Since: 3.0.0
2215  */
2216 void
ags_recall_global_set_omit_event(gboolean omit_event)2217 ags_recall_global_set_omit_event(gboolean omit_event)
2218 {
2219   ags_recall_global_omit_event = omit_event;
2220 }
2221 
2222 /**
2223  * ags_recall_global_get_children_lock_free:
2224  *
2225  * Get global config value lock free children.
2226  *
2227  * Returns: if %TRUE does lock free children, else not
2228  *
2229  * Since: 3.0.0
2230  */
2231 gboolean
ags_recall_global_get_children_lock_free()2232 ags_recall_global_get_children_lock_free()
2233 {
2234   gboolean children_lock_free;
2235 
2236   children_lock_free = ags_recall_global_children_lock_free;
2237 
2238   return(children_lock_free);
2239 }
2240 
2241 /**
2242  * ags_recall_global_get_omit_event:
2243  *
2244  * Get global config value omit event.
2245  *
2246  * Returns: if %TRUE does omit events, else not
2247  *
2248  * Since: 3.0.0
2249  */
2250 gboolean
ags_recall_global_get_omit_event()2251 ags_recall_global_get_omit_event()
2252 {
2253   gboolean omit_event;
2254 
2255   omit_event = ags_recall_global_omit_event;
2256 
2257   return(omit_event);
2258 }
2259 
2260 /**
2261  * ags_recall_global_get_performance_mode:
2262  *
2263  * Get global config value performance mode.
2264  *
2265  * Returns: if %TRUE does performance mode, else not
2266  *
2267  * Since: 3.0.0
2268  */
2269 gboolean
ags_recall_global_get_performance_mode()2270 ags_recall_global_get_performance_mode()
2271 {
2272   gboolean performance_mode;
2273 
2274   performance_mode = ags_recall_global_performance_mode;
2275 
2276   return(performance_mode);
2277 }
2278 
2279 /**
2280  * ags_recall_global_get_rt_safe:
2281  *
2282  * Get global config value rt-safe.
2283  *
2284  * Returns: if %TRUE does rt-safe strategy, else not
2285  *
2286  * Since: 3.0.0
2287  */
2288 gboolean
ags_recall_global_get_rt_safe()2289 ags_recall_global_get_rt_safe()
2290 {
2291   gboolean rt_safe;
2292 
2293   rt_safe = ags_recall_global_rt_safe;
2294 
2295   return(rt_safe);
2296 }
2297 
2298 /**
2299  * ags_recall_get_obj_mutex:
2300  * @recall: the #AgsRecall
2301  *
2302  * Get object mutex.
2303  *
2304  * Returns: (type gpointer) (transfer none): the #GRecMutex to lock @recall
2305  *
2306  * Since: 3.1.0
2307  */
2308 GRecMutex*
ags_recall_get_obj_mutex(AgsRecall * recall)2309 ags_recall_get_obj_mutex(AgsRecall *recall)
2310 {
2311   if(!AGS_IS_RECALL(recall)){
2312     return(NULL);
2313   }
2314 
2315   return(AGS_RECALL_GET_OBJ_MUTEX(recall));
2316 }
2317 
2318 /**
2319  * ags_recall_test_flags:
2320  * @recall: the #AgsRecall
2321  * @flags: the flags
2322  *
2323  * Test @flags to be set on @recall.
2324  *
2325  * Returns: %TRUE if flags are set, else %FALSE
2326  *
2327  * Since: 3.0.0
2328  */
2329 gboolean
ags_recall_test_flags(AgsRecall * recall,guint flags)2330 ags_recall_test_flags(AgsRecall *recall, guint flags)
2331 {
2332   gboolean retval;
2333 
2334   GRecMutex *recall_mutex;
2335 
2336   if(!AGS_IS_RECALL(recall)){
2337     return(FALSE);
2338   }
2339 
2340   /* get recall mutex */
2341   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2342 
2343   /* test */
2344   g_rec_mutex_lock(recall_mutex);
2345 
2346   retval = ((flags & (recall->flags)) != 0) ? TRUE: FALSE;
2347 
2348   g_rec_mutex_unlock(recall_mutex);
2349 
2350   return(retval);
2351 }
2352 
2353 /**
2354  * ags_recall_set_flags:
2355  * @recall: the #AgsRecall
2356  * @flags: the flags
2357  *
2358  * Set flags.
2359  *
2360  * Since: 3.0.0
2361  */
2362 void
ags_recall_set_flags(AgsRecall * recall,guint flags)2363 ags_recall_set_flags(AgsRecall *recall, guint flags)
2364 {
2365   GRecMutex *recall_mutex;
2366 
2367   if(!AGS_IS_RECALL(recall)){
2368     return;
2369   }
2370 
2371   /* get recall mutex */
2372   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2373 
2374   /* set flags */
2375   g_rec_mutex_lock(recall_mutex);
2376 
2377   recall->flags |= flags;
2378 
2379   g_rec_mutex_unlock(recall_mutex);
2380 }
2381 
2382 /**
2383  * ags_recall_unset_flags:
2384  * @recall: the #AgsRecall
2385  * @flags: the flags
2386  *
2387  * Unset flags.
2388  *
2389  * Since: 3.0.0
2390  */
2391 void
ags_recall_unset_flags(AgsRecall * recall,guint flags)2392 ags_recall_unset_flags(AgsRecall *recall, guint flags)
2393 {
2394   GRecMutex *recall_mutex;
2395 
2396   if(!AGS_IS_RECALL(recall)){
2397     return;
2398   }
2399 
2400   /* get recall mutex */
2401   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2402 
2403   /* set flags */
2404   g_rec_mutex_lock(recall_mutex);
2405 
2406   recall->flags &= (~flags);
2407 
2408   g_rec_mutex_unlock(recall_mutex);
2409 }
2410 
2411 /**
2412  * ags_recall_test_ability_flags:
2413  * @recall: the #AgsRecall
2414  * @ability_flags: the ability flags
2415  *
2416  * Test @ability_flags to be set on @recall.
2417  *
2418  * Returns: %TRUE if flags are set, else %FALSE
2419  *
2420  * Since: 3.0.0
2421  */
2422 gboolean
ags_recall_test_ability_flags(AgsRecall * recall,guint ability_flags)2423 ags_recall_test_ability_flags(AgsRecall *recall, guint ability_flags)
2424 {
2425   gboolean retval;
2426 
2427   GRecMutex *recall_mutex;
2428 
2429   if(!AGS_IS_RECALL(recall)){
2430     return(FALSE);
2431   }
2432 
2433   /* get recall mutex */
2434   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2435 
2436   /* test */
2437   g_rec_mutex_lock(recall_mutex);
2438 
2439   retval = ((ability_flags & (recall->ability_flags)) != 0) ? TRUE: FALSE;
2440 
2441   g_rec_mutex_unlock(recall_mutex);
2442 
2443   return(retval);
2444 }
2445 
2446 /**
2447  * ags_recall_set_ability_flags:
2448  * @recall: the #AgsRecall
2449  * @ability_flags: ability flags
2450  *
2451  * Set ability flags recursively.
2452  *
2453  * Since: 3.0.0
2454  */
2455 void
ags_recall_set_ability_flags(AgsRecall * recall,guint ability_flags)2456 ags_recall_set_ability_flags(AgsRecall *recall, guint ability_flags)
2457 {
2458   GList *child_start, *child, *next;
2459 
2460   gboolean children_lock_free;
2461 
2462   GRecMutex *recall_mutex;
2463 
2464   if(!AGS_IS_RECALL(recall)){
2465     return;
2466   }
2467 
2468   /* get recall mutex */
2469   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2470 
2471   children_lock_free = ags_recall_global_get_children_lock_free();
2472 
2473   /* set ability flags */
2474   g_rec_mutex_lock(recall_mutex);
2475 
2476   recall->ability_flags |= ability_flags;
2477 
2478   /* apply recursivly */
2479   if(!children_lock_free){
2480     child =
2481       child_start = g_list_copy(recall->children);
2482   }else{
2483     child =
2484       child_start = recall->children;
2485   }
2486 
2487   g_rec_mutex_unlock(recall_mutex);
2488 
2489   while(child != NULL){
2490     next = child->next;
2491 
2492     ags_recall_set_ability_flags(AGS_RECALL(child->data), ability_flags);
2493 
2494     child = next;
2495   }
2496 
2497   if(!children_lock_free){
2498     g_list_free(child_start);
2499   }
2500 }
2501 
2502 /**
2503  * ags_recall_unset_ability_flags:
2504  * @recall: the #AgsRecall
2505  * @ability_flags: ability flags
2506  *
2507  * Unset ability flags recursively.
2508  *
2509  * Since: 3.0.0
2510  */
2511 void
ags_recall_unset_ability_flags(AgsRecall * recall,guint ability_flags)2512 ags_recall_unset_ability_flags(AgsRecall *recall, guint ability_flags)
2513 {
2514   GList *child_start, *child, *next;
2515 
2516   gboolean children_lock_free;
2517 
2518   GRecMutex *recall_mutex;
2519 
2520   if(!AGS_IS_RECALL(recall)){
2521     return;
2522   }
2523 
2524   /* get recall mutex */
2525   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2526 
2527   children_lock_free = ags_recall_global_get_children_lock_free();
2528 
2529   /* unset ability flags */
2530   g_rec_mutex_lock(recall_mutex);
2531 
2532   recall->ability_flags &= (~ability_flags);
2533 
2534   /* apply recursivly */
2535   if(!children_lock_free){
2536     child =
2537       child_start = g_list_copy(recall->children);
2538   }else{
2539     child =
2540       child_start = recall->children;
2541   }
2542 
2543   g_rec_mutex_unlock(recall_mutex);
2544 
2545   while(child != NULL){
2546     next = child->next;
2547 
2548     ags_recall_set_ability_flags(AGS_RECALL(child->data), ability_flags);
2549 
2550     child = next;
2551   }
2552 
2553   if(!children_lock_free){
2554     g_list_free(child_start);
2555   }
2556 }
2557 
2558 /**
2559  * ags_recall_check_ability_flags:
2560  * @recall: the #AgsRecall
2561  * @ability_flags: the ability flags
2562  *
2563  * Check if @ability_flags is set for @recall.
2564  *
2565  * Returns: %TRUE flags are set, otherwise %FALSE
2566  *
2567  * Since: 3.0.0
2568  */
2569 gboolean
ags_recall_check_ability_flags(AgsRecall * recall,guint ability_flags)2570 ags_recall_check_ability_flags(AgsRecall *recall, guint ability_flags)
2571 {
2572   guint recall_ability_flags;
2573 
2574   GRecMutex *recall_mutex;
2575 
2576   if(!AGS_IS_RECALL(recall)){
2577     return(FALSE);
2578   }
2579 
2580   /* get recall mutex */
2581   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2582 
2583   /* get ability flags */
2584   g_rec_mutex_lock(recall_mutex);
2585 
2586   recall_ability_flags = recall->ability_flags;
2587 
2588   g_rec_mutex_unlock(recall_mutex);
2589 
2590   if((AGS_SOUND_ABILITY_PLAYBACK & (ability_flags)) != 0 &&
2591      (AGS_SOUND_ABILITY_PLAYBACK & (recall_ability_flags)) == 0){
2592     return(FALSE);
2593   }
2594 
2595   if((AGS_SOUND_ABILITY_NOTATION & (ability_flags)) != 0 &&
2596      (AGS_SOUND_ABILITY_NOTATION & (recall_ability_flags)) == 0){
2597     return(FALSE);
2598   }
2599 
2600   if((AGS_SOUND_ABILITY_SEQUENCER & (ability_flags)) != 0 &&
2601      (AGS_SOUND_ABILITY_SEQUENCER & (recall_ability_flags)) == 0){
2602     return(FALSE);
2603   }
2604 
2605   if((AGS_SOUND_ABILITY_WAVE & (ability_flags)) != 0 &&
2606      (AGS_SOUND_ABILITY_WAVE & (recall_ability_flags)) == 0){
2607     return(FALSE);
2608   }
2609 
2610   if((AGS_SOUND_ABILITY_MIDI & (ability_flags)) != 0 &&
2611      (AGS_SOUND_ABILITY_MIDI & (recall_ability_flags)) == 0){
2612     return(FALSE);
2613   }
2614 
2615   return(TRUE);
2616 }
2617 
2618 /**
2619  * ags_recall_match_ability_flags_to_scope:
2620  * @recall: the #AgsRecall
2621  * @sound_scope: the sound scope
2622  *
2623  * Check if @sound_scope related ability flag is set.
2624  *
2625  * Returns: %TRUE if sound scope is available, otherwise %FALSE
2626  *
2627  * Since: 3.0.0
2628  */
2629 gboolean
ags_recall_match_ability_flags_to_scope(AgsRecall * recall,gint sound_scope)2630 ags_recall_match_ability_flags_to_scope(AgsRecall *recall, gint sound_scope)
2631 {
2632   guint recall_ability_flags;
2633 
2634   GRecMutex *recall_mutex;
2635 
2636   if(!AGS_IS_RECALL(recall)){
2637     return(FALSE);
2638   }
2639 
2640   /* get recall mutex */
2641   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2642 
2643   /* get ability flags */
2644   g_rec_mutex_lock(recall_mutex);
2645 
2646   recall_ability_flags = recall->ability_flags;
2647 
2648   g_rec_mutex_unlock(recall_mutex);
2649 
2650   switch(sound_scope){
2651   case AGS_SOUND_SCOPE_PLAYBACK:
2652     {
2653       if((AGS_SOUND_ABILITY_PLAYBACK & (recall_ability_flags)) != 0){
2654 	return(TRUE);
2655       }else{
2656 	return(FALSE);
2657       }
2658     }
2659   case AGS_SOUND_SCOPE_NOTATION:
2660     {
2661       if((AGS_SOUND_ABILITY_NOTATION & (recall_ability_flags)) != 0){
2662 	return(TRUE);
2663       }else{
2664 	return(FALSE);
2665       }
2666     }
2667   case AGS_SOUND_SCOPE_SEQUENCER:
2668     {
2669       if((AGS_SOUND_ABILITY_SEQUENCER & (recall_ability_flags)) != 0){
2670 	return(TRUE);
2671       }else{
2672 	return(FALSE);
2673       }
2674     }
2675   case AGS_SOUND_SCOPE_WAVE:
2676     {
2677       if((AGS_SOUND_ABILITY_WAVE & (recall_ability_flags)) != 0){
2678 	return(TRUE);
2679       }else{
2680 	return(FALSE);
2681       }
2682     }
2683   case AGS_SOUND_SCOPE_MIDI:
2684     {
2685       if((AGS_SOUND_ABILITY_MIDI & (recall_ability_flags)) != 0){
2686 	return(TRUE);
2687       }else{
2688 	return(FALSE);
2689       }
2690     }
2691   default:
2692     return(FALSE);
2693   }
2694 }
2695 
2696 /**
2697  * ags_recall_test_behaviour_flags:
2698  * @recall: the #AgsRecall
2699  * @behaviour_flags: the behaviour flags
2700  *
2701  * Test @behaviour_flags to be set on @recall.
2702  *
2703  * Returns: %TRUE if flags are set, else %FALSE
2704  *
2705  * Since: 3.0.0
2706  */
2707 gboolean
ags_recall_test_behaviour_flags(AgsRecall * recall,guint behaviour_flags)2708 ags_recall_test_behaviour_flags(AgsRecall *recall, guint behaviour_flags)
2709 {
2710   gboolean retval;
2711 
2712   GRecMutex *recall_mutex;
2713 
2714   if(!AGS_IS_RECALL(recall)){
2715     return(FALSE);
2716   }
2717 
2718   /* get recall mutex */
2719   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2720 
2721   /* test */
2722   g_rec_mutex_lock(recall_mutex);
2723 
2724   retval = ((behaviour_flags & (recall->behaviour_flags)) != 0) ? TRUE: FALSE;
2725 
2726   g_rec_mutex_unlock(recall_mutex);
2727 
2728   return(retval);
2729 }
2730 
2731 /**
2732  * ags_recall_set_behaviour_flags:
2733  * @recall: the #AgsRecall
2734  * @behaviour_flags: the behaviour flags
2735  *
2736  * Set behaviour flags of @recall.
2737  *
2738  * Since: 3.0.0
2739  */
2740 void
ags_recall_set_behaviour_flags(AgsRecall * recall,guint behaviour_flags)2741 ags_recall_set_behaviour_flags(AgsRecall *recall, guint behaviour_flags)
2742 {
2743   GRecMutex *recall_mutex;
2744 
2745   if(!AGS_IS_RECALL(recall)){
2746     return;
2747   }
2748 
2749   /* get recall mutex */
2750   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2751 
2752   /* set behaviour flags */
2753   g_rec_mutex_lock(recall_mutex);
2754 
2755   recall->behaviour_flags |= behaviour_flags;
2756 
2757   g_rec_mutex_unlock(recall_mutex);
2758 }
2759 
2760 /**
2761  * ags_recall_unset_behaviour_flags:
2762  * @recall: the #AgsRecall
2763  * @behaviour_flags: the behaviour flags
2764  *
2765  * Unset behaviour flags of @recall.
2766  *
2767  * Since: 3.0.0
2768  */
2769 void
ags_recall_unset_behaviour_flags(AgsRecall * recall,guint behaviour_flags)2770 ags_recall_unset_behaviour_flags(AgsRecall *recall, guint behaviour_flags)
2771 {
2772   GRecMutex *recall_mutex;
2773 
2774   if(!AGS_IS_RECALL(recall)){
2775     return;
2776   }
2777 
2778   /* get recall mutex */
2779   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2780 
2781   /* unset behaviour flags */
2782   g_rec_mutex_lock(recall_mutex);
2783 
2784   recall->behaviour_flags &= (~behaviour_flags);
2785 
2786   g_rec_mutex_unlock(recall_mutex);
2787 }
2788 
2789 /**
2790  * ags_recall_check_behaviour_flags:
2791  * @recall: the #AgsRecall
2792  * @behaviour_flags: the behaviour flags
2793  *
2794  * Check if @behaviour_flags is set for @recall.
2795  *
2796  * Returns: %TRUE flags are set, otherwise %FALSE
2797  *
2798  * Since: 3.0.0
2799  */
2800 gboolean
ags_recall_check_behaviour_flags(AgsRecall * recall,guint behaviour_flags)2801 ags_recall_check_behaviour_flags(AgsRecall *recall, guint behaviour_flags)
2802 {
2803   guint recall_behaviour_flags;
2804 
2805   GRecMutex *recall_mutex;
2806 
2807   if(!AGS_IS_RECALL(recall)){
2808     return(FALSE);
2809   }
2810 
2811   /* get recall mutex */
2812   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2813 
2814   /* get behaviour flags */
2815   g_rec_mutex_lock(recall_mutex);
2816 
2817   recall_behaviour_flags = recall->behaviour_flags;
2818 
2819   g_rec_mutex_unlock(recall_mutex);
2820 
2821   if((AGS_SOUND_BEHAVIOUR_PATTERN_MODE & (behaviour_flags)) != 0 &&
2822      (AGS_SOUND_BEHAVIOUR_PATTERN_MODE & (recall_behaviour_flags)) == 0){
2823     return(FALSE);
2824   }
2825 
2826   if((AGS_SOUND_BEHAVIOUR_BULK_MODE & (behaviour_flags)) != 0 &&
2827      (AGS_SOUND_BEHAVIOUR_BULK_MODE & (recall_behaviour_flags)) == 0){
2828     return(FALSE);
2829   }
2830 
2831   if((AGS_SOUND_BEHAVIOUR_REVERSE_MAPPING & (behaviour_flags)) != 0 &&
2832      (AGS_SOUND_BEHAVIOUR_REVERSE_MAPPING & (recall_behaviour_flags)) == 0){
2833     return(FALSE);
2834   }
2835 
2836   if((AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_OUTPUT & (behaviour_flags)) != 0 &&
2837      (AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_OUTPUT & (recall_behaviour_flags)) == 0){
2838     return(FALSE);
2839   }
2840 
2841   if((AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_INPUT & (behaviour_flags)) != 0 &&
2842      (AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_INPUT & (recall_behaviour_flags)) == 0){
2843     return(FALSE);
2844   }
2845 
2846   if((AGS_SOUND_BEHAVIOUR_CHAINED_TO_OUTPUT & (behaviour_flags)) != 0 &&
2847      (AGS_SOUND_BEHAVIOUR_CHAINED_TO_OUTPUT & (recall_behaviour_flags)) == 0){
2848     return(FALSE);
2849   }
2850 
2851   if((AGS_SOUND_BEHAVIOUR_CHAINED_TO_INPUT & (behaviour_flags)) != 0 &&
2852      (AGS_SOUND_BEHAVIOUR_CHAINED_TO_INPUT & (recall_behaviour_flags)) == 0){
2853     return(FALSE);
2854   }
2855 
2856   if((AGS_SOUND_BEHAVIOUR_PERSISTENT & (behaviour_flags)) != 0 &&
2857      (AGS_SOUND_BEHAVIOUR_PERSISTENT & (recall_behaviour_flags)) == 0){
2858     return(FALSE);
2859   }
2860 
2861   if((AGS_SOUND_BEHAVIOUR_PERSISTENT_PLAYBACK & (behaviour_flags)) != 0 &&
2862      (AGS_SOUND_BEHAVIOUR_PERSISTENT_PLAYBACK & (recall_behaviour_flags)) == 0){
2863     return(FALSE);
2864   }
2865 
2866   if((AGS_SOUND_BEHAVIOUR_PERSISTENT_NOTATION & (behaviour_flags)) != 0 &&
2867      (AGS_SOUND_BEHAVIOUR_PERSISTENT_NOTATION & (recall_behaviour_flags)) == 0){
2868     return(FALSE);
2869   }
2870 
2871   if((AGS_SOUND_BEHAVIOUR_PERSISTENT_SEQUENCER & (behaviour_flags)) != 0 &&
2872      (AGS_SOUND_BEHAVIOUR_PERSISTENT_SEQUENCER & (recall_behaviour_flags)) == 0){
2873     return(FALSE);
2874   }
2875 
2876   if((AGS_SOUND_BEHAVIOUR_PERSISTENT_WAVE & (behaviour_flags)) != 0 &&
2877      (AGS_SOUND_BEHAVIOUR_PERSISTENT_WAVE & (recall_behaviour_flags)) == 0){
2878     return(FALSE);
2879   }
2880 
2881   if((AGS_SOUND_BEHAVIOUR_PERSISTENT_MIDI & (behaviour_flags)) != 0 &&
2882      (AGS_SOUND_BEHAVIOUR_PERSISTENT_MIDI & (recall_behaviour_flags)) == 0){
2883     return(FALSE);
2884   }
2885 
2886   if((AGS_SOUND_BEHAVIOUR_PROPAGATE_DONE & (behaviour_flags)) != 0 &&
2887      (AGS_SOUND_BEHAVIOUR_PROPAGATE_DONE & (recall_behaviour_flags)) == 0){
2888     return(FALSE);
2889   }
2890 
2891   return(TRUE);
2892 }
2893 
2894 /**
2895  * ags_recall_set_sound_scope:
2896  * @recall: the #AgsRecall
2897  * @sound_scope: the sound scope
2898  *
2899  * Set @sound_scope for @recall.
2900  *
2901  * Since: 3.0.0
2902  */
2903 void
ags_recall_set_sound_scope(AgsRecall * recall,gint sound_scope)2904 ags_recall_set_sound_scope(AgsRecall *recall, gint sound_scope)
2905 {
2906   GList *start_child, *child, *next;
2907 
2908   gboolean children_lock_free;
2909 
2910   GRecMutex *recall_mutex;
2911 
2912   if(!AGS_IS_RECALL(recall) &&
2913      ags_recall_check_sound_scope(recall,
2914 				  -1)){
2915     return;
2916   }
2917 
2918   /* get recall mutex */
2919   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2920 
2921   children_lock_free = ags_recall_global_get_children_lock_free();
2922 
2923   /* set sound scope */
2924   g_rec_mutex_lock(recall_mutex);
2925 
2926   recall->sound_scope = sound_scope;
2927 
2928   /* apply recursivly */
2929   if(!children_lock_free){
2930     child =
2931       start_child = g_list_copy(recall->children);
2932   }else{
2933     child =
2934       start_child = recall->children;
2935   }
2936 
2937   g_rec_mutex_unlock(recall_mutex);
2938 
2939   while(child != NULL){
2940     next = child->next;
2941 
2942     ags_recall_set_sound_scope(AGS_RECALL(child->data), sound_scope);
2943 
2944     child = next;
2945   }
2946 
2947   if(!children_lock_free){
2948     g_list_free(start_child);
2949   }
2950 }
2951 
2952 /**
2953  * ags_recall_get_sound_scope:
2954  * @recall: the #AgsRecall
2955  *
2956  * Get sound scope for @recall.
2957  *
2958  * Returns: the used sound scope
2959  *
2960  * Since: 3.0.0
2961  */
2962 gint
ags_recall_get_sound_scope(AgsRecall * recall)2963 ags_recall_get_sound_scope(AgsRecall *recall)
2964 {
2965   gint sound_scope;
2966 
2967   GRecMutex *recall_mutex;
2968 
2969   if(!AGS_IS_RECALL(recall)){
2970     return(-1);
2971   }
2972 
2973   /* get recall mutex */
2974   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
2975 
2976   /* set sound scope */
2977   g_rec_mutex_lock(recall_mutex);
2978 
2979   sound_scope = recall->sound_scope;
2980 
2981   g_rec_mutex_unlock(recall_mutex);
2982 
2983   return(sound_scope);
2984 }
2985 
2986 /**
2987  * ags_recall_check_sound_scope:
2988  * @recall: the #AgsRecall
2989  * @sound_scope: the sound scope to check or -1 to check all
2990  *
2991  * Check if @sound_scope is set for @recall.
2992  *
2993  * Returns: %TRUE if sound scope matches, otherwise  %FALSE
2994  *
2995  * Since: 3.0.0
2996  */
2997 gboolean
ags_recall_check_sound_scope(AgsRecall * recall,gint sound_scope)2998 ags_recall_check_sound_scope(AgsRecall *recall, gint sound_scope)
2999 {
3000   gint recall_sound_scope;
3001 
3002   GRecMutex *recall_mutex;
3003 
3004   if(!AGS_IS_RECALL(recall)){
3005     return(FALSE);
3006   }
3007 
3008   /* get recall mutex */
3009   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3010 
3011   /* get sound scope */
3012   g_rec_mutex_lock(recall_mutex);
3013 
3014   recall_sound_scope = recall->sound_scope;
3015 
3016   g_rec_mutex_unlock(recall_mutex);
3017 
3018   if(sound_scope < 0){
3019     switch(recall_sound_scope){
3020     case AGS_SOUND_SCOPE_PLAYBACK:
3021     case AGS_SOUND_SCOPE_NOTATION:
3022     case AGS_SOUND_SCOPE_SEQUENCER:
3023     case AGS_SOUND_SCOPE_WAVE:
3024     case AGS_SOUND_SCOPE_MIDI:
3025       return(TRUE);
3026     default:
3027       return(FALSE);
3028     }
3029   }else{
3030     if(sound_scope < AGS_SOUND_SCOPE_LAST &&
3031        sound_scope == recall_sound_scope){
3032       return(TRUE);
3033     }else{
3034       return(FALSE);
3035     }
3036   }
3037 }
3038 
3039 /**
3040  * ags_recall_test_staging_flags:
3041  * @recall: the #AgsRecall
3042  * @staging_flags: the staging flags
3043  *
3044  * Test @staging_flags to be set on @recall.
3045  *
3046  * Returns: %TRUE if flags are set, else %FALSE
3047  *
3048  * Since: 3.0.0
3049  */
3050 gboolean
ags_recall_test_staging_flags(AgsRecall * recall,guint staging_flags)3051 ags_recall_test_staging_flags(AgsRecall *recall,
3052 			       guint staging_flags)
3053 {
3054   gboolean retval;
3055 
3056   GRecMutex *recall_mutex;
3057 
3058   if(!AGS_IS_RECALL(recall)){
3059     return(FALSE);
3060   }
3061 
3062   /* get recall mutex */
3063   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3064 
3065   /* test */
3066   g_rec_mutex_lock(recall_mutex);
3067 
3068   retval = ((staging_flags & (recall->staging_flags)) != 0) ? TRUE: FALSE;
3069 
3070   g_rec_mutex_unlock(recall_mutex);
3071 
3072   return(retval);
3073 }
3074 
3075 /**
3076  * ags_recall_set_staging_flags:
3077  * @recall: the #AgsRecall
3078  * @staging_flags: staging flags to set
3079  *
3080  * Set staging flags.
3081  *
3082  * Since: 3.0.0
3083  */
3084 void
ags_recall_set_staging_flags(AgsRecall * recall,guint staging_flags)3085 ags_recall_set_staging_flags(AgsRecall *recall, guint staging_flags)
3086 {
3087   guint recall_staging_flags;
3088   guint recall_state_flags;
3089 
3090   gboolean omit_event;
3091 
3092   GRecMutex *recall_mutex;
3093 
3094   if(!AGS_IS_RECALL(recall)){
3095     return;
3096   }
3097 
3098   /* get recall mutex */
3099   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3100 
3101   omit_event = ags_recall_global_get_omit_event();
3102 
3103   /* get staging flags */
3104   g_rec_mutex_lock(recall_mutex);
3105 
3106   recall_staging_flags = recall->staging_flags;
3107   recall_state_flags = recall->state_flags;
3108 
3109   g_rec_mutex_unlock(recall_mutex);
3110 
3111   /* invoke appropriate staging */
3112   if((AGS_SOUND_STAGING_FINI & (recall_staging_flags)) == 0 &&
3113      (AGS_SOUND_STATE_IS_TERMINATING & (recall_state_flags)) == 0){
3114     if((AGS_SOUND_STAGING_CHECK_RT_DATA & (staging_flags)) != 0 &&
3115        (AGS_SOUND_STAGING_CHECK_RT_DATA & (recall_staging_flags)) == 0){
3116       if(omit_event){
3117 	AGS_RECALL_GET_CLASS(recall)->check_rt_data(recall);
3118       }else{
3119 	ags_recall_check_rt_data(recall);
3120       }
3121     }
3122 
3123     if((AGS_SOUND_STAGING_RUN_INIT_PRE & (staging_flags)) != 0 &&
3124        (AGS_SOUND_STAGING_RUN_INIT_PRE & (recall_staging_flags)) == 0){
3125       if(omit_event){
3126 	AGS_RECALL_GET_CLASS(recall)->run_init_pre(recall);
3127       }else{
3128 	ags_recall_run_init_pre(recall);
3129       }
3130     }
3131 
3132     if((AGS_SOUND_STAGING_RUN_INIT_INTER & (staging_flags)) != 0 &&
3133        (AGS_SOUND_STAGING_RUN_INIT_INTER & (recall_staging_flags)) == 0){
3134       if(omit_event){
3135 	AGS_RECALL_GET_CLASS(recall)->run_init_inter(recall);
3136       }else{
3137 	ags_recall_run_init_inter(recall);
3138       }
3139     }
3140 
3141     if((AGS_SOUND_STAGING_RUN_INIT_POST & (staging_flags)) != 0 &&
3142        (AGS_SOUND_STAGING_RUN_INIT_POST & (recall_staging_flags)) == 0){
3143       if(omit_event){
3144 	AGS_RECALL_GET_CLASS(recall)->run_init_post(recall);
3145       }else{
3146 	ags_recall_run_init_post(recall);
3147       }
3148     }
3149 
3150     if((AGS_SOUND_STAGING_FEED_INPUT_QUEUE & (staging_flags)) != 0 &&
3151        (AGS_SOUND_STAGING_FEED_INPUT_QUEUE & (recall_staging_flags)) == 0){
3152       if(omit_event){
3153 	AGS_RECALL_GET_CLASS(recall)->feed_input_queue(recall);
3154       }else{
3155 	ags_recall_feed_input_queue(recall);
3156       }
3157     }
3158 
3159     if((AGS_SOUND_STAGING_AUTOMATE & (staging_flags)) != 0 &&
3160        (AGS_SOUND_STAGING_AUTOMATE & (recall_staging_flags)) == 0){
3161       if(omit_event){
3162 	AGS_RECALL_GET_CLASS(recall)->automate(recall);
3163       }else{
3164 	ags_recall_automate(recall);
3165       }
3166     }
3167 
3168     if((AGS_SOUND_STAGING_RUN_PRE & (staging_flags)) != 0 &&
3169        (AGS_SOUND_STAGING_RUN_PRE & (recall_staging_flags)) == 0){
3170       if(omit_event){
3171 	AGS_RECALL_GET_CLASS(recall)->run_pre(recall);
3172       }else{
3173 	ags_recall_run_pre(recall);
3174       }
3175     }
3176 
3177     if((AGS_SOUND_STAGING_RUN_INTER & (staging_flags)) != 0 &&
3178        (AGS_SOUND_STAGING_RUN_INTER & (recall_staging_flags)) == 0){
3179       if(omit_event){
3180 	AGS_RECALL_GET_CLASS(recall)->run_inter(recall);
3181       }else{
3182 	ags_recall_run_inter(recall);
3183       }
3184     }
3185 
3186     if((AGS_SOUND_STAGING_RUN_POST & (staging_flags)) != 0 &&
3187        (AGS_SOUND_STAGING_RUN_POST & (recall_staging_flags)) == 0){
3188       if(omit_event){
3189 	AGS_RECALL_GET_CLASS(recall)->run_post(recall);
3190       }else{
3191 	ags_recall_run_post(recall);
3192       }
3193     }
3194 
3195     if((AGS_SOUND_STAGING_DO_FEEDBACK & (staging_flags)) != 0 &&
3196        (AGS_SOUND_STAGING_DO_FEEDBACK & (recall_staging_flags)) == 0){
3197       if(omit_event){
3198 	AGS_RECALL_GET_CLASS(recall)->do_feedback(recall);
3199       }else{
3200 	ags_recall_do_feedback(recall);
3201       }
3202     }
3203 
3204     if((AGS_SOUND_STAGING_FEED_OUTPUT_QUEUE & (staging_flags)) != 0 &&
3205        (AGS_SOUND_STAGING_FEED_OUTPUT_QUEUE & (recall_staging_flags)) == 0){
3206       if(omit_event){
3207 	AGS_RECALL_GET_CLASS(recall)->feed_output_queue(recall);
3208       }else{
3209 	ags_recall_feed_output_queue(recall);
3210       }
3211     }
3212   }
3213 
3214   if((AGS_SOUND_STAGING_FINI & (staging_flags)) != 0){
3215     ags_recall_unset_staging_flags(recall,
3216 				   (AGS_SOUND_STAGING_FEED_INPUT_QUEUE |
3217 				    AGS_SOUND_STAGING_AUTOMATE |
3218 				    AGS_SOUND_STAGING_RUN_PRE |
3219 				    AGS_SOUND_STAGING_RUN_INTER |
3220 				    AGS_SOUND_STAGING_RUN_POST |
3221 				    AGS_SOUND_STAGING_DO_FEEDBACK |
3222 				    AGS_SOUND_STAGING_FEED_OUTPUT_QUEUE));
3223   }
3224 
3225   if((AGS_SOUND_STAGING_CANCEL & (staging_flags)) != 0 &&
3226      (AGS_SOUND_STAGING_CANCEL & (recall_staging_flags)) == 0){
3227     ags_recall_set_state_flags(recall,
3228 			       AGS_SOUND_STATE_IS_TERMINATING);
3229 
3230     ags_recall_cancel(recall);
3231   }
3232 
3233   if((AGS_SOUND_STAGING_DONE & (staging_flags)) != 0 &&
3234      (AGS_SOUND_STAGING_DONE & (recall_staging_flags)) == 0){
3235     ags_recall_done(recall);
3236   }
3237 
3238 #if 0
3239   if((AGS_SOUND_STAGING_REMOVE & (staging_flags)) != 0 &&
3240      (AGS_SOUND_STAGING_REMOVE & (recall_staging_flags)) == 0){
3241     ags_recall_remove(recall);
3242   }
3243 #endif
3244 
3245   /* apply flags */
3246   g_rec_mutex_lock(recall_mutex);
3247 
3248   recall->staging_flags |= staging_flags;
3249 
3250   g_rec_mutex_unlock(recall_mutex);
3251 }
3252 
3253 /**
3254  * ags_recall_unset_staging_flags:
3255  * @recall: the #AgsRecall
3256 * @staging_flags: staging flags to unset
3257  *
3258  * Unset staging flags.
3259  *
3260  * Since: 3.0.0
3261  */
3262 void
ags_recall_unset_staging_flags(AgsRecall * recall,guint staging_flags)3263 ags_recall_unset_staging_flags(AgsRecall *recall, guint staging_flags)
3264 {
3265   GList *list_start, *list, *next;
3266 
3267   gboolean children_lock_free;
3268 
3269   GRecMutex *recall_mutex;
3270 
3271   if(!AGS_IS_RECALL(recall)){
3272     return;
3273   }
3274 
3275   /* get recall mutex */
3276   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3277 
3278   children_lock_free = ags_recall_global_get_children_lock_free();
3279 
3280   /* unset staging flags */
3281   g_rec_mutex_lock(recall_mutex);
3282 
3283   recall->staging_flags &= (~staging_flags);
3284 
3285   if(!children_lock_free){
3286     list =
3287       list_start = g_list_copy_deep(recall->children,
3288 				    (GCopyFunc) g_object_ref,
3289 				    NULL);
3290   }else{
3291     list =
3292       list_start = recall->children;
3293   }
3294 
3295   g_rec_mutex_unlock(recall_mutex);
3296 
3297   while(list != NULL){
3298     next = list->next;
3299 
3300     ags_recall_unset_staging_flags(AGS_RECALL(list->data), staging_flags);
3301 
3302     list = next;
3303   }
3304 
3305   if(!children_lock_free){
3306     g_list_free_full(list_start,
3307 		     g_object_unref);
3308   }
3309 }
3310 
3311 /**
3312  * ags_recall_check_staging_flags:
3313  * @recall: the #AgsRecall
3314  * @staging_flags: staging flags to check
3315  *
3316  * Check the occurence of @staging_flags in @recall.
3317  *
3318  * Returns: %TRUE if all flags matched, otherwise %FALSE
3319  *
3320  * Since: 3.0.0
3321  */
3322 gboolean
ags_recall_check_staging_flags(AgsRecall * recall,guint staging_flags)3323 ags_recall_check_staging_flags(AgsRecall *recall, guint staging_flags)
3324 {
3325   guint recall_staging_flags;
3326 
3327   GRecMutex *recall_mutex;
3328 
3329   if(!AGS_IS_RECALL(recall)){
3330     return(FALSE);
3331   }
3332 
3333   /* get recall mutex */
3334   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3335 
3336   /* get staging flags */
3337   g_rec_mutex_lock(recall_mutex);
3338 
3339   recall_staging_flags = recall->staging_flags;
3340 
3341   g_rec_mutex_unlock(recall_mutex);
3342 
3343   /* check staging flags */
3344   if((AGS_SOUND_STAGING_CHECK_RT_DATA & (staging_flags)) != 0 &&
3345      (AGS_SOUND_STAGING_CHECK_RT_DATA & (recall_staging_flags)) == 0){
3346     return(FALSE);
3347   }
3348 
3349   if((AGS_SOUND_STAGING_RUN_INIT_PRE & (staging_flags)) != 0 &&
3350      (AGS_SOUND_STAGING_RUN_INIT_PRE & (recall_staging_flags)) == 0){
3351     return(FALSE);
3352   }
3353 
3354   if((AGS_SOUND_STAGING_RUN_INIT_INTER & (staging_flags)) != 0 &&
3355      (AGS_SOUND_STAGING_RUN_INIT_INTER & (recall_staging_flags)) == 0){
3356     return(FALSE);
3357   }
3358 
3359   if((AGS_SOUND_STAGING_RUN_INIT_POST & (staging_flags)) != 0 &&
3360      (AGS_SOUND_STAGING_RUN_INIT_POST & (recall_staging_flags)) == 0){
3361     return(FALSE);
3362   }
3363 
3364   if((AGS_SOUND_STAGING_FEED_INPUT_QUEUE & (staging_flags)) != 0 &&
3365      (AGS_SOUND_STAGING_FEED_INPUT_QUEUE & (recall_staging_flags)) == 0){
3366     return(FALSE);
3367   }
3368 
3369   if((AGS_SOUND_STAGING_AUTOMATE & (staging_flags)) != 0 &&
3370      (AGS_SOUND_STAGING_AUTOMATE & (recall_staging_flags)) == 0){
3371     return(FALSE);
3372   }
3373 
3374   if((AGS_SOUND_STAGING_RUN_PRE & (staging_flags)) != 0 &&
3375      (AGS_SOUND_STAGING_RUN_PRE & (recall_staging_flags)) == 0){
3376     return(FALSE);
3377   }
3378 
3379   if((AGS_SOUND_STAGING_RUN_INTER & (staging_flags)) != 0 &&
3380      (AGS_SOUND_STAGING_RUN_INTER & (recall_staging_flags)) == 0){
3381     return(FALSE);
3382   }
3383 
3384   if((AGS_SOUND_STAGING_RUN_POST & (staging_flags)) != 0 &&
3385      (AGS_SOUND_STAGING_RUN_POST & (recall_staging_flags)) == 0){
3386     return(FALSE);
3387   }
3388 
3389   if((AGS_SOUND_STAGING_DO_FEEDBACK & (staging_flags)) != 0 &&
3390      (AGS_SOUND_STAGING_DO_FEEDBACK & (recall_staging_flags)) == 0){
3391     return(FALSE);
3392   }
3393 
3394   if((AGS_SOUND_STAGING_FEED_OUTPUT_QUEUE & (staging_flags)) != 0 &&
3395      (AGS_SOUND_STAGING_FEED_OUTPUT_QUEUE & (recall_staging_flags)) == 0){
3396     return(FALSE);
3397   }
3398 
3399   if((AGS_SOUND_STAGING_FINI & (staging_flags)) != 0 &&
3400      (AGS_SOUND_STAGING_FINI & (recall_staging_flags)) == 0){
3401     return(FALSE);
3402   }
3403 
3404   if((AGS_SOUND_STAGING_CANCEL & (staging_flags)) != 0 &&
3405      (AGS_SOUND_STAGING_CANCEL & (recall_staging_flags)) == 0){
3406     return(FALSE);
3407   }
3408 
3409   if((AGS_SOUND_STAGING_DONE & (staging_flags)) != 0 &&
3410      (AGS_SOUND_STAGING_DONE & (recall_staging_flags)) == 0){
3411     return(FALSE);
3412   }
3413 
3414   if((AGS_SOUND_STAGING_REMOVE & (staging_flags)) != 0 &&
3415      (AGS_SOUND_STAGING_REMOVE & (recall_staging_flags)) == 0){
3416     return(FALSE);
3417   }
3418 
3419   return(TRUE);
3420 }
3421 
3422 /**
3423  * ags_recall_test_state_flags:
3424  * @recall: the #AgsRecall
3425  * @state_flags: the state flags
3426  *
3427  * Test @state_flags to be set on @recall.
3428  *
3429  * Returns: %TRUE if flags are set, else %FALSE
3430  *
3431  * Since: 3.0.0
3432  */
3433 gboolean
ags_recall_test_state_flags(AgsRecall * recall,guint state_flags)3434 ags_recall_test_state_flags(AgsRecall *recall,
3435 			    guint state_flags)
3436 {
3437   gboolean retval;
3438 
3439   GRecMutex *recall_mutex;
3440 
3441   if(!AGS_IS_RECALL(recall)){
3442     return(FALSE);
3443   }
3444 
3445   /* get recall mutex */
3446   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3447 
3448   /* test */
3449   g_rec_mutex_lock(recall_mutex);
3450 
3451   retval = ((state_flags & (recall->state_flags)) != 0) ? TRUE: FALSE;
3452 
3453   g_rec_mutex_unlock(recall_mutex);
3454 
3455   return(retval);
3456 }
3457 
3458 /**
3459  * ags_recall_set_state_flags:
3460  * @recall: the #AgsRecall
3461  * @state_flags: state flags to set
3462  *
3463  * Set state flags.
3464  *
3465  * Since: 3.0.0
3466  */
3467 void
ags_recall_set_state_flags(AgsRecall * recall,guint state_flags)3468 ags_recall_set_state_flags(AgsRecall *recall, guint state_flags)
3469 {
3470   GRecMutex *recall_mutex;
3471 
3472   if(!AGS_IS_RECALL(recall)){
3473     return;
3474   }
3475 
3476   /* get recall mutex */
3477   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3478 
3479   /* set state flags */
3480   g_rec_mutex_lock(recall_mutex);
3481 
3482   recall->state_flags |= state_flags;
3483 
3484   g_rec_mutex_unlock(recall_mutex);
3485 }
3486 
3487 /**
3488  * ags_recall_unset_state_flags:
3489  * @recall: the #AgsRecall
3490  * @state_flags: state flags to unset
3491  *
3492  * Unset state flags.
3493  *
3494  * Since: 3.0.0
3495  */
3496 void
ags_recall_unset_state_flags(AgsRecall * recall,guint state_flags)3497 ags_recall_unset_state_flags(AgsRecall *recall, guint state_flags)
3498 {
3499   GRecMutex *recall_mutex;
3500 
3501   if(!AGS_IS_RECALL(recall)){
3502     return;
3503   }
3504 
3505   /* get recall mutex */
3506   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3507 
3508   /* unset state flags */
3509   g_rec_mutex_lock(recall_mutex);
3510 
3511   recall->state_flags &= (~state_flags);
3512 
3513   g_rec_mutex_unlock(recall_mutex);
3514 }
3515 
3516 /**
3517  * ags_recall_check_state_flags:
3518  * @recall: the #AgsRecall
3519  * @state_flags: state flags to check
3520  *
3521  * Check the occurence of @state_flags in @recall.
3522  *
3523  * Returns: %TRUE if all flags matched, otherwise %FALSE
3524  *
3525  * Since: 3.0.0
3526  */
3527 gboolean
ags_recall_check_state_flags(AgsRecall * recall,guint state_flags)3528 ags_recall_check_state_flags(AgsRecall *recall, guint state_flags)
3529 {
3530   guint recall_state_flags;
3531 
3532   GRecMutex *recall_mutex;
3533 
3534   if(!AGS_IS_RECALL(recall)){
3535     return(FALSE);
3536   }
3537 
3538   /* get recall mutex */
3539   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3540 
3541   /* get state flags */
3542   g_rec_mutex_lock(recall_mutex);
3543 
3544   recall_state_flags = recall->state_flags;
3545 
3546   g_rec_mutex_unlock(recall_mutex);
3547 
3548   /* check state flags */
3549   if((AGS_SOUND_STATE_IS_WAITING & (state_flags)) != 0 &&
3550      (AGS_SOUND_STATE_IS_WAITING & (recall_state_flags)) == 0){
3551     return(FALSE);
3552   }
3553 
3554   if((AGS_SOUND_STATE_IS_ACTIVE & (state_flags)) != 0 &&
3555      (AGS_SOUND_STATE_IS_ACTIVE & (recall_state_flags)) == 0){
3556     return(FALSE);
3557   }
3558 
3559   if((AGS_SOUND_STATE_IS_PROCESSING & (state_flags)) != 0 &&
3560      (AGS_SOUND_STATE_IS_PROCESSING & (recall_state_flags)) == 0){
3561     return(FALSE);
3562   }
3563 
3564   if((AGS_SOUND_STATE_IS_TERMINATING & (state_flags)) != 0 &&
3565      (AGS_SOUND_STATE_IS_TERMINATING & (recall_state_flags)) == 0){
3566     return(FALSE);
3567   }
3568 
3569   return(TRUE);
3570 }
3571 
3572 /**
3573  * ags_recall_get_filename:
3574  * @recall: the #AgsRecall
3575  *
3576  * Get filename.
3577  *
3578  * Returns: the filename
3579  *
3580  * Since: 3.1.0
3581  */
3582 gchar*
ags_recall_get_filename(AgsRecall * recall)3583 ags_recall_get_filename(AgsRecall *recall)
3584 {
3585   gchar *filename;
3586 
3587   if(!AGS_IS_RECALL(recall)){
3588     return(NULL);
3589   }
3590 
3591   g_object_get(recall,
3592 	       "filename", &filename,
3593 	       NULL);
3594 
3595   return(filename);
3596 }
3597 
3598 /**
3599  * ags_recall_set_filename:
3600  * @recall: the #AgsRecall
3601  * @filename: the filename
3602  *
3603  * Set filename.
3604  *
3605  * Since: 3.1.0
3606  */
3607 void
ags_recall_set_filename(AgsRecall * recall,gchar * filename)3608 ags_recall_set_filename(AgsRecall *recall,
3609 			gchar *filename)
3610 {
3611   if(!AGS_IS_RECALL(recall)){
3612     return;
3613   }
3614 
3615   g_object_set(recall,
3616 	       "filename", filename,
3617 	       NULL);
3618 }
3619 
3620 /**
3621  * ags_recall_get_effect:
3622  * @recall: the #AgsRecall
3623  *
3624  * Get effect.
3625  *
3626  * Returns: the effect
3627  *
3628  * Since: 3.1.0
3629  */
3630 gchar*
ags_recall_get_effect(AgsRecall * recall)3631 ags_recall_get_effect(AgsRecall *recall)
3632 {
3633   gchar *effect;
3634 
3635   if(!AGS_IS_RECALL(recall)){
3636     return(NULL);
3637   }
3638 
3639   g_object_get(recall,
3640 	       "effect", &effect,
3641 	       NULL);
3642 
3643   return(effect);
3644 }
3645 
3646 /**
3647  * ags_recall_set_effect:
3648  * @recall: the #AgsRecall
3649  * @effect: the effect
3650  *
3651  * Set effect.
3652  *
3653  * Since: 3.1.0
3654  */
3655 void
ags_recall_set_effect(AgsRecall * recall,gchar * effect)3656 ags_recall_set_effect(AgsRecall *recall,
3657 		      gchar *effect)
3658 {
3659   if(!AGS_IS_RECALL(recall)){
3660     return;
3661   }
3662 
3663   g_object_set(recall,
3664 	       "effect", effect,
3665 	       NULL);
3666 }
3667 
3668 /**
3669  * ags_recall_get_effect_index:
3670  * @recall: the #AgsRecall
3671  *
3672  * Get effect index.
3673  *
3674  * Returns: the effect index
3675  *
3676  * Since: 3.1.0
3677  */
3678 guint
ags_recall_get_effect_index(AgsRecall * recall)3679 ags_recall_get_effect_index(AgsRecall *recall)
3680 {
3681   guint effect_index;
3682 
3683   if(!AGS_IS_RECALL(recall)){
3684     return(0);
3685   }
3686 
3687   g_object_get(recall,
3688 	       "effect-index", &effect_index,
3689 	       NULL);
3690 
3691   return(effect_index);
3692 }
3693 
3694 /**
3695  * ags_recall_set_effect_index:
3696  * @recall: the #AgsRecall
3697  * @effect_index: the effect index
3698  *
3699  * Set effect index.
3700  *
3701  * Since: 3.1.0
3702  */
3703 void
ags_recall_set_effect_index(AgsRecall * recall,guint effect_index)3704 ags_recall_set_effect_index(AgsRecall *recall,
3705 			    guint effect_index)
3706 {
3707   if(!AGS_IS_RECALL(recall)){
3708     return;
3709   }
3710 
3711   g_object_set(recall,
3712 	       "effect-index", effect_index,
3713 	       NULL);
3714 }
3715 
3716 /**
3717  * ags_recall_get_recall_container:
3718  * @recall: the #AgsRecall
3719  *
3720  * Get recall container of @recall.
3721  *
3722  * Returns: the #AgsRecallContainer
3723  *
3724  * Since: 3.1.0
3725  */
3726 GObject*
ags_recall_get_recall_container(AgsRecall * recall)3727 ags_recall_get_recall_container(AgsRecall *recall)
3728 {
3729   GObject *recall_container;
3730 
3731   if(!AGS_IS_RECALL(recall)){
3732     return(NULL);
3733   }
3734 
3735   g_object_get(recall,
3736 	       "recall-container", &recall_container,
3737 	       NULL);
3738 
3739   return(recall_container);
3740 }
3741 
3742 /**
3743  * ags_recall_set_recall_container:
3744  * @recall: the #AgsRecall
3745  * @recall_container: the #AgsRecallContainer
3746  *
3747  * Set @recall_container of @recall.
3748  *
3749  * Since: 3.1.0
3750  */
3751 void
ags_recall_set_recall_container(AgsRecall * recall,GObject * recall_container)3752 ags_recall_set_recall_container(AgsRecall *recall,
3753 				GObject *recall_container)
3754 {
3755   if(!AGS_IS_RECALL(recall)){
3756     return;
3757   }
3758 
3759   g_object_set(recall,
3760 	       "recall-container", recall_container,
3761 	       NULL);
3762 }
3763 
3764 /**
3765  * ags_recall_get_recall_id:
3766  * @recall: the #AgsRecall
3767  *
3768  * Get recall id of @recall.
3769  *
3770  * Returns: the #AgsRecallID
3771  *
3772  * Since: 3.1.0
3773  */
3774 AgsRecallID*
ags_recall_get_recall_id(AgsRecall * recall)3775 ags_recall_get_recall_id(AgsRecall *recall)
3776 {
3777   AgsRecallID *recall_id;
3778 
3779   if(!AGS_IS_RECALL(recall)){
3780     return(NULL);
3781   }
3782 
3783   g_object_get(recall,
3784 	       "recall-id", &recall_id,
3785 	       NULL);
3786 
3787   return(recall_id);
3788 }
3789 
3790 /**
3791  * ags_recall_set_recall_id:
3792  * @recall: the #AgsRecall
3793  * @recall_id: the #AgsRecallID to set
3794  *
3795  * Set @recall_id of @recall and all its children.
3796  *
3797  * Since: 3.0.0
3798  */
3799 void
ags_recall_set_recall_id(AgsRecall * recall,AgsRecallID * recall_id)3800 ags_recall_set_recall_id(AgsRecall *recall,
3801 			 AgsRecallID *recall_id)
3802 {
3803   GList *list_start, *list, *next;
3804 
3805   gboolean children_lock_free;
3806 
3807   GRecMutex *recall_mutex;
3808 
3809   if(!AGS_IS_RECALL(recall)){
3810     return;
3811   }
3812 
3813   /* get recall mutex */
3814   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3815 
3816   children_lock_free = ags_recall_global_get_children_lock_free();
3817 
3818   /* set recall id - children */
3819   g_rec_mutex_lock(recall_mutex);
3820 
3821   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
3822     g_warning("set recall id on template");
3823   }
3824 
3825   if(!children_lock_free){
3826     list =
3827       list_start = g_list_copy(recall->children);
3828   }else{
3829     list =
3830       list_start = recall->children;
3831   }
3832 
3833   g_rec_mutex_unlock(recall_mutex);
3834 
3835   while(list != NULL){
3836     next = list->next;
3837 
3838     ags_recall_set_recall_id(AGS_RECALL(list->data), recall_id);
3839 
3840     list = next;
3841   }
3842 
3843   if(!children_lock_free){
3844     g_list_free(list_start);
3845   }
3846 
3847   /* set recall id */
3848   g_rec_mutex_lock(recall_mutex);
3849 
3850   recall->recall_id = recall_id;
3851   g_object_ref(recall_id);
3852 
3853   g_rec_mutex_unlock(recall_mutex);
3854 }
3855 
3856 /**
3857  * ags_recall_get_recall_dependency:
3858  * @recall: the #AgsRecall
3859  *
3860  * Get recall dependency.
3861  *
3862  * Returns: (element-type AgsAudio.RecallDependency) (transfer full): the #GList-struct containig #AgsRecallDependency
3863  *
3864  * Since: 3.1.0
3865  */
3866 GList*
ags_recall_get_recall_dependency(AgsRecall * recall)3867 ags_recall_get_recall_dependency(AgsRecall *recall)
3868 {
3869   GList *recall_dependency;
3870 
3871   if(!AGS_IS_RECALL(recall)){
3872     return(NULL);
3873   }
3874 
3875   g_object_get(recall,
3876 	       "recall-dependency", &recall_dependency,
3877 	       NULL);
3878 
3879   return(recall_dependency);
3880 }
3881 
3882 /**
3883  * ags_recall_set_recall_dependency:
3884  * @recall: the #AgsRecall
3885  * @recall_dependency: (element-type AgsAudio.RecallDependency) (transfer full): the #GList-struct containing #AgsRecallDependency
3886  *
3887  * Set recall dependency by replacing existing.
3888  *
3889  * Since: 3.1.0
3890  */
3891 void
ags_recall_set_recall_dependency(AgsRecall * recall,GList * recall_dependency)3892 ags_recall_set_recall_dependency(AgsRecall *recall,
3893 				 GList *recall_dependency)
3894 {
3895   GList *start_recall_dependency;
3896 
3897   GRecMutex *recall_mutex;
3898 
3899   if(!AGS_IS_RECALL(recall)){
3900     return;
3901   }
3902 
3903   /* get recall mutex */
3904   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3905 
3906   g_rec_mutex_lock(recall_mutex);
3907 
3908   start_recall_dependency = recall->recall_dependency;
3909   recall->recall_dependency = recall_dependency;
3910 
3911   g_rec_mutex_unlock(recall_mutex);
3912 
3913   g_list_free_full(start_recall_dependency,
3914 		   (GDestroyNotify) g_object_unref);
3915 }
3916 
3917 /**
3918  * ags_recall_add_recall_dependency:
3919  * @recall: the #AgsRecall
3920  * @recall_dependency: the #AgsRecallDependency
3921  *
3922  * Associate a new dependency for this recall.
3923  *
3924  * Since: 3.0.0
3925  */
3926 void
ags_recall_add_recall_dependency(AgsRecall * recall,AgsRecallDependency * recall_dependency)3927 ags_recall_add_recall_dependency(AgsRecall *recall, AgsRecallDependency *recall_dependency)
3928 {
3929   GRecMutex *recall_mutex;
3930 
3931   if(!AGS_IS_RECALL(recall) ||
3932      !AGS_IS_RECALL_DEPENDENCY(recall_dependency)){
3933     return;
3934   }
3935 
3936   /* get recall mutex */
3937   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3938 
3939   /* add recall dependency */
3940   g_rec_mutex_lock(recall_mutex);
3941 
3942   g_object_ref(recall_dependency);
3943   recall->recall_dependency = g_list_prepend(recall->recall_dependency,
3944 					     recall_dependency);
3945 
3946   g_rec_mutex_unlock(recall_mutex);
3947 }
3948 
3949 /**
3950  * ags_recall_remove_recall_dependency:
3951  * @recall: the #AgsRecall
3952  * @recall_dependency: the #AgsRecallDependency
3953  *
3954  * Remove a prior associated dependency.
3955  *
3956  * Since: 3.0.0
3957  */
3958 void
ags_recall_remove_recall_dependency(AgsRecall * recall,AgsRecallDependency * recall_dependency)3959 ags_recall_remove_recall_dependency(AgsRecall *recall, AgsRecallDependency *recall_dependency)
3960 {
3961   GRecMutex *recall_mutex;
3962 
3963   if(!AGS_IS_RECALL(recall) ||
3964      !AGS_IS_RECALL_DEPENDENCY(recall_dependency)){
3965     return;
3966   }
3967 
3968   /* get recall mutex */
3969   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
3970 
3971   /* remove recall dependency */
3972   g_rec_mutex_lock(recall_mutex);
3973 
3974   if(g_list_find(recall->recall_dependency,
3975 		 recall_dependency) != NULL){
3976     recall->recall_dependency = g_list_remove(recall->recall_dependency,
3977 					      recall_dependency);
3978     g_object_unref(G_OBJECT(recall_dependency));
3979   }
3980 
3981   g_rec_mutex_unlock(recall_mutex);
3982 }
3983 
3984 /**
3985  * ags_recall_get_port:
3986  * @recall: the #AgsRecall
3987  *
3988  * Get port.
3989  *
3990  * Returns: (element-type AgsAudio.Port) (transfer full): the #GList-struct containig #AgsPort
3991  *
3992  * Since: 3.7.18
3993  */
3994 GList*
ags_recall_get_port(AgsRecall * recall)3995 ags_recall_get_port(AgsRecall *recall)
3996 {
3997   GList *port;
3998 
3999   if(!AGS_IS_RECALL(recall)){
4000     return(NULL);
4001   }
4002 
4003   g_object_get(recall,
4004 	       "port", &port,
4005 	       NULL);
4006 
4007   return(port);
4008 }
4009 
4010 /**
4011  * ags_recall_set_port:
4012  * @recall: the #AgsRecall
4013  * @port: (element-type AgsAudio.Port) (transfer full): the #GList-struct containing #AgsPort
4014  *
4015  * Set port by replacing existing.
4016  *
4017  * Since: 3.7.18
4018  */
4019 void
ags_recall_set_port(AgsRecall * recall,GList * port)4020 ags_recall_set_port(AgsRecall *recall,
4021 		    GList *port)
4022 {
4023   GList *start_port;
4024 
4025   GRecMutex *recall_mutex;
4026 
4027   if(!AGS_IS_RECALL(recall)){
4028     return;
4029   }
4030 
4031   /* get recall mutex */
4032   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4033 
4034   g_rec_mutex_lock(recall_mutex);
4035 
4036   start_port = recall->port;
4037   recall->port = port;
4038 
4039   g_rec_mutex_unlock(recall_mutex);
4040 
4041   g_list_free_full(start_port,
4042 		   (GDestroyNotify) g_object_unref);
4043 }
4044 
4045 /**
4046  * ags_recall_add_port:
4047  * @recall: the #AgsRecall
4048  * @port: the #AgsPort
4049  *
4050  * Add @port to @recall.
4051  *
4052  * Since: 3.3.0
4053  */
4054 void
ags_recall_add_port(AgsRecall * recall,AgsPort * port)4055 ags_recall_add_port(AgsRecall *recall,
4056 		    AgsPort *port)
4057 {
4058   GRecMutex *recall_mutex;
4059 
4060   if(!AGS_IS_RECALL(recall) ||
4061      !AGS_IS_PORT(port)){
4062     return;
4063   }
4064 
4065   /* get recall mutex */
4066   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4067 
4068   /* add port */
4069   g_rec_mutex_lock(recall_mutex);
4070 
4071   if(g_list_find(recall->port, port) == NULL){
4072     g_object_ref(port);
4073     recall->port = g_list_prepend(recall->port,
4074 				  port);
4075   }
4076 
4077   g_rec_mutex_unlock(recall_mutex);
4078 }
4079 
4080 /**
4081  * ags_recall_remove_port:
4082  * @recall: the #AgsRecall
4083  * @port: the #AgsPort
4084  *
4085  * Remove @port from @recall.
4086  *
4087  * Since: 3.3.0
4088  */
4089 void
ags_recall_remove_port(AgsRecall * recall,AgsPort * port)4090 ags_recall_remove_port(AgsRecall *recall,
4091 		       AgsPort *port)
4092 {
4093   GRecMutex *recall_mutex;
4094 
4095   if(!AGS_IS_RECALL(recall) ||
4096      !AGS_IS_PORT(port)){
4097     return;
4098   }
4099 
4100   /* get recall mutex */
4101   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4102 
4103   /* remove port */
4104   g_rec_mutex_lock(recall_mutex);
4105 
4106   if(g_list_find(recall->port, port) != NULL){
4107     g_object_unref(port);
4108     recall->port = g_list_remove(recall->port,
4109 				 port);
4110   }
4111 
4112   g_rec_mutex_unlock(recall_mutex);
4113 }
4114 
4115 /**
4116  * ags_recall_get_children:
4117  * @recall: the #AgsRecall
4118  *
4119  * Get recall children.
4120  *
4121  * Returns: (element-type AgsAudio.Recall) (transfer full): the #GList-struct containig #AgsRecall
4122  *
4123  * Since: 3.1.0
4124  */
4125 GList*
ags_recall_get_children(AgsRecall * recall)4126 ags_recall_get_children(AgsRecall *recall)
4127 {
4128   GList *children;
4129 
4130   if(!AGS_IS_RECALL(recall)){
4131     return(NULL);
4132   }
4133 
4134   g_object_get(recall,
4135 	       "child", &children,
4136 	       NULL);
4137 
4138   return(children);
4139 }
4140 
4141 /**
4142  * ags_recall_set_children:
4143  * @recall: the #AgsRecall
4144  * @children: (element-type AgsAudio.Recall) (transfer full): the #GList-struct containing #AgsRecall
4145  *
4146  * Set recall children by replacing existing.
4147  *
4148  * Since: 3.1.0
4149  */
4150 void
ags_recall_set_children(AgsRecall * recall,GList * children)4151 ags_recall_set_children(AgsRecall *recall,
4152 			GList *children)
4153 {
4154   GList *start_children;
4155 
4156   GRecMutex *recall_mutex;
4157 
4158   if(!AGS_IS_RECALL(recall)){
4159     return;
4160   }
4161 
4162   /* get recall mutex */
4163   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4164 
4165   g_rec_mutex_lock(recall_mutex);
4166 
4167   start_children = recall->children;
4168   recall->children = children;
4169 
4170   g_rec_mutex_unlock(recall_mutex);
4171 
4172   g_list_free_full(start_children,
4173 		   (GDestroyNotify) g_object_unref);
4174 }
4175 
4176 /**
4177  * ags_recall_add_child:
4178  * @recall: the #AgsRecall
4179  * @child: the child #AgsRecall
4180  *
4181  * Add @child to @recall.
4182  *
4183  * Since: 3.0.0
4184  */
4185 void
ags_recall_add_child(AgsRecall * recall,AgsRecall * child)4186 ags_recall_add_child(AgsRecall *recall, AgsRecall *child)
4187 {
4188   AgsRecall *old_parent;
4189   AgsRecallID *recall_id;
4190 
4191   GObject *output_soundcard;
4192   GObject *input_soundcard;
4193 
4194   gint output_soundcard_channel;
4195   gint input_soundcard_channel;
4196   guint samplerate;
4197   guint buffer_size;
4198   guint format;
4199   guint recall_ability_flags;
4200   guint recall_behaviour_flags;
4201   gint recall_sound_scope;
4202   guint staging_flags;
4203 
4204   GRecMutex *recall_mutex, *child_mutex;
4205 
4206   if(!AGS_IS_RECALL(child) ||
4207      !AGS_IS_RECALL(recall)){
4208     return;
4209   }
4210 
4211   /* get recall mutex - recall and child */
4212   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4213   child_mutex = AGS_RECALL_GET_OBJ_MUTEX(child);
4214 
4215   /* check if already set */
4216   g_rec_mutex_lock(child_mutex);
4217 
4218   if(child->parent == recall){
4219     g_rec_mutex_unlock(child_mutex);
4220 
4221     return;
4222   }
4223 
4224   old_parent = child->parent;
4225 
4226   g_rec_mutex_unlock(child_mutex);
4227 
4228   /*  */
4229   g_object_ref(recall);
4230   g_object_ref(child);
4231 
4232   /* remove old */
4233   if(old_parent != NULL){
4234     ags_connectable_disconnect(AGS_CONNECTABLE(child));
4235     ags_recall_remove_child(old_parent,
4236 			    child);
4237   }
4238 
4239   /* add child */
4240   g_rec_mutex_lock(recall_mutex);
4241 
4242   recall_ability_flags = recall->ability_flags;
4243   recall_behaviour_flags = recall->behaviour_flags;
4244   recall_sound_scope = recall->sound_scope;
4245 
4246   output_soundcard = recall->output_soundcard;
4247   output_soundcard_channel = recall->output_soundcard_channel;
4248 
4249   input_soundcard = recall->input_soundcard;
4250   input_soundcard_channel = recall->input_soundcard_channel;
4251 
4252   samplerate = recall->samplerate;
4253   buffer_size = recall->buffer_size;
4254   format = recall->format;
4255 
4256   recall->children = g_list_prepend(recall->children,
4257 				    child);
4258 
4259   g_rec_mutex_unlock(recall_mutex);
4260 
4261   g_object_get(recall,
4262 	       "recall-id", &recall_id,
4263 	       NULL);
4264 
4265   /* ref new */
4266   ags_recall_set_ability_flags(child, recall_ability_flags);
4267   ags_recall_set_behaviour_flags(child, recall_behaviour_flags);
4268   ags_recall_set_sound_scope(child, recall_sound_scope);
4269 
4270   g_rec_mutex_lock(child_mutex);
4271 
4272   child->parent = recall;
4273 
4274   g_rec_mutex_unlock(child_mutex);
4275 
4276   g_object_set(G_OBJECT(child),
4277 	       "output-soundcard", output_soundcard,
4278 	       "output-soundcard-channel", output_soundcard_channel,
4279 	       "input-soundcard", input_soundcard,
4280 	       "input-soundcard-channel", input_soundcard_channel,
4281 	       "samplerate", samplerate,
4282 	       "buffer-size", buffer_size,
4283 	       "format", format,
4284 	       "recall-id", recall_id,
4285 	       NULL);
4286 
4287   g_signal_connect_after(G_OBJECT(child), "done",
4288 			 G_CALLBACK(ags_recall_child_done), recall);
4289 
4290   ags_recall_child_added(recall,
4291 			 child);
4292 
4293   if(ags_connectable_is_connected(AGS_CONNECTABLE(recall))){
4294     ags_connectable_connect(AGS_CONNECTABLE(child));
4295   }
4296 
4297   /* get mask */
4298   if(recall_id != NULL){
4299     staging_flags = (AGS_SOUND_STAGING_CHECK_RT_DATA |
4300 		     AGS_SOUND_STAGING_RUN_INIT_PRE |
4301 		     AGS_SOUND_STAGING_RUN_INIT_INTER |
4302 		     AGS_SOUND_STAGING_RUN_INIT_POST);
4303 
4304     //FIXME:JK: this doesn't work
4305 #if 0
4306     g_message("staging + 0x%x", staging_flags);
4307 
4308     g_rec_mutex_lock(recall_mutex);
4309 
4310     staging_flags = (staging_flags & (recall->staging_flags));
4311 
4312     g_rec_mutex_unlock(recall_mutex);
4313 
4314     g_message("staging - 0x%x", staging_flags);
4315 #endif
4316 
4317     /* set staging flags */
4318     ags_recall_set_staging_flags(child,
4319 				 staging_flags);
4320 
4321     g_object_unref(recall_id);
4322   }
4323 }
4324 
4325 /**
4326  * ags_recall_remove_child:
4327  * @recall: the #AgsRecall
4328  * @child: the child #AgsRecall
4329  *
4330  * Remove @child from @recall.
4331  *
4332  * Since: 3.0.0
4333  */
4334 void
ags_recall_remove_child(AgsRecall * recall,AgsRecall * child)4335 ags_recall_remove_child(AgsRecall *recall, AgsRecall *child)
4336 {
4337   GRecMutex *recall_mutex, *child_mutex;
4338 
4339   if(!AGS_IS_RECALL(child) ||
4340      !AGS_IS_RECALL(recall)){
4341     return;
4342   }
4343 
4344   /* get recall mutex - recall and child */
4345   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4346   child_mutex = AGS_RECALL_GET_OBJ_MUTEX(child);
4347 
4348   /* check if not set */
4349   g_rec_mutex_lock(child_mutex);
4350 
4351   if(child->parent != recall){
4352     g_rec_mutex_unlock(child_mutex);
4353 
4354     return;
4355   }
4356 
4357   g_rec_mutex_unlock(child_mutex);
4358 
4359   /* remove from recall */
4360   g_rec_mutex_lock(recall_mutex);
4361 
4362   if(g_list_find(recall->children,
4363 		 child) != NULL){
4364     recall->children = g_list_remove(recall->children,
4365 				     child);
4366     g_object_unref(child);
4367   }
4368 
4369   g_rec_mutex_unlock(recall_mutex);
4370 
4371   /* unref recall */
4372   child->parent = NULL;
4373 
4374   g_object_unref(recall);
4375 }
4376 
4377 /**
4378  * ags_recall_handler_free:
4379  * @recall_handler: (type gpointer) (transfer none): the #AgsRecallHandler-struct
4380  *
4381  * Free @recall_hanlder.
4382  *
4383  * Since: 3.0.0
4384  */
4385 void
ags_recall_handler_free(AgsRecallHandler * recall_handler)4386 ags_recall_handler_free(AgsRecallHandler *recall_handler)
4387 {
4388   if(recall_handler == NULL){
4389     return;
4390   }
4391 
4392   g_free(recall_handler->signal_name);
4393 
4394   free(recall_handler);
4395 }
4396 
4397 /**
4398  * ags_recall_handler_alloc:
4399  * @signal_name: signal's name to connect
4400  * @callback: (scope call): the #GCallback function
4401  * @data: the data to pass the callback
4402  *
4403  * Allocates #AgsRecallHandler-struct.
4404  *
4405  * Returns: (type gpointer) (transfer none): the newly allocated #AgsRecallHandler-struct
4406  *
4407  * Since: 3.0.0
4408  */
4409 AgsRecallHandler*
ags_recall_handler_alloc(const gchar * signal_name,GCallback callback,GObject * data)4410 ags_recall_handler_alloc(const gchar *signal_name,
4411 			 GCallback callback,
4412 			 GObject *data)
4413 {
4414   AgsRecallHandler *recall_handler;
4415 
4416   recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
4417 
4418   recall_handler->signal_name = g_strdup(signal_name);
4419   recall_handler->callback = callback;
4420   recall_handler->data = data;
4421 
4422   return(recall_handler);
4423 }
4424 
4425 /**
4426  * ags_recall_add_recall_handler:
4427  * @recall: the #AgsRecall to connect
4428  * @recall_handler: (type gpointer) (transfer none): the signal specs
4429  *
4430  * Connect callback to @recall specified by @recall_handler.
4431  *
4432  * Since: 3.0.0
4433  */
4434 void
ags_recall_add_recall_handler(AgsRecall * recall,AgsRecallHandler * recall_handler)4435 ags_recall_add_recall_handler(AgsRecall *recall,
4436 			      AgsRecallHandler *recall_handler)
4437 {
4438   GRecMutex *recall_mutex;
4439 
4440   if(!AGS_IS_RECALL(recall) ||
4441      recall_handler == NULL){
4442     return;
4443   }
4444 
4445   /* get recall mutex */
4446   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4447 
4448   /* add handler */
4449   g_rec_mutex_lock(recall_mutex);
4450 
4451   recall->recall_handler = g_list_prepend(recall->recall_handler,
4452 					  recall_handler);
4453 
4454   g_rec_mutex_unlock(recall_mutex);
4455 }
4456 
4457 /**
4458  * ags_recall_remove_recall_handler:
4459  * @recall: the #AgsRecall to connect
4460  * @recall_handler: (type gpointer) (transfer none): the signal specs
4461  *
4462  * Remove a #AgsRecallHandler-struct from @recall.
4463  *
4464  * Since: 3.0.0
4465  */
4466 void
ags_recall_remove_recall_handler(AgsRecall * recall,AgsRecallHandler * recall_handler)4467 ags_recall_remove_recall_handler(AgsRecall *recall,
4468 				 AgsRecallHandler *recall_handler)
4469 {
4470   GRecMutex *recall_mutex;
4471 
4472   if(!AGS_IS_RECALL(recall) ||
4473      recall_handler == NULL){
4474     return;
4475   }
4476 
4477   /* get recall mutex */
4478   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4479 
4480   /* remove handler */
4481   g_rec_mutex_lock(recall_mutex);
4482 
4483   recall->recall_handler = g_list_remove(recall->recall_handler,
4484 					 recall_handler);
4485 
4486   g_rec_mutex_unlock(recall_mutex);
4487 }
4488 
4489 /**
4490  * ags_recall_get_output_soundcard:
4491  * @recall: the #AgsRecall
4492  *
4493  * Get the output soundcard object of @recall.
4494  *
4495  * Returns: (transfer full): the output soundcard
4496  *
4497  * Since: 3.1.0
4498  */
4499 GObject*
ags_recall_get_output_soundcard(AgsRecall * recall)4500 ags_recall_get_output_soundcard(AgsRecall *recall)
4501 {
4502   GObject *output_soundcard;
4503 
4504   if(!AGS_IS_RECALL(recall)){
4505     return(NULL);
4506   }
4507 
4508   g_object_get(recall,
4509 	       "output-soundcard", &output_soundcard,
4510 	       NULL);
4511 
4512   return(output_soundcard);
4513 }
4514 
4515 /**
4516  * ags_recall_set_output_soundcard:
4517  * @recall: the #AgsRecall
4518  * @output_soundcard: the #GObject implementing #AgsSoundcard
4519  *
4520  * Set output soundcard of @recall.
4521  *
4522  * Since: 3.0.0
4523  */
4524 void
ags_recall_set_output_soundcard(AgsRecall * recall,GObject * output_soundcard)4525 ags_recall_set_output_soundcard(AgsRecall *recall, GObject *output_soundcard)
4526 {
4527   guint samplerate;
4528   guint buffer_size;
4529   guint format;
4530 
4531   GRecMutex *recall_mutex;
4532 
4533   if(!AGS_IS_RECALL(recall)){
4534     return;
4535   }
4536 
4537   /* get recall mutex */
4538   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4539 
4540   samplerate = AGS_SOUNDCARD_DEFAULT_SAMPLERATE;
4541   buffer_size = AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE;
4542   format = AGS_SOUNDCARD_DEFAULT_FORMAT;
4543 
4544   /* unref of old soundcard */
4545   g_rec_mutex_lock(recall_mutex);
4546 
4547   if(recall->output_soundcard != NULL){
4548     g_signal_handlers_disconnect_by_data(recall->output_soundcard,
4549 					 recall);
4550 
4551     g_object_unref(recall->output_soundcard);
4552   }
4553 
4554   /* ref and set output soundcard */
4555   if(output_soundcard != NULL){
4556     g_object_ref(output_soundcard);
4557 
4558     ags_soundcard_get_presets(AGS_SOUNDCARD(output_soundcard),
4559 			      NULL,
4560 			      &samplerate,
4561 			      &buffer_size,
4562 			      &format);
4563   }
4564 
4565   recall->output_soundcard = output_soundcard;
4566 
4567   g_rec_mutex_unlock(recall_mutex);
4568 
4569   g_object_set(recall,
4570 	       "samplerate", samplerate,
4571 	       "buffer-size", buffer_size,
4572 	       "format", format,
4573 	       NULL);
4574 }
4575 
4576 /**
4577  * ags_recall_get_input_soundcard:
4578  * @recall: the #AgsRecall
4579  *
4580  * Get the input soundcard object of @recall.
4581  *
4582  * Returns: (transfer full): the input soundcard
4583  *
4584  * Since: 3.1.0
4585  */
4586 GObject*
ags_recall_get_input_soundcard(AgsRecall * recall)4587 ags_recall_get_input_soundcard(AgsRecall *recall)
4588 {
4589   GObject *input_soundcard;
4590 
4591   if(!AGS_IS_RECALL(recall)){
4592     return(NULL);
4593   }
4594 
4595   g_object_get(recall,
4596 	       "input-soundcard", &input_soundcard,
4597 	       NULL);
4598 
4599   return(input_soundcard);
4600 }
4601 
4602 /**
4603  * ags_recall_set_input_soundcard:
4604  * @recall: the #AgsRecall
4605  * @input_soundcard: the #GObject implementing #AgsSoundcard
4606  *
4607  * Set input soundcard of @recall.
4608  *
4609  * Since: 3.0.0
4610  */
4611 void
ags_recall_set_input_soundcard(AgsRecall * recall,GObject * input_soundcard)4612 ags_recall_set_input_soundcard(AgsRecall *recall, GObject *input_soundcard)
4613 {
4614   GRecMutex *recall_mutex;
4615 
4616   if(!AGS_IS_RECALL(recall)){
4617     return;
4618   }
4619 
4620   /* get recall mutex */
4621   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4622 
4623   /* unref of old soundcard */
4624   g_rec_mutex_lock(recall_mutex);
4625 
4626   if(recall->input_soundcard != NULL){
4627     g_signal_handlers_disconnect_by_data(recall->input_soundcard,
4628 					 recall);
4629 
4630     g_object_unref(recall->input_soundcard);
4631   }
4632 
4633   /* ref and set input soundcard */
4634   if(input_soundcard != NULL){
4635     g_object_ref(input_soundcard);
4636   }
4637 
4638   recall->input_soundcard = input_soundcard;
4639 
4640   g_rec_mutex_unlock(recall_mutex);
4641 }
4642 
4643 /**
4644  * ags_recall_get_samplerate:
4645  * @recall: the #AgsRecall
4646  *
4647  * Gets samplerate.
4648  *
4649  * Returns: the samplerate
4650  *
4651  * Since: 3.1.0
4652  */
4653 guint
ags_recall_get_samplerate(AgsRecall * recall)4654 ags_recall_get_samplerate(AgsRecall *recall)
4655 {
4656   guint samplerate;
4657 
4658   if(!AGS_IS_RECALL(recall)){
4659     return(0);
4660   }
4661 
4662   g_object_get(recall,
4663 	       "samplerate", &samplerate,
4664 	       NULL);
4665 
4666   return(samplerate);
4667 }
4668 
4669 /**
4670  * ags_recall_set_samplerate:
4671  * @recall: the #AgsRecall
4672  * @samplerate: the samplerate
4673  *
4674  * Set samplerate of @recall.
4675  *
4676  * Since: 3.0.0
4677  */
4678 void
ags_recall_set_samplerate(AgsRecall * recall,guint samplerate)4679 ags_recall_set_samplerate(AgsRecall *recall, guint samplerate)
4680 {
4681   GRecMutex *recall_mutex;
4682 
4683   if(!AGS_IS_RECALL(recall)){
4684     return;
4685   }
4686 
4687   /* get recall mutex */
4688   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4689 
4690   /* set samplerate */
4691   g_rec_mutex_lock(recall_mutex);
4692 
4693   recall->samplerate = samplerate;
4694 
4695   g_rec_mutex_unlock(recall_mutex);
4696 }
4697 
4698 /**
4699  * ags_recall_get_buffer_size:
4700  * @recall: the #AgsRecall
4701  *
4702  * Gets buffer size.
4703  *
4704  * Returns: the buffer size
4705  *
4706  * Since: 3.1.0
4707  */
4708 guint
ags_recall_get_buffer_size(AgsRecall * recall)4709 ags_recall_get_buffer_size(AgsRecall *recall)
4710 {
4711   guint buffer_size;
4712 
4713   if(!AGS_IS_RECALL(recall)){
4714     return(0);
4715   }
4716 
4717   g_object_get(recall,
4718 	       "buffer-size", &buffer_size,
4719 	       NULL);
4720 
4721   return(buffer_size);
4722 }
4723 
4724 /**
4725  * ags_recall_set_buffer_size:
4726  * @recall: the #AgsRecall
4727  * @buffer_size: the buffer size
4728  *
4729  * Set buffer size of @recall.
4730  *
4731  * Since: 3.0.0
4732  */
4733 void
ags_recall_set_buffer_size(AgsRecall * recall,guint buffer_size)4734 ags_recall_set_buffer_size(AgsRecall *recall, guint buffer_size)
4735 {
4736   GRecMutex *recall_mutex;
4737 
4738   if(!AGS_IS_RECALL(recall)){
4739     return;
4740   }
4741 
4742   /* get recall mutex */
4743   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4744 
4745   /* set buffer size */
4746   g_rec_mutex_lock(recall_mutex);
4747 
4748   recall->buffer_size = buffer_size;
4749 
4750   g_rec_mutex_unlock(recall_mutex);
4751 }
4752 
4753 /**
4754  * ags_recall_get_format:
4755  * @recall: the #AgsRecall
4756  *
4757  * Gets format.
4758  *
4759  * Returns: the format
4760  *
4761  * Since: 3.1.0
4762  */
4763 guint
ags_recall_get_format(AgsRecall * recall)4764 ags_recall_get_format(AgsRecall *recall)
4765 {
4766   guint format;
4767 
4768   if(!AGS_IS_RECALL(recall)){
4769     return(0);
4770   }
4771 
4772   g_object_get(recall,
4773 	       "format", &format,
4774 	       NULL);
4775 
4776   return(format);
4777 }
4778 
4779 /**
4780  * ags_recall_set_format:
4781  * @recall: the #AgsRecall
4782  * @format: the format
4783  *
4784  * Set format of @recall.
4785  *
4786  * Since: 3.0.0
4787  */
4788 void
ags_recall_set_format(AgsRecall * recall,guint format)4789 ags_recall_set_format(AgsRecall *recall, guint format)
4790 {
4791   GRecMutex *recall_mutex;
4792 
4793   if(!AGS_IS_RECALL(recall)){
4794     return;
4795   }
4796 
4797   /* get recall mutex */
4798   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4799 
4800   /* set format */
4801   g_rec_mutex_lock(recall_mutex);
4802 
4803   recall->format = format;
4804 
4805   g_rec_mutex_unlock(recall_mutex);
4806 }
4807 
4808 void
ags_recall_real_resolve_dependency(AgsRecall * recall)4809 ags_recall_real_resolve_dependency(AgsRecall *recall)
4810 {
4811   GList *list_start, *list, *next;
4812 
4813   gboolean children_lock_free;
4814 
4815   GRecMutex *recall_mutex;
4816 
4817   /* get recall mutex */
4818   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4819 
4820   children_lock_free = ags_recall_global_get_children_lock_free();
4821 
4822   /* resolve dependency */
4823   g_rec_mutex_lock(recall_mutex);
4824 
4825   if((AGS_RECALL_TEMPLATE & (AGS_RECALL(recall)->flags)) != 0){
4826     g_warning("running on template");
4827   }
4828 
4829   if(!children_lock_free){
4830     list =
4831       list_start = g_list_copy(recall->children);
4832   }else{
4833     list =
4834       list_start = recall->children;
4835   }
4836 
4837   g_rec_mutex_unlock(recall_mutex);
4838 
4839   while(list != NULL){
4840     next = list->next;
4841 
4842     ags_recall_resolve_dependency(AGS_RECALL(list->data));
4843 
4844     list = next;
4845   }
4846 
4847   if(!children_lock_free){
4848     g_list_free(list_start);
4849   }
4850 }
4851 
4852 /**
4853  * ags_recall_resolve_dependency:
4854  * @recall: the #AgsRecall
4855  *
4856  * A signal indicating that the inheriting object should resolve
4857  * it's dependency.
4858  *
4859  * Since: 3.0.0
4860  */
4861 void
ags_recall_resolve_dependency(AgsRecall * recall)4862 ags_recall_resolve_dependency(AgsRecall *recall)
4863 {
4864   g_return_if_fail(AGS_IS_RECALL(recall));
4865 
4866 #ifdef AGS_DEBUG
4867   g_message("resolving %s", G_OBJECT_TYPE_NAME(recall));
4868 #endif
4869 
4870   g_object_ref(G_OBJECT(recall));
4871   g_signal_emit(G_OBJECT(recall),
4872 		recall_signals[PLAY_RESOLVE_DEPENDENCY], 0);
4873   g_object_unref(G_OBJECT(recall));
4874 }
4875 
4876 void
ags_recall_real_check_rt_data(AgsRecall * recall)4877 ags_recall_real_check_rt_data(AgsRecall *recall)
4878 {
4879   GList *list_start, *list, *next;
4880 
4881   gboolean children_lock_free;
4882 
4883   GRecMutex *recall_mutex;
4884 
4885   /* get recall mutex */
4886   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4887 
4888   children_lock_free = ags_recall_global_get_children_lock_free();
4889 
4890   /* check rt data */
4891   g_rec_mutex_lock(recall_mutex);
4892 
4893   recall->staging_flags |= AGS_SOUND_STAGING_CHECK_RT_DATA;
4894 
4895   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
4896     g_warning("running on template");
4897   }
4898 
4899   if(!children_lock_free){
4900     list =
4901       list_start = g_list_copy(recall->children);
4902   }else{
4903     list =
4904       list_start = recall->children;
4905   }
4906 
4907   g_rec_mutex_unlock(recall_mutex);
4908 
4909   while(list != NULL){
4910     next = list->next;
4911 
4912     ags_recall_check_rt_data(AGS_RECALL(list->data));
4913 
4914     list = next;
4915   }
4916 
4917   if(!children_lock_free){
4918     g_list_free(list_start);
4919   }
4920 
4921   /* set is waiting */
4922   g_rec_mutex_lock(recall_mutex);
4923 
4924   recall->state_flags |= (AGS_SOUND_STATE_IS_WAITING);
4925 
4926   g_rec_mutex_unlock(recall_mutex);
4927 }
4928 
4929 /**
4930  * ags_recall_check_rt_data:
4931  * @recall: the #AgsRecall
4932  *
4933  * Prepare for run, this is the pre stage within the preparation.
4934  *
4935  * Since: 3.0.0
4936  */
4937 void
ags_recall_check_rt_data(AgsRecall * recall)4938 ags_recall_check_rt_data(AgsRecall *recall)
4939 {
4940   g_return_if_fail(AGS_IS_RECALL(recall));
4941   g_return_if_fail(!ags_recall_test_state_flags(recall, AGS_SOUND_STATE_IS_TERMINATING));
4942 
4943   g_object_ref(G_OBJECT(recall));
4944   g_signal_emit(G_OBJECT(recall),
4945 		recall_signals[PLAY_CHECK_RT_DATA], 0);
4946   g_object_unref(G_OBJECT(recall));
4947 }
4948 
4949 void
ags_recall_real_run_init_pre(AgsRecall * recall)4950 ags_recall_real_run_init_pre(AgsRecall *recall)
4951 {
4952   GList *list_start, *list, *next;
4953 
4954   gboolean children_lock_free;
4955   gboolean omit_event;
4956 
4957   GRecMutex *recall_mutex;
4958 
4959   /* get recall mutex */
4960   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
4961 
4962   children_lock_free = ags_recall_global_get_children_lock_free();
4963   omit_event = ags_recall_global_get_omit_event();
4964 
4965   /* run init pre */
4966   g_rec_mutex_lock(recall_mutex);
4967 
4968   if((AGS_SOUND_STAGING_RUN_INIT_PRE & (recall->staging_flags)) != 0){
4969     g_rec_mutex_unlock(recall_mutex);
4970 
4971     return;
4972   }
4973 
4974   recall->flags |= AGS_RECALL_INITIAL_RUN;
4975   recall->staging_flags |= AGS_SOUND_STAGING_RUN_INIT_PRE;
4976 
4977   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
4978     g_warning("running on template");
4979   }
4980 
4981   if(!children_lock_free){
4982     list =
4983       list_start = g_list_copy_deep(recall->children,
4984 				    (GCopyFunc) g_object_ref,
4985 				    NULL);
4986   }else{
4987     list =
4988       list_start = recall->children;
4989   }
4990 
4991   g_rec_mutex_unlock(recall_mutex);
4992 
4993   while(list != NULL){
4994     next = list->next;
4995 
4996     if(omit_event){
4997       AGS_RECALL_GET_CLASS(AGS_RECALL(list->data))->run_init_pre(AGS_RECALL(list->data));
4998     }else{
4999       ags_recall_run_init_pre(AGS_RECALL(list->data));
5000     }
5001 
5002     list = next;
5003   }
5004 
5005   if(!children_lock_free){
5006     g_list_free_full(list_start,
5007 		     g_object_unref);
5008   }
5009 }
5010 
5011 /**
5012  * ags_recall_run_init_pre:
5013  * @recall: the #AgsRecall
5014  *
5015  * Prepare for run, this is the pre stage within the preparation.
5016  *
5017  * Since: 3.0.0
5018  */
5019 void
ags_recall_run_init_pre(AgsRecall * recall)5020 ags_recall_run_init_pre(AgsRecall *recall)
5021 {
5022   g_return_if_fail(AGS_IS_RECALL(recall));
5023   g_return_if_fail(!ags_recall_test_state_flags(recall, AGS_SOUND_STATE_IS_TERMINATING));
5024 
5025   g_object_ref(G_OBJECT(recall));
5026   g_signal_emit(G_OBJECT(recall),
5027 		recall_signals[PLAY_RUN_INIT_PRE], 0);
5028   g_object_unref(G_OBJECT(recall));
5029 }
5030 
5031 void
ags_recall_real_run_init_inter(AgsRecall * recall)5032 ags_recall_real_run_init_inter(AgsRecall *recall)
5033 {
5034   GList *list_start, *list, *next;
5035 
5036   gboolean children_lock_free;
5037   gboolean omit_event;
5038 
5039   GRecMutex *recall_mutex;
5040 
5041   /* get recall mutex */
5042   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5043 
5044   children_lock_free = ags_recall_global_get_children_lock_free();
5045   omit_event = ags_recall_global_get_omit_event();
5046 
5047   /* run init inter */
5048   g_rec_mutex_lock(recall_mutex);
5049 
5050   if((AGS_SOUND_STAGING_RUN_INIT_INTER & (recall->staging_flags)) != 0){
5051     g_rec_mutex_unlock(recall_mutex);
5052 
5053     return;
5054   }
5055 
5056   recall->staging_flags |= AGS_SOUND_STAGING_RUN_INIT_INTER;
5057 
5058   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
5059     g_warning("running on template");
5060   }
5061 
5062   if(!children_lock_free){
5063     list =
5064       list_start = g_list_copy_deep(recall->children,
5065 				    (GCopyFunc) g_object_ref,
5066 				    NULL);
5067   }else{
5068     list =
5069       list_start = recall->children;
5070   }
5071 
5072   g_rec_mutex_unlock(recall_mutex);
5073 
5074   while(list != NULL){
5075     next = list->next;
5076 
5077     if(omit_event){
5078       AGS_RECALL_GET_CLASS(AGS_RECALL(list->data))->run_init_inter(AGS_RECALL(list->data));
5079     }else{
5080       ags_recall_run_init_inter(AGS_RECALL(list->data));
5081     }
5082 
5083     list = next;
5084   }
5085 
5086   if(!children_lock_free){
5087     g_list_free_full(list_start,
5088 		     g_object_unref);
5089   }
5090 }
5091 
5092 /**
5093  * ags_recall_run_init_inter:
5094  * @recall: the #AgsRecall
5095  *
5096  * Prepare for run, this is the inter stage within the preparation.
5097  *
5098  * Since: 3.0.0
5099  */
5100 void
ags_recall_run_init_inter(AgsRecall * recall)5101 ags_recall_run_init_inter(AgsRecall *recall)
5102 {
5103   g_return_if_fail(AGS_IS_RECALL(recall));
5104   g_return_if_fail(!ags_recall_test_state_flags(recall, AGS_SOUND_STATE_IS_TERMINATING));
5105 
5106   g_object_ref(G_OBJECT(recall));
5107   g_signal_emit(G_OBJECT(recall),
5108 		recall_signals[PLAY_RUN_INIT_INTER], 0);
5109   g_object_unref(G_OBJECT(recall));
5110 }
5111 
5112 void
ags_recall_real_run_init_post(AgsRecall * recall)5113 ags_recall_real_run_init_post(AgsRecall *recall)
5114 {
5115   GList *list_start, *list, *next;
5116 
5117   gboolean children_lock_free;
5118   gboolean omit_event;
5119 
5120   GRecMutex *recall_mutex;
5121 
5122   /* get recall mutex */
5123   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5124 
5125   children_lock_free = ags_recall_global_get_children_lock_free();
5126   omit_event = ags_recall_global_get_omit_event();
5127 
5128   /* run init post */
5129   g_rec_mutex_lock(recall_mutex);
5130 
5131   if((AGS_SOUND_STAGING_RUN_INIT_POST & (recall->staging_flags)) != 0){
5132     g_rec_mutex_unlock(recall_mutex);
5133 
5134     return;
5135   }
5136 
5137   recall->staging_flags |= AGS_SOUND_STAGING_RUN_INIT_POST;
5138 
5139   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
5140     g_warning("running on template");
5141   }
5142 
5143   if(!children_lock_free){
5144     list =
5145       list_start = g_list_copy_deep(recall->children,
5146 				    (GCopyFunc) g_object_ref,
5147 				    NULL);
5148   }else{
5149     list =
5150       list_start = recall->children;
5151   }
5152 
5153   g_rec_mutex_unlock(recall_mutex);
5154 
5155   while(list != NULL){
5156     next = list->next;
5157 
5158     if(omit_event){
5159       AGS_RECALL_GET_CLASS(AGS_RECALL(list->data))->run_init_post(AGS_RECALL(list->data));
5160     }else{
5161       ags_recall_run_init_post(AGS_RECALL(list->data));
5162     }
5163 
5164     list = next;
5165   }
5166 
5167   if(!children_lock_free){
5168     g_list_free_full(list_start,
5169 		     g_object_unref);
5170   }
5171 
5172   /* set active */
5173   g_rec_mutex_lock(recall_mutex);
5174 
5175   recall->state_flags &= (~AGS_SOUND_STATE_IS_WAITING);
5176   recall->state_flags |= (AGS_SOUND_STATE_IS_ACTIVE);
5177 
5178   g_rec_mutex_unlock(recall_mutex);
5179 }
5180 
5181 /**
5182  * ags_recall_run_init_post:
5183  * @recall: the #AgsRecall
5184  *
5185  * Prepare for run, this is the post stage within the preparation.
5186  *
5187  * Since: 3.0.0
5188  */
5189 void
ags_recall_run_init_post(AgsRecall * recall)5190 ags_recall_run_init_post(AgsRecall *recall)
5191 {
5192   g_return_if_fail(AGS_IS_RECALL(recall));
5193   g_return_if_fail(!ags_recall_test_state_flags(recall, AGS_SOUND_STATE_IS_TERMINATING));
5194 
5195   g_object_ref(G_OBJECT(recall));
5196   g_signal_emit(G_OBJECT(recall),
5197 		recall_signals[PLAY_RUN_INIT_POST], 0);
5198   g_object_unref(G_OBJECT(recall));
5199 }
5200 
5201 void
ags_recall_real_feed_input_queue(AgsRecall * recall)5202 ags_recall_real_feed_input_queue(AgsRecall *recall)
5203 {
5204   GList *list_start, *list, *next;
5205 
5206   GRecMutex *recall_mutex;
5207 
5208   gboolean children_lock_free;
5209   gboolean omit_event;
5210 
5211   /* get recall mutex */
5212   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5213 
5214   children_lock_free = ags_recall_global_get_children_lock_free();
5215   omit_event = ags_recall_global_get_omit_event();
5216 
5217   /* feed input queue */
5218   g_rec_mutex_lock(recall_mutex);
5219 
5220   if((AGS_SOUND_STAGING_FEED_INPUT_QUEUE & (recall->staging_flags)) != 0){
5221     g_rec_mutex_unlock(recall_mutex);
5222 
5223     return;
5224   }
5225 
5226   recall->staging_flags |= AGS_SOUND_STAGING_FEED_INPUT_QUEUE;
5227 
5228   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
5229     g_warning("running on template");
5230   }
5231 
5232   if(!children_lock_free){
5233     list =
5234       list_start = g_list_copy_deep(recall->children,
5235 				    (GCopyFunc) g_object_ref,
5236 				    NULL);
5237   }else{
5238     list =
5239       list_start = recall->children;
5240   }
5241 
5242   g_rec_mutex_unlock(recall_mutex);
5243 
5244   while(list != NULL){
5245     next = list->next;
5246 
5247     if(omit_event){
5248       AGS_RECALL_GET_CLASS(AGS_RECALL(list->data))->feed_input_queue(AGS_RECALL(list->data));
5249     }else{
5250       ags_recall_feed_input_queue(AGS_RECALL(list->data));
5251     }
5252 
5253     list = next;
5254   }
5255 
5256   if(!children_lock_free){
5257     g_list_free_full(list_start,
5258 		     g_object_unref);
5259   }
5260 }
5261 
5262 /**
5263  * ags_recall_feed_input_queue:
5264  * @recall: the #AgsRecall
5265  *
5266  * Feed input queue of @recall.
5267  *
5268  * Since: 3.0.0
5269  */
5270 void
ags_recall_feed_input_queue(AgsRecall * recall)5271 ags_recall_feed_input_queue(AgsRecall *recall)
5272 {
5273   g_return_if_fail(AGS_IS_RECALL(recall));
5274   g_return_if_fail(!ags_recall_test_state_flags(recall, AGS_SOUND_STATE_IS_TERMINATING));
5275 
5276   g_object_ref(G_OBJECT(recall));
5277   g_signal_emit(G_OBJECT(recall),
5278 		recall_signals[PLAY_FEED_INPUT_QUEUE], 0);
5279   g_object_unref(G_OBJECT(recall));
5280 }
5281 
5282 void
ags_recall_real_automate(AgsRecall * recall)5283 ags_recall_real_automate(AgsRecall *recall)
5284 {
5285   GList *list_start, *list, *next;
5286 
5287   GRecMutex *recall_mutex;
5288 
5289   gboolean children_lock_free;
5290   gboolean omit_event;
5291 
5292   /* get recall mutex */
5293   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5294 
5295   children_lock_free = ags_recall_global_get_children_lock_free();
5296   omit_event = ags_recall_global_get_omit_event();
5297 
5298   /* automate */
5299   g_rec_mutex_lock(recall_mutex);
5300 
5301   if((AGS_SOUND_STAGING_AUTOMATE & (recall->staging_flags)) != 0){
5302     g_rec_mutex_unlock(recall_mutex);
5303 
5304     return;
5305   }
5306 
5307   recall->staging_flags |= AGS_SOUND_STAGING_AUTOMATE;
5308 
5309   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
5310     g_warning("running on template");
5311   }
5312 
5313   list =
5314     list_start = g_list_copy_deep(recall->children,
5315 				  (GCopyFunc) g_object_ref,
5316 				  NULL);
5317 
5318   g_rec_mutex_unlock(recall_mutex);
5319 
5320   while(list != NULL){
5321     next = list->next;
5322 
5323     if(omit_event){
5324       AGS_RECALL_GET_CLASS(AGS_RECALL(list->data))->automate(AGS_RECALL(list->data));
5325     }else{
5326       ags_recall_automate(AGS_RECALL(list->data));
5327     }
5328 
5329     list = next;
5330   }
5331 
5332   g_list_free_full(list_start,
5333 		   g_object_unref);
5334 }
5335 
5336 /**
5337  * ags_recall_automate:
5338  * @recall: the #AgsRecall
5339  *
5340  * Automate port of @recall.
5341  *
5342  * Since: 3.0.0
5343  */
5344 void
ags_recall_automate(AgsRecall * recall)5345 ags_recall_automate(AgsRecall *recall)
5346 {
5347   g_return_if_fail(AGS_IS_RECALL(recall));
5348 
5349   g_object_ref(G_OBJECT(recall));
5350   g_signal_emit(G_OBJECT(recall),
5351 		recall_signals[PLAY_AUTOMATE], 0);
5352   g_object_unref(G_OBJECT(recall));
5353 }
5354 
5355 void
ags_recall_real_run_pre(AgsRecall * recall)5356 ags_recall_real_run_pre(AgsRecall *recall)
5357 {
5358   GList *list_start, *list, *next;
5359 
5360   GRecMutex *recall_mutex;
5361 
5362   gboolean children_lock_free;
5363   gboolean omit_event;
5364 
5365 #if 0
5366   if(AGS_IS_RECALL_AUDIO_SIGNAL(recall)){
5367     g_message("%s::run-pre()", G_OBJECT_TYPE_NAME(recall));
5368   }
5369 #endif
5370 
5371   /* get recall mutex */
5372   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5373 
5374   children_lock_free = ags_recall_global_get_children_lock_free();
5375   omit_event = ags_recall_global_get_omit_event();
5376 
5377   /* run pre */
5378   g_rec_mutex_lock(recall_mutex);
5379 
5380   if((AGS_SOUND_STAGING_RUN_PRE & (recall->staging_flags)) != 0){
5381     g_rec_mutex_unlock(recall_mutex);
5382 
5383     return;
5384   }
5385 
5386   recall->staging_flags |= AGS_SOUND_STAGING_RUN_PRE;
5387 
5388   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
5389     g_warning("running on template");
5390   }
5391 
5392   if(!children_lock_free){
5393     list =
5394       list_start = g_list_copy_deep(recall->children,
5395 				    (GCopyFunc) g_object_ref,
5396 				    NULL);
5397   }else{
5398     list =
5399       list_start = recall->children;
5400   }
5401 
5402   g_rec_mutex_unlock(recall_mutex);
5403 
5404   while(list != NULL){
5405     next = list->next;
5406 
5407     if(omit_event){
5408       AGS_RECALL_GET_CLASS(AGS_RECALL(list->data))->run_pre(AGS_RECALL(list->data));
5409     }else{
5410       ags_recall_run_pre(AGS_RECALL(list->data));
5411     }
5412 
5413     list = next;
5414   }
5415 
5416   if(!children_lock_free){
5417     g_list_free_full(list_start,
5418 		     g_object_unref);
5419   }
5420 }
5421 
5422 /**
5423  * ags_recall_run_pre:
5424  * @recall: the #AgsRecall
5425  *
5426  * This is the pre stage within a run.
5427  *
5428  * Since: 3.0.0
5429  */
5430 void
ags_recall_run_pre(AgsRecall * recall)5431 ags_recall_run_pre(AgsRecall *recall)
5432 {
5433   g_return_if_fail(AGS_IS_RECALL(recall));
5434   g_return_if_fail(!ags_recall_test_state_flags(recall, AGS_SOUND_STATE_IS_TERMINATING));
5435 
5436   g_object_ref(G_OBJECT(recall));
5437   g_signal_emit(G_OBJECT(recall),
5438 		recall_signals[PLAY_RUN_PRE], 0);
5439   g_object_unref(G_OBJECT(recall));
5440 }
5441 
5442 void
ags_recall_real_run_inter(AgsRecall * recall)5443 ags_recall_real_run_inter(AgsRecall *recall)
5444 {
5445   GList *list_start, *list, *next;
5446 
5447   GRecMutex *recall_mutex;
5448 
5449   gboolean children_lock_free;
5450   gboolean omit_event;
5451 
5452 #if 0
5453   if(AGS_IS_RECALL_AUDIO_SIGNAL(recall)){
5454     g_message("%s::run-inter()", G_OBJECT_TYPE_NAME(recall));
5455   }
5456 #endif
5457 
5458   /* get recall mutex */
5459   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5460 
5461   children_lock_free = ags_recall_global_get_children_lock_free();
5462   omit_event = ags_recall_global_get_omit_event();
5463 
5464   /* run inter */
5465   g_rec_mutex_lock(recall_mutex);
5466 
5467   if((AGS_SOUND_STAGING_RUN_INTER & (recall->staging_flags)) != 0){
5468     g_rec_mutex_unlock(recall_mutex);
5469 
5470     return;
5471   }
5472 
5473   recall->staging_flags |= AGS_SOUND_STAGING_RUN_INTER;
5474 
5475   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
5476     g_warning("running on template");
5477   }
5478 
5479   if(!children_lock_free){
5480     list =
5481       list_start = g_list_copy_deep(recall->children,
5482 				    (GCopyFunc) g_object_ref,
5483 				    NULL);
5484   }else{
5485     list =
5486       list_start = recall->children;
5487   }
5488 
5489   g_rec_mutex_unlock(recall_mutex);
5490 
5491   while(list != NULL){
5492     next = list->next;
5493 
5494     if(omit_event){
5495       AGS_RECALL_GET_CLASS(AGS_RECALL(list->data))->run_inter(AGS_RECALL(list->data));
5496     }else{
5497       ags_recall_run_inter(AGS_RECALL(list->data));
5498     }
5499 
5500     list = next;
5501   }
5502 
5503   if(!children_lock_free){
5504     g_list_free_full(list_start,
5505 		     g_object_unref);
5506   }
5507 }
5508 
5509 /**
5510  * ags_recall_run_inter:
5511  * @recall: the #AgsRecall
5512  *
5513  * This is the inter stage within a run.
5514  *
5515  * Since: 3.0.0
5516  */
5517 void
ags_recall_run_inter(AgsRecall * recall)5518 ags_recall_run_inter(AgsRecall *recall)
5519 {
5520   g_return_if_fail(AGS_IS_RECALL(recall));
5521   g_return_if_fail(!ags_recall_test_state_flags(recall, AGS_SOUND_STATE_IS_TERMINATING));
5522 
5523   g_object_ref(G_OBJECT(recall));
5524   g_signal_emit(G_OBJECT(recall),
5525 		recall_signals[PLAY_RUN_INTER], 0);
5526   g_object_unref(G_OBJECT(recall));
5527 }
5528 
5529 void
ags_recall_real_run_post(AgsRecall * recall)5530 ags_recall_real_run_post(AgsRecall *recall)
5531 {
5532   GList *list_start, *list, *next;
5533 
5534   GRecMutex *recall_mutex;
5535 
5536   gboolean children_lock_free;
5537   gboolean omit_event;
5538 
5539 #if 0
5540   if(AGS_IS_RECALL_AUDIO_SIGNAL(recall)){
5541     g_message("%s::run-post()", G_OBJECT_TYPE_NAME(recall));
5542   }
5543 #endif
5544 
5545   /* get recall mutex */
5546   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5547 
5548   children_lock_free = ags_recall_global_get_children_lock_free();
5549   omit_event = ags_recall_global_get_omit_event();
5550 
5551   /* run post */
5552   g_rec_mutex_lock(recall_mutex);
5553 
5554   if((AGS_SOUND_STAGING_RUN_POST & (recall->staging_flags)) != 0){
5555     g_rec_mutex_unlock(recall_mutex);
5556 
5557     return;
5558   }
5559 
5560   recall->staging_flags |= AGS_SOUND_STAGING_RUN_POST;
5561   recall->flags &= (~AGS_RECALL_INITIAL_RUN);
5562 
5563   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
5564     g_warning("running on template");
5565   }
5566 
5567   if(!children_lock_free){
5568     list =
5569       list_start = g_list_copy_deep(recall->children,
5570 				    (GCopyFunc) g_object_ref,
5571 				    NULL);
5572   }else{
5573     list =
5574       list_start = recall->children;
5575   }
5576 
5577   g_rec_mutex_unlock(recall_mutex);
5578 
5579   while(list != NULL){
5580     next = list->next;
5581 
5582     if(omit_event){
5583       AGS_RECALL_GET_CLASS(AGS_RECALL(list->data))->run_post(AGS_RECALL(list->data));
5584     }else{
5585       ags_recall_run_post(AGS_RECALL(list->data));
5586     }
5587 
5588     list = next;
5589   }
5590 
5591   if(!children_lock_free){
5592     g_list_free_full(list_start,
5593 		     g_object_unref);
5594   }
5595 }
5596 
5597 /**
5598  * ags_recall_run_post:
5599  * @recall: the #AgsRecall
5600  *
5601  * This is the post stage within a run.
5602  *
5603  * Since: 3.0.0
5604  */
5605 void
ags_recall_run_post(AgsRecall * recall)5606 ags_recall_run_post(AgsRecall *recall)
5607 {
5608   g_return_if_fail(AGS_IS_RECALL(recall));
5609   g_return_if_fail(!ags_recall_test_state_flags(recall, AGS_SOUND_STATE_IS_TERMINATING));
5610 
5611   g_object_ref(G_OBJECT(recall));
5612   g_signal_emit(G_OBJECT(recall),
5613 		recall_signals[PLAY_RUN_POST], 0);
5614   g_object_unref(G_OBJECT(recall));
5615 }
5616 
5617 void
ags_recall_real_do_feedback(AgsRecall * recall)5618 ags_recall_real_do_feedback(AgsRecall *recall)
5619 {
5620   GList *list_start, *list, *next;
5621 
5622   GRecMutex *recall_mutex;
5623 
5624   gboolean children_lock_free;
5625   gboolean omit_event;
5626 
5627   /* get recall mutex */
5628   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5629 
5630   children_lock_free = ags_recall_global_get_children_lock_free();
5631   omit_event = ags_recall_global_get_omit_event();
5632 
5633   /* do feedback */
5634   g_rec_mutex_lock(recall_mutex);
5635 
5636   if((AGS_SOUND_STAGING_DO_FEEDBACK & (recall->staging_flags)) != 0){
5637     g_rec_mutex_unlock(recall_mutex);
5638 
5639     return;
5640   }
5641 
5642   recall->staging_flags |= AGS_SOUND_STAGING_DO_FEEDBACK;
5643 
5644   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
5645     g_warning("running on template");
5646   }
5647 
5648   if(!children_lock_free){
5649     list =
5650       list_start = g_list_copy_deep(recall->children,
5651 				    (GCopyFunc) g_object_ref,
5652 				    NULL);
5653   }else{
5654     list =
5655       list_start = recall->children;
5656   }
5657 
5658   g_rec_mutex_unlock(recall_mutex);
5659 
5660   while(list != NULL){
5661     next = list->next;
5662 
5663     if(omit_event){
5664       AGS_RECALL_GET_CLASS(AGS_RECALL(list->data))->do_feedback(AGS_RECALL(list->data));
5665     }else{
5666       ags_recall_do_feedback(AGS_RECALL(list->data));
5667     }
5668 
5669     list = next;
5670   }
5671 
5672   if(!children_lock_free){
5673     g_list_free_full(list_start,
5674 		     g_object_unref);
5675   }
5676 }
5677 
5678 /**
5679  * ags_recall_do_feedback:
5680  * @recall: the #AgsRecall
5681  *
5682  * Do feedback of @recall.
5683  *
5684  * Since: 3.0.0
5685  */
5686 void
ags_recall_do_feedback(AgsRecall * recall)5687 ags_recall_do_feedback(AgsRecall *recall)
5688 {
5689   g_return_if_fail(AGS_IS_RECALL(recall));
5690   g_return_if_fail(!ags_recall_test_state_flags(recall, AGS_SOUND_STATE_IS_TERMINATING));
5691 
5692   g_object_ref(G_OBJECT(recall));
5693   g_signal_emit(G_OBJECT(recall),
5694 		recall_signals[PLAY_DO_FEEDBACK], 0);
5695   g_object_unref(G_OBJECT(recall));
5696 }
5697 
5698 void
ags_recall_real_feed_output_queue(AgsRecall * recall)5699 ags_recall_real_feed_output_queue(AgsRecall *recall)
5700 {
5701   GList *list_start, *list, *next;
5702 
5703   GRecMutex *recall_mutex;
5704 
5705   gboolean children_lock_free;
5706   gboolean omit_event;
5707 
5708   /* get recall mutex */
5709   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5710 
5711   children_lock_free = ags_recall_global_get_children_lock_free();
5712   omit_event = ags_recall_global_get_omit_event();
5713 
5714   /* feed output queue */
5715   g_rec_mutex_lock(recall_mutex);
5716 
5717   if((AGS_SOUND_STAGING_FEED_OUTPUT_QUEUE & (recall->staging_flags)) != 0){
5718     g_rec_mutex_unlock(recall_mutex);
5719 
5720     return;
5721   }
5722 
5723   recall->staging_flags |= AGS_SOUND_STAGING_FEED_OUTPUT_QUEUE;
5724 
5725   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
5726     g_warning("running on template");
5727   }
5728 
5729   if(!children_lock_free){
5730     list =
5731       list_start = g_list_copy_deep(recall->children,
5732 				    (GCopyFunc) g_object_ref,
5733 				    NULL);
5734   }else{
5735     list =
5736       list_start = recall->children;
5737   }
5738 
5739   g_rec_mutex_unlock(recall_mutex);
5740 
5741   while(list != NULL){
5742     next = list->next;
5743 
5744     if(omit_event){
5745       AGS_RECALL_GET_CLASS(AGS_RECALL(list->data))->feed_output_queue(AGS_RECALL(list->data));
5746     }else{
5747       ags_recall_feed_output_queue(AGS_RECALL(list->data));
5748     }
5749 
5750     list = next;
5751   }
5752 
5753   if(!children_lock_free){
5754     g_list_free_full(list_start,
5755 		     g_object_unref);
5756   }
5757 }
5758 
5759 /**
5760  * ags_recall_feed_output_queue:
5761  * @recall: the #AgsRecall
5762  *
5763  * Feed output queue of @recall.
5764  *
5765  * Since: 3.0.0
5766  */
5767 void
ags_recall_feed_output_queue(AgsRecall * recall)5768 ags_recall_feed_output_queue(AgsRecall *recall)
5769 {
5770   g_return_if_fail(AGS_IS_RECALL(recall));
5771   g_return_if_fail(!ags_recall_test_state_flags(recall, AGS_SOUND_STATE_IS_TERMINATING));
5772 
5773   g_object_ref(G_OBJECT(recall));
5774   g_signal_emit(G_OBJECT(recall),
5775 		recall_signals[PLAY_FEED_OUTPUT_QUEUE], 0);
5776   g_object_unref(G_OBJECT(recall));
5777 }
5778 
5779 void
ags_recall_real_stop_persistent(AgsRecall * recall)5780 ags_recall_real_stop_persistent(AgsRecall *recall)
5781 {
5782   GRecMutex *recall_mutex;
5783 
5784   /* get recall mutex */
5785   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5786 
5787   /* check state and staging */
5788   g_rec_mutex_lock(recall_mutex);
5789 
5790   if((AGS_SOUND_STATE_IS_TERMINATING & (recall->state_flags)) != 0 ||
5791      (AGS_SOUND_STAGING_DONE & (recall->staging_flags)) != 0){
5792     g_rec_mutex_unlock(recall_mutex);
5793 
5794     return;
5795   }
5796 
5797   recall->behaviour_flags &= (~(AGS_SOUND_BEHAVIOUR_PERSISTENT |
5798 				AGS_SOUND_BEHAVIOUR_PERSISTENT_PLAYBACK |
5799 				AGS_SOUND_BEHAVIOUR_PERSISTENT_NOTATION |
5800 				AGS_SOUND_BEHAVIOUR_PERSISTENT_SEQUENCER |
5801 				AGS_SOUND_BEHAVIOUR_PERSISTENT_WAVE |
5802 				AGS_SOUND_BEHAVIOUR_PERSISTENT_MIDI));
5803 
5804   g_rec_mutex_unlock(recall_mutex);
5805 
5806   /* emit done */
5807   ags_recall_done(recall);
5808 }
5809 
5810 /**
5811  * ags_recall_stop_persistent:
5812  * @recall: the #AgsRecall
5813  *
5814  * Unsets the %AGS_SOUND_BEHAVIOUR_PERSISTENT and related behaviour flags and
5815  * invokes ags_recall_done().
5816  *
5817  * Since: 3.0.0
5818  */
5819 void
ags_recall_stop_persistent(AgsRecall * recall)5820 ags_recall_stop_persistent(AgsRecall *recall)
5821 {
5822   g_return_if_fail(AGS_IS_RECALL(recall));
5823 
5824   g_object_ref(G_OBJECT(recall));
5825   g_signal_emit(G_OBJECT(recall),
5826 		recall_signals[PLAY_STOP_PERSISTENT], 0);
5827   g_object_unref(G_OBJECT(recall));
5828 }
5829 
5830 void
ags_recall_real_cancel(AgsRecall * recall)5831 ags_recall_real_cancel(AgsRecall *recall)
5832 {
5833   GList *list_start, *list;
5834 
5835   GRecMutex *recall_mutex;
5836 
5837   /* get recall mutex */
5838   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5839 
5840   /* cancel */
5841   g_rec_mutex_lock(recall_mutex);
5842 
5843   recall->staging_flags |= AGS_SOUND_STAGING_CANCEL;
5844 
5845   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
5846     g_warning("running on template");
5847   }
5848 
5849   list =
5850     list_start = g_list_copy(recall->children);
5851 
5852   g_rec_mutex_unlock(recall_mutex);
5853 
5854   while(list != NULL){
5855     ags_recall_cancel(AGS_RECALL(list->data));
5856 
5857     list = list->next;
5858   }
5859 
5860   g_list_free(list_start);
5861 
5862   /* stop any recall */
5863   ags_recall_stop_persistent(recall);
5864 }
5865 
5866 /**
5867  * ags_recall_cancel:
5868  * @recall: the #AgsRecall
5869  *
5870  * The #AgsRecall doesn't want to run anymore, it aborts further execution.
5871  *
5872  * Since: 3.0.0
5873  */
5874 void
ags_recall_cancel(AgsRecall * recall)5875 ags_recall_cancel(AgsRecall *recall)
5876 {
5877   g_return_if_fail(AGS_IS_RECALL(recall));
5878 
5879   g_object_ref(G_OBJECT(recall));
5880   g_signal_emit(G_OBJECT(recall),
5881 		recall_signals[PLAY_CANCEL], 0);
5882   g_object_unref(G_OBJECT(recall));
5883 }
5884 
5885 void
ags_recall_real_done(AgsRecall * recall)5886 ags_recall_real_done(AgsRecall *recall)
5887 {
5888   GList *list_start, *list;
5889 
5890   GRecMutex *recall_mutex;
5891 
5892   /* get recall mutex */
5893   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5894 
5895 #ifdef AGS_DEBUG
5896   if(AGS_IS_RECALL_AUDIO_SIGNAL(recall)){
5897     g_message("done - %s", G_OBJECT_TYPE_NAME(recall));
5898   }
5899 #endif
5900 
5901   /* do feedback */
5902   g_rec_mutex_lock(recall_mutex);
5903 
5904   recall->staging_flags |= AGS_SOUND_STAGING_DONE;
5905 
5906   if((AGS_RECALL_TEMPLATE & (recall->flags)) != 0){
5907     g_warning("running on template");
5908   }
5909 
5910   list =
5911     list_start = g_list_copy(recall->children);
5912 
5913   g_rec_mutex_unlock(recall_mutex);
5914 
5915   while(list != NULL){
5916     ags_recall_done(AGS_RECALL(list->data));
5917 
5918     list = list->next;
5919   }
5920 
5921   g_list_free(list_start);
5922 }
5923 
5924 /**
5925  * ags_recall_done:
5926  * @recall: the #AgsRecall
5927  *
5928  * The #AgsRecall doesn't want to run anymore, it has been done its
5929  * work.
5930  *
5931  * Since: 3.0.0
5932  */
5933 void
ags_recall_done(AgsRecall * recall)5934 ags_recall_done(AgsRecall *recall)
5935 {
5936   g_return_if_fail(AGS_IS_RECALL(recall));
5937   g_object_ref(G_OBJECT(recall));
5938   g_signal_emit(G_OBJECT(recall),
5939 		recall_signals[PLAY_DONE], 0);
5940   g_object_unref(G_OBJECT(recall));
5941 }
5942 
5943 AgsRecall*
ags_recall_real_duplicate(AgsRecall * recall,AgsRecallID * recall_id,guint * n_params,gchar ** parameter_name,GValue * value)5944 ags_recall_real_duplicate(AgsRecall *recall,
5945 			  AgsRecallID *recall_id,
5946 			  guint *n_params, gchar **parameter_name, GValue *value)
5947 {
5948   AgsRecall *copy_recall;
5949   AgsRecallClass *recall_class, *copy_class;
5950   AgsRecallContainer *recall_container;
5951 
5952   GObject *output_soundcard;
5953   GObject *input_soundcard;
5954 
5955   GType child_type;
5956 
5957   GList *list, *child;
5958 
5959   guint recall_flags;
5960   guint ability_flags;
5961   guint behaviour_flags;
5962   gint output_soundcard_channel;
5963   gint input_soundcard_channel;
5964   guint local_n_params;
5965   guint i;
5966 
5967   GRecMutex *recall_mutex;
5968 
5969   /* get recall mutex */
5970   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
5971 
5972   /* get some fields */
5973   g_rec_mutex_lock(recall_mutex);
5974 
5975   recall_flags = recall->flags;
5976   ability_flags = recall->ability_flags;
5977   behaviour_flags = recall->behaviour_flags;
5978 
5979   recall_container = (AgsRecallContainer *) recall->recall_container;
5980 
5981   output_soundcard = recall->output_soundcard;
5982   output_soundcard_channel = recall->output_soundcard_channel;
5983 
5984   input_soundcard = recall->input_soundcard;
5985   input_soundcard_channel = recall->input_soundcard_channel;
5986 
5987   child_type = recall->child_type;
5988 
5989   g_rec_mutex_unlock(recall_mutex);
5990 
5991   /* grow parameter name and value */
5992   local_n_params = 0;
5993 
5994   if(n_params == NULL){
5995     n_params = &local_n_params;
5996   }
5997 
5998   if(n_params[0] == 0){
5999     parameter_name = (gchar **) malloc(8 * sizeof(gchar *));
6000     value = g_new0(GValue,
6001 		   7);
6002   }else{
6003     parameter_name = (gchar **) realloc(parameter_name,
6004 					(n_params[0] + 8) * sizeof(gchar *));
6005     value = g_renew(GValue,
6006 		    value,
6007 		    n_params[0] + 7);
6008   }
6009 
6010   /* set parameter name and value */
6011   parameter_name[n_params[0]] = "output-soundcard";
6012   memset(&(value[n_params[0]]), 0, sizeof(GValue));
6013   g_value_init(&(value[n_params[0]]),
6014 	       G_TYPE_OBJECT);
6015   g_value_set_object(&(value[n_params[0]]), output_soundcard);
6016 
6017   parameter_name[n_params[0] + 1] = "output-soundcard-channel";
6018   memset(&(value[n_params[0] + 1]), 0, sizeof(GValue));
6019   g_value_init(&(value[n_params[0] + 1]),
6020 	       G_TYPE_INT);
6021   g_value_set_int(&(value[n_params[0] + 1]), output_soundcard_channel);
6022 
6023   parameter_name[n_params[0] + 2] = "input-soundcard";
6024   memset(&(value[n_params[0] + 2]), 0, sizeof(GValue));
6025   g_value_init(&(value[n_params[0] + 2]),
6026 	       G_TYPE_OBJECT);
6027   g_value_set_object(&(value[n_params[0] + 2]), input_soundcard);
6028 
6029   parameter_name[n_params[0] + 3] = "input-soundcard-channel";
6030   memset(&(value[n_params[0] + 3]), 0, sizeof(GValue));
6031   g_value_init(&(value[n_params[0] + 3]),
6032 	       G_TYPE_INT);
6033   g_value_set_int(&(value[n_params[0] + 3]), input_soundcard_channel);
6034 
6035   parameter_name[n_params[0] + 4] = "recall-id";
6036   memset(&(value[n_params[0] + 4]), 0, sizeof(GValue));
6037   g_value_init(&(value[n_params[0] + 4]),
6038 	       G_TYPE_OBJECT);
6039   g_value_set_object(&(value[n_params[0] + 4]), recall_id);
6040 
6041   parameter_name[n_params[0] + 5] = "recall-container";
6042   memset(&(value[n_params[0] + 5]), 0, sizeof(GValue));
6043   g_value_init(&(value[n_params[0] + 5]),
6044 	       G_TYPE_OBJECT);
6045   g_value_set_object(&(value[n_params[0] + 5]), recall_container);
6046 
6047   parameter_name[n_params[0] + 6] = "child-type";
6048   memset(&(value[n_params[0] + 6]), 0, sizeof(GValue));
6049   g_value_init(&(value[n_params[0] + 6]),
6050 	       G_TYPE_GTYPE);
6051   g_value_set_gtype(&(value[n_params[0] + 6]), child_type);
6052 
6053   parameter_name[n_params[0] + 7] = NULL;
6054 
6055   n_params[0] += 7;
6056 
6057 #if HAVE_GLIB_2_54
6058   copy_recall = g_object_new_with_properties(G_OBJECT_TYPE(recall),
6059 					     n_params[0], parameter_name, value);
6060 #else
6061   copy_recall = g_object_new(G_OBJECT_TYPE(recall),
6062 			     NULL);
6063 
6064   {
6065     guint i;
6066 
6067     for(i = 0; i < n_params[0]; i++){
6068       g_object_set_property((GObject *) copy_recall,
6069 			    parameter_name[i], &(value[i]));
6070     }
6071   }
6072 #endif
6073 
6074   /* free parameter name and value */
6075   g_free(parameter_name);
6076 
6077   for(i = 0; i < n_params[0]; i++){
6078     g_value_unset(&(value[i]));
6079   }
6080 
6081   g_free(value);
6082 
6083   /* apply flags */
6084   ags_recall_set_flags(copy_recall,
6085 		       (recall_flags & (~ (AGS_RECALL_ADDED_TO_REGISTRY |
6086 					   AGS_RECALL_CONNECTED |
6087 					   AGS_RECALL_TEMPLATE))));
6088 
6089   ags_recall_set_ability_flags(copy_recall, ability_flags);
6090   ags_recall_set_behaviour_flags(copy_recall, behaviour_flags);
6091   //  ags_recall_set_sound_scope(copy_recall, sound_scope);
6092 
6093   /* duplicate handlers */
6094   g_rec_mutex_lock(recall_mutex);
6095 
6096   list = recall->recall_handler;
6097 
6098   while(list != NULL){
6099     AgsRecallHandler *recall_handler, *copy_recall_handler;
6100 
6101     recall_handler = AGS_RECALL_HANDLER(list->data);
6102 
6103     copy_recall_handler = ags_recall_handler_alloc(recall_handler->signal_name,
6104 						   recall_handler->callback,
6105 						   recall_handler->data);
6106     ags_recall_add_recall_handler(copy_recall,
6107 				  copy_recall_handler);
6108 
6109     list = list->next;
6110   }
6111 
6112   g_rec_mutex_unlock(recall_mutex);
6113 
6114   /* recall container */
6115   if(recall_container != NULL){
6116     if(AGS_IS_RECALL_AUDIO(copy_recall)){
6117       g_object_set(recall_container,
6118 		   "recall-audio", copy_recall,
6119 		   NULL);
6120     }else if(AGS_IS_RECALL_AUDIO_RUN(copy_recall)){
6121       g_object_set(recall_container,
6122 		   "recall-audio-run", copy_recall,
6123 		   NULL);
6124     }else if(AGS_IS_RECALL_CHANNEL(copy_recall)){
6125       g_object_set(recall_container,
6126 		   "recall-channel", copy_recall,
6127 		   NULL);
6128     }else if(AGS_IS_RECALL_CHANNEL_RUN(copy_recall)){
6129       g_object_set(recall_container,
6130 		   "recall-channel-run", copy_recall,
6131 		   NULL);
6132     }
6133   }
6134 
6135   return(copy_recall);
6136 }
6137 
6138 /**
6139  * ags_recall_duplicate:
6140  * @recall: the template #AgsRecAll
6141  * @recall_id: the #AgsRecallID
6142  * @n_params: guint pointer to parameter count
6143  * @parameter_name: string vector containing parameter names
6144  * @value: the #GValue-struct array
6145  *
6146  * Should duplicate an #AgsRecall, so it can pass the run stages. Mainly used for
6147  * creating duplicates of templates, see %AGS_RECALL_TEMPLATE.
6148  *
6149  * Returns: (transfer full): the duplicated #AgsRecall
6150  *
6151  * Since: 3.0.0
6152  */
6153 AgsRecall*
ags_recall_duplicate(AgsRecall * recall,AgsRecallID * recall_id,guint * n_params,gchar ** parameter_name,GValue * value)6154 ags_recall_duplicate(AgsRecall *recall,
6155 		     AgsRecallID *recall_id,
6156 		     guint *n_params, gchar **parameter_name, GValue *value)
6157 {
6158   AgsRecall *recall_copy;
6159 
6160   g_return_val_if_fail(AGS_IS_RECALL(recall), NULL);
6161   g_object_ref(G_OBJECT(recall));
6162   g_signal_emit(G_OBJECT(recall),
6163 		recall_signals[PLAY_DUPLICATE], 0,
6164 		recall_id,
6165 		n_params, parameter_name, value,
6166 		&recall_copy);
6167   g_object_unref(G_OBJECT(recall));
6168 
6169   return(recall_copy);
6170 }
6171 
6172 /**
6173  * ags_recall_notify_dependency:
6174  * @recall: the #AgsRecall
6175  * @dependency: the dependency to notify for, see #AgsRecallNotifyDependencyMode-enum
6176  * @increase: if %TRUE increase, else if %FALSE decrease
6177  *
6178  * Notifies a recall that an other depends on it.
6179  *
6180  * Since: 3.0.0
6181  */
6182 void
ags_recall_notify_dependency(AgsRecall * recall,guint dependency,gboolean increase)6183 ags_recall_notify_dependency(AgsRecall *recall, guint dependency, gboolean increase)
6184 {
6185   g_return_if_fail(AGS_IS_RECALL(recall));
6186 
6187   g_object_ref(G_OBJECT(recall));
6188   g_signal_emit(G_OBJECT(recall),
6189 		recall_signals[PLAY_NOTIFY_DEPENDENCY], 0,
6190 		dependency, increase);
6191   g_object_unref(G_OBJECT(recall));
6192 }
6193 
6194 /**
6195  * ags_recall_child_added:
6196  * @recall: the #AgsRecall
6197  * @child: the child #AgsRecall
6198  *
6199  * A signal indicating that the a child has been added.
6200  *
6201  * Since: 3.0.0
6202  */
6203 void
ags_recall_child_added(AgsRecall * recall,AgsRecall * child)6204 ags_recall_child_added(AgsRecall *recall, AgsRecall *child)
6205 {
6206   g_return_if_fail(AGS_IS_RECALL(recall));
6207   g_object_ref(G_OBJECT(recall));
6208   g_signal_emit(G_OBJECT(recall),
6209 		recall_signals[CHILD_ADDED], 0,
6210 		child);
6211   g_object_unref(G_OBJECT(recall));
6212 }
6213 
6214 /**
6215  * ags_recall_is_done:
6216  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
6217  * @recycling_context: the #AgsRecyclingContext
6218  *
6219  * Check if recall is over.
6220  *
6221  * Returns: %TRUE if recall is done, otherwise %FALSE
6222  *
6223  * Since: 3.0.0
6224  */
6225 gboolean
ags_recall_is_done(GList * recall,GObject * recycling_context)6226 ags_recall_is_done(GList *recall, GObject *recycling_context)
6227 {
6228   AgsRecall *current_recall;
6229   AgsRecallID *current_recall_id;
6230   AgsRecyclingContext *current_recycling_context;
6231 
6232   guint current_recall_flags;
6233   guint current_staging_flags;
6234 
6235   GRecMutex *current_recall_mutex;
6236   GRecMutex *current_recall_id_mutex;
6237 
6238   if(recall == NULL ||
6239      !AGS_IS_RECYCLING_CONTEXT(recycling_context)){
6240     return(FALSE);
6241   }
6242 
6243   while(recall != NULL){
6244     current_recall = AGS_RECALL(recall->data);
6245 
6246     /* get recall mutex */
6247     current_recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(current_recall);
6248 
6249     /* get some fields */
6250     g_rec_mutex_lock(current_recall_mutex);
6251 
6252     current_recall_flags = current_recall->flags;
6253     current_staging_flags = current_recall->staging_flags;
6254 
6255     current_recall_id = current_recall->recall_id;
6256 
6257     g_rec_mutex_unlock(current_recall_mutex);
6258 
6259     if(current_recall_id != NULL){
6260       /* get recall id mutex */
6261       current_recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(current_recall_id);
6262 
6263       /* get some fields */
6264       g_rec_mutex_lock(current_recall_id_mutex);
6265 
6266       current_recycling_context = current_recall_id->recycling_context;
6267 
6268       g_rec_mutex_unlock(current_recall_id_mutex);
6269     }else{
6270       current_recycling_context = NULL;
6271     }
6272 
6273     if((AGS_RECALL_TEMPLATE & (current_recall_flags)) == 0 &&
6274        !AGS_IS_RECALL_AUDIO(current_recall) &&
6275        !AGS_IS_RECALL_CHANNEL(current_recall) &&
6276        current_recycling_context == (AgsRecyclingContext *) recycling_context){
6277       if((AGS_SOUND_STAGING_DONE & (current_staging_flags)) == 0){
6278 	//FIXME:JK: replacement
6279 	//	current_recall->flags &= (~AGS_RECALL_RUN_INITIALIZED);
6280 	//	g_message("done: %s", G_OBJECT_TYPE_NAME(recall));
6281 
6282 	return(FALSE);
6283       }
6284     }
6285 
6286     /* iterate */
6287     recall = recall->next;
6288   }
6289 
6290   return(TRUE);
6291 }
6292 
6293 /**
6294  * ags_recall_get_by_effect:
6295  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
6296  * @filename: the filename containing @effect or %NULL
6297  * @effect: the effect name
6298  *
6299  * Finds all recalls matching @filename and @effect.
6300  *
6301  * Returns: (element-type AgsAudio.Recall) (transfer full): a #GList-struct containing #AgsRecall, or %NULL if not found
6302  *
6303  * Since: 3.0.0
6304  */
6305 GList*
ags_recall_get_by_effect(GList * recall,gchar * filename,gchar * effect)6306 ags_recall_get_by_effect(GList *recall, gchar *filename, gchar *effect)
6307 {
6308   GList *list;
6309 
6310   gchar *current_filename, *current_effect;
6311 
6312   if(recall == NULL ||
6313      effect == NULL){
6314     return(NULL);
6315   }
6316 
6317   list = NULL;
6318 
6319   while(recall != NULL){
6320     /* get some fields */
6321     current_filename = NULL;
6322     current_effect = NULL;
6323 
6324     g_object_get(recall->data,
6325 		 "filename", &current_filename,
6326 		 "effect", &current_effect,
6327 		 NULL);
6328 
6329     /* check filename and effect */
6330     if(filename == NULL){
6331       if(current_filename == NULL &&
6332 	 current_effect != NULL &&
6333 	 !g_strcmp0(current_effect, effect)){
6334 	g_object_ref(recall->data);
6335 	list = g_list_prepend(list,
6336 			      recall->data);
6337       }
6338     }else{
6339       if(current_filename != NULL &&
6340 	 !g_strcmp0(current_filename, filename) &&
6341 	 current_effect != NULL &&
6342 	 !g_strcmp0(current_effect, effect)){
6343 	g_object_ref(recall->data);
6344 	list = g_list_prepend(list,
6345 			      recall->data);
6346       }
6347     }
6348 
6349     g_free(current_filename);
6350     g_free(current_effect);
6351 
6352     /* iterate */
6353     recall = recall->next;
6354   }
6355 
6356   list = g_list_reverse(list);
6357 
6358   return(list);
6359 }
6360 
6361 /**
6362  * ags_recall_find_recall_id_with_effect:
6363  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
6364  * @recall_id: the #AgsRecallID, may be %NULL
6365  * @filename: the filename or %NULL
6366  * @effect: the effect name
6367  *
6368  * Finds next matching effect name. Intended to be used as
6369  * iteration function.
6370  *
6371  * Returns: (element-type AgsAudio.Recall) (transfer none): next matching #GList-struct, or %NULL if not found
6372  *
6373  * Since: 3.0.0
6374  */
6375 GList*
ags_recall_find_recall_id_with_effect(GList * recall,AgsRecallID * recall_id,gchar * filename,gchar * effect)6376 ags_recall_find_recall_id_with_effect(GList *recall, AgsRecallID *recall_id, gchar *filename, gchar *effect)
6377 {
6378   AgsRecall *current_recall;
6379   AgsRecallID *current_recall_id;
6380   AgsRecyclingContext *recycling_context;
6381   AgsRecyclingContext *current_recycling_context;
6382 
6383   gchar *current_filename, *current_effect;
6384 
6385   GRecMutex *current_recall_mutex;
6386   GRecMutex *recall_id_mutex;
6387   GRecMutex *current_recall_id_mutex;
6388 
6389   if(recall == NULL ||
6390      effect == NULL){
6391     return(NULL);
6392   }
6393 
6394   /* get recycling context */
6395   recycling_context = NULL;
6396 
6397   if(recall_id != NULL){
6398     /* get recall id mutex */
6399     recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
6400 
6401     /* recycling context */
6402     g_rec_mutex_lock(recall_id_mutex);
6403 
6404     recycling_context = recall_id->recycling_context;
6405 
6406     g_rec_mutex_unlock(recall_id_mutex);
6407   }
6408 
6409   while(recall != NULL){
6410     current_recall = AGS_RECALL(recall->data);
6411 
6412     /* get recall mutex */
6413     current_recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(current_recall);
6414 
6415     /* get some fields */
6416     g_rec_mutex_lock(current_recall_mutex);
6417 
6418     current_filename = current_recall->filename;
6419     current_effect = current_recall->effect;
6420 
6421     current_recall_id = current_recall->recall_id;
6422 
6423     g_rec_mutex_unlock(current_recall_mutex);
6424 
6425     /* get recycling context */
6426     current_recycling_context = NULL;
6427 
6428     if(current_recall_id != NULL){
6429       /* get recall id mutex */
6430       current_recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(current_recall_id);
6431 
6432       /* recycling context */
6433       g_rec_mutex_lock(current_recall_id_mutex);
6434 
6435       current_recycling_context = current_recall_id->recycling_context;
6436 
6437       g_rec_mutex_unlock(current_recall_id_mutex);
6438     }
6439 
6440     /* check recall id, filename and effect */
6441     if(filename == NULL){
6442       if(current_filename == NULL &&
6443 	 current_effect != NULL &&
6444 	 !g_strcmp0(current_effect, effect)){
6445 	if(recall_id == NULL){
6446 	  if(current_recall_id == NULL){
6447 	    return(recall);
6448 	  }
6449 	}else{
6450 	  if(recycling_context == current_recycling_context){
6451 	    return(recall);
6452 	  }
6453 	}
6454       }
6455     }else{
6456       if(current_filename != NULL &&
6457 	 !g_strcmp0(current_filename, filename) &&
6458 	 current_effect != NULL &&
6459 	 !g_strcmp0(current_effect, effect)){
6460 	if(recall_id == NULL){
6461 	  if(current_recall_id == NULL){
6462 	    return(recall);
6463 	  }
6464 	}else{
6465 	  if(recycling_context == current_recycling_context){
6466 	    return(recall);
6467 	  }
6468 	}
6469       }
6470     }
6471 
6472     /* iterate */
6473     recall = recall->next;
6474   }
6475 
6476   return(NULL);
6477 }
6478 
6479 /**
6480  * ags_recall_find_type:
6481  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
6482  * @type: the #GType
6483  *
6484  * Finds next matching recall for type. Intended to be used as
6485  * iteration function.
6486  *
6487  * Returns: (element-type AgsAudio.Recall) (transfer none): next matching #GList-struct, or %NULL if not found
6488  *
6489  * Since: 3.0.0
6490  */
6491 GList*
ags_recall_find_type(GList * recall,GType gtype)6492 ags_recall_find_type(GList *recall, GType gtype)
6493 {
6494   AgsRecall *current_recall;
6495 
6496   while(recall != NULL){
6497     GType current_gtype;
6498 
6499     current_recall = AGS_RECALL(recall->data);
6500 
6501     current_gtype = G_OBJECT_TYPE(current_recall);
6502 
6503     if(g_type_is_a(current_gtype, gtype)){
6504       break;
6505     }
6506 
6507     /* iterate */
6508     recall = recall->next;
6509   }
6510 
6511   return(recall);
6512 }
6513 
6514 /**
6515  * ags_recall_find_template:
6516  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
6517  *
6518  * Finds next template, see #AGS_RECALL_TEMPLATE flag. Intended to be used as
6519  * iteration function.
6520  *
6521  * Returns: (element-type AgsAudio.Recall) (transfer none): next matching #GList-struct, or %NULL if not found
6522  *
6523  * Since: 3.0.0
6524  */
6525 GList*
ags_recall_find_template(GList * recall)6526 ags_recall_find_template(GList *recall)
6527 {
6528   AgsRecall *current_recall;
6529 
6530   guint current_recall_flags;
6531 
6532   GRecMutex *current_recall_mutex;
6533 
6534   while(recall != NULL){
6535     current_recall = AGS_RECALL(recall->data);
6536 
6537     /* get recall mutex */
6538     current_recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(current_recall);
6539 
6540     /* get some fields */
6541     g_rec_mutex_lock(current_recall_mutex);
6542 
6543     current_recall_flags = current_recall->flags;
6544 
6545     g_rec_mutex_unlock(current_recall_mutex);
6546 
6547     /* check recall flags */
6548     if((AGS_RECALL_TEMPLATE & (current_recall_flags)) != 0){
6549       return(recall);
6550     }
6551 
6552     /* iterate */
6553     recall = recall->next;
6554   }
6555 
6556   return(NULL);
6557 }
6558 
6559 /**
6560  * ags_recall_template_find_type:
6561  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
6562  * @type: a #GType
6563  *
6564  * Finds next matching recall for type which is a template, see #AGS_RECALL_TEMPLATE flag.
6565  * Intended to be used as iteration function.
6566  *
6567  * Returns: (element-type AgsAudio.Recall) (transfer none): next matching #GList-struct, or %NULL if not found
6568  *
6569  * Since: 3.0.0
6570  */
6571 GList*
ags_recall_template_find_type(GList * recall,GType gtype)6572 ags_recall_template_find_type(GList *recall, GType gtype)
6573 {
6574   AgsRecall *current_recall;
6575 
6576   while(recall != NULL){
6577     current_recall = (AgsRecall *) recall->data;
6578 
6579     if(AGS_IS_RECALL(current_recall) &&
6580        (AGS_RECALL_TEMPLATE & (current_recall->flags)) != 0 &&
6581        g_type_is_a(G_OBJECT_TYPE(current_recall), gtype)){
6582       break;
6583     }
6584 
6585     recall = recall->next;
6586   }
6587 
6588   return(recall);
6589 }
6590 
6591 /**
6592  * ags_recall_template_find_all_type:
6593  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
6594  * @...: a #GType
6595  *
6596  * Finds next matching recall for type which is a template, see #AGS_RECALL_TEMPLATE flag.
6597  * Intended to be used as iteration function.
6598  *
6599  * Returns: (element-type AgsAudio.Recall) (transfer none): next matching #GList-struct, or %NULL if not found
6600  *
6601  * Since: 3.0.0
6602  */
6603 GList*
ags_recall_template_find_all_type(GList * recall,...)6604 ags_recall_template_find_all_type(GList *recall, ...)
6605 {
6606   AgsRecall *current_recall;
6607 
6608   GType *recall_type, *offset;
6609   GType current;
6610 
6611   guint current_recall_flags;
6612   guint i;
6613 
6614   va_list ap;
6615 
6616   GRecMutex *current_recall_mutex;
6617 
6618   /* read all types */
6619   va_start(ap,
6620 	   recall);
6621 
6622   recall_type = (GType *) malloc(sizeof(GType));
6623 
6624   i = 0;
6625 
6626   while(TRUE){
6627     current = va_arg(ap, GType);
6628 
6629     if(current == G_TYPE_NONE){
6630       break;
6631     }
6632 
6633     recall_type = (GType *) realloc(recall_type,
6634 				    (i + 2) * sizeof(GType));
6635     recall_type[i] = current;
6636 
6637     i++;
6638   }
6639 
6640   recall_type[i] = G_TYPE_NONE;
6641 
6642   va_end(ap);
6643 
6644   /* find all types */
6645   while(recall != NULL){
6646     current_recall = (AgsRecall *) recall->data;
6647 
6648     if(AGS_IS_RECALL(current_recall)){
6649       /* get recall mutex */
6650       current_recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(current_recall);
6651 
6652       /* get some fields */
6653       g_rec_mutex_lock(current_recall_mutex);
6654 
6655       current_recall_flags = current_recall->flags;
6656 
6657       g_rec_mutex_unlock(current_recall_mutex);
6658 
6659       /**/
6660       if((AGS_RECALL_TEMPLATE & (current_recall_flags)) != 0){
6661 	offset = recall_type;
6662 
6663 	while(offset[0] != G_TYPE_NONE){
6664 	  if(g_type_is_a(G_OBJECT_TYPE(current_recall), offset[0])){
6665 	    free(recall_type);
6666 
6667 	    return(recall);
6668 	  }
6669 
6670 	  offset++;
6671 	}
6672       }
6673     }
6674 
6675     /* iterate */
6676     recall = recall->next;
6677   }
6678 
6679   free(recall_type);
6680 
6681   return(NULL);
6682 }
6683 
6684 /**
6685  * ags_recall_find_type_with_recycling_context:
6686  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
6687  * @type: the #GType
6688  * @recycling_context: the #AgsRecyclingContext
6689  *
6690  * Finds next matching recall for type which has @recycling_context, see #AgsRecallId for further
6691  * details about #AgsRecyclingContext. Intended to be used as iteration function.
6692  *
6693  * Returns: (element-type AgsAudio.Recall) (transfer none): next matching #GList-struct, or %NULL if not found
6694  *
6695  * Since: 3.0.0
6696  */
6697 GList*
ags_recall_find_type_with_recycling_context(GList * recall,GType gtype,GObject * recycling_context)6698 ags_recall_find_type_with_recycling_context(GList *recall, GType gtype, GObject *recycling_context)
6699 {
6700   AgsRecall *current_recall;
6701   AgsRecallID *current_recall_id;
6702   AgsRecyclingContext *current_recycling_context;
6703 
6704   GRecMutex *current_recall_mutex;
6705   GRecMutex *current_recall_id_mutex;
6706 
6707   while(recall != NULL){
6708     current_recall = AGS_RECALL(recall->data);
6709 
6710     /* get recall mutex */
6711     current_recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(current_recall);
6712 
6713     /* get some fields */
6714     g_rec_mutex_lock(current_recall_mutex);
6715 
6716     current_recall_id = current_recall->recall_id;
6717 
6718     g_rec_mutex_unlock(current_recall_mutex);
6719 
6720     /* get recycling context */
6721     current_recycling_context = NULL;
6722 
6723     if(current_recall_id != NULL){
6724       /* get recall id mutex */
6725       current_recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(current_recall_id);
6726 
6727       /* recycling context */
6728       g_rec_mutex_lock(current_recall_id_mutex);
6729 
6730       current_recycling_context = current_recall_id->recycling_context;
6731 
6732       g_rec_mutex_unlock(current_recall_id_mutex);
6733     }
6734 
6735     if(g_type_is_a(G_OBJECT_TYPE(current_recall), gtype) &&
6736        current_recycling_context == (AgsRecyclingContext *) recycling_context){
6737       return(recall);
6738     }
6739 
6740     /* iterate */
6741     recall = recall->next;
6742   }
6743 
6744   return(NULL);
6745 }
6746 
6747 /**
6748  * ags_recall_find_recycling_context:
6749  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
6750  * @recycling_context: the #AgsRecyclingContext
6751  *
6752  * Finds next matching recall which has @recycling_context, see #AgsRecallId for further
6753  * details about #AgsRecyclingContext. Intended to be used as iteration function.
6754  *
6755  * Returns: (element-type AgsAudio.Recall) (transfer none): next matching #GList-struct, or %NULL if not found
6756  *
6757  * Since: 3.0.0
6758  */
6759 GList*
ags_recall_find_recycling_context(GList * recall,GObject * recycling_context)6760 ags_recall_find_recycling_context(GList *recall, GObject *recycling_context)
6761 {
6762   AgsRecall *current_recall;
6763   AgsRecallID *current_recall_id;
6764   AgsRecyclingContext *current_recycling_context;
6765 
6766   while(recall != NULL){
6767     current_recall = AGS_RECALL(recall->data);
6768 
6769     /* get some fields */
6770     current_recall_id = NULL;
6771     current_recycling_context = NULL;
6772 
6773     g_object_get(current_recall,
6774 		 "recall-id", &current_recall_id,
6775 		 NULL);
6776 
6777     /* get recycling context */
6778     if(current_recall_id != NULL){
6779       g_object_get(current_recall_id,
6780 		   "recycling-context", &current_recycling_context,
6781 		   NULL);
6782     }
6783 
6784     if(current_recall_id != NULL){
6785       g_object_unref(current_recall_id);
6786     }
6787 
6788     if(current_recycling_context != NULL){
6789       g_object_unref(current_recycling_context);
6790     }
6791 
6792     /* check recycling context */
6793     if(current_recycling_context == (AgsRecyclingContext *) recycling_context){
6794       return(recall);
6795     }
6796 
6797     /* iterate */
6798     recall = recall->next;
6799   }
6800 
6801   return(NULL);
6802 }
6803 
6804 /**
6805  * ags_recall_find_provider:
6806  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
6807  * @provider: the #GObject, either #AgsAudio, #AgsChannel, #AgsRecycling or #AgsAudioSignal
6808  *
6809  * Finds next matching recall for type which has @provider. The @provider may be either an #AgsChannel
6810  * or an #AgsAudio object. This function tries to find the corresponding #AgsRecallChannel and #AgsRecallAudio
6811  * objects of a #AgsRecall to find. If these recalls contains the @provider, the function will return.
6812  *
6813  * Returns: (element-type AgsAudio.Recall) (transfer none): next matching #GList-struct, or %NULL if not found
6814  *
6815  * Since: 3.0.0
6816  */
6817 GList*
ags_recall_find_provider(GList * recall,GObject * provider)6818 ags_recall_find_provider(GList *recall, GObject *provider)
6819 {
6820   AgsAudio *current_audio;
6821   AgsChannel *current_channel;
6822   AgsRecycling *current_recycling;
6823   AgsAudioSignal *current_audio_signal;
6824   AgsRecall *current_recall;
6825 
6826   gboolean success;
6827 
6828   while(recall != NULL){
6829     current_recall = AGS_RECALL(recall->data);
6830 
6831     if(AGS_IS_AUDIO(provider)){
6832       if(AGS_IS_RECALL_AUDIO(current_recall)){
6833 	g_object_get(current_recall,
6834 		     "audio", &current_audio,
6835 		     NULL);
6836 
6837 	success = ((GObject *) current_audio == provider) ? TRUE: FALSE;
6838 
6839 	if(current_audio != NULL){
6840 	  g_object_unref(current_audio);
6841 	}
6842 
6843 	if(success){
6844 	  return(recall);
6845 	}
6846       }else if(AGS_IS_RECALL_AUDIO_RUN(current_recall)){
6847 	g_object_get(current_recall,
6848 		     "audio", &current_audio,
6849 		     NULL);
6850 
6851 	success = ((GObject *) current_audio == provider) ? TRUE: FALSE;
6852 
6853 	if(current_audio != NULL){
6854 	  g_object_unref(current_audio);
6855 	}
6856 
6857 	if(success){
6858 	  return(recall);
6859 	}
6860       }
6861     }else if(AGS_IS_CHANNEL(provider)){
6862       if(AGS_IS_RECALL_CHANNEL(current_recall)){
6863 	g_object_get(current_recall,
6864 		     "source", &current_channel,
6865 		     NULL);
6866 
6867 	success = ((GObject *) current_channel == provider) ? TRUE: FALSE;
6868 
6869 	if(current_channel != NULL){
6870 	  g_object_unref(current_channel);
6871 	}
6872 
6873 	if(success){
6874 	  return(recall);
6875 	}
6876       }else if(AGS_IS_RECALL_CHANNEL_RUN(current_recall)){
6877 	g_object_get(current_recall,
6878 		     "source", &current_channel,
6879 		     NULL);
6880 
6881 	success = ((GObject *) current_channel == provider) ? TRUE: FALSE;
6882 
6883 	if(current_channel != NULL){
6884 	  g_object_unref(current_channel);
6885 	}
6886 
6887 	if(success){
6888 	  return(recall);
6889 	}
6890       }
6891     }else if(AGS_IS_RECYCLING(provider)){
6892       if(AGS_IS_RECALL_RECYCLING(current_recall)){
6893 	g_object_get(current_recall,
6894 		     "source", &current_recycling,
6895 		     NULL);
6896 
6897 	success = ((GObject *) current_recycling == provider) ? TRUE: FALSE;
6898 
6899 	if(current_recycling != NULL){
6900 	  g_object_unref(current_recycling);
6901 	}
6902 
6903 	if(success){
6904 	  return(recall);
6905 	}
6906       }
6907     }else if(AGS_IS_AUDIO_SIGNAL(provider)){
6908       if(AGS_IS_RECALL_AUDIO_SIGNAL(current_recall)){
6909 	g_object_get(current_recall,
6910 		     "source", &current_audio_signal,
6911 		     NULL);
6912 
6913 	success = ((GObject *) current_audio_signal == provider) ? TRUE: FALSE;
6914 
6915 	if(current_audio_signal != NULL){
6916 	  g_object_unref(current_audio_signal);
6917 	}
6918 
6919 	if(success){
6920 	  return(recall);
6921 	}
6922       }
6923     }
6924 
6925     /* iterate */
6926     recall = recall->next;
6927   }
6928 
6929   return(NULL);
6930 }
6931 
6932 /**
6933  * ags_recall_template_find_provider:
6934  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
6935  * @provider: the #GObject as provider
6936  *
6937  * Finds provider eg. #AgsAudio or #AgsChannel within @recall containig #AgsRecall.
6938  *
6939  * Returns: (element-type AgsAudio.Recall) (transfer none): next matching #GList-struct, or %NULL if not found
6940  *
6941  * Since: 3.0.0
6942  */
6943 GList*
ags_recall_template_find_provider(GList * recall,GObject * provider)6944 ags_recall_template_find_provider(GList *recall, GObject *provider)
6945 {
6946   AgsRecall *current_recall;
6947 
6948   guint current_recall_flags;
6949 
6950   GRecMutex *current_recall_mutex;
6951 
6952   while((recall = (ags_recall_find_provider(recall, provider))) != NULL){
6953     current_recall = AGS_RECALL(recall->data);
6954 
6955     /* get recall mutex */
6956     current_recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(current_recall);
6957 
6958     /* get some fields */
6959     g_rec_mutex_lock(current_recall_mutex);
6960 
6961     current_recall_flags = current_recall->flags;
6962 
6963     g_rec_mutex_unlock(current_recall_mutex);
6964 
6965     /* check template */
6966     if((AGS_RECALL_TEMPLATE & (current_recall_flags)) != 0){
6967       return(recall);
6968     }
6969 
6970     /* iterate */
6971     recall = recall->next;
6972   }
6973 
6974   return(NULL);
6975 }
6976 
6977 /**
6978  * ags_recall_find_provider_with_recycling_context:
6979  * @recall: (element-type AgsAudio.Recall) (transfer none): the #GList-struct containing #AgsRecall
6980  * @provider: the #GObject as provider
6981  * @recycling_context: the #AgsRecyclingContext
6982  *
6983  * Like ags_recall_template_find_provider() but given additionally @recycling_context as search parameter.
6984  *
6985  * Returns: (element-type AgsAudio.Recall) (transfer none): next matching #GList-struct, or %NULL if not found
6986  *
6987  * Since: 3.0.0
6988  */
6989 GList*
ags_recall_find_provider_with_recycling_context(GList * recall,GObject * provider,GObject * recycling_context)6990 ags_recall_find_provider_with_recycling_context(GList *recall, GObject *provider, GObject *recycling_context)
6991 {
6992   AgsRecall *current_recall;
6993   AgsRecallID *current_recall_id;
6994   AgsRecyclingContext *current_recycling_context;
6995 
6996   GRecMutex *current_recall_mutex;
6997   GRecMutex *current_recall_id_mutex;
6998 
6999   while((recall = ags_recall_find_provider(recall, provider)) != NULL){
7000     current_recall = AGS_RECALL(recall->data);
7001 
7002     /* get recall mutex */
7003     current_recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(current_recall);
7004 
7005     /* get some fields */
7006     g_rec_mutex_lock(current_recall_mutex);
7007 
7008     current_recall_id = current_recall->recall_id;
7009 
7010     g_rec_mutex_unlock(current_recall_mutex);
7011 
7012     /* get recycling context */
7013     current_recycling_context = NULL;
7014 
7015     if(current_recall_id != NULL){
7016       /* get recall id mutex */
7017       current_recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(current_recall_id);
7018 
7019       /* recycling context */
7020       g_rec_mutex_lock(current_recall_id_mutex);
7021 
7022       current_recycling_context = current_recall_id->recycling_context;
7023 
7024       g_rec_mutex_unlock(current_recall_id_mutex);
7025     }
7026 
7027     if(current_recycling_context == (AgsRecyclingContext *) recycling_context){
7028       return(recall);
7029     }
7030 
7031     /* iterate */
7032     recall = recall->next;
7033   }
7034 
7035   return(NULL);
7036 }
7037 
7038 void
ags_recall_child_done(AgsRecall * child,AgsRecall * parent)7039 ags_recall_child_done(AgsRecall *child,
7040 		      AgsRecall *parent)
7041 {
7042   GList *children;
7043 
7044   guint parent_behaviour_flags;
7045 
7046   /* remove child */
7047   ags_connectable_disconnect(AGS_CONNECTABLE(child));
7048   ags_recall_remove_child(parent,
7049 			  child);
7050 
7051   if(TRUE){
7052     AgsDestroyWorker *destroy_worker;
7053 
7054     destroy_worker = ags_destroy_worker_get_instance();
7055     ags_destroy_worker_add(destroy_worker,
7056 			   child, ags_destroy_util_dispose_and_unref);
7057   }else{
7058     g_object_run_dispose((GObject *) child);
7059     g_object_unref((GObject *) child);
7060   }
7061 
7062   g_object_get(parent,
7063 	       "child", &children,
7064 	       NULL);
7065 
7066   if(ags_recall_test_behaviour_flags(parent, AGS_SOUND_BEHAVIOUR_PROPAGATE_DONE) &&
7067      !ags_recall_test_behaviour_flags(parent, AGS_SOUND_BEHAVIOUR_PERSISTENT) &&
7068      children == NULL){
7069     ags_recall_done(parent);
7070   }
7071 
7072   g_list_free_full(children,
7073 		   g_object_unref);
7074 }
7075 
7076 /**
7077  * ags_recall_lock_port:
7078  * @recall: the #AgsRecall
7079  *
7080  * Locks the ports.
7081  *
7082  * Since: 3.0.0
7083  */
7084 void
ags_recall_lock_port(AgsRecall * recall)7085 ags_recall_lock_port(AgsRecall *recall)
7086 {
7087   AgsPort *port;
7088 
7089   GList *list_start, *list;
7090 
7091   GRecMutex *recall_mutex;
7092   GRecMutex *port_mutex;
7093 
7094   if(!AGS_IS_RECALL(recall)){
7095     return;
7096   }
7097 
7098   /* get recall mutex */
7099   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
7100 
7101   /* get some fields */
7102   g_rec_mutex_lock(recall_mutex);
7103 
7104   list =
7105     list_start = g_list_copy(recall->port);
7106 
7107   g_rec_mutex_unlock(recall_mutex);
7108 
7109   while(list != NULL){
7110     port = list->data;
7111 
7112     /* get port mutex */
7113     port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
7114 
7115     /* lock port mutex */
7116     g_rec_mutex_lock(port_mutex);
7117 
7118     /* iterate */
7119     list = list->next;
7120   }
7121 
7122   g_list_free(list_start);
7123 }
7124 
7125 /**
7126  * ags_recall_unlock_port:
7127  * @recall: the #AgsRecall
7128  *
7129  * Unlocks the ports.
7130  *
7131  * Since: 3.0.0
7132  */
7133 void
ags_recall_unlock_port(AgsRecall * recall)7134 ags_recall_unlock_port(AgsRecall *recall)
7135 {
7136   AgsPort *port;
7137 
7138   GList *list_start, *list;
7139 
7140   GRecMutex *recall_mutex;
7141   GRecMutex *port_mutex;
7142 
7143   if(!AGS_IS_RECALL(recall)){
7144     return;
7145   }
7146 
7147   /* get recall mutex */
7148   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
7149 
7150   /* get some fields */
7151   g_rec_mutex_lock(recall_mutex);
7152 
7153   list =
7154     list_start = g_list_copy(recall->port);
7155 
7156   g_rec_mutex_unlock(recall_mutex);
7157 
7158   while(list != NULL){
7159     port = list->data;
7160 
7161     /* get port mutex */
7162     port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
7163 
7164     /* lock port mutex */
7165     g_rec_mutex_unlock(port_mutex);
7166 
7167     /* iterate */
7168     list = list->next;
7169   }
7170 
7171   g_list_free(list_start);
7172 }
7173 
7174 /**
7175  * ags_recall_new:
7176  *
7177  * Instantiate #AgsRecall.
7178  *
7179  * Returns: the new instance of #AgsRecall.
7180  *
7181  * Since: 3.0.0
7182  */
7183 AgsRecall*
ags_recall_new()7184 ags_recall_new()
7185 {
7186   AgsRecall *recall;
7187 
7188   recall = (AgsRecall *) g_object_new(AGS_TYPE_RECALL,
7189 				      NULL);
7190 
7191   return(recall);
7192 }
7193