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_note.h>
21
22 #include <ags/audio/midi/ags_midi_buffer_util.h>
23
24 #include <stdlib.h>
25 #include <complex.h>
26
27 #include <ags/i18n.h>
28
29 void ags_note_class_init(AgsNoteClass *note);
30 void ags_note_init(AgsNote *note);
31 void ags_note_set_property(GObject *gobject,
32 guint prop_id,
33 const GValue *value,
34 GParamSpec *param_spec);
35 void ags_note_get_property(GObject *gobject,
36 guint prop_id,
37 GValue *value,
38 GParamSpec *param_spec);
39 void ags_note_finalize(GObject *gobject);
40
41 /**
42 * SECTION:ags_note
43 * @short_description: note class
44 * @title: AgsNote
45 * @section_id:
46 * @include: ags/audio/ags_note.h
47 *
48 * #AgsNote represents a tone.
49 */
50
51 enum{
52 PROP_0,
53 PROP_X0,
54 PROP_X1,
55 PROP_Y,
56 PROP_RT_OFFSET,
57 PROP_RT_ATTACK,
58 PROP_STREAM_DELAY,
59 PROP_STREAM_ATTACK,
60 PROP_STREAM_FRAME_COUNT,
61 PROP_ATTACK,
62 PROP_DECAY,
63 PROP_SUSTAIN,
64 PROP_RELEASE,
65 PROP_RATIO,
66 PROP_NOTE_NAME,
67 PROP_FREQUENCY,
68 };
69
70 static gpointer ags_note_parent_class = NULL;
71
72 GType
ags_note_get_type()73 ags_note_get_type()
74 {
75 static volatile gsize g_define_type_id__volatile = 0;
76
77 if(g_once_init_enter (&g_define_type_id__volatile)){
78 GType ags_type_note = 0;
79
80 static const GTypeInfo ags_note_info = {
81 sizeof(AgsNoteClass),
82 NULL,
83 NULL,
84 (GClassInitFunc) ags_note_class_init,
85 NULL,
86 NULL,
87 sizeof(AgsNote),
88 0,
89 (GInstanceInitFunc) ags_note_init,
90 };
91
92 ags_type_note = g_type_register_static(G_TYPE_OBJECT,
93 "AgsNote",
94 &ags_note_info,
95 0);
96
97 g_once_init_leave(&g_define_type_id__volatile, ags_type_note);
98 }
99
100 return g_define_type_id__volatile;
101 }
102
103 void
ags_note_class_init(AgsNoteClass * note)104 ags_note_class_init(AgsNoteClass *note)
105 {
106 GObjectClass *gobject;
107 GParamSpec *param_spec;
108
109 ags_note_parent_class = g_type_class_peek_parent(note);
110
111 gobject = (GObjectClass *) note;
112
113 gobject->set_property = ags_note_set_property;
114 gobject->get_property = ags_note_get_property;
115
116 gobject->finalize = ags_note_finalize;
117
118 /* properties */
119 /**
120 * AgsNote:x0:
121 *
122 * Note offset x0.
123 *
124 * Since: 3.0.0
125 */
126 param_spec = g_param_spec_uint("x0",
127 i18n_pspec("offset x0"),
128 i18n_pspec("The first x offset"),
129 0,
130 G_MAXUINT32,
131 0,
132 G_PARAM_READABLE | G_PARAM_WRITABLE);
133 g_object_class_install_property(gobject,
134 PROP_X0,
135 param_spec);
136
137 /**
138 * AgsNote:x1:
139 *
140 * Note offset x1.
141 *
142 * Since: 3.0.0
143 */
144 param_spec = g_param_spec_uint("x1",
145 i18n_pspec("offset x1"),
146 i18n_pspec("The last x offset"),
147 0,
148 G_MAXUINT32,
149 0,
150 G_PARAM_READABLE | G_PARAM_WRITABLE);
151 g_object_class_install_property(gobject,
152 PROP_X1,
153 param_spec);
154
155 /**
156 * AgsNote:y:
157 *
158 * Note offset y.
159 *
160 * Since: 3.0.0
161 */
162 param_spec = g_param_spec_uint("y",
163 i18n_pspec("offset y"),
164 i18n_pspec("The y offset"),
165 0,
166 G_MAXUINT32,
167 0,
168 G_PARAM_READABLE | G_PARAM_WRITABLE);
169 g_object_class_install_property(gobject,
170 PROP_Y,
171 param_spec);
172
173 /**
174 * AgsNote:rt-offset:
175 *
176 * Note realtime offset.
177 *
178 * Since: 3.0.0
179 */
180 param_spec = g_param_spec_uint64("rt-offset",
181 i18n_pspec("realtime offset"),
182 i18n_pspec("The realtime offset"),
183 0,
184 G_MAXUINT64,
185 0,
186 G_PARAM_READABLE | G_PARAM_WRITABLE);
187 g_object_class_install_property(gobject,
188 PROP_RT_OFFSET,
189 param_spec);
190
191 /**
192 * AgsNote:rt-attack:
193 *
194 * Note realtime attack.
195 *
196 * Since: 3.0.0
197 */
198 param_spec = g_param_spec_uint("rt-attack",
199 i18n_pspec("realtime attack"),
200 i18n_pspec("The realtime attack"),
201 0,
202 G_MAXUINT32,
203 0,
204 G_PARAM_READABLE | G_PARAM_WRITABLE);
205 g_object_class_install_property(gobject,
206 PROP_RT_ATTACK,
207 param_spec);
208
209 /**
210 * AgsNote:stream-delay:
211 *
212 * The stream's delay.
213 *
214 * Since: 3.0.0
215 */
216 param_spec = g_param_spec_double("stream-delay",
217 i18n_pspec("delay of stream"),
218 i18n_pspec("The delay of the stream"),
219 0.0,
220 G_MAXDOUBLE,
221 0.0,
222 G_PARAM_READABLE | G_PARAM_WRITABLE);
223 g_object_class_install_property(gobject,
224 PROP_STREAM_DELAY,
225 param_spec);
226
227 /**
228 * AgsNote:stream-attack:
229 *
230 * The stream's attack.
231 *
232 * Since: 3.0.0
233 */
234 param_spec = g_param_spec_double("stream-attack",
235 i18n_pspec("stream attack offset"),
236 i18n_pspec("The first x offset"),
237 0.0,
238 G_MAXDOUBLE,
239 0.0,
240 G_PARAM_READABLE | G_PARAM_WRITABLE);
241 g_object_class_install_property(gobject,
242 PROP_STREAM_ATTACK,
243 param_spec);
244
245 /**
246 * AgsNote:stream-frame-count:
247 *
248 * The stream's frame count.
249 *
250 * Since: 3.0.0
251 */
252 param_spec = g_param_spec_uint64("stream-frame-count",
253 i18n_pspec("stream frame count"),
254 i18n_pspec("The stream frame count"),
255 0,
256 G_MAXUINT64,
257 0,
258 G_PARAM_READABLE | G_PARAM_WRITABLE);
259 g_object_class_install_property(gobject,
260 PROP_STREAM_FRAME_COUNT,
261 param_spec);
262
263 /**
264 * AgsNote:attack:
265 *
266 * Envelope attack.
267 *
268 * Since: 3.0.0
269 */
270 param_spec = g_param_spec_boxed("attack",
271 i18n_pspec("envelope's attack"),
272 i18n_pspec("The envelope's attack"),
273 AGS_TYPE_COMPLEX,
274 G_PARAM_READABLE | G_PARAM_WRITABLE);
275 g_object_class_install_property(gobject,
276 PROP_ATTACK,
277 param_spec);
278
279 /**
280 * AgsNote:decay:
281 *
282 * Envelope decay.
283 *
284 * Since: 3.0.0
285 */
286 param_spec = g_param_spec_boxed("decay",
287 i18n_pspec("envelope's decay"),
288 i18n_pspec("The envelope's decay"),
289 AGS_TYPE_COMPLEX,
290 G_PARAM_READABLE | G_PARAM_WRITABLE);
291 g_object_class_install_property(gobject,
292 PROP_DECAY,
293 param_spec);
294
295 /**
296 * AgsNote:sustain:
297 *
298 * Envelope sustain.
299 *
300 * Since: 3.0.0
301 */
302 param_spec = g_param_spec_boxed("sustain",
303 i18n_pspec("envelope's sustain"),
304 i18n_pspec("The envelope's sustain"),
305 AGS_TYPE_COMPLEX,
306 G_PARAM_READABLE | G_PARAM_WRITABLE);
307 g_object_class_install_property(gobject,
308 PROP_SUSTAIN,
309 param_spec);
310
311 /**
312 * AgsNote:release:
313 *
314 * Envelope release.
315 *
316 * Since: 3.0.0
317 */
318 param_spec = g_param_spec_boxed("release",
319 i18n_pspec("envelope's release"),
320 i18n_pspec("The envelope's release"),
321 AGS_TYPE_COMPLEX,
322 G_PARAM_READABLE | G_PARAM_WRITABLE);
323 g_object_class_install_property(gobject,
324 PROP_RELEASE,
325 param_spec);
326
327 /**
328 * AgsNote:ratio:
329 *
330 * Envelope ratio.
331 *
332 * Since: 3.0.0
333 */
334 param_spec = g_param_spec_boxed("ratio",
335 i18n_pspec("envelope's ratio"),
336 i18n_pspec("The envelope's ratio"),
337 AGS_TYPE_COMPLEX,
338 G_PARAM_READABLE | G_PARAM_WRITABLE);
339 g_object_class_install_property(gobject,
340 PROP_RATIO,
341 param_spec);
342
343 /**
344 * AgsNote:note-name:
345 *
346 * The note's name.
347 *
348 * Since: 3.0.0
349 */
350 param_spec = g_param_spec_string("note-name",
351 i18n_pspec("note name"),
352 i18n_pspec("The note's name"),
353 NULL,
354 G_PARAM_READABLE | G_PARAM_WRITABLE);
355 g_object_class_install_property(gobject,
356 PROP_NOTE_NAME,
357 param_spec);
358
359 /**
360 * AgsNote:frequency:
361 *
362 * The note's frequency.
363 *
364 * Since: 3.0.0
365 */
366 param_spec = g_param_spec_double("frequency",
367 i18n_pspec("frequency"),
368 i18n_pspec("The note's frequency"),
369 0.0,
370 G_MAXDOUBLE,
371 0.0,
372 G_PARAM_READABLE | G_PARAM_WRITABLE);
373 g_object_class_install_property(gobject,
374 PROP_FREQUENCY,
375 param_spec);
376 }
377
378 void
ags_note_init(AgsNote * note)379 ags_note_init(AgsNote *note)
380 {
381 double _Complex z;
382
383 note->flags = 0;
384
385 /* note mutex */
386 g_rec_mutex_init(&(note->obj_mutex));
387
388 /* fields */
389 note->x[0] = 0;
390 note->x[1] = 1;
391 note->y = 0;
392
393 note->rt_offset = 0;
394 note->rt_attack = 0;
395
396 note->stream_delay = 0.0;
397 note->stream_attack = 0;
398
399 z = 0.25 + I * 1.0;
400 ags_complex_set(&(note->attack),
401 z);
402
403 z = 0.25 + I * 1.0;
404 ags_complex_set(&(note->decay),
405 z);
406
407 z = 0.25 + I * 1.0;
408 ags_complex_set(&(note->sustain),
409 z);
410
411 z = 0.25 + I * 1.0;
412 ags_complex_set(&(note->release),
413 z);
414
415 z = I * 1.0;
416 ags_complex_set(&(note->ratio),
417 z);
418
419 note->note_name = NULL;
420 note->frequency = 440.0;
421 }
422
423 void
ags_note_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)424 ags_note_set_property(GObject *gobject,
425 guint prop_id,
426 const GValue *value,
427 GParamSpec *param_spec)
428 {
429 AgsNote *note;
430
431 GRecMutex *note_mutex;
432
433 note = AGS_NOTE(gobject);
434
435 /* get note mutex */
436 note_mutex = AGS_NOTE_GET_OBJ_MUTEX(note);
437
438 switch(prop_id){
439 case PROP_X0:
440 {
441 g_rec_mutex_lock(note_mutex);
442
443 note->x[0] = g_value_get_uint(value);
444
445 g_rec_mutex_unlock(note_mutex);
446 }
447 break;
448 case PROP_X1:
449 {
450 g_rec_mutex_lock(note_mutex);
451
452 note->x[1] = g_value_get_uint(value);
453
454 g_rec_mutex_unlock(note_mutex);
455 }
456 break;
457 case PROP_Y:
458 {
459 g_rec_mutex_lock(note_mutex);
460
461 note->y = g_value_get_uint(value);
462
463 g_rec_mutex_unlock(note_mutex);
464 }
465 break;
466 case PROP_RT_OFFSET:
467 {
468 g_rec_mutex_lock(note_mutex);
469
470 note->rt_offset = g_value_get_uint64(value);
471
472 g_rec_mutex_unlock(note_mutex);
473 }
474 break;
475 case PROP_RT_ATTACK:
476 {
477 g_rec_mutex_lock(note_mutex);
478
479 note->rt_attack = g_value_get_uint(value);
480
481 g_rec_mutex_unlock(note_mutex);
482 }
483 break;
484 case PROP_STREAM_DELAY:
485 {
486 g_rec_mutex_lock(note_mutex);
487
488 note->stream_delay = g_value_get_double(value);
489
490 g_rec_mutex_unlock(note_mutex);
491 }
492 break;
493 case PROP_STREAM_ATTACK:
494 {
495 g_rec_mutex_lock(note_mutex);
496
497 note->stream_attack = g_value_get_double(value);
498
499 g_rec_mutex_unlock(note_mutex);
500 }
501 break;
502 case PROP_STREAM_FRAME_COUNT:
503 {
504 g_rec_mutex_lock(note_mutex);
505
506 note->stream_frame_count = g_value_get_uint64(value);
507
508 g_rec_mutex_unlock(note_mutex);
509 }
510 break;
511 case PROP_ATTACK:
512 {
513 AgsComplex *attack;
514
515 attack = (AgsComplex *) g_value_get_boxed(value);
516
517 g_rec_mutex_lock(note_mutex);
518
519 ags_complex_set(&(note->attack),
520 ags_complex_get(attack));
521
522 g_rec_mutex_unlock(note_mutex);
523 }
524 break;
525 case PROP_SUSTAIN:
526 {
527 AgsComplex *sustain;
528
529 sustain = (AgsComplex *) g_value_get_boxed(value);
530
531 g_rec_mutex_lock(note_mutex);
532
533 ags_complex_set(&(note->sustain),
534 ags_complex_get(sustain));
535
536 g_rec_mutex_unlock(note_mutex);
537 }
538 break;
539 case PROP_DECAY:
540 {
541 AgsComplex *decay;
542
543 decay = (AgsComplex *) g_value_get_boxed(value);
544
545 g_rec_mutex_lock(note_mutex);
546
547 ags_complex_set(&(note->decay),
548 ags_complex_get(decay));
549
550 g_rec_mutex_unlock(note_mutex);
551 }
552 break;
553 case PROP_RELEASE:
554 {
555 AgsComplex *release;
556
557 release = (AgsComplex *) g_value_get_boxed(value);
558
559 g_rec_mutex_lock(note_mutex);
560
561 ags_complex_set(&(note->release),
562 ags_complex_get(release));
563
564 g_rec_mutex_unlock(note_mutex);
565 }
566 break;
567 case PROP_RATIO:
568 {
569 AgsComplex *ratio;
570
571 ratio = (AgsComplex *) g_value_get_boxed(value);
572
573 g_rec_mutex_lock(note_mutex);
574
575 ags_complex_set(&(note->ratio),
576 ags_complex_get(ratio));
577
578 g_rec_mutex_unlock(note_mutex);
579 }
580 break;
581 case PROP_NOTE_NAME:
582 {
583 gchar *note_name;
584
585 note_name = g_value_get_string(value);
586
587 g_rec_mutex_lock(note_mutex);
588
589 if(note_name == note->note_name){
590 g_rec_mutex_unlock(note_mutex);
591
592 return;
593 }
594
595 if(note->note_name != NULL){
596 g_free(note->note_name);
597 }
598
599 note->note_name = g_strdup(note_name);
600
601 g_rec_mutex_unlock(note_mutex);
602 }
603 break;
604 case PROP_FREQUENCY:
605 {
606 g_rec_mutex_lock(note_mutex);
607
608 note->frequency = g_value_get_double(value);
609
610 g_rec_mutex_unlock(note_mutex);
611 }
612 break;
613 default:
614 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
615 break;
616 }
617 }
618
619 void
ags_note_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)620 ags_note_get_property(GObject *gobject,
621 guint prop_id,
622 GValue *value,
623 GParamSpec *param_spec)
624 {
625 AgsNote *note;
626
627 GRecMutex *note_mutex;
628
629 note = AGS_NOTE(gobject);
630
631 /* get note mutex */
632 note_mutex = AGS_NOTE_GET_OBJ_MUTEX(note);
633
634 switch(prop_id){
635 case PROP_X0:
636 {
637 g_rec_mutex_lock(note_mutex);
638
639 g_value_set_uint(value, note->x[0]);
640
641 g_rec_mutex_unlock(note_mutex);
642 }
643 break;
644 case PROP_X1:
645 {
646 g_rec_mutex_lock(note_mutex);
647
648 g_value_set_uint(value, note->x[1]);
649
650 g_rec_mutex_unlock(note_mutex);
651 }
652 break;
653 case PROP_Y:
654 {
655 g_rec_mutex_lock(note_mutex);
656
657 g_value_set_uint(value, note->y);
658
659 g_rec_mutex_unlock(note_mutex);
660 }
661 break;
662 case PROP_RT_OFFSET:
663 {
664 g_rec_mutex_lock(note_mutex);
665
666 g_value_set_uint64(value, note->rt_offset);
667
668 g_rec_mutex_unlock(note_mutex);
669 }
670 break;
671 case PROP_RT_ATTACK:
672 {
673 g_rec_mutex_lock(note_mutex);
674
675 g_value_set_uint(value, note->rt_attack);
676
677 g_rec_mutex_unlock(note_mutex);
678 }
679 break;
680 case PROP_STREAM_DELAY:
681 {
682 g_rec_mutex_lock(note_mutex);
683
684 g_value_set_double(value, note->stream_delay);
685
686 g_rec_mutex_unlock(note_mutex);
687 }
688 break;
689 case PROP_STREAM_ATTACK:
690 {
691 g_rec_mutex_lock(note_mutex);
692
693 g_value_set_double(value, note->stream_attack);
694
695 g_rec_mutex_unlock(note_mutex);
696 }
697 break;
698 case PROP_STREAM_FRAME_COUNT:
699 {
700 g_rec_mutex_lock(note_mutex);
701
702 g_value_set_uint64(value, note->stream_frame_count);
703
704 g_rec_mutex_unlock(note_mutex);
705 }
706 break;
707 case PROP_ATTACK:
708 {
709 g_rec_mutex_lock(note_mutex);
710
711 g_value_set_boxed(value, &(note->attack));
712
713 g_rec_mutex_unlock(note_mutex);
714 }
715 break;
716 case PROP_SUSTAIN:
717 {
718 g_rec_mutex_lock(note_mutex);
719
720 g_value_set_boxed(value, &(note->sustain));
721
722 g_rec_mutex_unlock(note_mutex);
723 }
724 break;
725 case PROP_DECAY:
726 {
727 g_rec_mutex_lock(note_mutex);
728
729 g_value_set_boxed(value, &(note->decay));
730
731 g_rec_mutex_unlock(note_mutex);
732 }
733 break;
734 case PROP_RELEASE:
735 {
736 g_rec_mutex_lock(note_mutex);
737
738 g_value_set_boxed(value, &(note->release));
739
740 g_rec_mutex_unlock(note_mutex);
741 }
742 break;
743 case PROP_RATIO:
744 {
745 g_rec_mutex_lock(note_mutex);
746
747 g_value_set_boxed(value, &(note->ratio));
748
749 g_rec_mutex_unlock(note_mutex);
750 }
751 break;
752 case PROP_NOTE_NAME:
753 {
754 g_rec_mutex_lock(note_mutex);
755
756 g_value_set_string(value, note->note_name);
757
758 g_rec_mutex_unlock(note_mutex);
759 }
760 break;
761 case PROP_FREQUENCY:
762 {
763 g_rec_mutex_lock(note_mutex);
764
765 g_value_set_double(value, note->frequency);
766
767 g_rec_mutex_unlock(note_mutex);
768 }
769 break;
770 default:
771 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
772 break;
773 }
774 }
775
776 void
ags_note_finalize(GObject * gobject)777 ags_note_finalize(GObject *gobject)
778 {
779 AgsNote *note;
780
781 note = AGS_NOTE(gobject);
782
783 /* note name */
784 if(note->note_name != NULL){
785 free(note->note_name);
786 }
787
788 /* call parent */
789 G_OBJECT_CLASS(ags_note_parent_class)->finalize(gobject);
790 }
791
792 /**
793 * ags_note_get_obj_mutex:
794 * @note: the #AgsNote
795 *
796 * Get object mutex.
797 *
798 * Returns: the #GRecMutex to lock @note
799 *
800 * Since: 3.1.0
801 */
802 GRecMutex*
ags_note_get_obj_mutex(AgsNote * note)803 ags_note_get_obj_mutex(AgsNote *note)
804 {
805 if(!AGS_IS_NOTE(note)){
806 return(NULL);
807 }
808
809 return(AGS_NOTE_GET_OBJ_MUTEX(note));
810 }
811
812 /**
813 * ags_note_test_flags:
814 * @note: the #AgsNote
815 * @flags: the flags
816 *
817 * Test @flags to be set on @note.
818 *
819 * Returns: %TRUE if flags are set, else %FALSE
820 *
821 * Since: 3.0.0
822 */
823 gboolean
ags_note_test_flags(AgsNote * note,guint flags)824 ags_note_test_flags(AgsNote *note, guint flags)
825 {
826 gboolean retval;
827
828 GRecMutex *note_mutex;
829
830 if(!AGS_IS_NOTE(note)){
831 return(FALSE);
832 }
833
834 /* get note mutex */
835 note_mutex = AGS_NOTE_GET_OBJ_MUTEX(note);
836
837 /* test */
838 g_rec_mutex_lock(note_mutex);
839
840 retval = (flags & (note->flags)) ? TRUE: FALSE;
841
842 g_rec_mutex_unlock(note_mutex);
843
844 return(retval);
845 }
846
847 /**
848 * ags_note_set_flags:
849 * @note: the #AgsNote
850 * @flags: the flags
851 *
852 * Set @flags on @note.
853 *
854 * Since: 3.0.0
855 */
856 void
ags_note_set_flags(AgsNote * note,guint flags)857 ags_note_set_flags(AgsNote *note, guint flags)
858 {
859 GRecMutex *note_mutex;
860
861 if(!AGS_IS_NOTE(note)){
862 return;
863 }
864
865 /* get note mutex */
866 note_mutex = AGS_NOTE_GET_OBJ_MUTEX(note);
867
868 /* set */
869 g_rec_mutex_lock(note_mutex);
870
871 note->flags |= flags;
872
873 g_rec_mutex_unlock(note_mutex);
874 }
875
876 /**
877 * ags_note_unset_flags:
878 * @note: the #AgsNote
879 * @flags: the flags
880 *
881 * Unset @flags on @note.
882 *
883 * Since: 3.0.0
884 */
885 void
ags_note_unset_flags(AgsNote * note,guint flags)886 ags_note_unset_flags(AgsNote *note, guint flags)
887 {
888 GRecMutex *note_mutex;
889
890 if(!AGS_IS_NOTE(note)){
891 return;
892 }
893
894 /* get note mutex */
895 note_mutex = AGS_NOTE_GET_OBJ_MUTEX(note);
896
897 /* unset */
898 g_rec_mutex_lock(note_mutex);
899
900 note->flags &= (~flags);
901
902 g_rec_mutex_unlock(note_mutex);
903 }
904
905 /**
906 * ags_note_sort_func:
907 * @a: the #AgsNote
908 * @b: another #AgsNote
909 *
910 * Sort notes.
911 *
912 * Returns: 0 if equal, -1 if smaller and 1 if bigger offset
913 *
914 * Since: 3.0.0
915 */
916 gint
ags_note_sort_func(gconstpointer a,gconstpointer b)917 ags_note_sort_func(gconstpointer a,
918 gconstpointer b)
919 {
920 guint a_x0, b_x0;
921 guint a_y, b_y;
922
923 if(a == NULL || b == NULL){
924 return(0);
925 }
926
927 g_object_get(a,
928 "x0", &a_x0,
929 "y", &a_y,
930 NULL);
931
932 g_object_get(b,
933 "x0", &b_x0,
934 "y", &b_y,
935 NULL);
936
937 if(a_x0 == b_x0){
938 if(a_y == b_y){
939 return(0);
940 }
941
942 if(a_y < b_y){
943 return(-1);
944 }else{
945 return(1);
946 }
947 }
948
949 if(a_x0 < b_x0){
950 return(-1);
951 }else{
952 return(1);
953 }
954 }
955
956 /**
957 * ags_note_get_is_minor:
958 * @note: the #AgsNote
959 *
960 * Gets is minor.
961 *
962 * Returns: is minor
963 *
964 * Since: 3.1.0
965 */
966 gboolean
ags_note_get_is_minor(AgsNote * note)967 ags_note_get_is_minor(AgsNote *note)
968 {
969 gboolean is_minor;
970
971 if(!AGS_IS_NOTE(note)){
972 return(FALSE);
973 }
974
975 g_object_get(note,
976 "is-minor", &is_minor,
977 NULL);
978
979 return(is_minor);
980 }
981
982 /**
983 * ags_note_set_is_minor:
984 * @note: the #AgsNote
985 * @is_minor: is minor
986 *
987 * Sets is minor.
988 *
989 * Since: 3.1.0
990 */
991 void
ags_note_set_is_minor(AgsNote * note,gboolean is_minor)992 ags_note_set_is_minor(AgsNote *note, gboolean is_minor)
993 {
994 if(!AGS_IS_NOTE(note)){
995 return;
996 }
997
998 g_object_set(note,
999 "is-minor", is_minor,
1000 NULL);
1001 }
1002
1003 /**
1004 * ags_note_get_sharp_flats:
1005 * @note: the #AgsNote
1006 *
1007 * Gets sharp flats.
1008 *
1009 * Returns: the sharp flats
1010 *
1011 * Since: 3.1.0
1012 */
1013 guint
ags_note_get_sharp_flats(AgsNote * note)1014 ags_note_get_sharp_flats(AgsNote *note)
1015 {
1016 guint sharp_flats;
1017
1018 if(!AGS_IS_NOTE(note)){
1019 return(0);
1020 }
1021
1022 g_object_get(note,
1023 "sharp-flats", &sharp_flats,
1024 NULL);
1025
1026 return(sharp_flats);
1027 }
1028
1029 /**
1030 * ags_note_set_sharp_flats:
1031 * @note: the #AgsNote
1032 * @sharp_flats: the sharp flats
1033 *
1034 * Sets sharp flats.
1035 *
1036 * Since: 3.1.0
1037 */
1038 void
ags_note_set_sharp_flats(AgsNote * note,guint sharp_flats)1039 ags_note_set_sharp_flats(AgsNote *note, guint sharp_flats)
1040 {
1041 if(!AGS_IS_NOTE(note)){
1042 return;
1043 }
1044
1045 g_object_set(note,
1046 "sharp-flats", sharp_flats,
1047 NULL);
1048 }
1049
1050 /**
1051 * ags_note_get_x0:
1052 * @note: the #AgsNote
1053 *
1054 * Gets x0.
1055 *
1056 * Returns: the sharp flats
1057 *
1058 * Since: 3.1.0
1059 */
1060 guint
ags_note_get_x0(AgsNote * note)1061 ags_note_get_x0(AgsNote *note)
1062 {
1063 guint x0;
1064
1065 if(!AGS_IS_NOTE(note)){
1066 return(0);
1067 }
1068
1069 g_object_get(note,
1070 "x0", &x0,
1071 NULL);
1072
1073 return(x0);
1074 }
1075
1076 /**
1077 * ags_note_set_x0:
1078 * @note: the #AgsNote
1079 * @x0: the x0
1080 *
1081 * Sets x0.
1082 *
1083 * Since: 3.1.0
1084 */
1085 void
ags_note_set_x0(AgsNote * note,guint x0)1086 ags_note_set_x0(AgsNote *note, guint x0)
1087 {
1088 if(!AGS_IS_NOTE(note)){
1089 return;
1090 }
1091
1092 g_object_set(note,
1093 "x0", x0,
1094 NULL);
1095 }
1096
1097 /**
1098 * ags_note_get_x1:
1099 * @note: the #AgsNote
1100 *
1101 * Gets x1.
1102 *
1103 * Returns: the x1
1104 *
1105 * Since: 3.1.0
1106 */
1107 guint
ags_note_get_x1(AgsNote * note)1108 ags_note_get_x1(AgsNote *note)
1109 {
1110 guint x1;
1111
1112 if(!AGS_IS_NOTE(note)){
1113 return(0);
1114 }
1115
1116 g_object_get(note,
1117 "x1", &x1,
1118 NULL);
1119
1120 return(x1);
1121 }
1122
1123 /**
1124 * ags_note_set_x1:
1125 * @note: the #AgsNote
1126 * @x1: the x1
1127 *
1128 * Sets x1.
1129 *
1130 * Since: 3.1.0
1131 */
1132 void
ags_note_set_x1(AgsNote * note,guint x1)1133 ags_note_set_x1(AgsNote *note, guint x1)
1134 {
1135 if(!AGS_IS_NOTE(note)){
1136 return;
1137 }
1138
1139 g_object_set(note,
1140 "x1", x1,
1141 NULL);
1142 }
1143
1144 /**
1145 * ags_note_get_y:
1146 * @note: the #AgsNote
1147 *
1148 * Gets y.
1149 *
1150 * Returns: the y
1151 *
1152 * Since: 3.1.0
1153 */
1154 guint
ags_note_get_y(AgsNote * note)1155 ags_note_get_y(AgsNote *note)
1156 {
1157 guint y;
1158
1159 if(!AGS_IS_NOTE(note)){
1160 return(0);
1161 }
1162
1163 g_object_get(note,
1164 "y", &y,
1165 NULL);
1166
1167 return(y);
1168 }
1169
1170 /**
1171 * ags_note_set_y:
1172 * @note: the #AgsNote
1173 * @y: the y
1174 *
1175 * Sets y.
1176 *
1177 * Since: 3.1.0
1178 */
1179 void
ags_note_set_y(AgsNote * note,guint y)1180 ags_note_set_y(AgsNote *note, guint y)
1181 {
1182 if(!AGS_IS_NOTE(note)){
1183 return;
1184 }
1185
1186 g_object_set(note,
1187 "y", y,
1188 NULL);
1189 }
1190
1191 /**
1192 * ags_note_get_rt_offset:
1193 * @note: the #AgsNote
1194 *
1195 * Gets rt-offset.
1196 *
1197 * Returns: the rt-offset
1198 *
1199 * Since: 3.1.0
1200 */
1201 guint64
ags_note_get_rt_offset(AgsNote * note)1202 ags_note_get_rt_offset(AgsNote *note)
1203 {
1204 guint64 rt_offset;
1205
1206 if(!AGS_IS_NOTE(note)){
1207 return(0);
1208 }
1209
1210 g_object_get(note,
1211 "rt-offset", &rt_offset,
1212 NULL);
1213
1214 return(rt_offset);
1215 }
1216
1217 /**
1218 * ags_note_set_rt_offset:
1219 * @note: the #AgsNote
1220 * @rt_offset: the rt-offset
1221 *
1222 * Sets rt-offset.
1223 *
1224 * Since: 3.1.0
1225 */
1226 void
ags_note_set_rt_offset(AgsNote * note,guint64 rt_offset)1227 ags_note_set_rt_offset(AgsNote *note, guint64 rt_offset)
1228 {
1229 if(!AGS_IS_NOTE(note)){
1230 return;
1231 }
1232
1233 g_object_set(note,
1234 "rt-offset", rt_offset,
1235 NULL);
1236 }
1237
1238 /**
1239 * ags_note_get_rt_attack:
1240 * @note: the #AgsNote
1241 *
1242 * Gets rt-attack.
1243 *
1244 * Returns: the rt-attack
1245 *
1246 * Since: 3.1.0
1247 */
1248 guint
ags_note_get_rt_attack(AgsNote * note)1249 ags_note_get_rt_attack(AgsNote *note)
1250 {
1251 guint rt_attack;
1252
1253 if(!AGS_IS_NOTE(note)){
1254 return(0);
1255 }
1256
1257 g_object_get(note,
1258 "rt-attack", &rt_attack,
1259 NULL);
1260
1261 return(rt_attack);
1262 }
1263
1264 /**
1265 * ags_note_set_rt_attack:
1266 * @note: the #AgsNote
1267 * @rt_attack: the rt-attack
1268 *
1269 * Sets rt-attack.
1270 *
1271 * Since: 3.1.0
1272 */
1273 void
ags_note_set_rt_attack(AgsNote * note,guint rt_attack)1274 ags_note_set_rt_attack(AgsNote *note, guint rt_attack)
1275 {
1276 if(!AGS_IS_NOTE(note)){
1277 return;
1278 }
1279
1280 g_object_set(note,
1281 "rt-attack", rt_attack,
1282 NULL);
1283 }
1284
1285 /**
1286 * ags_note_get_attack:
1287 * @note: the #AgsNote
1288 *
1289 * Gets attack.
1290 *
1291 * Returns: the attack
1292 *
1293 * Since: 3.1.0
1294 */
1295 AgsComplex*
ags_note_get_attack(AgsNote * note)1296 ags_note_get_attack(AgsNote *note)
1297 {
1298 AgsComplex *attack;
1299
1300 if(!AGS_IS_NOTE(note)){
1301 return(NULL);
1302 }
1303
1304 g_object_get(note,
1305 "attack", &attack,
1306 NULL);
1307
1308 return(attack);
1309 }
1310
1311 /**
1312 * ags_note_set_attack:
1313 * @note: the #AgsNote
1314 * @attack: the attack
1315 *
1316 * Sets attack.
1317 *
1318 * Since: 3.1.0
1319 */
1320 void
ags_note_set_attack(AgsNote * note,AgsComplex * attack)1321 ags_note_set_attack(AgsNote *note, AgsComplex *attack)
1322 {
1323 if(!AGS_IS_NOTE(note)){
1324 return;
1325 }
1326
1327 g_object_set(note,
1328 "attack", attack,
1329 NULL);
1330 }
1331
1332 /**
1333 * ags_note_get_sustain:
1334 * @note: the #AgsNote
1335 *
1336 * Gets sustain.
1337 *
1338 * Returns: the sustain
1339 *
1340 * Since: 3.1.0
1341 */
1342 AgsComplex*
ags_note_get_sustain(AgsNote * note)1343 ags_note_get_sustain(AgsNote *note)
1344 {
1345 AgsComplex *sustain;
1346
1347 if(!AGS_IS_NOTE(note)){
1348 return(NULL);
1349 }
1350
1351 g_object_get(note,
1352 "sustain", &sustain,
1353 NULL);
1354
1355 return(sustain);
1356 }
1357
1358 /**
1359 * ags_note_set_sustain:
1360 * @note: the #AgsNote
1361 * @sustain: the sustain
1362 *
1363 * Sets sustain.
1364 *
1365 * Since: 3.1.0
1366 */
1367 void
ags_note_set_sustain(AgsNote * note,AgsComplex * sustain)1368 ags_note_set_sustain(AgsNote *note, AgsComplex *sustain)
1369 {
1370 if(!AGS_IS_NOTE(note)){
1371 return;
1372 }
1373
1374 g_object_set(note,
1375 "sustain", sustain,
1376 NULL);
1377 }
1378
1379 /**
1380 * ags_note_get_decay:
1381 * @note: the #AgsNote
1382 *
1383 * Gets decay.
1384 *
1385 * Returns: the decay
1386 *
1387 * Since: 3.1.0
1388 */
1389 AgsComplex*
ags_note_get_decay(AgsNote * note)1390 ags_note_get_decay(AgsNote *note)
1391 {
1392 AgsComplex *decay;
1393
1394 if(!AGS_IS_NOTE(note)){
1395 return(NULL);
1396 }
1397
1398 g_object_get(note,
1399 "decay", &decay,
1400 NULL);
1401
1402 return(decay);
1403 }
1404
1405 /**
1406 * ags_note_set_decay:
1407 * @note: the #AgsNote
1408 * @decay: the decay
1409 *
1410 * Sets decay.
1411 *
1412 * Since: 3.1.0
1413 */
1414 void
ags_note_set_decay(AgsNote * note,AgsComplex * decay)1415 ags_note_set_decay(AgsNote *note, AgsComplex *decay)
1416 {
1417 if(!AGS_IS_NOTE(note)){
1418 return;
1419 }
1420
1421 g_object_set(note,
1422 "decay", decay,
1423 NULL);
1424 }
1425
1426 /**
1427 * ags_note_get_release:
1428 * @note: the #AgsNote
1429 *
1430 * Gets release.
1431 *
1432 * Returns: the release
1433 *
1434 * Since: 3.1.0
1435 */
1436 AgsComplex*
ags_note_get_release(AgsNote * note)1437 ags_note_get_release(AgsNote *note)
1438 {
1439 AgsComplex *release;
1440
1441 if(!AGS_IS_NOTE(note)){
1442 return(NULL);
1443 }
1444
1445 g_object_get(note,
1446 "release", &release,
1447 NULL);
1448
1449 return(release);
1450 }
1451
1452 /**
1453 * ags_note_set_release:
1454 * @note: the #AgsNote
1455 * @release: the release
1456 *
1457 * Sets release.
1458 *
1459 * Since: 3.1.0
1460 */
1461 void
ags_note_set_release(AgsNote * note,AgsComplex * release)1462 ags_note_set_release(AgsNote *note, AgsComplex *release)
1463 {
1464 if(!AGS_IS_NOTE(note)){
1465 return;
1466 }
1467
1468 g_object_set(note,
1469 "release", release,
1470 NULL);
1471 }
1472
1473 /**
1474 * ags_note_get_ratio:
1475 * @note: the #AgsNote
1476 *
1477 * Gets ratio.
1478 *
1479 * Returns: the ratio
1480 *
1481 * Since: 3.1.0
1482 */
1483 AgsComplex*
ags_note_get_ratio(AgsNote * note)1484 ags_note_get_ratio(AgsNote *note)
1485 {
1486 AgsComplex *ratio;
1487
1488 if(!AGS_IS_NOTE(note)){
1489 return(NULL);
1490 }
1491
1492 g_object_get(note,
1493 "ratio", &ratio,
1494 NULL);
1495
1496 return(ratio);
1497 }
1498
1499 /**
1500 * ags_note_set_ratio:
1501 * @note: the #AgsNote
1502 * @ratio: the ratio
1503 *
1504 * Sets ratio.
1505 *
1506 * Since: 3.1.0
1507 */
1508 void
ags_note_set_ratio(AgsNote * note,AgsComplex * ratio)1509 ags_note_set_ratio(AgsNote *note, AgsComplex *ratio)
1510 {
1511 if(!AGS_IS_NOTE(note)){
1512 return;
1513 }
1514
1515 g_object_set(note,
1516 "ratio", ratio,
1517 NULL);
1518 }
1519
1520 /**
1521 * ags_note_find_prev:
1522 * @note: (element-type AgsAudio.Note) (transfer none): the #GList-struct containing #AgsNote
1523 * @x0: x offset
1524 * @y: y offset
1525 *
1526 * Find prev note having the same y offset.
1527 *
1528 * Returns: (element-type AgsAudio.Note) (transfer none): the matching entry as #GList-struct if first entry's x offset bigger than @x0, else %NULL
1529 *
1530 * Since: 3.0.0
1531 */
1532 GList*
ags_note_find_prev(GList * note,guint x0,guint y)1533 ags_note_find_prev(GList *note,
1534 guint x0, guint y)
1535 {
1536 GList *current_match;
1537
1538 guint current_x0, current_y;
1539
1540 if(note == NULL){
1541 return(NULL);
1542 }
1543
1544 g_object_get(note->data,
1545 "x0", ¤t_x0,
1546 NULL);
1547
1548 if(current_x0 > x0){
1549 return(NULL);
1550 }
1551
1552 current_match = NULL;
1553
1554 while(note != NULL){
1555 g_object_get(note->data,
1556 "y", ¤t_y,
1557 NULL);
1558
1559 if(current_y == y){
1560 current_match = note;
1561
1562 note = note->next;
1563
1564 continue;
1565 }
1566
1567 g_object_get(note->data,
1568 "x0", ¤t_x0,
1569 NULL);
1570
1571 if(current_x0 > x0){
1572 return(current_match);
1573 }
1574
1575 note = note->next;
1576 }
1577
1578 return(current_match);
1579 }
1580
1581 /**
1582 * ags_note_find_next:
1583 * @note: (element-type AgsAudio.Note) (transfer none): the #GList-struct containing #AgsNote
1584 * @x0: x offset
1585 * @y: y offset
1586 *
1587 * Find next note having the same y offset.
1588 *
1589 * Returns: (element-type AgsAudio.Note) (transfer none): the matching entry as #GList-struct if last entry's x offset smaller than @x0, else %NULL
1590 *
1591 * Since: 3.0.0
1592 */
1593 GList*
ags_note_find_next(GList * note,guint x0,guint y)1594 ags_note_find_next(GList *note,
1595 guint x0, guint y)
1596 {
1597 GList *current_match;
1598
1599 guint current_x0, current_y;
1600
1601 if(note == NULL){
1602 return(NULL);
1603 }
1604
1605 g_object_get(note->data,
1606 "x0", ¤t_x0,
1607 NULL);
1608
1609 if(current_x0 < x0){
1610 return(NULL);
1611 }
1612
1613 current_match = NULL;
1614
1615 while(note != NULL){
1616 g_object_get(note->data,
1617 "y", ¤t_y,
1618 NULL);
1619
1620 if(current_y == y){
1621 current_match = note;
1622
1623 note = note->prev;
1624
1625 continue;
1626 }
1627
1628 g_object_get(note->data,
1629 "x0", ¤t_x0,
1630 NULL);
1631
1632 if(current_x0 < x0){
1633 return(current_match);
1634 }
1635
1636 note = note->prev;
1637 }
1638
1639 return(current_match);
1640 }
1641
1642 /**
1643 * ags_note_length_to_smf_delta_time:
1644 * @note_length: the note length to convert
1645 * @bpm: the source bpm
1646 * @delay_factor: the source delay factor
1647 * @nn: numerator
1648 * @dd: denominator
1649 * @cc: clocks
1650 * @bb: beats
1651 * @tempo: tempo
1652 *
1653 * Convert note length to SMF delta-time.
1654 *
1655 * Returns: the delta-time
1656 *
1657 * Since: 3.0.0
1658 */
1659 glong
ags_note_length_to_smf_delta_time(guint note_length,gdouble bpm,gdouble delay_factor,glong nn,glong dd,glong cc,glong bb,glong tempo)1660 ags_note_length_to_smf_delta_time(guint note_length,
1661 gdouble bpm, gdouble delay_factor,
1662 glong nn, glong dd, glong cc, glong bb,
1663 glong tempo)
1664 {
1665 //TODO:JK: implement me
1666
1667 return(0);
1668 }
1669
1670 /**
1671 * ags_note_smf_delta_time_to_length:
1672 * @delta_time: delta-time
1673 * @nn: numerator
1674 * @dd: denominator
1675 * @cc: clocks
1676 * @bb: beats
1677 * @tempo: tempo
1678 * @bpm: the target bpm
1679 * @delay_factor: the target delay factor
1680 *
1681 * Convert SMF delta-time to note length.
1682 *
1683 * Returns: the note length
1684 *
1685 * Since: 3.0.0
1686 */
1687 guint
ags_note_smf_delta_time_to_length(glong delta_time,glong nn,glong dd,glong cc,glong bb,glong tempo,gdouble bpm,gdouble delay_factor)1688 ags_note_smf_delta_time_to_length(glong delta_time,
1689 glong nn, glong dd, glong cc, glong bb,
1690 glong tempo,
1691 gdouble bpm, gdouble delay_factor)
1692 {
1693 //TODO:JK: implement me
1694
1695 return(0);
1696 }
1697
1698 /**
1699 * ags_note_to_raw_midi:
1700 * @note: the #AgsNote
1701 * @bpm: the bpm to use
1702 * @delay_factor: the segmentation delay factor
1703 * @buffer_length: the length of the returned buffer
1704 *
1705 * Convert @note to raw MIDI and set the buffer length of returned bytes
1706 * in the array as @buffer_length.
1707 *
1708 * Returns: The sequencer raw midi as array.
1709 *
1710 * Since: 3.0.0
1711 */
1712 guchar*
ags_note_to_raw_midi(AgsNote * note,gdouble bpm,gdouble delay_factor,guint * buffer_length)1713 ags_note_to_raw_midi(AgsNote *note,
1714 gdouble bpm, gdouble delay_factor,
1715 guint *buffer_length)
1716 {
1717 guchar *raw_midi;
1718 guint length;
1719 guint current_length;
1720 long delta_time;
1721 guint delta_time_length;
1722 guchar status;
1723 int channel;
1724 int key;
1725 int velocity;
1726 int pressure;
1727 gdouble ticks_per_beat;
1728 guint i, i_stop;
1729 guint j;
1730 guint k;
1731
1732 if(note == NULL){
1733 if(buffer_length != NULL){
1734 *buffer_length = 0;
1735 }
1736
1737 return(NULL);
1738 }
1739
1740 length = 0;
1741
1742 /* key-on */
1743 k = 0;
1744
1745 /* delta-time */
1746 delta_time = note->x[0] / 16.0 / bpm * 60.0 / ((AGS_USEC_PER_SEC * bpm / 4.0) / (4.0 * bpm) / AGS_USEC_PER_SEC);
1747 delta_time_length =
1748 current_length = ags_midi_buffer_util_get_varlength_size(delta_time);
1749
1750 /* status and channel */
1751 channel = 0;
1752 status = (0x90 | (0x7f & channel));
1753 current_length++;
1754
1755 /* note / key */
1756 key = (0x7f & (note->y));
1757 current_length++;
1758
1759 /* velocity */
1760 velocity = (0x7f & (guchar) (128 * (ags_complex_get(&(note->attack)))));
1761 current_length++;
1762
1763 /* prepare buffer */
1764 raw_midi = (guchar *) malloc(current_length * sizeof(guchar));
1765 length += current_length;
1766
1767 ags_midi_buffer_util_put_varlength(raw_midi,
1768 delta_time);
1769 k += delta_time_length;
1770
1771 raw_midi[k] = status;
1772 raw_midi[k + 1] = key;
1773 raw_midi[k + 2] = velocity;
1774
1775 k += 3;
1776
1777 /* key-pressure */
1778 ticks_per_beat = AGS_NOTE_DEFAULT_TICKS_PER_QUARTER_NOTE / 4.0 / delay_factor;
1779
1780 if(ticks_per_beat > 2.0){
1781 i_stop = (note->x[1] - note->x[0]) * (ticks_per_beat - 2.0);
1782
1783 for(i = 1; i <= i_stop; i++){
1784 /* delta-time */
1785 delta_time = (note->x[0] + i + 1) / 16.0 / bpm * 60.0 / ((AGS_USEC_PER_SEC * bpm / 4.0) / (4.0 * bpm) / AGS_USEC_PER_SEC);
1786 delta_time_length =
1787 current_length = ags_midi_buffer_util_get_varlength_size(delta_time);
1788
1789 /* status and channel */
1790 channel = 0;
1791 status = (0x90 | (0x7f & channel));
1792 current_length++;
1793
1794 /* note / key */
1795 key = (0x7f & (note->y));
1796 current_length++;
1797
1798 /* pressure */
1799 //TODO:JK: verify
1800 pressure = (0x7f & (guchar) (128 * (((ags_complex_get(&(note->decay)) / i) - (i * ags_complex_get(&(note->sustain)))))));
1801 current_length++;
1802
1803 /* prepare buffer */
1804 raw_midi = (guchar *) realloc(raw_midi,
1805 current_length * sizeof(guchar));
1806 length += current_length;
1807
1808 ags_midi_buffer_util_put_varlength(raw_midi,
1809 delta_time);
1810 k += delta_time_length;
1811
1812 raw_midi[k] = status;
1813 raw_midi[k + 1] = key;
1814 raw_midi[k + 2] = pressure;
1815
1816 k += 3;
1817 }
1818 }
1819
1820 /* key-off */
1821 /* delta-time */
1822 delta_time = note->x[1] / 16.0 / bpm * 60.0 / ((AGS_USEC_PER_SEC * bpm / 4.0) / (4.0 * bpm) / AGS_USEC_PER_SEC);
1823 delta_time_length =
1824 current_length = ags_midi_buffer_util_get_varlength_size(delta_time);
1825
1826 /* status and channel */
1827 channel = 0;
1828 status = (0x90 | (0x7f & channel));
1829 current_length++;
1830
1831 /* note / key */
1832 key = (0x7f & (note->y));
1833 current_length++;
1834
1835 /* velocity */
1836 velocity = (0x7f & (guchar) (128 * (ags_complex_get(&(note->attack)))));
1837 current_length++;
1838
1839 /* prepare buffer */
1840 raw_midi = (guchar *) realloc(raw_midi,
1841 current_length * sizeof(guchar));
1842 length += current_length;
1843
1844 ags_midi_buffer_util_put_varlength(raw_midi,
1845 delta_time);
1846 k += delta_time_length;
1847
1848 raw_midi[k] = status;
1849 raw_midi[k + 1] = key;
1850 raw_midi[k + 2] = velocity;
1851
1852 /* return value */
1853 if(buffer_length != NULL){
1854 *buffer_length = length;
1855 }
1856
1857 return(raw_midi);
1858 }
1859
1860 /**
1861 * ags_note_to_raw_midi_extended:
1862 * @note: the #AgsNote
1863 * @bpm: the source bpm
1864 * @delay_factor: the source delay factor
1865 * @nn: numerator
1866 * @dd: denominator
1867 * @cc: clocks
1868 * @bb: beats
1869 * @tempo: tempo
1870 * @buffer_length: the return location of buffer length
1871 *
1872 * Convert @note to raw-midi.
1873 *
1874 * Returns: the raw-midi buffer
1875 *
1876 * Since: 3.0.0
1877 */
1878 guchar*
ags_note_to_raw_midi_extended(AgsNote * note,gdouble bpm,gdouble delay_factor,glong nn,glong dd,glong cc,glong bb,glong tempo,guint * buffer_length)1879 ags_note_to_raw_midi_extended(AgsNote *note,
1880 gdouble bpm, gdouble delay_factor,
1881 glong nn, glong dd, glong cc, glong bb,
1882 glong tempo,
1883 guint *buffer_length)
1884 {
1885 //TODO:JK: implement me
1886
1887 return(NULL);
1888 }
1889
1890 /**
1891 * ags_note_to_seq_event:
1892 * @note: the #AgsNote
1893 * @bpm: the bpm to use
1894 * @delay_factor: the segmentation delay factor
1895 * @n_events: the count of events
1896 *
1897 * Convert @note to ALSA sequencer events and set the number of events
1898 * in the array as @n_events.
1899 *
1900 * Returns: (type gpointer) (transfer none): The sequencer events as array.
1901 *
1902 * Since: 3.0.0
1903 */
1904 snd_seq_event_t*
ags_note_to_seq_event(AgsNote * note,gdouble bpm,gdouble delay_factor,guint * n_events)1905 ags_note_to_seq_event(AgsNote *note,
1906 gdouble bpm, gdouble delay_factor,
1907 guint *n_events)
1908 {
1909 snd_seq_event_t *event;
1910
1911 event = NULL;
1912
1913 //TODO:JK: implement me
1914
1915 return(event);
1916 }
1917
1918 /**
1919 * ags_note_to_seq_event_extended:
1920 * @note: the #AgsNote
1921 * @bpm: the source bpm
1922 * @delay_factor: the source delay factor
1923 * @nn: numerator
1924 * @dd: denominator
1925 * @cc: clocks
1926 * @bb: beats
1927 * @tempo: tempo
1928 * @n_events: the return location of event count
1929 *
1930 * Convert @note to raw-midi.
1931 *
1932 * Returns: (type gpointer) (transfer none): an array of snd_seq_event_t structs
1933 *
1934 * Since: 3.0.0
1935 */
1936 snd_seq_event_t*
ags_note_to_seq_event_extended(AgsNote * note,gdouble bpm,gdouble delay_factor,glong nn,glong dd,glong cc,glong bb,glong tempo,guint * n_events)1937 ags_note_to_seq_event_extended(AgsNote *note,
1938 gdouble bpm, gdouble delay_factor,
1939 glong nn, glong dd, glong cc, glong bb,
1940 glong tempo,
1941 guint *n_events)
1942 {
1943 snd_seq_event_t *event;
1944
1945 event = NULL;
1946
1947 //TODO:JK: implement me
1948
1949 return(event);
1950 }
1951
1952 /**
1953 * ags_note_from_raw_midi:
1954 * @raw_midi: the data array
1955 * @bpm: the bpm to use
1956 * @delay_factor: the segmentation delay factor
1957 * @length: the length of the array
1958 *
1959 * Parse @raw_midi data and convert to #AgsNote.
1960 *
1961 * Returns: (element-type AgsAudio.Note) (transfer full): a #GList-struct containing the notes
1962 *
1963 * Since: 3.0.0
1964 */
1965 GList*
ags_note_from_raw_midi(guchar * raw_midi,gdouble bpm,gdouble delay_factor,guint length)1966 ags_note_from_raw_midi(guchar *raw_midi,
1967 gdouble bpm, gdouble delay_factor,
1968 guint length)
1969 {
1970 GList *list;
1971
1972 list = NULL;
1973
1974 //TODO:JK: implement me
1975
1976 return(list);
1977 }
1978
1979 /**
1980 * ags_note_from_raw_midi_extended:
1981 * @raw_midi: the data array
1982 * @nn: numerator
1983 * @dd: denominator
1984 * @cc: clocks
1985 * @bb: beats
1986 * @tempo: tempo
1987 * @bpm: the bpm to use
1988 * @delay_factor: the segmentation delay factor
1989 * @length: the length of the array
1990 *
1991 * Parse @raw_midi data and convert to #AgsNote.
1992 *
1993 * Returns: (element-type AgsAudio.Note) (transfer full): a #GList-struct containing the notes
1994 *
1995 * Since: 3.0.0
1996 */
1997 GList*
ags_note_from_raw_midi_extended(guchar * raw_midi,glong nn,glong dd,glong cc,glong bb,glong tempo,gdouble bpm,gdouble delay_factor,guint length)1998 ags_note_from_raw_midi_extended(guchar *raw_midi,
1999 glong nn, glong dd, glong cc, glong bb,
2000 glong tempo,
2001 gdouble bpm, gdouble delay_factor,
2002 guint length)
2003 {
2004 GList *list;
2005
2006 list = NULL;
2007
2008 //TODO:JK: implement me
2009
2010 return(list);
2011 }
2012
2013 /**
2014 * ags_note_from_seq_event:
2015 * @event: (type gpointer) (transfer none): ALSA sequencer events as array
2016 * @bpm: the bpm to use
2017 * @delay_factor: the segmentation delay factor
2018 * @n_events: the arrays length
2019 *
2020 * Convert ALSA sequencer data @event to #AgsNote.
2021 *
2022 * Returns: (element-type AgsAudio.Note) (transfer full): a #GList-struct containing the notes
2023 *
2024 * Since: 3.0.0
2025 */
2026 GList*
ags_note_from_seq_event(snd_seq_event_t * event,gdouble bpm,gdouble delay_factor,guint n_events)2027 ags_note_from_seq_event(snd_seq_event_t *event,
2028 gdouble bpm, gdouble delay_factor,
2029 guint n_events)
2030 {
2031 GList *list;
2032
2033 list = NULL;
2034
2035 //TODO:JK: implement me
2036
2037 return(list);
2038 }
2039
2040 /**
2041 * ags_note_from_seq_event_extended:
2042 * @event: (type gpointer) (transfer none): the snd_seq_event_t struct array
2043 * @nn: numerator
2044 * @dd: denominator
2045 * @cc: clocks
2046 * @bb: beats
2047 * @tempo: tempo
2048 * @bpm: the bpm to use
2049 * @delay_factor: the segmentation delay factor
2050 * @n_events: the count snd_seq_event_t structs
2051 *
2052 * Parse @raw_midi data and convert to #AgsNote.
2053 *
2054 * Returns: (element-type AgsAudio.Note) (transfer full): a #GList-struct containing the notes
2055 *
2056 * Since: 3.0.0
2057 */
2058 GList*
ags_note_from_seq_event_extended(snd_seq_event_t * event,glong nn,glong dd,glong cc,glong bb,glong tempo,gdouble bpm,gdouble delay_factor,guint n_events)2059 ags_note_from_seq_event_extended(snd_seq_event_t *event,
2060 glong nn, glong dd, glong cc, glong bb,
2061 glong tempo,
2062 gdouble bpm, gdouble delay_factor,
2063 guint n_events)
2064 {
2065 GList *list;
2066
2067 list = NULL;
2068
2069 //TODO:JK: implement me
2070
2071 return(list);
2072 }
2073
2074 /**
2075 * ags_note_duplicate:
2076 * @note: the #AgsNote
2077 *
2078 * Duplicate a note.
2079 *
2080 * Returns: (transfer full): the duplicated #AgsNote.
2081 *
2082 * Since: 3.0.0
2083 */
2084 AgsNote*
ags_note_duplicate(AgsNote * note)2085 ags_note_duplicate(AgsNote *note)
2086 {
2087 AgsNote *note_copy;
2088
2089 GRecMutex *note_mutex;
2090
2091 if(!AGS_IS_NOTE(note)){
2092 return(NULL);
2093 }
2094
2095 /* get note mutex */
2096 note_mutex = AGS_NOTE_GET_OBJ_MUTEX(note);
2097
2098 /* instantiate note */
2099 note_copy = ags_note_new();
2100
2101 note_copy->flags = 0;
2102
2103 g_rec_mutex_lock(note_mutex);
2104
2105 note_copy->note_name = g_strdup(note->note_name);
2106
2107 if(note->x[0] < note->x[1]){
2108 note_copy->x[0] = note->x[0];
2109 note_copy->x[1] = note->x[1];
2110 }else{
2111 note_copy->x[0] = note->x[1];
2112 note_copy->x[1] = note->x[0];
2113 }
2114
2115 note_copy->y = note->y;
2116
2117 note_copy->stream_delay = note->stream_delay;
2118 note_copy->stream_attack = note->stream_attack;
2119
2120 note_copy->attack.real = note->attack.real;
2121 note_copy->attack.imag = note->attack.imag;
2122
2123 note_copy->decay.real = note->decay.real;
2124 note_copy->decay.imag = note->decay.imag;
2125
2126 note_copy->sustain.real = note->sustain.real;
2127 note_copy->sustain.imag = note->sustain.imag;
2128
2129 note_copy->release.real = note->release.real;
2130 note_copy->release.imag = note->release.imag;
2131
2132 note_copy->ratio.real = note->ratio.real;
2133 note_copy->ratio.imag = note->ratio.imag;
2134
2135 g_rec_mutex_unlock(note_mutex);
2136
2137 return(note_copy);
2138 }
2139
2140 /**
2141 * ags_note_new:
2142 *
2143 * Creates a new instance of #AgsNote
2144 *
2145 * Returns: the new #AgsNote
2146 *
2147 * Since: 3.0.0
2148 */
2149 AgsNote*
ags_note_new()2150 ags_note_new()
2151 {
2152 AgsNote *note;
2153
2154 note = (AgsNote *) g_object_new(AGS_TYPE_NOTE,
2155 NULL);
2156
2157 return(note);
2158 }
2159
2160 /**
2161 * ags_note_new_with_offset:
2162 * @x0: x0
2163 * @x1: x1
2164 * @y: y
2165 * @stream_delay: delay
2166 * @stream_attack: attack
2167 *
2168 * Creates a new instance of #AgsNote
2169 *
2170 * Returns: the new #AgsNote
2171 *
2172 * Since: 3.0.0
2173 */
2174 AgsNote*
ags_note_new_with_offset(guint x0,guint x1,guint y,gdouble stream_delay,gdouble stream_attack)2175 ags_note_new_with_offset(guint x0, guint x1,
2176 guint y,
2177 gdouble stream_delay, gdouble stream_attack)
2178 {
2179 AgsNote *note;
2180
2181 note = (AgsNote *) g_object_new(AGS_TYPE_NOTE,
2182 "x0", x0,
2183 "x1", x1,
2184 "y", y,
2185 "stream-delay", stream_delay,
2186 "stream-attack", stream_attack,
2187 NULL);
2188
2189 return(note);
2190 }
2191