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/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::utils::NoteLength snapNoteLength READ snapNoteLength WRITE
43 setSnapNoteLength NOTIFY snapNoteLengthChanged)
44 Q_PROPERTY (
45 zrythm::utils::NoteType snapNoteType READ snapNoteType WRITE setSnapNoteType
46 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_UNCREATABLE ("")
53 QML_EXTENDED_NAMESPACE (zrythm::utils)
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 utils::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 utils::NoteLength snapNoteLength () const { return snap_note_length_; }
99 void setSnapNoteLength (utils::NoteLength length);
100
101 utils::NoteType snapNoteType () const { return snap_note_type_; }
102 void setSnapNoteType (utils::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 utils::NoteLength length,
145 utils::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 int ticks = 0;
153 switch (length)
154 {
155 case utils::NoteLength::Bar:
156 ticks = ticks_per_bar;
157 break;
158 case utils::NoteLength::Beat:
159 ticks = ticks_per_beat;
160 break;
161 case utils::NoteLength::Note_2_1:
162 ticks = 8 * TempoMap::get_ppq ();
163 break;
164 case utils::NoteLength::Note_1_1:
165 ticks = 4 * TempoMap::get_ppq ();
166 break;
167 case utils::NoteLength::Note_1_2:
168 ticks = 2 * TempoMap::get_ppq ();
169 break;
170 case utils::NoteLength::Note_1_4:
171 ticks = TempoMap::get_ppq ();
172 break;
173 case utils::NoteLength::Note_1_8:
174 ticks = TempoMap::get_ppq () / 2;
175 break;
176 case utils::NoteLength::Note_1_16:
177 ticks = TempoMap::get_ppq () / 4;
178 break;
179 case utils::NoteLength::Note_1_32:
180 ticks = TempoMap::get_ppq () / 8;
181 break;
182 case utils::NoteLength::Note_1_64:
183 ticks = TempoMap::get_ppq () / 16;
184 break;
185 case utils::NoteLength::Note_1_128:
186 ticks = TempoMap::get_ppq () / 32;
187 break;
188 }
189
190 switch (type)
191 {
192 case utils::NoteType::Normal:
193 break;
195 ticks = 3 * ticks;
196 assert (ticks % 2 == 0);
197 ticks = ticks / 2;
198 break;
200 ticks = 2 * ticks;
201 assert (ticks % 3 == 0);
202 ticks = ticks / 3;
203 break;
204 }
205
206 return ticks;
207 }
208
209 static QString stringize_length_and_type (
210 utils::NoteLength note_length,
211 utils::NoteType note_type);
212
213Q_SIGNALS:
214 void snapAdaptiveChanged ();
215 void snapToGridChanged ();
216 void snapToEventsChanged ();
217 void keepOffsetChanged ();
218 void sixteenthsVisibleChanged ();
219 void beatsVisibleChanged ();
220 void snapNoteLengthChanged ();
221 void snapNoteTypeChanged ();
222 void lengthTypeChanged ();
223 void snapChanged ();
224
225private:
226 static constexpr auto kSnapNoteLengthKey = "snapNoteLength"sv;
227 static constexpr auto kSnapNoteTypeKey = "snapNoteType"sv;
228 static constexpr auto kSnapAdaptiveKey = "snapAdaptive"sv;
229 static constexpr auto kLengthTypeKey = "lengthType"sv;
230 static constexpr auto kSnapToGridKey = "snapToGrid"sv;
231 static constexpr auto kKeepOffsetKey = "keepOffset"sv;
232 static constexpr auto kSnapToEventsKey = "snapToEvents"sv;
233 friend void to_json (nlohmann::json &j, const SnapGrid &p);
234 friend void from_json (const nlohmann::json &j, SnapGrid &p);
235
236 bool get_prev_or_next_snap_point (
237 double pivot_ticks,
238 double &out_ticks,
239 bool get_prev_point) const;
240 std::vector<double>
241 get_event_snap_points (double start_ticks, double end_ticks) const;
242
249 constexpr utils::NoteLength get_effective_note_length () const
250 {
251 return snap_adaptive_
252 ? (sixteenths_visible_
253 ? utils::NoteLength::Note_1_16
254 : (beats_visible_ ? utils::NoteLength::Beat : utils::NoteLength::Bar))
255 : snap_note_length_;
256 }
257
258private:
259 bool snap_adaptive_ = false;
260 utils::NoteLength snap_note_length_{ utils::NoteLength::Note_1_4 };
261 utils::NoteType snap_note_type_{ utils::NoteType::Normal };
262
264 bool snap_to_grid_ = true;
265
271 bool snap_to_grid_keep_offset_ = false;
272
279 bool snap_to_events_ = false;
280
282 bool sixteenths_visible_ = false;
283 bool beats_visible_ = false;
284
289 utils::NoteLength default_note_length_;
290
291 const TempoMap &tempo_map_;
292 std::optional<SnapEventCallback> event_callback_;
293 LastObjectLengthProvider last_object_length_provider_;
294};
295
296} // 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
String utilities.
@ Triplet
3/2 of its original size
Definition note_type.h:35
@ Dotted
2/3 of its original size
Definition note_type.h:34