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", &current_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", &current_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", &current_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", &current_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", &current_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", &current_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