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