]> git.tdb.fi Git - ext/openal.git/blob - core/filters/splitter.cpp
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / core / filters / splitter.cpp
1
2 #include "config.h"
3
4 #include "splitter.h"
5
6 #include <algorithm>
7 #include <cmath>
8 #include <limits>
9
10 #include "alnumbers.h"
11 #include "opthelpers.h"
12
13
14 template<typename Real>
15 void BandSplitterR<Real>::init(Real f0norm)
16 {
17     const Real w{f0norm * (al::numbers::pi_v<Real>*2)};
18     const Real cw{std::cos(w)};
19     if(cw > std::numeric_limits<float>::epsilon())
20         mCoeff = (std::sin(w) - 1.0f) / cw;
21     else
22         mCoeff = cw * -0.5f;
23
24     mLpZ1 = 0.0f;
25     mLpZ2 = 0.0f;
26     mApZ1 = 0.0f;
27 }
28
29 template<typename Real>
30 void BandSplitterR<Real>::process(const al::span<const Real> input, Real *hpout, Real *lpout)
31 {
32     const Real ap_coeff{mCoeff};
33     const Real lp_coeff{mCoeff*0.5f + 0.5f};
34     Real lp_z1{mLpZ1};
35     Real lp_z2{mLpZ2};
36     Real ap_z1{mApZ1};
37     auto proc_sample = [ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1,&lpout](const Real in) noexcept -> Real
38     {
39         /* Low-pass sample processing. */
40         Real d{(in - lp_z1) * lp_coeff};
41         Real lp_y{lp_z1 + d};
42         lp_z1 = lp_y + d;
43
44         d = (lp_y - lp_z2) * lp_coeff;
45         lp_y = lp_z2 + d;
46         lp_z2 = lp_y + d;
47
48         *(lpout++) = lp_y;
49
50         /* All-pass sample processing. */
51         Real ap_y{in*ap_coeff + ap_z1};
52         ap_z1 = in - ap_y*ap_coeff;
53
54         /* High-pass generated from removing low-passed output. */
55         return ap_y - lp_y;
56     };
57     std::transform(input.cbegin(), input.cend(), hpout, proc_sample);
58     mLpZ1 = lp_z1;
59     mLpZ2 = lp_z2;
60     mApZ1 = ap_z1;
61 }
62
63 template<typename Real>
64 void BandSplitterR<Real>::processHfScale(const al::span<const Real> input, Real *RESTRICT output,
65     const Real hfscale)
66 {
67     const Real ap_coeff{mCoeff};
68     const Real lp_coeff{mCoeff*0.5f + 0.5f};
69     Real lp_z1{mLpZ1};
70     Real lp_z2{mLpZ2};
71     Real ap_z1{mApZ1};
72     auto proc_sample = [hfscale,ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1](const Real in) noexcept -> Real
73     {
74         /* Low-pass sample processing. */
75         Real d{(in - lp_z1) * lp_coeff};
76         Real lp_y{lp_z1 + d};
77         lp_z1 = lp_y + d;
78
79         d = (lp_y - lp_z2) * lp_coeff;
80         lp_y = lp_z2 + d;
81         lp_z2 = lp_y + d;
82
83         /* All-pass sample processing. */
84         Real ap_y{in*ap_coeff + ap_z1};
85         ap_z1 = in - ap_y*ap_coeff;
86
87         /* High-pass generated by removing the low-passed signal, which is then
88          * scaled and added back to the low-passed signal.
89          */
90         return (ap_y-lp_y)*hfscale + lp_y;
91     };
92     std::transform(input.begin(), input.end(), output, proc_sample);
93     mLpZ1 = lp_z1;
94     mLpZ2 = lp_z2;
95     mApZ1 = ap_z1;
96 }
97
98 template<typename Real>
99 void BandSplitterR<Real>::processHfScale(const al::span<Real> samples, const Real hfscale)
100 {
101     const Real ap_coeff{mCoeff};
102     const Real lp_coeff{mCoeff*0.5f + 0.5f};
103     Real lp_z1{mLpZ1};
104     Real lp_z2{mLpZ2};
105     Real ap_z1{mApZ1};
106     auto proc_sample = [hfscale,ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1](const Real in) noexcept -> Real
107     {
108         /* Low-pass sample processing. */
109         Real d{(in - lp_z1) * lp_coeff};
110         Real lp_y{lp_z1 + d};
111         lp_z1 = lp_y + d;
112
113         d = (lp_y - lp_z2) * lp_coeff;
114         lp_y = lp_z2 + d;
115         lp_z2 = lp_y + d;
116
117         /* All-pass sample processing. */
118         Real ap_y{in*ap_coeff + ap_z1};
119         ap_z1 = in - ap_y*ap_coeff;
120
121         /* High-pass generated by removing the low-passed signal, which is then
122          * scaled and added back to the low-passed signal.
123          */
124         return (ap_y-lp_y)*hfscale + lp_y;
125     };
126     std::transform(samples.begin(), samples.end(), samples.begin(), proc_sample);
127     mLpZ1 = lp_z1;
128     mLpZ2 = lp_z2;
129     mApZ1 = ap_z1;
130 }
131
132 template<typename Real>
133 void BandSplitterR<Real>::processScale(const al::span<Real> samples, const Real hfscale, const Real lfscale)
134 {
135     const Real ap_coeff{mCoeff};
136     const Real lp_coeff{mCoeff*0.5f + 0.5f};
137     Real lp_z1{mLpZ1};
138     Real lp_z2{mLpZ2};
139     Real ap_z1{mApZ1};
140     auto proc_sample = [hfscale,lfscale,ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1](const Real in) noexcept -> Real
141     {
142         Real d{(in - lp_z1) * lp_coeff};
143         Real lp_y{lp_z1 + d};
144         lp_z1 = lp_y + d;
145
146         d = (lp_y - lp_z2) * lp_coeff;
147         lp_y = lp_z2 + d;
148         lp_z2 = lp_y + d;
149
150         Real ap_y{in*ap_coeff + ap_z1};
151         ap_z1 = in - ap_y*ap_coeff;
152
153         /* Apply separate factors to the high and low frequencies. */
154         return (ap_y-lp_y)*hfscale + lp_y*lfscale;
155     };
156     std::transform(samples.begin(), samples.end(), samples.begin(), proc_sample);
157     mLpZ1 = lp_z1;
158     mLpZ2 = lp_z2;
159     mApZ1 = ap_z1;
160 }
161
162 template<typename Real>
163 void BandSplitterR<Real>::processAllPass(const al::span<Real> samples)
164 {
165     const Real coeff{mCoeff};
166     Real z1{mApZ1};
167     auto proc_sample = [coeff,&z1](const Real in) noexcept -> Real
168     {
169         const Real out{in*coeff + z1};
170         z1 = in - out*coeff;
171         return out;
172     };
173     std::transform(samples.cbegin(), samples.cend(), samples.begin(), proc_sample);
174     mApZ1 = z1;
175 }
176
177
178 template class BandSplitterR<float>;
179 template class BandSplitterR<double>;