1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2020 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSequencer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/X/ags_automation_editor.h>
21 #include <ags/X/ags_automation_editor_callbacks.h>
22 
23 #include <ags/X/ags_ui_provider.h>
24 #include <ags/X/ags_window.h>
25 
26 #include <ags/X/editor/ags_scrolled_automation_edit_box.h>
27 #include <ags/X/editor/ags_vautomation_edit_box.h>
28 #include <ags/X/editor/ags_automation_edit.h>
29 
30 #include <libxml/tree.h>
31 #include <libxml/xpath.h>
32 
33 #include <math.h>
34 
35 #include <ags/config.h>
36 #include <ags/i18n.h>
37 
38 void ags_automation_editor_class_init(AgsAutomationEditorClass *automation_editor);
39 void ags_automation_editor_connectable_interface_init(AgsConnectableInterface *connectable);
40 void ags_automation_editor_init(AgsAutomationEditor *automation_editor);
41 void ags_automation_editor_connect(AgsConnectable *connectable);
42 void ags_automation_editor_disconnect(AgsConnectable *connectable);
43 void ags_automation_editor_finalize(GObject *gobject);
44 
45 void ags_automation_editor_show(GtkWidget *widget);
46 void ags_automation_editor_show_all(GtkWidget *widget);
47 
48 void ags_automation_editor_real_machine_changed(AgsAutomationEditor *automation_editor, AgsMachine *machine);
49 
50 gint ags_automation_editor_paste_automation_all(AgsAutomationEditor *automation_editor,
51 						AgsNotebook *notebook,
52 						AgsMachine *machine,
53 						xmlNode *automation_node,
54 						AgsTimestamp *timestamp,
55 						gboolean match_line, gboolean no_duplicates,
56 						guint position_x, guint position_y,
57 						gboolean paste_from_position,
58 						gint *last_x);
59 gint ags_automation_editor_paste_automation(AgsAutomationEditor *automation_editor,
60 					    AgsNotebook *notebook,
61 					    AgsMachine *machine,
62 					    xmlNode *audio_node,
63 					    guint position_x, guint position_y,
64 					    gboolean paste_from_position,
65 					    gint *last_x);
66 
67 enum{
68   MACHINE_CHANGED,
69   LAST_SIGNAL,
70 };
71 
72 enum{
73   PROP_0,
74 };
75 
76 static gpointer ags_automation_editor_parent_class = NULL;
77 static guint automation_editor_signals[LAST_SIGNAL];
78 
79 /**
80  * SECTION:ags_automation_editor
81  * @short_description: A composite widget to edit automation
82  * @title: AgsAutomationEditor
83  * @section_id:
84  * @include: ags/X/ags_automation_editor.h
85  *
86  * #AgsAutomationEditor is a composite widget to edit automation. You may select machines
87  * or change editor tool to do automation.
88  */
89 
90 GType
ags_automation_editor_get_type(void)91 ags_automation_editor_get_type(void)
92 {
93   static volatile gsize g_define_type_id__volatile = 0;
94 
95   if(g_once_init_enter (&g_define_type_id__volatile)){
96     GType ags_type_automation_editor = 0;
97 
98     static const GTypeInfo ags_automation_editor_info = {
99       sizeof (AgsAutomationEditorClass),
100       NULL, /* base_init */
101       NULL, /* base_finalize */
102       (GClassInitFunc) ags_automation_editor_class_init,
103       NULL, /* class_finalize */
104       NULL, /* class_data */
105       sizeof (AgsAutomationEditor),
106       0,    /* n_preallocs */
107       (GInstanceInitFunc) ags_automation_editor_init,
108     };
109 
110     static const GInterfaceInfo ags_connectable_interface_info = {
111       (GInterfaceInitFunc) ags_automation_editor_connectable_interface_init,
112       NULL, /* interface_finalize */
113       NULL, /* interface_data */
114     };
115 
116     ags_type_automation_editor = g_type_register_static(GTK_TYPE_BOX,
117 							"AgsAutomationEditor", &ags_automation_editor_info,
118 							0);
119 
120     g_type_add_interface_static(ags_type_automation_editor,
121 				AGS_TYPE_CONNECTABLE,
122 				&ags_connectable_interface_info);
123 
124     g_once_init_leave(&g_define_type_id__volatile, ags_type_automation_editor);
125   }
126 
127   return g_define_type_id__volatile;
128 }
129 
130 void
ags_automation_editor_connectable_interface_init(AgsConnectableInterface * connectable)131 ags_automation_editor_connectable_interface_init(AgsConnectableInterface *connectable)
132 {
133   connectable->is_ready = NULL;
134   connectable->is_connected = NULL;
135   connectable->connect = ags_automation_editor_connect;
136   connectable->disconnect = ags_automation_editor_disconnect;
137 }
138 
139 void
ags_automation_editor_class_init(AgsAutomationEditorClass * automation_editor)140 ags_automation_editor_class_init(AgsAutomationEditorClass *automation_editor)
141 {
142   GObjectClass *gobject;
143   GtkWidgetClass *widget;
144 
145   ags_automation_editor_parent_class = g_type_class_peek_parent(automation_editor);
146 
147   /* GObjectClass */
148   gobject = (GObjectClass *) automation_editor;
149 
150   gobject->finalize = ags_automation_editor_finalize;
151 
152   /* properties */
153 
154   /* GtkWidgetClass */
155   widget = (GtkWidgetClass *) automation_editor;
156 
157   widget->show = ags_automation_editor_show;
158   widget->show_all = ags_automation_editor_show_all;
159 
160   /* AgsEditorClass */
161   automation_editor->machine_changed = ags_automation_editor_real_machine_changed;
162 
163   /* signals */
164   /**
165    * AgsEditor::machine-changed:
166    * @editor: the object to change machine.
167    * @machine: the #AgsMachine to set
168    *
169    * The ::machine-changed signal notifies about changed machine.
170    *
171    * Since: 3.0.0
172    */
173   automation_editor_signals[MACHINE_CHANGED] =
174     g_signal_new("machine-changed",
175                  G_TYPE_FROM_CLASS(automation_editor),
176                  G_SIGNAL_RUN_LAST,
177 		 G_STRUCT_OFFSET(AgsAutomationEditorClass, machine_changed),
178                  NULL, NULL,
179                  g_cclosure_marshal_VOID__OBJECT,
180                  G_TYPE_NONE, 1,
181 		 G_TYPE_OBJECT);
182 }
183 
184 void
ags_automation_editor_init(AgsAutomationEditor * automation_editor)185 ags_automation_editor_init(AgsAutomationEditor *automation_editor)
186 {
187   GtkViewport *viewport;
188   GtkBox *hbox;
189   GtkScrolledWindow *scrolled_window;
190   GtkGrid *grid;
191 
192   GtkStyleContext *style_context;
193 
194   GtkAdjustment *adjustment;
195 
196   AgsApplicationContext *application_context;
197 
198   gdouble gui_scale_factor;
199 
200   gtk_orientable_set_orientation(GTK_ORIENTABLE(automation_editor),
201 				 GTK_ORIENTATION_VERTICAL);
202 
203   automation_editor->flags = (AGS_AUTOMATION_EDITOR_PASTE_MATCH_LINE |
204 			      AGS_AUTOMATION_EDITOR_PASTE_NO_DUPLICATES);
205 
206   automation_editor->version = AGS_AUTOMATION_EDITOR_DEFAULT_VERSION;
207   automation_editor->build_id = AGS_AUTOMATION_EDITOR_DEFAULT_BUILD_ID;
208 
209   application_context = ags_application_context_get_instance();
210 
211   /* scale factor */
212   gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
213 
214   /* offset */
215   automation_editor->tact_counter = 0;
216   automation_editor->current_tact = 0.0;
217 
218   /* automation toolbar */
219   automation_editor->automation_toolbar = ags_automation_toolbar_new();
220   gtk_box_pack_start((GtkBox *) automation_editor,
221 		     (GtkWidget *) automation_editor->automation_toolbar,
222 		     FALSE, FALSE,
223 		     0);
224 
225   /* paned */
226   automation_editor->paned = (GtkPaned *) gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
227   gtk_box_pack_start((GtkBox *) automation_editor,
228 		     (GtkWidget *) automation_editor->paned,
229 		     TRUE, TRUE,
230 		     0);
231 
232   /* machine selector */
233   viewport = (GtkViewport *) gtk_viewport_new(NULL,
234 					      NULL);
235   g_object_set(viewport,
236 	       "shadow-type", GTK_SHADOW_NONE,
237 	       NULL);
238   gtk_paned_pack1((GtkPaned *) automation_editor->paned,
239 		  (GtkWidget *) viewport,
240 		  FALSE, TRUE);
241 
242   scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
243   gtk_container_add(GTK_CONTAINER(viewport),
244 		    GTK_WIDGET(scrolled_window));
245   automation_editor->machine_selector = g_object_new(AGS_TYPE_MACHINE_SELECTOR,
246 						     "homogeneous", FALSE,
247 						     "spacing", 0,
248 						     NULL);
249   automation_editor->machine_selector->flags |= (AGS_MACHINE_SELECTOR_AUTOMATION);
250   gtk_label_set_label(automation_editor->machine_selector->label,
251 		      i18n("automation"));
252 
253   automation_editor->machine_selector->popup = ags_machine_selector_popup_new(automation_editor->machine_selector);
254   g_object_set(automation_editor->machine_selector->menu_button,
255 	       "menu", automation_editor->machine_selector->popup,
256 	       NULL);
257 
258   gtk_container_add((GtkContainer *) scrolled_window,
259 		    (GtkWidget *) automation_editor->machine_selector);
260 
261   /* selected machine */
262   automation_editor->selected_machine = NULL;
263 
264   /* notebook audio, output, input */
265   hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
266 				0);
267   gtk_paned_pack2((GtkPaned *) automation_editor->paned,
268 		  (GtkWidget *) hbox,
269 		  TRUE,
270 		  TRUE);
271 
272   viewport = (GtkViewport *) gtk_viewport_new(NULL,
273 					      NULL);
274   g_object_set(viewport,
275 	       "shadow-type", GTK_SHADOW_NONE,
276 	       NULL);
277   gtk_box_pack_start((GtkBox *) hbox,
278 		     (GtkWidget *) viewport,
279 		     TRUE, TRUE,
280 		     0);
281 
282   automation_editor->notebook = (GtkNotebook *) gtk_notebook_new();
283   gtk_container_add(GTK_CONTAINER(viewport),
284 		    GTK_WIDGET(automation_editor->notebook));
285 
286   /* audio */
287   grid = (GtkGrid *) gtk_grid_new();
288   gtk_notebook_append_page(automation_editor->notebook,
289 			   (GtkWidget *) grid,
290 			   gtk_label_new(i18n("audio")));
291 
292   /* audio - scrollbars */
293   adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, (guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_CONTROL_HEIGHT), 1.0);
294   automation_editor->audio_vscrollbar = (GtkScrollbar *) gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL,
295 									   adjustment);
296 
297   gtk_widget_set_valign((GtkWidget *) automation_editor->audio_vscrollbar,
298 			GTK_ALIGN_FILL);
299   gtk_widget_set_halign((GtkWidget *) automation_editor->audio_vscrollbar,
300 			GTK_ALIGN_FILL);
301 
302   gtk_grid_attach(grid,
303 		  (GtkWidget *) automation_editor->audio_vscrollbar,
304 		  2, 2,
305 		  1, 1);
306 
307   adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, (guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_CONTROL_WIDTH), 1.0);
308   automation_editor->audio_hscrollbar = (GtkScrollbar *) gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL,
309 									   adjustment);
310 
311   gtk_widget_set_valign((GtkWidget *) automation_editor->audio_hscrollbar,
312 			GTK_ALIGN_FILL);
313   gtk_widget_set_halign((GtkWidget *) automation_editor->audio_hscrollbar,
314 			GTK_ALIGN_FILL);
315 
316   gtk_grid_attach(grid,
317 		  (GtkWidget *) automation_editor->audio_hscrollbar,
318 		  1, 3,
319 		  1, 1);
320 
321   /* audio - ruler */
322   automation_editor->audio_ruler = ags_ruler_new();
323   g_object_set(automation_editor->audio_ruler,
324 	       "height-request", (gint) (gui_scale_factor * AGS_RULER_DEFAULT_HEIGHT),
325 	       "font-size",  (guint) (gui_scale_factor * automation_editor->audio_ruler->font_size),
326 	       "step", (guint) (AGS_RULER_DEFAULT_STEP),
327 	       "large-step", (guint) (gui_scale_factor * AGS_RULER_DEFAULT_LARGE_STEP),
328 	       "small-step", (guint) (gui_scale_factor * AGS_RULER_DEFAULT_SMALL_STEP),
329 	       NULL);
330 
331   gtk_widget_set_valign((GtkWidget *) automation_editor->audio_ruler,
332 			GTK_ALIGN_FILL);
333   gtk_widget_set_halign((GtkWidget *) automation_editor->audio_ruler,
334 			GTK_ALIGN_FILL);
335   gtk_widget_set_hexpand((GtkWidget *) automation_editor->audio_ruler,
336 			 TRUE);
337 
338   gtk_grid_attach(grid,
339 		   (GtkWidget *) automation_editor->audio_ruler,
340 		   1, 1,
341 		   1, 1);
342 
343   /* audio - scale */
344   automation_editor->audio_scrolled_scale_box = ags_scrolled_scale_box_new();
345   g_object_set(automation_editor->audio_scrolled_scale_box,
346 	       "margin-top", (gint) (gui_scale_factor * AGS_RULER_DEFAULT_HEIGHT),
347 	       NULL);
348 
349   automation_editor->audio_scrolled_scale_box->scale_box = (AgsScaleBox *) ags_vscale_box_new();
350   g_object_set(automation_editor->audio_scrolled_scale_box->scale_box,
351 	       "fixed-scale-width", (guint) (gui_scale_factor * AGS_SCALE_BOX_DEFAULT_FIXED_SCALE_WIDTH),
352 	       "fixed-scale-height", (guint) (gui_scale_factor * AGS_SCALE_BOX_DEFAULT_FIXED_SCALE_HEIGHT),
353 	       NULL);
354 
355   gtk_container_add(GTK_CONTAINER(automation_editor->audio_scrolled_scale_box->viewport),
356 		    GTK_WIDGET(automation_editor->audio_scrolled_scale_box->scale_box));
357   gtk_widget_set_size_request((GtkWidget *) automation_editor->audio_scrolled_scale_box,
358 			      (gint) (gui_scale_factor * AGS_SCALE_BOX_DEFAULT_FIXED_SCALE_WIDTH),
359 			      -1);
360 
361   gtk_widget_set_valign((GtkWidget *) automation_editor->audio_scrolled_scale_box,
362 			GTK_ALIGN_FILL);
363   gtk_widget_set_halign((GtkWidget *) automation_editor->audio_scrolled_scale_box,
364 			GTK_ALIGN_START);
365 
366   gtk_widget_set_vexpand((GtkWidget *) automation_editor->audio_scrolled_scale_box,
367 			 TRUE);
368   gtk_widget_set_hexpand((GtkWidget *) automation_editor->audio_scrolled_scale_box,
369 			 FALSE);
370 
371   gtk_grid_attach(grid,
372 		   (GtkWidget *) automation_editor->audio_scrolled_scale_box,
373 		   0, 2,
374 		   1, 1);
375 
376   /* audio - automation edit */
377   automation_editor->audio_scrolled_automation_edit_box = ags_scrolled_automation_edit_box_new();
378 
379   automation_editor->audio_scrolled_automation_edit_box->automation_edit_box = (AgsAutomationEditBox *) ags_vautomation_edit_box_new();
380   g_object_set(automation_editor->audio_scrolled_automation_edit_box->automation_edit_box,
381 	       "fixed-edit-height", (guint) (gui_scale_factor * AGS_SCALE_BOX_DEFAULT_FIXED_SCALE_HEIGHT),
382 	       NULL);
383   gtk_container_add(GTK_CONTAINER(automation_editor->audio_scrolled_automation_edit_box->viewport),
384 		    GTK_WIDGET(automation_editor->audio_scrolled_automation_edit_box->automation_edit_box));
385 
386   gtk_widget_set_valign((GtkWidget *) automation_editor->audio_scrolled_automation_edit_box,
387 			GTK_ALIGN_FILL);
388   gtk_widget_set_halign((GtkWidget *) automation_editor->audio_scrolled_automation_edit_box,
389 			GTK_ALIGN_FILL);
390   gtk_widget_set_vexpand((GtkWidget *) automation_editor->audio_scrolled_automation_edit_box,
391 			 TRUE);
392   gtk_widget_set_hexpand((GtkWidget *) automation_editor->audio_scrolled_automation_edit_box,
393 			 TRUE);
394 
395   gtk_grid_attach(grid,
396 		  (GtkWidget *) automation_editor->audio_scrolled_automation_edit_box,
397 		  1, 2,
398 		  1, 1);
399 
400   gtk_widget_set_events(GTK_WIDGET(automation_editor->audio_scrolled_automation_edit_box->viewport), GDK_EXPOSURE_MASK
401 			| GDK_LEAVE_NOTIFY_MASK
402 			| GDK_BUTTON_PRESS_MASK
403 			| GDK_BUTTON_RELEASE_MASK
404 			| GDK_POINTER_MOTION_MASK
405 			| GDK_POINTER_MOTION_HINT_MASK
406 			| GDK_CONTROL_MASK);
407 
408   /* output */
409   grid = (GtkGrid *) gtk_grid_new();
410   gtk_notebook_append_page(automation_editor->notebook,
411 			   (GtkWidget *) grid,
412 			   gtk_label_new(i18n("output")));
413 
414   /* output - scrollbars */
415   adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, (guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_CONTROL_HEIGHT), 1.0);
416   automation_editor->output_vscrollbar = (GtkScrollbar *) gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL,
417 									    adjustment);
418 
419   gtk_widget_set_valign((GtkWidget *) automation_editor->output_vscrollbar,
420 			GTK_ALIGN_FILL);
421   gtk_widget_set_halign((GtkWidget *) automation_editor->output_vscrollbar,
422 			GTK_ALIGN_FILL);
423 
424   gtk_grid_attach(grid,
425 		  (GtkWidget *) automation_editor->output_vscrollbar,
426 		  2, 2,
427 		  1, 1);
428 
429   adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, (guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_CONTROL_WIDTH), 1.0);
430   automation_editor->output_hscrollbar = (GtkScrollbar *) gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL,
431 									    adjustment);
432 
433   gtk_widget_set_valign((GtkWidget *) automation_editor->output_hscrollbar,
434 			GTK_ALIGN_FILL);
435   gtk_widget_set_halign((GtkWidget *) automation_editor->output_hscrollbar,
436 			GTK_ALIGN_FILL);
437 
438   gtk_grid_attach(grid,
439 		  (GtkWidget *) automation_editor->output_hscrollbar,
440 		  1, 3,
441 		  1, 1);
442 
443   /* output - notebook */
444   automation_editor->output_notebook = g_object_new(AGS_TYPE_NOTEBOOK,
445 						    "homogeneous", FALSE,
446 						    "spacing", 0,
447 						    "prefix", i18n("line"),
448 						    NULL);
449 
450   gtk_widget_set_valign((GtkWidget *) automation_editor->output_notebook,
451 			GTK_ALIGN_FILL);
452   gtk_widget_set_halign((GtkWidget *) automation_editor->output_notebook,
453 			GTK_ALIGN_FILL);
454   gtk_widget_set_hexpand((GtkWidget *) automation_editor->output_notebook,
455 			 TRUE);
456 
457   gtk_grid_attach(grid,
458 		  (GtkWidget *) automation_editor->output_notebook,
459 		  0, 0,
460 		  3, 1);
461 
462   /* output - ruler */
463   automation_editor->output_ruler = ags_ruler_new();
464   g_object_set(automation_editor->output_ruler,
465 	       "height-request", (gint) (gui_scale_factor * AGS_RULER_DEFAULT_HEIGHT),
466 	       "font-size",  (guint) (gui_scale_factor * automation_editor->output_ruler->font_size),
467 	       "step", (guint) (AGS_RULER_DEFAULT_STEP),
468 	       "large-step", (guint) (gui_scale_factor * AGS_RULER_DEFAULT_LARGE_STEP),
469 	       "small-step", (guint) (gui_scale_factor * AGS_RULER_DEFAULT_SMALL_STEP),
470 	       NULL);
471 
472   gtk_widget_set_valign((GtkWidget *) automation_editor->output_ruler,
473 			GTK_ALIGN_FILL);
474   gtk_widget_set_halign((GtkWidget *) automation_editor->output_ruler,
475 			GTK_ALIGN_FILL);
476   gtk_widget_set_hexpand((GtkWidget *) automation_editor->output_ruler,
477 			 TRUE);
478 
479   gtk_grid_attach(grid,
480 		  (GtkWidget *) automation_editor->output_ruler,
481 		  1, 1,
482 		  1, 1);
483 
484   /* output - scale */
485   automation_editor->output_scrolled_scale_box = ags_scrolled_scale_box_new();
486   g_object_set(automation_editor->output_scrolled_scale_box,
487 	       "margin-top", (gint) (gui_scale_factor * AGS_RULER_DEFAULT_HEIGHT),
488 	       NULL);
489 
490   automation_editor->output_scrolled_scale_box->scale_box = (AgsScaleBox *) ags_vscale_box_new();
491   g_object_set(automation_editor->output_scrolled_scale_box->scale_box,
492 	       "fixed-scale-width", (guint) (gui_scale_factor * AGS_SCALE_BOX_DEFAULT_FIXED_SCALE_WIDTH),
493 	       "fixed-scale-height", (guint) (gui_scale_factor * AGS_SCALE_BOX_DEFAULT_FIXED_SCALE_HEIGHT),
494 	       NULL);
495 
496   gtk_container_add(GTK_CONTAINER(automation_editor->output_scrolled_scale_box->viewport),
497 		    GTK_WIDGET(automation_editor->output_scrolled_scale_box->scale_box));
498   gtk_widget_set_size_request((GtkWidget *) automation_editor->output_scrolled_scale_box,
499 			      (gint) (gui_scale_factor * AGS_SCALE_BOX_DEFAULT_FIXED_SCALE_WIDTH),
500 			      -1);
501 
502   gtk_widget_set_valign((GtkWidget *) automation_editor->output_scrolled_scale_box,
503 			GTK_ALIGN_FILL);
504   gtk_widget_set_halign((GtkWidget *) automation_editor->output_scrolled_scale_box,
505 			GTK_ALIGN_START);
506 
507   gtk_widget_set_vexpand((GtkWidget *) automation_editor->output_scrolled_scale_box,
508 			 TRUE);
509   gtk_widget_set_hexpand((GtkWidget *) automation_editor->output_scrolled_scale_box,
510 			 FALSE);
511 
512   gtk_grid_attach(grid,
513 		  (GtkWidget *) automation_editor->output_scrolled_scale_box,
514 		  0, 2,
515 		  1, 1);
516 
517   /* output - automation edit */
518   automation_editor->output_scrolled_automation_edit_box = ags_scrolled_automation_edit_box_new();
519 
520   automation_editor->output_scrolled_automation_edit_box->automation_edit_box = (AgsAutomationEditBox *) ags_vautomation_edit_box_new();
521   g_object_set(automation_editor->output_scrolled_automation_edit_box->automation_edit_box,
522 	       "fixed-edit-height", (guint) (gui_scale_factor * AGS_SCALE_BOX_DEFAULT_FIXED_SCALE_HEIGHT),
523 	       NULL);
524   gtk_container_add(GTK_CONTAINER(automation_editor->output_scrolled_automation_edit_box->viewport),
525 		    GTK_WIDGET(automation_editor->output_scrolled_automation_edit_box->automation_edit_box));
526 
527   gtk_widget_set_valign((GtkWidget *) automation_editor->output_scrolled_automation_edit_box,
528 			GTK_ALIGN_FILL);
529   gtk_widget_set_halign((GtkWidget *) automation_editor->output_scrolled_automation_edit_box,
530 			GTK_ALIGN_FILL);
531   gtk_widget_set_vexpand((GtkWidget *) automation_editor->output_scrolled_automation_edit_box,
532 			 TRUE);
533   gtk_widget_set_hexpand((GtkWidget *) automation_editor->output_scrolled_automation_edit_box,
534 			 TRUE);
535 
536   gtk_grid_attach(grid,
537 		  (GtkWidget *) automation_editor->output_scrolled_automation_edit_box,
538 		  1, 2,
539 		  1, 1);
540 
541   gtk_widget_set_events(GTK_WIDGET(automation_editor->output_scrolled_automation_edit_box->viewport), GDK_EXPOSURE_MASK
542 			| GDK_LEAVE_NOTIFY_MASK
543 			| GDK_BUTTON_PRESS_MASK
544 			| GDK_BUTTON_RELEASE_MASK
545 			| GDK_POINTER_MOTION_MASK
546 			| GDK_POINTER_MOTION_HINT_MASK
547 			| GDK_CONTROL_MASK);
548 
549   /* input */
550   grid = (GtkGrid *) gtk_grid_new();
551   gtk_notebook_append_page(automation_editor->notebook,
552 			   (GtkWidget *) grid,
553 			   gtk_label_new(i18n("input")));
554 
555   /* input - scrollbars */
556   adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, (guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_CONTROL_HEIGHT), 1.0);
557   automation_editor->input_vscrollbar = (GtkScrollbar *) gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL,
558 									   adjustment);
559 
560   gtk_widget_set_valign((GtkWidget *) automation_editor->input_vscrollbar,
561 			GTK_ALIGN_FILL);
562   gtk_widget_set_halign((GtkWidget *) automation_editor->input_vscrollbar,
563 			GTK_ALIGN_FILL);
564 
565   gtk_grid_attach(grid,
566 		  (GtkWidget *) automation_editor->input_vscrollbar,
567 		  2, 2,
568 		  1, 1);
569 
570   adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, (guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_CONTROL_WIDTH), 1.0);
571   automation_editor->input_hscrollbar = (GtkScrollbar *) gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL,
572 									   adjustment);
573 
574   gtk_widget_set_valign((GtkWidget *) automation_editor->input_hscrollbar,
575 			GTK_ALIGN_FILL);
576   gtk_widget_set_halign((GtkWidget *) automation_editor->input_hscrollbar,
577 			GTK_ALIGN_FILL);
578 
579   gtk_grid_attach(grid,
580 		  (GtkWidget *) automation_editor->input_hscrollbar,
581 		  1, 3,
582 		  1, 1);
583 
584   /* input - notebook */
585   automation_editor->input_notebook = g_object_new(AGS_TYPE_NOTEBOOK,
586 						   "homogeneous", FALSE,
587 						   "spacing", 0,
588 						   "prefix", i18n("line"),
589 						   NULL);
590 
591   gtk_widget_set_valign((GtkWidget *) automation_editor->input_notebook,
592 			GTK_ALIGN_FILL);
593   gtk_widget_set_halign((GtkWidget *) automation_editor->input_notebook,
594 			GTK_ALIGN_FILL);
595   gtk_widget_set_hexpand((GtkWidget *) automation_editor->input_notebook,
596 			 TRUE);
597 
598   gtk_grid_attach(grid,
599 		  (GtkWidget *) automation_editor->input_notebook,
600 		  0, 0,
601 		  3, 1);
602 
603   /* input - ruler */
604   automation_editor->input_ruler = ags_ruler_new();
605   g_object_set(automation_editor->input_ruler,
606 	       "height-request", (gint) (gui_scale_factor * AGS_RULER_DEFAULT_HEIGHT),
607 	       "font-size",  (guint) (gui_scale_factor * automation_editor->input_ruler->font_size),
608 	       "step", (guint) (AGS_RULER_DEFAULT_STEP),
609 	       "large-step", (guint) (gui_scale_factor * AGS_RULER_DEFAULT_LARGE_STEP),
610 	       "small-step", (guint) (gui_scale_factor * AGS_RULER_DEFAULT_SMALL_STEP),
611 	       NULL);
612 
613   gtk_widget_set_valign((GtkWidget *) automation_editor->input_ruler,
614 			GTK_ALIGN_FILL);
615   gtk_widget_set_halign((GtkWidget *) automation_editor->input_ruler,
616 			GTK_ALIGN_FILL);
617   gtk_widget_set_hexpand((GtkWidget *) automation_editor->input_ruler,
618 			 TRUE);
619 
620   gtk_grid_attach(grid,
621 		  (GtkWidget *) automation_editor->input_ruler,
622 		  1, 1,
623 		  1, 1);
624 
625   /* input - scale */
626   automation_editor->input_scrolled_scale_box = ags_scrolled_scale_box_new();
627   g_object_set(automation_editor->input_scrolled_scale_box,
628 	       "margin-top", (gint) (gui_scale_factor * AGS_RULER_DEFAULT_HEIGHT),
629 	       NULL);
630 
631   automation_editor->input_scrolled_scale_box->scale_box = (AgsScaleBox *) ags_vscale_box_new();
632   g_object_set(automation_editor->input_scrolled_scale_box->scale_box,
633 	       "fixed-scale-width", (guint) (gui_scale_factor * AGS_SCALE_BOX_DEFAULT_FIXED_SCALE_WIDTH),
634 	       "fixed-scale-height", (guint) (gui_scale_factor * AGS_SCALE_BOX_DEFAULT_FIXED_SCALE_HEIGHT),
635 	       NULL);
636 
637   gtk_container_add(GTK_CONTAINER(automation_editor->input_scrolled_scale_box->viewport),
638 		    GTK_WIDGET(automation_editor->input_scrolled_scale_box->scale_box));
639   gtk_widget_set_size_request((GtkWidget *) automation_editor->input_scrolled_scale_box,
640 			      (gint) (gui_scale_factor * AGS_SCALE_BOX_DEFAULT_FIXED_SCALE_WIDTH),
641 			      -1);
642 
643   gtk_widget_set_valign((GtkWidget *) automation_editor->input_scrolled_scale_box,
644 			GTK_ALIGN_FILL);
645   gtk_widget_set_halign((GtkWidget *) automation_editor->input_scrolled_scale_box,
646 			GTK_ALIGN_START);
647 
648   gtk_widget_set_vexpand((GtkWidget *) automation_editor->input_scrolled_scale_box,
649 			 TRUE);
650   gtk_widget_set_hexpand((GtkWidget *) automation_editor->input_scrolled_scale_box,
651 			 FALSE);
652 
653   gtk_grid_attach(grid,
654 		   (GtkWidget *) automation_editor->input_scrolled_scale_box,
655 		   0, 2,
656 		   1, 1);
657 
658   //TODO:JK: check remove
659 //  gtk_widget_show_all(GTK_WIDGET(automation_editor->input_scrolled_scale_box));
660 //  gtk_widget_show_all(GTK_WIDGET(automation_editor->input_scrolled_scale_box->viewport));
661 
662   /* input automation edit */
663   automation_editor->input_scrolled_automation_edit_box = ags_scrolled_automation_edit_box_new();
664 
665   automation_editor->input_scrolled_automation_edit_box->automation_edit_box = (AgsAutomationEditBox *) ags_vautomation_edit_box_new();
666   g_object_set(automation_editor->input_scrolled_automation_edit_box->automation_edit_box,
667 	       "fixed-edit-height", (guint) (gui_scale_factor * AGS_SCALE_BOX_DEFAULT_FIXED_SCALE_HEIGHT),
668 	       NULL);
669   gtk_container_add(GTK_CONTAINER(automation_editor->input_scrolled_automation_edit_box->viewport),
670 		    GTK_WIDGET(automation_editor->input_scrolled_automation_edit_box->automation_edit_box));
671 
672   gtk_widget_set_valign((GtkWidget *) automation_editor->input_scrolled_automation_edit_box,
673 			GTK_ALIGN_FILL);
674   gtk_widget_set_halign((GtkWidget *) automation_editor->input_scrolled_automation_edit_box,
675 			GTK_ALIGN_FILL);
676   gtk_widget_set_vexpand((GtkWidget *) automation_editor->input_scrolled_automation_edit_box,
677 			 TRUE);
678   gtk_widget_set_hexpand((GtkWidget *) automation_editor->input_scrolled_automation_edit_box,
679 			 TRUE);
680 
681   gtk_grid_attach(grid,
682 		  (GtkWidget *) automation_editor->input_scrolled_automation_edit_box,
683 		  1, 2,
684 		  1, 1);
685 
686   gtk_widget_set_events(GTK_WIDGET(automation_editor->input_scrolled_automation_edit_box->viewport), GDK_EXPOSURE_MASK
687 			| GDK_LEAVE_NOTIFY_MASK
688 			| GDK_BUTTON_PRESS_MASK
689 			| GDK_BUTTON_RELEASE_MASK
690 			| GDK_POINTER_MOTION_MASK
691 			| GDK_POINTER_MOTION_HINT_MASK
692 			| GDK_CONTROL_MASK);
693 
694   /* focused automation edit */
695   automation_editor->focused_automation_edit = NULL;
696 
697   /* automation meta */
698   automation_editor->automation_meta = ags_automation_meta_new();
699   g_object_set(automation_editor->automation_meta,
700 	       "valign", GTK_ALIGN_START,
701 	       NULL);
702   gtk_box_pack_start((GtkBox *) hbox,
703 		     (GtkWidget *) automation_editor->automation_meta,
704 		     FALSE, FALSE,
705 		     0);
706 
707   /* style context */
708   style_context = gtk_widget_get_style_context((GtkWidget *) automation_editor);
709   gtk_style_context_add_class(style_context,
710 			      "editor");
711 }
712 
713 void
ags_automation_editor_connect(AgsConnectable * connectable)714 ags_automation_editor_connect(AgsConnectable *connectable)
715 {
716   AgsAutomationEditor *automation_editor;
717 
718   automation_editor = AGS_AUTOMATION_EDITOR(connectable);
719 
720   if((AGS_AUTOMATION_EDITOR_CONNECTED & (automation_editor->flags)) != 0){
721     return;
722   }
723 
724   automation_editor->flags |= AGS_AUTOMATION_EDITOR_CONNECTED;
725 
726   /* audio */
727   g_signal_connect_after((GObject *) automation_editor->audio_scrolled_automation_edit_box->viewport, "configure_event",
728 			 G_CALLBACK(ags_automation_editor_audio_edit_configure_event), (gpointer) automation_editor);
729 
730   g_signal_connect_after((GObject *) automation_editor->audio_vscrollbar, "value-changed",
731 			 G_CALLBACK(ags_automation_editor_audio_vscrollbar_value_changed), (gpointer) automation_editor);
732 
733   g_signal_connect_after((GObject *) automation_editor->audio_hscrollbar, "value-changed",
734 			 G_CALLBACK(ags_automation_editor_audio_hscrollbar_value_changed), (gpointer) automation_editor);
735 
736   /* output */
737   g_signal_connect_after((GObject *) automation_editor->output_scrolled_automation_edit_box->viewport, "configure_event",
738 			 G_CALLBACK(ags_automation_editor_output_edit_configure_event), (gpointer) automation_editor);
739 
740   g_signal_connect_after((GObject *) automation_editor->output_vscrollbar, "value-changed",
741 			 G_CALLBACK(ags_automation_editor_output_vscrollbar_value_changed), (gpointer) automation_editor);
742 
743   g_signal_connect_after((GObject *) automation_editor->output_hscrollbar, "value-changed",
744 			 G_CALLBACK(ags_automation_editor_output_hscrollbar_value_changed), (gpointer) automation_editor);
745 
746   /* input */
747   g_signal_connect_after((GObject *) automation_editor->input_scrolled_automation_edit_box->viewport, "configure_event",
748 			 G_CALLBACK(ags_automation_editor_input_edit_configure_event), (gpointer) automation_editor);
749 
750   g_signal_connect_after((GObject *) automation_editor->input_vscrollbar, "value-changed",
751 			 G_CALLBACK(ags_automation_editor_input_vscrollbar_value_changed), (gpointer) automation_editor);
752 
753   g_signal_connect_after((GObject *) automation_editor->input_hscrollbar, "value-changed",
754 			 G_CALLBACK(ags_automation_editor_input_hscrollbar_value_changed), (gpointer) automation_editor);
755 
756   /* machine selector */
757   g_signal_connect((GObject *) automation_editor->machine_selector, "changed",
758 		   G_CALLBACK(ags_automation_editor_machine_changed_callback), (gpointer) automation_editor);
759 
760   /* toolbar and selector */
761   ags_connectable_connect(AGS_CONNECTABLE(automation_editor->automation_toolbar));
762   ags_connectable_connect(AGS_CONNECTABLE(automation_editor->machine_selector));
763 
764   ags_connectable_connect(AGS_CONNECTABLE(automation_editor->automation_meta));
765 }
766 
767 void
ags_automation_editor_disconnect(AgsConnectable * connectable)768 ags_automation_editor_disconnect(AgsConnectable *connectable)
769 {
770   AgsAutomationEditor *automation_editor;
771 
772   automation_editor = AGS_AUTOMATION_EDITOR(connectable);
773 
774   if((AGS_AUTOMATION_EDITOR_CONNECTED & (automation_editor->flags)) == 0){
775     return;
776   }
777 
778   automation_editor->flags &= (~AGS_AUTOMATION_EDITOR_CONNECTED);
779 
780   /* audio */
781   g_object_disconnect((GObject *) automation_editor->audio_scrolled_automation_edit_box->viewport,
782 		      "any_signal::configure_event",
783 		      G_CALLBACK(ags_automation_editor_audio_edit_configure_event),
784 		      automation_editor,
785 		      NULL);
786 
787   /* output */
788   g_object_disconnect((GObject *) automation_editor->output_scrolled_automation_edit_box->viewport,
789 		      "any_signal::configure_event",
790 		      G_CALLBACK(ags_automation_editor_output_edit_configure_event),
791 		      automation_editor,
792 		      NULL);
793 
794   /* input */
795   g_object_disconnect((GObject *) automation_editor->input_scrolled_automation_edit_box->viewport,
796 		      "any_signal::configure_event",
797 		      G_CALLBACK(ags_automation_editor_input_edit_configure_event),
798 		      automation_editor,
799 		      NULL);
800 
801   /* toolbar and selector */
802   ags_connectable_disconnect(AGS_CONNECTABLE(automation_editor->automation_toolbar));
803   ags_connectable_disconnect(AGS_CONNECTABLE(automation_editor->machine_selector));
804 
805   ags_connectable_disconnect(AGS_CONNECTABLE(automation_editor->automation_meta));
806 }
807 
808 void
ags_automation_editor_finalize(GObject * gobject)809 ags_automation_editor_finalize(GObject *gobject)
810 {
811   /* call parent */
812   G_OBJECT_CLASS(ags_automation_editor_parent_class)->finalize(gobject);
813 }
814 
815 void
ags_automation_editor_reset_audio_scrollbar(AgsAutomationEditor * automation_editor)816 ags_automation_editor_reset_audio_scrollbar(AgsAutomationEditor *automation_editor)
817 {
818   AgsAutomationToolbar *automation_toolbar;
819 
820   GtkAdjustment *audio_vscrollbar_adjustment;
821   GtkAdjustment *audio_hscrollbar_adjustment;
822 
823   GtkAllocation automation_edit_box_allocation;
824   GtkAllocation viewport_allocation;
825 
826   GList *list_start, *list;
827 
828   gdouble old_h_upper;
829   gdouble v_upper, h_upper;
830   double zoom;
831   double zoom_correction;
832   guint map_width;
833 
834   automation_toolbar = automation_editor->automation_toolbar;
835 
836   /* audio */
837   gtk_widget_get_allocation(GTK_WIDGET(automation_editor->audio_scrolled_automation_edit_box->automation_edit_box),
838 			    &automation_edit_box_allocation);
839 
840   gtk_widget_get_allocation(GTK_WIDGET(automation_editor->audio_scrolled_automation_edit_box->viewport),
841 			    &viewport_allocation);
842 
843   /* reset vertical scrollbar */
844   v_upper = automation_edit_box_allocation.height - viewport_allocation.height;
845 
846   if(v_upper < 0.0){
847     v_upper = 0.0;
848   }
849 
850   audio_vscrollbar_adjustment = gtk_range_get_adjustment(GTK_RANGE(automation_editor->audio_vscrollbar));
851 
852   gtk_adjustment_set_upper(audio_vscrollbar_adjustment,
853 			   v_upper);
854 
855   gtk_adjustment_set_upper(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(automation_editor->audio_scrolled_automation_edit_box->viewport)),
856 			   v_upper);
857   gtk_adjustment_set_upper(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(automation_editor->audio_scrolled_scale_box->viewport)),
858 			   v_upper);
859 
860   /* reset horizontal scrollbar */
861   zoom = exp2((double) gtk_combo_box_get_active((GtkComboBox *) automation_toolbar->zoom) - 2.0);
862 
863   /* upper */
864   audio_hscrollbar_adjustment = gtk_range_get_adjustment(GTK_RANGE(automation_editor->audio_hscrollbar));
865 
866   old_h_upper = gtk_adjustment_get_upper(audio_hscrollbar_adjustment);
867 
868   zoom_correction = 1.0 / 16;
869 
870 //  map_width = (gui_scale_factor * (double) AGS_AUTOMATION_EDITOR_MAX_CONTROLS * zoom * zoom_correction);
871   map_width = ((64.0) * (16.0 * 16.0 * 1200.0) * zoom * zoom_correction);
872   h_upper = map_width - automation_edit_box_allocation.width;
873 
874   if(h_upper < 0.0){
875     h_upper = 0.0;
876   }
877 
878   gtk_adjustment_set_upper(automation_editor->audio_ruler->adjustment,
879 			   h_upper);
880 
881   gtk_adjustment_set_upper(audio_hscrollbar_adjustment,
882 			   h_upper);
883 
884   /* automation edit */
885   list_start =
886     list = gtk_container_get_children(GTK_CONTAINER(automation_editor->audio_scrolled_automation_edit_box->automation_edit_box));
887 
888   while(list != NULL){
889     GtkAdjustment *adjustment;
890 
891     adjustment = gtk_range_get_adjustment(GTK_RANGE(AGS_AUTOMATION_EDIT(list->data)->hscrollbar));
892 
893     gtk_adjustment_set_upper(adjustment,
894 			     h_upper);
895 
896     list = list->next;
897   }
898 
899   g_list_free(list_start);
900 
901   /* reset value */
902   if(old_h_upper != 0.0){
903 #if 0
904     gtk_adjustment_set_value(audio_hscrollbar_adjustment,
905 			     gtk_adjustment_get_value(audio_hscrollbar_adjustment) / old_h_upper * h_upper);
906 #endif
907   }
908 }
909 
910 void
ags_automation_editor_reset_output_scrollbar(AgsAutomationEditor * automation_editor)911 ags_automation_editor_reset_output_scrollbar(AgsAutomationEditor *automation_editor)
912 {
913   AgsAutomationToolbar *automation_toolbar;
914 
915   GtkAdjustment *output_vscrollbar_adjustment;
916   GtkAdjustment *output_hscrollbar_adjustment;
917 
918   GtkAllocation automation_edit_box_allocation;
919   GtkAllocation viewport_allocation;
920 
921   GList *list_start, *list;
922 
923   gdouble old_h_upper;
924   gdouble v_upper, h_upper;
925   double zoom;
926   double zoom_correction;
927   guint map_width;
928 
929   automation_toolbar = automation_editor->automation_toolbar;
930 
931   /* output */
932   gtk_widget_get_allocation(GTK_WIDGET(automation_editor->output_scrolled_automation_edit_box->automation_edit_box),
933 			    &automation_edit_box_allocation);
934 
935   gtk_widget_get_allocation(GTK_WIDGET(automation_editor->output_scrolled_automation_edit_box->viewport),
936 			    &viewport_allocation);
937 
938   /* reset vertical scrollbar */
939   v_upper = automation_edit_box_allocation.height - viewport_allocation.height;
940 
941   if(v_upper < 0.0){
942     v_upper = 0.0;
943   }
944 
945   output_vscrollbar_adjustment = gtk_range_get_adjustment(GTK_RANGE(automation_editor->output_vscrollbar));
946 
947   gtk_adjustment_set_upper(output_vscrollbar_adjustment,
948 			   v_upper);
949 
950   gtk_adjustment_set_upper(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(automation_editor->output_scrolled_automation_edit_box->viewport)),
951 			   v_upper);
952   gtk_adjustment_set_upper(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(automation_editor->output_scrolled_scale_box->viewport)),
953 			   v_upper);
954 
955   /* reset horizontal scrollbar */
956   zoom = exp2((double) gtk_combo_box_get_active((GtkComboBox *) automation_toolbar->zoom) - 2.0);
957 
958   /* upper */
959   output_hscrollbar_adjustment = gtk_range_get_adjustment(GTK_RANGE(automation_editor->output_hscrollbar));
960 
961   old_h_upper = gtk_adjustment_get_upper(output_hscrollbar_adjustment);
962 
963   zoom_correction = 1.0 / 16;
964 
965 //  map_width = (gui_scale_factor * (double) AGS_AUTOMATION_EDITOR_MAX_CONTROLS * zoom * zoom_correction);
966   map_width = ((64.0) * (16.0 * 16.0 * 1200.0) * zoom * zoom_correction);
967   h_upper = map_width - automation_edit_box_allocation.width;
968 
969   if(h_upper < 0.0){
970     h_upper = 0.0;
971   }
972 
973   gtk_adjustment_set_upper(automation_editor->output_ruler->adjustment,
974 			   h_upper);
975 
976   gtk_adjustment_set_upper(output_hscrollbar_adjustment,
977 			   h_upper);
978 
979   /* automation edit */
980   list_start =
981     list = gtk_container_get_children(GTK_CONTAINER(automation_editor->output_scrolled_automation_edit_box->automation_edit_box));
982 
983   while(list != NULL){
984     GtkAdjustment *adjustment;
985 
986     adjustment = gtk_range_get_adjustment(GTK_RANGE(AGS_AUTOMATION_EDIT(list->data)->hscrollbar));
987 
988     gtk_adjustment_set_upper(adjustment,
989 			     h_upper);
990 
991 
992     list = list->next;
993   }
994 
995   g_list_free(list_start);
996 
997   /* reset value */
998   if(old_h_upper != 0.0){
999 #if 0
1000     gtk_adjustment_set_value(output_hscrollbar_adjustment,
1001 			     gtk_adjustment_get_value(output_hscrollbar_adjustment) / old_h_upper * h_upper);
1002 #endif
1003   }
1004 }
1005 
1006 void
ags_automation_editor_reset_input_scrollbar(AgsAutomationEditor * automation_editor)1007 ags_automation_editor_reset_input_scrollbar(AgsAutomationEditor *automation_editor)
1008 {
1009   AgsAutomationToolbar *automation_toolbar;
1010 
1011   GtkAdjustment *input_vscrollbar_adjustment;
1012   GtkAdjustment *input_hscrollbar_adjustment;
1013 
1014   GtkAllocation automation_edit_box_allocation;
1015   GtkAllocation viewport_allocation;
1016 
1017   GList *list_start, *list;
1018 
1019   gdouble old_h_upper;
1020   gdouble v_upper, h_upper;
1021   double zoom;
1022   double zoom_correction;
1023   guint map_width;
1024 
1025   automation_toolbar = automation_editor->automation_toolbar;
1026 
1027   /* input */
1028   gtk_widget_get_allocation(GTK_WIDGET(automation_editor->input_scrolled_automation_edit_box->automation_edit_box),
1029 			    &automation_edit_box_allocation);
1030 
1031   gtk_widget_get_allocation(GTK_WIDGET(automation_editor->input_scrolled_automation_edit_box->viewport),
1032 			    &viewport_allocation);
1033 
1034   /* reset vertical scrollbar */
1035   v_upper = automation_edit_box_allocation.height - viewport_allocation.height;
1036 
1037   if(v_upper < 0.0){
1038     v_upper = 0.0;
1039   }
1040 
1041   input_vscrollbar_adjustment = gtk_range_get_adjustment(GTK_RANGE(automation_editor->input_vscrollbar));
1042 
1043   gtk_adjustment_set_upper(input_vscrollbar_adjustment,
1044 			   v_upper);
1045 
1046   gtk_adjustment_set_upper(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(automation_editor->input_scrolled_automation_edit_box->viewport)),
1047 			   v_upper);
1048   gtk_adjustment_set_upper(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(automation_editor->input_scrolled_scale_box->viewport)),
1049 			   v_upper);
1050 
1051   /* reset horizontal scrollbar */
1052   zoom = exp2((double) gtk_combo_box_get_active((GtkComboBox *) automation_toolbar->zoom) - 2.0);
1053 
1054   /* upper */
1055   input_hscrollbar_adjustment = gtk_range_get_adjustment(GTK_RANGE(automation_editor->input_hscrollbar));
1056 
1057   old_h_upper = gtk_adjustment_get_upper(input_hscrollbar_adjustment);
1058 
1059   zoom_correction = 1.0 / 16;
1060 
1061 //  map_width = (gui_scale_factor * (double) AGS_AUTOMATION_EDITOR_MAX_CONTROLS * zoom * zoom_correction);
1062   map_width = ((64.0) * (16.0 * 16.0 * 1200.0) * zoom * zoom_correction);
1063   h_upper = map_width - automation_edit_box_allocation.width;
1064 
1065   if(h_upper < 0.0){
1066     h_upper = 0.0;
1067   }
1068 
1069   gtk_adjustment_set_upper(automation_editor->input_ruler->adjustment,
1070 			   h_upper);
1071 
1072   gtk_adjustment_set_upper(input_hscrollbar_adjustment,
1073 			   h_upper);
1074 
1075   /* automation edit */
1076   list_start =
1077     list = gtk_container_get_children(GTK_CONTAINER(automation_editor->input_scrolled_automation_edit_box->automation_edit_box));
1078 
1079   while(list != NULL){
1080     GtkAdjustment *adjustment;
1081 
1082     adjustment = gtk_range_get_adjustment(GTK_RANGE(AGS_AUTOMATION_EDIT(list->data)->hscrollbar));
1083 
1084     gtk_adjustment_set_upper(adjustment,
1085 			     h_upper);
1086 
1087 
1088     list = list->next;
1089   }
1090 
1091   g_list_free(list_start);
1092 
1093   /* reset value */
1094   if(old_h_upper != 0.0){
1095 #if 0
1096     gtk_adjustment_set_value(input_hscrollbar_adjustment,
1097 			     gtk_adjustment_get_value(input_hscrollbar_adjustment) / old_h_upper * h_upper);
1098 #endif
1099   }
1100 }
1101 
1102 void
ags_automation_editor_show(GtkWidget * widget)1103 ags_automation_editor_show(GtkWidget *widget)
1104 {
1105   GTK_WIDGET_CLASS(ags_automation_editor_parent_class)->show(widget);
1106 
1107   gtk_widget_hide((GtkWidget *) AGS_AUTOMATION_EDITOR(widget)->automation_meta);
1108 }
1109 
1110 void
ags_automation_editor_show_all(GtkWidget * widget)1111 ags_automation_editor_show_all(GtkWidget *widget)
1112 {
1113   GTK_WIDGET_CLASS(ags_automation_editor_parent_class)->show_all(widget);
1114 
1115   gtk_widget_hide((GtkWidget *) AGS_AUTOMATION_EDITOR(widget)->automation_meta);
1116 }
1117 
1118 void
ags_automation_editor_real_machine_changed(AgsAutomationEditor * automation_editor,AgsMachine * machine)1119 ags_automation_editor_real_machine_changed(AgsAutomationEditor *automation_editor, AgsMachine *machine)
1120 {
1121   AgsMachine *old_machine;
1122 
1123   AgsApplicationContext *application_context;
1124 
1125   GList *list_start, *list;
1126   GList *tab;
1127 
1128   gdouble gui_scale_factor;
1129   guint length;
1130   guint output_pads, input_pads;
1131   guint audio_channels;
1132   guint i;
1133 
1134   /* disconnect set pads - old */
1135   old_machine = automation_editor->selected_machine;
1136 
1137   if(old_machine != NULL){
1138     g_object_disconnect(old_machine,
1139 			"any_signal::resize-audio-channels",
1140 			G_CALLBACK(ags_automation_editor_resize_audio_channels_callback),
1141 			(gpointer) automation_editor,
1142 			"any_signal::resize-pads",
1143 			G_CALLBACK(ags_automation_editor_resize_pads_callback),
1144 			(gpointer) automation_editor,
1145 			NULL);
1146   }
1147 
1148   application_context = ags_application_context_get_instance();
1149 
1150   /* scale factor */
1151   gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
1152 
1153   /* notebook - remove tabs */
1154   length = g_list_length(automation_editor->output_notebook->tab);
1155 
1156   for(i = 0; i < length; i++){
1157     ags_notebook_remove_tab(automation_editor->output_notebook,
1158 			    0);
1159   }
1160 
1161   length = g_list_length(automation_editor->input_notebook->tab);
1162 
1163   for(i = 0; i < length; i++){
1164     ags_notebook_remove_tab(automation_editor->input_notebook,
1165 			    0);
1166   }
1167 
1168   /* notebook - add tabs */
1169   if(machine != NULL){
1170     audio_channels = 0;
1171 
1172     output_pads = 0;
1173     input_pads = 0;
1174 
1175     g_object_get(machine->audio,
1176 		 "audio-channels", &audio_channels,
1177 		 "output-pads", &output_pads,
1178 		 "input-pads", &input_pads,
1179 		 NULL);
1180 
1181     for(i = 0; i < output_pads * audio_channels; i++){
1182       ags_notebook_insert_tab(automation_editor->output_notebook,
1183 			      i);
1184 
1185       tab = automation_editor->output_notebook->tab;
1186       gtk_toggle_button_set_active(AGS_NOTEBOOK_TAB(tab->data)->toggle,
1187 				   TRUE);
1188     }
1189 
1190     for(i = 0; i < input_pads * audio_channels; i++){
1191       ags_notebook_insert_tab(automation_editor->input_notebook,
1192 			      i);
1193 
1194       tab = automation_editor->input_notebook->tab;
1195       gtk_toggle_button_set_active(AGS_NOTEBOOK_TAB(tab->data)->toggle,
1196 				   TRUE);
1197     }
1198   }
1199 
1200   /*
1201    * destroy old
1202    */
1203   /* audio */
1204   list =
1205     list_start = gtk_container_get_children(GTK_CONTAINER(automation_editor->audio_scrolled_scale_box->scale_box));
1206 
1207   while(list != NULL){
1208     gtk_widget_destroy(list->data);
1209 
1210     list = list->next;
1211   }
1212 
1213   g_list_free(list_start);
1214 
1215   list =
1216     list_start = gtk_container_get_children(GTK_CONTAINER(automation_editor->audio_scrolled_automation_edit_box->automation_edit_box));
1217 
1218   while(list != NULL){
1219     g_object_disconnect(AGS_AUTOMATION_EDIT(list->data)->hscrollbar,
1220 			"any_signal::value-changed",
1221 			G_CALLBACK(ags_automation_editor_audio_automation_edit_hscrollbar_value_changed),
1222 			(gpointer) automation_editor,
1223 			NULL);
1224 
1225     gtk_widget_destroy(list->data);
1226 
1227     list = list->next;
1228   }
1229 
1230   g_list_free(list_start);
1231 
1232   /* output */
1233   list =
1234     list_start = gtk_container_get_children(GTK_CONTAINER(automation_editor->output_scrolled_scale_box->scale_box));
1235 
1236   while(list != NULL){
1237     gtk_widget_destroy(list->data);
1238 
1239     list = list->next;
1240   }
1241 
1242   g_list_free(list_start);
1243 
1244   list =
1245     list_start = gtk_container_get_children(GTK_CONTAINER(automation_editor->output_scrolled_automation_edit_box->automation_edit_box));
1246 
1247   while(list != NULL){
1248     g_object_disconnect(AGS_AUTOMATION_EDIT(list->data)->hscrollbar,
1249 			"any_signal::value-changed",
1250 			G_CALLBACK(ags_automation_editor_output_automation_edit_hscrollbar_value_changed),
1251 			(gpointer) automation_editor,
1252 			NULL);
1253 
1254     gtk_widget_destroy(list->data);
1255 
1256     list = list->next;
1257   }
1258 
1259   g_list_free(list_start);
1260 
1261   /* input */
1262   list =
1263     list_start = gtk_container_get_children(GTK_CONTAINER(automation_editor->input_scrolled_scale_box->scale_box));
1264 
1265   while(list != NULL){
1266     gtk_widget_destroy(list->data);
1267 
1268     list = list->next;
1269   }
1270 
1271   g_list_free(list_start);
1272 
1273   list =
1274     list_start = gtk_container_get_children(GTK_CONTAINER(automation_editor->input_scrolled_automation_edit_box->automation_edit_box));
1275 
1276   while(list != NULL){
1277     g_object_disconnect(AGS_AUTOMATION_EDIT(list->data)->hscrollbar,
1278 			"any_signal::value-changed",
1279 			G_CALLBACK(ags_automation_editor_input_automation_edit_hscrollbar_value_changed),
1280 			(gpointer) automation_editor,
1281 			NULL);
1282 
1283     gtk_widget_destroy(list->data);
1284 
1285     list = list->next;
1286   }
1287 
1288   g_list_free(list_start);
1289 
1290   /*
1291    * add new
1292    */
1293   if(machine != NULL){
1294     AgsChannel *start_channel, *channel;
1295 
1296     GList *automation_port;
1297     GList *start_audio_port;
1298     GList *start_output_port;
1299     GList *start_input_port;
1300     GList *start_port, *port;
1301 
1302     /* audio */
1303     automation_port = machine->enabled_automation_port;
1304 
1305     start_audio_port = ags_audio_collect_all_audio_ports(machine->audio);
1306 
1307     g_object_get(machine->audio,
1308 		 "output", &start_channel,
1309 		 NULL);
1310 
1311     channel = start_channel;
1312 
1313     start_output_port = NULL;
1314 
1315     while(channel != NULL){
1316       AgsChannel *next_channel;
1317 
1318       GList *list;
1319 
1320       list = ags_channel_collect_all_channel_ports(channel);
1321 
1322       if(start_output_port == NULL){
1323 	start_output_port = list;
1324       }else{
1325 	start_output_port = g_list_concat(start_output_port,
1326 					  list);
1327       }
1328 
1329       /* iterate */
1330       next_channel = ags_channel_next(channel);
1331 
1332       g_object_unref(channel);
1333 
1334       channel = next_channel;
1335     }
1336 
1337     g_object_get(machine->audio,
1338 		 "input", &start_channel,
1339 		 NULL);
1340 
1341     channel = start_channel;
1342 
1343     start_input_port = NULL;
1344 
1345     while(channel != NULL){
1346       AgsChannel *next_channel;
1347 
1348       GList *list;
1349 
1350       list = ags_channel_collect_all_channel_ports(channel);
1351 
1352       if(start_input_port == NULL){
1353 	start_input_port = list;
1354       }else{
1355 	start_input_port = g_list_concat(start_input_port,
1356 					 list);
1357       }
1358 
1359       /* iterate */
1360       next_channel = ags_channel_next(channel);
1361 
1362       g_object_unref(channel);
1363 
1364       channel = next_channel;
1365     }
1366 
1367     while(automation_port != NULL){
1368       AgsAutomationEdit *automation_edit;
1369       AgsScale *scale;
1370 
1371       gchar *control_name;
1372 
1373       gdouble upper, lower;
1374       gdouble default_value;
1375 
1376       g_message("%s", AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->control_name);
1377 
1378       /* scale */
1379       scale = ags_scale_new();
1380       g_object_set(scale,
1381 		   "scale-width", (guint) (gui_scale_factor * AGS_SCALE_DEFAULT_SCALE_WIDTH),
1382 		   "scale-height", (guint) (gui_scale_factor * AGS_SCALE_DEFAULT_SCALE_HEIGHT),
1383 		   NULL);
1384 
1385       control_name = g_strdup(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->control_name);
1386 
1387       start_port = NULL;
1388 
1389       if(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type == G_TYPE_NONE){
1390 	start_port = start_audio_port;
1391       }else if(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type == AGS_TYPE_OUTPUT){
1392 	start_port = start_output_port;
1393       }else if(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type == AGS_TYPE_INPUT){
1394 	start_port = start_input_port;
1395       }
1396 
1397       upper = 0.0;
1398       lower = 0.0;
1399 
1400       default_value = 0.0;
1401 
1402       port = start_port;
1403 
1404       while(port != NULL){
1405 	AgsPluginPort *plugin_port;
1406 
1407 	gchar *specifier;
1408 
1409 	gboolean success;
1410 
1411 	specifier = NULL;
1412 	plugin_port = NULL;
1413 
1414 	g_object_get(port->data,
1415 		     "specifier", &specifier,
1416 		     "plugin-port", &plugin_port,
1417 		     NULL);
1418 
1419 	success = FALSE;
1420 
1421 	if(!g_strcmp0(specifier,
1422 		      control_name)){
1423 	  GValue *upper_value;
1424 	  GValue *lower_value;
1425 	  GValue *value;
1426 
1427 	  upper_value = NULL;
1428 	  lower_value = NULL;
1429 	  value = NULL;
1430 
1431 	  g_object_get(plugin_port,
1432 		       "upper-value", &upper_value,
1433 		       "lower-value", &lower_value,
1434 		       "default-value", &value,
1435 		       NULL);
1436 
1437 	  upper = g_value_get_float(upper_value);
1438 	  lower = g_value_get_float(lower_value);
1439 
1440 	  default_value = g_value_get_float(value);
1441 
1442 	  g_value_unset(upper_value);
1443 	  g_free(upper_value);
1444 
1445 	  g_value_unset(lower_value);
1446 	  g_free(lower_value);
1447 
1448 	  g_value_unset(value);
1449 	  g_free(value);
1450 
1451 	  success = TRUE;
1452 	}
1453 
1454 	if(plugin_port != NULL){
1455 	  g_object_unref(plugin_port);
1456 	}
1457 
1458 	if(success){
1459 	  break;
1460 	}
1461 
1462 	port = port->next;
1463       }
1464 
1465       g_object_set(scale,
1466 		   "control-name", control_name,
1467 		   "upper", upper,
1468 		   "lower", lower,
1469 		   "default-value", default_value,
1470 		   NULL);
1471 
1472       if(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type == G_TYPE_NONE){
1473 	gtk_box_pack_start(GTK_BOX(automation_editor->audio_scrolled_scale_box->scale_box),
1474 			   GTK_WIDGET(scale),
1475 			   FALSE, TRUE,
1476 			   AGS_AUTOMATION_EDIT_DEFAULT_PADDING);
1477       }else if(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type == AGS_TYPE_OUTPUT){
1478 	gtk_box_pack_start(GTK_BOX(automation_editor->output_scrolled_scale_box->scale_box),
1479 			   GTK_WIDGET(scale),
1480 			   FALSE, TRUE,
1481 			   AGS_AUTOMATION_EDIT_DEFAULT_PADDING);
1482       }else if(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type == AGS_TYPE_INPUT){
1483 	gtk_box_pack_start(GTK_BOX(automation_editor->input_scrolled_scale_box->scale_box),
1484 			   GTK_WIDGET(scale),
1485 			   FALSE, TRUE,
1486 			   AGS_AUTOMATION_EDIT_DEFAULT_PADDING);
1487       }
1488 
1489       {
1490 	GtkAllocation allocation;
1491 
1492 	gtk_widget_get_allocation((GtkWidget *) scale,
1493 				  &allocation);
1494 
1495 	g_message("%d|%d %d,%d", allocation.x, allocation.y, allocation.width, allocation.height);
1496       }
1497 
1498       gtk_widget_show(GTK_WIDGET(scale));
1499 
1500       /* automation edit */
1501       automation_edit = ags_automation_edit_new();
1502 
1503       g_object_set(automation_edit,
1504 		   "channel-type", AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type,
1505 		   "control-specifier", AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->control_name,
1506 		   "control-name", control_name,
1507 		   "upper", upper,
1508 		   "lower", lower,
1509 		   "default-value", default_value,
1510 		   NULL);
1511 
1512       if(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type == G_TYPE_NONE){
1513 	gtk_box_pack_start(GTK_BOX(automation_editor->audio_scrolled_automation_edit_box->automation_edit_box),
1514 			   GTK_WIDGET(automation_edit),
1515 			   FALSE, TRUE,
1516 			   AGS_AUTOMATION_EDIT_DEFAULT_PADDING);
1517       }else if(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type == AGS_TYPE_OUTPUT){
1518 	gtk_box_pack_start(GTK_BOX(automation_editor->output_scrolled_automation_edit_box->automation_edit_box),
1519 			   GTK_WIDGET(automation_edit),
1520 			   FALSE, TRUE,
1521 			   AGS_AUTOMATION_EDIT_DEFAULT_PADDING);
1522       }else if(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type == AGS_TYPE_INPUT){
1523 	gtk_box_pack_start(GTK_BOX(automation_editor->input_scrolled_automation_edit_box->automation_edit_box),
1524 			   GTK_WIDGET(automation_edit),
1525 			   FALSE, TRUE,
1526 			   AGS_AUTOMATION_EDIT_DEFAULT_PADDING);
1527       }
1528 
1529       ags_connectable_connect(AGS_CONNECTABLE(automation_edit));
1530       gtk_widget_show(GTK_WIDGET(automation_edit));
1531 
1532       if(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type == G_TYPE_NONE){
1533 	g_signal_connect_after((GObject *) automation_edit->hscrollbar, "value-changed",
1534 			       G_CALLBACK(ags_automation_editor_audio_automation_edit_hscrollbar_value_changed), (gpointer) automation_editor);
1535       }else if(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type == AGS_TYPE_OUTPUT){
1536 	g_signal_connect_after((GObject *) automation_edit->hscrollbar, "value-changed",
1537 			       G_CALLBACK(ags_automation_editor_output_automation_edit_hscrollbar_value_changed), (gpointer) automation_editor);
1538       }else if(AGS_MACHINE_AUTOMATION_PORT(automation_port->data)->channel_type == AGS_TYPE_INPUT){
1539 	g_signal_connect_after((GObject *) automation_edit->hscrollbar, "value-changed",
1540 			       G_CALLBACK(ags_automation_editor_input_automation_edit_hscrollbar_value_changed), (gpointer) automation_editor);
1541       }
1542 
1543       g_free(control_name);
1544 
1545       /* iterate */
1546       automation_port = automation_port->next;
1547     }
1548 
1549     g_list_free_full(start_audio_port,
1550 		     (GDestroyNotify) g_object_unref);
1551 
1552     g_list_free_full(start_output_port,
1553 		     (GDestroyNotify) g_object_unref);
1554 
1555     g_list_free_full(start_input_port,
1556 		     (GDestroyNotify) g_object_unref);
1557   }
1558 
1559   /* selected machine */
1560   automation_editor->selected_machine = machine;
1561 
1562   /* connect set-pads - new */
1563   if(machine != NULL){
1564     g_signal_connect_after(machine, "resize-audio-channels",
1565 			   G_CALLBACK(ags_automation_editor_resize_audio_channels_callback), automation_editor);
1566 
1567     g_signal_connect_after(machine, "resize-pads",
1568 			   G_CALLBACK(ags_automation_editor_resize_pads_callback), automation_editor);
1569   }
1570 }
1571 
1572 /**
1573  * ags_automation_editor_machine_changed:
1574  * @automation_editor: an #AgsAutomationEditor
1575  * @machine: the new #AgsMachine
1576  *
1577  * Is emitted as machine changed of automation editor.
1578  *
1579  * Since: 3.0.0
1580  */
1581 void
ags_automation_editor_machine_changed(AgsAutomationEditor * automation_editor,AgsMachine * machine)1582 ags_automation_editor_machine_changed(AgsAutomationEditor *automation_editor, AgsMachine *machine)
1583 {
1584   g_return_if_fail(AGS_IS_AUTOMATION_EDITOR(automation_editor));
1585 
1586   g_object_ref((GObject *) automation_editor);
1587   g_signal_emit((GObject *) automation_editor,
1588 		automation_editor_signals[MACHINE_CHANGED], 0,
1589 		machine);
1590   g_object_unref((GObject *) automation_editor);
1591 }
1592 
1593 void
ags_automation_editor_add_acceleration(AgsAutomationEditor * automation_editor,AgsAcceleration * acceleration)1594 ags_automation_editor_add_acceleration(AgsAutomationEditor *automation_editor,
1595 				       AgsAcceleration *acceleration)
1596 {
1597   AgsMachine *machine;
1598   AgsNotebook *notebook;
1599 
1600   AgsAutomation *automation;
1601 
1602   AgsTimestamp *timestamp;
1603 
1604   gint i;
1605 
1606   if(!AGS_IS_AUTOMATION_EDITOR(automation_editor) ||
1607      !AGS_IS_ACCELERATION(acceleration) ||
1608      automation_editor->focused_automation_edit == NULL){
1609     return;
1610   }
1611 
1612   if(automation_editor->selected_machine != NULL){
1613     AgsChannel *start_output, *start_input;
1614     AgsChannel *nth_channel;
1615 
1616     machine = automation_editor->selected_machine;
1617 
1618     notebook = NULL;
1619 
1620     if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_OUTPUT){
1621       notebook = automation_editor->output_notebook;
1622     }else if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_INPUT){
1623       notebook = automation_editor->input_notebook;
1624     }
1625 
1626     /* get some fields */
1627     start_output = NULL;
1628     start_input = NULL;
1629 
1630     g_object_get(machine->audio,
1631 		 "output", &start_output,
1632 		 "input", &start_input,
1633 		 NULL);
1634 
1635     /* check all active tabs */
1636     timestamp = ags_timestamp_new();
1637 
1638     timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
1639     timestamp->flags |= AGS_TIMESTAMP_OFFSET;
1640 
1641     timestamp->timer.ags_offset.offset = AGS_AUTOMATION_DEFAULT_OFFSET * floor(acceleration->x / AGS_AUTOMATION_DEFAULT_OFFSET);
1642 
1643     i = 0;
1644 
1645     while(notebook == NULL ||
1646 	  (i = ags_notebook_next_active_tab(notebook,
1647 					    i)) != -1){
1648       AgsAcceleration *new_acceleration;
1649 
1650       GList *start_play_port, *play_port;
1651       GList *start_recall_port, *recall_port;
1652       GList *start_list, *list;
1653 
1654       play_port = NULL;
1655       recall_port = NULL;
1656 
1657       if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_OUTPUT){
1658 	nth_channel = ags_channel_nth(start_output,
1659 				      i);
1660 
1661 	play_port =
1662 	  start_play_port = ags_channel_collect_all_channel_ports_by_specifier_and_context(nth_channel,
1663 											   automation_editor->focused_automation_edit->control_name,
1664 											   TRUE);
1665 
1666 	recall_port =
1667 	  start_recall_port = ags_channel_collect_all_channel_ports_by_specifier_and_context(nth_channel,
1668 											     automation_editor->focused_automation_edit->control_name,
1669 											     FALSE);
1670 
1671 	if(nth_channel != NULL){
1672 	  g_object_unref(nth_channel);
1673 	}
1674       }else if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_INPUT){
1675 	nth_channel = ags_channel_nth(start_input,
1676 				      i);
1677 
1678 	play_port =
1679 	  start_play_port = ags_channel_collect_all_channel_ports_by_specifier_and_context(nth_channel,
1680 											   automation_editor->focused_automation_edit->control_name,
1681 											   TRUE);
1682 
1683 	recall_port =
1684 	  start_recall_port = ags_channel_collect_all_channel_ports_by_specifier_and_context(nth_channel,
1685 											     automation_editor->focused_automation_edit->control_name,
1686 											     FALSE);
1687 
1688 	if(nth_channel != NULL){
1689 	  g_object_unref(nth_channel);
1690 	}
1691       }else{
1692 	play_port =
1693 	  start_play_port = ags_audio_collect_all_audio_ports_by_specifier_and_context(machine->audio,
1694 										       automation_editor->focused_automation_edit->control_name,
1695 										       TRUE);
1696 
1697 	recall_port =
1698 	  start_recall_port = ags_audio_collect_all_audio_ports_by_specifier_and_context(machine->audio,
1699 											 automation_editor->focused_automation_edit->control_name,
1700 											 FALSE);
1701       }
1702 
1703       /* play port */
1704       while(play_port != NULL){
1705 	AgsPort *current_port;
1706 
1707 	current_port = play_port->data;
1708 
1709 	g_object_get(current_port,
1710 		     "automation", &start_list,
1711 		     NULL);
1712 
1713 	list = ags_automation_find_near_timestamp(start_list, i,
1714 						  timestamp);
1715 
1716 	if(list == NULL){
1717 	  automation = ags_automation_new(G_OBJECT(machine->audio),
1718 					  i,
1719 					  automation_editor->focused_automation_edit->channel_type, automation_editor->focused_automation_edit->control_name);
1720 	  automation->timestamp->timer.ags_offset.offset = timestamp->timer.ags_offset.offset;
1721 
1722 	  g_object_set(automation,
1723 		       "port", current_port,
1724 		       NULL);
1725 
1726 	  /* add to audio */
1727 	  ags_audio_add_automation(machine->audio,
1728 				   (GObject *) automation);
1729 
1730 	  /* add to port */
1731 	  ags_port_add_automation(current_port,
1732 				  (GObject *) automation);
1733 	}else{
1734 	  automation = list->data;
1735 	}
1736 
1737 	new_acceleration = ags_acceleration_duplicate(acceleration);
1738 	ags_automation_add_acceleration(automation,
1739 					new_acceleration,
1740 					FALSE);
1741 
1742 	g_list_free_full(start_list,
1743 			 g_object_unref);
1744 
1745 	/* iterate */
1746 	play_port = play_port->next;
1747       }
1748 
1749       g_list_free_full(start_play_port,
1750 		       g_object_unref);
1751 
1752       /* recall port */
1753       if(recall_port != NULL){
1754 	AgsPort *current_port;
1755 
1756 	current_port = recall_port->data;
1757 
1758 	g_object_get(current_port,
1759 		     "automation", &start_list,
1760 		     NULL);
1761 
1762 	list = ags_automation_find_near_timestamp(start_list, i,
1763 						  timestamp);
1764 
1765 	if(list == NULL){
1766 	  automation = ags_automation_new(G_OBJECT(machine->audio),
1767 					  i,
1768 					  automation_editor->focused_automation_edit->channel_type, automation_editor->focused_automation_edit->control_name);
1769 	  automation->timestamp->timer.ags_offset.offset = timestamp->timer.ags_offset.offset;
1770 	  g_object_set(automation,
1771 		       "port", current_port,
1772 		       NULL);
1773 
1774 	  /* add to audio */
1775 	  ags_audio_add_automation(machine->audio,
1776 				   (GObject *) automation);
1777 
1778 	  /* add to port */
1779 	  ags_port_add_automation(current_port,
1780 				  (GObject *) automation);
1781 	}else{
1782 	  automation = list->data;
1783 	}
1784 
1785 	new_acceleration = ags_acceleration_duplicate(acceleration);
1786 	ags_automation_add_acceleration(automation,
1787 					new_acceleration,
1788 					FALSE);
1789 
1790 	g_list_free_full(start_list,
1791 			 g_object_unref);
1792 
1793 	/* iterate */
1794 	recall_port = recall_port->next;
1795       }
1796 
1797       g_list_free_full(start_recall_port,
1798 		       g_object_unref);
1799 
1800       if(notebook == NULL){
1801 	break;
1802       }
1803 
1804       i++;
1805     }
1806 
1807     /* unref */
1808     if(start_output != NULL){
1809       g_object_unref(start_output);
1810     }
1811 
1812     if(start_input != NULL){
1813       g_object_unref(start_input);
1814     }
1815 
1816     g_object_unref(timestamp);
1817 
1818     gtk_widget_queue_draw(GTK_WIDGET(automation_editor->focused_automation_edit));
1819   }
1820 }
1821 
1822 void
ags_automation_editor_delete_acceleration(AgsAutomationEditor * automation_editor,guint x,gdouble y)1823 ags_automation_editor_delete_acceleration(AgsAutomationEditor *automation_editor,
1824 					  guint x, gdouble y)
1825 {
1826   AgsMachine *machine;
1827   AgsNotebook *notebook;
1828 
1829   GtkAdjustment *automation_edit_vscrollbar_adjustment;
1830 
1831   AgsAutomation *automation;
1832 
1833   AgsTimestamp *timestamp;
1834 
1835   GtkAllocation automation_edit_allocation;
1836 
1837   GList *start_list_automation, *list_automation;
1838 
1839   gdouble c_range;
1840   guint g_range;
1841   guint scan_x;
1842   gdouble scan_y;
1843   gboolean success;
1844   gint i, j, j_step, j_stop;
1845 
1846   if(!AGS_IS_AUTOMATION_EDITOR(automation_editor) ||
1847      automation_editor->focused_automation_edit == NULL){
1848     return;
1849   }
1850 
1851   if(automation_editor->selected_machine != NULL){
1852     machine = automation_editor->selected_machine;
1853 
1854     notebook = NULL;
1855 
1856     if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_OUTPUT){
1857       notebook = automation_editor->output_notebook;
1858     }else if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_INPUT){
1859       notebook = automation_editor->input_notebook;
1860     }
1861 
1862     if((AGS_AUTOMATION_EDIT_LOGARITHMIC & (automation_editor->focused_automation_edit->flags)) != 0){
1863       c_range = exp(automation_editor->focused_automation_edit->upper) - exp(automation_editor->focused_automation_edit->lower);
1864     }else{
1865       c_range = automation_editor->focused_automation_edit->upper - automation_editor->focused_automation_edit->lower;
1866     }
1867 
1868     gtk_widget_get_allocation(GTK_WIDGET(automation_editor->focused_automation_edit->drawing_area),
1869 			      &automation_edit_allocation);
1870 
1871     automation_edit_vscrollbar_adjustment = gtk_range_get_adjustment(GTK_RANGE(automation_editor->focused_automation_edit->vscrollbar));
1872 
1873     g_range = gtk_adjustment_get_upper(automation_edit_vscrollbar_adjustment) + automation_edit_allocation.height;
1874 
1875     /* check all active tabs */
1876     g_object_get(machine->audio,
1877 		 "automation", &start_list_automation,
1878 		 NULL);
1879 
1880     timestamp = ags_timestamp_new();
1881 
1882     timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
1883     timestamp->flags |= AGS_TIMESTAMP_OFFSET;
1884 
1885     timestamp->timer.ags_offset.offset = AGS_AUTOMATION_DEFAULT_OFFSET * floor(x / AGS_AUTOMATION_DEFAULT_OFFSET);
1886 
1887     i = 0;
1888 
1889     while(notebook == NULL ||
1890 	  (i = ags_notebook_next_active_tab(notebook,
1891 					    i)) != -1){
1892       list_automation = start_list_automation;
1893 
1894       while((list_automation = ags_automation_find_near_timestamp_extended(list_automation, i,
1895 									   automation_editor->focused_automation_edit->channel_type, automation_editor->focused_automation_edit->control_name,
1896 									   timestamp)) != NULL){
1897 
1898 	if(list_automation != NULL){
1899 	  automation = list_automation->data;
1900 	}else{
1901 	  if(notebook == NULL){
1902 	    break;
1903 	  }
1904 
1905 	  list_automation = list_automation->next;
1906 
1907 	  i++;
1908 
1909 	  continue;
1910 	}
1911 
1912 	success = FALSE;
1913 
1914 	j = 0;
1915 	j_step = 1;
1916 	j_stop = 4;
1917 
1918 	while(!success &&
1919 	      exp2(j_step) <= AGS_AUTOMATION_EDIT_DEFAULT_SCAN_WIDTH){
1920 	  scan_x = (-1 * j_step + floor(j / (2 * j_step)));
1921 
1922 	  if((AGS_AUTOMATION_EDIT_LOGARITHMIC & (automation_editor->focused_automation_edit->flags)) != 0){
1923 	    scan_y = log((-1 * j_step + floor(j % (2 * j_step))) / g_range) * c_range;
1924 	  }else{
1925 	    scan_y = ((-1 * j_step + floor(j % (2 * j_step))) / g_range) * c_range;
1926 	  }
1927 
1928 	  success = ags_automation_remove_acceleration_at_position(automation,
1929 								   x - scan_x, y - scan_y);
1930 
1931 	  j++;
1932 
1933 	  if(j >= j_stop){
1934 	    j_step++;
1935 	    j_stop = exp2(j_step + 1);
1936 	  }
1937 	}
1938 
1939 
1940 	list_automation = list_automation->next;
1941       }
1942 
1943       if(notebook == NULL){
1944 	break;
1945       }
1946 
1947       i++;
1948     }
1949 
1950     g_list_free_full(start_list_automation,
1951 		     g_object_unref);
1952 
1953     /* queue draw */
1954     gtk_widget_queue_draw(GTK_WIDGET(automation_editor->focused_automation_edit));
1955   }
1956 }
1957 
1958 void
ags_automation_editor_select_region(AgsAutomationEditor * automation_editor,guint x0,gdouble y0,guint x1,gdouble y1)1959 ags_automation_editor_select_region(AgsAutomationEditor *automation_editor,
1960 				    guint x0, gdouble y0,
1961 				    guint x1, gdouble y1)
1962 {
1963   AgsMachine *machine;
1964   AgsNotebook *notebook;
1965 
1966   AgsTimestamp *timestamp;
1967 
1968   GList *start_list_automation, *list_automation;
1969 
1970   gint i;
1971 
1972   if(!AGS_IS_AUTOMATION_EDITOR(automation_editor) ||
1973      automation_editor->focused_automation_edit == NULL){
1974     return;
1975   }
1976 
1977   if(automation_editor->selected_machine != NULL){
1978     machine = automation_editor->selected_machine;
1979 
1980     notebook = NULL;
1981 
1982     if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_OUTPUT){
1983       notebook = automation_editor->output_notebook;
1984     }else if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_INPUT){
1985       notebook = automation_editor->input_notebook;
1986     }
1987 
1988     /* swap values if needed */
1989     if(x0 > x1){
1990       guint tmp;
1991 
1992       tmp = x0;
1993 
1994       x0 = x1;
1995       x1 = tmp;
1996     }
1997 
1998     if(y0 > y1){
1999       gdouble tmp;
2000 
2001       tmp = y0;
2002 
2003       y0 = y1;
2004       y1 = tmp;
2005     }
2006 
2007     /* check all active tabs */
2008     g_object_get(machine->audio,
2009 		 "automation", &start_list_automation,
2010 		 NULL);
2011 
2012     timestamp = ags_timestamp_new();
2013 
2014     timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
2015     timestamp->flags |= AGS_TIMESTAMP_OFFSET;
2016 
2017     i = 0;
2018 
2019     while(notebook == NULL ||
2020 	  (i = ags_notebook_next_active_tab(notebook,
2021 					    i)) != -1){
2022       list_automation = start_list_automation;
2023 
2024       timestamp->timer.ags_offset.offset = AGS_AUTOMATION_DEFAULT_OFFSET * floor(x0 / AGS_AUTOMATION_DEFAULT_OFFSET);
2025 
2026       while(timestamp->timer.ags_offset.offset < (AGS_AUTOMATION_DEFAULT_OFFSET * floor(x1 / AGS_AUTOMATION_DEFAULT_OFFSET)) + AGS_AUTOMATION_DEFAULT_OFFSET){
2027 	while((list_automation = ags_automation_find_near_timestamp_extended(list_automation, i,
2028 									     automation_editor->focused_automation_edit->channel_type, automation_editor->focused_automation_edit->control_name,
2029 									     timestamp)) != NULL){
2030 	  ags_automation_add_region_to_selection(list_automation->data,
2031 						 x0, y0,
2032 						 x1, y1,
2033 						 TRUE);
2034 
2035 	  /* iterate */
2036 
2037 	  list_automation = list_automation->next;
2038 	}
2039 
2040 	timestamp->timer.ags_offset.offset += AGS_AUTOMATION_DEFAULT_OFFSET;
2041       }
2042 
2043       if(notebook == NULL){
2044 	break;
2045       }
2046 
2047       i++;
2048     }
2049 
2050     g_list_free_full(start_list_automation,
2051 		     g_object_unref);
2052 
2053     /* queue draw */
2054     gtk_widget_queue_draw(GTK_WIDGET(automation_editor->focused_automation_edit));
2055   }
2056 }
2057 
2058 void
ags_automation_editor_select_all(AgsAutomationEditor * automation_editor)2059 ags_automation_editor_select_all(AgsAutomationEditor *automation_editor)
2060 {
2061   AgsMachine *machine;
2062   AgsNotebook *notebook;
2063 
2064   GType channel_type;
2065 
2066   GList *start_list_automation, *list_automation;
2067 
2068   gchar *control_name;
2069 
2070   guint line;
2071   gint i;
2072 
2073   if(!AGS_IS_AUTOMATION_EDITOR(automation_editor)){
2074     return;
2075   }
2076 
2077   if(automation_editor->selected_machine != NULL){
2078     machine = automation_editor->selected_machine;
2079 
2080     notebook = NULL;
2081 
2082     if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_OUTPUT){
2083       notebook = automation_editor->output_notebook;
2084     }else if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_INPUT){
2085       notebook = automation_editor->input_notebook;
2086     }
2087 
2088     /* check all active tabs */
2089     g_object_get(machine->audio,
2090 		 "automation", &start_list_automation,
2091 		 NULL);
2092 
2093     i = 0;
2094 
2095     while(notebook == NULL ||
2096 	  (i = ags_notebook_next_active_tab(notebook,
2097 					    i)) != -1){
2098       list_automation = start_list_automation;
2099 
2100       while(list_automation != NULL){
2101 	g_object_get(list_automation->data,
2102 		     "line", &line,
2103 		     "channel-type", &channel_type,
2104 		     "control-name", &control_name,
2105 		     NULL);
2106 
2107 	if(i != line ||
2108 	   channel_type != automation_editor->focused_automation_edit->channel_type ||
2109 	   (!g_strcmp0(control_name,
2110 		       automation_editor->focused_automation_edit->control_name)) != TRUE){
2111 	  list_automation = list_automation->next;
2112 
2113 	  continue;
2114 	}
2115 
2116 	ags_automation_add_all_to_selection(AGS_AUTOMATION(list_automation->data));
2117 
2118 	list_automation = list_automation->next;
2119       }
2120 
2121       if(notebook == NULL){
2122 	break;
2123       }
2124 
2125       i++;
2126     }
2127 
2128     g_list_free_full(start_list_automation,
2129 		     g_object_unref);
2130 
2131     /* queue draw */
2132     gtk_widget_queue_draw(GTK_WIDGET(automation_editor->focused_automation_edit));
2133   }
2134 }
2135 
2136 gint
ags_automation_editor_paste_automation_all(AgsAutomationEditor * automation_editor,AgsNotebook * notebook,AgsMachine * machine,xmlNode * automation_node,AgsTimestamp * timestamp,gboolean match_line,gboolean no_duplicates,guint position_x,guint position_y,gboolean paste_from_position,gint * last_x)2137 ags_automation_editor_paste_automation_all(AgsAutomationEditor *automation_editor,
2138 					   AgsNotebook *notebook,
2139 					   AgsMachine *machine,
2140 					   xmlNode *automation_node,
2141 					   AgsTimestamp *timestamp,
2142 					   gboolean match_line, gboolean no_duplicates,
2143 					   guint position_x, guint position_y,
2144 					   gboolean paste_from_position,
2145 					   gint *last_x)
2146 {
2147   AgsChannel *start_output, *start_input;
2148   AgsChannel *nth_channel;
2149   AgsAutomation *automation;
2150 
2151   GList *start_list_automation, *list_automation;
2152 
2153   guint first_x;
2154   guint current_x;
2155   gint i;
2156 
2157   first_x = -1;
2158 
2159   /* get some fields */
2160   start_output = NULL;
2161   start_input = NULL;
2162 
2163   g_object_get(machine->audio,
2164 	       "output", &start_output,
2165 	       "input", &start_input,
2166 	       NULL);
2167 
2168   /*  */
2169   i = 0;
2170 
2171   while(notebook == NULL ||
2172 	(i = ags_notebook_next_active_tab(notebook,
2173 					  i)) != -1){
2174     g_object_get(machine->audio,
2175 		 "automation", &start_list_automation,
2176 		 NULL);
2177 
2178     list_automation = ags_automation_find_near_timestamp_extended(start_list_automation, i,
2179 								  automation_editor->focused_automation_edit->channel_type, automation_editor->focused_automation_edit->control_name,
2180 								  timestamp);
2181 
2182     if(list_automation == NULL){
2183       GList *start_play_port, *play_port;
2184       GList *start_recall_port, *recall_port;
2185 
2186       play_port = NULL;
2187       recall_port = NULL;
2188 
2189       if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_OUTPUT){
2190 	nth_channel = ags_channel_nth(start_output,
2191 				      i);
2192 
2193 	play_port =
2194 	  start_play_port = ags_channel_collect_all_channel_ports_by_specifier_and_context(nth_channel,
2195 											   automation_editor->focused_automation_edit->control_name,
2196 											   TRUE);
2197 
2198 	recall_port =
2199 	  start_recall_port = ags_channel_collect_all_channel_ports_by_specifier_and_context(nth_channel,
2200 											     automation_editor->focused_automation_edit->control_name,
2201 											     FALSE);
2202 
2203 	if(nth_channel != NULL){
2204 	  g_object_unref(nth_channel);
2205 	}
2206       }else if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_INPUT){
2207 	nth_channel = ags_channel_nth(start_input,
2208 				      i);
2209 
2210 	play_port =
2211 	  start_play_port = ags_channel_collect_all_channel_ports_by_specifier_and_context(nth_channel,
2212 											   automation_editor->focused_automation_edit->control_name,
2213 											   TRUE);
2214 
2215 	recall_port =
2216 	  start_recall_port = ags_channel_collect_all_channel_ports_by_specifier_and_context(nth_channel,
2217 											     automation_editor->focused_automation_edit->control_name,
2218 											     FALSE);
2219 
2220 	if(nth_channel != NULL){
2221 	  g_object_unref(nth_channel);
2222 	}
2223       }else{
2224 	play_port =
2225 	  start_play_port = ags_audio_collect_all_audio_ports_by_specifier_and_context(machine->audio,
2226 										       automation_editor->focused_automation_edit->control_name,
2227 										       TRUE);
2228 
2229 	recall_port =
2230 	  start_recall_port = ags_audio_collect_all_audio_ports_by_specifier_and_context(machine->audio,
2231 											 automation_editor->focused_automation_edit->control_name,
2232 											 FALSE);
2233       }
2234 
2235       /* play port */
2236       while(play_port != NULL){
2237 	AgsPort *current_port;
2238 
2239 	current_port = play_port->data;
2240 
2241 	automation = ags_automation_new(G_OBJECT(machine->audio),
2242 					i,
2243 					automation_editor->focused_automation_edit->channel_type,
2244 					automation_editor->focused_automation_edit->control_name);
2245 	automation->timestamp->timer.ags_offset.offset = timestamp->timer.ags_offset.offset;
2246 
2247 	g_object_set(automation,
2248 		     "port", current_port,
2249 		     NULL);
2250 
2251 	/* add to audio */
2252 	ags_audio_add_automation(machine->audio,
2253 				 (GObject *) automation);
2254 
2255 	/* add to port */
2256 	ags_port_add_automation(current_port,
2257 				(GObject *) automation);
2258 
2259 	/* iterate */
2260 	play_port = play_port->next;
2261       }
2262 
2263       g_list_free_full(start_play_port,
2264 		       g_object_unref);
2265 
2266       /* recall port */
2267       if(recall_port != NULL){
2268 	AgsPort *current_port;
2269 
2270 	current_port = recall_port->data;
2271 
2272 	automation = ags_automation_new(G_OBJECT(machine->audio),
2273 					i,
2274 					automation_editor->focused_automation_edit->channel_type,
2275 					automation_editor->focused_automation_edit->control_name);
2276 	automation->timestamp->timer.ags_offset.offset = timestamp->timer.ags_offset.offset;
2277 
2278 	g_object_set(automation,
2279 		     "port", current_port,
2280 		     NULL);
2281 
2282 	/* add to audio */
2283 	ags_audio_add_automation(machine->audio,
2284 				 (GObject *) automation);
2285 
2286 	/* add to port */
2287 	ags_port_add_automation(current_port,
2288 				(GObject *) automation);
2289 
2290 	/* iterate */
2291 	recall_port = recall_port->next;
2292       }
2293 
2294       g_list_free_full(start_recall_port,
2295 		       g_object_unref);
2296     }else{
2297       automation = AGS_AUTOMATION(list_automation->data);
2298     }
2299 
2300     g_list_free_full(start_list_automation,
2301 		     g_object_unref);
2302 
2303     g_object_get(machine->audio,
2304 		 "automation", &start_list_automation,
2305 		 NULL);
2306 
2307     list_automation = start_list_automation;
2308 
2309     while((list_automation = ags_automation_find_near_timestamp_extended(list_automation, i,
2310 									 automation_editor->focused_automation_edit->channel_type, automation_editor->focused_automation_edit->control_name,
2311 									 timestamp)) != NULL){
2312       automation = list_automation->data;
2313 
2314       if(paste_from_position){
2315 	xmlNode *child;
2316 
2317 	guint x_boundary;
2318 
2319 	ags_automation_insert_from_clipboard_extended(automation,
2320 						      automation_node,
2321 						      TRUE, position_x,
2322 						      TRUE, position_y,
2323 						      match_line, no_duplicates);
2324 
2325 	/* get boundaries */
2326 	child = automation_node->children;
2327 	current_x = 0;
2328 
2329 	while(child != NULL){
2330 	  if(child->type == XML_ELEMENT_NODE){
2331 	    if(!xmlStrncmp(child->name,
2332 			   BAD_CAST "note",
2333 			   5)){
2334 	      guint tmp;
2335 
2336 	      tmp = g_ascii_strtoull((gchar *) xmlGetProp(child,
2337 							  BAD_CAST "x"),
2338 				     NULL,
2339 				     10);
2340 
2341 	      if(tmp > current_x){
2342 		current_x = tmp;
2343 	      }
2344 	    }
2345 	  }
2346 
2347 	  child = child->next;
2348 	}
2349 
2350 	x_boundary = g_ascii_strtoull((gchar *) xmlGetProp(automation_node,
2351 							   BAD_CAST "x_boundary"),
2352 				      NULL,
2353 				      10);
2354 
2355 
2356 	if(first_x == -1 || x_boundary < first_x){
2357 	  first_x = x_boundary;
2358 	}
2359 
2360 	if(position_x > x_boundary){
2361 	  current_x += (position_x - x_boundary);
2362 	}else{
2363 	  current_x -= (x_boundary - position_x);
2364 	}
2365 
2366 	if(current_x > last_x[0]){
2367 	  last_x[0] = current_x;
2368 	}
2369       }else{
2370 	xmlNode *child;
2371 
2372 	ags_automation_insert_from_clipboard(automation,
2373 					     automation_node,
2374 					     FALSE, 0,
2375 					     FALSE, 0);
2376 
2377 	/* get boundaries */
2378 	child = automation_node->children;
2379 	current_x = 0;
2380 
2381 	while(child != NULL){
2382 	  if(child->type == XML_ELEMENT_NODE){
2383 	    if(!xmlStrncmp(child->name,
2384 			   BAD_CAST "note",
2385 			   5)){
2386 	      guint tmp;
2387 
2388 	      tmp = g_ascii_strtoull((gchar *) xmlGetProp(child,
2389 							  BAD_CAST "x"),
2390 				     NULL,
2391 				     10);
2392 
2393 	      if(tmp > current_x){
2394 		current_x = tmp;
2395 	      }
2396 	    }
2397 	  }
2398 
2399 	  child = child->next;
2400 	}
2401 
2402 	if(current_x > last_x[0]){
2403 	  last_x[0] = current_x;
2404 	}
2405       }
2406 
2407       list_automation = list_automation->next;
2408     }
2409 
2410     g_list_free_full(start_list_automation,
2411 		     g_object_unref);
2412 
2413     if(notebook == NULL){
2414       break;
2415     }
2416 
2417     i++;
2418   }
2419 
2420   /* unref */
2421   if(start_output != NULL){
2422     g_object_unref(start_output);
2423   }
2424 
2425   if(start_input != NULL){
2426     g_object_unref(start_input);
2427   }
2428 
2429   return(first_x);
2430 }
2431 
2432 gint
ags_automation_editor_paste_automation(AgsAutomationEditor * automation_editor,AgsNotebook * notebook,AgsMachine * machine,xmlNode * audio_node,guint position_x,guint position_y,gboolean paste_from_position,gint * last_x)2433 ags_automation_editor_paste_automation(AgsAutomationEditor *automation_editor,
2434 				       AgsNotebook *notebook,
2435 				       AgsMachine *machine,
2436 				       xmlNode *audio_node,
2437 				       guint position_x, guint position_y,
2438 				       gboolean paste_from_position,
2439 				       gint *last_x)
2440 {
2441   AgsTimestamp *timestamp;
2442 
2443   xmlNode *automation_list_node, *automation_node;
2444   xmlNode *timestamp_node;
2445 
2446   guint first_x;
2447   gboolean match_line, no_duplicates;
2448 
2449   first_x = -1;
2450 
2451   match_line = ((AGS_AUTOMATION_EDITOR_PASTE_MATCH_LINE & (automation_editor->flags)) != 0) ? TRUE: FALSE;
2452   no_duplicates = ((AGS_AUTOMATION_EDITOR_PASTE_NO_DUPLICATES & (automation_editor->flags)) != 0) ? TRUE: FALSE;
2453 
2454   timestamp = ags_timestamp_new();
2455 
2456   timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
2457   timestamp->flags |= AGS_TIMESTAMP_OFFSET;
2458 
2459   timestamp->timer.ags_offset.offset = 0;
2460 
2461   /* paste automation */
2462   automation_list_node = audio_node->children;
2463 
2464   while(automation_list_node != NULL){
2465     if(automation_list_node->type == XML_ELEMENT_NODE){
2466       if(!xmlStrncmp(automation_list_node->name,
2467 		     BAD_CAST "automation-list",
2468 		     14)){
2469 	automation_node = automation_list_node->children;
2470 
2471 	while(automation_node != NULL){
2472 	  if(automation_node->type == XML_ELEMENT_NODE){
2473 	    if(!xmlStrncmp(automation_node->name,
2474 			   BAD_CAST "automation",
2475 			   9)){
2476 	      guint64 offset;
2477 
2478 	      timestamp_node = automation_node->children;
2479 	      offset = 0;
2480 
2481 	      while(timestamp_node != NULL){
2482 		if(timestamp_node->type == XML_ELEMENT_NODE){
2483 		  if(!xmlStrncmp(timestamp_node->name,
2484 				 BAD_CAST "timestamp",
2485 				 10)){
2486 		    offset = g_ascii_strtoull((gchar *) xmlGetProp(timestamp_node,
2487 								   BAD_CAST "offset"),
2488 					      NULL,
2489 					      10);
2490 
2491 		    break;
2492 		  }
2493 		}
2494 
2495 		timestamp_node = timestamp_node->next;
2496 	      }
2497 
2498 	      /* 1st attempt */
2499 	      timestamp->timer.ags_offset.offset = (guint64) AGS_AUTOMATION_DEFAULT_OFFSET * floor((double) position_x / (double) AGS_AUTOMATION_DEFAULT_OFFSET);
2500 
2501 	      first_x = ags_automation_editor_paste_automation_all(automation_editor,
2502 								   notebook,
2503 								   machine,
2504 								   automation_node,
2505 								   timestamp,
2506 								   match_line, no_duplicates,
2507 								   position_x, position_y,
2508 								   paste_from_position,
2509 								   last_x);
2510 
2511 	      /* 2nd attempt */
2512 	      timestamp->timer.ags_offset.offset += AGS_AUTOMATION_DEFAULT_OFFSET;
2513 
2514 	      ags_automation_editor_paste_automation_all(automation_editor,
2515 							 notebook,
2516 							 machine,
2517 							 automation_node,
2518 							 timestamp,
2519 							 match_line, no_duplicates,
2520 							 position_x, position_y,
2521 							 paste_from_position,
2522 							 last_x);
2523 
2524 	    }
2525 	  }
2526 
2527 	  automation_node = automation_node->next;
2528 	}
2529       }
2530     }
2531 
2532     automation_list_node = automation_list_node->next;
2533   }
2534 
2535   g_object_unref(timestamp);
2536 
2537   return(first_x);
2538 }
2539 
2540 void
ags_automation_editor_paste(AgsAutomationEditor * automation_editor)2541 ags_automation_editor_paste(AgsAutomationEditor *automation_editor)
2542 {
2543   AgsMachine *machine;
2544   AgsAutomationEdit *automation_edit;
2545   AgsNotebook *notebook;
2546 
2547   xmlDoc *clipboard;
2548   xmlNode *audio_node;
2549 
2550   gchar *buffer;
2551 
2552   guint position_x, position_y;
2553   gint first_x, last_x;
2554   gboolean paste_from_position;
2555 
2556   if(!AGS_IS_AUTOMATION_EDITOR(automation_editor) ||
2557      automation_editor->focused_automation_edit == NULL){
2558     return;
2559   }
2560 
2561   if((machine = automation_editor->selected_machine) != NULL){
2562     machine = automation_editor->selected_machine;
2563 
2564     automation_edit = NULL;
2565     notebook = NULL;
2566 
2567     position_x = 0;
2568     position_y = 0;
2569 
2570     if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_OUTPUT){
2571       GList *list_start, *list;
2572 
2573       notebook = automation_editor->output_notebook;
2574 
2575       list =
2576 	list_start = gtk_container_get_children(GTK_CONTAINER(automation_editor->output_scrolled_automation_edit_box->automation_edit_box));
2577 
2578       while(list != NULL){
2579 	if(!g_strcmp0(automation_editor->focused_automation_edit->control_name,
2580 		      AGS_AUTOMATION_EDIT(list->data)->control_name)){
2581 	  automation_edit = list->data;
2582 
2583 	  break;
2584 	}
2585 
2586 	list = list->next;
2587       }
2588 
2589       g_list_free(list_start);
2590     }else if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_INPUT){
2591       GList *list_start, *list;
2592 
2593       notebook = automation_editor->input_notebook;
2594 
2595       list =
2596 	list_start = gtk_container_get_children(GTK_CONTAINER(automation_editor->input_scrolled_automation_edit_box->automation_edit_box));
2597 
2598       while(list != NULL){
2599 	if(!g_strcmp0(automation_editor->focused_automation_edit->control_name,
2600 		      AGS_AUTOMATION_EDIT(list->data)->control_name)){
2601 	  automation_edit = list->data;
2602 
2603 	  break;
2604 	}
2605 
2606 	list = list->next;
2607       }
2608 
2609       g_list_free(list_start);
2610     }else{
2611       GList *list_start, *list;
2612 
2613       list =
2614 	list_start = gtk_container_get_children(GTK_CONTAINER(automation_editor->audio_scrolled_automation_edit_box->automation_edit_box));
2615 
2616       while(list != NULL){
2617 	if(!g_strcmp0(automation_editor->focused_automation_edit->control_name,
2618 		      AGS_AUTOMATION_EDIT(list->data)->control_name)){
2619 	  automation_edit = list->data;
2620 
2621 	  break;
2622 	}
2623 
2624 	list = list->next;
2625       }
2626 
2627       g_list_free(list_start);
2628     }
2629 
2630     /* get clipboard */
2631     buffer = gtk_clipboard_wait_for_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
2632 
2633     if(buffer == NULL){
2634       return;
2635     }
2636 
2637     /* get position */
2638     if(automation_editor->automation_toolbar->selected_edit_mode == automation_editor->automation_toolbar->position){
2639       last_x = 0;
2640       paste_from_position = TRUE;
2641 
2642       position_x = automation_editor->focused_automation_edit->cursor_position_x;
2643       position_y = automation_editor->focused_automation_edit->cursor_position_y;
2644 
2645 #ifdef DEBUG
2646       printf("pasting at position: [%u,%u]\n", position_x, position_y);
2647 #endif
2648     }else{
2649       paste_from_position = FALSE;
2650     }
2651 
2652     /* get xml tree */
2653     clipboard = xmlReadMemory(buffer, strlen(buffer),
2654 			      NULL, "UTF-8",
2655 			      0);
2656     audio_node = xmlDocGetRootElement(clipboard);
2657 
2658     first_x = -1;
2659 
2660     /* iterate xml tree */
2661     while(audio_node != NULL){
2662       if(audio_node->type == XML_ELEMENT_NODE){
2663 	if(!xmlStrncmp(BAD_CAST "audio",
2664 		       audio_node->name,
2665 		       6)){
2666 	  first_x = ags_automation_editor_paste_automation(automation_editor,
2667 							   notebook,
2668 							   machine,
2669 							   audio_node,
2670 							   position_x, position_y,
2671 							   paste_from_position,
2672 							   &last_x);
2673 
2674 	  break;
2675 	}
2676       }
2677 
2678       audio_node = audio_node->next;
2679     }
2680 
2681     if(first_x == -1){
2682       first_x = 0;
2683     }
2684 
2685     xmlFreeDoc(clipboard);
2686 
2687     if(paste_from_position){
2688       gint big_step, small_step;
2689 
2690       //TODO:JK: implement me
2691       big_step = (guint) ceil((double) last_x / 16.0) * 16.0 + (automation_editor->focused_automation_edit->cursor_position_x % (guint) 16);
2692       small_step = (guint) big_step - 16;
2693 
2694       if(small_step < last_x){
2695 	automation_editor->focused_automation_edit->cursor_position_x = big_step;
2696       }else{
2697 	automation_editor->focused_automation_edit->cursor_position_x = small_step;
2698       }
2699     }
2700 
2701     gtk_widget_queue_draw(GTK_WIDGET(automation_edit));
2702   }
2703 }
2704 
2705 void
ags_automation_editor_copy(AgsAutomationEditor * automation_editor)2706 ags_automation_editor_copy(AgsAutomationEditor *automation_editor)
2707 {
2708   AgsMachine *machine;
2709   AgsNotebook *notebook;
2710 
2711   xmlDoc *clipboard;
2712   xmlNode *audio_node, *automation_list_node, *automation_node;
2713 
2714   GList *start_list_automation, *list_automation;
2715 
2716   xmlChar *buffer;
2717 
2718   int size;
2719   gint i;
2720 
2721   if(!AGS_IS_AUTOMATION_EDITOR(automation_editor) ||
2722      automation_editor->focused_automation_edit == NULL){
2723     return;
2724   }
2725 
2726   if(automation_editor->selected_machine != NULL){
2727     machine = automation_editor->selected_machine;
2728 
2729     notebook = NULL;
2730 
2731     if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_OUTPUT){
2732       notebook = automation_editor->output_notebook;
2733     }else if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_INPUT){
2734       notebook = automation_editor->input_notebook;
2735     }
2736 
2737     /* create document */
2738     clipboard = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
2739 
2740     /* create root node */
2741     audio_node = xmlNewNode(NULL,
2742 			    BAD_CAST "audio");
2743     xmlDocSetRootElement(clipboard, audio_node);
2744 
2745     automation_list_node = xmlNewNode(NULL,
2746 				    BAD_CAST "automation-list");
2747     xmlAddChild(audio_node,
2748 		automation_list_node);
2749 
2750     /* create automation nodes */
2751     g_object_get(machine->audio,
2752 		 "automation", &start_list_automation,
2753 		 NULL);
2754 
2755     i = 0;
2756 
2757     while(notebook == NULL ||
2758 	  (i = ags_notebook_next_active_tab(notebook,
2759 					    i)) != -1){
2760       list_automation = start_list_automation;
2761 
2762       /* copy */
2763       while((list_automation = ags_automation_find_near_timestamp_extended(list_automation, i,
2764 									   automation_editor->focused_automation_edit->channel_type, automation_editor->focused_automation_edit->control_name,
2765 									   NULL)) != NULL){
2766 	automation_node = ags_automation_copy_selection(AGS_AUTOMATION(list_automation->data));
2767 	xmlAddChild(automation_list_node,
2768 		    automation_node);
2769 
2770 	list_automation = list_automation->next;
2771       }
2772 
2773       if(notebook == NULL){
2774 	break;
2775       }
2776 
2777       i++;
2778     }
2779 
2780     g_list_free_full(start_list_automation,
2781 		     g_object_unref);
2782 
2783     /* write to clipboard */
2784     xmlDocDumpFormatMemoryEnc(clipboard, &buffer, &size, "UTF-8", TRUE);
2785     gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
2786 			   (gchar *) buffer, size);
2787     gtk_clipboard_store(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
2788 
2789     xmlFreeDoc(clipboard);
2790   }
2791 }
2792 
2793 void
ags_automation_editor_cut(AgsAutomationEditor * automation_editor)2794 ags_automation_editor_cut(AgsAutomationEditor *automation_editor)
2795 {
2796   AgsMachine *machine;
2797   AgsNotebook *notebook;
2798 
2799   xmlDoc *clipboard;
2800   xmlNode *audio_node;
2801   xmlNode *automation_list_node, *automation_node;
2802 
2803   GList *start_list_automation, *list_automation;
2804 
2805   xmlChar *buffer;
2806   int size;
2807   gint i;
2808 
2809   if(!AGS_IS_AUTOMATION_EDITOR(automation_editor) ||
2810      automation_editor->focused_automation_edit == NULL){
2811     return;
2812   }
2813 
2814   if(automation_editor->selected_machine != NULL){
2815     machine = automation_editor->selected_machine;
2816 
2817     notebook = NULL;
2818 
2819     if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_OUTPUT){
2820       notebook = automation_editor->output_notebook;
2821     }else if(automation_editor->focused_automation_edit->channel_type == AGS_TYPE_INPUT){
2822       notebook = automation_editor->input_notebook;
2823     }
2824 
2825     /* create document */
2826     clipboard = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
2827 
2828     /* create root node */
2829     audio_node = xmlNewNode(NULL,
2830 			    BAD_CAST "audio");
2831     xmlDocSetRootElement(clipboard, audio_node);
2832 
2833     automation_list_node = xmlNewNode(NULL,
2834 				      BAD_CAST "automation-list");
2835     xmlAddChild(audio_node,
2836 		automation_list_node);
2837 
2838     /* create automation nodes */
2839     g_object_get(machine->audio,
2840 		 "automation", &start_list_automation,
2841 		 NULL);
2842 
2843     i = 0;
2844 
2845     while(notebook == NULL ||
2846 	  (i = ags_notebook_next_active_tab(notebook,
2847 					    i)) != -1){
2848       list_automation = start_list_automation;
2849 
2850       /* cut */
2851       while((list_automation = ags_automation_find_near_timestamp_extended(list_automation, i,
2852 									   automation_editor->focused_automation_edit->channel_type, automation_editor->focused_automation_edit->control_name,
2853 									   NULL)) != NULL){
2854 	automation_node = ags_automation_cut_selection(AGS_AUTOMATION(list_automation->data));
2855 	xmlAddChild(automation_list_node,
2856 		    automation_node);
2857 
2858 	list_automation = list_automation->next;
2859       }
2860 
2861       if(notebook == NULL){
2862 	break;
2863       }
2864 
2865       i++;
2866     }
2867 
2868     g_list_free_full(start_list_automation,
2869 		     g_object_unref);
2870 
2871     gtk_widget_queue_draw(GTK_WIDGET(automation_editor->focused_automation_edit));
2872 
2873     /* write to clipboard */
2874     xmlDocDumpFormatMemoryEnc(clipboard, &buffer, &size, "UTF-8", TRUE);
2875     gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
2876 			   (gchar *) buffer, size);
2877     gtk_clipboard_store(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
2878 
2879     xmlFreeDoc(clipboard);
2880   }
2881 }
2882 
2883 void
ags_automation_editor_invert(AgsAutomationEditor * automation_editor)2884 ags_automation_editor_invert(AgsAutomationEditor *automation_editor)
2885 {
2886   g_message("ags_automation_editor_invert() - not implemented");
2887 }
2888 
2889 /**
2890  * ags_automation_editor_new:
2891  *
2892  * Create a new instance of #AgsAutomationEditor.
2893  *
2894  * Returns: the new #AgsAutomationEditor
2895  *
2896  * Since: 3.0.0
2897  */
2898 AgsAutomationEditor*
ags_automation_editor_new()2899 ags_automation_editor_new()
2900 {
2901   AgsAutomationEditor *automation_editor;
2902 
2903   automation_editor = (AgsAutomationEditor *) g_object_new(AGS_TYPE_AUTOMATION_EDITOR,
2904 							   NULL);
2905 
2906   return(automation_editor);
2907 }
2908