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 "audio/audio_region.h"
21 #include "audio/automation_point.h"
22 #include "audio/automation_region.h"
23 #include "audio/chord_region.h"
24 #include "audio/chord_track.h"
25 #include "audio/marker_track.h"
26 #include "audio/midi_region.h"
27 #include "audio/router.h"
28 #include "audio/stretcher.h"
29 #include "gui/backend/arranger_object.h"
30 #include "gui/backend/automation_selections.h"
31 #include "gui/backend/chord_selections.h"
32 #include "gui/backend/event.h"
33 #include "gui/backend/event_manager.h"
34 #include "gui/backend/timeline_selections.h"
35 #include "gui/widgets/automation_arranger.h"
36 #include "gui/widgets/automation_editor_space.h"
37 #include "gui/widgets/automation_point.h"
38 #include "gui/widgets/automation_region.h"
39 #include "gui/widgets/bot_dock_edge.h"
40 #include "gui/widgets/center_dock.h"
41 #include "gui/widgets/chord_arranger.h"
42 #include "gui/widgets/chord_editor_space.h"
43 #include "gui/widgets/chord_object.h"
44 #include "gui/widgets/chord_region.h"
45 #include "gui/widgets/clip_editor.h"
46 #include "gui/widgets/clip_editor_inner.h"
47 #include "gui/widgets/main_notebook.h"
48 #include "gui/widgets/marker.h"
49 #include "gui/widgets/midi_arranger.h"
50 #include "gui/widgets/midi_editor_space.h"
51 #include "gui/widgets/midi_modifier_arranger.h"
52 #include "gui/widgets/midi_note.h"
53 #include "gui/widgets/midi_region.h"
54 #include "gui/widgets/region.h"
55 #include "gui/widgets/scale_object.h"
56 #include "gui/widgets/timeline_arranger.h"
57 #include "gui/widgets/timeline_panel.h"
58 #include "gui/widgets/track.h"
59 #include "gui/widgets/velocity.h"
60 #include "project.h"
61 #include "utils/cairo.h"
62 #include "utils/debug.h"
63 #include "utils/dsp.h"
64 #include "utils/error.h"
65 #include "utils/flags.h"
66 #include "utils/math.h"
67 #include "utils/objects.h"
68 #include "zrythm_app.h"
69 
70 #include <glib/gi18n.h>
71 
72 #define TYPE(x) \
73   ARRANGER_OBJECT_TYPE_##x
74 
75 #define TYPE_IS(x) \
76   (self->type == TYPE (x))
77 
78 #define POSITION_TYPE(x) \
79   ARRANGER_OBJECT_POSITION_TYPE_##x
80 
81 #define FOREACH_TYPE(func) \
82   func (REGION, ZRegion, region) \
83   func (SCALE_OBJECT, ScaleObject, scale_object) \
84   func (MARKER, Marker, marker) \
85   func (MIDI_NOTE, MidiNote, midi_note) \
86   func (VELOCITY, Velocity, velocity) \
87   func (CHORD_OBJECT, ChordObject, chord_object) \
88   func (AUTOMATION_POINT, AutomationPoint, \
89         automation_point)
90 
91 void
arranger_object_init(ArrangerObject * self)92 arranger_object_init (
93   ArrangerObject * self)
94 {
95   self->schema_version =
96     ARRANGER_OBJECT_SCHEMA_VERSION;
97   self->magic = ARRANGER_OBJECT_MAGIC;
98 
99   position_init (&self->pos);
100   position_init (&self->end_pos);
101   position_init (&self->clip_start_pos);
102   position_init (&self->loop_start_pos);
103   position_init (&self->loop_end_pos);
104   position_init (&self->fade_in_pos);
105   position_init (&self->fade_out_pos);
106 
107   curve_opts_init (&self->fade_in_opts);
108   curve_opts_init (&self->fade_out_opts);
109 
110   self->region_id.schema_version =
111     REGION_IDENTIFIER_SCHEMA_VERSION;
112 }
113 
114 /**
115  * Returns the ArrangerSelections corresponding
116  * to the given object type.
117  */
118 ArrangerSelections *
arranger_object_get_selections_for_type(ArrangerObjectType type)119 arranger_object_get_selections_for_type (
120   ArrangerObjectType type)
121 {
122   switch (type)
123     {
124     case TYPE (REGION):
125     case TYPE (SCALE_OBJECT):
126     case TYPE (MARKER):
127       return (ArrangerSelections *) TL_SELECTIONS;
128     case TYPE (MIDI_NOTE):
129     case TYPE (VELOCITY):
130       return (ArrangerSelections *) MA_SELECTIONS;
131     case TYPE (CHORD_OBJECT):
132       return (ArrangerSelections *) CHORD_SELECTIONS;
133     case TYPE (AUTOMATION_POINT):
134       return
135         (ArrangerSelections *) AUTOMATION_SELECTIONS;
136     default:
137       return NULL;
138     }
139 }
140 
141 /**
142  * Selects the object by adding it to its
143  * corresponding selections or making it the
144  * only selection.
145  *
146  * @param select 1 to select, 0 to deselect.
147  * @param append 1 to append, 0 to make it the only
148  *   selection.
149  */
150 void
arranger_object_select(ArrangerObject * self,const bool select,const bool append,bool fire_events)151 arranger_object_select (
152   ArrangerObject * self,
153   const bool       select,
154   const bool       append,
155   bool             fire_events)
156 {
157   g_return_if_fail (IS_ARRANGER_OBJECT (self));
158 
159   g_debug ("selecting object:");
160   arranger_object_print (self);
161 
162   if (self->type == ARRANGER_OBJECT_TYPE_VELOCITY)
163     {
164       self =
165         (ArrangerObject *)
166         velocity_get_midi_note ((Velocity *) self);
167       g_return_if_fail (IS_MIDI_NOTE (self));
168     }
169 
170   ArrangerSelections * selections =
171     arranger_object_get_selections_for_type (
172       self->type);
173 
174   /* if nothing to do, return */
175   bool is_selected =
176     arranger_object_is_selected (self);
177   if ((is_selected && select && append) ||
178       (!is_selected && !select))
179     {
180       return;
181     }
182 
183   if (select)
184     {
185       if (!append)
186         {
187           arranger_selections_clear (
188             selections, F_NO_FREE, fire_events);
189         }
190       arranger_selections_add_object (
191         selections, self);
192     }
193   else
194     {
195       arranger_selections_remove_object (
196         selections, self);
197     }
198 
199   if (fire_events)
200     {
201       EVENTS_PUSH (
202         ET_ARRANGER_OBJECT_CHANGED, self);
203     }
204 }
205 
206 /**
207  * Returns the number of loops in the ArrangerObject,
208  * optionally including incomplete ones.
209  */
210 int
arranger_object_get_num_loops(ArrangerObject * self,const int count_incomplete)211 arranger_object_get_num_loops (
212   ArrangerObject * self,
213   const int        count_incomplete)
214 {
215   g_return_val_if_fail (
216     arranger_object_type_can_loop (self->type), 0);
217 
218   int i = 0;
219   long loop_size =
220     arranger_object_get_loop_length_in_frames (
221       self);
222   z_return_val_if_fail_cmp (loop_size, >, 0, 0);
223   long full_size =
224     arranger_object_get_length_in_frames (self);
225   long loop_start =
226     self->loop_start_pos.frames -
227     self->clip_start_pos.frames;
228   long curr_frames = loop_start;
229 
230   while (curr_frames < full_size)
231     {
232       i++;
233       curr_frames += loop_size;
234     }
235 
236   if (!count_incomplete)
237     i--;
238 
239   return i;
240 }
241 
242 static void
set_to_region_object(ZRegion * src,ZRegion * dest)243 set_to_region_object (
244   ZRegion * src,
245   ZRegion * dest)
246 {
247   g_return_if_fail (src && dest);
248 }
249 
250 static void
set_to_midi_note_object(MidiNote * src,MidiNote * dest)251 set_to_midi_note_object (
252   MidiNote * src,
253   MidiNote * dest)
254 {
255   g_return_if_fail (
256     dest && dest->vel && src && src->vel);
257   dest->vel->vel = src->vel->vel;
258   dest->val = src->val;
259 }
260 
261 /**
262  * Sets the mute status of the object.
263  */
264 void
arranger_object_set_muted(ArrangerObject * self,bool muted,bool fire_events)265 arranger_object_set_muted (
266   ArrangerObject * self,
267   bool             muted,
268   bool             fire_events)
269 {
270   self->muted = muted;
271 
272   if (fire_events)
273     {
274       EVENTS_PUSH (
275         ET_ARRANGER_OBJECT_CHANGED, self);
276     }
277 }
278 
279 /**
280  * Sets the dest object's values to the main
281  * src object's values.
282  */
283 void
arranger_object_set_to_object(ArrangerObject * dest,ArrangerObject * src)284 arranger_object_set_to_object (
285   ArrangerObject * dest,
286   ArrangerObject * src)
287 {
288   g_return_if_fail (src && dest);
289 
290   /* reset positions */
291   dest->pos = src->pos;
292   if (arranger_object_type_has_length (src->type))
293     {
294       dest->end_pos = src->end_pos;
295     }
296   if (arranger_object_type_can_loop (src->type))
297     {
298       dest->clip_start_pos = src->clip_start_pos;
299       dest->loop_start_pos = src->loop_start_pos;
300       dest->loop_end_pos = src->loop_end_pos;
301     }
302   if (arranger_object_can_fade (src))
303     {
304       dest->fade_in_pos = src->fade_in_pos;
305       dest->fade_out_pos = src->fade_out_pos;
306     }
307 
308   /* reset other members */
309   switch (src->type)
310     {
311     case TYPE (REGION):
312       set_to_region_object (
313         (ZRegion *) src, (ZRegion *) dest);
314       break;
315     case TYPE (MIDI_NOTE):
316       set_to_midi_note_object (
317         (MidiNote *) src, (MidiNote *) dest);
318       break;
319     case TYPE (CHORD_OBJECT):
320       {
321         ChordObject * dest_co =
322           (ChordObject *) dest;
323         ChordObject * src_co =
324           (ChordObject *) src;
325         dest_co->index = src_co->index;
326       }
327       break;
328     case TYPE (AUTOMATION_POINT):
329       {
330         AutomationPoint * dest_ap =
331           (AutomationPoint *) dest;
332         AutomationPoint * src_ap =
333           (AutomationPoint *) src;
334         dest_ap->fvalue = src_ap->fvalue;
335       }
336       break;
337     default:
338       break;
339     }
340 }
341 
342 /**
343  * Returns if the object is in the selections.
344  */
345 bool
arranger_object_is_selected(ArrangerObject * self)346 arranger_object_is_selected (
347   ArrangerObject * self)
348 {
349   ArrangerSelections * selections =
350     arranger_object_get_selections_for_type (
351       self->type);
352 
353   return
354     arranger_selections_contains_object (
355       selections, self);
356 }
357 
358 /**
359  * If the object is part of a ZRegion, returns it,
360  * otherwise returns NULL.
361  */
362 ZRegion *
arranger_object_get_region(const ArrangerObject * const self)363 arranger_object_get_region (
364   const ArrangerObject * const self)
365 {
366   const RegionIdentifier * id = NULL;
367   switch (self->type)
368     {
369     case ARRANGER_OBJECT_TYPE_AUTOMATION_POINT:
370     case ARRANGER_OBJECT_TYPE_MIDI_NOTE:
371     case ARRANGER_OBJECT_TYPE_CHORD_OBJECT:
372       id = &self->region_id;
373       break;
374     case ARRANGER_OBJECT_TYPE_VELOCITY:
375       {
376         Velocity * vel =
377           (Velocity *) self;
378         ArrangerObject * mn_obj =
379           (ArrangerObject *)
380           vel->midi_note;
381         id = &mn_obj->region_id;
382       }
383       break;
384     default:
385       return NULL;
386       break;
387     }
388 
389   ZRegion * region = region_find (id);
390 
391   return region;
392 }
393 
394 /**
395  * Returns whether the given object is hit by the
396  * given position or range.
397  *
398  * @param start Start position.
399  * @param end End position, or NULL to only check
400  *   for intersection with \ref start.
401  */
402 bool
arranger_object_is_hit(ArrangerObject * self,Position * start,Position * end)403 arranger_object_is_hit (
404   ArrangerObject * self,
405   Position *       start,
406   Position *       end)
407 {
408   if (end)
409     {
410       /* check range */
411       if (position_is_after (
412             &self->pos, end) ||
413           position_is_after (
414             start, &self->end_pos))
415         {
416           return false;
417         }
418       else
419         {
420           return true;
421         }
422     }
423   else
424     {
425       /* check position hit */
426       return
427         position_is_after_or_equal (
428           start, &self->pos) &&
429         position_is_before_or_equal (
430           start, &self->end_pos);
431     }
432 }
433 
434 /**
435  * Gets a pointer to the Position in the
436  * ArrangerObject matching the given arguments.
437  */
438 static Position *
get_position_ptr(ArrangerObject * self,ArrangerObjectPositionType pos_type)439 get_position_ptr (
440   ArrangerObject *           self,
441   ArrangerObjectPositionType pos_type)
442 {
443   switch (pos_type)
444     {
445     case ARRANGER_OBJECT_POSITION_TYPE_START:
446       return &self->pos;
447     case ARRANGER_OBJECT_POSITION_TYPE_END:
448       return &self->end_pos;
449     case ARRANGER_OBJECT_POSITION_TYPE_CLIP_START:
450       return &self->clip_start_pos;
451     case ARRANGER_OBJECT_POSITION_TYPE_LOOP_START:
452       return &self->loop_start_pos;
453     case ARRANGER_OBJECT_POSITION_TYPE_LOOP_END:
454       return &self->loop_end_pos;
455     case ARRANGER_OBJECT_POSITION_TYPE_FADE_IN:
456       return &self->fade_in_pos;
457     case ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT:
458       return &self->fade_out_pos;
459     }
460   g_return_val_if_reached (NULL);
461 }
462 
463 /**
464  * Returns if the given Position is valid.
465  *
466  * @param pos The position to set to.
467  * @param pos_type The type of Position to set in the
468  *   ArrangerObject.
469  * @param validate Validate the Position before
470  *   setting it.
471  */
472 bool
arranger_object_is_position_valid(ArrangerObject * self,const Position * pos,ArrangerObjectPositionType pos_type)473 arranger_object_is_position_valid (
474   ArrangerObject *           self,
475   const Position *           pos,
476   ArrangerObjectPositionType pos_type)
477 {
478   bool is_valid = false;
479   switch (pos_type)
480     {
481     case ARRANGER_OBJECT_POSITION_TYPE_START:
482       if (arranger_object_type_has_length (
483             self->type))
484         {
485           is_valid =
486             position_is_before (
487               pos, &self->end_pos);
488 
489           if (!arranger_object_owned_by_region (
490                 self))
491             {
492               is_valid =
493                 is_valid &&
494                 position_is_after_or_equal (
495                   pos, &POSITION_START);
496             }
497         }
498       else if (arranger_object_type_has_global_pos (
499                  self->type))
500         {
501           is_valid =
502             position_is_after_or_equal (
503               pos, &POSITION_START);
504         }
505       else
506         {
507           is_valid = true;
508         }
509       break;
510     case ARRANGER_OBJECT_POSITION_TYPE_LOOP_START:
511       {
512         is_valid =
513           position_is_before (
514             pos, &self->loop_end_pos)
515           &&
516           position_is_after_or_equal (
517             pos, &POSITION_START);
518       }
519       break;
520     case ARRANGER_OBJECT_POSITION_TYPE_LOOP_END:
521       {
522         if (position_is_before (
523               pos, &self->clip_start_pos))
524           return false;
525 
526         is_valid = true;
527         if (self->type ==
528               ARRANGER_OBJECT_TYPE_REGION)
529           {
530             ZRegion * r = (ZRegion *) self;
531             if (r->id.type == REGION_TYPE_AUDIO)
532               {
533                 AudioClip * clip =
534                   audio_region_get_clip (r);
535                 Position clip_frames;
536                 position_from_frames (
537                   &clip_frames, clip->num_frames);
538                 is_valid =
539                   position_is_before_or_equal (
540                     pos, &clip_frames);
541               }
542           }
543       }
544       break;
545     case ARRANGER_OBJECT_POSITION_TYPE_CLIP_START:
546       {
547         is_valid =
548           position_is_before (
549             pos, &self->loop_end_pos)
550           &&
551           position_is_after_or_equal (
552             pos, &POSITION_START);
553       }
554       break;
555     case ARRANGER_OBJECT_POSITION_TYPE_END:
556       {
557         is_valid =
558           position_is_after (pos, &self->pos);
559       }
560       break;
561     case ARRANGER_OBJECT_POSITION_TYPE_FADE_IN:
562       {
563         Position local_end_pos;
564         position_from_frames (
565           &local_end_pos,
566           self->end_pos.frames - self->pos.frames);
567         is_valid =
568           position_is_after_or_equal (
569             pos, &POSITION_START)
570           &&
571           position_is_before (pos, &local_end_pos);
572       }
573       break;
574     case ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT:
575       {
576         Position local_end_pos;
577         position_from_frames (
578           &local_end_pos,
579           self->end_pos.frames - self->pos.frames);
580         is_valid =
581           position_is_after_or_equal (
582             pos, &POSITION_START)
583           &&
584           position_is_before (pos, &local_end_pos);
585       }
586       break;
587     default:
588       break;
589     }
590 
591 #if 0
592   g_debug (
593     "%s position with ticks %f",
594     is_valid ? "Valid" : "Invalid",
595     pos->ticks);
596 #endif
597 
598   return is_valid;
599 }
600 
601 /**
602  * Copies the identifier from src to dest.
603  */
604 void
arranger_object_copy_identifier(ArrangerObject * dest,ArrangerObject * src)605 arranger_object_copy_identifier (
606   ArrangerObject * dest,
607   ArrangerObject * src)
608 {
609   g_return_if_fail (
610     IS_ARRANGER_OBJECT (dest) &&
611     IS_ARRANGER_OBJECT (src) &&
612     dest->type == src->type);
613 
614   if (arranger_object_owned_by_region (dest))
615     {
616       region_identifier_copy (
617         &dest->region_id, &src->region_id);
618     }
619 
620   switch (dest->type)
621     {
622     case TYPE (REGION):
623       {
624         ZRegion * dest_r = (ZRegion *) dest;
625         ZRegion * src_r = (ZRegion *) src;
626         region_identifier_copy (
627           &dest_r->id, &src_r->id);
628       }
629       break;
630     case TYPE (MIDI_NOTE):
631       {
632         MidiNote * destmn = (MidiNote *) dest;
633         MidiNote * srcmn = (MidiNote *) src;
634         destmn->pos = srcmn->pos;
635       }
636       break;
637     case TYPE (AUTOMATION_POINT):
638       {
639         AutomationPoint * destap =
640           (AutomationPoint *) dest;
641         AutomationPoint * srcap =
642           (AutomationPoint *) src;
643         destap->index = srcap->index;
644       }
645       break;
646     case TYPE (CHORD_OBJECT):
647       {
648         ChordObject * destap =
649           (ChordObject *) dest;
650         ChordObject * srcap =
651           (ChordObject *) src;
652         destap->index = srcap->index;
653         destap->chord_index =
654           srcap->chord_index;
655       }
656       break;
657     case TYPE (SCALE_OBJECT):
658       {
659         ScaleObject * dest_so =
660           (ScaleObject *) dest;
661         ScaleObject * src_so =
662           (ScaleObject *) src;
663         dest_so->index = src_so->index;
664       }
665       break;
666     case TYPE (MARKER):
667       {
668         Marker * dest_marker =
669           (Marker *) dest;
670         Marker * src_marker =
671           (Marker *) src;
672         dest_marker->track_name_hash =
673           src_marker->track_name_hash;
674         dest_marker->index =
675           src_marker->index;
676         if (dest_marker->name)
677           g_free (dest_marker->name);
678         dest_marker->name =
679           g_strdup (src_marker->name);
680       }
681     default:
682       break;
683     }
684 }
685 
686 /**
687  * Sets the Position  all of the object's linked
688  * objects (see ArrangerObjectInfo)
689  *
690  * @param pos The position to set to.
691  * @param pos_type The type of Position to set in the
692  *   ArrangerObject.
693  * @param validate Validate the Position before
694  *   setting it.
695  */
696 void
arranger_object_set_position(ArrangerObject * self,const Position * pos,ArrangerObjectPositionType pos_type,const int validate)697 arranger_object_set_position (
698   ArrangerObject *           self,
699   const Position *           pos,
700   ArrangerObjectPositionType pos_type,
701   const int                  validate)
702 {
703   g_return_if_fail (self && pos);
704 
705   /* return if validate is on and position is
706    * invalid */
707   if (validate &&
708       !arranger_object_is_position_valid (
709         self, pos, pos_type))
710     return;
711 
712   Position * pos_ptr;
713   pos_ptr = get_position_ptr (self, pos_type);
714   g_return_if_fail (pos_ptr);
715   position_set_to_pos (pos_ptr, pos);
716 }
717 
718 /**
719  * Returns the type as a string.
720  */
721 const char *
arranger_object_stringize_type(ArrangerObjectType type)722 arranger_object_stringize_type (
723   ArrangerObjectType type)
724 {
725   return arranger_object_type_strings[type].str;
726 }
727 
728 /**
729  * Sets the magic on the arranger object.
730  */
731 void
arranger_object_set_magic(ArrangerObject * self)732 arranger_object_set_magic (
733   ArrangerObject * self)
734 {
735   self->magic = ARRANGER_OBJECT_MAGIC;
736 
737   switch (self->type)
738     {
739     case TYPE (REGION):
740       ((ZRegion *) self)->magic = REGION_MAGIC;
741       break;
742     case TYPE (MIDI_NOTE):
743       ((MidiNote *) self)->magic = MIDI_NOTE_MAGIC;
744       break;
745     default:
746       /* nothing needed */
747       break;
748     }
749 }
750 
751 /**
752  * Prints debug information about the given
753  * object.
754  */
755 void
arranger_object_print(ArrangerObject * self)756 arranger_object_print (
757   ArrangerObject * self)
758 {
759   g_return_if_fail (self);
760 
761   const char * type =
762     arranger_object_stringize_type (self->type);
763 
764   char positions[900];
765   char start_pos_str[100];
766   position_to_string (
767     &self->pos, start_pos_str);
768   if (arranger_object_type_has_length (self->type))
769     {
770       char end_pos_str[100];
771       position_to_string (
772         &self->end_pos, end_pos_str);
773 
774       if (arranger_object_type_can_loop (
775             self->type))
776         {
777           char clip_start_pos_str[100];
778           position_to_string (
779             &self->clip_start_pos,
780             clip_start_pos_str);
781           char loop_start_pos_str[100];
782           position_to_string (
783             &self->loop_start_pos,
784             loop_start_pos_str);
785           char loop_end_pos_str[100];
786           position_to_string (
787             &self->loop_end_pos,
788             loop_end_pos_str);
789           sprintf (
790             positions,
791             "(%s ~ %s | cs: %s ls: %s le: %s)",
792             start_pos_str, end_pos_str,
793             clip_start_pos_str,
794             loop_start_pos_str, loop_end_pos_str);
795         }
796       else
797         {
798           sprintf (
799             positions, "(%s ~ %s)",
800             start_pos_str, end_pos_str);
801         }
802     }
803   else
804     {
805       sprintf (positions, "(%s)", start_pos_str);
806     }
807 
808   char * extra_info = NULL;
809   switch (self->type)
810     {
811     case ARRANGER_OBJECT_TYPE_REGION:
812       {
813         ZRegion * region = (ZRegion *) self;
814         extra_info =
815           g_strdup_printf (
816             " track: %u - lane: %d - idx: %d - "
817             "link group: %d",
818             region->id.track_name_hash,
819             region->id.lane_pos,
820             region->id.idx,
821             region->id.link_group);
822         if (region->id.type == REGION_TYPE_AUDIO)
823           {
824             char * tmp = extra_info;
825             AudioClip * clip =
826               audio_region_get_clip (region);
827             g_return_if_fail (clip);
828             Position pos;
829             position_from_frames (
830               &pos, clip->num_frames);
831             char pos_str[100];
832             position_to_string (&pos, pos_str);
833             extra_info =
834               g_strdup_printf (
835                 " | audio clip total ticks %s "
836                 "(%ld frames)",
837                 pos_str,
838                 clip->num_frames);
839             g_free (tmp);
840           }
841       }
842       break;
843     case ARRANGER_OBJECT_TYPE_SCALE_OBJECT:
844       {
845         ScaleObject * so = (ScaleObject *) self;
846         extra_info =
847           g_strdup_printf (
848             " index: %d", so->index);
849       }
850       break;
851     default:
852       break;
853     }
854 
855   g_message (
856     "%s %s%s",
857     type, positions, extra_info ? extra_info : "");
858 
859   if (extra_info)
860     g_free (extra_info);
861 }
862 
863 /**
864  * Moves the object by the given amount of
865  * ticks.
866  */
867 void
arranger_object_move(ArrangerObject * self,const double ticks)868 arranger_object_move (
869   ArrangerObject *         self,
870   const double             ticks)
871 {
872   if (arranger_object_type_has_length (self->type))
873     {
874       long length_frames =
875         arranger_object_get_length_in_frames (
876           self);
877 
878       /* start pos */
879       Position tmp;
880       position_set_to_pos (
881         &tmp, &self->pos);
882       position_add_ticks (
883         &tmp, ticks);
884       arranger_object_set_position (
885         self, &tmp,
886         ARRANGER_OBJECT_POSITION_TYPE_START,
887         F_NO_VALIDATE);
888 
889       /* end pos */
890       if (self->type == TYPE (REGION))
891         {
892           /* audio regions need the exact
893            * number of frames to match the clip.
894            *
895            * this should be used for all
896            * objects but currently moving objects
897            * before 1.1.1.1 causes bugs hence this
898            * (temporary) if statement */
899           position_add_frames (
900             &tmp, length_frames);
901         }
902       else
903         {
904           position_set_to_pos (
905             &tmp, &self->end_pos);
906           position_add_ticks (
907             &tmp, ticks);
908         }
909       arranger_object_set_position (
910         self, &tmp,
911         ARRANGER_OBJECT_POSITION_TYPE_END,
912         F_NO_VALIDATE);
913     }
914   else
915     {
916       Position tmp;
917       position_set_to_pos (
918         &tmp, &self->pos);
919       position_add_ticks (
920         &tmp, ticks);
921       arranger_object_set_position (
922         self, &tmp,
923         ARRANGER_OBJECT_POSITION_TYPE_START,
924         F_NO_VALIDATE);
925     }
926 }
927 
928 /**
929  * Getter.
930  */
931 void
arranger_object_get_pos(const ArrangerObject * self,Position * pos)932 arranger_object_get_pos (
933   const ArrangerObject * self,
934   Position *             pos)
935 {
936   position_set_to_pos (
937     pos, &self->pos);
938 }
939 
940 /**
941  * Getter.
942  */
943 void
arranger_object_get_end_pos(const ArrangerObject * self,Position * pos)944 arranger_object_get_end_pos (
945   const ArrangerObject * self,
946   Position *             pos)
947 
948 {
949   position_set_to_pos (
950     pos, &self->end_pos);
951 }
952 
953 /**
954  * Getter.
955  */
956 void
arranger_object_get_clip_start_pos(const ArrangerObject * self,Position * pos)957 arranger_object_get_clip_start_pos (
958   const ArrangerObject * self,
959   Position *             pos)
960 
961 {
962   position_set_to_pos (
963     pos, &self->clip_start_pos);
964 }
965 
966 /**
967  * Getter.
968  */
969 void
arranger_object_get_loop_start_pos(const ArrangerObject * self,Position * pos)970 arranger_object_get_loop_start_pos (
971   const ArrangerObject * self,
972   Position *             pos)
973 
974 {
975   position_set_to_pos (
976     pos, &self->loop_start_pos);
977 }
978 
979 /**
980  * Getter.
981  */
982 void
arranger_object_get_loop_end_pos(const ArrangerObject * self,Position * pos)983 arranger_object_get_loop_end_pos (
984   const ArrangerObject * self,
985   Position *             pos)
986 
987 {
988   position_set_to_pos (
989     pos, &self->loop_end_pos);
990 }
991 
992 static void
init_loaded_midi_note(MidiNote * self)993 init_loaded_midi_note (
994   MidiNote * self)
995 {
996   self->magic = MIDI_NOTE_MAGIC;
997   self->vel->midi_note = self;
998 }
999 
1000 static void
init_loaded_scale_object(ScaleObject * self)1001 init_loaded_scale_object (
1002   ScaleObject * self)
1003 {
1004   self->magic = SCALE_OBJECT_MAGIC;
1005 }
1006 
1007 static void
init_loaded_chord_object(ChordObject * self)1008 init_loaded_chord_object (
1009   ChordObject * self)
1010 {
1011   self->magic = CHORD_OBJECT_MAGIC;
1012 }
1013 
1014 static void
init_loaded_marker(Marker * self)1015 init_loaded_marker (
1016   Marker * self)
1017 {
1018   arranger_object_gen_escaped_name (
1019     (ArrangerObject *) self);
1020 }
1021 
1022 static void
init_loaded_region(ZRegion * self)1023 init_loaded_region (
1024   ZRegion * self)
1025 {
1026   self->magic = REGION_MAGIC;
1027 
1028   int i;
1029   switch (self->id.type)
1030     {
1031     case REGION_TYPE_AUDIO:
1032       {
1033         self->read_from_pool = true;
1034         AudioClip * clip =
1035           audio_region_get_clip (self);
1036         g_return_if_fail (clip);
1037         self->last_clip_change =
1038           g_get_monotonic_time ();
1039 
1040         for (i = 0; i < self->num_aps; i++)
1041           {
1042             AutomationPoint * ap = self->aps[i];
1043             arranger_object_init_loaded (
1044               (ArrangerObject *) ap);
1045           }
1046         self->aps_size =
1047           (size_t) self->num_aps;
1048       }
1049       break;
1050     case REGION_TYPE_MIDI:
1051       {
1052         MidiNote * mn;
1053         for (i = 0; i < self->num_midi_notes; i++)
1054           {
1055             mn = self->midi_notes[i];
1056             arranger_object_init_loaded (
1057               (ArrangerObject *) mn);
1058           }
1059         self->midi_notes_size =
1060           (size_t) self->num_midi_notes;
1061       }
1062       break;
1063     case REGION_TYPE_CHORD:
1064       {
1065         ChordObject * chord;
1066         for (i = 0; i < self->num_chord_objects;
1067              i++)
1068           {
1069             chord = self->chord_objects[i];
1070             arranger_object_init_loaded (
1071               (ArrangerObject *) chord);
1072           }
1073         self->chord_objects_size =
1074           (size_t) self->num_chord_objects;
1075         }
1076       break;
1077     case REGION_TYPE_AUTOMATION:
1078       {
1079         for (i = 0; i < self->num_aps; i++)
1080           {
1081             AutomationPoint * ap = self->aps[i];
1082             arranger_object_init_loaded (
1083               (ArrangerObject *) ap);
1084           }
1085         self->aps_size =
1086           (size_t) self->num_aps;
1087       }
1088       break;
1089     }
1090 
1091   arranger_object_gen_escaped_name (
1092     (ArrangerObject *) self);
1093 
1094   region_validate (self, false);
1095 }
1096 
1097 /**
1098  * Initializes the object after loading a Project.
1099  */
1100 void
arranger_object_init_loaded(ArrangerObject * self)1101 arranger_object_init_loaded (
1102   ArrangerObject * self)
1103 {
1104   g_return_if_fail (self->type > TYPE (NONE));
1105 
1106   /* init positions */
1107   self->magic = ARRANGER_OBJECT_MAGIC;
1108 
1109   switch (self->type)
1110     {
1111     case TYPE (REGION):
1112       init_loaded_region (
1113         (ZRegion *) self);
1114       break;
1115     case TYPE (MIDI_NOTE):
1116       init_loaded_midi_note (
1117         (MidiNote *) self);
1118       arranger_object_init_loaded (
1119         (ArrangerObject *)
1120         ((MidiNote *) self)->vel);
1121       break;
1122     case TYPE (SCALE_OBJECT):
1123       init_loaded_scale_object (
1124         (ScaleObject *) self);
1125       break;
1126     case TYPE (CHORD_OBJECT):
1127       init_loaded_chord_object (
1128         (ChordObject *) self);
1129       break;
1130     case TYPE (MARKER):
1131       init_loaded_marker ((Marker *) self);
1132       break;
1133     default:
1134       /* nothing needed */
1135       break;
1136     }
1137 }
1138 
1139 /**
1140  * Updates the positions in each child recursively.
1141  *
1142  * @param from_ticks Whether to update the
1143  *   positions based on ticks (true) or frames
1144  *   (false).
1145  */
1146 void
arranger_object_update_positions(ArrangerObject * self,bool from_ticks)1147 arranger_object_update_positions (
1148   ArrangerObject * self,
1149   bool             from_ticks)
1150 {
1151   long frames_len_before = 0;
1152   if (arranger_object_type_has_length (self->type))
1153     {
1154       frames_len_before =
1155         arranger_object_get_length_in_frames (self);
1156     }
1157 
1158   position_update (&self->pos, from_ticks);
1159   if (arranger_object_type_has_length (self->type))
1160     {
1161       position_update (&self->end_pos, from_ticks);
1162 
1163       if (router_is_processing_kickoff_thread (
1164             ROUTER))
1165         {
1166           /* do some validation */
1167           g_return_if_fail (
1168             arranger_object_is_position_valid (
1169               self, &self->end_pos,
1170               ARRANGER_OBJECT_POSITION_TYPE_END));
1171         }
1172     }
1173   if (arranger_object_type_can_loop (self->type))
1174     {
1175       position_update (
1176         &self->clip_start_pos, from_ticks);
1177       position_update (
1178         &self->loop_start_pos, from_ticks);
1179       position_update (
1180         &self->loop_end_pos, from_ticks);
1181     }
1182   if (arranger_object_can_fade (self))
1183     {
1184       position_update (
1185         &self->fade_in_pos, from_ticks);
1186       position_update (
1187         &self->fade_out_pos, from_ticks);
1188     }
1189 
1190   ZRegion * r;
1191   switch (self->type)
1192     {
1193     case TYPE (REGION):
1194       r = (ZRegion *) self;
1195 
1196       /* validate */
1197       if (r->id.type == REGION_TYPE_AUDIO &&
1198           !region_get_musical_mode (r))
1199         {
1200           long frames_len_after =
1201             arranger_object_get_length_in_frames (
1202               self);
1203           if (frames_len_after !=
1204                 frames_len_before)
1205             {
1206               double ticks =
1207                 (frames_len_before -
1208                 frames_len_after) *
1209                 AUDIO_ENGINE->ticks_per_frame;
1210               arranger_object_resize (
1211                 self, false,
1212                 ARRANGER_OBJECT_RESIZE_STRETCH_BPM_CHANGE,
1213                 ticks, false);
1214             }
1215           z_return_if_fail_cmp (
1216             self->loop_end_pos.frames, >=, 0);
1217           long tl_frames =
1218             self->end_pos.frames - 1;
1219           long local_frames;
1220           AudioClip * clip;
1221           local_frames =
1222             region_timeline_frames_to_local (
1223               r, tl_frames, F_NORMALIZE);
1224           clip = audio_region_get_clip (r);
1225           g_return_if_fail (clip);
1226           if (local_frames >= clip->num_frames)
1227             {
1228             }
1229           g_return_if_fail (
1230             local_frames < clip->num_frames);
1231         }
1232 
1233       for (int i = 0; i < r->num_midi_notes; i++)
1234         {
1235           arranger_object_update_positions (
1236             (ArrangerObject *) r->midi_notes[i],
1237             from_ticks);
1238         }
1239       for (int i = 0; i < r->num_unended_notes; i++)
1240         {
1241           arranger_object_update_positions (
1242             (ArrangerObject *) r->unended_notes[i],
1243             from_ticks);
1244         }
1245 
1246       for (int i = 0; i < r->num_aps; i++)
1247         {
1248           arranger_object_update_positions (
1249             (ArrangerObject *) r->aps[i],
1250             from_ticks);
1251         }
1252 
1253       for (int i = 0; i < r->num_chord_objects; i++)
1254         {
1255           arranger_object_update_positions (
1256             (ArrangerObject *) r->chord_objects[i],
1257             from_ticks);
1258         }
1259       break;
1260     default:
1261       break;
1262     }
1263 }
1264 
1265 void
arranger_object_append_children(ArrangerObject * self,GPtrArray * children)1266 arranger_object_append_children (
1267   ArrangerObject * self,
1268   GPtrArray *      children)
1269 {
1270   if (self->type != ARRANGER_OBJECT_TYPE_REGION)
1271     return;
1272 
1273   ZRegion * r = (ZRegion *) self;
1274   switch (r->id.type)
1275     {
1276     case REGION_TYPE_MIDI:
1277       for (int i = 0; i < r->num_midi_notes; i++)
1278         {
1279           g_ptr_array_add (
1280             children, r->midi_notes[i]);
1281         }
1282       break;
1283     case REGION_TYPE_AUDIO:
1284       break;
1285     case REGION_TYPE_AUTOMATION:
1286       for (int i = 0; i < r->num_aps; i++)
1287         {
1288           g_ptr_array_add (children, r->aps[i]);
1289         }
1290       break;
1291     case REGION_TYPE_CHORD:
1292       for (int i = 0; i < r->num_chord_objects;
1293            i++)
1294         {
1295           g_ptr_array_add (
1296             children, r->chord_objects[i]);
1297         }
1298       break;
1299     }
1300 }
1301 
1302 static void
add_ticks_to_region_children(ZRegion * self,const double ticks)1303 add_ticks_to_region_children (
1304   ZRegion *    self,
1305   const double ticks)
1306 {
1307   switch (self->id.type)
1308     {
1309     case REGION_TYPE_MIDI:
1310       for (int i = 0; i < self->num_midi_notes; i++)
1311         {
1312           arranger_object_move (
1313             (ArrangerObject *) self->midi_notes[i],
1314             ticks);
1315         }
1316       break;
1317     case REGION_TYPE_AUDIO:
1318       break;
1319     case REGION_TYPE_AUTOMATION:
1320       for (int i = 0; i < self->num_aps; i++)
1321         {
1322           arranger_object_move (
1323             (ArrangerObject *) self->aps[i],
1324             ticks);
1325         }
1326       break;
1327     case REGION_TYPE_CHORD:
1328       for (int i = 0; i < self->num_chord_objects;
1329            i++)
1330         {
1331           arranger_object_move (
1332             (ArrangerObject *)
1333               self->chord_objects[i],
1334             ticks);
1335         }
1336       break;
1337     }
1338 }
1339 
1340 /**
1341  * Adds the given ticks to each included object.
1342  */
1343 void
arranger_object_add_ticks_to_children(ArrangerObject * self,const double ticks)1344 arranger_object_add_ticks_to_children (
1345   ArrangerObject * self,
1346   const double     ticks)
1347 {
1348   if (self->type == TYPE (REGION))
1349     {
1350       add_ticks_to_region_children (
1351         (ZRegion *) self, ticks);
1352     }
1353 }
1354 
1355 /**
1356  * Resizes the object on the left side or right
1357  * side by given amount of ticks, for objects that
1358  * do not have loops (currently none? keep it as
1359  * reference).
1360  *
1361  * @param left 1 to resize left side, 0 to resize
1362  *   right side.
1363  * @param ticks Number of ticks to resize.
1364  * @param during_ui_action Whether this is called
1365  *   during a UI action (not at the end).
1366  */
1367 void
arranger_object_resize(ArrangerObject * self,const bool left,ArrangerObjectResizeType type,const double ticks,bool during_ui_action)1368 arranger_object_resize (
1369   ArrangerObject *         self,
1370   const bool               left,
1371   ArrangerObjectResizeType type,
1372   const double             ticks,
1373   bool                     during_ui_action)
1374 {
1375   double before_length =
1376     arranger_object_get_length_in_ticks (self);
1377   Position tmp;
1378   if (left)
1379     {
1380       if (type == ARRANGER_OBJECT_RESIZE_FADE)
1381         {
1382           tmp = self->fade_in_pos;
1383           position_add_ticks (&tmp, ticks);
1384           arranger_object_set_position (
1385             self, &tmp,
1386             ARRANGER_OBJECT_POSITION_TYPE_FADE_IN,
1387             F_NO_VALIDATE);
1388         }
1389       else
1390         {
1391           tmp = self->pos;
1392           position_add_ticks (&tmp, ticks);
1393           arranger_object_set_position (
1394             self, &tmp,
1395             ARRANGER_OBJECT_POSITION_TYPE_START,
1396             F_NO_VALIDATE);
1397 
1398           if (arranger_object_can_fade (self))
1399             {
1400               tmp = self->fade_out_pos;
1401               position_add_ticks (&tmp, - ticks);
1402               arranger_object_set_position (
1403                 self, &tmp,
1404                 ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT,
1405                 F_NO_VALIDATE);
1406             }
1407 
1408           if (type == ARRANGER_OBJECT_RESIZE_LOOP)
1409             {
1410               double loop_len =
1411                 arranger_object_get_loop_length_in_ticks (
1412                   self);
1413 
1414               /* if clip start is not before loop
1415                * start, adjust clip start pos */
1416               if (position_is_after_or_equal (
1417                     &self->clip_start_pos,
1418                     &self->loop_start_pos))
1419                 {
1420                   position_add_ticks (
1421                     &self->clip_start_pos,
1422                     ticks);
1423 
1424                   while (
1425                     position_is_before (
1426                       &self->clip_start_pos,
1427                       &self->loop_start_pos))
1428                     {
1429                       position_add_ticks (
1430                         &self->clip_start_pos,
1431                         loop_len);
1432                     }
1433                 }
1434 
1435               /* make sure clip start goes back to
1436                * loop start if it exceeds loop
1437                * end */
1438               while (
1439                 position_is_after (
1440                   &self->clip_start_pos,
1441                   &self->loop_end_pos))
1442                 {
1443                   position_add_ticks (
1444                     &self->clip_start_pos,
1445                     - loop_len);
1446                 }
1447             }
1448           else if (arranger_object_type_can_loop (
1449                     self->type))
1450             {
1451               tmp = self->loop_end_pos;
1452               position_add_ticks (&tmp, - ticks);
1453               arranger_object_set_position (
1454                 self, &tmp,
1455                 ARRANGER_OBJECT_POSITION_TYPE_LOOP_END,
1456                 F_NO_VALIDATE);
1457 
1458               /* move containing items */
1459               arranger_object_add_ticks_to_children (
1460                 self, - ticks);
1461             }
1462         }
1463     }
1464   /* else if resizing right side */
1465   else
1466     {
1467       if (type == ARRANGER_OBJECT_RESIZE_FADE)
1468         {
1469           tmp = self->fade_out_pos;
1470           position_add_ticks (&tmp, ticks);
1471           arranger_object_set_position (
1472             self, &tmp,
1473             ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT,
1474             F_NO_VALIDATE);
1475         }
1476       else
1477         {
1478           tmp = self->end_pos;
1479           Position prev_end_pos = self->end_pos;
1480           position_add_ticks (&tmp, ticks);
1481           arranger_object_set_position (
1482             self, &tmp,
1483             ARRANGER_OBJECT_POSITION_TYPE_END,
1484             F_NO_VALIDATE);
1485 
1486           double change_ratio =
1487             (self->end_pos.ticks - self->pos.ticks) /
1488             (prev_end_pos.ticks - self->pos.ticks);
1489 
1490           if (type != ARRANGER_OBJECT_RESIZE_LOOP
1491               &&
1492               arranger_object_type_can_loop (
1493                 self->type))
1494             {
1495               tmp = self->loop_end_pos;
1496               if (type == ARRANGER_OBJECT_RESIZE_STRETCH_BPM_CHANGE
1497                   ||
1498                   type == ARRANGER_OBJECT_RESIZE_STRETCH)
1499                 {
1500                   position_from_ticks (
1501                     &tmp,
1502                     self->loop_end_pos.ticks * change_ratio);
1503                 }
1504               else
1505                 {
1506                   position_add_ticks (&tmp, ticks);
1507                 }
1508               z_return_if_fail_cmp (
1509                 tmp.frames, >=, 0);
1510               arranger_object_set_position (
1511                 self, &tmp,
1512                 ARRANGER_OBJECT_POSITION_TYPE_LOOP_END,
1513                 F_NO_VALIDATE);
1514               g_return_if_fail (
1515                 self->loop_end_pos.frames >= 0);
1516 
1517               /* if stretching, also stretch loop
1518                * start */
1519               if (type == ARRANGER_OBJECT_RESIZE_STRETCH_BPM_CHANGE
1520                   ||
1521                   type == ARRANGER_OBJECT_RESIZE_STRETCH)
1522                 {
1523                   tmp = self->loop_start_pos;
1524                   position_from_ticks (
1525                     &tmp,
1526                     self->loop_start_pos.ticks * change_ratio);
1527                   z_return_if_fail_cmp (
1528                     tmp.frames, >=, 0);
1529                   arranger_object_set_position (
1530                     self, &tmp,
1531                     ARRANGER_OBJECT_POSITION_TYPE_LOOP_START,
1532                     F_NO_VALIDATE);
1533                   g_return_if_fail (
1534                     self->loop_start_pos.frames >= 0);
1535                 }
1536             }
1537           if (arranger_object_can_fade (self))
1538             {
1539               tmp = self->fade_out_pos;
1540               if (type == ARRANGER_OBJECT_RESIZE_STRETCH_BPM_CHANGE
1541                   ||
1542                   type == ARRANGER_OBJECT_RESIZE_STRETCH)
1543                 {
1544                   position_from_ticks (
1545                     &tmp,
1546                     self->fade_out_pos.ticks * change_ratio);
1547                 }
1548               else
1549                 {
1550                   position_add_ticks (&tmp, ticks);
1551                 }
1552               z_return_if_fail_cmp (
1553                 tmp.frames, >=, 0);
1554               arranger_object_set_position (
1555                 self, &tmp,
1556                 ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT,
1557                 F_NO_VALIDATE);
1558               g_return_if_fail (
1559                 self->fade_out_pos.frames >= 0);
1560 
1561               /* if stretching, also stretch fade
1562                * in */
1563               if (type == ARRANGER_OBJECT_RESIZE_STRETCH_BPM_CHANGE
1564                   ||
1565                   type == ARRANGER_OBJECT_RESIZE_STRETCH)
1566                 {
1567                   tmp = self->fade_in_pos;
1568                   position_from_ticks (
1569                     &tmp,
1570                     self->fade_in_pos.ticks * change_ratio);
1571                   z_return_if_fail_cmp (
1572                     tmp.frames, >=, 0);
1573                   arranger_object_set_position (
1574                     self, &tmp,
1575                     ARRANGER_OBJECT_POSITION_TYPE_FADE_IN,
1576                     F_NO_VALIDATE);
1577                   g_return_if_fail (
1578                     self->fade_in_pos.frames >= 0);
1579                 }
1580             }
1581 
1582           if (type ==
1583                 ARRANGER_OBJECT_RESIZE_STRETCH
1584               &&
1585               self->type ==
1586                 ARRANGER_OBJECT_TYPE_REGION)
1587             {
1588 #if 0
1589               /* move fade out */
1590               tmp = self->fade_out_pos;
1591               position_add_ticks (&tmp, ticks);
1592               arranger_object_set_position (
1593                 self, &tmp,
1594                 ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT,
1595                 F_NO_VALIDATE);
1596 #endif
1597 
1598               ZRegion * region = (ZRegion *) self;
1599               double new_length =
1600                 arranger_object_get_length_in_ticks (
1601                   self);
1602 
1603               if (type !=
1604                     ARRANGER_OBJECT_RESIZE_STRETCH_BPM_CHANGE)
1605                 {
1606                   /* FIXME this flag is not good,
1607                    * remove from this function and
1608                    * do it in the arranger */
1609                   if (during_ui_action)
1610                     {
1611                       region->stretch_ratio =
1612                         new_length /
1613                         region->before_length;
1614                     }
1615                   /* else if as part of an action */
1616                   else
1617                     {
1618                       /* stretch contents */
1619                       double stretch_ratio =
1620                         new_length / before_length;
1621                       g_message ("resizing with %f",
1622                         stretch_ratio);
1623                       region_stretch (
1624                         region, stretch_ratio);
1625                     }
1626                 }
1627             }
1628         }
1629     }
1630 }
1631 
1632 static void
post_deserialize_children(ArrangerObject * self)1633 post_deserialize_children (
1634   ArrangerObject * self)
1635 {
1636   if (self->type == TYPE (REGION))
1637     {
1638       ZRegion * r = (ZRegion *) self;
1639       for (int i = 0; i < r->num_midi_notes; i++)
1640         {
1641           MidiNote * mn = r->midi_notes[i];
1642           arranger_object_post_deserialize (
1643             (ArrangerObject *) mn);
1644         }
1645 
1646       for (int i = 0; i < r->num_aps; i++)
1647         {
1648           AutomationPoint * ap = r->aps[i];
1649           arranger_object_post_deserialize (
1650             (ArrangerObject *) ap);
1651         }
1652 
1653       for (int i = 0; i < r->num_chord_objects;
1654            i++)
1655         {
1656           ChordObject * co = r->chord_objects[i];
1657           arranger_object_post_deserialize (
1658             (ArrangerObject *) co);
1659         }
1660     }
1661 }
1662 
1663 void
arranger_object_post_deserialize(ArrangerObject * self)1664 arranger_object_post_deserialize (
1665   ArrangerObject * self)
1666 {
1667   g_return_if_fail (self);
1668 
1669   self->magic = ARRANGER_OBJECT_MAGIC;
1670 
1671   switch (self->type)
1672     {
1673     case TYPE (REGION):
1674       {
1675         ZRegion * r = (ZRegion *) self;
1676         r->magic = REGION_MAGIC;
1677       }
1678       break;
1679     case TYPE (SCALE_OBJECT):
1680       {
1681         ScaleObject * so = (ScaleObject *) self;
1682         so->magic = SCALE_OBJECT_MAGIC;
1683       }
1684       break;
1685     case TYPE (MARKER):
1686       {
1687         /*Marker * marker = (Marker *) self;*/
1688       }
1689       break;
1690     case TYPE (AUTOMATION_POINT):
1691       {
1692         /*AutomationPoint * ap =*/
1693           /*(AutomationPoint *) self;*/
1694       }
1695       break;
1696     case TYPE (CHORD_OBJECT):
1697       {
1698         ChordObject * co = (ChordObject *) self;
1699         co->magic = CHORD_OBJECT_MAGIC;
1700       }
1701       break;
1702     case TYPE (MIDI_NOTE):
1703       {
1704         MidiNote * mn = (MidiNote *) self;
1705         mn->magic = MIDI_NOTE_MAGIC;
1706         ((ArrangerObject *) mn->vel)->magic =
1707           ARRANGER_OBJECT_MAGIC;
1708       }
1709       break;
1710     case TYPE (VELOCITY):
1711       break;
1712     default:
1713       g_warn_if_reached ();
1714       break;
1715     }
1716 
1717   post_deserialize_children (self);
1718 }
1719 
1720 /**
1721  * The setter is for use in e.g. the digital meters
1722  * whereas the set_pos func is used during
1723  * arranger actions.
1724  */
1725 void
arranger_object_pos_setter(ArrangerObject * self,const Position * pos)1726 arranger_object_pos_setter (
1727   ArrangerObject * self,
1728   const Position * pos)
1729 {
1730   arranger_object_set_position (
1731     self, pos,
1732     ARRANGER_OBJECT_POSITION_TYPE_START,
1733     F_VALIDATE);
1734 }
1735 
1736 /**
1737  * The setter is for use in e.g. the digital meters
1738  * whereas the set_pos func is used during
1739  * arranger actions.
1740  */
1741 void
arranger_object_end_pos_setter(ArrangerObject * self,const Position * pos)1742 arranger_object_end_pos_setter (
1743   ArrangerObject * self,
1744   const Position * pos)
1745 {
1746   arranger_object_set_position (
1747     self, pos,
1748     ARRANGER_OBJECT_POSITION_TYPE_END,
1749     F_VALIDATE);
1750 }
1751 
1752 /**
1753  * The setter is for use in e.g. the digital meters
1754  * whereas the set_pos func is used during
1755  * arranger actions.
1756  */
1757 void
arranger_object_clip_start_pos_setter(ArrangerObject * self,const Position * pos)1758 arranger_object_clip_start_pos_setter (
1759   ArrangerObject * self,
1760   const Position * pos)
1761 {
1762   arranger_object_set_position (
1763     self, pos,
1764     ARRANGER_OBJECT_POSITION_TYPE_CLIP_START,
1765     F_VALIDATE);
1766 }
1767 
1768 /**
1769  * The setter is for use in e.g. the digital meters
1770  * whereas the set_pos func is used during
1771  * arranger actions.
1772  */
1773 void
arranger_object_loop_start_pos_setter(ArrangerObject * self,const Position * pos)1774 arranger_object_loop_start_pos_setter (
1775   ArrangerObject * self,
1776   const Position * pos)
1777 {
1778   arranger_object_set_position (
1779     self, pos,
1780     ARRANGER_OBJECT_POSITION_TYPE_LOOP_START,
1781     F_VALIDATE);
1782 }
1783 
1784 /**
1785  * The setter is for use in e.g. the digital meters
1786  * whereas the set_pos func is used during
1787  * arranger actions.
1788  */
1789 void
arranger_object_loop_end_pos_setter(ArrangerObject * self,const Position * pos)1790 arranger_object_loop_end_pos_setter (
1791   ArrangerObject * self,
1792   const Position * pos)
1793 {
1794   arranger_object_set_position (
1795     self, pos,
1796     ARRANGER_OBJECT_POSITION_TYPE_LOOP_END,
1797     F_VALIDATE);
1798 }
1799 
1800 /**
1801  * Validates the given Position.
1802  *
1803  * @return 1 if valid, 0 otherwise.
1804  */
1805 int
arranger_object_validate_pos(const ArrangerObject * const self,const Position * pos,ArrangerObjectPositionType type)1806 arranger_object_validate_pos (
1807   const ArrangerObject * const self,
1808   const Position *             pos,
1809   ArrangerObjectPositionType   type)
1810 {
1811   switch (self->type)
1812     {
1813     case TYPE (REGION):
1814       switch (type)
1815         {
1816         case POSITION_TYPE (START):
1817           return
1818             position_is_before (
1819               pos, &self->end_pos) &&
1820             position_is_after_or_equal (
1821               pos, &POSITION_START);
1822           break;
1823         default:
1824           break;
1825         }
1826       break;
1827     default:
1828       break;
1829     }
1830 
1831   return 1;
1832 }
1833 
1834 /**
1835  * Validates the arranger object.
1836  *
1837  * @return True if valid.
1838  */
1839 bool
arranger_object_validate(const ArrangerObject * const self)1840 arranger_object_validate (
1841   const ArrangerObject * const self)
1842 {
1843   if (!arranger_object_validate_pos (
1844          self, &self->pos,
1845          ARRANGER_OBJECT_POSITION_TYPE_START))
1846     return false;
1847 
1848   if (arranger_object_type_has_length (self->type))
1849     {
1850       if (!arranger_object_validate_pos (
1851              self, &self->end_pos,
1852              ARRANGER_OBJECT_POSITION_TYPE_END))
1853         return false;
1854     }
1855   if (arranger_object_type_can_loop (self->type))
1856     {
1857       if (!arranger_object_validate_pos (
1858              self, &self->loop_start_pos,
1859              ARRANGER_OBJECT_POSITION_TYPE_LOOP_START))
1860         return false;
1861       if (!arranger_object_validate_pos (
1862              self, &self->loop_end_pos,
1863              ARRANGER_OBJECT_POSITION_TYPE_LOOP_END))
1864         return false;
1865       if (!arranger_object_validate_pos (
1866              self, &self->clip_start_pos,
1867              ARRANGER_OBJECT_POSITION_TYPE_CLIP_START))
1868         return false;
1869     }
1870   if (arranger_object_can_fade (self))
1871     {
1872       if (!arranger_object_validate_pos (
1873              self, &self->fade_in_pos,
1874              ARRANGER_OBJECT_POSITION_TYPE_FADE_IN))
1875         return false;
1876       if (!arranger_object_validate_pos (
1877              self, &self->fade_out_pos,
1878              ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT))
1879         return false;
1880     }
1881 
1882   return true;
1883 }
1884 
1885 /**
1886  * Validates the given name.
1887  *
1888  * @return True if valid, false otherwise.
1889  */
1890 bool
arranger_object_validate_name(ArrangerObject * self,const char * name)1891 arranger_object_validate_name (
1892   ArrangerObject * self,
1893   const char *     name)
1894 {
1895   switch (self->type)
1896     {
1897     case ARRANGER_OBJECT_TYPE_REGION:
1898       return true;
1899     case ARRANGER_OBJECT_TYPE_MARKER:
1900       if (marker_find_by_name (name))
1901         {
1902           return false;
1903         }
1904       else
1905         {
1906           return true;
1907         }
1908       break;
1909     default:
1910       g_warn_if_reached ();
1911     }
1912   return false;
1913 }
1914 
1915 /**
1916  * Returns the Track this ArrangerObject is in.
1917  */
1918 Track *
arranger_object_get_track(const ArrangerObject * const self)1919 arranger_object_get_track (
1920   const ArrangerObject * const self)
1921 {
1922   g_return_val_if_fail (
1923     IS_ARRANGER_OBJECT (self), NULL);
1924 
1925   Track * track = NULL;
1926   Tracklist * tracklist =
1927     self->is_auditioner ?
1928       SAMPLE_PROCESSOR->tracklist : TRACKLIST;
1929 
1930   switch (self->type)
1931     {
1932     case TYPE (REGION):
1933       {
1934         const ZRegion * const  r =
1935           (const ZRegion * const) self;
1936         track =
1937           tracklist_find_track_by_name_hash (
1938             tracklist, r->id.track_name_hash);
1939         g_return_val_if_fail (
1940           IS_TRACK_AND_NONNULL (track), NULL);
1941       }
1942       break;
1943     case TYPE (SCALE_OBJECT):
1944       {
1945         return P_CHORD_TRACK;
1946       }
1947       break;
1948     case TYPE (MARKER):
1949       {
1950         const Marker * const marker =
1951           (const Marker * const) self;
1952         track =
1953           tracklist_find_track_by_name_hash (
1954             tracklist, marker->track_name_hash);
1955         g_return_val_if_fail (
1956           IS_TRACK_AND_NONNULL (track), NULL);
1957       }
1958       break;
1959     case TYPE (AUTOMATION_POINT):
1960       {
1961         const AutomationPoint * const ap =
1962           (const AutomationPoint * const) self;
1963         AutomationTrack * at =
1964           automation_point_get_automation_track (
1965             ap);
1966         track =
1967           automation_track_get_track (at);
1968       }
1969       break;
1970     case TYPE (CHORD_OBJECT):
1971     case TYPE (MIDI_NOTE):
1972       track =
1973         tracklist_find_track_by_name_hash (
1974           tracklist,
1975           self->region_id.track_name_hash);
1976       g_return_val_if_fail (
1977         IS_TRACK_AND_NONNULL (track), NULL);
1978       break;
1979     case TYPE (VELOCITY):
1980       {
1981         const Velocity * const vel =
1982           (const Velocity * const) self;
1983         const MidiNote * const mn =
1984           velocity_get_midi_note (vel);
1985         const ArrangerObject * const mn_obj =
1986           (const ArrangerObject * const) mn;
1987         track =
1988           tracklist_find_track_by_name_hash (
1989             tracklist,
1990             mn_obj->region_id.track_name_hash);
1991         g_return_val_if_fail (
1992           IS_TRACK_AND_NONNULL (track), NULL);
1993       }
1994       break;
1995     default:
1996       g_warn_if_reached ();
1997       break;
1998     }
1999 
2000   g_return_val_if_fail (
2001     IS_TRACK_AND_NONNULL (track), NULL);
2002 
2003   return track;
2004 }
2005 
2006 /**
2007  * Gets the arranger for this arranger object.
2008  */
2009 ArrangerWidget *
arranger_object_get_arranger(ArrangerObject * self)2010 arranger_object_get_arranger (
2011   ArrangerObject * self)
2012 {
2013   g_return_val_if_fail (
2014     IS_ARRANGER_OBJECT (self), NULL);
2015 
2016   Track * track =
2017     arranger_object_get_track (self);
2018   g_return_val_if_fail (track, NULL);
2019 
2020   ArrangerWidget * arranger = NULL;
2021   switch (self->type)
2022     {
2023     case TYPE (REGION):
2024       {
2025         if (track_is_pinned (track))
2026           {
2027             arranger =
2028               (ArrangerWidget *) (MW_PINNED_TIMELINE);
2029           }
2030         else
2031           {
2032             arranger =
2033               (ArrangerWidget *) (MW_TIMELINE);
2034           }
2035       }
2036       break;
2037     case TYPE (CHORD_OBJECT):
2038       arranger =
2039         (ArrangerWidget *) (MW_CHORD_ARRANGER);
2040       break;
2041     case TYPE (SCALE_OBJECT):
2042       {
2043         if (track_is_pinned (track))
2044           {
2045             arranger =
2046               (ArrangerWidget *) (MW_PINNED_TIMELINE);
2047           }
2048         else
2049           {
2050             arranger =
2051               (ArrangerWidget *) (MW_TIMELINE);
2052           }
2053       }
2054       break;
2055     case TYPE (MARKER):
2056       {
2057         if (track_is_pinned (track))
2058           {
2059             arranger =
2060               (ArrangerWidget *) (MW_PINNED_TIMELINE);
2061           }
2062         else
2063           {
2064             arranger =
2065               (ArrangerWidget *) (MW_TIMELINE);
2066           }
2067       }
2068       break;
2069     case TYPE (AUTOMATION_POINT):
2070       arranger =
2071         (ArrangerWidget *) (MW_AUTOMATION_ARRANGER);
2072       break;
2073     case TYPE (MIDI_NOTE):
2074       arranger =
2075         (ArrangerWidget *) (MW_MIDI_ARRANGER);
2076       break;
2077     case TYPE (VELOCITY):
2078       arranger =
2079         (ArrangerWidget *) (MW_MIDI_MODIFIER_ARRANGER);
2080       break;
2081     default:
2082       g_return_val_if_reached (NULL);
2083     }
2084 
2085   g_warn_if_fail (arranger);
2086   return arranger;
2087 }
2088 
2089 /**
2090  * Returns if the cached object should be visible,
2091  * ie, while copy- moving (ctrl+drag) we want to
2092  * show both the object at its original position
2093  * and the current object.
2094  *
2095  * This refers to the object at its original
2096  * position (called "transient").
2097  */
2098 bool
arranger_object_should_orig_be_visible(ArrangerObject * self)2099 arranger_object_should_orig_be_visible (
2100   ArrangerObject * self)
2101 {
2102   g_return_val_if_fail (self, 0);
2103 
2104   if (!ZRYTHM_HAVE_UI)
2105     {
2106       return false;
2107     }
2108 
2109   ArrangerWidget * arranger =
2110     arranger_object_get_arranger (self);
2111   g_return_val_if_fail (arranger, false);
2112 
2113   /* check trans/non-trans visiblity */
2114   if (ARRANGER_WIDGET_GET_ACTION (
2115         arranger, MOVING) ||
2116       ARRANGER_WIDGET_GET_ACTION (
2117         arranger, CREATING_MOVING))
2118     {
2119       return false;
2120     }
2121   else if (
2122     ARRANGER_WIDGET_GET_ACTION (
2123       arranger, MOVING_COPY) ||
2124     ARRANGER_WIDGET_GET_ACTION (
2125       arranger, MOVING_LINK))
2126     {
2127       return true;
2128     }
2129   else
2130     {
2131       return false;
2132     }
2133 }
2134 
2135 static ArrangerObject *
find_region(ZRegion * self)2136 find_region (
2137   ZRegion * self)
2138 {
2139   g_return_val_if_fail (IS_REGION (self), NULL);
2140 
2141   g_debug (
2142     "looking for project region '%s'",
2143     self->name);
2144 
2145   ArrangerObject * obj =
2146     (ArrangerObject *)
2147     region_find (&self->id);
2148 
2149   if (!IS_REGION (obj))
2150     {
2151       g_critical ("region not found");
2152       return NULL;
2153     }
2154 
2155   g_debug ("found:");
2156   region_print ((ZRegion *) obj);
2157 
2158   bool has_warning = false;
2159   g_debug (
2160     "verifying positions are the same...");
2161   ArrangerObject * self_obj =
2162     (ArrangerObject *) self;
2163   if (!position_is_equal_ticks (
2164         &self_obj->pos, &obj->pos))
2165     {
2166       char tmp[100];
2167       position_to_string (&self_obj->pos, tmp);
2168       char tmp2[100];
2169       position_to_string (&obj->pos, tmp2);
2170       g_warning (
2171         "start positions are not equal: "
2172         "%s (own) vs %s (project)",
2173         tmp, tmp2);
2174       has_warning = true;
2175     }
2176   if (!position_is_equal_ticks (
2177          &self_obj->end_pos, &obj->end_pos))
2178     {
2179       char tmp[100];
2180       position_to_string (&self_obj->end_pos, tmp);
2181       char tmp2[100];
2182       position_to_string (&obj->end_pos, tmp2);
2183       g_warning (
2184         "end positions are not equal: "
2185         "%s (own) vs %s (project)",
2186         tmp, tmp2);
2187       has_warning = true;
2188     }
2189 
2190   if (has_warning)
2191     {
2192       g_debug ("own region:");
2193       region_print (self);
2194       g_debug ("found region:");
2195       region_print ((ZRegion *) obj);
2196     }
2197 
2198   g_debug ("checked positions");
2199 
2200   return obj;
2201 }
2202 
2203 static ArrangerObject *
find_chord_object(ChordObject * clone)2204 find_chord_object (
2205   ChordObject * clone)
2206 {
2207   ArrangerObject * clone_obj =
2208     (ArrangerObject *) clone;
2209 
2210   /* get actual region - clone's region might be
2211    * an unused clone */
2212   ZRegion * r =
2213     region_find (&clone_obj->region_id);
2214   g_return_val_if_fail (r, NULL);
2215 
2216   g_return_val_if_fail (
2217     r && r->num_chord_objects > clone->index, NULL);
2218 
2219   ChordObject * prj_co =
2220     r->chord_objects[clone->index];
2221   g_return_val_if_fail (
2222     chord_object_is_equal (prj_co, clone), NULL);
2223 
2224   return (ArrangerObject *) prj_co;
2225 }
2226 
2227 static ArrangerObject *
find_scale_object(ScaleObject * clone)2228 find_scale_object (
2229   ScaleObject * clone)
2230 {
2231   g_return_val_if_fail (
2232     clone->index < P_CHORD_TRACK->num_scales, NULL);
2233   ScaleObject * prj_co =
2234     P_CHORD_TRACK->scales[clone->index];
2235   g_return_val_if_fail (
2236     scale_object_is_equal (prj_co, clone), NULL);
2237 
2238   return (ArrangerObject *) prj_co;
2239 }
2240 
2241 static ArrangerObject *
find_marker(Marker * clone)2242 find_marker (
2243   Marker * clone)
2244 {
2245   g_return_val_if_fail (
2246     P_MARKER_TRACK->num_markers > clone->index,
2247     NULL);
2248 
2249   Marker * marker =
2250     P_MARKER_TRACK->markers[clone->index];
2251   g_warn_if_fail (
2252     marker_is_equal (marker, clone));
2253 
2254   return (ArrangerObject *) marker;
2255 }
2256 
2257 static ArrangerObject *
find_automation_point(AutomationPoint * src)2258 find_automation_point (
2259   AutomationPoint * src)
2260 {
2261   ArrangerObject * src_obj =
2262     (ArrangerObject *) src;
2263   ZRegion * region =
2264     region_find (&src_obj->region_id);
2265   g_return_val_if_fail (
2266     region && region->num_aps > src->index, NULL);
2267 
2268   AutomationPoint * ap = region->aps[src->index];
2269   g_return_val_if_fail (
2270     automation_point_is_equal (src, ap), NULL);
2271 
2272   return (ArrangerObject *) ap;
2273 }
2274 
2275 static ArrangerObject *
find_midi_note(MidiNote * src)2276 find_midi_note (
2277   MidiNote * src)
2278 {
2279   ArrangerObject * src_obj =
2280     (ArrangerObject *) src;
2281   ZRegion * r =
2282     region_find (&src_obj->region_id);
2283   g_return_val_if_fail (
2284     r && r->num_midi_notes > src->pos, NULL);
2285 
2286   return
2287     (ArrangerObject *)
2288     r->midi_notes[src->pos];
2289 }
2290 
2291 /**
2292  * Returns the ArrangerObject matching the
2293  * given one.
2294  *
2295  * This should be called when we have a copy or a
2296  * clone, to get the actual region in the project.
2297  */
2298 ArrangerObject *
arranger_object_find(ArrangerObject * self)2299 arranger_object_find (
2300   ArrangerObject * self)
2301 {
2302   switch (self->type)
2303     {
2304     case TYPE (REGION):
2305       return
2306         find_region ((ZRegion *) self);
2307     case TYPE (CHORD_OBJECT):
2308       return
2309         find_chord_object ((ChordObject *) self);
2310     case TYPE (SCALE_OBJECT):
2311       return
2312         find_scale_object ((ScaleObject *) self);
2313     case TYPE (MARKER):
2314       return
2315         find_marker ((Marker *) self);
2316     case TYPE (AUTOMATION_POINT):
2317       return
2318         find_automation_point (
2319           (AutomationPoint *) self);
2320     case TYPE (MIDI_NOTE):
2321       return
2322         find_midi_note ((MidiNote *) self);
2323     case TYPE (VELOCITY):
2324       {
2325         Velocity * clone =
2326           (Velocity *) self;
2327         MidiNote * mn =
2328           (MidiNote *)
2329           velocity_get_midi_note (clone);
2330         g_return_val_if_fail (mn && mn->vel, NULL);
2331         return (ArrangerObject *) mn->vel;
2332       }
2333     default:
2334       g_return_val_if_reached (NULL);
2335     }
2336   g_return_val_if_reached (NULL);
2337 }
2338 
2339 static ArrangerObject *
clone_region(ZRegion * region)2340 clone_region (
2341   ZRegion *               region)
2342 {
2343   g_return_val_if_fail (region->name, NULL);
2344 
2345   ArrangerObject * r_obj =
2346     (ArrangerObject *) region;
2347   ZRegion * new_region = NULL;
2348   switch (region->id.type)
2349     {
2350     case REGION_TYPE_MIDI:
2351       {
2352         ZRegion * mr =
2353           midi_region_new (
2354             &r_obj->pos, &r_obj->end_pos,
2355             region->id.track_name_hash,
2356             region->id.lane_pos,
2357             region->id.idx);
2358         ZRegion * mr_orig = region;
2359         for (int i = 0;
2360              i < mr_orig->num_midi_notes; i++)
2361           {
2362             MidiNote * orig_mn =
2363               mr_orig->midi_notes[i];
2364             ArrangerObject * orig_mn_obj =
2365               (ArrangerObject *) orig_mn;
2366             MidiNote * mn;
2367 
2368             region_identifier_copy (
2369               &orig_mn_obj->region_id,
2370               &mr_orig->id);
2371             mn =
2372               (MidiNote *)
2373               arranger_object_clone (
2374                 (ArrangerObject *)
2375                 mr_orig->midi_notes[i]);
2376 
2377             midi_region_add_midi_note (
2378               mr, mn, F_NO_PUBLISH_EVENTS);
2379           }
2380 
2381         new_region = (ZRegion *) mr;
2382       }
2383     break;
2384     case REGION_TYPE_AUDIO:
2385       {
2386         ZRegion * ar =
2387           audio_region_new (
2388             region->pool_id, NULL, true, NULL, -1,
2389             NULL, 0, 0, &r_obj->pos,
2390             region->id.track_name_hash,
2391             region->id.lane_pos,
2392             region->id.idx);
2393 
2394 #if 0
2395         /* copy the actual frames - they might
2396          * be different from the clip due to
2397          * eg. stretching */
2398         AudioClip * clip =
2399           audio_region_get_clip (region);
2400         size_t frame_bytes_size =
2401           sizeof (float) *
2402             (size_t) region->num_frames *
2403             clip->channels;
2404         ar->frames =
2405           realloc (
2406             ar->frames, frame_bytes_size);
2407         ar->num_frames = region->num_frames;
2408         memcpy (
2409           &ar->frames[0], &region->frames[0],
2410           frame_bytes_size);
2411 #endif
2412 
2413         new_region = ar;
2414         new_region->pool_id = region->pool_id;
2415         new_region->gain = region->gain;
2416         ar->musical_mode = region->musical_mode;
2417       }
2418     break;
2419     case REGION_TYPE_AUTOMATION:
2420       {
2421         ZRegion * ar  =
2422           automation_region_new (
2423             &r_obj->pos, &r_obj->end_pos,
2424             region->id.track_name_hash,
2425             region->id.at_idx,
2426             region->id.idx);
2427         ZRegion * ar_orig = region;
2428 
2429         /* add automation points */
2430         AutomationPoint * src_ap, * dest_ap;
2431         for (int j = 0; j < ar_orig->num_aps; j++)
2432           {
2433             src_ap = ar_orig->aps[j];
2434             ArrangerObject * src_ap_obj =
2435               (ArrangerObject *) src_ap;
2436 
2437             dest_ap =
2438               automation_point_new_float (
2439                 src_ap->fvalue,
2440                 src_ap->normalized_val,
2441                 &src_ap_obj->pos);
2442             dest_ap->curve_opts =
2443               src_ap->curve_opts;
2444             automation_region_add_ap (
2445               ar, dest_ap, F_NO_PUBLISH_EVENTS);
2446           }
2447 
2448         new_region = ar;
2449       }
2450       break;
2451     case REGION_TYPE_CHORD:
2452       {
2453         ZRegion * cr =
2454           chord_region_new (
2455             &r_obj->pos, &r_obj->end_pos,
2456             region->id.idx);
2457         ZRegion * cr_orig = region;
2458         ChordObject * src_co, * dest_co;
2459         for (int i = 0;
2460              i < cr_orig->num_chord_objects;
2461              i++)
2462           {
2463             src_co = cr_orig->chord_objects[i];
2464 
2465             dest_co =
2466               (ChordObject *)
2467               arranger_object_clone (
2468                 (ArrangerObject *) src_co);
2469             g_return_val_if_fail (dest_co, NULL);
2470 
2471             chord_region_add_chord_object (
2472               cr, dest_co, F_NO_PUBLISH_EVENTS);
2473           }
2474 
2475         new_region = cr;
2476       }
2477       break;
2478     }
2479 
2480   g_return_val_if_fail (
2481     new_region &&
2482     new_region->schema_version ==
2483       REGION_SCHEMA_VERSION,
2484     NULL);
2485 
2486   /* clone name */
2487   new_region->name = g_strdup (region->name);
2488   arranger_object_gen_escaped_name (
2489     (ArrangerObject *) new_region);
2490 
2491   /* set track to NULL and remember track pos */
2492   region_identifier_copy (
2493     &new_region->id, &region->id);
2494   g_warn_if_fail (new_region->id.idx >= 0);
2495 
2496   return (ArrangerObject *) new_region;
2497 }
2498 
2499 /**
2500  * Returns a pointer to the name of the object,
2501  * if the object can have names.
2502  */
2503 const char *
arranger_object_get_name(ArrangerObject * self)2504 arranger_object_get_name (
2505   ArrangerObject * self)
2506 {
2507   switch (self->type)
2508     {
2509     case ARRANGER_OBJECT_TYPE_REGION:
2510       {
2511         ZRegion * r = (ZRegion *) self;
2512         return r->name;
2513       }
2514       break;
2515     case ARRANGER_OBJECT_TYPE_MARKER:
2516       {
2517         Marker * m = (Marker *) self;
2518         return m->name;
2519       }
2520       break;
2521     default:
2522       break;
2523     }
2524   return NULL;
2525 }
2526 
2527 /**
2528  * Generates the escaped name for the object,
2529  * where applicable.
2530  */
2531 void
arranger_object_gen_escaped_name(ArrangerObject * self)2532 arranger_object_gen_escaped_name (
2533   ArrangerObject * self)
2534 {
2535   switch (self->type)
2536     {
2537     case ARRANGER_OBJECT_TYPE_REGION:
2538       {
2539         ZRegion * r = (ZRegion *) self;
2540         r->escaped_name =
2541           g_markup_escape_text (r->name, -1);
2542       }
2543       break;
2544     case ARRANGER_OBJECT_TYPE_MARKER:
2545       {
2546         Marker * m = (Marker *) self;
2547         m->escaped_name =
2548           g_markup_escape_text (m->name, -1);
2549       }
2550       break;
2551     default:
2552       break;
2553     }
2554 }
2555 
2556 static ArrangerObject *
clone_midi_note(MidiNote * src)2557 clone_midi_note (
2558   MidiNote *              src)
2559 {
2560   ArrangerObject * src_obj =
2561     (ArrangerObject *) src;
2562   MidiNote * mn =
2563     midi_note_new (
2564       &src_obj->region_id, &src_obj->pos,
2565       &src_obj->end_pos,
2566       src->val, src->vel->vel);
2567   mn->currently_listened = src->currently_listened;
2568   mn->last_listened_val = src->last_listened_val;
2569   mn->pos = src->pos;
2570   mn->vel->vel_at_start = src->vel->vel_at_start;
2571 
2572   return (ArrangerObject *) mn;
2573 }
2574 
2575 static ArrangerObject *
clone_chord_object(ChordObject * src)2576 clone_chord_object (
2577   ChordObject *           src)
2578 {
2579   ArrangerObject * src_obj =
2580     (ArrangerObject *) src;
2581   ChordObject * chord =
2582     chord_object_new (
2583       &src_obj->region_id, src->chord_index,
2584       src->index);
2585 
2586   return (ArrangerObject *) chord;
2587 }
2588 
2589 static ArrangerObject *
clone_scale_object(ScaleObject * src)2590 clone_scale_object (
2591   ScaleObject * src)
2592 {
2593   MusicalScale * musical_scale =
2594     musical_scale_clone (src->scale);
2595   ScaleObject * scale =
2596     scale_object_new (musical_scale);
2597   scale->index = src->index;
2598 
2599   return (ArrangerObject *) scale;
2600 }
2601 
2602 static ArrangerObject *
clone_marker(Marker * src)2603 clone_marker (
2604   Marker *                src)
2605 {
2606   Marker * marker = marker_new (src->name);
2607   marker->index = src->index;
2608   marker->type = src->type;
2609   marker->track_name_hash = src->track_name_hash;
2610 
2611   return (ArrangerObject *) marker;
2612 }
2613 
2614 static ArrangerObject *
clone_automation_point(AutomationPoint * src)2615 clone_automation_point (
2616   AutomationPoint *       src)
2617 {
2618   if (ZRYTHM_TESTING)
2619     {
2620       g_return_val_if_fail (
2621         math_assert_nonnann (
2622           src->normalized_val) &&
2623         math_assert_nonnann (src->fvalue),
2624         NULL);
2625     }
2626 
2627   ArrangerObject * src_obj =
2628     (ArrangerObject *) src;
2629   AutomationPoint * ap =
2630     automation_point_new_float (
2631       src->fvalue, src->normalized_val,
2632       &src_obj->pos);
2633   ap->curve_opts = src->curve_opts;
2634   ArrangerObject * ap_obj =
2635     (ArrangerObject *) ap;
2636   region_identifier_copy (
2637     &ap_obj->region_id, &src_obj->region_id);
2638   ap->index = src->index;
2639 
2640   return ap_obj;
2641 }
2642 
2643 /**
2644  * Clones the ArrangerObject.
2645  */
2646 ArrangerObject *
arranger_object_clone(ArrangerObject * self)2647 arranger_object_clone (
2648   ArrangerObject * self)
2649 {
2650   g_return_val_if_fail (self, NULL);
2651 
2652   ArrangerObject * new_obj = NULL;
2653   switch (self->type)
2654     {
2655     case TYPE (REGION):
2656       new_obj =
2657         clone_region ((ZRegion *) self);
2658       break;
2659     case TYPE (MIDI_NOTE):
2660       new_obj =
2661         clone_midi_note ((MidiNote *) self);
2662       break;
2663     case TYPE (CHORD_OBJECT):
2664       new_obj =
2665         clone_chord_object (
2666           (ChordObject *) self);
2667       break;
2668     case TYPE (SCALE_OBJECT):
2669       new_obj =
2670         clone_scale_object (
2671           (ScaleObject *) self);
2672       break;
2673     case TYPE (AUTOMATION_POINT):
2674       new_obj =
2675         clone_automation_point (
2676           (AutomationPoint *) self);
2677       break;
2678     case TYPE (MARKER):
2679       new_obj =
2680         clone_marker (
2681           (Marker *) self);
2682       break;
2683     case TYPE (VELOCITY):
2684       {
2685         Velocity * src = (Velocity *) self;
2686         MidiNote * mn =
2687           velocity_get_midi_note (src);
2688         Velocity * new_vel =
2689           velocity_new (mn, src->vel);
2690         new_obj =
2691           (ArrangerObject *) new_vel;
2692         new_vel->vel_at_start = src->vel_at_start;
2693       }
2694       break;
2695     default:
2696       g_return_val_if_reached (NULL);
2697     }
2698   g_return_val_if_fail (new_obj, NULL);
2699 
2700   /* set positions */
2701   g_warn_if_fail (
2702     self->schema_version ==
2703       ARRANGER_OBJECT_SCHEMA_VERSION &&
2704     self->pos.schema_version ==
2705       POSITION_SCHEMA_VERSION);
2706   new_obj->pos = self->pos;
2707   if (arranger_object_type_has_length (self->type))
2708     {
2709       new_obj->end_pos = self->end_pos;
2710     }
2711   if (arranger_object_type_can_loop (self->type))
2712     {
2713       new_obj->clip_start_pos = self->clip_start_pos;
2714       new_obj->loop_start_pos = self->loop_start_pos;
2715       new_obj->loop_end_pos = self->loop_end_pos;
2716     }
2717   if (arranger_object_can_fade (self))
2718     {
2719       new_obj->fade_in_pos = self->fade_in_pos;
2720       new_obj->fade_out_pos = self->fade_out_pos;
2721       new_obj->fade_in_opts = self->fade_in_opts;
2722       new_obj->fade_out_opts = self->fade_out_opts;
2723     }
2724   if (arranger_object_can_mute (self))
2725     {
2726       new_obj->muted = self->muted;
2727     }
2728 
2729   new_obj->magic = ARRANGER_OBJECT_MAGIC;
2730   new_obj->index_in_prev_lane =
2731     self->index_in_prev_lane;
2732 
2733   return new_obj;
2734 }
2735 
2736 /**
2737  * Removes the child from the given object.
2738  */
2739 void
arranger_object_remove_child(ArrangerObject * self,ArrangerObject * child)2740 arranger_object_remove_child (
2741   ArrangerObject * self,
2742   ArrangerObject * child)
2743 {
2744   if (self->type != ARRANGER_OBJECT_TYPE_REGION)
2745     return;
2746 
2747   ZRegion * r = (ZRegion *) self;
2748   switch (r->id.type)
2749     {
2750     case REGION_TYPE_MIDI:
2751       midi_region_remove_midi_note (
2752         r, (MidiNote *) child, F_FREE,
2753         F_NO_PUBLISH_EVENTS);
2754       break;
2755     case REGION_TYPE_AUDIO:
2756       break;
2757     case REGION_TYPE_AUTOMATION:
2758       automation_region_remove_ap (
2759         r, (AutomationPoint *) child, F_FREE,
2760         F_NO_PUBLISH_EVENTS);
2761       break;
2762     case REGION_TYPE_CHORD:
2763       chord_region_remove_chord_object (
2764         r, (ChordObject *) child, F_FREE,
2765         F_NO_PUBLISH_EVENTS);
2766       break;
2767     }
2768 }
2769 
2770 /**
2771  * Splits the given object at the given Position.
2772  *
2773  * if \ref is_project is true, it
2774  * deletes the original object and adds 2 new
2775  * objects in the same parent (Track or
2776  * AutomationTrack or Region).
2777  *
2778  * @param region The ArrangerObject to split. This
2779  *   ArrangerObject will be deleted.
2780  * @param pos The Position to split at.
2781  * @param pos_is_local If the position is local (1)
2782  *   or global (0).
2783  * @param r1 Address to hold the pointer to the
2784  *   newly created ArrangerObject 1.
2785  * @param r2 Address to hold the pointer to the
2786  *   newly created ArrangerObject 2.
2787  * @param is_project Whether the object being
2788  *   passed is a project object. If true, it will
2789  *   be removed from the project and the child
2790  *   objects will be added to the project,
2791  *   otherwise it will be untouched and the
2792  *   children will be mere clones.
2793  */
2794 void
arranger_object_split(ArrangerObject * self,const Position * pos,const bool pos_is_local,ArrangerObject ** r1,ArrangerObject ** r2,bool is_project)2795 arranger_object_split (
2796   ArrangerObject *  self,
2797   const Position *  pos,
2798   const bool        pos_is_local,
2799   ArrangerObject ** r1,
2800   ArrangerObject ** r2,
2801   bool              is_project)
2802 {
2803   g_return_if_fail (IS_ARRANGER_OBJECT (self));
2804 
2805   /* create the new objects */
2806   *r1 = arranger_object_clone (self);
2807   *r2 = arranger_object_clone (self);
2808 
2809   bool orig_is_looped =
2810     self->type == ARRANGER_OBJECT_TYPE_REGION
2811     && region_is_looped ((ZRegion *) self);
2812 
2813   g_debug ("splitting objects...");
2814 
2815   bool set_clip_editor_region = false;
2816   if (is_project)
2817     {
2818       /* change to r1 if the original region was
2819        * the clip editor region */
2820       ZRegion * clip_editor_region =
2821         clip_editor_get_region (CLIP_EDITOR);
2822       if (clip_editor_region == (ZRegion *) self)
2823         {
2824           set_clip_editor_region = true;
2825           clip_editor_set_region (
2826             CLIP_EDITOR, NULL, true);
2827         }
2828     }
2829 
2830   /* get global/local positions (the local pos
2831    * is after traversing the loops) */
2832   Position globalp, localp;
2833   if (pos_is_local)
2834     {
2835       position_set_to_pos (&globalp, pos);
2836       position_add_ticks (
2837         &globalp, self->pos.ticks);
2838       position_set_to_pos (&localp, pos);
2839     }
2840   else
2841     {
2842       position_set_to_pos (&globalp, pos);
2843       if (self->type == ARRANGER_OBJECT_TYPE_REGION)
2844         {
2845           long localp_frames =
2846             region_timeline_frames_to_local (
2847               (ZRegion *) self, globalp.frames, 1);
2848           position_from_frames (
2849             &localp, localp_frames);
2850 
2851           g_return_if_fail (
2852             position_is_after (
2853               &globalp, &self->pos) &&
2854             position_is_before (
2855               &globalp, &self->end_pos));
2856         }
2857       else
2858         {
2859           position_set_to_pos (&localp, &globalp);
2860         }
2861     }
2862 
2863   /*
2864    * for first object set:
2865    * - end pos
2866    * - fade out pos
2867    */
2868   arranger_object_end_pos_setter (
2869     *r1, &globalp);
2870   arranger_object_set_position (
2871     *r1, &localp,
2872     ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT,
2873     F_NO_VALIDATE);
2874 
2875   /* of original object was not looped, make the
2876    * new object unlooped also */
2877   if (!orig_is_looped)
2878     {
2879       arranger_object_loop_end_pos_setter (
2880         *r1, &localp);
2881 
2882       /* remove objects starting after the end */
2883       GPtrArray * children = g_ptr_array_new ();
2884       arranger_object_append_children (
2885         *r1, children);
2886       for (size_t i = 0; i < children->len; i++)
2887         {
2888           ArrangerObject * child =
2889             g_ptr_array_index (children, i);
2890           if (position_is_after (
2891                 &child->pos, &localp))
2892             arranger_object_remove_child (
2893               *r1, child);
2894         }
2895       g_ptr_array_unref (children);
2896 
2897       /* if audio region, create a new region */
2898       if ((*r1)->type == ARRANGER_OBJECT_TYPE_REGION
2899           &&
2900           ((ZRegion *) (*r1))->id.type ==
2901             REGION_TYPE_AUDIO)
2902         {
2903           ZRegion * prev_r1 = (ZRegion *) *r1;
2904           AudioClip * prev_r1_clip =
2905             audio_region_get_clip (prev_r1);
2906           g_return_if_fail (prev_r1_clip);
2907           float frames[
2908             localp.frames * prev_r1_clip->channels];
2909           dsp_copy (
2910             &frames[0], &prev_r1_clip->frames[0],
2911             (size_t) localp.frames *
2912               prev_r1_clip->channels);
2913           g_return_if_fail (prev_r1->name);
2914           ZRegion * new_r1 =
2915             audio_region_new (
2916               -1, NULL, true, frames, localp.frames,
2917               prev_r1->name, prev_r1_clip->channels,
2918               prev_r1_clip->bit_depth,
2919               &prev_r1->base.pos,
2920               prev_r1->id.track_name_hash,
2921               prev_r1->id.lane_pos,
2922               prev_r1->id.idx);
2923           g_return_if_fail (
2924             new_r1->pool_id != prev_r1->pool_id);
2925           arranger_object_free (
2926             (ArrangerObject *) prev_r1);
2927           *r1 = (ArrangerObject *) new_r1;
2928         }
2929     }
2930 
2931   /*
2932    * for second object set:
2933    * - start pos
2934    * - clip start pos
2935    */
2936   arranger_object_clip_start_pos_setter (
2937     *r2, &localp);
2938   arranger_object_pos_setter (
2939     *r2, &globalp);
2940   Position r2_local_end;
2941   position_set_to_pos (
2942     &r2_local_end, &((*r2)->end_pos));
2943   position_add_ticks (
2944     &r2_local_end, - (*r2)->pos.ticks);
2945   arranger_object_set_position (
2946     *r2, &r2_local_end,
2947     ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT,
2948     F_NO_VALIDATE);
2949 
2950   /* of original object was not looped, make the
2951    * new object unlooped also */
2952   if (!orig_is_looped)
2953     {
2954       Position init_pos;
2955       position_init (&init_pos);
2956       arranger_object_clip_start_pos_setter (
2957         *r2, &init_pos);
2958       arranger_object_loop_start_pos_setter (
2959         *r2, &init_pos);
2960       arranger_object_loop_end_pos_setter (
2961         *r2, &r2_local_end);
2962 
2963       /* move all objects backwards */
2964       arranger_object_add_ticks_to_children (
2965         *r2, - localp.ticks);
2966 
2967       /* remove objects starting before the start */
2968       GPtrArray * children = g_ptr_array_new ();
2969       arranger_object_append_children (
2970         *r2, children);
2971       for (size_t i = 0; i < children->len; i++)
2972         {
2973           ArrangerObject * child =
2974             g_ptr_array_index (children, i);
2975           if (child->pos.frames < 0)
2976             arranger_object_remove_child (
2977               *r2, child);
2978         }
2979       g_ptr_array_unref (children);
2980 
2981       /* if audio region, create a new region */
2982       if ((*r2)->type == ARRANGER_OBJECT_TYPE_REGION
2983           &&
2984           ((ZRegion *) (*r2))->id.type ==
2985             REGION_TYPE_AUDIO)
2986         {
2987           ZRegion * prev_r2 = (ZRegion *) *r2;
2988           AudioClip * prev_r2_clip =
2989             audio_region_get_clip (prev_r2);
2990           g_return_if_fail (prev_r2_clip);
2991           size_t num_frames =
2992             (size_t) r2_local_end.frames *
2993               prev_r2_clip->channels;
2994           float frames[num_frames];
2995           dsp_copy (
2996             &frames[0],
2997             &prev_r2_clip->frames[
2998               (size_t) localp.frames *
2999                 prev_r2_clip->channels],
3000             num_frames);
3001           g_return_if_fail (prev_r2->name);
3002           ZRegion * new_r2 =
3003             audio_region_new (
3004               -1, NULL, true, frames,
3005               r2_local_end.frames,
3006               prev_r2->name, prev_r2_clip->channels,
3007               prev_r2_clip->bit_depth,
3008               &globalp,
3009               prev_r2->id.track_name_hash,
3010               prev_r2->id.lane_pos,
3011               prev_r2->id.idx);
3012           g_return_if_fail (
3013             new_r2->pool_id != prev_r2->pool_id);
3014           arranger_object_free (
3015             (ArrangerObject *) prev_r2);
3016           *r2 = (ArrangerObject *) new_r2;
3017         }
3018     }
3019 
3020   /* make sure regions have names */
3021   if (self->type == ARRANGER_OBJECT_TYPE_REGION)
3022     {
3023       Track * track =
3024         arranger_object_get_track (self);
3025       ZRegion * src_region = (ZRegion *) self;
3026       ZRegion * region1 = (ZRegion *) *r1;
3027       ZRegion * region2 = (ZRegion *) *r2;
3028       AutomationTrack * at = NULL;
3029       if (src_region->id.type ==
3030             REGION_TYPE_AUTOMATION)
3031         {
3032           at =
3033             region_get_automation_track (
3034               src_region);
3035         }
3036       region_gen_name (
3037         region1, src_region->name, at, track);
3038       region_gen_name (
3039         region2, src_region->name, at, track);
3040     }
3041 
3042   /* skip rest if non-project object */
3043   if (!is_project)
3044     {
3045       return;
3046     }
3047 
3048   /* add them to the parent */
3049   switch (self->type)
3050     {
3051     case ARRANGER_OBJECT_TYPE_REGION:
3052       {
3053         Track * track =
3054           arranger_object_get_track (self);
3055         ZRegion * src_region =
3056           (ZRegion *) self;
3057         ZRegion * region1 =
3058           (ZRegion *) *r1;
3059         ZRegion * region2 =
3060           (ZRegion *) *r2;
3061         AutomationTrack * at = NULL;
3062         if (src_region->id.type ==
3063               REGION_TYPE_AUTOMATION)
3064           {
3065             at =
3066               region_get_automation_track (
3067                 src_region);
3068           }
3069         track_add_region (
3070           track, region1, at,
3071           src_region->id.lane_pos,
3072           F_GEN_NAME, F_PUBLISH_EVENTS);
3073         track_add_region (
3074           track, region2, at,
3075           src_region->id.lane_pos,
3076           F_GEN_NAME, F_PUBLISH_EVENTS);
3077       }
3078       break;
3079     case ARRANGER_OBJECT_TYPE_MIDI_NOTE:
3080       {
3081         MidiNote * src_midi_note =
3082           (MidiNote *) self;
3083         ZRegion * parent_region =
3084           midi_note_get_region (src_midi_note);
3085         midi_region_add_midi_note (
3086           parent_region, (MidiNote *) *r1, 1);
3087         midi_region_add_midi_note (
3088           parent_region, (MidiNote *) *r2, 1);
3089       }
3090       break;
3091     default:
3092       break;
3093     }
3094 
3095   /* select the first one */
3096   ArrangerSelections * sel =
3097     arranger_object_get_selections_for_type (
3098       self->type);
3099   arranger_selections_remove_object (sel, self);
3100   arranger_selections_add_object (sel, *r1);
3101   /*arranger_selections_add_object (sel, *r2);*/
3102 
3103   /* remove and free the original object */
3104   switch (self->type)
3105     {
3106     case ARRANGER_OBJECT_TYPE_REGION:
3107       {
3108         track_remove_region (
3109           arranger_object_get_track (self),
3110           (ZRegion *) self, F_PUBLISH_EVENTS,
3111           F_FREE);
3112         ZRegion * region1 = (ZRegion *) *r1;
3113         ZRegion * region2 = (ZRegion *) *r2;
3114         if (region1->id.type == REGION_TYPE_CHORD)
3115           {
3116             g_return_if_fail (
3117               region1->id.idx <
3118                 P_CHORD_TRACK->num_chord_regions);
3119             g_return_if_fail (
3120               region2->id.idx <
3121                 P_CHORD_TRACK->num_chord_regions);
3122           }
3123       }
3124       break;
3125     case ARRANGER_OBJECT_TYPE_MIDI_NOTE:
3126       {
3127         ZRegion * parent_region =
3128           midi_note_get_region (
3129             ((MidiNote *) self));
3130         midi_region_remove_midi_note (
3131           parent_region, (MidiNote *) self,
3132           F_FREE, F_PUBLISH_EVENTS);
3133       }
3134       break;
3135     default:
3136       g_warn_if_reached ();
3137       break;
3138     }
3139 
3140   if (set_clip_editor_region)
3141     {
3142       clip_editor_set_region (
3143         CLIP_EDITOR, (ZRegion *) *r1, true);
3144     }
3145 
3146   EVENTS_PUSH (ET_ARRANGER_OBJECT_CREATED, *r1);
3147   EVENTS_PUSH (ET_ARRANGER_OBJECT_CREATED, *r2);
3148 }
3149 
3150 /**
3151  * Undoes what arranger_object_split() did.
3152  */
3153 void
arranger_object_unsplit(ArrangerObject * r1,ArrangerObject * r2,ArrangerObject ** obj,bool fire_events)3154 arranger_object_unsplit (
3155   ArrangerObject *  r1,
3156   ArrangerObject *  r2,
3157   ArrangerObject ** obj,
3158   bool              fire_events)
3159 {
3160   g_debug ("unsplitting objects...");
3161 
3162   /* change to the original region if the clip
3163    * editor region is r1 or r2 */
3164   ZRegion * clip_editor_region =
3165     clip_editor_get_region (CLIP_EDITOR);
3166   bool set_clip_editor_region = false;
3167   if (clip_editor_region == (ZRegion *) r1 ||
3168       clip_editor_region == (ZRegion *) r2)
3169     {
3170       set_clip_editor_region = true;
3171       clip_editor_set_region (
3172         CLIP_EDITOR, NULL, true);
3173     }
3174 
3175   /* create the new object */
3176   *obj = arranger_object_clone (r1);
3177 
3178   /* set the end pos to the end pos of r2 and
3179    * fade out */
3180   arranger_object_end_pos_setter (
3181     *obj, &r2->end_pos);
3182   Position fade_out_pos;
3183   position_set_to_pos (
3184     &fade_out_pos, &r2->end_pos);
3185   position_add_ticks (
3186     &fade_out_pos, - r2->pos.ticks);
3187   arranger_object_set_position (
3188     *obj, &fade_out_pos,
3189     ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT,
3190     F_NO_VALIDATE);
3191 
3192   /* add it to the parent */
3193   switch (r1->type)
3194     {
3195     case ARRANGER_OBJECT_TYPE_REGION:
3196       {
3197         ZRegion * r1_region = (ZRegion *) r1;
3198         AutomationTrack * at = NULL;
3199         if (r1_region->id.type ==
3200               REGION_TYPE_AUTOMATION)
3201           {
3202             at =
3203               region_get_automation_track (
3204                 r1_region);
3205           }
3206         track_add_region (
3207           arranger_object_get_track (r1),
3208           (ZRegion *) *obj, at,
3209           ((ZRegion *) r1)->id.lane_pos,
3210           F_GEN_NAME, fire_events);
3211       }
3212       break;
3213     case ARRANGER_OBJECT_TYPE_MIDI_NOTE:
3214       {
3215         ZRegion * parent_region =
3216           midi_note_get_region (
3217             ((MidiNote *) r1));
3218         midi_region_add_midi_note (
3219           parent_region, (MidiNote *) *obj, 1);
3220       }
3221       break;
3222     default:
3223       break;
3224     }
3225 
3226   /* generate widgets so update visibility in the
3227    * arranger can work */
3228   /*arranger_object_gen_widget (*obj);*/
3229 
3230   /* select it */
3231   ArrangerSelections * sel =
3232     arranger_object_get_selections_for_type (
3233       (*obj)->type);
3234   arranger_selections_remove_object (
3235     sel, r1);
3236   arranger_selections_remove_object (
3237     sel, r2);
3238   arranger_selections_add_object (
3239     sel, *obj);
3240 
3241   /* remove and free the original regions */
3242   switch (r1->type)
3243     {
3244     case ARRANGER_OBJECT_TYPE_REGION:
3245       {
3246         track_remove_region (
3247           arranger_object_get_track (r1),
3248           (ZRegion *) r1, fire_events,
3249           F_FREE);
3250         track_remove_region (
3251           arranger_object_get_track (r2),
3252           (ZRegion *) r2, fire_events,
3253           F_FREE);
3254       }
3255       break;
3256     case ARRANGER_OBJECT_TYPE_MIDI_NOTE:
3257       {
3258         MidiNote * mn1 = (MidiNote *) r1;
3259         MidiNote * mn2 = (MidiNote *) r2;
3260         ZRegion * region1 =
3261           midi_note_get_region (mn1);
3262         ZRegion * region2 =
3263           midi_note_get_region (mn2);
3264         midi_region_remove_midi_note (
3265           region1, mn1,
3266           fire_events, F_FREE);
3267         midi_region_remove_midi_note (
3268           region2, mn2,
3269           fire_events, F_FREE);
3270       }
3271       break;
3272     default:
3273       break;
3274     }
3275 
3276   if (set_clip_editor_region)
3277     {
3278       clip_editor_set_region (
3279         CLIP_EDITOR, (ZRegion *) *obj, true);
3280     }
3281 
3282   if (fire_events)
3283     {
3284       EVENTS_PUSH (
3285         ET_ARRANGER_OBJECT_CREATED, *obj);
3286     }
3287 }
3288 
3289 /**
3290  * Sets the name of the object, if the object can
3291  * have a name.
3292  */
3293 void
arranger_object_set_name(ArrangerObject * self,const char * name,int fire_events)3294 arranger_object_set_name (
3295   ArrangerObject * self,
3296   const char *     name,
3297   int              fire_events)
3298 {
3299   g_return_if_fail (IS_ARRANGER_OBJECT (self));
3300   switch (self->type)
3301     {
3302     case ARRANGER_OBJECT_TYPE_MARKER:
3303       {
3304         arranger_object_set_string (
3305           Marker, self, name, name);
3306         char * escaped_name =
3307           g_markup_escape_text (name, -1);
3308         arranger_object_set_string (
3309           Marker, self, escaped_name,
3310           escaped_name);
3311         g_free (escaped_name);
3312       }
3313       break;
3314     case ARRANGER_OBJECT_TYPE_REGION:
3315       {
3316         arranger_object_set_string (
3317           ZRegion, self, name, name);
3318         char * escaped_name =
3319           g_markup_escape_text (name, -1);
3320         arranger_object_set_string (
3321           ZRegion, self, escaped_name,
3322           escaped_name);
3323         g_free (escaped_name);
3324       }
3325       break;
3326     default:
3327       break;
3328     }
3329   if (fire_events)
3330     {
3331       EVENTS_PUSH (
3332         ET_ARRANGER_OBJECT_CHANGED, self);
3333     }
3334 }
3335 
3336 /**
3337  * Changes the name and adds an action to the
3338  * undo stack.
3339  *
3340  * Calls arranger_object_set_name() internally.
3341  */
3342 void
arranger_object_set_name_with_action(ArrangerObject * self,const char * name)3343 arranger_object_set_name_with_action (
3344   ArrangerObject * self,
3345   const char *     name)
3346 {
3347   /* validate */
3348   if (!arranger_object_validate_name (self, name))
3349     {
3350       char * msg =
3351         g_strdup_printf (
3352           _("Invalid object name %s"), name);
3353       ui_show_error_message (MAIN_WINDOW, msg);
3354       return;
3355     }
3356 
3357   ArrangerObject * clone_obj =
3358     arranger_object_clone (self);
3359   g_return_if_fail (
3360     IS_ARRANGER_OBJECT_AND_NONNULL (clone_obj));
3361 
3362   /* prepare the before/after selections to
3363    * create the undoable action */
3364   ArrangerSelections * before =
3365     arranger_selections_clone (
3366       (ArrangerSelections *) TL_SELECTIONS);
3367   g_return_if_fail (
3368     IS_ARRANGER_SELECTIONS_AND_NONNULL (before));
3369   arranger_selections_clear (
3370     before, F_FREE, F_NO_PUBLISH_EVENTS);
3371   arranger_selections_add_object (
3372     before, clone_obj);
3373   ArrangerSelections * after =
3374     arranger_selections_clone (
3375       (ArrangerSelections *) before);
3376   ArrangerObject * after_obj =
3377     arranger_selections_get_first_object (after);
3378   arranger_object_set_name (
3379     after_obj, name, F_NO_PUBLISH_EVENTS);
3380 
3381   GError * err = NULL;
3382   bool ret =
3383     arranger_selections_action_perform_edit (
3384       before, after,
3385       ARRANGER_SELECTIONS_ACTION_EDIT_NAME,
3386       F_NOT_ALREADY_EDITED, &err);
3387   if (!ret)
3388     {
3389       HANDLE_ERROR (
3390         err, "%s",
3391         _("Failed to rename object"));
3392     }
3393 
3394   arranger_selections_free_full (before);
3395   arranger_selections_free_full (after);
3396 }
3397 
3398 static void
set_loop_and_fade_to_full_size(ArrangerObject * obj)3399 set_loop_and_fade_to_full_size (
3400   ArrangerObject * obj)
3401 {
3402   if (arranger_object_type_can_loop (obj->type))
3403     {
3404       double ticks =
3405         arranger_object_get_length_in_ticks (obj);
3406       position_from_ticks (
3407         &obj->loop_end_pos, ticks);
3408     }
3409   if (arranger_object_can_fade (obj))
3410     {
3411       double ticks =
3412         arranger_object_get_length_in_ticks (obj);
3413       position_from_ticks (
3414         &obj->fade_out_pos, ticks);
3415     }
3416 }
3417 
3418 /**
3419  * Sets the end position of the ArrangerObject and
3420  * also sets the loop end and fade out so that
3421  * they are at the end.
3422  */
3423 void
arranger_object_set_start_pos_full_size(ArrangerObject * obj,Position * pos)3424 arranger_object_set_start_pos_full_size (
3425   ArrangerObject * obj,
3426   Position *       pos)
3427 {
3428   arranger_object_pos_setter (obj, pos);
3429   set_loop_and_fade_to_full_size (obj);
3430   g_warn_if_fail (
3431     pos->frames == obj->pos.frames);
3432 }
3433 
3434 /**
3435  * Sets the end position of the ArrangerObject and
3436  * also sets the loop end and fade out to that
3437  * position.
3438  */
3439 void
arranger_object_set_end_pos_full_size(ArrangerObject * obj,Position * pos)3440 arranger_object_set_end_pos_full_size (
3441   ArrangerObject * obj,
3442   Position *       pos)
3443 {
3444   arranger_object_end_pos_setter (obj, pos);
3445   set_loop_and_fade_to_full_size (obj);
3446   g_warn_if_fail (
3447     pos->frames == obj->end_pos.frames);
3448 }
3449 
3450 /**
3451  * Appends the ArrangerObject to where it belongs
3452  * in the project (eg, a Track), without taking
3453  * into account its previous index (eg, before
3454  * deletion if undoing).
3455  */
3456 void
arranger_object_add_to_project(ArrangerObject * obj,bool fire_events)3457 arranger_object_add_to_project (
3458   ArrangerObject * obj,
3459   bool             fire_events)
3460 {
3461   g_message ("adding object to project:");
3462   arranger_object_print (obj);
3463 
3464   /* find the region (if owned by region) */
3465   ZRegion * region = NULL;
3466   if (arranger_object_owned_by_region (obj))
3467     {
3468       region = region_find (&obj->region_id);
3469       g_return_if_fail (region);
3470     }
3471 
3472   switch (obj->type)
3473     {
3474     case ARRANGER_OBJECT_TYPE_AUTOMATION_POINT:
3475       {
3476         AutomationPoint * ap =
3477           (AutomationPoint *) obj;
3478 
3479         /* add it to the region */
3480         g_return_if_fail (region);
3481         automation_region_add_ap (
3482           region, ap, fire_events);
3483       }
3484       break;
3485     case ARRANGER_OBJECT_TYPE_CHORD_OBJECT:
3486       {
3487         ChordObject * chord =
3488           (ChordObject *) obj;
3489 
3490         /* add it to the region */
3491         g_return_if_fail (region);
3492         chord_region_add_chord_object (
3493           region, chord, fire_events);
3494       }
3495       break;
3496     case ARRANGER_OBJECT_TYPE_MIDI_NOTE:
3497       {
3498         MidiNote * mn =
3499           (MidiNote *) obj;
3500 
3501         /* add it to the region */
3502         g_return_if_fail (region);
3503         midi_region_add_midi_note (
3504           region, mn, fire_events);
3505       }
3506       break;
3507     case ARRANGER_OBJECT_TYPE_SCALE_OBJECT:
3508       {
3509         ScaleObject * scale =
3510           (ScaleObject *) obj;
3511 
3512         /* add it to the track */
3513         chord_track_add_scale (
3514           P_CHORD_TRACK, scale);
3515       }
3516       break;
3517     case ARRANGER_OBJECT_TYPE_MARKER:
3518       {
3519         Marker * marker =
3520           (Marker *) obj;
3521 
3522         /* add it to the track */
3523         marker_track_add_marker (
3524           P_MARKER_TRACK, marker);
3525       }
3526       break;
3527     case ARRANGER_OBJECT_TYPE_REGION:
3528       {
3529         ZRegion * r = (ZRegion *) obj;
3530 
3531         /* add it to track */
3532         Track * track =
3533           tracklist_find_track_by_name_hash (
3534             TRACKLIST, r->id.track_name_hash);
3535         g_return_if_fail (
3536           IS_TRACK_AND_NONNULL (track));
3537         switch (r->id.type)
3538           {
3539           case REGION_TYPE_AUTOMATION:
3540             {
3541               AutomationTrack * at =
3542                 track->
3543                   automation_tracklist.
3544                     ats[r->id.at_idx];
3545               track_add_region (
3546                 track, r, at, -1,
3547                 F_GEN_NAME,
3548                 fire_events);
3549             }
3550             break;
3551           case REGION_TYPE_CHORD:
3552             track_add_region (
3553               P_CHORD_TRACK, r, NULL,
3554               -1, F_GEN_NAME,
3555               fire_events);
3556             break;
3557           default:
3558             track_add_region (
3559               track, r, NULL, r->id.lane_pos,
3560               F_GEN_NAME, fire_events);
3561             break;
3562           }
3563 
3564         /* if region, also set is as the clip
3565          * editor region */
3566         clip_editor_set_region (
3567           CLIP_EDITOR, r, true);
3568       }
3569       break;
3570     default:
3571       g_warn_if_reached ();
3572       break;
3573     }
3574 
3575   g_message ("after adding:");
3576   arranger_object_print (obj);
3577 }
3578 
3579 /**
3580  * Inserts the ArrangerObject where it belongs in
3581  * the project (eg, a Track).
3582  *
3583  * This function assumes that the object already
3584  * knows the index where it should be inserted
3585  * in its parent.
3586  *
3587  * This is mostly used when undoing.
3588  */
3589 void
arranger_object_insert_to_project(ArrangerObject * obj)3590 arranger_object_insert_to_project (
3591   ArrangerObject * obj)
3592 {
3593   /* find the region (if owned by region) */
3594   ZRegion * region = NULL;
3595   if (arranger_object_owned_by_region (obj))
3596     {
3597       region = region_find (&obj->region_id);
3598       g_return_if_fail (
3599         IS_REGION_AND_NONNULL (region));
3600     }
3601 
3602   switch (obj->type)
3603     {
3604     case ARRANGER_OBJECT_TYPE_AUTOMATION_POINT:
3605       {
3606         AutomationPoint * ap =
3607           (AutomationPoint *) obj;
3608 
3609         /* add it to the region */
3610         g_return_if_fail (
3611           IS_REGION_AND_NONNULL (region));
3612         automation_region_add_ap (
3613           region, ap, F_NO_PUBLISH_EVENTS);
3614       }
3615       break;
3616     case ARRANGER_OBJECT_TYPE_CHORD_OBJECT:
3617       {
3618         ChordObject * chord =
3619           (ChordObject *) obj;
3620 
3621         /* add it to the region */
3622         g_return_if_fail (
3623           IS_REGION_AND_NONNULL (region));
3624         chord_region_insert_chord_object (
3625           region, chord, chord->index,
3626           F_NO_PUBLISH_EVENTS);
3627       }
3628       break;
3629     case ARRANGER_OBJECT_TYPE_MIDI_NOTE:
3630       {
3631         MidiNote * mn =
3632           (MidiNote *) obj;
3633 
3634         /* add it to the region */
3635         g_return_if_fail (
3636           IS_REGION_AND_NONNULL (region));
3637         midi_region_insert_midi_note (
3638           region, mn, mn->pos, F_PUBLISH_EVENTS);
3639       }
3640       break;
3641     case ARRANGER_OBJECT_TYPE_SCALE_OBJECT:
3642       {
3643         ScaleObject * scale =
3644           (ScaleObject *) obj;
3645 
3646         /* add it to the track */
3647         chord_track_insert_scale (
3648           P_CHORD_TRACK, scale, scale->index);
3649       }
3650       break;
3651     case ARRANGER_OBJECT_TYPE_MARKER:
3652       {
3653         Marker * marker =
3654           (Marker *) obj;
3655 
3656         /* add it to the track */
3657         marker_track_insert_marker (
3658           P_MARKER_TRACK, marker, marker->index);
3659       }
3660       break;
3661     case ARRANGER_OBJECT_TYPE_REGION:
3662       {
3663         ZRegion * r = (ZRegion *) obj;
3664 
3665         /* add it to track */
3666         Track * track =
3667           tracklist_find_track_by_name_hash (
3668             TRACKLIST, r->id.track_name_hash);
3669         switch (r->id.type)
3670           {
3671           case REGION_TYPE_AUTOMATION:
3672             {
3673               AutomationTrack * at =
3674                 track->
3675                   automation_tracklist.
3676                     ats[r->id.at_idx];
3677               track_insert_region (
3678                 track, r, at, -1, r->id.idx,
3679                 F_GEN_NAME,
3680                 F_PUBLISH_EVENTS);
3681             }
3682             break;
3683           case REGION_TYPE_CHORD:
3684             track_insert_region (
3685               P_CHORD_TRACK, r, NULL,
3686               -1, r->id.idx, F_GEN_NAME,
3687               F_PUBLISH_EVENTS);
3688             break;
3689           default:
3690             track_insert_region (
3691               track, r, NULL, r->id.lane_pos,
3692               r->id.idx, F_GEN_NAME,
3693               F_PUBLISH_EVENTS);
3694             break;
3695           }
3696 
3697         /* if region, also set is as the clip
3698          * editor region */
3699         clip_editor_set_region (
3700           CLIP_EDITOR, r, true);
3701       }
3702       break;
3703     default:
3704       g_warn_if_reached ();
3705       break;
3706     }
3707 }
3708 
3709 /**
3710  * Removes the object from its parent in the
3711  * project.
3712  */
3713 void
arranger_object_remove_from_project(ArrangerObject * obj)3714 arranger_object_remove_from_project (
3715   ArrangerObject * obj)
3716 {
3717   /* TODO make sure no event contains this object */
3718   /*event_manager_remove_events_for_obj (*/
3719     /*EVENT_MANAGER, obj);*/
3720 
3721   ZRegion * region = NULL;
3722   if (arranger_object_owned_by_region (obj))
3723     {
3724       region =
3725         arranger_object_get_region (obj);
3726       g_return_if_fail (
3727         IS_REGION_AND_NONNULL (region));
3728     }
3729 
3730   switch (obj->type)
3731     {
3732     case ARRANGER_OBJECT_TYPE_AUTOMATION_POINT:
3733       {
3734         AutomationPoint * ap =
3735           (AutomationPoint *) obj;
3736         automation_region_remove_ap (
3737           region, ap, false, F_FREE);
3738       }
3739       break;
3740     case ARRANGER_OBJECT_TYPE_CHORD_OBJECT:
3741       {
3742         ChordObject * chord = (ChordObject *) obj;
3743       g_return_if_fail (
3744         IS_REGION_AND_NONNULL (region));
3745         chord_region_remove_chord_object (
3746           region, chord, F_FREE,
3747           F_NO_PUBLISH_EVENTS);
3748       }
3749       break;
3750     case ARRANGER_OBJECT_TYPE_REGION:
3751       {
3752         ZRegion * r =
3753           (ZRegion *) obj;
3754         Track * track =
3755           arranger_object_get_track (obj);
3756         g_return_if_fail (
3757           IS_TRACK_AND_NONNULL (track));
3758         track_remove_region (
3759           track, r, F_PUBLISH_EVENTS, F_FREE);
3760       }
3761       break;
3762     case ARRANGER_OBJECT_TYPE_SCALE_OBJECT:
3763       {
3764         ScaleObject * scale =
3765           (ScaleObject *) obj;
3766         chord_track_remove_scale (
3767           P_CHORD_TRACK, scale, F_FREE);
3768       }
3769       break;
3770     case ARRANGER_OBJECT_TYPE_MARKER:
3771       {
3772         Marker * marker =
3773           (Marker *) obj;
3774         marker_track_remove_marker (
3775           P_MARKER_TRACK, marker, F_FREE);
3776       }
3777       break;
3778     case ARRANGER_OBJECT_TYPE_MIDI_NOTE:
3779       {
3780         MidiNote * mn = (MidiNote *) obj;
3781         midi_region_remove_midi_note (
3782           region, mn, F_FREE,
3783           F_NO_PUBLISH_EVENTS);
3784       }
3785       break;
3786     default:
3787       break;
3788     }
3789 
3790   if (region)
3791     {
3792       region_update_link_group (region);
3793     }
3794 }
3795 
3796 /**
3797  * Returns whether the arranger object is part of
3798  * a frozen track.
3799  */
3800 bool
arranger_object_is_frozen(ArrangerObject * obj)3801 arranger_object_is_frozen (
3802   ArrangerObject * obj)
3803 {
3804   Track * track =
3805     arranger_object_get_track (obj);
3806   g_return_val_if_fail (
3807     IS_TRACK_AND_NONNULL (track), false);
3808   return track->frozen;
3809 }
3810 
3811 /**
3812  * Returns whether the given object is deletable
3813  * or not (eg, start marker).
3814  */
3815 bool
arranger_object_is_deletable(ArrangerObject * obj)3816 arranger_object_is_deletable (
3817   ArrangerObject * obj)
3818 {
3819   switch (obj->type)
3820     {
3821     case ARRANGER_OBJECT_TYPE_MARKER:
3822       {
3823         Marker * m = (Marker *) obj;
3824         return marker_is_deletable (m);
3825       }
3826       break;
3827     default:
3828       break;
3829     }
3830   return true;
3831 }
3832 
3833 static void
free_region(ZRegion * self)3834 free_region (
3835   ZRegion * self)
3836 {
3837   g_return_if_fail (IS_REGION (self));
3838 
3839   g_message ("freeing region %s...", self->name);
3840 
3841 #define FREE_R(type,sc) \
3842   case REGION_TYPE_##type: \
3843     sc##_region_free_members (self); \
3844   break
3845 
3846   switch (self->id.type)
3847     {
3848       FREE_R (MIDI, midi);
3849       FREE_R (AUDIO, audio);
3850       FREE_R (CHORD, chord);
3851       FREE_R (AUTOMATION, automation);
3852     }
3853 
3854   g_free_and_null (self->name);
3855   g_free_and_null (self->escaped_name);
3856   if (G_IS_OBJECT (self->layout))
3857     {
3858       object_free_w_func_and_null (
3859         g_object_unref, self->layout);
3860     }
3861 
3862 #undef FREE_R
3863 
3864   object_zero_and_free (self);
3865 }
3866 
3867 static void
free_midi_note(MidiNote * self)3868 free_midi_note (
3869   MidiNote * self)
3870 {
3871   g_return_if_fail (
3872     IS_MIDI_NOTE (self) && self->vel);
3873   arranger_object_free (
3874     (ArrangerObject *) self->vel);
3875 
3876   if (G_IS_OBJECT (self->layout))
3877     g_object_unref (self->layout);
3878 
3879   object_zero_and_free (self);
3880 }
3881 
3882 /**
3883  * Frees only this object.
3884  */
3885 void
arranger_object_free(ArrangerObject * self)3886 arranger_object_free (
3887   ArrangerObject * self)
3888 {
3889   g_return_if_fail (IS_ARRANGER_OBJECT (self));
3890 
3891   switch (self->type)
3892     {
3893     case TYPE (REGION):
3894       free_region ((ZRegion *) self);
3895       return;
3896     case TYPE (MIDI_NOTE):
3897       free_midi_note ((MidiNote *) self);
3898       return;
3899     case TYPE (MARKER):
3900       {
3901         Marker * marker = (Marker *) self;
3902         g_free_and_null (marker->name);
3903         g_free_and_null (marker->escaped_name);
3904         object_zero_and_free (marker);
3905       }
3906       return;
3907     case TYPE (CHORD_OBJECT):
3908       {
3909         ChordObject * co = (ChordObject *) self;
3910         object_zero_and_free (co);
3911       }
3912       return;
3913     case TYPE (SCALE_OBJECT):
3914       {
3915         ScaleObject * scale = (ScaleObject *) self;
3916         musical_scale_free (scale->scale);
3917         object_zero_and_free (scale);
3918       }
3919       return;
3920     case TYPE (AUTOMATION_POINT):
3921       {
3922         AutomationPoint * ap =
3923           (AutomationPoint *) self;
3924         object_zero_and_free (ap);
3925       }
3926       return;
3927     case TYPE (VELOCITY):
3928       {
3929         Velocity * vel =
3930           (Velocity *) self;
3931         object_zero_and_free (vel);
3932       }
3933       return;
3934     default:
3935       g_return_if_reached ();
3936     }
3937   g_return_if_reached ();
3938 }
3939