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/editor/ags_select_buffer_dialog.h>
21 #include <ags/X/editor/ags_select_buffer_dialog_callbacks.h>
22 
23 #include <ags/X/ags_window.h>
24 #include <ags/X/ags_wave_window.h>
25 #include <ags/X/ags_wave_editor.h>
26 #include <ags/X/ags_machine.h>
27 
28 #include <ags/i18n.h>
29 
30 void ags_select_buffer_dialog_class_init(AgsSelectBufferDialogClass *select_buffer_dialog);
31 void ags_select_buffer_dialog_connectable_interface_init(AgsConnectableInterface *connectable);
32 void ags_select_buffer_dialog_applicable_interface_init(AgsApplicableInterface *applicable);
33 void ags_select_buffer_dialog_init(AgsSelectBufferDialog *select_buffer_dialog);
34 void ags_select_buffer_dialog_set_property(GObject *gobject,
35 					   guint prop_id,
36 					   const GValue *value,
37 					   GParamSpec *param_spec);
38 void ags_select_buffer_dialog_get_property(GObject *gobject,
39 					   guint prop_id,
40 					   GValue *value,
41 					   GParamSpec *param_spec);
42 void ags_select_buffer_dialog_finalize(GObject *gobject);
43 
44 void ags_select_buffer_dialog_connect(AgsConnectable *connectable);
45 void ags_select_buffer_dialog_disconnect(AgsConnectable *connectable);
46 
47 void ags_select_buffer_dialog_set_update(AgsApplicable *applicable, gboolean update);
48 void ags_select_buffer_dialog_apply(AgsApplicable *applicable);
49 void ags_select_buffer_dialog_reset(AgsApplicable *applicable);
50 gboolean ags_select_buffer_dialog_delete_event(GtkWidget *widget, GdkEventAny *event);
51 
52 /**
53  * SECTION:ags_select_buffer_dialog
54  * @short_description: select tool
55  * @title: AgsSelectBufferDialog
56  * @section_id:
57  * @include: ags/X/editor/ags_select_buffer_dialog.h
58  *
59  * The #AgsSelectBufferDialog lets you select buffers.
60  */
61 
62 enum{
63   PROP_0,
64   PROP_MAIN_WINDOW,
65 };
66 
67 static gpointer ags_select_buffer_dialog_parent_class = NULL;
68 
69 GType
ags_select_buffer_dialog_get_type(void)70 ags_select_buffer_dialog_get_type(void)
71 {
72   static volatile gsize g_define_type_id__volatile = 0;
73 
74   if(g_once_init_enter (&g_define_type_id__volatile)){
75     GType ags_type_select_buffer_dialog = 0;
76 
77     static const GTypeInfo ags_select_buffer_dialog_info = {
78       sizeof (AgsSelectBufferDialogClass),
79       NULL, /* base_init */
80       NULL, /* base_finalize */
81       (GClassInitFunc) ags_select_buffer_dialog_class_init,
82       NULL, /* class_finalize */
83       NULL, /* class_data */
84       sizeof (AgsSelectBufferDialog),
85       0,    /* n_preallocs */
86       (GInstanceInitFunc) ags_select_buffer_dialog_init,
87     };
88 
89     static const GInterfaceInfo ags_connectable_interface_info = {
90       (GInterfaceInitFunc) ags_select_buffer_dialog_connectable_interface_init,
91       NULL, /* interface_finalize */
92       NULL, /* interface_data */
93     };
94 
95     static const GInterfaceInfo ags_applicable_interface_info = {
96       (GInterfaceInitFunc) ags_select_buffer_dialog_applicable_interface_init,
97       NULL, /* interface_finalize */
98       NULL, /* interface_data */
99     };
100 
101     ags_type_select_buffer_dialog = g_type_register_static(GTK_TYPE_DIALOG,
102 							   "AgsSelectBufferDialog", &ags_select_buffer_dialog_info,
103 							   0);
104 
105     g_type_add_interface_static(ags_type_select_buffer_dialog,
106 				AGS_TYPE_CONNECTABLE,
107 				&ags_connectable_interface_info);
108 
109     g_type_add_interface_static(ags_type_select_buffer_dialog,
110 				AGS_TYPE_APPLICABLE,
111 				&ags_applicable_interface_info);
112 
113     g_once_init_leave(&g_define_type_id__volatile, ags_type_select_buffer_dialog);
114   }
115 
116   return g_define_type_id__volatile;
117 }
118 
119 void
ags_select_buffer_dialog_class_init(AgsSelectBufferDialogClass * select_buffer_dialog)120 ags_select_buffer_dialog_class_init(AgsSelectBufferDialogClass *select_buffer_dialog)
121 {
122   GObjectClass *gobject;
123   GtkWidgetClass *widget;
124 
125   GParamSpec *param_spec;
126 
127   ags_select_buffer_dialog_parent_class = g_type_class_peek_parent(select_buffer_dialog);
128 
129   /* GObjectClass */
130   gobject = (GObjectClass *) select_buffer_dialog;
131 
132   gobject->set_property = ags_select_buffer_dialog_set_property;
133   gobject->get_property = ags_select_buffer_dialog_get_property;
134 
135   gobject->finalize = ags_select_buffer_dialog_finalize;
136 
137   /* properties */
138   /**
139    * AgsSelectBufferDialog:main-window:
140    *
141    * The assigned #AgsWindow.
142    *
143    * Since: 3.0.0
144    */
145   param_spec = g_param_spec_object("main-window",
146 				   i18n_pspec("assigned main window"),
147 				   i18n_pspec("The assigned main window"),
148 				   AGS_TYPE_WINDOW,
149 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
150   g_object_class_install_property(gobject,
151 				  PROP_MAIN_WINDOW,
152 				  param_spec);
153 
154   /* GtkWidgetClass */
155   widget = (GtkWidgetClass *) select_buffer_dialog;
156 
157   widget->delete_event = ags_select_buffer_dialog_delete_event;
158 }
159 
160 void
ags_select_buffer_dialog_connectable_interface_init(AgsConnectableInterface * connectable)161 ags_select_buffer_dialog_connectable_interface_init(AgsConnectableInterface *connectable)
162 {
163   connectable->is_ready = NULL;
164   connectable->is_connected = NULL;
165   connectable->connect = ags_select_buffer_dialog_connect;
166   connectable->disconnect = ags_select_buffer_dialog_disconnect;
167 }
168 
169 void
ags_select_buffer_dialog_applicable_interface_init(AgsApplicableInterface * applicable)170 ags_select_buffer_dialog_applicable_interface_init(AgsApplicableInterface *applicable)
171 {
172   applicable->set_update = ags_select_buffer_dialog_set_update;
173   applicable->apply = ags_select_buffer_dialog_apply;
174   applicable->reset = ags_select_buffer_dialog_reset;
175 }
176 
177 void
ags_select_buffer_dialog_init(AgsSelectBufferDialog * select_buffer_dialog)178 ags_select_buffer_dialog_init(AgsSelectBufferDialog *select_buffer_dialog)
179 {
180   GtkVBox *vbox;
181   GtkHBox *hbox;
182   GtkLabel *label;
183 
184   select_buffer_dialog->flags = 0;
185 
186   g_object_set(select_buffer_dialog,
187 	       "title", i18n("select buffers"),
188 	       NULL);
189 
190   vbox = (GtkVBox *) gtk_vbox_new(FALSE,
191 				  0);
192   gtk_box_pack_start((GtkBox *) gtk_dialog_get_content_area(select_buffer_dialog),
193 		     GTK_WIDGET(vbox),
194 		     FALSE, FALSE,
195 		     0);
196 
197   /* copy selection */
198   select_buffer_dialog->copy_selection = (GtkCheckButton *) gtk_check_button_new_with_label(i18n("copy selection"));
199   gtk_toggle_button_set_active((GtkToggleButton *) select_buffer_dialog->copy_selection,
200 			       TRUE);
201   gtk_box_pack_start((GtkBox *) vbox,
202 		     GTK_WIDGET(select_buffer_dialog->copy_selection),
203 		     FALSE, FALSE,
204 		     0);
205 
206   /* select x0 - hbox */
207   hbox = (GtkHBox *) gtk_hbox_new(FALSE, 0);
208   gtk_box_pack_start((GtkBox *) vbox,
209 		     GTK_WIDGET(hbox),
210 		     FALSE, FALSE,
211 		     0);
212 
213   /* select x0 - label */
214   label = (GtkLabel *) gtk_label_new(i18n("select x0"));
215   gtk_box_pack_start((GtkBox *) hbox,
216 		     GTK_WIDGET(label),
217 		     FALSE, FALSE,
218 		     0);
219 
220   /* select x0 - spin button */
221   select_buffer_dialog->select_x0 = (GtkSpinButton *) gtk_spin_button_new_with_range(0.0,
222 										     AGS_SELECT_BUFFER_MAX_BEATS,
223 										     0.25);
224   gtk_spin_button_set_digits(select_buffer_dialog->select_x0,
225 			     2);
226   gtk_spin_button_set_value(select_buffer_dialog->select_x0,
227 			    0.0);
228   gtk_box_pack_start((GtkBox *) hbox,
229 		     GTK_WIDGET(select_buffer_dialog->select_x0),
230 		     FALSE, FALSE,
231 		     0);
232 
233   /* select x1 - hbox */
234   hbox = (GtkHBox *) gtk_hbox_new(FALSE, 0);
235   gtk_box_pack_start((GtkBox *) vbox,
236 		     GTK_WIDGET(hbox),
237 		     FALSE, FALSE,
238 		     0);
239 
240   /* select x1 - label */
241   label = (GtkLabel *) gtk_label_new(i18n("select x1"));
242   gtk_box_pack_start((GtkBox *) hbox,
243 		     GTK_WIDGET(label),
244 		     FALSE, FALSE,
245 		     0);
246 
247   /* select x1 - spin button */
248   select_buffer_dialog->select_x1 = (GtkSpinButton *) gtk_spin_button_new_with_range(0.0,
249 										     AGS_SELECT_BUFFER_MAX_BEATS,
250 										     0.25);
251   gtk_spin_button_set_digits(select_buffer_dialog->select_x1,
252 			     2);
253   gtk_spin_button_set_value(select_buffer_dialog->select_x1,
254 			    0.0);
255   gtk_box_pack_start((GtkBox *) hbox,
256 		     GTK_WIDGET(select_buffer_dialog->select_x1),
257 		     FALSE, FALSE,
258 		     0);
259 
260   /* dialog buttons */
261   gtk_dialog_add_buttons((GtkDialog *) select_buffer_dialog,
262 			 i18n("_Apply"), GTK_RESPONSE_APPLY,
263 			 i18n("_OK"), GTK_RESPONSE_OK,
264 			 i18n("_Cancel"), GTK_RESPONSE_CANCEL,
265 			 NULL);
266 }
267 
268 void
ags_select_buffer_dialog_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)269 ags_select_buffer_dialog_set_property(GObject *gobject,
270 				      guint prop_id,
271 				      const GValue *value,
272 				      GParamSpec *param_spec)
273 {
274   AgsSelectBufferDialog *select_buffer_dialog;
275 
276   select_buffer_dialog = AGS_SELECT_BUFFER_DIALOG(gobject);
277 
278   switch(prop_id){
279   case PROP_MAIN_WINDOW:
280     {
281       AgsWindow *main_window;
282 
283       main_window = (AgsWindow *) g_value_get_object(value);
284 
285       if((AgsWindow *) select_buffer_dialog->main_window == main_window){
286 	return;
287       }
288 
289       if(select_buffer_dialog->main_window != NULL){
290 	g_object_unref(select_buffer_dialog->main_window);
291       }
292 
293       if(main_window != NULL){
294 	g_object_ref(main_window);
295       }
296 
297       select_buffer_dialog->main_window = (GtkWidget *) main_window;
298     }
299     break;
300   default:
301     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
302     break;
303   }
304 }
305 
306 void
ags_select_buffer_dialog_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)307 ags_select_buffer_dialog_get_property(GObject *gobject,
308 				      guint prop_id,
309 				      GValue *value,
310 				      GParamSpec *param_spec)
311 {
312   AgsSelectBufferDialog *select_buffer_dialog;
313 
314   select_buffer_dialog = AGS_SELECT_BUFFER_DIALOG(gobject);
315 
316   switch(prop_id){
317   case PROP_MAIN_WINDOW:
318     {
319       g_value_set_object(value, select_buffer_dialog->main_window);
320     }
321     break;
322   default:
323     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
324     break;
325   }
326 }
327 
328 void
ags_select_buffer_dialog_connect(AgsConnectable * connectable)329 ags_select_buffer_dialog_connect(AgsConnectable *connectable)
330 {
331   AgsSelectBufferDialog *select_buffer_dialog;
332 
333   select_buffer_dialog = AGS_SELECT_BUFFER_DIALOG(connectable);
334 
335   if((AGS_SELECT_BUFFER_DIALOG_CONNECTED & (select_buffer_dialog->flags)) != 0){
336     return;
337   }
338 
339   select_buffer_dialog->flags |= AGS_SELECT_BUFFER_DIALOG_CONNECTED;
340 
341   g_signal_connect(select_buffer_dialog, "response",
342 		   G_CALLBACK(ags_select_buffer_dialog_response_callback), select_buffer_dialog);
343 }
344 
345 void
ags_select_buffer_dialog_disconnect(AgsConnectable * connectable)346 ags_select_buffer_dialog_disconnect(AgsConnectable *connectable)
347 {
348   AgsSelectBufferDialog *select_buffer_dialog;
349 
350   select_buffer_dialog = AGS_SELECT_BUFFER_DIALOG(connectable);
351 
352   if((AGS_SELECT_BUFFER_DIALOG_CONNECTED & (select_buffer_dialog->flags)) == 0){
353     return;
354   }
355 
356   select_buffer_dialog->flags &= (~AGS_SELECT_BUFFER_DIALOG_CONNECTED);
357 
358   g_object_disconnect(G_OBJECT(select_buffer_dialog),
359 		      "any_signal::response",
360 		      G_CALLBACK(ags_select_buffer_dialog_response_callback),
361 		      select_buffer_dialog,
362 		      NULL);
363 }
364 
365 void
ags_select_buffer_dialog_finalize(GObject * gobject)366 ags_select_buffer_dialog_finalize(GObject *gobject)
367 {
368   AgsSelectBufferDialog *select_buffer_dialog;
369 
370   select_buffer_dialog = (AgsSelectBufferDialog *) gobject;
371 
372   G_OBJECT_CLASS(ags_select_buffer_dialog_parent_class)->finalize(gobject);
373 }
374 
375 void
ags_select_buffer_dialog_set_update(AgsApplicable * applicable,gboolean update)376 ags_select_buffer_dialog_set_update(AgsApplicable *applicable, gboolean update)
377 {
378   /* empty */
379 }
380 
381 void
ags_select_buffer_dialog_apply(AgsApplicable * applicable)382 ags_select_buffer_dialog_apply(AgsApplicable *applicable)
383 {
384   AgsSelectBufferDialog *select_buffer_dialog;
385 
386   AgsWindow *window;
387   AgsWaveEditor *wave_editor;
388   AgsMachine *machine;
389 
390   AgsAudio *audio;
391 
392   AgsTimestamp *timestamp;
393 
394   GObject *output_soundcard;
395 
396   xmlDoc *clipboard;
397   xmlNode *audio_node, *wave_node;
398 
399   GList *start_list_wave, *list_wave;
400 
401   xmlChar *buffer;
402 
403   guint samplerate;
404   guint buffer_size;
405   gdouble delay;
406   guint64 relative_offset;
407   int size;
408   guint x0, y0;
409   guint x1, y1;
410   gint i;
411 
412   gboolean copy_selection;
413 
414   select_buffer_dialog = AGS_SELECT_BUFFER_DIALOG(applicable);
415 
416   window = (AgsWindow *) select_buffer_dialog->main_window;
417   wave_editor = window->wave_window->wave_editor;
418 
419   machine = wave_editor->selected_machine;
420 
421   if(machine == NULL){
422     return;
423   }
424 
425   audio = machine->audio;
426 
427   g_object_get(audio,
428 	       "output-soundcard", &output_soundcard,
429 	       "buffer-size", &buffer_size,
430 	       "samplerate", &samplerate,
431 	       "wave", &start_list_wave,
432 	       NULL);
433 
434   delay = ags_soundcard_get_delay(AGS_SOUNDCARD(output_soundcard));
435 
436   /* get some values */
437   copy_selection = gtk_toggle_button_get_active((GtkToggleButton *) select_buffer_dialog->copy_selection);
438 
439   x0 = gtk_spin_button_get_value_as_int(select_buffer_dialog->select_x0);
440   x0 = delay * buffer_size * x0;
441 
442   x1 = gtk_spin_button_get_value_as_int(select_buffer_dialog->select_x1);
443   x1 = delay * buffer_size * x1;
444 
445   timestamp = ags_timestamp_new();
446 
447   timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
448   timestamp->flags |= AGS_TIMESTAMP_OFFSET;
449 
450   relative_offset = samplerate * AGS_WAVE_DEFAULT_BUFFER_LENGTH;
451 
452   /* select buffer */
453   if(copy_selection){
454     /* create document */
455     clipboard = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
456 
457     /* create root node */
458     audio_node = xmlNewNode(NULL, BAD_CAST "audio");
459     xmlDocSetRootElement(clipboard, audio_node);
460   }
461 
462   i = 0;
463 
464   while((i = ags_notebook_next_active_tab(wave_editor->notebook,
465 					  i)) != -1){
466     list_wave = start_list_wave;
467     timestamp->timer.ags_offset.offset = 0;
468 
469     while((list_wave = ags_wave_find_near_timestamp(list_wave, i,
470 						    timestamp)) != NULL){
471       ags_wave_add_region_to_selection(AGS_WAVE(list_wave->data),
472 				       x0, x1,
473 				       TRUE);
474 
475       if(copy_selection){
476 	wave_node = ags_wave_copy_selection(AGS_WAVE(list_wave->data));
477 	xmlAddChild(audio_node, wave_node);
478       }
479 
480       /* iterate */
481       timestamp->timer.ags_offset.offset += relative_offset;
482 
483       list_wave = list_wave->next;
484     }
485 
486     i++;
487   }
488 
489   g_object_unref(timestamp);
490 
491   g_list_free_full(start_list_wave,
492 		   g_object_unref);
493 
494   g_object_unref(output_soundcard);
495 
496   /* write to clipboard */
497   if(copy_selection){
498     xmlDocDumpFormatMemoryEnc(clipboard, &buffer, &size, "UTF-8", TRUE);
499     gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
500 			   buffer, size);
501     gtk_clipboard_store(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
502 
503     xmlFreeDoc(clipboard);
504   }
505 }
506 
507 void
ags_select_buffer_dialog_reset(AgsApplicable * applicable)508 ags_select_buffer_dialog_reset(AgsApplicable *applicable)
509 {
510   //TODO:JK: implement me
511 }
512 
513 gboolean
ags_select_buffer_dialog_delete_event(GtkWidget * widget,GdkEventAny * event)514 ags_select_buffer_dialog_delete_event(GtkWidget *widget, GdkEventAny *event)
515 {
516   gtk_widget_hide(widget);
517 
518   //  GTK_WIDGET_CLASS(ags_select_buffer_dialog_parent_class)->delete_event(widget, event);
519 
520   return(TRUE);
521 }
522 
523 /**
524  * ags_select_buffer_dialog_new:
525  * @main_window: the #AgsWindow
526  *
527  * Create a new #AgsSelectBufferDialog.
528  *
529  * Returns: a new #AgsSelectBufferDialog
530  *
531  * Since: 3.0.0
532  */
533 AgsSelectBufferDialog*
ags_select_buffer_dialog_new(GtkWidget * main_window)534 ags_select_buffer_dialog_new(GtkWidget *main_window)
535 {
536   AgsSelectBufferDialog *select_buffer_dialog;
537 
538   select_buffer_dialog = (AgsSelectBufferDialog *) g_object_new(AGS_TYPE_SELECT_BUFFER_DIALOG,
539 								"main-window", main_window,
540 								NULL);
541 
542   return(select_buffer_dialog);
543 }
544