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