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_copy_pattern_audio_run.h>
21 
22 #include <ags/audio/ags_recall_container.h>
23 
24 #include <ags/audio/recall/ags_copy_pattern_audio.h>
25 
26 #include <ags/i18n.h>
27 
28 void ags_copy_pattern_audio_run_class_init(AgsCopyPatternAudioRunClass *copy_pattern_audio_run);
29 void ags_copy_pattern_audio_run_init(AgsCopyPatternAudioRun *copy_pattern_audio_run);
30 void ags_copy_pattern_audio_run_set_property(GObject *gobject,
31 					     guint prop_id,
32 					     const GValue *value,
33 					     GParamSpec *param_spec);
34 void ags_copy_pattern_audio_run_get_property(GObject *gobject,
35 					     guint prop_id,
36 					     GValue *value,
37 					     GParamSpec *param_spec);
38 void ags_copy_pattern_audio_run_dispose(GObject *gobject);
39 void ags_copy_pattern_audio_run_finalize(GObject *gobject);
40 
41 void ags_copy_pattern_audio_run_resolve_dependency(AgsRecall *recall);
42 void ags_copy_pattern_audio_run_notify_dependency(AgsRecall *recall,
43 						  guint dependency, gboolean increase);
44 
45 /**
46  * SECTION:ags_copy_pattern_audio_run
47  * @short_description: copy pattern
48  * @title: AgsCopyPatternAudioRun
49  * @section_id:
50  * @include: ags/audio/recall/ags_copy_pattern_audio_run.h
51  *
52  * The #AgsCopyPatternAudioRun class copy pattern.
53  */
54 
55 enum{
56   PROP_0,
57   PROP_DELAY_AUDIO_RUN,
58   PROP_COUNT_BEATS_AUDIO_RUN,
59 };
60 
61 static gpointer ags_copy_pattern_audio_run_parent_class = NULL;
62 
63 GType
ags_copy_pattern_audio_run_get_type()64 ags_copy_pattern_audio_run_get_type()
65 {
66   static volatile gsize g_define_type_id__volatile = 0;
67 
68   if(g_once_init_enter (&g_define_type_id__volatile)){
69     GType ags_type_copy_pattern_audio_run = 0;
70 
71     static const GTypeInfo ags_copy_pattern_audio_run_info = {
72       sizeof(AgsCopyPatternAudioRunClass),
73       NULL, /* base_init */
74       NULL, /* base_finalize */
75       (GClassInitFunc) ags_copy_pattern_audio_run_class_init,
76       NULL, /* class_finalize */
77       NULL, /* class_data */
78       sizeof(AgsCopyPatternAudioRun),
79       0,    /* n_preallocs */
80       (GInstanceInitFunc) ags_copy_pattern_audio_run_init,
81     };
82 
83     ags_type_copy_pattern_audio_run = g_type_register_static(AGS_TYPE_RECALL_AUDIO_RUN,
84 							     "AgsCopyPatternAudioRun",
85 							     &ags_copy_pattern_audio_run_info,
86 							     0);
87 
88     g_once_init_leave(&g_define_type_id__volatile, ags_type_copy_pattern_audio_run);
89   }
90 
91   return g_define_type_id__volatile;
92 }
93 
94 void
ags_copy_pattern_audio_run_class_init(AgsCopyPatternAudioRunClass * copy_pattern_audio_run)95 ags_copy_pattern_audio_run_class_init(AgsCopyPatternAudioRunClass *copy_pattern_audio_run)
96 {
97   GObjectClass *gobject;
98   AgsRecallClass *recall;
99 
100   GParamSpec *param_spec;
101 
102   ags_copy_pattern_audio_run_parent_class = g_type_class_peek_parent(copy_pattern_audio_run);
103 
104   /* GObjectClass */
105   gobject = (GObjectClass *) copy_pattern_audio_run;
106 
107   gobject->set_property = ags_copy_pattern_audio_run_set_property;
108   gobject->get_property = ags_copy_pattern_audio_run_get_property;
109 
110   gobject->dispose = ags_copy_pattern_audio_run_dispose;
111   gobject->finalize = ags_copy_pattern_audio_run_finalize;
112 
113   /* properties */
114   /**
115    * AgsCopyPatternAudioRun:delay-audio-run:
116    *
117    * The delay audio run dependency.
118    *
119    * Since: 3.0.0
120    */
121   param_spec = g_param_spec_object("delay-audio-run",
122 				   i18n_pspec("assigned AgsDelayAudioRun"),
123 				   i18n_pspec("the AgsDelayAudioRun which emits alloc signal"),
124 				   AGS_TYPE_DELAY_AUDIO_RUN,
125 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
126   g_object_class_install_property(gobject,
127 				  PROP_DELAY_AUDIO_RUN,
128 				  param_spec);
129 
130   /**
131    * AgsCopyPatternAudioRun:count-beats-audio-run:
132    *
133    * The count beats audio run dependency.
134    *
135    * Since: 3.0.0
136    */
137   param_spec = g_param_spec_object("count-beats-audio-run",
138 				   i18n_pspec("assigned AgsCountBeatsAudioRun"),
139 				   i18n_pspec("the AgsCountBeatsAudioRun which emits beat signal"),
140 				   AGS_TYPE_COUNT_BEATS_AUDIO_RUN,
141 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
142   g_object_class_install_property(gobject,
143 				  PROP_COUNT_BEATS_AUDIO_RUN,
144 				  param_spec);
145 
146   /* AgsRecallClass */
147   recall = (AgsRecallClass *) copy_pattern_audio_run;
148 
149   recall->resolve_dependency = ags_copy_pattern_audio_run_resolve_dependency;
150   recall->notify_dependency = ags_copy_pattern_audio_run_notify_dependency;
151 }
152 
153 void
ags_copy_pattern_audio_run_init(AgsCopyPatternAudioRun * copy_pattern_audio_run)154 ags_copy_pattern_audio_run_init(AgsCopyPatternAudioRun *copy_pattern_audio_run)
155 {
156   ags_recall_set_ability_flags((AgsRecall *) copy_pattern_audio_run, (AGS_SOUND_ABILITY_SEQUENCER));
157 
158   AGS_RECALL(copy_pattern_audio_run)->name = "ags-copy-pattern";
159   AGS_RECALL(copy_pattern_audio_run)->version = AGS_RECALL_DEFAULT_VERSION;
160   AGS_RECALL(copy_pattern_audio_run)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
161   AGS_RECALL(copy_pattern_audio_run)->xml_type = "ags-copy-pattern-audio-run";
162   AGS_RECALL(copy_pattern_audio_run)->port = NULL;
163 
164   copy_pattern_audio_run->hide_ref = 0;
165   copy_pattern_audio_run->hide_ref_counter = 0;
166 
167   copy_pattern_audio_run->delay_audio_run = NULL;
168   copy_pattern_audio_run->count_beats_audio_run = NULL;
169 }
170 
171 void
ags_copy_pattern_audio_run_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)172 ags_copy_pattern_audio_run_set_property(GObject *gobject,
173 					guint prop_id,
174 					const GValue *value,
175 					GParamSpec *param_spec)
176 {
177   AgsCopyPatternAudioRun *copy_pattern_audio_run;
178 
179   GRecMutex *recall_mutex;
180 
181   copy_pattern_audio_run = AGS_COPY_PATTERN_AUDIO_RUN(gobject);
182 
183   /* get recall mutex */
184   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(copy_pattern_audio_run);
185 
186   switch(prop_id){
187   case PROP_DELAY_AUDIO_RUN:
188     {
189       AgsDelayAudioRun *delay_audio_run, *old_delay_audio_run;
190 
191       gboolean is_template;
192 
193       delay_audio_run = (AgsDelayAudioRun *) g_value_get_object(value);
194       old_delay_audio_run = NULL;
195 
196       g_rec_mutex_lock(recall_mutex);
197 
198       if(copy_pattern_audio_run->delay_audio_run == delay_audio_run){
199 	g_rec_mutex_unlock(recall_mutex);
200 
201 	return;
202       }
203 
204       if(copy_pattern_audio_run->delay_audio_run != NULL){
205 	old_delay_audio_run = copy_pattern_audio_run->delay_audio_run;
206 
207 	g_object_unref(G_OBJECT(copy_pattern_audio_run->delay_audio_run));
208       }
209 
210       if(delay_audio_run != NULL){
211 	g_object_ref(G_OBJECT(delay_audio_run));
212       }
213 
214       copy_pattern_audio_run->delay_audio_run = delay_audio_run;
215 
216       g_rec_mutex_unlock(recall_mutex);
217 
218       /* dependency */
219       if(ags_recall_test_flags((AgsRecall *) delay_audio_run, AGS_RECALL_TEMPLATE)){
220 	is_template = TRUE;
221       }else{
222 	is_template = FALSE;
223       }
224 
225       if(is_template){
226 	if(old_delay_audio_run != NULL){
227 	  AgsRecallDependency *recall_dependency;
228 
229 	  GList *list;
230 
231 	  recall_dependency = NULL;
232 	  list = ags_recall_dependency_find_dependency(AGS_RECALL(copy_pattern_audio_run)->recall_dependency,
233 						       (GObject *) old_delay_audio_run);
234 
235 	  if(list != NULL){
236 	    recall_dependency = list->data;
237 	  }
238 
239 	  ags_recall_remove_recall_dependency(AGS_RECALL(copy_pattern_audio_run),
240 					      recall_dependency);
241 	}
242       }
243 
244       if(is_template &&
245 	 delay_audio_run != NULL){
246 	ags_recall_add_recall_dependency(AGS_RECALL(copy_pattern_audio_run),
247 					 ags_recall_dependency_new((GObject *) delay_audio_run));
248       }
249     }
250     break;
251   case PROP_COUNT_BEATS_AUDIO_RUN:
252     {
253       AgsCountBeatsAudioRun *count_beats_audio_run, *old_count_beats_audio_run;
254 
255       gboolean is_template;
256 
257       count_beats_audio_run = (AgsCountBeatsAudioRun *) g_value_get_object(value);
258       old_count_beats_audio_run = NULL;
259 
260       g_rec_mutex_lock(recall_mutex);
261 
262       if(copy_pattern_audio_run->count_beats_audio_run == count_beats_audio_run){
263 	g_rec_mutex_unlock(recall_mutex);
264 
265 	return;
266       }
267 
268       if(copy_pattern_audio_run->count_beats_audio_run != NULL){
269 	old_count_beats_audio_run = copy_pattern_audio_run->count_beats_audio_run;
270 
271 	g_object_unref(G_OBJECT(copy_pattern_audio_run->count_beats_audio_run));
272       }
273 
274       if(count_beats_audio_run != NULL){
275 	g_object_ref(G_OBJECT(count_beats_audio_run));
276       }
277 
278       copy_pattern_audio_run->count_beats_audio_run = count_beats_audio_run;
279 
280       g_rec_mutex_unlock(recall_mutex);
281 
282       /* check template */
283       if(count_beats_audio_run != NULL &&
284 	 ags_recall_test_flags((AgsRecall *) count_beats_audio_run, AGS_RECALL_TEMPLATE)){
285 	is_template = TRUE;
286       }else{
287 	is_template = FALSE;
288       }
289 
290       /* dependency - remove */
291       if(is_template){
292 	if(old_count_beats_audio_run != NULL){
293 	  AgsRecallDependency *recall_dependency;
294 
295 	  GList *list;
296 
297 	  recall_dependency = NULL;
298 	  list = ags_recall_dependency_find_dependency(AGS_RECALL(copy_pattern_audio_run)->recall_dependency,
299 						       (GObject *) old_count_beats_audio_run);
300 
301 	  if(list != NULL){
302 	    recall_dependency = list->data;
303 	  }
304 
305 	  ags_recall_remove_recall_dependency(AGS_RECALL(copy_pattern_audio_run),
306 					      recall_dependency);
307 	}
308       }
309 
310       /* dependency - add */
311       if(is_template &&
312 	 count_beats_audio_run != NULL){
313 	ags_recall_add_recall_dependency(AGS_RECALL(copy_pattern_audio_run),
314 					 ags_recall_dependency_new((GObject *) count_beats_audio_run));
315       }
316     }
317     break;
318   default:
319     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
320     break;
321   };
322 }
323 
324 void
ags_copy_pattern_audio_run_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)325 ags_copy_pattern_audio_run_get_property(GObject *gobject,
326 					guint prop_id,
327 					GValue *value,
328 					GParamSpec *param_spec)
329 {
330   AgsCopyPatternAudioRun *copy_pattern_audio_run;
331 
332   GRecMutex *recall_mutex;
333 
334   copy_pattern_audio_run = AGS_COPY_PATTERN_AUDIO_RUN(gobject);
335 
336   /* get recall mutex */
337   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(copy_pattern_audio_run);
338 
339   switch(prop_id){
340   case PROP_DELAY_AUDIO_RUN:
341     {
342       g_rec_mutex_lock(recall_mutex);
343 
344       g_value_set_object(value, copy_pattern_audio_run->delay_audio_run);
345 
346       g_rec_mutex_unlock(recall_mutex);
347     }
348     break;
349   case PROP_COUNT_BEATS_AUDIO_RUN:
350     {
351       g_rec_mutex_lock(recall_mutex);
352 
353       g_value_set_object(value, copy_pattern_audio_run->count_beats_audio_run);
354 
355       g_rec_mutex_unlock(recall_mutex);
356     }
357     break;
358   default:
359     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
360     break;
361   };
362 }
363 
364 void
ags_copy_pattern_audio_run_dispose(GObject * gobject)365 ags_copy_pattern_audio_run_dispose(GObject *gobject)
366 {
367   AgsCopyPatternAudioRun *copy_pattern_audio_run;
368 
369   copy_pattern_audio_run = AGS_COPY_PATTERN_AUDIO_RUN(gobject);
370 
371   /* delay audio run */
372   if(copy_pattern_audio_run->delay_audio_run != NULL){
373     g_object_unref(copy_pattern_audio_run->delay_audio_run);
374 
375     copy_pattern_audio_run->delay_audio_run = NULL;
376   }
377 
378   /* count beats audio run */
379   if(copy_pattern_audio_run->count_beats_audio_run != NULL){
380     g_object_unref(copy_pattern_audio_run->count_beats_audio_run);
381 
382     copy_pattern_audio_run->count_beats_audio_run = NULL;
383   }
384 
385   /* call parent */
386   G_OBJECT_CLASS(ags_copy_pattern_audio_run_parent_class)->dispose(gobject);
387 }
388 
389 void
ags_copy_pattern_audio_run_finalize(GObject * gobject)390 ags_copy_pattern_audio_run_finalize(GObject *gobject)
391 {
392   AgsCopyPatternAudioRun *copy_pattern_audio_run;
393 
394   copy_pattern_audio_run = AGS_COPY_PATTERN_AUDIO_RUN(gobject);
395 
396   /* delay audio run */
397   if(copy_pattern_audio_run->delay_audio_run != NULL){
398     g_object_unref(copy_pattern_audio_run->delay_audio_run);
399   }
400 
401   /* count beats audio run */
402   if(copy_pattern_audio_run->count_beats_audio_run != NULL){
403     g_object_unref(copy_pattern_audio_run->count_beats_audio_run);
404   }
405 
406   /* call parent */
407   G_OBJECT_CLASS(ags_copy_pattern_audio_run_parent_class)->finalize(gobject);
408 }
409 
410 void
ags_copy_pattern_audio_run_resolve_dependency(AgsRecall * recall)411 ags_copy_pattern_audio_run_resolve_dependency(AgsRecall *recall)
412 {
413   AgsRecall *template;
414   AgsRecallContainer *recall_container;
415   AgsRecallID *parent_recall_id;
416   AgsRecallID *recall_id;
417   AgsRecyclingContext *parent_recycling_context;
418   AgsRecyclingContext *recycling_context;
419   AgsRecallDependency *recall_dependency;
420 
421   AgsDelayAudioRun *delay_audio_run;
422   AgsCountBeatsAudioRun *count_beats_audio_run;
423 
424   GList *list_start, *list;
425 
426   guint i, i_stop;
427 
428   g_object_get(recall,
429 	       "recall-container", &recall_container,
430 	       NULL);
431 
432   g_object_get(recall_container,
433 	       "recall-audio-run", &list_start,
434 	       NULL);
435 
436   list = ags_recall_find_template(list_start);
437 
438   if(list == NULL){
439     g_warning("AgsRecallClass::resolve - missing dependency");
440 
441     g_object_unref(recall_container);
442 
443     g_list_free_full(list_start,
444 		     g_object_unref);
445 
446     return;
447   }
448 
449   template = AGS_RECALL(list->data);
450 
451   g_list_free_full(list_start,
452 		   g_object_unref);
453 
454   g_object_get(template,
455 	       "recall-dependency", &list_start,
456 	       NULL);
457 
458   g_object_get(recall,
459 	       "recall-id", &recall_id,
460 	       NULL);
461 
462   g_object_get(recall_id,
463 	       "recycling-context", &recycling_context,
464 	       NULL);
465 
466   g_object_get(recycling_context,
467 	       "parent", &parent_recycling_context,
468 	       NULL);
469 
470   g_object_get(parent_recycling_context,
471 	       "recall-id", &parent_recall_id,
472 	       NULL);
473 
474   /* prepare to resolve */
475   delay_audio_run = NULL;
476   count_beats_audio_run = NULL;
477 
478   list = list_start;
479 
480   i_stop = 2;
481 
482   for(i = 0; i < i_stop && list != NULL;){
483     GObject *dependency;
484 
485     recall_dependency = AGS_RECALL_DEPENDENCY(list->data);
486 
487     g_object_get(recall_dependency,
488 		 "dependency", &dependency,
489 		 NULL);
490 
491     if(AGS_IS_DELAY_AUDIO_RUN(dependency)){
492       delay_audio_run = (AgsDelayAudioRun *) ags_recall_dependency_resolve(recall_dependency,
493 									   parent_recall_id);
494 
495       i++;
496     }else if(AGS_IS_COUNT_BEATS_AUDIO_RUN(dependency)){
497       count_beats_audio_run = (AgsCountBeatsAudioRun *) ags_recall_dependency_resolve(recall_dependency,
498 										      parent_recall_id);
499 
500       i++;
501     }
502 
503     g_object_unref(dependency);
504 
505     list = list->next;
506   }
507 
508   g_object_set(G_OBJECT(recall),
509 	       "delay-audio-run", delay_audio_run,
510 	       "count-beats-audio-run", count_beats_audio_run,
511 	       NULL);
512 
513   g_object_unref(recall_container);
514 
515   g_list_free_full(list_start,
516 		   g_object_unref);
517 
518   g_object_unref(recall_id);
519 
520   g_object_unref(recycling_context);
521   g_object_unref(parent_recycling_context);
522 
523   g_object_unref(parent_recall_id);
524 }
525 
526 void
ags_copy_pattern_audio_run_notify_dependency(AgsRecall * recall,guint dependency,gboolean increase)527 ags_copy_pattern_audio_run_notify_dependency(AgsRecall *recall,
528 					     guint dependency, gboolean increase)
529 {
530   AgsCopyPatternAudioRun *copy_pattern_audio_run;
531 
532   GRecMutex *recall_mutex;
533 
534   copy_pattern_audio_run = AGS_COPY_PATTERN_AUDIO_RUN(recall);
535 
536   /* get mutex */
537   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(copy_pattern_audio_run);
538 
539   /* notify */
540   g_rec_mutex_lock(recall_mutex);
541 
542   switch(dependency){
543   case AGS_RECALL_NOTIFY_RUN:
544     break;
545   case AGS_RECALL_NOTIFY_AUDIO:
546     break;
547   case AGS_RECALL_NOTIFY_AUDIO_RUN:
548     break;
549   case AGS_RECALL_NOTIFY_CHANNEL:
550     break;
551   case AGS_RECALL_NOTIFY_CHANNEL_RUN:
552     if(increase){
553       copy_pattern_audio_run->hide_ref += 1;
554     }else{
555       copy_pattern_audio_run->hide_ref -= 1;
556     }
557     break;
558   default:
559     g_message("ags_copy_pattern_audio_run.c - ags_copy_pattern_audio_run_notify: unknown notify");
560   }
561 
562   g_rec_mutex_unlock(recall_mutex);
563 }
564 
565 /**
566  * ags_copy_pattern_audio_run_new:
567  * @audio: the #AgsAudio
568  * @delay_audio_run: the #AgsDelayAudioRun dependency
569  * @count_beats_audio_run: the #AgsCountBeatsAudioRun dependency
570  *
571  * Create a new instance of #AgsCopyPatternAudioRun
572  *
573  * Returns: the new #AgsCopyPatternAudioRun
574  *
575  * Since: 3.0.0
576  */
577 AgsCopyPatternAudioRun*
ags_copy_pattern_audio_run_new(AgsAudio * audio,AgsDelayAudioRun * delay_audio_run,AgsCountBeatsAudioRun * count_beats_audio_run)578 ags_copy_pattern_audio_run_new(AgsAudio *audio,
579 			       AgsDelayAudioRun *delay_audio_run,
580 			       AgsCountBeatsAudioRun *count_beats_audio_run)
581 {
582   AgsCopyPatternAudioRun *copy_pattern_audio_run;
583 
584   copy_pattern_audio_run = (AgsCopyPatternAudioRun *) g_object_new(AGS_TYPE_COPY_PATTERN_AUDIO_RUN,
585 								   "audio", audio,
586 								   "delay-audio-run", delay_audio_run,
587 								   "count-beats-audio-run", count_beats_audio_run,
588 								   NULL);
589 
590   return(copy_pattern_audio_run);
591 }
592