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", ¤t_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", ¤t_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", ¤t_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", ×tamp,
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