Zrythm v2.0.0-DEV
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 "structure/arrangement/arranger_object_owner.h"
11#include "structure/arrangement/automation_region.h"
12#include "structure/arrangement/timeline_data_provider.h"
13#include "structure/tracks/playback_cache_activity_tracker.h"
14#include "utils/playback_cache_scheduler.h"
15#include "utils/units.h"
16
17#include <QtQmlIntegration/qqmlintegration.h>
18
19namespace zrythm::structure::tracks
20{
22 : public QObject,
23 public arrangement::ArrangerObjectOwner<arrangement::AutomationRegion>
24{
25 Q_OBJECT
26 QML_ELEMENT
27 Q_PROPERTY (
28 zrythm::dsp::ProcessorParameter * parameter READ parameter CONSTANT)
29 Q_PROPERTY (
30 AutomationMode automationMode READ getAutomationMode WRITE setAutomationMode
31 NOTIFY automationModeChanged)
32 Q_PROPERTY (
33 AutomationRecordMode recordMode READ getRecordMode WRITE setRecordMode
34 NOTIFY recordModeChanged)
35 DEFINE_ARRANGER_OBJECT_OWNER_QML_PROPERTIES (
37 regions,
39 Q_PROPERTY (
41 playbackCacheActivityTracker READ playbackCacheActivityTracker CONSTANT)
42 QML_UNCREATABLE ("")
43
44public:
45 using ArrangerObjectRegistry = arrangement::ArrangerObjectRegistry;
46 using AutomationRegion = arrangement::AutomationRegion;
47 using AutomationPoint = arrangement::AutomationPoint;
48
50 static constexpr int AUTOMATION_RECORDING_TOUCH_REL_MS = 800;
51
52 enum class AutomationMode : uint8_t
53 {
54 Read,
55 Record,
56 Off,
57 };
58 Q_ENUM (AutomationMode)
59
60 enum class AutomationRecordMode : uint8_t
61 {
62 Touch,
63 Latch,
64 };
65 Q_ENUM (AutomationRecordMode)
66
67public:
70 const dsp::TempoMapWrapper &tempo_map,
71 dsp::FileAudioSourceRegistry &file_audio_source_registry,
72 ArrangerObjectRegistry &obj_registry,
73 dsp::ProcessorParameterUuidReference param_id,
74 QObject * parent = nullptr);
75
76public:
77 // ========================================================================
78 // QML Interface
79 // ========================================================================
80
81 dsp::ProcessorParameter * parameter () const
82 {
83 return param_id_.get_object_as<dsp::ProcessorParameter> ();
84 }
85
86 AutomationMode getAutomationMode () const { return automation_mode_.load (); }
87 void setAutomationMode (AutomationMode automation_mode);
88 Q_SIGNAL void automationModeChanged (AutomationMode automation_mode);
89
90 AutomationRecordMode getRecordMode () const { return record_mode_; }
91 void setRecordMode (AutomationRecordMode record_mode);
92 Q_INVOKABLE void swapRecordMode ();
93 Q_SIGNAL void recordModeChanged (AutomationRecordMode record_mode);
94
101 Q_INVOKABLE void
107 Q_SIGNAL void
109
110 // cache activity tracking
111 [[nodiscard]] PlaybackCacheActivityTracker *
112 playbackCacheActivityTracker () const
113 {
114 return playback_cache_activity_tracker_.get ();
115 }
116
117 // ========================================================================
118
122 [[gnu::hot]] bool should_read_automation () const;
123
138 [[gnu::hot]] bool should_be_recording (bool record_aps) const;
139
149 AutomationPoint * get_automation_point_around (
150 units::precise_tick_t position_ticks,
151 units::precise_tick_t delta_ticks,
152 bool search_only_backwards = false);
153
163 AutomationPoint * get_automation_point_before (
164 units::sample_t timeline_position,
165 bool search_only_regions_enclosing_position) const;
166
176 auto get_region_before (
177 units::sample_t pos_samples,
178 bool search_only_regions_enclosing_position) const -> AutomationRegion *;
179
188 std::optional<float> get_normalized_value (
189 units::sample_t timeline_frames,
190 bool search_only_regions_enclosing_position) const;
191
192 bool contains_automation () const { return !get_children_vector ().empty (); }
193
194 std::string
195 get_field_name_for_serialization (const AutomationRegion *) const override
196 {
197 return "regions";
198 }
199
200public:
201 static constexpr auto kParameterKey = "parameter"sv;
202
203private:
204 static constexpr auto kAutomationModeKey = "automationMode"sv;
205 static constexpr auto kRecordModeKey = "recordMode"sv;
206 friend void to_json (nlohmann::json &j, const AutomationTrack &track);
207 friend void from_json (const nlohmann::json &j, AutomationTrack &track);
208
209 friend void init_from (
210 AutomationTrack &obj,
211 const AutomationTrack &other,
212 utils::ObjectCloneType clone_type);
213
214private:
215 const dsp::TempoMapWrapper &tempo_map_;
216 ArrangerObjectRegistry &object_registry_;
217
219 dsp::ProcessorParameterUuidReference param_id_;
220
222 std::atomic<AutomationMode> automation_mode_{ AutomationMode::Read };
223
225 AutomationRecordMode record_mode_{};
226
230 utils::QObjectUniquePtr<arrangement::AutomationTimelineDataProvider>
231 automation_data_provider_;
232
236 utils::QObjectUniquePtr<utils::PlaybackCacheScheduler>
237 automation_cache_request_debouncer_;
238
239 utils::QObjectUniquePtr<PlaybackCacheActivityTracker>
240 playback_cache_activity_tracker_;
241};
242
246inline void
247generate_automation_tracks_for_processor (
248 std::vector<utils::QObjectUniquePtr<AutomationTrack>> &ret,
249 const dsp::ProcessorBase &processor,
250 const dsp::TempoMapWrapper &tempo_map,
251 dsp::FileAudioSourceRegistry &file_audio_source_registry,
252 arrangement::ArrangerObjectRegistry &object_registry)
253{
254 z_debug ("generating automation tracks for {}...", processor.get_node_name ());
255 for (const auto &param_ref : processor.get_parameters ())
256 {
257 auto * const param =
258 param_ref.template get_object_as<dsp::ProcessorParameter> ();
259 if (!param->automatable ())
260 continue;
261
262 ret.emplace_back (
263 utils::make_qobject_unique<AutomationTrack> (
264 tempo_map, file_audio_source_registry, object_registry, param_ref));
265 }
266}
267}
268
269DEFINE_ENUM_FORMATTER (
270 zrythm::structure::tracks::AutomationTrack::AutomationRecordMode,
271 AutomationRecordMode,
272 QT_TR_NOOP_UTF8 ("Touch"),
273 QT_TR_NOOP_UTF8 ("Latch"));
274
275DEFINE_ENUM_FORMATTER (
276 zrythm::structure::tracks::AutomationTrack::AutomationMode,
277 AutomationMode,
278 "On",
279 "Rec",
280 "Off");
Processor parameter that accepts automation and modulation sources and integrates with QML and the DS...
Definition parameter.h:252
An automation point inside an AutomationTrack.
Represents an automation region, which contains a collection of automation points.
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.
std::optional< float > get_normalized_value(units::sample_t timeline_frames, bool search_only_regions_enclosing_position) const
Returns the normalized parameter value at 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_before(units::sample_t timeline_position, bool search_only_regions_enclosing_position) const
Returns the last automation point before the given timeline position.
AutomationTrack(const dsp::TempoMapWrapper &tempo_map, dsp::FileAudioSourceRegistry &file_audio_source_registry, ArrangerObjectRegistry &obj_registry, dsp::ProcessorParameterUuidReference param_id, QObject *parent=nullptr)
Creates an automation track for the given parameter.
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.
Q_INVOKABLE void regeneratePlaybackCaches(utils::ExpandableTickRange affectedRange)
To be connected to to notify of any changes to the automation content.
auto get_region_before(units::sample_t pos_samples, bool search_only_regions_enclosing_position) const -> AutomationRegion *
Returns the active region at a given position, if any.
Helper that manages cache activity state for a cache-holding object.