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