Zrythm v2.0.0-alpha.1
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
arranger_object_all.h
1// SPDX-FileCopyrightText: © 2024-2025 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include "structure/arrangement/audio_clip.h"
7#include "structure/arrangement/audio_source_object.h"
8#include "structure/arrangement/automation_clip.h"
9#include "structure/arrangement/chord_clip.h"
10#include "structure/arrangement/chord_object.h"
11#include "structure/arrangement/marker.h"
12#include "structure/arrangement/midi_clip.h"
13#include "structure/arrangement/midi_control_event.h"
14#include "structure/arrangement/midi_note.h"
15#include "structure/arrangement/scale_object.h"
16#include "structure/arrangement/tempo_object.h"
17#include "structure/arrangement/time_signature_object.h"
18
19namespace zrythm::structure::arrangement
20{
21
22template <FinalArrangerObjectSubclass ObjT>
23bool
24is_arranger_object_deletable (const ObjT &obj)
25{
26 if constexpr (std::is_same_v<ObjT, Marker>)
27 {
28 return obj.markerType () == Marker::MarkerType::Custom;
29 }
30 else
31 {
32 return true;
33 }
34}
35
36// Currently unused
37#if 0
46template <ClipObject ObjectT>
47[[gnu::nonnull]] std::pair<int64_t, bool>
48get_frames_till_next_loop_or_end (
49 const ObjectT &obj,
50 int64_t timeline_frames)
51{
52 const auto loop_size = obj.get_loop_length_in_frames ();
53 assert (loop_size > 0);
54 const auto object_position_frames = obj.position ()->samples ();
55 const int64_t loop_end_frames =
56 obj.loopEndPosition ()->samples ();
57 const int64_t clip_start_frames =
58 obj.clipStartPosition ()->samples ();
59
60 int64_t local_frames = timeline_frames - object_position_frames;
61 local_frames += clip_start_frames;
62 while (local_frames >= loop_end_frames)
63 {
64 local_frames -= loop_size;
65 }
66
67 const int64_t frames_till_next_loop = loop_end_frames - local_frames;
68 const int64_t frames_till_end =
69 obj.get_end_position_samples (true) - timeline_frames;
70
71 return std::make_pair (
72 std::min (frames_till_end, frames_till_next_loop),
73 frames_till_next_loop < frames_till_end);
74}
75#endif
76
81inline bool
82is_clip (const ArrangerObject &obj)
83{
84 return qobject_cast<const Clip *> (&obj) != nullptr;
85}
86
97inline dsp::TimelineTick
98timeline_ticks (const ArrangerObject &obj)
99{
100 const auto * parent = obj.parentObject ();
101 if (parent != nullptr)
102 {
103 if (const auto * clip = qobject_cast<const Clip *> (parent))
104 {
105 return clip->contentWarp ()->contentToTimeline (
106 qobject_cast<const dsp::ContentPosition *> (obj.position ())
107 ->asTick ());
108 }
109 }
110 return dsp::TimelineTick{ units::ticks (obj.position ()->ticks ()) };
111}
112
120inline dsp::TimelineTick
121timeline_end_ticks (const ArrangerObject &obj)
122{
123 if (obj.length () == nullptr)
124 return timeline_ticks (obj);
125
126 const auto * parent = obj.parentObject ();
127 if (parent != nullptr)
128 {
129 if (const auto * clip = qobject_cast<const Clip *> (parent))
130 {
131 const auto content_pos =
132 qobject_cast<const dsp::ContentPosition *> (obj.position ())
133 ->asTick ();
134 return clip->contentWarp ()->contentToTimeline (
135 content_pos + obj.length ()->asTick ());
136 }
137 }
138
139 if (const auto * clip = qobject_cast<const Clip *> (&obj))
140 {
141 return clip->contentWarp ()->contentToTimeline (
142 clip->length ()->asTick ());
143 }
144
145 // Standalone bounded object (no clip context): raw addition.
146 return dsp::TimelineTick{
147 units::ticks (obj.position ()->ticks () + obj.length ()->ticks ())
148 };
149}
150
151inline auto
152get_object_tick_range (const ArrangerObject * obj)
153{
154 return std::make_pair (
155 timeline_ticks (*obj).asDouble (), timeline_end_ticks (*obj).asDouble ());
156}
157
166inline void
167set_end_from_timeline_ticks (ArrangerObject &obj, dsp::TimelineTick timeline_end)
168{
169 if (obj.length () == nullptr)
170 return;
171
172 // Child object inside a clip — reverse-warp through parent
173 const auto * parent = obj.parentObject ();
174 if (parent != nullptr)
175 {
176 if (const auto * parent_clip = qobject_cast<const Clip *> (parent))
177 {
178 const auto content_end =
179 parent_clip->contentWarp ()->timelineToContent (timeline_end);
180 const auto content_pos =
181 qobject_cast<const dsp::ContentPosition *> (obj.position ())
182 ->asTick ();
183 obj.length ()->setTicks ((content_end - content_pos).asDouble ());
184 return;
185 }
186 }
187
188 // Clip itself — reverse-warp through own warp
189 if (auto * clip = qobject_cast<Clip *> (&obj))
190 {
191 const auto content_end =
192 clip->contentWarp ()->timelineToContent (timeline_end);
193 clip->length ()->setTicks (content_end.asDouble ());
194 return;
195 }
196
197 // Standalone bounded object (no clip context) — raw subtraction
198 obj.length ()->setTicks (
199 (timeline_end - dsp::TimelineTick{ units::ticks (obj.position ()->ticks ()) })
200 .asDouble ());
201}
202
203}
Base class for all objects in the arranger.
void clip(std::span< float > buf, float minf, float maxf)
Clamp the buffer to min/max.