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#pragma once
5
6#include <limits>
7
8#include "utils/traits.h"
9#include "utils/types.h"
10
11#include <fmt/format.h>
12#include <nlohmann/json.hpp>
13#include <type_safe/strong_typedef.hpp>
14
15namespace zrythm::dsp
16{
17
18struct FramesPerTick
19 : type_safe::strong_typedef<FramesPerTick, double>,
20 type_safe::strong_typedef_op::equality_comparison<FramesPerTick>,
21 type_safe::strong_typedef_op::relational_comparison<FramesPerTick>
22{
23 using FramesPerTickTag = void; // used by the fmt formatter below
24 using type_safe::strong_typedef<FramesPerTick, double>::strong_typedef;
25
26 explicit FramesPerTick () = default;
27
28 static_assert (StrongTypedef<FramesPerTick>);
29};
30static_assert (std::regular<FramesPerTick>);
31
32struct TicksPerFrame
33 : type_safe::strong_typedef<TicksPerFrame, double>,
34 type_safe::strong_typedef_op::equality_comparison<TicksPerFrame>,
35 type_safe::strong_typedef_op::relational_comparison<TicksPerFrame>
36{
37 using TicksPerFrameTag = void; // used by the fmt formatter below
38 using type_safe::strong_typedef<TicksPerFrame, double>::strong_typedef;
39
40 explicit TicksPerFrame () = default;
41
42 static_assert (StrongTypedef<TicksPerFrame>);
43};
44static_assert (std::regular<TicksPerFrame>);
45
46static constexpr TicksPerFrame
47to_ticks_per_frame (const FramesPerTick &frames_per_tick)
48{
49 return TicksPerFrame (1.0 / type_safe::get (frames_per_tick));
50}
51static constexpr FramesPerTick
52to_frames_per_tick (const TicksPerFrame &ticks_per_frame)
53{
54 return FramesPerTick (1.0 / type_safe::get (ticks_per_frame));
55}
56
71class Position
72{
73public:
74 static constexpr int TICKS_PER_QUARTER_NOTE = 960;
75 static constexpr int TICKS_PER_SIXTEENTH_NOTE = 240;
76 static constexpr double TICKS_PER_QUARTER_NOTE_DBL = 960.0;
77 static constexpr double TICKS_PER_SIXTEENTH_NOTE_DBL = 240.0;
78 static constexpr double TICKS_PER_NINETYSIXTH_NOTE_DBL = 40.0;
79 static constexpr int POSITION_MAX_BAR = 160000;
80
81public:
82 // Rule of 0
83 Position () = default;
84
91 const char * str,
92 int beats_per_bar,
93 int sixteenths_per_beat,
94 FramesPerTick frames_per_tick);
95
97 Position (double ticks, dsp::FramesPerTick frames_per_tick)
98 {
99 from_ticks (ticks, frames_per_tick);
100 }
101
103 Position (signed_frame_t frames, TicksPerFrame ticks_per_frame)
104 {
105 from_frames (frames, ticks_per_frame);
106 }
107
108 void zero ()
109 {
110 ticks_ = 0.0;
111 frames_ = 0;
112 }
113
116
118 double get_total_ticks () const { return ticks_; }
119
127 static signed_frame_t compare_frames (const Position &p1, const Position &p2)
128 {
129 return p1.frames_ - p2.frames_;
130 }
131
132 bool ticks_equal (const Position &other) const
133 {
134 return std::abs (ticks_ - other.ticks_)
135 <= std::numeric_limits<double>::epsilon ();
136 }
137
139 static const Position &get_min (const Position &p1, const Position &p2)
140 {
141 return compare_frames (p1, p2) < 0 ? p1 : p2;
142 }
143
145 static const Position &get_max (const Position &p1, const Position &p2)
146 {
147 return compare_frames (p1, p2) > 0 ? p1 : p2;
148 }
149
150 bool is_positive () const { return frames_ >= 0 && ticks_ >= 0; }
151
156 bool
158 {
159 return frames_ >= f1 && frames_ < f2;
160 }
161
163 bool is_between_excl_2nd (const Position &start, const Position &end) const
164 {
166 }
167
170 bool is_between_incl_2nd (const Position &start, const Position &end) const
171 {
172 return frames_ >= start.frames_ && frames_ <= end.frames_;
173 }
174
175 bool is_between_excl_both (const Position &start, const Position &end) const
176 {
177 return frames_ > start.frames_ && frames_ < end.frames_;
178 }
179
180 bool
181 is_between_excl_1st_incl_2nd (const Position &start, const Position &end) const
182 {
183 return frames_ > start.frames_ && frames_ <= end.frames_;
184 }
185
189 void
190 set_to_bar (int bar, int ticks_per_bar, dsp::FramesPerTick frames_per_tick);
191
196 void add_frames (signed_frame_t frames, TicksPerFrame ticks_per_frame)
197 {
198 frames_ += frames;
199 update_ticks_from_frames (ticks_per_frame);
200 }
201
206 double secs,
207 sample_rate_t sample_rate,
208 TicksPerFrame ticks_per_frame);
209
210 void from_frames (const signed_frame_t frames, TicksPerFrame ticks_per_frame)
211 {
212 frames_ = frames;
213 update_ticks_from_frames (ticks_per_frame);
214 }
215
219 void from_ticks (double ticks, dsp::FramesPerTick frames_per_tick)
220 {
221 ticks_ = ticks;
222 update_frames_from_ticks (frames_per_tick);
223 }
224
225 void from_ms (
226 const double ms,
227 sample_rate_t sample_rate,
228 TicksPerFrame ticks_per_frame)
229 {
230 zero ();
231 add_ms (ms, sample_rate, ticks_per_frame);
232 }
233
234 void
235 from_bars (int bars, int ticks_per_bar, dsp::FramesPerTick frames_per_tick)
236 {
237 zero ();
238 add_bars (bars, ticks_per_bar, frames_per_tick);
239 }
240
241 void
242 add_bars (int bars, int ticks_per_bar, dsp::FramesPerTick frames_per_tick);
243
244 void
245 add_beats (int beats, int ticks_per_beat, dsp::FramesPerTick frames_per_tick);
246
247 void add_sixteenths (int sixteenths, dsp::FramesPerTick frames_per_tick)
248 {
249 add_ticks (sixteenths * TICKS_PER_SIXTEENTH_NOTE_DBL, frames_per_tick);
250 }
251
252 void add_ticks (double ticks, dsp::FramesPerTick frames_per_tick)
253 {
254 ticks_ += ticks;
255 update_frames_from_ticks (frames_per_tick);
256 }
257
261 signed_ms_t to_ms (sample_rate_t sample_rate) const;
262
263 static signed_frame_t ms_to_frames (double ms, sample_rate_t sample_rate);
264
265 static double
266 ms_to_ticks (double ms, sample_rate_t sample_rate, TicksPerFrame ticks_per_frame)
267 {
268 /* FIXME simplify - this is a roundabout way not suitable for realtime
269 * calculations */
270 const signed_frame_t frames = ms_to_frames (ms, sample_rate);
271 Position tmp;
272 tmp.from_frames (frames, ticks_per_frame);
273 return tmp.ticks_;
274 }
275
276 void
277 add_ms (double ms, sample_rate_t sample_rate, TicksPerFrame ticks_per_frame)
278 {
279 add_frames (ms_to_frames (ms, sample_rate), ticks_per_frame);
280 }
281
282 void
283 add_minutes (int mins, sample_rate_t sample_rate, TicksPerFrame ticks_per_frame)
284 {
285 add_frames (ms_to_frames (mins * 60 * 1'000, sample_rate), ticks_per_frame);
286 }
287
288 void add_seconds (
289 signed_sec_t seconds,
290 sample_rate_t sample_rate,
291 TicksPerFrame ticks_per_frame)
292 {
293 add_frames (
294 ms_to_frames (static_cast<double> (seconds * 1'000), sample_rate),
295 ticks_per_frame);
296 }
297
304 [[gnu::hot]] void update_ticks_from_frames (TicksPerFrame ticks_per_frame);
305
312 static signed_frame_t
313 get_frames_from_ticks (double ticks, dsp::FramesPerTick frames_per_tick);
314
318 [[gnu::hot]] void update_frames_from_ticks (FramesPerTick frames_per_tick);
319
327 const Position &start_pos,
328 const Position &end_pos,
329 FramesPerTick frames_per_tick)
330 {
331 ticks_ = start_pos.ticks_ + (end_pos.ticks_ - start_pos.ticks_) / 2.0;
332 update_frames_from_ticks (frames_per_tick);
333 }
334
338 std::string to_string (
339 int beats_per_bar,
340 int sixteenths_per_beat,
341 FramesPerTick frames_per_tick,
342 int decimal_places = 4) const;
343
344 [[gnu::nonnull]] void to_string (
345 int beats_per_bar,
346 int sixteenths_per_beat,
347 FramesPerTick frames_per_tick,
348 char * buf,
349 int decimal_places = 4) const;
350
354 void print (
355 int beats_per_bar,
356 int sixteenths_per_beat,
357 FramesPerTick frames_per_tick) const;
358
359 static void print_range (
360 int beats_per_bar,
361 int sixteenths_per_beat,
362 FramesPerTick frames_per_tick,
363 const Position &p1,
364 const Position &p2);
365
373 bool include_current,
374 int ticks_per_bar,
375 FramesPerTick frames_per_tick) const;
376
384 bool include_current,
385 int beats_per_bar,
386 int ticks_per_beat,
387 FramesPerTick frames_per_tick) const;
388
392 int
393 get_total_sixteenths (bool include_current, dsp::FramesPerTick frames_per_tick)
394 const;
395
402 {
403 ticks_ = -ticks_;
404 frames_ = -frames_;
405 }
406
414 int get_bars (bool start_at_one, int ticks_per_bar) const;
415
423 int
424 get_beats (bool start_at_one, int beats_per_bar, int ticks_per_beat) const;
425
434 bool start_at_one,
435 int beats_per_bar,
436 int sixteenths_per_beat,
437 FramesPerTick frames_per_tick) const;
438
444 double get_ticks_part (FramesPerTick frames_per_tick) const;
445
446 void set_to_position (const Position &pos)
447 {
448 ticks_ = pos.ticks_;
449 frames_ = pos.frames_;
450 }
451
458 Position &get_closest_position (Position &p1, Position &p2) const
459 {
460 if (ticks_ - p1.ticks_ <= p2.ticks_ - ticks_)
461 {
462 return p1;
463 }
464
465 return p2;
466 }
467
469 friend auto operator<=> (const Position &lhs, const Position &rhs)
470 {
471 return lhs.frames_ <=> rhs.frames_;
472 }
473
474 friend bool operator== (const Position &lhs, const Position &rhs)
475 {
476 return (lhs <=> rhs) == 0;
477 }
478
479private:
480 NLOHMANN_DEFINE_TYPE_INTRUSIVE (Position, ticks_, frames_)
481
482public:
484 double ticks_ = 0.0;
485
492
501 // double precise_frames;
502};
503
504inline auto
505format_as (const Position &p)
506{
507 return fmt::format ("{:.3f} ticks ({} frames)", p.ticks_, p.frames_);
508}
509
510}; // namespace zynth::dsp
Represents the position of an object.
Definition position.h:72
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:163
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:139
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:145
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:401
friend auto operator<=>(const Position &lhs, const Position &rhs)
Note: only checks frames.
Definition position.h:469
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:118
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:170
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:491
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:196
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:103
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:157
static signed_frame_t compare_frames(const Position &p1, const Position &p2)
Compares 2 positions based on their frames.
Definition position.h:127
Position & get_closest_position(Position &p1, Position &p2) const
Returns the closest position.
Definition position.h:458
Position(double ticks, dsp::FramesPerTick frames_per_tick)
Construct from total number of ticks.
Definition position.h:97
void from_ticks(double ticks, dsp::FramesPerTick frames_per_tick)
Sets position to the given total tick count.
Definition position.h:219
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:484
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:326
signed_frame_t get_total_frames() const
Getter.
Definition position.h:115
double get_ticks_part(FramesPerTick frames_per_tick) const
Gets the ticks of the position.
uint32_t sample_rate_t
Sample rate.
Definition types.h:61
signed_frame_t signed_ms_t
Signed millisecond index.
Definition types.h:84
signed_frame_t signed_sec_t
Signed second index.
Definition types.h:87
int_fast64_t signed_frame_t
Signed type for frame index.
Definition types.h:78