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