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