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/task/ags_open_sfz_file.h>
21 
22 #include <ags/audio/ags_diatonic_scale.h>
23 #include <ags/audio/ags_audio.h>
24 #include <ags/audio/ags_channel.h>
25 #include <ags/audio/ags_input.h>
26 #include <ags/audio/ags_filter_util.h>
27 
28 #include <ags/audio/file/ags_audio_file_link.h>
29 #include <ags/audio/file/ags_sound_container.h>
30 #include <ags/audio/file/ags_sound_resource.h>
31 #include <ags/audio/file/ags_audio_file_link.h>
32 #include <ags/audio/file/ags_audio_container.h>
33 #include <ags/audio/file/ags_sfz_file.h>
34 #include <ags/audio/file/ags_sfz_group.h>
35 #include <ags/audio/file/ags_sfz_region.h>
36 #include <ags/audio/file/ags_sfz_sample.h>
37 
38 #include <ags/config.h>
39 
40 #include <ags/i18n.h>
41 
42 void ags_open_sfz_file_class_init(AgsOpenSFZFileClass *open_sfz_file);
43 void ags_open_sfz_file_init(AgsOpenSFZFile *open_sfz_file);
44 void ags_open_sfz_file_set_property(GObject *gobject,
45 				    guint prop_id,
46 				    const GValue *value,
47 				    GParamSpec *param_spec);
48 void ags_open_sfz_file_get_property(GObject *gobject,
49 				    guint prop_id,
50 				    GValue *value,
51 				    GParamSpec *param_spec);
52 void ags_open_sfz_file_dispose(GObject *gobject);
53 void ags_open_sfz_file_finalize(GObject *gobject);
54 
55 void ags_open_sfz_file_launch(AgsTask *task);
56 
57 
58 /**
59  * SECTION:ags_open_sfz_file
60  * @short_description: open SFZ file
61  * @title: AgsOpenSFZFile
62  * @section_id:
63  * @include: ags/audio/task/ags_open_sfz_file.h
64  *
65  * The #AgsOpenSFZFile task opens SFZ file.
66  */
67 
68 static gpointer ags_open_sfz_file_parent_class = NULL;
69 
70 enum{
71   PROP_0,
72   PROP_AUDIO,
73   PROP_SFZ_FILE,
74   PROP_FILENAME,
75   PROP_START_PAD,
76 };
77 
78 GType
ags_open_sfz_file_get_type()79 ags_open_sfz_file_get_type()
80 {
81   static volatile gsize g_define_type_id__volatile = 0;
82 
83   if(g_once_init_enter (&g_define_type_id__volatile)){
84     GType ags_type_open_sfz_file = 0;
85 
86     static const GTypeInfo ags_open_sfz_file_info = {
87       sizeof(AgsOpenSFZFileClass),
88       NULL, /* base_init */
89       NULL, /* base_finalize */
90       (GClassInitFunc) ags_open_sfz_file_class_init,
91       NULL, /* class_finalize */
92       NULL, /* class_data */
93       sizeof(AgsOpenSFZFile),
94       0,    /* n_preallocs */
95       (GInstanceInitFunc) ags_open_sfz_file_init,
96     };
97 
98     ags_type_open_sfz_file = g_type_register_static(AGS_TYPE_TASK,
99 						    "AgsOpenSFZFile",
100 						    &ags_open_sfz_file_info,
101 						    0);
102 
103     g_once_init_leave(&g_define_type_id__volatile, ags_type_open_sfz_file);
104   }
105 
106   return g_define_type_id__volatile;
107 }
108 
109 void
ags_open_sfz_file_class_init(AgsOpenSFZFileClass * open_sfz_file)110 ags_open_sfz_file_class_init(AgsOpenSFZFileClass *open_sfz_file)
111 {
112   GObjectClass *gobject;
113   AgsTaskClass *task;
114 
115   GParamSpec *param_spec;
116 
117   ags_open_sfz_file_parent_class = g_type_class_peek_parent(open_sfz_file);
118 
119   /* GObject */
120   gobject = (GObjectClass *) open_sfz_file;
121 
122   gobject->set_property = ags_open_sfz_file_set_property;
123   gobject->get_property = ags_open_sfz_file_get_property;
124 
125   gobject->dispose = ags_open_sfz_file_dispose;
126   gobject->finalize = ags_open_sfz_file_finalize;
127 
128   /* properties */
129   /**
130    * AgsOpenSFZFile:audio:
131    *
132    * The assigned #AgsAudio
133    *
134    * Since: 3.4.0
135    */
136   param_spec = g_param_spec_object("audio",
137 				   i18n_pspec("audio of open sf2 instrument"),
138 				   i18n_pspec("The audio of open sf2 instrument task"),
139 				   AGS_TYPE_AUDIO,
140 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
141   g_object_class_install_property(gobject,
142 				  PROP_AUDIO,
143 				  param_spec);
144 
145   /**
146    * AgsOpenSFZFile:sfz-file:
147    *
148    * The assigned #AgsSFZFile
149    *
150    * Since: 3.4.0
151    */
152   param_spec = g_param_spec_object("sfz-file",
153 				   i18n_pspec("SFZ file object"),
154 				   i18n_pspec("The SFZ file object of open task"),
155 				   AGS_TYPE_SFZ_FILE,
156 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
157   g_object_class_install_property(gobject,
158 				  PROP_SFZ_FILE,
159 				  param_spec);
160 
161   /**
162    * AgsOpenSFZFile:filename:
163    *
164    * The assigned filename.
165    *
166    * Since: 3.4.0
167    */
168   param_spec = g_param_spec_string("filename",
169 				   i18n_pspec("the filename"),
170 				   i18n_pspec("The filename"),
171 				   NULL,
172 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
173   g_object_class_install_property(gobject,
174 				  PROP_FILENAME,
175 				  param_spec);
176 
177   /**
178    * AgsOpenSFZFile:start-pad:
179    *
180    * The assigned start-pad.
181    *
182    * Since: 3.4.0
183    */
184   param_spec = g_param_spec_uint("start-pad",
185 				 i18n_pspec("the start pad"),
186 				 i18n_pspec("The start pad"),
187 				 0,
188 				 G_MAXUINT32,
189 				 0,
190 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
191   g_object_class_install_property(gobject,
192 				  PROP_START_PAD,
193 				  param_spec);
194 
195   /* AgsTask */
196   task = (AgsTaskClass *) open_sfz_file;
197 
198   task->launch = ags_open_sfz_file_launch;
199 }
200 
201 void
ags_open_sfz_file_init(AgsOpenSFZFile * open_sfz_file)202 ags_open_sfz_file_init(AgsOpenSFZFile *open_sfz_file)
203 {
204   open_sfz_file->audio = NULL;
205 
206   open_sfz_file->filename = NULL;
207 
208   open_sfz_file->start_pad = 0;
209 }
210 
211 void
ags_open_sfz_file_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)212 ags_open_sfz_file_set_property(GObject *gobject,
213 			       guint prop_id,
214 			       const GValue *value,
215 			       GParamSpec *param_spec)
216 {
217   AgsOpenSFZFile *open_sfz_file;
218 
219   open_sfz_file = AGS_OPEN_SFZ_FILE(gobject);
220 
221   switch(prop_id){
222   case PROP_AUDIO:
223   {
224     AgsAudio *audio;
225 
226     audio = (AgsAudio *) g_value_get_object(value);
227 
228     if(open_sfz_file->audio == audio){
229       return;
230     }
231 
232     if(open_sfz_file->audio != NULL){
233       g_object_unref(open_sfz_file->audio);
234     }
235 
236     if(audio != NULL){
237       g_object_ref(audio);
238     }
239 
240     open_sfz_file->audio = audio;
241   }
242   break;
243   case PROP_SFZ_FILE:
244   {
245     AgsSFZFile *sfz_file;
246 
247     sfz_file = (AgsSFZFile *) g_value_get_object(value);
248 
249     if(open_sfz_file->sfz_file == sfz_file){
250       return;
251     }
252 
253     if(open_sfz_file->sfz_file != NULL){
254       g_object_unref(open_sfz_file->sfz_file);
255     }
256 
257     if(sfz_file != NULL){
258       g_object_ref(sfz_file);
259     }
260 
261     open_sfz_file->sfz_file = sfz_file;
262   }
263   break;
264   case PROP_FILENAME:
265   {
266     gchar *filename;
267 
268     filename = g_value_get_string(value);
269 
270     if(open_sfz_file->filename == filename){
271       return;
272     }
273 
274     if(open_sfz_file->filename != NULL){
275       g_free(open_sfz_file->filename);
276     }
277 
278     open_sfz_file->filename = g_strdup(filename);
279   }
280   break;
281   case PROP_START_PAD:
282   {
283     open_sfz_file->start_pad = g_value_get_uint(value);
284   }
285   break;
286   default:
287     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
288     break;
289   }
290 }
291 
292 void
ags_open_sfz_file_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)293 ags_open_sfz_file_get_property(GObject *gobject,
294 			       guint prop_id,
295 			       GValue *value,
296 			       GParamSpec *param_spec)
297 {
298   AgsOpenSFZFile *open_sfz_file;
299 
300   open_sfz_file = AGS_OPEN_SFZ_FILE(gobject);
301 
302   switch(prop_id){
303   case PROP_AUDIO:
304   {
305     g_value_set_object(value, open_sfz_file->audio);
306   }
307   break;
308   case PROP_SFZ_FILE:
309   {
310     g_value_set_object(value, open_sfz_file->sfz_file);
311   }
312   break;
313   case PROP_FILENAME:
314   {
315     g_value_set_string(value, open_sfz_file->filename);
316   }
317   break;
318   case PROP_START_PAD:
319   {
320     g_value_set_uint(value, open_sfz_file->start_pad);
321   }
322   break;
323   default:
324     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
325     break;
326   }
327 }
328 
329 void
ags_open_sfz_file_dispose(GObject * gobject)330 ags_open_sfz_file_dispose(GObject *gobject)
331 {
332   AgsOpenSFZFile *open_sfz_file;
333 
334   open_sfz_file = AGS_OPEN_SFZ_FILE(gobject);
335 
336   if(open_sfz_file->audio != NULL){
337     g_object_unref(open_sfz_file->audio);
338 
339     open_sfz_file->audio = NULL;
340   }
341 
342   if(open_sfz_file->sfz_file != NULL){
343     g_object_unref(open_sfz_file->sfz_file);
344 
345     open_sfz_file->sfz_file = NULL;
346   }
347 
348   /* call parent */
349   G_OBJECT_CLASS(ags_open_sfz_file_parent_class)->dispose(gobject);
350 }
351 
352 void
ags_open_sfz_file_finalize(GObject * gobject)353 ags_open_sfz_file_finalize(GObject *gobject)
354 {
355   AgsOpenSFZFile *open_sfz_file;
356 
357   open_sfz_file = AGS_OPEN_SFZ_FILE(gobject);
358 
359   if(open_sfz_file->audio != NULL){
360     g_object_unref(open_sfz_file->audio);
361   }
362 
363   if(open_sfz_file->sfz_file != NULL){
364     g_object_unref(open_sfz_file->sfz_file);
365   }
366 
367   g_free(open_sfz_file->filename);
368 
369   /* call parent */
370   G_OBJECT_CLASS(ags_open_sfz_file_parent_class)->finalize(gobject);
371 }
372 
373 void
ags_open_sfz_file_launch(AgsTask * task)374 ags_open_sfz_file_launch(AgsTask *task)
375 {
376   AgsChannel *start_input, *next_input, *input;
377   AgsSFZGroup *group;
378   AgsSFZRegion *region;
379   AgsOpenSFZFile *open_sfz_file;
380 
381   GObject *output_soundcard;
382 
383   GList *start_audio_signal, *audio_signal;
384   GList *start_list, *list;
385 
386   glong key, current_key;
387   glong hikey, lokey, current_hikey, current_lokey;
388   guint n_pads, current_pads;
389   guint n_audio_channels, current_audio_channels;
390   int retval;
391   guint j_stop;
392   guint i, j;
393 
394   open_sfz_file = AGS_OPEN_SFZ_FILE(task);
395 
396   g_return_if_fail(AGS_IS_AUDIO(open_sfz_file->audio));
397   g_return_if_fail(AGS_IS_SFZ_FILE(open_sfz_file->sfz_file));
398 
399   g_object_get(open_sfz_file->audio,
400 	       "output-soundcard", &output_soundcard,
401 	       NULL);
402 
403   /* select */
404   start_input = NULL;
405 
406   n_pads = 0;
407   n_audio_channels = 0;
408 
409   g_object_get(open_sfz_file->audio,
410 	       "input-pads", &n_pads,
411 	       "audio-channels", &n_audio_channels,
412 	       NULL);
413 
414   hikey = 0;
415   lokey = 0;
416 
417   ags_sfz_file_get_range(AGS_SFZ_FILE(open_sfz_file->sfz_file),
418 			 &lokey, &hikey);
419 
420   /* resize */
421   g_object_get(open_sfz_file->sfz_file,
422 	       "sample", &start_list,
423 	       NULL);
424 
425   list = start_list;
426   current_audio_channels = n_audio_channels;
427 
428   while(list != NULL){
429     guint tmp;
430 
431     ags_sound_resource_get_presets(AGS_SOUND_RESOURCE(list->data),
432 				   &tmp,
433 				   NULL,
434 				   NULL,
435 				   NULL);
436 
437     if(tmp > current_audio_channels){
438       current_audio_channels = tmp;
439     }
440 
441     /* iterate */
442     list = list->next;
443   }
444 
445   if(current_audio_channels > n_audio_channels){
446     n_audio_channels = current_audio_channels;
447 
448     ags_audio_set_audio_channels(open_sfz_file->audio,
449 				 n_audio_channels, 0);
450   }
451 
452   current_pads = hikey - lokey + 1;
453 
454   if(lokey <= hikey &&
455      current_pads > n_pads){
456     n_pads = current_pads;
457 
458     ags_audio_set_pads(open_sfz_file->audio,
459 		       AGS_TYPE_INPUT,
460 		       n_pads, 0);
461   }
462 
463   g_object_get(open_sfz_file->audio,
464 	       "input", &start_input,
465 	       NULL);
466 
467   input = start_input;
468 
469   audio_signal =
470     start_audio_signal = NULL;
471 
472   j_stop = n_audio_channels;
473 
474   for(i = 0, j = 0; input != NULL;){
475     AgsRecycling *first_recycling;
476 
477     g_object_get(input,
478 		 "first-recycling", &first_recycling,
479 		 NULL);
480 
481     list = start_list;
482 
483     while(list != NULL){
484       gchar *str_key, *str_pitch_keycenter;
485       gchar *str_lokey, *str_hikey;
486 
487       gboolean success;
488 
489       g_object_get(list->data,
490 		   "group", &group,
491 		   "region", &region,
492 		   NULL);
493 
494       /* group */
495       str_pitch_keycenter = ags_sfz_group_lookup_control(group,
496 							 "pitch_keycenter");
497 
498       str_key = ags_sfz_group_lookup_control(group,
499 					     "key");
500 
501       str_lokey = ags_sfz_group_lookup_control(group,
502 					       "lokey");
503 
504       str_hikey = ags_sfz_group_lookup_control(group,
505 					       "hikey");
506 
507       lokey = 0;
508 
509       if(str_lokey != NULL){
510 	retval = sscanf(str_lokey, "%lu", &current_lokey);
511 
512 	if(retval <= 0){
513 	  retval = ags_diatonic_scale_note_to_midi_key(str_lokey,
514 						       &current_lokey);
515 
516 	  if(retval > 0){
517 	    lokey = current_lokey;
518 	  }
519 	}else{
520 	  lokey = current_lokey;
521 	}
522       }
523 
524       key = lokey + i;
525 
526       success = FALSE;
527 
528       if(str_pitch_keycenter != NULL){
529 	retval = sscanf(str_pitch_keycenter, "%lu", &current_key);
530 
531 	if(retval > 0){
532 	  if(current_key == key){
533 	    success = TRUE;
534 	  }
535 	}else{
536 	  retval = ags_diatonic_scale_note_to_midi_key(str_pitch_keycenter,
537 						       &current_key);
538 
539 	  if(retval > 0){
540 	    if(current_key == key){
541 	      success = TRUE;
542 	    }
543 	  }
544 	}
545       }
546 
547       if(str_key != NULL){
548 	retval = sscanf(str_key, "%lu", &current_key);
549 
550 	if(retval > 0){
551 	  if(current_key == key){
552 	    success = TRUE;
553 	  }
554 	}else{
555 	  retval = ags_diatonic_scale_note_to_midi_key(str_key,
556 						       &current_key);
557 
558 	  if(retval > 0){
559 	    if(current_key == key){
560 	      success = TRUE;
561 	    }
562 	  }
563 	}
564 
565 	if(success){
566 	  g_free(str_pitch_keycenter);
567 	  g_free(str_key);
568 
569 	  g_free(str_hikey);
570 	  g_free(str_lokey);
571 
572 	  break;
573 	}
574       }
575 
576       if(str_hikey != NULL && str_lokey != NULL){
577 	success = FALSE;
578 
579 	retval = sscanf(str_hikey, "%lu", &current_hikey);
580 
581 	if(retval <= 0){
582 	  retval = ags_diatonic_scale_note_to_midi_key(str_hikey,
583 						       &current_hikey);
584 
585 	  if(retval > 0){
586 	    if(current_key <= current_hikey){
587 	      success = TRUE;
588 	    }
589 	  }
590 	}else{
591 	  if(current_key <= current_hikey){
592 	    success = TRUE;
593 	  }
594 	}
595 
596 	retval = sscanf(str_lokey, "%lu", &current_lokey);
597 
598 	if(retval <= 0){
599 	  retval = ags_diatonic_scale_note_to_midi_key(str_lokey,
600 						       &current_lokey);
601 
602 	  if(retval > 0){
603 	    if(current_key >= current_lokey){
604 	      success = TRUE;
605 	    }else{
606 	      success = FALSE;
607 	    }
608 	  }else{
609 	    success = FALSE;
610 	  }
611 	}else{
612 	  if(current_key >= current_lokey){
613 	    success = TRUE;
614 	  }else{
615 	    success = FALSE;
616 	  }
617 	}
618 
619 	if(success){
620 	  hikey = current_hikey;
621 	  lokey = current_lokey;
622 
623 	  g_free(str_pitch_keycenter);
624 	  g_free(str_key);
625 
626 	  g_free(str_hikey);
627 	  g_free(str_lokey);
628 
629 	  break;
630 	}
631       }
632 
633       g_free(str_pitch_keycenter);
634       g_free(str_key);
635 
636       g_free(str_hikey);
637       g_free(str_lokey);
638 
639       /* region */
640       str_pitch_keycenter = ags_sfz_region_lookup_control(region,
641 							  "pitch_keycenter");
642 
643       str_key = ags_sfz_region_lookup_control(region,
644 					      "key");
645 
646       str_lokey = ags_sfz_region_lookup_control(region,
647 						"lokey");
648 
649       str_hikey = ags_sfz_region_lookup_control(region,
650 						"hikey");
651 
652       lokey = 0;
653 
654       if(str_lokey != NULL){
655 	retval = sscanf(str_lokey, "%lu", &current_lokey);
656 
657 	if(retval <= 0){
658 	  retval = ags_diatonic_scale_note_to_midi_key(str_lokey,
659 						       &current_lokey);
660 
661 	  if(retval > 0){
662 	    lokey = current_lokey;
663 	  }
664 	}else{
665 	  lokey = current_lokey;
666 	}
667       }
668 
669       key = lokey + i;
670 
671       success = FALSE;
672 
673       if(str_pitch_keycenter != NULL){
674 	retval = sscanf(str_pitch_keycenter, "%lu", &current_key);
675 
676 	if(retval > 0){
677 	  if(current_key == key){
678 	    success = TRUE;
679 	  }
680 	}else{
681 	  retval = ags_diatonic_scale_note_to_midi_key(str_pitch_keycenter,
682 						       &current_key);
683 
684 	  if(retval > 0){
685 	    if(current_key == key){
686 	      success = TRUE;
687 	    }
688 	  }
689 	}
690       }
691 
692       if(str_key != NULL){
693 	retval = sscanf(str_key, "%lu", &current_key);
694 
695 	if(retval > 0){
696 	  if(current_key == key){
697 	    success = TRUE;
698 	  }
699 	}else{
700 	  retval = ags_diatonic_scale_note_to_midi_key(str_key,
701 						       &current_key);
702 
703 	  if(retval > 0){
704 	    if(current_key == key){
705 	      success = TRUE;
706 	    }
707 	  }
708 	}
709 
710 	if(success){
711 	  g_free(str_pitch_keycenter);
712 	  g_free(str_key);
713 
714 	  g_free(str_hikey);
715 	  g_free(str_lokey);
716 
717 	  break;
718 	}
719       }
720 
721       if(str_hikey != NULL && str_lokey != NULL){
722 	gboolean success;
723 
724 	success = FALSE;
725 
726 	retval = sscanf(str_hikey, "%lu", &current_hikey);
727 
728 	if(retval <= 0){
729 	  retval = ags_diatonic_scale_note_to_midi_key(str_hikey,
730 						       &current_hikey);
731 
732 	  if(retval > 0){
733 	    if(current_key <= current_hikey){
734 	      success = TRUE;
735 	    }
736 	  }
737 	}else{
738 	  if(current_key <= current_hikey){
739 	    success = TRUE;
740 	  }
741 	}
742 
743 	retval = sscanf(str_lokey, "%lu", &current_lokey);
744 
745 	if(retval <= 0){
746 	  retval = ags_diatonic_scale_note_to_midi_key(str_lokey,
747 						       &current_lokey);
748 
749 	  if(retval > 0){
750 	    if(current_key >= current_lokey){
751 	      success = TRUE;
752 	    }else{
753 	      success = FALSE;
754 	    }
755 	  }else{
756 	    success = FALSE;
757 	  }
758 	}else{
759 	  if(current_key >= current_lokey){
760 	    success = TRUE;
761 	  }else{
762 	    success = FALSE;
763 	  }
764 	}
765 
766 	if(success){
767 	  hikey = current_hikey;
768 	  lokey = current_lokey;
769 
770 	  g_free(str_pitch_keycenter);
771 	  g_free(str_key);
772 
773 	  g_free(str_hikey);
774 	  g_free(str_lokey);
775 
776 	  break;
777 	}
778       }
779 
780       g_free(str_pitch_keycenter);
781       g_free(str_key);
782 
783       g_free(str_hikey);
784       g_free(str_lokey);
785 
786       /* iterate */
787       list = list->next;
788     }
789 
790     if(j == 0 &&
791        list != NULL){
792       audio_signal =
793 	start_audio_signal = ags_sound_resource_read_audio_signal(AGS_SOUND_RESOURCE(list->data),
794 								  output_soundcard,
795 								  -1);
796     }
797 
798     /* add audio signal as template to recycling */
799     audio_signal = g_list_nth(start_audio_signal,
800 			      j);
801 
802     if(audio_signal != NULL){
803       AgsAudioSignal *current_audio_signal;
804 
805       GList *start_stream, *stream;
806 
807       gchar *str_key, *str_pitch_keycenter;
808       gchar *str_lokey;
809 
810       guint samplerate;
811       guint buffer_size;
812       guint format;
813       guint loop_start, loop_end;
814       glong pitch_keycenter, current_pitch_keycenter;
815       guint x_offset;
816 
817       /* key center */
818       g_object_get(list->data,
819 		   "group", &group,
820 		   "region", &region,
821 		   NULL);
822 
823       key = lokey + i;
824       pitch_keycenter = 49;
825 
826       /* group */
827       str_pitch_keycenter = ags_sfz_group_lookup_control(group,
828 							 "pitch_keycenter");
829 
830       str_key = ags_sfz_group_lookup_control(group,
831 					     "key");
832 
833       if(str_pitch_keycenter != NULL){
834 	retval = sscanf(str_pitch_keycenter, "%lu", &current_pitch_keycenter);
835 
836 	if(retval > 0){
837 	  pitch_keycenter = current_pitch_keycenter;
838 	}else{
839 	  retval = ags_diatonic_scale_note_to_midi_key(str_pitch_keycenter,
840 						       &current_key);
841 
842 	  if(retval > 0){
843 	    pitch_keycenter = current_key;
844 	  }
845 	}
846       }else if(str_key != NULL){
847 	retval = sscanf(str_key, "%lu", &current_pitch_keycenter);
848 
849 	if(retval > 0){
850 	  pitch_keycenter = current_key;
851 	}else{
852 	  retval = ags_diatonic_scale_note_to_midi_key(str_key,
853 						       &current_key);
854 
855 	  if(retval > 0){
856 	    pitch_keycenter = current_key;
857 	  }
858 	}
859       }
860 
861       g_free(str_pitch_keycenter);
862       g_free(str_key);
863 
864       /* region */
865       str_pitch_keycenter = ags_sfz_region_lookup_control(region,
866 							  "pitch_keycenter");
867 
868       str_key = ags_sfz_region_lookup_control(region,
869 					      "key");
870 
871       if(str_pitch_keycenter != NULL){
872 	retval = sscanf(str_pitch_keycenter, "%lu", &current_pitch_keycenter);
873 
874 	if(retval > 0){
875 	  pitch_keycenter = current_pitch_keycenter;
876 	}else{
877 	  retval = ags_diatonic_scale_note_to_midi_key(str_pitch_keycenter,
878 						       &current_key);
879 
880 	  if(retval > 0){
881 	    pitch_keycenter = current_key;
882 	  }
883 	}
884       }else if(str_key != NULL){
885 	retval = sscanf(str_key, "%lu", &current_pitch_keycenter);
886 
887 	if(retval > 0){
888 	  pitch_keycenter = current_key;
889 	}else{
890 	  retval = ags_diatonic_scale_note_to_midi_key(str_key,
891 						       &current_key);
892 
893 	  if(retval > 0){
894 	    pitch_keycenter = current_key;
895 	  }
896 	}
897       }
898 
899       g_free(str_pitch_keycenter);
900       g_free(str_key);
901 
902       /* loop start/end */
903       g_object_get(audio_signal->data,
904 		   "samplerate", &samplerate,
905 		   "buffer-size", &buffer_size,
906 		   "format", &format,
907 		   "loop-start", &loop_start,
908 		   "loop-end", &loop_end,
909 		   NULL);
910 
911       /* create audio signal */
912       current_audio_signal = ags_audio_signal_new(output_soundcard,
913 						  (GObject *) first_recycling,
914 						  NULL);
915       current_audio_signal->flags |= AGS_AUDIO_SIGNAL_TEMPLATE;
916 
917       g_object_set(current_audio_signal,
918 		   "loop-start", loop_start,
919 		   "loop-end", loop_end,
920 		   NULL);
921 
922       ags_audio_signal_duplicate_stream(current_audio_signal,
923 					audio_signal->data);
924 
925       /* pitch */
926       stream =
927 	start_stream = current_audio_signal->stream;
928 
929       x_offset = 0;
930 
931       key -= lokey;
932 
933       while(stream != NULL){
934 	switch(format){
935 	case AGS_SOUNDCARD_SIGNED_8_BIT:
936 	{
937 	  ags_filter_util_pitch_s8((gint8 *) stream->data,
938 				   buffer_size,
939 				   samplerate,
940 				   pitch_keycenter - 48.0,
941 				   ((gdouble) key - (gdouble) pitch_keycenter) * 100.0);
942 	}
943 	break;
944 	case AGS_SOUNDCARD_SIGNED_16_BIT:
945 	{
946 	  ags_filter_util_pitch_s16((gint16 *) stream->data,
947 				    buffer_size,
948 				    samplerate,
949 				    pitch_keycenter - 48.0,
950 				    ((gdouble) key - (gdouble) pitch_keycenter) * 100.0);
951 	}
952 	break;
953 	case AGS_SOUNDCARD_SIGNED_24_BIT:
954 	{
955 	  ags_filter_util_pitch_s24((gint32 *) stream->data,
956 				    buffer_size,
957 				    samplerate,
958 				    pitch_keycenter - 48.0,
959 				    ((gdouble) key - (gdouble) pitch_keycenter) * 100.0);
960 	}
961 	break;
962 	case AGS_SOUNDCARD_SIGNED_32_BIT:
963 	{
964 	  ags_filter_util_pitch_s32((gint32 *) stream->data,
965 				    buffer_size,
966 				    samplerate,
967 				    pitch_keycenter - 48.0,
968 				    ((gdouble) key - (gdouble) pitch_keycenter) * 100.0);
969 	}
970 	break;
971 	case AGS_SOUNDCARD_SIGNED_64_BIT:
972 	{
973 	  ags_filter_util_pitch_s64((gint64 *) stream->data,
974 				    buffer_size,
975 				    samplerate,
976 				    pitch_keycenter - 48.0,
977 				    ((gdouble) key - (gdouble) pitch_keycenter) * 100.0);
978 	}
979 	break;
980 	case AGS_SOUNDCARD_FLOAT:
981 	{
982 	  ags_filter_util_pitch_float((gfloat *) stream->data,
983 				      buffer_size,
984 				      samplerate,
985 				      pitch_keycenter - 48.0,
986 				      ((gdouble) key - (gdouble) pitch_keycenter) * 100.0);
987 	}
988 	break;
989 	case AGS_SOUNDCARD_DOUBLE:
990 	{
991 	  ags_filter_util_pitch_double((gdouble *) stream->data,
992 				       buffer_size,
993 				       samplerate,
994 				       pitch_keycenter - 48.0,
995 				       ((gdouble) key - (gdouble) pitch_keycenter) * 100.0);
996 	}
997 	break;
998 	case AGS_SOUNDCARD_COMPLEX:
999 	{
1000 	  ags_filter_util_pitch_complex((AgsComplex *) stream->data,
1001 					buffer_size,
1002 					samplerate,
1003 					pitch_keycenter - 48.0,
1004 					((gdouble) key - (gdouble) pitch_keycenter) * 100.0);
1005 	}
1006 	break;
1007 	}
1008 
1009 	/* iterate */
1010 	x_offset += buffer_size;
1011 
1012 	stream = stream->next;
1013       }
1014 
1015       /* add audio signal */
1016       ags_recycling_add_audio_signal(first_recycling,
1017 				     current_audio_signal);
1018     }else{
1019       g_message("SFZ audio signal not found");
1020     }
1021 
1022     g_object_unref(first_recycling);
1023 
1024     /* iterate */
1025     if(j + 1 < j_stop){
1026       j++;
1027     }else{
1028       g_list_free_full(start_audio_signal,
1029 		       g_object_unref);
1030 
1031       audio_signal =
1032 	start_audio_signal = NULL;
1033 
1034       i++;
1035       j = 0;
1036 
1037       list = list->next;
1038     }
1039 
1040     next_input = ags_channel_next(input);
1041 
1042     g_object_unref(input);
1043 
1044     input = next_input;
1045   }
1046 
1047   g_object_unref(output_soundcard);
1048 
1049   g_list_free_full(start_list,
1050 		   g_object_unref);
1051 }
1052 
1053 /**
1054  * ags_open_sfz_file_new:
1055  * @audio: the #AgsAudio
1056  * @sfz_file: the #AgsSFZFile or %NULL
1057  * @filename: the Soundfont2 file
1058  * @start_pad: the pad start
1059  *
1060  * Creates an #AgsOpenSFZFile.
1061  *
1062  * Returns: an new #AgsOpenSFZFile.
1063  *
1064  * Since: 3.4.0
1065  */
1066 AgsOpenSFZFile*
ags_open_sfz_file_new(AgsAudio * audio,AgsSFZFile * sfz_file,gchar * filename,guint start_pad)1067 ags_open_sfz_file_new(AgsAudio *audio,
1068 		      AgsSFZFile *sfz_file,
1069 		      gchar *filename,
1070 		      guint start_pad)
1071 {
1072   AgsOpenSFZFile *open_sfz_file;
1073 
1074   open_sfz_file = (AgsOpenSFZFile *) g_object_new(AGS_TYPE_OPEN_SFZ_FILE,
1075 						  "audio", audio,
1076 						  "sfz-file", sfz_file,
1077 						  "filename", filename,
1078 						  "start-pad", start_pad,
1079 						  NULL);
1080 
1081   return(open_sfz_file);
1082 }
1083