Zrythm v2.0.0-alpha.1
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
automation_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 <utility>
7
8#include "dsp/processor_base.h"
9#include "dsp/tempo_map_qml_adapter.h"
10#include "dsp/timebase.h"
11#include "structure/arrangement/arranger_object_owner.h"
12#include "structure/arrangement/automation_clip.h"
13#include "structure/arrangement/timeline_data_provider.h"
14#include "structure/tracks/playback_cache_activity_tracker.h"
15#include "utils/enum_utils.h"
16#include "utils/playback_cache_scheduler.h"
17#include "utils/units.h"
18
19#include <QtQmlIntegration/qqmlintegration.h>
20
21namespace zrythm::structure::tracks
22{
24 : public QObject,
25 public arrangement::ArrangerObjectOwner<arrangement::AutomationClip>
26{
27 Q_OBJECT
28 QML_ELEMENT
29 Q_PROPERTY (
30 zrythm::dsp::ProcessorParameter * parameter READ parameter CONSTANT)
31 Q_PROPERTY (
32 AutomationMode automationMode READ getAutomationMode WRITE setAutomationMode
33 NOTIFY automationModeChanged)
34 Q_PROPERTY (
35 AutomationRecordMode recordMode READ getRecordMode WRITE setRecordMode
36 NOTIFY recordModeChanged)
37 DEFINE_ARRANGER_OBJECT_OWNER_QML_PROPERTIES (
39 clips,
41 Q_PROPERTY (
43 playbackCacheActivityTracker READ playbackCacheActivityTracker CONSTANT)
44 QML_UNCREATABLE ("")
45
46public:
47 using AutomationClip = arrangement::AutomationClip;
48 using AutomationPoint = arrangement::AutomationPoint;
49
51 static constexpr int AUTOMATION_RECORDING_TOUCH_REL_MS = 800;
52
53 enum class AutomationMode : uint8_t
54 {
55 Read,
56 Record,
57 Off,
58 };
59 Q_ENUM (AutomationMode)
60
61 enum class AutomationRecordMode : uint8_t
62 {
63 Touch,
64 Latch,
65 };
66 Q_ENUM (AutomationRecordMode)
67
68public:
71 const dsp::TempoMapWrapper &tempo_map,
72 utils::IObjectRegistry &registry,
73 dsp::ProcessorParameterUuidReference param_id,
74 dsp::TimebaseProvider * timebase_provider = nullptr,
75 QObject * parent = nullptr);
76
77public:
78 // ========================================================================
79 // QML Interface
80 // ========================================================================
81
82 dsp::ProcessorParameter * parameter () const { return param_id_.get (); }
83
84 AutomationMode getAutomationMode () const { return automation_mode_.load (); }
85 void setAutomationMode (AutomationMode automation_mode);
86 Q_SIGNAL void automationModeChanged (AutomationMode automation_mode);
87
88 AutomationRecordMode getRecordMode () const { return record_mode_; }
89 void setRecordMode (AutomationRecordMode record_mode);
90 Q_INVOKABLE void swapRecordMode ();
91 Q_SIGNAL void recordModeChanged (AutomationRecordMode record_mode);
92
99 Q_INVOKABLE void
105 Q_SIGNAL void
107
108 // cache activity tracking
109 [[nodiscard]] PlaybackCacheActivityTracker *
110 playbackCacheActivityTracker () const
111 {
112 return playback_cache_activity_tracker_.get ();
113 }
114
115 // ========================================================================
116
120 [[gnu::hot]] bool should_read_automation () const;
121
136 [[gnu::hot]] bool should_be_recording (bool record_aps) const;
137
147 AutomationPoint * get_automation_point_around (
148 units::precise_tick_t position_ticks,
149 units::precise_tick_t delta_ticks,
150 bool search_only_backwards = false);
151
161 AutomationPoint * get_automation_point_before (
162 units::sample_t timeline_position,
163 bool search_only_clips_enclosing_position) const;
164
174 auto get_clip_before (
175 units::sample_t pos_samples,
176 bool search_only_clips_enclosing_position) const -> AutomationClip *;
177
186 std::optional<float> get_normalized_value (
187 units::sample_t timeline_frames,
188 bool search_only_clips_enclosing_position) const;
189
190 bool contains_automation () const { return !get_children_vector ().empty (); }
191
192 std::string
193 get_field_name_for_serialization (const AutomationClip *) const override
194 {
195 return "clips";
196 }
197
198public:
199 static constexpr auto kParameterKey = "parameter"sv;
200
201private:
202 static constexpr auto kAutomationModeKey = "automationMode"sv;
203 static constexpr auto kRecordModeKey = "recordMode"sv;
204 friend void to_json (nlohmann::json &j, const AutomationTrack &track);
205 friend void from_json (const nlohmann::json &j, AutomationTrack &track);
206
207 friend void init_from (
208 AutomationTrack &obj,
209 const AutomationTrack &other,
210 utils::ObjectCloneType clone_type);
211
212private:
213 const dsp::TempoMapWrapper &tempo_map_;
214 utils::IObjectRegistry &registry_;
215
217 dsp::ProcessorParameterUuidReference param_id_;
218 QPointer<dsp::TimebaseProvider> timebase_provider_;
219
221 std::atomic<AutomationMode> automation_mode_{ AutomationMode::Read };
222
224 AutomationRecordMode record_mode_{};
225
229 utils::QObjectUniquePtr<arrangement::AutomationTimelineDataProvider>
230 automation_data_provider_;
231
235 utils::QObjectUniquePtr<utils::PlaybackCacheScheduler>
236 automation_cache_request_debouncer_;
237
238 utils::QObjectUniquePtr<PlaybackCacheActivityTracker>
239 playback_cache_activity_tracker_;
240};
241
245inline void
246generate_automation_tracks_for_processor (
247 std::vector<utils::QObjectUniquePtr<AutomationTrack>> &ret,
248 const dsp::ProcessorBase &processor,
249 const dsp::TempoMapWrapper &tempo_map,
250 utils::IObjectRegistry &registry,
251 dsp::TimebaseProvider * timebase_provider)
252{
253 z_debug ("generating automation tracks for {}...", processor.get_node_name ());
254 for (const auto &param_ref : processor.get_parameters ())
255 {
256 auto * const param = param_ref.get ();
257 if (!param->automatable ())
258 continue;
259
260 ret.emplace_back (
261 utils::make_qobject_unique<AutomationTrack> (
262 tempo_map, registry, param_ref, timebase_provider));
263 }
264}
265}
266
267DEFINE_ENUM_FORMATTER (
268 zrythm::structure::tracks::AutomationTrack::AutomationRecordMode,
269 AutomationRecordMode,
270 QT_TR_NOOP_UTF8 ("Touch"),
271 QT_TR_NOOP_UTF8 ("Latch"));
272
273DEFINE_ENUM_FORMATTER (
274 zrythm::structure::tracks::AutomationTrack::AutomationMode,
275 AutomationMode,
276 "On",
277 "Rec",
278 "Off");
Processor parameter that accepts automation and modulation sources and integrates with QML and the DS...
Definition parameter.h:255
Represents an automation clip, which contains a collection of automation points.
An automation point inside an AutomationTrack.
Q_SIGNAL void automationObjectsNeedRecache(utils::ExpandableTickRange affectedRange)
Fired when a new cache is required.
bool should_read_automation() const
Returns whether the automation in the automation track should be read.
auto get_clip_before(units::sample_t pos_samples, bool search_only_clips_enclosing_position) const -> AutomationClip *
Returns the active clip at a given position, if any.
AutomationPoint * get_automation_point_before(units::sample_t timeline_position, bool search_only_clips_enclosing_position) const
Returns the last automation point before the given timeline position.
bool should_be_recording(bool record_aps) const
Returns if the automation track should currently be recording data.
AutomationPoint * get_automation_point_around(units::precise_tick_t position_ticks, units::precise_tick_t delta_ticks, bool search_only_backwards=false)
Find an automation point near the given position position_ticks with a tolerance of delta_ticks.
AutomationTrack(const dsp::TempoMapWrapper &tempo_map, utils::IObjectRegistry &registry, dsp::ProcessorParameterUuidReference param_id, dsp::TimebaseProvider *timebase_provider=nullptr, QObject *parent=nullptr)
Creates an automation track for the given parameter.
Q_INVOKABLE void regeneratePlaybackCaches(utils::ExpandableTickRange affectedRange)
To be connected to to notify of any changes to the automation content.
std::optional< float > get_normalized_value(units::sample_t timeline_frames, bool search_only_clips_enclosing_position) const
Returns the normalized parameter value at the given timeline position.
Helper that manages cache activity state for a cache-holding object.
Abstract interface for a UUID-keyed object registry.