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  * This file incorporates work covered by the following copyright and
20  * permission notices:
21  *
22  * Copyright (C) 2017-2019 Robin Gareus <robin@gareus.org>
23  *
24  * This program is free software; you can redistribute it and/or modify
25  * it under the terms of the GNU General Public License as published by
26  * the Free Software Foundation; either version 2 of the License, or
27  * (at your option) any later version.
28  *
29  * This program is distributed in the hope that it will be useful,
30  * but WITHOUT ANY WARRANTY; without even the implied warranty of
31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32  * GNU General Public License for more details.
33  *
34  * You should have received a copy of the GNU General Public License along
35  * with this program; if not, write to the Free Software Foundation, Inc.,
36  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
37  */
38 
39 /**
40  * \file
41  *
42  * Math utils.
43  *
44  * For more, look at libs/pbd/pbd/control_math.h in
45  * ardour.
46  */
47 
48 #ifndef __UTILS_MATH_H__
49 #define __UTILS_MATH_H__
50 
51 #include <float.h>
52 #include <math.h>
53 #include <stdbool.h>
54 #include <stdint.h>
55 
56 #include "utils/types.h"
57 
58 /**
59  * @addtogroup utils
60  *
61  * @{
62  */
63 
64 /**
65  * Frames to skip when calculating the RMS.
66  *
67  * The lower the more CPU intensive.
68  */
69 #define MATH_RMS_FRAMES 1
70 
71 /** Tiny number to be used for denormaml prevention
72  * (-140dB). */
73 #define MATH_TINY_NUMBER (0.0000001)
74 
75 #define MATH_MINUS_INFINITY (- HUGE_VAL)
76 
77 /**
78  * Checks if 2 doubles are equal.
79  *
80  * @param epsilon The allowed difference.
81  */
82 #define math_floats_equal_epsilon(a,b,e) \
83   ((a) > (b) ? (a) - (b) < e : (b) - (a) < e)
84 
85 #define math_doubles_equal_epsilon \
86   math_floats_equal_epsilon
87 
88 /**
89  * Checks if 2 doubles are equal.
90  */
91 #define math_floats_equal(a,b) \
92   ((a) > (b) ? \
93    (a) - (b) < FLT_EPSILON : \
94    (b) - (a) < FLT_EPSILON)
95 
96 #define math_doubles_equal(a,b) \
97   ((a) > (b) ? \
98    (a) - (b) < DBL_EPSILON : \
99    (b) - (a) < DBL_EPSILON)
100 
101 /**
102  * Rounds a double to an int.
103  */
104 #define math_round_double_to_type(x,type) \
105   ((type) ((x) + 0.5 - ((x) < 0.0)))
106 
107 /**
108  * Rounds a double to an int.
109  */
110 #define math_round_double_to_int(x) \
111   math_round_double_to_type (x, int)
112 
113 #define math_round_double_to_uint(x) \
114   math_round_double_to_type (x, unsigned int)
115 
116 /**
117  * Rounds a double to a size_t.
118  */
119 #define math_round_double_to_size_t(x) \
120   math_round_double_to_type (x,size_t)
121 
122 /**
123  * Rounds a double to a long.
124  */
125 #define math_round_double_to_long(x) \
126   math_round_double_to_type (x,long)
127 
128 /**
129  * Rounds a float to a given type.
130  */
131 #define math_round_float_to_type(x,type) \
132   ((type) (x + 0.5f - (x < 0.f)))
133 
134 /**
135  * Rounds a float to an int.
136  */
137 #define math_round_float_to_int(x) \
138   math_round_float_to_type (x,int)
139 
140 /**
141  * Rounds a float to a long.
142  */
143 #define math_round_float_to_long(x) \
144   math_round_float_to_type (x,long)
145 
146 /**
147  * Fast log calculation to be used where precision
148  * is not required (like log curves).
149  *
150  * Taken from ardour from code in the public domain.
151  */
152 CONST
153 static inline float
math_fast_log2(float val)154 math_fast_log2 (
155   float val)
156 {
157   union {float f; int i;} t;
158   t.f = val;
159   int* const exp_ptr =  &t.i;
160   int        x       = *exp_ptr;
161   const int  log_2   = ((x >> 23) & 255) - 128;
162 
163   x &= ~(255 << 23);
164   x += 127 << 23;
165 
166   *exp_ptr = x;
167 
168   val = ((-1.0f/3) * t.f + 2) * t.f - 2.0f/3;
169 
170   return (val + log_2);
171 }
172 
173 CONST
174 static inline float
math_fast_log(const float val)175 math_fast_log (
176   const float val)
177 {
178   return (math_fast_log2 (val) * 0.69314718f);
179 }
180 
181 CONST
182 static inline float
math_fast_log10(const float val)183 math_fast_log10 (
184   const float val)
185 {
186   return math_fast_log2(val) / 3.312500f;
187 }
188 
189 /**
190  * Returns fader value 0.0 to 1.0 from amp value
191  * 0.0 to 2.0 (+6 dbFS).
192  */
193 CONST
194 static inline sample_t
math_get_fader_val_from_amp(sample_t amp)195 math_get_fader_val_from_amp (
196   sample_t amp)
197 {
198   static const float fader_coefficient1 =
199     /*192.f * logf (2.f);*/
200     133.084258667509499408f;
201   static const float fader_coefficient2 =
202     /*powf (logf (2.f), 8.f) * powf (198.f, 8.f);*/
203     1.25870863180257576e17f;
204 
205   /* to prevent weird values when amp is very
206    * small */
207   if (amp <= 0.00001f)
208     {
209       return 1e-20f;
210     }
211   else
212     {
213       if (math_floats_equal (amp, 1.f))
214         {
215           amp = 1.f + 1e-20f;
216         }
217       sample_t fader =
218         powf (
219           6.f * logf (amp) + fader_coefficient1, 8.f) /
220         fader_coefficient2;
221       return (sample_t) fader;
222     }
223 }
224 
225 /**
226  * Returns amp value 0.0 to 2.0 (+6 dbFS) from
227  * fader value 0.0 to 1.0.
228  */
229 CONST
230 static inline sample_t
math_get_amp_val_from_fader(sample_t fader)231 math_get_amp_val_from_fader (
232   sample_t fader)
233 {
234   static const float val1 = 1.f / 6.f;
235   return
236     powf (
237       2.f,
238       (val1) *
239       (-192.f + 198.f * powf (fader, 1.f / 8.f)));
240 }
241 
242 /**
243  * Convert from amplitude 0.0 to 2.0 to dbFS.
244  */
245 CONST
246 static inline sample_t
math_amp_to_dbfs(sample_t amp)247 math_amp_to_dbfs (
248   sample_t amp)
249 {
250   return 20.f * log10f (amp);
251 }
252 
253 sample_t
254 math_calculate_rms_amp (
255   sample_t *      buf,
256   const nframes_t nframes);
257 
258 /**
259  * Gets the digital peak of the given signal as
260  * amplitude (0-2).
261  */
262 DEPRECATED_MSG ("use abs max")
263 sample_t
264 math_calculate_max_amp (
265   sample_t *      buf,
266   const nframes_t nframes);
267 
268 /**
269  * Calculate db using RMS method.
270  *
271  * @param buf Buffer containing the samples.
272  * @param nframes Number of samples.
273  */
274 sample_t
275 math_calculate_rms_db (
276   sample_t *      buf,
277   const nframes_t nframes);
278 
279 /**
280  * Convert form dbFS to amplitude 0.0 to 2.0.
281  */
282 CONST
283 static inline sample_t
math_dbfs_to_amp(sample_t dbfs)284 math_dbfs_to_amp (
285   sample_t dbfs)
286 {
287   return powf (10.f, (dbfs / 20.f));
288 }
289 
290 /**
291  * Convert form dbFS to fader val 0.0 to 1.0.
292  */
293 CONST
294 static inline sample_t
math_dbfs_to_fader_val(sample_t dbfs)295 math_dbfs_to_fader_val (
296   sample_t dbfs)
297 {
298   return
299     math_get_fader_val_from_amp (
300       math_dbfs_to_amp (dbfs));
301 }
302 
303 /**
304  * Asserts that the value is non-nan.
305  *
306  * Not real-time safe.
307  *
308  * @return Whether the value is valid (nonnan).
309  */
310 bool
311 math_assert_nonnann (
312   float x);
313 
314 /**
315  * @}
316  */
317 
318 #endif
319