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