1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2020 Joël Krähemann
3 *
4 * This file is part of GSequencer.
5 *
6 * GSequencer is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GSequencer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GSequencer. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <ags/X/ags_notation_editor.h>
21 #include <ags/X/ags_notation_editor_callbacks.h>
22
23 #include <ags/X/ags_ui_provider.h>
24 #include <ags/X/ags_window.h>
25
26 #include <ags/X/machine/ags_drum.h>
27 #include <ags/X/machine/ags_matrix.h>
28
29 #include <libxml/tree.h>
30 #include <libxml/xpath.h>
31
32 #include <math.h>
33
34 #include <ags/config.h>
35 #include <ags/i18n.h>
36
37 void ags_notation_editor_class_init(AgsNotationEditorClass *notation_editor);
38 void ags_notation_editor_connectable_interface_init(AgsConnectableInterface *connectable);
39 void ags_notation_editor_init(AgsNotationEditor *notation_editor);
40 void ags_notation_editor_set_property(GObject *gobject,
41 guint prop_id,
42 const GValue *value,
43 GParamSpec *param_spec);
44 void ags_notation_editor_get_property(GObject *gobject,
45 guint prop_id,
46 GValue *value,
47 GParamSpec *param_spec);
48 void ags_notation_editor_finalize(GObject *gobject);
49
50 void ags_notation_editor_connect(AgsConnectable *connectable);
51 void ags_notation_editor_disconnect(AgsConnectable *connectable);
52
53 void ags_notation_editor_show(GtkWidget *widget);
54 void ags_notation_editor_show_all(GtkWidget *widget);
55
56 void ags_notation_editor_real_machine_changed(AgsNotationEditor *notation_editor,
57 AgsMachine *machine);
58
59 gint ags_notation_editor_paste_notation_all(AgsNotationEditor *notation_editor,
60 AgsMachine *machine,
61 xmlNode *notation_node,
62 AgsTimestamp *timestamp,
63 gboolean match_channel, gboolean no_duplicates,
64 guint position_x, guint position_y,
65 gboolean paste_from_position,
66 gint *last_x);
67 gint ags_notation_editor_paste_notation(AgsNotationEditor *notation_editor,
68 AgsMachine *machine,
69 xmlNode *audio_node,
70 guint position_x, guint position_y,
71 gboolean paste_from_position,
72 gint *last_x);
73
74 void ags_notation_editor_get_boundary(AgsNotationEditor *notation_editor,
75 AgsMachine *machine,
76 AgsNotation *notation,
77 guint *lower, guint *upper);
78 void ags_notation_editor_invert_notation(AgsNotationEditor *notation_editor,
79 AgsMachine *machine,
80 AgsNotation *notation,
81 guint lower, guint upper);
82
83 enum{
84 MACHINE_CHANGED,
85 LAST_SIGNAL,
86 };
87
88 enum{
89 PROP_0,
90 PROP_SOUNDCARD,
91 };
92
93 static gpointer ags_notation_editor_parent_class = NULL;
94 static guint notation_editor_signals[LAST_SIGNAL];
95
96 /**
97 * SECTION:ags_notation_editor
98 * @short_description: A composite widget to edit notation
99 * @title: AgsNotationEditor
100 * @section_id:
101 * @include: ags/X/ags_notation_editor.h
102 *
103 * #AgsNotationEditor is a composite widget to edit notation. You may select machines
104 * or change editor tool to do notation.
105 */
106
107 GType
ags_notation_editor_get_type(void)108 ags_notation_editor_get_type(void)
109 {
110 static volatile gsize g_define_type_id__volatile = 0;
111
112 if(g_once_init_enter (&g_define_type_id__volatile)){
113 GType ags_type_notation_editor = 0;
114
115 static const GTypeInfo ags_notation_editor_info = {
116 sizeof (AgsNotationEditorClass),
117 NULL, /* base_init */
118 NULL, /* base_finalize */
119 (GClassInitFunc) ags_notation_editor_class_init,
120 NULL, /* class_finalize */
121 NULL, /* class_data */
122 sizeof (AgsNotationEditor),
123 0, /* n_preallocs */
124 (GInstanceInitFunc) ags_notation_editor_init,
125 };
126
127 static const GInterfaceInfo ags_connectable_interface_info = {
128 (GInterfaceInitFunc) ags_notation_editor_connectable_interface_init,
129 NULL, /* interface_finalize */
130 NULL, /* interface_data */
131 };
132
133 ags_type_notation_editor = g_type_register_static(GTK_TYPE_BOX,
134 "AgsNotationEditor", &ags_notation_editor_info,
135 0);
136
137 g_type_add_interface_static(ags_type_notation_editor,
138 AGS_TYPE_CONNECTABLE,
139 &ags_connectable_interface_info);
140
141 g_once_init_leave(&g_define_type_id__volatile, ags_type_notation_editor);
142 }
143
144 return g_define_type_id__volatile;
145 }
146
147 void
ags_notation_editor_connectable_interface_init(AgsConnectableInterface * connectable)148 ags_notation_editor_connectable_interface_init(AgsConnectableInterface *connectable)
149 {
150 connectable->is_ready = NULL;
151 connectable->is_connected = NULL;
152 connectable->connect = ags_notation_editor_connect;
153 connectable->disconnect = ags_notation_editor_disconnect;
154 }
155
156 void
ags_notation_editor_class_init(AgsNotationEditorClass * notation_editor)157 ags_notation_editor_class_init(AgsNotationEditorClass *notation_editor)
158 {
159 GObjectClass *gobject;
160 GtkWidgetClass *widget;
161
162 GParamSpec *param_spec;
163
164 ags_notation_editor_parent_class = g_type_class_peek_parent(notation_editor);
165
166 /* GObjectClass */
167 gobject = (GObjectClass *) notation_editor;
168
169 gobject->set_property = ags_notation_editor_set_property;
170 gobject->get_property = ags_notation_editor_get_property;
171
172 gobject->finalize = ags_notation_editor_finalize;
173
174 /* properties */
175 /**
176 * AgsNotationEditor:soundcard:
177 *
178 * The assigned #AgsSoundcard acting as default sink.
179 *
180 * Since: 3.0.0
181 */
182 param_spec = g_param_spec_object("soundcard",
183 i18n_pspec("assigned soundcard"),
184 i18n_pspec("The soundcard it is assigned with"),
185 G_TYPE_OBJECT,
186 G_PARAM_READABLE | G_PARAM_WRITABLE);
187 g_object_class_install_property(gobject,
188 PROP_SOUNDCARD,
189 param_spec);
190
191 /* GtkWidgetClass */
192 widget = (GtkWidgetClass *) notation_editor;
193
194 widget->show = ags_notation_editor_show;
195 widget->show_all = ags_notation_editor_show_all;
196
197 /* AgsNotationEditorClass */
198 notation_editor->machine_changed = ags_notation_editor_real_machine_changed;
199
200 /* signals */
201 /**
202 * AgsNotationEditor::machine-changed:
203 * @editor: the object to change machine.
204 * @machine: the #AgsMachine to set
205 *
206 * The ::machine-changed signal notifies about changed machine.
207 *
208 * Since: 3.0.0
209 */
210 notation_editor_signals[MACHINE_CHANGED] =
211 g_signal_new("machine-changed",
212 G_TYPE_FROM_CLASS(notation_editor),
213 G_SIGNAL_RUN_LAST,
214 G_STRUCT_OFFSET(AgsNotationEditorClass, machine_changed),
215 NULL, NULL,
216 g_cclosure_marshal_VOID__OBJECT,
217 G_TYPE_NONE, 1,
218 G_TYPE_OBJECT);
219 }
220
221 void
ags_notation_editor_init(AgsNotationEditor * notation_editor)222 ags_notation_editor_init(AgsNotationEditor *notation_editor)
223 {
224 GtkViewport *viewport;
225 GtkScrolledWindow *scrolled_window;
226 GtkGrid *grid;
227
228 AgsApplicationContext *application_context;
229
230 gdouble gui_scale_factor;
231
232 gtk_orientable_set_orientation(GTK_ORIENTABLE(notation_editor),
233 GTK_ORIENTATION_VERTICAL);
234
235 gtk_box_set_homogeneous((GtkBox *) notation_editor,
236 FALSE);
237
238 notation_editor->flags = (AGS_NOTATION_EDITOR_PASTE_MATCH_AUDIO_CHANNEL |
239 AGS_NOTATION_EDITOR_PASTE_NO_DUPLICATES);
240
241 notation_editor->version = AGS_NOTATION_EDITOR_DEFAULT_VERSION;
242 notation_editor->build_id = AGS_NOTATION_EDITOR_DEFAULT_BUILD_ID;
243
244 application_context = ags_application_context_get_instance();
245
246 /* scale factor */
247 gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
248
249 /* offset */
250 notation_editor->tact_counter = 0;
251 notation_editor->current_tact = 0.0;
252
253 /* active keys */
254 notation_editor->active_key = NULL;
255 notation_editor->active_key_count = 0;
256
257 /* soundcard */
258 notation_editor->soundcard = NULL;
259
260 /* notation toolbar */
261 notation_editor->notation_toolbar = ags_notation_toolbar_new();
262 gtk_box_pack_start((GtkBox *) notation_editor,
263 (GtkWidget *) notation_editor->notation_toolbar,
264 FALSE, FALSE,
265 0);
266
267 /* paned */
268 notation_editor->paned = (GtkPaned *) gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
269 gtk_box_pack_start((GtkBox *) notation_editor,
270 (GtkWidget *) notation_editor->paned,
271 TRUE, TRUE, 0);
272
273 /* machine selector */
274 viewport = (GtkViewport *) gtk_viewport_new(NULL,
275 NULL);
276 g_object_set(viewport,
277 "shadow-type", GTK_SHADOW_NONE,
278 NULL);
279 gtk_paned_pack1((GtkPaned *) notation_editor->paned,
280 (GtkWidget *) viewport,
281 FALSE, TRUE);
282
283 scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
284 gtk_container_add(GTK_CONTAINER(viewport),
285 GTK_WIDGET(scrolled_window));
286
287 notation_editor->machine_selector = g_object_new(AGS_TYPE_MACHINE_SELECTOR,
288 "homogeneous", FALSE,
289 "spacing", 0,
290 NULL);
291 notation_editor->machine_selector->flags |= (AGS_MACHINE_SELECTOR_SHOW_REVERSE_MAPPING |
292 AGS_MACHINE_SELECTOR_SHOW_SHIFT_PIANO |
293 AGS_MACHINE_SELECTOR_NOTATION);
294 gtk_label_set_label(notation_editor->machine_selector->label,
295 i18n("notation"));
296
297 notation_editor->machine_selector->popup = ags_machine_selector_popup_new(notation_editor->machine_selector);
298 g_object_set(notation_editor->machine_selector->menu_button,
299 "menu", notation_editor->machine_selector->popup,
300 NULL);
301
302 gtk_container_add((GtkContainer *) scrolled_window,
303 (GtkWidget *) notation_editor->machine_selector);
304
305 /* selected machine */
306 notation_editor->selected_machine = NULL;
307
308 /* grid */
309 viewport = (GtkViewport *) gtk_viewport_new(NULL,
310 NULL);
311 g_object_set(viewport,
312 "shadow-type", GTK_SHADOW_NONE,
313 NULL);
314 gtk_paned_pack2((GtkPaned *) notation_editor->paned,
315 (GtkWidget *) viewport,
316 TRUE, TRUE);
317
318 grid = (GtkGrid *) gtk_grid_new();
319 gtk_container_add(GTK_CONTAINER(viewport),
320 GTK_WIDGET(grid));
321
322 /* notebook */
323 notation_editor->notebook = g_object_new(AGS_TYPE_NOTEBOOK,
324 "homogeneous", FALSE,
325 "spacing", 0,
326 "prefix", i18n("channel"),
327 NULL);
328
329 gtk_widget_set_valign((GtkWidget *) notation_editor->notebook,
330 GTK_ALIGN_FILL);
331 gtk_widget_set_halign((GtkWidget *) notation_editor->notebook,
332 GTK_ALIGN_FILL);
333
334 gtk_widget_set_vexpand((GtkWidget *) notation_editor->notebook,
335 FALSE);
336
337 gtk_grid_attach(grid,
338 (GtkWidget *) notation_editor->notebook,
339 0, 0,
340 3, 1);
341
342 /* scrolled piano */
343 notation_editor->scrolled_piano = ags_scrolled_piano_new();
344 g_object_set(notation_editor->scrolled_piano,
345 "margin-top", (gint) (gui_scale_factor * AGS_RULER_DEFAULT_HEIGHT),
346 NULL);
347 g_object_set(notation_editor->scrolled_piano->piano,
348 "key-width", (guint) (gui_scale_factor * AGS_PIANO_DEFAULT_KEY_WIDTH),
349 "key-height", (guint) (gui_scale_factor * AGS_PIANO_DEFAULT_KEY_HEIGHT),
350 NULL);
351
352 gtk_widget_set_valign((GtkWidget *) notation_editor->scrolled_piano,
353 GTK_ALIGN_FILL);
354 gtk_widget_set_halign((GtkWidget *) notation_editor->scrolled_piano,
355 GTK_ALIGN_FILL);
356
357 gtk_grid_attach(grid,
358 (GtkWidget *) notation_editor->scrolled_piano,
359 0, 1,
360 1, 1);
361
362 /* notation edit */
363 notation_editor->notation_edit = ags_notation_edit_new();
364
365 gtk_widget_set_valign((GtkWidget *) notation_editor->notation_edit,
366 GTK_ALIGN_FILL);
367 gtk_widget_set_halign((GtkWidget *) notation_editor->notation_edit,
368 GTK_ALIGN_FILL);
369
370 gtk_widget_set_vexpand((GtkWidget *) notation_editor->notation_edit,
371 TRUE);
372 gtk_widget_set_hexpand((GtkWidget *) notation_editor->notation_edit,
373 TRUE);
374
375 gtk_grid_attach(grid,
376 (GtkWidget *) notation_editor->notation_edit,
377 1, 1,
378 1, 1);
379
380 /* notation meta */
381 notation_editor->notation_meta = ags_notation_meta_new();
382 g_object_set(notation_editor->notation_meta,
383 "valign", GTK_ALIGN_START,
384 NULL);
385
386 gtk_widget_set_valign((GtkWidget *) notation_editor->notation_meta,
387 GTK_ALIGN_FILL);
388 gtk_widget_set_halign((GtkWidget *) notation_editor->notation_meta,
389 GTK_ALIGN_FILL);
390
391 gtk_grid_attach(grid,
392 (GtkWidget *) notation_editor->notation_meta,
393 2, 1,
394 1, 1);
395 }
396
397 void
ags_notation_editor_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)398 ags_notation_editor_set_property(GObject *gobject,
399 guint prop_id,
400 const GValue *value,
401 GParamSpec *param_spec)
402 {
403 AgsNotationEditor *notation_editor;
404
405 notation_editor = AGS_NOTATION_EDITOR(gobject);
406
407 switch(prop_id){
408 case PROP_SOUNDCARD:
409 {
410 GObject *soundcard;
411
412 soundcard = g_value_get_object(value);
413
414 if(notation_editor->soundcard == soundcard){
415 return;
416 }
417
418 if(notation_editor->soundcard != NULL){
419 g_object_unref(notation_editor->soundcard);
420 }
421
422 if(soundcard != NULL){
423 g_object_ref(soundcard);
424 }
425
426 notation_editor->soundcard = soundcard;
427 }
428 break;
429 default:
430 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
431 break;
432 }
433 }
434
435 void
ags_notation_editor_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)436 ags_notation_editor_get_property(GObject *gobject,
437 guint prop_id,
438 GValue *value,
439 GParamSpec *param_spec)
440 {
441 AgsNotationEditor *notation_editor;
442
443 notation_editor = AGS_NOTATION_EDITOR(gobject);
444
445 switch(prop_id){
446 case PROP_SOUNDCARD:
447 {
448 g_value_set_object(value, notation_editor->soundcard);
449 }
450 break;
451 default:
452 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
453 break;
454 }
455 }
456
457 void
ags_notation_editor_finalize(GObject * gobject)458 ags_notation_editor_finalize(GObject *gobject)
459 {
460 AgsNotationEditor *notation_editor;
461
462 notation_editor = AGS_NOTATION_EDITOR(gobject);
463
464 if(notation_editor->soundcard != NULL){
465 g_object_unref(notation_editor->soundcard);
466 }
467
468 /* call parent */
469 G_OBJECT_CLASS(ags_notation_editor_parent_class)->finalize(gobject);
470 }
471
472 void
ags_notation_editor_connect(AgsConnectable * connectable)473 ags_notation_editor_connect(AgsConnectable *connectable)
474 {
475 AgsNotationEditor *notation_editor;
476
477 notation_editor = AGS_NOTATION_EDITOR(connectable);
478
479 if((AGS_NOTATION_EDITOR_CONNECTED & (notation_editor->flags)) != 0){
480 return;
481 }
482
483 notation_editor->flags |= AGS_NOTATION_EDITOR_CONNECTED;
484
485 g_signal_connect((GObject *) notation_editor->machine_selector, "changed",
486 G_CALLBACK(ags_notation_editor_machine_changed_callback), (gpointer) notation_editor);
487
488 g_signal_connect((GObject *) notation_editor->scrolled_piano->piano, "key-pressed",
489 G_CALLBACK(ags_notation_editor_piano_key_pressed_callback), (gpointer) notation_editor);
490
491 g_signal_connect((GObject *) notation_editor->scrolled_piano->piano, "key-released",
492 G_CALLBACK(ags_notation_editor_piano_key_released_callback), (gpointer) notation_editor);
493
494
495 /* toolbar */
496 ags_connectable_connect(AGS_CONNECTABLE(notation_editor->notation_toolbar));
497
498 /* machine selector */
499 ags_connectable_connect(AGS_CONNECTABLE(notation_editor->machine_selector));
500
501 /* notation edit */
502 ags_connectable_connect(AGS_CONNECTABLE(notation_editor->notation_edit));
503
504 /* notation meta */
505 ags_connectable_connect(AGS_CONNECTABLE(notation_editor->notation_meta));
506 }
507
508 void
ags_notation_editor_disconnect(AgsConnectable * connectable)509 ags_notation_editor_disconnect(AgsConnectable *connectable)
510 {
511 AgsNotationEditor *notation_editor;
512
513 notation_editor = AGS_NOTATION_EDITOR(connectable);
514
515 if((AGS_NOTATION_EDITOR_CONNECTED & (notation_editor->flags)) == 0){
516 return;
517 }
518
519 notation_editor->flags &= (~AGS_NOTATION_EDITOR_CONNECTED);
520
521 g_object_disconnect((GObject *) notation_editor->machine_selector,
522 "any_signal::changed",
523 G_CALLBACK(ags_notation_editor_machine_changed_callback),
524 (gpointer) notation_editor,
525 NULL);
526
527 g_object_disconnect((GObject *) notation_editor->scrolled_piano->piano,
528 "any_signal::key-pressed",
529 G_CALLBACK(ags_notation_editor_piano_key_pressed_callback),
530 (gpointer) notation_editor,
531 "any_signal::key-released",
532 G_CALLBACK(ags_notation_editor_piano_key_released_callback),
533 (gpointer) notation_editor,
534 NULL);
535
536 /* notation toolbar */
537 ags_connectable_disconnect(AGS_CONNECTABLE(notation_editor->notation_toolbar));
538
539 /* machine selector */
540 ags_connectable_disconnect(AGS_CONNECTABLE(notation_editor->machine_selector));
541
542 /* notation edit */
543 ags_connectable_disconnect(AGS_CONNECTABLE(notation_editor->notation_edit));
544
545 /* notation meta */
546 ags_connectable_disconnect(AGS_CONNECTABLE(notation_editor->notation_meta));
547 }
548
549 void
ags_notation_editor_show(GtkWidget * widget)550 ags_notation_editor_show(GtkWidget *widget)
551 {
552 GTK_WIDGET_CLASS(ags_notation_editor_parent_class)->show(widget);
553
554 gtk_widget_hide((GtkWidget *) AGS_NOTATION_EDITOR(widget)->notation_meta);
555 }
556
557 void
ags_notation_editor_show_all(GtkWidget * widget)558 ags_notation_editor_show_all(GtkWidget *widget)
559 {
560 GTK_WIDGET_CLASS(ags_notation_editor_parent_class)->show_all(widget);
561
562 gtk_widget_hide((GtkWidget *) AGS_NOTATION_EDITOR(widget)->notation_meta);
563 }
564
565 void
ags_notation_editor_real_machine_changed(AgsNotationEditor * notation_editor,AgsMachine * machine)566 ags_notation_editor_real_machine_changed(AgsNotationEditor *notation_editor,
567 AgsMachine *machine)
568 {
569 AgsMachine *old_machine;
570
571 GList *tab;
572
573 guint length;
574 guint audio_channels;
575 guint i;
576
577 /* disconnect set pads - old */
578 old_machine = notation_editor->selected_machine;
579
580 if(old_machine != NULL){
581 g_object_disconnect(old_machine,
582 "any_signal::resize-audio-channels",
583 G_CALLBACK(ags_notation_editor_resize_audio_channels_callback),
584 (gpointer) notation_editor,
585 "any_signal::resize-pads",
586 G_CALLBACK(ags_notation_editor_resize_pads_callback),
587 (gpointer) notation_editor,
588 NULL);
589 }
590
591 /* notebook - remove tabs */
592 length = g_list_length(notation_editor->notebook->tab);
593
594 for(i = 0; i < length; i++){
595 ags_notebook_remove_tab(notation_editor->notebook,
596 0);
597 }
598
599 /* check pattern mode */
600 if(AGS_IS_DRUM(machine) ||
601 AGS_IS_MATRIX(machine)){
602 notation_editor->flags |= AGS_NOTATION_EDITOR_PATTERN_MODE;
603 }else{
604 notation_editor->flags &= (~AGS_NOTATION_EDITOR_PATTERN_MODE);
605 }
606
607 /* notebook - add tabs */
608 if(machine != NULL){
609 g_object_get(machine->audio,
610 "audio-channels", &audio_channels,
611 NULL);
612
613 for(i = 0; i < audio_channels; i++){
614 ags_notebook_insert_tab(notation_editor->notebook,
615 i);
616
617 tab = notation_editor->notebook->tab;
618 gtk_toggle_button_set_active(AGS_NOTEBOOK_TAB(tab->data)->toggle,
619 TRUE);
620 }
621 }
622
623 /* piano */
624 if(machine != NULL){
625 guint channel_count;
626
627 /* get channel count */
628 if(ags_audio_test_behaviour_flags(machine->audio, AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_INPUT)){
629 g_object_get(machine->audio,
630 "input-pads", &channel_count,
631 NULL);
632 }else{
633 g_object_get(machine->audio,
634 "output-pads", &channel_count,
635 NULL);
636 }
637
638 /* apply channel count */
639 g_object_set(notation_editor->scrolled_piano->piano,
640 "key-count", channel_count,
641 NULL);
642 }else{
643 /* apply default */
644 g_object_set(notation_editor->scrolled_piano->piano,
645 "key-count", AGS_PIANO_DEFAULT_KEY_COUNT,
646 NULL);
647 }
648
649 gtk_widget_queue_resize((GtkWidget *) notation_editor->scrolled_piano->piano);
650 gtk_widget_queue_resize((GtkWidget *) notation_editor->scrolled_piano);
651
652 gtk_widget_queue_draw((GtkWidget *) notation_editor->scrolled_piano->piano);
653 gtk_widget_queue_draw((GtkWidget *) notation_editor->scrolled_piano);
654
655 /* selected machine */
656 notation_editor->selected_machine = machine;
657
658 /* reset scrollbars */
659 ags_notation_edit_reset_vscrollbar(notation_editor->notation_edit);
660 ags_notation_edit_reset_hscrollbar(notation_editor->notation_edit);
661
662 /* redraw */
663 gtk_widget_queue_draw((GtkWidget *) notation_editor->notation_edit);
664
665 /* connect set-pads - new */
666 if(machine != NULL){
667 g_signal_connect_after(machine, "resize-audio-channels",
668 G_CALLBACK(ags_notation_editor_resize_audio_channels_callback), notation_editor);
669
670 g_signal_connect_after(machine, "resize-pads",
671 G_CALLBACK(ags_notation_editor_resize_pads_callback), notation_editor);
672 }
673 }
674
675 /**
676 * ags_notation_editor_machine_changed:
677 * @notation_editor: the #AgsNotationEditor
678 * @machine: the new #AgsMachine
679 *
680 * Is emitted as machine changed of notation_editor.
681 *
682 * Since: 3.0.0
683 */
684 void
ags_notation_editor_machine_changed(AgsNotationEditor * notation_editor,AgsMachine * machine)685 ags_notation_editor_machine_changed(AgsNotationEditor *notation_editor,
686 AgsMachine *machine)
687 {
688 g_return_if_fail(AGS_IS_NOTATION_EDITOR(notation_editor));
689
690 g_object_ref((GObject *) notation_editor);
691 g_signal_emit((GObject *) notation_editor,
692 notation_editor_signals[MACHINE_CHANGED], 0,
693 machine);
694 g_object_unref((GObject *) notation_editor);
695 }
696
697 /**
698 * ags_notation_editor_add_note:
699 * @notation_editor: the #AgsNotationEditor
700 * @note: the #AgsNote to add
701 *
702 * Add note.
703 *
704 * Since: 3.0.0
705 */
706 void
ags_notation_editor_add_note(AgsNotationEditor * notation_editor,AgsNote * note)707 ags_notation_editor_add_note(AgsNotationEditor *notation_editor,
708 AgsNote *note)
709 {
710 AgsMachine *machine;
711
712 AgsNotation *notation;
713
714 AgsTimestamp *timestamp;
715
716 GList *start_list_notation, *list_notation;
717
718 guint x0;
719 gint i;
720
721 if(!AGS_IS_NOTATION_EDITOR(notation_editor) ||
722 !AGS_IS_NOTE(note)){
723 return;
724 }
725
726 if(notation_editor->selected_machine != NULL){
727 machine = notation_editor->selected_machine;
728
729 /* check all active tabs */
730 timestamp = ags_timestamp_new();
731
732 timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
733 timestamp->flags |= AGS_TIMESTAMP_OFFSET;
734
735 g_object_get(note,
736 "x0", &x0,
737 NULL);
738
739 timestamp->timer.ags_offset.offset = (guint64) AGS_NOTATION_DEFAULT_OFFSET * floor((double) x0 / (double) AGS_NOTATION_DEFAULT_OFFSET);
740
741 i = 0;
742
743 while((i = ags_notebook_next_active_tab(notation_editor->notebook,
744 i)) != -1){
745 AgsNote *new_note;
746
747 g_object_get(machine->audio,
748 "notation", &start_list_notation,
749 NULL);
750
751 list_notation = ags_notation_find_near_timestamp(start_list_notation, i,
752 timestamp);
753
754 if(list_notation != NULL){
755 notation = list_notation->data;
756 }else{
757 notation = ags_notation_new((GObject *) machine->audio,
758 i);
759 AGS_TIMESTAMP(notation->timestamp)->timer.ags_offset.offset = timestamp->timer.ags_offset.offset;
760
761 ags_audio_add_notation(machine->audio,
762 (GObject *) notation);
763 }
764
765 new_note = ags_note_duplicate(note);
766 ags_notation_add_note(notation,
767 new_note,
768 FALSE);
769
770 g_list_free_full(start_list_notation,
771 g_object_unref);
772
773 /* iterate */
774 i++;
775 }
776
777 g_object_unref(timestamp);
778
779 gtk_widget_queue_draw((GtkWidget *) notation_editor->notation_edit);
780 }
781 }
782
783 /**
784 * ags_notation_editor_delete_note:
785 * @notation_editor: the #AgsNotationEditor
786 * @x: point x
787 * @y: point y
788 *
789 * Delete note.
790 *
791 * Since: 3.0.0
792 */
793 void
ags_notation_editor_delete_note(AgsNotationEditor * notation_editor,guint x,guint y)794 ags_notation_editor_delete_note(AgsNotationEditor *notation_editor,
795 guint x, guint y)
796 {
797 AgsMachine *machine;
798
799 AgsNotation *notation;
800
801 AgsTimestamp *timestamp;
802
803 GList *start_list_notation, *list_notation;
804
805 gint i;
806
807 if(!AGS_IS_NOTATION_EDITOR(notation_editor)){
808 return;
809 }
810
811 if(notation_editor->selected_machine != NULL){
812 machine = notation_editor->selected_machine;
813
814 /* check all active tabs */
815 timestamp = ags_timestamp_new();
816
817 timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
818 timestamp->flags |= AGS_TIMESTAMP_OFFSET;
819
820 timestamp->timer.ags_offset.offset = (guint64) AGS_NOTATION_DEFAULT_OFFSET * floor((double) x / (double) AGS_NOTATION_DEFAULT_OFFSET);
821
822 i = 0;
823
824 while((i = ags_notebook_next_active_tab(notation_editor->notebook,
825 i)) != -1){
826 g_object_get(machine->audio,
827 "notation", &start_list_notation,
828 NULL);
829
830 list_notation = ags_notation_find_near_timestamp(start_list_notation, i,
831 timestamp);
832
833 if(list_notation != NULL){
834 notation = list_notation->data;
835 ags_notation_remove_note_at_position(notation,
836 x, y);
837 }
838
839 g_list_free_full(start_list_notation,
840 g_object_unref);
841
842 /* iterate */
843 i++;
844 }
845
846 g_object_unref(timestamp);
847
848 gtk_widget_queue_draw((GtkWidget *) notation_editor->notation_edit);
849 }
850 }
851
852 /**
853 * ags_notation_editor_select_region:
854 * @notation_editor: the #AgsNotationEditor
855 * @x0: point x0
856 * @y0: point y0
857 * @x1: point x1
858 * @y1: point y1
859 *
860 * Select region.
861 *
862 * Since: 3.0.0
863 */
864 void
ags_notation_editor_select_region(AgsNotationEditor * notation_editor,guint x0,guint y0,guint x1,guint y1)865 ags_notation_editor_select_region(AgsNotationEditor *notation_editor,
866 guint x0, guint y0,
867 guint x1, guint y1)
868 {
869 AgsMachine *machine;
870
871 AgsTimestamp *timestamp;
872
873 GList *start_list_notation, *list_notation;
874
875 gint i;
876
877 if(!AGS_IS_NOTATION_EDITOR(notation_editor)){
878 return;
879 }
880
881 if(notation_editor->selected_machine != NULL){
882 machine = notation_editor->selected_machine;
883
884 /* swap values if needed */
885 if(x0 > x1){
886 guint tmp;
887
888 tmp = x0;
889
890 x0 = x1;
891 x1 = tmp;
892 }
893
894 if(y0 > y1){
895 guint tmp;
896
897 tmp = y0;
898
899 y0 = y1;
900 y1 = tmp;
901 }
902
903 /* check all active tabs */
904 timestamp = ags_timestamp_new();
905
906 timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
907 timestamp->flags |= AGS_TIMESTAMP_OFFSET;
908
909 i = 0;
910
911 g_object_get(machine->audio,
912 "notation", &start_list_notation,
913 NULL);
914
915 while((i = ags_notebook_next_active_tab(notation_editor->notebook,
916 i)) != -1){
917 list_notation = start_list_notation;
918
919 timestamp->timer.ags_offset.offset = AGS_NOTATION_DEFAULT_OFFSET * floor(x0 / AGS_NOTATION_DEFAULT_OFFSET);
920
921 while((list_notation = ags_notation_find_near_timestamp(list_notation, i,
922 timestamp)) != NULL &&
923 timestamp->timer.ags_offset.offset < (AGS_NOTATION_DEFAULT_OFFSET * floor(x1 / AGS_NOTATION_DEFAULT_OFFSET)) + AGS_NOTATION_DEFAULT_OFFSET){
924 ags_notation_add_region_to_selection(list_notation->data,
925 x0, y0,
926 x1, y1,
927 TRUE);
928
929 /* iterate */
930 timestamp->timer.ags_offset.offset += AGS_NOTATION_DEFAULT_OFFSET;
931
932 list_notation = list_notation->next;
933 }
934
935 /* iterate */
936 i++;
937 }
938
939 g_list_free_full(start_list_notation,
940 g_object_unref);
941
942 gtk_widget_queue_draw((GtkWidget *) notation_editor->notation_edit);
943 }
944 }
945
946 /**
947 * ags_notation_editor_do_feedback:
948 * @notation_editor: the #AgsNotationEditor
949 *
950 * Do playback feedback.
951 *
952 * Since: 3.0.0
953 */
954 void
ags_notation_editor_do_feedback(AgsNotationEditor * notation_editor)955 ags_notation_editor_do_feedback(AgsNotationEditor *notation_editor)
956 {
957 if(!AGS_IS_NOTATION_EDITOR(notation_editor)){
958 return;
959 }
960
961 if(notation_editor->selected_machine != NULL){
962 AgsNotationEdit *notation_edit;
963 AgsMachine *machine;
964
965 AgsChannel *start_output, *start_input;
966 AgsChannel *nth_channel, *nth_pad;
967 AgsPlayback *playback;
968
969 AgsTimestamp *timestamp;
970
971 GList *start_list_notation, *list_notation;
972
973 guint output_pads, input_pads;
974 gint i;
975
976 notation_edit = notation_editor->notation_edit;
977 machine = notation_editor->selected_machine;
978
979 /* check all active tabs */
980 timestamp = ags_timestamp_new();
981
982 timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
983 timestamp->flags |= AGS_TIMESTAMP_OFFSET;
984
985 timestamp->timer.ags_offset.offset = AGS_NOTATION_DEFAULT_OFFSET * floor(notation_edit->cursor_position_x / AGS_NOTATION_DEFAULT_OFFSET);
986
987 i = 0;
988
989 g_object_get(machine->audio,
990 "output", &start_output,
991 "output-pads", &output_pads,
992 "input", &start_input,
993 "input-pads", &input_pads,
994 "notation", &start_list_notation,
995 NULL);
996
997 while((i = ags_notebook_next_active_tab(notation_editor->notebook,
998 i)) != -1){
999 AgsNote *current_note;
1000 AgsNote *play_note;
1001
1002 list_notation = start_list_notation;
1003 list_notation = ags_notation_find_near_timestamp(list_notation, i,
1004 timestamp);
1005
1006 if(list_notation == NULL){
1007 i++;
1008
1009 continue;
1010 }
1011
1012 current_note = ags_notation_find_point(list_notation->data,
1013 notation_edit->cursor_position_x, notation_edit->cursor_position_y,
1014 FALSE);
1015
1016 if(current_note != NULL){
1017 if(ags_audio_test_behaviour_flags(machine->audio, AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_OUTPUT)){
1018 nth_channel = ags_channel_nth(start_output,
1019 i);
1020 }else{
1021 nth_channel = ags_channel_nth(start_input,
1022 i);
1023 }
1024
1025 if(ags_audio_test_behaviour_flags(machine->audio, AGS_SOUND_BEHAVIOUR_REVERSE_MAPPING)){
1026 nth_pad = ags_channel_pad_nth(nth_channel,
1027 (ags_audio_test_behaviour_flags(machine->audio, AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_OUTPUT) ? output_pads: input_pads) - notation_edit->cursor_position_y - 1);
1028 }else{
1029 nth_pad = ags_channel_pad_nth(nth_channel,
1030 notation_edit->cursor_position_y);
1031 }
1032
1033 if(nth_pad != NULL){
1034 guint x0, x1;
1035
1036 g_object_get(nth_pad,
1037 "playback", &playback,
1038 NULL);
1039
1040 g_object_get(playback,
1041 "play-note", &play_note,
1042 NULL);
1043
1044 g_object_get(current_note,
1045 "x0", &x0,
1046 "x1", &x1,
1047 NULL);
1048
1049 g_object_set(play_note,
1050 "x0", 0,
1051 "x1", x1 - x0,
1052 NULL);
1053
1054 ags_machine_playback_set_active(machine,
1055 playback,
1056 TRUE);
1057
1058 g_object_unref(playback);
1059
1060 g_object_unref(play_note);
1061 }
1062
1063 /* unref */
1064 if(nth_channel != NULL){
1065 g_object_unref(nth_channel);
1066 }
1067
1068 if(nth_pad != NULL){
1069 g_object_unref(nth_pad);
1070 }
1071 }
1072
1073 /* iterate */
1074 i++;
1075 }
1076
1077 g_list_free_full(start_list_notation,
1078 g_object_unref);
1079
1080 /* unref */
1081 if(start_output != NULL){
1082 g_object_unref(start_output);
1083 }
1084
1085 if(start_input != NULL){
1086 g_object_unref(start_input);
1087 }
1088 }
1089 }
1090
1091 /**
1092 * ags_notation_editor_start_play_key:
1093 * @notation_editor: the #AgsNotationEditor
1094 * @key_code: the key to play
1095 *
1096 * Start play @key_code.
1097 *
1098 * Since: 3.0.0
1099 */
1100 void
ags_notation_editor_start_play_key(AgsNotationEditor * notation_editor,gint key_code)1101 ags_notation_editor_start_play_key(AgsNotationEditor *notation_editor,
1102 gint key_code)
1103 {
1104 if(!AGS_IS_NOTATION_EDITOR(notation_editor)){
1105 return;
1106 }
1107
1108 if(notation_editor->selected_machine != NULL){
1109 AgsMachine *machine;
1110
1111 AgsChannel *start_output, *start_input;
1112 AgsChannel *nth_channel, *nth_pad;
1113 AgsPlayback *playback;
1114
1115 GObject *output_soundcard;
1116
1117 guint output_pads, input_pads;
1118 guint audio_channels;
1119 guint note_offset;
1120 guint y;
1121 gint i;
1122
1123 machine = notation_editor->selected_machine;
1124
1125 i = 0;
1126
1127 g_object_get(machine->audio,
1128 "output-soundcard", &output_soundcard,
1129 "output", &start_output,
1130 "output-pads", &output_pads,
1131 "input", &start_input,
1132 "input-pads", &input_pads,
1133 "audio-channels", &audio_channels,
1134 NULL);
1135
1136 for(i = 0; i < audio_channels; i++){
1137 AgsNote *play_note;
1138
1139 //TODO:JK: improve me
1140 y = key_code;
1141
1142 #if 0
1143 if(ags_audio_test_behaviour_flags(machine->audio, AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_OUTPUT)){
1144 nth_channel = ags_channel_nth(start_output,
1145 i);
1146 }else{
1147 nth_channel = ags_channel_nth(start_input,
1148 i);
1149 }
1150
1151 if(ags_audio_test_behaviour_flags(machine->audio, AGS_SOUND_BEHAVIOUR_REVERSE_MAPPING)){
1152 nth_pad = ags_channel_pad_nth(nth_channel,
1153 (ags_audio_test_behaviour_flags(machine->audio, AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_OUTPUT) ? output_pads: input_pads) - y - 1);
1154 }else{
1155 nth_pad = ags_channel_pad_nth(nth_channel,
1156 y);
1157 }
1158 #else
1159 nth_channel = ags_channel_nth(start_input,
1160 i);
1161
1162 if(ags_audio_test_behaviour_flags(machine->audio, AGS_SOUND_BEHAVIOUR_REVERSE_MAPPING)){
1163 nth_pad = ags_channel_pad_nth(nth_channel,
1164 (input_pads) - y - 1);
1165 }else{
1166 nth_pad = ags_channel_pad_nth(nth_channel,
1167 y);
1168 }
1169 #endif
1170
1171 if(nth_pad != NULL){
1172 g_object_get(nth_pad,
1173 "playback", &playback,
1174 NULL);
1175
1176 g_object_get(playback,
1177 "play-note", &play_note,
1178 NULL);
1179
1180 note_offset = ags_soundcard_get_note_offset(AGS_SOUNDCARD(output_soundcard));
1181
1182 ags_note_set_flags(play_note, AGS_NOTE_FEED);
1183 g_object_set(play_note,
1184 "x0", note_offset,
1185 "x1", note_offset + 1,
1186 NULL);
1187
1188 ags_machine_playback_set_active(machine,
1189 playback,
1190 TRUE);
1191
1192 g_object_unref(playback);
1193
1194 g_object_unref(play_note);
1195 }
1196
1197 /* unref */
1198 if(nth_channel != NULL){
1199 g_object_unref(nth_channel);
1200 }
1201
1202 if(nth_pad != NULL){
1203 g_object_unref(nth_pad);
1204 }
1205 }
1206
1207 /* unref */
1208 if(start_output != NULL){
1209 g_object_unref(start_output);
1210 }
1211
1212 if(start_input != NULL){
1213 g_object_unref(start_input);
1214 }
1215 }
1216 }
1217
1218 /**
1219 * ags_notation_editor_stop_play_key:
1220 * @notation_editor: the #AgsNotationEditor
1221 * @key_code: the key to stop
1222 *
1223 * Stop play @key_code.
1224 *
1225 * Since: 3.0.0
1226 */
1227 void
ags_notation_editor_stop_play_key(AgsNotationEditor * notation_editor,gint key_code)1228 ags_notation_editor_stop_play_key(AgsNotationEditor *notation_editor,
1229 gint key_code)
1230 {
1231 if(!AGS_IS_NOTATION_EDITOR(notation_editor)){
1232 return;
1233 }
1234
1235 if(notation_editor->selected_machine != NULL){
1236 AgsMachine *machine;
1237
1238 AgsChannel *start_output, *start_input;
1239 AgsChannel *nth_channel, *nth_pad;
1240 AgsPlayback *playback;
1241
1242 guint output_pads, input_pads;
1243 guint audio_channels;
1244 guint y;
1245 gint i;
1246
1247 machine = notation_editor->selected_machine;
1248
1249 i = 0;
1250
1251 g_object_get(machine->audio,
1252 "output", &start_output,
1253 "output-pads", &output_pads,
1254 "input", &start_input,
1255 "input-pads", &input_pads,
1256 "audio-channels", &audio_channels,
1257 NULL);
1258
1259 for(i = 0; i < audio_channels; i++){
1260 AgsNote *play_note;
1261
1262 //TODO:JK: improve me
1263 y = key_code;
1264
1265 #if 0
1266 if(ags_audio_test_behaviour_flags(machine->audio, AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_OUTPUT)){
1267 nth_channel = ags_channel_nth(start_output,
1268 i);
1269 }else{
1270 nth_channel = ags_channel_nth(start_input,
1271 i);
1272 }
1273
1274 if(ags_audio_test_behaviour_flags(machine->audio, AGS_SOUND_BEHAVIOUR_REVERSE_MAPPING)){
1275 nth_pad = ags_channel_pad_nth(nth_channel,
1276 (ags_audio_test_behaviour_flags(machine->audio, AGS_SOUND_BEHAVIOUR_DEFAULTS_TO_OUTPUT) ? output_pads: input_pads) - y - 1);
1277 }else{
1278 nth_pad = ags_channel_pad_nth(nth_channel,
1279 y);
1280 }
1281 #else
1282 nth_channel = ags_channel_nth(start_input,
1283 i);
1284
1285 if(ags_audio_test_behaviour_flags(machine->audio, AGS_SOUND_BEHAVIOUR_REVERSE_MAPPING)){
1286 nth_pad = ags_channel_pad_nth(nth_channel,
1287 (input_pads) - y - 1);
1288 }else{
1289 nth_pad = ags_channel_pad_nth(nth_channel,
1290 y);
1291 }
1292 #endif
1293
1294 if(nth_pad != NULL){
1295 g_object_get(nth_pad,
1296 "playback", &playback,
1297 NULL);
1298
1299 g_object_get(playback,
1300 "play-note", &play_note,
1301 NULL);
1302
1303 ags_note_unset_flags(play_note, AGS_NOTE_FEED);
1304
1305 ags_machine_playback_set_active(machine,
1306 playback,
1307 FALSE);
1308
1309 g_object_unref(playback);
1310
1311 g_object_unref(play_note);
1312 }
1313
1314 /* unref */
1315 if(nth_channel != NULL){
1316 g_object_unref(nth_channel);
1317 }
1318
1319 if(nth_pad != NULL){
1320 g_object_unref(nth_pad);
1321 }
1322 }
1323
1324 /* unref */
1325 if(start_output != NULL){
1326 g_object_unref(start_output);
1327 }
1328
1329 if(start_input != NULL){
1330 g_object_unref(start_input);
1331 }
1332 }
1333 }
1334
1335 /**
1336 * ags_notation_editor_select_all:
1337 * @notation_editor: the #AgsNotationEditor
1338 *
1339 * Is emitted as machine changed of notation_editor.
1340 *
1341 * Since: 3.0.0
1342 */
1343 void
ags_notation_editor_select_all(AgsNotationEditor * notation_editor)1344 ags_notation_editor_select_all(AgsNotationEditor *notation_editor)
1345 {
1346 AgsMachine *machine;
1347
1348 GList *start_list_notation, *list_notation;
1349
1350 guint audio_channel;
1351 gint i;
1352
1353 if(!AGS_IS_NOTATION_EDITOR(notation_editor)){
1354 return;
1355 }
1356
1357 if(notation_editor->selected_machine != NULL){
1358 machine = notation_editor->selected_machine;
1359
1360 /* check all active tabs */
1361 g_object_get(machine->audio,
1362 "notation", &start_list_notation,
1363 NULL);
1364
1365 i = 0;
1366
1367 while((i = ags_notebook_next_active_tab(notation_editor->notebook,
1368 i)) != -1){
1369 list_notation = start_list_notation;
1370
1371 while(list_notation != NULL){
1372 g_object_get(list_notation->data,
1373 "audio-channel", &audio_channel,
1374 NULL);
1375
1376 if(i != audio_channel){
1377 list_notation = list_notation->next;
1378
1379 continue;
1380 }
1381
1382 ags_notation_add_all_to_selection(AGS_NOTATION(list_notation->data));
1383
1384 list_notation = list_notation->next;
1385 }
1386
1387 /* iterate */
1388 i++;
1389 }
1390
1391 g_list_free_full(start_list_notation,
1392 g_object_unref);
1393
1394 gtk_widget_queue_draw((GtkWidget *) notation_editor->notation_edit);
1395 }
1396 }
1397
1398 gint
ags_notation_editor_paste_notation_all(AgsNotationEditor * notation_editor,AgsMachine * machine,xmlNode * notation_node,AgsTimestamp * timestamp,gboolean match_channel,gboolean no_duplicates,guint position_x,guint position_y,gboolean paste_from_position,gint * last_x)1399 ags_notation_editor_paste_notation_all(AgsNotationEditor *notation_editor,
1400 AgsMachine *machine,
1401 xmlNode *notation_node,
1402 AgsTimestamp *timestamp,
1403 gboolean match_channel, gboolean no_duplicates,
1404 guint position_x, guint position_y,
1405 gboolean paste_from_position,
1406 gint *last_x)
1407 {
1408 AgsNotation *notation;
1409
1410 GList *start_list_notation, *list_notation;
1411
1412 gint first_x;
1413 guint current_x;
1414 gint i;
1415
1416 first_x = -1;
1417
1418 /* */
1419 i = 0;
1420
1421 while((i = ags_notebook_next_active_tab(notation_editor->notebook,
1422 i)) != -1){
1423 g_object_get(machine->audio,
1424 "notation", &start_list_notation,
1425 NULL);
1426
1427 list_notation = ags_notation_find_near_timestamp(start_list_notation, i,
1428 timestamp);
1429
1430 if(list_notation == NULL){
1431 notation = ags_notation_new((GObject *) machine->audio,
1432 i);
1433 notation->timestamp->timer.ags_offset.offset = timestamp->timer.ags_offset.offset;
1434
1435 ags_audio_add_notation(machine->audio,
1436 (GObject *) notation);
1437 }else{
1438 notation = AGS_NOTATION(list_notation->data);
1439 }
1440
1441 g_list_free_full(start_list_notation,
1442 g_object_unref);
1443
1444 if(paste_from_position){
1445 xmlNode *child;
1446
1447 guint x_boundary;
1448
1449 ags_notation_insert_from_clipboard_extended(notation,
1450 notation_node,
1451 TRUE, position_x,
1452 TRUE, position_y,
1453 match_channel, no_duplicates);
1454
1455 /* get boundaries */
1456 child = notation_node->children;
1457 current_x = 0;
1458
1459 while(child != NULL){
1460 if(child->type == XML_ELEMENT_NODE){
1461 if(!xmlStrncmp(child->name,
1462 BAD_CAST "note",
1463 5)){
1464 guint tmp;
1465
1466 tmp = g_ascii_strtoull(xmlGetProp(child,
1467 BAD_CAST "x1"),
1468 NULL,
1469 10);
1470
1471 if(tmp > current_x){
1472 current_x = tmp;
1473 }
1474 }
1475 }
1476
1477 child = child->next;
1478 }
1479
1480 x_boundary = g_ascii_strtoull(xmlGetProp(notation_node,
1481 BAD_CAST "x_boundary"),
1482 NULL,
1483 10);
1484
1485
1486 if(first_x == -1 || x_boundary < first_x){
1487 first_x = x_boundary;
1488 }
1489
1490 if(position_x > x_boundary){
1491 current_x += (position_x - x_boundary);
1492 }else{
1493 current_x -= (x_boundary - position_x);
1494 }
1495
1496 if(current_x > last_x[0]){
1497 last_x[0] = current_x;
1498 }
1499 }else{
1500 xmlNode *child;
1501
1502 ags_notation_insert_from_clipboard(notation,
1503 notation_node,
1504 FALSE, 0,
1505 FALSE, 0);
1506
1507 /* get boundaries */
1508 child = notation_node->children;
1509 current_x = 0;
1510
1511 while(child != NULL){
1512 if(child->type == XML_ELEMENT_NODE){
1513 if(!xmlStrncmp(child->name,
1514 BAD_CAST "note",
1515 5)){
1516 guint tmp;
1517
1518 tmp = g_ascii_strtoull(xmlGetProp(child,
1519 BAD_CAST "x1"),
1520 NULL,
1521 10);
1522
1523 if(tmp > current_x){
1524 current_x = tmp;
1525 }
1526 }
1527 }
1528
1529 child = child->next;
1530 }
1531
1532 if(current_x > last_x[0]){
1533 last_x[0] = current_x;
1534 }
1535 }
1536
1537 /* iterate */
1538 i++;
1539 }
1540
1541 return(first_x);
1542 }
1543
1544 gint
ags_notation_editor_paste_notation(AgsNotationEditor * notation_editor,AgsMachine * machine,xmlNode * audio_node,guint position_x,guint position_y,gboolean paste_from_position,gint * last_x)1545 ags_notation_editor_paste_notation(AgsNotationEditor *notation_editor,
1546 AgsMachine *machine,
1547 xmlNode *audio_node,
1548 guint position_x, guint position_y,
1549 gboolean paste_from_position,
1550 gint *last_x)
1551 {
1552 AgsTimestamp *timestamp;
1553
1554 xmlNode *notation_list_node, *notation_node;
1555 xmlNode *timestamp_node;
1556
1557 gint first_x;
1558 gboolean match_channel, no_duplicates;
1559
1560 first_x = -1;
1561
1562 match_channel = ((AGS_NOTATION_EDITOR_PASTE_MATCH_AUDIO_CHANNEL & (notation_editor->flags)) != 0) ? TRUE: FALSE;
1563 no_duplicates = ((AGS_NOTATION_EDITOR_PASTE_NO_DUPLICATES & (notation_editor->flags)) != 0) ? TRUE: FALSE;
1564
1565 /* timestamp */
1566 timestamp = ags_timestamp_new();
1567
1568 timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
1569 timestamp->flags |= AGS_TIMESTAMP_OFFSET;
1570
1571 timestamp->timer.ags_offset.offset = 0;
1572
1573 /* paste notation */
1574 notation_list_node = audio_node->children;
1575
1576 while(notation_list_node != NULL){
1577 if(notation_list_node->type == XML_ELEMENT_NODE){
1578 if(!xmlStrncmp(notation_list_node->name,
1579 BAD_CAST "notation-list",
1580 14)){
1581 notation_node = notation_list_node->children;
1582
1583 while(notation_node != NULL){
1584 if(notation_node->type == XML_ELEMENT_NODE){
1585 if(!xmlStrncmp(notation_node->name,
1586 BAD_CAST "notation",
1587 9)){
1588 guint64 offset;
1589
1590 timestamp_node = notation_node->children;
1591 offset = 0;
1592
1593 while(timestamp_node != NULL){
1594 if(timestamp_node->type == XML_ELEMENT_NODE){
1595 if(!xmlStrncmp(timestamp_node->name,
1596 BAD_CAST "timestamp",
1597 10)){
1598 offset = g_ascii_strtoull((gchar *) xmlGetProp(timestamp_node,
1599 BAD_CAST "offset"),
1600 NULL,
1601 10);
1602
1603 break;
1604 }
1605 }
1606
1607 timestamp_node = timestamp_node->next;
1608 }
1609
1610 /* 1st attempt */
1611 timestamp->timer.ags_offset.offset = (guint64) AGS_NOTATION_DEFAULT_OFFSET * floor((double) position_x / (double) AGS_NOTATION_DEFAULT_OFFSET);
1612
1613 first_x = ags_notation_editor_paste_notation_all(notation_editor,
1614 machine,
1615 notation_node,
1616 timestamp,
1617 match_channel, no_duplicates,
1618 position_x, position_y,
1619 paste_from_position,
1620 last_x);
1621
1622 /* 2nd attempt */
1623 timestamp->timer.ags_offset.offset += AGS_NOTATION_DEFAULT_OFFSET;
1624
1625 ags_notation_editor_paste_notation_all(notation_editor,
1626 machine,
1627 notation_node,
1628 timestamp,
1629 match_channel, no_duplicates,
1630 position_x, position_y,
1631 paste_from_position,
1632 last_x);
1633 }
1634 }
1635
1636 notation_node = notation_node->next;
1637 }
1638 }
1639 }
1640
1641 notation_list_node = notation_list_node->next;
1642 }
1643
1644 g_object_unref(timestamp);
1645
1646 return(first_x);
1647 }
1648
1649 /**
1650 * ags_notation_editor_paste:
1651 * @notation_editor: the #AgsNotationEditor
1652 *
1653 * Is emitted as machine changed of notation_editor.
1654 *
1655 * Since: 3.0.0
1656 */
1657 void
ags_notation_editor_paste(AgsNotationEditor * notation_editor)1658 ags_notation_editor_paste(AgsNotationEditor *notation_editor)
1659 {
1660 AgsMachine *machine;
1661 AgsNotationEdit *notation_edit;
1662
1663 xmlDoc *clipboard;
1664 xmlNode *audio_node;
1665
1666 gchar *buffer;
1667
1668 guint position_x, position_y;
1669 gint first_x, last_x;
1670 gboolean paste_from_position;
1671
1672 if(!AGS_IS_NOTATION_EDITOR(notation_editor)){
1673 return;
1674 }
1675
1676 if((machine = notation_editor->selected_machine) != NULL){
1677 notation_edit = notation_editor->notation_edit;
1678
1679 /* get clipboard */
1680 buffer = gtk_clipboard_wait_for_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
1681
1682 if(buffer == NULL){
1683 return;
1684 }
1685
1686 position_x = 0;
1687 position_y = 0;
1688
1689 /* get position */
1690 if(notation_editor->notation_toolbar->selected_edit_mode == notation_editor->notation_toolbar->position){
1691 last_x = 0;
1692 paste_from_position = TRUE;
1693
1694 position_x = notation_editor->notation_edit->cursor_position_x;
1695 position_y = notation_editor->notation_edit->cursor_position_y;
1696
1697 #ifdef DEBUG
1698 printf("pasting at position: [%u,%u]\n", position_x, position_y);
1699 #endif
1700 }else{
1701 paste_from_position = FALSE;
1702 }
1703
1704 /* get xml tree */
1705 clipboard = xmlReadMemory(buffer, strlen(buffer),
1706 NULL, "UTF-8",
1707 0);
1708 audio_node = xmlDocGetRootElement(clipboard);
1709
1710 first_x = -1;
1711
1712 /* iterate xml tree */
1713 while(audio_node != NULL){
1714 if(audio_node->type == XML_ELEMENT_NODE){
1715 if(!xmlStrncmp(audio_node->name,
1716 BAD_CAST "audio",
1717 6)){
1718 first_x = ags_notation_editor_paste_notation(notation_editor,
1719 machine,
1720 audio_node,
1721 position_x, position_y,
1722 paste_from_position,
1723 &last_x);
1724
1725 break;
1726 }
1727 }
1728
1729 audio_node = audio_node->next;
1730 }
1731
1732 if(first_x == -1){
1733 first_x = 0;
1734 }
1735
1736 xmlFreeDoc(clipboard);
1737
1738 if(paste_from_position){
1739 gint big_step, small_step;
1740
1741 //TODO:JK: implement me
1742 big_step = (guint) ceil((double) last_x / 16.0) * 16.0 + (notation_edit->cursor_position_x % (guint) 16);
1743 small_step = (guint) big_step - 16;
1744
1745 if(small_step < last_x){
1746 notation_editor->notation_edit->cursor_position_x = big_step;
1747 }else{
1748 notation_editor->notation_edit->cursor_position_x = small_step;
1749 }
1750 }
1751
1752 gtk_widget_queue_draw((GtkWidget *) notation_editor->notation_edit);
1753 }
1754 }
1755
1756 /**
1757 * ags_notation_editor_copy:
1758 * @notation_editor: the #AgsNotationEditor
1759 *
1760 * Is emitted as machine changed of notation_editor.
1761 *
1762 * Since: 3.0.0
1763 */
1764 void
ags_notation_editor_copy(AgsNotationEditor * notation_editor)1765 ags_notation_editor_copy(AgsNotationEditor *notation_editor)
1766 {
1767 AgsMachine *machine;
1768
1769 xmlDoc *clipboard;
1770 xmlNode *audio_node, *notation_list_node, *notation_node;
1771
1772 GList *start_list_notation, *list_notation;
1773
1774 xmlChar *buffer;
1775
1776 int buffer_size;
1777 guint audio_channel;
1778 gint i;
1779
1780 if(!AGS_IS_NOTATION_EDITOR(notation_editor)){
1781 return;
1782 }
1783
1784 if(notation_editor->selected_machine != NULL){
1785 machine = notation_editor->selected_machine;
1786
1787 /* create document */
1788 clipboard = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
1789
1790 /* create root node */
1791 audio_node = xmlNewNode(NULL,
1792 BAD_CAST "audio");
1793 xmlDocSetRootElement(clipboard, audio_node);
1794
1795 notation_list_node = xmlNewNode(NULL,
1796 BAD_CAST "notation-list");
1797 xmlAddChild(audio_node,
1798 notation_list_node);
1799
1800 /* create notation nodes */
1801 g_object_get(machine->audio,
1802 "notation", &start_list_notation,
1803 NULL);
1804
1805 i = 0;
1806
1807 while((i = ags_notebook_next_active_tab(notation_editor->notebook,
1808 i)) != -1){
1809 list_notation = start_list_notation;
1810
1811 /* copy */
1812 while(list_notation != NULL){
1813 g_object_get(list_notation->data,
1814 "audio-channel", &audio_channel,
1815 NULL);
1816
1817 if(i != audio_channel){
1818 list_notation = list_notation->next;
1819
1820 continue;
1821 }
1822
1823 notation_node = ags_notation_copy_selection(AGS_NOTATION(list_notation->data));
1824 xmlAddChild(notation_list_node,
1825 notation_node);
1826
1827 list_notation = list_notation->next;
1828 }
1829
1830 /* iterate */
1831 i++;
1832 }
1833
1834 g_list_free_full(start_list_notation,
1835 g_object_unref);
1836
1837 /* write to clipboard */
1838 xmlDocDumpFormatMemoryEnc(clipboard, &buffer, &buffer_size, "UTF-8", TRUE);
1839 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
1840 (gchar *) buffer, buffer_size);
1841 gtk_clipboard_store(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
1842
1843 xmlFreeDoc(clipboard);
1844 }
1845 }
1846
1847 /**
1848 * ags_notation_editor_cut:
1849 * @notation_editor: the #AgsNotationEditor
1850 *
1851 * Is emitted as machine changed of notation_editor.
1852 *
1853 * Since: 3.0.0
1854 */
1855 void
ags_notation_editor_cut(AgsNotationEditor * notation_editor)1856 ags_notation_editor_cut(AgsNotationEditor *notation_editor)
1857 {
1858 AgsMachine *machine;
1859
1860 xmlDoc *clipboard;
1861 xmlNode *audio_node;
1862 xmlNode *notation_list_node, *notation_node;
1863
1864 GList *start_list_notation, *list_notation;
1865
1866 xmlChar *buffer;
1867
1868 int buffer_size;
1869 guint audio_channel;
1870 gint i;
1871
1872 if(!AGS_IS_NOTATION_EDITOR(notation_editor)){
1873 return;
1874 }
1875
1876 if(notation_editor->selected_machine != NULL){
1877 machine = notation_editor->selected_machine;
1878
1879 /* create document */
1880 clipboard = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
1881
1882 /* create root node */
1883 audio_node = xmlNewNode(NULL,
1884 BAD_CAST "audio");
1885 xmlDocSetRootElement(clipboard, audio_node);
1886
1887 notation_list_node = xmlNewNode(NULL,
1888 BAD_CAST "notation-list");
1889 xmlAddChild(audio_node,
1890 notation_list_node);
1891
1892 /* create notation nodes */
1893 g_object_get(machine->audio,
1894 "notation", &start_list_notation,
1895 NULL);
1896
1897 i = 0;
1898
1899 while((i = ags_notebook_next_active_tab(notation_editor->notebook,
1900 i)) != -1){
1901 list_notation = start_list_notation;
1902
1903 /* cut */
1904 while(list_notation != NULL){
1905 g_object_get(list_notation->data,
1906 "audio-channel", &audio_channel,
1907 NULL);
1908
1909 if(i != audio_channel){
1910 list_notation = list_notation->next;
1911
1912 continue;
1913 }
1914
1915 notation_node = ags_notation_cut_selection(AGS_NOTATION(list_notation->data));
1916 xmlAddChild(notation_list_node,
1917 notation_node);
1918
1919 list_notation = list_notation->next;
1920 }
1921
1922 /* iterate */
1923 i++;
1924 }
1925
1926 g_list_free_full(start_list_notation,
1927 g_object_unref);
1928
1929 gtk_widget_queue_draw((GtkWidget *) notation_editor->notation_edit);
1930
1931 /* write to clipboard */
1932 xmlDocDumpFormatMemoryEnc(clipboard, &buffer, &buffer_size, "UTF-8", TRUE);
1933 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
1934 (gchar *) buffer, buffer_size);
1935 gtk_clipboard_store(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
1936
1937 xmlFreeDoc(clipboard);
1938 }
1939 }
1940
1941
1942 void
ags_notation_editor_get_boundary(AgsNotationEditor * notation_editor,AgsMachine * machine,AgsNotation * notation,guint * lower,guint * upper)1943 ags_notation_editor_get_boundary(AgsNotationEditor *notation_editor,
1944 AgsMachine *machine,
1945 AgsNotation *notation,
1946 guint *lower, guint *upper)
1947 {
1948 GList *start_note, *note;
1949
1950 guint note_y;
1951
1952 g_object_get(notation,
1953 "note", &start_note,
1954 NULL);
1955
1956 /* retrieve upper and lower */
1957 note = start_note;
1958
1959 while(note != NULL){
1960 g_object_get(note->data,
1961 "y", ¬e_y,
1962 NULL);
1963
1964 if(note_y < lower[0]){
1965 lower[0] = note_y;
1966 }
1967
1968 if(note_y > upper[0]){
1969 upper[0] = note_y;
1970 }
1971
1972 note = note->next;
1973 }
1974
1975 g_list_free_full(start_note,
1976 g_object_unref);
1977 }
1978
1979 void
ags_notation_editor_invert_notation(AgsNotationEditor * notation_editor,AgsMachine * machine,AgsNotation * notation,guint lower,guint upper)1980 ags_notation_editor_invert_notation(AgsNotationEditor *notation_editor,
1981 AgsMachine *machine,
1982 AgsNotation *notation,
1983 guint lower, guint upper)
1984 {
1985 GList *start_note, *note;
1986
1987 guint note_y;
1988
1989 g_object_get(notation,
1990 "note", &start_note,
1991 NULL);
1992
1993 /* invert */
1994 note = start_note;
1995
1996 while(note != NULL){
1997 g_object_get(note->data,
1998 "y", ¬e_y,
1999 NULL);
2000
2001 if((gdouble) note_y < (gdouble) (upper - lower) / 2.0){
2002 g_object_set(note->data,
2003 "y", (upper - (note_y - lower)),
2004 NULL);
2005 }else if((gdouble) note_y > (gdouble) (upper - lower) / 2.0){
2006 g_object_set(note->data,
2007 "y", (lower + (upper - AGS_NOTE(note->data)->y)),
2008 NULL);
2009 }
2010
2011 note = note->next;
2012 }
2013
2014 g_list_free_full(start_note,
2015 g_object_unref);
2016 }
2017
2018 /**
2019 * ags_notation_editor_invert:
2020 * @notation_editor: the #AgsNotationEditor
2021 *
2022 * Invert all notation of @notation_editor's selected machine.
2023 *
2024 * Since: 3.0.0
2025 */
2026 void
ags_notation_editor_invert(AgsNotationEditor * notation_editor)2027 ags_notation_editor_invert(AgsNotationEditor *notation_editor)
2028 {
2029 AgsMachine *machine;
2030
2031 GList *start_list_notation, *list_notation;
2032
2033 guint audio_channel;
2034 gint i;
2035
2036 if(!AGS_IS_NOTATION_EDITOR(notation_editor)){
2037 return;
2038 }
2039
2040 if(notation_editor->selected_machine != NULL){
2041 guint lower, upper;
2042
2043 /* create notation nodes */
2044 machine = notation_editor->selected_machine;
2045
2046 g_object_get(machine->audio,
2047 "notation", &start_list_notation,
2048 NULL);
2049
2050 i = 0;
2051
2052 while((i = ags_notebook_next_active_tab(notation_editor->notebook,
2053 i)) != -1){
2054 /* get boundary */
2055 list_notation = start_list_notation;
2056
2057 lower = G_MAXUINT;
2058 upper = 0;
2059
2060 while(list_notation != NULL){
2061 g_object_get(list_notation->data,
2062 "audio-channel", &audio_channel,
2063 NULL);
2064
2065 if(i != audio_channel){
2066 list_notation = list_notation->next;
2067
2068 continue;
2069 }
2070
2071 ags_notation_editor_get_boundary(notation_editor,
2072 machine,
2073 AGS_NOTATION(list_notation->data),
2074 &lower, &upper);
2075
2076 list_notation = list_notation->next;
2077 }
2078
2079 /* invert */
2080 list_notation = start_list_notation;
2081
2082 while(list_notation != NULL){
2083 g_object_get(list_notation->data,
2084 "audio-channel", &audio_channel,
2085 NULL);
2086
2087 if(i != audio_channel){
2088 list_notation = list_notation->next;
2089
2090 continue;
2091 }
2092
2093 ags_notation_editor_invert_notation(notation_editor,
2094 machine,
2095 AGS_NOTATION(list_notation->data),
2096 lower, upper);
2097
2098 list_notation = list_notation->next;
2099 }
2100
2101 i++;
2102 }
2103
2104 g_list_free_full(start_list_notation,
2105 g_object_unref);
2106
2107 gtk_widget_queue_draw((GtkWidget *) notation_editor->notation_edit);
2108 }
2109 }
2110
2111 /**
2112 * ags_notation_editor_new:
2113 *
2114 * Creates the #AgsNotationEditor
2115 *
2116 * Returns: a new #AgsNotationEditor
2117 *
2118 * Since: 3.0.0
2119 */
2120 AgsNotationEditor*
ags_notation_editor_new()2121 ags_notation_editor_new()
2122 {
2123 AgsNotationEditor *notation_editor;
2124
2125 notation_editor = (AgsNotationEditor *) g_object_new(AGS_TYPE_NOTATION_EDITOR,
2126 NULL);
2127
2128 return(notation_editor);
2129 }
2130