1 /*
2 * Copyright (C) 2018-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 Zrythm. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "audio/audio_region.h"
21 #include "audio/automation_region.h"
22 #include "audio/chord_region.h"
23 #include "audio/chord_track.h"
24 #include "audio/channel.h"
25 #include "audio/clip.h"
26 #include "audio/midi_note.h"
27 #include "audio/midi_region.h"
28 #include "audio/instrument_track.h"
29 #include "audio/pool.h"
30 #include "audio/recording_manager.h"
31 #include "audio/region.h"
32 #include "audio/region_link_group_manager.h"
33 #include "audio/router.h"
34 #include "audio/stretcher.h"
35 #include "audio/track.h"
36 #include "gui/widgets/automation_region.h"
37 #include "gui/widgets/bot_dock_edge.h"
38 #include "gui/widgets/center_dock.h"
39 #include "gui/widgets/chord_region.h"
40 #include "gui/widgets/clip_editor.h"
41 #include "gui/widgets/main_window.h"
42 #include "gui/widgets/midi_arranger.h"
43 #include "gui/widgets/midi_region.h"
44 #include "gui/widgets/region.h"
45 #include "gui/widgets/timeline_arranger.h"
46 #include "gui/widgets/timeline_panel.h"
47 #include "project.h"
48 #include "settings/settings.h"
49 #include "utils/arrays.h"
50 #include "utils/debug.h"
51 #include "utils/flags.h"
52 #include "utils/audio.h"
53 #include "utils/objects.h"
54 #include "utils/yaml.h"
55
56 #include <glib/gi18n.h>
57
58 #include <sndfile.h>
59 #include <samplerate.h>
60
61
62 /**
63 * Only to be used by implementing structs.
64 */
65 void
region_init(ZRegion * self,const Position * start_pos,const Position * end_pos,unsigned int track_name_hash,int lane_pos_or_at_idx,int idx_inside_lane_or_at)66 region_init (
67 ZRegion * self,
68 const Position * start_pos,
69 const Position * end_pos,
70 unsigned int track_name_hash,
71 int lane_pos_or_at_idx,
72 int idx_inside_lane_or_at)
73 {
74 self->schema_version = REGION_SCHEMA_VERSION;
75
76 ArrangerObject * obj =
77 (ArrangerObject *) self;
78 obj->type = ARRANGER_OBJECT_TYPE_REGION;
79 arranger_object_init (obj);
80
81 self->id.schema_version =
82 REGION_IDENTIFIER_SCHEMA_VERSION;
83 self->id.track_name_hash = track_name_hash;
84 self->id.lane_pos = lane_pos_or_at_idx;
85 self->id.at_idx = lane_pos_or_at_idx;
86 self->id.idx = idx_inside_lane_or_at;
87 self->id.link_group = -1;
88
89 position_init (&obj->pos);
90 position_set_to_pos (
91 &obj->pos, start_pos);
92 obj->pos.frames = start_pos->frames;
93 position_init (&obj->end_pos);
94 position_set_to_pos (
95 &obj->end_pos, end_pos);
96 obj->end_pos.frames = end_pos->frames;
97 position_init (&obj->clip_start_pos);
98 long length =
99 arranger_object_get_length_in_frames (obj);
100 g_warn_if_fail (length > 0);
101 position_init (&obj->loop_start_pos);
102 position_init (&obj->loop_end_pos);
103 position_from_frames (
104 &obj->loop_end_pos, length);
105 obj->loop_end_pos.frames = length;
106
107 /* set fade positions to start/end */
108 position_init (&obj->fade_in_pos);
109 position_init (&obj->fade_out_pos);
110 position_from_frames (
111 &obj->fade_out_pos, length);
112
113 self->magic = REGION_MAGIC;
114
115 region_validate (self, false);
116 }
117
118 /**
119 * Generates a name for the ZRegion, either using
120 * the given AutomationTrack or Track, or appending
121 * to the given base name.
122 */
123 void
region_gen_name(ZRegion * self,const char * base_name,AutomationTrack * at,Track * track)124 region_gen_name (
125 ZRegion * self,
126 const char * base_name,
127 AutomationTrack * at,
128 Track * track)
129 {
130 g_return_if_fail (IS_REGION (self));
131
132 /* Name to try to assign */
133 char * orig_name = NULL;
134 if (base_name)
135 orig_name =
136 g_strdup (base_name);
137 else if (at)
138 orig_name =
139 g_strdup_printf (
140 "%s - %s",
141 track->name, at->port_id.label);
142 else
143 orig_name = g_strdup (track->name);
144
145 arranger_object_set_name (
146 (ArrangerObject *) self, orig_name,
147 F_NO_PUBLISH_EVENTS);
148 g_free (orig_name);
149 }
150
151 /**
152 * Sets the track lane.
153 */
154 void
region_set_lane(ZRegion * self,const TrackLane * const lane)155 region_set_lane (
156 ZRegion * self,
157 const TrackLane * const lane)
158 {
159 g_return_if_fail (IS_REGION (self));
160 g_return_if_fail (
161 IS_TRACK_AND_NONNULL (lane->track));
162
163 if (track_lane_is_auditioner (lane))
164 self->base.is_auditioner = true;
165
166 self->id.lane_pos = lane->pos;
167 self->id.track_name_hash =
168 track_get_name_hash (lane->track);
169 }
170
171 /**
172 * Moves the ZRegion to the given Track, maintaining
173 * the selection status of the ZRegion and the
174 * TrackLane position.
175 *
176 * Assumes that the ZRegion is already in a
177 * TrackLane.
178 *
179 * @param index_in_lane Index in lane in the
180 * new track to insert the region to, or -1 to
181 * append.
182 */
183 void
region_move_to_track(ZRegion * region,Track * track,int index_in_lane)184 region_move_to_track (
185 ZRegion * region,
186 Track * track,
187 int index_in_lane)
188 {
189 g_return_if_fail (IS_REGION (region) && track);
190
191 g_message ("moving region %s to track %s",
192 region->name, track->name);
193 size_t sz = 2000;
194 char buf[sz];
195 region_print_to_str (region, buf, sz);
196 g_debug ("before: %s", buf);
197
198 RegionLinkGroup * link_group = NULL;
199 if (region_has_link_group (region))
200 {
201 link_group = region_get_link_group (region);
202 g_return_if_fail (link_group);
203 region_link_group_remove_region (
204 link_group, region, false, true);
205 }
206
207 Track * region_track =
208 arranger_object_get_track (
209 (ArrangerObject *) region);
210 g_return_if_fail (region_track);
211
212 if (region_track == track)
213 return;
214
215 int selected = region_is_selected (region);
216 int lane_pos = region->id.lane_pos;
217
218 /* create lanes if they don't exist */
219 track_create_missing_lanes (
220 track, lane_pos);
221
222 /* remove the region from its old track */
223 track_remove_region (
224 region_track,
225 region, F_NO_PUBLISH_EVENTS, F_NO_FREE);
226
227 /* add the region to its new track */
228 if (index_in_lane >= 0)
229 {
230 track_insert_region (
231 track, region, NULL, lane_pos,
232 index_in_lane,
233 F_NO_GEN_NAME, F_NO_PUBLISH_EVENTS);
234 }
235 else
236 {
237 track_add_region (
238 track, region, NULL, lane_pos,
239 F_NO_GEN_NAME, F_NO_PUBLISH_EVENTS);
240 }
241 g_warn_if_fail (region->id.lane_pos == lane_pos);
242 g_warn_if_fail (
243 track->lanes[lane_pos]->num_regions > 0 &&
244 track->lanes[lane_pos]->regions[
245 region->id.idx] == region);
246 region_set_lane (
247 region, track->lanes[lane_pos]);
248
249 /* reselect if necessary */
250 arranger_object_select (
251 (ArrangerObject *) region, selected,
252 F_APPEND, F_NO_PUBLISH_EVENTS);
253
254 /* remove empty lanes if the region was the
255 * last on its track lane */
256 track_remove_empty_last_lanes (
257 region_track);
258
259 if (link_group)
260 {
261 region_link_group_add_region (
262 link_group, region);
263 }
264
265 region_print_to_str (region, buf, sz);
266 g_debug ("after: %s", buf);
267
268 if (ZRYTHM_TESTING)
269 {
270 region_link_group_manager_validate (
271 REGION_LINK_GROUP_MANAGER);
272 }
273 }
274
275 /**
276 * Stretch the region's contents.
277 *
278 * This should be called right after changing the
279 * region's size.
280 *
281 * @param ratio The ratio to stretch by.
282 */
283 void
region_stretch(ZRegion * self,double ratio)284 region_stretch (
285 ZRegion * self,
286 double ratio)
287 {
288 g_return_if_fail (IS_REGION (self));
289
290 self->stretching = true;
291 ArrangerObject * obj = (ArrangerObject *) self;
292
293 switch (self->id.type)
294 {
295 case REGION_TYPE_MIDI:
296 for (int i = 0; i < self->num_midi_notes; i++)
297 {
298 MidiNote * mn =
299 self->midi_notes[i];
300 ArrangerObject * mn_obj =
301 (ArrangerObject *) mn;
302
303 /* set start pos */
304 double before_ticks = mn_obj->pos.ticks;
305 double new_ticks = before_ticks * ratio;
306 Position tmp;
307 position_from_ticks (
308 &tmp, new_ticks);
309 arranger_object_pos_setter (
310 mn_obj, &tmp);
311
312 /* set end pos */
313 before_ticks =
314 mn_obj->end_pos.ticks;
315 new_ticks = before_ticks * ratio;
316 position_from_ticks (
317 &tmp, new_ticks);
318 arranger_object_end_pos_setter (
319 mn_obj, &tmp);
320 }
321 break;
322 case REGION_TYPE_AUDIO:
323 {
324 g_return_if_fail (
325 router_is_processing_thread (ROUTER));
326 AudioClip * clip =
327 audio_region_get_clip (self);
328 int new_clip_id =
329 audio_pool_duplicate_clip (
330 AUDIO_POOL, clip->pool_id,
331 F_NO_WRITE_FILE);
332 AudioClip * new_clip =
333 audio_pool_get_clip (
334 AUDIO_POOL, new_clip_id);
335 audio_region_set_clip_id (
336 self, new_clip->pool_id);
337 Stretcher * stretcher =
338 stretcher_new_rubberband (
339 AUDIO_ENGINE->sample_rate,
340 new_clip->channels, ratio, 1.0, false);
341 ssize_t returned_frames =
342 stretcher_stretch_interleaved (
343 stretcher, new_clip->frames,
344 (size_t) new_clip->num_frames,
345 &new_clip->frames);
346 g_warn_if_fail (returned_frames > 0);
347 new_clip->num_frames = returned_frames;
348 audio_clip_write_to_pool (
349 new_clip, F_NO_PARTS, F_NOT_BACKUP);
350 (void) obj;
351 /* readjust end position to match the
352 * number of frames exactly */
353 Position new_end_pos;
354 position_from_frames (
355 &new_end_pos, returned_frames);
356 arranger_object_set_position (
357 obj, &new_end_pos,
358 ARRANGER_OBJECT_POSITION_TYPE_LOOP_END,
359 F_NO_VALIDATE);
360 position_add_frames (
361 &new_end_pos, obj->pos.frames);
362 arranger_object_set_position (
363 obj, &new_end_pos,
364 ARRANGER_OBJECT_POSITION_TYPE_END,
365 F_NO_VALIDATE);
366 stretcher_free (stretcher);
367 }
368 break;
369 default:
370 g_critical ("unimplemented");
371 break;
372 }
373
374 obj->use_cache = false;
375 self->stretching = false;
376 }
377
378 /**
379 * Moves the given ZRegion to the given TrackLane.
380 *
381 * Works with TrackLane's of other Track's as well.
382 *
383 * Maintains the selection status of the
384 * Region.
385 *
386 * Assumes that the ZRegion is already in a
387 * TrackLane.
388 *
389 * @param index_in_lane Index in lane in the
390 * new track to insert the region to, or -1 to
391 * append.
392 */
393 void
region_move_to_lane(ZRegion * region,TrackLane * lane,int index_in_lane)394 region_move_to_lane (
395 ZRegion * region,
396 TrackLane * lane,
397 int index_in_lane)
398 {
399 g_return_if_fail (IS_REGION (region) && lane);
400
401 Track * region_track =
402 arranger_object_get_track (
403 (ArrangerObject *) region);
404 g_return_if_fail (region_track);
405
406 int selected = region_is_selected (region);
407 int is_clip_editor_region =
408 region == clip_editor_get_region (CLIP_EDITOR);
409
410 Track * lane_track =
411 track_lane_get_track (lane);
412 track_remove_region (
413 region_track, region,
414 F_NO_PUBLISH_EVENTS, F_NO_FREE);
415 if (index_in_lane >= 0)
416 {
417 track_insert_region (
418 lane_track, region, NULL, lane->pos,
419 index_in_lane,
420 F_NO_GEN_NAME, F_NO_PUBLISH_EVENTS);
421 }
422 else
423 {
424 track_add_region (
425 lane_track, region, NULL, lane->pos,
426 F_NO_GEN_NAME, F_NO_PUBLISH_EVENTS);
427 }
428
429 /* reset the clip editor region because
430 * track_remove_region clears it */
431 if (is_clip_editor_region)
432 {
433 clip_editor_set_region (
434 CLIP_EDITOR, region, true);
435 }
436
437 arranger_object_select (
438 (ArrangerObject *) region, selected,
439 F_APPEND, F_NO_PUBLISH_EVENTS);
440 region_set_lane (region, lane);
441 g_warn_if_fail (
442 lane->pos == region->id.lane_pos);
443
444 track_create_missing_lanes (
445 region_track, lane->pos);
446 track_remove_empty_last_lanes (region_track);
447 }
448
449 /**
450 * Sets the automation track.
451 */
452 void
region_set_automation_track(ZRegion * self,AutomationTrack * at)453 region_set_automation_track (
454 ZRegion * self,
455 AutomationTrack * at)
456 {
457 g_return_if_fail (IS_REGION (self) && at);
458
459 g_debug (
460 "setting region automation track to %d %s",
461 at->index, at->port_id.label);
462
463 /* if clip editor region or region selected,
464 * unselect it */
465 if (region_identifier_is_equal (
466 &self->id, &CLIP_EDITOR->region_id))
467 {
468 clip_editor_set_region (
469 CLIP_EDITOR, NULL, true);
470 }
471 bool was_selected = false;
472 if (region_is_selected (self))
473 {
474 was_selected = true;
475 arranger_object_select (
476 (ArrangerObject *) self, F_NO_SELECT,
477 F_NO_APPEND, F_NO_PUBLISH_EVENTS);
478 }
479 self->id.at_idx = at->index;
480 Track * track =
481 automation_track_get_track (at);
482 self->id.track_name_hash =
483 track_get_name_hash (track);
484
485 region_update_identifier (self);
486
487 /* reselect it if was selected */
488 if (was_selected)
489 {
490 arranger_object_select (
491 (ArrangerObject *) self, F_SELECT,
492 F_APPEND, F_NO_PUBLISH_EVENTS);
493 }
494 }
495
496 void
region_get_type_as_string(RegionType type,char * buf)497 region_get_type_as_string (
498 RegionType type,
499 char * buf)
500 {
501 g_return_if_fail (
502 type >= 0 && type <= REGION_TYPE_CHORD);
503 switch (type)
504 {
505 case REGION_TYPE_MIDI:
506 strcpy (buf, _("MIDI"));
507 break;
508 case REGION_TYPE_AUDIO:
509 strcpy (buf, _("Audio"));
510 break;
511 case REGION_TYPE_AUTOMATION:
512 strcpy (buf, _("Automation"));
513 break;
514 case REGION_TYPE_CHORD:
515 strcpy (buf, _("Chord"));
516 break;
517 }
518 }
519
520 /**
521 * Sanity checking.
522 */
523 bool
region_validate(ZRegion * self,bool is_project)524 region_validate (
525 ZRegion * self,
526 bool is_project)
527 {
528 g_return_val_if_fail (IS_REGION (self), false);
529
530 if (!region_identifier_validate (&self->id))
531 {
532 return false;
533 }
534
535 if (is_project)
536 {
537 ZRegion * found = region_find (&self->id);
538 if (found != self)
539 {
540 return false;
541 }
542 }
543
544 ArrangerObject * r_obj = (ArrangerObject *) self;
545 g_return_val_if_fail (
546 position_is_before (
547 &r_obj->loop_start_pos, &r_obj->loop_end_pos),
548 false);
549
550 switch (self->id.type)
551 {
552 case REGION_TYPE_CHORD:
553 chord_region_validate (self);
554 break;
555 case REGION_TYPE_AUTOMATION:
556 automation_region_validate (self);
557 break;
558 case REGION_TYPE_AUDIO:
559 audio_region_validate (self);
560 break;
561 default:
562 break;
563 }
564
565 return true;
566 }
567
568 TrackLane *
region_get_lane(const ZRegion * self)569 region_get_lane (
570 const ZRegion * self)
571 {
572 g_return_val_if_fail (IS_REGION (self), NULL);
573
574 Track * track =
575 arranger_object_get_track (
576 (ArrangerObject *) self);
577 g_return_val_if_fail (IS_TRACK (track), NULL);
578 if (self->id.lane_pos < track->num_lanes)
579 {
580 TrackLane * lane =
581 track->lanes[self->id.lane_pos];
582 g_return_val_if_fail (lane, NULL);
583 return lane;
584 }
585
586 g_return_val_if_reached (NULL);
587 }
588
589 /**
590 * Returns the region's link group.
591 */
592 RegionLinkGroup *
region_get_link_group(ZRegion * self)593 region_get_link_group (
594 ZRegion * self)
595 {
596 g_return_val_if_fail (
597 self && self->id.link_group >= 0 &&
598 REGION_LINK_GROUP_MANAGER->num_groups >
599 self->id.link_group, NULL);
600 RegionLinkGroup * group =
601 region_link_group_manager_get_group (
602 REGION_LINK_GROUP_MANAGER,
603 self->id.link_group);
604 return group;
605 }
606
607 /**
608 * Sets the link group to the region.
609 *
610 * @param group_idx If -1, the region will be
611 * removed from its current link group, if any.
612 */
613 void
region_set_link_group(ZRegion * region,int group_idx,bool update_identifier)614 region_set_link_group (
615 ZRegion * region,
616 int group_idx,
617 bool update_identifier)
618 {
619 ArrangerObject * obj =
620 (ArrangerObject *) region;
621 if (obj->flags & ARRANGER_OBJECT_FLAG_NON_PROJECT)
622 {
623 region->id.link_group = group_idx;
624 return;
625 }
626
627 if (region->id.link_group >= 0 &&
628 region->id.link_group != group_idx)
629 {
630 RegionLinkGroup * link_group =
631 region_get_link_group (region);
632 g_return_if_fail (link_group);
633 region_link_group_remove_region (
634 link_group,
635 region, true, update_identifier);
636 }
637 if (group_idx >= 0)
638 {
639 RegionLinkGroup * group =
640 region_link_group_manager_get_group (
641 REGION_LINK_GROUP_MANAGER, group_idx);
642 g_return_if_fail (group);
643 region_link_group_add_region (
644 group, region);
645 }
646
647 g_return_if_fail (
648 group_idx == region->id.link_group);
649
650 if (update_identifier)
651 region_update_identifier (region);
652 }
653
654 void
region_create_link_group_if_none(ZRegion * region)655 region_create_link_group_if_none (
656 ZRegion * region)
657 {
658 ArrangerObject * obj =
659 (ArrangerObject *) region;
660 if (obj->flags & ARRANGER_OBJECT_FLAG_NON_PROJECT)
661 return;
662
663 if (region->id.link_group < 0)
664 {
665 size_t sz = 2000;
666 char buf[sz];
667 region_print_to_str (region, buf, sz);
668 g_debug (
669 "creating link group for region: %s", buf);
670 int new_group =
671 region_link_group_manager_add_group (
672 REGION_LINK_GROUP_MANAGER);
673 region_set_link_group (
674 region, new_group, true);
675
676 region_print_to_str (region, buf, sz);
677 g_debug (
678 "after link group (%d): %s",
679 new_group, buf);
680 }
681 }
682
683 bool
region_has_link_group(ZRegion * region)684 region_has_link_group (
685 ZRegion * region)
686 {
687 g_return_val_if_fail (IS_REGION (region), false);
688 return region->id.link_group >= 0;
689 }
690
691 /**
692 * Removes the link group from the region, if any.
693 */
694 void
region_unlink(ZRegion * region)695 region_unlink (
696 ZRegion * region)
697 {
698 ArrangerObject * obj =
699 (ArrangerObject *) region;
700 if (obj->flags & ARRANGER_OBJECT_FLAG_NON_PROJECT)
701 {
702 region->id.link_group = -1;
703 }
704 else if (region->id.link_group >= 0)
705 {
706 RegionLinkGroup * group =
707 region_link_group_manager_get_group (
708 REGION_LINK_GROUP_MANAGER,
709 region->id.link_group);
710 region_link_group_remove_region (
711 group, region, true, true);
712 }
713 else
714 {
715 g_warn_if_reached ();
716 }
717
718 g_warn_if_fail (region->id.link_group == -1);
719
720 region_update_identifier (region);
721 }
722
723 /**
724 * Looks for the ZRegion matching the identifier.
725 */
726 ZRegion *
region_find(const RegionIdentifier * const id)727 region_find (
728 const RegionIdentifier * const id)
729 {
730 Track * track = NULL;
731 TrackLane * lane = NULL;
732 AutomationTrack * at = NULL;
733 if (id->type == REGION_TYPE_MIDI ||
734 id->type == REGION_TYPE_AUDIO)
735 {
736 track =
737 tracklist_find_track_by_name_hash (
738 TRACKLIST, id->track_name_hash);
739 g_return_val_if_fail (track, NULL);
740
741 if (id->lane_pos >= track->num_lanes)
742 {
743 g_critical (
744 "%s: given lane pos %d is greater than "
745 "track '%s' (%d) number of lanes %d",
746 __func__,
747 id->lane_pos, track->name, track->pos,
748 track->num_lanes);
749 return NULL;
750 }
751 lane = track->lanes[id->lane_pos];
752 g_return_val_if_fail (lane, NULL);
753
754 z_return_val_if_fail_cmp (
755 id->idx, >=, 0, NULL);
756 z_return_val_if_fail_cmp (
757 id->idx, <, lane->num_regions, NULL);
758
759 ZRegion * region = lane->regions[id->idx];
760 g_return_val_if_fail (
761 IS_REGION (region), NULL);
762
763 return region;
764 }
765 else if (id->type == REGION_TYPE_AUTOMATION)
766 {
767 track =
768 tracklist_find_track_by_name_hash (
769 TRACKLIST, id->track_name_hash);
770 g_return_val_if_fail (track, NULL);
771
772 AutomationTracklist * atl =
773 &track->automation_tracklist;
774 g_return_val_if_fail (
775 id->at_idx < atl->num_ats, NULL);
776 at = atl->ats[id->at_idx];
777 g_return_val_if_fail (at, NULL);
778
779 if (id->idx >= at->num_regions)
780 {
781 automation_tracklist_print_regions (atl);
782 g_critical (
783 "Automation track for %s has no "
784 "regions", at->port_id.label);
785 return NULL;
786 }
787 ZRegion * region = at->regions[id->idx];
788 g_return_val_if_fail (
789 IS_REGION (region), NULL);
790
791 return region;
792 }
793 else if (id->type == REGION_TYPE_CHORD)
794 {
795 track = P_CHORD_TRACK;
796 g_return_val_if_fail (track, NULL);
797
798 if (id->idx >= track->num_chord_regions)
799 g_return_val_if_reached (NULL);
800 ZRegion * region =
801 track->chord_regions[id->idx];
802 g_return_val_if_fail (
803 IS_REGION (region), NULL);
804
805 return region;
806 }
807
808 g_return_val_if_reached (NULL);
809 }
810
811 /**
812 * To be called every time the identifier changes
813 * to update the region's children.
814 */
815 void
region_update_identifier(ZRegion * self)816 region_update_identifier (
817 ZRegion * self)
818 {
819 g_return_if_fail (IS_REGION (self));
820
821 /* reset link group */
822 region_set_link_group (
823 self, self->id.link_group, false);
824
825 switch (self->id.type)
826 {
827 case REGION_TYPE_AUDIO:
828 break;
829 case REGION_TYPE_MIDI:
830 for (int i = 0; i < self->num_midi_notes; i++)
831 {
832 MidiNote * mn = self->midi_notes[i];
833 midi_note_set_region_and_index (
834 mn, self, i);
835 }
836 break;
837 case REGION_TYPE_AUTOMATION:
838 for (int i = 0; i < self->num_aps; i++)
839 {
840 AutomationPoint * ap = self->aps[i];
841 automation_point_set_region_and_index (
842 ap, self, i);
843 }
844 break;
845 case REGION_TYPE_CHORD:
846 for (int i = 0; i < self->num_chord_objects;
847 i++)
848 {
849 ChordObject * co = self->chord_objects[i];
850 chord_object_set_region_and_index (
851 co, self, i);
852 }
853 break;
854 default:
855 break;
856 }
857 }
858
859 /**
860 * Updates all other regions in the region link
861 * group, if any.
862 */
863 void
region_update_link_group(ZRegion * self)864 region_update_link_group (
865 ZRegion * self)
866 {
867 g_message ("updating link group %d",
868 self->id.link_group);
869 if (self->id.link_group >= 0)
870 {
871 RegionLinkGroup * group =
872 region_link_group_manager_get_group (
873 REGION_LINK_GROUP_MANAGER,
874 self->id.link_group);
875 region_link_group_update (group, self);
876 }
877 }
878
879 /**
880 * Removes all children objects from the region.
881 */
882 void
region_remove_all_children(ZRegion * region)883 region_remove_all_children (
884 ZRegion * region)
885 {
886 g_message ("removing all children from %d %s",
887 region->id.idx, region->name);
888 switch (region->id.type)
889 {
890 case REGION_TYPE_MIDI:
891 {
892 g_message (
893 "%d midi notes", region->num_midi_notes);
894 for (int i = region->num_midi_notes - 1;
895 i >= 0; i--)
896 {
897 MidiNote * mn =
898 region->midi_notes[i];
899 midi_region_remove_midi_note (
900 region, mn, F_FREE,
901 F_NO_PUBLISH_EVENTS);
902 }
903 g_warn_if_fail (
904 region->num_midi_notes == 0);
905 }
906 break;
907 case REGION_TYPE_AUDIO:
908 break;
909 case REGION_TYPE_AUTOMATION:
910 {
911 for (int i = region->num_aps - 1;
912 i >= 0; i--)
913 {
914 AutomationPoint * ap = region->aps[i];
915 automation_region_remove_ap (
916 region, ap, false, F_FREE);
917 }
918 }
919 break;
920 case REGION_TYPE_CHORD:
921 {
922 for (int i = region->num_chord_objects - 1;
923 i >= 0; i--)
924 {
925 ChordObject * co =
926 region->chord_objects[i];
927 chord_region_remove_chord_object (
928 region, co, F_FREE,
929 F_NO_PUBLISH_EVENTS);
930 }
931 }
932 break;
933 }
934 }
935
936 /**
937 * Clones and copies all children from \ref src to
938 * \ref dest.
939 */
940 void
region_copy_children(ZRegion * dest,ZRegion * src)941 region_copy_children (
942 ZRegion * dest,
943 ZRegion * src)
944 {
945 g_return_if_fail (dest->id.type == src->id.type);
946
947 g_message (
948 "copying children from %d %s to %d %s",
949 src->id.idx, src->name,
950 dest->id.idx, dest->name);
951
952 switch (src->id.type)
953 {
954 case REGION_TYPE_MIDI:
955 {
956 g_warn_if_fail (dest->num_midi_notes == 0);
957 g_message (
958 "%d midi notes", src->num_midi_notes);
959 for (int i = 0;
960 i < src->num_midi_notes; i++)
961 {
962 MidiNote * orig_mn =
963 src->midi_notes[i];
964 ArrangerObject * orig_mn_obj =
965 (ArrangerObject *) orig_mn;
966
967 MidiNote * mn =
968 (MidiNote *)
969 arranger_object_clone (
970 orig_mn_obj);
971
972 midi_region_add_midi_note (
973 dest, mn, F_NO_PUBLISH_EVENTS);
974 }
975 }
976 break;
977 case REGION_TYPE_AUDIO:
978 break;
979 case REGION_TYPE_AUTOMATION:
980 {
981 /* add automation points */
982 AutomationPoint * src_ap, * dest_ap;
983 for (int j = 0; j < src->num_aps; j++)
984 {
985 src_ap = src->aps[j];
986 ArrangerObject * src_ap_obj =
987 (ArrangerObject *) src_ap;
988
989 dest_ap =
990 automation_point_new_float (
991 src_ap->fvalue,
992 src_ap->normalized_val,
993 &src_ap_obj->pos);
994 automation_region_add_ap (
995 dest, dest_ap, F_NO_PUBLISH_EVENTS);
996 }
997 }
998 break;
999 case REGION_TYPE_CHORD:
1000 {
1001 ChordObject * src_co, * dest_co;
1002 for (int i = 0;
1003 i < src->num_chord_objects; i++)
1004 {
1005 src_co = src->chord_objects[i];
1006
1007 dest_co =
1008 (ChordObject *)
1009 arranger_object_clone (
1010 (ArrangerObject *) src_co);
1011
1012 chord_region_add_chord_object (
1013 dest, dest_co, F_NO_PUBLISH_EVENTS);
1014 }
1015 }
1016 break;
1017 }
1018 }
1019
1020 /**
1021 * Returns the MidiNote matching the properties of
1022 * the given MidiNote.
1023 *
1024 * Used to find the actual MidiNote in the region
1025 * from a cloned MidiNote (e.g. when doing/undoing).
1026 */
1027 MidiNote *
region_find_midi_note(ZRegion * r,MidiNote * clone)1028 region_find_midi_note (
1029 ZRegion * r,
1030 MidiNote * clone)
1031 {
1032 MidiNote * mn;
1033 for (int i = 0; i < r->num_midi_notes; i++)
1034 {
1035 mn = r->midi_notes[i];
1036
1037 if (midi_note_is_equal (
1038 clone, mn))
1039 return mn;
1040 }
1041
1042 return NULL;
1043 }
1044
1045 /**
1046 * Gets the AutomationTrack using the saved index.
1047 */
1048 AutomationTrack *
region_get_automation_track(const ZRegion * const region)1049 region_get_automation_track (
1050 const ZRegion * const region)
1051 {
1052 Track * track =
1053 arranger_object_get_track (
1054 (const ArrangerObject * const) region);
1055 g_return_val_if_fail (
1056 IS_TRACK (track) &&
1057 track->automation_tracklist.num_ats >
1058 region->id.at_idx, NULL);
1059
1060 return
1061 track->automation_tracklist.ats[
1062 region->id.at_idx];
1063 }
1064
1065 void
region_print_to_str(const ZRegion * self,char * buf,const size_t buf_size)1066 region_print_to_str (
1067 const ZRegion * self,
1068 char * buf,
1069 const size_t buf_size)
1070 {
1071 char from_pos_str[100], to_pos_str[100],
1072 loop_end_pos_str[100];
1073 position_to_string (
1074 &self->base.pos, from_pos_str);
1075 position_to_string (
1076 &self->base.end_pos, to_pos_str);
1077 position_to_string (
1078 &self->base.loop_end_pos, loop_end_pos_str);
1079 snprintf (
1080 buf, buf_size,
1081 "%s [%s] - track name hash %u - lane pos %d - "
1082 "idx %d - address %p - <%s> to <%s> - "
1083 "loop end <%s> - link group %d",
1084 self->name,
1085 region_identifier_get_region_type_name (
1086 self->id.type),
1087 self->id.track_name_hash,
1088 self->id.lane_pos,
1089 self->id.idx, self,
1090 from_pos_str, to_pos_str,
1091 loop_end_pos_str,
1092 self->id.link_group);
1093 }
1094
1095 /**
1096 * Print region info for debugging.
1097 */
1098 void
region_print(const ZRegion * self)1099 region_print (
1100 const ZRegion * self)
1101 {
1102 size_t sz = 2000;
1103 char buf[sz];
1104 region_print_to_str (self, buf, sz);
1105 g_message ("%s", buf);
1106 }
1107
1108 /**
1109 * Returns the region at the given position in the
1110 * given Track.
1111 *
1112 * @param at The automation track to look in.
1113 * @param track The track to look in, if at is
1114 * NULL.
1115 * @param pos The position.
1116 */
1117 ZRegion *
region_at_position(Track * track,AutomationTrack * at,Position * pos)1118 region_at_position (
1119 Track * track,
1120 AutomationTrack * at,
1121 Position * pos)
1122 {
1123 ZRegion * region;
1124 if (track)
1125 {
1126 TrackLane * lane;
1127 for (int i = 0; i < track->num_lanes; i++)
1128 {
1129 lane = track->lanes[i];
1130 for (int j = 0; j < lane->num_regions; j++)
1131 {
1132 region = lane->regions[j];
1133 ArrangerObject * r_obj =
1134 (ArrangerObject *) region;
1135 if (position_is_after_or_equal (
1136 pos, &r_obj->pos) &&
1137 position_is_before_or_equal (
1138 pos, &r_obj->end_pos))
1139 {
1140 return region;
1141 }
1142 }
1143 }
1144 }
1145 else if (at)
1146 {
1147 for (int i = 0; i < at->num_regions; i++)
1148 {
1149 region = at->regions[i];
1150 ArrangerObject * r_obj =
1151 (ArrangerObject *) region;
1152 if (position_is_after_or_equal (
1153 pos, &r_obj->pos) &&
1154 position_is_before_or_equal (
1155 pos, &r_obj->end_pos))
1156 {
1157 return region;
1158 }
1159 }
1160 }
1161 return NULL;
1162 }
1163
1164 /**
1165 * Returns if the position is inside the region
1166 * or not.
1167 *
1168 * @param gframes Global position in frames.
1169 * @param inclusive Whether the last frame should
1170 * be counted as part of the region.
1171 */
1172 int
region_is_hit(const ZRegion * region,const long gframes,const int inclusive)1173 region_is_hit (
1174 const ZRegion * region,
1175 const long gframes,
1176 const int inclusive)
1177 {
1178 const ArrangerObject * r_obj =
1179 (const ArrangerObject *) region;
1180 return
1181 r_obj->pos.frames <= gframes &&
1182 ((inclusive &&
1183 r_obj->end_pos.frames >=
1184 gframes) ||
1185 (!inclusive &&
1186 r_obj->end_pos.frames >
1187 gframes));
1188 }
1189
1190 /**
1191 * Returns the ArrangerSelections based on the
1192 * given region type.
1193 */
1194 ArrangerSelections *
region_get_arranger_selections(ZRegion * self)1195 region_get_arranger_selections (
1196 ZRegion * self)
1197 {
1198 ArrangerSelections * sel = NULL;
1199 switch (self->id.type)
1200 {
1201 case REGION_TYPE_MIDI:
1202 sel =
1203 (ArrangerSelections *) MA_SELECTIONS;
1204 break;
1205 case REGION_TYPE_AUTOMATION:
1206 sel =
1207 (ArrangerSelections *)
1208 AUTOMATION_SELECTIONS;
1209 break;
1210 case REGION_TYPE_CHORD:
1211 sel =
1212 (ArrangerSelections *)
1213 CHORD_SELECTIONS;
1214 break;
1215 case REGION_TYPE_AUDIO:
1216 sel =
1217 (ArrangerSelections *)
1218 AUDIO_SELECTIONS;
1219 break;
1220 default:
1221 break;
1222 }
1223
1224 return sel;
1225 }
1226
1227 /**
1228 * Returns whether the region is effectively in
1229 * musical mode.
1230 *
1231 * @note Only applicable to audio regions.
1232 */
1233 bool
region_get_musical_mode(ZRegion * self)1234 region_get_musical_mode (
1235 ZRegion * self)
1236 {
1237 /* off for v1 */
1238 return false;
1239
1240 switch (self->musical_mode)
1241 {
1242 case REGION_MUSICAL_MODE_INHERIT:
1243 return
1244 g_settings_get_boolean (
1245 S_UI, "musical-mode");
1246 case REGION_MUSICAL_MODE_OFF:
1247 return false;
1248 case REGION_MUSICAL_MODE_ON:
1249 return true;
1250 }
1251 g_return_val_if_reached (false);
1252 }
1253
1254 /**
1255 * Returns if any part of the ZRegion is inside the
1256 * given range, inclusive.
1257 */
1258 int
region_is_hit_by_range(const ZRegion * region,const long gframes_start,const long gframes_end,const bool end_inclusive)1259 region_is_hit_by_range (
1260 const ZRegion * region,
1261 const long gframes_start,
1262 const long gframes_end,
1263 const bool end_inclusive)
1264 {
1265 const ArrangerObject * obj =
1266 (const ArrangerObject *) region;
1267 /* 4 cases:
1268 * - region start is inside range
1269 * - region end is inside range
1270 * - start is inside region
1271 * - end is inside region
1272 */
1273 if (end_inclusive)
1274 {
1275 return
1276 (gframes_start <=
1277 obj->pos.frames &&
1278 gframes_end >=
1279 obj->pos.frames) ||
1280 (gframes_start <=
1281 obj->end_pos.frames &&
1282 gframes_end >=
1283 obj->end_pos.frames) ||
1284 region_is_hit (region, gframes_start, 1) ||
1285 region_is_hit (region, gframes_end, 1);
1286 }
1287 else
1288 {
1289 return
1290 (gframes_start <=
1291 obj->pos.frames &&
1292 gframes_end >
1293 obj->pos.frames) ||
1294 (gframes_start <
1295 obj->end_pos.frames &&
1296 gframes_end >
1297 obj->end_pos.frames) ||
1298 region_is_hit (region, gframes_start, 0) ||
1299 region_is_hit (region, gframes_end, 0);
1300 }
1301 }
1302
1303 /**
1304 * Copies the data from src to dest.
1305 *
1306 * Used when doing/undoing changes in name,
1307 * clip start point, loop start point, etc.
1308 */
1309 void
region_copy(ZRegion * src,ZRegion * dest)1310 region_copy (
1311 ZRegion * src,
1312 ZRegion * dest)
1313 {
1314 g_free (dest->name);
1315 dest->name = g_strdup (src->name);
1316
1317 ArrangerObject * src_obj =
1318 (ArrangerObject *) src;
1319 ArrangerObject * dest_obj =
1320 (ArrangerObject *) dest;
1321
1322 dest_obj->clip_start_pos = src_obj->clip_start_pos;
1323 dest_obj->loop_start_pos = src_obj->loop_start_pos;
1324 dest_obj->loop_end_pos = src_obj->loop_end_pos;
1325 dest_obj->fade_in_pos = src_obj->fade_in_pos;
1326 dest_obj->fade_out_pos = src_obj->fade_out_pos;
1327 }
1328
1329 /**
1330 * Wrapper for adding an arranger object.
1331 */
1332 void
region_add_arranger_object(ZRegion * self,ArrangerObject * obj,bool fire_events)1333 region_add_arranger_object (
1334 ZRegion * self,
1335 ArrangerObject * obj,
1336 bool fire_events)
1337 {
1338 switch (obj->type)
1339 {
1340 case ARRANGER_OBJECT_TYPE_CHORD_OBJECT:
1341 chord_region_add_chord_object (
1342 self, (ChordObject *) obj, fire_events);
1343 break;
1344 case ARRANGER_OBJECT_TYPE_MIDI_NOTE:
1345 midi_region_add_midi_note (
1346 self, (MidiNote *) obj, fire_events);
1347 break;
1348 case ARRANGER_OBJECT_TYPE_AUTOMATION_POINT:
1349 automation_region_add_ap (
1350 self, (AutomationPoint *) obj,
1351 fire_events);
1352 break;
1353 default:
1354 g_return_if_reached ();
1355 break;
1356 }
1357 }
1358
1359 /**
1360 * Converts frames on the timeline (global)
1361 * to local frames (in the clip).
1362 *
1363 * If normalize is 1 it will only return a position
1364 * from 0 to loop_end (it will traverse the
1365 * loops to find the appropriate position),
1366 * otherwise it may exceed loop_end.
1367 *
1368 * @param timeline_frames Timeline position in
1369 * frames.
1370 *
1371 * @return The local frames.
1372 */
1373 long
region_timeline_frames_to_local(const ZRegion * const self,const long timeline_frames,const bool normalize)1374 region_timeline_frames_to_local (
1375 const ZRegion * const self,
1376 const long timeline_frames,
1377 const bool normalize)
1378 {
1379 g_return_val_if_fail (IS_REGION (self), 0);
1380
1381 const ArrangerObject * const r_obj =
1382 (const ArrangerObject * const) self;
1383
1384 if (normalize)
1385 {
1386 long diff_frames =
1387 timeline_frames -
1388 r_obj->pos.frames;
1389
1390 /* special case: timeline frames is exactly
1391 * at the end of the region */
1392 if (timeline_frames == r_obj->end_pos.frames)
1393 return diff_frames;
1394
1395 const long loop_end_frames =
1396 r_obj->loop_end_pos.frames;
1397 const long clip_start_frames =
1398 r_obj->clip_start_pos.frames;
1399 const long loop_size =
1400 arranger_object_get_loop_length_in_frames (
1401 r_obj);
1402 z_return_val_if_fail_cmp (
1403 loop_size, >, 0, 0);
1404
1405 diff_frames += clip_start_frames;
1406
1407 while (diff_frames >= loop_end_frames)
1408 {
1409 diff_frames -= loop_size;
1410 }
1411
1412 return diff_frames;
1413 }
1414 else
1415 {
1416 return
1417 timeline_frames -
1418 r_obj->pos.frames;
1419 }
1420 }
1421
1422 /**
1423 * Returns the number of frames until the next
1424 * loop end point or the end of the region.
1425 *
1426 * @param[in] timeline_frames Global frames at
1427 * start.
1428 * @param[out] ret_frames Return frames.
1429 * @param[out] is_loop Whether the return frames
1430 * are for a loop (if false, the return frames
1431 * are for the region's end).
1432 */
1433 void
region_get_frames_till_next_loop_or_end(const ZRegion * const self,const long timeline_frames,long * ret_frames,bool * is_loop)1434 region_get_frames_till_next_loop_or_end (
1435 const ZRegion * const self,
1436 const long timeline_frames,
1437 long * ret_frames,
1438 bool * is_loop)
1439 {
1440 g_return_if_fail (IS_REGION (self));
1441
1442 ArrangerObject * r_obj = (ArrangerObject *) self;
1443
1444 long local_frames =
1445 timeline_frames - r_obj->pos.frames;
1446 long loop_size =
1447 arranger_object_get_loop_length_in_frames (
1448 r_obj);
1449 g_return_if_fail (loop_size > 0);
1450
1451 local_frames += r_obj->clip_start_pos.frames;
1452
1453 while (local_frames >=
1454 r_obj->loop_end_pos.frames)
1455 {
1456 local_frames -= loop_size;
1457 }
1458
1459 long frames_till_next_loop =
1460 r_obj->loop_end_pos.frames - local_frames;
1461
1462 long frames_till_end =
1463 r_obj->end_pos.frames - timeline_frames;
1464
1465 *is_loop =
1466 frames_till_next_loop < frames_till_end;
1467 *ret_frames =
1468 MIN (frames_till_end, frames_till_next_loop);
1469 }
1470
1471 /**
1472 * Generates the filename for this region.
1473 *
1474 * MUST be free'd.
1475 *
1476 * FIXME logic needs changing
1477 */
1478 char *
region_generate_filename(ZRegion * region)1479 region_generate_filename (ZRegion * region)
1480 {
1481 Track * track =
1482 arranger_object_get_track (
1483 (ArrangerObject *) region);
1484 return
1485 g_strdup_printf (
1486 REGION_PRINTF_FILENAME, track->name,
1487 region->name);
1488 }
1489
1490 /**
1491 * Returns if this region is currently being
1492 * recorded onto.
1493 */
1494 bool
region_is_recording(ZRegion * self)1495 region_is_recording (
1496 ZRegion * self)
1497 {
1498 if (RECORDING_MANAGER->num_active_recordings == 0)
1499 {
1500 return false;
1501 }
1502
1503 for (int i = 0;
1504 i < RECORDING_MANAGER->num_recorded_ids;
1505 i++)
1506 {
1507 if (region_identifier_is_equal (
1508 &self->id,
1509 &RECORDING_MANAGER->recorded_ids[i]))
1510 {
1511 return true;
1512 }
1513 }
1514
1515 return false;
1516 }
1517
1518 /**
1519 * Disconnects the region and anything using it.
1520 *
1521 * Does not free the ZRegion or its children's
1522 * resources.
1523 */
1524 void
region_disconnect(ZRegion * self)1525 region_disconnect (
1526 ZRegion * self)
1527 {
1528 ZRegion * clip_editor_region =
1529 clip_editor_get_region (CLIP_EDITOR);
1530 if (clip_editor_region == self)
1531 {
1532 clip_editor_set_region (
1533 CLIP_EDITOR, NULL, true);
1534 }
1535 if (TL_SELECTIONS)
1536 {
1537 arranger_selections_remove_object (
1538 (ArrangerSelections *) TL_SELECTIONS,
1539 (ArrangerObject *) self);
1540 }
1541 for (int i = 0; i < self->num_midi_notes; i++)
1542 {
1543 MidiNote * mn = self->midi_notes[i];
1544 arranger_selections_remove_object (
1545 (ArrangerSelections *) MA_SELECTIONS,
1546 (ArrangerObject *) mn);
1547 }
1548 for (int i = 0; i < self->num_chord_objects; i++)
1549 {
1550 ChordObject * c = self->chord_objects[i];
1551 arranger_selections_remove_object (
1552 (ArrangerSelections *) CHORD_SELECTIONS,
1553 (ArrangerObject *) c);
1554 }
1555 for (int i = 0; i < self->num_aps; i++)
1556 {
1557 AutomationPoint * ap = self->aps[i];
1558 arranger_selections_remove_object (
1559 (ArrangerSelections *) AUTOMATION_SELECTIONS,
1560 (ArrangerObject *) ap);
1561 }
1562 if (ZRYTHM_HAVE_UI)
1563 {
1564 /*ARRANGER_WIDGET_GET_PRIVATE (MW_TIMELINE);*/
1565 /*if (ar_prv->start_object ==*/
1566 /*(ArrangerObject *) self)*/
1567 /*ar_prv->start_object = NULL;*/
1568 }
1569 }
1570