1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2021 Joël Krähemann
3 *
4 * This file is part of GSequencer.
5 *
6 * GSequencer is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GSequencer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GSequencer. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <ags/X/ags_wave_editor.h>
21 #include <ags/X/ags_wave_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_wave_edit_box.h>
27 #include <ags/X/editor/ags_vwave_edit_box.h>
28 #include <ags/X/editor/ags_wave_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_wave_editor_class_init(AgsWaveEditorClass *wave_editor);
39 void ags_wave_editor_connectable_interface_init(AgsConnectableInterface *connectable);
40 void ags_wave_editor_init(AgsWaveEditor *wave_editor);
41 void ags_wave_editor_set_property(GObject *gobject,
42 guint prop_id,
43 const GValue *value,
44 GParamSpec *param_spec);
45 void ags_wave_editor_get_property(GObject *gobject,
46 guint prop_id,
47 GValue *value,
48 GParamSpec *param_spec);
49 void ags_wave_editor_finalize(GObject *gobject);
50
51 void ags_wave_editor_connect(AgsConnectable *connectable);
52 void ags_wave_editor_disconnect(AgsConnectable *connectable);
53
54 void ags_wave_editor_show(GtkWidget *widget);
55 void ags_wave_editor_show_all(GtkWidget *widget);
56
57 gint ags_wave_editor_paste_wave_all(AgsWaveEditor *wave_editor,
58 AgsMachine *machine,
59 AgsNotebook *notebook,
60 xmlNode *wave_node,
61 AgsTimestamp *timestamp,
62 gboolean match_line,
63 gboolean paste_from_position,
64 guint64 position_x,
65 gint64 *last_x);
66 gint ags_wave_editor_paste_wave(AgsWaveEditor *wave_editor,
67 AgsMachine *machine,
68 AgsNotebook *notebook,
69 xmlNode *audio_node,
70 gboolean paste_from_position,
71 guint64 position_x,
72 guint64 relative_offset);
73
74 void ags_wave_editor_real_machine_changed(AgsWaveEditor *wave_editor, AgsMachine *machine);
75
76 enum{
77 MACHINE_CHANGED,
78 LAST_SIGNAL,
79 };
80
81 enum{
82 PROP_0,
83 };
84
85 static gpointer ags_wave_editor_parent_class = NULL;
86 static guint wave_editor_signals[LAST_SIGNAL];
87
88 /**
89 * SECTION:ags_wave_editor
90 * @short_description: A composite widget to edit wave
91 * @title: AgsWaveEditor
92 * @section_id:
93 * @include: ags/X/ags_wave_editor.h
94 *
95 * #AgsWaveEditor is a composite widget to edit wave. You may select machines
96 * or change editor tool to do wave.
97 */
98
99 GType
ags_wave_editor_get_type(void)100 ags_wave_editor_get_type(void)
101 {
102 static volatile gsize g_define_type_id__volatile = 0;
103
104 if(g_once_init_enter (&g_define_type_id__volatile)){
105 GType ags_type_wave_editor = 0;
106
107 static const GTypeInfo ags_wave_editor_info = {
108 sizeof (AgsWaveEditorClass),
109 NULL, /* base_init */
110 NULL, /* base_finalize */
111 (GClassInitFunc) ags_wave_editor_class_init,
112 NULL, /* class_finalize */
113 NULL, /* class_data */
114 sizeof (AgsWaveEditor),
115 0, /* n_preallocs */
116 (GInstanceInitFunc) ags_wave_editor_init,
117 };
118
119 static const GInterfaceInfo ags_connectable_interface_info = {
120 (GInterfaceInitFunc) ags_wave_editor_connectable_interface_init,
121 NULL, /* interface_finalize */
122 NULL, /* interface_data */
123 };
124
125 ags_type_wave_editor = g_type_register_static(GTK_TYPE_BOX,
126 "AgsWaveEditor", &ags_wave_editor_info,
127 0);
128
129 g_type_add_interface_static(ags_type_wave_editor,
130 AGS_TYPE_CONNECTABLE,
131 &ags_connectable_interface_info);
132
133 g_once_init_leave(&g_define_type_id__volatile, ags_type_wave_editor);
134 }
135
136 return g_define_type_id__volatile;
137 }
138
139 void
ags_wave_editor_connectable_interface_init(AgsConnectableInterface * connectable)140 ags_wave_editor_connectable_interface_init(AgsConnectableInterface *connectable)
141 {
142 connectable->is_ready = NULL;
143 connectable->is_connected = NULL;
144 connectable->connect = ags_wave_editor_connect;
145 connectable->disconnect = ags_wave_editor_disconnect;
146 }
147
148 void
ags_wave_editor_class_init(AgsWaveEditorClass * wave_editor)149 ags_wave_editor_class_init(AgsWaveEditorClass *wave_editor)
150 {
151 GObjectClass *gobject;
152 GtkWidgetClass *widget;
153
154 GParamSpec *param_spec;
155
156 ags_wave_editor_parent_class = g_type_class_peek_parent(wave_editor);
157
158 /* GObjectClass */
159 gobject = (GObjectClass *) wave_editor;
160
161 gobject->set_property = ags_wave_editor_set_property;
162 gobject->get_property = ags_wave_editor_get_property;
163
164 gobject->finalize = ags_wave_editor_finalize;
165
166 /* properties */
167
168 /* GtkWidgetClass */
169 widget = (GtkWidgetClass *) wave_editor;
170
171 widget->show = ags_wave_editor_show;
172 widget->show_all = ags_wave_editor_show_all;
173
174 /* AgsEditorClass */
175 wave_editor->machine_changed = ags_wave_editor_real_machine_changed;
176
177 /* signals */
178 /**
179 * AgsEditor::machine-changed:
180 * @editor: the object to change machine.
181 * @machine: the #AgsMachine to set
182 *
183 * The ::machine-changed signal notifies about changed machine.
184 *
185 * Since: 3.0.0
186 */
187 wave_editor_signals[MACHINE_CHANGED] =
188 g_signal_new("machine-changed",
189 G_TYPE_FROM_CLASS(wave_editor),
190 G_SIGNAL_RUN_LAST,
191 G_STRUCT_OFFSET(AgsWaveEditorClass, machine_changed),
192 NULL, NULL,
193 g_cclosure_marshal_VOID__OBJECT,
194 G_TYPE_NONE, 1,
195 G_TYPE_OBJECT);
196 }
197
198 void
ags_wave_editor_init(AgsWaveEditor * wave_editor)199 ags_wave_editor_init(AgsWaveEditor *wave_editor)
200 {
201 GtkViewport *viewport;
202 GtkBox *hbox;
203 GtkScrolledWindow *scrolled_window;
204 GtkGrid *grid;
205
206 GtkStyleContext *style_context;
207
208 GtkAdjustment *adjustment;
209
210 AgsApplicationContext *application_context;
211
212 gdouble gui_scale_factor;
213
214 gtk_orientable_set_orientation(GTK_ORIENTABLE(wave_editor),
215 GTK_ORIENTATION_VERTICAL);
216
217 wave_editor->flags = AGS_WAVE_EDITOR_PASTE_MATCH_LINE;
218
219 wave_editor->version = AGS_WAVE_EDITOR_DEFAULT_VERSION;
220 wave_editor->build_id = AGS_WAVE_EDITOR_DEFAULT_BUILD_ID;
221
222 application_context = ags_application_context_get_instance();
223
224 /* scale factor */
225 gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
226
227 /* offset */
228 wave_editor->tact_counter = 0;
229 wave_editor->current_tact = 0.0;
230
231 /* soundcard */
232 wave_editor->wave_toolbar = ags_wave_toolbar_new();
233 gtk_box_pack_start((GtkBox *) wave_editor,
234 (GtkWidget *) wave_editor->wave_toolbar,
235 FALSE, FALSE, 0);
236
237 wave_editor->paned = (GtkPaned *) gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
238 gtk_box_pack_start((GtkBox *) wave_editor,
239 (GtkWidget *) wave_editor->paned,
240 TRUE, TRUE, 0);
241
242 /* machine selector */
243 viewport = (GtkViewport *) gtk_viewport_new(NULL,
244 NULL);
245 g_object_set(viewport,
246 "shadow-type", GTK_SHADOW_NONE,
247 NULL);
248 gtk_paned_pack1((GtkPaned *) wave_editor->paned,
249 (GtkWidget *) viewport,
250 FALSE, TRUE);
251
252 scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
253 gtk_container_add(GTK_CONTAINER(viewport),
254 GTK_WIDGET(scrolled_window));
255
256 wave_editor->machine_selector = g_object_new(AGS_TYPE_MACHINE_SELECTOR,
257 "homogeneous", FALSE,
258 "spacing", 0,
259 NULL);
260 wave_editor->machine_selector->flags |= (AGS_MACHINE_SELECTOR_WAVE);
261 gtk_label_set_label(wave_editor->machine_selector->label,
262 i18n("wave"));
263
264 wave_editor->machine_selector->popup = ags_machine_selector_popup_new(wave_editor->machine_selector);
265 g_object_set(wave_editor->machine_selector->menu_button,
266 "menu", wave_editor->machine_selector->popup,
267 NULL);
268
269 gtk_container_add((GtkContainer *) scrolled_window,
270 (GtkWidget *) wave_editor->machine_selector);
271
272 /* selected machine */
273 wave_editor->selected_machine = NULL;
274
275 /* grid */
276 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
277 0);
278 gtk_paned_pack2((GtkPaned *) wave_editor->paned,
279 (GtkWidget *) hbox,
280 TRUE,
281 TRUE);
282
283 viewport = (GtkViewport *) gtk_viewport_new(NULL,
284 NULL);
285 g_object_set(viewport,
286 "shadow-type", GTK_SHADOW_NONE,
287 NULL);
288 gtk_box_pack_start((GtkBox *) hbox,
289 (GtkWidget *) viewport,
290 TRUE, TRUE,
291 0);
292
293 grid = (GtkGrid *) gtk_grid_new();
294 gtk_container_add(GTK_CONTAINER(viewport),
295 GTK_WIDGET(grid));
296
297 /* notebook */
298 wave_editor->notebook = g_object_new(AGS_TYPE_NOTEBOOK,
299 "homogeneous", FALSE,
300 "spacing", 0,
301 "prefix", i18n("line"),
302 NULL);
303
304 gtk_widget_set_valign((GtkWidget *) wave_editor->notebook,
305 GTK_ALIGN_FILL);
306 gtk_widget_set_halign((GtkWidget *) wave_editor->notebook,
307 GTK_ALIGN_FILL);
308
309 gtk_widget_set_hexpand((GtkWidget *) wave_editor->notebook,
310 TRUE);
311
312 gtk_grid_attach(grid,
313 (GtkWidget *) wave_editor->notebook,
314 0, 0,
315 3, 1);
316
317 /* ruler */
318 wave_editor->ruler = ags_ruler_new();
319 g_object_set(wave_editor->ruler,
320 "height-request", (gint) (gui_scale_factor * AGS_RULER_DEFAULT_HEIGHT),
321 "font-size", (guint) (gui_scale_factor * wave_editor->ruler->font_size),
322 "step", (guint) (gui_scale_factor * AGS_RULER_DEFAULT_STEP),
323 "large-step", (guint) (gui_scale_factor * AGS_RULER_DEFAULT_LARGE_STEP),
324 "small-step", (guint) (gui_scale_factor * AGS_RULER_DEFAULT_SMALL_STEP),
325 NULL);
326
327 gtk_widget_set_valign((GtkWidget *) wave_editor->ruler,
328 GTK_ALIGN_FILL);
329 gtk_widget_set_halign((GtkWidget *) wave_editor->ruler,
330 GTK_ALIGN_FILL);
331
332 gtk_widget_set_hexpand((GtkWidget *) wave_editor->ruler,
333 TRUE);
334
335 gtk_grid_attach(grid,
336 (GtkWidget *) wave_editor->ruler,
337 1, 1,
338 1, 1);
339
340 /* level */
341 wave_editor->scrolled_level_box = ags_scrolled_level_box_new();
342
343 gtk_widget_set_vexpand((GtkWidget *) wave_editor->scrolled_level_box->viewport,
344 TRUE);
345
346 g_object_set(wave_editor->scrolled_level_box,
347 "margin-top", (gint) (gui_scale_factor * AGS_RULER_DEFAULT_HEIGHT),
348 NULL);
349
350 wave_editor->scrolled_level_box->level_box = (AgsLevelBox *) ags_vlevel_box_new();
351 g_object_set(wave_editor->scrolled_level_box->level_box,
352 "fixed-level-width", (guint) (gui_scale_factor * AGS_LEVEL_BOX_DEFAULT_FIXED_LEVEL_WIDTH),
353 "fixed-level-height", (guint) (gui_scale_factor * AGS_LEVEL_BOX_DEFAULT_FIXED_LEVEL_HEIGHT),
354 NULL);
355
356 gtk_container_add(GTK_CONTAINER(wave_editor->scrolled_level_box->viewport),
357 GTK_WIDGET(wave_editor->scrolled_level_box->level_box));
358 gtk_widget_set_size_request((GtkWidget *) wave_editor->scrolled_level_box,
359 (gint) (gui_scale_factor * AGS_LEVEL_BOX_DEFAULT_FIXED_LEVEL_WIDTH),
360 -1);
361
362 gtk_widget_set_valign((GtkWidget *) wave_editor->scrolled_level_box,
363 GTK_ALIGN_FILL);
364 gtk_widget_set_halign((GtkWidget *) wave_editor->scrolled_level_box,
365 GTK_ALIGN_FILL);
366
367 gtk_widget_set_vexpand((GtkWidget *) wave_editor->scrolled_level_box,
368 TRUE);
369
370 gtk_grid_attach(grid,
371 (GtkWidget *) wave_editor->scrolled_level_box,
372 0, 2,
373 1, 1);
374
375 /* wave edit */
376 wave_editor->scrolled_wave_edit_box = ags_scrolled_wave_edit_box_new();
377
378 wave_editor->scrolled_wave_edit_box->wave_edit_box = (AgsWaveEditBox *) ags_vwave_edit_box_new();
379 g_object_set(wave_editor->scrolled_wave_edit_box->wave_edit_box,
380 "fixed-edit-height", (guint) (gui_scale_factor * AGS_LEVEL_BOX_DEFAULT_FIXED_LEVEL_HEIGHT),
381 NULL);
382 gtk_container_add(GTK_CONTAINER(wave_editor->scrolled_wave_edit_box->viewport),
383 GTK_WIDGET(wave_editor->scrolled_wave_edit_box->wave_edit_box));
384
385 gtk_widget_set_valign((GtkWidget *) wave_editor->scrolled_wave_edit_box,
386 GTK_ALIGN_FILL);
387 gtk_widget_set_halign((GtkWidget *) wave_editor->scrolled_wave_edit_box,
388 GTK_ALIGN_FILL);
389
390 gtk_widget_set_vexpand((GtkWidget *) wave_editor->scrolled_wave_edit_box,
391 TRUE);
392 gtk_widget_set_hexpand((GtkWidget *) wave_editor->scrolled_wave_edit_box,
393 TRUE);
394
395 gtk_grid_attach(grid,
396 (GtkWidget *) wave_editor->scrolled_wave_edit_box,
397 1, 2,
398 1, 1);
399
400 gtk_widget_set_events(GTK_WIDGET(wave_editor->scrolled_wave_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 /* scrollbars */
409 adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, (guint) (gui_scale_factor * AGS_WAVE_EDIT_DEFAULT_CONTROL_HEIGHT), 1.0);
410
411 wave_editor->vscrollbar = (GtkScrollbar *) gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL,
412 adjustment);
413
414 gtk_widget_set_valign((GtkWidget *) wave_editor->vscrollbar,
415 GTK_ALIGN_FILL);
416 gtk_widget_set_halign((GtkWidget *) wave_editor->vscrollbar,
417 GTK_ALIGN_FILL);
418
419 gtk_grid_attach(grid,
420 (GtkWidget *) wave_editor->vscrollbar,
421 2, 2,
422 1, 1);
423
424 adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, (guint) (gui_scale_factor * AGS_WAVE_EDIT_DEFAULT_CONTROL_WIDTH), 1.0);
425
426 wave_editor->hscrollbar = (GtkScrollbar *) gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL,
427 adjustment);
428
429 gtk_widget_set_valign((GtkWidget *) wave_editor->hscrollbar,
430 GTK_ALIGN_FILL);
431 gtk_widget_set_halign((GtkWidget *) wave_editor->hscrollbar,
432 GTK_ALIGN_FILL);
433
434 gtk_grid_attach(grid,
435 (GtkWidget *) wave_editor->hscrollbar,
436 1, 3,
437 1, 1);
438
439 /* focused wave edit */
440 wave_editor->focused_wave_edit = NULL;
441
442 /* wave meta */
443 wave_editor->wave_meta = ags_wave_meta_new();
444
445 gtk_widget_set_valign(wave_editor->wave_meta,
446 GTK_ALIGN_START);
447
448 gtk_box_pack_start((GtkBox *) hbox,
449 (GtkWidget *) wave_editor->wave_meta,
450 FALSE, FALSE,
451 0);
452
453 /* style context */
454 style_context = gtk_widget_get_style_context((GtkWidget *) wave_editor);
455 gtk_style_context_add_class(style_context,
456 "editor");
457 }
458
459 void
ags_wave_editor_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)460 ags_wave_editor_set_property(GObject *gobject,
461 guint prop_id,
462 const GValue *value,
463 GParamSpec *param_spec)
464 {
465 AgsWaveEditor *wave_editor;
466
467 wave_editor = AGS_WAVE_EDITOR(gobject);
468
469 switch(prop_id){
470 default:
471 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
472 break;
473 }
474 }
475
476 void
ags_wave_editor_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)477 ags_wave_editor_get_property(GObject *gobject,
478 guint prop_id,
479 GValue *value,
480 GParamSpec *param_spec)
481 {
482 AgsWaveEditor *wave_editor;
483
484 wave_editor = AGS_WAVE_EDITOR(gobject);
485
486 switch(prop_id){
487 default:
488 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
489 break;
490 }
491 }
492
493 void
ags_wave_editor_connect(AgsConnectable * connectable)494 ags_wave_editor_connect(AgsConnectable *connectable)
495 {
496 AgsWaveEditor *wave_editor;
497
498 wave_editor = AGS_WAVE_EDITOR(connectable);
499
500 if((AGS_WAVE_EDITOR_CONNECTED & (wave_editor->flags)) != 0){
501 return;
502 }
503
504 wave_editor->flags |= AGS_WAVE_EDITOR_CONNECTED;
505
506 /* edit */
507 g_signal_connect_after((GObject *) wave_editor->scrolled_wave_edit_box->viewport, "configure_event",
508 G_CALLBACK(ags_wave_editor_edit_configure_event), (gpointer) wave_editor);
509
510 g_signal_connect_after((GObject *) wave_editor->vscrollbar, "value-changed",
511 G_CALLBACK(ags_wave_editor_vscrollbar_value_changed), (gpointer) wave_editor);
512
513 g_signal_connect_after((GObject *) wave_editor->hscrollbar, "value-changed",
514 G_CALLBACK(ags_wave_editor_hscrollbar_value_changed), (gpointer) wave_editor);
515
516 /* */
517 g_signal_connect((GObject *) wave_editor->machine_selector, "changed",
518 G_CALLBACK(ags_wave_editor_machine_changed_callback), (gpointer) wave_editor);
519
520 /* */
521 ags_connectable_connect(AGS_CONNECTABLE(wave_editor->wave_toolbar));
522 ags_connectable_connect(AGS_CONNECTABLE(wave_editor->machine_selector));
523
524 ags_connectable_connect(AGS_CONNECTABLE(wave_editor->wave_meta));
525 }
526
527 void
ags_wave_editor_disconnect(AgsConnectable * connectable)528 ags_wave_editor_disconnect(AgsConnectable *connectable)
529 {
530 AgsWaveEditor *wave_editor;
531
532 wave_editor = AGS_WAVE_EDITOR(connectable);
533
534 if((AGS_WAVE_EDITOR_CONNECTED & (wave_editor->flags)) == 0){
535 return;
536 }
537
538 wave_editor->flags &= (~AGS_WAVE_EDITOR_CONNECTED);
539
540 /* edit */
541 g_object_disconnect((GObject *) wave_editor->scrolled_wave_edit_box->viewport,
542 "any_signal::configure_event",
543 G_CALLBACK(ags_wave_editor_edit_configure_event),
544 wave_editor,
545 NULL);
546
547 /* */
548 g_object_disconnect((GObject *) wave_editor->machine_selector,
549 "changed",
550 G_CALLBACK(ags_wave_editor_machine_changed_callback),
551 (gpointer) wave_editor,
552 NULL);
553
554 ags_connectable_disconnect(AGS_CONNECTABLE(wave_editor->wave_toolbar));
555 ags_connectable_disconnect(AGS_CONNECTABLE(wave_editor->machine_selector));
556
557 ags_connectable_disconnect(AGS_CONNECTABLE(wave_editor->wave_meta));
558 }
559
560 void
ags_wave_editor_finalize(GObject * gobject)561 ags_wave_editor_finalize(GObject *gobject)
562 {
563 AgsWaveEditor *wave_editor;
564
565 wave_editor = AGS_WAVE_EDITOR(gobject);
566
567 G_OBJECT_CLASS(ags_wave_editor_parent_class)->finalize(gobject);
568 }
569
570 void
ags_wave_editor_reset_scrollbar(AgsWaveEditor * wave_editor)571 ags_wave_editor_reset_scrollbar(AgsWaveEditor *wave_editor)
572 {
573 AgsWaveToolbar *wave_toolbar;
574
575 GtkAdjustment *vscrollbar_adjustment, *hscrollbar_adjustment;
576
577 AgsApplicationContext *application_context;
578
579 GtkAllocation wave_edit_box_allocation;
580 GtkAllocation viewport_allocation;
581
582 GList *list_start, *list;
583
584 gdouble gui_scale_factor;
585 gdouble old_h_upper;
586 gdouble v_upper, h_upper;
587 double zoom_factor, zoom;
588 double zoom_correction;
589 guint map_width;
590
591 wave_toolbar = wave_editor->wave_toolbar;
592
593 application_context = ags_application_context_get_instance();
594
595 /* scale factor */
596 gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
597
598 /* reset vertical scrollbar */
599 gtk_widget_get_allocation(GTK_WIDGET(wave_editor->scrolled_wave_edit_box->wave_edit_box),
600 &wave_edit_box_allocation);
601
602 gtk_widget_get_allocation(GTK_WIDGET(wave_editor->scrolled_wave_edit_box->viewport),
603 &viewport_allocation);
604
605 v_upper = wave_edit_box_allocation.height - viewport_allocation.height;
606
607 if(v_upper < 0.0){
608 v_upper = 0.0;
609 }
610
611 vscrollbar_adjustment = gtk_range_get_adjustment(GTK_RANGE(wave_editor->vscrollbar));
612
613 gtk_adjustment_set_upper(vscrollbar_adjustment,
614 v_upper);
615
616 gtk_adjustment_set_upper(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(wave_editor->scrolled_wave_edit_box->viewport)),
617 v_upper);
618 gtk_adjustment_set_upper(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(wave_editor->scrolled_level_box->viewport)),
619 v_upper);
620
621 /* reset horizontal scrollbar */
622 zoom = exp2((double) gtk_combo_box_get_active((GtkComboBox *) wave_toolbar->zoom) - 2.0);
623
624 /* upper */
625 hscrollbar_adjustment = gtk_range_get_adjustment(GTK_RANGE(wave_editor->hscrollbar));
626
627 old_h_upper = gtk_adjustment_get_upper(hscrollbar_adjustment);
628
629 zoom_correction = 1.0 / 16;
630
631 // map_width = (gui_scale_factor * (double) AGS_WAVE_EDITOR_MAX_CONTROLS * zoom * zoom_correction);
632 map_width = (gui_scale_factor * 64.0) * (16.0 * 16.0 * 1200.0) * zoom * zoom_correction;
633 h_upper = map_width - wave_edit_box_allocation.width;
634
635 if(h_upper < 0.0){
636 h_upper = 0.0;
637 }
638
639 gtk_adjustment_set_upper(wave_editor->ruler->adjustment,
640 h_upper);
641
642 gtk_adjustment_set_upper(hscrollbar_adjustment,
643 h_upper);
644
645 /* wave edit */
646 list_start =
647 list = gtk_container_get_children(GTK_CONTAINER(wave_editor->scrolled_wave_edit_box->wave_edit_box));
648
649 while(list != NULL){
650 gtk_adjustment_set_upper(hscrollbar_adjustment,
651 h_upper);
652
653
654 list = list->next;
655 }
656
657 g_list_free(list_start);
658
659 /* reset value */
660 if(old_h_upper != 0.0){
661 #if 0
662 gtk_adjustment_set_value(hscrollbar_adjustment,
663 gtk_adjustment_get_value(hscrollbar_adjustment) / old_h_upper * h_upper);
664 #endif
665 }
666 }
667
668 void
ags_wave_editor_show(GtkWidget * widget)669 ags_wave_editor_show(GtkWidget *widget)
670 {
671 GTK_WIDGET_CLASS(ags_wave_editor_parent_class)->show(widget);
672
673 gtk_widget_hide((GtkWidget *) AGS_WAVE_EDITOR(widget)->wave_meta);
674 }
675
676 void
ags_wave_editor_show_all(GtkWidget * widget)677 ags_wave_editor_show_all(GtkWidget *widget)
678 {
679 GTK_WIDGET_CLASS(ags_wave_editor_parent_class)->show_all(widget);
680
681 gtk_widget_hide(AGS_WAVE_EDITOR(widget)->wave_meta);
682 }
683
684 void
ags_wave_editor_real_machine_changed(AgsWaveEditor * wave_editor,AgsMachine * machine)685 ags_wave_editor_real_machine_changed(AgsWaveEditor *wave_editor, AgsMachine *machine)
686 {
687 AgsMachine *old_machine;
688 AgsWaveEdit *wave_edit;
689 AgsLevel *level;
690
691 AgsApplicationContext *application_context;
692
693 GList *list_start, *list;
694 GList *tab;
695
696 gdouble gui_scale_factor;
697 guint length;
698 guint output_lines, input_lines;
699 guint pads;
700 guint i;
701
702 if(wave_editor->selected_machine == machine){
703 return;
704 }
705
706 old_machine = wave_editor->selected_machine;
707
708 if(old_machine != NULL){
709 g_object_disconnect(old_machine,
710 "any_signal::resize-audio-channels",
711 G_CALLBACK(ags_wave_editor_resize_audio_channels_callback),
712 (gpointer) wave_editor,
713 "any_signal::resize-pads",
714 G_CALLBACK(ags_wave_editor_resize_pads_callback),
715 (gpointer) wave_editor,
716 NULL);
717 }
718
719 application_context = ags_application_context_get_instance();
720
721 /* scale factor */
722 gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
723
724 /* notebook - remove tabs */
725 length = g_list_length(wave_editor->notebook->tab);
726
727 for(i = 0; i < length; i++){
728 ags_notebook_remove_tab(wave_editor->notebook,
729 0);
730 }
731
732 /* */
733 if(machine != NULL){
734 g_object_get(machine->audio,
735 "input-lines", &input_lines,
736 NULL);
737
738 for(i = 0; i < input_lines; i++){
739 ags_notebook_insert_tab(wave_editor->notebook,
740 i);
741
742 tab = wave_editor->notebook->tab;
743 gtk_toggle_button_set_active(AGS_NOTEBOOK_TAB(tab->data)->toggle,
744 TRUE);
745 }
746 }
747
748 /* destroy edit */
749 list =
750 list_start = gtk_container_get_children(GTK_CONTAINER(wave_editor->scrolled_level_box->level_box));
751
752 while(list != NULL){
753 gtk_widget_destroy(list->data);
754
755 list = list->next;
756 }
757
758 g_list_free(list_start);
759
760 list =
761 list_start = gtk_container_get_children(GTK_CONTAINER(wave_editor->scrolled_wave_edit_box->wave_edit_box));
762
763 while(list != NULL){
764 g_object_disconnect(AGS_WAVE_EDIT(list->data)->hscrollbar,
765 "any_signal::value-changed",
766 G_CALLBACK(ags_wave_editor_wave_edit_hscrollbar_value_changed),
767 (gpointer) wave_editor,
768 NULL);
769
770 gtk_widget_destroy(list->data);
771
772 list = list->next;
773 }
774
775 g_list_free(list_start);
776
777 /*
778 * add new
779 */
780 if(machine != NULL){
781 guint input_lines;
782
783 g_object_get(machine->audio,
784 "input-lines", &input_lines,
785 NULL);
786
787 for(i = 0; i < input_lines; i++){
788 AgsWaveEdit *wave_edit;
789 AgsLevel *level;
790
791 /* level */
792 level = ags_level_new();
793 g_object_set(level,
794 "level-width", (guint) (gui_scale_factor * AGS_LEVEL_DEFAULT_LEVEL_WIDTH),
795 "level-height", (guint) (gui_scale_factor * AGS_LEVEL_DEFAULT_LEVEL_HEIGHT),
796 NULL);
797 gtk_box_pack_start(GTK_BOX(wave_editor->scrolled_level_box->level_box),
798 GTK_WIDGET(level),
799 FALSE, TRUE,
800 AGS_WAVE_EDIT_DEFAULT_PADDING);
801
802 gtk_widget_show(GTK_WIDGET(level));
803
804 /* wave edit */
805 wave_edit = ags_wave_edit_new(i);
806 gtk_box_pack_start(GTK_BOX(wave_editor->scrolled_wave_edit_box->wave_edit_box),
807 GTK_WIDGET(wave_edit),
808 FALSE, FALSE,
809 AGS_WAVE_EDIT_DEFAULT_PADDING);
810
811 ags_connectable_connect(AGS_CONNECTABLE(wave_edit));
812 gtk_widget_show(GTK_WIDGET(wave_edit));
813
814 g_signal_connect_after((GObject *) wave_edit->hscrollbar, "value-changed",
815 G_CALLBACK(ags_wave_editor_wave_edit_hscrollbar_value_changed), (gpointer) wave_editor);
816 }
817 }
818
819 /* connect set-pads - new */
820 if(machine != NULL){
821 g_signal_connect_after(machine, "resize-audio-channels",
822 G_CALLBACK(ags_wave_editor_resize_audio_channels_callback), wave_editor);
823
824 g_signal_connect_after(machine, "resize-pads",
825 G_CALLBACK(ags_wave_editor_resize_pads_callback), wave_editor);
826 }
827
828 /* selected machine */
829 wave_editor->selected_machine = machine;
830 }
831
832 /**
833 * ags_wave_editor_machine_changed:
834 * @wave_editor: an #AgsWaveEditor
835 * @machine: the new #AgsMachine
836 *
837 * Is emitted as machine changed of wave editor.
838 *
839 * Since: 3.0.0
840 */
841 void
ags_wave_editor_machine_changed(AgsWaveEditor * wave_editor,AgsMachine * machine)842 ags_wave_editor_machine_changed(AgsWaveEditor *wave_editor, AgsMachine *machine)
843 {
844 g_return_if_fail(AGS_IS_WAVE_EDITOR(wave_editor));
845
846 g_object_ref((GObject *) wave_editor);
847 g_signal_emit((GObject *) wave_editor,
848 wave_editor_signals[MACHINE_CHANGED], 0,
849 machine);
850 g_object_unref((GObject *) wave_editor);
851 }
852
853 void
ags_wave_editor_select_region(AgsWaveEditor * wave_editor,guint x0,gdouble y0,guint x1,gdouble y1)854 ags_wave_editor_select_region(AgsWaveEditor *wave_editor,
855 guint x0, gdouble y0,
856 guint x1, gdouble y1)
857 {
858 AgsWindow *window;
859 AgsWaveWindow *wave_window;
860 AgsWaveToolbar *wave_toolbar;
861 AgsNotebook *notebook;
862 AgsMachine *machine;
863
864 AgsWave *wave;
865
866 AgsTimestamp *timestamp;
867
868 GObject *soundcard;
869
870 GList *start_wave_edit, *wave_edit;
871 GList *start_list_wave, *list_wave;
872
873 gdouble bpm;
874 guint samplerate;
875 guint buffer_size;
876 guint64 relative_offset;
877 guint64 x0_offset, x1_offset;
878 double zoom, zoom_factor;
879 gdouble delay_factor;
880 gint i;
881
882 if(!AGS_IS_WAVE_EDITOR(wave_editor) ||
883 wave_editor->focused_wave_edit == NULL){
884 return;
885 }
886
887 if(wave_editor->selected_machine != NULL){
888 machine = wave_editor->selected_machine;
889
890 wave_window = (AgsWaveWindow *) gtk_widget_get_ancestor(GTK_WIDGET(wave_editor),
891 AGS_TYPE_WAVE_WINDOW);
892 window = (AgsWindow *) wave_window->parent_window;
893
894 wave_toolbar = wave_editor->wave_toolbar;
895
896 notebook = wave_editor->notebook;
897
898 bpm = gtk_spin_button_get_value(window->navigation->bpm);
899
900 /* swap values if needed */
901 if(x0 > x1){
902 guint tmp;
903
904 tmp = x0;
905
906 x0 = x1;
907 x1 = tmp;
908 }
909
910 if(y0 > y1){
911 gdouble tmp;
912
913 tmp = y0;
914
915 y0 = y1;
916 y1 = tmp;
917 }
918
919 /* zoom */
920 zoom = exp2((double) gtk_combo_box_get_active((GtkComboBox *) wave_toolbar->zoom) - 2.0);
921 zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) wave_toolbar->zoom));
922
923 /* check all active tabs */
924 g_object_get(machine->audio,
925 "output-soundcard", &soundcard,
926 "wave", &start_list_wave,
927 "samplerate", &samplerate,
928 "buffer-size", &buffer_size,
929 NULL);
930
931 delay_factor = ags_soundcard_get_delay_factor(AGS_SOUNDCARD(soundcard));
932
933 relative_offset = AGS_WAVE_DEFAULT_BUFFER_LENGTH * samplerate;
934
935 x0_offset = (x0 / 64.0) * delay_factor / (bpm / 60.0) * samplerate;
936 x1_offset = (x1 / 64.0) * delay_factor / (bpm / 60.0) * samplerate;
937
938 //TODO:JK: improve me
939 x0_offset = buffer_size * floor(x0_offset / buffer_size);
940 x1_offset = buffer_size * ceil(x1_offset / buffer_size);
941
942 timestamp = ags_timestamp_new();
943
944 timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
945 timestamp->flags |= AGS_TIMESTAMP_OFFSET;
946
947 start_wave_edit = gtk_container_get_children(GTK_CONTAINER(wave_editor->scrolled_wave_edit_box->wave_edit_box));
948 i = 0;
949
950 while((i = ags_notebook_next_active_tab(notebook,
951 i)) != -1){
952 wave_edit = g_list_nth(start_wave_edit,
953 i);
954
955 list_wave = start_list_wave;
956
957 timestamp->timer.ags_offset.offset = relative_offset * floor(x0 / relative_offset);
958
959 while(timestamp->timer.ags_offset.offset < (relative_offset * floor(x1 / relative_offset)) + relative_offset){
960 while((list_wave = ags_wave_find_near_timestamp(list_wave, i,
961 timestamp)) != NULL){
962 ags_wave_add_region_to_selection(list_wave->data,
963 x0_offset,
964 x1_offset,
965 TRUE);
966
967 /* iterate */
968 list_wave = list_wave->next;
969 }
970
971 timestamp->timer.ags_offset.offset += relative_offset;
972 }
973
974 /* queue draw */
975 gtk_widget_queue_draw(GTK_WIDGET(wave_edit->data));
976
977 i++;
978 }
979
980 if(soundcard != NULL){
981 g_object_unref(soundcard);
982 }
983
984 g_list_free(start_wave_edit);
985 g_list_free_full(start_list_wave,
986 g_object_unref);
987 }
988 }
989
990 void
ags_wave_editor_select_all(AgsWaveEditor * wave_editor)991 ags_wave_editor_select_all(AgsWaveEditor *wave_editor)
992 {
993 AgsMachine *machine;
994 AgsNotebook *notebook;
995
996 GList *start_list_wave, *list_wave;
997
998 guint samplerate;
999 guint64 relative_offset;
1000 guint line;
1001 gint i;
1002
1003 if(!AGS_IS_WAVE_EDITOR(wave_editor)){
1004 return;
1005 }
1006
1007 if(wave_editor->selected_machine != NULL){
1008 machine = wave_editor->selected_machine;
1009
1010 notebook = wave_editor->notebook;
1011
1012 /* check all active tabs */
1013 g_object_get(machine->audio,
1014 "wave", &start_list_wave,
1015 "samplerate", &samplerate,
1016 NULL);
1017
1018 relative_offset = AGS_WAVE_DEFAULT_BUFFER_LENGTH * samplerate;
1019
1020 i = 0;
1021
1022 while(notebook == NULL ||
1023 (i = ags_notebook_next_active_tab(notebook,
1024 i)) != -1){
1025 list_wave = start_list_wave;
1026
1027 while(list_wave != NULL){
1028 g_object_get(list_wave->data,
1029 "line", &line,
1030 NULL);
1031
1032 if(i != line){
1033 list_wave = list_wave->next;
1034
1035 continue;
1036 }
1037
1038 ags_wave_add_all_to_selection(AGS_WAVE(list_wave->data));
1039
1040 list_wave = list_wave->next;
1041 }
1042
1043 i++;
1044 }
1045
1046 g_list_free_full(start_list_wave,
1047 g_object_unref);
1048
1049 /* queue draw */
1050 gtk_widget_queue_draw(GTK_WIDGET(wave_editor->focused_wave_edit));
1051 }
1052 }
1053
1054 gint
ags_wave_editor_paste_wave_all(AgsWaveEditor * wave_editor,AgsMachine * machine,AgsNotebook * notebook,xmlNode * wave_node,AgsTimestamp * timestamp,gboolean match_line,gboolean paste_from_position,guint64 position_x,gint64 * last_x)1055 ags_wave_editor_paste_wave_all(AgsWaveEditor *wave_editor,
1056 AgsMachine *machine,
1057 AgsNotebook *notebook,
1058 xmlNode *wave_node,
1059 AgsTimestamp *timestamp,
1060 gboolean match_line,
1061 gboolean paste_from_position,
1062 guint64 position_x,
1063 gint64 *last_x)
1064 {
1065 AgsWave *wave;
1066
1067 GList *start_list_wave, *list_wave;
1068
1069 guint64 first_x;
1070 guint64 current_x;
1071 gint i;
1072
1073 first_x = -1;
1074
1075 /* */
1076 i = 0;
1077
1078 while((i = ags_notebook_next_active_tab(notebook,
1079 i)) != -1){
1080 g_object_get(machine->audio,
1081 "wave", &start_list_wave,
1082 NULL);
1083
1084 list_wave = ags_wave_find_near_timestamp(start_list_wave, i,
1085 timestamp);
1086
1087 if(list_wave == NULL){
1088 wave = ags_wave_new((GObject *) machine->audio,
1089 i);
1090 wave->timestamp->timer.ags_offset.offset = timestamp->timer.ags_offset.offset;
1091
1092 /* add to audio */
1093 ags_audio_add_wave(machine->audio,
1094 (GObject *) wave);
1095 }else{
1096 wave = AGS_WAVE(list_wave->data);
1097 }
1098
1099 if(paste_from_position){
1100 xmlNode *child;
1101
1102 guint64 x_boundary;
1103
1104 ags_wave_insert_from_clipboard_extended(wave,
1105 wave_node,
1106 TRUE, position_x,
1107 0.0, 0,
1108 match_line, FALSE);
1109
1110 /* get boundaries */
1111 child = wave_node->children;
1112 current_x = 0;
1113
1114 while(child != NULL){
1115 if(child->type == XML_ELEMENT_NODE){
1116 if(!xmlStrncmp(child->name,
1117 BAD_CAST "buffer",
1118 5)){
1119 guint64 tmp;
1120
1121 tmp = g_ascii_strtoull(xmlGetProp(child,
1122 BAD_CAST "x"),
1123 NULL,
1124 10);
1125
1126 if(tmp > current_x){
1127 current_x = tmp;
1128 }
1129 }
1130 }
1131
1132 child = child->next;
1133 }
1134
1135 x_boundary = g_ascii_strtoull(xmlGetProp(wave_node,
1136 BAD_CAST "x-boundary"),
1137 NULL,
1138 10);
1139
1140
1141 if(first_x == -1 || x_boundary < first_x){
1142 first_x = x_boundary;
1143 }
1144
1145 if(position_x > x_boundary){
1146 current_x += (position_x - x_boundary);
1147 }else{
1148 current_x -= (x_boundary - position_x);
1149 }
1150
1151 if(current_x > last_x[0]){
1152 last_x[0] = current_x;
1153 }
1154 }else{
1155 xmlNode *child;
1156
1157 ags_wave_insert_from_clipboard_extended(wave,
1158 wave_node,
1159 FALSE, 0,
1160 0.0, 0,
1161 match_line, FALSE);
1162
1163 /* get boundaries */
1164 child = wave_node->children;
1165 current_x = 0;
1166
1167 while(child != NULL){
1168 if(child->type == XML_ELEMENT_NODE){
1169 if(!xmlStrncmp(child->name,
1170 BAD_CAST "buffer",
1171 5)){
1172 guint64 tmp;
1173
1174 tmp = g_ascii_strtoull(xmlGetProp(child,
1175 BAD_CAST "x"),
1176 NULL,
1177 10);
1178
1179 if(tmp > current_x){
1180 current_x = tmp;
1181 }
1182 }
1183 }
1184
1185 child = child->next;
1186 }
1187
1188 if(current_x > last_x[0]){
1189 last_x[0] = current_x;
1190 }
1191 }
1192
1193 g_list_free_full(start_list_wave,
1194 g_object_unref);
1195
1196 i++;
1197 }
1198
1199 return(first_x);
1200 }
1201
1202 gint
ags_wave_editor_paste_wave(AgsWaveEditor * wave_editor,AgsMachine * machine,AgsNotebook * notebook,xmlNode * audio_node,gboolean paste_from_position,guint64 position_x,guint64 relative_offset)1203 ags_wave_editor_paste_wave(AgsWaveEditor *wave_editor,
1204 AgsMachine *machine,
1205 AgsNotebook *notebook,
1206 xmlNode *audio_node,
1207 gboolean paste_from_position,
1208 guint64 position_x,
1209 guint64 relative_offset)
1210 {
1211 AgsTimestamp *timestamp;
1212
1213 xmlNode *wave_list_node, *wave_node;
1214 xmlNode *timestamp_node;
1215
1216 gint64 first_x, last_x;
1217 gboolean match_line;
1218
1219 first_x = -1;
1220
1221 match_line = ((AGS_WAVE_EDITOR_PASTE_MATCH_LINE & (wave_editor->flags)) != 0) ? TRUE: FALSE;
1222
1223 timestamp = ags_timestamp_new();
1224
1225 timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
1226 timestamp->flags |= AGS_TIMESTAMP_OFFSET;
1227
1228 timestamp->timer.ags_offset.offset = 0;
1229
1230 /* paste wave */
1231 wave_list_node = audio_node->children;
1232
1233 while(wave_list_node != NULL){
1234 if(wave_list_node->type == XML_ELEMENT_NODE){
1235 if(!xmlStrncmp(wave_list_node->name,
1236 BAD_CAST "wave-list",
1237 14)){
1238 wave_node = wave_list_node->children;
1239
1240 while(wave_node != NULL){
1241 if(wave_node->type == XML_ELEMENT_NODE){
1242 if(!xmlStrncmp(wave_node->name,
1243 BAD_CAST "wave",
1244 9)){
1245 guint64 offset;
1246
1247 timestamp_node = wave_node->children;
1248 offset = 0;
1249
1250 while(timestamp_node != NULL){
1251 if(timestamp_node->type == XML_ELEMENT_NODE){
1252 if(!xmlStrncmp(timestamp_node->name,
1253 BAD_CAST "timestamp",
1254 10)){
1255 offset = g_ascii_strtoull(xmlGetProp(timestamp_node,
1256 BAD_CAST "offset"),
1257 NULL,
1258 10);
1259
1260 break;
1261 }
1262 }
1263
1264 timestamp_node = timestamp_node->next;
1265 }
1266
1267 /* 1st attempt */
1268 timestamp->timer.ags_offset.offset = (guint64) relative_offset * floor((double) position_x / (double) relative_offset);
1269
1270 first_x = ags_wave_editor_paste_wave_all(wave_editor,
1271 machine,
1272 notebook,
1273 wave_node,
1274 timestamp,
1275 match_line,
1276 paste_from_position,
1277 position_x,
1278 &last_x);
1279
1280 /* 2nd attempt */
1281 timestamp->timer.ags_offset.offset += relative_offset;
1282
1283 ags_wave_editor_paste_wave_all(wave_editor,
1284 machine,
1285 notebook,
1286 wave_node,
1287 timestamp,
1288 match_line,
1289 paste_from_position,
1290 position_x,
1291 &last_x);
1292
1293 }
1294 }
1295
1296 wave_node = wave_node->next;
1297 }
1298 }
1299 }
1300
1301 wave_list_node = wave_list_node->next;
1302 }
1303
1304 g_object_unref(timestamp);
1305
1306 return(first_x);
1307 }
1308
1309 void
ags_wave_editor_paste(AgsWaveEditor * wave_editor)1310 ags_wave_editor_paste(AgsWaveEditor *wave_editor)
1311 {
1312 AgsWindow *window;
1313 AgsWaveWindow *wave_window;
1314 AgsWaveToolbar *wave_toolbar;
1315 AgsWaveEdit *wave_edit;
1316 AgsNotebook *notebook;
1317 AgsMachine *machine;
1318
1319 AgsWave *wave;
1320
1321 GObject *soundcard;
1322
1323 xmlDoc *clipboard;
1324 xmlNode *audio_node;
1325 xmlNode *wave_node;
1326
1327 gchar *buffer;
1328
1329 gdouble bpm;
1330 guint samplerate;
1331 guint64 relative_offset;
1332 guint64 position_x;
1333 gint64 first_x, last_x;
1334 double zoom, zoom_factor;
1335 gdouble delay_factor;
1336 gboolean paste_from_position;
1337
1338 if(!AGS_IS_WAVE_EDITOR(wave_editor) ||
1339 wave_editor->focused_wave_edit == NULL){
1340 return;
1341 }
1342
1343 if((machine = wave_editor->selected_machine) != NULL){
1344 machine = wave_editor->selected_machine;
1345
1346 wave_window = (AgsWaveWindow *) gtk_widget_get_ancestor(GTK_WIDGET(wave_editor),
1347 AGS_TYPE_WAVE_WINDOW);
1348 window = (AgsWindow *) wave_window->parent_window;
1349
1350 wave_toolbar = wave_editor->wave_toolbar;
1351 wave_edit = wave_editor->focused_wave_edit;
1352
1353 notebook = wave_editor->notebook;
1354
1355 bpm = gtk_spin_button_get_value(window->navigation->bpm);
1356
1357 /* zoom */
1358 zoom = exp2((double) gtk_combo_box_get_active((GtkComboBox *) wave_toolbar->zoom) - 2.0);
1359 zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) wave_toolbar->zoom));
1360
1361 /* check all active tabs */
1362 g_object_get(machine->audio,
1363 "output-soundcard", &soundcard,
1364 "samplerate", &samplerate,
1365 NULL);
1366
1367 delay_factor = ags_soundcard_get_delay_factor(AGS_SOUNDCARD(soundcard));
1368
1369 relative_offset = AGS_WAVE_DEFAULT_BUFFER_LENGTH * samplerate;
1370
1371 /* get clipboard */
1372 buffer = gtk_clipboard_wait_for_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
1373
1374 if(buffer == NULL){
1375 if(soundcard != NULL){
1376 g_object_unref(soundcard);
1377 }
1378
1379 return;
1380 }
1381
1382 /* get position */
1383 position_x = 0;
1384
1385 if(wave_toolbar->selected_edit_mode == wave_toolbar->position){
1386 last_x = 0;
1387 paste_from_position = TRUE;
1388
1389 position_x = 15.0 * delay_factor * wave_editor->focused_wave_edit->cursor_position_x * samplerate / (16.0 * bpm);
1390
1391 #ifdef DEBUG
1392 printf("pasting at position: [%u]\n", position_x);
1393 #endif
1394 }else{
1395 paste_from_position = FALSE;
1396 }
1397
1398 /* get xml tree */
1399 clipboard = xmlReadMemory(buffer, strlen(buffer),
1400 NULL, "UTF-8",
1401 XML_PARSE_HUGE);
1402 audio_node = xmlDocGetRootElement(clipboard);
1403
1404 first_x = -1;
1405
1406 /* iterate xml tree */
1407 while(audio_node != NULL){
1408 if(audio_node->type == XML_ELEMENT_NODE){
1409 if(!xmlStrncmp(BAD_CAST "audio", audio_node->name, 6)){
1410 wave_node = audio_node->children;
1411
1412 // g_message("paste");
1413 first_x = ags_wave_editor_paste_wave(wave_editor,
1414 machine,
1415 notebook,
1416 audio_node,
1417 paste_from_position,
1418 position_x,
1419 relative_offset);
1420
1421 break;
1422 }
1423 }
1424
1425 audio_node = audio_node->next;
1426 }
1427
1428 if(first_x == -1){
1429 first_x = 0;
1430 }
1431
1432 xmlFreeDoc(clipboard);
1433
1434 if(paste_from_position){
1435 gint big_step, small_step;
1436
1437 //TODO:JK: implement me
1438 }
1439
1440 if(soundcard != NULL){
1441 g_object_unref(soundcard);
1442 }
1443
1444 gtk_widget_queue_draw(GTK_WIDGET(wave_edit));
1445 }
1446 }
1447
1448 void
ags_wave_editor_copy(AgsWaveEditor * wave_editor)1449 ags_wave_editor_copy(AgsWaveEditor *wave_editor)
1450 {
1451 AgsMachine *machine;
1452 AgsNotebook *notebook;
1453
1454 xmlDoc *clipboard;
1455 xmlNode *audio_node, *wave_list_node, *wave_node;
1456
1457 GList *start_list_wave, *list_wave;
1458
1459 xmlChar *buffer;
1460
1461 int size;
1462 guint line;
1463 gint i;
1464
1465 if(!AGS_IS_WAVE_EDITOR(wave_editor) ||
1466 wave_editor->focused_wave_edit == NULL){
1467 return;
1468 }
1469
1470 if(wave_editor->selected_machine != NULL){
1471 machine = wave_editor->selected_machine;
1472
1473 notebook = wave_editor->notebook;
1474
1475 /* create document */
1476 clipboard = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
1477
1478 /* create root node */
1479 audio_node = xmlNewNode(NULL,
1480 BAD_CAST "audio");
1481 xmlDocSetRootElement(clipboard, audio_node);
1482
1483 wave_list_node = xmlNewNode(NULL,
1484 BAD_CAST "wave-list");
1485 xmlAddChild(audio_node,
1486 wave_list_node);
1487
1488 /* create wave nodes */
1489 g_object_get(machine->audio,
1490 "wave", &start_list_wave,
1491 NULL);
1492
1493 i = 0;
1494
1495 while((i = ags_notebook_next_active_tab(notebook,
1496 i)) != -1){
1497 list_wave = start_list_wave;
1498
1499 /* copy */
1500 while(list_wave != NULL){
1501 g_object_get(list_wave->data,
1502 "line", &line,
1503 NULL);
1504
1505 if(i != line){
1506 list_wave = list_wave->next;
1507
1508 continue;
1509 }
1510
1511 // g_message("copy %d", i);
1512 wave_node = ags_wave_copy_selection(AGS_WAVE(list_wave->data));
1513 xmlAddChild(wave_list_node,
1514 wave_node);
1515
1516 list_wave = list_wave->next;
1517 }
1518
1519 i++;
1520 }
1521
1522 g_list_free_full(start_list_wave,
1523 g_object_unref);
1524
1525 /* write to clipboard */
1526 xmlDocDumpFormatMemoryEnc(clipboard, &buffer, &size, "UTF-8", TRUE);
1527 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
1528 (gchar *) buffer, size);
1529 gtk_clipboard_store(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
1530
1531 xmlFreeDoc(clipboard);
1532 }
1533 }
1534
1535 void
ags_wave_editor_cut(AgsWaveEditor * wave_editor)1536 ags_wave_editor_cut(AgsWaveEditor *wave_editor)
1537 {
1538 AgsMachine *machine;
1539 AgsNotebook *notebook;
1540
1541 xmlDoc *clipboard;
1542 xmlNode *audio_node;
1543 xmlNode *wave_list_node, *wave_node;
1544
1545 GList *start_list_wave, *list_wave;
1546
1547 xmlChar *buffer;
1548
1549 int size;
1550 guint line;
1551 gint i;
1552
1553 if(!AGS_IS_WAVE_EDITOR(wave_editor) ||
1554 wave_editor->focused_wave_edit == NULL){
1555 return;
1556 }
1557
1558 if(wave_editor->selected_machine != NULL){
1559 machine = wave_editor->selected_machine;
1560
1561 notebook = wave_editor->notebook;
1562
1563 /* create document */
1564 clipboard = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
1565
1566 /* create root node */
1567 audio_node = xmlNewNode(NULL,
1568 BAD_CAST "audio");
1569 xmlDocSetRootElement(clipboard, audio_node);
1570
1571 wave_list_node = xmlNewNode(NULL,
1572 BAD_CAST "wave-list");
1573 xmlAddChild(audio_node,
1574 wave_list_node);
1575
1576 /* create wave nodes */
1577 g_object_get(machine->audio,
1578 "wave", &start_list_wave,
1579 NULL);
1580
1581 i = 0;
1582
1583 while((i = ags_notebook_next_active_tab(notebook,
1584 i)) != -1){
1585 list_wave = start_list_wave;
1586
1587 /* cut */
1588 while(list_wave != NULL){
1589 g_object_get(list_wave->data,
1590 "line", &line,
1591 NULL);
1592
1593 if(i != line){
1594 list_wave = list_wave->next;
1595
1596 continue;
1597 }
1598
1599 // g_message("cut %d", i);
1600 wave_node = ags_wave_cut_selection(AGS_WAVE(list_wave->data));
1601 xmlAddChild(wave_list_node,
1602 wave_node);
1603
1604 list_wave = list_wave->next;
1605 }
1606
1607 i++;
1608 }
1609
1610 g_list_free_full(start_list_wave,
1611 g_object_unref);
1612
1613 gtk_widget_queue_draw(GTK_WIDGET(wave_editor->focused_wave_edit));
1614
1615 /* write to clipboard */
1616 xmlDocDumpFormatMemoryEnc(clipboard, &buffer, &size, "UTF-8", TRUE);
1617 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
1618 (gchar *) buffer, size);
1619 gtk_clipboard_store(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
1620
1621 xmlFreeDoc(clipboard);
1622 }
1623 }
1624
1625 void
ags_wave_editor_invert(AgsWaveEditor * wave_editor)1626 ags_wave_editor_invert(AgsWaveEditor *wave_editor)
1627 {
1628 g_message("ags_wave_editor_invert() - not implemented");
1629 }
1630
1631 /**
1632 * ags_wave_editor_new:
1633 *
1634 * Create a new #AgsWaveEditor.
1635 *
1636 * Returns: a new #AgsWaveEditor
1637 *
1638 * Since: 3.0.0
1639 */
1640 AgsWaveEditor*
ags_wave_editor_new()1641 ags_wave_editor_new()
1642 {
1643 AgsWaveEditor *wave_editor;
1644
1645 wave_editor = (AgsWaveEditor *) g_object_new(AGS_TYPE_WAVE_EDITOR,
1646 NULL);
1647
1648 return(wave_editor);
1649 }
1650