1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2019 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/recall/ags_play_notation_audio_run.h>
21
22 #include <ags/audio/ags_recall_id.h>
23 #include <ags/audio/ags_recall_container.h>
24
25 #include <ags/audio/recall/ags_play_notation_audio.h>
26 #include <ags/audio/recall/ags_delay_audio.h>
27
28 #include <ags/audio/thread/ags_audio_loop.h>
29 #include <ags/audio/thread/ags_soundcard_thread.h>
30
31 #include <ags/i18n.h>
32
33 void ags_play_notation_audio_run_class_init(AgsPlayNotationAudioRunClass *play_notation_audio_run);
34 void ags_play_notation_audio_run_connectable_interface_init(AgsConnectableInterface *connectable);
35 void ags_play_notation_audio_run_init(AgsPlayNotationAudioRun *play_notation_audio_run);
36 void ags_play_notation_audio_run_set_property(GObject *gobject,
37 guint prop_id,
38 const GValue *value,
39 GParamSpec *param_spec);
40 void ags_play_notation_audio_run_get_property(GObject *gobject,
41 guint prop_id,
42 GValue *value,
43 GParamSpec *param_spec);
44 void ags_play_notation_audio_run_dispose(GObject *gobject);
45 void ags_play_notation_audio_run_finalize(GObject *gobject);
46
47 void ags_play_notation_audio_run_connect(AgsConnectable *connectable);
48 void ags_play_notation_audio_run_disconnect(AgsConnectable *connectable);
49 void ags_play_notation_audio_run_connect_connection(AgsConnectable *connectable,
50 GObject *connection);
51 void ags_play_notation_audio_run_disconnect_connection(AgsConnectable *connectable,
52 GObject *connection);
53
54 void ags_play_notation_audio_run_resolve_dependency(AgsRecall *recall);
55
56 void ags_play_notation_audio_run_alloc_input_callback(AgsDelayAudioRun *delay_audio_run,
57 guint nth_run,
58 gdouble delay, guint attack,
59 AgsPlayNotationAudioRun *play_notation_audio_run);
60
61 /**
62 * SECTION:ags_play_notation_audio_run
63 * @short_description: play notation
64 * @title: AgsPlayNotationAudioRun
65 * @section_id:
66 * @include: ags/audio/recall/ags_play_notation_audio_run.h
67 *
68 * The #AgsPlayNotationAudioRun class play notation.
69 */
70
71 enum{
72 PROP_0,
73 PROP_DELAY_AUDIO_RUN,
74 PROP_COUNT_BEATS_AUDIO_RUN,
75 PROP_NOTATION,
76 };
77
78 static gpointer ags_play_notation_audio_run_parent_class = NULL;
79 static AgsConnectableInterface* ags_play_notation_audio_run_parent_connectable_interface;
80
81 GType
ags_play_notation_audio_run_get_type()82 ags_play_notation_audio_run_get_type()
83 {
84 static volatile gsize g_define_type_id__volatile = 0;
85
86 if(g_once_init_enter (&g_define_type_id__volatile)){
87 GType ags_type_play_notation_audio_run = 0;
88
89 static const GTypeInfo ags_play_notation_audio_run_info = {
90 sizeof (AgsPlayNotationAudioRunClass),
91 NULL, /* base_init */
92 NULL, /* base_finalize */
93 (GClassInitFunc) ags_play_notation_audio_run_class_init,
94 NULL, /* class_finalize */
95 NULL, /* class_data */
96 sizeof (AgsPlayNotationAudioRun),
97 0, /* n_preallocs */
98 (GInstanceInitFunc) ags_play_notation_audio_run_init,
99 };
100
101 static const GInterfaceInfo ags_connectable_interface_info = {
102 (GInterfaceInitFunc) ags_play_notation_audio_run_connectable_interface_init,
103 NULL, /* interface_finalize */
104 NULL, /* interface_data */
105 };
106
107 ags_type_play_notation_audio_run = g_type_register_static(AGS_TYPE_RECALL_AUDIO_RUN,
108 "AgsPlayNotationAudioRun",
109 &ags_play_notation_audio_run_info,
110 0);
111
112 g_type_add_interface_static(ags_type_play_notation_audio_run,
113 AGS_TYPE_CONNECTABLE,
114 &ags_connectable_interface_info);
115
116 g_once_init_leave(&g_define_type_id__volatile, ags_type_play_notation_audio_run);
117 }
118
119 return g_define_type_id__volatile;
120 }
121
122 void
ags_play_notation_audio_run_class_init(AgsPlayNotationAudioRunClass * play_notation_audio_run)123 ags_play_notation_audio_run_class_init(AgsPlayNotationAudioRunClass *play_notation_audio_run)
124 {
125 GObjectClass *gobject;
126 AgsRecallClass *recall;
127 GParamSpec *param_spec;
128
129 ags_play_notation_audio_run_parent_class = g_type_class_peek_parent(play_notation_audio_run);
130
131 /* GObjectClass */
132 gobject = (GObjectClass *) play_notation_audio_run;
133
134 gobject->set_property = ags_play_notation_audio_run_set_property;
135 gobject->get_property = ags_play_notation_audio_run_get_property;
136
137 gobject->dispose = ags_play_notation_audio_run_dispose;
138 gobject->finalize = ags_play_notation_audio_run_finalize;
139
140 /* properties */
141 /**
142 * AgsPlayNotationAudioRun:delay-audio-run:
143 *
144 * The delay audio run dependency.
145 *
146 * Since: 3.0.0
147 */
148 param_spec = g_param_spec_object("delay-audio-run",
149 i18n_pspec("assigned AgsDelayAudioRun"),
150 i18n_pspec("the AgsDelayAudioRun which emits notation_alloc_input signal"),
151 AGS_TYPE_DELAY_AUDIO_RUN,
152 G_PARAM_READABLE | G_PARAM_WRITABLE);
153 g_object_class_install_property(gobject,
154 PROP_DELAY_AUDIO_RUN,
155 param_spec);
156
157 /**
158 * AgsPlayNotationAudioRun:count-beats-audio-run:
159 *
160 * The count beats audio run dependency.
161 *
162 * Since: 3.0.0
163 */
164 param_spec = g_param_spec_object("count-beats-audio-run",
165 i18n_pspec("assigned AgsCountBeatsAudioRun"),
166 i18n_pspec("the AgsCountBeatsAudioRun which just counts"),
167 AGS_TYPE_COUNT_BEATS_AUDIO_RUN,
168 G_PARAM_READABLE | G_PARAM_WRITABLE);
169 g_object_class_install_property(gobject,
170 PROP_COUNT_BEATS_AUDIO_RUN,
171 param_spec);
172
173 /**
174 * AgsPlayNotationAudioRun:notation:
175 *
176 * The notation containing the notes.
177 *
178 * Since: 3.0.0
179 */
180 param_spec = g_param_spec_object("notation",
181 i18n_pspec("assigned AgsNotation"),
182 i18n_pspec("The AgsNotation containing notes"),
183 AGS_TYPE_NOTATION,
184 G_PARAM_READABLE | G_PARAM_WRITABLE);
185 g_object_class_install_property(gobject,
186 PROP_NOTATION,
187 param_spec);
188
189 /* AgsRecallClass */
190 recall = (AgsRecallClass *) play_notation_audio_run;
191
192 recall->resolve_dependency = ags_play_notation_audio_run_resolve_dependency;
193 }
194
195 void
ags_play_notation_audio_run_connectable_interface_init(AgsConnectableInterface * connectable)196 ags_play_notation_audio_run_connectable_interface_init(AgsConnectableInterface *connectable)
197 {
198 ags_play_notation_audio_run_parent_connectable_interface = g_type_interface_peek_parent(connectable);
199
200 connectable->connect = ags_play_notation_audio_run_connect;
201 connectable->disconnect = ags_play_notation_audio_run_disconnect;
202
203 connectable->connect_connection = ags_play_notation_audio_run_connect_connection;
204 connectable->disconnect_connection = ags_play_notation_audio_run_disconnect_connection;
205 }
206
207 void
ags_play_notation_audio_run_init(AgsPlayNotationAudioRun * play_notation_audio_run)208 ags_play_notation_audio_run_init(AgsPlayNotationAudioRun *play_notation_audio_run)
209 {
210 ags_recall_set_ability_flags((AgsRecall *) play_notation_audio_run, (AGS_SOUND_ABILITY_NOTATION));
211
212 AGS_RECALL(play_notation_audio_run)->name = "ags-play-notation";
213 AGS_RECALL(play_notation_audio_run)->version = AGS_RECALL_DEFAULT_VERSION;
214 AGS_RECALL(play_notation_audio_run)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
215 AGS_RECALL(play_notation_audio_run)->xml_type = "ags-play-notation-audio-run";
216 AGS_RECALL(play_notation_audio_run)->port = NULL;
217
218 play_notation_audio_run->delay_audio_run = NULL;
219 play_notation_audio_run->count_beats_audio_run = NULL;
220
221 play_notation_audio_run->notation = NULL;
222
223 play_notation_audio_run->timestamp = ags_timestamp_new();
224 g_object_ref(play_notation_audio_run->timestamp);
225
226 play_notation_audio_run->timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
227 play_notation_audio_run->timestamp->flags |= AGS_TIMESTAMP_OFFSET;
228
229 play_notation_audio_run->timestamp->timer.ags_offset.offset = 0;
230 }
231
232 void
ags_play_notation_audio_run_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)233 ags_play_notation_audio_run_set_property(GObject *gobject,
234 guint prop_id,
235 const GValue *value,
236 GParamSpec *param_spec)
237 {
238 AgsPlayNotationAudioRun *play_notation_audio_run;
239
240 GRecMutex *recall_mutex;
241
242 play_notation_audio_run = AGS_PLAY_NOTATION_AUDIO_RUN(gobject);
243
244 /* get recall mutex */
245 recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_notation_audio_run);
246
247 switch(prop_id){
248 case PROP_DELAY_AUDIO_RUN:
249 {
250 AgsDelayAudioRun *delay_audio_run, *old_delay_audio_run;
251
252 gboolean is_template;
253
254 delay_audio_run = g_value_get_object(value);
255 old_delay_audio_run = NULL;
256
257 g_rec_mutex_lock(recall_mutex);
258
259 if(delay_audio_run == play_notation_audio_run->delay_audio_run){
260 g_rec_mutex_unlock(recall_mutex);
261
262 return;
263 }
264
265 if(play_notation_audio_run->delay_audio_run != NULL){
266 old_delay_audio_run = play_notation_audio_run->delay_audio_run;
267
268 g_object_unref(G_OBJECT(play_notation_audio_run->delay_audio_run));
269 }
270
271 if(delay_audio_run != NULL){
272 g_object_ref(delay_audio_run);
273 }
274
275 g_rec_mutex_unlock(recall_mutex);
276
277 /* check template */
278 if(delay_audio_run != NULL &&
279 ags_recall_test_flags((AgsRecall *) play_notation_audio_run, AGS_RECALL_TEMPLATE)){
280 is_template = TRUE;
281 }else{
282 is_template = FALSE;
283 }
284
285 /* old - dependency/connection */
286 if(is_template){
287 if(old_delay_audio_run != NULL){
288 AgsRecallDependency *recall_dependency;
289
290 GList *list;
291
292 recall_dependency = NULL;
293 list = ags_recall_dependency_find_dependency(AGS_RECALL(play_notation_audio_run)->recall_dependency,
294 (GObject *) old_delay_audio_run);
295
296 if(list != NULL){
297 recall_dependency = list->data;
298 }
299
300 ags_recall_remove_recall_dependency(AGS_RECALL(play_notation_audio_run),
301 recall_dependency);
302 }
303 }else{
304 if(ags_connectable_is_connected(AGS_CONNECTABLE(play_notation_audio_run))){
305 ags_connectable_disconnect_connection(AGS_CONNECTABLE(play_notation_audio_run),
306 (GObject *) old_delay_audio_run);
307 }
308 }
309
310 /* new - dependency/connection */
311 g_rec_mutex_lock(recall_mutex);
312
313 play_notation_audio_run->delay_audio_run = delay_audio_run;
314
315 g_rec_mutex_unlock(recall_mutex);
316
317 if(delay_audio_run != NULL){
318 if(is_template){
319 ags_recall_add_recall_dependency(AGS_RECALL(play_notation_audio_run),
320 ags_recall_dependency_new((GObject *) delay_audio_run));
321 }else{
322 if(ags_connectable_is_connected(AGS_CONNECTABLE(play_notation_audio_run))){
323 ags_connectable_connect_connection(AGS_CONNECTABLE(play_notation_audio_run),
324 (GObject *) delay_audio_run);
325 }
326 }
327 }
328 }
329 break;
330 case PROP_COUNT_BEATS_AUDIO_RUN:
331 {
332 AgsCountBeatsAudioRun *count_beats_audio_run, *old_count_beats_audio_run;
333
334 gboolean is_template;
335
336 count_beats_audio_run = g_value_get_object(value);
337 old_count_beats_audio_run = NULL;
338
339 g_rec_mutex_lock(recall_mutex);
340
341 if(count_beats_audio_run == play_notation_audio_run->count_beats_audio_run){
342 g_rec_mutex_unlock(recall_mutex);
343
344 return;
345 }
346
347 if((AGS_RECALL_TEMPLATE & (AGS_RECALL(play_notation_audio_run)->flags)) != 0){
348 is_template = TRUE;
349 }else{
350 is_template = FALSE;
351 }
352
353 if(play_notation_audio_run->count_beats_audio_run != NULL){
354 old_count_beats_audio_run = play_notation_audio_run->count_beats_audio_run;
355
356 g_object_unref(G_OBJECT(play_notation_audio_run->count_beats_audio_run));
357 }
358
359 if(count_beats_audio_run != NULL){
360 g_object_ref(count_beats_audio_run);
361 }
362
363 play_notation_audio_run->count_beats_audio_run = count_beats_audio_run;
364
365 g_rec_mutex_unlock(recall_mutex);
366
367 /* check template */
368 if(count_beats_audio_run != NULL &&
369 ags_recall_test_flags((AgsRecall *) play_notation_audio_run, AGS_RECALL_TEMPLATE)){
370 is_template = TRUE;
371 }else{
372 is_template = FALSE;
373 }
374
375 /* dependency - remove */
376 if(is_template){
377 if(old_count_beats_audio_run != NULL){
378 AgsRecallDependency *recall_dependency;
379
380 GList *list;
381
382 recall_dependency = NULL;
383 list = ags_recall_dependency_find_dependency(AGS_RECALL(play_notation_audio_run)->recall_dependency,
384 (GObject *) old_count_beats_audio_run);
385
386 if(list != NULL){
387 recall_dependency = list->data;
388 }
389
390 ags_recall_remove_recall_dependency(AGS_RECALL(play_notation_audio_run),
391 recall_dependency);
392 }
393 }
394
395 /* dependency - add */
396 if(is_template &&
397 count_beats_audio_run != NULL){
398 ags_recall_add_recall_dependency(AGS_RECALL(play_notation_audio_run),
399 ags_recall_dependency_new((GObject *) count_beats_audio_run));
400 }
401 }
402 break;
403 case PROP_NOTATION:
404 {
405 AgsNotation *notation;
406
407 notation = (AgsNotation *) g_value_get_object(value);
408
409 g_rec_mutex_lock(recall_mutex);
410
411 if(play_notation_audio_run->notation == notation){
412 g_rec_mutex_unlock(recall_mutex);
413
414 return;
415 }
416
417 if(play_notation_audio_run->notation != NULL){
418 g_object_unref(play_notation_audio_run->notation);
419 }
420
421 if(notation != NULL){
422 g_object_ref(notation);
423 }
424
425 play_notation_audio_run->notation = notation;
426
427 g_rec_mutex_unlock(recall_mutex);
428 }
429 break;
430 default:
431 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
432 break;
433 };
434 }
435
436 void
ags_play_notation_audio_run_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)437 ags_play_notation_audio_run_get_property(GObject *gobject,
438 guint prop_id,
439 GValue *value,
440 GParamSpec *param_spec)
441 {
442 AgsPlayNotationAudioRun *play_notation_audio_run;
443
444 GRecMutex *recall_mutex;
445
446 play_notation_audio_run = AGS_PLAY_NOTATION_AUDIO_RUN(gobject);
447
448 /* get recall mutex */
449 recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_notation_audio_run);
450
451 switch(prop_id){
452 case PROP_DELAY_AUDIO_RUN:
453 {
454 g_rec_mutex_lock(recall_mutex);
455
456 g_value_set_object(value,
457 play_notation_audio_run->delay_audio_run);
458
459 g_rec_mutex_unlock(recall_mutex);
460 }
461 break;
462 case PROP_COUNT_BEATS_AUDIO_RUN:
463 {
464 g_rec_mutex_lock(recall_mutex);
465
466 g_value_set_object(value,
467 play_notation_audio_run->count_beats_audio_run);
468
469 g_rec_mutex_unlock(recall_mutex);
470 }
471 break;
472 case PROP_NOTATION:
473 {
474 g_rec_mutex_lock(recall_mutex);
475
476 g_value_set_object(value,
477 play_notation_audio_run->notation);
478
479 g_rec_mutex_unlock(recall_mutex);
480 }
481 break;
482 default:
483 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
484 break;
485 };
486 }
487
488 void
ags_play_notation_audio_run_dispose(GObject * gobject)489 ags_play_notation_audio_run_dispose(GObject *gobject)
490 {
491 AgsPlayNotationAudioRun *play_notation_audio_run;
492
493 play_notation_audio_run = AGS_PLAY_NOTATION_AUDIO_RUN(gobject);
494
495 /* delay audio run */
496 if(play_notation_audio_run->delay_audio_run != NULL){
497 g_object_unref(G_OBJECT(play_notation_audio_run->delay_audio_run));
498
499 play_notation_audio_run->delay_audio_run = NULL;
500 }
501
502 /* count beats audio run */
503 if(play_notation_audio_run->count_beats_audio_run != NULL){
504 g_object_unref(G_OBJECT(play_notation_audio_run->count_beats_audio_run));
505
506 play_notation_audio_run->count_beats_audio_run = NULL;
507 }
508
509 /* notation */
510 if(play_notation_audio_run->notation != NULL){
511 g_object_unref(G_OBJECT(play_notation_audio_run->notation));
512
513 play_notation_audio_run->notation = NULL;
514 }
515
516 /* call parent */
517 G_OBJECT_CLASS(ags_play_notation_audio_run_parent_class)->dispose(gobject);
518 }
519
520 void
ags_play_notation_audio_run_finalize(GObject * gobject)521 ags_play_notation_audio_run_finalize(GObject *gobject)
522 {
523 AgsPlayNotationAudioRun *play_notation_audio_run;
524
525 play_notation_audio_run = AGS_PLAY_NOTATION_AUDIO_RUN(gobject);
526
527 /* delay audio run */
528 if(play_notation_audio_run->delay_audio_run != NULL){
529 g_object_unref(G_OBJECT(play_notation_audio_run->delay_audio_run));
530 }
531
532 /* count beats audio run */
533 if(play_notation_audio_run->count_beats_audio_run != NULL){
534 g_object_unref(G_OBJECT(play_notation_audio_run->count_beats_audio_run));
535 }
536
537 /* notation */
538 if(play_notation_audio_run->notation != NULL){
539 g_object_unref(G_OBJECT(play_notation_audio_run->notation));
540 }
541
542 /* timestamp */
543 if(play_notation_audio_run->timestamp != NULL){
544 g_object_unref(G_OBJECT(play_notation_audio_run->timestamp));
545 }
546
547 /* call parent */
548 G_OBJECT_CLASS(ags_play_notation_audio_run_parent_class)->finalize(gobject);
549 }
550
551 void
ags_play_notation_audio_run_connect(AgsConnectable * connectable)552 ags_play_notation_audio_run_connect(AgsConnectable *connectable)
553 {
554 AgsPlayNotationAudioRun *play_notation_audio_run;
555 AgsDelayAudioRun *delay_audio_run;
556
557 if(ags_connectable_is_connected(connectable)){
558 return;
559 }
560
561 play_notation_audio_run = AGS_PLAY_NOTATION_AUDIO_RUN(connectable);
562
563 g_object_get(play_notation_audio_run,
564 "delay-audio-run", &delay_audio_run,
565 NULL);
566
567 ags_connectable_connect_connection(connectable, (GObject *) delay_audio_run);
568
569 /* call parent */
570 ags_play_notation_audio_run_parent_connectable_interface->connect(connectable);
571
572 if(delay_audio_run != NULL){
573 g_object_unref(delay_audio_run);
574 }
575 }
576
577 void
ags_play_notation_audio_run_disconnect(AgsConnectable * connectable)578 ags_play_notation_audio_run_disconnect(AgsConnectable *connectable)
579 {
580 AgsPlayNotationAudioRun *play_notation_audio_run;
581 AgsDelayAudioRun *delay_audio_run;
582
583 if(!ags_connectable_is_connected(connectable)){
584 return;
585 }
586
587 play_notation_audio_run = AGS_PLAY_NOTATION_AUDIO_RUN(connectable);
588
589 g_object_get(play_notation_audio_run,
590 "delay-audio-run", &delay_audio_run,
591 NULL);
592
593 ags_connectable_disconnect_connection(connectable, (GObject *) delay_audio_run);
594
595 /* call parent */
596 ags_play_notation_audio_run_parent_connectable_interface->disconnect(connectable);
597
598 if(delay_audio_run != NULL){
599 g_object_unref(delay_audio_run);
600 }
601 }
602
603 void
ags_play_notation_audio_run_connect_connection(AgsConnectable * connectable,GObject * connection)604 ags_play_notation_audio_run_connect_connection(AgsConnectable *connectable, GObject *connection)
605 {
606 AgsPlayNotationAudioRun *play_notation_audio_run;
607 AgsDelayAudioRun *delay_audio_run;
608
609 if(connection == NULL){
610 return;
611 }
612
613 play_notation_audio_run = AGS_PLAY_NOTATION_AUDIO_RUN(connectable);
614
615 g_object_get(play_notation_audio_run,
616 "delay-audio-run", &delay_audio_run,
617 NULL);
618
619 if(connection == (GObject *) delay_audio_run){
620 g_signal_connect(G_OBJECT(delay_audio_run), "notation-alloc-input",
621 G_CALLBACK(ags_play_notation_audio_run_alloc_input_callback), play_notation_audio_run);
622 }
623
624 if(delay_audio_run != NULL){
625 g_object_unref(delay_audio_run);
626 }
627 }
628
629 void
ags_play_notation_audio_run_disconnect_connection(AgsConnectable * connectable,GObject * connection)630 ags_play_notation_audio_run_disconnect_connection(AgsConnectable *connectable, GObject *connection)
631 {
632 AgsPlayNotationAudioRun *play_notation_audio_run;
633 AgsDelayAudioRun *delay_audio_run;
634
635 if(connection == NULL){
636 return;
637 }
638
639 play_notation_audio_run = AGS_PLAY_NOTATION_AUDIO_RUN(connectable);
640
641 g_object_get(play_notation_audio_run,
642 "delay-audio-run", &delay_audio_run,
643 NULL);
644
645 if(connection == (GObject *) delay_audio_run){
646 g_object_disconnect(G_OBJECT(delay_audio_run),
647 "any_signal::notation-alloc-input",
648 G_CALLBACK(ags_play_notation_audio_run_alloc_input_callback),
649 play_notation_audio_run,
650 NULL);
651 }
652
653 if(delay_audio_run != NULL){
654 g_object_unref(delay_audio_run);
655 }
656 }
657
658 void
ags_play_notation_audio_run_resolve_dependency(AgsRecall * recall)659 ags_play_notation_audio_run_resolve_dependency(AgsRecall *recall)
660 {
661 AgsRecall *template;
662 AgsRecallID *recall_id;
663 AgsRecallContainer *recall_container;
664 AgsRecallDependency *recall_dependency;
665 AgsDelayAudioRun *delay_audio_run;
666 AgsCountBeatsAudioRun *count_beats_audio_run;
667
668 GList *list_start, *list;
669
670 guint i, i_stop;
671
672 g_object_get(recall,
673 "recall-id", &recall_id,
674 "recall-container", &recall_container,
675 NULL);
676
677 g_object_get(recall_container,
678 "recall-audio-run", &list_start,
679 NULL);
680
681 template = NULL;
682 list = ags_recall_find_template(list_start);
683
684 if(list != NULL){
685 template = AGS_RECALL(list->data);
686 }
687
688 g_list_free_full(list_start,
689 g_object_unref);
690
691 g_object_get(template,
692 "recall-dependency", &list_start,
693 NULL);
694
695 list = list_start;
696
697 delay_audio_run = NULL;
698 count_beats_audio_run = NULL;
699
700 i_stop = 2;
701
702 for(i = 0; i < i_stop && list != NULL;){
703 GObject *dependency;
704
705 recall_dependency = AGS_RECALL_DEPENDENCY(list->data);
706
707 g_object_get(recall_dependency,
708 "dependency", &dependency,
709 NULL);
710
711 if(AGS_IS_DELAY_AUDIO_RUN(dependency)){
712 delay_audio_run = (AgsDelayAudioRun *) ags_recall_dependency_resolve(recall_dependency,
713 recall_id);
714
715 i++;
716 }else if(AGS_IS_COUNT_BEATS_AUDIO_RUN(dependency)){
717 count_beats_audio_run = (AgsCountBeatsAudioRun *) ags_recall_dependency_resolve(recall_dependency,
718 recall_id);
719
720 i++;
721 }
722
723 g_object_unref(dependency);
724
725 /* iterate */
726 list = list->next;
727 }
728
729 g_list_free_full(list_start,
730 g_object_unref);
731
732 g_object_set(G_OBJECT(recall),
733 "delay-audio-run", delay_audio_run,
734 "count-beats-audio-run", count_beats_audio_run,
735 NULL);
736
737 /* unref */
738 g_object_unref(recall_id);
739
740 g_object_unref(recall_container);
741 }
742
743 void
ags_play_notation_audio_run_alloc_input_callback(AgsDelayAudioRun * delay_audio_run,guint nth_run,gdouble delay,guint attack,AgsPlayNotationAudioRun * play_notation_audio_run)744 ags_play_notation_audio_run_alloc_input_callback(AgsDelayAudioRun *delay_audio_run,
745 guint nth_run,
746 gdouble delay, guint attack,
747 AgsPlayNotationAudioRun *play_notation_audio_run)
748 {
749 AgsAudio *audio;
750 AgsChannel *start_output, *start_input;
751 AgsChannel *selected_channel, *channel, *next_pad;
752 AgsRecycling *first_recycling, *last_recycling;
753 AgsRecycling *recycling, *next_recycling;
754 AgsRecycling *end_recycling;
755 AgsAudioSignal *audio_signal;
756 AgsNotation *notation;
757 AgsNote *note;
758 AgsRecallID *recall_id;
759 AgsRecyclingContext *recycling_context;
760 AgsPlayNotationAudio *play_notation_audio;
761 AgsDelayAudio *delay_audio;
762 AgsCountBeatsAudioRun *count_beats_audio_run;
763
764 AgsTimestamp *timestamp;
765
766 GObject *output_soundcard;
767
768 GList *start_current_position, *current_position;
769 GList *start_list, *list;
770
771 gchar *str;
772
773 guint audio_flags;
774 guint pads;
775 guint64 notation_counter;
776 guint output_pads, input_pads;
777 guint audio_channel;
778 guint samplerate;
779 guint i;
780
781 GRecMutex *audio_mutex;
782 GRecMutex *channel_mutex;
783 GRecMutex *recycling_mutex;
784
785 if(delay != 0.0){
786 // g_message("d %f", delay);
787 return;
788 }
789
790 audio = NULL;
791
792 g_object_get(play_notation_audio_run,
793 "audio", &audio,
794 NULL);
795
796 g_object_get(audio,
797 "notation", &start_list,
798 NULL);
799
800 if(start_list == NULL){
801 g_object_unref(audio);
802
803 return;
804 }
805
806 /* get some fields */
807 recall_id = NULL;
808 recycling_context = NULL;
809
810 play_notation_audio = NULL;
811
812 output_soundcard = NULL;
813
814 delay_audio = NULL;
815 delay_audio_run = NULL;
816 count_beats_audio_run = NULL;
817
818 g_object_get(play_notation_audio_run,
819 "recall-id", &recall_id,
820 "recall-audio", &play_notation_audio,
821 "output-soundcard", &output_soundcard,
822 "audio-channel", &audio_channel,
823 "samplerate", &samplerate,
824 "delay-audio-run", &delay_audio_run,
825 "count-beats-audio-run", &count_beats_audio_run,
826 NULL);
827
828 timestamp = play_notation_audio_run->timestamp;
829
830 g_object_get(recall_id,
831 "recycling-context", &recycling_context,
832 NULL);
833
834 g_object_get(delay_audio_run,
835 "recall-audio", &delay_audio,
836 NULL);
837
838 /* audio mutex */
839 audio_mutex = AGS_AUDIO_GET_OBJ_MUTEX(audio);
840
841 /* get audio channel */
842 g_rec_mutex_lock(audio_mutex);
843
844 audio_flags = audio->flags;
845
846 input_pads = audio->input_pads;
847 output_pads = audio->output_pads;
848
849 start_output = audio->output;
850
851 if(start_output != NULL){
852 g_object_ref(start_output);
853 }
854
855 start_input = audio->input;
856
857 if(start_input != NULL){
858 g_object_ref(start_input);
859 }
860
861 g_rec_mutex_unlock(audio_mutex);
862
863 /* get channel */
864 if(ags_audio_test_behaviour_flags(audio, AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_INPUT)){
865 channel = ags_channel_nth(start_input,
866 audio_channel);
867 pads = input_pads;
868 }else{
869 channel = ags_channel_nth(start_output,
870 audio_channel);
871 pads = output_pads;
872 }
873
874 /* play notation */
875 notation = NULL;
876
877 g_object_get(count_beats_audio_run,
878 "notation-counter", ¬ation_counter,
879 NULL);
880
881 ags_timestamp_set_ags_offset(timestamp,
882 AGS_NOTATION_DEFAULT_OFFSET * floor(notation_counter / AGS_NOTATION_DEFAULT_OFFSET));
883
884 list = ags_notation_find_near_timestamp(start_list, audio_channel,
885 timestamp);
886
887 if(list != NULL){
888 notation = list->data;
889 }
890
891 if(notation != NULL){
892 AgsPort *port;
893
894 gdouble notation_delay;
895
896 GValue value = {0,};
897
898 /* get notation delay */
899 g_object_get(delay_audio,
900 "notation-delay", &port,
901 NULL);
902
903 g_value_init(&value,
904 G_TYPE_DOUBLE);
905
906 ags_port_safe_read(port,
907 &value);
908
909 notation_delay = g_value_get_double(&value);
910 g_value_unset(&value);
911
912 g_object_unref(port);
913
914 /* */
915 start_current_position = ags_notation_find_offset(notation,
916 notation_counter,
917 FALSE);
918
919 current_position = start_current_position;
920
921 while(current_position != NULL){
922 AgsRecallID *child_recall_id;
923
924 GList *start_list, *list;
925
926 guint y;
927
928 note = AGS_NOTE(current_position->data);
929 g_object_get(note,
930 "y", &y,
931 NULL);
932
933 if(ags_audio_test_behaviour_flags(audio, AGS_SOUND_BEHAVIOUR_REVERSE_MAPPING)){
934 selected_channel = ags_channel_pad_nth(channel,
935 pads - y - 1);
936 }else{
937 selected_channel = ags_channel_pad_nth(channel,
938 y);
939 }
940
941 if(selected_channel == NULL){
942 current_position = current_position->next;
943
944 continue;
945 }
946
947 /* get child recall id */
948 g_object_get(selected_channel,
949 "recall-id", &start_list,
950 NULL);
951
952 list = start_list;
953 child_recall_id = NULL;
954
955 while(child_recall_id == NULL &&
956 list != NULL){
957 AgsRecallID *current_recall_id;
958 AgsRecyclingContext *current_recycling_context, *current_parent_recycling_context;
959
960 g_object_get(list->data,
961 "recycling-context", ¤t_recycling_context,
962 NULL);
963
964 g_object_get(current_recycling_context,
965 "parent", ¤t_parent_recycling_context,
966 NULL);
967
968 if(current_parent_recycling_context == recycling_context){
969 child_recall_id = (AgsRecallID *) list->data;
970 g_object_ref(child_recall_id);
971 }
972
973 if(current_recycling_context != NULL){
974 g_object_unref(current_recycling_context);
975 }
976
977 if(current_parent_recycling_context != NULL){
978 g_object_unref(current_parent_recycling_context);
979 }
980
981 /* iterate */
982 list = list->next;
983 }
984
985 g_list_free_full(start_list,
986 g_object_unref);
987
988 /* recycling */
989 g_object_get(selected_channel,
990 "first-recycling", &first_recycling,
991 "last-recycling", &last_recycling,
992 NULL);
993
994 recycling = first_recycling;
995 g_object_ref(recycling);
996
997 end_recycling = ags_recycling_next(last_recycling);
998
999 g_object_set(note,
1000 "rt-attack", attack,
1001 NULL);
1002
1003 #ifdef AGS_DEBUG
1004 g_message("playing[%u|%u]: %u | %u\n", audio_channel, selected_channel->pad, note->x[0], note->y);
1005 #endif
1006
1007 next_recycling = NULL;
1008
1009 while(recycling != end_recycling){
1010 g_object_set(note,
1011 "rt-offset", 0,
1012 NULL);
1013
1014 if(!ags_recall_global_get_rt_safe()){
1015 /* create audio signal */
1016 audio_signal = ags_audio_signal_new((GObject *) output_soundcard,
1017 (GObject *) recycling,
1018 (GObject *) child_recall_id);
1019 g_object_set(audio_signal,
1020 "note", note,
1021 NULL);
1022
1023 if(ags_audio_test_behaviour_flags(audio, AGS_SOUND_BEHAVIOUR_PATTERN_MODE)){
1024 ags_recycling_create_audio_signal_with_defaults(recycling,
1025 audio_signal,
1026 0.0, 0);
1027 }else{
1028 guint note_x0, note_x1;
1029
1030 note_x0 = notation_counter;
1031
1032 g_object_get(note,
1033 "x1", ¬e_x1,
1034 NULL);
1035
1036 /* create audio signal with frame count */
1037 ags_recycling_create_audio_signal_with_frame_count(recycling,
1038 audio_signal,
1039 (guint) (((gdouble) audio_signal->buffer_size * notation_delay) * (gdouble) (note_x1 - note_x0)),
1040 0.0, 0);
1041 }
1042
1043 audio_signal->stream_current = audio_signal->stream;
1044
1045 ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
1046
1047 /* lock and add */
1048 ags_recycling_add_audio_signal(recycling,
1049 audio_signal);
1050
1051 //g_object_unref(audio_signal);
1052 }else{
1053 GList *start_list, *list;
1054
1055 g_object_get(recycling,
1056 "audio-signal", &start_list,
1057 NULL);
1058
1059 audio_signal = NULL;
1060 list = ags_audio_signal_find_by_recall_id(start_list,
1061 (GObject *) child_recall_id);
1062
1063 if(list != NULL){
1064 audio_signal = list->data;
1065
1066 g_object_set(audio_signal,
1067 "delay", notation_delay,
1068 "note", note,
1069 NULL);
1070 }
1071
1072 g_list_free_full(start_list,
1073 g_object_unref);
1074 }
1075
1076 /* iterate */
1077 next_recycling = ags_recycling_next(recycling);
1078
1079 g_object_unref(recycling);
1080
1081 recycling = next_recycling;
1082 }
1083
1084 /* unref */
1085 g_object_unref(selected_channel);
1086
1087 if(first_recycling != NULL){
1088 g_object_unref(first_recycling);
1089 g_object_unref(last_recycling);
1090 }
1091
1092 if(end_recycling != NULL){
1093 g_object_unref(end_recycling);
1094 }
1095
1096 if(next_recycling != NULL){
1097 g_object_unref(next_recycling);
1098 }
1099
1100 if(child_recall_id != NULL){
1101 g_object_unref(child_recall_id);
1102 }
1103
1104 /* iterate */
1105 current_position = current_position->next;
1106 }
1107
1108 g_list_free_full(start_current_position,
1109 g_object_unref);
1110 }
1111
1112 /* unref */
1113 if(audio != NULL){
1114 g_object_unref(audio);
1115 }
1116
1117 if(play_notation_audio != NULL){
1118 g_object_unref(play_notation_audio);
1119 }
1120
1121 if(output_soundcard != NULL){
1122 g_object_unref(output_soundcard);
1123 }
1124
1125 if(recall_id != NULL){
1126 g_object_unref(recall_id);
1127 }
1128
1129 if(recycling_context != NULL){
1130 g_object_unref(recycling_context);
1131 }
1132
1133 if(delay_audio_run != NULL){
1134 g_object_unref(delay_audio_run);
1135 }
1136
1137 if(count_beats_audio_run != NULL){
1138 g_object_unref(count_beats_audio_run);
1139 }
1140
1141 g_list_free_full(start_list,
1142 g_object_unref);
1143
1144 if(start_output != NULL){
1145 g_object_unref(start_output);
1146 }
1147
1148 if(start_input != NULL){
1149 g_object_unref(start_input);
1150 }
1151
1152 if(channel != NULL){
1153 g_object_unref(channel);
1154 }
1155 }
1156
1157 /**
1158 * ags_play_notation_audio_run_new:
1159 * @audio: the #AgsAudio
1160 * @delay_audio_run: the #AgsDelayAudioRun dependency
1161 * @count_beats_audio_run: the #AgsCountBeatsAudioRun dependency
1162 *
1163 * Create a new instance of #AgsPlayNotationAudioRun
1164 *
1165 * Returns: the new #AgsPlayNotationAudioRun
1166 *
1167 * Since: 3.0.0
1168 */
1169 AgsPlayNotationAudioRun*
ags_play_notation_audio_run_new(AgsAudio * audio,AgsDelayAudioRun * delay_audio_run,AgsCountBeatsAudioRun * count_beats_audio_run)1170 ags_play_notation_audio_run_new(AgsAudio *audio,
1171 AgsDelayAudioRun *delay_audio_run,
1172 AgsCountBeatsAudioRun *count_beats_audio_run)
1173 {
1174 AgsPlayNotationAudioRun *play_notation_audio_run;
1175
1176 play_notation_audio_run = (AgsPlayNotationAudioRun *) g_object_new(AGS_TYPE_PLAY_NOTATION_AUDIO_RUN,
1177 "audio", audio,
1178 "delay-audio-run", delay_audio_run,
1179 "count-beats-audio-run", count_beats_audio_run,
1180 NULL);
1181
1182 return(play_notation_audio_run);
1183 }
1184