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