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", &notation_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", &current_recycling_context,
962 		     NULL);
963 
964 	g_object_get(current_recycling_context,
965 		     "parent", &current_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", &note_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