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/audio/task/ags_move_note.h>
21
22 #include <ags/i18n.h>
23
24 #include <math.h>
25
26 void ags_move_note_class_init(AgsMoveNoteClass *move_note);
27 void ags_move_note_init(AgsMoveNote *move_note);
28 void ags_move_note_set_property(GObject *gobject,
29 guint prop_id,
30 const GValue *value,
31 GParamSpec *param_spec);
32 void ags_move_note_get_property(GObject *gobject,
33 guint prop_id,
34 GValue *value,
35 GParamSpec *param_spec);
36 void ags_move_note_dispose(GObject *gobject);
37 void ags_move_note_finalize(GObject *gobject);
38
39 void ags_move_note_launch(AgsTask *task);
40
41 /**
42 * SECTION:ags_move_note
43 * @short_description: move notation
44 * @title: AgsMoveNote
45 * @section_id:
46 * @include: ags/audio/task/ags_move_note.h
47 *
48 * The #AgsMoveNote task moves #AgsNotation.
49 */
50
51 static gpointer ags_move_note_parent_class = NULL;
52
53 enum{
54 PROP_0,
55 PROP_AUDIO,
56 PROP_NOTATION,
57 PROP_SELECTION,
58 PROP_FIRST_X,
59 PROP_FIRST_Y,
60 PROP_MOVE_X,
61 PROP_MOVE_Y,
62 PROP_RELATIVE,
63 PROP_ABSOLUTE,
64 };
65
66 GType
ags_move_note_get_type()67 ags_move_note_get_type()
68 {
69 static volatile gsize g_define_type_id__volatile = 0;
70
71 if(g_once_init_enter (&g_define_type_id__volatile)){
72 GType ags_type_move_note = 0;
73
74 static const GTypeInfo ags_move_note_info = {
75 sizeof(AgsMoveNoteClass),
76 NULL, /* base_init */
77 NULL, /* base_finalize */
78 (GClassInitFunc) ags_move_note_class_init,
79 NULL, /* class_finalize */
80 NULL, /* class_data */
81 sizeof(AgsMoveNote),
82 0, /* n_preallocs */
83 (GInstanceInitFunc) ags_move_note_init,
84 };
85
86 ags_type_move_note = g_type_register_static(AGS_TYPE_TASK,
87 "AgsMoveNote",
88 &ags_move_note_info,
89 0);
90
91 g_once_init_leave(&g_define_type_id__volatile, ags_type_move_note);
92 }
93
94 return g_define_type_id__volatile;
95 }
96
97 void
ags_move_note_class_init(AgsMoveNoteClass * move_note)98 ags_move_note_class_init(AgsMoveNoteClass *move_note)
99 {
100 GObjectClass *gobject;
101 AgsTaskClass *task;
102
103 GParamSpec *param_spec;
104
105 ags_move_note_parent_class = g_type_class_peek_parent(move_note);
106
107 /* gobject */
108 gobject = (GObjectClass *) move_note;
109
110 gobject->set_property = ags_move_note_set_property;
111 gobject->get_property = ags_move_note_get_property;
112
113 gobject->dispose = ags_move_note_dispose;
114 gobject->finalize = ags_move_note_finalize;
115
116 /* properties */
117 /**
118 * AgsMoveNote:audio:
119 *
120 * The assigned #AgsAudio
121 *
122 * Since: 3.0.0
123 */
124 param_spec = g_param_spec_object("audio",
125 i18n_pspec("audio of move note"),
126 i18n_pspec("The audio of move note task"),
127 AGS_TYPE_AUDIO,
128 G_PARAM_READABLE | G_PARAM_WRITABLE);
129 g_object_class_install_property(gobject,
130 PROP_AUDIO,
131 param_spec);
132
133 /**
134 * AgsMoveNote:notation:
135 *
136 * The assigned #AgsNotation
137 *
138 * Since: 3.0.0
139 */
140 param_spec = g_param_spec_object("notation",
141 i18n_pspec("notation of move note"),
142 i18n_pspec("The notation of move note task"),
143 AGS_TYPE_NOTATION,
144 G_PARAM_READABLE | G_PARAM_WRITABLE);
145 g_object_class_install_property(gobject,
146 PROP_NOTATION,
147 param_spec);
148
149 /**
150 * AgsMoveNote:selection: (type GList(AgsNote))
151 *
152 * The assigned #AgsNote
153 *
154 * Since: 3.0.0
155 */
156 param_spec = g_param_spec_pointer("selection",
157 i18n_pspec("selection to move"),
158 i18n_pspec("The selection to move"),
159 G_PARAM_READABLE | G_PARAM_WRITABLE);
160 g_object_class_install_property(gobject,
161 PROP_SELECTION,
162 param_spec);
163
164 /**
165 * AgsMoveNote:first-x:
166 *
167 * Move notation from x offset.
168 *
169 * Since: 3.0.0
170 */
171 param_spec = g_param_spec_uint("first-x",
172 i18n_pspec("move from x offset"),
173 i18n_pspec("Move the notation from x offset"),
174 0,
175 AGS_MOVE_NOTE_DEFAULT_X_LENGTH,
176 0,
177 G_PARAM_READABLE | G_PARAM_WRITABLE);
178 g_object_class_install_property(gobject,
179 PROP_FIRST_X,
180 param_spec);
181
182 /**
183 * AgsMoveNote:first-y:
184 *
185 * Move notation with x padding.
186 *
187 * Since: 3.0.0
188 */
189 param_spec = g_param_spec_uint("first-y",
190 i18n_pspec("move with x padding"),
191 i18n_pspec("Move the notation with x padding"),
192 0,
193 AGS_MOVE_NOTE_DEFAULT_X_LENGTH,
194 0,
195 G_PARAM_READABLE | G_PARAM_WRITABLE);
196 g_object_class_install_property(gobject,
197 PROP_FIRST_Y,
198 param_spec);
199
200 /**
201 * AgsMoveNote:move-x:
202 *
203 * Move notation by move-x amount.
204 *
205 * Since: 3.0.0
206 */
207 param_spec = g_param_spec_int("move-x",
208 i18n_pspec("move with move-x amount"),
209 i18n_pspec("Move the notation by move-x amount"),
210 -1 * AGS_MOVE_NOTE_DEFAULT_X_LENGTH,
211 AGS_MOVE_NOTE_DEFAULT_X_LENGTH,
212 0,
213 G_PARAM_READABLE | G_PARAM_WRITABLE);
214 g_object_class_install_property(gobject,
215 PROP_MOVE_X,
216 param_spec);
217
218 /**
219 * AgsMoveNote:move-y:
220 *
221 * Move notation by move-y amount.
222 *
223 * Since: 3.0.0
224 */
225 param_spec = g_param_spec_int("move-y",
226 i18n_pspec("move with move-y amount"),
227 i18n_pspec("Move the notation by move-y amount"),
228 -1 * AGS_MOVE_NOTE_DEFAULT_Y_LENGTH,
229 AGS_MOVE_NOTE_DEFAULT_Y_LENGTH,
230 0,
231 G_PARAM_READABLE | G_PARAM_WRITABLE);
232 g_object_class_install_property(gobject,
233 PROP_MOVE_Y,
234 param_spec);
235
236 /**
237 * AgsMoveNote:relative:
238 *
239 * Move notation by relative position.
240 *
241 * Since: 3.0.0
242 */
243 param_spec = g_param_spec_boolean("relative",
244 i18n_pspec("move relative"),
245 i18n_pspec("Move the notation by relative position"),
246 FALSE,
247 G_PARAM_READABLE | G_PARAM_WRITABLE);
248 g_object_class_install_property(gobject,
249 PROP_RELATIVE,
250 param_spec);
251
252 /**
253 * AgsMoveNote:absolute:
254 *
255 * Move notation by absolute position.
256 *
257 * Since: 3.0.0
258 */
259 param_spec = g_param_spec_boolean("absolute",
260 i18n_pspec("move absolute"),
261 i18n_pspec("Move the notation by absolute position"),
262 FALSE,
263 G_PARAM_READABLE | G_PARAM_WRITABLE);
264 g_object_class_install_property(gobject,
265 PROP_ABSOLUTE,
266 param_spec);
267
268 /* task */
269 task = (AgsTaskClass *) move_note;
270
271 task->launch = ags_move_note_launch;
272 }
273
274 void
ags_move_note_init(AgsMoveNote * move_note)275 ags_move_note_init(AgsMoveNote *move_note)
276 {
277 move_note->audio = NULL;
278 move_note->notation = NULL;
279
280 move_note->selection = NULL;
281
282 move_note->first_x = 0;
283 move_note->first_y = 0;
284 move_note->move_x = 0;
285 move_note->move_y = 0;
286
287 move_note->relative = FALSE;
288 move_note->absolute = FALSE;
289 }
290
291 void
ags_move_note_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)292 ags_move_note_set_property(GObject *gobject,
293 guint prop_id,
294 const GValue *value,
295 GParamSpec *param_spec)
296 {
297 AgsMoveNote *move_note;
298
299 move_note = AGS_MOVE_NOTE(gobject);
300
301 switch(prop_id){
302 case PROP_AUDIO:
303 {
304 AgsAudio *audio;
305
306 audio = (AgsAudio *) g_value_get_object(value);
307
308 if(move_note->audio == audio){
309 return;
310 }
311
312 if(move_note->audio != NULL){
313 g_object_unref(move_note->audio);
314 }
315
316 if(audio != NULL){
317 g_object_ref(audio);
318 }
319
320 move_note->audio = audio;
321 }
322 break;
323 case PROP_NOTATION:
324 {
325 AgsNotation *notation;
326
327 notation = (AgsNotation *) g_value_get_object(value);
328
329 if(move_note->notation == notation){
330 return;
331 }
332
333 if(move_note->notation != NULL){
334 g_object_unref(move_note->notation);
335 }
336
337 if(notation != NULL){
338 g_object_ref(notation);
339 }
340
341 move_note->notation = notation;
342 }
343 break;
344 case PROP_SELECTION:
345 {
346 AgsNote *note;
347
348 note = (AgsNote *) g_value_get_pointer(value);
349
350 if(note == NULL ||
351 g_list_find(move_note->selection, note) != NULL){
352 return;
353 }
354
355 g_object_ref(note);
356 move_note->selection = g_list_prepend(move_note->selection,
357 note);
358 }
359 break;
360 case PROP_FIRST_X:
361 {
362 move_note->first_x = g_value_get_uint(value);
363 }
364 break;
365 case PROP_FIRST_Y:
366 {
367 move_note->first_y = g_value_get_uint(value);
368 }
369 break;
370 case PROP_MOVE_X:
371 {
372 move_note->move_x = g_value_get_int(value);
373 }
374 break;
375 case PROP_MOVE_Y:
376 {
377 move_note->move_y = g_value_get_int(value);
378 }
379 break;
380 case PROP_RELATIVE:
381 {
382 move_note->relative = g_value_get_boolean(value);
383 }
384 break;
385 case PROP_ABSOLUTE:
386 {
387 move_note->absolute = g_value_get_boolean(value);
388 }
389 break;
390 default:
391 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
392 break;
393 }
394 }
395
396 void
ags_move_note_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)397 ags_move_note_get_property(GObject *gobject,
398 guint prop_id,
399 GValue *value,
400 GParamSpec *param_spec)
401 {
402 AgsMoveNote *move_note;
403
404 move_note = AGS_MOVE_NOTE(gobject);
405
406 switch(prop_id){
407 case PROP_AUDIO:
408 {
409 g_value_set_object(value, move_note->audio);
410 }
411 break;
412 case PROP_NOTATION:
413 {
414 g_value_set_object(value, move_note->notation);
415 }
416 break;
417 case PROP_SELECTION:
418 {
419 g_value_set_pointer(value,
420 g_list_copy_deep(move_note->selection,
421 (GCopyFunc) g_object_ref,
422 NULL));
423 }
424 break;
425 case PROP_FIRST_X:
426 {
427 g_value_set_int(value, move_note->first_x);
428 }
429 break;
430 case PROP_FIRST_Y:
431 {
432 g_value_set_uint(value, move_note->first_y);
433 }
434 break;
435 case PROP_MOVE_X:
436 {
437 g_value_set_uint(value, move_note->move_x);
438 }
439 break;
440 case PROP_MOVE_Y:
441 {
442 g_value_set_uint(value, move_note->move_y);
443 }
444 break;
445 case PROP_RELATIVE:
446 {
447 g_value_set_boolean(value, move_note->relative);
448 }
449 break;
450 case PROP_ABSOLUTE:
451 {
452 g_value_set_boolean(value, move_note->absolute);
453 }
454 break;
455 default:
456 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
457 break;
458 }
459 }
460
461 void
ags_move_note_dispose(GObject * gobject)462 ags_move_note_dispose(GObject *gobject)
463 {
464 AgsMoveNote *move_note;
465
466 move_note = AGS_MOVE_NOTE(gobject);
467
468 if(move_note->audio != NULL){
469 g_object_unref(move_note->audio);
470
471 move_note->audio = NULL;
472 }
473
474 if(move_note->notation != NULL){
475 g_object_unref(move_note->notation);
476
477 move_note->notation = NULL;
478 }
479
480 if(move_note->selection != NULL){
481 g_list_free(move_note->selection);
482
483 move_note->selection = NULL;
484 }
485
486 /* call parent */
487 G_OBJECT_CLASS(ags_move_note_parent_class)->dispose(gobject);
488 }
489
490 void
ags_move_note_finalize(GObject * gobject)491 ags_move_note_finalize(GObject *gobject)
492 {
493 AgsMoveNote *move_note;
494
495 move_note = AGS_MOVE_NOTE(gobject);
496
497 if(move_note->audio != NULL){
498 g_object_unref(move_note->audio);
499 }
500
501 if(move_note->notation != NULL){
502 g_object_unref(move_note->notation);
503 }
504
505 if(move_note->selection != NULL){
506 g_list_free(move_note->selection);
507 }
508
509 /* call parent */
510 G_OBJECT_CLASS(ags_move_note_parent_class)->finalize(gobject);
511 }
512
513 void
ags_move_note_launch(AgsTask * task)514 ags_move_note_launch(AgsTask *task)
515 {
516 AgsAudio *audio;
517 AgsNotation *notation, *current_notation;
518 AgsNote *note;
519
520 AgsMoveNote *move_note;
521
522 GList *selection;
523
524 guint audio_channel;
525 guint first_x;
526 guint first_y;
527 gint move_x;
528 gint move_y;
529
530 gboolean relative;
531 gboolean absolute;
532
533 move_note = AGS_MOVE_NOTE(task);
534
535 g_return_if_fail(AGS_IS_AUDIO(move_note->audio));
536 g_return_if_fail(AGS_IS_NOTATION(move_note->notation));
537
538 g_object_get(move_note,
539 "audio", &audio,
540 NULL);
541
542 /* get some properties */
543 notation =
544 current_notation = move_note->notation;
545
546 g_object_get(notation,
547 "audio-channel", &audio_channel,
548 NULL);
549
550 selection = move_note->selection;
551
552 first_x = move_note->first_x;
553 first_y = move_note->first_y;
554
555 move_x = move_note->move_x;
556 move_y = move_note->move_y;
557
558 relative = move_note->relative;
559 absolute = move_note->absolute;
560
561 /* move */
562 while(selection != NULL){
563 note = ags_note_duplicate(AGS_NOTE(selection->data));
564
565 if(relative){
566 note->x[0] = note->x[0] + move_x;
567 note->x[1] = note->x[1] + move_x;
568
569 note->y = note->y + move_y;
570 }else if(absolute){
571 note->x[0] = move_x + (note->x[0] - first_x);
572 note->x[1] = move_x + (note->x[1] - first_x);
573
574 note->y = move_y + (note->y + first_y);
575 }
576
577 if(note->x[0] >= ags_timestamp_get_ags_offset(current_notation->timestamp) + AGS_NOTATION_DEFAULT_OFFSET){
578 AgsTimestamp *timestamp;
579
580 GList *list_start, *list;
581
582 g_object_get(audio,
583 "notation", &list_start,
584 NULL);
585
586 timestamp = ags_timestamp_new();
587 timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
588 timestamp->flags |= AGS_TIMESTAMP_OFFSET;
589
590 timestamp->timer.ags_offset.offset = (guint64) (AGS_NOTATION_DEFAULT_OFFSET * floor(note->x[0] / AGS_NOTATION_DEFAULT_OFFSET));
591
592 if((list = ags_notation_find_near_timestamp(list_start, audio_channel,
593 timestamp)) == NULL){
594 current_notation = ags_notation_new((GObject *) audio,
595 audio_channel);
596
597 current_notation->timestamp->timer.ags_offset.offset = ags_timestamp_get_ags_offset(timestamp);
598 ags_audio_add_notation(audio,
599 (GObject *) current_notation);
600 }else{
601 current_notation = list->data;
602 }
603
604 g_list_free_full(list_start,
605 g_object_unref);
606 g_object_unref(timestamp);
607 }
608
609 /* remove old note */
610 ags_notation_remove_note(notation,
611 selection->data,
612 TRUE);
613 ags_notation_remove_note(notation,
614 selection->data,
615 FALSE);
616
617 /* add new note */
618 ags_notation_add_note(current_notation,
619 note,
620 FALSE);
621
622 selection = selection->next;
623 }
624
625 g_object_unref(audio);
626 }
627
628 /**
629 * ags_move_note_set_selection:
630 * @move_note: the #AgsMoveNote
631 * @selection: (element-type AgsAudio.Note) (transfer none): the selection as #GList-struct
632 *
633 * Set @selection of @move_note.
634 *
635 * Since: 3.2.3
636 */
637 void
ags_move_note_set_selection(AgsMoveNote * move_note,GList * selection)638 ags_move_note_set_selection(AgsMoveNote *move_note,
639 GList *selection)
640 {
641 if(!AGS_IS_MOVE_NOTE(move_note) ||
642 move_note->selection == selection){
643 return;
644 }
645
646 if(move_note->selection != NULL){
647 g_list_free_full(move_note->selection,
648 (GDestroyNotify) g_object_unref);
649 }
650
651 move_note->selection = g_list_copy_deep(selection,
652 (GCopyFunc) g_object_ref,
653 NULL);
654 }
655
656 /**
657 * ags_move_note_new:
658 * @audio: the #AgsAudio
659 * @notation: the #AgsNotation
660 * @selection: (element-type AgsAudio.Note) (transfer none): the selection as #GList-struct
661 * @first_x: the x offset to move from
662 * @first_y: the x padding to use
663 * @move_x: the amout to move in x direction
664 * @move_y: the amout to move in y direction
665 * @relative: if %TRUE move relative position
666 * @absolute: if %TRUE move absolute position
667 *
668 * Create a new instance of #AgsMoveNote task. Note either @relative or @absolute shall
669 * be %TRUE else it won't have any effect.
670 *
671 * Returns: a new #AgsMoveNote
672 *
673 * Since: 3.0.0
674 */
675 AgsMoveNote*
ags_move_note_new(AgsAudio * audio,AgsNotation * notation,GList * selection,guint first_x,guint first_y,gint move_x,gint move_y,gboolean relative,gboolean absolute)676 ags_move_note_new(AgsAudio *audio,
677 AgsNotation *notation,
678 GList *selection,
679 guint first_x, guint first_y,
680 gint move_x, gint move_y,
681 gboolean relative, gboolean absolute)
682 {
683 AgsMoveNote *move_note;
684
685 move_note = (AgsMoveNote *) g_object_new(AGS_TYPE_MOVE_NOTE,
686 "audio", audio,
687 "notation", notation,
688 "first-x", first_x,
689 "first-y", first_y,
690 "move-x", move_x,
691 "move-y", move_y,
692 "relative", relative,
693 "absolute", absolute,
694 NULL);
695
696 ags_move_note_set_selection(move_note,
697 selection);
698
699 return(move_note);
700 }
701