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