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