Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
snap_grid.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 <functional>
7#include <vector>
8
9#include "dsp/tempo_map.h"
10#include "utils/note_type.h"
11
12#include <QObject>
13#include <QtQmlIntegration>
14
15namespace zrythm::dsp
16{
17
21class SnapGrid : public QObject
22{
23 Q_OBJECT
24 Q_PROPERTY (
25 bool snapAdaptive READ snapAdaptive WRITE setSnapAdaptive NOTIFY
26 snapAdaptiveChanged)
27 Q_PROPERTY (
28 bool snapToGrid READ snapToGrid WRITE setSnapToGrid NOTIFY snapToGridChanged)
29 Q_PROPERTY (
30 bool snapToEvents READ snapToEvents WRITE setSnapToEvents NOTIFY
31 snapToEventsChanged)
32 Q_PROPERTY (
33 bool keepOffset READ keepOffset WRITE setKeepOffset NOTIFY keepOffsetChanged)
34 Q_PROPERTY (
35 bool sixteenthsVisible READ sixteenthsVisible WRITE setSixteenthsVisible
36 NOTIFY sixteenthsVisibleChanged)
37 Q_PROPERTY (
38 bool beatsVisible READ beatsVisible WRITE setBeatsVisible NOTIFY
39 beatsVisibleChanged)
40 Q_PROPERTY (
41 zrythm::utils::NoteLength snapNoteLength READ snapNoteLength WRITE
42 setSnapNoteLength NOTIFY snapNoteLengthChanged)
43 Q_PROPERTY (
44 zrythm::utils::NoteType snapNoteType READ snapNoteType WRITE setSnapNoteType
45 NOTIFY snapNoteTypeChanged)
46 Q_PROPERTY (
47 NoteLengthType lengthType READ lengthType WRITE setLengthType NOTIFY
48 lengthTypeChanged)
49 Q_PROPERTY (QString snapString READ snapString NOTIFY snapChanged)
50 QML_ELEMENT
51 QML_UNCREATABLE ("")
52 QML_EXTENDED_NAMESPACE (zrythm::utils)
53
54public:
55 enum class NoteLengthType
56 {
58 Link,
59
62
64 Custom,
65 };
66 Q_ENUM (NoteLengthType)
67
68 using SnapEventCallback =
69 std::function<std::vector<double> (double start_ticks, double end_ticks)>;
70 using LastObjectLengthProvider = std::function<double ()>;
71
72 SnapGrid (
73 const TempoMap &tempo_map,
74 utils::NoteLength default_note_length,
75 LastObjectLengthProvider last_object_length_provider,
76 QObject * parent = nullptr);
77
78 // QML Properties
79 bool snapAdaptive () const { return snap_adaptive_; }
80 void setSnapAdaptive (bool adaptive);
81
82 bool snapToGrid () const { return snap_to_grid_; }
83 void setSnapToGrid (bool snap);
84
85 bool snapToEvents () const { return snap_to_events_; }
86 void setSnapToEvents (bool snap);
87
88 bool keepOffset () const { return snap_to_grid_keep_offset_; }
89 void setKeepOffset (bool keep);
90
91 bool sixteenthsVisible () const { return sixteenths_visible_; }
92 void setSixteenthsVisible (bool visible);
93
94 bool beatsVisible () const { return beats_visible_; }
95 void setBeatsVisible (bool visible);
96
97 utils::NoteLength snapNoteLength () const { return snap_note_length_; }
98 void setSnapNoteLength (utils::NoteLength length);
99
100 utils::NoteType snapNoteType () const { return snap_note_type_; }
101 void setSnapNoteType (utils::NoteType type);
102
103 NoteLengthType lengthType () const { return length_type_; }
104 void setLengthType (NoteLengthType type);
105
106 QString snapString () const;
107
108 // QML Invokable Methods
109 Q_INVOKABLE double snapWithoutStartTicks (double ticks)
110 {
111 return snap (units::ticks (ticks)).in (units::ticks);
112 }
113 Q_INVOKABLE double snapWithStartTicks (double ticks, double startTicks)
115 return snap (units::ticks (ticks), units::ticks (startTicks))
116 .in (units::ticks);
117 }
118 Q_INVOKABLE double nextSnapPoint (double ticks) const;
119 Q_INVOKABLE double prevSnapPoint (double ticks) const;
120 Q_INVOKABLE double closestSnapPoint (double ticks) const;
121 Q_INVOKABLE double snapTicks (int64_t ticks) const;
122 Q_INVOKABLE double defaultTicks (int64_t ticks) const;
123
130 units::precise_tick_t snap (
131 units::precise_tick_t ticks,
132 std::optional<units::precise_tick_t> start_ticks = std::nullopt) const;
133
134 // Callback configuration
135 void set_event_callback (SnapEventCallback callback);
136 void set_last_object_length_callback (LastObjectLengthProvider callback)
137 {
138 last_object_length_provider_ = callback;
139 }
140 void clear_callbacks ();
141
142 static constexpr int get_ticks_from_length_and_type (
143 utils::NoteLength length,
144 utils::NoteType type,
145 int ticks_per_bar,
146 int ticks_per_beat)
147 {
148 assert (ticks_per_beat > 0);
149 assert (ticks_per_bar > 0);
150
151 int ticks = 0;
152 switch (length)
153 {
154 case utils::NoteLength::Bar:
155 ticks = ticks_per_bar;
156 break;
157 case utils::NoteLength::Beat:
158 ticks = ticks_per_beat;
159 break;
160 case utils::NoteLength::Note_2_1:
161 ticks = 8 * TempoMap::get_ppq ();
162 break;
163 case utils::NoteLength::Note_1_1:
164 ticks = 4 * TempoMap::get_ppq ();
165 break;
166 case utils::NoteLength::Note_1_2:
167 ticks = 2 * TempoMap::get_ppq ();
168 break;
169 case utils::NoteLength::Note_1_4:
170 ticks = TempoMap::get_ppq ();
171 break;
172 case utils::NoteLength::Note_1_8:
173 ticks = TempoMap::get_ppq () / 2;
174 break;
175 case utils::NoteLength::Note_1_16:
176 ticks = TempoMap::get_ppq () / 4;
177 break;
178 case utils::NoteLength::Note_1_32:
179 ticks = TempoMap::get_ppq () / 8;
180 break;
181 case utils::NoteLength::Note_1_64:
182 ticks = TempoMap::get_ppq () / 16;
183 break;
184 case utils::NoteLength::Note_1_128:
185 ticks = TempoMap::get_ppq () / 32;
186 break;
187 }
188
189 switch (type)
190 {
191 case utils::NoteType::Normal:
192 break;
194 ticks = 3 * ticks;
195 assert (ticks % 2 == 0);
196 ticks = ticks / 2;
197 break;
199 ticks = 2 * ticks;
200 assert (ticks % 3 == 0);
201 ticks = ticks / 3;
202 break;
203 }
204
205 return ticks;
206 }
207
208 static QString stringize_length_and_type (
209 utils::NoteLength note_length,
210 utils::NoteType note_type);
211
212Q_SIGNALS:
213 void snapAdaptiveChanged ();
214 void snapToGridChanged ();
215 void snapToEventsChanged ();
216 void keepOffsetChanged ();
217 void sixteenthsVisibleChanged ();
218 void beatsVisibleChanged ();
219 void snapNoteLengthChanged ();
220 void snapNoteTypeChanged ();
221 void lengthTypeChanged ();
222 void snapChanged ();
223
224private:
225 static constexpr auto kSnapNoteLengthKey = "snapNoteLength"sv;
226 static constexpr auto kSnapNoteTypeKey = "snapNoteType"sv;
227 static constexpr auto kSnapAdaptiveKey = "snapAdaptive"sv;
228 static constexpr auto kLengthTypeKey = "lengthType"sv;
229 static constexpr auto kSnapToGridKey = "snapToGrid"sv;
230 static constexpr auto kKeepOffsetKey = "keepOffset"sv;
231 static constexpr auto kSnapToEventsKey = "snapToEvents"sv;
232 friend void to_json (nlohmann::json &j, const SnapGrid &p)
233 {
234 j = nlohmann::json{
235 { kSnapNoteLengthKey, p.snap_note_length_ },
236 { kSnapNoteTypeKey, p.snap_note_type_ },
237 { kSnapAdaptiveKey, p.snap_adaptive_ },
238 { kLengthTypeKey, p.length_type_ },
239 { kSnapToGridKey, p.snap_to_grid_ },
240 { kKeepOffsetKey, p.snap_to_grid_keep_offset_ },
241 { kSnapToEventsKey, p.snap_to_events_ }
242 };
243 }
244 friend void from_json (const nlohmann::json &j, SnapGrid &p)
245 {
246 j.at (kSnapNoteLengthKey).get_to (p.snap_note_length_);
247 j.at (kSnapNoteTypeKey).get_to (p.snap_note_type_);
248 j.at (kSnapAdaptiveKey).get_to (p.snap_adaptive_);
249 j.at (kLengthTypeKey).get_to (p.length_type_);
250 j.at (kSnapToGridKey).get_to (p.snap_to_grid_);
251 j.at (kKeepOffsetKey).get_to (p.snap_to_grid_keep_offset_);
252 j.at (kSnapToEventsKey).get_to (p.snap_to_events_);
253 }
254
255 bool get_prev_or_next_snap_point (
256 double pivot_ticks,
257 double &out_ticks,
258 bool get_prev_point) const;
259 std::vector<double>
260 get_event_snap_points (double start_ticks, double end_ticks) const;
261
268 constexpr utils::NoteLength get_effective_note_length () const
269 {
270 return snap_adaptive_
271 ? (sixteenths_visible_
272 ? utils::NoteLength::Note_1_16
273 : (beats_visible_ ? utils::NoteLength::Beat : utils::NoteLength::Bar))
274 : snap_note_length_;
275 }
276
277private:
278 bool snap_adaptive_ = false;
279 utils::NoteLength snap_note_length_{ utils::NoteLength::Note_1_4 };
280 utils::NoteType snap_note_type_{ utils::NoteType::Normal };
281
283 bool snap_to_grid_ = true;
284
290 bool snap_to_grid_keep_offset_ = false;
291
298 bool snap_to_events_ = false;
299
301 bool sixteenths_visible_ = false;
302 bool beats_visible_ = false;
303
308 utils::NoteLength default_note_length_;
309
310 const TempoMap &tempo_map_;
311 std::optional<SnapEventCallback> event_callback_;
312 LastObjectLengthProvider last_object_length_provider_;
313};
314
315} // namespace zrythm::dsp
Snap/grid information.
Definition snap_grid.h:22
@ LastObject
Use last created object's length.
Definition snap_grid.h:45
@ Link
Link length with snap setting.
Definition snap_grid.h:42
units::precise_tick_t snap(units::precise_tick_t ticks, std::optional< units::precise_tick_t > start_ticks=std::nullopt) const
String utilities.
Definition algorithms.h:12
@ Triplet
3/2 of its original size
Definition note_type.h:34
@ Dotted
2/3 of its original size
Definition note_type.h:33