1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2021 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/X/machine/ags_pitch_sampler.h>
21 #include <ags/X/machine/ags_pitch_sampler_callbacks.h>
22 
23 #include <ags/X/ags_ui_provider.h>
24 #include <ags/X/ags_window.h>
25 #include <ags/X/ags_navigation.h>
26 
27 #include <math.h>
28 
29 #include <ags/i18n.h>
30 
31 void ags_pitch_sampler_class_init(AgsPitchSamplerClass *pitch_sampler);
32 void ags_pitch_sampler_connectable_interface_init(AgsConnectableInterface *connectable);
33 void ags_pitch_sampler_init(AgsPitchSampler *pitch_sampler);
34 void ags_pitch_sampler_finalize(GObject *gobject);
35 
36 void ags_pitch_sampler_connect(AgsConnectable *connectable);
37 void ags_pitch_sampler_disconnect(AgsConnectable *connectable);
38 
39 void ags_pitch_sampler_resize_audio_channels(AgsMachine *machine,
40 					     guint audio_channels, guint audio_channels_old,
41 					     gpointer data);
42 void ags_pitch_sampler_resize_pads(AgsMachine *machine, GType type,
43 				   guint pads, guint pads_old,
44 				   gpointer data);
45 
46 void ags_pitch_sampler_map_recall(AgsMachine *machine);
47 void ags_pitch_sampler_output_map_recall(AgsPitchSampler *pitch_sampler,
48 					 guint audio_channel_start,
49 					 guint output_pad_start);
50 void ags_pitch_sampler_input_map_recall(AgsPitchSampler *pitch_sampler,
51 					guint audio_channel_start,
52 					guint input_pad_start);
53 
54 /**
55  * SECTION:ags_pitch_sampler
56  * @short_description: pitch_sampler notation
57  * @title: AgsPitchSampler
58  * @section_id:
59  * @include: ags/X/machine/ags_pitch_sampler.h
60  *
61  * The #AgsPitchSampler is a composite widget to act as soundfont2 notation player.
62  */
63 
64 static gpointer ags_pitch_sampler_parent_class = NULL;
65 static AgsConnectableInterface *ags_pitch_sampler_parent_connectable_interface;
66 
67 GHashTable *ags_pitch_sampler_sfz_loader_completed = NULL;
68 
69 GType
ags_pitch_sampler_get_type(void)70 ags_pitch_sampler_get_type(void)
71 {
72   static volatile gsize g_define_type_id__volatile = 0;
73 
74   if(g_once_init_enter (&g_define_type_id__volatile)){
75     GType ags_type_pitch_sampler = 0;
76 
77     static const GTypeInfo ags_pitch_sampler_info = {
78       sizeof(AgsPitchSamplerClass),
79       NULL, /* base_init */
80       NULL, /* base_finalize */
81       (GClassInitFunc) ags_pitch_sampler_class_init,
82       NULL, /* class_finalize */
83       NULL, /* class_data */
84       sizeof(AgsPitchSampler),
85       0,    /* n_preallocs */
86       (GInstanceInitFunc) ags_pitch_sampler_init,
87     };
88 
89     static const GInterfaceInfo ags_connectable_interface_info = {
90       (GInterfaceInitFunc) ags_pitch_sampler_connectable_interface_init,
91       NULL, /* interface_finalize */
92       NULL, /* interface_data */
93     };
94 
95     ags_type_pitch_sampler = g_type_register_static(AGS_TYPE_MACHINE,
96 						    "AgsPitchSampler", &ags_pitch_sampler_info,
97 						    0);
98 
99     g_type_add_interface_static(ags_type_pitch_sampler,
100 				AGS_TYPE_CONNECTABLE,
101 				&ags_connectable_interface_info);
102 
103     g_once_init_leave(&g_define_type_id__volatile, ags_type_pitch_sampler);
104   }
105 
106   return g_define_type_id__volatile;
107 }
108 
109 void
ags_pitch_sampler_class_init(AgsPitchSamplerClass * pitch_sampler)110 ags_pitch_sampler_class_init(AgsPitchSamplerClass *pitch_sampler)
111 {
112   GObjectClass *gobject;
113   AgsMachineClass *machine;
114 
115   ags_pitch_sampler_parent_class = g_type_class_peek_parent(pitch_sampler);
116 
117   /* GObjectClass */
118   gobject = (GObjectClass *) pitch_sampler;
119 
120   gobject->finalize = ags_pitch_sampler_finalize;
121 
122   /* AgsMachineClass */
123   machine = (AgsMachineClass *) pitch_sampler;
124 
125   machine->map_recall = ags_pitch_sampler_map_recall;
126 }
127 
128 void
ags_pitch_sampler_connectable_interface_init(AgsConnectableInterface * connectable)129 ags_pitch_sampler_connectable_interface_init(AgsConnectableInterface *connectable)
130 {
131   ags_pitch_sampler_parent_connectable_interface = g_type_interface_peek_parent(connectable);
132 
133   connectable->connect = ags_pitch_sampler_connect;
134   connectable->disconnect = ags_pitch_sampler_disconnect;
135 }
136 
137 void
ags_pitch_sampler_init(AgsPitchSampler * pitch_sampler)138 ags_pitch_sampler_init(AgsPitchSampler *pitch_sampler)
139 {
140   GtkExpander *expander;
141   GtkBox *vbox;
142   AgsPitchSamplerFile *file;
143   GtkBox *hbox;
144   GtkBox *control_vbox;
145   GtkBox *filename_hbox;
146   GtkBox *synth_generator_vbox;
147   GtkBox *pitch_hbox;
148   GtkBox *base_note_hbox;
149   GtkBox *key_count_hbox;
150   GtkBox *aliase_hbox;
151   GtkGrid *lfo_grid;
152   GtkBox *volume_hbox;
153   GtkFrame *frame;
154   GtkLabel *label;
155 
156   GtkAdjustment *adjustment;
157 
158   AgsAudio *audio;
159   AgsSFZSynthGenerator *sfz_synth_generator;
160 
161   AgsApplicationContext *application_context;
162 
163   gdouble gui_scale_factor;
164   gdouble page, step;
165 
166   application_context = ags_application_context_get_instance();
167 
168   /* scale factor */
169   gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
170 
171   g_signal_connect_after((GObject *) pitch_sampler, "parent_set",
172 			 G_CALLBACK(ags_pitch_sampler_parent_set_callback), (gpointer) pitch_sampler);
173 
174   audio = AGS_MACHINE(pitch_sampler)->audio;
175   ags_audio_set_flags(audio, (AGS_AUDIO_SYNC |
176 			      AGS_AUDIO_ASYNC |
177 			      AGS_AUDIO_OUTPUT_HAS_RECYCLING |
178 			      AGS_AUDIO_INPUT_HAS_RECYCLING |
179 			      AGS_AUDIO_INPUT_HAS_FILE));
180   ags_audio_set_ability_flags(audio, (AGS_SOUND_ABILITY_PLAYBACK |
181 				      AGS_SOUND_ABILITY_NOTATION));
182   ags_audio_set_behaviour_flags(audio, (AGS_SOUND_BEHAVIOUR_REVERSE_MAPPING |
183 					AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_INPUT));
184 
185   g_object_set(audio,
186 	       "min-audio-channels", 1,
187 	       "min-output-pads", 1,
188 	       "min-input-pads", 1,
189 	       "max-input-pads", 128,
190 	       "audio-start-mapping", 0,
191 	       "audio-end-mapping", 128,
192 	       "midi-start-mapping", 0,
193 	       "midi-end-mapping", 128,
194 	       NULL);
195 
196   sfz_synth_generator = ags_sfz_synth_generator_new();
197 
198   ags_audio_add_sfz_synth_generator(audio,
199 				    (GObject *) sfz_synth_generator);
200 
201   AGS_MACHINE(pitch_sampler)->flags |= (AGS_MACHINE_IS_SYNTHESIZER |
202 					AGS_MACHINE_REVERSE_NOTATION);
203   AGS_MACHINE(pitch_sampler)->file_input_flags |= AGS_MACHINE_ACCEPT_SFZ;
204 
205   AGS_MACHINE(pitch_sampler)->input_pad_type = G_TYPE_NONE;
206   AGS_MACHINE(pitch_sampler)->input_line_type = G_TYPE_NONE;
207   AGS_MACHINE(pitch_sampler)->output_pad_type = G_TYPE_NONE;
208   AGS_MACHINE(pitch_sampler)->output_line_type = G_TYPE_NONE;
209 
210   /* context menu */
211   ags_machine_popup_add_connection_options((AgsMachine *) pitch_sampler,
212   					   (AGS_MACHINE_POPUP_MIDI_DIALOG));
213 
214   /* audio resize */
215   g_signal_connect_after(G_OBJECT(pitch_sampler), "resize-audio-channels",
216 			 G_CALLBACK(ags_pitch_sampler_resize_audio_channels), NULL);
217 
218   g_signal_connect_after(G_OBJECT(pitch_sampler), "resize-pads",
219 			 G_CALLBACK(ags_pitch_sampler_resize_pads), NULL);
220 
221   /* flags */
222   pitch_sampler->flags = 0;
223 
224   /* mapped IO */
225   pitch_sampler->mapped_input_pad = 0;
226   pitch_sampler->mapped_output_pad = 0;
227 
228   pitch_sampler->playback_play_container = ags_recall_container_new();
229   pitch_sampler->playback_recall_container = ags_recall_container_new();
230 
231   pitch_sampler->notation_play_container = ags_recall_container_new();
232   pitch_sampler->notation_recall_container = ags_recall_container_new();
233 
234   pitch_sampler->lfo_play_container = ags_recall_container_new();
235   pitch_sampler->lfo_recall_container = ags_recall_container_new();
236 
237   pitch_sampler->two_pass_aliase_play_container = ags_recall_container_new();
238   pitch_sampler->two_pass_aliase_recall_container = ags_recall_container_new();
239 
240   pitch_sampler->volume_play_container = ags_recall_container_new();
241   pitch_sampler->volume_recall_container = ags_recall_container_new();
242 
243   pitch_sampler->envelope_play_container = ags_recall_container_new();
244   pitch_sampler->envelope_recall_container = ags_recall_container_new();
245 
246   pitch_sampler->buffer_play_container = ags_recall_container_new();
247   pitch_sampler->buffer_recall_container = ags_recall_container_new();
248 
249   /* context menu */
250   ags_machine_popup_add_edit_options((AgsMachine *) pitch_sampler,
251 				     (AGS_MACHINE_POPUP_ENVELOPE));
252 
253   /* name and xml type */
254   pitch_sampler->name = NULL;
255   pitch_sampler->xml_type = "ags-pitch-sampler";
256 
257   /* audio container */
258   pitch_sampler->audio_container = NULL;
259 
260   /* create widgets */
261   vbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_VERTICAL,
262 				0);
263   gtk_container_add((GtkContainer *) (gtk_bin_get_child((GtkBin *) pitch_sampler)),
264 		    (GtkWidget *) vbox);
265 
266   /* hbox */
267   hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
268 				0);
269   gtk_box_pack_start(vbox,
270 		     (GtkWidget *) hbox,
271 		     FALSE, FALSE,
272 		     0);
273 
274   /* file */
275   expander = gtk_expander_new(i18n("file"));
276   gtk_box_pack_start(hbox,
277 		     (GtkWidget *) expander,
278 		     FALSE, FALSE,
279 		     0);
280 
281   pitch_sampler->file = (GtkBox *) gtk_box_new(GTK_ORIENTATION_VERTICAL,
282 					       0);
283   gtk_container_add((GtkContainer *) expander,
284 		    (GtkWidget *) pitch_sampler->file);
285 
286   /* add 1 sample */
287   file = ags_pitch_sampler_file_new();
288   ags_pitch_sampler_add_file(pitch_sampler,
289 			     file);
290 
291   /* control */
292   control_vbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_VERTICAL,
293 					0);
294   gtk_box_pack_start(hbox,
295 		     (GtkWidget *) control_vbox,
296 		     FALSE, FALSE,
297 		     0);
298 
299   /* filename */
300   filename_hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
301 					 0);
302   gtk_box_pack_start(control_vbox,
303 		     (GtkWidget *) filename_hbox,
304 		     FALSE, FALSE,
305 		     0);
306 
307   pitch_sampler->filename = (GtkEntry *) gtk_entry_new();
308   gtk_box_pack_start(filename_hbox,
309 		     (GtkWidget *) pitch_sampler->filename,
310 		     FALSE, FALSE,
311 		     0);
312 
313   pitch_sampler->open = (GtkButton *) gtk_button_new_from_icon_name("document-open",
314 								    GTK_ICON_SIZE_BUTTON);
315   gtk_box_pack_start(filename_hbox,
316 		     (GtkWidget *) pitch_sampler->open,
317 		     FALSE, FALSE,
318 		     0);
319 
320   pitch_sampler->sfz_loader = NULL;
321 
322   pitch_sampler->position = -1;
323 
324   pitch_sampler->loading = (GtkLabel *) gtk_label_new(i18n("loading ...  "));
325   gtk_box_pack_start(filename_hbox,
326 		     (GtkWidget *) pitch_sampler->loading,
327 		     FALSE, FALSE,
328 		     0);
329   gtk_widget_set_no_show_all((GtkWidget *) pitch_sampler->loading,
330 			     TRUE);
331   gtk_widget_hide((GtkWidget *) pitch_sampler->loading);
332 
333 
334   /* synth generator */
335   frame = (GtkFrame *) gtk_frame_new(i18n("synth generator"));
336   gtk_box_pack_start(hbox,
337 		     (GtkWidget *) frame,
338 		     FALSE, FALSE,
339 		     0);
340 
341   synth_generator_vbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_VERTICAL,
342 						0);
343   gtk_container_add((GtkContainer *) frame,
344 		    (GtkWidget *) synth_generator_vbox);
345 
346   pitch_sampler->enable_synth_generator = (GtkCheckButton *) gtk_check_button_new_with_label(i18n("enabled"));
347   gtk_box_pack_start(synth_generator_vbox,
348 		     (GtkWidget *) pitch_sampler->enable_synth_generator,
349 		     FALSE, FALSE,
350 		     0);
351 
352   /* pitch function */
353   pitch_hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
354 				      0);
355   gtk_box_pack_start(synth_generator_vbox,
356 		     (GtkWidget *) pitch_hbox,
357 		     FALSE, FALSE,
358 		     0);
359 
360   label = (GtkLabel *) gtk_label_new(i18n("pitch"));
361   gtk_box_pack_start(pitch_hbox,
362 		     (GtkWidget *) label,
363 		     FALSE, FALSE,
364 		     0);
365 
366   pitch_sampler->pitch_function = (GtkComboBox *) gtk_combo_box_text_new();
367 
368   gtk_combo_box_text_append_text((GtkComboBoxText *) pitch_sampler->pitch_function,
369 				 "ags-fast-pitch");
370 
371   gtk_combo_box_text_append_text((GtkComboBoxText *) pitch_sampler->pitch_function,
372 				 "ags-hq-pitch");
373 
374   gtk_combo_box_text_append_text((GtkComboBoxText *) pitch_sampler->pitch_function,
375 				 "fluid-no-interpolate");
376 
377   gtk_combo_box_text_append_text((GtkComboBoxText *) pitch_sampler->pitch_function,
378 				 "fluid-linear-interpolate");
379 
380   gtk_combo_box_text_append_text((GtkComboBoxText *) pitch_sampler->pitch_function,
381 				 "fluid-4th-order-interpolate");
382 
383   gtk_combo_box_text_append_text((GtkComboBoxText *) pitch_sampler->pitch_function,
384 				 "fluid-7th-order-interpolate");
385 
386   gtk_combo_box_set_active(pitch_sampler->pitch_function,
387 			   4);
388 
389   gtk_box_pack_start(pitch_hbox,
390 		     (GtkWidget *) pitch_sampler->pitch_function,
391 		     FALSE, FALSE,
392 		     0);
393 
394   /* base note */
395   base_note_hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
396 					  0);
397   gtk_box_pack_start(synth_generator_vbox,
398 		     (GtkWidget *) base_note_hbox,
399 		     FALSE, FALSE,
400 		     0);
401 
402   label = (GtkLabel *) gtk_label_new(i18n("lower"));
403   gtk_box_pack_start(base_note_hbox,
404 		     (GtkWidget *) label,
405 		     FALSE, FALSE,
406 		     0);
407 
408   pitch_sampler->lower = (GtkSpinButton *) gtk_spin_button_new_with_range(-70.0,
409 									  70.0,
410 									  1.0);
411   gtk_spin_button_set_digits(pitch_sampler->lower,
412 			     2);
413   gtk_spin_button_set_value(pitch_sampler->lower,
414 			    -48.0);
415   gtk_box_pack_start(base_note_hbox,
416 		     (GtkWidget *) pitch_sampler->lower,
417 		     FALSE, FALSE,
418 		     0);
419 
420   /* key count */
421   key_count_hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
422 					  0);
423   gtk_box_pack_start(synth_generator_vbox,
424 		     (GtkWidget *) key_count_hbox,
425 		     FALSE, FALSE,
426 		     0);
427 
428   label = (GtkLabel *) gtk_label_new(i18n("key count"));
429   gtk_box_pack_start(key_count_hbox,
430 		     (GtkWidget *) label,
431 		     FALSE, FALSE,
432 		     0);
433 
434   pitch_sampler->key_count = (GtkSpinButton *) gtk_spin_button_new_with_range(0.0,
435 									 128.0,
436 									 1.0);
437   gtk_spin_button_set_value(pitch_sampler->key_count,
438 			    78.0);
439   gtk_box_pack_start((GtkBox *) key_count_hbox,
440 		     (GtkWidget *) pitch_sampler->key_count,
441 		     FALSE, FALSE,
442 		     0);
443 
444   pitch_sampler->update = (GtkButton *) gtk_button_new_with_label(i18n("update"));
445   gtk_widget_set_valign((GtkWidget *) pitch_sampler->update,
446 			GTK_ALIGN_END);
447   gtk_box_pack_start(hbox,
448 		     (GtkWidget *) pitch_sampler->update,
449 		     FALSE, FALSE,
450 		     0);
451 
452   /* other controls */
453   /* aliase */
454   frame = (GtkFrame *) gtk_frame_new(i18n("aliase"));
455 
456   gtk_widget_set_valign((GtkWidget *) frame,
457 			GTK_ALIGN_FILL);
458   gtk_widget_set_halign((GtkWidget *) frame,
459 			GTK_ALIGN_FILL);
460 
461   gtk_box_pack_start(hbox,
462 		     (GtkWidget *) frame,
463 		     FALSE, FALSE,
464 		     0);
465 
466   aliase_hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
467 				       0);
468   gtk_container_add((GtkContainer *) frame,
469 		    (GtkWidget *) aliase_hbox);
470 
471   pitch_sampler->enable_aliase = (GtkCheckButton *) gtk_check_button_new_with_label(i18n("enabled"));
472   gtk_box_pack_start(aliase_hbox,
473 		     (GtkWidget *) pitch_sampler->enable_aliase,
474 		     FALSE, FALSE,
475 		     0);
476 
477   step = 2.0 * M_PI / 100.0;
478   page = 2.0 * M_PI / AGS_DIAL_DEFAULT_PRECISION;
479 
480   /* aliase a */
481   pitch_sampler->aliase_a_amount = (AgsDial *) ags_dial_new();
482 
483   adjustment = ags_dial_get_adjustment(pitch_sampler->aliase_a_amount);
484 
485   gtk_adjustment_set_step_increment(adjustment,
486 				    step);
487   gtk_adjustment_set_page_increment(adjustment,
488 				    page);
489 
490   gtk_adjustment_set_lower(adjustment,
491 			   0.0);
492   gtk_adjustment_set_upper(adjustment,
493 			   2.0 * M_PI);
494 
495   gtk_box_pack_start(aliase_hbox,
496 		     (GtkWidget *) pitch_sampler->aliase_a_amount,
497 		     FALSE, FALSE,
498 		     0);
499 
500   pitch_sampler->aliase_a_phase = (AgsDial *) ags_dial_new();
501 
502   adjustment = ags_dial_get_adjustment(pitch_sampler->aliase_a_phase);
503 
504   gtk_adjustment_set_step_increment(adjustment,
505 				    step);
506   gtk_adjustment_set_page_increment(adjustment,
507 				    page);
508 
509   gtk_adjustment_set_lower(adjustment,
510 			   0.0);
511   gtk_adjustment_set_upper(adjustment,
512 			   2.0 * M_PI);
513 
514   gtk_box_pack_start(aliase_hbox,
515 		     (GtkWidget *) pitch_sampler->aliase_a_phase,
516 		     FALSE, FALSE,
517 		     0);
518 
519   /* aliase b */
520   pitch_sampler->aliase_b_amount = (AgsDial *) ags_dial_new();
521 
522   adjustment = ags_dial_get_adjustment(pitch_sampler->aliase_b_amount);
523 
524   gtk_adjustment_set_step_increment(adjustment,
525 				    step);
526   gtk_adjustment_set_page_increment(adjustment,
527 				    page);
528 
529   gtk_adjustment_set_lower(adjustment,
530 			   0.0);
531   gtk_adjustment_set_upper(adjustment,
532 			   2.0 * M_PI);
533 
534   gtk_box_pack_start(aliase_hbox,
535 		     (GtkWidget *) pitch_sampler->aliase_b_amount,
536 		     FALSE, FALSE,
537 		     0);
538 
539   pitch_sampler->aliase_b_phase = (AgsDial *) ags_dial_new();
540 
541   adjustment = ags_dial_get_adjustment(pitch_sampler->aliase_b_phase);
542 
543   gtk_adjustment_set_step_increment(adjustment,
544 				    step);
545   gtk_adjustment_set_page_increment(adjustment,
546 				    page);
547 
548   gtk_adjustment_set_lower(adjustment,
549 			   0.0);
550   gtk_adjustment_set_upper(adjustment,
551 			   2.0 * M_PI);
552 
553   gtk_box_pack_start(aliase_hbox,
554 		     (GtkWidget *) pitch_sampler->aliase_b_phase,
555 		     FALSE, FALSE,
556 		     0);
557 
558   /* volume */
559   frame = (GtkFrame *) gtk_frame_new(i18n("volume"));
560 
561   gtk_widget_set_valign((GtkWidget *) frame,
562 			GTK_ALIGN_FILL);
563   gtk_widget_set_halign((GtkWidget *) frame,
564 			GTK_ALIGN_FILL);
565 
566   gtk_box_pack_start(hbox,
567 		     (GtkWidget *) frame,
568 		     FALSE, FALSE,
569 		     0);
570 
571   volume_hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
572 				       0);
573   gtk_container_add((GtkContainer *) frame,
574 		    (GtkWidget *) volume_hbox);
575 
576   pitch_sampler->volume = (GtkScale *) gtk_scale_new_with_range(GTK_ORIENTATION_VERTICAL,
577 							   0.0,
578 							   2.0,
579 							   0.025);
580 
581   gtk_widget_set_size_request(pitch_sampler->volume,
582 			      gui_scale_factor * 16, gui_scale_factor * 100);
583 
584   gtk_box_pack_start(volume_hbox,
585 		     (GtkWidget *) pitch_sampler->volume,
586 		     FALSE, FALSE,
587 		     0);
588 
589   gtk_scale_set_digits(pitch_sampler->volume,
590 		       3);
591 
592   gtk_range_set_increments(GTK_RANGE(pitch_sampler->volume),
593 			   0.025, 0.1);
594   gtk_range_set_value(GTK_RANGE(pitch_sampler->volume),
595 		      1.0);
596   gtk_range_set_inverted(GTK_RANGE(pitch_sampler->volume),
597 			 TRUE);
598 
599   /* LFO grid */
600   lfo_grid = (GtkGrid *) gtk_grid_new();
601   gtk_box_pack_start(hbox,
602 		     (GtkWidget *) lfo_grid,
603 		     FALSE, FALSE,
604 		     0);
605 
606   pitch_sampler->enable_lfo = gtk_check_button_new_with_label(i18n("enable LFO"));
607 
608   gtk_widget_set_valign((GtkWidget *) pitch_sampler->enable_lfo,
609 			GTK_ALIGN_FILL);
610   gtk_widget_set_halign((GtkWidget *) pitch_sampler->enable_lfo,
611 			GTK_ALIGN_FILL);
612 
613   gtk_grid_attach(lfo_grid,
614 		  (GtkWidget *) pitch_sampler->enable_lfo,
615 		  0, 0,
616 		  1, 1);
617 
618   label = gtk_label_new(i18n("LFO freq"));
619 
620   gtk_widget_set_valign((GtkWidget *) label,
621 			GTK_ALIGN_FILL);
622   gtk_widget_set_halign((GtkWidget *) label,
623 			GTK_ALIGN_FILL);
624 
625   gtk_grid_attach(lfo_grid,
626 		   (GtkWidget *) label,
627 		   1, 0,
628 		   1, 1);
629 
630   pitch_sampler->lfo_freq = (GtkSpinButton *) gtk_spin_button_new_with_range(AGS_PITCH_SAMPLER_LFO_FREQ_MIN,
631 									     AGS_PITCH_SAMPLER_LFO_FREQ_MAX,
632 									     0.001);
633   gtk_spin_button_set_digits(pitch_sampler->lfo_freq,
634 			     3);
635   gtk_spin_button_set_value(pitch_sampler->lfo_freq, AGS_PITCH_SAMPLER_DEFAULT_LFO_FREQ);
636 
637   gtk_widget_set_valign((GtkWidget *) pitch_sampler->lfo_freq,
638 			GTK_ALIGN_FILL);
639   gtk_widget_set_halign((GtkWidget *) pitch_sampler->lfo_freq,
640 			GTK_ALIGN_FILL);
641 
642   gtk_grid_attach(lfo_grid,
643 		   (GtkWidget *) pitch_sampler->lfo_freq,
644 		   2, 0,
645 		   1, 1);
646 
647   label = gtk_label_new(i18n("LFO phase"));
648 
649   gtk_widget_set_valign((GtkWidget *) label,
650 			GTK_ALIGN_FILL);
651   gtk_widget_set_halign((GtkWidget *) label,
652 			GTK_ALIGN_FILL);
653 
654   gtk_grid_attach(lfo_grid,
655 		   (GtkWidget *) label,
656 		   1, 1,
657 		   1, 1);
658 
659   pitch_sampler->lfo_phase = (GtkSpinButton *) gtk_spin_button_new_with_range(0.0,
660 									      G_MAXDOUBLE,
661 									      1.0);
662   gtk_spin_button_set_value(pitch_sampler->lfo_phase, 0.0);
663 
664   gtk_widget_set_valign((GtkWidget *) pitch_sampler->lfo_phase,
665 			GTK_ALIGN_FILL);
666   gtk_widget_set_halign((GtkWidget *) pitch_sampler->lfo_phase,
667 			GTK_ALIGN_FILL);
668 
669   gtk_grid_attach(lfo_grid,
670 		   (GtkWidget *) pitch_sampler->lfo_phase,
671 		   2, 1,
672 		   1, 1);
673 
674   label = gtk_label_new(i18n("LFO depth"));
675 
676   gtk_widget_set_valign((GtkWidget *) label,
677 			GTK_ALIGN_FILL);
678   gtk_widget_set_halign((GtkWidget *) label,
679 			GTK_ALIGN_FILL);
680 
681   gtk_grid_attach(lfo_grid,
682 		   (GtkWidget *) label,
683 		   1, 2,
684 		   1, 1);
685 
686   pitch_sampler->lfo_depth = (GtkSpinButton *) gtk_spin_button_new_with_range(-1200.0,
687 									      1200.0,
688 									      1.0);
689   gtk_spin_button_set_digits(pitch_sampler->lfo_depth,
690 			     3);
691   gtk_spin_button_set_value(pitch_sampler->lfo_depth, 0.0);
692 
693   gtk_widget_set_valign((GtkWidget *) pitch_sampler->lfo_depth,
694 			GTK_ALIGN_FILL);
695   gtk_widget_set_halign((GtkWidget *) pitch_sampler->lfo_depth,
696 			GTK_ALIGN_FILL);
697 
698   gtk_grid_attach(lfo_grid,
699 		   (GtkWidget *) pitch_sampler->lfo_depth,
700 		   2, 2,
701 		   1, 1);
702 
703   label = gtk_label_new(i18n("LFO tuning"));
704 
705   gtk_widget_set_valign((GtkWidget *) label,
706 			GTK_ALIGN_FILL);
707   gtk_widget_set_halign((GtkWidget *) label,
708 			GTK_ALIGN_FILL);
709 
710   gtk_grid_attach(lfo_grid,
711 		   (GtkWidget *) label,
712 		   1, 3,
713 		   1, 1);
714 
715   pitch_sampler->lfo_tuning = (GtkSpinButton *) gtk_spin_button_new_with_range(-1200.0,
716 									       1200.0,
717 									       1.0);
718   gtk_spin_button_set_digits(pitch_sampler->lfo_tuning,
719 			     2);
720   gtk_spin_button_set_value(pitch_sampler->lfo_tuning, 1.0);
721 
722   gtk_widget_set_valign((GtkWidget *) pitch_sampler->lfo_tuning,
723 			GTK_ALIGN_FILL);
724   gtk_widget_set_halign((GtkWidget *) pitch_sampler->lfo_tuning,
725 			GTK_ALIGN_FILL);
726 
727   gtk_grid_attach(lfo_grid,
728 		   (GtkWidget *) pitch_sampler->lfo_tuning,
729 		   2, 3,
730 		   1, 1);
731 
732   /* dialog */
733   pitch_sampler->open_dialog = NULL;
734 
735   /* SFZ loader */
736   if(ags_pitch_sampler_sfz_loader_completed == NULL){
737     ags_pitch_sampler_sfz_loader_completed = g_hash_table_new_full(g_direct_hash, g_direct_equal,
738 								   NULL,
739 								   NULL);
740   }
741 
742   g_hash_table_insert(ags_pitch_sampler_sfz_loader_completed,
743 		      pitch_sampler, ags_pitch_sampler_sfz_loader_completed_timeout);
744   g_timeout_add(1000 / 4, (GSourceFunc) ags_pitch_sampler_sfz_loader_completed_timeout, (gpointer) pitch_sampler);
745 }
746 
747 void
ags_pitch_sampler_finalize(GObject * gobject)748 ags_pitch_sampler_finalize(GObject *gobject)
749 {
750   g_hash_table_remove(ags_pitch_sampler_sfz_loader_completed,
751 		      gobject);
752 
753   /* call parent */
754   G_OBJECT_CLASS(ags_pitch_sampler_parent_class)->finalize(gobject);
755 }
756 
757 void
ags_pitch_sampler_connect(AgsConnectable * connectable)758 ags_pitch_sampler_connect(AgsConnectable *connectable)
759 {
760   AgsPitchSampler *pitch_sampler;
761 
762   GList *start_list, *list;
763 
764   if((AGS_MACHINE_CONNECTED & (AGS_MACHINE(connectable)->flags)) != 0){
765     return;
766   }
767 
768   ags_pitch_sampler_parent_connectable_interface->connect(connectable);
769 
770   pitch_sampler = AGS_PITCH_SAMPLER(connectable);
771 
772   list =
773     start_list = gtk_container_get_children((GtkContainer *) pitch_sampler->file);
774 
775   while(list != NULL){
776     GList *child_start;
777 
778     child_start = gtk_container_get_children(GTK_CONTAINER(list->data));
779 
780     ags_connectable_connect(AGS_CONNECTABLE(child_start->next->data));
781 
782     list = list->next;
783   }
784 
785   g_list_free(start_list);
786 
787   /* filename */
788   g_signal_connect(pitch_sampler->open, "clicked",
789 		   G_CALLBACK(ags_pitch_sampler_open_callback), pitch_sampler);
790 
791   /* update */
792   g_signal_connect(pitch_sampler->update, "clicked",
793 		   G_CALLBACK(ags_pitch_sampler_update_callback), pitch_sampler);
794 
795   /* LFO */
796   g_signal_connect_after((GObject *) pitch_sampler->enable_lfo, "toggled",
797 			 G_CALLBACK(ags_pitch_sampler_enable_lfo_callback), pitch_sampler);
798 
799   g_signal_connect_after((GObject *) pitch_sampler->lfo_freq, "value-changed",
800 			 G_CALLBACK(ags_pitch_sampler_lfo_freq_callback), (gpointer) pitch_sampler);
801 
802   g_signal_connect_after((GObject *) pitch_sampler->lfo_phase, "value-changed",
803 			 G_CALLBACK(ags_pitch_sampler_lfo_phase_callback), (gpointer) pitch_sampler);
804 
805   g_signal_connect_after((GObject *) pitch_sampler->lfo_depth, "value-changed",
806 			 G_CALLBACK(ags_pitch_sampler_lfo_depth_callback), (gpointer) pitch_sampler);
807 
808   g_signal_connect_after((GObject *) pitch_sampler->lfo_tuning, "value-changed",
809 			 G_CALLBACK(ags_pitch_sampler_lfo_tuning_callback), (gpointer) pitch_sampler);
810 
811   g_signal_connect((GObject *) pitch_sampler->enable_aliase, "clicked",
812 		   G_CALLBACK(ags_pitch_sampler_enable_aliase_callback), (gpointer) pitch_sampler);
813 
814   g_signal_connect((GObject *) pitch_sampler->aliase_a_amount, "value-changed",
815 		   G_CALLBACK(ags_pitch_sampler_aliase_a_amount_callback), (gpointer) pitch_sampler);
816 
817   g_signal_connect((GObject *) pitch_sampler->aliase_a_phase, "value-changed",
818 		   G_CALLBACK(ags_pitch_sampler_aliase_a_phase_callback), (gpointer) pitch_sampler);
819 
820   g_signal_connect((GObject *) pitch_sampler->aliase_b_amount, "value-changed",
821 		   G_CALLBACK(ags_pitch_sampler_aliase_b_amount_callback), (gpointer) pitch_sampler);
822 
823   g_signal_connect((GObject *) pitch_sampler->aliase_b_phase, "value-changed",
824 		   G_CALLBACK(ags_pitch_sampler_aliase_b_phase_callback), (gpointer) pitch_sampler);
825 
826   g_signal_connect((GObject *) pitch_sampler->volume, "value-changed",
827 		   G_CALLBACK(ags_pitch_sampler_volume_callback), (gpointer) pitch_sampler);
828 }
829 
830 void
ags_pitch_sampler_disconnect(AgsConnectable * connectable)831 ags_pitch_sampler_disconnect(AgsConnectable *connectable)
832 {
833   AgsPitchSampler *pitch_sampler;
834 
835   GList *start_list, *list;
836 
837   if((AGS_MACHINE_CONNECTED & (AGS_MACHINE(connectable)->flags)) == 0){
838     return;
839   }
840 
841   ags_pitch_sampler_parent_connectable_interface->disconnect(connectable);
842 
843   pitch_sampler = AGS_PITCH_SAMPLER(connectable);
844 
845   list =
846     start_list = gtk_container_get_children((GtkContainer *) pitch_sampler->file);
847 
848   while(list != NULL){
849     GList *child_start;
850 
851     child_start = gtk_container_get_children(GTK_CONTAINER(list->data));
852 
853     ags_connectable_disconnect(AGS_CONNECTABLE(child_start->next->data));
854 
855     g_list_free(child_start);
856 
857     list = list->next;
858   }
859 
860   g_list_free(start_list);
861 
862   /* filename */
863   g_object_disconnect(pitch_sampler->open,
864 		      "any_signal::clicked",
865 		      G_CALLBACK(ags_pitch_sampler_open_callback),
866 		      pitch_sampler,
867 		      NULL);
868 
869   /* update */
870   g_object_disconnect(pitch_sampler->update,
871 		      "any_signal::clicked",
872 		      G_CALLBACK(ags_pitch_sampler_update_callback),
873 		      pitch_sampler,
874 		      NULL);
875 
876   /* LFO */
877   g_object_disconnect((GObject *) pitch_sampler->enable_lfo,
878 		      "any_signal::toggled",
879 		      G_CALLBACK(ags_pitch_sampler_enable_lfo_callback),
880 		      pitch_sampler,
881 		      NULL);
882 
883   g_object_disconnect((GObject *) pitch_sampler->lfo_freq,
884 		      "any_signal::value-changed",
885 		      G_CALLBACK(ags_pitch_sampler_lfo_freq_callback),
886 		      (gpointer) pitch_sampler,
887 		      NULL);
888 
889   g_object_disconnect((GObject *) pitch_sampler->lfo_phase,
890 		      "any_signal::value-changed",
891 		      G_CALLBACK(ags_pitch_sampler_lfo_phase_callback),
892 		      (gpointer) pitch_sampler,
893 		      NULL);
894 
895   g_object_disconnect((GObject *) pitch_sampler->lfo_depth,
896 		      "any_signal::value-changed",
897 		      G_CALLBACK(ags_pitch_sampler_lfo_depth_callback),
898 		      (gpointer) pitch_sampler,
899 		      NULL);
900 
901   g_object_disconnect((GObject *) pitch_sampler->lfo_tuning,
902 		      "any_signal::value-changed",
903 		      G_CALLBACK(ags_pitch_sampler_lfo_tuning_callback),
904 		      (gpointer) pitch_sampler,
905 		      NULL);
906 
907   /* aliase */
908   g_object_disconnect((GObject *) pitch_sampler->enable_aliase,
909 		      "any_signal::clicked",
910 		      G_CALLBACK(ags_pitch_sampler_enable_aliase_callback),
911 		      (gpointer) pitch_sampler,
912 		      NULL);
913 
914   g_object_disconnect((GObject *) pitch_sampler->aliase_a_amount,
915 		      "any_signal::value-changed",
916 		      G_CALLBACK(ags_pitch_sampler_aliase_a_amount_callback),
917 		      (gpointer) pitch_sampler,
918 		      NULL);
919 
920   g_object_disconnect((GObject *) pitch_sampler->aliase_a_phase,
921 		      "any_signal::value-changed",
922 		      G_CALLBACK(ags_pitch_sampler_aliase_a_phase_callback),
923 		      (gpointer) pitch_sampler,
924 		      NULL);
925 
926   g_object_disconnect((GObject *) pitch_sampler->aliase_b_amount,
927 		      "any_signal::value-changed",
928 		      G_CALLBACK(ags_pitch_sampler_aliase_b_amount_callback),
929 		      (gpointer) pitch_sampler,
930 		      NULL);
931 
932   g_object_disconnect((GObject *) pitch_sampler->aliase_b_phase,
933 		      "any_signal::value-changed",
934 		      G_CALLBACK(ags_pitch_sampler_aliase_b_phase_callback),
935 		      (gpointer) pitch_sampler,
936 		      NULL);
937 
938   /* volume */
939   g_object_disconnect((GObject *) pitch_sampler->volume,
940 		      "any_signal::value-changed",
941 		      G_CALLBACK(ags_pitch_sampler_volume_callback),
942 		      (gpointer) pitch_sampler,
943 		      NULL);
944 }
945 
946 void
ags_pitch_sampler_resize_audio_channels(AgsMachine * machine,guint audio_channels,guint audio_channels_old,gpointer data)947 ags_pitch_sampler_resize_audio_channels(AgsMachine *machine,
948 					guint audio_channels, guint audio_channels_old,
949 					gpointer data)
950 {
951   AgsPitchSampler *pitch_sampler;
952 
953   pitch_sampler = (AgsPitchSampler *) machine;
954 
955   /*  */
956   if(audio_channels > audio_channels_old){
957     /* recall */
958     if((AGS_MACHINE_MAPPED_RECALL & (machine->flags)) != 0){
959       ags_pitch_sampler_input_map_recall(pitch_sampler,
960 					 audio_channels_old,
961 					 0);
962 
963       ags_pitch_sampler_output_map_recall(pitch_sampler,
964 					  audio_channels_old,
965 					  0);
966     }
967   }
968 }
969 
970 void
ags_pitch_sampler_resize_pads(AgsMachine * machine,GType channel_type,guint pads,guint pads_old,gpointer data)971 ags_pitch_sampler_resize_pads(AgsMachine *machine, GType channel_type,
972 			      guint pads, guint pads_old,
973 			      gpointer data)
974 {
975   AgsPitchSampler *pitch_sampler;
976 
977   gboolean grow;
978 
979   pitch_sampler = (AgsPitchSampler *) machine;
980 
981   /* check grow */
982   if(pads_old < pads){
983     grow = TRUE;
984   }else{
985     grow = FALSE;
986   }
987 
988   if(g_type_is_a(channel_type, AGS_TYPE_INPUT)){
989     if(grow){
990       /* depending on destination */
991       ags_pitch_sampler_input_map_recall(pitch_sampler,
992 					 0,
993 					 pads_old);
994     }else{
995       pitch_sampler->mapped_input_pad = pads;
996     }
997   }else if(g_type_is_a(channel_type, AGS_TYPE_OUTPUT)){
998     if(grow){
999       /* depending on destination */
1000       ags_pitch_sampler_output_map_recall(pitch_sampler,
1001 					  0,
1002 					  pads_old);
1003     }else{
1004       pitch_sampler->mapped_output_pad = pads;
1005     }
1006   }else{
1007     g_critical("unknown channel type");
1008   }
1009 }
1010 
1011 void
ags_pitch_sampler_map_recall(AgsMachine * machine)1012 ags_pitch_sampler_map_recall(AgsMachine *machine)
1013 {
1014   AgsNavigation *navigation;
1015   AgsPitchSampler *pitch_sampler;
1016 
1017   AgsAudio *audio;
1018 
1019   AgsApplicationContext *application_context;
1020 
1021   GList *start_recall, *recall;
1022 
1023   gint position;
1024 
1025   if((AGS_MACHINE_MAPPED_RECALL & (machine->flags)) != 0 ||
1026      (AGS_MACHINE_PREMAPPED_RECALL & (machine->flags)) != 0){
1027     return;
1028   }
1029 
1030   application_context = ags_application_context_get_instance();
1031 
1032   navigation = (AgsNavigation *) ags_ui_provider_get_navigation(AGS_UI_PROVIDER(application_context));
1033 
1034   pitch_sampler = AGS_PITCH_SAMPLER(machine);
1035 
1036   audio = machine->audio;
1037 
1038   position = 0;
1039 
1040   /* ags-fx-playback */
1041   start_recall = ags_fx_factory_create(audio,
1042 				       pitch_sampler->playback_play_container, pitch_sampler->playback_recall_container,
1043 				       "ags-fx-playback",
1044 				       NULL,
1045 				       NULL,
1046 				       0, 0,
1047 				       0, 0,
1048 				       position,
1049 				       (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT),
1050 				       0);
1051 
1052   g_list_free_full(start_recall,
1053 		   (GDestroyNotify) g_object_unref);
1054 
1055   /* ags-fx-notation */
1056   start_recall = ags_fx_factory_create(audio,
1057 				       pitch_sampler->notation_play_container, pitch_sampler->notation_recall_container,
1058 				       "ags-fx-notation",
1059 				       NULL,
1060 				       NULL,
1061 				       0, 0,
1062 				       0, 0,
1063 				       position,
1064 				       (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT),
1065 				       0);
1066 
1067   g_list_free_full(start_recall,
1068 		   (GDestroyNotify) g_object_unref);
1069 
1070   /* ags-fx-lfo */
1071   start_recall = ags_fx_factory_create(audio,
1072 				       pitch_sampler->lfo_play_container, pitch_sampler->lfo_recall_container,
1073 				       "ags-fx-lfo",
1074 				       NULL,
1075 				       NULL,
1076 				       0, 0,
1077 				       0, 0,
1078 				       position,
1079 				       (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT),
1080 				       0);
1081 
1082   g_list_free_full(start_recall,
1083 		   (GDestroyNotify) g_object_unref);
1084 
1085   /* ags-fx-two-pass-aliase */
1086   start_recall = ags_fx_factory_create(audio,
1087 				       pitch_sampler->two_pass_aliase_play_container, pitch_sampler->two_pass_aliase_recall_container,
1088 				       "ags-fx-two-pass-aliase",
1089 				       NULL,
1090 				       NULL,
1091 				       0, 0,
1092 				       0, 0,
1093 				       position,
1094 				       (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT),
1095 				       0);
1096 
1097   g_list_free_full(start_recall,
1098 		   (GDestroyNotify) g_object_unref);
1099 
1100   /* ags-fx-volume */
1101   start_recall = ags_fx_factory_create(audio,
1102 				       pitch_sampler->volume_play_container, pitch_sampler->volume_recall_container,
1103 				       "ags-fx-volume",
1104 				       NULL,
1105 				       NULL,
1106 				       0, 0,
1107 				       0, 0,
1108 				       position,
1109 				       (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT),
1110 				       0);
1111 
1112   g_list_free_full(start_recall,
1113 		   (GDestroyNotify) g_object_unref);
1114 
1115   /* ags-fx-envelope */
1116   start_recall = ags_fx_factory_create(audio,
1117 				       pitch_sampler->envelope_play_container, pitch_sampler->envelope_recall_container,
1118 				       "ags-fx-envelope",
1119 				       NULL,
1120 				       NULL,
1121 				       0, 0,
1122 				       0, 0,
1123 				       position,
1124 				       (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT),
1125 				       0);
1126 
1127   g_list_free_full(start_recall,
1128 		   (GDestroyNotify) g_object_unref);
1129 
1130   /* ags-fx-buffer */
1131   start_recall = ags_fx_factory_create(audio,
1132 				       pitch_sampler->buffer_play_container, pitch_sampler->buffer_recall_container,
1133 				       "ags-fx-buffer",
1134 				       NULL,
1135 				       NULL,
1136 				       0, 0,
1137 				       0, 0,
1138 				       position,
1139 				       (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT),
1140 				       0);
1141 
1142   g_list_free_full(start_recall,
1143 		   (GDestroyNotify) g_object_unref);
1144 
1145   /* depending on destination */
1146   ags_pitch_sampler_input_map_recall(pitch_sampler,
1147 				     0,
1148 				     0);
1149 
1150   /* depending on destination */
1151   ags_pitch_sampler_output_map_recall(pitch_sampler,
1152 				      0,
1153 				      0);
1154 
1155   /* call parent */
1156   AGS_MACHINE_CLASS(ags_pitch_sampler_parent_class)->map_recall(machine);
1157 }
1158 
1159 void
ags_pitch_sampler_input_map_recall(AgsPitchSampler * pitch_sampler,guint audio_channel_start,guint input_pad_start)1160 ags_pitch_sampler_input_map_recall(AgsPitchSampler *pitch_sampler,
1161 				   guint audio_channel_start,
1162 				   guint input_pad_start)
1163 {
1164   AgsAudio *audio;
1165 
1166   GList *start_recall;
1167 
1168   gint position;
1169   guint input_pads;
1170   guint audio_channels;
1171 
1172   if(pitch_sampler->mapped_input_pad > input_pad_start){
1173     return;
1174   }
1175 
1176   audio = AGS_MACHINE(pitch_sampler)->audio;
1177 
1178   position = 0;
1179 
1180   input_pads = 0;
1181   audio_channels = 0;
1182 
1183   /* get some fields */
1184   g_object_get(audio,
1185 	       "input-pads", &input_pads,
1186 	       "audio-channels", &audio_channels,
1187 	       NULL);
1188 
1189   /* ags-fx-playback */
1190   start_recall = ags_fx_factory_create(audio,
1191 				       pitch_sampler->playback_play_container, pitch_sampler->playback_recall_container,
1192 				       "ags-fx-playback",
1193 				       NULL,
1194 				       NULL,
1195 				       audio_channel_start, audio_channels,
1196 				       input_pad_start, input_pads,
1197 				       position,
1198 				       (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
1199 
1200   g_list_free_full(start_recall,
1201 		   (GDestroyNotify) g_object_unref);
1202 
1203   /* ags-fx-notation */
1204   start_recall = ags_fx_factory_create(audio,
1205 				       pitch_sampler->notation_play_container, pitch_sampler->notation_recall_container,
1206 				       "ags-fx-notation",
1207 				       NULL,
1208 				       NULL,
1209 				       audio_channel_start, audio_channels,
1210 				       input_pad_start, input_pads,
1211 				       position,
1212 				       (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
1213 
1214   g_list_free_full(start_recall,
1215 		   (GDestroyNotify) g_object_unref);
1216 
1217   /* ags-fx-lfo */
1218   start_recall = ags_fx_factory_create(audio,
1219 				       pitch_sampler->lfo_play_container, pitch_sampler->lfo_recall_container,
1220 				       "ags-fx-lfo",
1221 				       NULL,
1222 				       NULL,
1223 				       audio_channel_start, audio_channels,
1224 				       input_pad_start, input_pads,
1225 				       position,
1226 				       (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
1227 
1228   g_list_free_full(start_recall,
1229 		   (GDestroyNotify) g_object_unref);
1230 
1231   /* ags-fx-two-pass-aliase */
1232   start_recall = ags_fx_factory_create(audio,
1233 				       pitch_sampler->two_pass_aliase_play_container, pitch_sampler->two_pass_aliase_recall_container,
1234 				       "ags-fx-two-pass-aliase",
1235 				       NULL,
1236 				       NULL,
1237 				       audio_channel_start, audio_channels,
1238 				       input_pad_start, input_pads,
1239 				       position,
1240 				       (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
1241 
1242   g_list_free_full(start_recall,
1243 		   (GDestroyNotify) g_object_unref);
1244 
1245   /* ags-fx-volume */
1246   start_recall = ags_fx_factory_create(audio,
1247 				       pitch_sampler->volume_play_container, pitch_sampler->volume_recall_container,
1248 				       "ags-fx-volume",
1249 				       NULL,
1250 				       NULL,
1251 				       audio_channel_start, audio_channels,
1252 				       input_pad_start, input_pads,
1253 				       position,
1254 				       (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
1255 
1256   g_list_free_full(start_recall,
1257 		   (GDestroyNotify) g_object_unref);
1258 
1259   /* ags-fx-envelope */
1260   start_recall = ags_fx_factory_create(audio,
1261 				       pitch_sampler->envelope_play_container, pitch_sampler->envelope_recall_container,
1262 				       "ags-fx-envelope",
1263 				       NULL,
1264 				       NULL,
1265 				       audio_channel_start, audio_channels,
1266 				       input_pad_start, input_pads,
1267 				       position,
1268 				       (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
1269 
1270   g_list_free_full(start_recall,
1271 		   (GDestroyNotify) g_object_unref);
1272 
1273   /* ags-fx-buffer */
1274   start_recall = ags_fx_factory_create(audio,
1275 				       pitch_sampler->buffer_play_container, pitch_sampler->buffer_recall_container,
1276 				       "ags-fx-buffer",
1277 				       NULL,
1278 				       NULL,
1279 				       audio_channel_start, audio_channels,
1280 				       input_pad_start, input_pads,
1281 				       position,
1282 				       (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
1283 
1284   g_list_free_full(start_recall,
1285 		   (GDestroyNotify) g_object_unref);
1286 
1287   pitch_sampler->mapped_input_pad = input_pads;
1288 }
1289 
1290 void
ags_pitch_sampler_output_map_recall(AgsPitchSampler * pitch_sampler,guint audio_channel_start,guint output_pad_start)1291 ags_pitch_sampler_output_map_recall(AgsPitchSampler *pitch_sampler,
1292 				    guint audio_channel_start,
1293 				    guint output_pad_start)
1294 {
1295   AgsAudio *audio;
1296 
1297   guint output_pads;
1298 
1299   if(pitch_sampler->mapped_output_pad > output_pad_start){
1300     return;
1301   }
1302 
1303   audio = AGS_MACHINE(pitch_sampler)->audio;
1304 
1305   /* get some fields */
1306   g_object_get(audio,
1307 	       "output-pads", &output_pads,
1308 	       NULL);
1309 
1310   pitch_sampler->mapped_output_pad = output_pads;
1311 }
1312 
1313 /**
1314  * ags_pitch_sampler_add_file:
1315  * @pitch_sampler: the #AgsPitchSampler
1316  * @file: the #AgsPitchSamplerFile
1317  *
1318  * Add @file to @pitch_sampler.
1319  *
1320  * Since: 3.0.0
1321  */
1322 void
ags_pitch_sampler_add_file(AgsPitchSampler * pitch_sampler,AgsPitchSamplerFile * file)1323 ags_pitch_sampler_add_file(AgsPitchSampler *pitch_sampler,
1324 			   AgsPitchSamplerFile *file)
1325 {
1326   GtkBox *hbox;
1327   GtkCheckButton *check_button;
1328 
1329   hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
1330 				0);
1331 
1332   check_button = (GtkCheckButton *) gtk_check_button_new();
1333   gtk_box_pack_start(hbox,
1334 		     (GtkWidget *) check_button,
1335 		     FALSE,
1336 		     FALSE,
1337 		     0);
1338 
1339   gtk_box_pack_start(hbox,
1340 		     (GtkWidget *) file,
1341 		     FALSE,
1342 		     FALSE,
1343 		     0);
1344 
1345   gtk_box_pack_start(pitch_sampler->file,
1346 		     (GtkWidget *) hbox,
1347 		     FALSE,
1348 		     FALSE,
1349 		     0);
1350   gtk_widget_show_all((GtkWidget *) hbox);
1351 }
1352 
1353 /**
1354  * ags_pitch_sampler_remove_file:
1355  * @pitch_sampler: the #AgsPitchSampler
1356  * @nth: the nth #AgsPitchSamplerFile
1357  *
1358  * Remove nth file.
1359  *
1360  * Since: 3.0.0
1361  */
1362 void
ags_pitch_sampler_remove_file(AgsPitchSampler * pitch_sampler,guint nth)1363 ags_pitch_sampler_remove_file(AgsPitchSampler *pitch_sampler,
1364 			      guint nth)
1365 {
1366   GList *list, *list_start;
1367 
1368   list_start = gtk_container_get_children(GTK_CONTAINER(pitch_sampler->file));
1369 
1370   list = g_list_nth(list_start,
1371 		    nth);
1372 
1373   if(list != NULL){
1374     gtk_widget_destroy(list->data);
1375   }
1376 
1377   g_list_free(list_start);
1378 }
1379 
1380 /**
1381  * ags_pitch_sampler_open_filename:
1382  * @pitch_sampler: the #AgsPitchSampler
1383  * @filename: the filename
1384  *
1385  * Open @filename.
1386  *
1387  * Since: 3.0.0
1388  */
1389 void
ags_pitch_sampler_open_filename(AgsPitchSampler * pitch_sampler,gchar * filename)1390 ags_pitch_sampler_open_filename(AgsPitchSampler *pitch_sampler,
1391 				gchar *filename)
1392 {
1393   AgsSFZLoader *sfz_loader;
1394 
1395   if(!AGS_IS_PITCH_SAMPLER(pitch_sampler) ||
1396      filename == NULL){
1397     return;
1398   }
1399 
1400   pitch_sampler->sfz_loader =
1401     sfz_loader = ags_sfz_loader_new(AGS_MACHINE(pitch_sampler)->audio,
1402 				    filename,
1403 				    TRUE);
1404 
1405   ags_sfz_loader_start(sfz_loader);
1406 }
1407 
1408 /**
1409  * ags_pitch_sampler_update:
1410  * @pitch_sampler: the #AgsPitchSampler
1411  *
1412  * Update @pitch_sampler.
1413  *
1414  * Since: 3.0.0
1415  */
1416 void
ags_pitch_sampler_update(AgsPitchSampler * pitch_sampler)1417 ags_pitch_sampler_update(AgsPitchSampler *pitch_sampler)
1418 {
1419   AgsAudio *audio;
1420   AgsChannel *start_input;
1421 
1422   AgsAudioContainer *audio_container;
1423 
1424   AgsResizeAudio *resize_audio;
1425   AgsApplySFZSynth *apply_sfz_synth;
1426   AgsOpenSFZFile *open_sfz_file;
1427 
1428   AgsApplicationContext *application_context;
1429 
1430   gchar *str;
1431 
1432   gdouble lower;
1433   gdouble key_count;
1434   guint audio_channels;
1435   guint output_pads;
1436   guint pitch_type;
1437 
1438   if(!AGS_IS_PITCH_SAMPLER(pitch_sampler)){
1439     return;
1440   }
1441 
1442   application_context = ags_application_context_get_instance();
1443 
1444   audio_container = pitch_sampler->audio_container;
1445 
1446   if(audio_container == NULL){
1447     return;
1448   }
1449 
1450   audio = AGS_MACHINE(pitch_sampler)->audio;
1451 
1452   start_input = NULL;
1453 
1454   g_object_get(audio,
1455 	       "input", &start_input,
1456 	       NULL);
1457 
1458   /*  */
1459   lower = gtk_spin_button_get_value(pitch_sampler->lower);
1460   key_count = gtk_spin_button_get_value(pitch_sampler->key_count);
1461 
1462   audio_channels = AGS_MACHINE(pitch_sampler)->audio_channels;
1463 
1464   output_pads = AGS_MACHINE(pitch_sampler)->output_pads;
1465 
1466   /* pitch type */
1467   pitch_type = AGS_FLUID_4TH_ORDER_INTERPOLATE;
1468 
1469   str = gtk_combo_box_text_get_active_text(pitch_sampler->pitch_function);
1470 
1471   if(!g_ascii_strncasecmp(str,
1472 			  "ags-fast-pitch",
1473 			  16)){
1474     pitch_type = AGS_FAST_PITCH;
1475   }else if(!g_ascii_strncasecmp(str,
1476 				"ags-hq-pitch",
1477 				14)){
1478     pitch_type = AGS_HQ_PITCH;
1479   }else if(!g_ascii_strncasecmp(str,
1480 				"fluid-no-interpolate",
1481 				21)){
1482     pitch_type = AGS_FLUID_NO_INTERPOLATE;
1483   }else if(!g_ascii_strncasecmp(str,
1484 				"fluid-linear-interpolate",
1485 				26)){
1486     pitch_type = AGS_FLUID_LINEAR_INTERPOLATE;
1487   }else if(!g_ascii_strncasecmp(str,
1488 				"fluid-4th-order-interpolate",
1489 				29)){
1490     pitch_type = AGS_FLUID_4TH_ORDER_INTERPOLATE;
1491   }else if(!g_ascii_strncasecmp(str,
1492 				"fluid-7th-order-interpolate",
1493 				29)){
1494     pitch_type = AGS_FLUID_7TH_ORDER_INTERPOLATE;
1495   }
1496 
1497   /* open sfz file */
1498   if(gtk_toggle_button_get_active((GtkToggleButton *) pitch_sampler->enable_synth_generator)){
1499     GList *start_sfz_synth_generator;
1500     GList *start_sound_resource;
1501 
1502     guint requested_frame_count;
1503 
1504     resize_audio = ags_resize_audio_new(audio,
1505 					output_pads,
1506 					key_count,
1507 					audio_channels);
1508 
1509     /* append task */
1510     ags_ui_provider_schedule_task(AGS_UI_PROVIDER(application_context),
1511 				  (AgsTask *) resize_audio);
1512 
1513     start_sfz_synth_generator = NULL;
1514 
1515     g_object_get(audio,
1516 		 "sfz-synth-generator", &start_sfz_synth_generator,
1517 		 NULL);
1518 
1519     requested_frame_count = 0;
1520 
1521     start_sound_resource = ags_audio_container_find_sound_resource(audio_container,
1522 								   NULL,
1523 								   NULL,
1524 								   NULL);
1525 
1526     if(start_sound_resource != NULL){
1527       ags_sound_resource_info(AGS_SOUND_RESOURCE(start_sound_resource->data),
1528 			      &requested_frame_count,
1529 			      NULL, NULL);
1530     }
1531 
1532     if(start_sfz_synth_generator != NULL){
1533       g_object_set(start_sfz_synth_generator->data,
1534 		   "filename", audio_container->filename,
1535 		   "frame-count", requested_frame_count,
1536 		   "pitch-type", pitch_type,
1537 		   NULL);
1538 
1539       apply_sfz_synth = ags_apply_sfz_synth_new(start_sfz_synth_generator->data,
1540 						start_input,
1541 						lower, (guint) key_count);
1542 
1543       g_object_set(apply_sfz_synth,
1544 		   "requested-frame-count", requested_frame_count,
1545 		   NULL);
1546 
1547       /* append task */
1548       ags_ui_provider_schedule_task(AGS_UI_PROVIDER(application_context),
1549 				    (AgsTask *) apply_sfz_synth);
1550     }
1551 
1552     g_list_free_full(start_sound_resource,
1553 		     (GDestroyNotify) g_object_unref);
1554 
1555     g_list_free_full(start_sfz_synth_generator,
1556 		     (GDestroyNotify) g_object_unref);
1557   }else{
1558     open_sfz_file = ags_open_sfz_file_new(audio,
1559 					  AGS_SFZ_FILE(audio_container->sound_container),
1560 					  NULL,
1561 					  0);
1562 
1563     /* append task */
1564     ags_ui_provider_schedule_task(AGS_UI_PROVIDER(application_context),
1565 				  (AgsTask *) open_sfz_file);
1566   }
1567 }
1568 
1569 /**
1570  * ags_pitch_sampler_sfz_loader_completed_timeout:
1571  * @pitch_sampler: the #AgsPitchSampler
1572  *
1573  * Queue draw widget
1574  *
1575  * Returns: %TRUE if proceed poll completed, otherwise %FALSE
1576  *
1577  * Since: 3.0.0
1578  */
1579 gboolean
ags_pitch_sampler_sfz_loader_completed_timeout(AgsPitchSampler * pitch_sampler)1580 ags_pitch_sampler_sfz_loader_completed_timeout(AgsPitchSampler *pitch_sampler)
1581 {
1582   if(g_hash_table_lookup(ags_pitch_sampler_sfz_loader_completed,
1583 			 pitch_sampler) != NULL){
1584     if(pitch_sampler->sfz_loader != NULL){
1585       if(ags_sfz_loader_test_flags(pitch_sampler->sfz_loader, AGS_SFZ_LOADER_HAS_COMPLETED)){
1586 	AgsPitchSamplerFile *file;
1587 
1588 	GList *start_list, *list;
1589 
1590 	/* file */
1591 	list =
1592 	  start_list = gtk_container_get_children(GTK_CONTAINER(pitch_sampler->file));
1593 
1594 	while(list != NULL){
1595 	  gtk_widget_destroy(list->data);
1596 
1597 	  list = list->next;
1598 	}
1599 
1600 	g_list_free(start_list);
1601 
1602 	/* reassign audio container */
1603 	pitch_sampler->audio_container = pitch_sampler->sfz_loader->audio_container;
1604 	pitch_sampler->sfz_loader->audio_container = NULL;
1605 
1606 	g_object_get(pitch_sampler->audio_container->sound_container,
1607 		     "sample", &start_list,
1608 		     NULL);
1609 
1610 	list = start_list;
1611 
1612 	while(list != NULL){
1613 	  AgsSFZGroup *group;
1614 	  AgsSFZRegion *region;
1615 
1616 	  gchar *filename;
1617 	  gchar *str_key, *str_pitch_keycenter;
1618 	  gchar *str;
1619 
1620 	  glong current_key;
1621 	  glong pitch_keycenter, current_pitch_keycenter;
1622 	  guint loop_start, loop_end;
1623 	  int retval;
1624 
1625 	  file = ags_pitch_sampler_file_new();
1626 	  ags_pitch_sampler_add_file(pitch_sampler,
1627 				     file);
1628 	  ags_connectable_connect(AGS_CONNECTABLE(file));
1629 
1630 	  /* pitch keycenter */
1631 	  g_object_get(list->data,
1632 		       "group", &group,
1633 		       "region", &region,
1634 		       "filename", &filename,
1635 		       NULL);
1636 
1637 	  pitch_keycenter = 49;
1638 
1639 	  /* group */
1640 	  str_pitch_keycenter = ags_sfz_group_lookup_control(group,
1641 							     "pitch_keycenter");
1642 
1643 	  str_key = ags_sfz_group_lookup_control(group,
1644 						 "key");
1645 
1646 	  if(str_pitch_keycenter != NULL){
1647 	    retval = sscanf(str_pitch_keycenter, "%lu", &current_pitch_keycenter);
1648 
1649 	    if(retval > 0){
1650 	      pitch_keycenter = current_pitch_keycenter;
1651 	    }else{
1652 	      retval = ags_diatonic_scale_note_to_midi_key(str_pitch_keycenter,
1653 							   &current_key);
1654 
1655 	      if(retval > 0){
1656 		pitch_keycenter = current_key;
1657 	      }
1658 	    }
1659 	  }else if(str_key != NULL){
1660 	    retval = sscanf(str_key, "%lu", &current_pitch_keycenter);
1661 
1662 	    if(retval > 0){
1663 	      pitch_keycenter = current_pitch_keycenter;
1664 	    }else{
1665 	      retval = ags_diatonic_scale_note_to_midi_key(str_key,
1666 							   &current_key);
1667 
1668 	      if(retval > 0){
1669 		pitch_keycenter = current_key;
1670 	      }
1671 	    }
1672 	  }
1673 
1674 	  /* region */
1675 	  str_pitch_keycenter = ags_sfz_region_lookup_control(region,
1676 							      "pitch_keycenter");
1677 
1678 	  str_key = ags_sfz_region_lookup_control(region,
1679 						  "key");
1680 
1681 	  if(str_pitch_keycenter != NULL){
1682 	    retval = sscanf(str_pitch_keycenter, "%lu", &current_pitch_keycenter);
1683 
1684 	    if(retval > 0){
1685 	      pitch_keycenter = current_pitch_keycenter;
1686 	    }else{
1687 	      retval = ags_diatonic_scale_note_to_midi_key(str_pitch_keycenter,
1688 							   &current_key);
1689 
1690 	      if(retval > 0){
1691 		pitch_keycenter = current_key;
1692 	      }
1693 	    }
1694 	  }else if(str_key != NULL){
1695 	    retval = sscanf(str_key, "%lu", &current_pitch_keycenter);
1696 
1697 	    if(retval > 0){
1698 	      pitch_keycenter = current_pitch_keycenter;
1699 	    }else{
1700 	      retval = ags_diatonic_scale_note_to_midi_key(str_key,
1701 							   &current_key);
1702 
1703 	      if(retval > 0){
1704 		pitch_keycenter = current_key;
1705 	      }
1706 	    }
1707 	  }
1708 
1709 	  /* set filename */
1710 	  gtk_entry_set_text(file->filename,
1711 			     filename);
1712 	  g_free(filename);
1713 
1714 	  /* set pitch keycenter */
1715 	  str = g_strdup_printf("%f",
1716 				27.5 * exp2((gdouble) pitch_keycenter / 12.0));
1717 	  gtk_label_set_text(file->freq,
1718 			     str);
1719 
1720 	  g_free(str);
1721 
1722 	  str = g_strdup_printf("%ld",
1723 				pitch_keycenter);
1724 	  gtk_label_set_text(file->base_key,
1725 			     str);
1726 
1727 	  g_free(str);
1728 
1729 	  /* set loop start/end */
1730 	  g_object_get(list->data,
1731 		       "loop-start", &loop_start,
1732 		       "loop-end", &loop_end,
1733 		       NULL);
1734 
1735 	  str = g_strdup_printf("%d",
1736 				loop_start);
1737 	  gtk_label_set_text(file->loop_start,
1738 			     str);
1739 
1740 	  g_free(str);
1741 
1742 	  str = g_strdup_printf("%d",
1743 				loop_end);
1744 	  gtk_label_set_text(file->loop_end,
1745 			     str);
1746 
1747 	  g_free(str);
1748 
1749 	  /* iterate */
1750 	  list = list->next;
1751 	}
1752 
1753 	g_list_free_full(start_list,
1754 			 g_object_unref);
1755 
1756 	/* cleanup */
1757 	g_object_run_dispose((GObject *) pitch_sampler->sfz_loader);
1758 	g_object_unref(pitch_sampler->sfz_loader);
1759 
1760 	pitch_sampler->sfz_loader = NULL;
1761 
1762 	pitch_sampler->position = -1;
1763 	gtk_widget_hide((GtkWidget *) pitch_sampler->loading);
1764 
1765       }else{
1766 	if(pitch_sampler->position == -1){
1767 	  pitch_sampler->position = 0;
1768 
1769 	  gtk_widget_show((GtkWidget *) pitch_sampler->loading);
1770 	}
1771 
1772 	switch(pitch_sampler->position){
1773 	case 0:
1774 	{
1775 	  pitch_sampler->position = 1;
1776 
1777 	  gtk_label_set_label(pitch_sampler->loading,
1778 			      "loading ...  ");
1779 	}
1780 	break;
1781 	case 1:
1782 	{
1783 	  pitch_sampler->position = 2;
1784 
1785 	  gtk_label_set_label(pitch_sampler->loading,
1786 			      "loading  ... ");
1787 	}
1788 	break;
1789 	case 2:
1790 	{
1791 	  pitch_sampler->position = 0;
1792 
1793 	  gtk_label_set_label(pitch_sampler->loading,
1794 			      "loading   ...");
1795 	}
1796 	break;
1797 	}
1798       }
1799     }
1800 
1801     return(TRUE);
1802   }else{
1803     return(FALSE);
1804   }
1805 }
1806 
1807 /**
1808  * ags_pitch_sampler_new:
1809  * @soundcard: the assigned soundcard.
1810  *
1811  * Create a new instance of #AgsPitchSampler
1812  *
1813  * Returns: the new #AgsPitchSampler
1814  *
1815  * Since: 3.0.0
1816  */
1817 AgsPitchSampler*
ags_pitch_sampler_new(GObject * output_soundcard)1818 ags_pitch_sampler_new(GObject *output_soundcard)
1819 {
1820   AgsPitchSampler *pitch_sampler;
1821 
1822   pitch_sampler = (AgsPitchSampler *) g_object_new(AGS_TYPE_PITCH_SAMPLER,
1823 						   NULL);
1824 
1825   if(output_soundcard != NULL){
1826     g_object_set(AGS_MACHINE(pitch_sampler)->audio,
1827 		 "output-soundcard", output_soundcard,
1828 		 NULL);
1829   }
1830 
1831   return(pitch_sampler);
1832 }
1833