1 /** @addtogroup dsp_extra
2 * @{
3 */
4 /*
5 Copyright (C) 2016 D Levin (https://www.kfrlib.com)
6 This file is part of KFR
7
8 KFR is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
12
13 KFR is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with KFR.
20
21 If GPL is not suitable for your project, you must purchase a commercial license to use KFR.
22 Buying a commercial license is mandatory as soon as you develop commercial activities without
23 disclosing the source code of your own applications.
24 See https://www.kfrlib.com for details.
25 */
26 #pragma once
27
28 #include "../base/basic_expressions.hpp"
29 #include "../math/abs.hpp"
30 #include "../math/log_exp.hpp"
31 #include "../simd/vec.hpp"
32
33 namespace kfr
34 {
35 inline namespace CMT_ARCH_NAME
36 {
37
38 using sample_rate_t = double;
39
40 namespace intrinsics
41 {
42 template <typename T1, typename T2>
fix_nans(const T1 & val,const T2 & replacement)43 KFR_INTRINSIC common_type<T1, T2> fix_nans(const T1& val, const T2& replacement)
44 {
45 return select(val != val, replacement, val);
46 }
47
48 template <typename T, typename TF = flt_type<T>>
amp_to_dB(const T & amp)49 KFR_INTRINSIC TF amp_to_dB(const T& amp)
50 {
51 return fix_nans(log(static_cast<TF>(abs(amp))) * subtype<TF>(8.6858896380650365530225783783322),
52 -c_infinity<T>);
53 // return T( 20.0 ) * log10( level );
54 }
55
56 template <typename T, typename TF = flt_type<T>>
dB_to_amp(const T & dB)57 KFR_INTRINSIC TF dB_to_amp(const T& dB)
58 {
59 return exp(dB * subtype<TF>(0.11512925464970228420089957273422));
60 // return exp10( dB / 20 );
61 }
62
63 template <typename T, typename TF = flt_type<T>>
amp_to_dB(const T & amp,const T & offset)64 KFR_INTRINSIC TF amp_to_dB(const T& amp, const T& offset)
65 {
66 return fix_nans(
67 log_fmadd(static_cast<TF>(abs(amp)), subtype<TF>(8.6858896380650365530225783783322), offset),
68 -c_infinity<T>);
69 // return T( 20.0 ) * log10( level );
70 }
71
72 template <typename T, typename TF = flt_type<T>>
dB_to_amp(const T & dB,const T & offset)73 KFR_INTRINSIC TF dB_to_amp(const T& dB, const T& offset)
74 {
75 auto offs = -subtype<TF>(0.11512925464970228420089957273422) * offset;
76 return exp_fmadd(dB, subtype<TF>(0.11512925464970228420089957273422), offs);
77 // return exp10( dB / 20 );
78 }
79
80 template <typename T, typename Tout = flt_type<T>>
power_to_dB(const T & x)81 KFR_INTRINSIC Tout power_to_dB(const T& x)
82 {
83 return log(static_cast<Tout>(abs(x))) * (10 * c_recip_log_10<Tout>);
84 }
85
86 template <typename T, typename Tout = flt_type<T>>
dB_to_power(const T & x)87 KFR_INTRINSIC Tout dB_to_power(const T& x)
88 {
89 if (x == -c_infinity<Tout>)
90 return 0.0;
91 else
92 return exp(x * (c_log_10<Tout> / 10.0));
93 }
94
95 template <typename T, typename TF = flt_type<T>>
note_to_hertz(const T & note)96 KFR_INTRINSIC TF note_to_hertz(const T& note)
97 {
98 const subtype<TF> offset = 2.1011784386926213177653145771814;
99
100 return intrinsics::exp_fmadd(note, subtype<TF>(0.05776226504666210911810267678818), offset);
101 }
102
103 template <typename T, typename TF = flt_type<T>>
hertz_to_note(const T & hertz)104 KFR_INTRINSIC TF hertz_to_note(const T& hertz)
105 {
106 const subtype<TF> offset = -36.376316562295915248836189714583;
107
108 return intrinsics::log_fmadd(hertz, subtype<TF>(17.312340490667560888319096172023), offset);
109 }
110
111 template <typename T1, typename T2, typename T3, typename Tc = flt_type<common_type<T1, T2, T3, f32>>>
note_to_hertz(const T1 & note,const T2 & tunenote,const T3 & tunehertz)112 KFR_INTRINSIC Tc note_to_hertz(const T1& note, const T2& tunenote, const T3& tunehertz)
113 {
114 const Tc offset = log(tunehertz) - tunenote * subtype<Tc>(0.05776226504666210911810267678818);
115
116 return intrinsics::exp_fmadd(note, subtype<Tc>(0.05776226504666210911810267678818), offset);
117 }
118
119 template <typename T1, typename T2, typename T3, typename Tc = flt_type<common_type<T1, T2, T3, f32>>>
hertz_to_note(const T1 & hertz,const T2 & tunenote,const T3 & tunehertz)120 KFR_INTRINSIC Tc hertz_to_note(const T1& hertz, const T2& tunenote, const T3& tunehertz)
121 {
122 const Tc offset = tunenote - log(tunehertz) * subtype<Tc>(17.312340490667560888319096172023);
123
124 return intrinsics::log_fmadd(hertz, subtype<Tc>(17.312340490667560888319096172023), offset);
125 }
126 } // namespace intrinsics
127 KFR_I_FN(note_to_hertz)
KFR_I_FN(hertz_to_note)128 KFR_I_FN(hertz_to_note)
129 KFR_I_FN(amp_to_dB)
130 KFR_I_FN(dB_to_amp)
131 KFR_I_FN(power_to_dB)
132 KFR_I_FN(dB_to_power)
133
134 template <typename T1, KFR_ENABLE_IF(is_numeric<T1>)>
135 KFR_FUNCTION flt_type<T1> note_to_hertz(const T1& x)
136 {
137 return intrinsics::note_to_hertz(x);
138 }
139
140 template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>)>
note_to_hertz(E1 && x)141 KFR_FUNCTION internal::expression_function<fn::note_to_hertz, E1> note_to_hertz(E1&& x)
142 {
143 return { fn::note_to_hertz(), std::forward<E1>(x) };
144 }
145
146 template <typename T1, KFR_ENABLE_IF(is_numeric<T1>)>
hertz_to_note(const T1 & x)147 KFR_FUNCTION flt_type<T1> hertz_to_note(const T1& x)
148 {
149 return intrinsics::hertz_to_note(x);
150 }
151
152 template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>)>
hertz_to_note(E1 && x)153 KFR_FUNCTION internal::expression_function<fn::hertz_to_note, E1> hertz_to_note(E1&& x)
154 {
155 return { fn::hertz_to_note(), std::forward<E1>(x) };
156 }
157
158 template <typename T1, KFR_ENABLE_IF(is_numeric<T1>)>
amp_to_dB(const T1 & x)159 KFR_FUNCTION flt_type<T1> amp_to_dB(const T1& x)
160 {
161 return intrinsics::amp_to_dB(x);
162 }
163
164 template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>)>
amp_to_dB(E1 && x)165 KFR_INTRINSIC internal::expression_function<fn::amp_to_dB, E1> amp_to_dB(E1&& x)
166 {
167 return { fn::amp_to_dB(), std::forward<E1>(x) };
168 }
169
170 template <typename T1, KFR_ENABLE_IF(is_numeric<T1>)>
dB_to_amp(const T1 & x)171 KFR_FUNCTION flt_type<T1> dB_to_amp(const T1& x)
172 {
173 return intrinsics::dB_to_amp(x);
174 }
175
176 template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>)>
dB_to_amp(E1 && x)177 KFR_FUNCTION internal::expression_function<fn::dB_to_amp, E1> dB_to_amp(E1&& x)
178 {
179 return { fn::dB_to_amp(), std::forward<E1>(x) };
180 }
181
182 template <typename T1, KFR_ENABLE_IF(is_numeric<T1>)>
power_to_dB(const T1 & x)183 KFR_FUNCTION flt_type<T1> power_to_dB(const T1& x)
184 {
185 return intrinsics::power_to_dB(x);
186 }
187
188 template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>)>
power_to_dB(E1 && x)189 KFR_FUNCTION internal::expression_function<fn::power_to_dB, E1> power_to_dB(E1&& x)
190 {
191 return { fn::power_to_dB(), std::forward<E1>(x) };
192 }
193
194 template <typename T1, KFR_ENABLE_IF(is_numeric<T1>)>
dB_to_power(const T1 & x)195 KFR_FUNCTION flt_type<T1> dB_to_power(const T1& x)
196 {
197 return intrinsics::dB_to_power(x);
198 }
199
200 template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>)>
dB_to_power(E1 && x)201 KFR_FUNCTION internal::expression_function<fn::dB_to_power, E1> dB_to_power(E1&& x)
202 {
203 return { fn::dB_to_power(), std::forward<E1>(x) };
204 }
205 } // namespace CMT_ARCH_NAME
206 } // namespace kfr
207