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/editor/ags_notation_meta.h>
21 #include <ags/X/editor/ags_notation_meta_callbacks.h>
22
23 #include <ags/X/ags_notation_editor.h>
24
25 #include <ags/i18n.h>
26
27 void ags_notation_meta_class_init(AgsNotationMetaClass *notation_meta);
28 void ags_notation_meta_connectable_interface_init(AgsConnectableInterface *connectable);
29 void ags_notation_meta_init(AgsNotationMeta *notation_meta);
30
31 void ags_notation_meta_connect(AgsConnectable *connectable);
32 void ags_notation_meta_disconnect(AgsConnectable *connectable);
33
34 /**
35 * SECTION:ags_notation_meta
36 * @short_description: notation_meta
37 * @title: AgsNotationMeta
38 * @section_id:
39 * @include: ags/X/editor/ags_notation_meta.h
40 *
41 * The #AgsNotationMeta provides you information about notation editor.
42 */
43
44 GType
ags_notation_meta_get_type(void)45 ags_notation_meta_get_type(void)
46 {
47 static volatile gsize g_define_type_id__volatile = 0;
48
49 if(g_once_init_enter (&g_define_type_id__volatile)){
50 GType ags_type_notation_meta = 0;
51
52 static const GTypeInfo ags_notation_meta_info = {
53 sizeof (AgsNotationMetaClass),
54 NULL, /* base_init */
55 NULL, /* base_finalize */
56 (GClassInitFunc) ags_notation_meta_class_init,
57 NULL, /* class_finalize */
58 NULL, /* class_data */
59 sizeof (AgsNotationMeta),
60 0, /* n_preallocs */
61 (GInstanceInitFunc) ags_notation_meta_init,
62 };
63
64 static const GInterfaceInfo ags_connectable_interface_info = {
65 (GInterfaceInitFunc) ags_notation_meta_connectable_interface_init,
66 NULL, /* interface_finalize */
67 NULL, /* interface_data */
68 };
69
70 ags_type_notation_meta = g_type_register_static(GTK_TYPE_VBOX,
71 "AgsNotationMeta", &ags_notation_meta_info,
72 0);
73
74 g_type_add_interface_static(ags_type_notation_meta,
75 AGS_TYPE_CONNECTABLE,
76 &ags_connectable_interface_info);
77
78 g_once_init_leave(&g_define_type_id__volatile, ags_type_notation_meta);
79 }
80
81 return g_define_type_id__volatile;
82 }
83
84 void
ags_notation_meta_class_init(AgsNotationMetaClass * notation_meta)85 ags_notation_meta_class_init(AgsNotationMetaClass *notation_meta)
86 {
87 /* empty */
88 }
89
90 void
ags_notation_meta_connectable_interface_init(AgsConnectableInterface * connectable)91 ags_notation_meta_connectable_interface_init(AgsConnectableInterface *connectable)
92 {
93 connectable->is_ready = NULL;
94 connectable->is_connected = NULL;
95 connectable->connect = ags_notation_meta_connect;
96 connectable->disconnect = ags_notation_meta_disconnect;
97 }
98
99 void
ags_notation_meta_init(AgsNotationMeta * notation_meta)100 ags_notation_meta_init(AgsNotationMeta *notation_meta)
101 {
102 GtkGrid *grid;
103 GtkLabel *label;
104
105 guint i;
106
107 notation_meta->flags = 0;
108
109 grid = gtk_grid_new();
110 gtk_box_pack_start((GtkBox *) notation_meta,
111 (GtkWidget *) grid,
112 FALSE,
113 TRUE,
114 0);
115
116 /* machine type */
117 i = 0;
118
119 label = (GtkLabel *) gtk_label_new(i18n("machine type: "));
120 g_object_set(label,
121 "halign", GTK_ALIGN_START,
122 NULL);
123 gtk_grid_attach(grid,
124 (GtkWidget *) label,
125 0, i,
126 1, 1);
127
128 notation_meta->machine_type = (GtkLabel *) gtk_label_new("(null)");
129 g_object_set(notation_meta->machine_type,
130 "halign", GTK_ALIGN_START,
131 NULL);
132 gtk_grid_attach(grid,
133 (GtkWidget *) notation_meta->machine_type,
134 1, i,
135 1, 1);
136
137 /* machine name */
138 i++;
139
140 label = (GtkLabel *) gtk_label_new(i18n("machine name: "));
141 g_object_set(label,
142 "halign", GTK_ALIGN_START,
143 NULL);
144 gtk_grid_attach(grid,
145 (GtkWidget *) label,
146 0, i,
147 1, 1);
148
149 notation_meta->machine_name = (GtkLabel *) gtk_label_new("(null)");
150 g_object_set(notation_meta->machine_name,
151 "halign", GTK_ALIGN_START,
152 NULL);
153 gtk_grid_attach(grid,
154 (GtkWidget *) notation_meta->machine_name,
155 1, i,
156 1, 1);
157
158 /* audio channels */
159 i++;
160
161 label = (GtkLabel *) gtk_label_new(i18n("audio channels: "));
162 g_object_set(label,
163 "halign", GTK_ALIGN_START,
164 NULL);
165 gtk_grid_attach(grid,
166 (GtkWidget *) label,
167 0, i,
168 1, 1);
169
170 notation_meta->audio_channels = (GtkLabel *) gtk_label_new("-1");
171 g_object_set(notation_meta->audio_channels,
172 "halign", GTK_ALIGN_START,
173 NULL);
174 gtk_grid_attach(grid,
175 (GtkWidget *) notation_meta->audio_channels,
176 1, i,
177 1, 1);
178
179 /* output pads */
180 i++;
181
182 label = (GtkLabel *) gtk_label_new(i18n("output pads: "));
183 g_object_set(label,
184 "halign", GTK_ALIGN_START,
185 NULL);
186 gtk_grid_attach(grid,
187 (GtkWidget *) label,
188 0, i,
189 1, 1);
190
191 notation_meta->output_pads = (GtkLabel *) gtk_label_new("-1");
192 g_object_set(notation_meta->output_pads,
193 "halign", GTK_ALIGN_START,
194 NULL);
195 gtk_grid_attach(grid,
196 (GtkWidget *) notation_meta->output_pads,
197 1, i,
198 1, 1);
199
200 /* input pads */
201 i++;
202
203 label = (GtkLabel *) gtk_label_new(i18n("input pads: "));
204 g_object_set(label,
205 "halign", GTK_ALIGN_START,
206 NULL);
207 gtk_grid_attach(grid,
208 (GtkWidget *) label,
209 0, i,
210 1, 1);
211
212 notation_meta->input_pads = (GtkLabel *) gtk_label_new("-1");
213 g_object_set(notation_meta->input_pads,
214 "halign", GTK_ALIGN_START,
215 NULL);
216 gtk_grid_attach(grid,
217 (GtkWidget *) notation_meta->input_pads,
218 1, i,
219 1, 1);
220
221 /* editor tool */
222 i++;
223
224 label = (GtkLabel *) gtk_label_new(i18n("editor tool: "));
225 g_object_set(label,
226 "halign", GTK_ALIGN_START,
227 NULL);
228 gtk_grid_attach(grid,
229 (GtkWidget *) label,
230 0, i,
231 1, 1);
232
233 notation_meta->editor_tool = (GtkLabel *) gtk_label_new("(null)");
234 g_object_set(notation_meta->editor_tool,
235 "halign", GTK_ALIGN_START,
236 NULL);
237 gtk_grid_attach(grid,
238 (GtkWidget *) notation_meta->editor_tool,
239 1, i,
240 1, 1);
241
242 /* active audio channel */
243 i++;
244
245 label = (GtkLabel *) gtk_label_new(i18n("active audio channel: "));
246 g_object_set(label,
247 "halign", GTK_ALIGN_START,
248 "valign", GTK_ALIGN_START,
249 NULL);
250 gtk_grid_attach(grid,
251 (GtkWidget *) label,
252 0, i,
253 1, 1);
254
255 notation_meta->active_audio_channel = (GtkLabel *) gtk_label_new("(null)");
256 g_object_set(notation_meta->active_audio_channel,
257 "halign", GTK_ALIGN_START,
258 NULL);
259 gtk_grid_attach(grid,
260 (GtkWidget *) notation_meta->active_audio_channel,
261 1, i,
262 1, 1);
263
264 /* cursor x-position */
265 i++;
266
267 label = (GtkLabel *) gtk_label_new(i18n("cursor x-position: "));
268 g_object_set(label,
269 "halign", GTK_ALIGN_START,
270 NULL);
271 gtk_grid_attach(grid,
272 (GtkWidget *) label,
273 0, i,
274 1, 1);
275
276 notation_meta->cursor_x_position = (GtkLabel *) gtk_label_new("-1");
277 g_object_set(notation_meta->cursor_x_position,
278 "halign", GTK_ALIGN_START,
279 NULL);
280 gtk_grid_attach(grid,
281 (GtkWidget *) notation_meta->cursor_x_position,
282 1, i,
283 1, 1);
284
285 /* cursor y-position */
286 i++;
287
288 label = (GtkLabel *) gtk_label_new(i18n("cursor y-position: "));
289 g_object_set(label,
290 "halign", GTK_ALIGN_START,
291 NULL);
292 gtk_grid_attach(grid,
293 (GtkWidget *) label,
294 0, i,
295 1, 1);
296
297 notation_meta->cursor_y_position = (GtkLabel *) gtk_label_new("-1");
298 g_object_set(notation_meta->cursor_y_position,
299 "halign", GTK_ALIGN_START,
300 NULL);
301 gtk_grid_attach(grid,
302 (GtkWidget *) notation_meta->cursor_y_position,
303 1, i,
304 1, 1);
305
306 /* current note */
307 i++;
308
309 label = (GtkLabel *) gtk_label_new(i18n("current note: "));
310 g_object_set(label,
311 "halign", GTK_ALIGN_START,
312 "valign", GTK_ALIGN_START,
313 NULL);
314 gtk_grid_attach(grid,
315 (GtkWidget *) label,
316 0, i,
317 1, 1);
318
319 notation_meta->current_note = (GtkLabel *) gtk_label_new("(null)");
320 g_object_set(notation_meta->current_note,
321 "halign", GTK_ALIGN_START,
322 NULL);
323 gtk_grid_attach(grid,
324 (GtkWidget *) notation_meta->current_note,
325 1, i,
326 1, 1);
327 }
328
329 void
ags_notation_meta_connect(AgsConnectable * connectable)330 ags_notation_meta_connect(AgsConnectable *connectable)
331 {
332 AgsNotationEditor *notation_editor;
333 AgsNotationMeta *notation_meta;
334
335 notation_meta = AGS_NOTATION_META(connectable);
336
337 if((AGS_NOTATION_META_CONNECTED & (notation_meta->flags)) != 0){
338 return;
339 }
340
341 notation_meta->flags |= AGS_NOTATION_META_CONNECTED;
342
343 notation_editor = gtk_widget_get_ancestor(notation_meta,
344 AGS_TYPE_NOTATION_EDITOR);
345
346 if(notation_editor != NULL){
347 g_signal_connect_after(notation_editor, "machine-changed",
348 G_CALLBACK(ags_notation_meta_machine_changed_callback), notation_meta);
349 }
350 }
351
352 void
ags_notation_meta_disconnect(AgsConnectable * connectable)353 ags_notation_meta_disconnect(AgsConnectable *connectable)
354 {
355 AgsNotationEditor *notation_editor;
356 AgsNotationMeta *notation_meta;
357
358 notation_meta = AGS_NOTATION_META(connectable);
359
360 if((AGS_NOTATION_META_CONNECTED & (notation_meta->flags)) == 0){
361 return;
362 }
363
364 notation_meta->flags &= (~AGS_NOTATION_META_CONNECTED);
365
366 notation_editor = gtk_widget_get_ancestor(notation_meta,
367 AGS_TYPE_NOTATION_EDITOR);
368
369 if(notation_editor != NULL){
370 g_object_disconnect(notation_editor,
371 "any_signal::machine-changed",
372 G_CALLBACK(ags_notation_meta_machine_changed_callback),
373 notation_meta,
374 NULL);
375 }
376 }
377
378 /**
379 * ags_notation_meta_refresh:
380 * @notation_meta: the #AgsNotationMeta
381 *
382 * Refresh @notation_meta.
383 *
384 * Since: 3.1.0
385 */
386 void
ags_notation_meta_refresh(AgsNotationMeta * notation_meta)387 ags_notation_meta_refresh(AgsNotationMeta *notation_meta)
388 {
389 AgsNotationEditor *notation_editor;
390
391 if(!AGS_IS_NOTATION_META(notation_meta)){
392 return;
393 }
394
395 notation_editor = gtk_widget_get_ancestor(notation_meta,
396 AGS_TYPE_NOTATION_EDITOR);
397
398 if(notation_editor == NULL){
399 return;
400 }
401
402 if(notation_editor->selected_machine == NULL){
403 gtk_label_set_label(notation_meta->machine_type,
404 "(null)");
405
406 gtk_label_set_label(notation_meta->machine_name,
407 "(null)");
408
409 gtk_label_set_label(notation_meta->audio_channels,
410 "-1");
411
412 gtk_label_set_label(notation_meta->output_pads,
413 "-1");
414
415 gtk_label_set_label(notation_meta->input_pads,
416 "-1");
417
418 gtk_label_set_label(notation_meta->editor_tool,
419 "(null)");
420
421 gtk_label_set_label(notation_meta->active_audio_channel,
422 "(null)");
423
424 gtk_label_set_label(notation_meta->cursor_x_position,
425 "-1");
426
427 gtk_label_set_label(notation_meta->cursor_y_position,
428 "-1");
429
430 gtk_label_set_label(notation_meta->current_note,
431 "(null)");
432 }else{
433 AgsTimestamp *timestamp;
434
435 GList *start_notation, *notation;
436 GList *start_note, *note;
437
438 gchar *str;
439
440 guint audio_channels;
441 guint output_pads, input_pads;
442 gint active_start, active_end;
443 gint position;
444 guint x0, y0;
445 guint x1, y1;
446 guint i;
447
448 gtk_label_set_label(notation_meta->machine_type,
449 G_OBJECT_TYPE_NAME(notation_editor->selected_machine));
450
451 gtk_label_set_label(notation_meta->machine_name,
452 notation_editor->selected_machine->machine_name);
453
454 g_object_get(notation_editor->selected_machine->audio,
455 "audio-channels", &audio_channels,
456 "output-pads", &output_pads,
457 "input-pads", &input_pads,
458 NULL);
459
460 /* audio channels */
461 str = g_strdup_printf("%u", audio_channels);
462 gtk_label_set_label(notation_meta->audio_channels,
463 str);
464
465 g_free(str);
466
467 /* output pads */
468 str = g_strdup_printf("%u", output_pads);
469 gtk_label_set_label(notation_meta->output_pads,
470 str);
471
472 g_free(str);
473
474 /* input pads */
475 str = g_strdup_printf("%u", input_pads);
476 gtk_label_set_label(notation_meta->input_pads,
477 str);
478
479 g_free(str);
480
481 str = NULL;
482
483 if(notation_editor->notation_toolbar->selected_edit_mode == notation_editor->notation_toolbar->position){
484 str = i18n("position");
485 }else if(notation_editor->notation_toolbar->selected_edit_mode == notation_editor->notation_toolbar->edit){
486 str = i18n("edit");
487 }else if(notation_editor->notation_toolbar->selected_edit_mode == notation_editor->notation_toolbar->clear){
488 str = i18n("clear");
489 }else if(notation_editor->notation_toolbar->selected_edit_mode == notation_editor->notation_toolbar->select){
490 str = i18n("select");
491 }
492
493 if(str != NULL){
494 gtk_label_set_label(notation_meta->editor_tool,
495 str);
496 }else{
497 gtk_label_set_label(notation_meta->editor_tool,
498 "(null)");
499 }
500
501 /* active audio channels */
502 str = NULL;
503
504 active_start = -1;
505 active_end = -1;
506
507 position = 0;
508
509 for(; (position = ags_notebook_next_active_tab(notation_editor->notebook, position)) != -1; position++){
510 if(active_start == -1){
511 active_start = position;
512 active_end = position;
513 }else{
514 if(position == active_end + 1){
515 active_end = position;
516 }else{
517 if(str == NULL){
518 if(active_start == active_end){
519 str = g_strdup_printf("%d",
520 active_start);
521 }else{
522 str = g_strdup_printf("%d-%d",
523 active_start,
524 active_end);
525 }
526 }else{
527 if(active_start == active_end){
528 gchar *tmp;
529
530 tmp = g_strdup_printf("%s, %d",
531 str,
532 active_start);
533
534 g_free(str);
535
536 str = tmp;
537 }else{
538 gchar *tmp;
539
540 tmp = g_strdup_printf("%s, %d-%d",
541 str,
542 active_start,
543 active_end);
544
545 g_free(str);
546
547 str = tmp;
548 }
549 }
550
551 active_start = position;
552 active_end = position;
553 }
554 }
555 }
556
557 if(active_start == -1){
558 gtk_label_set_label(notation_meta->active_audio_channel,
559 "(null)");
560 }else{
561 if(str == NULL){
562 if(active_start == active_end){
563 str = g_strdup_printf("[%d]",
564 active_start);
565 }else{
566 gchar *tmp;
567
568 tmp = g_strdup_printf("[%d-%d]",
569 active_start,
570 active_end);
571
572 g_free(str);
573
574 str = tmp;
575 }
576 }else{
577 if(active_start == active_end){
578 gchar *tmp;
579
580 tmp = g_strdup_printf("[%s, %d]",
581 str,
582 active_start);
583
584 g_free(str);
585
586 str = tmp;
587 }else{
588 gchar *tmp;
589
590 tmp = g_strdup_printf("[%s, %d-%d]",
591 str,
592 active_start,
593 active_end);
594
595 g_free(str);
596
597 str = tmp;
598 }
599 }
600
601 gtk_label_set_label(notation_meta->active_audio_channel,
602 str);
603
604 g_free(str);
605 }
606
607 /* cursor position x */
608 str = g_strdup_printf("%u", notation_editor->notation_edit->cursor_position_x);
609 gtk_label_set_label(notation_meta->cursor_x_position,
610 str);
611
612 g_free(str);
613
614 /* cursor position y */
615 str = g_strdup_printf("%u", notation_editor->notation_edit->cursor_position_y);
616 gtk_label_set_label(notation_meta->cursor_y_position,
617 str);
618
619 g_free(str);
620
621 /* current note */
622 g_object_get(notation_editor->selected_machine->audio,
623 "notation", &start_notation,
624 NULL);
625
626 timestamp = ags_timestamp_new();
627
628 timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
629 timestamp->flags |= AGS_TIMESTAMP_OFFSET;
630
631 x0 = notation_editor->notation_edit->cursor_position_x;
632 y0 = notation_editor->notation_edit->cursor_position_y;
633
634 x1 = x0 + exp2(6.0 - (double) gtk_combo_box_get_active(notation_editor->notation_toolbar->zoom));
635 y1 = y0 + 1;
636
637 str = NULL;
638
639 for(i = 0; i < audio_channels;){
640 gchar *current_str;
641
642 timestamp->timer.ags_offset.offset = AGS_NOTATION_DEFAULT_OFFSET * floor(x0 / AGS_NOTATION_DEFAULT_OFFSET);
643
644 position = i;
645 position = ags_notebook_next_active_tab(notation_editor->notebook, position);
646
647 if(position == -1){
648 break;
649 }
650
651 current_str = NULL;
652 ags_notation_meta_refresh_CURRENT_NOTE_TIMESTAMP_NO2:
653
654 notation = start_notation;
655
656 i = position;
657
658 while((notation = ags_notation_find_near_timestamp(notation, i,
659 timestamp)) != NULL){
660 start_note = ags_notation_find_region(notation->data,
661 x0, y0,
662 x1, y1,
663 FALSE);
664
665 note = start_note;
666
667 while(note != NULL){
668 guint x0, x1;
669 guint y;
670
671 g_object_get(note->data,
672 "x0", &x0,
673 "x1", &x1,
674 "y", &y,
675 NULL);
676
677 if(current_str == NULL){
678 current_str = g_strdup_printf("%u-%u",
679 x0,
680 x1);
681 }else{
682 gchar *tmp;
683
684 tmp = g_strdup_printf("%s, %u-%u",
685 current_str,
686 x0,
687 x1);
688
689 g_free(current_str);
690
691 current_str = tmp;
692 }
693
694 note = note->next;
695 }
696
697 notation = notation->next;
698 }
699
700 if(timestamp->timer.ags_offset.offset < AGS_NOTATION_DEFAULT_OFFSET * floor(x1 / AGS_NOTATION_DEFAULT_OFFSET)){
701 timestamp->timer.ags_offset.offset = AGS_NOTATION_DEFAULT_OFFSET * floor(x1 / AGS_NOTATION_DEFAULT_OFFSET);
702
703 position = i;
704
705 goto ags_notation_meta_refresh_CURRENT_NOTE_TIMESTAMP_NO2;
706 }
707
708 if(current_str == NULL){
709 if(str == NULL){
710 str = g_strdup_printf("@audio_channel[%d] -> (null)",
711 i);
712 }else{
713 gchar *tmp;
714
715 tmp = g_strdup_printf("%s,\n @audio_channel[%d] -> (null)",
716 str,
717 i);
718
719 g_free(str);
720
721 str = tmp;
722 }
723 }else{
724 if(str == NULL){
725 str = g_strdup_printf("@audio_channel[%d] -> {%s}",
726 i,
727 current_str);
728 }else{
729 gchar *tmp;
730
731 tmp = g_strdup_printf("%s,\n @audio_channel[%d] -> {%s}",
732 str,
733 i,
734 current_str);
735
736 g_free(str);
737
738 str = tmp;
739 }
740
741 g_free(current_str);
742 }
743
744 i++;
745 }
746
747 g_list_free_full(start_notation,
748 (GDestroyNotify) g_object_unref);
749
750 if(str == NULL){
751 gtk_label_set_label(notation_meta->current_note,
752 "(null)");
753 }else{
754 gchar *tmp;
755
756 tmp = g_strdup_printf("[%s]", str);
757 gtk_label_set_label(notation_meta->current_note,
758 tmp);
759
760 g_free(str);
761 g_free(tmp);
762 }
763
764 g_object_unref(timestamp);
765 }
766 }
767
768 /**
769 * ags_notation_meta_new:
770 *
771 * Create a new #AgsNotationMeta.
772 *
773 * Returns: a new #AgsNotationMeta
774 *
775 * Since: 3.1.0
776 */
777 AgsNotationMeta*
ags_notation_meta_new()778 ags_notation_meta_new()
779 {
780 AgsNotationMeta *notation_meta;
781
782 notation_meta = (AgsNotationMeta *) g_object_new(AGS_TYPE_NOTATION_META,
783 NULL);
784
785 return(notation_meta);
786 }
787