Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
math_utils.h
1// SPDX-FileCopyrightText: © 2018-2024 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3/*
4 * This file incorporates work covered by the following copyright and
5 * permission notices:
6 *
7 * ---
8 *
9 * Copyright (C) 2017-2019 Robin Gareus <robin@gareus.org>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 *
25 * ---
26 */
27
28#pragma once
29
30#include <cmath>
31#include <cstdint>
32#include <limits>
33#include <numbers>
34#include <string>
35
42{
43
49constexpr unsigned RMS_FRAMES = 1;
50
53constexpr float ALMOST_SILENCE = 0.0000001f;
54
55constexpr auto MINUS_INFINITY = -HUGE_VAL;
56
62template <std::floating_point T>
63constexpr bool
64floats_near (T a, T b, T e)
65{
66 return std::abs (a - b) < e;
67}
68
72template <std::floating_point T>
73constexpr bool
74floats_equal (T a, T b)
75{
76 return floats_near (a, b, std::numeric_limits<T>::epsilon ());
77}
78
82template <std::floating_point T>
83constexpr long
85{
86 if constexpr (std::is_same_v<T, float>)
87 {
88 return lroundf (x);
89 }
90 else
91 {
92 return lround (x);
93 }
94}
95
99template <std::floating_point T>
100constexpr long long
102{
103 if constexpr (std::is_same_v<T, float>)
104 {
105 return llroundf (x);
106 }
107 else
108 {
109 return llround (x);
110 }
111}
112
119[[gnu::const]]
120constexpr float
121fast_log2 (float val)
122{
123 union
124 {
125 float f;
126 int i;
127 } t{};
128 t.f = val;
129 int * const exp_ptr = &t.i;
130 int x = *exp_ptr;
131 const auto log_2 = (float) (((x >> 23) & 255) - 128);
132
133 x &= ~(255 << 23);
134 x += 127 << 23;
135
136 *exp_ptr = x;
137
138 val = ((-1.0f / 3) * t.f + 2) * t.f - 2.0f / 3;
139
140 return (val + log_2);
141}
142
143[[gnu::const]]
144constexpr auto
145fast_log (const float val)
146{
147 return (fast_log2 (val) * std::numbers::ln2_v<float>);
148}
149
150[[gnu::const]]
151constexpr auto
152fast_log10 (const float val)
153{
154 return fast_log2 (val) / 3.312500f;
155}
156
161template <std::floating_point T>
162[[gnu::const]]
163static inline T
164get_fader_val_from_amp (T amp)
165{
166 constexpr T fader_coefficient1 =
167 /*192.f * logf (2.f);*/
168 133.084258667509499408f;
169 constexpr T fader_coefficient2 =
170 /*powf (logf (2.f), 8.f) * powf (198.f, 8.f);*/
171 1.25870863180257576e17f;
172
173 /* to prevent weird values when amp is very
174 * small */
175 if (amp <= 0.00001f)
176 {
177 return 1e-20f;
178 }
179
180 if (floats_equal (amp, 1.f))
181 {
182 amp = 1.f + 1e-20f;
183 }
184 T fader =
185 std::powf (
186 // note: don't use fast_log here - it causes weirdness in faders
187 (6.f * std::logf (amp)) + fader_coefficient1, 8.f)
188 / fader_coefficient2;
189 return fader;
190}
191
195template <std::floating_point T>
196[[gnu::const]]
197static inline T
198get_amp_val_from_fader (T fader)
199{
200 constexpr float val1 = 1.f / 6.f;
201 return std::powf (
202 2.f, (val1) * (-192.f + 198.f * std::powf (fader, 1.f / 8.f)));
203}
204
208template <std::floating_point T>
209[[gnu::const]]
210static inline T
211amp_to_dbfs (T amp)
212{
213 return 20.f * std::log10f (amp);
214}
215
220float
221calculate_rms_amp (const float * buf, uint32_t nframes);
222
229template <std::floating_point T>
230static inline T
231calculate_rms_db (const T * buf, uint32_t nframes)
232{
233 return amp_to_dbfs (calculate_rms_amp (buf, nframes));
234}
235
239template <std::floating_point T>
240[[gnu::const]]
241static inline T
242dbfs_to_amp (T dbfs)
243{
244 return std::powf (10.f, (dbfs / 20.f));
245}
246
250template <std::floating_point T>
251[[gnu::const]]
252static inline T
253dbfs_to_fader_val (T dbfs)
254{
255 return get_fader_val_from_amp (dbfs_to_amp (dbfs));
256}
257
265bool
267
273bool
274is_string_valid_float (const std::string &str, float * ret);
275
276} // namespace zrythm::utils::math
float calculate_rms_amp(const float *buf, uint32_t nframes)
Gets the RMS of the given signal as amplitude (0-2).
constexpr bool floats_equal(T a, T b)
Checks if 2 floating point numbers are equal.
Definition math_utils.h:74
constexpr float fast_log2(float val)
Fast log calculation to be used where precision is not required (like log curves).
Definition math_utils.h:121
constexpr long round_to_signed_32(T x)
Rounds a double to a (minimum) signed 32-bit integer.
Definition math_utils.h:84
constexpr bool floats_near(T a, T b, T e)
Returns whether 2 floating point numbers are equal.
Definition math_utils.h:64
constexpr long long round_to_signed_64(T x)
Rounds a double to a (minimum) signed 64-bit integer.
Definition math_utils.h:101
bool is_string_valid_float(const std::string &str, float *ret)
Returns whether the given string is a valid float.
constexpr float ALMOST_SILENCE
Tiny number to be used for denormaml prevention (-140dB).
Definition math_utils.h:53
constexpr unsigned RMS_FRAMES
Frames to skip when calculating the RMS.
Definition math_utils.h:49
bool assert_nonnann(float x)
Asserts that the value is non-nan.