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_fm_syncsynth.h>
21 #include <ags/X/machine/ags_fm_syncsynth_callbacks.h>
22 
23 #include <ags/X/ags_ui_provider.h>
24 #include <ags/X/ags_window.h>
25 #include <ags/X/ags_machine.h>
26 #include <ags/X/ags_pad.h>
27 #include <ags/X/ags_line.h>
28 
29 #include <math.h>
30 
31 #include <ags/i18n.h>
32 
33 void ags_fm_syncsynth_class_init(AgsFMSyncsynthClass *fm_syncsynth);
34 void ags_fm_syncsynth_connectable_interface_init(AgsConnectableInterface *connectable);
35 void ags_fm_syncsynth_init(AgsFMSyncsynth *fm_syncsynth);
36 void ags_fm_syncsynth_finalize(GObject *gobject);
37 
38 void ags_fm_syncsynth_connect(AgsConnectable *connectable);
39 void ags_fm_syncsynth_disconnect(AgsConnectable *connectable);
40 
41 void ags_fm_syncsynth_show(GtkWidget *widget);
42 
43 void ags_fm_syncsynth_resize_audio_channels(AgsMachine *machine,
44 					    guint audio_channels, guint audio_channels_old,
45 					    gpointer data);
46 void ags_fm_syncsynth_resize_pads(AgsMachine *machine, GType channel_type,
47 				  guint pads, guint pads_old,
48 				  gpointer data);
49 
50 void ags_fm_syncsynth_map_recall(AgsMachine *machine);
51 
52 void ags_fm_syncsynth_input_map_recall(AgsFMSyncsynth *fm_syncsynth,
53 				       guint audio_channel_start,
54 				       guint input_pad_start);
55 void ags_fm_syncsynth_output_map_recall(AgsFMSyncsynth *fm_syncsynth,
56 					guint audio_channel_start,
57 					guint output_pad_start);
58 
59 /**
60  * SECTION:ags_fm_syncsynth
61  * @short_description: fm syncsynth
62  * @title: AgsFMSyncsynth
63  * @section_id:
64  * @include: ags/X/machine/ags_fm_syncsynth.h
65  *
66  * The #AgsFMSyncsynth is a composite widget to act as fm syncsynth.
67  */
68 
69 static gpointer ags_fm_syncsynth_parent_class = NULL;
70 static AgsConnectableInterface *ags_fm_syncsynth_parent_connectable_interface;
71 
72 GType
ags_fm_syncsynth_get_type(void)73 ags_fm_syncsynth_get_type(void)
74 {
75   static volatile gsize g_define_type_id__volatile = 0;
76 
77   if(g_once_init_enter (&g_define_type_id__volatile)){
78     GType ags_type_fm_syncsynth = 0;
79 
80     static const GTypeInfo ags_fm_syncsynth_info = {
81       sizeof(AgsFMSyncsynthClass),
82       NULL, /* base_init */
83       NULL, /* base_finalize */
84       (GClassInitFunc) ags_fm_syncsynth_class_init,
85       NULL, /* class_finalize */
86       NULL, /* class_data */
87       sizeof(AgsFMSyncsynth),
88       0,    /* n_preallocs */
89       (GInstanceInitFunc) ags_fm_syncsynth_init,
90     };
91 
92     static const GInterfaceInfo ags_connectable_interface_info = {
93       (GInterfaceInitFunc) ags_fm_syncsynth_connectable_interface_init,
94       NULL, /* interface_finalize */
95       NULL, /* interface_data */
96     };
97 
98     ags_type_fm_syncsynth = g_type_register_static(AGS_TYPE_MACHINE,
99 						   "AgsFMSyncsynth", &ags_fm_syncsynth_info,
100 						   0);
101 
102     g_type_add_interface_static(ags_type_fm_syncsynth,
103 				AGS_TYPE_CONNECTABLE,
104 				&ags_connectable_interface_info);
105 
106     g_once_init_leave(&g_define_type_id__volatile, ags_type_fm_syncsynth);
107   }
108 
109   return g_define_type_id__volatile;
110 }
111 
112 void
ags_fm_syncsynth_class_init(AgsFMSyncsynthClass * fm_syncsynth)113 ags_fm_syncsynth_class_init(AgsFMSyncsynthClass *fm_syncsynth)
114 {
115   GObjectClass *gobject;
116   AgsMachineClass *machine;
117 
118   ags_fm_syncsynth_parent_class = g_type_class_peek_parent(fm_syncsynth);
119 
120   /* GObjectClass */
121   gobject = (GObjectClass *) fm_syncsynth;
122 
123   gobject->finalize = ags_fm_syncsynth_finalize;
124 
125   /* AgsMachineClass */
126   machine = (AgsMachineClass *) fm_syncsynth;
127 
128   machine->map_recall = ags_fm_syncsynth_map_recall;
129 }
130 
131 void
ags_fm_syncsynth_connectable_interface_init(AgsConnectableInterface * connectable)132 ags_fm_syncsynth_connectable_interface_init(AgsConnectableInterface *connectable)
133 {
134   ags_fm_syncsynth_parent_connectable_interface = g_type_interface_peek_parent(connectable);
135 
136   connectable->connect = ags_fm_syncsynth_connect;
137   connectable->disconnect = ags_fm_syncsynth_disconnect;
138 }
139 
140 void
ags_fm_syncsynth_init(AgsFMSyncsynth * fm_syncsynth)141 ags_fm_syncsynth_init(AgsFMSyncsynth *fm_syncsynth)
142 {
143   GtkBox *hbox;
144   GtkBox *vbox;
145   GtkGrid *grid;
146   GtkFrame *frame;
147   GtkBox *volume_hbox;
148   GtkLabel *label;
149 
150   AgsAudio *audio;
151 
152   AgsApplicationContext *application_context;
153 
154   gdouble gui_scale_factor;
155 
156   application_context = ags_application_context_get_instance();
157 
158   /* scale factor */
159   gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
160 
161   g_signal_connect_after((GObject *) fm_syncsynth, "parent_set",
162 			 G_CALLBACK(ags_fm_syncsynth_parent_set_callback), (gpointer) fm_syncsynth);
163 
164   audio = AGS_MACHINE(fm_syncsynth)->audio;
165   ags_audio_set_flags(audio, (AGS_AUDIO_SYNC |
166 			      AGS_AUDIO_ASYNC |
167 			      AGS_AUDIO_OUTPUT_HAS_RECYCLING |
168 			      AGS_AUDIO_INPUT_HAS_RECYCLING |
169 			      AGS_AUDIO_INPUT_HAS_SYNTH));
170   ags_audio_set_ability_flags(audio, (AGS_SOUND_ABILITY_PLAYBACK |
171 				      AGS_SOUND_ABILITY_NOTATION));
172   ags_audio_set_behaviour_flags(audio, (AGS_SOUND_BEHAVIOUR_REVERSE_MAPPING |
173 					AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_INPUT));
174   g_object_set(audio,
175 	       "min-audio-channels", 1,
176 	       "max-audio-channels", 1,
177 	       "min-output-pads", 1,
178 	       "min-input-pads", 1,
179 	       "max-input-pads", 128,
180 	       "audio-start-mapping", 0,
181 	       "audio-end-mapping", 128,
182 	       "midi-start-mapping", 0,
183 	       "midi-end-mapping", 128,
184 	       NULL);
185 
186   AGS_MACHINE(fm_syncsynth)->flags |= (AGS_MACHINE_IS_SYNTHESIZER |
187 				       AGS_MACHINE_REVERSE_NOTATION);
188   AGS_MACHINE(fm_syncsynth)->mapping_flags |= AGS_MACHINE_MONO;
189 
190   AGS_MACHINE(fm_syncsynth)->input_pad_type = G_TYPE_NONE;
191   AGS_MACHINE(fm_syncsynth)->input_line_type = G_TYPE_NONE;
192   AGS_MACHINE(fm_syncsynth)->output_pad_type = G_TYPE_NONE;
193   AGS_MACHINE(fm_syncsynth)->output_line_type = G_TYPE_NONE;
194 
195   /* context menu */
196   ags_machine_popup_add_connection_options((AgsMachine *) fm_syncsynth,
197   					   (AGS_MACHINE_POPUP_MIDI_DIALOG));
198 
199   /* audio resize */
200   g_signal_connect(fm_syncsynth, "samplerate-changed",
201 		   G_CALLBACK(ags_fm_syncsynth_samplerate_changed_callback), NULL);
202 
203   g_signal_connect_after(G_OBJECT(fm_syncsynth), "resize-audio-channels",
204 			 G_CALLBACK(ags_fm_syncsynth_resize_audio_channels), NULL);
205 
206   g_signal_connect_after(G_OBJECT(fm_syncsynth), "resize-pads",
207 			 G_CALLBACK(ags_fm_syncsynth_resize_pads), NULL);
208 
209   /* create widgets */
210   fm_syncsynth->flags = 0;
211 
212   /* mapped IO */
213   fm_syncsynth->mapped_input_pad = 0;
214   fm_syncsynth->mapped_output_pad = 0;
215 
216   fm_syncsynth->playback_play_container = ags_recall_container_new();
217   fm_syncsynth->playback_recall_container = ags_recall_container_new();
218 
219   fm_syncsynth->notation_play_container = ags_recall_container_new();
220   fm_syncsynth->notation_recall_container = ags_recall_container_new();
221 
222   fm_syncsynth->volume_play_container = ags_recall_container_new();
223   fm_syncsynth->volume_recall_container = ags_recall_container_new();
224 
225   fm_syncsynth->envelope_play_container = ags_recall_container_new();
226   fm_syncsynth->envelope_recall_container = ags_recall_container_new();
227 
228   fm_syncsynth->buffer_play_container = ags_recall_container_new();
229   fm_syncsynth->buffer_recall_container = ags_recall_container_new();
230 
231   /* context menu */
232   ags_machine_popup_add_edit_options((AgsMachine *) fm_syncsynth,
233 				     (AGS_MACHINE_POPUP_ENVELOPE));
234 
235   /* name and xml type */
236   fm_syncsynth->name = NULL;
237   fm_syncsynth->xml_type = "ags-fm_syncsynth";
238 
239   /* create widgets */
240   hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
241 				0);
242   gtk_container_add((GtkContainer*) (gtk_bin_get_child((GtkBin *) fm_syncsynth)), (GtkWidget *) hbox);
243 
244   fm_syncsynth->fm_oscillator = (GtkVBox *) gtk_vbox_new(FALSE, 0);
245   gtk_box_pack_start(hbox,
246 		     (GtkWidget *) fm_syncsynth->fm_oscillator,
247 		     FALSE,
248 		     FALSE,
249 		     0);
250 
251   /* add fm oscillator */
252   ags_fm_syncsynth_add_fm_oscillator(fm_syncsynth,
253 				     ags_fm_oscillator_new());
254 
255   /* add and remove buttons */
256   vbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_VERTICAL,
257 				0);
258   gtk_box_pack_start(hbox,
259 		     (GtkWidget *) vbox,
260 		     FALSE, FALSE,
261 		     0);
262 
263   fm_syncsynth->add = (GtkButton *) gtk_button_new_from_icon_name("list-add",
264 								  GTK_ICON_SIZE_BUTTON);
265   gtk_box_pack_start(vbox,
266 		     (GtkWidget *) fm_syncsynth->add,
267 		     FALSE, FALSE,
268 		     0);
269 
270   fm_syncsynth->remove = (GtkButton *) gtk_button_new_from_icon_name("list-remove",
271 								     GTK_ICON_SIZE_BUTTON);
272   gtk_box_pack_start(vbox,
273 		     (GtkWidget *) fm_syncsynth->remove,
274 		     FALSE, FALSE,
275 		     0);
276 
277   /* update */
278   vbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_VERTICAL,
279 				0);
280   gtk_box_pack_start(hbox,
281 		     (GtkWidget *) vbox,
282 		     FALSE, FALSE,
283 		     0);
284 
285   fm_syncsynth->auto_update = (GtkCheckButton *) gtk_check_button_new_with_label(i18n("auto update"));
286   gtk_box_pack_start(vbox,
287 		     (GtkWidget *) fm_syncsynth->auto_update,
288 		     FALSE, FALSE,
289 		     0);
290 
291   fm_syncsynth->update = (GtkButton *) gtk_button_new_with_label(i18n("update"));
292   gtk_box_pack_start(vbox,
293 		     (GtkWidget *) fm_syncsynth->update,
294 		     FALSE, FALSE,
295 		     0);
296 
297   /* grid */
298   grid = (GtkGrid *) gtk_grid_new();
299   gtk_box_pack_start(vbox,
300 		     (GtkWidget *) grid,
301 		     FALSE, FALSE,
302 		     0);
303 
304   /* lower - frequency */
305   label = (GtkLabel *) g_object_new(GTK_TYPE_LABEL,
306 				    "label", i18n("lower"),
307 				    "xalign", 0.0,
308 				    NULL);
309 
310   gtk_widget_set_valign((GtkWidget *) label,
311 			GTK_ALIGN_FILL);
312   gtk_widget_set_halign((GtkWidget *) label,
313 			GTK_ALIGN_FILL);
314 
315   gtk_grid_attach(grid,
316 		  GTK_WIDGET(label),
317 		  0, 0,
318 		  1, 1);
319 
320   fm_syncsynth->lower = (GtkSpinButton *) gtk_spin_button_new_with_range(AGS_FM_SYNCSYNTH_BASE_NOTE_MIN,
321 									 AGS_FM_SYNCSYNTH_BASE_NOTE_MAX,
322 									 1.0);
323   gtk_spin_button_set_digits(fm_syncsynth->lower,
324 			     2);
325   gtk_spin_button_set_value(fm_syncsynth->lower, -48.0);
326 
327   gtk_widget_set_valign((GtkWidget *) fm_syncsynth->lower,
328 			GTK_ALIGN_FILL);
329   gtk_widget_set_halign((GtkWidget *) fm_syncsynth->lower,
330 			GTK_ALIGN_FILL);
331 
332   gtk_grid_attach(grid,
333 		  (GtkWidget *) fm_syncsynth->lower,
334 		  1, 0,
335 		  1, 1);
336 
337   /* loop start */
338   label = (GtkLabel *) g_object_new(GTK_TYPE_LABEL,
339 				    "label", i18n("loop start"),
340 				    "xalign", 0.0,
341 				    NULL);
342 
343   gtk_widget_set_valign((GtkWidget *) label,
344 			GTK_ALIGN_FILL);
345   gtk_widget_set_halign((GtkWidget *) label,
346 			GTK_ALIGN_FILL);
347 
348   gtk_grid_attach(grid,
349 		  (GtkWidget *) label,
350 		  0, 1,
351 		  1, 1);
352 
353   fm_syncsynth->loop_start = (GtkSpinButton *) gtk_spin_button_new_with_range(0.0, AGS_FM_OSCILLATOR_DEFAULT_FRAME_COUNT, 1.0);
354 
355   gtk_widget_set_valign((GtkWidget *) fm_syncsynth->loop_start,
356 			GTK_ALIGN_FILL);
357   gtk_widget_set_halign((GtkWidget *) fm_syncsynth->loop_start,
358 			GTK_ALIGN_FILL);
359 
360   gtk_grid_attach(grid,
361 		  GTK_WIDGET(fm_syncsynth->loop_start),
362 		  1, 1,
363 		  1, 1);
364 
365   /* loop end */
366   label = (GtkLabel *) g_object_new(GTK_TYPE_LABEL,
367 				    "label", i18n("loop end"),
368 				    "xalign", 0.0,
369 				    NULL);
370 
371   gtk_widget_set_valign((GtkWidget *) label,
372 			GTK_ALIGN_FILL);
373   gtk_widget_set_halign((GtkWidget *) label,
374 			GTK_ALIGN_FILL);
375 
376   gtk_grid_attach(grid,
377 		  (GtkWidget *) label,
378 		   0, 2,
379 		   1, 1);
380 
381   fm_syncsynth->loop_end = (GtkSpinButton *) gtk_spin_button_new_with_range(0.0, AGS_FM_OSCILLATOR_DEFAULT_FRAME_COUNT, 1.0);
382 
383   gtk_widget_set_valign((GtkWidget *) fm_syncsynth->loop_end,
384 			GTK_ALIGN_FILL);
385   gtk_widget_set_halign((GtkWidget *) fm_syncsynth->loop_end,
386 			GTK_ALIGN_FILL);
387 
388   gtk_grid_attach(grid,
389 		  (GtkWidget *) fm_syncsynth->loop_end,
390 		  1, 2,
391 		  1, 1);
392 
393   /* volume */
394   frame = (GtkFrame *) gtk_frame_new(i18n("volume"));
395 
396   gtk_widget_set_valign((GtkWidget *) frame,
397 			GTK_ALIGN_FILL);
398   gtk_widget_set_halign((GtkWidget *) frame,
399 			GTK_ALIGN_FILL);
400 
401   gtk_box_pack_start(hbox,
402 		     (GtkWidget *) frame,
403 		     FALSE, FALSE,
404 		     0);
405 
406   volume_hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
407 				       0);
408   gtk_container_add((GtkContainer *) frame,
409 		    (GtkWidget *) volume_hbox);
410 
411   fm_syncsynth->volume = (GtkScale *) gtk_scale_new_with_range(GTK_ORIENTATION_VERTICAL,
412 							       0.0,
413 							       2.0,
414 							       0.025);
415 
416   gtk_widget_set_size_request(fm_syncsynth->volume,
417 			      gui_scale_factor * 16, gui_scale_factor * 100);
418 
419   gtk_box_pack_start(volume_hbox,
420 		     (GtkWidget *) fm_syncsynth->volume,
421 		     FALSE, FALSE,
422 		     0);
423 
424   gtk_scale_set_digits(fm_syncsynth->volume,
425 		       3);
426 
427   gtk_range_set_increments(GTK_RANGE(fm_syncsynth->volume),
428 			   0.025, 0.1);
429   gtk_range_set_value(GTK_RANGE(fm_syncsynth->volume),
430 		      1.0);
431   gtk_range_set_inverted(GTK_RANGE(fm_syncsynth->volume),
432 			 TRUE);
433 }
434 
435 void
ags_fm_syncsynth_finalize(GObject * gobject)436 ags_fm_syncsynth_finalize(GObject *gobject)
437 {
438   /* call parent */
439   G_OBJECT_CLASS(ags_fm_syncsynth_parent_class)->finalize(gobject);
440 }
441 
442 void
ags_fm_syncsynth_connect(AgsConnectable * connectable)443 ags_fm_syncsynth_connect(AgsConnectable *connectable)
444 {
445   AgsFMSyncsynth *fm_syncsynth;
446 
447   GList *list_start, *list;
448   GList *child_start;
449 
450   if((AGS_MACHINE_CONNECTED & (AGS_MACHINE(connectable)->flags)) != 0){
451     return;
452   }
453 
454   ags_fm_syncsynth_parent_connectable_interface->connect(connectable);
455 
456   /* AgsFMSyncsynth */
457   fm_syncsynth = AGS_FM_SYNCSYNTH(connectable);
458 
459   list =
460     list_start = gtk_container_get_children(GTK_CONTAINER(fm_syncsynth->fm_oscillator));
461 
462   while(list != NULL){
463     child_start = gtk_container_get_children(GTK_CONTAINER(list->data));
464 
465     ags_connectable_connect(AGS_CONNECTABLE(child_start->next->data));
466 
467     g_signal_connect((GObject *) child_start->next->data, "control-changed",
468 		     G_CALLBACK(ags_fm_syncsynth_fm_oscillator_control_changed_callback), (gpointer) fm_syncsynth);
469 
470     g_list_free(child_start);
471 
472     list = list->next;
473   }
474 
475   g_list_free(list_start);
476 
477   g_signal_connect((GObject *) fm_syncsynth->add, "clicked",
478 		   G_CALLBACK(ags_fm_syncsynth_add_callback), (gpointer) fm_syncsynth);
479 
480   g_signal_connect((GObject *) fm_syncsynth->remove, "clicked",
481 		   G_CALLBACK(ags_fm_syncsynth_remove_callback), (gpointer) fm_syncsynth);
482 
483   g_signal_connect((GObject *) fm_syncsynth->auto_update, "toggled",
484 		   G_CALLBACK(ags_fm_syncsynth_auto_update_callback), fm_syncsynth);
485 
486   g_signal_connect((GObject *) fm_syncsynth->update, "clicked",
487 		   G_CALLBACK(ags_fm_syncsynth_update_callback), (gpointer) fm_syncsynth);
488 
489   g_signal_connect((GObject *) fm_syncsynth->volume, "value-changed",
490 		   G_CALLBACK(ags_fm_syncsynth_volume_callback), (gpointer) fm_syncsynth);
491 }
492 
493 void
ags_fm_syncsynth_disconnect(AgsConnectable * connectable)494 ags_fm_syncsynth_disconnect(AgsConnectable *connectable)
495 {
496   AgsFMSyncsynth *fm_syncsynth;
497 
498   GList *list_start, *list;
499   GList *child_start;
500 
501   if((AGS_MACHINE_CONNECTED & (AGS_MACHINE(connectable)->flags)) == 0){
502     return;
503   }
504 
505   ags_fm_syncsynth_parent_connectable_interface->disconnect(connectable);
506 
507   /* AgsFMSyncsynth */
508   fm_syncsynth = AGS_FM_SYNCSYNTH(connectable);
509 
510   list =
511     list_start = gtk_container_get_children(GTK_CONTAINER(fm_syncsynth->fm_oscillator));
512 
513   while(list != NULL){
514     child_start = gtk_container_get_children(GTK_CONTAINER(list->data));
515 
516     ags_connectable_disconnect(AGS_CONNECTABLE(child_start->next->data));
517 
518     g_object_disconnect((GObject *) child_start->next->data,
519 			"any_signal::control-changed",
520 			G_CALLBACK(ags_fm_syncsynth_fm_oscillator_control_changed_callback),
521 			(gpointer) fm_syncsynth,
522 			NULL);
523 
524     g_list_free(child_start);
525 
526     list = list->next;
527   }
528 
529   g_list_free(list_start);
530 
531   g_object_disconnect((GObject *) fm_syncsynth->add,
532 		      "any_signal::clicked",
533 		      G_CALLBACK(ags_fm_syncsynth_add_callback),
534 		      (gpointer) fm_syncsynth,
535 		      NULL);
536 
537   g_object_disconnect((GObject *) fm_syncsynth->remove,
538 		      "any_signal::clicked",
539 		      G_CALLBACK(ags_fm_syncsynth_remove_callback),
540 		      (gpointer) fm_syncsynth,
541 		      NULL);
542 
543   g_object_disconnect((GObject *) fm_syncsynth->auto_update,
544 		      "any_signal::toggled",
545 		      G_CALLBACK(ags_fm_syncsynth_auto_update_callback),
546 		      fm_syncsynth,
547 		      NULL);
548 
549   g_object_disconnect((GObject *) fm_syncsynth->update,
550 		      "any_signal::clicked",
551 		      G_CALLBACK(ags_fm_syncsynth_update_callback),
552 		      (gpointer) fm_syncsynth,
553 		      NULL);
554 
555   g_object_disconnect((GObject *) fm_syncsynth->volume,
556 		      "any_signal::value-changed",
557 		      G_CALLBACK(ags_fm_syncsynth_volume_callback),
558 		      (gpointer) fm_syncsynth,
559 		      NULL);
560 }
561 
562 void
ags_fm_syncsynth_resize_audio_channels(AgsMachine * machine,guint audio_channels,guint audio_channels_old,gpointer data)563 ags_fm_syncsynth_resize_audio_channels(AgsMachine *machine,
564 				       guint audio_channels, guint audio_channels_old,
565 				       gpointer data)
566 {
567   AgsFMSyncsynth *fm_syncsynth;
568 
569   fm_syncsynth = (AgsFMSyncsynth *) machine;
570 
571   if(audio_channels > audio_channels_old){
572     /* recall */
573     if((AGS_MACHINE_MAPPED_RECALL & (machine->flags)) != 0){
574       ags_fm_syncsynth_input_map_recall(fm_syncsynth,
575 					audio_channels_old,
576 					0);
577 
578       ags_fm_syncsynth_output_map_recall(fm_syncsynth,
579 					 audio_channels_old,
580 					 0);
581     }
582   }
583 }
584 
585 void
ags_fm_syncsynth_resize_pads(AgsMachine * machine,GType type,guint pads,guint pads_old,gpointer data)586 ags_fm_syncsynth_resize_pads(AgsMachine *machine, GType type,
587 			     guint pads, guint pads_old,
588 			     gpointer data)
589 {
590   AgsFMSyncsynth *fm_syncsynth;
591 
592   gboolean grow;
593 
594   if(pads == pads_old){
595     return;
596   }
597 
598   fm_syncsynth = (AgsFMSyncsynth *) machine;
599 
600   if(pads_old < pads){
601     grow = TRUE;
602   }else{
603     grow = FALSE;
604   }
605 
606   if(type == AGS_TYPE_INPUT){
607     if(grow){
608       if((AGS_MACHINE_MAPPED_RECALL & (machine->flags)) != 0){
609 	/* depending on destination */
610 	ags_fm_syncsynth_input_map_recall(fm_syncsynth,
611 					  0,
612 					  pads_old);
613       }
614     }else{
615       fm_syncsynth->mapped_input_pad = pads;
616     }
617   }else{
618     if(grow){
619       if((AGS_MACHINE_MAPPED_RECALL & (machine->flags)) != 0){
620 	ags_fm_syncsynth_output_map_recall(fm_syncsynth,
621 					   0,
622 					   pads_old);
623       }
624     }else{
625       fm_syncsynth->mapped_output_pad = pads;
626     }
627   }
628 }
629 
630 void
ags_fm_syncsynth_map_recall(AgsMachine * machine)631 ags_fm_syncsynth_map_recall(AgsMachine *machine)
632 {
633   AgsFMSyncsynth *fm_syncsynth;
634 
635   AgsAudio *audio;
636 
637   GList *start_recall, *recall;
638 
639   gint position;
640 
641   if((AGS_MACHINE_MAPPED_RECALL & (machine->flags)) != 0 ||
642      (AGS_MACHINE_PREMAPPED_RECALL & (machine->flags)) != 0){
643     return;
644   }
645 
646   fm_syncsynth = AGS_FM_SYNCSYNTH(machine);
647 
648   audio = machine->audio;
649 
650   position = 0;
651 
652   /* ags-fx-playback */
653   start_recall = ags_fx_factory_create(audio,
654 				       fm_syncsynth->playback_play_container, fm_syncsynth->playback_recall_container,
655 				       "ags-fx-playback",
656 				       NULL,
657 				       NULL,
658 				       0, 0,
659 				       0, 0,
660 				       position,
661 				       (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT),
662 				       0);
663 
664   g_list_free_full(start_recall,
665 		   (GDestroyNotify) g_object_unref);
666 
667   /* ags-fx-notation */
668   start_recall = ags_fx_factory_create(audio,
669 				       fm_syncsynth->notation_play_container, fm_syncsynth->notation_recall_container,
670 				       "ags-fx-notation",
671 				       NULL,
672 				       NULL,
673 				       0, 0,
674 				       0, 0,
675 				       position,
676 				       (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT),
677 				       0);
678 
679   g_list_free_full(start_recall,
680 		   (GDestroyNotify) g_object_unref);
681 
682   /* ags-fx-volume */
683   start_recall = ags_fx_factory_create(audio,
684 				       fm_syncsynth->volume_play_container, fm_syncsynth->volume_recall_container,
685 				       "ags-fx-volume",
686 				       NULL,
687 				       NULL,
688 				       0, 0,
689 				       0, 0,
690 				       position,
691 				       (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT),
692 				       0);
693 
694   g_list_free_full(start_recall,
695 		   (GDestroyNotify) g_object_unref);
696 
697   /* ags-fx-envelope */
698   start_recall = ags_fx_factory_create(audio,
699 				       fm_syncsynth->envelope_play_container, fm_syncsynth->envelope_recall_container,
700 				       "ags-fx-envelope",
701 				       NULL,
702 				       NULL,
703 				       0, 0,
704 				       0, 0,
705 				       position,
706 				       (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT),
707 				       0);
708 
709   g_list_free_full(start_recall,
710 		   (GDestroyNotify) g_object_unref);
711 
712   /* ags-fx-buffer */
713   start_recall = ags_fx_factory_create(audio,
714 				       fm_syncsynth->buffer_play_container, fm_syncsynth->buffer_recall_container,
715 				       "ags-fx-buffer",
716 				       NULL,
717 				       NULL,
718 				       0, 0,
719 				       0, 0,
720 				       position,
721 				       (AGS_FX_FACTORY_ADD | AGS_FX_FACTORY_INPUT),
722 				       0);
723 
724   g_list_free_full(start_recall,
725 		   (GDestroyNotify) g_object_unref);
726 
727   /* depending on destination */
728   ags_fm_syncsynth_input_map_recall(fm_syncsynth,
729 				    0,
730 				    0);
731 
732   /* depending on destination */
733   ags_fm_syncsynth_output_map_recall(fm_syncsynth,
734 				     0,
735 				     0);
736 
737   /* call parent */
738   AGS_MACHINE_CLASS(ags_fm_syncsynth_parent_class)->map_recall(machine);
739 }
740 
741 void
ags_fm_syncsynth_input_map_recall(AgsFMSyncsynth * fm_syncsynth,guint audio_channel_start,guint input_pad_start)742 ags_fm_syncsynth_input_map_recall(AgsFMSyncsynth *fm_syncsynth,
743 				  guint audio_channel_start,
744 				  guint input_pad_start)
745 {
746   AgsAudio *audio;
747 
748   GList *start_recall;
749 
750   gint position;
751   guint input_pads;
752   guint audio_channels;
753 
754   if(fm_syncsynth->mapped_input_pad > input_pad_start){
755     return;
756   }
757 
758   audio = AGS_MACHINE(fm_syncsynth)->audio;
759 
760   position = 0;
761 
762   input_pads = 0;
763   audio_channels = 0;
764 
765   /* get some fields */
766   g_object_get(audio,
767 	       "input-pads", &input_pads,
768 	       "audio-channels", &audio_channels,
769 	       NULL);
770 
771   /* ags-fx-playback */
772   start_recall = ags_fx_factory_create(audio,
773 				       fm_syncsynth->playback_play_container, fm_syncsynth->playback_recall_container,
774 				       "ags-fx-playback",
775 				       NULL,
776 				       NULL,
777 				       audio_channel_start, audio_channels,
778 				       input_pad_start, input_pads,
779 				       position,
780 				       (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
781 
782   g_list_free_full(start_recall,
783 		   (GDestroyNotify) g_object_unref);
784 
785   /* ags-fx-notation */
786   start_recall = ags_fx_factory_create(audio,
787 				       fm_syncsynth->notation_play_container, fm_syncsynth->notation_recall_container,
788 				       "ags-fx-notation",
789 				       NULL,
790 				       NULL,
791 				       audio_channel_start, audio_channels,
792 				       input_pad_start, input_pads,
793 				       position,
794 				       (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
795 
796   g_list_free_full(start_recall,
797 		   (GDestroyNotify) g_object_unref);
798 
799   /* ags-fx-volume */
800   start_recall = ags_fx_factory_create(audio,
801 				       fm_syncsynth->volume_play_container, fm_syncsynth->volume_recall_container,
802 				       "ags-fx-volume",
803 				       NULL,
804 				       NULL,
805 				       audio_channel_start, audio_channels,
806 				       input_pad_start, input_pads,
807 				       position,
808 				       (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
809 
810   g_list_free_full(start_recall,
811 		   (GDestroyNotify) g_object_unref);
812 
813   /* ags-fx-envelope */
814   start_recall = ags_fx_factory_create(audio,
815 				       fm_syncsynth->envelope_play_container, fm_syncsynth->envelope_recall_container,
816 				       "ags-fx-envelope",
817 				       NULL,
818 				       NULL,
819 				       audio_channel_start, audio_channels,
820 				       input_pad_start, input_pads,
821 				       position,
822 				       (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
823 
824   g_list_free_full(start_recall,
825 		   (GDestroyNotify) g_object_unref);
826 
827   /* ags-fx-buffer */
828   start_recall = ags_fx_factory_create(audio,
829 				       fm_syncsynth->buffer_play_container, fm_syncsynth->buffer_recall_container,
830 				       "ags-fx-buffer",
831 				       NULL,
832 				       NULL,
833 				       audio_channel_start, audio_channels,
834 				       input_pad_start, input_pads,
835 				       position,
836 				       (AGS_FX_FACTORY_REMAP | AGS_FX_FACTORY_INPUT), 0);
837 
838   g_list_free_full(start_recall,
839 		   (GDestroyNotify) g_object_unref);
840 
841   fm_syncsynth->mapped_input_pad = input_pads;
842 }
843 
844 void
ags_fm_syncsynth_output_map_recall(AgsFMSyncsynth * fm_syncsynth,guint audio_channel_start,guint output_pad_start)845 ags_fm_syncsynth_output_map_recall(AgsFMSyncsynth *fm_syncsynth,
846 				   guint audio_channel_start,
847 				   guint output_pad_start)
848 {
849   AgsAudio *audio;
850 
851   guint output_pads;
852 
853   if(fm_syncsynth->mapped_output_pad > output_pad_start){
854     return;
855   }
856 
857   audio = AGS_MACHINE(fm_syncsynth)->audio;
858 
859   /* get some fields */
860   g_object_get(audio,
861 	       "output-pads", &output_pads,
862 	       NULL);
863 
864   fm_syncsynth->mapped_output_pad = output_pads;
865 }
866 
867 /**
868  * ags_fm_syncsynth_test_flags:
869  * @fm_syncsynth: the #AgsFMSyncsynth
870  * @flags: the flags
871  *
872  * Test @flags of @fm_syncsynth.
873  *
874  * Returns: %TRUE on success, otherwise %FALSE
875  *
876  * Since: 3.2.15
877  */
878 gboolean
ags_fm_syncsynth_test_flags(AgsFMSyncsynth * fm_syncsynth,guint flags)879 ags_fm_syncsynth_test_flags(AgsFMSyncsynth *fm_syncsynth, guint flags)
880 {
881   gboolean success;
882 
883   if(!AGS_IS_FM_SYNCSYNTH(fm_syncsynth)){
884     return(FALSE);
885   }
886 
887   success = ((flags & (fm_syncsynth->flags))) ? TRUE: FALSE;
888 
889   return(success);
890 }
891 
892 /**
893  * ags_fm_syncsynth_set_flags:
894  * @fm_syncsynth: the #AgsFMSyncsynth
895  * @flags: the flags
896  *
897  * Set @flags of @fm_syncsynth.
898  *
899  * Since: 3.2.15
900  */
901 void
ags_fm_syncsynth_set_flags(AgsFMSyncsynth * fm_syncsynth,guint flags)902 ags_fm_syncsynth_set_flags(AgsFMSyncsynth *fm_syncsynth, guint flags)
903 {
904   if(!AGS_IS_FM_SYNCSYNTH(fm_syncsynth)){
905     return;
906   }
907 
908   fm_syncsynth->flags |= flags;
909 }
910 
911 /**
912  * ags_fm_syncsynth_unset_flags:
913  * @fm_syncsynth: the #AgsFMSyncsynth
914  * @flags: the flags
915  *
916  * Unset @flags of @fm_syncsynth.
917  *
918  * Since: 3.2.15
919  */
920 void
ags_fm_syncsynth_unset_flags(AgsFMSyncsynth * fm_syncsynth,guint flags)921 ags_fm_syncsynth_unset_flags(AgsFMSyncsynth *fm_syncsynth, guint flags)
922 {
923   if(!AGS_IS_FM_SYNCSYNTH(fm_syncsynth)){
924     return;
925   }
926 
927   fm_syncsynth->flags &= (~flags);
928 }
929 
930 /**
931  * ags_fm_syncsynth_add_fm_oscillator:
932  * @fm_syncsynth: the #AgsFMSyncsynth
933  * @fm_oscillator: the #AgsFMOscillator
934  *
935  * Add @fm_oscillator to @fm_syncsynth.
936  *
937  * Since: 3.0.0
938  */
939 void
ags_fm_syncsynth_add_fm_oscillator(AgsFMSyncsynth * fm_syncsynth,AgsFMOscillator * fm_oscillator)940 ags_fm_syncsynth_add_fm_oscillator(AgsFMSyncsynth *fm_syncsynth,
941 				   AgsFMOscillator *fm_oscillator)
942 {
943   AgsAudio *audio;
944 
945   GtkBox *hbox;
946   GtkCheckButton *check_button;
947 
948   audio = AGS_MACHINE(fm_syncsynth)->audio;
949   ags_audio_add_synth_generator(audio,
950 				(GObject *) ags_synth_generator_new());
951 
952   hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
953 				0);
954 
955   check_button = (GtkCheckButton *) gtk_check_button_new();
956   gtk_box_pack_start(hbox,
957 		     (GtkWidget *) check_button,
958 		     FALSE,
959 		     FALSE,
960 		     0);
961 
962   gtk_box_pack_start(hbox,
963 		     (GtkWidget *) fm_oscillator,
964 		     FALSE,
965 		     FALSE,
966 		     0);
967 
968   gtk_box_pack_start(fm_syncsynth->fm_oscillator,
969 		     (GtkWidget *) hbox,
970 		     FALSE,
971 		     FALSE,
972 		     0);
973   gtk_widget_show_all((GtkWidget *) hbox);
974 }
975 
976 /**
977  * ags_fm_syncsynth_remove_fm_oscillator:
978  * @fm_syncsynth: the #AgsFMSyncsynth
979  * @nth: the nth #AgsFMOscillator
980  *
981  * Remove nth fm_oscillator.
982  *
983  * Since: 3.0.0
984  */
985 void
ags_fm_syncsynth_remove_fm_oscillator(AgsFMSyncsynth * fm_syncsynth,guint nth)986 ags_fm_syncsynth_remove_fm_oscillator(AgsFMSyncsynth *fm_syncsynth,
987 				      guint nth)
988 {
989   AgsAudio *audio;
990 
991   GList *list, *list_start;
992   GList *start_synth_generator;
993 
994   audio = AGS_MACHINE(fm_syncsynth)->audio;
995   g_object_get(audio,
996 	       "synth-generator", &start_synth_generator,
997 	       NULL);
998 
999   start_synth_generator = g_list_reverse(start_synth_generator);
1000   ags_audio_remove_synth_generator(audio,
1001 				   g_list_nth_data(start_synth_generator,
1002 						   nth));
1003 
1004   g_list_free_full(start_synth_generator,
1005 		   g_object_unref);
1006 
1007   list_start = gtk_container_get_children(GTK_CONTAINER(fm_syncsynth->fm_oscillator));
1008 
1009   list = g_list_nth(list_start,
1010 		    nth);
1011 
1012   if(list != NULL){
1013     gtk_widget_destroy(list->data);
1014   }
1015 
1016   g_list_free(list_start);
1017 }
1018 
1019 /**
1020  * ags_fm_syncsynth_reset_loop:
1021  * @fm_syncsynth: the #AgsFMSyncsynth
1022  *
1023  * Reset loop spin buttons.
1024  *
1025  * Since: 3.0.0
1026  */
1027 void
ags_fm_syncsynth_reset_loop(AgsFMSyncsynth * fm_syncsynth)1028 ags_fm_syncsynth_reset_loop(AgsFMSyncsynth *fm_syncsynth)
1029 {
1030   GList *list, *list_start;
1031   GList *child_start;
1032 
1033   gdouble loop_upper, tmp0, tmp1;
1034 
1035   loop_upper = 0.0;
1036 
1037   list =
1038     list_start = gtk_container_get_children(GTK_CONTAINER(fm_syncsynth->fm_oscillator));
1039 
1040   while(list != NULL){
1041     child_start = gtk_container_get_children(GTK_CONTAINER(list->data));
1042 
1043     tmp0 = gtk_spin_button_get_value(AGS_FM_OSCILLATOR(child_start->next->data)->frame_count);
1044     tmp1 = gtk_spin_button_get_value(AGS_FM_OSCILLATOR(child_start->next->data)->attack);
1045 
1046     if(tmp0 + tmp1 > loop_upper){
1047       loop_upper = tmp0 + tmp1;
1048     }
1049 
1050     g_list_free(child_start);
1051 
1052     list = list->next;
1053   }
1054 
1055   g_list_free(list_start);
1056 
1057   gtk_spin_button_set_range(fm_syncsynth->loop_start,
1058 			    0.0, loop_upper);
1059   gtk_spin_button_set_range(fm_syncsynth->loop_end,
1060 			    0.0, loop_upper);
1061 }
1062 
1063 /**
1064  * ags_fm_syncsynth_update:
1065  * @fm_syncsynth: the #AgsFMSyncsynth
1066  *
1067  * Update audio data.
1068  *
1069  * Since: 3.0.0
1070  */
1071 void
ags_fm_syncsynth_update(AgsFMSyncsynth * fm_syncsynth)1072 ags_fm_syncsynth_update(AgsFMSyncsynth *fm_syncsynth)
1073 {
1074   AgsFMOscillator *fm_oscillator;
1075 
1076   AgsAudio *audio;
1077   AgsChannel *start_input;
1078   AgsChannel *channel, *next_channel;
1079 
1080   AgsClearAudioSignal *clear_audio_signal;
1081   AgsApplySynth *apply_synth;
1082 
1083   AgsApplicationContext *application_context;
1084 
1085   GList *list, *list_start;
1086   GList *start_synth_generator, *synth_generator;
1087   GList *child_start;
1088   GList *task;
1089 
1090   guint input_lines;
1091   guint requested_frame_count;
1092   guint buffer_size;
1093   guint format;
1094   guint attack, frame_count;
1095   guint loop_start, loop_end;
1096   gdouble frequency, phase, start_frequency;
1097   gdouble volume;
1098   gdouble fm_lfo_frequency, fm_lfo_depth;
1099   gdouble fm_tuning;
1100 
1101   guint sync_point_count;
1102 
1103   application_context = ags_application_context_get_instance();
1104 
1105   audio = AGS_MACHINE(fm_syncsynth)->audio;
1106 
1107   /*  */
1108   start_frequency = (gdouble) gtk_spin_button_get_value(fm_syncsynth->lower);
1109 
1110   /* clear input */
1111   g_object_get(audio,
1112 	       "input", &start_input,
1113 	       NULL);
1114 
1115   channel = start_input;
1116 
1117   if(channel != NULL){
1118     g_object_ref(channel);
1119   }
1120 
1121   next_channel = NULL;
1122 
1123   task = NULL;
1124 
1125   while(channel != NULL){
1126     AgsRecycling *first_recycling;
1127     AgsAudioSignal *template;
1128 
1129     GList *start_list;
1130 
1131     g_object_get(channel,
1132 		 "first-recycling", &first_recycling,
1133 		 NULL);
1134 
1135     g_object_get(first_recycling,
1136 		 "audio-signal", &start_list,
1137 		 NULL);
1138 
1139     /* clear task */
1140     template = ags_audio_signal_get_template(start_list);
1141 
1142     clear_audio_signal = ags_clear_audio_signal_new(template);
1143     task = g_list_prepend(task,
1144 			  clear_audio_signal);
1145 
1146     g_list_free_full(start_list,
1147 		     g_object_unref);
1148 
1149     g_object_unref(first_recycling);
1150     g_object_unref(template);
1151 
1152     /* iterate */
1153     next_channel = ags_channel_next(channel);
1154 
1155     g_object_unref(channel);
1156 
1157     channel = next_channel;
1158   }
1159 
1160   if(next_channel != NULL){
1161     g_object_unref(next_channel);
1162   }
1163 
1164   /* write input */
1165   list =
1166     list_start = gtk_container_get_children(GTK_CONTAINER(fm_syncsynth->fm_oscillator));
1167 
1168   /* get some fields */
1169   g_object_get(audio,
1170 	       "input-lines", &input_lines,
1171 	       "synth-generator", &start_synth_generator,
1172 	       NULL);
1173 
1174   g_object_get(start_input,
1175 	       "buffer-size", &buffer_size,
1176 	       "format", &format,
1177 	       NULL);
1178 
1179   loop_start = (guint) gtk_spin_button_get_value_as_int(fm_syncsynth->loop_start);
1180   loop_end = (guint) gtk_spin_button_get_value_as_int(fm_syncsynth->loop_end);
1181 
1182   requested_frame_count = 0;
1183 
1184   while(list != NULL){
1185     guint current_frame_count;
1186 
1187     child_start = gtk_container_get_children(GTK_CONTAINER(list->data));
1188 
1189     fm_oscillator = AGS_FM_OSCILLATOR(child_start->next->data);
1190 
1191     current_frame_count = gtk_spin_button_get_value(fm_oscillator->attack) + gtk_spin_button_get_value(fm_oscillator->frame_count);
1192 
1193     if(requested_frame_count < current_frame_count){
1194       requested_frame_count = current_frame_count;
1195     }
1196 
1197     list = list->next;
1198   }
1199 
1200   list = list_start;
1201 
1202   synth_generator = start_synth_generator;
1203 
1204   while(list != NULL){
1205     guint i;
1206     gboolean do_sync;
1207 
1208     /* do it so */
1209     child_start = gtk_container_get_children(GTK_CONTAINER(list->data));
1210 
1211     fm_oscillator = AGS_FM_OSCILLATOR(child_start->next->data);
1212 
1213     g_list_free(child_start);
1214 
1215     attack = (guint) gtk_spin_button_get_value_as_int(fm_oscillator->attack);
1216     frame_count = (guint) gtk_spin_button_get_value_as_int(fm_oscillator->frame_count);
1217     phase = (gdouble) gtk_spin_button_get_value(fm_oscillator->phase);
1218     frequency = (gdouble) gtk_spin_button_get_value(fm_oscillator->frequency);
1219     volume = (gdouble) gtk_spin_button_get_value(fm_oscillator->volume);
1220 
1221     fm_lfo_frequency = gtk_spin_button_get_value(fm_oscillator->fm_lfo_frequency);
1222     fm_lfo_depth = gtk_spin_button_get_value(fm_oscillator->fm_lfo_depth);
1223 
1224     fm_tuning = gtk_spin_button_get_value(fm_oscillator->fm_tuning);
1225 
1226     g_object_set(synth_generator->data,
1227 		 "format", format,
1228 		 "delay", (gdouble) attack / buffer_size,
1229 		 "attack", attack,
1230 		 "frame-count", frame_count,
1231 		 "loop-start", loop_start,
1232 		 "loop-end", loop_end,
1233 		 "oscillator", gtk_combo_box_get_active(fm_oscillator->wave),
1234 		 "frequency", frequency,
1235 		 "phase", phase,
1236 		 "volume", volume,
1237 		 "do-fm-synth", TRUE,
1238 		 "fm-lfo-oscillator", gtk_combo_box_get_active(fm_oscillator->fm_lfo_wave),
1239 		 "fm-lfo-frequency", fm_lfo_frequency,
1240 		 "fm-lfo-depth", fm_lfo_depth,
1241 		 "fm-tuning", fm_tuning,
1242 		 NULL);
1243 
1244     do_sync = gtk_toggle_button_get_active((GtkToggleButton *) fm_oscillator->do_sync);
1245 
1246     if(do_sync){
1247       sync_point_count = fm_oscillator->sync_point_count;
1248 
1249       /* free previous sync point */
1250       if(AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point != NULL){
1251 	for(i = 0; i < AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point_count; i++){
1252 	  ags_complex_free(AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point[i]);
1253 	}
1254 
1255 	free(AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point);
1256       }
1257 
1258       /* set new sync point */
1259       if(sync_point_count > 0){
1260 	AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point = (AgsComplex **) malloc(sync_point_count * sizeof(AgsComplex *));
1261       }else{
1262 	AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point = NULL;
1263       }
1264 
1265       AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point_count = sync_point_count;
1266 
1267       for(i = 0; i < sync_point_count; i++){
1268 	AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point[i] = ags_complex_alloc();
1269 
1270 	AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point[i][0].real = gtk_spin_button_get_value(fm_oscillator->sync_point[2 * i]);
1271 	AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point[i][0].imag = gtk_spin_button_get_value(fm_oscillator->sync_point[2 * i + 1]);
1272       }
1273     }else{
1274       for(i = 0; i < AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point_count; i++){
1275 	ags_complex_free(AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point[i]);
1276       }
1277 
1278       free(AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point);
1279 
1280       AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point = NULL;
1281       AGS_SYNTH_GENERATOR(synth_generator->data)->sync_point_count = 0;
1282     }
1283 
1284     apply_synth = ags_apply_synth_new(synth_generator->data,
1285 				      start_input,
1286 				      start_frequency, input_lines);
1287     g_object_set(apply_synth,
1288 		 "requested-frame-count", requested_frame_count,
1289 		 NULL);
1290 
1291     task = g_list_prepend(task,
1292 			  apply_synth);
1293 
1294     /* iterate */
1295     synth_generator = synth_generator->next;
1296 
1297     list = list->next;
1298   }
1299 
1300   g_list_free_full(start_synth_generator,
1301 		   g_object_unref);
1302 
1303   g_list_free(list_start);
1304 
1305   ags_ui_provider_schedule_task_all(AGS_UI_PROVIDER(application_context),
1306 				    g_list_reverse(task));
1307 }
1308 
1309 /**
1310  * ags_fm_syncsynth_new:
1311  * @soundcard: the assigned soundcard.
1312  *
1313  * Create a new instance of #AgsFMSyncsynth
1314  *
1315  * Returns: the new #AgsFMSyncsynth
1316  *
1317  * Since: 3.0.0
1318  */
1319 AgsFMSyncsynth*
ags_fm_syncsynth_new(GObject * soundcard)1320 ags_fm_syncsynth_new(GObject *soundcard)
1321 {
1322   AgsFMSyncsynth *fm_syncsynth;
1323 
1324   fm_syncsynth = (AgsFMSyncsynth *) g_object_new(AGS_TYPE_FM_SYNCSYNTH,
1325 						 NULL);
1326 
1327   g_object_set(AGS_MACHINE(fm_syncsynth)->audio,
1328 	       "output-soundcard", soundcard,
1329 	       NULL);
1330 
1331   return(fm_syncsynth);
1332 }
1333