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], ®ion->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, ®ion->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