1 /*
2 * Copyright (C) 2019-2020 Alexandros Theodotou <alex at zrythm dot org>
3 *
4 * This file is part of ZLFO
5 *
6 * ZLFO is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * ZLFO 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 General Affero Public License
17 * along with ZLFO. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 /**
21 * \file
22 *
23 * Math module.
24 */
25
26 #ifndef __Z_LFO_MATH_H__
27 #define __Z_LFO_MATH_H__
28
29 #include PLUGIN_CONFIG
30
31 #include <float.h>
32 #include <math.h>
33
34 #include "common.h"
35
36 static inline float
sync_rate_to_float(SyncRate rate,SyncRateType type)37 sync_rate_to_float (
38 SyncRate rate,
39 SyncRateType type)
40 {
41 float r = 0.01f;
42 switch (rate)
43 {
44 case SYNC_1_128:
45 r = 1.f / 128.f;
46 break;
47 case SYNC_1_64:
48 r = 1.f / 64.f;
49 break;
50 case SYNC_1_32:
51 r = 1.f / 32.f;
52 break;
53 case SYNC_1_16:
54 r = 1.f / 16.f;
55 break;
56 case SYNC_1_8:
57 r = 1.f / 8.f;
58 break;
59 case SYNC_1_4:
60 r = 1.f / 4.f;
61 break;
62 case SYNC_1_2:
63 r = 1.f / 2.f;
64 break;
65 case SYNC_1_1:
66 r = 1.f;
67 break;
68 case SYNC_2_1:
69 r = 2.f;
70 break;
71 case SYNC_4_1:
72 r = 4.f;
73 break;
74 case SYNC_8_1:
75 r = 8.f;
76 break;
77 case SYNC_16_1:
78 r = 16.f;
79 break;
80 case SYNC_32_1:
81 r = 32.f;
82 break;
83 case SYNC_64_1:
84 r = 64.f;
85 break;
86 case SYNC_128_1:
87 r = 128.f;
88 break;
89 default:
90 break;
91 }
92
93 switch (type)
94 {
95 case SYNC_TYPE_NORMAL:
96 break;
97 case SYNC_TYPE_DOTTED:
98 r *= 1.5f;
99 break;
100 case SYNC_TYPE_TRIPLET:
101 r *= (2.f / 3.f);
102 break;
103 default:
104 break;
105 }
106
107 return r;
108 }
109
110 /**
111 * Returns the number to use for dividing by the
112 * grid step.
113 *
114 * Eg., when grid step is HALF, this returns 2, the
115 * bottom half of "1/2".
116 */
117 static inline int
grid_step_to_divisor(GridStep step)118 grid_step_to_divisor (
119 GridStep step)
120 {
121 int ret = 0;
122 switch (step)
123 {
124 case GRID_STEP_FULL:
125 ret = 1;
126 break;
127 case GRID_STEP_HALF:
128 ret = 2;
129 break;
130 case GRID_STEP_FOURTH:
131 ret = 4;
132 break;
133 case GRID_STEP_EIGHTH:
134 ret = 8;
135 break;
136 case GRID_STEP_SIXTEENTH:
137 ret = 16;
138 break;
139 case GRID_STEP_THIRTY_SECOND:
140 ret = 32;
141 break;
142 default:
143 break;
144 }
145
146 return ret;
147 }
148
149 /**
150 * Gets the y value for a node at the given X coord.
151 *
152 * See https://stackoverflow.com/questions/17623152/how-map-tween-a-number-based-on-a-dynamic-curve
153 * @param x X-coordinate.
154 * @param curviness Curviness variable (1.0 is
155 * a straight line, 0.0 is full curved).
156 * @param start_higher Start at higher point.
157 */
158 static inline double
get_y_normalized(double x,double curviness,CurveAlgorithm algo,int start_higher,int curve_up)159 get_y_normalized (
160 double x,
161 double curviness,
162 CurveAlgorithm algo,
163 int start_higher,
164 int curve_up)
165 {
166 if (!start_higher)
167 x = 1.0 - x;
168 if (curve_up)
169 x = 1.0 - x;
170
171 double val;
172 switch (algo)
173 {
174 case CURVE_ALGORITHM_EXPONENT:
175 val =
176 pow (x, curviness);
177 break;
178 case CURVE_ALGORITHM_SUPERELLIPSE:
179 val =
180 pow (
181 1.0 - pow (x, curviness),
182 (1.0 / curviness));
183 break;
184 }
185 if (curve_up)
186 {
187 val = 1.0 - val;
188 }
189 return val;
190
191 fprintf (
192 stderr, "This line should not be reached");
193 }
194
195 static inline float
get_frames_per_beat(float bpm,float samplerate)196 get_frames_per_beat (
197 float bpm,
198 float samplerate)
199 {
200 return 60.0f / bpm * samplerate;
201 }
202
203 static inline float
get_effective_freq(int freerunning,float freq,HostPosition * host_pos,float sync_rate_float)204 get_effective_freq (
205 int freerunning,
206 float freq,
207 HostPosition * host_pos,
208 float sync_rate_float)
209 {
210 /* if beat_unit is 0 that means we don't know the
211 * time info yet */
212 if (freerunning || host_pos->beat_unit == 0)
213 {
214 if (!freerunning && host_pos->beat_unit == 0)
215 {
216 fprintf (
217 stderr,
218 "Host did not send time info. Beat "
219 "unit is unknown.\n");
220 }
221 return freq;
222 }
223 else /* synced */
224 {
225 /* bpm / (60 * BU * sync note) */
226 return
227 host_pos->bpm /
228 (60.f *
229 host_pos->beat_unit * sync_rate_float);
230 }
231 }
232
233 static inline uint32_t
get_period_size(int freerunning,HostPosition * host_pos,float effective_freq,float sync_rate_float,float frames_per_beat,float samplerate)234 get_period_size (
235 int freerunning,
236 HostPosition * host_pos,
237 float effective_freq,
238 float sync_rate_float,
239 float frames_per_beat,
240 float samplerate)
241 {
242 /* if beat_unit is 0 that means we don't know the
243 * time info yet */
244 if (freerunning || host_pos->beat_unit == 0)
245 {
246 if (!freerunning && host_pos->beat_unit == 0)
247 {
248 fprintf (
249 stderr,
250 "Host did not send time info. Beat "
251 "unit is unknown.\n");
252 }
253 return
254 (uint32_t) (samplerate / effective_freq);
255 }
256 else /* synced */
257 {
258 return
259 (uint32_t)
260 (frames_per_beat * host_pos->beat_unit *
261 sync_rate_float);
262 }
263 }
264
265 static inline uint32_t
get_current_sample(int freerunning,HostPosition * host_pos,uint32_t period_size)266 get_current_sample (
267 int freerunning,
268 HostPosition * host_pos,
269 uint32_t period_size)
270 {
271 if (freerunning)
272 {
273 return 0;
274 }
275 else if (host_pos->beat_unit == 0)
276 {
277 /* if beat_unit is 0 that means we don't
278 * know the time info yet */
279 fprintf (
280 stderr,
281 "Host did not send time info. Beat "
282 "unit is unknown.\n");
283 return 0;
284 }
285 else /* synced */
286 {
287 return host_pos->frame % period_size;
288 }
289 }
290
291 static inline int
float_array_contains_nonzero(const float * arr,size_t size)292 float_array_contains_nonzero (
293 const float * arr,
294 size_t size)
295 {
296 for (size_t i = 0; i < size; i++)
297 {
298 if (arr[i] > 0.0001f ||
299 arr[i] < - 0.0001f)
300 return 1;
301 }
302 return 0;
303 }
304
305 /**
306 * @param sine_multipler Position to save the sine
307 * multiplier in.
308 * @param saw_multipler Position to save the saw
309 * multiplier in.
310 */
311 static void
recalc_vars(int freerunning,float * sine_multiplier,float * saw_multiplier,long * period_size,long * current_sample,HostPosition * host_pos,float effective_freq,float sync_rate_float,float samplerate)312 recalc_vars (
313 int freerunning,
314 float * sine_multiplier,
315 float * saw_multiplier,
316 long * period_size,
317 long * current_sample,
318 HostPosition * host_pos,
319 float effective_freq,
320 float sync_rate_float,
321 float samplerate)
322 {
323 float frames_per_beat =
324 get_frames_per_beat (host_pos->bpm, samplerate);
325
326 /*
327 * F = frequency
328 * X = samples processed
329 * SR = sample rate
330 *
331 * First, get the radians.
332 * ? radians =
333 * (2 * PI) radians per LFO cycle *
334 * F cycles per second *
335 * (1 / SR samples per second) *
336 * X samples
337 *
338 * Then the LFO value is the sine of
339 * (radians % (2 * PI)).
340 *
341 * This multiplier handles the part known by now
342 * and the first part of the calculation should
343 * become:
344 * ? radians = X samples * sine_multiplier
345 */
346 *sine_multiplier =
347 (effective_freq / samplerate) * 2.f * PI;
348
349 /*
350 * F = frequency
351 * X = samples processed
352 * SR = sample rate
353 *
354 * First, get the value.
355 * ? value =
356 * (1 value per LFO cycle *
357 * F cycles per second *
358 * 1 / SR samples per second *
359 * X samples) % 1
360 *
361 * Then the LFO value is value * 2 - 1 (to make
362 * it start from -1 and end at 1).
363 *
364 * This multiplier handles the part known by now and the
365 * first part of the calculation should become:
366 * ? value = ((X samples * saw_multiplier) % 1) * 2 - 1
367 */
368 *saw_multiplier = effective_freq / samplerate;
369
370 *period_size =
371 get_period_size (
372 freerunning, host_pos, effective_freq,
373 sync_rate_float, frames_per_beat, samplerate);
374 if (current_sample)
375 {
376 *current_sample =
377 get_current_sample (
378 freerunning, host_pos, *period_size);
379 }
380 }
381
382 static inline long
invert_and_shift_xval(long base,long max_val,int hinvert,float shift)383 invert_and_shift_xval (
384 long base,
385 long max_val,
386 int hinvert,
387 float shift)
388 {
389 long ret = base;
390
391 /* invert horizontally */
392 if (hinvert)
393 {
394 ret = max_val - ret;
395 while (ret >= max_val)
396 ret -= max_val;
397 }
398
399 /* shift */
400 if (shift >= 0.5f)
401 {
402 /* add the samples to shift from 0 to
403 * (half the period width) */
404 ret +=
405 (long)
406 /* shift ratio */
407 (((shift - 0.5f) * 2.f) *
408 /* half a period */
409 (max_val / 2.f));
410
411 /* readjust */
412 ret = ret % max_val;
413 }
414 else
415 {
416 /* subtract the samples to shift between
417 * 0 and (half the period width) */
418 ret -=
419 (long)
420 /* shift ratio */
421 (((0.5f - shift) * 2.f) *
422 /* half a period */
423 (max_val / 2.f));
424
425 /* readjust */
426 while (ret < 0)
427 {
428 ret += max_val;
429 }
430 }
431
432 return ret;
433 }
434
435 /**
436 * This will return -1 if the next index is
437 * the copy of the first one at the end.
438 */
439 static inline int
get_next_idx(NodeIndexElement * elements,int num_nodes,float ratio)440 get_next_idx (
441 NodeIndexElement * elements,
442 int num_nodes,
443 float ratio)
444 {
445 float max_pos = 2.f;
446 int max_idx = 0;
447 for (int i = 0; i < num_nodes; i++)
448 {
449 if (elements[i].pos < max_pos &&
450 elements[i].pos >= ratio)
451 {
452 max_pos = elements[i].pos;
453 max_idx = elements[i].index;
454 }
455 }
456
457 /* if no match, the next index is the copy of
458 * the first one */
459 if (max_pos > 1.9f)
460 {
461 return -1;
462 }
463
464 return max_idx;
465 }
466
467 static inline int
get_prev_idx(NodeIndexElement * elements,int num_nodes,float ratio)468 get_prev_idx (
469 NodeIndexElement * elements,
470 int num_nodes,
471 float ratio)
472 {
473 float min_pos = -1.f;
474 int min_idx = 0;
475 for (int i = 0; i < num_nodes; i++)
476 {
477 if (elements[i].pos > min_pos &&
478 elements[i].pos <
479 (ratio + 0.0001f))
480 {
481 min_pos = elements[i].pos;
482 min_idx = elements[i].index;
483 }
484 }
485 return min_idx;
486 }
487
488 static int
pos_cmp(const void * a,const void * b)489 pos_cmp (const void * a, const void * b)
490 {
491 float pos_a = (*(NodeIndexElement*)a).pos;
492 float pos_b = (*(NodeIndexElement*)b).pos;
493 return pos_a > pos_b;
494 }
495
496 static inline void
sort_node_indices_by_pos(float nodes[16][3],NodeIndexElement * elements,int num_nodes)497 sort_node_indices_by_pos (
498 float nodes[16][3],
499 NodeIndexElement * elements,
500 int num_nodes)
501 {
502 for (int i = 0; i < num_nodes; i++)
503 {
504 /* set index and position */
505 elements[i].index = i;
506 elements[i].pos = nodes[i][0];
507 }
508
509 qsort (
510 elements, (size_t) num_nodes,
511 sizeof (NodeIndexElement), pos_cmp);
512 }
513
514 #endif
515