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