Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
track.h
1// SPDX-FileCopyrightText: © 2018-2022, 2024-2025 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include "dsp/port_connections_manager.h"
7#include "gui/dsp/arranger_object_all.h"
8#include "gui/dsp/automation_tracklist.h"
9#include "gui/dsp/fader.h"
10#include "gui/dsp/plugin.h"
11#include "gui/dsp/track_lane.h"
12#include "utils/format.h"
13
14#include <QColor>
15#include <QHash>
16
17using namespace zrythm;
18
19class FileDescriptor;
20class FoldableTrack;
21class ChannelTrack;
22struct FileImportInfo;
24
30
31class TrackFactory;
32
33#define DECLARE_FINAL_TRACK_CONSTRUCTORS(ClassType) \
34 /* FIXME: make private */ \
35public: \
36 ClassType ( \
37 TrackRegistry &track_registry, PluginRegistry &plugin_registry, \
38 PortRegistry &port_registry, ArrangerObjectRegistry &obj_registry, \
39 bool new_identity);
40
41#define DEFINE_TRACK_QML_PROPERTIES(ClassType) \
42public: \
43 /* ================================================================ */ \
44 /* name */ \
45 /* ================================================================ */ \
46 Q_PROPERTY (QString name READ getName WRITE setName NOTIFY nameChanged) \
47 QString getName () const \
48 { \
49 return name_.to_qstring (); \
50 } \
51 void setName (const QString &name) \
52 { \
53 const auto name_str = utils::Utf8String::from_qstring (name); \
54 if (name_ == name_str) \
55 return; \
56\
57 name_ = name_str; \
58 Q_EMIT nameChanged (name); \
59 } \
60\
61 Q_SIGNAL void nameChanged (const QString &name); \
62\
63 /* ================================================================ */ \
64 /* color */ \
65 /* ================================================================ */ \
66 Q_PROPERTY (QColor color READ getColor WRITE setColor NOTIFY colorChanged) \
67\
68 QColor getColor () const \
69 { \
70 return color_.to_qcolor (); \
71 } \
72 void setColor (const QColor &color) \
73 { \
74 if (color_.to_qcolor () == color) \
75 return; \
76\
77 color_ = color; \
78 Q_EMIT colorChanged (color); \
79 } \
80\
81 Q_SIGNAL void colorChanged (const QColor &color); \
82\
83 /* ================================================================ */ \
84 /* comment */ \
85 /* ================================================================ */ \
86 Q_PROPERTY ( \
87 QString comment READ getComment WRITE setComment NOTIFY commentChanged) \
88\
89 QString getComment () const \
90 { \
91 return comment_.to_qstring (); \
92 } \
93 void setComment (const QString &comment) \
94 { \
95 const auto comment_str = utils::Utf8String::from_qstring (comment); \
96 if (comment_ == comment_str) \
97 return; \
98\
99 comment_ = comment_str; \
100 Q_EMIT commentChanged (comment); \
101 } \
102\
103 Q_SIGNAL void commentChanged (const QString &comment); \
104\
105 /* ================================================================ */ \
106 /* visible */ \
107 /* ================================================================ */ \
108 Q_PROPERTY ( \
109 bool visible READ getVisible WRITE setVisible NOTIFY visibleChanged) \
110 bool getVisible () const \
111 { \
112 return visible_; \
113 } \
114 void setVisible (bool visible) \
115 { \
116 if (visible_ == visible) \
117 return; \
118\
119 visible_ = visible; \
120 Q_EMIT visibleChanged (visible); \
121 } \
122\
123 Q_SIGNAL void visibleChanged (bool visible); \
124\
125 /* ================================================================ */ \
126 /* enabled */ \
127 /* ================================================================ */ \
128 Q_PROPERTY ( \
129 bool enabled READ getEnabled WRITE setEnabled NOTIFY enabledChanged) \
130 bool getEnabled () const \
131 { \
132 return enabled_; \
133 } \
134\
135 void setEnabled (bool enabled) \
136 { \
137 set_enabled (enabled, true, true, true); \
138 } \
139 Q_SIGNAL void enabledChanged (bool enabled); \
140\
141 /* ================================================================ */ \
142 /* selected */ \
143 /* ================================================================ */ \
144 Q_PROPERTY (bool selected READ getSelected NOTIFY selectedChanged) \
145 bool getSelected () const \
146 { \
147 if (track_selection_status_getter_) \
148 { \
149 return (*track_selection_status_getter_) (get_uuid ()); \
150 } \
151 return false; \
152 } \
153 Q_SIGNAL void selectedChanged (bool selected); \
154\
155 /* ================================================================ */ \
156 /* type */ \
157 /* ================================================================ */ \
158 Q_PROPERTY (int type READ getType CONSTANT) \
159 int getType () const \
160 { \
161 return ENUM_VALUE_TO_INT (type_); \
162 } \
163 /* ================================================================ */ \
164 /* isRecordable */ \
165 /* ================================================================ */ \
166 Q_PROPERTY (bool isRecordable READ getIsRecordable CONSTANT) \
167 bool getIsRecordable () const \
168 { \
169 if constexpr (std::derived_from<ClassType, RecordableTrack>) \
170 { \
171 return true; \
172 } \
173 return false; \
174 } \
175\
176 /* ================================================================ */ \
177 /* hasLanes */ \
178 /* ================================================================ */ \
179 Q_PROPERTY (bool hasLanes READ getHasLanes CONSTANT) \
180 bool getHasLanes () const \
181 { \
182 if constexpr (std::derived_from<ClassType, LanedTrack>) \
183 { \
184 return true; \
185 } \
186 return false; \
187 } \
188\
189 /* ================================================================ */ \
190 /* hasChannel */ \
191 /* ================================================================ */ \
192 Q_PROPERTY (bool hasChannel READ getHasChannel CONSTANT) \
193 bool getHasChannel () const \
194 { \
195 if constexpr (std::derived_from<ClassType, ChannelTrack>) \
196 { \
197 return true; \
198 } \
199 return false; \
200 } \
201\
202 /* ================================================================ */ \
203 /* isAutomatable */ \
204 /* ================================================================ */ \
205 Q_PROPERTY (bool isAutomatable READ getIsAutomatable CONSTANT) \
206 bool getIsAutomatable () const \
207 { \
208 if constexpr (std::derived_from<ClassType, AutomatableTrack>) \
209 { \
210 return true; \
211 } \
212 return false; \
213 } \
214\
215 /* ================================================================ */ \
216 /* height */ \
217 /* ================================================================ */ \
218 Q_PROPERTY ( \
219 double height READ getHeight WRITE setHeight NOTIFY heightChanged) \
220 double getHeight () const \
221 { \
222 return main_height_; \
223 } \
224 void setHeight (double height) \
225 { \
226 if (utils::math::floats_equal (height, main_height_)) \
227 { \
228 return; \
229 } \
230 main_height_ = height; \
231 Q_EMIT heightChanged (height); \
232 } \
233 Q_SIGNAL void heightChanged (double height); \
234 Q_PROPERTY ( \
235 double fullVisibleHeight READ getFullVisibleHeight NOTIFY \
236 fullVisibleHeightChanged) \
237 double getFullVisibleHeight () const \
238 { \
239 return get_full_visible_height (); \
240 } \
241 Q_SIGNAL void fullVisibleHeightChanged (); \
242 /* ================================================================ */ \
243 /* icon */ \
244 /* ================================================================ */ \
245 Q_PROPERTY (QString icon READ getIcon WRITE setIcon NOTIFY iconChanged) \
246 QString getIcon () const \
247 { \
248 return icon_name_.to_qstring (); \
249 } \
250 void setIcon (const QString &icon) \
251 { \
252 const auto icon_str = utils::Utf8String::from_qstring (icon); \
253 if (icon_name_ == icon_str) \
254 { \
255 return; \
256 } \
257 icon_name_ = icon_str; \
258 Q_EMIT iconChanged (icon); \
259 } \
260 Q_SIGNAL void iconChanged (const QString &icon);
261
265using TracksReadyCallback = void (*) (const FileImportInfo *);
266
278class Track
280 public IPortOwner,
282{
283 Q_GADGET
284 QML_ELEMENT
285
286public:
287 using PortType = dsp::PortType;
288 using PluginRegistry = gui::old_dsp::plugins::PluginRegistry;
289 using PluginPtrVariant = PluginRegistry::VariantType;
290 using PluginSlot = plugins::PluginSlot;
291
292 using TrackSelectionStatusGetter = std::function<bool (const TrackUuid &)>;
293
294 static constexpr int MIN_HEIGHT = 26;
295 static constexpr int DEF_HEIGHT = 52;
296
300 enum class Type
301 {
307
313
318
324
329
334
339
346
353
359
362
365
368 };
369 Q_ENUM (Type)
370
371 using Color = zrythm::utils::Color;
372 using Position = zrythm::dsp::Position;
373
378 {
379 switch (type)
380 {
381 case Type::Midi:
382 case Type::MidiBus:
383 case Type::Chord:
384 case Type::MidiGroup:
385 return Fader::Type::MidiChannel;
386 case Type::Instrument:
387 case Type::Audio:
388 case Type::AudioBus:
389 case Type::Master:
390 case Type::AudioGroup:
392 case Type::Marker:
393 case Type::Folder:
394 return Fader::Type::None;
395 default:
396 z_return_val_if_reached (Fader::Type::None);
397 }
398 }
399
400 static constexpr bool type_can_have_direct_out (Type type)
401 {
402 return type != Type::Master;
403 }
404
405 static bool
406 type_can_have_region_type (Type type, ArrangerObject::Type region_type)
407 {
408 switch (region_type)
409 {
410 case ArrangerObject::Type::AudioRegion:
411 return type == Type::Audio;
412 case ArrangerObject::Type::MidiRegion:
413 return type == Type::Midi || type == Type::Instrument;
414 case ArrangerObject::Type::ChordRegion:
415 return type == Type::Chord;
416 case ArrangerObject::Type::AutomationRegion:
417 return true;
418 default:
419 throw std::runtime_error ("Invalid region type");
420 }
421 }
422
423 static constexpr bool type_is_copyable (Type type)
424 {
425 return type != Type::Master && type != Type::Tempo && type != Type::Chord
426 && type != Type::Modulator && type != Type::Marker;
427 }
428
432 static constexpr bool type_is_deletable (Type type)
433 {
434 return type_is_copyable (type);
435 }
436
437 static Type type_get_from_plugin_descriptor (
439
440 static consteval bool type_has_mono_compat_switch (const Type tt)
441 {
442 return tt == Type::AudioGroup || tt == Type::Master;
443 }
444
448 static constexpr bool
449 type_is_compatible_for_moving (const Type type1, const Type type2)
450 {
451 return type1 == type2 || (type1 == Type::Midi && type2 == Type::Instrument)
452 || (type1 == Type::Instrument && type2 == Type::Midi);
453 }
454
458 [[gnu::const]]
459 static constexpr bool type_has_piano_roll (const Type type)
460 {
461 return type == Type::Midi || type == Type::Instrument;
462 }
463
467 static constexpr bool type_has_inputs (const Type type)
468 {
469 return type == Type::Midi || type == Type::Instrument || type == Type::Audio;
470 }
471
479 static bool type_can_be_group_target (const Type type)
480 {
481 return type == Type::AudioGroup || type == Type::MidiGroup
482 || type == Type::Instrument || type == Type::Master;
483 }
484
485 template <typename T> static consteval Type get_type_for_class ()
486 {
487 if constexpr (std::is_same_v<T, MidiTrack>)
488 return Type::Midi;
489 else if constexpr (std::is_same_v<T, AudioTrack>)
490 return Type::Audio;
491 else if constexpr (std::is_same_v<T, ChordTrack>)
492 return Type::Chord;
493 else if constexpr (std::is_same_v<T, InstrumentTrack>)
494 return Type::Instrument;
495 else if constexpr (std::is_same_v<T, AudioBusTrack>)
496 return Type::AudioBus;
497 else if constexpr (std::is_same_v<T, MidiBusTrack>)
498 return Type::MidiBus;
499 else if constexpr (std::is_same_v<T, MasterTrack>)
500 return Type::Master;
501 else if constexpr (std::is_same_v<T, TempoTrack>)
502 return Type::Tempo;
503 else if constexpr (std::is_same_v<T, ModulatorTrack>)
504 return Type::Modulator;
505 else if constexpr (std::is_same_v<T, MarkerTrack>)
506 return Type::Marker;
507 else if constexpr (std::is_same_v<T, FolderTrack>)
508 return Type::Folder;
509 else if constexpr (std::is_same_v<T, AudioGroupTrack>)
510 return Type::AudioGroup;
511 else if constexpr (std::is_same_v<T, MidiGroupTrack>)
512 return Type::MidiGroup;
513 else
514 {
515 static_assert (dependent_false_v<T>, "Unknown track type");
516 }
517 }
518
519public:
520 ~Track () override;
521 Q_DISABLE_COPY_MOVE (Track)
522
523 [[nodiscard]] static TrackUniquePtrVariant
524 create_unique_from_type (Type type);
525
526protected:
533 Type type,
534 PortType in_signal_type,
535 PortType out_signal_type,
536 PluginRegistry &plugin_registry,
537 PortRegistry &port_registry,
538 ArrangerObjectRegistry &obj_registry);
539
540public:
546 virtual void
547 init_loaded (PluginRegistry &plugin_registry, PortRegistry &port_registry) = 0;
548
549 Tracklist * get_tracklist () const;
550
551 dsp::PortConnectionsManager * get_port_connections_manager () const;
552
553 bool has_piano_roll () const { return type_has_piano_roll (type_); }
554
561 bool should_be_visible () const;
562
563 bool is_tempo () const { return type_ == Type::Tempo; }
564 bool is_folder () const { return type_ == Type::Folder; }
565 bool is_audio_group () const { return type_ == Type::AudioGroup; }
566 bool is_midi_group () const { return type_ == Type::MidiGroup; }
567 bool is_audio_bus () const { return type_ == Type::AudioBus; }
568 bool is_midi_bus () const { return type_ == Type::MidiBus; }
569 bool is_modulator () const { return type_ == Type::Modulator; }
570 bool is_chord () const { return type_ == Type::Chord; }
571 bool is_marker () const { return type_ == Type::Marker; }
572 bool is_audio () const { return type_ == Type::Audio; }
573 bool is_instrument () const { return type_ == Type::Instrument; }
574 bool is_midi () const { return type_ == Type::Midi; }
575 bool is_master () const { return type_ == Type::Master; }
576
577 static Track * from_variant (const TrackPtrVariant &variant);
578
579 // bool has_lanes () const { return type_has_lanes (type_); }
580
581 bool is_deletable () const { return type_is_deletable (type_); }
582 bool is_copyable () const { return type_is_copyable (type_); }
583 // bool has_automation () const { return type_has_automation (type_); }
584
589 template <typename DerivedT>
590 double get_full_visible_height (this DerivedT &&self)
591 requires std::derived_from<base_type<DerivedT>, Track>
593 {
594 double height = self.main_height_;
595
596 if constexpr (std::derived_from<DerivedT, LanedTrack>)
597 {
598 height += self.get_visible_lane_heights ();
599 }
600 if constexpr (std::derived_from<DerivedT, AutomatableTrack>)
601 {
602 if (self.automation_visible_)
603 {
604 const AutomationTracklist &atl = self.get_automation_tracklist ();
605 for (const auto &at : atl.get_visible_automation_tracks ())
606 {
607 z_warn_if_fail (at->height_ > 0);
608 if (at->visible_)
609 height += at->height_;
610 }
611 }
612 }
613 return height;
614 }
615
616 template <typename DerivedT>
617 bool multiply_heights (
618 this DerivedT &&self,
619 double multiplier,
620 bool visible_only,
621 bool check_only)
622 requires std::derived_from<base_type<DerivedT>, Track>
624 {
625 if (self.main_height_ * multiplier < MIN_HEIGHT)
626 return false;
627
628 if (!check_only)
629 {
630 self.main_height_ *= multiplier;
631 }
632
633 if constexpr (std::derived_from<DerivedT, LanedTrack>)
634 {
635 if (!visible_only || self.lanes_visible_)
636 {
637 for (auto &lane_var : self.lanes_)
638 {
639 using TrackLaneT = DerivedT::TrackLaneType;
640 auto lane = std::get<TrackLaneT *> (lane_var);
641 if (lane->height_ * multiplier < MIN_HEIGHT)
642 {
643 return false;
644 }
645
646 if (!check_only)
647 {
648 lane->height_ *= multiplier;
649 }
650 }
651 }
652 }
653 if constexpr (std::derived_from<DerivedT, AutomatableTrack>)
654 {
655 if (!visible_only || self.automation_visible_)
656 {
657 auto &atl = self.get_automation_tracklist ();
658 for (auto &at : atl.ats_)
659 {
660 if (visible_only && !at->visible_)
661 continue;
662
663 if (at->height_ * multiplier < MIN_HEIGHT)
664 {
665 return false;
666 }
667
668 if (!check_only)
669 {
670 at->height_ *= multiplier;
671 }
672 }
673 }
674 }
675
676 return true;
677 }
678
680 bool is_auditioner () const;
681
682 bool can_be_group_target () const { return type_can_be_group_target (type_); }
683
684 bool is_frozen () const { return frozen_clip_id_.has_value (); }
685
701 template <FinalRegionSubclass RegionT, FinalClass SelfT>
703 this SelfT &self,
704 ArrangerObjectUuidReference region_ref,
705 AutomationTrack * at,
706 std::optional<int> lane_pos,
707 std::optional<int> idx,
708 bool gen_name)
709 {
710 auto * region = std::get<RegionT *> (region_ref.get_object ());
711 // assert (region->validate (false, 0));
712 assert (type_can_have_region_type (self.type_, region->get_type ()));
713
714 if (gen_name)
715 {
716 if (at)
717 {
718 region->generate_name_from_automation_track (self, *at);
719 }
720 else
721 {
722 region->generate_name_from_track (self);
723 }
724 }
725
726 assert (!region->get_name ().empty ());
727 z_debug (
728 "inserting region '{}' to track '{}' at lane {} (idx {})",
729 region->get_name (), self.name_, lane_pos, idx);
730
731 region->set_track_id (self.get_uuid ());
732
733 if constexpr (
734 std::derived_from<RegionT, LaneOwnedObject>
735 && std::derived_from<SelfT, LanedTrack>)
736 {
737 /* enable extra lane if necessary */
738 self.create_missing_lanes (*lane_pos);
739
740 auto lane = std::get<typename SelfT::TrackLaneType *> (
741 self.lanes_.at (*lane_pos));
742 if (idx.has_value ())
743 {
744 lane->insert_object (region_ref, *idx);
745 }
746 else
747 {
748 lane->add_object (region_ref);
749 }
750 }
751 else if constexpr (std::is_same_v<RegionT, AutomationRegion>)
752 {
753 assert (at != nullptr);
754 if (idx.has_value ())
755 {
756 at->insert_object (region_ref, *idx);
757 }
758 else
759 {
760 at->add_object (region_ref);
761 }
762 }
763 else if constexpr (
764 std::is_same_v<RegionT, ChordRegion> && std::is_same_v<SelfT, ChordTrack>)
765 {
766 if (idx.has_value ())
767 {
768 self.ArrangerObjectOwner<ChordRegion>::insert_object (
769 region_ref, *idx);
770 }
771 else
772 {
773 self.ArrangerObjectOwner<ChordRegion>::add_object (region_ref);
774 }
775 }
776
777 /* write clip if audio region */
778 if constexpr (std::is_same_v<RegionT, AudioRegion>)
779 {
780 if (!self.is_auditioner ())
781 {
782 auto * clip = region->get_clip ();
783 self.write_audio_clip_to_pool_after_adding_audio_region (*clip);
784 }
785 }
786
787 z_debug ("inserted: {}", *region);
788 }
789
790 // FIXME: break this dependency on AudioPool
791 void
792 write_audio_clip_to_pool_after_adding_audio_region (AudioClip &clip) const;
793
801 template <FinalRegionSubclass RegionT>
803 this auto &self,
804 auto region_ref,
805 AutomationTrack * at,
806 std::optional<int> lane_pos,
807 bool gen_name)
808 {
809 return self.Track::template insert_region<RegionT> (
810 region_ref, at, lane_pos, std::nullopt, gen_name);
811 }
812
821 void append_objects (std::vector<ArrangerObjectPtrVariant> &objects) const;
822
827
828 template <typename DerivedT>
829 bool contains_uninstantiated_plugin (this DerivedT &&self)
830 requires std::derived_from<base_type<DerivedT>, Track>
832 {
833 std::vector<zrythm::gui::old_dsp::plugins::Plugin *> plugins;
834 self.get_plugins (plugins);
835 return std::ranges::any_of (plugins, [] (auto pl) {
836 return pl->instantiation_failed_;
837 });
838 }
839
840 utils::Utf8String get_node_name () const override { return get_name (); }
841
845 virtual void clear_objects () { };
846
852 virtual bool validate () const = 0;
853
859 void
860 add_folder_parents (std::vector<FoldableTrack *> &parents, bool prepend) const;
861
866 {
867 std::vector<FoldableTrack *> parents;
868 add_folder_parents (parents, true);
869 if (!parents.empty ())
870 {
871 return parents.front ();
872 }
873 return nullptr;
874 }
875
882
886 utils::Utf8String get_name () const { return name_; };
887
892
897
905 void set_name (
906 const Tracklist &tracklist,
907 const utils::Utf8String &name,
908 bool pub_events);
909
914 get_unique_name (const Tracklist &tracklist, const utils::Utf8String &name);
915
927 bool from_ticks,
928 bool bpm_change,
929 dsp::FramesPerTick frames_per_tick);
930
937 virtual void get_regions_in_range (
938 std::vector<Region *> &regions,
939 const dsp::Position * p1,
940 const dsp::Position * p2)
941 {
942 }
943
944 // FIXME: this member is likely not needed
945 int get_index () const { return pos_; }
946 void set_index (int index) { pos_ = index; }
947
948 auto get_input_signal_type () const { return in_signal_type_; }
949 auto get_output_signal_type () const { return out_signal_type_; }
950
954 template <typename DerivedT>
956 this DerivedT &&self,
957 std::vector<zrythm::gui::old_dsp::plugins::Plugin *> &arr)
958 requires std::derived_from<base_type<DerivedT>, Track>
960 {
961 if constexpr (std::derived_from<DerivedT, ChannelTrack>)
962 {
963 self.channel_->get_plugins (arr);
964 }
965
966 if constexpr (std::is_same_v<DerivedT, ModulatorTrack>)
967 {
968 for (const auto &modulator : self.modulators_)
969 {
970 if (modulator)
971 {
972 arr.push_back (modulator.get ());
973 }
974 }
975 }
976 }
977
984 template <typename DerivedT>
985 void activate_all_plugins (this DerivedT &&self, bool activate)
986 requires std::derived_from<base_type<DerivedT>, Track>
988 {
989 std::vector<zrythm::gui::old_dsp::plugins::Plugin *> pls;
990 self.get_plugins (pls);
991
992 for (auto &pl : pls)
993 {
994 if (!pl->instantiated_ && !pl->instantiation_failed_)
995 {
996 try
997 {
998 pl->instantiate ();
999 }
1000 catch (const ZrythmException &e)
1001 {
1002 e.handle ("Failed to instantiate plugin");
1003 }
1004 }
1005
1006 if (pl->instantiated_)
1007 {
1008 pl->activate (activate);
1009 }
1010 }
1011 }
1012
1013 utils::Utf8String get_comment () const { return comment_; }
1014
1018 void set_comment (const utils::Utf8String &comment, bool undoable);
1019
1020 void set_comment_with_action (const utils::Utf8String &comment)
1021 {
1022 set_comment (comment, true);
1023 }
1024
1028 void set_color (const Color &color, bool undoable, bool fire_events);
1029
1033 void
1034 set_icon (const utils::Utf8String &icon_name, bool undoable, bool fire_events);
1035
1039 virtual void
1040 append_ports (std::vector<Port *> &ports, bool include_plugins) const = 0;
1041
1055 void track_freeze (bool freeze);
1056
1062 template <typename DerivedT>
1063 PluginPtrVariant insert_plugin (
1064 this DerivedT &&self,
1065 PluginUuid plugin_id,
1067 bool instantiate_plugin,
1068 bool replacing_plugin,
1069 bool moving_plugin,
1070 bool confirm,
1071 bool gen_automatables,
1072 bool recalc_graph,
1073 bool fire_events)
1074 requires std::derived_from<base_type<DerivedT>, Track>
1076 {
1077 if (!slot.validate_slot_type_slot_combo ())
1078 {
1079 throw std::runtime_error ("Invalid slot type and slot combo");
1080 }
1081
1082 PluginPtrVariant plugin_var{};
1083
1084 if (slot.is_modulator ())
1085 {
1086 if constexpr (std::is_same_v<DerivedT, ModulatorTrack>)
1087 {
1088 plugin_var = self.insert_modulator (
1089 slot.get_slot_with_index ().second, plugin_id, replacing_plugin,
1090 confirm, gen_automatables, recalc_graph, fire_events);
1091 }
1092 }
1093 else
1094 {
1095 if constexpr (std::derived_from<DerivedT, ChannelTrack>)
1096 {
1097 plugin_var = self.get_channel ()->add_plugin (
1098 plugin_id, slot, confirm, moving_plugin, gen_automatables,
1099 recalc_graph, fire_events);
1100 }
1101 }
1102
1103 std::visit (
1104 [&] (auto &&plugin) {
1105 if (plugin && !plugin->instantiated_ && !plugin->instantiation_failed_)
1106 {
1107 try
1108 {
1109 plugin->instantiate ();
1110 }
1111 catch (const ZrythmException &e)
1112 {
1113 e.handle ("Failed to instantiate plugin");
1114 }
1115 }
1116 },
1117 plugin_var);
1118
1119 return plugin_var;
1120 }
1121
1126 template <typename SelfT>
1127 void remove_plugin (this SelfT &self, plugins::PluginSlot slot)
1128 requires (
1129 std::derived_from<SelfT, ChannelTrack>
1130 || std::is_same_v<SelfT, ModulatorTrack>)
1131 {
1132 z_debug ("removing plugin from track {}", self.name_);
1133 if constexpr (std::is_same_v<SelfT, ModulatorTrack>)
1134 {
1135 assert (slot.is_modulator ());
1136 self.remove_modulator (slot.get_slot_with_index ().second);
1137 }
1138 else if constexpr (std::derived_from<SelfT, ChannelTrack>)
1139 {
1140 assert (!slot.is_modulator ());
1141 self.get_channel ()->remove_plugin_from_channel (slot, false, true);
1142 }
1143 }
1144
1145 template <typename SelfT>
1147 get_plugin_slot (this const SelfT &self, const PluginUuid &plugin_id)
1148 requires (
1149 std::derived_from<SelfT, ChannelTrack>
1150 || std::is_same_v<SelfT, ModulatorTrack>)
1151 {
1152 if constexpr (std::derived_from<SelfT, ChannelTrack>)
1153 {
1154 return self.channel_->get_plugin_slot (plugin_id);
1155 }
1156 else if constexpr (std::is_same_v<SelfT, ModulatorTrack>)
1157 {
1158 return self.modulator_->get_plugin_slot (plugin_id);
1159 }
1160 }
1161
1167 const plugins::PluginDescriptor &descr,
1168 zrythm::plugins::PluginSlotType slot_type,
1169 Track::Type track_type)
1170 {
1171 switch (slot_type)
1172 {
1173 case zrythm::plugins::PluginSlotType::Insert:
1174 if (track_type == Track::Type::Midi)
1175 {
1176 return descr.num_midi_outs_ > 0;
1177 }
1178 else
1179 {
1180 return descr.num_audio_outs_ > 0;
1181 }
1182 case zrythm::plugins::PluginSlotType::MidiFx:
1183 return descr.num_midi_outs_ > 0;
1184 break;
1185 case zrythm::plugins::PluginSlotType::Instrument:
1186 return track_type == Track::Type::Instrument && descr.is_instrument ();
1187 default:
1188 break;
1189 }
1190
1191 z_return_val_if_reached (false);
1192 }
1193
1199
1200 bool is_enabled () const { return enabled_; }
1201 bool get_enabled () const { return enabled_; }
1202 bool get_disabled () const { return !enabled_; }
1203 void set_enabled (bool enabled) { enabled_ = enabled; }
1204
1205 void set_enabled (
1206 bool enabled,
1207 bool trigger_undo,
1208 bool auto_select,
1209 bool fire_events);
1210
1211 int get_total_bars (const Transport &transport, int total_bars) const;
1212
1217 void set_caches (CacheType types);
1218
1229 Type type,
1230 const zrythm::plugins::PluginConfiguration * pl_setting,
1231 const FileDescriptor * file_descr,
1232 const dsp::Position * pos,
1233 int index,
1234 int num_tracks,
1235 int disable_track_idx,
1236 TracksReadyCallback ready_cb);
1237
1247 static Track * create_empty_at_idx_with_action (Type type, int index);
1248
1260 Type type,
1261 const zrythm::plugins::PluginConfiguration * pl_setting,
1262 int index);
1263
1264 template <typename T = Track>
1266 const zrythm::plugins::PluginConfiguration * pl_setting,
1267 int index)
1268 {
1269 return dynamic_cast<T *> (create_for_plugin_at_idx_w_action (
1270 get_type_for_class<T> (), pl_setting, index));
1271 }
1272
1281
1282 template <typename T = Track> static T * create_empty_with_action ()
1283 {
1284 return dynamic_cast<T *> (
1285 create_empty_with_action (get_type_for_class<T> ()));
1286 }
1287
1295 [[nodiscard]] static TrackUniquePtrVariant
1296 create_track (Type type, const utils::Utf8String &name, int pos);
1297
1298 // GMenu * generate_edit_context_menu (int num_selected);
1299
1300 bool is_in_active_project () const override;
1301
1303 const override;
1304
1306 get_full_designation_for_port (const dsp::PortIdentifier &id) const override;
1307
1308 virtual bool get_muted () const { return false; }
1309
1310 virtual bool get_listened () const { return false; }
1311
1316 virtual bool get_implied_soloed () const { return false; }
1317
1318 virtual bool get_soloed () const { return false; }
1319
1320 void set_selection_status_getter (TrackSelectionStatusGetter getter)
1321 {
1323 }
1324 void unset_selection_status_getter ()
1325 {
1327 }
1328
1329 auto &get_plugin_registry () const { return plugin_registry_; }
1330 auto &get_plugin_registry () { return plugin_registry_; }
1331 auto &get_port_registry () const { return port_registry_; }
1332 auto &get_port_registry () { return port_registry_; }
1333 auto &get_object_registry () const { return object_registry_; }
1334 auto &get_object_registry () { return object_registry_; }
1335
1336 auto get_type () const { return type_; }
1337 auto get_icon_name () const { return icon_name_; }
1338
1339 friend bool operator< (const Track &lhs, const Track &rhs)
1340 {
1341 return lhs.pos_ < rhs.pos_;
1342 }
1343
1344protected:
1345 void copy_members_from (const Track &other, ObjectCloneType clone_type);
1346
1347 bool validate_base () const;
1348
1354 virtual void set_playback_caches () { }
1355
1356 void add_region_if_in_range (
1357 const dsp::Position * p1,
1358 const dsp::Position * p2,
1359 std::vector<Region *> &regions,
1360 Region * region);
1361
1362private:
1363 static constexpr std::string_view kTypeKey = "type";
1364 static constexpr std::string_view kNameKey = "name";
1365 static constexpr std::string_view kIconNameKey = "iconName";
1366 static constexpr std::string_view kIndexKey = "index";
1367 static constexpr std::string_view kVisibleKey = "visible";
1368 static constexpr std::string_view kMainHeightKey = "mainHeight";
1369 static constexpr std::string_view kEnabledKey = "enabled";
1370 static constexpr std::string_view kColorKey = "color";
1371 static constexpr std::string_view kInputSignalTypeKey = "inSignalType";
1372 static constexpr std::string_view kOutputSignalTypeKey = "outSignalType";
1373 static constexpr std::string_view kCommentKey = "comment";
1374 static constexpr std::string_view kFrozenClipIdKey = "frozenClipId";
1375 friend void to_json (nlohmann::json &j, const Track &track)
1376 {
1377 to_json (j, static_cast<const UuidIdentifiableObject &> (track));
1378 j[kTypeKey] = track.type_;
1379 j[kNameKey] = track.name_;
1380 j[kIconNameKey] = track.icon_name_;
1381 j[kIndexKey] = track.pos_;
1382 j[kVisibleKey] = track.visible_;
1383 j[kMainHeightKey] = track.main_height_;
1384 j[kEnabledKey] = track.enabled_;
1385 j[kColorKey] = track.color_;
1386 j[kInputSignalTypeKey] = track.in_signal_type_;
1387 j[kOutputSignalTypeKey] = track.out_signal_type_;
1388 j[kCommentKey] = track.comment_;
1389 j[kFrozenClipIdKey] = track.frozen_clip_id_;
1390 }
1391 friend void from_json (const nlohmann::json &j, Track &track)
1392 {
1393 from_json (j, static_cast<UuidIdentifiableObject &> (track));
1394 j.at (kTypeKey).get_to (track.type_);
1395 j.at (kNameKey).get_to (track.name_);
1396 j.at (kIconNameKey).get_to (track.icon_name_);
1397 j.at (kIndexKey).get_to (track.pos_);
1398 j.at (kVisibleKey).get_to (track.visible_);
1399 j.at (kMainHeightKey).get_to (track.main_height_);
1400 j.at (kEnabledKey).get_to (track.enabled_);
1401 j.at (kColorKey).get_to (track.color_);
1402 j.at (kInputSignalTypeKey).get_to (track.in_signal_type_);
1403 j.at (kOutputSignalTypeKey).get_to (track.out_signal_type_);
1404 j.at (kCommentKey).get_to (track.comment_);
1405 j.at (kFrozenClipIdKey).get_to (track.frozen_clip_id_);
1406 }
1407
1417 static Track * create_without_file_with_action (
1418 Type type,
1419 const zrythm::plugins::PluginConfiguration * pl_setting,
1420 int index);
1421
1422protected:
1423 PluginRegistry &plugin_registry_;
1424 PortRegistry &port_registry_;
1425 ArrangerObjectRegistry &object_registry_;
1426
1433 int pos_ = 0;
1434
1437
1440
1443
1449 // TrackWidget * widget_ = nullptr;
1450
1452 bool visible_ = true;
1453
1455 bool filtered_ = false;
1456
1458 double main_height_{ DEF_HEIGHT };
1459
1466 bool enabled_ = true;
1467
1473 Color color_;
1474
1478 PortType in_signal_type_ = {};
1479
1483 PortType out_signal_type_ = {};
1484
1487
1488public:
1494 bool bounce_{};
1495
1500 bool bounce_to_master_ = false;
1501
1503 bool disconnecting_ = false;
1504
1512
1514 std::optional<AudioClip::Uuid> frozen_clip_id_;
1515
1518
1524 std::optional<TrackSelectionStatusGetter> track_selection_status_getter_;
1525};
1526
1527DEFINE_ENUM_FORMATTER (
1529 Track_Type,
1530 QT_TR_NOOP_UTF8 ("Instrument"),
1531 QT_TR_NOOP_UTF8 ("Audio"),
1532 QT_TR_NOOP_UTF8 ("Master"),
1533 QT_TR_NOOP_UTF8 ("Chord"),
1534 QT_TR_NOOP_UTF8 ("Marker"),
1535 QT_TR_NOOP_UTF8 ("Tempo"),
1536 QT_TR_NOOP_UTF8 ("Modulator"),
1537 QT_TR_NOOP_UTF8 ("Audio FX"),
1538 QT_TR_NOOP_UTF8 ("Audio Group"),
1539 QT_TR_NOOP_UTF8 ("MIDI"),
1540 QT_TR_NOOP_UTF8 ("MIDI FX"),
1541 QT_TR_NOOP_UTF8 ("MIDI Group"),
1542 QT_TR_NOOP_UTF8 ("Folder"));
1543
1544template <typename T>
1545concept TrackSubclass = std::derived_from<T, Track>;
1546
1547template <typename TrackT>
1549
1550template <typename TrackT>
1553 && (std::derived_from<TrackT, ChannelTrack> || std::is_same_v<TrackT, ModulatorTrack>);
1554
1556using TrackRegistryRef = std::reference_wrapper<TrackRegistry>;
1557using TrackUuidReference = utils::UuidReference<TrackRegistry>;
1558using TrackSelectionManager =
1560
Audio clips for the pool.
Definition clip.h:26
Each track has an automation tracklist with automation tracks to be generated at runtime,...
Abstract class for a track that has a channel in the mixer.
Type
Fader type.
Definition fader.h:60
@ AudioChannel
Audio fader for Channel's.
Definition fader.h:70
Descriptor of a file.
Abstract base for a foldable track.
Abstract base class for a track that can be routed to.
A region (clip) is an object on the timeline that contains either MidiNote's or AudioClip's.
Definition region.h:112
Factory for tracks.
Represents a track in the project.
Definition track.h:282
std::optional< AudioClip::Uuid > frozen_clip_id_
Pool ID of the clip if track is frozen (unset if not frozen).
Definition track.h:1514
void get_plugins(this DerivedT &&self, std::vector< zrythm::gui::old_dsp::plugins::Plugin * > &arr)
Fills in the given array with all plugins in the track.
Definition track.h:955
virtual bool get_implied_soloed() const
Returns whether the track is not soloed on its own but its direct out (or its direct out's direct out...
Definition track.h:1316
std::optional< TrackSelectionStatusGetter > track_selection_status_getter_
Track selection status getter.
Definition track.h:1524
void set_caches(CacheType types)
Set various caches (snapshots, track name hash, plugin input/output ports, etc).
int pos_
Position in the Tracklist.
Definition track.h:1433
bool disconnecting_
Whether currently disconnecting.
Definition track.h:1503
PluginPtrVariant insert_plugin(this DerivedT &&self, PluginUuid plugin_id, plugins::PluginSlot slot, bool instantiate_plugin, bool replacing_plugin, bool moving_plugin, bool confirm, bool gen_automatables, bool recalc_graph, bool fire_events)
Wrapper over Channel.add_plugin() and ModulatorTrack.insert_modulator().
Definition track.h:1063
static constexpr bool type_has_inputs(const Type type)
Returns if the Track should have an inputs selector.
Definition track.h:467
Color color_
Track color.
Definition track.h:1473
bool filtered_
Track will be hidden if true (temporary and not serializable).
Definition track.h:1455
static Track * create_empty_at_idx_with_action(Type type, int index)
Creates a new empty track at the given index.
utils::Utf8String get_unique_name(const Tracklist &tracklist, const utils::Utf8String &name)
Returns a unique name for a new track based on the given name.
bool visible_
Track Widget created dynamically.
Definition track.h:1452
bool bounce_
Set to ON during bouncing if this track should be included.
Definition track.h:1494
utils::Utf8String name_
Track name, used in channel too.
Definition track.h:1439
static constexpr bool type_is_compatible_for_moving(const Type type1, const Type type2)
Returns if regions in tracks from type1 can be moved to type2.
Definition track.h:449
static TrackUniquePtrVariant create_track(Type type, const utils::Utf8String &name, int pos)
Create a track of the given type with the given name and position.
bool bounce_to_master_
Whether to temporarily route the output to master (e.g., when bouncing the track on its own without i...
Definition track.h:1500
bool enabled_
Active (enabled) or not.
Definition track.h:1466
static Track * create_empty_with_action(Type type)
Creates a new empty track at the end of the tracklist.
utils::Utf8String comment_
User comments.
Definition track.h:1486
void set_port_metadata_from_owner(dsp::PortIdentifier &id, PortRange &range) const override
Function that will be called by the Port to update the identifier's relevant members based on this po...
Type
The Track's type.
Definition track.h:301
@ Marker
Marker Track's contain named markers at specific Position's in the song.
Definition track.h:328
@ AudioGroup
Group Tracks are used for grouping audio signals, for example routing multiple drum tracks to a "Drum...
Definition track.h:352
@ AudioBus
Buses are channels that receive audio input and have effects on their channel strip.
Definition track.h:345
@ Modulator
Special track to contain global Modulator's.
Definition track.h:338
@ Midi
Midi tracks can only have MIDI effects in the strip and produce MIDI output that can be routed to ins...
Definition track.h:358
@ Instrument
Instrument tracks must have an Instrument plugin at the first slot and they produce audio output.
Definition track.h:306
@ Folder
Foldable track used for visual grouping.
Definition track.h:367
@ Audio
Audio tracks can record and contain audio clips.
Definition track.h:312
@ MidiGroup
Same with audio group but for MIDI signals.
Definition track.h:364
@ MidiBus
Same with audio bus but for MIDI signals.
Definition track.h:361
@ Tempo
Special track for BPM (tempo) and time signature events.
Definition track.h:333
@ Chord
The chord track contains chords that can be used to modify midi in real time or to color the piano ro...
Definition track.h:323
@ Master
The master track is a special type of group track.
Definition track.h:317
void add_folder_parents(std::vector< FoldableTrack * > &parents, bool prepend) const
Adds the track's folder parents to the given vector.
double main_height_
Height of the main part (without lanes).
Definition track.h:1458
void unselect_all()
Unselects all arranger objects in the track.
Track(Type type, PortType in_signal_type, PortType out_signal_type, PluginRegistry &plugin_registry, PortRegistry &port_registry, ArrangerObjectRegistry &obj_registry)
Constructor to be used by subclasses.
utils::Utf8String get_name() const
Getter for the track name.
Definition track.h:886
void set_name(const Tracklist &tracklist, const utils::Utf8String &name, bool pub_events)
Setter for the track name.
Tracklist * tracklist_
Pointer to owner tracklist, if any.
Definition track.h:1517
double get_full_visible_height(this DerivedT &&self)
Returns the full visible height (main height + height of all visible automation tracks + height of al...
Definition track.h:590
static void create_with_action(Type type, const zrythm::plugins::PluginConfiguration *pl_setting, const FileDescriptor *file_descr, const dsp::Position *pos, int index, int num_tracks, int disable_track_idx, TracksReadyCallback ready_cb)
Creates a new track with the given parameters.
virtual void init_loaded(PluginRegistry &plugin_registry, PortRegistry &port_registry)=0
Adds additional metadata to track members after deserialization.
bool set_name_with_action_full(const utils::Utf8String &name)
Internally called by set_name_with_action().
utils::Utf8String get_node_name() const override
Returns a human friendly name of the node.
Definition track.h:840
PortType out_signal_type_
The output signal type (eg midi tracks have MIDI output signals).
Definition track.h:1483
void set_comment(const utils::Utf8String &comment, bool undoable)
static Track * create_for_plugin_at_idx_w_action(Type type, const zrythm::plugins::PluginConfiguration *pl_setting, int index)
Creates a new track for the given plugin at the given index.
utils::Utf8String icon_name_
Icon name of the track.
Definition track.h:1442
PortType in_signal_type_
The input signal type (eg audio bus tracks have audio input signals).
Definition track.h:1478
FoldableTrack * get_direct_folder_parent() const
Returns the closest foldable parent or NULL.
Definition track.h:865
virtual void get_regions_in_range(std::vector< Region * > &regions, const dsp::Position *p1, const dsp::Position *p2)
Returns all the regions inside the given range, or all the regions if both p1 and p2 are NULL.
Definition track.h:937
void set_name_with_action(const utils::Utf8String &name)
Setter to be used by the UI to create an undoable action.
virtual void set_playback_caches()
Set the playback caches for a track.
Definition track.h:1354
void track_freeze(bool freeze)
Freezes or unfreezes the track.
void insert_region(this SelfT &self, ArrangerObjectUuidReference region_ref, AutomationTrack *at, std::optional< int > lane_pos, std::optional< int > idx, bool gen_name)
Inserts a Region to the given lane or AutomationTrack of the track, at the given index.
Definition track.h:702
void add_region(this auto &self, auto region_ref, AutomationTrack *at, std::optional< int > lane_pos, bool gen_name)
Appends a Region to the given lane or AutomationTrack of the track.
Definition track.h:802
void append_objects(std::vector< ArrangerObjectPtrVariant > &objects) const
Appends all the objects in the track to objects.
void set_color(const Color &color, bool undoable, bool fire_events)
Sets the track color.
static constexpr bool type_has_piano_roll(const Type type)
Returns if the Track should have a piano roll.
Definition track.h:459
bool is_auditioner() const
Whether this track is part of the SampleProcessor auditioner tracklist.
bool should_be_visible() const
Returns whether the track should be visible.
virtual void clear_objects()
Removes all objects recursively from the track.
Definition track.h:845
void disconnect_track()
Disconnects the track from the processing chain and removes any plugins it contains.
void remove_from_folder_parents()
Remove the track from all folders.
static bool is_plugin_descriptor_valid_for_slot_type(const plugins::PluginDescriptor &descr, zrythm::plugins::PluginSlotType slot_type, Track::Type track_type)
Returns if descr can be dropped at slot_type in a track of type track_type.
Definition track.h:1166
static Fader::Type type_get_prefader_type(const Type type)
Returns the prefader type.
Definition track.h:377
static constexpr bool type_is_deletable(Type type)
Returns whether a track of the given type should be deletable by the user.
Definition track.h:432
void update_positions(bool from_ticks, bool bpm_change, dsp::FramesPerTick frames_per_tick)
Updates the frames/ticks of each position in each child of the track recursively.
virtual bool validate() const =0
Verifies the identifiers on a live Track (in the project, not a clone).
virtual void append_ports(std::vector< Port * > &ports, bool include_plugins) const =0
Appends all channel ports and optionally plugin ports to the array.
void set_icon(const utils::Utf8String &icon_name, bool undoable, bool fire_events)
Sets the track icon.
void remove_plugin(this SelfT &self, plugins::PluginSlot slot)
Wrapper over Channel::remove_plugin() and ModulatorTrack::remove_modulator().
Definition track.h:1127
void activate_all_plugins(this DerivedT &&self, bool activate)
Activate or deactivate all plugins.
Definition track.h:985
bool trigger_midi_activity_
Flag to tell the UI that this channel had MIDI activity.
Definition track.h:1511
static bool type_can_be_group_target(const Type type)
Returns if the Track can be a direct route target.
Definition track.h:479
Type type_
The type of track this is.
Definition track.h:1436
The Tracklist contains all the tracks in the Project.
Definition tracklist.h:32
Struct used to identify Ports in the project.
Represents the position of an object.
Definition position.h:67
Interface for objects that can be processed in the DSP graph.
Definition graph_node.h:50
Configuration for instantiating a plugin descriptor.
The PluginDescriptor class provides a set of static utility functions and member functions to work wi...
int num_midi_outs_
Number of MIDI output ports.
int num_audio_outs_
Number of audio output ports.
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.
Base class for exceptions in Zrythm.
Definition exceptions.h:20
void(*)(const FileImportInfo *) TracksReadyCallback
Called when track(s) are actually imported into the project.
Definition track.h:265
ObjectCloneType
Definition icloneable.h:25