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_recycling.h>
21
22 #include <ags/audio/ags_audio.h>
23 #include <ags/audio/ags_channel.h>
24 #include <ags/audio/ags_audio_buffer_util.h>
25
26 #include <string.h>
27 #include <math.h>
28
29 #include <ags/i18n.h>
30
31 void ags_recycling_class_init(AgsRecyclingClass *recycling_class);
32 void ags_recycling_connectable_interface_init(AgsConnectableInterface *connectable);
33 void ags_recycling_set_property(GObject *gobject,
34 guint prop_id,
35 const GValue *value,
36 GParamSpec *param_spec);
37 void ags_recycling_get_property(GObject *gobject,
38 guint prop_id,
39 GValue *value,
40 GParamSpec *param_spec);
41 void ags_recycling_init(AgsRecycling *recycling);
42 void ags_recycling_dispose(GObject *gobject);
43 void ags_recycling_finalize(GObject *gobject);
44
45 AgsUUID* ags_recycling_get_uuid(AgsConnectable *connectable);
46 gboolean ags_recycling_has_resource(AgsConnectable *connectable);
47 gboolean ags_recycling_is_ready(AgsConnectable *connectable);
48 void ags_recycling_add_to_registry(AgsConnectable *connectable);
49 void ags_recycling_remove_from_registry(AgsConnectable *connectable);
50 xmlNode* ags_recycling_list_resource(AgsConnectable *connectable);
51 xmlNode* ags_recycling_xml_compose(AgsConnectable *connectable);
52 void ags_recycling_xml_parse(AgsConnectable *connectable,
53 xmlNode *node);
54 gboolean ags_recycling_is_connected(AgsConnectable *connectable);
55 void ags_recycling_connect(AgsConnectable *connectable);
56 void ags_recycling_disconnect(AgsConnectable *connectable);
57
58 void ags_recycling_real_set_output_soundcard(AgsRecycling *recycling, GObject *output_soundcard);
59
60 void ags_recycling_real_set_input_soundcard(AgsRecycling *recycling, GObject *input_soundcard);
61
62 void ags_recycling_real_add_audio_signal(AgsRecycling *recycling,
63 AgsAudioSignal *audio_signal);
64
65 void ags_recycling_real_remove_audio_signal(AgsRecycling *recycling,
66 AgsAudioSignal *audio_signal);
67
68 /**
69 * SECTION:ags_recycling
70 * @short_description: recycling container of audio signals
71 * @title: AgsRecycling
72 * @section_id:
73 * @include: ags/audio/ags_recycling.h
74 *
75 * #AgsRecycling forms the nested tree of AgsChannel. Every channel
76 * owning audio signal contains therefor an #AgsRecycling.
77 */
78
79 enum{
80 PROP_0,
81 PROP_CHANNEL,
82 PROP_OUTPUT_SOUNDCARD,
83 PROP_OUTPUT_SOUNDCARD_CHANNEL,
84 PROP_INPUT_SOUNDCARD,
85 PROP_INPUT_SOUNDCARD_CHANNEL,
86 PROP_SAMPLERATE,
87 PROP_BUFFER_SIZE,
88 PROP_FORMAT,
89 PROP_PARENT,
90 PROP_NEXT,
91 PROP_PREV,
92 PROP_AUDIO_SIGNAL,
93 };
94
95 enum{
96 ADD_AUDIO_SIGNAL,
97 REMOVE_AUDIO_SIGNAL,
98 DATA_REQUEST,
99 LAST_SIGNAL,
100 };
101
102 static gpointer ags_recycling_parent_class = NULL;
103 static guint recycling_signals[LAST_SIGNAL];
104
105 GType
ags_recycling_get_type(void)106 ags_recycling_get_type(void)
107 {
108 static volatile gsize g_define_type_id__volatile = 0;
109
110 if(g_once_init_enter (&g_define_type_id__volatile)){
111 GType ags_type_recycling = 0;
112
113 static const GTypeInfo ags_recycling_info = {
114 sizeof (AgsRecyclingClass),
115 NULL, /* base_init */
116 NULL, /* base_finalize */
117 (GClassInitFunc) ags_recycling_class_init,
118 NULL, /* class_finalize */
119 NULL, /* class_data */
120 sizeof (AgsRecycling),
121 0, /* n_preallocs */
122 (GInstanceInitFunc) ags_recycling_init,
123 };
124
125 static const GInterfaceInfo ags_connectable_interface_info = {
126 (GInterfaceInitFunc) ags_recycling_connectable_interface_init,
127 NULL, /* interface_finalize */
128 NULL, /* interface_data */
129 };
130
131 ags_type_recycling = g_type_register_static(G_TYPE_OBJECT,
132 "AgsRecycling",
133 &ags_recycling_info, 0);
134
135 g_type_add_interface_static(ags_type_recycling,
136 AGS_TYPE_CONNECTABLE,
137 &ags_connectable_interface_info);
138
139 g_once_init_leave(&g_define_type_id__volatile, ags_type_recycling);
140 }
141
142 return g_define_type_id__volatile;
143 }
144
145 void
ags_recycling_class_init(AgsRecyclingClass * recycling)146 ags_recycling_class_init(AgsRecyclingClass *recycling)
147 {
148 GObjectClass *gobject;
149 GParamSpec *param_spec;
150
151 ags_recycling_parent_class = g_type_class_peek_parent(recycling);
152
153 /* GObjectClass */
154 gobject = (GObjectClass *) recycling;
155
156 gobject->set_property = ags_recycling_set_property;
157 gobject->get_property = ags_recycling_get_property;
158
159 gobject->dispose = ags_recycling_dispose;
160 gobject->finalize = ags_recycling_finalize;
161
162 /* properties */
163 /**
164 * AgsRecycling:channel:
165 *
166 * The assigned #AgsChannel.
167 *
168 * Since: 3.0.0
169 */
170 param_spec = g_param_spec_object("channel",
171 "assigned channel",
172 "The channel it is assigned with",
173 AGS_TYPE_CHANNEL,
174 G_PARAM_READABLE | G_PARAM_WRITABLE);
175 g_object_class_install_property(gobject,
176 PROP_CHANNEL,
177 param_spec);
178
179 /**
180 * AgsRecycling:output-soundcard:
181 *
182 * The assigned output soundcard acting as default sink.
183 *
184 * Since: 3.0.0
185 */
186 param_spec = g_param_spec_object("output-soundcard",
187 "assigned output soundcard",
188 "The output soundcard it is assigned with",
189 G_TYPE_OBJECT,
190 G_PARAM_READABLE | G_PARAM_WRITABLE);
191 g_object_class_install_property(gobject,
192 PROP_OUTPUT_SOUNDCARD,
193 param_spec);
194
195 /**
196 * AgsRecycling:output-soundcard-channel:
197 *
198 * The output soundcard channel.
199 *
200 * Since: 3.0.0
201 */
202 param_spec = g_param_spec_int("output-soundcard-channel",
203 i18n_pspec("output soundcard channel"),
204 i18n_pspec("The output soundcard channel"),
205 -1,
206 G_MAXINT32,
207 0,
208 G_PARAM_READABLE | G_PARAM_WRITABLE);
209 g_object_class_install_property(gobject,
210 PROP_OUTPUT_SOUNDCARD_CHANNEL,
211 param_spec);
212
213 /**
214 * AgsRecycling:input-soundcard:
215 *
216 * The assigned input soundcard.
217 *
218 * Since: 3.0.0
219 */
220 param_spec = g_param_spec_object("input-soundcard",
221 "assigned input soundcard",
222 "The input soundcard it is assigned with",
223 G_TYPE_OBJECT,
224 G_PARAM_READABLE | G_PARAM_WRITABLE);
225 g_object_class_install_property(gobject,
226 PROP_INPUT_SOUNDCARD,
227 param_spec);
228
229 /**
230 * AgsRecycling:input-soundcard-channel:
231 *
232 * The input soundcard channel.
233 *
234 * Since: 3.0.0
235 */
236 param_spec = g_param_spec_int("input-soundcard-channel",
237 i18n_pspec("input soundcard channel"),
238 i18n_pspec("The input soundcard channel"),
239 -1,
240 G_MAXINT32,
241 0,
242 G_PARAM_READABLE | G_PARAM_WRITABLE);
243 g_object_class_install_property(gobject,
244 PROP_INPUT_SOUNDCARD_CHANNEL,
245 param_spec);
246
247 /**
248 * AgsRecycling:samplerate:
249 *
250 * The samplerate.
251 *
252 * Since: 3.0.0
253 */
254 param_spec = g_param_spec_uint("samplerate",
255 i18n_pspec("samplerate"),
256 i18n_pspec("The samplerate"),
257 0,
258 G_MAXUINT32,
259 0,
260 G_PARAM_READABLE | G_PARAM_WRITABLE);
261 g_object_class_install_property(gobject,
262 PROP_SAMPLERATE,
263 param_spec);
264
265 /**
266 * AgsRecycling:buffer-size:
267 *
268 * The buffer size.
269 *
270 * Since: 3.0.0
271 */
272 param_spec = g_param_spec_uint("buffer-size",
273 i18n_pspec("buffer size"),
274 i18n_pspec("The buffer size"),
275 0,
276 G_MAXUINT32,
277 0,
278 G_PARAM_READABLE | G_PARAM_WRITABLE);
279 g_object_class_install_property(gobject,
280 PROP_BUFFER_SIZE,
281 param_spec);
282
283 /**
284 * AgsRecycling:format:
285 *
286 * The format.
287 *
288 * Since: 3.0.0
289 */
290 param_spec = g_param_spec_uint("format",
291 i18n_pspec("format"),
292 i18n_pspec("The format"),
293 0,
294 G_MAXUINT32,
295 0,
296 G_PARAM_READABLE | G_PARAM_WRITABLE);
297 g_object_class_install_property(gobject,
298 PROP_FORMAT,
299 param_spec);
300
301 /**
302 * AgsRecycling:parent:
303 *
304 * The assigned parent #AgsRecycling.
305 *
306 * Since: 3.0.0
307 */
308 param_spec = g_param_spec_object("parent",
309 "assigned parent",
310 "The parent it is assigned with",
311 AGS_TYPE_RECYCLING,
312 G_PARAM_READABLE | G_PARAM_WRITABLE);
313 g_object_class_install_property(gobject,
314 PROP_PARENT,
315 param_spec);
316
317 /**
318 * AgsRecycling:prev:
319 *
320 * The assigned prev #AgsRecycling.
321 *
322 * Since: 3.0.0
323 */
324 param_spec = g_param_spec_object("prev",
325 "assigned prev",
326 "The prev it is assigned with",
327 AGS_TYPE_RECYCLING,
328 G_PARAM_READABLE | G_PARAM_WRITABLE);
329 g_object_class_install_property(gobject,
330 PROP_PREV,
331 param_spec);
332
333 /**
334 * AgsRecycling:next:
335 *
336 * The assigned next #AgsRecycling.
337 *
338 * Since: 3.0.0
339 */
340 param_spec = g_param_spec_object("next",
341 "assigned next",
342 "The next it is assigned with",
343 AGS_TYPE_RECYCLING,
344 G_PARAM_READABLE | G_PARAM_WRITABLE);
345 g_object_class_install_property(gobject,
346 PROP_NEXT,
347 param_spec);
348
349 /**
350 * AgsRecycling:audio-signal: (type GList(AgsAudioSignal)) (transfer full)
351 *
352 * The containing #AgsAudioSignal.
353 *
354 * Since: 3.0.0
355 */
356 param_spec = g_param_spec_pointer("audio-signal",
357 "containing audio signal",
358 "The audio signal it contains",
359 G_PARAM_READABLE | G_PARAM_WRITABLE);
360 g_object_class_install_property(gobject,
361 PROP_AUDIO_SIGNAL,
362 param_spec);
363
364 /* */
365 recycling->add_audio_signal = ags_recycling_real_add_audio_signal;
366 recycling->remove_audio_signal = ags_recycling_real_remove_audio_signal;
367
368 /**
369 * AgsRecycling::add-audio-signal
370 * @recycling: an #AgsRecycling
371 * @audio_signal: the #AgsAudioSignal to add
372 *
373 * The ::add-audio-signal signal is emited as adding #AgsAudioSignal.
374 *
375 * Since: 3.0.0
376 */
377 recycling_signals[ADD_AUDIO_SIGNAL] =
378 g_signal_new("add-audio-signal",
379 G_TYPE_FROM_CLASS(recycling),
380 G_SIGNAL_RUN_LAST,
381 G_STRUCT_OFFSET(AgsRecyclingClass, add_audio_signal),
382 NULL, NULL,
383 g_cclosure_marshal_VOID__OBJECT,
384 G_TYPE_NONE, 1,
385 G_TYPE_OBJECT);
386
387 /**
388 * AgsRecycling::remove-audio-signal:
389 * @recycling: an #AgsRecycling
390 * @audio_signal: the #AgsAudioSignal to remove
391 *
392 * The ::remove-audio-signal signal is emited as removing #AgsAudioSignal.
393 *
394 * Since: 3.0.0
395 */
396 recycling_signals[REMOVE_AUDIO_SIGNAL] =
397 g_signal_new("remove-audio-signal",
398 G_TYPE_FROM_CLASS(recycling),
399 G_SIGNAL_RUN_LAST,
400 G_STRUCT_OFFSET(AgsRecyclingClass, remove_audio_signal),
401 NULL, NULL,
402 g_cclosure_marshal_VOID__OBJECT,
403 G_TYPE_NONE, 1,
404 G_TYPE_OBJECT);
405
406 /**
407 * AgsRecycling::data-request
408 * @recycling: an #AgsRecycling
409 * @audio_signal: the #AgsAudioSignal to request
410 *
411 * The ::data-request signal is emited as requesting data for @audio_signal.
412 *
413 * Since: 3.0.0
414 */
415 recycling_signals[DATA_REQUEST] =
416 g_signal_new("data-request",
417 G_TYPE_FROM_CLASS(recycling),
418 G_SIGNAL_RUN_LAST,
419 G_STRUCT_OFFSET(AgsRecyclingClass, data_request),
420 NULL, NULL,
421 g_cclosure_marshal_VOID__OBJECT,
422 G_TYPE_NONE, 1,
423 G_TYPE_OBJECT);
424 }
425
426 void
ags_recycling_connectable_interface_init(AgsConnectableInterface * connectable)427 ags_recycling_connectable_interface_init(AgsConnectableInterface *connectable)
428 {
429 connectable->get_uuid = ags_recycling_get_uuid;
430 connectable->has_resource = ags_recycling_has_resource;
431
432 connectable->is_ready = ags_recycling_is_ready;
433 connectable->add_to_registry = ags_recycling_add_to_registry;
434 connectable->remove_from_registry = ags_recycling_remove_from_registry;
435
436 connectable->list_resource = ags_recycling_list_resource;
437 connectable->xml_compose = ags_recycling_xml_compose;
438 connectable->xml_parse = ags_recycling_xml_parse;
439
440 connectable->is_connected = ags_recycling_is_connected;
441 connectable->connect = ags_recycling_connect;
442 connectable->disconnect = ags_recycling_disconnect;
443
444 connectable->connect_connection = NULL;
445 connectable->disconnect_connection = NULL;
446 }
447
448 void
ags_recycling_init(AgsRecycling * recycling)449 ags_recycling_init(AgsRecycling *recycling)
450 {
451 AgsAudioSignal *audio_signal;
452
453 AgsConfig *config;
454
455 gchar *str;
456 gchar *str0, *str1;
457
458 recycling->flags = 0;
459
460 /* add recycling mutex */
461 g_rec_mutex_init(&(recycling->obj_mutex));
462
463 /* uuid */
464 recycling->uuid = ags_uuid_alloc();
465 ags_uuid_generate(recycling->uuid);
466
467 /* config */
468 config = ags_config_get_instance();
469
470 /* base init */
471 recycling->channel = NULL;
472
473 recycling->output_soundcard = NULL;
474 recycling->output_soundcard_channel = 0;
475
476 recycling->input_soundcard = NULL;
477 recycling->input_soundcard_channel = 0;
478
479 /* presets */
480 recycling->samplerate = ags_soundcard_helper_config_get_samplerate(config);
481 recycling->buffer_size = ags_soundcard_helper_config_get_buffer_size(config);
482 recycling->format = ags_soundcard_helper_config_get_format(config);
483
484 /* nested tree */
485 recycling->parent = NULL;
486
487 recycling->next = NULL;
488 recycling->prev = NULL;
489
490 /* audio signal */
491 audio_signal = ags_audio_signal_new(NULL,
492 (GObject *) recycling,
493 NULL);
494 audio_signal->flags |= AGS_AUDIO_SIGNAL_TEMPLATE;
495
496 recycling->audio_signal = g_list_alloc();
497 recycling->audio_signal->data = audio_signal;
498 }
499
500 void
ags_recycling_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)501 ags_recycling_set_property(GObject *gobject,
502 guint prop_id,
503 const GValue *value,
504 GParamSpec *param_spec)
505 {
506 AgsRecycling *recycling;
507
508 GRecMutex *recycling_mutex;
509
510 recycling = AGS_RECYCLING(gobject);
511
512 /* get recycling mutex */
513 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
514
515 switch(prop_id){
516 case PROP_CHANNEL:
517 {
518 AgsChannel *channel;
519
520 channel = (AgsChannel *) g_value_get_object(value);
521
522 g_rec_mutex_lock(recycling_mutex);
523
524 if(recycling->channel == (GObject *) channel){
525 g_rec_mutex_unlock(recycling_mutex);
526
527 return;
528 }
529
530 if(recycling->channel != NULL){
531 g_object_unref(recycling->channel);
532 }
533
534 if(channel != NULL){
535 g_object_ref(channel);
536 }
537
538 recycling->channel = (GObject *) channel;
539
540 g_rec_mutex_unlock(recycling_mutex);
541 }
542 break;
543 case PROP_OUTPUT_SOUNDCARD:
544 {
545 GObject *soundcard;
546
547 soundcard = (GObject *) g_value_get_object(value);
548
549 ags_recycling_real_set_output_soundcard(recycling, (GObject *) soundcard);
550 }
551 break;
552 case PROP_OUTPUT_SOUNDCARD_CHANNEL:
553 {
554 g_rec_mutex_lock(recycling_mutex);
555
556 recycling->output_soundcard_channel = g_value_get_int(value);
557
558 g_rec_mutex_unlock(recycling_mutex);
559 }
560 break;
561 case PROP_INPUT_SOUNDCARD:
562 {
563 GObject *soundcard;
564
565 soundcard = (GObject *) g_value_get_object(value);
566
567 ags_recycling_real_set_input_soundcard(recycling, (GObject *) soundcard);
568 }
569 break;
570 case PROP_INPUT_SOUNDCARD_CHANNEL:
571 {
572 g_rec_mutex_lock(recycling_mutex);
573
574 recycling->input_soundcard_channel = g_value_get_int(value);
575
576 g_rec_mutex_unlock(recycling_mutex);
577 }
578 break;
579 case PROP_SAMPLERATE:
580 {
581 guint samplerate;
582
583 samplerate = g_value_get_uint(value);
584
585 ags_recycling_set_samplerate(recycling,
586 samplerate);
587 }
588 break;
589 case PROP_BUFFER_SIZE:
590 {
591 guint buffer_size;
592
593 buffer_size = g_value_get_uint(value);
594
595 ags_recycling_set_buffer_size(recycling,
596 buffer_size);
597 }
598 break;
599 case PROP_FORMAT:
600 {
601 guint format;
602
603 format = g_value_get_uint(value);
604
605 ags_recycling_set_format(recycling,
606 format);
607 }
608 break;
609 case PROP_PARENT:
610 {
611 AgsRecycling *parent;
612
613 parent = (AgsRecycling *) g_value_get_object(value);
614
615 g_rec_mutex_lock(recycling_mutex);
616
617 if(recycling->parent == parent){
618 g_rec_mutex_unlock(recycling_mutex);
619
620 return;
621 }
622
623 if(recycling->parent != NULL){
624 g_object_unref(recycling->parent);
625 }
626
627 if(parent != NULL){
628 g_object_ref(parent);
629 }
630
631 recycling->parent = parent;
632
633 g_rec_mutex_unlock(recycling_mutex);
634 }
635 break;
636 case PROP_NEXT:
637 {
638 AgsRecycling *next;
639
640 next = (AgsRecycling *) g_value_get_object(value);
641
642 g_rec_mutex_lock(recycling_mutex);
643
644 if(recycling->next == next){
645 g_rec_mutex_unlock(recycling_mutex);
646
647 return;
648 }
649
650 if(recycling->next != NULL){
651 g_object_unref(recycling->next);
652 }
653
654 if(next != NULL){
655 g_object_ref(next);
656 }
657
658 recycling->next = next;
659
660 g_rec_mutex_unlock(recycling_mutex);
661 }
662 break;
663 case PROP_PREV:
664 {
665 AgsRecycling *prev;
666
667 prev = (AgsRecycling *) g_value_get_object(value);
668
669 g_rec_mutex_lock(recycling_mutex);
670
671 if(recycling->prev == prev){
672 g_rec_mutex_unlock(recycling_mutex);
673
674 return;
675 }
676
677 if(recycling->prev != NULL){
678 g_object_unref(recycling->prev);
679 }
680
681 if(prev != NULL){
682 g_object_ref(prev);
683 }
684
685 recycling->prev = prev;
686
687 g_rec_mutex_unlock(recycling_mutex);
688 }
689 break;
690 case PROP_AUDIO_SIGNAL:
691 {
692 AgsAudioSignal *audio_signal;
693
694 audio_signal = g_value_get_pointer(value);
695
696 ags_recycling_add_audio_signal(recycling,
697 audio_signal);
698 }
699 break;
700 default:
701 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
702 break;
703 }
704 }
705
706 void
ags_recycling_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)707 ags_recycling_get_property(GObject *gobject,
708 guint prop_id,
709 GValue *value,
710 GParamSpec *param_spec)
711 {
712 AgsRecycling *recycling;
713
714 GRecMutex *recycling_mutex;
715
716 recycling = AGS_RECYCLING(gobject);
717
718 /* get recycling mutex */
719 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
720
721 switch(prop_id){
722 case PROP_CHANNEL:
723 {
724 g_rec_mutex_lock(recycling_mutex);
725
726 g_value_set_object(value, recycling->channel);
727
728 g_rec_mutex_unlock(recycling_mutex);
729 }
730 break;
731 case PROP_OUTPUT_SOUNDCARD:
732 {
733 g_rec_mutex_lock(recycling_mutex);
734
735 g_value_set_object(value, recycling->output_soundcard);
736
737 g_rec_mutex_unlock(recycling_mutex);
738 }
739 break;
740 case PROP_OUTPUT_SOUNDCARD_CHANNEL:
741 {
742 g_rec_mutex_lock(recycling_mutex);
743
744 g_value_set_int(value, recycling->output_soundcard_channel);
745
746 g_rec_mutex_unlock(recycling_mutex);
747 }
748 break;
749 case PROP_INPUT_SOUNDCARD:
750 {
751 g_rec_mutex_lock(recycling_mutex);
752
753 g_value_set_object(value, recycling->input_soundcard);
754
755 g_rec_mutex_unlock(recycling_mutex);
756 }
757 break;
758 case PROP_INPUT_SOUNDCARD_CHANNEL:
759 {
760 g_rec_mutex_lock(recycling_mutex);
761
762 g_value_set_int(value, recycling->input_soundcard_channel);
763
764 g_rec_mutex_unlock(recycling_mutex);
765 }
766 break;
767 case PROP_SAMPLERATE:
768 {
769 g_rec_mutex_lock(recycling_mutex);
770
771 g_value_set_uint(value, recycling->samplerate);
772
773 g_rec_mutex_unlock(recycling_mutex);
774 }
775 break;
776 case PROP_BUFFER_SIZE:
777 {
778 g_rec_mutex_lock(recycling_mutex);
779
780 g_value_set_uint(value, recycling->buffer_size);
781
782 g_rec_mutex_unlock(recycling_mutex);
783 }
784 break;
785 case PROP_FORMAT:
786 {
787 g_rec_mutex_lock(recycling_mutex);
788
789 g_value_set_uint(value, recycling->format);
790
791 g_rec_mutex_unlock(recycling_mutex);
792 }
793 break;
794 case PROP_PARENT:
795 {
796 g_rec_mutex_lock(recycling_mutex);
797
798 g_value_set_object(value, recycling->parent);
799
800 g_rec_mutex_unlock(recycling_mutex);
801 }
802 break;
803 case PROP_NEXT:
804 {
805 g_rec_mutex_lock(recycling_mutex);
806
807 g_value_set_object(value, recycling->next);
808
809 g_rec_mutex_unlock(recycling_mutex);
810 }
811 break;
812 case PROP_PREV:
813 {
814 g_rec_mutex_lock(recycling_mutex);
815
816 g_value_set_object(value, recycling->prev);
817
818 g_rec_mutex_unlock(recycling_mutex);
819 }
820 break;
821 case PROP_AUDIO_SIGNAL:
822 {
823 g_rec_mutex_lock(recycling_mutex);
824
825 g_value_set_pointer(value, g_list_copy_deep(recycling->audio_signal,
826 (GCopyFunc) g_object_ref,
827 NULL));
828
829 g_rec_mutex_unlock(recycling_mutex);
830 }
831 break;
832 default:
833 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
834 break;
835 }
836 }
837
838 void
ags_recycling_dispose(GObject * gobject)839 ags_recycling_dispose(GObject *gobject)
840 {
841 AgsRecycling *recycling;
842
843 GList *start_list, *list;
844
845 GRecMutex *recycling_mutex;
846
847 recycling = AGS_RECYCLING(gobject);
848
849 /* get recycling mutex */
850 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
851
852 g_rec_mutex_lock(recycling_mutex);
853
854 /* channel */
855 if(recycling->channel != NULL){
856 AgsChannel *channel;
857
858 channel = recycling->channel;
859
860 recycling->channel = NULL;
861
862 g_object_unref(channel);
863 }
864
865 /* output soundcard */
866 if(recycling->output_soundcard != NULL){
867 g_object_unref(recycling->output_soundcard);
868
869 recycling->output_soundcard = NULL;
870 }
871
872 /* input soundcard */
873 if(recycling->input_soundcard != NULL){
874 g_object_unref(recycling->input_soundcard);
875
876 recycling->input_soundcard = NULL;
877 }
878
879 /* parent */
880 if(recycling->parent != NULL){
881 g_object_unref(recycling->parent);
882
883 recycling->parent = NULL;
884 }
885
886 /* next and prev */
887 if(recycling->next != NULL){
888 g_object_unref(recycling->next);
889
890 recycling->next = NULL;
891 }
892
893 if(recycling->prev != NULL){
894 g_object_unref(recycling->prev);
895
896 recycling->prev = NULL;
897 }
898
899 g_rec_mutex_unlock(recycling_mutex);
900
901 /* AgsAudioSignal */
902 g_rec_mutex_lock(recycling_mutex);
903
904 list =
905 start_list = recycling->audio_signal;
906
907 recycling->audio_signal = NULL;
908
909 g_rec_mutex_unlock(recycling_mutex);
910
911 while(list != NULL){
912 g_object_run_dispose(list->data);
913
914 list = list->next;
915 }
916
917 g_list_free_full(start_list,
918 g_object_unref);
919
920 /* call parent */
921 G_OBJECT_CLASS(ags_recycling_parent_class)->dispose(gobject);
922 }
923
924 void
ags_recycling_finalize(GObject * gobject)925 ags_recycling_finalize(GObject *gobject)
926 {
927 AgsRecycling *recycling;
928
929 GList *start_list, *list;
930
931 recycling = AGS_RECYCLING(gobject);
932
933 ags_uuid_free(recycling->uuid);
934
935 /* channel */
936 if(recycling->channel != NULL){
937 g_object_unref(recycling->channel);
938 }
939
940 /* output soundcard */
941 if(recycling->output_soundcard != NULL){
942 g_object_unref(recycling->output_soundcard);
943 }
944
945 /* input soundcard */
946 if(recycling->input_soundcard != NULL){
947 g_object_unref(recycling->input_soundcard);
948 }
949
950 /* parent */
951 if(recycling->parent != NULL){
952 g_object_unref(recycling->parent);
953 }
954
955 /* next and prev */
956 if(recycling->next != NULL){
957 g_object_unref(recycling->next);
958 }
959
960 if(recycling->prev != NULL){
961 g_object_unref(recycling->prev);
962 }
963
964 /* AgsAudioSignal */
965 list =
966 start_list = recycling->audio_signal;
967
968 while(list != NULL){
969 g_object_run_dispose(list->data);
970
971 list = list->next;
972 }
973
974 g_list_free_full(start_list,
975 g_object_unref);
976
977 /* call parent */
978 G_OBJECT_CLASS(ags_recycling_parent_class)->finalize(gobject);
979 }
980
981 AgsUUID*
ags_recycling_get_uuid(AgsConnectable * connectable)982 ags_recycling_get_uuid(AgsConnectable *connectable)
983 {
984 AgsRecycling *recycling;
985
986 AgsUUID *ptr;
987
988 GRecMutex *recycling_mutex;
989
990 recycling = AGS_RECYCLING(connectable);
991
992 /* get recycling signal mutex */
993 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
994
995 /* get UUID */
996 g_rec_mutex_lock(recycling_mutex);
997
998 ptr = recycling->uuid;
999
1000 g_rec_mutex_unlock(recycling_mutex);
1001
1002 return(ptr);
1003 }
1004
1005 gboolean
ags_recycling_has_resource(AgsConnectable * connectable)1006 ags_recycling_has_resource(AgsConnectable *connectable)
1007 {
1008 return(TRUE);
1009 }
1010
1011 gboolean
ags_recycling_is_ready(AgsConnectable * connectable)1012 ags_recycling_is_ready(AgsConnectable *connectable)
1013 {
1014 AgsRecycling *recycling;
1015
1016 gboolean is_ready;
1017
1018 recycling = AGS_RECYCLING(connectable);
1019
1020 is_ready = ags_recycling_test_flags(recycling, AGS_RECYCLING_ADDED_TO_REGISTRY);
1021
1022 return(is_ready);
1023 }
1024
1025 void
ags_recycling_add_to_registry(AgsConnectable * connectable)1026 ags_recycling_add_to_registry(AgsConnectable *connectable)
1027 {
1028 AgsRecycling *recycling;
1029
1030 AgsRegistry *registry;
1031 AgsRegistryEntry *entry;
1032
1033 AgsApplicationContext *application_context;
1034
1035 GList *start_list, *list;
1036
1037 if(ags_connectable_is_ready(connectable)){
1038 return;
1039 }
1040
1041 recycling = AGS_RECYCLING(connectable);
1042
1043 application_context = ags_application_context_get_instance();
1044
1045 ags_recycling_set_flags(recycling, AGS_RECYCLING_ADDED_TO_REGISTRY);
1046
1047 registry = (AgsRegistry *) ags_service_provider_get_registry(AGS_SERVICE_PROVIDER(application_context));
1048
1049 if(registry != NULL){
1050 entry = ags_registry_entry_alloc(registry);
1051 g_value_set_object(entry->entry,
1052 (gpointer) recycling);
1053 ags_registry_add_entry(registry,
1054 entry);
1055 }
1056
1057 /* add audio signal */
1058 g_object_get(recycling,
1059 "audio-signal", &start_list,
1060 NULL);
1061
1062 list = start_list;
1063
1064 while(list != NULL){
1065 ags_connectable_add_to_registry(AGS_CONNECTABLE(list->data));
1066
1067 list = list->next;
1068 }
1069
1070 g_list_free_full(start_list,
1071 g_object_unref);
1072 }
1073
1074 void
ags_recycling_remove_from_registry(AgsConnectable * connectable)1075 ags_recycling_remove_from_registry(AgsConnectable *connectable)
1076 {
1077 if(!ags_connectable_is_ready(connectable)){
1078 return;
1079 }
1080
1081 //TODO:JK: implement me
1082 }
1083
1084 xmlNode*
ags_recycling_list_resource(AgsConnectable * connectable)1085 ags_recycling_list_resource(AgsConnectable *connectable)
1086 {
1087 xmlNode *node;
1088
1089 node = NULL;
1090
1091 //TODO:JK: implement me
1092
1093 return(node);
1094 }
1095
1096 xmlNode*
ags_recycling_xml_compose(AgsConnectable * connectable)1097 ags_recycling_xml_compose(AgsConnectable *connectable)
1098 {
1099 xmlNode *node;
1100
1101 node = NULL;
1102
1103 //TODO:JK: implement me
1104
1105 return(node);
1106 }
1107
1108 void
ags_recycling_xml_parse(AgsConnectable * connectable,xmlNode * node)1109 ags_recycling_xml_parse(AgsConnectable *connectable,
1110 xmlNode *node)
1111 {
1112 //TODO:JK: implement me
1113 }
1114
1115 gboolean
ags_recycling_is_connected(AgsConnectable * connectable)1116 ags_recycling_is_connected(AgsConnectable *connectable)
1117 {
1118 AgsRecycling *recycling;
1119
1120 gboolean is_connected;
1121
1122 recycling = AGS_RECYCLING(connectable);
1123
1124 is_connected = ags_recycling_test_flags(recycling, AGS_RECYCLING_CONNECTED);
1125
1126 return(is_connected);
1127 }
1128
1129 void
ags_recycling_connect(AgsConnectable * connectable)1130 ags_recycling_connect(AgsConnectable *connectable)
1131 {
1132 AgsRecycling *recycling;
1133
1134 GList *start_list, *list;
1135
1136 if(ags_connectable_is_connected(connectable)){
1137 return;
1138 }
1139
1140 recycling = AGS_RECYCLING(connectable);
1141
1142 ags_recycling_set_flags(recycling, AGS_RECYCLING_CONNECTED);
1143
1144 #ifdef AGS_DEBUG
1145 g_message("connecting recycling");
1146 #endif
1147
1148 /* audio signal */
1149 g_object_get(recycling,
1150 "audio-signal", &start_list,
1151 NULL);
1152
1153 list = start_list;
1154
1155 while(list != NULL){
1156 ags_connectable_connect(AGS_CONNECTABLE(list->data));
1157
1158 list = list->next;
1159 }
1160
1161 g_list_free_full(start_list,
1162 g_object_unref);
1163 }
1164
1165 void
ags_recycling_disconnect(AgsConnectable * connectable)1166 ags_recycling_disconnect(AgsConnectable *connectable)
1167 {
1168 AgsRecycling *recycling;
1169
1170 GList *start_list, *list;
1171
1172 if(!ags_connectable_is_connected(connectable)){
1173 return;
1174 }
1175
1176 recycling = AGS_RECYCLING(connectable);
1177
1178 ags_recycling_unset_flags(recycling, AGS_RECYCLING_CONNECTED);
1179
1180 #ifdef AGS_DEBUG
1181 g_message("disconnecting recycling");
1182 #endif
1183
1184 /* audio signal */
1185 g_object_get(recycling,
1186 "audio-signal", &start_list,
1187 NULL);
1188
1189 list = start_list;
1190
1191 while(list != NULL){
1192 ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
1193
1194 list = list->next;
1195 }
1196
1197 g_list_free_full(start_list,
1198 g_object_unref);
1199 }
1200
1201 /**
1202 * ags_recycling_get_obj_mutex:
1203 * @recycling: the #AgsRecycling
1204 *
1205 * Get object mutex.
1206 *
1207 * Returns: the #GRecMutex to lock @recycling
1208 *
1209 * Since: 3.1.0
1210 */
1211 GRecMutex*
ags_recycling_get_obj_mutex(AgsRecycling * recycling)1212 ags_recycling_get_obj_mutex(AgsRecycling *recycling)
1213 {
1214 if(!AGS_IS_RECYCLING(recycling)){
1215 return(NULL);
1216 }
1217
1218 return(AGS_RECYCLING_GET_OBJ_MUTEX(recycling));
1219 }
1220
1221 /**
1222 * ags_recycling_test_flags:
1223 * @recycling: the #AgsRecycling
1224 * @flags: the flags
1225 *
1226 * Test @flags to be set on @recycling.
1227 *
1228 * Returns: %TRUE if flags are set, else %FALSE
1229 *
1230 * Since: 3.0.0
1231 */
1232 gboolean
ags_recycling_test_flags(AgsRecycling * recycling,guint flags)1233 ags_recycling_test_flags(AgsRecycling *recycling, guint flags)
1234 {
1235 gboolean retval;
1236
1237 GRecMutex *recycling_mutex;
1238
1239 if(!AGS_IS_RECYCLING(recycling)){
1240 return(FALSE);
1241 }
1242
1243 /* get recycling mutex */
1244 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1245
1246 /* test */
1247 g_rec_mutex_lock(recycling_mutex);
1248
1249 retval = (flags & (recycling->flags)) ? TRUE: FALSE;
1250
1251 g_rec_mutex_unlock(recycling_mutex);
1252
1253 return(retval);
1254 }
1255
1256 /**
1257 * ags_recycling_set_flags:
1258 * @recycling: the #AgsRecycling
1259 * @flags: see #AgsRecyclingFlags-enum
1260 *
1261 * Enable a feature of @recycling.
1262 *
1263 * Since: 3.0.0
1264 */
1265 void
ags_recycling_set_flags(AgsRecycling * recycling,guint flags)1266 ags_recycling_set_flags(AgsRecycling *recycling, guint flags)
1267 {
1268 GRecMutex *recycling_mutex;
1269
1270 if(!AGS_IS_RECYCLING(recycling)){
1271 return;
1272 }
1273
1274 /* get recycling mutex */
1275 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1276
1277 //TODO:JK: add more?
1278
1279 /* set flags */
1280 g_rec_mutex_lock(recycling_mutex);
1281
1282 recycling->flags |= flags;
1283
1284 g_rec_mutex_unlock(recycling_mutex);
1285 }
1286
1287 /**
1288 * ags_recycling_unset_flags:
1289 * @recycling: the #AgsRecycling
1290 * @flags: see #AgsRecyclingFlags-enum
1291 *
1292 * Disable a feature of @recycling.
1293 *
1294 * Since: 3.0.0
1295 */
1296 void
ags_recycling_unset_flags(AgsRecycling * recycling,guint flags)1297 ags_recycling_unset_flags(AgsRecycling *recycling, guint flags)
1298 {
1299 GRecMutex *recycling_mutex;
1300
1301 if(!AGS_IS_RECYCLING(recycling)){
1302 return;
1303 }
1304
1305 /* get recycling mutex */
1306 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1307
1308 //TODO:JK: add more?
1309
1310 /* unset flags */
1311 g_rec_mutex_lock(recycling_mutex);
1312
1313 recycling->flags &= (~flags);
1314
1315 g_rec_mutex_unlock(recycling_mutex);
1316 }
1317
1318 /**
1319 * ags_recycling_get_channel:
1320 * @recycling: the #AgsRecycling
1321 *
1322 * Get channel.
1323 *
1324 * Returns: (transfer full): the #AgsChannel
1325 *
1326 * Since: 3.1.0
1327 */
1328 GObject*
ags_recycling_get_channel(AgsRecycling * recycling)1329 ags_recycling_get_channel(AgsRecycling *recycling)
1330 {
1331 GObject *channel;
1332
1333 if(!AGS_IS_RECYCLING(recycling)){
1334 return(NULL);
1335 }
1336
1337 g_object_get(recycling,
1338 "channel", &channel,
1339 NULL);
1340
1341 return(channel);
1342 }
1343
1344 /**
1345 * ags_recycling_set_channel:
1346 * @recycling: the #AgsRecycling
1347 * @channel: the #AgsChannel
1348 *
1349 * Set channel.
1350 *
1351 * Since: 3.1.0
1352 */
1353 void
ags_recycling_set_channel(AgsRecycling * recycling,GObject * channel)1354 ags_recycling_set_channel(AgsRecycling *recycling, GObject *channel)
1355 {
1356 if(!AGS_IS_RECYCLING(recycling)){
1357 return;
1358 }
1359
1360 g_object_set(recycling,
1361 "channel", channel,
1362 NULL);
1363 }
1364
1365 /**
1366 * ags_recycling_next:
1367 * @recycling: the #AgsRecycling
1368 *
1369 * Iterate @recycling.
1370 *
1371 * Returns: (transfer full): the next of #AgsRecycling if available, otherwise %NULL
1372 *
1373 * Since: 3.0.0
1374 */
1375 AgsRecycling*
ags_recycling_next(AgsRecycling * recycling)1376 ags_recycling_next(AgsRecycling *recycling)
1377 {
1378 AgsRecycling *next;
1379
1380 GRecMutex *recycling_mutex;
1381
1382 if(!AGS_IS_RECYCLING(recycling)){
1383 return(NULL);
1384 }
1385
1386 /* get recycling mutex */
1387 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1388
1389 /* next */
1390 g_rec_mutex_lock(recycling_mutex);
1391
1392 next = recycling->next;
1393
1394 if(next != NULL){
1395 g_object_ref(next);
1396 }
1397
1398 g_rec_mutex_unlock(recycling_mutex);
1399
1400 return(next);
1401 }
1402
1403 /**
1404 * ags_recycling_prev:
1405 * @recycling: the #AgsRecycling
1406 *
1407 * Iterate @recycling.
1408 *
1409 * Returns: (transfer full): the prev of #AgsRecycling if available, otherwise %NULL
1410 *
1411 * Since: 3.0.0
1412 */
1413 AgsRecycling*
ags_recycling_prev(AgsRecycling * recycling)1414 ags_recycling_prev(AgsRecycling *recycling)
1415 {
1416 AgsRecycling *prev;
1417
1418 GRecMutex *recycling_mutex;
1419
1420 if(!AGS_IS_RECYCLING(recycling)){
1421 return(NULL);
1422 }
1423
1424 /* get recycling mutex */
1425 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1426
1427 /* prev */
1428 g_rec_mutex_lock(recycling_mutex);
1429
1430 prev = recycling->prev;
1431
1432 if(prev != NULL){
1433 g_object_ref(prev);
1434 }
1435
1436 g_rec_mutex_unlock(recycling_mutex);
1437
1438 return(prev);
1439 }
1440
1441 /**
1442 * ags_recycling_get_output_soundcard:
1443 * @recycling: the #AgsRecycling
1444 *
1445 * Get the output soundcard object of @recycling.
1446 *
1447 * Returns: (transfer full): the output soundcard
1448 *
1449 * Since: 3.1.0
1450 */
1451 GObject*
ags_recycling_get_output_soundcard(AgsRecycling * recycling)1452 ags_recycling_get_output_soundcard(AgsRecycling *recycling)
1453 {
1454 GObject *output_soundcard;
1455
1456 if(!AGS_IS_RECYCLING(recycling)){
1457 return(NULL);
1458 }
1459
1460 g_object_get(recycling,
1461 "output-soundcard", &output_soundcard,
1462 NULL);
1463
1464 return(output_soundcard);
1465 }
1466
1467 void
ags_recycling_real_set_output_soundcard(AgsRecycling * recycling,GObject * output_soundcard)1468 ags_recycling_real_set_output_soundcard(AgsRecycling *recycling, GObject *output_soundcard)
1469 {
1470 GList *start_list, *list;
1471
1472 GRecMutex *recycling_mutex;
1473
1474 if(!AGS_IS_RECYCLING(recycling)){
1475 return;
1476 }
1477
1478 /* get recycling mutex */
1479 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1480
1481 /* recycling */
1482 g_rec_mutex_lock(recycling_mutex);
1483
1484 if(recycling->output_soundcard == output_soundcard){
1485 g_rec_mutex_unlock(recycling_mutex);
1486
1487 return;
1488 }
1489
1490 if(recycling->output_soundcard != NULL){
1491 g_object_unref(recycling->output_soundcard);
1492 }
1493
1494 if(output_soundcard != NULL){
1495 g_object_ref(output_soundcard);
1496 }
1497
1498 recycling->output_soundcard = (GObject *) output_soundcard;
1499
1500 g_rec_mutex_unlock(recycling_mutex);
1501
1502 /* audio signal */
1503 g_object_get(recycling,
1504 "audio-signal", &start_list,
1505 NULL);
1506
1507 list = start_list;
1508
1509 while(list != NULL){
1510 g_object_set(list->data,
1511 "output-soundcard", output_soundcard,
1512 NULL);
1513
1514 list = list->next;
1515 }
1516
1517 g_list_free_full(start_list,
1518 g_object_unref);
1519 }
1520
1521 /**
1522 * ags_recycling_set_output_soundcard:
1523 * @recycling: the #AgsRecycling
1524 * @output_soundcard: the #GObject implementing #AgsSoundcard
1525 *
1526 * Set the output soundcard object of @recycling.
1527 *
1528 * Since: 3.0.0
1529 */
1530 void
ags_recycling_set_output_soundcard(AgsRecycling * recycling,GObject * output_soundcard)1531 ags_recycling_set_output_soundcard(AgsRecycling *recycling, GObject *output_soundcard)
1532 {
1533 if(!AGS_IS_RECYCLING(recycling)){
1534 return;
1535 }
1536
1537 g_object_set(recycling,
1538 "output-soundcard", output_soundcard,
1539 NULL);
1540 }
1541
1542 /**
1543 * ags_recycling_get_input_soundcard:
1544 * @recycling: the #AgsRecycling
1545 *
1546 * Get the input soundcard object of @recycling.
1547 *
1548 * Returns: (transfer full): the input soundcard
1549 *
1550 * Since: 3.1.0
1551 */
1552 GObject*
ags_recycling_get_input_soundcard(AgsRecycling * recycling)1553 ags_recycling_get_input_soundcard(AgsRecycling *recycling)
1554 {
1555 GObject *input_soundcard;
1556
1557 if(!AGS_IS_RECYCLING(recycling)){
1558 return(NULL);
1559 }
1560
1561 g_object_get(recycling,
1562 "input-soundcard", &input_soundcard,
1563 NULL);
1564
1565 return(input_soundcard);
1566 }
1567
1568 void
ags_recycling_real_set_input_soundcard(AgsRecycling * recycling,GObject * input_soundcard)1569 ags_recycling_real_set_input_soundcard(AgsRecycling *recycling, GObject *input_soundcard)
1570 {
1571 GList *start_list, *list;
1572
1573 GRecMutex *recycling_mutex;
1574
1575 if(!AGS_IS_RECYCLING(recycling)){
1576 return;
1577 }
1578
1579 /* get recycling mutex */
1580 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1581
1582 /* recycling */
1583 g_rec_mutex_lock(recycling_mutex);
1584
1585 if(recycling->input_soundcard == input_soundcard){
1586 g_rec_mutex_unlock(recycling_mutex);
1587
1588 return;
1589 }
1590
1591 if(recycling->input_soundcard != NULL){
1592 g_object_unref(recycling->input_soundcard);
1593 }
1594
1595 if(input_soundcard != NULL){
1596 g_object_ref(input_soundcard);
1597 }
1598
1599 recycling->input_soundcard = (GObject *) input_soundcard;
1600
1601 g_rec_mutex_unlock(recycling_mutex);
1602
1603 /* audio signal */
1604 g_object_get(recycling,
1605 "audio-signal", &start_list,
1606 NULL);
1607
1608 list = start_list;
1609
1610 while(list != NULL){
1611 g_object_set(list->data,
1612 "input-soundcard", input_soundcard,
1613 NULL);
1614
1615 list = list->next;
1616 }
1617
1618 g_list_free_full(start_list,
1619 g_object_unref);
1620 }
1621
1622 /**
1623 * ags_recycling_set_input_soundcard:
1624 * @recycling: an #AgsRecycling
1625 * @input_soundcard: the #GObject implementing #AgsSoundcard
1626 *
1627 * Set the input soundcard object of @recycling.
1628 *
1629 * Since: 3.0.0
1630 */
1631 void
ags_recycling_set_input_soundcard(AgsRecycling * recycling,GObject * input_soundcard)1632 ags_recycling_set_input_soundcard(AgsRecycling *recycling, GObject *input_soundcard)
1633 {
1634 if(!AGS_IS_RECYCLING(recycling)){
1635 return;
1636 }
1637
1638 g_object_set(recycling,
1639 "input-soundcard", input_soundcard,
1640 NULL);
1641 }
1642
1643 /**
1644 * ags_recycling_get_samplerate:
1645 * @recycling: the #AgsRecycling
1646 *
1647 * Gets samplerate.
1648 *
1649 * Returns: the samplerate
1650 *
1651 * Since: 3.1.0
1652 */
1653 guint
ags_recycling_get_samplerate(AgsRecycling * recycling)1654 ags_recycling_get_samplerate(AgsRecycling *recycling)
1655 {
1656 guint samplerate;
1657
1658 if(!AGS_IS_RECYCLING(recycling)){
1659 return(0);
1660 }
1661
1662 g_object_get(recycling,
1663 "samplerate", &samplerate,
1664 NULL);
1665
1666 return(samplerate);
1667 }
1668
1669 /**
1670 * ags_recycling_set_samplerate:
1671 * @recycling: the #AgsRecycling
1672 * @samplerate: the samplerate
1673 *
1674 * Sets samplerate.
1675 *
1676 * Since: 3.0.0
1677 */
1678 void
ags_recycling_set_samplerate(AgsRecycling * recycling,guint samplerate)1679 ags_recycling_set_samplerate(AgsRecycling *recycling, guint samplerate)
1680 {
1681 AgsAudioSignal *template;
1682
1683 GList *audio_signal;
1684 GList *start_rt_template, *rt_template;
1685
1686 GRecMutex *recycling_mutex;
1687
1688 if(!AGS_IS_RECYCLING(recycling)){
1689 return;
1690 }
1691
1692 /* get recycling mutex */
1693 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1694
1695 /* get audio signal */
1696 g_object_get(recycling,
1697 "audio-signal", &audio_signal,
1698 NULL);
1699
1700 /* get template */
1701 template = ags_audio_signal_get_template(audio_signal);
1702
1703 if(template != NULL){
1704 g_object_set(template,
1705 "samplerate", samplerate,
1706 NULL);
1707 }
1708
1709 g_object_unref(template);
1710
1711 /* get rt-template */
1712 rt_template =
1713 start_rt_template = ags_audio_signal_get_rt_template(audio_signal);
1714
1715 while(rt_template != NULL){
1716 g_object_set(rt_template->data,
1717 "samplerate", samplerate,
1718 NULL);
1719
1720 rt_template = rt_template->next;
1721 }
1722
1723 g_list_free_full(start_rt_template,
1724 g_object_unref);
1725
1726 /* free list */
1727 g_list_free_full(audio_signal,
1728 g_object_unref);
1729 }
1730
1731 /**
1732 * ags_recycling_get_buffer_size:
1733 * @recycling: the #AgsRecycling
1734 *
1735 * Gets buffer size.
1736 *
1737 * Returns: the buffer size
1738 *
1739 * Since: 3.1.0
1740 */
1741 guint
ags_recycling_get_buffer_size(AgsRecycling * recycling)1742 ags_recycling_get_buffer_size(AgsRecycling *recycling)
1743 {
1744 guint buffer_size;
1745
1746 if(!AGS_IS_RECYCLING(recycling)){
1747 return(0);
1748 }
1749
1750 g_object_get(recycling,
1751 "buffer-size", &buffer_size,
1752 NULL);
1753
1754 return(buffer_size);
1755 }
1756
1757 /**
1758 * ags_recycling_set_buffer_size:
1759 * @recycling: the #AgsRecycling
1760 * @buffer_size: the buffer size
1761 *
1762 * Set buffer size.
1763 *
1764 * Since: 3.0.0
1765 */
1766 void
ags_recycling_set_buffer_size(AgsRecycling * recycling,guint buffer_size)1767 ags_recycling_set_buffer_size(AgsRecycling *recycling, guint buffer_size)
1768 {
1769 AgsAudioSignal *template;
1770
1771 GList *audio_signal;
1772 GList *start_rt_template, *rt_template;
1773
1774 GRecMutex *recycling_mutex;
1775
1776 if(!AGS_IS_RECYCLING(recycling)){
1777 return;
1778 }
1779
1780 /* get recycling mutex */
1781 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1782
1783 /* get audio signal */
1784 g_object_get(recycling,
1785 "audio-signal", &audio_signal,
1786 NULL);
1787
1788 /* get template */
1789 template = ags_audio_signal_get_template(audio_signal);
1790
1791 if(template != NULL){
1792 g_object_set(template,
1793 "buffer-size", buffer_size,
1794 NULL);
1795 }
1796
1797 g_object_unref(template);
1798
1799 /* get rt-template */
1800 rt_template =
1801 start_rt_template = ags_audio_signal_get_rt_template(audio_signal);
1802
1803 while(rt_template != NULL){
1804 g_object_set(rt_template->data,
1805 "buffer-size", buffer_size,
1806 NULL);
1807
1808 rt_template = rt_template->next;
1809 }
1810
1811 g_list_free_full(start_rt_template,
1812 g_object_unref);
1813
1814 /* free list */
1815 g_list_free_full(audio_signal,
1816 g_object_unref);
1817 }
1818
1819 /**
1820 * ags_recycling_get_format:
1821 * @recycling: the #AgsRecycling
1822 *
1823 * Gets format.
1824 *
1825 * Returns: the format
1826 *
1827 * Since: 3.1.0
1828 */
1829 guint
ags_recycling_get_format(AgsRecycling * recycling)1830 ags_recycling_get_format(AgsRecycling *recycling)
1831 {
1832 guint format;
1833
1834 if(!AGS_IS_RECYCLING(recycling)){
1835 return(0);
1836 }
1837
1838 g_object_get(recycling,
1839 "format", &format,
1840 NULL);
1841
1842 return(format);
1843 }
1844
1845 /**
1846 * ags_recycling_set_format:
1847 * @recycling: the #AgsRecycling
1848 * @format: the format
1849 *
1850 * Set format.
1851 *
1852 * Since: 3.0.0
1853 */
1854 void
ags_recycling_set_format(AgsRecycling * recycling,guint format)1855 ags_recycling_set_format(AgsRecycling *recycling, guint format)
1856 {
1857 AgsAudioSignal *template;
1858
1859 GList *audio_signal;
1860 GList *start_rt_template, *rt_template;
1861
1862 GRecMutex *recycling_mutex;
1863
1864 if(!AGS_IS_RECYCLING(recycling)){
1865 return;
1866 }
1867
1868 /* get recycling mutex */
1869 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1870
1871 /* get audio signal */
1872 g_object_get(recycling,
1873 "audio-signal", &audio_signal,
1874 NULL);
1875
1876 /* get template */
1877 template = ags_audio_signal_get_template(audio_signal);
1878
1879 if(template != NULL){
1880 g_object_set(template,
1881 "format", format,
1882 NULL);
1883 }
1884
1885 g_object_unref(template);
1886
1887 /* get rt-template */
1888 rt_template =
1889 start_rt_template = ags_audio_signal_get_rt_template(audio_signal);
1890
1891 while(rt_template != NULL){
1892 g_object_set(rt_template->data,
1893 "format", format,
1894 NULL);
1895
1896 rt_template = rt_template->next;
1897 }
1898
1899 g_list_free_full(start_rt_template,
1900 g_object_unref);
1901
1902 /* free list */
1903 g_list_free_full(audio_signal,
1904 g_object_unref);
1905 }
1906
1907 /**
1908 * ags_recycling_get_audio_signal:
1909 * @recycling: the #AgsRecycling
1910 *
1911 * Get recall id.
1912 *
1913 * Returns: (element-type AgsAudio.AudioSignal) (transfer full): the #GList-struct containig #AgsAudioSignal
1914 *
1915 * Since: 3.1.0
1916 */
1917 GList*
ags_recycling_get_audio_signal(AgsRecycling * recycling)1918 ags_recycling_get_audio_signal(AgsRecycling *recycling)
1919 {
1920 GList *audio_signal;
1921
1922 if(!AGS_IS_RECYCLING(recycling)){
1923 return(NULL);
1924 }
1925
1926 g_object_get(recycling,
1927 "audio-signal", &audio_signal,
1928 NULL);
1929
1930 return(audio_signal);
1931 }
1932
1933 /**
1934 * ags_recycling_set_audio_signal:
1935 * @recycling: the #AgsRecycling
1936 * @audio_signal: (element-type AgsAudio.AudioSignal) (transfer full): the #GList-struct containing #AgsAudioSignal
1937 *
1938 * Set recall id by replacing existing.
1939 *
1940 * Since: 3.1.0
1941 */
1942 void
ags_recycling_set_audio_signal(AgsRecycling * recycling,GList * audio_signal)1943 ags_recycling_set_audio_signal(AgsRecycling *recycling, GList *audio_signal)
1944 {
1945 GList *start_audio_signal;
1946
1947 GRecMutex *recycling_mutex;
1948
1949 if(!AGS_IS_RECYCLING(recycling)){
1950 return;
1951 }
1952
1953 /* get recycling mutex */
1954 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1955
1956 g_rec_mutex_lock(recycling_mutex);
1957
1958 start_audio_signal = recycling->audio_signal;
1959
1960 recycling->audio_signal = audio_signal;
1961
1962 g_rec_mutex_unlock(recycling_mutex);
1963
1964 g_list_free_full(start_audio_signal,
1965 (GDestroyNotify) g_object_unref);
1966 }
1967
1968 void
ags_recycling_real_add_audio_signal(AgsRecycling * recycling,AgsAudioSignal * audio_signal)1969 ags_recycling_real_add_audio_signal(AgsRecycling *recycling,
1970 AgsAudioSignal *audio_signal)
1971 {
1972 AgsAudioSignal *old_template;
1973
1974 GObject *output_soundcard;
1975
1976 GHashTable *hash_table;
1977 GList *start_list, *list;
1978
1979 GRecMutex *recycling_mutex;
1980
1981 /* get recycling mutex */
1982 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1983
1984 /* get audio signal */
1985 g_rec_mutex_lock(recycling_mutex);
1986
1987 if(g_list_find(recycling->audio_signal,
1988 audio_signal) != NULL){
1989 g_rec_mutex_unlock(recycling_mutex);
1990
1991 return;
1992 }
1993
1994 output_soundcard = recycling->output_soundcard;
1995
1996 g_rec_mutex_unlock(recycling_mutex);
1997
1998 g_object_get(recycling,
1999 "audio-signal", &start_list,
2000 NULL);
2001
2002 /* get some fields */
2003 if(ags_audio_signal_test_flags(audio_signal, AGS_AUDIO_SIGNAL_TEMPLATE)){
2004 /* old template */
2005 old_template = ags_audio_signal_get_template(start_list);
2006
2007 /* remove old template */
2008 ags_recycling_remove_audio_signal(recycling,
2009 old_template);
2010
2011 g_object_unref(old_template);
2012
2013 /* add new template */
2014 g_rec_mutex_lock(recycling_mutex);
2015
2016 recycling->audio_signal = g_list_prepend(recycling->audio_signal,
2017 audio_signal);
2018 g_object_ref(audio_signal);
2019
2020 g_rec_mutex_unlock(recycling_mutex);
2021
2022 /* add/remove */
2023 list = start_list;
2024 hash_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
2025 NULL,
2026 NULL);
2027
2028 while(list != NULL){
2029 AgsAudioSignal *current_audio_signal;
2030 AgsAudioSignal *rt_template, *old_rt_template;
2031 AgsRecallID *current_recall_id;
2032
2033 current_audio_signal = list->data;
2034
2035 /* get some fields */
2036 if(ags_audio_signal_test_flags(current_audio_signal, AGS_AUDIO_SIGNAL_RT_TEMPLATE)){
2037 current_recall_id = (AgsRecallID *) current_audio_signal->recall_id;
2038
2039 /* create rt-template */
2040 rt_template = ags_audio_signal_new(output_soundcard,
2041 (GObject *) recycling,
2042 (GObject *) current_recall_id);
2043 ags_audio_signal_set_flags(rt_template, AGS_AUDIO_SIGNAL_RT_TEMPLATE);
2044
2045 g_hash_table_insert(hash_table,
2046 current_audio_signal, rt_template);
2047
2048 /* remove old rt-template */
2049 ags_recycling_remove_audio_signal(recycling,
2050 current_audio_signal);
2051
2052 /* add new rt-template */
2053 ags_recycling_add_audio_signal(recycling,
2054 rt_template);
2055 }
2056
2057 list = list->next;
2058 }
2059
2060 /* update */
2061 list = start_list;
2062
2063 while(list != NULL){
2064 AgsAudioSignal *current_audio_signal;
2065 AgsAudioSignal *rt_template;
2066
2067 current_audio_signal = list->data;
2068
2069 /* get some fields */
2070 g_object_get(current_audio_signal,
2071 "rt-template", &rt_template,
2072 NULL);
2073
2074 if(rt_template != NULL){
2075 g_object_set(list->data,
2076 "rt-template", g_hash_table_lookup(hash_table,
2077 rt_template),
2078 NULL);
2079
2080 g_object_unref(rt_template);
2081 }
2082
2083 list = list->next;
2084 }
2085
2086 g_hash_table_destroy(hash_table);
2087 }else{
2088 /* add new audio signal */
2089 g_rec_mutex_lock(recycling_mutex);
2090
2091 recycling->audio_signal = g_list_prepend(recycling->audio_signal,
2092 audio_signal);
2093 g_object_ref(audio_signal);
2094
2095 g_rec_mutex_unlock(recycling_mutex);
2096 }
2097
2098 g_list_free_full(start_list,
2099 g_object_unref);
2100
2101 g_object_set(audio_signal,
2102 "recycling", recycling,
2103 NULL);
2104 }
2105
2106 /**
2107 * ags_recycling_add_audio_signal:
2108 * @recycling: the #AgsRecycling
2109 * @audio_signal: the #AgsAudioSignal to add
2110 *
2111 * Add @audio_signal to @recycling.
2112 *
2113 * Since: 3.0.0
2114 */
2115 void
ags_recycling_add_audio_signal(AgsRecycling * recycling,AgsAudioSignal * audio_signal)2116 ags_recycling_add_audio_signal(AgsRecycling *recycling,
2117 AgsAudioSignal *audio_signal)
2118 {
2119 GRecMutex *recycling_mutex;
2120
2121 g_return_if_fail(AGS_IS_RECYCLING(recycling) &&
2122 AGS_IS_AUDIO_SIGNAL(audio_signal));
2123
2124 /* get recycling mutex */
2125 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
2126
2127 /* get audio signal */
2128 g_rec_mutex_lock(recycling_mutex);
2129
2130 if(g_list_find(recycling->audio_signal,
2131 audio_signal) != NULL){
2132 g_rec_mutex_unlock(recycling_mutex);
2133
2134 return;
2135 }
2136
2137 g_rec_mutex_unlock(recycling_mutex);
2138
2139 /* emit signal */
2140 g_object_ref(G_OBJECT(recycling));
2141 g_object_ref(G_OBJECT(audio_signal));
2142 g_signal_emit(G_OBJECT(recycling),
2143 recycling_signals[ADD_AUDIO_SIGNAL], 0,
2144 audio_signal);
2145 g_object_unref(G_OBJECT(audio_signal));
2146 g_object_unref(G_OBJECT(recycling));
2147 }
2148
2149 void
ags_recycling_real_remove_audio_signal(AgsRecycling * recycling,AgsAudioSignal * audio_signal)2150 ags_recycling_real_remove_audio_signal(AgsRecycling *recycling,
2151 AgsAudioSignal *audio_signal)
2152 {
2153 GRecMutex *recycling_mutex;
2154
2155 /* get recycling mutex */
2156 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
2157
2158 /* check audio signal */
2159 g_rec_mutex_lock(recycling_mutex);
2160
2161 if(g_list_find(recycling->audio_signal,
2162 audio_signal) == NULL){
2163 g_rec_mutex_unlock(recycling_mutex);
2164
2165 return;
2166 }
2167
2168 recycling->audio_signal = g_list_remove(recycling->audio_signal,
2169 audio_signal);
2170
2171 g_rec_mutex_unlock(recycling_mutex);
2172
2173 g_object_set(audio_signal,
2174 "recycling", NULL,
2175 NULL);
2176
2177 g_object_unref(audio_signal);
2178 }
2179
2180 /**
2181 * ags_recycling_remove_audio_signal:
2182 * @recycling: the #AgsRecycling
2183 * @audio_signal: the #AgsAudioSignal to remove
2184 *
2185 * Remove @audio_signal of @recycling.
2186 *
2187 * Since: 3.0.0
2188 */
2189 void
ags_recycling_remove_audio_signal(AgsRecycling * recycling,AgsAudioSignal * audio_signal)2190 ags_recycling_remove_audio_signal(AgsRecycling *recycling,
2191 AgsAudioSignal *audio_signal)
2192 {
2193 g_return_if_fail(AGS_IS_RECYCLING(recycling) && AGS_IS_AUDIO_SIGNAL(audio_signal));
2194
2195 /* emit signal */
2196 g_object_ref((GObject *) recycling);
2197 g_object_ref((GObject *) audio_signal);
2198 g_signal_emit(G_OBJECT(recycling),
2199 recycling_signals[REMOVE_AUDIO_SIGNAL], 0,
2200 audio_signal);
2201 g_object_unref((GObject *) audio_signal);
2202 g_object_unref((GObject *) recycling);
2203 }
2204
2205 /**
2206 * ags_recycling_data_request:
2207 * @recycling: the #AgsRecycling
2208 * @audio_signal: the #AgsAudioSignal
2209 *
2210 * Request data of @audio_signal.
2211 *
2212 * Since: 3.0.0
2213 */
2214 void
ags_recycling_data_request(AgsRecycling * recycling,AgsAudioSignal * audio_signal)2215 ags_recycling_data_request(AgsRecycling *recycling,
2216 AgsAudioSignal *audio_signal)
2217 {
2218 g_return_if_fail(AGS_IS_RECYCLING(recycling));
2219
2220 /* emit signal */
2221 g_object_ref((GObject *) recycling);
2222 g_signal_emit(G_OBJECT(recycling),
2223 recycling_signals[DATA_REQUEST], 0,
2224 audio_signal);
2225 g_object_unref((GObject *) recycling);
2226 }
2227
2228 /**
2229 * ags_recycling_create_audio_signal_with_defaults:
2230 * @recycling: the #AgsRecycling
2231 * @audio_signal: the #AgsAudioSignal to apply defaults
2232 * @delay: the delay
2233 * @attack: the attack
2234 *
2235 * Create audio signal with defaults.
2236 *
2237 * Since: 3.0.0
2238 */
2239 void
ags_recycling_create_audio_signal_with_defaults(AgsRecycling * recycling,AgsAudioSignal * audio_signal,gdouble delay,guint attack)2240 ags_recycling_create_audio_signal_with_defaults(AgsRecycling *recycling,
2241 AgsAudioSignal *audio_signal,
2242 gdouble delay, guint attack)
2243 {
2244 AgsAudioSignal *template;
2245
2246 GObject *output_soundcard;
2247
2248 GList *start_list, *list;
2249
2250 guint samplerate;
2251 guint buffer_size;
2252 guint format;
2253 guint last_frame;
2254 guint loop_start, loop_end;
2255 guint length;
2256 guint frame_count;
2257
2258 GRecMutex *recycling_mutex;
2259 GRecMutex *audio_signal_mutex;
2260 GRecMutex *template_mutex;
2261
2262 if(!AGS_IS_RECYCLING(recycling) ||
2263 !AGS_IS_AUDIO_SIGNAL(audio_signal)){
2264 return;
2265 }
2266
2267 /* get recycling mutex */
2268 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
2269
2270 /* get audio signal mutex */
2271 audio_signal_mutex = AGS_AUDIO_SIGNAL_GET_OBJ_MUTEX(audio_signal);
2272
2273 /* get audio signal list */
2274 g_object_get(recycling,
2275 "audio-signal", &start_list,
2276 NULL);
2277
2278 /* get template */
2279 template = ags_audio_signal_get_template(start_list);
2280
2281 g_list_free_full(start_list,
2282 g_object_unref);
2283
2284 /* set delay and attack */
2285 g_object_set(audio_signal,
2286 "delay", delay,
2287 "attack", attack,
2288 NULL);
2289
2290 if(template == NULL){
2291 ags_audio_signal_stream_resize(audio_signal,
2292 0);
2293
2294 return;
2295 }
2296
2297 /* get template mutex */
2298 template_mutex = AGS_AUDIO_SIGNAL_GET_OBJ_MUTEX(template);
2299
2300 /* get some fields */
2301 g_rec_mutex_lock(template_mutex);
2302
2303 output_soundcard = template->output_soundcard;
2304
2305 samplerate = template->samplerate;
2306 buffer_size = template->buffer_size;
2307 format = template->format;
2308
2309 length = template->length;
2310 frame_count = template->frame_count;
2311
2312 last_frame = template->last_frame;
2313 loop_start = template->loop_start;
2314 loop_end = template->loop_end;
2315
2316 g_rec_mutex_unlock(template_mutex);
2317
2318 /* apply delay and attack */
2319 last_frame = (((guint)(delay *
2320 buffer_size) +
2321 attack +
2322 last_frame) %
2323 buffer_size);
2324 loop_start = (((guint) (delay *
2325 buffer_size) +
2326 attack +
2327 loop_start) %
2328 buffer_size);
2329 loop_end = (((guint)(delay *
2330 buffer_size) +
2331 attack +
2332 loop_end) %
2333 buffer_size);
2334
2335 /* apply defaults */
2336 g_object_set(audio_signal,
2337 "recycling", recycling,
2338 "output-soundcard", output_soundcard,
2339 "samplerate", samplerate,
2340 "buffer-size", buffer_size,
2341 "format", format,
2342 "frame-count", frame_count,
2343 "last-frame", last_frame,
2344 "loop-start", loop_start,
2345 "loop-end", loop_end,
2346 NULL);
2347
2348 /* resize and duplicate */
2349 ags_audio_signal_stream_resize(audio_signal,
2350 length);
2351 ags_audio_signal_duplicate_stream(audio_signal,
2352 template);
2353
2354 g_object_unref(template);
2355 }
2356
2357 /**
2358 * ags_recycling_create_audio_signal_with_frame_count:
2359 * @recycling: the #AgsRecycling
2360 * @audio_signal: the #AgsAudioSignal to apply defaults
2361 * @frame_count: the audio data size
2362 * @delay: the delay
2363 * @attack: the attack
2364 *
2365 * Create audio signal with frame count.
2366 *
2367 * Since: 3.0.0
2368 */
2369 void
ags_recycling_create_audio_signal_with_frame_count(AgsRecycling * recycling,AgsAudioSignal * audio_signal,guint frame_count,gdouble delay,guint attack)2370 ags_recycling_create_audio_signal_with_frame_count(AgsRecycling *recycling,
2371 AgsAudioSignal *audio_signal,
2372 guint frame_count,
2373 gdouble delay, guint attack)
2374 {
2375 AgsAudioSignal *template;
2376
2377 GObject *output_soundcard;
2378
2379 GList *start_list, *list;
2380 GList *stream, *template_stream;
2381
2382 guint samplerate;
2383 guint buffer_size;
2384 guint format;
2385 guint last_frame;
2386 guint loop_start, loop_end;
2387 guint new_last_frame;
2388 guint new_loop_start, new_loop_end;
2389 guint template_length;
2390 guint loop_length;
2391 guint loop_frame_count;
2392 guint n_frames;
2393 guint copy_n_frames;
2394 guint nth_loop;
2395 guint i, j;
2396 guint copy_mode;
2397
2398 GRecMutex *recycling_mutex;
2399 GRecMutex *audio_signal_mutex;
2400 GRecMutex *template_mutex;
2401 GRecMutex *template_stream_mutex;
2402
2403 if(!AGS_IS_RECYCLING(recycling) ||
2404 !AGS_IS_AUDIO_SIGNAL(audio_signal)){
2405 return;
2406 }
2407
2408 /* get recycling mutex */
2409 recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
2410
2411 /* get audio signal mutex */
2412 audio_signal_mutex = AGS_AUDIO_SIGNAL_GET_OBJ_MUTEX(audio_signal);
2413
2414 /* get audio signal list */
2415 g_object_get(recycling,
2416 "audio-signal", &start_list,
2417 NULL);
2418
2419 /* get template */
2420 template = ags_audio_signal_get_template(start_list);
2421
2422 g_list_free_full(start_list,
2423 g_object_unref);
2424
2425 /* set delay and attack */
2426 g_object_set(audio_signal,
2427 "delay", delay,
2428 "attack", attack,
2429 NULL);
2430
2431 if(template == NULL){
2432 g_rec_mutex_lock(audio_signal_mutex);
2433
2434 buffer_size = audio_signal->buffer_size;
2435
2436 g_rec_mutex_unlock(audio_signal_mutex);
2437
2438 ags_audio_signal_stream_resize(audio_signal,
2439 (guint) ceil((attack + frame_count) / buffer_size) + 1);
2440
2441 return;
2442 }
2443
2444 /* get template mutex */
2445 template_mutex = AGS_AUDIO_SIGNAL_GET_OBJ_MUTEX(template);
2446
2447 /* get some fields */
2448 g_rec_mutex_lock(template_mutex);
2449
2450 output_soundcard = template->output_soundcard;
2451
2452 samplerate = template->samplerate;
2453 buffer_size = template->buffer_size;
2454 format = template->format;
2455
2456 last_frame = template->last_frame;
2457 loop_start = template->loop_start;
2458 loop_end = template->loop_end;
2459
2460 template_length = template->length;
2461
2462 g_rec_mutex_unlock(template_mutex);
2463
2464 /* apply delay and attack */
2465 new_last_frame = (((guint)(delay *
2466 buffer_size) +
2467 attack +
2468 last_frame) %
2469 buffer_size);
2470 new_loop_start = ((guint) (delay *
2471 buffer_size) +
2472 attack +
2473 loop_start);
2474 new_loop_end = ((guint)(delay *
2475 buffer_size) +
2476 attack +
2477 loop_end);
2478
2479 /* apply defaults */
2480 g_object_set(audio_signal,
2481 "recycling", recycling,
2482 "output-soundcard", output_soundcard,
2483 "samplerate", samplerate,
2484 "buffer-size", buffer_size,
2485 "format", format,
2486 NULL);
2487
2488 /* resize */
2489 if(loop_end > loop_start){
2490 loop_length = loop_end - loop_start;
2491
2492 if((frame_count - loop_start) > (last_frame - loop_end) &&
2493 last_frame >= loop_end){
2494 loop_frame_count = (frame_count - loop_start) - (last_frame - loop_end);
2495 }else{
2496 loop_frame_count = loop_length;
2497 }
2498
2499 ags_audio_signal_stream_resize(audio_signal,
2500 (guint) ceil(frame_count / buffer_size) + 1);
2501 }else{
2502 ags_audio_signal_duplicate_stream(audio_signal,
2503 template);
2504 ags_audio_signal_stream_resize(audio_signal,
2505 (guint) ceil(frame_count / buffer_size) + 1);
2506
2507 return;
2508 }
2509
2510 new_last_frame = ((guint) (delay * buffer_size) + frame_count + attack) % buffer_size;
2511
2512 g_object_set(audio_signal,
2513 "last-frame", new_last_frame,
2514 NULL);
2515
2516 if(template_length == 0){
2517 g_object_unref(template);
2518
2519 return;
2520 }
2521
2522 /* get template stream mutex */
2523 template_stream_mutex = AGS_AUDIO_SIGNAL_GET_STREAM_MUTEX(template);
2524
2525 /* loop related copying */
2526 copy_mode = ags_audio_buffer_util_get_copy_mode(ags_audio_buffer_util_format_from_soundcard(format),
2527 ags_audio_buffer_util_format_from_soundcard(format));
2528
2529 /* generic copying */
2530 stream = g_list_nth(audio_signal->stream,
2531 (guint) ((delay * buffer_size) + attack) / buffer_size);
2532
2533 g_rec_mutex_lock(template_stream_mutex);
2534
2535 template_stream = template->stream;
2536
2537 for(i = 0, j = attack, nth_loop = 0; i < frame_count && stream != NULL && template_stream != NULL;){
2538 /* compute count of frames to copy */
2539 copy_n_frames = buffer_size;
2540
2541 if(loop_start < loop_end &&
2542 i + copy_n_frames < loop_start + loop_frame_count){
2543 if(j + copy_n_frames > loop_end){
2544 copy_n_frames = loop_end - j;
2545 }
2546 }
2547
2548 if((i % buffer_size) + copy_n_frames > buffer_size){
2549 copy_n_frames = buffer_size - (i % buffer_size);
2550 }
2551
2552 if((j % buffer_size) + copy_n_frames > buffer_size){
2553 copy_n_frames = buffer_size - (j % buffer_size);
2554 }
2555
2556 if(i + copy_n_frames > frame_count){
2557 copy_n_frames = frame_count - i;
2558 }
2559
2560 /* copy */
2561 ags_audio_buffer_util_copy_buffer_to_buffer(stream->data, 1, i % buffer_size,
2562 template_stream->data, 1, j % buffer_size,
2563 copy_n_frames, copy_mode);
2564
2565 if((i + copy_n_frames) % buffer_size == 0){
2566 stream = stream->next;
2567 }
2568
2569 if((j + copy_n_frames) % buffer_size == 0){
2570 template_stream = template_stream->next;
2571 }
2572
2573 i += copy_n_frames;
2574
2575 if(loop_start < loop_end){
2576 if(j + copy_n_frames == loop_end &&
2577 i + copy_n_frames < loop_start + loop_frame_count){
2578 template_stream = g_list_nth(template->stream,
2579 floor(loop_start / buffer_size));
2580
2581 j = loop_start;
2582
2583 nth_loop++;
2584 }else{
2585 j += copy_n_frames;
2586 }
2587 }else{
2588 j += copy_n_frames;
2589 }
2590 }
2591
2592 g_rec_mutex_unlock(template_stream_mutex);
2593
2594 g_object_unref(template);
2595 }
2596
2597 /**
2598 * ags_recycling_find_next_channel:
2599 * @start_region: boundary start
2600 * @end_region: boundary end
2601 * @prev_channel: previous channel
2602 *
2603 * Retrieve next recycling with different channel.
2604 *
2605 * Returns: (transfer full): Matching recycling.
2606 *
2607 * Since: 3.0.0
2608 */
2609 AgsRecycling*
ags_recycling_find_next_channel(AgsRecycling * start_region,AgsRecycling * end_region,GObject * prev_channel)2610 ags_recycling_find_next_channel(AgsRecycling *start_region, AgsRecycling *end_region,
2611 GObject *prev_channel)
2612 {
2613 AgsRecycling *recycling, *next_recycling;
2614
2615 /* verify objects and get pointer for safe access */
2616 if(!AGS_IS_RECYCLING(start_region)){
2617 return(NULL);
2618 }
2619
2620 /* find */
2621 recycling = start_region;
2622
2623 if(recycling != NULL){
2624 g_object_ref(recycling);
2625 }
2626
2627 while(recycling != NULL &&
2628 recycling != end_region){
2629 GObject *current_channel;
2630
2631 gboolean success;
2632
2633 g_object_get(recycling,
2634 "channel", ¤t_channel,
2635 NULL);
2636
2637 /* check if new match */
2638 success = (current_channel != prev_channel) ? TRUE: FALSE;
2639 g_object_unref(current_channel);
2640
2641 if(success){
2642 return(recycling);
2643 }
2644
2645 /* iterate */
2646 next_recycling = ags_recycling_next(recycling);
2647
2648 g_object_unref(recycling);
2649
2650 recycling = next_recycling;
2651 }
2652
2653 if(recycling != NULL){
2654 g_object_unref(recycling);
2655 }
2656
2657 /* no new channel within region */
2658 return(NULL);
2659 }
2660
2661 /**
2662 * ags_recycling_position:
2663 * @start_region: boundary start
2664 * @end_region: boundary end
2665 * @recycling: matching recycling
2666 *
2667 * Retrieve position of recycling.
2668 *
2669 * Returns: position within boundary.
2670 *
2671 * Since: 3.0.0
2672 */
2673 gint
ags_recycling_position(AgsRecycling * start_region,AgsRecycling * end_region,AgsRecycling * recycling)2674 ags_recycling_position(AgsRecycling *start_region, AgsRecycling *end_region,
2675 AgsRecycling *recycling)
2676 {
2677 AgsRecycling *current, *next;
2678
2679 gint position;
2680
2681 if(!AGS_IS_RECYCLING(start_region)){
2682 return(-1);
2683 }
2684
2685 /* determine position */
2686 current = start_region;
2687 g_object_ref(current);
2688
2689 position = -1;
2690
2691 while(current != NULL && current != end_region){
2692 position++;
2693
2694 /* check if new match */
2695 if(current == recycling){
2696 break;
2697 }
2698
2699 /* iterate */
2700 next = ags_recycling_next(current);
2701
2702 g_object_unref(current);
2703
2704 current = next;
2705 }
2706
2707 if(current != NULL){
2708 g_object_unref(current);
2709 }
2710
2711 return(position);
2712 }
2713
2714 /**
2715 * ags_recycling_is_active:
2716 * @start_region: boundary start
2717 * @end_region: boundary end
2718 * @recall_id: the #AgsRecallID
2719 *
2720 * Check if is active.
2721 *
2722 * Returns: %TRUE if related audio signal to recall id is available, otherwise %FALSE
2723 *
2724 * Since: 3.0.0
2725 */
2726 gboolean
ags_recycling_is_active(AgsRecycling * start_region,AgsRecycling * end_region,GObject * recall_id)2727 ags_recycling_is_active(AgsRecycling *start_region, AgsRecycling *end_region,
2728 GObject *recall_id)
2729 {
2730 AgsRecycling *current, *next;
2731 AgsRecyclingContext *recycling_context;
2732
2733 GList *start_list, *list;
2734
2735 gboolean is_active;
2736 gboolean success;
2737
2738 if(!AGS_IS_RECYCLING(start_region) ||
2739 !AGS_IS_RECALL_ID(recall_id)){
2740 return(FALSE);
2741 }
2742
2743 current = start_region;
2744 g_object_ref(current);
2745
2746 success = FALSE;
2747
2748 while(current != end_region){
2749 /* get audio signal */
2750 g_object_get(current,
2751 "audio-signal", &start_list,
2752 NULL);
2753
2754 /* is active */
2755 is_active = (ags_audio_signal_is_active(start_list,
2756 recall_id)) ? TRUE: FALSE;
2757
2758 g_list_free_full(start_list,
2759 g_object_unref);
2760
2761 if(is_active){
2762 success = TRUE;
2763
2764 break;
2765 }
2766
2767 /* iterate */
2768 next = ags_recycling_next(current);
2769
2770 g_object_unref(next);
2771
2772 current = next;
2773 }
2774
2775 if(current != NULL){
2776 g_object_unref(current);
2777 }
2778
2779 return(success);
2780 }
2781
2782 /**
2783 * ags_recycling_new:
2784 * @output_soundcard: the #GObject implementing #AgsSoundcard
2785 *
2786 * Creates a #AgsRecycling, with defaults of @soundcard.
2787 *
2788 * Returns: a new #AgsRecycling
2789 *
2790 * Since: 3.0.0
2791 */
2792 AgsRecycling*
ags_recycling_new(GObject * output_soundcard)2793 ags_recycling_new(GObject *output_soundcard)
2794 {
2795 AgsRecycling *recycling;
2796
2797 recycling = (AgsRecycling *) g_object_new(AGS_TYPE_RECYCLING,
2798 "output-soundcard", output_soundcard,
2799 NULL);
2800
2801 return(recycling);
2802 }
2803