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/ags_machine_callbacks.h>
21 
22 #include <ags/X/ags_ui_provider.h>
23 #include <ags/X/ags_window.h>
24 #include <ags/X/ags_pad.h>
25 #include <ags/X/ags_automation_editor.h>
26 #include <ags/X/ags_notation_editor.h>
27 #include <ags/X/ags_machine_editor.h>
28 #include <ags/X/ags_connection_editor.h>
29 #include <ags/X/ags_midi_dialog.h>
30 
31 #include <ags/X/export/ags_wave_export_dialog.h>
32 
33 #include <ags/X/editor/ags_envelope_dialog.h>
34 #include <ags/X/editor/ags_machine_radio_button.h>
35 
36 #include <ags/i18n.h>
37 
38 #define AGS_RENAME_ENTRY "AgsRenameEntry"
39 
40 void ags_machine_recall_set_loop(AgsMachine *machine,
41 				 AgsRecall *recall);
42 
43 int ags_machine_popup_rename_response_callback(GtkWidget *widget, gint response, AgsMachine *machine);
44 int ags_machine_popup_rename_audio_response_callback(GtkWidget *widget, gint response, AgsMachine *machine);
45 int ags_machine_popup_reposition_audio_response_callback(GtkWidget *widget, gint response, AgsMachine *machine);
46 int ags_machine_popup_properties_destroy_callback(GtkWidget *widget, AgsMachine *machine);
47 
48 void
ags_machine_parent_set_callback(GtkWidget * widget,GtkWidget * old_parent,AgsMachine * machine)49 ags_machine_parent_set_callback(GtkWidget *widget, GtkWidget *old_parent, AgsMachine *machine)
50 {
51   AgsAudio *audio;
52   AgsPlaybackDomain *playback_domain;
53 
54   guint i;
55 
56   static const guint staging_program[] = {
57     (AGS_SOUND_STAGING_AUTOMATE | AGS_SOUND_STAGING_RUN_INTER | AGS_SOUND_STAGING_FX),
58   };
59 
60   if(old_parent != NULL){
61     return;
62   }
63 
64   audio = machine->audio;
65 
66   g_object_get(audio,
67 	       "playback-domain", &playback_domain,
68 	       NULL);
69 
70   if(playback_domain != NULL){
71     for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
72       AgsThread *audio_thread;
73 
74       audio_thread = ags_playback_domain_get_audio_thread(playback_domain,
75 							  i);
76 
77       if(audio_thread != NULL){
78 	ags_audio_thread_set_do_fx_staging((AgsAudioThread *) audio_thread,
79 					   TRUE);
80 	ags_audio_thread_set_staging_program((AgsAudioThread *) audio_thread,
81 					     staging_program,
82 					     1);
83 
84 	g_object_unref(audio_thread);
85       }
86     }
87 
88     g_object_unref(playback_domain);
89   }
90 }
91 
92 void
ags_machine_check_message_callback(GObject * application_context,AgsMachine * machine)93 ags_machine_check_message_callback(GObject *application_context, AgsMachine *machine)
94 {
95   ags_machine_check_message(machine);
96 }
97 
98 void
ags_machine_recall_set_loop(AgsMachine * machine,AgsRecall * recall)99 ags_machine_recall_set_loop(AgsMachine *machine,
100 			    AgsRecall *recall)
101 {
102   AgsNavigation *navigation;
103   AgsPort *port;
104 
105   AgsApplicationContext *application_context;
106 
107   GValue value = G_VALUE_INIT;
108 
109   application_context = ags_application_context_get_instance();
110 
111   navigation = ags_ui_provider_get_navigation(AGS_UI_PROVIDER(application_context));
112 
113   /* loop */
114   port = NULL;
115 
116   g_object_get(recall,
117 	       "loop", &port,
118 	       NULL);
119 
120   g_value_init(&value,
121 	       G_TYPE_BOOLEAN);
122 
123   g_value_set_boolean(&value,
124 		      gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(navigation->loop)));
125 
126   ags_port_safe_write(port,
127 		      &value);
128 
129   if(port != NULL){
130     g_object_unref(port);
131   }
132 
133   /* loop start */
134   port = NULL;
135 
136   g_object_get(recall,
137 	       "loop-start", &port,
138 	       NULL);
139 
140   g_value_unset(&value);
141   g_value_init(&value,
142 	       G_TYPE_UINT64);
143 
144   g_value_set_uint64(&value,
145 		     16 * gtk_spin_button_get_value_as_int(navigation->loop_left_tact));
146 
147   ags_port_safe_write(port,
148 		      &value);
149 
150   if(port != NULL){
151     g_object_unref(port);
152   }
153 
154   /* loop end */
155   port = NULL;
156 
157   g_object_get(recall,
158 	       "loop-end", &port,
159 	       NULL);
160 
161   g_value_unset(&value);
162   g_value_init(&value,
163 	       G_TYPE_UINT64);
164 
165   g_value_set_uint64(&value,
166 		     16 * gtk_spin_button_get_value_as_int(navigation->loop_right_tact));
167 
168   ags_port_safe_write(port,
169 		      &value);
170 
171   if(port != NULL){
172     g_object_unref(port);
173   }
174 }
175 
176 void
ags_machine_map_recall_callback(AgsMachine * machine,gpointer user_data)177 ags_machine_map_recall_callback(AgsMachine *machine,
178 				gpointer user_data)
179 {
180   GList *start_play;
181   GList *start_recall;
182   GList *list;
183 
184   start_play = NULL;
185   start_recall = NULL;
186 
187   g_object_get(machine->audio,
188 	       "play", &start_play,
189 	       "recall", &start_recall,
190 	       NULL);
191 
192   list = start_play;
193 
194   while((list = ags_recall_template_find_type(list, AGS_TYPE_FX_NOTATION_AUDIO)) != NULL){
195     ags_machine_recall_set_loop(machine,
196 				list->data);
197 
198     /* iterate */
199     list = list->next;
200   }
201 
202   list = start_play;
203 
204   while((list = ags_recall_template_find_type(list, AGS_TYPE_FX_PLAYBACK_AUDIO)) != NULL){
205     ags_machine_recall_set_loop(machine,
206 				list->data);
207 
208     /* iterate */
209     list = list->next;
210   }
211 
212   list = start_recall;
213 
214   while((list = ags_recall_template_find_type(list, AGS_TYPE_FX_NOTATION_AUDIO)) != NULL){
215     ags_machine_recall_set_loop(machine,
216 				list->data);
217 
218     /* iterate */
219     list = list->next;
220   }
221 
222   list = start_recall;
223 
224   while((list = ags_recall_template_find_type(list, AGS_TYPE_FX_PLAYBACK_AUDIO)) != NULL){
225     ags_machine_recall_set_loop(machine,
226 				list->data);
227 
228     /* iterate */
229     list = list->next;
230   }
231 
232   g_list_free_full(start_play,
233 		   (GDestroyNotify) g_object_unref);
234 
235   g_list_free_full(start_recall,
236 		   (GDestroyNotify) g_object_unref);
237 }
238 
239 int
ags_machine_button_press_callback(GtkWidget * handle_box,GdkEventButton * event,AgsMachine * machine)240 ags_machine_button_press_callback(GtkWidget *handle_box, GdkEventButton *event, AgsMachine *machine)
241 {
242   if(event->button == 3){
243     gtk_menu_popup_at_widget(GTK_MENU(machine->popup),
244 			     handle_box,
245 			     GDK_GRAVITY_SOUTH_EAST,
246 			     GDK_GRAVITY_NORTH_WEST,
247 			     NULL);
248   }else if(event->button == 1){
249     AgsWindow *window;
250 
251     AgsApplicationContext *application_context;
252 
253     application_context = ags_application_context_get_instance();
254 
255     window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
256 
257     window->selected = machine;
258   }
259 
260   return(0);
261 }
262 
263 void
ags_machine_popup_move_up_activate_callback(GtkWidget * widget,AgsMachine * machine)264 ags_machine_popup_move_up_activate_callback(GtkWidget *widget, AgsMachine *machine)
265 {
266   GValue val = G_VALUE_INIT;
267 
268   g_value_init(&val,
269 	       G_TYPE_INT);
270 
271   gtk_container_child_get_property(GTK_CONTAINER(gtk_widget_get_parent(GTK_WIDGET(machine))),
272 				   GTK_WIDGET(machine),
273 				   "position", &val);
274 
275   if(g_value_get_int (&val) > 0){
276     gtk_box_reorder_child(GTK_BOX(gtk_widget_get_parent(GTK_WIDGET(machine))),
277 			  GTK_WIDGET(machine),
278 			  g_value_get_int (&val) - 1);
279   }
280 
281   g_value_unset (&val);
282 }
283 
284 void
ags_machine_popup_move_down_activate_callback(GtkWidget * widget,AgsMachine * machine)285 ags_machine_popup_move_down_activate_callback(GtkWidget *widget, AgsMachine *machine)
286 {
287   GList *start_list;
288 
289   GValue val={0,};
290 
291   g_value_init (&val, G_TYPE_INT);
292 
293   gtk_container_child_get_property(GTK_CONTAINER(gtk_widget_get_parent(GTK_WIDGET(machine))),
294 				   GTK_WIDGET(machine),
295 				   "position", &val);
296 
297   start_list = gtk_container_get_children((GtkContainer *) gtk_widget_get_parent(GTK_WIDGET(machine)));
298 
299   if(g_value_get_int (&val) < g_list_length(start_list) - 1){
300     gtk_box_reorder_child(GTK_BOX(gtk_widget_get_parent(GTK_WIDGET(machine))),
301 			  GTK_WIDGET(machine),
302 			  g_value_get_int (&val) + 1);
303   }
304 
305   g_value_unset (&val);
306 
307   g_list_free(start_list);
308 }
309 
310 void
ags_machine_popup_hide_activate_callback(GtkWidget * widget,AgsMachine * machine)311 ags_machine_popup_hide_activate_callback(GtkWidget *widget, AgsMachine *machine)
312 {
313   GList *start_list;
314 
315   start_list = gtk_container_get_children((GtkContainer *) machine);
316 
317   gtk_widget_hide(gtk_bin_get_child(GTK_BIN(start_list->data)));
318 
319   g_list_free(start_list);
320 }
321 
322 void
ags_machine_popup_show_activate_callback(GtkWidget * widget,AgsMachine * machine)323 ags_machine_popup_show_activate_callback(GtkWidget *widget, AgsMachine *machine)
324 {
325   GList *start_list;
326 
327   start_list = gtk_container_get_children((GtkContainer *) machine);
328 
329   gtk_widget_show(gtk_bin_get_child(GTK_BIN(start_list->data)));
330 
331   g_list_free(start_list);
332 }
333 
334 void
ags_machine_popup_destroy_activate_callback(GtkWidget * widget,AgsMachine * machine)335 ags_machine_popup_destroy_activate_callback(GtkWidget *widget, AgsMachine *machine)
336 {
337   AgsWindow *window;
338 
339   AgsAudio *audio;
340 
341   AgsRemoveAudio *remove_audio;
342 
343   AgsApplicationContext *application_context;
344 
345   GList *list, *list_start;
346 
347   window = (AgsWindow *) gtk_widget_get_toplevel((GtkWidget *) machine);
348 
349   application_context = ags_application_context_get_instance();
350 
351   ags_machine_set_run(machine,
352 		      FALSE);
353 
354   /* destroy editor */
355   list =
356     list_start = gtk_container_get_children((GtkContainer *) window->notation_editor->machine_selector);
357 
358   list = list->next;
359 
360   while(list != NULL){
361     if(AGS_IS_MACHINE_RADIO_BUTTON(list->data) && AGS_MACHINE_RADIO_BUTTON(list->data)->machine == machine){
362       gtk_widget_destroy(list->data);
363       break;
364     }
365 
366     list = list->next;
367   }
368 
369   g_list_free(list_start);
370 
371   /* destroy automation editor */
372   list =
373     list_start = gtk_container_get_children((GtkContainer *) window->automation_window->automation_editor->machine_selector);
374 
375   list = list->next;
376 
377   while(list != NULL){
378     if(AGS_IS_MACHINE_RADIO_BUTTON(list->data) && AGS_MACHINE_RADIO_BUTTON(list->data)->machine == machine){
379       gtk_widget_destroy(list->data);
380       break;
381     }
382 
383     list = list->next;
384   }
385 
386   g_list_free(list_start);
387 
388   /* destroy machine */
389   audio = machine->audio;
390   g_object_ref(audio);
391 
392   ags_connectable_disconnect(AGS_CONNECTABLE(machine));
393   gtk_widget_destroy((GtkWidget *) machine);
394 
395   /* get task thread */
396   remove_audio = ags_remove_audio_new(audio);
397 
398   ags_ui_provider_schedule_task(AGS_UI_PROVIDER(application_context),
399 				(AgsTask *) remove_audio);
400 }
401 
402 void
ags_machine_popup_rename_activate_callback(GtkWidget * widget,AgsMachine * machine)403 ags_machine_popup_rename_activate_callback(GtkWidget *widget, AgsMachine *machine)
404 {
405   GtkDialog *dialog;
406   GtkEntry *entry;
407 
408   if(machine->rename != NULL){
409     return;
410   }
411 
412   machine->rename =
413     dialog = (GtkDialog *) gtk_dialog_new_with_buttons(i18n("rename"),
414 						       (GtkWindow *) gtk_widget_get_toplevel(GTK_WIDGET(machine)),
415 						       GTK_DIALOG_DESTROY_WITH_PARENT,
416 						       "_OK", GTK_RESPONSE_ACCEPT,
417 						       "_Cancel", GTK_RESPONSE_REJECT,
418 						       NULL);
419 
420   entry = (GtkEntry *) gtk_entry_new();
421   gtk_entry_set_text(entry, machine->machine_name);
422   gtk_box_pack_start((GtkBox *) gtk_dialog_get_content_area(dialog),
423 		     (GtkWidget *) entry,
424 		     FALSE, FALSE,
425 		     0);
426 
427   gtk_widget_show_all((GtkWidget *) dialog);
428 
429   g_signal_connect((GObject *) dialog, "response",
430 		   G_CALLBACK(ags_machine_popup_rename_response_callback), (gpointer) machine);
431 }
432 
433 int
ags_machine_popup_rename_response_callback(GtkWidget * widget,gint response,AgsMachine * machine)434 ags_machine_popup_rename_response_callback(GtkWidget *widget, gint response, AgsMachine *machine)
435 {
436   if(response == GTK_RESPONSE_ACCEPT){
437     GList *children;
438 
439     gchar *str;
440 
441     children = gtk_container_get_children((GtkContainer *) gtk_dialog_get_content_area(GTK_DIALOG(widget)));
442 
443     str = gtk_editable_get_chars(GTK_EDITABLE(children->data),
444 				 0, -1);
445     g_object_set(machine,
446 		 "machine-name", str,
447 		 NULL);
448 
449     g_list_free(children);
450   }
451 
452   machine->rename = NULL;
453   gtk_widget_destroy(widget);
454 
455   return(0);
456 }
457 
458 void
ags_machine_popup_rename_audio_activate_callback(GtkWidget * widget,AgsMachine * machine)459 ags_machine_popup_rename_audio_activate_callback(GtkWidget *widget, AgsMachine *machine)
460 {
461   GtkDialog *dialog;
462   GtkEntry *entry;
463 
464   AgsAudio *audio;
465 
466   gchar *audio_name;
467 
468   if(machine->rename_audio != NULL){
469     return;
470   }
471 
472   audio = machine->audio;
473 
474   machine->rename_audio =
475     dialog = (GtkDialog *) gtk_dialog_new_with_buttons(i18n("rename audio"),
476 						       (GtkWindow *) gtk_widget_get_toplevel(GTK_WIDGET(machine)),
477 						       GTK_DIALOG_DESTROY_WITH_PARENT,
478 						       "_OK", GTK_RESPONSE_ACCEPT,
479 						       "_Cancel", GTK_RESPONSE_REJECT,
480 						       NULL);
481 
482   g_object_get(audio,
483 	       "audio-name", &audio_name,
484 	       NULL);
485 
486   entry = (GtkEntry *) gtk_entry_new();
487   gtk_entry_set_text(entry, audio_name);
488   gtk_box_pack_start((GtkBox *) gtk_dialog_get_content_area(dialog),
489 		     (GtkWidget *) entry,
490 		     FALSE, FALSE,
491 		     0);
492 
493   g_free(audio_name);
494 
495   gtk_widget_show_all((GtkWidget *) dialog);
496 
497   g_signal_connect((GObject *) dialog, "response",
498 		   G_CALLBACK(ags_machine_popup_rename_audio_response_callback), (gpointer) machine);
499 }
500 
501 int
ags_machine_popup_rename_audio_response_callback(GtkWidget * widget,gint response,AgsMachine * machine)502 ags_machine_popup_rename_audio_response_callback(GtkWidget *widget, gint response, AgsMachine *machine)
503 {
504   if(response == GTK_RESPONSE_ACCEPT){
505     GList *children;
506 
507     gchar *str;
508 
509     children = gtk_container_get_children((GtkContainer *) gtk_dialog_get_content_area(GTK_DIALOG(widget)));
510 
511     str = gtk_editable_get_chars(GTK_EDITABLE(children->data),
512 				 0, -1);
513     g_object_set(machine->audio,
514 		 "audio-name", str,
515 		 NULL);
516 
517     g_list_free(children);
518   }
519 
520   machine->rename_audio = NULL;
521   gtk_widget_destroy(widget);
522 
523   return(0);
524 }
525 
526 void
ags_machine_popup_reposition_audio_activate_callback(GtkWidget * widget,AgsMachine * machine)527 ags_machine_popup_reposition_audio_activate_callback(GtkWidget *widget, AgsMachine *machine)
528 {
529   GtkDialog *dialog;
530   GtkSpinButton *spin_button;
531 
532   AgsAudio *audio;
533 
534   AgsApplicationContext *application_context;
535 
536   GList *start_list;
537 
538   gint length;
539   gint position;
540 
541   if(machine->reposition_audio != NULL){
542     return;
543   }
544 
545   application_context = ags_application_context_get_instance();
546 
547   audio = machine->audio;
548 
549   start_list = ags_sound_provider_get_audio(AGS_SOUND_PROVIDER(application_context));
550 
551   length = g_list_length(start_list);
552   position = g_list_index(start_list,
553 			  audio);
554 
555   machine->reposition_audio =
556     dialog = (GtkDialog *) gtk_dialog_new_with_buttons(i18n("reposition audio"),
557 						       (GtkWindow *) gtk_widget_get_toplevel(GTK_WIDGET(machine)),
558 						       GTK_DIALOG_DESTROY_WITH_PARENT,
559 						       "_OK", GTK_RESPONSE_ACCEPT,
560 						       "_Cancel", GTK_RESPONSE_REJECT,
561 						       NULL);
562 
563   if(position >= 0){
564     spin_button = (GtkSpinButton *) gtk_spin_button_new_with_range(0.0, (gdouble) (length - 1), 1.0);
565   }else{
566     spin_button = (GtkSpinButton *) gtk_spin_button_new_with_range(-1.0, -1.0, 0.0);
567   }
568 
569   gtk_spin_button_set_value(spin_button,
570 			    (gdouble) position);
571   gtk_box_pack_start((GtkBox *) gtk_dialog_get_content_area(dialog),
572 		     (GtkWidget *) spin_button,
573 		     FALSE, FALSE,
574 		     0);
575 
576   gtk_widget_show_all((GtkWidget *) dialog);
577 
578   g_signal_connect((GObject *) dialog, "response",
579 		   G_CALLBACK(ags_machine_popup_reposition_audio_response_callback), (gpointer) machine);
580 
581   g_list_free_full(start_list,
582 		   g_object_unref);
583 }
584 
585 int
ags_machine_popup_reposition_audio_response_callback(GtkWidget * widget,gint response,AgsMachine * machine)586 ags_machine_popup_reposition_audio_response_callback(GtkWidget *widget, gint response, AgsMachine *machine)
587 {
588   if(response == GTK_RESPONSE_ACCEPT){
589     AgsAudio *audio;
590 
591     AgsApplicationContext *application_context;
592 
593     GList *children;
594     GList *start_list;
595 
596     gint new_position;
597 
598     application_context = ags_application_context_get_instance();
599 
600     audio = machine->audio;
601 
602     start_list = ags_sound_provider_get_audio(AGS_SOUND_PROVIDER(application_context));
603 
604     children = gtk_container_get_children((GtkContainer *) gtk_dialog_get_content_area(GTK_DIALOG(widget)));
605 
606     new_position = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(children->data));
607 
608     start_list = g_list_remove(start_list,
609 			       audio);
610     start_list = g_list_insert(start_list,
611 			       audio,
612 			       new_position);
613 
614     ags_sound_provider_set_audio(AGS_SOUND_PROVIDER(application_context),
615 				 start_list);
616     g_list_foreach(start_list,
617 		   (GFunc) g_object_unref,
618 		   NULL);
619 
620     g_list_free(children);
621   }
622 
623   machine->reposition_audio = NULL;
624   gtk_widget_destroy(widget);
625 
626   return(0);
627 }
628 
629 void
ags_machine_popup_properties_activate_callback(GtkWidget * widget,AgsMachine * machine)630 ags_machine_popup_properties_activate_callback(GtkWidget *widget, AgsMachine *machine)
631 {
632   machine->properties = (GtkDialog *) ags_machine_editor_new(machine);
633   g_signal_connect_after(machine->properties, "destroy",
634 			 G_CALLBACK(ags_machine_popup_properties_destroy_callback), machine);
635 
636   gtk_window_set_default_size((GtkWindow *) machine->properties, -1, 400);
637 
638   ags_connectable_connect(AGS_CONNECTABLE(machine->properties));
639 
640   ags_applicable_reset(AGS_APPLICABLE(machine->properties));
641 
642   gtk_widget_show_all((GtkWidget *) machine->properties);
643 }
644 
645 void
ags_machine_popup_sticky_controls_toggled_callback(GtkWidget * widget,AgsMachine * machine)646 ags_machine_popup_sticky_controls_toggled_callback(GtkWidget *widget, AgsMachine *machine)
647 {
648   if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))){
649     machine->flags |= AGS_MACHINE_STICKY_CONTROLS;
650   }else{
651     machine->flags &= (~AGS_MACHINE_STICKY_CONTROLS);
652   }
653 }
654 
655 int
ags_machine_popup_properties_destroy_callback(GtkWidget * widget,AgsMachine * machine)656 ags_machine_popup_properties_destroy_callback(GtkWidget *widget, AgsMachine *machine)
657 {
658   machine->properties = NULL;
659 
660   return(0);
661 }
662 
663 void
ags_machine_popup_copy_pattern_callback(GtkWidget * widget,AgsMachine * machine)664 ags_machine_popup_copy_pattern_callback(GtkWidget *widget, AgsMachine *machine)
665 {
666   ags_machine_copy_pattern(machine);
667 }
668 
669 void
ags_machine_popup_paste_pattern_callback(GtkWidget * widget,AgsMachine * machine)670 ags_machine_popup_paste_pattern_callback(GtkWidget *widget, AgsMachine *machine)
671 {
672   //TODO:JK: implement me
673 }
674 
675 void
ags_machine_popup_envelope_callback(GtkWidget * widget,AgsMachine * machine)676 ags_machine_popup_envelope_callback(GtkWidget *widget, AgsMachine *machine)
677 {
678   AgsEnvelopeDialog *envelope_dialog;
679 
680   if(machine->envelope_dialog == NULL){
681     envelope_dialog = ags_envelope_dialog_new(machine);
682 
683     if((AGS_MACHINE_IS_SEQUENCER & (machine->flags)) != 0){
684       ags_envelope_dialog_add_pattern_tab(envelope_dialog);
685     }
686 
687     machine->envelope_dialog = (GtkDialog *) envelope_dialog;
688 
689     ags_connectable_connect(AGS_CONNECTABLE(envelope_dialog));
690     ags_applicable_reset(AGS_APPLICABLE(envelope_dialog));
691 
692     gtk_widget_show_all((GtkWidget *) envelope_dialog);
693   }
694 }
695 
696 void
ags_machine_popup_connection_editor_callback(GtkWidget * widget,AgsMachine * machine)697 ags_machine_popup_connection_editor_callback(GtkWidget *widget, AgsMachine *machine)
698 {
699   AgsConnectionEditor *connection_editor;
700 
701   if(machine->connection_editor == NULL){
702     connection_editor = ags_connection_editor_new(NULL);
703 
704     if((AGS_MACHINE_SHOW_AUDIO_OUTPUT_CONNECTION & (machine->connection_flags)) != 0){
705       connection_editor->flags |= AGS_CONNECTION_EDITOR_SHOW_OUTPUT;
706     }
707 
708     if((AGS_MACHINE_SHOW_AUDIO_INPUT_CONNECTION & (machine->connection_flags)) != 0){
709       connection_editor->flags |= AGS_CONNECTION_EDITOR_SHOW_INPUT;
710     }
711 
712     ags_connection_editor_set_machine(connection_editor, machine);
713 
714     machine->connection_editor = (GtkDialog *) connection_editor;
715 
716     ags_connectable_connect(AGS_CONNECTABLE(connection_editor));
717     ags_applicable_reset(AGS_APPLICABLE(connection_editor));
718 
719     gtk_widget_show_all((GtkWidget *) connection_editor);
720   }else{
721     connection_editor = (AgsConnectionEditor *) machine->connection_editor;
722   }
723 
724   gtk_widget_show_all((GtkWidget *) connection_editor);
725 }
726 
727 void
ags_machine_popup_midi_dialog_callback(GtkWidget * widget,AgsMachine * machine)728 ags_machine_popup_midi_dialog_callback(GtkWidget *widget, AgsMachine *machine)
729 {
730   AgsMidiDialog *midi_dialog;
731 
732   if(machine->midi_dialog == NULL){
733     midi_dialog = ags_midi_dialog_new(machine);
734     machine->midi_dialog = (GtkDialog *) midi_dialog;
735     midi_dialog->flags |= (AGS_MIDI_DIALOG_IO_OPTIONS |
736 			   AGS_MIDI_DIALOG_MAPPING |
737 			   AGS_MIDI_DIALOG_DEVICE);
738 
739     ags_connectable_connect(AGS_CONNECTABLE(midi_dialog));
740     ags_applicable_reset(AGS_APPLICABLE(midi_dialog));
741 
742     gtk_widget_show_all((GtkWidget *) midi_dialog);
743   }else{
744     midi_dialog = (AgsMidiDialog *) machine->midi_dialog;
745   }
746 
747   gtk_widget_show_all((GtkWidget *) midi_dialog);
748 }
749 
750 void
ags_machine_popup_midi_export_callback(GtkWidget * widget,AgsMachine * machine)751 ags_machine_popup_midi_export_callback(GtkWidget *widget, AgsMachine *machine)
752 {
753   //TODO:JK: implement me
754 }
755 
756 void
ags_machine_popup_wave_export_callback(GtkWidget * widget,AgsMachine * machine)757 ags_machine_popup_wave_export_callback(GtkWidget *widget, AgsMachine *machine)
758 {
759   AgsWaveExportDialog *wave_export_dialog;
760 
761   if(machine->wave_export_dialog == NULL){
762     wave_export_dialog = ags_wave_export_dialog_new(machine);
763     machine->wave_export_dialog = (GtkDialog *) wave_export_dialog;
764 
765     ags_connectable_connect(AGS_CONNECTABLE(wave_export_dialog));
766     ags_applicable_reset(AGS_APPLICABLE(wave_export_dialog));
767 
768     gtk_widget_show_all((GtkWidget *) wave_export_dialog);
769   }else{
770     wave_export_dialog = (AgsWaveExportDialog *) machine->wave_export_dialog;
771   }
772 
773   gtk_widget_show_all((GtkWidget *) wave_export_dialog);
774 }
775 
776 void
ags_machine_popup_midi_import_callback(GtkWidget * widget,AgsMachine * machine)777 ags_machine_popup_midi_import_callback(GtkWidget *widget, AgsMachine *machine)
778 {
779   //TODO:JK: implement me
780 }
781 
782 void
ags_machine_popup_wave_import_callback(GtkWidget * widget,AgsMachine * machine)783 ags_machine_popup_wave_import_callback(GtkWidget *widget, AgsMachine *machine)
784 {
785   //TODO:JK: implement me
786 }
787 
788 void
ags_machine_open_response_callback(GtkDialog * dialog,gint response,AgsMachine * machine)789 ags_machine_open_response_callback(GtkDialog *dialog, gint response, AgsMachine *machine)
790 {
791   GtkFileChooserDialog *file_chooser;
792   GtkCheckButton *overwrite;
793   GtkCheckButton *create;
794   GSList *filenames;
795 
796   file_chooser = GTK_FILE_CHOOSER_DIALOG(dialog);
797 
798   if(response == GTK_RESPONSE_ACCEPT){
799     filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(file_chooser));
800     overwrite = g_object_get_data(G_OBJECT(dialog), "overwrite");
801     create = g_object_get_data(G_OBJECT(dialog), "create");
802 
803     ags_machine_open_files(machine,
804 			   filenames,
805 			   gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(overwrite)),
806 			   gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(create)));
807   }
808 
809   gtk_widget_destroy(GTK_WIDGET(file_chooser));
810 }
811 
812 void
ags_machine_play_callback(GtkWidget * toggle_button,AgsMachine * machine)813 ags_machine_play_callback(GtkWidget *toggle_button, AgsMachine *machine)
814 {
815   if(machine == NULL){
816     return;
817   }
818 
819   if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button))){
820     if((AGS_MACHINE_BLOCK_PLAY & (machine->flags)) != 0){
821       return;
822     }
823 
824     g_message("machine: on");
825 
826     machine->flags |= AGS_MACHINE_BLOCK_PLAY;
827 
828     ags_machine_set_run_extended(machine,
829 				 TRUE,
830 				 TRUE, FALSE, FALSE, FALSE);
831 
832     machine->flags &= (~AGS_MACHINE_BLOCK_PLAY);
833   }else{
834     if((AGS_MACHINE_BLOCK_STOP & (machine->flags)) != 0){
835       return;
836     }
837 
838     g_message("machine: off");
839 
840     machine->flags |= AGS_MACHINE_BLOCK_STOP;
841 
842     ags_machine_set_run_extended(machine,
843 				 FALSE,
844 				 TRUE, FALSE, FALSE, FALSE);
845 
846     machine->flags &= (~AGS_MACHINE_BLOCK_STOP);
847   }
848 }
849 
850 void
ags_machine_resize_audio_channels_callback(AgsMachine * machine,guint audio_channels,guint audio_channels_old,gpointer data)851 ags_machine_resize_audio_channels_callback(AgsMachine *machine,
852 					   guint audio_channels, guint audio_channels_old,
853 					   gpointer data)
854 {
855   AgsAudio *audio;
856   AgsPlayback *playback;
857   AgsChannel *start_output;
858   AgsChannel *start_input;
859   AgsChannel *channel, *next_pad, *next_channel;
860 
861   GList *pad_list;
862   GList *line_list;
863 
864   guint i;
865 
866   static const guint staging_program[] = {
867     (AGS_SOUND_STAGING_AUTOMATE | AGS_SOUND_STAGING_RUN_INTER | AGS_SOUND_STAGING_FX),
868   };
869 
870   audio = machine->audio;
871 
872   start_output = NULL;
873   start_input = NULL;
874 
875   g_object_get(audio,
876 	       "output", &start_output,
877 	       "input", &start_input,
878 	       NULL);
879 
880   if(audio_channels > audio_channels_old){
881     /* AgsOutput */
882     channel = start_output;
883 
884     if(channel != NULL){
885       g_object_ref(channel);
886     }
887 
888     next_pad = NULL;
889 
890     while(channel != NULL){
891       /* get some fields */
892       next_pad = ags_channel_next_pad(channel);
893 
894       next_channel = ags_channel_nth(channel,
895 				     audio_channels_old);
896 
897       if(channel != NULL){
898 	g_object_unref(channel);
899       }
900 
901       channel = next_channel;
902 
903       while(channel != next_pad && channel != NULL){
904 	/* fx engine */
905 	g_object_get(channel,
906 		     "playback", &playback,
907 		     NULL);
908 
909 	if(playback != NULL){
910 	  for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
911 	    AgsThread *channel_thread;
912 
913 	    channel_thread = ags_playback_get_channel_thread(playback,
914 							     i);
915 
916 	    if(channel_thread != NULL){
917 	      ags_channel_thread_set_do_fx_staging((AgsChannelThread *) channel_thread,
918 						   TRUE);
919 	      ags_channel_thread_set_staging_program((AgsChannelThread *) channel_thread,
920 						     staging_program,
921 						     1);
922 
923 	      g_object_unref(channel_thread);
924 	    }
925 	  }
926 
927 	  g_object_unref(playback);
928 	}
929 
930 	/* iterate */
931 	next_channel = ags_channel_next(channel);
932 
933 	g_object_unref(channel);
934 
935 	channel = next_channel;
936       }
937 
938       if(next_pad != NULL){
939 	g_object_unref(next_pad);
940       }
941     }
942 
943     if(channel != NULL){
944       g_object_unref(channel);
945     }
946 
947     /* AgsInput */
948     channel = start_input;
949 
950     if(channel != NULL){
951       g_object_ref(channel);
952     }
953 
954     next_pad = NULL;
955 
956     while(channel != NULL){
957       /* get some fields */
958       next_pad = ags_channel_next_pad(channel);
959 
960       next_channel = ags_channel_nth(channel,
961 				     audio_channels_old);
962 
963       if(channel != NULL){
964 	g_object_unref(channel);
965       }
966 
967       channel = next_channel;
968 
969       while(channel != next_pad && channel != NULL){
970 	/* fx engine */
971 	g_object_get(channel,
972 		     "playback", &playback,
973 		     NULL);
974 
975 	if(playback != NULL){
976 	  for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
977 	    AgsThread *channel_thread;
978 
979 	    channel_thread = ags_playback_get_channel_thread(playback,
980 							     i);
981 
982 	    if(channel_thread != NULL){
983 	      ags_channel_thread_set_do_fx_staging((AgsChannelThread *) channel_thread,
984 						   TRUE);
985 	      ags_channel_thread_set_staging_program((AgsChannelThread *) channel_thread,
986 						     staging_program,
987 						     1);
988 
989 	      g_object_unref(channel_thread);
990 	    }
991 	  }
992 
993 	  g_object_unref(playback);
994 	}
995 
996 	/* iterate */
997 	next_channel = ags_channel_next(channel);
998 
999 	g_object_unref(channel);
1000 
1001 	channel = next_channel;
1002       }
1003 
1004       if(next_pad != NULL){
1005 	g_object_unref(next_pad);
1006       }
1007     }
1008 
1009     if(channel != NULL){
1010       g_object_unref(channel);
1011     }
1012   }
1013 
1014   /* unref */
1015   if(start_output != NULL){
1016     g_object_unref(start_output);
1017   }
1018 
1019   if(start_input != NULL){
1020     g_object_unref(start_input);
1021   }
1022 
1023   /* resize */
1024   if((AGS_MACHINE_CONNECTED & (machine->flags)) != 0){
1025     if(audio_channels > audio_channels_old){
1026       if(machine->input != NULL){
1027 	pad_list = gtk_container_get_children(GTK_CONTAINER(machine->input));
1028 
1029 	while(pad_list != NULL){
1030 	  line_list = gtk_container_get_children((GtkContainer *) AGS_PAD(pad_list->data)->expander_set);
1031 	  line_list = g_list_nth(line_list,
1032 				 audio_channels_old);
1033 
1034 	  for(i = 0; i < audio_channels - audio_channels_old; i++){
1035 	    ags_connectable_connect(AGS_CONNECTABLE(line_list->data));
1036 
1037 	    line_list = line_list->next;
1038 	  }
1039 
1040 	  pad_list = pad_list->next;
1041 	}
1042       }
1043 
1044       if(machine->output != NULL){
1045 	pad_list = gtk_container_get_children(GTK_CONTAINER(machine->output));
1046 
1047 	while(pad_list != NULL){
1048 	  line_list = gtk_container_get_children((GtkContainer *) AGS_PAD(pad_list->data)->expander_set);
1049 	  line_list = g_list_nth(line_list,
1050 				 audio_channels_old);
1051 
1052 	  for(i = 0; i < audio_channels - audio_channels_old; i++){
1053 	    ags_connectable_connect(AGS_CONNECTABLE(line_list->data));
1054 
1055 	    line_list = line_list->next;
1056 	  }
1057 
1058 	  pad_list = pad_list->next;
1059 	}
1060       }
1061     }
1062   }
1063 }
1064 
1065 void
ags_machine_resize_pads_callback(AgsMachine * machine,GType channel_type,guint pads,guint pads_old,gpointer data)1066 ags_machine_resize_pads_callback(AgsMachine *machine,
1067 				 GType channel_type,
1068 				 guint pads, guint pads_old,
1069 				 gpointer data)
1070 {
1071   AgsAudio *audio;
1072   AgsPlayback *playback;
1073   AgsChannel *start_output;
1074   AgsChannel *start_input;
1075   AgsChannel *channel, *next_channel;
1076 
1077   GList *pad_list;
1078 
1079   guint audio_channels;
1080   guint i;
1081 
1082   static const guint staging_program[] = {
1083     (AGS_SOUND_STAGING_AUTOMATE | AGS_SOUND_STAGING_RUN_INTER | AGS_SOUND_STAGING_FX),
1084   };
1085 
1086   audio = machine->audio;
1087 
1088   start_output = NULL;
1089   start_input = NULL;
1090 
1091   audio_channels = 0;
1092 
1093   if(g_type_is_a(channel_type, AGS_TYPE_INPUT)){
1094     if(pads > pads_old){
1095       /* get some fields */
1096       g_object_get(audio,
1097 		   "input", &start_input,
1098 		   "audio-channels", &audio_channels,
1099 		   NULL);
1100 
1101       /* AgsOutput */
1102       channel = ags_channel_pad_nth(start_input,
1103 				    pads_old);
1104 
1105       while(channel != NULL){
1106 	/* fx engine */
1107 	g_object_get(channel,
1108 		     "playback", &playback,
1109 		     NULL);
1110 
1111 	if(playback != NULL){
1112 	  for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
1113 	    AgsThread *channel_thread;
1114 
1115 	    channel_thread = ags_playback_get_channel_thread(playback,
1116 							     i);
1117 
1118 	    if(channel_thread != NULL){
1119 	      ags_channel_thread_set_do_fx_staging((AgsChannelThread *) channel_thread,
1120 						   TRUE);
1121 	      ags_channel_thread_set_staging_program((AgsChannelThread *) channel_thread,
1122 						     staging_program,
1123 						     1);
1124 
1125 	      g_object_unref(channel_thread);
1126 	    }
1127 	  }
1128 
1129 	  g_object_unref(playback);
1130 	}
1131 
1132 	/* iterate */
1133 	next_channel = ags_channel_next(channel);
1134 
1135 	g_object_unref(channel);
1136 
1137 	channel = next_channel;
1138       }
1139 
1140       if(start_input != NULL){
1141 	g_object_unref(start_input);
1142       }
1143 
1144       if(channel != NULL){
1145 	g_object_unref(channel);
1146       }
1147     }
1148   }else{
1149     if(pads > pads_old){
1150       /* get some fields */
1151       g_object_get(audio,
1152 		   "output", &start_output,
1153 		   "audio-channels", &audio_channels,
1154 		   NULL);
1155 
1156       /* AgsOutput */
1157       channel = ags_channel_pad_nth(start_output,
1158 				    pads_old);
1159 
1160       while(channel != NULL){
1161 	/* fx engine */
1162 	g_object_get(channel,
1163 		     "playback", &playback,
1164 		     NULL);
1165 
1166 	if(playback != NULL){
1167 	  for(i = 0; i < AGS_SOUND_SCOPE_LAST; i++){
1168 	    AgsThread *channel_thread;
1169 
1170 	    channel_thread = ags_playback_get_channel_thread(playback,
1171 							     i);
1172 
1173 	    if(channel_thread != NULL){
1174 	      ags_channel_thread_set_do_fx_staging((AgsChannelThread *) channel_thread,
1175 						   TRUE);
1176 	      ags_channel_thread_set_staging_program((AgsChannelThread *) channel_thread,
1177 						     staging_program,
1178 						     1);
1179 
1180 	      g_object_unref(channel_thread);
1181 	    }
1182 	  }
1183 
1184 	  g_object_unref(playback);
1185 	}
1186 
1187 	/* iterate */
1188 	next_channel = ags_channel_next(channel);
1189 
1190 	g_object_unref(channel);
1191 
1192 	channel = next_channel;
1193       }
1194 
1195       if(start_output != NULL){
1196 	g_object_unref(start_output);
1197       }
1198 
1199       if(channel != NULL){
1200 	g_object_unref(channel);
1201       }
1202     }
1203   }
1204 
1205   /* resize */
1206   if((AGS_MACHINE_CONNECTED & (machine->flags)) != 0){
1207     if(pads > pads_old){
1208       if(g_type_is_a(channel_type,
1209 		     AGS_TYPE_INPUT)){
1210 	if(machine->input != NULL){
1211 	  pad_list = gtk_container_get_children(GTK_CONTAINER(machine->input));
1212 	  pad_list = g_list_nth(pad_list,
1213 				pads_old);
1214 
1215 	  while(pad_list != NULL){
1216 	    ags_connectable_connect(AGS_CONNECTABLE(pad_list->data));
1217 
1218 	    pad_list = pad_list->next;
1219 	  }
1220 	}
1221       }
1222 
1223       if(g_type_is_a(channel_type,
1224 		     AGS_TYPE_OUTPUT)){
1225 	if(machine->output != NULL){
1226 	  pad_list = gtk_container_get_children(GTK_CONTAINER(machine->output));
1227 	  pad_list = g_list_nth(pad_list,
1228 				pads_old);
1229 
1230 	  while(pad_list != NULL){
1231 	    ags_connectable_connect(AGS_CONNECTABLE(pad_list->data));
1232 
1233 	    pad_list = pad_list->next;
1234 	  }
1235 	}
1236       }
1237     }
1238   }
1239 }
1240 
1241 void
ags_machine_stop_callback(AgsMachine * machine,GList * recall_id,gint sound_scope,gpointer data)1242 ags_machine_stop_callback(AgsMachine *machine,
1243 			  GList *recall_id, gint sound_scope,
1244 			  gpointer data)
1245 {
1246   gboolean reset_active;
1247 
1248   if((AGS_MACHINE_BLOCK_STOP_CALLBACK & (machine->flags)) != 0){
1249     return;
1250   }
1251 
1252   machine->flags |= AGS_MACHINE_BLOCK_STOP_CALLBACK;
1253 
1254   /* play button - check reset active */
1255   reset_active = (sound_scope == AGS_SOUND_SCOPE_SEQUENCER) ? TRUE: FALSE;
1256 
1257   if(reset_active){
1258     gtk_toggle_button_set_active(machine->play, FALSE);
1259   }
1260 
1261 #if 0
1262   if(sound_scope == AGS_SOUND_SCOPE_SEQUENCER){
1263     ags_machine_set_run_extended(machine,
1264 				 FALSE,
1265 				 TRUE, FALSE, FALSE, FALSE);
1266   }
1267 
1268   if(sound_scope == AGS_SOUND_SCOPE_NOTATION){
1269     ags_machine_set_run_extended(machine,
1270 				 FALSE,
1271 				 FALSE, TRUE, FALSE, FALSE);
1272   }
1273 
1274   if(sound_scope == AGS_SOUND_SCOPE_WAVE){
1275     ags_machine_set_run_extended(machine,
1276 				 FALSE,
1277 				 FALSE, FALSE, TRUE, FALSE);
1278   }
1279 
1280   if(sound_scope == AGS_SOUND_SCOPE_MIDI){
1281     ags_machine_set_run_extended(machine,
1282 				 FALSE,
1283 				 FALSE, FALSE, FALSE, TRUE);
1284   }
1285 #endif
1286 
1287   machine->flags &= (~AGS_MACHINE_BLOCK_STOP_CALLBACK);
1288 }
1289 
1290 void
ags_machine_active_playback_start_channel_launch_callback(AgsTask * task,AgsPlayback * playback)1291 ags_machine_active_playback_start_channel_launch_callback(AgsTask *task,
1292 							  AgsPlayback *playback)
1293 {
1294   AgsAudio *audio;
1295   AgsChannel *channel;
1296   AgsRecycling *first_recycling, *last_recycling;
1297   AgsRecycling *recycling, *next_recycling, *end_recycling;
1298   AgsAudioSignal *template, *audio_signal;
1299   AgsRecallID *recall_id;
1300   AgsNote *play_note;
1301   AgsFxPlaybackAudio *fx_playback_audio;
1302 
1303   GObject *output_soundcard;
1304 
1305   GList *start_recall, *recall;
1306 
1307   GRecMutex *recycling_mutex;
1308 
1309   audio = NULL;
1310 
1311   channel = NULL;
1312 
1313   first_recycling = NULL;
1314   last_recycling = NULL;
1315 
1316   play_note = NULL;
1317 
1318   fx_playback_audio = NULL;
1319 
1320   start_recall = NULL;
1321 
1322   g_object_get(playback,
1323 	       "channel", &channel,
1324 	       "play-note", &play_note,
1325 	       NULL);
1326 
1327   g_object_get(channel,
1328 	       "audio", &audio,
1329 	       NULL);
1330 
1331   g_object_get(audio,
1332 	       "play", &start_recall,
1333 	       NULL);
1334 
1335   recall = ags_recall_template_find_type(start_recall, AGS_TYPE_FX_PLAYBACK_AUDIO);
1336 
1337   if(recall != NULL){
1338     fx_playback_audio = recall->data;
1339   }
1340 
1341   recall_id = ags_playback_get_recall_id(playback,
1342 					 AGS_SOUND_SCOPE_PLAYBACK);
1343 
1344   /* get some fields */
1345   g_object_get(channel,
1346 	       "first-recycling", &first_recycling,
1347 	       "last-recycling", &last_recycling,
1348 	       NULL);
1349 
1350   end_recycling = ags_recycling_next(last_recycling);
1351 
1352   recycling = first_recycling;
1353   g_object_ref(recycling);
1354 
1355   next_recycling = NULL;
1356 
1357   while(recycling != end_recycling){
1358     output_soundcard = NULL;
1359 
1360     g_object_get(recycling,
1361 		 "output-soundcard", &output_soundcard,
1362 		 NULL);
1363 
1364     recycling_mutex = AGS_RECYCLING_GET_OBJ_MUTEX(recycling);
1365 
1366     g_rec_mutex_lock(recycling_mutex);
1367 
1368     template = ags_audio_signal_get_template(recycling->audio_signal);
1369 
1370     g_rec_mutex_unlock(recycling_mutex);
1371 
1372     /* instantiate audio signal */
1373     audio_signal = ags_audio_signal_new((GObject *) output_soundcard,
1374 					(GObject *) recycling,
1375 					(GObject *) recall_id);
1376     ags_audio_signal_set_flags(audio_signal, (AGS_AUDIO_SIGNAL_FEED |
1377 					      AGS_AUDIO_SIGNAL_STREAM));
1378     g_object_set(audio_signal,
1379 		 "template", template,
1380 		 "note", play_note,
1381 		 NULL);
1382 
1383     /* add audio signal */
1384     if(ags_audio_test_behaviour_flags(audio, AGS_SOUND_BEHAVIOUR_PATTERN_MODE)){
1385       ags_recycling_create_audio_signal_with_defaults(recycling,
1386 						      audio_signal,
1387 						      0.0, 0);
1388     }else{
1389       gdouble notation_delay;
1390       guint buffer_size;
1391       guint note_x0, note_x1;
1392 
1393       notation_delay = ags_soundcard_get_absolute_delay(AGS_SOUNDCARD(output_soundcard));
1394 
1395       g_object_get(recycling,
1396 		   "buffer-size", &buffer_size,
1397 		   NULL);
1398 
1399       g_object_get(play_note,
1400 		   "x0", &note_x0,
1401 		   "x1", &note_x1,
1402 		   NULL);
1403 
1404       ags_recycling_create_audio_signal_with_frame_count(recycling,
1405 							 audio_signal,
1406 							 (guint) (((gdouble) buffer_size * notation_delay) * (gdouble) (note_x1 - note_x0)),
1407 							 0.0, 0);
1408     }
1409 
1410     audio_signal->stream_current = audio_signal->stream;
1411     ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
1412 
1413     ags_fx_playback_audio_add_feed_audio_signal(fx_playback_audio, audio_signal);
1414 
1415     /*
1416      * emit add_audio_signal on AgsRecycling
1417      */
1418     ags_recycling_add_audio_signal(recycling,
1419 				   audio_signal);
1420 
1421     g_object_unref(output_soundcard);
1422 
1423     /* iterate */
1424     next_recycling = ags_recycling_next(recycling);
1425 
1426     g_object_unref(recycling);
1427 
1428     recycling = next_recycling;
1429   }
1430 
1431   if(next_recycling != NULL){
1432     g_object_unref(next_recycling);
1433   }
1434 
1435   /* unref */
1436   g_object_unref(audio);
1437 
1438   g_object_unref(channel);
1439 
1440   if(first_recycling != NULL){
1441     g_object_unref(first_recycling);
1442     g_object_unref(last_recycling);
1443   }
1444 
1445   if(end_recycling != NULL){
1446     g_object_unref(end_recycling);
1447   }
1448 
1449   g_object_unref(recall_id);
1450 
1451   g_object_unref(play_note);
1452 }
1453