1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2020 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSequencer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/audio/ags_pattern.h>
21 
22 #include <ags/audio/ags_channel.h>
23 #include <ags/audio/ags_port.h>
24 
25 #include <stdarg.h>
26 #include <math.h>
27 #include <string.h>
28 
29 void ags_pattern_class_init(AgsPatternClass *pattern_class);
30 void ags_pattern_connectable_interface_init(AgsConnectableInterface *connectable);
31 void ags_pattern_tactable_interface_init(AgsTactableInterface *tactable);
32 void ags_pattern_init(AgsPattern *pattern);
33 void ags_pattern_set_property(GObject *gobject,
34 			      guint prop_id,
35 			      const GValue *value,
36 			      GParamSpec *param_spec);
37 void ags_pattern_get_property(GObject *gobject,
38 			      guint prop_id,
39 			      GValue *value,
40 			      GParamSpec *param_spec);
41 void ags_pattern_dispose(GObject *gobject);
42 void ags_pattern_finalize(GObject *gobject);
43 
44 AgsUUID* ags_pattern_get_uuid(AgsConnectable *connectable);
45 gboolean ags_pattern_has_resource(AgsConnectable *connectable);
46 gboolean ags_pattern_is_ready(AgsConnectable *connectable);
47 void ags_pattern_add_to_registry(AgsConnectable *connectable);
48 void ags_pattern_remove_from_registry(AgsConnectable *connectable);
49 xmlNode* ags_pattern_list_resource(AgsConnectable *connectable);
50 xmlNode* ags_pattern_xml_compose(AgsConnectable *connectable);
51 void ags_pattern_xml_parse(AgsConnectable *connectable,
52 			   xmlNode *node);
53 gboolean ags_pattern_is_connected(AgsConnectable *connectable);
54 void ags_pattern_connect(AgsConnectable *connectable);
55 void ags_pattern_disconnect(AgsConnectable *connectable);
56 
57 void ags_pattern_change_bpm(AgsTactable *tactable, gdouble new_bpm, gdouble old_bpm);
58 
59 /**
60  * SECTION:ags_pattern
61  * @short_description: Pattern representing tones
62  * @title: AgsPattern
63  * @section_id:
64  * @include: ags/audio/ags_pattern.h
65  *
66  * #AgsPattern represents an audio pattern of tones.
67  */
68 
69 enum{
70   PROP_0,
71   PROP_CHANNEL,
72   PROP_PORT,
73   PROP_FIRST_INDEX,
74   PROP_SECOND_INDEX,
75   PROP_OFFSET,
76   PROP_CURRENT_BIT,
77   PROP_TIMESTAMP,
78 };
79 
80 static gpointer ags_pattern_parent_class = NULL;
81 
82 GType
ags_pattern_get_type(void)83 ags_pattern_get_type (void)
84 {
85   static volatile gsize g_define_type_id__volatile = 0;
86 
87   if(g_once_init_enter (&g_define_type_id__volatile)){
88     GType ags_type_pattern = 0;
89 
90     static const GTypeInfo ags_pattern_info = {
91       sizeof (AgsPatternClass),
92       NULL, /* base_init */
93       NULL, /* base_finalize */
94       (GClassInitFunc) ags_pattern_class_init,
95       NULL, /* class_finalize */
96       NULL, /* class_data */
97       sizeof (AgsPattern),
98       0,    /* n_preallocs */
99       (GInstanceInitFunc) ags_pattern_init,
100     };
101 
102     static const GInterfaceInfo ags_connectable_interface_info = {
103       (GInterfaceInitFunc) ags_pattern_connectable_interface_init,
104       NULL, /* interface_finalize */
105       NULL, /* interface_data */
106     };
107 
108     static const GInterfaceInfo ags_tactable_interface_info = {
109       (GInterfaceInitFunc) ags_pattern_tactable_interface_init,
110       NULL, /* interface_finalize */
111       NULL, /* interface_data */
112     };
113 
114     ags_type_pattern = g_type_register_static(G_TYPE_OBJECT,
115 					      "AgsPattern",
116 					      &ags_pattern_info,
117 					      0);
118 
119     g_type_add_interface_static(ags_type_pattern,
120 				AGS_TYPE_CONNECTABLE,
121 				&ags_connectable_interface_info);
122 
123     g_type_add_interface_static(ags_type_pattern,
124 				AGS_TYPE_TACTABLE,
125 				&ags_tactable_interface_info);
126 
127     g_once_init_leave(&g_define_type_id__volatile, ags_type_pattern);
128   }
129 
130   return g_define_type_id__volatile;
131 }
132 
133 void
ags_pattern_class_init(AgsPatternClass * pattern)134 ags_pattern_class_init(AgsPatternClass *pattern)
135 {
136   GObjectClass *gobject;
137   GParamSpec *param_spec;
138 
139   ags_pattern_parent_class = g_type_class_peek_parent(pattern);
140 
141   gobject = (GObjectClass *) pattern;
142 
143   gobject->set_property = ags_pattern_set_property;
144   gobject->get_property = ags_pattern_get_property;
145 
146   gobject->dispose = ags_pattern_dispose;
147   gobject->finalize = ags_pattern_finalize;
148 
149   /* properties */
150   /**
151    * AgsPattern:channel:
152    *
153    * The pattern's channel.
154    *
155    * Since: 3.3.0
156    */
157   param_spec = g_param_spec_object("channel",
158 				   "channel of pattern",
159 				   "The channel of pattern",
160 				   AGS_TYPE_CHANNEL,
161 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
162   g_object_class_install_property(gobject,
163 				  PROP_CHANNEL,
164 				  param_spec);
165 
166   /**
167    * AgsPattern:port:
168    *
169    * The pattern's port.
170    *
171    * Since: 3.0.0
172    */
173   param_spec = g_param_spec_object("port",
174 				   "port of pattern",
175 				   "The port of pattern",
176 				   AGS_TYPE_PORT,
177 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
178   g_object_class_install_property(gobject,
179 				  PROP_PORT,
180 				  param_spec);
181 
182   /**
183    * AgsPattern:first-index:
184    *
185    * Selected bank 0.
186    *
187    * Since: 3.0.0
188    */
189   param_spec = g_param_spec_uint("first-index",
190 				 "the first index",
191 				 "The first index to select pattern",
192 				 0, 256,
193 				 0,
194 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
195   g_object_class_install_property(gobject,
196 				  PROP_FIRST_INDEX,
197 				  param_spec);
198 
199   /**
200    * AgsPattern:second-index:
201    *
202    * Selected bank 1.
203    *
204    * Since: 3.0.0
205    */
206   param_spec = g_param_spec_uint("second-index",
207 				 "the second index",
208 				 "The second index to select pattern",
209 				 0, 256,
210 				 0,
211 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
212   g_object_class_install_property(gobject,
213 				  PROP_SECOND_INDEX,
214 				  param_spec);
215 
216   /**
217    * AgsPattern:offset:
218    *
219    * Position of pattern.
220    *
221    * Since: 3.0.0
222    */
223   param_spec = g_param_spec_uint("offset",
224 				 "the offset",
225 				 "The offset within the pattern",
226 				 0, 65535,
227 				 0,
228 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
229   g_object_class_install_property(gobject,
230 				  PROP_OFFSET,
231 				  param_spec);
232 
233   /**
234    * AgsPattern:current-bit:
235    *
236    * Offset of current position.
237    *
238    * Since: 3.0.0
239    */
240   param_spec = g_param_spec_boolean("current-bit",
241 				    "current bit for offset",
242 				    "The current bit for offset",
243 				    FALSE,
244 				    G_PARAM_READABLE);
245   g_object_class_install_property(gobject,
246 				  PROP_CURRENT_BIT,
247 				  param_spec);
248 
249   /**
250    * AgsPattern:timestamp:
251    *
252    * The pattern's timestamp.
253    *
254    * Since: 3.0.0
255    */
256   param_spec = g_param_spec_object("timestamp",
257 				   "timestamp of pattern",
258 				   "The timestamp of pattern",
259 				   AGS_TYPE_TIMESTAMP,
260 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
261   g_object_class_install_property(gobject,
262 				  PROP_TIMESTAMP,
263 				  param_spec);
264 }
265 
266 void
ags_pattern_connectable_interface_init(AgsConnectableInterface * connectable)267 ags_pattern_connectable_interface_init(AgsConnectableInterface *connectable)
268 {
269   connectable->get_uuid = ags_pattern_get_uuid;
270   connectable->has_resource = ags_pattern_has_resource;
271 
272   connectable->is_ready = ags_pattern_is_ready;
273   connectable->add_to_registry = ags_pattern_add_to_registry;
274   connectable->remove_from_registry = ags_pattern_remove_from_registry;
275 
276   connectable->list_resource = ags_pattern_list_resource;
277   connectable->xml_compose = ags_pattern_xml_compose;
278   connectable->xml_parse = ags_pattern_xml_parse;
279 
280   connectable->is_connected = ags_pattern_is_connected;
281   connectable->connect = ags_pattern_connect;
282   connectable->disconnect = ags_pattern_disconnect;
283 
284   connectable->connect_connection = NULL;
285   connectable->disconnect_connection = NULL;
286 }
287 
288 void
ags_pattern_tactable_interface_init(AgsTactableInterface * tactable)289 ags_pattern_tactable_interface_init(AgsTactableInterface *tactable)
290 {
291   tactable->change_bpm = ags_pattern_change_bpm;
292 }
293 
294 void
ags_pattern_init(AgsPattern * pattern)295 ags_pattern_init(AgsPattern *pattern)
296 {
297   /* base initialization */
298   pattern->flags = 0;
299 
300   /* pattern mutex */
301   g_rec_mutex_init(&(pattern->obj_mutex));
302 
303   /* channel */
304   pattern->channel = NULL;
305 
306   /* timestamp */
307   pattern->timestamp = NULL;
308 
309   /* dimension and pattern */
310   pattern->dim[0] = 0;
311   pattern->dim[1] = 0;
312   pattern->dim[2] = 0;
313 
314   pattern->pattern = NULL;
315 
316   /* port */
317   pattern->port = NULL;
318 
319   /* indices */
320   pattern->i = 0;
321   pattern->j = 0;
322   pattern->bit = 0;
323 
324   /* note */
325   pattern->note = NULL;
326 }
327 
328 void
ags_pattern_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)329 ags_pattern_set_property(GObject *gobject,
330 			 guint prop_id,
331 			 const GValue *value,
332 			 GParamSpec *param_spec)
333 {
334   AgsPattern *pattern;
335 
336   GRecMutex *pattern_mutex;
337 
338   pattern = AGS_PATTERN(gobject);
339 
340   /* get pattern mutex */
341   pattern_mutex = AGS_PATTERN_GET_OBJ_MUTEX(pattern);
342 
343   switch(prop_id){
344   case PROP_CHANNEL:
345   {
346     AgsChannel *channel;
347 
348     channel = (AgsChannel *) g_value_get_object(value);
349 
350     g_rec_mutex_lock(pattern_mutex);
351 
352     if(channel == pattern->channel){
353       g_rec_mutex_unlock(pattern_mutex);
354 
355       return;
356     }
357 
358     if(pattern->channel != NULL){
359       g_object_unref(G_OBJECT(pattern->channel));
360     }
361 
362     if(channel != NULL){
363       g_object_ref(G_OBJECT(channel));
364     }
365 
366     pattern->channel = channel;
367 
368     g_rec_mutex_unlock(pattern_mutex);
369   }
370   break;
371   case PROP_FIRST_INDEX:
372   {
373     guint i;
374 
375     i = g_value_get_uint(value);
376 
377     g_rec_mutex_lock(pattern_mutex);
378 
379     pattern->i = i;
380 
381     g_rec_mutex_unlock(pattern_mutex);
382   }
383   break;
384   case PROP_SECOND_INDEX:
385   {
386     guint j;
387 
388     j = g_value_get_uint(value);
389 
390     g_rec_mutex_lock(pattern_mutex);
391 
392     pattern->j = j;
393 
394     g_rec_mutex_unlock(pattern_mutex);
395   }
396   break;
397   case PROP_OFFSET:
398   {
399     guint bit;
400 
401     bit = g_value_get_uint(value);
402 
403     g_rec_mutex_lock(pattern_mutex);
404 
405     pattern->bit = bit;
406 
407     g_rec_mutex_unlock(pattern_mutex);
408   }
409   break;
410   case PROP_TIMESTAMP:
411   {
412     AgsTimestamp *timestamp;
413 
414     timestamp = (AgsTimestamp *) g_value_get_object(value);
415 
416     g_rec_mutex_lock(pattern_mutex);
417 
418     if(timestamp == pattern->timestamp){
419       g_rec_mutex_unlock(pattern_mutex);
420 
421       return;
422     }
423 
424     if(pattern->timestamp != NULL){
425       g_object_unref(G_OBJECT(pattern->timestamp));
426     }
427 
428     if(timestamp != NULL){
429       g_object_ref(G_OBJECT(timestamp));
430     }
431 
432     pattern->timestamp = timestamp;
433 
434     g_rec_mutex_unlock(pattern_mutex);
435   }
436   break;
437   default:
438     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
439     break;
440   }
441 }
442 
443 void
ags_pattern_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)444 ags_pattern_get_property(GObject *gobject,
445 			 guint prop_id,
446 			 GValue *value,
447 			 GParamSpec *param_spec)
448 {
449   AgsPattern *pattern;
450 
451   GRecMutex *pattern_mutex;
452 
453   pattern = AGS_PATTERN(gobject);
454 
455   /* get pattern mutex */
456   pattern_mutex = AGS_PATTERN_GET_OBJ_MUTEX(pattern);
457 
458   switch(prop_id){
459   case PROP_CHANNEL:
460   {
461     g_rec_mutex_lock(pattern_mutex);
462 
463     g_value_set_object(value,
464 		       pattern->channel);
465 
466     g_rec_mutex_unlock(pattern_mutex);
467   }
468   break;
469   case PROP_PORT:
470   {
471     g_rec_mutex_lock(pattern_mutex);
472 
473     g_value_set_object(value, pattern->port);
474 
475     g_rec_mutex_unlock(pattern_mutex);
476   }
477   break;
478   case PROP_FIRST_INDEX:
479   {
480     g_rec_mutex_lock(pattern_mutex);
481 
482     g_value_set_uint(value, pattern->i);
483 
484     g_rec_mutex_unlock(pattern_mutex);
485   }
486   break;
487   case PROP_SECOND_INDEX:
488   {
489     g_rec_mutex_lock(pattern_mutex);
490 
491     g_value_set_uint(value, pattern->j);
492 
493     g_rec_mutex_unlock(pattern_mutex);
494   }
495   break;
496   case PROP_OFFSET:
497   {
498     g_rec_mutex_lock(pattern_mutex);
499 
500     g_value_set_uint(value, pattern->bit);
501 
502     g_rec_mutex_unlock(pattern_mutex);
503   }
504   break;
505   case PROP_CURRENT_BIT:
506   {
507     guint i, j;
508     guint bit;
509 
510     g_rec_mutex_lock(pattern_mutex);
511 
512     i = pattern->i;
513     j = pattern->j;
514     bit = pattern->bit;
515 
516     g_rec_mutex_unlock(pattern_mutex);
517 
518     g_value_set_boolean(value, ags_pattern_get_bit(pattern,
519 						   i,
520 						   j,
521 						   bit));
522   }
523   break;
524   case PROP_TIMESTAMP:
525   {
526     g_rec_mutex_lock(pattern_mutex);
527 
528     g_value_set_object(value,
529 		       pattern->timestamp);
530 
531     g_rec_mutex_unlock(pattern_mutex);
532   }
533   break;
534   default:
535     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
536     break;
537   }
538 }
539 
540 void
ags_pattern_dispose(GObject * gobject)541 ags_pattern_dispose(GObject *gobject)
542 {
543   AgsPattern *pattern;
544 
545   pattern = AGS_PATTERN(gobject);
546 
547   /* channel */
548   if(pattern->channel != NULL){
549     g_object_unref(G_OBJECT(pattern->channel));
550 
551     pattern->channel = NULL;
552   }
553 
554   /* timestamp */
555   if(pattern->timestamp != NULL){
556     g_object_run_dispose(G_OBJECT(pattern->timestamp));
557 
558     g_object_unref(G_OBJECT(pattern->timestamp));
559 
560     pattern->timestamp = NULL;
561   }
562 
563   /* port */
564   if(pattern->port != NULL){
565     g_object_unref(G_OBJECT(pattern->port));
566 
567     pattern->port = NULL;
568   }
569 
570   /* call parent */
571   G_OBJECT_CLASS(ags_pattern_parent_class)->dispose(gobject);
572 }
573 
574 void
ags_pattern_finalize(GObject * gobject)575 ags_pattern_finalize(GObject *gobject)
576 {
577   AgsPattern *pattern;
578 
579   guint i, j;
580 
581   pattern = AGS_PATTERN(gobject);
582 
583   /* channel */
584   if(pattern->channel != NULL){
585     g_object_unref(G_OBJECT(pattern->channel));
586   }
587 
588   /* timestamp */
589   if(pattern->timestamp != NULL){
590     g_object_unref(G_OBJECT(pattern->timestamp));
591   }
592 
593   /* pattern */
594   if(pattern->pattern != NULL){
595     for(i = 0; i < pattern->dim[0]; i++){
596       if(pattern->pattern[i] != NULL){
597 	for(j = 0; j < pattern->dim[1]; j++){
598 	  if(pattern->pattern[i][j] != NULL){
599 	    g_free(pattern->pattern[i][j]);
600 	  }
601 	}
602 
603 	g_free(pattern->pattern[i]);
604       }
605     }
606 
607     g_free(pattern->pattern);
608   }
609 
610   /* port */
611   if(pattern->port != NULL){
612     g_object_unref(G_OBJECT(pattern->port));
613   }
614 
615   /* call parent */
616   G_OBJECT_CLASS(ags_pattern_parent_class)->finalize(gobject);
617 }
618 
619 AgsUUID*
ags_pattern_get_uuid(AgsConnectable * connectable)620 ags_pattern_get_uuid(AgsConnectable *connectable)
621 {
622   AgsPattern *pattern;
623 
624   AgsUUID *ptr;
625 
626   GRecMutex *pattern_mutex;
627 
628   pattern = AGS_PATTERN(connectable);
629 
630   /* get pattern mutex */
631   pattern_mutex = AGS_PATTERN_GET_OBJ_MUTEX(pattern);
632 
633   /* get UUID */
634   g_rec_mutex_lock(pattern_mutex);
635 
636   ptr = pattern->uuid;
637 
638   g_rec_mutex_unlock(pattern_mutex);
639 
640   return(ptr);
641 }
642 
643 gboolean
ags_pattern_has_resource(AgsConnectable * connectable)644 ags_pattern_has_resource(AgsConnectable *connectable)
645 {
646   return(TRUE);
647 }
648 
649 gboolean
ags_pattern_is_ready(AgsConnectable * connectable)650 ags_pattern_is_ready(AgsConnectable *connectable)
651 {
652   AgsPattern *pattern;
653 
654   gboolean is_ready;
655 
656   pattern = AGS_PATTERN(connectable);
657 
658   /* check is added */
659   is_ready = ags_pattern_test_flags(pattern, AGS_PATTERN_ADDED_TO_REGISTRY);
660 
661   return(is_ready);
662 }
663 
664 void
ags_pattern_add_to_registry(AgsConnectable * connectable)665 ags_pattern_add_to_registry(AgsConnectable *connectable)
666 {
667   AgsPattern *pattern;
668 
669   AgsRegistry *registry;
670   AgsRegistryEntry *entry;
671 
672   AgsApplicationContext *application_context;
673 
674   GList *list;
675 
676   if(ags_connectable_is_ready(connectable)){
677     return;
678   }
679 
680   pattern = AGS_PATTERN(connectable);
681 
682   ags_pattern_set_flags(pattern, AGS_PATTERN_ADDED_TO_REGISTRY);
683 
684   application_context = ags_application_context_get_instance();
685 
686   registry = ags_service_provider_get_registry(AGS_SERVICE_PROVIDER(application_context));
687 
688   if(registry != NULL){
689     entry = ags_registry_entry_alloc(registry);
690     g_value_set_object(entry->entry,
691 		       (gpointer) pattern);
692     ags_registry_add_entry(registry,
693 			   entry);
694   }
695 
696   //TODO:JK: implement me
697 }
698 
699 void
ags_pattern_remove_from_registry(AgsConnectable * connectable)700 ags_pattern_remove_from_registry(AgsConnectable *connectable)
701 {
702   if(!ags_connectable_is_ready(connectable)){
703     return;
704   }
705 
706   //TODO:JK: implement me
707 }
708 
709 xmlNode*
ags_pattern_list_resource(AgsConnectable * connectable)710 ags_pattern_list_resource(AgsConnectable *connectable)
711 {
712   xmlNode *node;
713 
714   node = NULL;
715 
716   //TODO:JK: implement me
717 
718   return(node);
719 }
720 
721 xmlNode*
ags_pattern_xml_compose(AgsConnectable * connectable)722 ags_pattern_xml_compose(AgsConnectable *connectable)
723 {
724   xmlNode *node;
725 
726   node = NULL;
727 
728   //TODO:JK: implement me
729 
730   return(node);
731 }
732 
733 void
ags_pattern_xml_parse(AgsConnectable * connectable,xmlNode * node)734 ags_pattern_xml_parse(AgsConnectable *connectable,
735 		      xmlNode *node)
736 {
737   //TODO:JK: implement me
738 }
739 
740 gboolean
ags_pattern_is_connected(AgsConnectable * connectable)741 ags_pattern_is_connected(AgsConnectable *connectable)
742 {
743   AgsPattern *pattern;
744 
745   gboolean is_connected;
746 
747   pattern = AGS_PATTERN(connectable);
748 
749   /* check is connected */
750   is_connected = ags_pattern_test_flags(pattern, AGS_PATTERN_CONNECTED);
751 
752   return(is_connected);
753 }
754 
755 void
ags_pattern_connect(AgsConnectable * connectable)756 ags_pattern_connect(AgsConnectable *connectable)
757 {
758   AgsPattern *pattern;
759 
760   GList *list_start, *list;
761 
762   GRecMutex *pattern_mutex;
763 
764   if(ags_connectable_is_connected(connectable)){
765     return;
766   }
767 
768   pattern = AGS_PATTERN(connectable);
769 
770   ags_pattern_set_flags(pattern, AGS_PATTERN_CONNECTED);
771 }
772 
773 void
ags_pattern_disconnect(AgsConnectable * connectable)774 ags_pattern_disconnect(AgsConnectable *connectable)
775 {
776   AgsPattern *pattern;
777 
778   GList *list_start, *list;
779 
780   GRecMutex *pattern_mutex;
781 
782   if(!ags_connectable_is_connected(connectable)){
783     return;
784   }
785 
786   pattern = AGS_PATTERN(connectable);
787 
788   ags_pattern_unset_flags(pattern, AGS_PATTERN_CONNECTED);
789 }
790 
791 /**
792  * ags_pattern_get_obj_mutex:
793  * @pattern: the #AgsPattern
794  *
795  * Get object mutex.
796  *
797  * Returns: the #GRecMutex to lock @pattern
798  *
799  * Since: 3.1.0
800  */
801 GRecMutex*
ags_pattern_get_obj_mutex(AgsPattern * pattern)802 ags_pattern_get_obj_mutex(AgsPattern *pattern)
803 {
804   if(!AGS_IS_PATTERN(pattern)){
805     return(NULL);
806   }
807 
808   return(AGS_PATTERN_GET_OBJ_MUTEX(pattern));
809 }
810 
811 /**
812  * ags_pattern_test_flags:
813  * @pattern: the #AgsPattern
814  * @flags: the flags
815  *
816  * Test @flags to be set on @pattern.
817  *
818  * Returns: %TRUE if flags are set, else %FALSE
819  *
820  * Since: 3.0.0
821  */
822 gboolean
ags_pattern_test_flags(AgsPattern * pattern,guint flags)823 ags_pattern_test_flags(AgsPattern *pattern, guint flags)
824 {
825   gboolean retval;
826 
827   GRecMutex *pattern_mutex;
828 
829   if(!AGS_IS_PATTERN(pattern)){
830     return(FALSE);
831   }
832 
833   /* get pattern mutex */
834   pattern_mutex = AGS_PATTERN_GET_OBJ_MUTEX(pattern);
835 
836   /* test */
837   g_rec_mutex_lock(pattern_mutex);
838 
839   retval = (flags & (pattern->flags)) ? TRUE: FALSE;
840 
841   g_rec_mutex_unlock(pattern_mutex);
842 
843   return(retval);
844 }
845 
846 /**
847  * ags_pattern_set_flags:
848  * @pattern: the #AgsPattern
849  * @flags: the flags
850  *
851  * Set flags.
852  *
853  * Since: 3.0.0
854  */
855 void
ags_pattern_set_flags(AgsPattern * pattern,guint flags)856 ags_pattern_set_flags(AgsPattern *pattern, guint flags)
857 {
858   GRecMutex *pattern_mutex;
859 
860   if(!AGS_IS_PATTERN(pattern)){
861     return;
862   }
863 
864   /* get pattern mutex */
865   pattern_mutex = AGS_PATTERN_GET_OBJ_MUTEX(pattern);
866 
867   /* set flags */
868   g_rec_mutex_lock(pattern_mutex);
869 
870   pattern->flags |= flags;
871 
872   g_rec_mutex_unlock(pattern_mutex);
873 }
874 
875 /**
876  * ags_pattern_unset_flags:
877  * @pattern: the #AgsPattern
878  * @flags: the flags
879  *
880  * Unset flags.
881  *
882  * Since: 3.0.0
883  */
884 void
ags_pattern_unset_flags(AgsPattern * pattern,guint flags)885 ags_pattern_unset_flags(AgsPattern *pattern, guint flags)
886 {
887   GRecMutex *pattern_mutex;
888 
889   if(!AGS_IS_PATTERN(pattern)){
890     return;
891   }
892 
893   /* get pattern mutex */
894   pattern_mutex = AGS_PATTERN_GET_OBJ_MUTEX(pattern);
895 
896   /* set flags */
897   g_rec_mutex_lock(pattern_mutex);
898 
899   pattern->flags &= (~flags);
900 
901   g_rec_mutex_unlock(pattern_mutex);
902 }
903 
904 void
ags_pattern_change_bpm(AgsTactable * tactable,gdouble new_bpm,gdouble old_bpm)905 ags_pattern_change_bpm(AgsTactable *tactable, gdouble new_bpm, gdouble old_bpm)
906 {
907   //TODO:JK: implement me
908 }
909 
910 /**
911  * ags_pattern_find_near_timestamp:
912  * @pattern: (element-type AgsAudio.Pattern) (transfer none): the #GList-struct containing #AgsPattern
913  * @timestamp: the matching #AgsTimestamp
914  *
915  * Retrieve appropriate pattern for timestamp.
916  *
917  * Returns: (element-type AgsAudio.Pattern) (transfer none): Next match.
918  *
919  * Since: 3.0.0
920  */
921 GList*
ags_pattern_find_near_timestamp(GList * pattern,AgsTimestamp * timestamp)922 ags_pattern_find_near_timestamp(GList *pattern, AgsTimestamp *timestamp)
923 {
924   AgsTimestamp *current_timestamp;
925 
926   GList *retval;
927   GList *current_start, *current_end, *current;
928 
929   guint64 current_x, x;
930   guint length, position;
931   gboolean use_ags_offset;
932   gboolean success;
933 
934   if(pattern == NULL){
935     return(NULL);
936   }
937 
938   current_start = pattern;
939   current_end = g_list_last(pattern);
940 
941   length = g_list_length(pattern);
942   position = length / 2;
943 
944   current = g_list_nth(current_start,
945 		       position);
946 
947   if(ags_timestamp_test_flags(timestamp,
948 			      AGS_TIMESTAMP_OFFSET)){
949     x = ags_timestamp_get_ags_offset(timestamp);
950 
951     use_ags_offset = TRUE;
952   }else if(ags_timestamp_test_flags(timestamp,
953 				    AGS_TIMESTAMP_UNIX)){
954     x = ags_timestamp_get_unix_time(timestamp);
955 
956     use_ags_offset = FALSE;
957   }else{
958     return(NULL);
959   }
960 
961   retval = NULL;
962   success = FALSE;
963 
964   while(!success && current != NULL){
965     current_x = 0;
966 
967     /* check current - start */
968     if(timestamp == NULL){
969       retval = current_start;
970 
971       break;
972     }
973 
974     g_object_get(current_start->data,
975 		 "timestamp", &current_timestamp,
976 		 NULL);
977 
978     if(current_timestamp != NULL){
979       if(use_ags_offset){
980 	current_x = ags_timestamp_get_ags_offset(current_timestamp);
981 
982 	g_object_unref(current_timestamp);
983 
984 	if(current_x > x){
985 	  break;
986 	}
987       }else{
988 	current_x = ags_timestamp_get_unix_time(current_timestamp);
989 
990 	g_object_unref(current_timestamp);
991 
992 	if(current_x > x){
993 	  break;
994 	}
995       }
996 
997       if(use_ags_offset){
998 	if(current_x >= x &&
999 	   current_x < x + AGS_PATTERN_DEFAULT_OFFSET){
1000 	  retval = current_start;
1001 
1002 	  break;
1003 	}
1004       }else{
1005 	if(current_x >= x &&
1006 	   current_x < x + AGS_PATTERN_DEFAULT_DURATION){
1007 	  retval = current_start;
1008 
1009 	  break;
1010 	}
1011       }
1012     }else{
1013       g_warning("inconsistent data");
1014     }
1015 
1016     /* check current - end */
1017     if(timestamp == NULL){
1018       retval = current_end;
1019 
1020       break;
1021     }
1022 
1023     g_object_get(current_end->data,
1024 		 "timestamp", &current_timestamp,
1025 		 NULL);
1026 
1027     if(current_timestamp != NULL){
1028       if(use_ags_offset){
1029 	current_x = ags_timestamp_get_ags_offset(current_timestamp);
1030 
1031 	g_object_unref(current_timestamp);
1032 
1033 	if(current_x < x){
1034 	  break;
1035 	}
1036       }else{
1037 	current_x = ags_timestamp_get_unix_time(current_timestamp);
1038 
1039 	g_object_unref(current_timestamp);
1040 
1041 	if(current_x < x){
1042 	  break;
1043 	}
1044       }
1045 
1046       if(use_ags_offset){
1047 	if(current_x >= x &&
1048 	   current_x < x + AGS_PATTERN_DEFAULT_OFFSET){
1049 	  retval = current_end;
1050 
1051 	  break;
1052 	}
1053       }else{
1054 	if(current_x >= x &&
1055 	   current_x < x + AGS_PATTERN_DEFAULT_DURATION){
1056 	  retval = current_end;
1057 
1058 	  break;
1059 	}
1060       }
1061     }else{
1062       g_warning("inconsistent data");
1063     }
1064 
1065     /* check current - center */
1066     if(timestamp == NULL){
1067       retval = current;
1068 
1069       break;
1070     }
1071 
1072     g_object_get(current->data,
1073 		 "timestamp", &current_timestamp,
1074 		 NULL);
1075 
1076     if(current_timestamp != NULL){
1077       if(use_ags_offset){
1078 	current_x = ags_timestamp_get_ags_offset(current_timestamp);
1079 
1080 	g_object_unref(current_timestamp);
1081 
1082 	if(current_x >= x &&
1083 	   current_x < x + AGS_PATTERN_DEFAULT_OFFSET){
1084 	  retval = current;
1085 
1086 	  break;
1087 	}
1088       }else{
1089 	current_x = ags_timestamp_get_unix_time(current_timestamp);
1090 
1091 	g_object_unref(current_timestamp);
1092 
1093 	if(current_x >= x &&
1094 	   current_x < x + AGS_PATTERN_DEFAULT_DURATION){
1095 	  retval = current;
1096 
1097 	  break;
1098 	}
1099       }
1100     }else{
1101       g_warning("inconsistent data");
1102     }
1103 
1104     if(position == 0){
1105       break;
1106     }
1107 
1108     position = position / 2;
1109 
1110     if(current_x < x){
1111       current_start = current->next;
1112       current_end = current_end->prev;
1113     }else{
1114       current_start = current_start->next;
1115       current_end = current->prev;
1116     }
1117 
1118     current = g_list_nth(current_start,
1119 			 position);
1120   }
1121 
1122   return(retval);
1123 }
1124 
1125 /**
1126  * ags_pattern_get_channel:
1127  * @pattern: the #AgsPattern
1128  *
1129  * Get channel.
1130  *
1131  * Returns: (transfer full): the #AgsChannel
1132  *
1133  * Since: 3.1.0
1134  */
1135 GObject*
ags_pattern_get_channel(AgsPattern * pattern)1136 ags_pattern_get_channel(AgsPattern *pattern)
1137 {
1138   GObject *channel;
1139 
1140   if(!AGS_IS_PATTERN(pattern)){
1141     return(NULL);
1142   }
1143 
1144   g_object_get(pattern,
1145 	       "channel", &channel,
1146 	       NULL);
1147 
1148   return(channel);
1149 }
1150 
1151 /**
1152  * ags_pattern_set_channel:
1153  * @pattern: the #AgsPattern
1154  * @channel: the #AgsChannel
1155  *
1156  * Set channel.
1157  *
1158  * Since: 3.1.0
1159  */
1160 void
ags_pattern_set_channel(AgsPattern * pattern,GObject * channel)1161 ags_pattern_set_channel(AgsPattern *pattern, GObject *channel)
1162 {
1163   if(!AGS_IS_PATTERN(pattern)){
1164     return;
1165   }
1166 
1167   g_object_set(pattern,
1168 	       "channel", channel,
1169 	       NULL);
1170 }
1171 
1172 /**
1173  * ags_pattern_get_timestamp:
1174  * @pattern: the #AgsPattern
1175  *
1176  * Get timestamp.
1177  *
1178  * Returns: (transfer full): the #AgsTimestamp
1179  *
1180  * Since: 3.1.0
1181  */
1182 AgsTimestamp*
ags_pattern_get_timestamp(AgsPattern * pattern)1183 ags_pattern_get_timestamp(AgsPattern *pattern)
1184 {
1185   AgsTimestamp *timestamp;
1186 
1187   if(!AGS_IS_PATTERN(pattern)){
1188     return(NULL);
1189   }
1190 
1191   g_object_get(pattern,
1192 	       "timestamp", &timestamp,
1193 	       NULL);
1194 
1195   return(timestamp);
1196 }
1197 
1198 /**
1199  * ags_pattern_set_timestamp:
1200  * @pattern: the #AgsPattern
1201  * @timestamp: the #AgsTimestamp
1202  *
1203  * Set timestamp.
1204  *
1205  * Since: 3.1.0
1206  */
1207 void
ags_pattern_set_timestamp(AgsPattern * pattern,AgsTimestamp * timestamp)1208 ags_pattern_set_timestamp(AgsPattern *pattern, AgsTimestamp *timestamp)
1209 {
1210   if(!AGS_IS_PATTERN(pattern)){
1211     return;
1212   }
1213 
1214   g_object_set(pattern,
1215 	       "timestamp", timestamp,
1216 	       NULL);
1217 }
1218 
1219 /**
1220  * ags_pattern_get_dim:
1221  * @pattern: an #AgsPattern
1222  * @dim0: (out): bank 0 size
1223  * @dim1: (out): bank 1 size
1224  * @length: (out): amount of beats
1225  *
1226  * Get the pattern's dimensions.
1227  *
1228  * Since: 3.1.0
1229  */
1230 void
ags_pattern_get_dim(AgsPattern * pattern,guint * dim0,guint * dim1,guint * length)1231 ags_pattern_get_dim(AgsPattern *pattern, guint *dim0, guint *dim1, guint *length)
1232 {
1233   GRecMutex *pattern_mutex;
1234 
1235   if(!AGS_IS_PATTERN(pattern)){
1236     return;
1237   }
1238 
1239   /* get pattern mutex */
1240   pattern_mutex = AGS_PATTERN_GET_OBJ_MUTEX(pattern);
1241 
1242   /* get dim */
1243   g_rec_mutex_lock(pattern_mutex);
1244 
1245   if(dim0 != NULL){
1246     dim0[0] = pattern->dim[0];
1247   }
1248 
1249   if(dim1 != NULL){
1250     dim1[0] = pattern->dim[1];
1251   }
1252 
1253   if(length != NULL){
1254     length[0] = pattern->dim[2];
1255   }
1256 
1257   g_rec_mutex_unlock(pattern_mutex);
1258 }
1259 
1260 /**
1261  * ags_pattern_set_dim:
1262  * @pattern: an #AgsPattern
1263  * @dim0: bank 0 size
1264  * @dim1: bank 1 size
1265  * @length: amount of beats
1266  *
1267  * Reallocates the pattern's dimensions.
1268  *
1269  * Since: 3.0.0
1270  */
1271 void
ags_pattern_set_dim(AgsPattern * pattern,guint dim0,guint dim1,guint length)1272 ags_pattern_set_dim(AgsPattern *pattern, guint dim0, guint dim1, guint length)
1273 {
1274   AgsChannel *channel;
1275 
1276   guint ***index0, **index1, *bitmap;
1277 
1278   guint pad;
1279   guint i, j, k, j_set, k_set;
1280   guint bitmap_size;
1281 
1282   GRecMutex *pattern_mutex;
1283 
1284   if(!AGS_IS_PATTERN(pattern)){
1285     return;
1286   }
1287 
1288   channel = NULL;
1289 
1290   pad = 0;
1291 
1292   /* get pattern mutex */
1293   pattern_mutex = AGS_PATTERN_GET_OBJ_MUTEX(pattern);
1294 
1295   /* set dim */
1296   g_rec_mutex_lock(pattern_mutex);
1297 
1298   if(dim0 == 0 && pattern->pattern == NULL){
1299     g_rec_mutex_unlock(pattern_mutex);
1300 
1301     return;
1302   }
1303 
1304   // shrink
1305   if(pattern->dim[0] > dim0){
1306     for(i = dim0; i < pattern->dim[0]; i++){
1307       for(j = 0; j < pattern->dim[1]; j++){
1308 	g_free(pattern->pattern[i][j]);
1309       }
1310 
1311       g_free(pattern->pattern[i]);
1312 
1313       pattern->pattern[i] = NULL;
1314     }
1315 
1316     if(dim0 == 0){
1317       g_free(pattern->pattern);
1318 
1319       pattern->pattern = NULL;
1320       pattern->dim[0] = 0;
1321 
1322       g_rec_mutex_unlock(pattern_mutex);
1323 
1324       return;
1325     }else{
1326       pattern->pattern = (guint ***) g_realloc(pattern->pattern,
1327 					       (int) dim0 * sizeof(guint **));
1328 
1329       pattern->dim[0] = dim0;
1330     }
1331   }
1332 
1333   if(pattern->dim[1] > dim1){
1334     if(dim1 == 0){
1335       for(i = 0; i < pattern->dim[0]; i++){
1336 	for(j = dim1; j < pattern->dim[1]; j++){
1337 	  g_free(pattern->pattern[i][j]);
1338 	}
1339 
1340 	pattern->pattern[i] = NULL;
1341       }
1342 
1343       pattern->dim[1] = 0;
1344 
1345       g_rec_mutex_unlock(pattern_mutex);
1346 
1347       return;
1348     }else{
1349       for(i = 0; i < pattern->dim[0]; i++){
1350 	for(j = dim1; j < pattern->dim[1]; j++){
1351 	  g_free(pattern->pattern[i][j]);
1352 	}
1353       }
1354 
1355       for(i = 0; pattern->dim[0]; i++){
1356 	pattern->pattern[i] = (guint **) g_realloc(pattern->pattern[i],
1357 						   dim1 * sizeof(guint *));
1358       }
1359 
1360       pattern->dim[1] = dim1;
1361     }
1362   }
1363 
1364   if(pattern->dim[2] > length){
1365     if(length == 0){
1366       for(i = 0; i < pattern->dim[0]; i++){
1367 	for(j = 0; j < pattern->dim[1]; j++){
1368       	  g_free(pattern->pattern[i][j]);
1369 
1370 	  pattern->pattern[i][j] = NULL;
1371 	}
1372       }
1373 
1374       for(k = 0; k < pattern->dim[2]; k++){
1375 	g_object_unref(pattern->note[k]);
1376       }
1377 
1378       g_free(pattern->note);
1379 
1380       pattern->note = NULL;
1381 
1382       pattern->dim[2] = 0;
1383     }else{
1384       for(i = 0; i < pattern->dim[0]; i++){
1385 	for(j = 0; j < pattern->dim[1]; j++){
1386 	  pattern->pattern[i][j] = (guint *) g_realloc(pattern->pattern[i][j],
1387 						       (guint) ceil((double) length / (double) (sizeof(guint) * 8)) * sizeof(guint));
1388 	}
1389       }
1390 
1391       for(k = length; k < pattern->dim[2]; k++){
1392 	g_object_unref(pattern->note[k]);
1393       }
1394 
1395       pattern->note = g_realloc(pattern->note,
1396 				length * sizeof(AgsNote *));
1397 
1398       pattern->dim[2] = length;
1399     }
1400   }
1401 
1402   // grow
1403   bitmap_size = (guint) ceil((double) pattern->dim[2] / (double) (sizeof(guint) * 8)) * sizeof(guint);
1404 
1405   if(pattern->dim[0] < dim0){
1406     if(pattern->pattern == NULL){
1407       pattern->pattern = (guint ***) g_malloc(dim0 * sizeof(guint **));
1408     }else{
1409       pattern->pattern = (guint ***) g_realloc(pattern->pattern,
1410 					       dim0 * sizeof(guint **));
1411     }
1412 
1413     for(i = pattern->dim[0]; i < dim0; i++){
1414       pattern->pattern[i] = (guint **) g_malloc(pattern->dim[1] * sizeof(guint *));
1415 
1416       for(j = 0; j < pattern->dim[1]; j++){
1417 	if(bitmap_size == 0){
1418 	  pattern->pattern[i][j] = NULL;
1419 	}else{
1420 	  pattern->pattern[i][j] = (guint *) g_malloc(bitmap_size);
1421 	  memset(pattern->pattern[i][j], 0, bitmap_size);
1422 	}
1423       }
1424     }
1425 
1426     pattern->dim[0] = dim0;
1427   }
1428 
1429   if(pattern->dim[1] < dim1){
1430     for(i = 0; i < pattern->dim[0]; i++){
1431       if(pattern->pattern[i] == NULL){
1432 	pattern->pattern[i] = (guint **) g_malloc(dim1 * sizeof(guint *));
1433       }else{
1434 	pattern->pattern[i] = (guint **) g_realloc(pattern->pattern[i],
1435 						   dim1 * sizeof(guint *));
1436       }
1437 
1438       for(j = pattern->dim[1]; j < dim1; j++){
1439 	if(bitmap_size == 0){
1440 	  pattern->pattern[i][j] = NULL;
1441 	}else{
1442 	  pattern->pattern[i][j] = (guint *) g_malloc(bitmap_size);
1443 	  memset(pattern->pattern[i][j], 0, bitmap_size);
1444 	}
1445       }
1446     }
1447 
1448     pattern->dim[1] = dim1;
1449   }
1450 
1451   if(pattern->dim[2] < length){
1452     guint new_bitmap_size;
1453 
1454     new_bitmap_size = (guint) ceil((double) length / (double) (sizeof(guint) * 8)) * sizeof(guint);
1455 
1456     for(i = 0; i < pattern->dim[0]; i++){
1457       for(j = 0; j < pattern->dim[1]; j++){
1458 	if(pattern->pattern[i][j] == NULL){
1459 	  pattern->pattern[i][j] = (guint *) g_malloc(new_bitmap_size);
1460 	  memset(pattern->pattern[i][j], 0, new_bitmap_size);
1461 	}else{
1462 	  pattern->pattern[i][j] =(guint *) g_realloc(pattern->pattern[i][j],
1463 						      new_bitmap_size);
1464 	  memset(pattern->pattern[i][j] + bitmap_size, 0, new_bitmap_size - bitmap_size);
1465 	}
1466       }
1467     }
1468 
1469     if(pattern->note == NULL){
1470       pattern->note = (AgsNote **) g_malloc(length * sizeof(AgsNote *));
1471     }else{
1472       pattern->note = (AgsNote **) g_realloc(pattern->note,
1473 					     length * sizeof(AgsNote *));
1474     }
1475 
1476     channel = NULL;
1477     pad = 0;
1478 
1479     g_object_get(pattern,
1480 		 "channel", &channel,
1481 		 NULL);
1482 
1483     if(channel != NULL){
1484       g_object_get(channel,
1485 		   "pad", &pad,
1486 		   NULL);
1487     }
1488 
1489     for(k = pattern->dim[2]; k < length; k++){
1490       pattern->note[k] = ags_note_new();
1491 
1492       g_object_set(pattern->note[k],
1493 		   "x0", k,
1494 		   "x1", k + 1,
1495 		   "y", pad,
1496 		   NULL);
1497     }
1498 
1499 
1500     pattern->dim[2] = length;
1501   }
1502 
1503   g_rec_mutex_unlock(pattern_mutex);
1504 }
1505 
1506 gboolean
ags_pattern_is_empty(AgsPattern * pattern,guint i,guint j)1507 ags_pattern_is_empty(AgsPattern *pattern, guint i, guint j)
1508 {
1509   guint bitmap_length;
1510   guint n;
1511 
1512   GRecMutex *pattern_mutex;
1513 
1514   if(!AGS_IS_PATTERN(pattern)){
1515     return(TRUE);
1516   }
1517 
1518   /* get pattern mutex */
1519   pattern_mutex = AGS_PATTERN_GET_OBJ_MUTEX(pattern);
1520 
1521   if(!(i < pattern->dim[0] ||
1522        j < pattern->dim[1])){
1523     g_rec_mutex_unlock(pattern_mutex);
1524 
1525     return(FALSE);
1526   }
1527 
1528   /* check */
1529   g_rec_mutex_lock(pattern_mutex);
1530 
1531   bitmap_length = (guint) ceil((double) pattern->dim[2] / (double) (sizeof(guint) * 8));
1532 
1533   for(n = 0; n < bitmap_length; n++){
1534     if(pattern->pattern[i][j][n] != 0){
1535       g_rec_mutex_unlock(pattern_mutex);
1536 
1537       return(FALSE);
1538     }
1539   }
1540 
1541   g_rec_mutex_unlock(pattern_mutex);
1542 
1543   return(TRUE);
1544 }
1545 
1546 /**
1547  * ags_pattern_get_bit:
1548  * @pattern: an #AgsPattern
1549  * @i: bank index 0
1550  * @j: bank index 1
1551  * @bit: the tic to check
1552  *
1553  * Check for tic to be played.
1554  *
1555  * Returns: %TRUE if tone is enabled.
1556  *
1557  * Since: 3.0.0
1558  */
1559 gboolean
ags_pattern_get_bit(AgsPattern * pattern,guint i,guint j,guint bit)1560 ags_pattern_get_bit(AgsPattern *pattern, guint i, guint j, guint bit)
1561 {
1562   guint k, value;
1563 
1564   GRecMutex *pattern_mutex;
1565 
1566   if(!AGS_IS_PATTERN(pattern)){
1567     return(FALSE);
1568   }
1569 
1570   /* get pattern mutex */
1571   pattern_mutex = AGS_PATTERN_GET_OBJ_MUTEX(pattern);
1572 
1573   /* get bit */
1574   g_rec_mutex_lock(pattern_mutex);
1575 
1576   if(!(i < pattern->dim[0] ||
1577        j < pattern->dim[1] ||
1578        bit < pattern->dim[2])){
1579     g_rec_mutex_unlock(pattern_mutex);
1580 
1581     return(FALSE);
1582   }
1583 
1584   k = (guint) floor((double) bit / (double) (sizeof(guint) * 8));
1585   value = 1 << (bit % (sizeof(guint) * 8));
1586 
1587 #ifdef AGS_DEBUG
1588   g_message("i,j,bit = %d,%d,%d", i, j, bit);
1589   g_message("k = %d; value = %x", k, value);
1590 #endif
1591 
1592   //((1 << (bit % (sizeof(guint) *8))) & (pattern->pattern[i][j][(guint) floor((double) bit / (double) (sizeof(guint) * 8))])) != 0
1593   if((value & (pattern->pattern[i][j][k])) != 0){
1594     g_rec_mutex_unlock(pattern_mutex);
1595 
1596     return(TRUE);
1597   }else{
1598     g_rec_mutex_unlock(pattern_mutex);
1599 
1600     return(FALSE);
1601   }
1602 }
1603 
1604 /**
1605  * ags_pattern_toggle_bit:
1606  * @pattern: an #AgsPattern
1607  * @i: bank index 0
1608  * @j: bank index 1
1609  * @bit: the tic to toggle
1610  *
1611  * Toggle tone.
1612  *
1613  * Since: 3.0.0
1614  */
1615 void
ags_pattern_toggle_bit(AgsPattern * pattern,guint i,guint j,guint bit)1616 ags_pattern_toggle_bit(AgsPattern *pattern, guint i, guint j, guint bit)
1617 {
1618   guint k, value;
1619 
1620   GRecMutex *pattern_mutex;
1621 
1622   if(!AGS_IS_PATTERN(pattern)){
1623     return;
1624   }
1625 
1626   /* get pattern mutex */
1627   pattern_mutex = AGS_PATTERN_GET_OBJ_MUTEX(pattern);
1628 
1629   /* toggle */
1630   g_rec_mutex_lock(pattern_mutex);
1631 
1632   if(!(i < pattern->dim[0] ||
1633        j < pattern->dim[1] ||
1634        bit < pattern->dim[2])){
1635     g_rec_mutex_unlock(pattern_mutex);
1636 
1637     return;
1638   }
1639 
1640   k = (guint) floor((double) bit / (double) (sizeof(guint) * 8));
1641   value = 1 << (bit % (sizeof(guint) * 8));
1642 
1643   if((value & (pattern->pattern[i][j][k])) != 0){
1644     pattern->pattern[i][j][k] &= (~value);
1645   }else{
1646     pattern->pattern[i][j][k] |= value;
1647   }
1648 
1649   g_rec_mutex_unlock(pattern_mutex);
1650 }
1651 
1652 /**
1653  * ags_pattern_get_note:
1654  * @pattern: an #AgsPattern
1655  * @bit: the tic
1656  *
1657  * Get note of @pattern.
1658  *
1659  * Returns: (transfer full): the #AgsNote at given position or %NULL
1660  *
1661  * Since: 3.3.0
1662  */
1663 AgsNote*
ags_pattern_get_note(AgsPattern * pattern,guint bit)1664 ags_pattern_get_note(AgsPattern *pattern, guint bit)
1665 {
1666   AgsNote *note;
1667 
1668   GRecMutex *pattern_mutex;
1669 
1670   if(!AGS_IS_PATTERN(pattern)){
1671     return(NULL);
1672   }
1673 
1674   note = NULL;
1675 
1676   /* get pattern mutex */
1677   pattern_mutex = AGS_PATTERN_GET_OBJ_MUTEX(pattern);
1678 
1679   g_rec_mutex_lock(pattern_mutex);
1680 
1681   if(bit < pattern->dim[2]){
1682     note = pattern->note[bit];
1683 
1684     g_object_ref(note);
1685   }
1686 
1687   g_rec_mutex_unlock(pattern_mutex);
1688 
1689   return(note);
1690 }
1691 
1692 /**
1693  * ags_pattern_new:
1694  *
1695  * Creates a new instance of #AgsPattern
1696  *
1697  * Returns: the new #AgsPattern
1698  *
1699  * Since: 3.0.0
1700  */
1701 AgsPattern*
ags_pattern_new()1702 ags_pattern_new()
1703 {
1704   AgsPattern *pattern;
1705 
1706   pattern = (AgsPattern *) g_object_new(AGS_TYPE_PATTERN,
1707 					NULL);
1708 
1709   return(pattern);
1710 }
1711