1 /*
2 * Copyright (C) 2019-2021 Alexandros Theodotou <alex at zrythm dot org>
3 *
4 * This file is part of Zrythm
5 *
6 * Zrythm is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero 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 * Zrythm 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 Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <limits.h>
21
22 #include "audio/chord_track.h"
23 #include "audio/engine.h"
24 #include "audio/marker_track.h"
25 #include "audio/position.h"
26 #include "audio/track.h"
27 #include "audio/transport.h"
28 #include "gui/backend/event.h"
29 #include "gui/backend/event_manager.h"
30 #include "gui/backend/timeline_selections.h"
31 #include "gui/widgets/midi_region.h"
32 #include "project.h"
33 #include "utils/arrays.h"
34 #include "utils/audio.h"
35 #include "utils/flags.h"
36 #include "utils/objects.h"
37 #include "utils/yaml.h"
38 #include "zrythm_app.h"
39
40 #include <gtk/gtk.h>
41
42 /**
43 * Creates a new TimelineSelections instance for
44 * the given range.
45 *
46 * @bool clone_objs True to clone each object,
47 * false to use pointers to project objects.
48 */
49 TimelineSelections *
timeline_selections_new_for_range(Position * start_pos,Position * end_pos,bool clone_objs)50 timeline_selections_new_for_range (
51 Position * start_pos,
52 Position * end_pos,
53 bool clone_objs)
54 {
55 TimelineSelections * self =
56 (TimelineSelections *)
57 arranger_selections_new (
58 ARRANGER_SELECTIONS_TYPE_TIMELINE);
59
60 #define ADD_OBJ(obj) \
61 if (arranger_object_is_hit ( \
62 (ArrangerObject *) (obj), \
63 start_pos, end_pos)) \
64 { \
65 ArrangerObject * _obj = \
66 (ArrangerObject *) (obj); \
67 if (clone_objs) \
68 { \
69 _obj = \
70 arranger_object_clone (_obj); \
71 } \
72 arranger_selections_add_object ( \
73 (ArrangerSelections *) self, _obj); \
74 }
75
76 /* regions */
77 for (int i = 0; i < TRACKLIST->num_tracks; i++)
78 {
79 Track * track = TRACKLIST->tracks[i];
80 AutomationTracklist * atl =
81 track_get_automation_tracklist (track);
82 for (int j = 0; j < track->num_lanes; j++)
83 {
84 TrackLane * lane = track->lanes[j];
85 for (int k = 0; k < lane->num_regions; k++)
86 {
87 ADD_OBJ (lane->regions[k]);
88 }
89 }
90 for (int j = 0; j < track->num_chord_regions;
91 j++)
92 {
93 ADD_OBJ (track->chord_regions[j]);
94 }
95 if (atl)
96 {
97 for (int j = 0; j < atl->num_ats; j++)
98 {
99 AutomationTrack * at = atl->ats[j];
100
101 for (int k = 0; k < at->num_regions;
102 k++)
103 {
104 ADD_OBJ (at->regions[k]);
105 }
106 }
107 }
108 for (int j = 0; j < track->num_scales; j++)
109 {
110 ADD_OBJ (track->scales[j]);
111 }
112 for (int j = 0; j < track->num_markers; j++)
113 {
114 ADD_OBJ (track->markers[j]);
115 }
116 }
117
118 #undef ADD_OBJ
119
120 return self;
121 }
122
123 /**
124 * Gets highest track in the selections.
125 */
126 Track *
timeline_selections_get_last_track(TimelineSelections * ts)127 timeline_selections_get_last_track (
128 TimelineSelections * ts)
129 {
130 int track_pos = -1;
131 Track * track = NULL;
132 int tmp_pos;
133 Track * tmp_track;
134
135 #define CHECK_POS(_track) \
136 tmp_track = _track; \
137 tmp_pos = \
138 tracklist_get_track_pos ( \
139 TRACKLIST, tmp_track); \
140 if (tmp_pos > track_pos) \
141 { \
142 track_pos = tmp_pos; \
143 track = tmp_track; \
144 }
145
146 ZRegion * region;
147 for (int i = 0; i < ts->num_regions; i++)
148 {
149 region = ts->regions[i];
150 ArrangerObject * r_obj =
151 (ArrangerObject *) region;
152 Track * _track =
153 arranger_object_get_track (r_obj);
154 CHECK_POS (_track);
155 }
156 CHECK_POS (P_CHORD_TRACK);
157
158 return track;
159 #undef CHECK_POS
160 }
161
162 /**
163 * Gets lowest track in the selections.
164 */
165 Track *
timeline_selections_get_first_track(TimelineSelections * ts)166 timeline_selections_get_first_track (
167 TimelineSelections * ts)
168 {
169 int track_pos = INT_MAX;
170 Track * track = NULL;
171 int tmp_pos;
172 Track * tmp_track;
173
174 #define CHECK_POS(_track) \
175 tmp_track = _track; \
176 tmp_pos = \
177 tracklist_get_track_pos ( \
178 TRACKLIST, tmp_track); \
179 if (tmp_pos < track_pos) \
180 { \
181 track_pos = tmp_pos; \
182 track = tmp_track; \
183 }
184
185 ZRegion * region;
186 for (int i = 0; i < ts->num_regions; i++)
187 {
188 region = ts->regions[i];
189 ArrangerObject * r_obj =
190 (ArrangerObject *) region;
191 Track * _track =
192 arranger_object_get_track (r_obj);
193 CHECK_POS (_track);
194 }
195 if (ts->num_scale_objects > 0)
196 {
197 CHECK_POS (P_CHORD_TRACK);
198 }
199 if (ts->num_markers > 0)
200 {
201 CHECK_POS (P_MARKER_TRACK);
202 }
203
204 return track;
205 #undef CHECK_POS
206 }
207
208 /**
209 * Gets index of the lowest track in the selections.
210 *
211 * Used during pasting.
212 */
213 static int
get_lowest_track_pos(TimelineSelections * ts)214 get_lowest_track_pos (
215 TimelineSelections * ts)
216 {
217 int track_pos = INT_MAX;
218
219 #define CHECK_POS(id) \
220 { \
221 }
222
223 for (int i = 0; i < ts->num_regions; i++)
224 {
225 ZRegion * r = ts->regions[i];
226 Track * tr =
227 tracklist_find_track_by_name_hash (
228 TRACKLIST, r->id.track_name_hash);
229 if (tr->pos < track_pos)
230 {
231 track_pos = tr->pos;
232 }
233 }
234
235 if (ts->num_scale_objects > 0)
236 {
237 if (ts->chord_track_vis_index < track_pos)
238 track_pos = ts->chord_track_vis_index;
239 }
240 if (ts->num_markers > 0)
241 {
242 if (ts->marker_track_vis_index < track_pos)
243 track_pos = ts->marker_track_vis_index;
244 }
245
246 return track_pos;
247 }
248
249 /**
250 * Replaces the track positions in each object with
251 * visible track indices starting from 0.
252 *
253 * Used during copying.
254 */
255 void
timeline_selections_set_vis_track_indices(TimelineSelections * ts)256 timeline_selections_set_vis_track_indices (
257 TimelineSelections * ts)
258 {
259 int i;
260 Track * highest_tr =
261 timeline_selections_get_first_track (ts);
262
263 for (i = 0; i < ts->num_regions; i++)
264 {
265 ZRegion * r = ts->regions[i];
266 Track * region_track =
267 arranger_object_get_track (
268 (ArrangerObject *) r);
269 ts->region_track_vis_index =
270 tracklist_get_visible_track_diff (
271 TRACKLIST, highest_tr, region_track);
272 }
273 if (ts->num_scale_objects > 0)
274 ts->chord_track_vis_index =
275 tracklist_get_visible_track_diff (
276 TRACKLIST, highest_tr, P_CHORD_TRACK);
277 if (ts->num_markers > 0)
278 ts->marker_track_vis_index =
279 tracklist_get_visible_track_diff (
280 TRACKLIST, highest_tr, P_MARKER_TRACK);
281 }
282
283 /**
284 * Saves the track positions in the poses array
285 * and the size in num_poses.
286 */
287 static void
get_track_poses(TimelineSelections * ts,int * poses,int * num_poses)288 get_track_poses (
289 TimelineSelections * ts,
290 int * poses,
291 int * num_poses)
292 {
293 int i;
294 for (i = 0; i < ts->num_regions; i++)
295 {
296 ZRegion * r = ts->regions[i];
297 Track * region_track =
298 arranger_object_get_track (
299 (ArrangerObject *) r);
300 if (!array_contains_int (
301 poses, *num_poses, region_track->pos))
302 {
303 array_append (
304 poses, *num_poses, region_track->pos);
305 }
306 }
307 if (ts->num_scale_objects > 0)
308 if (!array_contains_int (
309 poses, *num_poses,
310 ts->chord_track_vis_index))
311 {
312 array_append (
313 poses, *num_poses,
314 ts->chord_track_vis_index);
315 }
316 if (ts->num_markers > 0)
317 if (!array_contains_int (
318 poses, *num_poses,
319 ts->marker_track_vis_index))
320 {
321 array_append (
322 poses, *num_poses,
323 ts->marker_track_vis_index);
324 }
325 }
326
327 /**
328 * Returns if the selections can be pasted.
329 *
330 * @param pos Position to paste to.
331 * @param idx Track index to start pasting to.
332 */
333 int
timeline_selections_can_be_pasted(TimelineSelections * ts,Position * pos,const int idx)334 timeline_selections_can_be_pasted (
335 TimelineSelections * ts,
336 Position * pos,
337 const int idx)
338 {
339 int i, j;
340 ZRegion * r;
341 /*Marker * m;*/
342 /*ScaleObject * s;*/
343 int lowest_track_pos =
344 get_lowest_track_pos (ts);
345 Track * cur_track =
346 TRACKLIST_SELECTIONS->tracks[0];
347 int poses[800];
348 int num_poses = 0;
349 get_track_poses (ts, poses, &num_poses);
350 if (!cur_track || num_poses <= 0
351 || lowest_track_pos == INT_MAX)
352 return false;
353
354 /*check if enough visible tracks exist and the*/
355 /*content can be pasted in each*/
356 int ts_pos;
357 for (i = 0; i < num_poses; i++)
358 {
359 ts_pos = poses[i];
360 g_return_val_if_fail (ts_pos >= 0, 0);
361
362 /*[> track at the new position <]*/
363 Track * tr =
364 tracklist_get_visible_track_after_delta (
365 TRACKLIST, cur_track, ts_pos);
366 if (!tr)
367 {
368 g_message (
369 "no track at current pos (%d) + "
370 "ts pos (%d)",
371 cur_track->pos, ts_pos);
372 return false;
373 }
374
375 /* check if content matches */
376 for (j = 0; j < ts->num_regions; j++)
377 {
378 /* get region at this ts_pos */
379 r = ts->regions[j];
380 Track * region_track =
381 arranger_object_get_track (
382 (ArrangerObject *) r);
383 if (region_track->pos != ts_pos)
384 continue;
385
386 /*check if this track can host this*/
387 /*region*/
388 if (!track_type_can_host_region_type (
389 tr->type, r->id.type))
390 {
391 g_message (
392 "track %s cant host region type %d",
393 tr->name, r->id.type);
394 return false;
395 }
396 }
397
398 /* check for chord track/marker track too */
399 if (ts->num_scale_objects > 0 &&
400 ts_pos == ts->chord_track_vis_index &&
401 tr->type != TRACK_TYPE_CHORD)
402 return false;
403 if (ts->num_markers > 0 &&
404 ts_pos == ts->marker_track_vis_index &&
405 tr->type != TRACK_TYPE_MARKER)
406 return false;
407 }
408
409 return true;
410 }
411
412 #if 0
413 void
414 timeline_selections_paste_to_pos (
415 TimelineSelections * ts,
416 Position * pos)
417 {
418 Track * track =
419 TRACKLIST_SELECTIONS->tracks[0];
420
421 arranger_selections_clear (
422 (ArrangerSelections *) TL_SELECTIONS, F_NO_FREE);
423
424 double pos_ticks = position_to_ticks (pos);
425
426 /* get pos of earliest object */
427 Position start_pos;
428 arranger_selections_get_start_pos (
429 (ArrangerSelections *) ts, &start_pos,
430 F_GLOBAL);
431 double start_pos_ticks =
432 position_to_ticks (&start_pos);
433
434 double curr_ticks, diff;
435 int i;
436 for (i = 0; i < ts->num_regions; i++)
437 {
438 ZRegion * region = ts->regions[i];
439 ArrangerObject * r_obj =
440 (ArrangerObject *) region;
441 Track * region_track =
442 tracklist_get_visible_track_after_delta (
443 TRACKLIST, track, region->id.track_pos);
444 g_return_if_fail (region_track);
445
446 /* update positions */
447 curr_ticks =
448 position_to_ticks (&r_obj->pos);
449 diff = curr_ticks - start_pos_ticks;
450 position_from_ticks (
451 &r_obj->pos, pos_ticks + diff);
452 curr_ticks =
453 position_to_ticks (&r_obj->end_pos);
454 diff = curr_ticks - start_pos_ticks;
455 position_from_ticks (
456 &r_obj->end_pos, pos_ticks + diff);
457 /* TODO */
458
459 /* clone and add to track */
460 ZRegion * cp =
461 (ZRegion *)
462 arranger_object_clone (
463 r_obj,
464 ARRANGER_OBJECT_CLONE_COPY_MAIN);
465
466 switch (region->id.type)
467 {
468 case REGION_TYPE_MIDI:
469 case REGION_TYPE_AUDIO:
470 track_add_region (
471 region_track, cp, NULL,
472 region->id.lane_pos,
473 F_GEN_NAME, F_PUBLISH_EVENTS);
474 break;
475 case REGION_TYPE_AUTOMATION:
476 {
477 AutomationTrack * at =
478 region_track->automation_tracklist.
479 ats[region->id.at_idx];
480 g_return_if_fail (at);
481 track_add_region (
482 region_track, cp, at, -1,
483 F_GEN_NAME, F_PUBLISH_EVENTS);
484 }
485 break;
486 case REGION_TYPE_CHORD:
487 track_add_region (
488 region_track, cp, NULL, -1,
489 F_GEN_NAME, F_PUBLISH_EVENTS);
490 break;
491 }
492
493 /* select it */
494 arranger_object_select (
495 (ArrangerObject *) cp, F_SELECT,
496 F_APPEND);
497 }
498 for (i = 0; i < ts->num_scale_objects; i++)
499 {
500 ScaleObject * scale = ts->scale_objects[i];
501 ArrangerObject * s_obj =
502 (ArrangerObject *) scale;
503
504 curr_ticks =
505 position_to_ticks (&s_obj->pos);
506 diff = curr_ticks - start_pos_ticks;
507 position_from_ticks (
508 &s_obj->pos, pos_ticks + diff);
509
510 /* clone and add to track */
511 ScaleObject * clone =
512 (ScaleObject *)
513 arranger_object_clone (
514 s_obj,
515 ARRANGER_OBJECT_CLONE_COPY_MAIN);
516 chord_track_add_scale (
517 P_CHORD_TRACK, clone);
518
519 /* select it */
520 arranger_object_select (
521 (ArrangerObject *) clone, F_SELECT,
522 F_APPEND);
523 }
524 for (i = 0; i < ts->num_markers; i++)
525 {
526 Marker * m = ts->markers[i];
527 ArrangerObject * m_obj =
528 (ArrangerObject *) m;
529
530 curr_ticks =
531 position_to_ticks (&m_obj->pos);
532 diff = curr_ticks - start_pos_ticks;
533 position_from_ticks (
534 &m_obj->pos, pos_ticks + diff);
535
536 /* clone and add to track */
537 Marker * clone =
538 (Marker *)
539 arranger_object_clone (
540 m_obj,
541 ARRANGER_OBJECT_CLONE_COPY_MAIN);
542 marker_track_add_marker (
543 P_MARKER_TRACK, clone);
544
545 /* select it */
546 arranger_object_select (
547 (ArrangerObject *) clone, F_SELECT,
548 F_APPEND);
549 }
550 #undef DIFF
551 }
552 #endif
553
554 /**
555 * @param with_parents Also mark all the track's
556 * parents recursively.
557 */
558 void
timeline_selections_mark_for_bounce(TimelineSelections * ts,bool with_parents)559 timeline_selections_mark_for_bounce (
560 TimelineSelections * ts,
561 bool with_parents)
562 {
563 engine_reset_bounce_mode (AUDIO_ENGINE);
564
565 for (int i = 0; i < ts->num_regions; i++)
566 {
567 ZRegion * r = ts->regions[i];
568 Track * track =
569 arranger_object_get_track (
570 (ArrangerObject *) r);
571 g_return_if_fail (track);
572
573 track_mark_for_bounce (
574 track, F_BOUNCE, F_NO_MARK_REGIONS,
575 F_MARK_CHILDREN, with_parents);
576 r->bounce = 1;
577 }
578 }
579
580 /**
581 * Move the selected Regions to new Lanes.
582 *
583 * @param diff The delta to move the
584 * Tracks.
585 *
586 * @return True if moved.
587 */
588 bool
timeline_selections_move_regions_to_new_lanes(TimelineSelections * self,const int diff)589 timeline_selections_move_regions_to_new_lanes (
590 TimelineSelections * self,
591 const int diff)
592 {
593 arranger_selections_sort_by_indices (
594 (ArrangerSelections *) self, false);
595
596 /* store selected regions because they will be
597 * deselected during moving */
598 ZRegion * regions[600];
599 int num_regions = 0;
600 ZRegion * region;
601 for (int i = 0; i < self->num_regions; i++)
602 {
603 regions[num_regions++] =
604 self->regions[i];
605 }
606
607 /* check that:
608 * - all regions are in the same track
609 * - only lane regions are selected
610 * - the lane bounds are not exceeded */
611 bool compatible = true;
612 for (int i = 0; i < num_regions; i++)
613 {
614 region = regions[i];
615 if (region->id.lane_pos + diff < 0)
616 {
617 compatible = false;
618 break;
619 }
620 }
621 if (self->num_scale_objects > 0 ||
622 self->num_markers > 0)
623 {
624 compatible = false;
625 }
626 if (!compatible)
627 return false;
628
629 /* new positions are all compatible, move the
630 * regions */
631 for (int i = 0; i < num_regions; i++)
632 {
633 region = regions[i];
634 TrackLane * lane = region_get_lane (region);
635 g_return_val_if_fail (region && lane, -1);
636
637 TrackLane * lane_to_move_to = NULL;
638 int new_lane_pos =
639 lane->pos + diff;
640 g_return_val_if_fail (
641 new_lane_pos >= 0, -1);
642 Track * track = track_lane_get_track (lane);
643 track_create_missing_lanes (
644 track, new_lane_pos);
645 lane_to_move_to =
646 track->lanes[new_lane_pos];
647 g_warn_if_fail (lane_to_move_to);
648
649 region_move_to_lane (
650 region, lane_to_move_to, -1);
651 }
652
653 EVENTS_PUSH (
654 ET_TRACK_LANES_VISIBILITY_CHANGED, NULL);
655
656 return true;
657 }
658
659 /**
660 * Move the selected Regions to the new Track.
661 *
662 * @param new_track_is_before 1 if the Region's
663 * should move to their previous tracks, 0 for
664 * their next tracks.
665 *
666 * @return True if moved.
667 */
668 bool
timeline_selections_move_regions_to_new_tracks(TimelineSelections * self,const int vis_track_diff)669 timeline_selections_move_regions_to_new_tracks (
670 TimelineSelections * self,
671 const int vis_track_diff)
672 {
673 g_debug (
674 "moving %d regions to new tracks "
675 "(visible track diff %d)...",
676 self->num_regions, vis_track_diff);
677
678 arranger_selections_sort_by_indices (
679 (ArrangerSelections *) self, false);
680
681 /* store selected regions because they will be
682 * deselected during moving */
683 ZRegion * regions[600];
684 int num_regions = 0;
685 ZRegion * region;
686 ArrangerObject * r_obj;
687 for (int i = 0; i < self->num_regions; i++)
688 {
689 regions[num_regions++] =
690 self->regions[i];
691 }
692
693 /* check that all regions can be moved to a
694 * compatible track */
695 bool compatible = true;
696 for (int i = 0; i < num_regions; i++)
697 {
698 region = regions[i];
699 r_obj = (ArrangerObject *) region;
700 Track * region_track =
701 arranger_object_get_track (r_obj);
702 Track * visible =
703 tracklist_get_visible_track_after_delta (
704 TRACKLIST,
705 region_track,
706 vis_track_diff);
707 if (
708 !visible ||
709 !track_type_is_compatible_for_moving (
710 region_track->type,
711 visible->type) ||
712 /* do not allow moving automation tracks
713 * to other tracks for now */
714 region->id.type == REGION_TYPE_AUTOMATION)
715 {
716 compatible = false;
717 break;
718 }
719 }
720 if (!compatible)
721 {
722 return false;
723 }
724
725 /* new positions are all compatible, move the
726 * regions */
727 for (int i = 0; i < num_regions; i++)
728 {
729 region = regions[i];
730 r_obj = (ArrangerObject *) region;
731 Track * region_track =
732 arranger_object_get_track (r_obj);
733 g_warn_if_fail (region && region_track);
734 Track * track_to_move_to =
735 tracklist_get_visible_track_after_delta (
736 TRACKLIST,
737 region_track,
738 vis_track_diff);
739 g_warn_if_fail (track_to_move_to);
740
741 region_move_to_track (
742 region, track_to_move_to, -1);
743 }
744
745 g_debug ("moved");
746
747 return true;
748 }
749
750 /**
751 * Sets the regions'
752 * \ref ZRegion.index_in_prev_lane.
753 */
754 void
timeline_selections_set_index_in_prev_lane(TimelineSelections * self)755 timeline_selections_set_index_in_prev_lane (
756 TimelineSelections * self)
757 {
758 for (int i = 0; i < self->num_regions; i++)
759 {
760 ZRegion * r = self->regions[i];
761 ArrangerObject * r_obj = (ArrangerObject *) r;
762 r_obj->index_in_prev_lane = r->id.idx;
763 }
764 }
765
766 bool
timeline_selections_contains_only_regions(TimelineSelections * self)767 timeline_selections_contains_only_regions (
768 TimelineSelections * self)
769 {
770 return
771 self->num_regions > 0
772 && self->num_scale_objects == 0
773 && self->num_markers == 0 ;
774 }
775
776 bool
timeline_selections_contains_only_region_types(TimelineSelections * self,RegionType types)777 timeline_selections_contains_only_region_types (
778 TimelineSelections * self,
779 RegionType types)
780 {
781 if (!timeline_selections_contains_only_regions (self))
782 return false;
783
784 for (int i = 0; i < self->num_regions; i++)
785 {
786 ZRegion * r = self->regions[i];
787 if (!(types & r->id.type))
788 return false;
789 }
790 return true;
791 }
792