1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2020 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSequencer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/audio/ags_recall_id.h>
21 
22 #include <stdlib.h>
23 #include <stdio.h>
24 
25 #include <ags/i18n.h>
26 
27 void ags_recall_id_class_init(AgsRecallIDClass *recall_id);
28 void ags_recall_id_init(AgsRecallID *recall_id);
29 void ags_recall_id_set_property(GObject *gobject,
30 				guint prop_id,
31 				const GValue *value,
32 				GParamSpec *param_spec);
33 void ags_recall_id_get_property(GObject *gobject,
34 				guint prop_id,
35 				GValue *value,
36 				GParamSpec *param_spec);
37 void ags_recall_id_dispose(GObject *gobject);
38 void ags_recall_id_finalize(GObject *gobject);
39 
40 /**
41  * SECTION:ags_recall_id
42  * @short_description: The object specifies run context.
43  * @title: AgsRecallID
44  * @section_id:
45  * @include: ags/audio/ags_recall_id.h
46  *
47  * #AgsRecallID acts as dynamic context identifier.
48  */
49 
50 enum{
51   PROP_0,
52   PROP_RECYCLING_CONTEXT,
53 };
54 
55 static gpointer ags_recall_id_parent_class = NULL;
56 
57 GType
ags_recall_id_get_type(void)58 ags_recall_id_get_type(void)
59 {
60   static volatile gsize g_define_type_id__volatile = 0;
61 
62   if(g_once_init_enter (&g_define_type_id__volatile)){
63     GType ags_type_recall_id = 0;
64 
65     static const GTypeInfo ags_recall_id_info = {
66       sizeof(AgsRecallIDClass),
67       NULL, /* base_init */
68       NULL, /* base_finalize */
69       (GClassInitFunc) ags_recall_id_class_init,
70       NULL, /* class_finalize */
71       NULL, /* class_data */
72       sizeof(AgsRecallID),
73       0,    /* n_preallocs */
74       (GInstanceInitFunc) ags_recall_id_init,
75     };
76 
77     ags_type_recall_id = g_type_register_static(G_TYPE_OBJECT,
78 						"AgsRecallID",
79 						&ags_recall_id_info,
80 						0);
81 
82     g_once_init_leave(&g_define_type_id__volatile, ags_type_recall_id);
83   }
84 
85   return g_define_type_id__volatile;
86 }
87 
88 void
ags_recall_id_class_init(AgsRecallIDClass * recall_id)89 ags_recall_id_class_init(AgsRecallIDClass *recall_id)
90 {
91   GObjectClass *gobject;
92 
93   GParamSpec *param_spec;
94 
95   ags_recall_id_parent_class = g_type_class_peek_parent(recall_id);
96 
97   /* GObjectClass */
98   gobject = (GObjectClass *) recall_id;
99 
100   gobject->set_property = ags_recall_id_set_property;
101   gobject->get_property = ags_recall_id_get_property;
102 
103   gobject->dispose = ags_recall_id_dispose;
104   gobject->finalize = ags_recall_id_finalize;
105 
106   /* properties */
107   /**
108    * AgsRecallID:recycling-context:
109    *
110    * The dynamic run context belonging to.
111    *
112    * Since: 3.0.0
113    */
114   param_spec = g_param_spec_object("recycling-context",
115 				   i18n_pspec("assigned recycling context"),
116 				   i18n_pspec("The recycling context it is assigned with"),
117 				   G_TYPE_OBJECT,
118 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
119   g_object_class_install_property(gobject,
120 				  PROP_RECYCLING_CONTEXT,
121 				  param_spec);
122 }
123 
124 void
ags_recall_id_init(AgsRecallID * recall_id)125 ags_recall_id_init(AgsRecallID *recall_id)
126 {
127   recall_id->flags = 0;
128   recall_id->sound_scope = -1;
129   recall_id->staging_flags = 0;
130   recall_id->state_flags = 0;
131 
132   /* recall id mutex */
133   g_rec_mutex_init(&(recall_id->obj_mutex));
134 
135   /* recycling context */
136   recall_id->recycling_context = NULL;
137 }
138 
139 void
ags_recall_id_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)140 ags_recall_id_set_property(GObject *gobject,
141 			   guint prop_id,
142 			   const GValue *value,
143 			   GParamSpec *param_spec)
144 {
145   AgsRecallID *recall_id;
146 
147   GRecMutex *recall_id_mutex;
148 
149   recall_id = AGS_RECALL_ID(gobject);
150 
151   /* get recall id mutex */
152   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
153 
154   switch(prop_id){
155   case PROP_RECYCLING_CONTEXT:
156     {
157       AgsRecyclingContext *recycling_context;
158 
159       recycling_context = g_value_get_object(value);
160 
161       g_rec_mutex_lock(recall_id_mutex);
162 
163       if(recall_id->recycling_context == recycling_context){
164 	g_rec_mutex_unlock(recall_id_mutex);
165 
166 	return;
167       }
168 
169       if(recall_id->recycling_context != NULL){
170 	g_object_unref(recall_id->recycling_context);
171       }
172 
173       if(recycling_context != NULL){
174 	g_object_ref(recycling_context);
175       }
176 
177       recall_id->recycling_context = recycling_context;
178 
179       g_rec_mutex_unlock(recall_id_mutex);
180     }
181     break;
182   default:
183     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
184     break;
185   }
186 }
187 
188 void
ags_recall_id_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)189 ags_recall_id_get_property(GObject *gobject,
190 			   guint prop_id,
191 			   GValue *value,
192 			   GParamSpec *param_spec)
193 {
194   AgsRecallID *recall_id;
195 
196   GRecMutex *recall_id_mutex;
197 
198   recall_id = AGS_RECALL_ID(gobject);
199 
200   /* get recall id mutex */
201   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
202 
203   switch(prop_id){
204   case PROP_RECYCLING_CONTEXT:
205     {
206       g_rec_mutex_lock(recall_id_mutex);
207 
208       g_value_set_object(value, recall_id->recycling_context);
209 
210       g_rec_mutex_unlock(recall_id_mutex);
211     }
212     break;
213   default:
214     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
215     break;
216   }
217 }
218 
219 void
ags_recall_id_dispose(GObject * gobject)220 ags_recall_id_dispose(GObject *gobject)
221 {
222   AgsRecallID *recall_id;
223 
224   recall_id = AGS_RECALL_ID(gobject);
225 
226   if(recall_id->recycling_context != NULL){
227     g_object_unref(recall_id->recycling_context);
228 
229     recall_id->recycling_context = NULL;
230   }
231 
232   /* call parent */
233   G_OBJECT_CLASS(ags_recall_id_parent_class)->dispose(gobject);
234 }
235 
236 void
ags_recall_id_finalize(GObject * gobject)237 ags_recall_id_finalize(GObject *gobject)
238 {
239   AgsRecallID *recall_id;
240 
241   recall_id = AGS_RECALL_ID(gobject);
242 
243   if(recall_id->recycling_context != NULL){
244     g_object_unref(recall_id->recycling_context);
245   }
246 
247   /* call parent */
248   G_OBJECT_CLASS(ags_recall_id_parent_class)->finalize(gobject);
249 }
250 
251 /**
252  * ags_recall_id_set_scope:
253  * @recall_id: the #AgsRecallID
254  * @sound_scope: the sound scope
255  *
256  * Set @sound_scope for @recall_id.
257  *
258  * Since: 3.0.0
259  */
260 void
ags_recall_id_set_sound_scope(AgsRecallID * recall_id,gint sound_scope)261 ags_recall_id_set_sound_scope(AgsRecallID *recall_id, gint sound_scope)
262 {
263   GRecMutex *recall_id_mutex;
264 
265   if(!AGS_IS_RECALL_ID(recall_id) ||
266      ags_recall_id_check_sound_scope(recall_id,
267 				     -1)){
268     return;
269   }
270 
271   /* get recall id mutex */
272   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
273 
274   /* set sound scope */
275   g_rec_mutex_lock(recall_id_mutex);
276 
277   recall_id->sound_scope = sound_scope;
278 
279   g_rec_mutex_unlock(recall_id_mutex);
280 }
281 
282 /**
283  * ags_recall_id_check_sound_scope:
284  * @recall_id: the #AgsRecallID
285  * @sound_scope: the sound scope to check or -1 to check all
286  *
287  * Check if @sound_scope is set for @recall_id.
288  *
289  * Returns: %TRUE if sound scope matches, otherwise  %FALSE
290  *
291  * Since: 3.0.0
292  */
293 gboolean
ags_recall_id_check_sound_scope(AgsRecallID * recall_id,gint sound_scope)294 ags_recall_id_check_sound_scope(AgsRecallID *recall_id, gint sound_scope)
295 {
296   gint recall_id_sound_scope;
297 
298   GRecMutex *recall_id_mutex;
299 
300   if(!AGS_IS_RECALL_ID(recall_id)){
301     return(FALSE);
302   }
303 
304   /* get recall id mutex */
305   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
306 
307   /* get sound scope */
308   g_rec_mutex_lock(recall_id_mutex);
309 
310   recall_id_sound_scope = recall_id->sound_scope;
311 
312   g_rec_mutex_unlock(recall_id_mutex);
313 
314   if(sound_scope < 0){
315     switch(recall_id_sound_scope){
316     case AGS_SOUND_SCOPE_PLAYBACK:
317     case AGS_SOUND_SCOPE_NOTATION:
318     case AGS_SOUND_SCOPE_SEQUENCER:
319     case AGS_SOUND_SCOPE_WAVE:
320     case AGS_SOUND_SCOPE_MIDI:
321       return(TRUE);
322     default:
323       return(FALSE);
324     }
325   }else{
326     if(sound_scope < AGS_SOUND_SCOPE_LAST &&
327        sound_scope == recall_id_sound_scope){
328       return(TRUE);
329     }else{
330       return(FALSE);
331     }
332   }
333 }
334 
335 /**
336  * ags_recall_id_test_staging_flags:
337  * @recall_id: the #AgsRecallID
338  * @staging_flags: the staging flags
339  *
340  * Test @staging_flags to be set on @recall_id.
341  *
342  * Returns: %TRUE if flags are set, else %FALSE
343  *
344  * Since: 3.0.0
345  */
346 gboolean
ags_recall_id_test_staging_flags(AgsRecallID * recall_id,guint staging_flags)347 ags_recall_id_test_staging_flags(AgsRecallID *recall_id,
348 				 guint staging_flags)
349 {
350   gboolean retval;
351 
352   GRecMutex *recall_id_mutex;
353 
354   if(!AGS_IS_RECALL_ID(recall_id)){
355     return(FALSE);
356   }
357 
358   /* get recall id mutex */
359   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
360 
361   /* test */
362   g_rec_mutex_lock(recall_id_mutex);
363 
364   retval = (staging_flags & (recall_id->staging_flags)) ? TRUE: FALSE;
365 
366   g_rec_mutex_unlock(recall_id_mutex);
367 
368   return(retval);
369 }
370 
371 /**
372  * ags_recall_id_set_staging_flags:
373  * @recall_id: the #AgsRecallID
374  * @staging_flags: staging flags to set
375  *
376  * Set staging flags.
377  *
378  * Since: 3.0.0
379  */
380 void
ags_recall_id_set_staging_flags(AgsRecallID * recall_id,guint staging_flags)381 ags_recall_id_set_staging_flags(AgsRecallID *recall_id, guint staging_flags)
382 {
383   GRecMutex *recall_id_mutex;
384 
385   if(!AGS_IS_RECALL_ID(recall_id)){
386     return;
387   }
388 
389   /* get recall id mutex */
390   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
391 
392   /* set staging flags */
393   g_rec_mutex_lock(recall_id_mutex);
394 
395   recall_id->staging_flags |= staging_flags;
396 
397   g_rec_mutex_unlock(recall_id_mutex);
398 }
399 
400 /**
401  * ags_recall_id_unset_staging_flags:
402  * @recall_id: the #AgsRecallID
403  * @staging_flags: staging flags to unset
404  *
405  * Unset staging flags.
406  *
407  * Since: 3.0.0
408  */
409 void
ags_recall_id_unset_staging_flags(AgsRecallID * recall_id,guint staging_flags)410 ags_recall_id_unset_staging_flags(AgsRecallID *recall_id, guint staging_flags)
411 {
412   GRecMutex *recall_id_mutex;
413 
414   if(!AGS_IS_RECALL_ID(recall_id)){
415     return;
416   }
417 
418   /* get recall id mutex */
419   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
420 
421   /* unset staging flags */
422   g_rec_mutex_lock(recall_id_mutex);
423 
424   recall_id->staging_flags &= (~staging_flags);
425 
426   g_rec_mutex_unlock(recall_id_mutex);
427 }
428 
429 /**
430  * ags_recall_id_check_staging_flags:
431  * @recall_id: the #AgsRecallID
432  * @staging_flags: staging flags to check
433  *
434  * Check the occurence of @staging_flags in @recall_id.
435  *
436  * Returns: %TRUE if all flags matched, otherwise %FALSE
437  *
438  * Since: 3.0.0
439  */
440 gboolean
ags_recall_id_check_staging_flags(AgsRecallID * recall_id,guint staging_flags)441 ags_recall_id_check_staging_flags(AgsRecallID *recall_id, guint staging_flags)
442 {
443   guint recall_id_staging_flags;
444 
445   GRecMutex *recall_id_mutex;
446 
447   if(!AGS_IS_RECALL_ID(recall_id)){
448     return(FALSE);
449   }
450 
451   /* get recall id mutex */
452   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
453 
454   /* get staging flags */
455   g_rec_mutex_lock(recall_id_mutex);
456 
457   recall_id_staging_flags = recall_id->staging_flags;
458 
459   g_rec_mutex_unlock(recall_id_mutex);
460 
461   /* check staging flags */
462   if((AGS_SOUND_STAGING_CHECK_RT_DATA & (staging_flags)) != 0 &&
463      (AGS_SOUND_STAGING_CHECK_RT_DATA & (recall_id_staging_flags)) == 0){
464     return(FALSE);
465   }
466 
467   if((AGS_SOUND_STAGING_RUN_INIT_PRE & (staging_flags)) != 0 &&
468      (AGS_SOUND_STAGING_RUN_INIT_PRE & (recall_id_staging_flags)) == 0){
469     return(FALSE);
470   }
471 
472   if((AGS_SOUND_STAGING_RUN_INIT_INTER & (staging_flags)) != 0 &&
473      (AGS_SOUND_STAGING_RUN_INIT_INTER & (recall_id_staging_flags)) == 0){
474     return(FALSE);
475   }
476 
477   if((AGS_SOUND_STAGING_RUN_INIT_POST & (staging_flags)) != 0 &&
478      (AGS_SOUND_STAGING_RUN_INIT_POST & (recall_id_staging_flags)) == 0){
479     return(FALSE);
480   }
481 
482   if((AGS_SOUND_STAGING_FEED_INPUT_QUEUE & (staging_flags)) != 0 &&
483      (AGS_SOUND_STAGING_FEED_INPUT_QUEUE & (recall_id_staging_flags)) == 0){
484     return(FALSE);
485   }
486 
487   if((AGS_SOUND_STAGING_AUTOMATE & (staging_flags)) != 0 &&
488      (AGS_SOUND_STAGING_AUTOMATE & (recall_id_staging_flags)) == 0){
489     return(FALSE);
490   }
491 
492   if((AGS_SOUND_STAGING_RUN_PRE & (staging_flags)) != 0 &&
493      (AGS_SOUND_STAGING_RUN_PRE & (recall_id_staging_flags)) == 0){
494     return(FALSE);
495   }
496 
497   if((AGS_SOUND_STAGING_RUN_INTER & (staging_flags)) != 0 &&
498      (AGS_SOUND_STAGING_RUN_INTER & (recall_id_staging_flags)) == 0){
499     return(FALSE);
500   }
501 
502   if((AGS_SOUND_STAGING_RUN_POST & (staging_flags)) != 0 &&
503      (AGS_SOUND_STAGING_RUN_POST & (recall_id_staging_flags)) == 0){
504     return(FALSE);
505   }
506 
507   if((AGS_SOUND_STAGING_DO_FEEDBACK & (staging_flags)) != 0 &&
508      (AGS_SOUND_STAGING_DO_FEEDBACK & (recall_id_staging_flags)) == 0){
509     return(FALSE);
510   }
511 
512   if((AGS_SOUND_STAGING_FEED_OUTPUT_QUEUE & (staging_flags)) != 0 &&
513      (AGS_SOUND_STAGING_FEED_OUTPUT_QUEUE & (recall_id_staging_flags)) == 0){
514     return(FALSE);
515   }
516 
517   if((AGS_SOUND_STAGING_FINI & (staging_flags)) != 0 &&
518      (AGS_SOUND_STAGING_FINI & (recall_id_staging_flags)) == 0){
519     return(FALSE);
520   }
521 
522   if((AGS_SOUND_STAGING_CANCEL & (staging_flags)) != 0 &&
523      (AGS_SOUND_STAGING_CANCEL & (recall_id_staging_flags)) == 0){
524     return(FALSE);
525   }
526 
527   if((AGS_SOUND_STAGING_DONE & (staging_flags)) != 0 &&
528      (AGS_SOUND_STAGING_DONE & (recall_id_staging_flags)) == 0){
529     return(FALSE);
530   }
531 
532   if((AGS_SOUND_STAGING_REMOVE & (staging_flags)) != 0 &&
533      (AGS_SOUND_STAGING_REMOVE & (recall_id_staging_flags)) == 0){
534     return(FALSE);
535   }
536 
537   return(TRUE);
538 }
539 
540 /**
541  * ags_recall_id_test_state_flags:
542  * @recall_id: the #AgsRecallID
543  * @state_flags: the state flags
544  *
545  * Test @state_flags to be set on @recall_id.
546  *
547  * Returns: %TRUE if flags are set, else %FALSE
548  *
549  * Since: 3.0.0
550  */
551 gboolean
ags_recall_id_test_state_flags(AgsRecallID * recall_id,guint state_flags)552 ags_recall_id_test_state_flags(AgsRecallID *recall_id,
553 			       guint state_flags)
554 {
555   gboolean retval;
556 
557   GRecMutex *recall_id_mutex;
558 
559   if(!AGS_IS_RECALL_ID(recall_id)){
560     return(FALSE);
561   }
562 
563   /* get recall_id mutex */
564   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
565 
566   /* test */
567   g_rec_mutex_lock(recall_id_mutex);
568 
569   retval = (state_flags & (recall_id->state_flags)) ? TRUE: FALSE;
570 
571   g_rec_mutex_unlock(recall_id_mutex);
572 
573   return(retval);
574 }
575 
576 /**
577  * ags_recall_id_set_state_flags:
578  * @recall_id: the #AgsRecallID
579  * @state_flags: state flags to set
580  *
581  * Set state flags.
582  *
583  * Since: 3.0.0
584  */
585 void
ags_recall_id_set_state_flags(AgsRecallID * recall_id,guint state_flags)586 ags_recall_id_set_state_flags(AgsRecallID *recall_id, guint state_flags)
587 {
588   GRecMutex *recall_id_mutex;
589 
590   if(!AGS_IS_RECALL_ID(recall_id)){
591     return;
592   }
593 
594   /* get recall id mutex */
595   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
596 
597   /* set state flags */
598   g_rec_mutex_lock(recall_id_mutex);
599 
600   recall_id->state_flags |= state_flags;
601 
602   g_rec_mutex_unlock(recall_id_mutex);
603 }
604 
605 /**
606  * ags_recall_id_unset_state_flags:
607  * @recall_id: the #AgsRecallID
608  * @state_flags: state flags to unset
609  *
610  * Unset state flags.
611  *
612  * Since: 3.0.0
613  */
614 void
ags_recall_id_unset_state_flags(AgsRecallID * recall_id,guint state_flags)615 ags_recall_id_unset_state_flags(AgsRecallID *recall_id, guint state_flags)
616 {
617   GRecMutex *recall_id_mutex;
618 
619   if(!AGS_IS_RECALL_ID(recall_id)){
620     return;
621   }
622 
623   /* get recall id mutex */
624   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
625 
626   /* unset state flags */
627   g_rec_mutex_lock(recall_id_mutex);
628 
629   recall_id->state_flags &= (~state_flags);
630 
631   g_rec_mutex_unlock(recall_id_mutex);
632 }
633 
634 /**
635  * ags_recall_id_check_state_flags:
636  * @recall_id: the #AgsRecallID
637  * @state_flags: state flags to check
638  *
639  * Check the occurence of @state_flags in @recall_id.
640  *
641  * Returns: %TRUE if all flags matched, otherwise %FALSE
642  *
643  * Since: 3.0.0
644  */
645 gboolean
ags_recall_id_check_state_flags(AgsRecallID * recall_id,guint state_flags)646 ags_recall_id_check_state_flags(AgsRecallID *recall_id, guint state_flags)
647 {
648   guint recall_id_state_flags;
649 
650   GRecMutex *recall_id_mutex;
651 
652   if(!AGS_IS_RECALL_ID(recall_id)){
653     return(FALSE);
654   }
655 
656   /* get recall id mutex */
657   recall_id_mutex = AGS_RECALL_ID_GET_OBJ_MUTEX(recall_id);
658 
659   /* get state flags */
660   g_rec_mutex_lock(recall_id_mutex);
661 
662   recall_id_state_flags = recall_id->state_flags;
663 
664   g_rec_mutex_unlock(recall_id_mutex);
665 
666   /* check state flags */
667   if((AGS_SOUND_STATE_IS_WAITING & (state_flags)) != 0 &&
668      (AGS_SOUND_STATE_IS_WAITING & (recall_id_state_flags)) == 0){
669     return(FALSE);
670   }
671 
672   if((AGS_SOUND_STATE_IS_ACTIVE & (state_flags)) != 0 &&
673      (AGS_SOUND_STATE_IS_ACTIVE & (recall_id_state_flags)) == 0){
674     return(FALSE);
675   }
676 
677   if((AGS_SOUND_STATE_IS_PROCESSING & (state_flags)) != 0 &&
678      (AGS_SOUND_STATE_IS_PROCESSING & (recall_id_state_flags)) == 0){
679     return(FALSE);
680   }
681 
682   if((AGS_SOUND_STATE_IS_TERMINATING & (state_flags)) != 0 &&
683      (AGS_SOUND_STATE_IS_TERMINATING & (recall_id_state_flags)) == 0){
684     return(FALSE);
685   }
686 
687   return(TRUE);
688 }
689 
690 /**
691  * ags_recall_id_get_recycling_context:
692  * @recall_id: the #AgsRecallId
693  *
694  * Get recycling context.
695  *
696  * Returns: (transfer full): the #AgsRecyclingContext
697  *
698  * Since: 3.3.0
699  */
700 AgsRecyclingContext*
ags_recall_id_get_recycling_context(AgsRecallID * recall_id)701 ags_recall_id_get_recycling_context(AgsRecallID *recall_id)
702 {
703   AgsRecyclingContext *recycling_context;
704 
705   if(!AGS_IS_RECALL_ID(recall_id)){
706     return(NULL);
707   }
708 
709   g_object_get(recall_id,
710 	       "recycling-context", &recycling_context,
711 	       NULL);
712 
713   return(recycling_context);
714 }
715 
716 /**
717  * ags_recall_id_set_recycling_context:
718  * @recall_id: the #AgsRecallId
719  * @recycling_context: the #AgsRecyclingContext
720  *
721  * Set recycling context.
722  *
723  * Since: 3.3.0
724  */
725 void
ags_recall_id_set_recycling_context(AgsRecallID * recall_id,AgsRecyclingContext * recycling_context)726 ags_recall_id_set_recycling_context(AgsRecallID *recall_id, AgsRecyclingContext *recycling_context)
727 {
728   if(!AGS_IS_RECALL_ID(recall_id)){
729     return;
730   }
731 
732   g_object_set(recall_id,
733 	       "recycling-context", recycling_context,
734 	       NULL);
735 }
736 
737 /**
738  * ags_recall_id_find_recycling_context:
739  * @recall_id: (element-type AgsAudio.RecallID) (transfer none): the #GList-struct containing #AgsRecallID
740  * @recycling_context: the #AgsRecyclingContext to match
741  *
742  * Retrieve recall id by recycling context.
743  *
744  * Returns: (transfer none): Matching #AgsRecallID
745  *
746  * Since: 3.0.0
747  */
748 AgsRecallID*
ags_recall_id_find_recycling_context(GList * recall_id,AgsRecyclingContext * recycling_context)749 ags_recall_id_find_recycling_context(GList *recall_id,
750 				     AgsRecyclingContext *recycling_context)
751 {
752   while(recall_id != NULL){
753     AgsRecyclingContext *current_recycling_context;
754 
755     gboolean success;
756 
757     current_recycling_context = NULL;
758 
759     g_object_get(recall_id->data,
760 		 "recycling-context", &current_recycling_context,
761 		 NULL);
762 
763     success = (current_recycling_context == recycling_context) ? TRUE: FALSE;
764 
765     if(current_recycling_context != NULL){
766       g_object_unref(current_recycling_context);
767     }
768 
769     if(success){
770       return(recall_id->data);
771     }
772 
773     recall_id = recall_id->next;
774   }
775 
776   return(NULL);
777 }
778 
779 /**
780  * ags_recall_id_find_parent_recycling_context:
781  * @recall_id: (element-type AgsAudio.RecallID) (transfer none): the #GList-struct containing #AgsRecallID
782  * @parent_recycling_context: the #AgsRecyclingContext to match
783  *
784  * Retrieve recall id by recycling context.
785  *
786  * Returns: (transfer none): Matching #AgsRecallID
787  *
788  * Since: 3.0.0
789  */
790 AgsRecallID*
ags_recall_id_find_parent_recycling_context(GList * recall_id,AgsRecyclingContext * parent_recycling_context)791 ags_recall_id_find_parent_recycling_context(GList *recall_id,
792 					    AgsRecyclingContext *parent_recycling_context)
793 {
794   while(recall_id != NULL){
795     AgsRecyclingContext *current_recycling_context;
796 
797     gboolean success;
798 
799     current_recycling_context = NULL;
800 
801     success = FALSE;
802 
803     g_object_get(recall_id->data,
804 		 "recycling-context", &current_recycling_context,
805 		 NULL);
806 
807     if(current_recycling_context != NULL){
808       AgsRecyclingContext *current_parent_recycling_context;
809 
810       current_parent_recycling_context = NULL;
811 
812       g_object_get(current_recycling_context,
813 		   "parent", &current_parent_recycling_context,
814 		   NULL);
815 
816       if(current_parent_recycling_context == parent_recycling_context){
817 	success = TRUE;
818       }
819 
820       /* unref */
821       if(current_parent_recycling_context != NULL){
822 	g_object_unref(current_parent_recycling_context);
823       }
824 
825       g_object_unref(current_recycling_context);
826     }
827 
828     if(success){
829       return(recall_id->data);
830     }
831 
832     recall_id = recall_id->next;
833   }
834 
835   return(NULL);
836 }
837 
838 /**
839  * ags_recall_id_new:
840  *
841  * Creates a #AgsRecallID
842  *
843  * Returns: a new #AgsRecallID
844  *
845  * Since: 3.0.0
846  */
847 AgsRecallID*
ags_recall_id_new()848 ags_recall_id_new()
849 {
850   AgsRecallID *recall_id;
851 
852   recall_id = (AgsRecallID *) g_object_new(AGS_TYPE_RECALL_ID,
853 					   NULL);
854 
855   return(recall_id);
856 }
857