Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
arranger_object.h
1// SPDX-FileCopyrightText: © 2019-2022, 2024-2025 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#ifndef __GUI_BACKEND_ARRANGER_OBJECT_H__
5#define __GUI_BACKEND_ARRANGER_OBJECT_H__
6
7#include "gui/backend/position_proxy.h"
8#include "gui/dsp/arranger_object_fwd.h"
9#include "gui/dsp/track_fwd.h"
10
11#include <QtGlobal>
12
13using namespace zrythm;
14
15#define DEFINE_ARRANGER_OBJECT_QML_PROPERTIES(ClassType) \
16public: \
17 /* ================================================================ */ \
18 /* type */ \
19 /* ================================================================ */ \
20 Q_PROPERTY (int type READ getType CONSTANT) \
21 int getType () const \
22 { \
23 return ENUM_VALUE_TO_INT (get_type ()); \
24 } \
25 /* ================================================================ */ \
26 /* hasLength */ \
27 /* ================================================================ */ \
28 Q_PROPERTY (bool hasLength READ getHasLength CONSTANT) \
29 bool getHasLength () const \
30 { \
31 return std::derived_from<ClassType, BoundedObject>; \
32 } \
33 /* ================================================================ */ \
34 /* selected */ \
35 /* ================================================================ */ \
36 Q_PROPERTY (bool selected READ getSelected NOTIFY selectedChanged) \
37 bool getSelected () const \
38 { \
39 if (selection_status_getter_) \
40 { \
41 return (*selection_status_getter_) (get_uuid ()); \
42 } \
43 return false; \
44 } \
45 Q_SIGNAL void selectedChanged (bool selected); \
46 /* ================================================================ */ \
47 /* position */ \
48 /* ================================================================ */ \
49 Q_PROPERTY (PositionProxy * position READ getPosition CONSTANT) \
50 PositionProxy * getPosition () const \
51 { \
52 return pos_; \
53 } \
54 /* ================================================================ */ \
55 /* misc. signals */ \
56 /* ================================================================ */ \
57 Q_SIGNAL void addedToProject (); \
58 Q_SIGNAL void removedFromProject ();
59
60#define DECLARE_FINAL_ARRANGER_OBJECT_CONSTRUCTORS(ClassType) \
61public: \
62 ClassType ( \
63 ArrangerObjectRegistry &obj_registry, TrackResolver track_resolver, \
64 QObject * parent = nullptr);
65
74class ArrangerObject : public utils::UuidIdentifiableObject<ArrangerObject>
75{
76 Z_DISABLE_COPY_MOVE (ArrangerObject)
77
78public:
79 using SelectionStatusGetter = std::function<bool (const Uuid &)>;
80
81 static constexpr double DEFAULT_NUDGE_TICKS = 0.1;
82
86 enum class ResizeType
87 {
88 Normal,
89 Loop,
90 Fade,
91 Stretch,
92
99 };
100
104 enum class Type
105 {
106 MidiRegion,
107 AudioRegion,
108 ChordRegion,
109 AutomationRegion,
110 MidiNote,
111 ChordObject,
112 ScaleObject,
113 Marker,
114 AutomationPoint,
115 };
116
120 enum class Flags
121 {
124 NonProject = 1 << 0,
125
127 // FLAG_SNAPSHOT = 1 << 1,
128 };
129
130 enum class PositionType
131 {
132 Start,
133 End,
134 ClipStart,
135 LoopStart,
136 LoopEnd,
137 FadeIn,
138 FadeOut,
139 };
140
141 using Position = zrythm::dsp::Position;
142
143public:
144 ~ArrangerObject () noexcept override = default;
145
146 using ArrangerObjectPtr = ArrangerObject *;
147
148 auto get_type () const { return type_; }
149
157 {
158 /* this will be called if unimplemented - it's not needed for things like
159 * Velocity, which don't have reasonable names. */
160 z_return_val_if_reached ({});
161 };
162
173 const dsp::Position &start,
174 const dsp::Position &end,
175 bool range_start_inclusive = true,
176 bool range_end_inclusive = false) const
177 {
178 return is_start_hit_by_range (
179 start.frames_, end.frames_, range_start_inclusive, range_end_inclusive);
180 }
181
186 const signed_frame_t global_frames_start,
187 const signed_frame_t global_frames_end,
188 bool range_start_inclusive = true,
189 bool range_end_inclusive = false) const
190 {
191 return (range_start_inclusive
192 ? (pos_->frames_ >= global_frames_start)
193 : (pos_->frames_ > global_frames_start))
194 && (range_end_inclusive ? (pos_->frames_ <= global_frames_end) : (pos_->frames_ < global_frames_end));
195 }
196
206 void set_parent_on_base_qproperties (QObject &derived);
207
211 auto get_position () const { return *static_cast<dsp::Position *> (pos_); };
212
220 const dsp::Position &pos,
221 dsp::TicksPerFrame ticks_per_frame);
222
223 void set_position_unvalidated (const dsp::Position &pos)
224 {
225 // FIXME qobject updates...
226 *static_cast<dsp::Position *> (pos_) = pos;
227 }
228
236 const dsp::Position &pos,
237 PositionType pos_type,
238 dsp::TicksPerFrame ticks_per_frame) const;
239
251 const dsp::Position &pos,
252 PositionType pos_type,
253 bool validate,
254 dsp::TicksPerFrame ticks_per_frame);
255
259 void move (double ticks, dsp::FramesPerTick frames_per_tick);
260
261 void set_track_id (const TrackUuid &track_id) { track_id_ = track_id; }
262 void set_track_id (std::optional<TrackUuid> track_id)
263 {
264 track_id_ = track_id;
265 }
266 void unset_track_id () { track_id_ = std::nullopt; }
267
277 bool from_ticks,
278 bool bpm_change,
279 dsp::FramesPerTick frames_per_tick);
280
284 [[gnu::hot]] auto get_track () const
285 {
286 assert (track_id_);
287 return track_resolver_ (*track_id_);
288 }
289
290 std::optional<TrackUuid> get_track_id () const { return track_id_; }
291
301 virtual bool
302 validate (bool is_project, dsp::FramesPerTick frames_per_tick) const = 0;
303
312 virtual ArrangerObjectPtrVariant
313 add_clone_to_project (bool fire_events) const = 0;
314
326 virtual ArrangerObjectPtrVariant insert_clone_to_project () const = 0;
327
335 std::optional<ArrangerObjectPtrVariant>
336 remove_from_project (bool free_obj, bool fire_events = false);
337
338 void set_selection_status_getter (SelectionStatusGetter getter)
339 {
341 }
342 void unset_selection_status_getter () { selection_status_getter_.reset (); }
343
347 virtual bool is_deletable () const { return true; };
348
349 friend bool operator== (const ArrangerObject &lhs, const ArrangerObject &rhs)
350 {
351 return lhs.type_ == rhs.type_ && *lhs.pos_ == *rhs.pos_
352 && lhs.track_id_ == rhs.track_id_;
353 }
354
355protected:
356 ArrangerObject (Type type, TrackResolver track_resolver) noexcept;
357
358 void
359 copy_members_from (const ArrangerObject &other, ObjectCloneType clone_type);
360
364 bool
365 are_members_valid (bool is_project, dsp::FramesPerTick frames_per_tick) const;
366
367private:
368 dsp::Position * get_position_ptr (PositionType type);
369
370 friend void to_json (nlohmann::json &j, const ArrangerObject &arranger_object)
371 {
372 to_json (j, static_cast<const UuidIdentifiableObject &> (arranger_object));
373 j["type"] = arranger_object.type_;
374 j["flags"] = arranger_object.flags_;
375 j["trackId"] = arranger_object.track_id_;
376 j["pos"] = arranger_object.pos_;
377 }
378 friend void
379 from_json (const nlohmann::json &j, ArrangerObject &arranger_object)
380 {
381 j.at ("type").get_to (arranger_object.type_);
382 j.at ("flags").get_to (arranger_object.flags_);
383 j.at ("trackId").get_to (arranger_object.track_id_);
384 j.at ("pos").get_to (*arranger_object.pos_);
385 }
386
387protected:
388 TrackResolver track_resolver_;
389
393 PositionProxy * pos_ = nullptr;
394
395private:
396 Type type_{};
397
398protected:
404 std::optional<TrackUuid> track_id_;
405
407 // OptionalTrackPtrVariant track_;
408
415 // bool deleted_temporarily_ = false;
416
417public:
420
421protected:
424 // bool is_auditioner_ = false;
425
426 std::optional<SelectionStatusGetter> selection_status_getter_;
427};
428
429using ArrangerObjectRegistry =
431using ArrangerObjectUuidReference = utils::UuidReference<ArrangerObjectRegistry>;
432using ArrangerObjectSelectionManager =
434
435template <typename T>
436concept ArrangerObjectSubclass = std::derived_from<T, ArrangerObject>;
437
438template <typename T>
440 std::derived_from<T, ArrangerObject> && FinalClass<T> && CompleteType<T>;
441
442DEFINE_ENUM_FORMATTER (
444 ArrangerObject_Type,
445 QT_TR_NOOP ("None"),
446 QT_TR_NOOP ("All"),
447 QT_TR_NOOP ("Region"),
448 QT_TR_NOOP ("Midi Note"),
449 QT_TR_NOOP ("Chord Object"),
450 QT_TR_NOOP ("Scale Object"),
451 QT_TR_NOOP ("Marker"),
452 QT_TR_NOOP ("Automation Point"));
453
454#endif
Base class for all objects in the arranger.
void position_setter_validated(const dsp::Position &pos, dsp::TicksPerFrame ticks_per_frame)
The setter is for use in e.g.
virtual bool is_deletable() const
Returns whether the given object is deletable or not (eg, start marker).
std::optional< SelectionStatusGetter > selection_status_getter_
Whether part of an auditioner track.
std::optional< ArrangerObjectPtrVariant > remove_from_project(bool free_obj, bool fire_events=false)
Removes the object (which can be obtained from find_in_project()) from its parent in the project.
std::optional< TrackUuid > track_id_
ID of the track this object belongs to.
bool is_start_hit_by_range(const dsp::Position &start, const dsp::Position &end, bool range_start_inclusive=true, bool range_end_inclusive=false) const
Returns whether the given object is hit by the given range.
void update_positions(bool from_ticks, bool bpm_change, dsp::FramesPerTick frames_per_tick)
Updates the positions in each child recursively.
bool are_members_valid(bool is_project, dsp::FramesPerTick frames_per_tick) const
To be called by validate() implementations.
bool is_position_valid(const dsp::Position &pos, PositionType pos_type, dsp::TicksPerFrame ticks_per_frame) const
Returns if the given Position is valid.
bool is_start_hit_by_range(const signed_frame_t global_frames_start, const signed_frame_t global_frames_end, bool range_start_inclusive=true, bool range_end_inclusive=false) const
void set_parent_on_base_qproperties(QObject &derived)
Set the parent on QObject's that are children of this class.
virtual utils::Utf8String gen_human_friendly_name() const
Generates a human readable name for the object.
auto get_position() const
Getter.
virtual bool validate(bool is_project, dsp::FramesPerTick frames_per_tick) const =0
Validates the arranger object.
virtual ArrangerObjectPtrVariant insert_clone_to_project() const =0
Inserts the object where it belongs in the project (eg, a Track).
bool set_position(const dsp::Position &pos, PositionType pos_type, bool validate, dsp::TicksPerFrame ticks_per_frame)
Sets the given position on the object, optionally attempting to validate before.
auto get_track() const
Returns the Track this ArrangerObject is in.
Type
The type of the object.
virtual ArrangerObjectPtrVariant add_clone_to_project(bool fire_events) const =0
Appends the ArrangerObject to where it belongs in the project (eg, a Track), without taking into acco...
@ NonProject
This object is not a project object, but an object used temporarily eg.
ResizeType
Flag used in some functions.
@ StretchTempoChange
Used when we want to resize to contents when BPM changes.
Flags flags_
Track this object belongs to (cache to be set during graph calculation).
PositionProxy * pos_
Position (or start Position if the object has length).
void move(double ticks, dsp::FramesPerTick frames_per_tick)
Moves the object by the given amount of ticks.
Represents the position of an object.
Definition position.h:67
signed_frame_t frames_
Position in frames (samples).
Definition position.h:487
A registry that owns and manages objects identified by a UUID.
Lightweight UTF-8 string wrapper with safe conversions.
Definition string.h:39
Base class for objects that need to be uniquely identified by UUID.
A reference-counted RAII wrapper for a UUID in a registry.
ObjectCloneType
Definition icloneable.h:25
int_fast64_t signed_frame_t
Signed type for frame index.
Definition types.h:82
@ End
Range end.
Definition ruler.h:97
@ Start
Range start.
Definition ruler.h:93