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/fx/ags_fx_notation_audio_processor.h>
21 
22 #include <ags/audio/ags_audio.h>
23 #include <ags/audio/ags_channel.h>
24 #include <ags/audio/ags_recycling.h>
25 #include <ags/audio/ags_audio_signal.h>
26 #include <ags/audio/ags_port.h>
27 #include <ags/audio/ags_notation.h>
28 #include <ags/audio/ags_note.h>
29 #include <ags/audio/ags_recall_id.h>
30 #include <ags/audio/ags_recycling_context.h>
31 
32 #include <ags/audio/midi/ags_midi_util.h>
33 
34 #include <ags/audio/fx/ags_fx_notation_audio.h>
35 
36 #include <ags/i18n.h>
37 
38 void ags_fx_notation_audio_processor_class_init(AgsFxNotationAudioProcessorClass *fx_notation_audio_processor);
39 void ags_fx_notation_audio_processor_seekable_interface_init(AgsSeekableInterface *seekable);
40 void ags_fx_notation_audio_processor_countable_interface_init(AgsCountableInterface *countable);
41 void ags_fx_notation_audio_processor_tactable_interface_init(AgsTactableInterface *tactable);
42 void ags_fx_notation_audio_processor_init(AgsFxNotationAudioProcessor *fx_notation_audio_processor);
43 void ags_fx_notation_audio_processor_dispose(GObject *gobject);
44 void ags_fx_notation_audio_processor_finalize(GObject *gobject);
45 
46 void ags_fx_notation_audio_processor_seek(AgsSeekable *seekable,
47 					  gint64 offset,
48 					  guint whence);
49 
50 guint64 ags_fx_notation_audio_processor_get_notation_counter(AgsCountable *countable);
51 
52 gdouble ags_fx_notation_audio_processor_get_bpm(AgsTactable *tactable);
53 gdouble ags_fx_notation_audio_processor_get_tact(AgsTactable *tactable);
54 void ags_fx_notation_audio_processor_change_bpm(AgsTactable *tactable, gdouble new_bpm, gdouble old_bpm);
55 void ags_fx_notation_audio_processor_change_tact(AgsTactable *tactable, gdouble new_tact, gdouble old_tact);
56 
57 void ags_fx_notation_audio_processor_run_init_pre(AgsRecall *recall);
58 void ags_fx_notation_audio_processor_run_inter(AgsRecall *recall);
59 
60 void ags_fx_notation_audio_processor_real_key_on(AgsFxNotationAudioProcessor *fx_notation_audio_processor,
61 						 AgsNote *note,
62 						 guint velocity,
63 						 guint key_mode);
64 void ags_fx_notation_audio_processor_real_key_off(AgsFxNotationAudioProcessor *fx_notation_audio_processor,
65 						  AgsNote *note,
66 						  guint velocity,
67 						  guint key_mode);
68 void ags_fx_notation_audio_processor_real_key_pressure(AgsFxNotationAudioProcessor *fx_notation_audio_processor,
69 						       AgsNote *note,
70 						       guint velocity,
71 						       guint key_mode);
72 
73 void ags_fx_notation_audio_processor_real_play(AgsFxNotationAudioProcessor *fx_notation_audio_processor);
74 void ags_fx_notation_audio_processor_real_record(AgsFxNotationAudioProcessor *fx_notation_audio_processor);
75 void ags_fx_notation_audio_processor_real_feed(AgsFxNotationAudioProcessor *fx_notation_audio_processor);
76 
77 void ags_fx_notation_audio_processor_real_counter_change(AgsFxNotationAudioProcessor *fx_notation_audio_processor);
78 
79 /**
80  * SECTION:ags_fx_notation_audio_processor
81  * @short_description: fx notation audio processor
82  * @title: AgsFxNotationAudioProcessor
83  * @section_id:
84  * @include: ags/audio/fx/ags_fx_notation_audio_processor.h
85  *
86  * The #AgsFxNotationAudioProcessor class provides ports to the effect processor.
87  */
88 
89 static gpointer ags_fx_notation_audio_processor_parent_class = NULL;
90 
91 GType
ags_fx_notation_audio_processor_get_type()92 ags_fx_notation_audio_processor_get_type()
93 {
94   static volatile gsize g_define_type_id__volatile = 0;
95 
96   if(g_once_init_enter (&g_define_type_id__volatile)){
97     GType ags_type_fx_notation_audio_processor = 0;
98 
99     static const GTypeInfo ags_fx_notation_audio_processor_info = {
100       sizeof (AgsFxNotationAudioProcessorClass),
101       NULL, /* base_init */
102       NULL, /* base_finalize */
103       (GClassInitFunc) ags_fx_notation_audio_processor_class_init,
104       NULL, /* class_finalize */
105       NULL, /* class_audio_processor */
106       sizeof (AgsFxNotationAudioProcessor),
107       0,    /* n_preallocs */
108       (GInstanceInitFunc) ags_fx_notation_audio_processor_init,
109     };
110 
111     static const GInterfaceInfo ags_seekable_interface_info = {
112       (GInterfaceInitFunc) ags_fx_notation_audio_processor_seekable_interface_init,
113       NULL, /* interface_finalize */
114       NULL, /* interface_data */
115     };
116 
117     static const GInterfaceInfo ags_countable_interface_info = {
118       (GInterfaceInitFunc) ags_fx_notation_audio_processor_countable_interface_init,
119       NULL, /* interface_finalize */
120       NULL, /* interface_data */
121     };
122 
123     static const GInterfaceInfo ags_tactable_interface_info = {
124       (GInterfaceInitFunc) ags_fx_notation_audio_processor_tactable_interface_init,
125       NULL, /* interface_finalize */
126       NULL, /* interface_data */
127     };
128 
129     ags_type_fx_notation_audio_processor = g_type_register_static(AGS_TYPE_RECALL_AUDIO_RUN,
130 								  "AgsFxNotationAudioProcessor",
131 								  &ags_fx_notation_audio_processor_info,
132 								  0);
133 
134     g_type_add_interface_static(ags_type_fx_notation_audio_processor,
135 				AGS_TYPE_COUNTABLE,
136 				&ags_countable_interface_info);
137 
138     g_type_add_interface_static(ags_type_fx_notation_audio_processor,
139 				AGS_TYPE_SEEKABLE,
140 				&ags_seekable_interface_info);
141 
142     g_type_add_interface_static(ags_type_fx_notation_audio_processor,
143 				AGS_TYPE_TACTABLE,
144 				&ags_tactable_interface_info);
145 
146     g_once_init_leave(&g_define_type_id__volatile, ags_type_fx_notation_audio_processor);
147   }
148 
149   return g_define_type_id__volatile;
150 }
151 
152 void
ags_fx_notation_audio_processor_class_init(AgsFxNotationAudioProcessorClass * fx_notation_audio_processor)153 ags_fx_notation_audio_processor_class_init(AgsFxNotationAudioProcessorClass *fx_notation_audio_processor)
154 {
155   GObjectClass *gobject;
156   AgsRecallClass *recall;
157 
158   ags_fx_notation_audio_processor_parent_class = g_type_class_peek_parent(fx_notation_audio_processor);
159 
160   /* GObjectClass */
161   gobject = (GObjectClass *) fx_notation_audio_processor;
162 
163   gobject->dispose = ags_fx_notation_audio_processor_dispose;
164   gobject->finalize = ags_fx_notation_audio_processor_finalize;
165 
166   /* AgsRecallClass */
167   recall = (AgsRecallClass *) fx_notation_audio_processor;
168 
169   recall->run_init_pre = ags_fx_notation_audio_processor_run_init_pre;
170   recall->run_inter = ags_fx_notation_audio_processor_run_inter;
171 
172   /* AgsFxNotationAudioProcessorClass */
173   fx_notation_audio_processor->key_on = ags_fx_notation_audio_processor_real_key_on;
174   fx_notation_audio_processor->key_off = ags_fx_notation_audio_processor_real_key_off;
175   fx_notation_audio_processor->key_pressure = ags_fx_notation_audio_processor_real_key_pressure;
176 
177   fx_notation_audio_processor->play = ags_fx_notation_audio_processor_real_play;
178   fx_notation_audio_processor->record = ags_fx_notation_audio_processor_real_record;
179   fx_notation_audio_processor->feed = ags_fx_notation_audio_processor_real_feed;
180 
181   fx_notation_audio_processor->counter_change = ags_fx_notation_audio_processor_real_counter_change;
182 }
183 
184 void
ags_fx_notation_audio_processor_seekable_interface_init(AgsSeekableInterface * seekable)185 ags_fx_notation_audio_processor_seekable_interface_init(AgsSeekableInterface *seekable)
186 {
187   seekable->seek = ags_fx_notation_audio_processor_seek;
188 }
189 
190 void
ags_fx_notation_audio_processor_countable_interface_init(AgsCountableInterface * countable)191 ags_fx_notation_audio_processor_countable_interface_init(AgsCountableInterface *countable)
192 {
193   countable->get_sequencer_counter = NULL;
194   countable->get_notation_counter = ags_fx_notation_audio_processor_get_notation_counter;
195   countable->get_wave_counter = NULL;
196   countable->get_midi_counter = NULL;
197 }
198 
199 void
ags_fx_notation_audio_processor_tactable_interface_init(AgsTactableInterface * tactable)200 ags_fx_notation_audio_processor_tactable_interface_init(AgsTactableInterface *tactable)
201 {
202   tactable->get_bpm = ags_fx_notation_audio_processor_get_bpm;
203   tactable->get_tact = ags_fx_notation_audio_processor_get_tact;
204 
205   tactable->get_sequencer_duration = NULL;
206   tactable->get_notation_duration = NULL;
207   tactable->get_wave_duration = NULL;
208   tactable->get_midi_duration = NULL;
209 
210   tactable->change_sequencer_duration = NULL;
211   tactable->change_notation_duration = NULL;
212   tactable->change_wave_duration = NULL;
213   tactable->change_midi_duration = NULL;
214 
215   tactable->change_bpm = ags_fx_notation_audio_processor_change_bpm;
216   tactable->change_tact = ags_fx_notation_audio_processor_change_tact;
217 }
218 
219 void
ags_fx_notation_audio_processor_init(AgsFxNotationAudioProcessor * fx_notation_audio_processor)220 ags_fx_notation_audio_processor_init(AgsFxNotationAudioProcessor *fx_notation_audio_processor)
221 {
222   AGS_RECALL(fx_notation_audio_processor)->name = "ags-fx-notation";
223   AGS_RECALL(fx_notation_audio_processor)->version = AGS_RECALL_DEFAULT_VERSION;
224   AGS_RECALL(fx_notation_audio_processor)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
225   AGS_RECALL(fx_notation_audio_processor)->xml_type = "ags-fx-notation-audio-processor";
226 
227   /* counter */
228   fx_notation_audio_processor->delay_completion = 0.0;
229 
230   fx_notation_audio_processor->delay_counter = 0.0;
231   fx_notation_audio_processor->offset_counter = 0;
232 
233   fx_notation_audio_processor->current_delay_counter = 0.0;
234   fx_notation_audio_processor->current_offset_counter = 0;
235 
236   /* timestamp */
237   fx_notation_audio_processor->timestamp = ags_timestamp_new();
238   g_object_ref(fx_notation_audio_processor->timestamp);
239 
240   fx_notation_audio_processor->timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
241   fx_notation_audio_processor->timestamp->flags |= AGS_TIMESTAMP_OFFSET;
242 
243   fx_notation_audio_processor->timestamp->timer.ags_offset.offset = 0;
244 
245   /* recording */
246   fx_notation_audio_processor->recording_note = NULL;
247   fx_notation_audio_processor->recording_audio_signal = NULL;
248 
249   /* feeding */
250   fx_notation_audio_processor->feeding_note = NULL;
251   fx_notation_audio_processor->feeding_audio_signal = NULL;
252 }
253 
254 void
ags_fx_notation_audio_processor_dispose(GObject * gobject)255 ags_fx_notation_audio_processor_dispose(GObject *gobject)
256 {
257   AgsFxNotationAudioProcessor *fx_notation_audio_processor;
258 
259   fx_notation_audio_processor = AGS_FX_NOTATION_AUDIO_PROCESSOR(gobject);
260 
261   /* call parent */
262   G_OBJECT_CLASS(ags_fx_notation_audio_processor_parent_class)->dispose(gobject);
263 }
264 
265 void
ags_fx_notation_audio_processor_finalize(GObject * gobject)266 ags_fx_notation_audio_processor_finalize(GObject *gobject)
267 {
268   AgsFxNotationAudioProcessor *fx_notation_audio_processor;
269 
270   fx_notation_audio_processor = AGS_FX_NOTATION_AUDIO_PROCESSOR(gobject);
271 
272   /* timestamp */
273   if(fx_notation_audio_processor->timestamp != NULL){
274     g_object_unref((GObject *) fx_notation_audio_processor->timestamp);
275   }
276 
277   /* recording - note */
278   if(fx_notation_audio_processor->recording_note != NULL){
279     g_list_free_full(fx_notation_audio_processor->recording_note,
280 		     (GDestroyNotify) g_object_unref);
281   }
282 
283   /* recording - audio signal */
284   if(fx_notation_audio_processor->recording_audio_signal != NULL){
285     g_list_free_full(fx_notation_audio_processor->recording_audio_signal,
286 		     (GDestroyNotify) g_object_unref);
287   }
288 
289   /* feeding - note */
290   if(fx_notation_audio_processor->feeding_note != NULL){
291     g_list_free_full(fx_notation_audio_processor->feeding_note,
292 		     (GDestroyNotify) g_object_unref);
293   }
294 
295   /* feeding - audio signal */
296   if(fx_notation_audio_processor->feeding_audio_signal != NULL){
297     g_list_free_full(fx_notation_audio_processor->feeding_audio_signal,
298 		     (GDestroyNotify) g_object_unref);
299   }
300 
301   /* call parent */
302   G_OBJECT_CLASS(ags_fx_notation_audio_processor_parent_class)->finalize(gobject);
303 }
304 
305 void
ags_fx_notation_audio_processor_seek(AgsSeekable * seekable,gint64 offset,guint whence)306 ags_fx_notation_audio_processor_seek(AgsSeekable *seekable,
307 				     gint64 offset,
308 				     guint whence)
309 {
310   AgsFxNotationAudio *fx_notation_audio;
311   AgsFxNotationAudioProcessor *fx_notation_audio_processor;
312   AgsPort *port;
313 
314   gdouble notation_duration;
315 
316   GRecMutex *recall_mutex;
317 
318   gdouble delay;
319   guint64 notation_counter;
320 
321   GValue value = {0,};
322 
323   fx_notation_audio = NULL;
324 
325   fx_notation_audio_processor = AGS_FX_NOTATION_AUDIO_PROCESSOR(seekable);
326 
327   /* get recall mutex */
328   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(fx_notation_audio_processor);
329 
330   g_object_get(fx_notation_audio_processor,
331 	       "recall-audio", &fx_notation_audio,
332 	       NULL);
333 
334   /* delay */
335   port = NULL;
336 
337   delay = AGS_SOUNDCARD_DEFAULT_DELAY;
338 
339   notation_duration = ceil(AGS_NOTATION_DEFAULT_DURATION * delay);
340 
341   g_object_get(fx_notation_audio,
342 	       "delay", &port,
343 	       NULL);
344 
345   if(port != NULL){
346     g_value_init(&value, G_TYPE_DOUBLE);
347 
348     ags_port_safe_read(port, &value);
349 
350     delay = g_value_get_double(&value);
351 
352     g_value_unset(&value);
353 
354     g_object_unref(port);
355   }
356 
357   /* duration */
358   port = NULL;
359 
360   g_object_get(fx_notation_audio,
361 	       "duration", &port,
362 	       NULL);
363 
364   if(port != NULL){
365     g_value_init(&value, G_TYPE_UINT64);
366 
367     ags_port_safe_read(port, &value);
368 
369     notation_duration = g_value_get_uint64(&value);
370 
371     g_value_unset(&value);
372 
373     g_object_unref(port);
374   }
375 
376   switch(whence){
377   case AGS_SEEK_CUR:
378     {
379       g_rec_mutex_lock(recall_mutex);
380 
381       notation_counter = fx_notation_audio_processor->offset_counter;
382 
383       if(notation_counter + offset < 0){
384 	notation_counter = (guint64) notation_duration - (guint64) ((offset - notation_counter) % (guint64) notation_duration);
385       }else{
386 	notation_counter = (guint64) (notation_counter + offset) % (guint64) notation_duration;
387       }
388 
389       fx_notation_audio_processor->delay_counter =
390 	fx_notation_audio_processor->current_delay_counter = 0.0;
391 
392       fx_notation_audio_processor->offset_counter =
393 	fx_notation_audio_processor->current_offset_counter = notation_counter;
394 
395       g_rec_mutex_unlock(recall_mutex);
396     }
397     break;
398   case AGS_SEEK_END:
399     {
400       g_rec_mutex_lock(recall_mutex);
401 
402       notation_counter = fx_notation_audio_processor->offset_counter;
403 
404       /* notation */
405       if(notation_duration + offset < 0){
406 	notation_counter = (guint64) notation_duration - ((guint64) (offset - notation_duration) % (guint64) notation_duration);
407       }else{
408 	notation_counter = (guint64) (notation_duration + offset) % (guint64) notation_duration;
409       }
410 
411       fx_notation_audio_processor->delay_counter =
412 	fx_notation_audio_processor->current_delay_counter = 0.0;
413 
414       fx_notation_audio_processor->offset_counter =
415 	fx_notation_audio_processor->current_offset_counter = notation_counter;
416 
417       g_rec_mutex_unlock(recall_mutex);
418     }
419     break;
420   case AGS_SEEK_SET:
421     {
422       g_rec_mutex_lock(recall_mutex);
423 
424       fx_notation_audio_processor->delay_counter =
425 	fx_notation_audio_processor->current_delay_counter = 0.0;
426 
427       fx_notation_audio_processor->offset_counter =
428 	fx_notation_audio_processor->current_offset_counter = offset;
429 
430       g_rec_mutex_unlock(recall_mutex);
431     }
432     break;
433   }
434 
435   if(fx_notation_audio != NULL){
436     g_object_unref(fx_notation_audio);
437   }
438 }
439 
440 guint64
ags_fx_notation_audio_processor_get_notation_counter(AgsCountable * countable)441 ags_fx_notation_audio_processor_get_notation_counter(AgsCountable *countable)
442 {
443   AgsFxNotationAudioProcessor *fx_notation_audio_processor;
444 
445   guint64 notation_counter;
446 
447   GRecMutex *recall_mutex;
448 
449   fx_notation_audio_processor = AGS_FX_NOTATION_AUDIO_PROCESSOR(countable);
450 
451   /* get recall mutex */
452   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(fx_notation_audio_processor);
453 
454   /* bpm */
455   g_rec_mutex_lock(recall_mutex);
456 
457   notation_counter = fx_notation_audio_processor->offset_counter;
458 
459   g_rec_mutex_unlock(recall_mutex);
460 
461   return(notation_counter);
462 }
463 
464 gdouble
ags_fx_notation_audio_processor_get_bpm(AgsTactable * tactable)465 ags_fx_notation_audio_processor_get_bpm(AgsTactable *tactable)
466 {
467   AgsFxNotationAudio *fx_notation_audio;
468   AgsFxNotationAudioProcessor *fx_notation_audio_processor;
469   AgsPort *port;
470 
471   gdouble bpm;
472 
473   GValue value = {0,};
474 
475   fx_notation_audio  = NULL;
476 
477   fx_notation_audio_processor = AGS_FX_NOTATION_AUDIO_PROCESSOR(tactable);
478 
479   port = NULL;
480 
481   bpm = AGS_SOUNDCARD_DEFAULT_BPM;
482 
483   g_object_get(fx_notation_audio_processor,
484 	       "recall-audio", &fx_notation_audio,
485 	       NULL);
486 
487   if(fx_notation_audio != NULL){
488     g_object_get(fx_notation_audio,
489 		 "bpm", &port,
490 		 NULL);
491 
492     if(port != NULL){
493       g_value_init(&value, G_TYPE_DOUBLE);
494 
495       ags_port_safe_read(port, &value);
496 
497       bpm = g_value_get_double(&value);
498 
499       g_value_unset(&value);
500 
501       g_object_unref(port);
502     }
503   }
504 
505   if(fx_notation_audio != NULL){
506     g_object_unref(fx_notation_audio);
507   }
508 
509   return(bpm);
510 }
511 
512 gdouble
ags_fx_notation_audio_processor_get_tact(AgsTactable * tactable)513 ags_fx_notation_audio_processor_get_tact(AgsTactable *tactable)
514 {
515   AgsFxNotationAudio *fx_notation_audio;
516   AgsFxNotationAudioProcessor *fx_notation_audio_processor;
517   AgsPort *port;
518 
519   gdouble tact;
520 
521   GValue value = {0,};
522 
523   fx_notation_audio  = NULL;
524 
525   fx_notation_audio_processor = AGS_FX_NOTATION_AUDIO_PROCESSOR(tactable);
526 
527   port = NULL;
528 
529   tact = AGS_SOUNDCARD_DEFAULT_TACT;
530 
531   g_object_get(fx_notation_audio_processor,
532 	       "recall-audio", &fx_notation_audio,
533 	       NULL);
534 
535   if(fx_notation_audio != NULL){
536     g_object_get(fx_notation_audio,
537 		 "tact", &port,
538 		 NULL);
539 
540     if(port != NULL){
541       g_value_init(&value, G_TYPE_DOUBLE);
542 
543       ags_port_safe_read(port, &value);
544 
545       tact = g_value_get_double(&value);
546 
547       g_value_unset(&value);
548 
549       g_object_unref(port);
550     }
551   }
552 
553   if(fx_notation_audio != NULL){
554     g_object_unref(fx_notation_audio);
555   }
556 
557   return(tact);
558 }
559 
560 void
ags_fx_notation_audio_processor_change_bpm(AgsTactable * tactable,gdouble new_bpm,gdouble old_bpm)561 ags_fx_notation_audio_processor_change_bpm(AgsTactable *tactable, gdouble new_bpm, gdouble old_bpm)
562 {
563   AgsFxNotationAudio *fx_notation_audio;
564   AgsFxNotationAudioProcessor *fx_notation_audio_processor;
565   AgsPort *port;
566 
567   GObject *output_soundcard;
568 
569   GValue value = {0,};
570 
571   output_soundcard = NULL;
572 
573   fx_notation_audio  = NULL;
574 
575   fx_notation_audio_processor = AGS_FX_NOTATION_AUDIO_PROCESSOR(tactable);
576 
577   port = NULL;
578 
579   g_object_get(fx_notation_audio_processor,
580 	       "output-soundcard", &output_soundcard,
581 	       "recall-audio", &fx_notation_audio,
582 	       NULL);
583 
584   /* delay */
585   if(fx_notation_audio != NULL){
586     port = NULL;
587 
588     g_object_get(fx_notation_audio,
589 		 "delay", &port,
590 		 NULL);
591 
592     if(port != NULL){
593       g_value_init(&value, G_TYPE_DOUBLE);
594 
595       g_value_set_double(&value, ags_soundcard_get_absolute_delay(AGS_SOUNDCARD(output_soundcard)));
596 
597       ags_port_safe_write(port, &value);
598 
599       g_value_unset(&value);
600 
601       g_object_unref(port);
602     }
603   }
604 
605   /* bpm */
606   if(fx_notation_audio != NULL){
607     port = NULL;
608 
609     g_object_get(fx_notation_audio,
610 		 "bpm", &port,
611 		 NULL);
612 
613     if(port != NULL){
614       g_value_init(&value, G_TYPE_DOUBLE);
615 
616       g_value_set_double(&value, new_bpm);
617 
618       ags_port_safe_write(port, &value);
619 
620       g_value_unset(&value);
621 
622       g_object_unref(port);
623     }
624   }
625 
626   if(fx_notation_audio != NULL){
627     g_object_unref(fx_notation_audio);
628   }
629 }
630 
631 void
ags_fx_notation_audio_processor_change_tact(AgsTactable * tactable,gdouble new_tact,gdouble old_tact)632 ags_fx_notation_audio_processor_change_tact(AgsTactable *tactable, gdouble new_tact, gdouble old_tact)
633 {
634   AgsFxNotationAudio *fx_notation_audio;
635   AgsFxNotationAudioProcessor *fx_notation_audio_processor;
636   AgsPort *port;
637 
638   GObject *output_soundcard;
639 
640   GValue value = {0,};
641 
642   output_soundcard = NULL;
643 
644   fx_notation_audio  = NULL;
645 
646   fx_notation_audio_processor = AGS_FX_NOTATION_AUDIO_PROCESSOR(tactable);
647 
648   port = NULL;
649 
650   g_object_get(fx_notation_audio_processor,
651 	       "output-soundcard", &output_soundcard,
652 	       "recall-audio", &fx_notation_audio,
653 	       NULL);
654   /* delay */
655   if(fx_notation_audio != NULL){
656     port = NULL;
657 
658     g_object_get(fx_notation_audio,
659 		 "delay", &port,
660 		 NULL);
661 
662     if(port != NULL){
663       g_value_init(&value, G_TYPE_DOUBLE);
664 
665       g_value_set_double(&value, ags_soundcard_get_absolute_delay(AGS_SOUNDCARD(output_soundcard)));
666 
667       ags_port_safe_write(port, &value);
668 
669       g_value_unset(&value);
670 
671       g_object_unref(port);
672     }
673   }
674 
675   /* tact */
676   if(fx_notation_audio != NULL){
677     port = NULL;
678 
679     g_object_get(fx_notation_audio,
680 		 "tact", &port,
681 		 NULL);
682 
683     if(port != NULL){
684       g_value_init(&value, G_TYPE_DOUBLE);
685 
686       g_value_set_double(&value, new_tact);
687 
688       ags_port_safe_write(port, &value);
689 
690       g_value_unset(&value);
691 
692       g_object_unref(port);
693     }
694   }
695 
696   if(fx_notation_audio != NULL){
697     g_object_unref(fx_notation_audio);
698   }
699 }
700 
701 void
ags_fx_notation_audio_processor_run_init_pre(AgsRecall * recall)702 ags_fx_notation_audio_processor_run_init_pre(AgsRecall *recall)
703 {
704   AgsFxNotationAudioProcessor *fx_notation_audio_processor;
705 
706   gdouble delay_counter;
707 
708   GRecMutex *fx_notation_audio_processor_mutex;
709 
710   fx_notation_audio_processor = AGS_FX_NOTATION_AUDIO_PROCESSOR(recall);
711 
712   fx_notation_audio_processor_mutex = AGS_RECALL_GET_OBJ_MUTEX(fx_notation_audio_processor);
713 
714   /* get delay counter */
715   g_rec_mutex_lock(fx_notation_audio_processor_mutex);
716 
717   fx_notation_audio_processor->delay_counter = 0;
718   fx_notation_audio_processor->offset_counter = 0;
719 
720   fx_notation_audio_processor->current_delay_counter = 0;
721   fx_notation_audio_processor->current_offset_counter = 0;
722 
723   g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
724 
725   /* call parent */
726   AGS_RECALL_CLASS(ags_fx_notation_audio_processor_parent_class)->run_init_pre(recall);
727 }
728 
729 void
ags_fx_notation_audio_processor_run_inter(AgsRecall * recall)730 ags_fx_notation_audio_processor_run_inter(AgsRecall *recall)
731 {
732   AgsFxNotationAudioProcessor *fx_notation_audio_processor;
733   AgsRecallID *recall_id;
734   AgsRecyclingContext *parent_recycling_context, *recycling_context;
735 
736   gint sound_scope;
737   gdouble delay_counter;
738 
739   GRecMutex *fx_notation_audio_processor_mutex;
740 
741   fx_notation_audio_processor = AGS_FX_NOTATION_AUDIO_PROCESSOR(recall);
742 
743   fx_notation_audio_processor_mutex = AGS_RECALL_GET_OBJ_MUTEX(fx_notation_audio_processor);
744 
745   recall_id = NULL;
746 
747   sound_scope = ags_recall_get_sound_scope(recall);
748 
749   g_object_get(recall,
750 	       "recall-id", &recall_id,
751 	       NULL);
752 
753   if(!ags_recall_id_check_sound_scope(recall_id, sound_scope)){
754     if(recall_id != NULL){
755       g_object_unref(recall_id);
756     }
757 
758     AGS_RECALL_CLASS(ags_fx_notation_audio_processor_parent_class)->run_inter(recall);
759 
760     return;
761   }
762 
763   recycling_context = NULL;
764   parent_recycling_context = NULL;
765 
766   g_object_get(recall_id,
767 	       "recycling-context", &recycling_context,
768 	       NULL);
769 
770   g_object_get(recycling_context,
771 	       "parent", &parent_recycling_context,
772 	       NULL);
773 
774   /* get delay counter */
775   g_rec_mutex_lock(fx_notation_audio_processor_mutex);
776 
777   fx_notation_audio_processor->delay_counter = fx_notation_audio_processor->current_delay_counter;
778   fx_notation_audio_processor->offset_counter = fx_notation_audio_processor->current_offset_counter;
779 
780   delay_counter = fx_notation_audio_processor->delay_counter;
781 
782   g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
783 
784   /* run */
785   if(ags_recall_id_check_sound_scope(recall_id, AGS_SOUND_SCOPE_NOTATION)){
786     if(parent_recycling_context == NULL &&
787        delay_counter == 0.0){
788       ags_fx_notation_audio_processor_play(fx_notation_audio_processor);
789     }
790   }
791 
792   if(ags_recall_id_check_sound_scope(recall_id, AGS_SOUND_SCOPE_NOTATION)){
793     if(parent_recycling_context == NULL){
794       ags_fx_notation_audio_processor_record(fx_notation_audio_processor);
795     }
796   }
797 
798   if(ags_recall_id_check_sound_scope(recall_id, AGS_SOUND_SCOPE_PLAYBACK)){
799     if(parent_recycling_context == NULL){
800       ags_fx_notation_audio_processor_feed(fx_notation_audio_processor);
801     }
802   }
803 
804   /* counter change */
805   ags_fx_notation_audio_processor_counter_change(fx_notation_audio_processor);
806 
807   if(recall_id != NULL){
808     g_object_unref(recall_id);
809   }
810 
811   if(recycling_context != NULL){
812     g_object_unref(recycling_context);
813   }
814 
815   if(parent_recycling_context != NULL){
816     g_object_unref(parent_recycling_context);
817   }
818 
819   /* call parent */
820   AGS_RECALL_CLASS(ags_fx_notation_audio_processor_parent_class)->run_inter(recall);
821 }
822 
823 void
ags_fx_notation_audio_processor_real_key_on(AgsFxNotationAudioProcessor * fx_notation_audio_processor,AgsNote * note,guint velocity,guint key_mode)824 ags_fx_notation_audio_processor_real_key_on(AgsFxNotationAudioProcessor *fx_notation_audio_processor,
825 					    AgsNote *note,
826 					    guint velocity,
827 					    guint key_mode)
828 {
829   AgsAudio *audio;
830   AgsChannel *start_input;
831   AgsChannel *input, *selected_input;
832   AgsRecallID *recall_id;
833   AgsRecyclingContext *recycling_context;
834   AgsFxNotationAudio *fx_notation_audio;
835   AgsPort *port;
836 
837   gdouble delay;
838   guint64 offset_counter;
839   guint input_pads;
840   guint audio_channel;
841   guint y;
842 
843   GValue value = {0,};
844 
845   GRecMutex *fx_notation_audio_processor_mutex;
846 
847   fx_notation_audio_processor_mutex = AGS_RECALL_GET_OBJ_MUTEX(fx_notation_audio_processor);
848 
849   audio = NULL;
850 
851   start_input = NULL;
852 
853   recall_id = NULL;
854 
855   fx_notation_audio = NULL;
856 
857   g_object_get(fx_notation_audio_processor,
858 	       "audio", &audio,
859 	       "recall-id", &recall_id,
860 	       "recall-audio", &fx_notation_audio,
861 	       "audio-channel", &audio_channel,
862 	       NULL);
863 
864   g_object_get(audio,
865 	       "input", &start_input,
866 	       NULL);
867 
868   recycling_context = NULL;
869 
870   g_object_get(recall_id,
871 	       "recycling-context", &recycling_context,
872 	       NULL);
873 
874   g_rec_mutex_lock(fx_notation_audio_processor_mutex);
875 
876   offset_counter = fx_notation_audio_processor->offset_counter;
877 
878   g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
879 
880   /* get delay */
881   delay = AGS_SOUNDCARD_DEFAULT_DELAY;
882 
883   if(fx_notation_audio != NULL){
884     port = NULL;
885 
886     g_object_get(fx_notation_audio,
887 		 "delay", &port,
888 		 NULL);
889 
890     if(port != NULL){
891       g_value_init(&value,
892 		   G_TYPE_DOUBLE);
893 
894       ags_port_safe_read(port,
895 			 &value);
896 
897       delay = g_value_get_double(&value);
898       g_value_unset(&value);
899 
900       g_object_unref(port);
901     }
902   }
903 
904   input_pads = 0;
905 
906   g_object_get(audio,
907 	       "input-pads", &input_pads,
908 	       NULL);
909 
910   y = 0;
911 
912   g_object_get(note,
913 	       "y", &y,
914 	       NULL);
915 
916   input = ags_channel_nth(start_input,
917 			  audio_channel);
918 
919   if(ags_audio_test_behaviour_flags(audio, AGS_SOUND_BEHAVIOUR_REVERSE_MAPPING)){
920     selected_input = ags_channel_pad_nth(input,
921 					 input_pads - y - 1);
922   }else{
923     selected_input = ags_channel_pad_nth(input,
924 					 y);
925   }
926 
927   if(selected_input != NULL){
928     AgsRecycling *first_recycling, *last_recycling;
929     AgsRecycling *recycling, *next_recycling;
930     AgsRecycling *end_recycling;
931     AgsRecallID *child_recall_id;
932 
933     GObject *output_soundcard;
934 
935     GList *start_list, *list;
936 
937     guint attack;
938 
939     output_soundcard = NULL;
940 
941     first_recycling = NULL;
942     last_recycling = NULL;
943 
944     g_object_get(selected_input,
945 		 "output-soundcard", &output_soundcard,
946 		 "first-recycling", &first_recycling,
947 		 "last-recycling", &last_recycling,
948 		 NULL);
949 
950     attack = 0;
951 
952     if(output_soundcard != NULL){
953       attack = ags_soundcard_get_attack(AGS_SOUNDCARD(output_soundcard));
954     }
955 
956     end_recycling = ags_recycling_next(last_recycling);
957 
958     /* get child recall id */
959     start_list = NULL;
960 
961     g_object_get(selected_input,
962 		 "recall-id", &start_list,
963 		 NULL);
964 
965     list = start_list;
966     child_recall_id = NULL;
967 
968     while(child_recall_id == NULL &&
969 	  list != NULL){
970       AgsRecyclingContext *current_recycling_context, *current_parent_recycling_context;
971 
972       g_object_get(list->data,
973 		   "recycling-context", &current_recycling_context,
974 		   NULL);
975 
976       g_object_get(current_recycling_context,
977 		   "parent", &current_parent_recycling_context,
978 		   NULL);
979 
980       if(current_parent_recycling_context == recycling_context){
981 	child_recall_id = (AgsRecallID *) list->data;
982 	g_object_ref(child_recall_id);
983       }
984 
985       if(current_recycling_context != NULL){
986 	g_object_unref(current_recycling_context);
987       }
988 
989       if(current_parent_recycling_context != NULL){
990 	g_object_unref(current_parent_recycling_context);
991       }
992 
993       /* iterate */
994       list = list->next;
995     }
996 
997     recycling = first_recycling;
998     g_object_ref(recycling);
999 
1000 //    g_message(" - audio processor");
1001 
1002     while(recycling != end_recycling){
1003       AgsAudioSignal *template, *audio_signal;
1004 
1005       GRecMutex *recycling_mutex;
1006 
1007       recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1008 
1009       g_rec_mutex_lock(recycling_mutex);
1010 
1011       template = ags_audio_signal_get_template(recycling->audio_signal);
1012 
1013       g_rec_mutex_unlock(recycling_mutex);
1014 
1015       /* create audio signal */
1016       audio_signal = ags_audio_signal_new((GObject *) output_soundcard,
1017 					  (GObject *) recycling,
1018 					  (GObject *) child_recall_id);
1019       ags_audio_signal_set_flags(audio_signal, (AGS_AUDIO_SIGNAL_STREAM |
1020 						AGS_AUDIO_SIGNAL_SLICE_ALLOC));
1021       g_object_set(audio_signal,
1022 		   "template", template,
1023 		   "note", note,
1024 		   "attack", attack,
1025 		   NULL);
1026 
1027       ags_audio_signal_stream_resize(audio_signal,
1028 				     2);
1029 
1030       audio_signal->stream_current = audio_signal->stream;
1031 
1032       ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
1033       ags_recycling_add_audio_signal(recycling,
1034 				     audio_signal);
1035 
1036 //      g_message(" `- added");
1037 
1038       if(key_mode == AGS_FX_NOTATION_AUDIO_PROCESSOR_KEY_MODE_RECORD){
1039 #if 0
1040 	g_object_ref(audio_signal);
1041 
1042 	g_rec_mutex_lock(fx_notation_audio_processor_mutex);
1043 
1044 	fx_notation_audio_processor->recording_audio_signal = g_list_prepend(fx_notation_audio_processor->recording_audio_signal,
1045 									     audio_signal);
1046 
1047 	g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
1048 #endif
1049       }else if(key_mode == AGS_FX_NOTATION_AUDIO_PROCESSOR_KEY_MODE_FEED){
1050 	g_object_ref(audio_signal);
1051 
1052 	g_rec_mutex_lock(fx_notation_audio_processor_mutex);
1053 
1054 	fx_notation_audio_processor->feeding_audio_signal = g_list_prepend(fx_notation_audio_processor->feeding_audio_signal,
1055 									   audio_signal);
1056 
1057 	g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
1058       }
1059 
1060       /* iterate */
1061       next_recycling = ags_recycling_next(recycling);
1062 
1063       g_object_unref(recycling);
1064 
1065       recycling = next_recycling;
1066     }
1067 
1068     if(output_soundcard != NULL){
1069       g_object_unref(output_soundcard);
1070     }
1071 
1072     if(first_recycling != NULL){
1073       g_object_unref(first_recycling);
1074     }
1075 
1076     if(last_recycling != NULL){
1077       g_object_unref(last_recycling);
1078     }
1079 
1080     if(recycling != NULL){
1081       g_object_unref(recycling);
1082     }
1083 
1084     if(end_recycling != NULL){
1085       g_object_unref(end_recycling);
1086     }
1087 
1088     g_list_free_full(start_list,
1089 		     g_object_unref);
1090 
1091     if(child_recall_id != NULL){
1092       g_object_unref(child_recall_id);
1093     }
1094   }
1095 
1096   if(audio != NULL){
1097     g_object_unref(audio);
1098   }
1099 
1100   if(start_input != NULL){
1101     g_object_unref(start_input);
1102   }
1103 
1104   if(input != NULL){
1105     g_object_unref(input);
1106   }
1107 
1108   if(selected_input != NULL){
1109     g_object_unref(selected_input);
1110   }
1111 
1112   if(recall_id != NULL){
1113     g_object_unref(recall_id);
1114   }
1115 
1116   if(fx_notation_audio != NULL){
1117     g_object_unref(fx_notation_audio);
1118   }
1119 }
1120 
1121 void
ags_fx_notation_audio_processor_key_on(AgsFxNotationAudioProcessor * fx_notation_audio_processor,AgsNote * note,guint velocity,guint key_mode)1122 ags_fx_notation_audio_processor_key_on(AgsFxNotationAudioProcessor *fx_notation_audio_processor,
1123 				       AgsNote *note,
1124 				       guint velocity,
1125 				       guint key_mode)
1126 {
1127   g_return_if_fail(AGS_IS_FX_NOTATION_AUDIO_PROCESSOR(fx_notation_audio_processor));
1128 
1129   g_object_ref(fx_notation_audio_processor);
1130 
1131   if(AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->key_on != NULL){
1132     AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->key_on(fx_notation_audio_processor,
1133 										   note,
1134 										   velocity,
1135 										   key_mode);
1136   }
1137 
1138   g_object_unref(fx_notation_audio_processor);
1139 }
1140 
1141 void
ags_fx_notation_audio_processor_real_key_off(AgsFxNotationAudioProcessor * fx_notation_audio_processor,AgsNote * note,guint velocity,guint key_mode)1142 ags_fx_notation_audio_processor_real_key_off(AgsFxNotationAudioProcessor *fx_notation_audio_processor,
1143 					     AgsNote *note,
1144 					     guint velocity,
1145 					     guint key_mode)
1146 {
1147   //TODO:JK: implement me
1148 }
1149 
1150 void
ags_fx_notation_audio_processor_key_off(AgsFxNotationAudioProcessor * fx_notation_audio_processor,AgsNote * note,guint velocity,guint key_mode)1151 ags_fx_notation_audio_processor_key_off(AgsFxNotationAudioProcessor *fx_notation_audio_processor,
1152 					AgsNote *note,
1153 					guint velocity,
1154 					guint key_mode)
1155 {
1156   g_return_if_fail(AGS_IS_FX_NOTATION_AUDIO_PROCESSOR(fx_notation_audio_processor));
1157 
1158   g_object_ref(fx_notation_audio_processor);
1159 
1160   if(AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->key_off != NULL){
1161     AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->key_off(fx_notation_audio_processor,
1162 										    note,
1163 										    velocity,
1164 										    key_mode);
1165   }
1166 
1167   g_object_unref(fx_notation_audio_processor);
1168 }
1169 
1170 void
ags_fx_notation_audio_processor_real_key_pressure(AgsFxNotationAudioProcessor * fx_notation_audio_processor,AgsNote * note,guint velocity,guint key_mode)1171 ags_fx_notation_audio_processor_real_key_pressure(AgsFxNotationAudioProcessor *fx_notation_audio_processor,
1172 						  AgsNote *note,
1173 						  guint velocity,
1174 						  guint key_mode)
1175 {
1176   //TODO:JK: implement me
1177 }
1178 
1179 void
ags_fx_notation_audio_processor_key_pressure(AgsFxNotationAudioProcessor * fx_notation_audio_processor,AgsNote * note,guint velocity,guint key_mode)1180 ags_fx_notation_audio_processor_key_pressure(AgsFxNotationAudioProcessor *fx_notation_audio_processor,
1181 					     AgsNote *note,
1182 					     guint velocity,
1183 					     guint key_mode)
1184 {
1185   g_return_if_fail(AGS_IS_FX_NOTATION_AUDIO_PROCESSOR(fx_notation_audio_processor));
1186 
1187   g_object_ref(fx_notation_audio_processor);
1188 
1189   if(AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->key_pressure != NULL){
1190     AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->key_pressure(fx_notation_audio_processor,
1191 											 note,
1192 											 velocity,
1193 											 key_mode);
1194   }
1195 
1196   g_object_unref(fx_notation_audio_processor);
1197 }
1198 
1199 void
ags_fx_notation_audio_processor_real_play(AgsFxNotationAudioProcessor * fx_notation_audio_processor)1200 ags_fx_notation_audio_processor_real_play(AgsFxNotationAudioProcessor *fx_notation_audio_processor)
1201 {
1202   AgsAudio *audio;
1203 
1204   AgsTimestamp *timestamp;
1205 
1206   GList *start_notation, *notation;
1207 
1208   guint64 offset_counter;
1209   guint audio_channel;
1210 
1211   GRecMutex *fx_notation_audio_processor_mutex;
1212 
1213   fx_notation_audio_processor_mutex = AGS_RECALL_GET_OBJ_MUTEX(fx_notation_audio_processor);
1214 
1215   audio = NULL;
1216 
1217   g_object_get(fx_notation_audio_processor,
1218 	       "audio", &audio,
1219 	       "audio-channel", &audio_channel,
1220 	       NULL);
1221 
1222   if(audio == NULL){
1223     return;
1224   }
1225 
1226   g_object_get(audio,
1227 	       "notation", &start_notation,
1228 	       NULL);
1229 
1230   /* timestamp and offset counter */
1231   g_rec_mutex_lock(fx_notation_audio_processor_mutex);
1232 
1233   timestamp = fx_notation_audio_processor->timestamp;
1234 
1235   offset_counter = fx_notation_audio_processor->offset_counter;
1236 
1237   g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
1238 
1239   ags_timestamp_set_ags_offset(timestamp,
1240 			       AGS_NOTATION_DEFAULT_OFFSET * floor(offset_counter / AGS_NOTATION_DEFAULT_OFFSET));
1241 
1242   /* find near timestamp */
1243   notation = ags_notation_find_near_timestamp(start_notation, audio_channel,
1244 					      timestamp);
1245 
1246   if(notation != NULL){
1247     GList *start_note, *note;
1248 
1249     start_note = ags_notation_find_offset(notation->data,
1250 					  offset_counter,
1251 					  FALSE);
1252 
1253     note = start_note;
1254 
1255     while(note != NULL){
1256       ags_fx_notation_audio_processor_key_on(fx_notation_audio_processor,
1257 					     note->data,
1258 					     AGS_FX_NOTATION_AUDIO_PROCESSOR_DEFAULT_KEY_ON_VELOCITY,
1259 					     AGS_FX_NOTATION_AUDIO_PROCESSOR_KEY_MODE_PLAY);
1260 
1261       /* iterate */
1262       note = note->next;
1263     }
1264 
1265     g_list_free_full(start_note,
1266 		     (GDestroyNotify) g_object_unref);
1267   }
1268 
1269   if(audio != NULL){
1270     g_object_unref(audio);
1271   }
1272 
1273   g_list_free_full(start_notation,
1274 		   (GDestroyNotify) g_object_unref);
1275 }
1276 
1277 void
ags_fx_notation_audio_processor_play(AgsFxNotationAudioProcessor * fx_notation_audio_processor)1278 ags_fx_notation_audio_processor_play(AgsFxNotationAudioProcessor *fx_notation_audio_processor)
1279 {
1280   g_return_if_fail(AGS_IS_FX_NOTATION_AUDIO_PROCESSOR(fx_notation_audio_processor));
1281 
1282   g_object_ref(fx_notation_audio_processor);
1283 
1284   if(AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->play != NULL){
1285     AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->play(fx_notation_audio_processor);
1286   }
1287 
1288   g_object_unref(fx_notation_audio_processor);
1289 }
1290 
1291 void
ags_fx_notation_audio_processor_real_record(AgsFxNotationAudioProcessor * fx_notation_audio_processor)1292 ags_fx_notation_audio_processor_real_record(AgsFxNotationAudioProcessor *fx_notation_audio_processor)
1293 {
1294   AgsAudio *audio;
1295   AgsPort *port;
1296   AgsNotation *current_notation;
1297   AgsFxNotationAudio *fx_notation_audio;
1298 
1299   AgsTimestamp *timestamp;
1300 
1301   GObject *input_sequencer;
1302 
1303   GList *start_notation, *notation;
1304   GList *start_note, *note;
1305   GList *start_recording_note, *recording_note;
1306 
1307   guchar *midi_buffer;
1308 
1309   guint input_pads;
1310   guint audio_start_mapping;
1311   guint midi_start_mapping, midi_end_mapping;
1312   guint midi_channel;
1313   gdouble delay;
1314   guint64 offset_counter;
1315   guint audio_channel;
1316   guint buffer_length;
1317   gboolean reverse_mapping;
1318   gboolean pattern_mode;
1319 
1320   GValue value = {0,};
1321 
1322   GRecMutex *fx_notation_audio_processor_mutex;
1323 
1324   fx_notation_audio_processor_mutex = AGS_RECALL_GET_OBJ_MUTEX(fx_notation_audio_processor);
1325 
1326   audio = NULL;
1327 
1328   fx_notation_audio = NULL;
1329 
1330   audio_channel = 0;
1331 
1332   g_object_get(fx_notation_audio_processor,
1333 	       "audio", &audio,
1334 	       "recall-audio", &fx_notation_audio,
1335 	       "audio-channel", &audio_channel,
1336 	       NULL);
1337 
1338   if(audio == NULL){
1339     if(fx_notation_audio != NULL){
1340       g_object_unref(fx_notation_audio);
1341     }
1342 
1343     return;
1344   }
1345 
1346   input_sequencer = NULL;
1347 
1348   input_pads = 0;
1349 
1350   audio_start_mapping = 0;
1351 
1352   midi_start_mapping = 0;
1353   midi_end_mapping = 0;
1354 
1355   midi_channel = 0;
1356 
1357   g_object_get(audio,
1358 	       "input-sequencer", &input_sequencer,
1359 	       "input-pads", &input_pads,
1360 	       "audio-start-mapping", &audio_start_mapping,
1361 	       "midi-start-mapping", &midi_start_mapping,
1362 	       "midi-end-mapping", &midi_end_mapping,
1363 	       "midi-channel", &midi_channel,
1364 	       NULL);
1365 
1366   if(input_sequencer == NULL){
1367     if(audio != NULL){
1368       g_object_unref(audio);
1369     }
1370 
1371     if(fx_notation_audio != NULL){
1372       g_object_unref(fx_notation_audio);
1373     }
1374 
1375     return;
1376   }
1377 
1378   current_notation = NULL;
1379 
1380   start_notation = NULL;
1381   start_note = NULL;
1382 
1383   g_object_get(audio,
1384 	       "notation", &start_notation,
1385 	       NULL);
1386 
1387   /* get delay */
1388   delay = AGS_SOUNDCARD_DEFAULT_DELAY;
1389 
1390   if(fx_notation_audio != NULL){
1391     g_object_get(fx_notation_audio,
1392 		 "delay", &port,
1393 		 NULL);
1394 
1395     if(port != NULL){
1396       g_value_init(&value,
1397 		   G_TYPE_DOUBLE);
1398 
1399       ags_port_safe_read(port,
1400 			 &value);
1401 
1402       delay = g_value_get_double(&value);
1403       g_value_unset(&value);
1404 
1405       g_object_unref(port);
1406     }
1407   }
1408 
1409   /* timestamp and offset counter */
1410   g_rec_mutex_lock(fx_notation_audio_processor_mutex);
1411 
1412   timestamp = fx_notation_audio_processor->timestamp;
1413 
1414   offset_counter = fx_notation_audio_processor->offset_counter;
1415 
1416   g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
1417 
1418   ags_timestamp_set_ags_offset(timestamp,
1419 			       AGS_NOTATION_DEFAULT_OFFSET * floor(offset_counter / AGS_NOTATION_DEFAULT_OFFSET));
1420 
1421   /* test flags */
1422   reverse_mapping = ags_audio_test_behaviour_flags(audio,
1423 						   AGS_SOUND_BEHAVIOUR_REVERSE_MAPPING);
1424 
1425   pattern_mode = ags_audio_test_behaviour_flags(audio,
1426 						AGS_SOUND_BEHAVIOUR_PATTERN_MODE);
1427 
1428   /* find near timestamp */
1429   notation = ags_notation_find_near_timestamp(start_notation, audio_channel,
1430 					      timestamp);
1431 
1432   if(notation != NULL){
1433     current_notation = notation->data;
1434   }
1435 
1436   /* retrieve buffer */
1437   midi_buffer = ags_sequencer_get_buffer(AGS_SEQUENCER(input_sequencer),
1438 					 &buffer_length);
1439 
1440   ags_sequencer_lock_buffer(AGS_SEQUENCER(input_sequencer),
1441 			    midi_buffer);
1442 
1443   if(midi_buffer != NULL){
1444     guchar *midi_iter;
1445 
1446     /* parse bytes */
1447     midi_iter = midi_buffer;
1448 
1449     while(midi_iter < midi_buffer + buffer_length){
1450       if(ags_midi_util_is_key_on(midi_iter)){
1451 	/* check midi channel */
1452 	if(midi_channel == (0x0f & midi_iter[0])){
1453 	  AgsNote *current_note;
1454 
1455 	  gint y;
1456 
1457 	  current_note = NULL;
1458 	  y = -1;
1459 
1460 	  /* check mapping */
1461 	  if((0x7f & midi_iter[1]) >= midi_start_mapping &&
1462 	     (0x7f & midi_iter[1]) <= midi_end_mapping){
1463 	    /* check channel */
1464 	    if(!reverse_mapping){
1465 	      y = audio_start_mapping + ((0x7f & midi_iter[1]) - midi_start_mapping);
1466 	    }else{
1467 	      y = input_pads - (audio_start_mapping + ((0x7f & midi_iter[1]) - midi_start_mapping)) - 1;
1468 	    }
1469 	  }
1470 
1471 	  if(y >= 0 &&
1472 	     y < input_pads){
1473 	    g_rec_mutex_lock(fx_notation_audio_processor_mutex);
1474 
1475 	    start_recording_note = g_list_copy_deep(fx_notation_audio_processor->recording_note,
1476 						    (GCopyFunc) g_object_ref,
1477 						    NULL);
1478 
1479 	    g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
1480 
1481 	    recording_note = start_recording_note;
1482 
1483 	    while(recording_note != NULL){
1484 	      guint current_y;
1485 
1486 	      current_y = 0;
1487 
1488 	      g_object_get(recording_note->data,
1489 			   "y", &current_y,
1490 			   NULL);
1491 
1492 	      if(current_y == y){
1493 		current_note = recording_note->data;
1494 
1495 		break;
1496 	      }
1497 
1498 	      /* iterate */
1499 	      recording_note = recording_note->next;
1500 	    }
1501 
1502 	    if(current_note == NULL){
1503 	      current_note = ags_note_new();
1504 
1505 	      current_note->x[0] = offset_counter;
1506 	      current_note->x[1] = offset_counter + 1;
1507 
1508 	      current_note->y = y;
1509 
1510 	      if(!pattern_mode){
1511 		fx_notation_audio_processor->recording_note = g_list_prepend(fx_notation_audio_processor->recording_note,
1512 									     current_note);
1513 		g_object_ref(current_note);
1514 
1515 		ags_note_set_flags(current_note,
1516 				   AGS_NOTE_FEED);
1517 	      }
1518 
1519 	      g_object_ref(current_note);
1520 	      start_note = g_list_prepend(start_note,
1521 					  current_note);
1522 
1523 	      /* check notation */
1524 	      if(current_notation == NULL){
1525 		current_notation = ags_notation_new((GObject *) audio,
1526 						    audio_channel);
1527 
1528 		ags_timestamp_set_ags_offset(current_notation->timestamp,
1529 					     ags_timestamp_get_ags_offset(timestamp));
1530 
1531 		ags_audio_add_notation(audio,
1532 				       (GObject *) current_notation);
1533 	      }
1534 
1535 	      /* add note */
1536 	      ags_notation_add_note(current_notation,
1537 				    current_note,
1538 				    FALSE);
1539 	    }else{
1540 	      if((0x7f & (midi_iter[2])) == 0){
1541 		/* note-off */
1542 		ags_note_unset_flags(current_note,
1543 				     AGS_NOTE_FEED);
1544 
1545 		fx_notation_audio_processor->recording_note = g_list_remove(fx_notation_audio_processor->recording_note,
1546 									    current_note);
1547 		g_object_unref(current_note);
1548 	      }
1549 	    }
1550 
1551 	    g_list_free_full(start_recording_note,
1552 			     (GDestroyNotify) g_object_unref);
1553 	  }
1554 	}
1555 
1556 	midi_iter += 3;
1557       }else if(ags_midi_util_is_key_off(midi_iter)){
1558 	/* check midi channel */
1559 	if(midi_channel == (0x0f & midi_iter[0])){
1560 	  AgsNote *current_note;
1561 
1562 	  gint y;
1563 
1564 	  current_note = NULL;
1565 	  y = -1;
1566 
1567 	  /* check mapping */
1568 	  if((0x7f & midi_iter[1]) >= midi_start_mapping &&
1569 	     (0x7f & midi_iter[1]) <= midi_end_mapping){
1570 	    /* check channel */
1571 	    if(!reverse_mapping){
1572 	      y = audio_start_mapping + ((0x7f & midi_iter[1]) - midi_start_mapping);
1573 	    }else{
1574 	      y = input_pads - (audio_start_mapping + ((0x7f & midi_iter[1]) - midi_start_mapping)) - 1;
1575 	    }
1576 	  }
1577 
1578 	  if(y >= 0 &&
1579 	     y < input_pads){
1580 	    g_rec_mutex_lock(fx_notation_audio_processor_mutex);
1581 
1582 	    start_recording_note = g_list_copy_deep(fx_notation_audio_processor->recording_note,
1583 						    (GCopyFunc) g_object_ref,
1584 						    NULL);
1585 
1586 	    g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
1587 
1588 	    recording_note = start_recording_note;
1589 
1590 	    while(recording_note != NULL){
1591 	      guint current_y;
1592 
1593 	      current_y = 0;
1594 
1595 	      g_object_get(recording_note->data,
1596 			   "y", &current_y,
1597 			   NULL);
1598 
1599 	      if(current_y == y){
1600 		current_note = recording_note->data;
1601 
1602 		break;
1603 	      }
1604 
1605 	      /* iterate */
1606 	      recording_note = recording_note->next;
1607 	    }
1608 
1609 	    if(current_note != NULL){
1610 	      ags_note_unset_flags(current_note,
1611 				   AGS_NOTE_FEED);
1612 
1613 	      fx_notation_audio_processor->recording_note = g_list_remove(fx_notation_audio_processor->recording_note,
1614 									  current_note);
1615 	      g_object_unref(current_note);
1616 	    }
1617 
1618 	    g_list_free_full(start_recording_note,
1619 			     (GDestroyNotify) g_object_unref);
1620 	  }
1621 	}
1622 
1623 	midi_iter += 3;
1624       }else if(ags_midi_util_is_key_pressure(midi_iter)){
1625 	midi_iter += 3;
1626       }else if(ags_midi_util_is_change_parameter(midi_iter)){
1627 	/* change parameter */
1628 	//TODO:JK: implement me
1629 
1630 	midi_iter += 3;
1631       }else if(ags_midi_util_is_pitch_bend(midi_iter)){
1632 	/* change parameter */
1633 	//TODO:JK: implement me
1634 
1635 	midi_iter += 3;
1636       }else if(ags_midi_util_is_change_program(midi_iter)){
1637 	/* change program */
1638 	//TODO:JK: implement me
1639 
1640 	midi_iter += 2;
1641       }else if(ags_midi_util_is_change_pressure(midi_iter)){
1642 	/* change pressure */
1643 	//TODO:JK: implement me
1644 
1645 	midi_iter += 2;
1646       }else if(ags_midi_util_is_sysex(midi_iter)){
1647 	guint n;
1648 
1649 	/* sysex */
1650 	n = 0;
1651 
1652 	while(midi_iter[n] != 0xf7){
1653 	  n++;
1654 	}
1655 
1656 	//TODO:JK: implement me
1657 
1658 	midi_iter += (n + 1);
1659       }else if(ags_midi_util_is_song_position(midi_iter)){
1660 	/* song position */
1661 	//TODO:JK: implement me
1662 
1663 	midi_iter += 3;
1664       }else if(ags_midi_util_is_song_select(midi_iter)){
1665 	/* song select */
1666 	//TODO:JK: implement me
1667 
1668 	midi_iter += 2;
1669       }else if(ags_midi_util_is_tune_request(midi_iter)){
1670 	/* tune request */
1671 	//TODO:JK: implement me
1672 
1673 	midi_iter += 1;
1674       }else if(ags_midi_util_is_meta_event(midi_iter)){
1675 	/* meta event */
1676 	//TODO:JK: implement me
1677 
1678 	midi_iter += (3 + midi_iter[2]);
1679       }else{
1680 	g_warning("ags_fx_notation_audio_processor.c - unexpected byte %x", midi_iter[0]);
1681 
1682 	midi_iter++;
1683       }
1684     }
1685   }
1686 
1687   ags_sequencer_unlock_buffer(AGS_SEQUENCER(input_sequencer),
1688 			      midi_buffer);
1689 
1690   /* key on */
1691   note = start_note;
1692 
1693   while(note != NULL){
1694     ags_fx_notation_audio_processor_key_on(fx_notation_audio_processor,
1695 					   note->data,
1696 					   AGS_FX_NOTATION_AUDIO_PROCESSOR_DEFAULT_KEY_ON_VELOCITY,
1697 					   AGS_FX_NOTATION_AUDIO_PROCESSOR_KEY_MODE_RECORD);
1698 
1699     note = note->next;
1700   }
1701 
1702   /* update */
1703   g_rec_mutex_lock(fx_notation_audio_processor_mutex);
1704 
1705   start_recording_note = g_list_copy_deep(fx_notation_audio_processor->recording_note,
1706 					  (GCopyFunc) g_object_ref,
1707 					  NULL);
1708 
1709   g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
1710 
1711   recording_note = start_recording_note;
1712 
1713   while(recording_note != NULL){
1714     guint current_x1;
1715 
1716     current_x1 = 0;
1717 
1718     g_object_get(recording_note->data,
1719 		 "x1", &current_x1,
1720 		 NULL);
1721 
1722     if(current_x1 <= offset_counter + 1){
1723       g_object_set(recording_note->data,
1724 		   "x1", current_x1 + 1,
1725 		   NULL);
1726     }
1727 
1728     /* iterate */
1729     recording_note = recording_note->next;
1730   }
1731 
1732   /* unref */
1733   g_list_free_full(start_recording_note,
1734 		   (GDestroyNotify) g_object_unref);
1735 
1736   if(audio != NULL){
1737     g_object_unref(audio);
1738   }
1739 
1740   if(fx_notation_audio != NULL){
1741     g_object_unref(fx_notation_audio);
1742   }
1743 
1744   if(input_sequencer != NULL){
1745     g_object_unref(input_sequencer);
1746   }
1747 
1748   g_list_free_full(start_notation,
1749 		   (GDestroyNotify) g_object_unref);
1750 
1751   g_list_free_full(start_note,
1752 		   (GDestroyNotify) g_object_unref);
1753 }
1754 
1755 void
ags_fx_notation_audio_processor_record(AgsFxNotationAudioProcessor * fx_notation_audio_processor)1756 ags_fx_notation_audio_processor_record(AgsFxNotationAudioProcessor *fx_notation_audio_processor)
1757 {
1758   g_return_if_fail(AGS_IS_FX_NOTATION_AUDIO_PROCESSOR(fx_notation_audio_processor));
1759 
1760   g_object_ref(fx_notation_audio_processor);
1761 
1762   if(AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->record != NULL){
1763     AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->record(fx_notation_audio_processor);
1764   }
1765 
1766   g_object_unref(fx_notation_audio_processor);
1767 }
1768 
1769 void
ags_fx_notation_audio_processor_real_feed(AgsFxNotationAudioProcessor * fx_notation_audio_processor)1770 ags_fx_notation_audio_processor_real_feed(AgsFxNotationAudioProcessor *fx_notation_audio_processor)
1771 {
1772   AgsAudio *audio;
1773   AgsPort *port;
1774   AgsFxNotationAudio *fx_notation_audio;
1775 
1776   GList *start_feed_note, *feed_note;
1777   GList *start_feeding_note, *feeding_note;
1778 
1779   gdouble delay;
1780   guint64 offset_counter;
1781 
1782   GValue value = {0,};
1783 
1784   GRecMutex *fx_notation_audio_processor_mutex;
1785 
1786   fx_notation_audio_processor_mutex = AGS_RECALL_GET_OBJ_MUTEX(fx_notation_audio_processor);
1787 
1788   audio = NULL;
1789 
1790   fx_notation_audio = NULL;
1791 
1792   g_object_get(fx_notation_audio_processor,
1793 	       "audio", &audio,
1794 	       "recall-audio", &fx_notation_audio,
1795 	       NULL);
1796 
1797   g_rec_mutex_lock(fx_notation_audio_processor_mutex);
1798 
1799   offset_counter = fx_notation_audio_processor->offset_counter;
1800 
1801   g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
1802 
1803   /* get delay */
1804   delay = AGS_SOUNDCARD_DEFAULT_DELAY;
1805 
1806   if(fx_notation_audio != NULL){
1807     port = NULL;
1808 
1809     g_object_get(fx_notation_audio,
1810 		 "delay", &port,
1811 		 NULL);
1812 
1813     if(port != NULL){
1814       g_value_init(&value,
1815 		   G_TYPE_DOUBLE);
1816 
1817       ags_port_safe_read(port,
1818 			 &value);
1819 
1820       delay = g_value_get_double(&value);
1821       g_value_unset(&value);
1822 
1823       g_object_unref(port);
1824     }
1825   }
1826 
1827   /* get feed note */
1828   feed_note =
1829     start_feed_note = ags_fx_notation_audio_get_feed_note(fx_notation_audio);
1830 
1831   /* check new */
1832   while(feed_note != NULL){
1833     gboolean is_new;
1834 
1835     g_rec_mutex_lock(fx_notation_audio_processor_mutex);
1836 
1837     is_new = (g_list_find(fx_notation_audio_processor->feeding_note, feed_note->data) == NULL) ? TRUE: FALSE;
1838 
1839     g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
1840 
1841     if(is_new){
1842       ags_fx_notation_audio_processor_key_on(fx_notation_audio_processor,
1843 					     feed_note->data,
1844 					     AGS_FX_NOTATION_AUDIO_PROCESSOR_DEFAULT_KEY_ON_VELOCITY,
1845 					     AGS_FX_NOTATION_AUDIO_PROCESSOR_KEY_MODE_FEED);
1846     }
1847 
1848     feed_note = feed_note->next;
1849   }
1850 
1851   /* check removed and update */
1852   g_rec_mutex_lock(fx_notation_audio_processor_mutex);
1853 
1854   feeding_note =
1855     start_feeding_note = g_list_copy_deep(fx_notation_audio_processor->feeding_note,
1856 					  (GCopyFunc) g_object_ref,
1857 					  NULL);
1858 
1859   g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
1860 
1861   while(feeding_note != NULL){
1862     gboolean is_removed;
1863 
1864     is_removed = (g_list_find(start_feed_note, feeding_note->data) == NULL) ? TRUE: FALSE;
1865 
1866     if(!is_removed){
1867       guint current_x1;
1868 
1869       current_x1 = 0;
1870 
1871       g_object_get(feeding_note->data,
1872 		   "x1", &current_x1,
1873 		   NULL);
1874 
1875       if(current_x1 < offset_counter){
1876 	g_object_set(feeding_note->data,
1877 		     "x1", current_x1 + 1,
1878 		     NULL);
1879       }
1880     }else{
1881       g_rec_mutex_lock(fx_notation_audio_processor_mutex);
1882 
1883       start_feeding_note = g_list_remove(fx_notation_audio_processor->feeding_note,
1884 					 feeding_note->data);
1885 
1886       g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
1887 
1888       g_object_unref(feeding_note->data);
1889     }
1890 
1891     feeding_note = feeding_note->next;
1892   }
1893 
1894   /* unref */
1895   if(audio != NULL){
1896     g_object_unref(audio);
1897   }
1898 
1899   if(fx_notation_audio != NULL){
1900     g_object_unref(fx_notation_audio);
1901   }
1902 
1903   g_list_free_full(start_feed_note,
1904 		   (GDestroyNotify) g_object_unref);
1905 
1906   g_list_free_full(start_feeding_note,
1907 		   (GDestroyNotify) g_object_unref);
1908 }
1909 
1910 void
ags_fx_notation_audio_processor_feed(AgsFxNotationAudioProcessor * fx_notation_audio_processor)1911 ags_fx_notation_audio_processor_feed(AgsFxNotationAudioProcessor *fx_notation_audio_processor)
1912 {
1913   g_return_if_fail(AGS_IS_FX_NOTATION_AUDIO_PROCESSOR(fx_notation_audio_processor));
1914 
1915   g_object_ref(fx_notation_audio_processor);
1916 
1917   if(AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->feed != NULL){
1918     AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->feed(fx_notation_audio_processor);
1919   }
1920 
1921   g_object_unref(fx_notation_audio_processor);
1922 }
1923 
1924 void
ags_fx_notation_audio_processor_real_counter_change(AgsFxNotationAudioProcessor * fx_notation_audio_processor)1925 ags_fx_notation_audio_processor_real_counter_change(AgsFxNotationAudioProcessor *fx_notation_audio_processor)
1926 {
1927   AgsFxNotationAudio *fx_notation_audio;
1928 
1929   GObject *output_soundcard;
1930 
1931   gdouble delay;
1932   guint delay_counter;
1933   guint offset_counter;
1934   gboolean loop;
1935   guint64 loop_start, loop_end;
1936 
1937   GValue value = {0,};
1938 
1939   GRecMutex *fx_notation_audio_processor_mutex;
1940 
1941   fx_notation_audio_processor_mutex = AGS_RECALL_GET_OBJ_MUTEX(fx_notation_audio_processor);
1942 
1943   output_soundcard = NULL;
1944 
1945   fx_notation_audio = NULL;
1946 
1947   g_object_get(fx_notation_audio_processor,
1948 	       "output-soundcard", &output_soundcard,
1949 	       "recall-audio", &fx_notation_audio,
1950 	       NULL);
1951 
1952   delay = AGS_SOUNDCARD_DEFAULT_DELAY;
1953 
1954   loop = FALSE;
1955 
1956   loop_start = AGS_FX_NOTATION_AUDIO_DEFAULT_LOOP_START;
1957   loop_end = AGS_FX_NOTATION_AUDIO_DEFAULT_LOOP_END;
1958 
1959   if(fx_notation_audio != NULL){
1960     AgsPort *port;
1961 
1962     /* delay */
1963     port = NULL;
1964 
1965     g_object_get(fx_notation_audio,
1966 		 "delay", &port,
1967 		 NULL);
1968 
1969     if(port != NULL){
1970       g_value_init(&value,
1971 		   G_TYPE_DOUBLE);
1972 
1973       ags_port_safe_read(port,
1974 			 &value);
1975 
1976       delay = g_value_get_double(&value);
1977       g_value_unset(&value);
1978 
1979       g_object_unref(port);
1980     }
1981 
1982     /* loop */
1983     port = NULL;
1984 
1985     g_object_get(fx_notation_audio,
1986 		 "loop", &port,
1987 		 NULL);
1988 
1989     if(port != NULL){
1990       g_value_init(&value,
1991 		   G_TYPE_BOOLEAN);
1992 
1993       ags_port_safe_read(port,
1994 			 &value);
1995 
1996       loop = g_value_get_boolean(&value);
1997       g_value_unset(&value);
1998 
1999       g_object_unref(port);
2000     }
2001 
2002     /* loop-start */
2003     port = NULL;
2004 
2005     g_object_get(fx_notation_audio,
2006 		 "loop-start", &port,
2007 		 NULL);
2008 
2009     if(port != NULL){
2010       g_value_init(&value,
2011 		   G_TYPE_UINT64);
2012 
2013       ags_port_safe_read(port,
2014 			 &value);
2015 
2016       loop_start = g_value_get_uint64(&value);
2017       g_value_unset(&value);
2018 
2019       g_object_unref(port);
2020     }
2021 
2022     /* loop-end */
2023     port = NULL;
2024 
2025     g_object_get(fx_notation_audio,
2026 		 "loop-end", &port,
2027 		 NULL);
2028 
2029     if(port != NULL){
2030       g_value_init(&value,
2031 		   G_TYPE_UINT64);
2032 
2033       ags_port_safe_read(port,
2034 			 &value);
2035 
2036       loop_end = g_value_get_uint64(&value);
2037       g_value_unset(&value);
2038 
2039       g_object_unref(port);
2040     }
2041   }
2042 
2043   g_rec_mutex_lock(fx_notation_audio_processor_mutex);
2044 
2045   delay_counter = floor(fx_notation_audio_processor->delay_counter);
2046 
2047   offset_counter = fx_notation_audio_processor->offset_counter;
2048 
2049   g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
2050 
2051   if(output_soundcard != NULL){
2052     delay = ags_soundcard_get_delay(AGS_SOUNDCARD(output_soundcard));
2053 
2054     delay_counter = ags_soundcard_get_delay_counter(AGS_SOUNDCARD(output_soundcard));
2055   }
2056 
2057   if(delay_counter + 1.0 >= floor(delay)){
2058     g_rec_mutex_lock(fx_notation_audio_processor_mutex);
2059 
2060     fx_notation_audio_processor->current_delay_counter = 0.0;
2061 
2062     if(loop &&
2063        offset_counter + 1 >= loop_end){
2064       fx_notation_audio_processor->current_offset_counter = loop_start;
2065     }else{
2066       fx_notation_audio_processor->current_offset_counter += 1;
2067     }
2068 
2069     g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
2070   }else{
2071     g_rec_mutex_lock(fx_notation_audio_processor_mutex);
2072 
2073     fx_notation_audio_processor->current_delay_counter += 1.0;
2074 
2075     g_rec_mutex_unlock(fx_notation_audio_processor_mutex);
2076   }
2077 
2078   if(output_soundcard != NULL){
2079     g_object_unref(output_soundcard);
2080   }
2081 
2082   /* unref */
2083   if(fx_notation_audio != NULL){
2084     g_object_unref(fx_notation_audio);
2085   }
2086 }
2087 
2088 void
ags_fx_notation_audio_processor_counter_change(AgsFxNotationAudioProcessor * fx_notation_audio_processor)2089 ags_fx_notation_audio_processor_counter_change(AgsFxNotationAudioProcessor *fx_notation_audio_processor)
2090 {
2091   g_return_if_fail(AGS_IS_FX_NOTATION_AUDIO_PROCESSOR(fx_notation_audio_processor));
2092 
2093   g_object_ref(fx_notation_audio_processor);
2094 
2095   if(AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->counter_change != NULL){
2096     AGS_FX_NOTATION_AUDIO_PROCESSOR_GET_CLASS(fx_notation_audio_processor)->counter_change(fx_notation_audio_processor);
2097   }
2098 
2099   g_object_unref(fx_notation_audio_processor);
2100 }
2101 
2102 /**
2103  * ags_fx_notation_audio_processor_new:
2104  * @audio: the #AgsAudio
2105  *
2106  * Create a new instance of #AgsFxNotationAudioProcessor
2107  *
2108  * Returns: the new #AgsFxNotationAudioProcessor
2109  *
2110  * Since: 3.3.0
2111  */
2112 AgsFxNotationAudioProcessor*
ags_fx_notation_audio_processor_new(AgsAudio * audio)2113 ags_fx_notation_audio_processor_new(AgsAudio *audio)
2114 {
2115   AgsFxNotationAudioProcessor *fx_notation_audio_processor;
2116 
2117   fx_notation_audio_processor = (AgsFxNotationAudioProcessor *) g_object_new(AGS_TYPE_FX_NOTATION_AUDIO_PROCESSOR,
2118 									     "audio", audio,
2119 									     NULL);
2120 
2121   return(fx_notation_audio_processor);
2122 }
2123