Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
position.h
1// SPDX-FileCopyrightText: © 2018-2021, 2023-2025 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#ifndef ZRYTHM_COMMON_DSP_POSITION_H
5#define ZRYTHM_COMMON_DSP_POSITION_H
6
7#include "utils/serialization.h"
8#include "utils/types.h"
9
10namespace zrythm::dsp
11{
12
13struct FramesPerTick
14 : type_safe::strong_typedef<FramesPerTick, double>,
15 type_safe::strong_typedef_op::equality_comparison<FramesPerTick>,
16 type_safe::strong_typedef_op::relational_comparison<FramesPerTick>
17{
18 using FramesPerTickTag = void; // used by the fmt formatter below
19 using type_safe::strong_typedef<FramesPerTick, double>::strong_typedef;
20
21 explicit FramesPerTick () = default;
22
23 static_assert (StrongTypedef<FramesPerTick>);
24};
25static_assert (std::regular<FramesPerTick>);
26
27struct TicksPerFrame
28 : type_safe::strong_typedef<TicksPerFrame, double>,
29 type_safe::strong_typedef_op::equality_comparison<TicksPerFrame>,
30 type_safe::strong_typedef_op::relational_comparison<TicksPerFrame>
31{
32 using TicksPerFrameTag = void; // used by the fmt formatter below
33 using type_safe::strong_typedef<TicksPerFrame, double>::strong_typedef;
34
35 explicit TicksPerFrame () = default;
36
37 static_assert (StrongTypedef<TicksPerFrame>);
38};
39static_assert (std::regular<TicksPerFrame>);
40
41static constexpr TicksPerFrame
42to_ticks_per_frame (const FramesPerTick &frames_per_tick)
43{
44 return TicksPerFrame (1.0 / type_safe::get (frames_per_tick));
45}
46static constexpr FramesPerTick
47to_frames_per_tick (const TicksPerFrame &ticks_per_frame)
48{
49 return FramesPerTick (1.0 / type_safe::get (ticks_per_frame));
50}
51
66class Position
67{
68public:
69 static constexpr int TICKS_PER_QUARTER_NOTE = 960;
70 static constexpr int TICKS_PER_SIXTEENTH_NOTE = 240;
71 static constexpr double TICKS_PER_QUARTER_NOTE_DBL = 960.0;
72 static constexpr double TICKS_PER_SIXTEENTH_NOTE_DBL = 240.0;
73 static constexpr double TICKS_PER_NINETYSIXTH_NOTE_DBL = 40.0;
74 static constexpr int POSITION_MAX_BAR = 160000;
75
76public:
77 // Rule of 0
78 Position () = default;
79
86 const char * str,
87 int beats_per_bar,
88 int sixteenths_per_beat,
89 FramesPerTick frames_per_tick);
90
92 Position (double ticks, dsp::FramesPerTick frames_per_tick)
93 {
94 from_ticks (ticks, frames_per_tick);
95 }
96
98 Position (signed_frame_t frames, TicksPerFrame ticks_per_frame)
99 {
100 from_frames (frames, ticks_per_frame);
101 }
102
103 void zero ()
104 {
105 ticks_ = 0.0;
106 frames_ = 0;
107 }
108
111
113 double get_total_ticks () const { return ticks_; }
114
122 static signed_frame_t compare_frames (const Position &p1, const Position &p2)
123 {
124 return p1.frames_ - p2.frames_;
125 }
126
127 bool ticks_equal (const Position &other) const
128 {
129 return fabs (ticks_ - other.ticks_) <= DBL_EPSILON;
130 }
131
133 static const Position &get_min (const Position &p1, const Position &p2)
134 {
135 return compare_frames (p1, p2) < 0 ? p1 : p2;
136 }
137
139 static const Position &get_max (const Position &p1, const Position &p2)
140 {
141 return compare_frames (p1, p2) > 0 ? p1 : p2;
142 }
143
144 bool is_positive () const { return frames_ >= 0 && ticks_ >= 0; }
145
150 bool
152 {
153 return frames_ >= f1 && frames_ < f2;
154 }
155
157 bool is_between_excl_2nd (const Position &start, const Position &end) const
158 {
160 }
161
164 bool is_between_incl_2nd (const Position &start, const Position &end) const
165 {
166 return frames_ >= start.frames_ && frames_ <= end.frames_;
167 }
168
169 bool is_between_excl_both (const Position &start, const Position &end) const
170 {
171 return frames_ > start.frames_ && frames_ < end.frames_;
172 }
173
174 bool
175 is_between_excl_1st_incl_2nd (const Position &start, const Position &end) const
176 {
177 return frames_ > start.frames_ && frames_ <= end.frames_;
178 }
179
183 void
184 set_to_bar (int bar, int ticks_per_bar, dsp::FramesPerTick frames_per_tick);
185
190 void add_frames (signed_frame_t frames, TicksPerFrame ticks_per_frame)
191 {
192 frames_ += frames;
193 update_ticks_from_frames (ticks_per_frame);
194 }
195
200 double secs,
201 sample_rate_t sample_rate,
202 TicksPerFrame ticks_per_frame);
203
204 void from_frames (const signed_frame_t frames, TicksPerFrame ticks_per_frame)
205 {
206 frames_ = frames;
207 update_ticks_from_frames (ticks_per_frame);
208 }
209
213 void from_ticks (double ticks, dsp::FramesPerTick frames_per_tick)
214 {
215 ticks_ = ticks;
216 update_frames_from_ticks (frames_per_tick);
217 }
218
219 void from_ms (
220 const double ms,
221 sample_rate_t sample_rate,
222 TicksPerFrame ticks_per_frame)
223 {
224 zero ();
225 add_ms (ms, sample_rate, ticks_per_frame);
226 }
227
228 void
229 from_bars (int bars, int ticks_per_bar, dsp::FramesPerTick frames_per_tick)
230 {
231 zero ();
232 add_bars (bars, ticks_per_bar, frames_per_tick);
233 }
234
235 void
236 add_bars (int bars, int ticks_per_bar, dsp::FramesPerTick frames_per_tick);
237
238 void
239 add_beats (int beats, int ticks_per_beat, dsp::FramesPerTick frames_per_tick);
240
241 void add_sixteenths (int sixteenths, dsp::FramesPerTick frames_per_tick)
242 {
243 add_ticks (sixteenths * TICKS_PER_SIXTEENTH_NOTE_DBL, frames_per_tick);
244 }
245
246 void add_ticks (double ticks, dsp::FramesPerTick frames_per_tick)
247 {
248 ticks_ += ticks;
249 update_frames_from_ticks (frames_per_tick);
250 }
251
255 signed_ms_t to_ms (sample_rate_t sample_rate) const;
256
257 static signed_frame_t ms_to_frames (double ms, sample_rate_t sample_rate);
258
259 static double
260 ms_to_ticks (double ms, sample_rate_t sample_rate, TicksPerFrame ticks_per_frame)
261 {
262 /* FIXME simplify - this is a roundabout way not suitable for realtime
263 * calculations */
264 const signed_frame_t frames = ms_to_frames (ms, sample_rate);
265 Position tmp;
266 tmp.from_frames (frames, ticks_per_frame);
267 return tmp.ticks_;
268 }
269
270 void
271 add_ms (double ms, sample_rate_t sample_rate, TicksPerFrame ticks_per_frame)
272 {
273 add_frames (ms_to_frames (ms, sample_rate), ticks_per_frame);
274 }
275
276 void
277 add_minutes (int mins, sample_rate_t sample_rate, TicksPerFrame ticks_per_frame)
278 {
279 add_frames (ms_to_frames (mins * 60 * 1'000, sample_rate), ticks_per_frame);
280 }
281
282 void add_seconds (
283 signed_sec_t seconds,
284 sample_rate_t sample_rate,
285 TicksPerFrame ticks_per_frame)
286 {
287 add_frames (
288 ms_to_frames (static_cast<double> (seconds * 1'000), sample_rate),
289 ticks_per_frame);
290 }
291
298 [[gnu::hot]] void update_ticks_from_frames (TicksPerFrame ticks_per_frame);
299
306 static signed_frame_t
307 get_frames_from_ticks (double ticks, dsp::FramesPerTick frames_per_tick);
308
312 [[gnu::hot]] void update_frames_from_ticks (FramesPerTick frames_per_tick);
313
321 const Position &start_pos,
322 const Position &end_pos,
323 FramesPerTick frames_per_tick)
324 {
325 ticks_ = start_pos.ticks_ + (end_pos.ticks_ - start_pos.ticks_) / 2.0;
326 update_frames_from_ticks (frames_per_tick);
327 }
328
332 std::string to_string (
333 int beats_per_bar,
334 int sixteenths_per_beat,
335 FramesPerTick frames_per_tick,
336 int decimal_places = 4) const;
337
338 [[gnu::nonnull]] void to_string (
339 int beats_per_bar,
340 int sixteenths_per_beat,
341 FramesPerTick frames_per_tick,
342 char * buf,
343 int decimal_places = 4) const;
344
348 void print (
349 int beats_per_bar,
350 int sixteenths_per_beat,
351 FramesPerTick frames_per_tick) const;
352
353 static void print_range (
354 int beats_per_bar,
355 int sixteenths_per_beat,
356 FramesPerTick frames_per_tick,
357 const Position &p1,
358 const Position &p2);
359
367 bool include_current,
368 int ticks_per_bar,
369 FramesPerTick frames_per_tick) const;
370
378 bool include_current,
379 int beats_per_bar,
380 int ticks_per_beat,
381 FramesPerTick frames_per_tick) const;
382
386 int
387 get_total_sixteenths (bool include_current, dsp::FramesPerTick frames_per_tick)
388 const;
389
396 {
397 ticks_ = -ticks_;
398 frames_ = -frames_;
399 }
400
408 int get_bars (bool start_at_one, int ticks_per_bar) const;
409
417 int
418 get_beats (bool start_at_one, int beats_per_bar, int ticks_per_beat) const;
419
428 bool start_at_one,
429 int beats_per_bar,
430 int sixteenths_per_beat,
431 FramesPerTick frames_per_tick) const;
432
438 double get_ticks_part (FramesPerTick frames_per_tick) const;
439
440 void set_to_pos (const Position &pos)
441 {
442 ticks_ = pos.ticks_;
443 frames_ = pos.frames_;
444 }
445
446 bool validate () const;
447
454 Position &get_closest_position (Position &p1, Position &p2) const
455 {
456 if (ticks_ - p1.ticks_ <= p2.ticks_ - ticks_)
457 {
458 return p1;
459 }
460
461 return p2;
462 }
463
465 friend auto operator<=> (const Position &lhs, const Position &rhs)
466 {
467 return lhs.frames_ <=> rhs.frames_;
468 }
469
470 friend bool operator== (const Position &lhs, const Position &rhs)
471 {
472 return (lhs <=> rhs) == 0;
473 }
474
475private:
476 NLOHMANN_DEFINE_TYPE_INTRUSIVE (Position, ticks_, frames_)
477
478public:
480 double ticks_ = 0.0;
481
488
497 // double precise_frames;
498};
499
500// Other comparison operators are automatically generated by the spaceship
501// operator
502
503}; // namespace zynth::dsp
504
505DEFINE_OBJECT_FORMATTER (zrythm::dsp::Position, Position, [] (const auto &obj) {
506 return fmt::format ("{:.3f} ticks ({} frames)", obj.ticks_, obj.frames_);
507});
508
509#endif
Represents the position of an object.
Definition position.h:67
bool is_between_excl_2nd(const Position &start, const Position &end) const
Returns if the position is after or equal to start and before end.
Definition position.h:157
int get_total_sixteenths(bool include_current, dsp::FramesPerTick frames_per_tick) const
Returns the total number of sixteenths not including the current one.
static const Position & get_min(const Position &p1, const Position &p2)
Returns minimum of p1 and p2.
Definition position.h:133
int get_total_beats(bool include_current, int beats_per_bar, int ticks_per_beat, FramesPerTick frames_per_tick) const
Returns the total number of beats.
int get_sixteenths(bool start_at_one, int beats_per_bar, int sixteenths_per_beat, FramesPerTick frames_per_tick) const
Gets the sixteenths of the position.
static const Position & get_max(const Position &p1, const Position &p2)
Returns maximum of p1 and p2.
Definition position.h:139
void update_ticks_from_frames(TicksPerFrame ticks_per_frame)
Updates ticks.
void from_seconds(double secs, sample_rate_t sample_rate, TicksPerFrame ticks_per_frame)
Converts seconds to position and puts the result in the given Position.
Position(const char *str, int beats_per_bar, int sixteenths_per_beat, FramesPerTick frames_per_tick)
Parses a position from the given string.
void print(int beats_per_bar, int sixteenths_per_beat, FramesPerTick frames_per_tick) const
Prints the Position in the "0.0.0.0" form.
void change_sign()
Changes the sign of the position.
Definition position.h:395
friend auto operator<=>(const Position &lhs, const Position &rhs)
Note: only checks frames.
Definition position.h:465
void update_frames_from_ticks(FramesPerTick frames_per_tick)
Updates frames.
signed_ms_t to_ms(sample_rate_t sample_rate) const
Returns the Position in milliseconds.
double get_total_ticks() const
Getter.
Definition position.h:113
bool is_between_incl_2nd(const Position &start, const Position &end) const
Returns if the position is after or equal to start and before or equal to end (ie,...
Definition position.h:164
int get_bars(bool start_at_one, int ticks_per_bar) const
Gets the bars of the position.
signed_frame_t frames_
Position in frames (samples).
Definition position.h:487
void add_frames(signed_frame_t frames, TicksPerFrame ticks_per_frame)
Adds the frames to the position and updates the rest of the fields, and makes sure the frames are sti...
Definition position.h:190
void set_to_bar(int bar, int ticks_per_bar, dsp::FramesPerTick frames_per_tick)
Sets position to given bar.
std::string to_string(int beats_per_bar, int sixteenths_per_beat, FramesPerTick frames_per_tick, int decimal_places=4) const
Creates a string in the form of "0.0.0.0" from the given position.
static signed_frame_t get_frames_from_ticks(double ticks, dsp::FramesPerTick frames_per_tick)
Converts ticks to frames.
Position(signed_frame_t frames, TicksPerFrame ticks_per_frame)
Construct from total number of frames.
Definition position.h:98
bool is_between_frames_excluding_2nd(signed_frame_t f1, signed_frame_t f2) const
Whether the position starts on or after f1 and before f2 (ie, the position is between f1 and f2,...
Definition position.h:151
static signed_frame_t compare_frames(const Position &p1, const Position &p2)
Compares 2 positions based on their frames.
Definition position.h:122
Position & get_closest_position(Position &p1, Position &p2) const
Returns the closest position.
Definition position.h:454
Position(double ticks, dsp::FramesPerTick frames_per_tick)
Construct from total number of ticks.
Definition position.h:92
void from_ticks(double ticks, dsp::FramesPerTick frames_per_tick)
Sets position to the given total tick count.
Definition position.h:213
int get_total_bars(bool include_current, int ticks_per_bar, FramesPerTick frames_per_tick) const
Returns the total number of beats.
int get_beats(bool start_at_one, int beats_per_bar, int ticks_per_beat) const
Gets the beats of the position.
double ticks_
Precise total number of ticks.
Definition position.h:480
void set_to_midway_pos(const Position &start_pos, const Position &end_pos, FramesPerTick frames_per_tick)
Sets the position to the midway point between the two given positions.
Definition position.h:320
signed_frame_t get_total_frames() const
Getter.
Definition position.h:110
double get_ticks_part(FramesPerTick frames_per_tick) const
Gets the ticks of the position.
#define DEFINE_OBJECT_FORMATTER(obj_type, function_prefix, formatter_func)
Defines a formatter for the given object type.
Definition format.h:80
uint32_t sample_rate_t
Sample rate.
Definition types.h:65
signed_frame_t signed_ms_t
Signed millisecond index.
Definition types.h:92
signed_frame_t signed_sec_t
Signed second index.
Definition types.h:95
int_fast64_t signed_frame_t
Signed type for frame index.
Definition types.h:82
Custom types.