1 /*
2  * Copyright (C) 2018-2021 Alexandros Theodotou <alex at zrythm dot org>
3  *
4  * This file is part of Zrythm
5  *
6  * Zrythm is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Zrythm is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with Zrythm.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 /**
21  * \file
22  *
23  * Position struct and API.
24  */
25 
26 #ifndef __AUDIO_POSITION_H__
27 #define __AUDIO_POSITION_H__
28 
29 #include <stdbool.h>
30 
31 #include "utils/yaml.h"
32 
33 /**
34  * @addtogroup audio
35  *
36  * @{
37  */
38 
39 #define POSITION_SCHEMA_VERSION 1
40 
41 #define TICKS_PER_QUARTER_NOTE 960
42 #define TICKS_PER_SIXTEENTH_NOTE 240
43 #define TICKS_PER_QUARTER_NOTE_DBL 960.0
44 #define TICKS_PER_SIXTEENTH_NOTE_DBL 240.0
45 #define position_add_sixteenths(_pos, _s) \
46   position_add_ticks ( \
47     (_pos), (_s) * TICKS_PER_SIXTEENTH_NOTE)
48 #define position_add_beats(_pos, _b) \
49   g_warn_if_fail (TRANSPORT->ticks_per_beat > 0); \
50   position_add_ticks ( \
51     (_pos), (_b) * TRANSPORT->ticks_per_beat)
52 #define position_add_bars(_pos, _b) \
53   g_warn_if_fail (TRANSPORT->ticks_per_bar > 0); \
54   position_add_ticks ( \
55     (_pos), (_b) * TRANSPORT->ticks_per_bar)
56 #define position_snap_simple(pos, sg) \
57   position_snap (NULL, pos, NULL, NULL, sg)
58 
59 #define POSITION_MAX_BAR 160000
60 
61 /**
62  * Whether the position starts on or after f1 and
63  * before f2.
64  */
65 #define position_between_frames_excl2(pos,f1,f2) \
66   ((pos)->frames >= f1 && (pos)->frames < f2)
67 
68 /**
69  * Compares 2 positions based on their frames.
70  *
71  * negative = p1 is earlier
72  * 0 = equal
73  * positive = p2 is earlier
74  */
75 #define position_compare(p1,p2) \
76   ((p1)->frames - (p2)->frames)
77 
78 /** Checks if _pos is before _cmp. */
79 #define position_is_before(_pos,_cmp) \
80   (position_compare (_pos, _cmp) < 0)
81 
82 /** Checks if _pos is before or equal to _cmp. */
83 #define position_is_before_or_equal(_pos,_cmp) \
84   (position_compare (_pos, _cmp) <= 0)
85 
86 /** Checks if _pos is equal to _cmp. */
87 #define position_is_equal(_pos,_cmp) \
88   (position_compare (_pos, _cmp) == 0)
89 
90 /** Checks if _pos is after _cmp. */
91 #define position_is_after(_pos,_cmp) \
92   (position_compare (_pos, _cmp) > 0)
93 
94 /** Checks if _pos is after or equal to _cmp. */
95 #define position_is_after_or_equal(_pos,_cmp) \
96   (position_compare (_pos, _cmp) >= 0)
97 
98 #define position_is_positive(pos) \
99   ((pos)->frames >= 0 && (pos)->ticks >= 0)
100 
101 /**
102  * Compares 2 positions based on their total ticks.
103  *
104  * negative = p1 is earlier
105  * 0 = equal
106  * positive = p2 is earlier
107  */
108 #define position_compare_ticks(p1,p2) \
109   ((p1)->ticks - (p2)->ticks)
110 
111 #define position_is_equal_ticks(p1,p2) \
112   (fabs (position_compare_ticks (p1, p2)) <= \
113      DBL_EPSILON)
114 
115 /** Returns if _pos is after or equal to _start and
116  * before _end. */
117 #define position_is_between(_pos,_start,_end) \
118   (position_is_after_or_equal (_pos, _start) && \
119    position_is_before (_pos, _end))
120 
121 /** Returns if _pos is after _start and
122  * before _end. */
123 #define position_is_between_excl_start(_pos,_start,_end) \
124   (position_is_after (_pos, _start) && \
125    position_is_before (_pos, _end))
126 
127 /** Inits the default position on the stack. */
128 #define POSITION_INIT_ON_STACK(name) \
129   Position name = POSITION_START;
130 
131 /**
132  * Initializes given position.
133  *
134  * Assumes the given argument is a Pointer *.
135  */
136 #define position_init(__pos) \
137   *(__pos) = POSITION_START
138 
139 typedef struct SnapGrid SnapGrid;
140 typedef struct Track Track;
141 typedef struct ZRegion ZRegion;
142 
143 /**
144  * A Position is made up of
145  * bars.beats.sixteenths.ticks.
146  */
147 typedef struct Position
148 {
149   int       schema_version;
150 
151   /** Precise total number of ticks. */
152   double    ticks;
153 
154   /** Position in frames (samples). */
155   long      frames;
156 } Position;
157 
158 static const cyaml_schema_field_t
159   position_fields_schema[] =
160 {
161   YAML_FIELD_INT (Position, schema_version),
162   YAML_FIELD_FLOAT (Position, ticks),
163   YAML_FIELD_INT (Position, frames),
164 
165   CYAML_FIELD_END
166 };
167 
168 static const cyaml_schema_value_t
169   position_schema =
170 {
171   YAML_VALUE_PTR (
172     Position, position_fields_schema),
173 };
174 
175 /** Start Position to be used in calculations. */
176 static const Position POSITION_START =
177 {
178   .schema_version = POSITION_SCHEMA_VERSION,
179   .ticks = 0.0,
180   .frames = 0
181 };
182 
183 static inline int
position_cmp_func(const void * _a,const void * _b)184 position_cmp_func (
185   const void * _a,
186   const void * _b)
187 {
188   const Position * a =
189     (Position const *) _a;
190   const Position * b =
191     (Position const *) _b;
192   return
193     position_compare (a, b);
194 }
195 
196 /**
197  * Sets position to given bar.
198  */
199 void
200 position_set_to_bar (
201   Position * self,
202   int        bar);
203 
204 /**
205  * Sorts an array of Position's.
206  */
207 void
208 position_sort_array (
209   Position *   array,
210   const size_t size);
211 
212 /**
213  * Sets position to target position
214  *
215  * Assumes each position is Position *.
216  */
217 #define position_set_to_pos(_pos,_target) \
218   *(_pos) = *(_target)
219 
220 /**
221  * Adds the frames to the position and updates
222  * the rest of the fields, and makes sure the
223  * frames are still accurate.
224  */
225 HOT
226 void
227 position_add_frames (
228   Position * pos,
229   const long frames);
230 
231 /** Deprecated - added for compatibility. */
232 #define position_to_frames(x) ((x)->frames)
233 #define position_to_ticks(x) ((x)->ticks)
234 
235 /**
236  * Converts seconds to position and puts the result
237  * in the given Position.
238  */
239 void
240 position_from_seconds (
241   Position * position,
242   double     secs);
243 
244 HOT
245 NONNULL
246 void
247 position_from_frames (
248   Position * pos,
249   long       frames);
250 
251 /**
252  * Sets position to the given total tick count.
253  */
254 HOT
255 NONNULL
256 void
257 position_from_ticks (
258   Position * pos,
259   double     ticks);
260 
261 NONNULL
262 void
263 position_from_bars (
264   Position * pos,
265   int        bars);
266 
267 HOT
268 NONNULL
269 void
270 position_add_ticks (
271   Position * self,
272   double     ticks);
273 
274 /**
275  * Returns the Position in milliseconds.
276  */
277 long
278 position_to_ms (
279   const Position * pos);
280 
281 long
282 position_ms_to_frames (
283   const long ms);
284 
285 void
286 position_add_ms (
287   Position * pos,
288   long       ms);
289 
290 void
291 position_add_minutes (
292   Position * pos,
293   int        mins);
294 
295 void
296 position_add_seconds (
297   Position * pos,
298   long       seconds);
299 
300 /**
301  * Snaps position using given options.
302  *
303  * @param start_pos The previous position (ie, the
304  *   position the drag started at. This is only used
305  *   when the "keep offset" setting is on.
306  * @param pos Position to edit.
307  * @param track Track, used when moving things in
308  *   the timeline. If keep offset is on and this is
309  *   passed, the objects in the track will be taken
310  *   into account. If keep offset is on and this is
311  *   NULL, all applicable objects will be taken into
312  *   account. Not used if keep offset is off.
313  * @param region Region, used when moving
314  *   things in the editor. Same behavior as @ref
315  *   track.
316  * @param sg SnapGrid options.
317  */
318 NONNULL_ARGS (2)
319 void
320 position_snap (
321   const Position * start_pos,
322   Position *       pos,
323   Track    *       track,
324   ZRegion   *      region,
325   const SnapGrid * sg);
326 
327 /**
328  * Sets the end position to be 1 snap point away
329  * from the start pos.
330  *
331  * FIXME rename to something more meaningful.
332  *
333  * @param start_pos Start Position.
334  * @param end_pos End Position.
335  * @param snap SnapGrid.
336  */
337 void
338 position_set_min_size (
339   const Position * start_pos,
340   Position * end_pos,
341   SnapGrid * snap);
342 
343 /**
344  * Updates ticks.
345  */
346 HOT
347 NONNULL
348 void
349 position_update_ticks_from_frames (
350   Position * position);
351 
352 /**
353  * Converts ticks to frames.
354  */
355 long
356 position_get_frames_from_ticks (
357   double ticks);
358 
359 /**
360  * Updates frames.
361  */
362 HOT
363 NONNULL
364 void
365 position_update_frames_from_ticks (
366   Position * position);
367 
368 /**
369  * Updates the position from ticks or frames.
370  *
371  * @param from_ticks Whether to update the
372  *   position based on ticks (true) or frames
373  *   (false).
374  */
375 static inline void
position_update(Position * self,bool from_ticks)376 position_update (
377   Position * self,
378   bool       from_ticks)
379 {
380   if (from_ticks)
381     position_update_frames_from_ticks (self);
382   else
383     position_update_ticks_from_frames (self);
384 }
385 
386 /**
387  * Calculates the midway point between the two
388  * Positions and sets it on pos.
389  *
390  * @param pos Position to set to.
391  */
392 void
393 position_get_midway_pos (
394   Position * start_pos,
395   Position * end_pos,
396   Position * pos);
397 
398 /**
399  * Returns the difference in ticks between the two
400  * Position's, snapped based on the given SnapGrid
401  * (if any).
402  *
403  * @param end_pos End position.
404  * @param start_pos Start Position.
405  * @param sg SnapGrid to snap with, or NULL to not
406  *   snap.
407  */
408 double
409 position_get_ticks_diff (
410   const Position * end_pos,
411   const Position * start_pos,
412   const SnapGrid * sg);
413 
414 /**
415  * Creates a string in the form of "0.0.0.0" from
416  * the given position.
417  *
418  * Must be free'd by caller.
419  */
420 NONNULL
421 char *
422 position_to_string_alloc (
423   const Position * pos);
424 
425 NONNULL
426 void
427 position_to_string_full (
428   const Position * pos,
429   char *           buf,
430   int              decimal_places);
431 
432 /**
433  * Creates a string in the form of "0.0.0.0" from
434  * the given position.
435  */
436 NONNULL
437 void
438 position_to_string (
439   const Position * pos,
440   char *           buf);
441 
442 /**
443  * Prints the Position in the "0.0.0.0" form.
444  */
445 NONNULL
446 void
447 position_print (
448   const Position * pos);
449 
450 NONNULL
451 void
452 position_print_range (
453   const Position * pos,
454   const Position * pos2);
455 
456 /**
457  * Returns the total number of beats.
458  *
459  * @param include_current Whether to count the
460  *   current beat if it is at the beat start.
461  */
462 NONNULL
463 int
464 position_get_total_bars (
465   const Position * pos,
466   bool  include_current);
467 
468 /**
469  * Returns the total number of beats.
470  *
471  * @param include_current Whether to count the
472  *   current beat if it is at the beat start.
473  */
474 NONNULL
475 int
476 position_get_total_beats (
477   const Position * pos,
478   bool  include_current);
479 
480 /**
481  * Returns the total number of sixteenths not
482  * including the current one.
483  */
484 NONNULL
485 int
486 position_get_total_sixteenths (
487   const Position * pos,
488   bool             include_current);
489 
490 /**
491  * Changes the sign of the position.
492  *
493  * For example, 4.2.1.21 would become -4.2.1.21.
494  */
495 NONNULL
496 void
497 position_change_sign (
498   Position * pos);
499 
500 /**
501  * Gets the bars of the position.
502  *
503  * Ie, if the position is equivalent to 4.1.2.42,
504  * this will return 4.
505  *
506  * @param start_at_one Start at 1 or -1 instead of
507  *   0.
508  */
509 NONNULL
510 int
511 position_get_bars (
512   const Position * pos,
513   bool  start_at_one);
514 
515 /**
516  * Gets the beats of the position.
517  *
518  * Ie, if the position is equivalent to 4.1.2.42,
519  * this will return 1.
520  *
521  * @param start_at_one Start at 1 or -1 instead of
522  *   0.
523  */
524 NONNULL
525 int
526 position_get_beats (
527   const Position * pos,
528   bool  start_at_one);
529 
530 /**
531  * Gets the sixteenths of the position.
532  *
533  * Ie, if the position is equivalent to 4.1.2.42,
534  * this will return 2.
535  *
536  * @param start_at_one Start at 1 or -1 instead of
537  *   0.
538  */
539 NONNULL
540 int
541 position_get_sixteenths (
542   const Position * pos,
543   bool  start_at_one);
544 
545 /**
546  * Gets the ticks of the position.
547  *
548  * Ie, if the position is equivalent to 4.1.2.42,
549  * this will return 42.
550  */
551 NONNULL
552 double
553 position_get_ticks (
554   const Position * pos);
555 
556 NONNULL
557 bool
558 position_validate (
559   const Position * pos);
560 
561 /**
562  * @}
563  */
564 
565 #endif
566