aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/filters/splitter.cpp
blob: 8b1a4db4b39a9fbb7652acba141a60108498c716 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

#include "config.h"

#include "splitter.h"

#include <cmath>
#include <limits>
#include <algorithm>

#include "math_defs.h"

template<typename Real>
void BandSplitterR<Real>::init(Real f0norm)
{
    const Real w{f0norm * al::MathDefs<Real>::Tau()};
    const Real cw{std::cos(w)};
    if(cw > std::numeric_limits<float>::epsilon())
        coeff = (std::sin(w) - 1.0f) / cw;
    else
        coeff = cw * -0.5f;

    lp_z1 = 0.0f;
    lp_z2 = 0.0f;
    ap_z1 = 0.0f;
}

template<typename Real>
void BandSplitterR<Real>::process(Real *hpout, Real *lpout, const Real *input, const int count)
{
    ASSUME(count > 0);

    const Real ap_coeff{this->coeff};
    const Real lp_coeff{this->coeff*0.5f + 0.5f};
    Real lp_z1{this->lp_z1};
    Real lp_z2{this->lp_z2};
    Real ap_z1{this->ap_z1};
    auto proc_sample = [ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1,&lpout](const Real in) noexcept -> Real
    {
        /* Low-pass sample processing. */
        Real d{(in - lp_z1) * lp_coeff};
        Real lp_y{lp_z1 + d};
        lp_z1 = lp_y + d;

        d = (lp_y - lp_z2) * lp_coeff;
        lp_y = lp_z2 + d;
        lp_z2 = lp_y + d;

        *(lpout++) = lp_y;

        /* All-pass sample processing. */
        Real ap_y{in*ap_coeff + ap_z1};
        ap_z1 = in - ap_y*ap_coeff;

        /* High-pass generated from removing low-passed output. */
        return ap_y - lp_y;
    };
    std::transform(input, input+count, hpout, proc_sample);
    this->lp_z1 = lp_z1;
    this->lp_z2 = lp_z2;
    this->ap_z1 = ap_z1;
}

template<typename Real>
void BandSplitterR<Real>::applyHfScale(Real *samples, const Real hfscale, const int count)
{
    ASSUME(count > 0);

    const Real ap_coeff{this->coeff};
    const Real lp_coeff{this->coeff*0.5f + 0.5f};
    Real lp_z1{this->lp_z1};
    Real lp_z2{this->lp_z2};
    Real ap_z1{this->ap_z1};
    auto proc_sample = [hfscale,ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1](const Real in) noexcept -> Real
    {
        /* Low-pass sample processing. */
        Real d{(in - lp_z1) * lp_coeff};
        Real lp_y{lp_z1 + d};
        lp_z1 = lp_y + d;

        d = (lp_y - lp_z2) * lp_coeff;
        lp_y = lp_z2 + d;
        lp_z2 = lp_y + d;

        /* All-pass sample processing. */
        Real ap_y{in*ap_coeff + ap_z1};
        ap_z1 = in - ap_y*ap_coeff;

        /* High-pass generated from removing low-passed output. */
        return (ap_y-lp_y)*hfscale + lp_y;
    };
    std::transform(samples, samples+count, samples, proc_sample);
    this->lp_z1 = lp_z1;
    this->lp_z2 = lp_z2;
    this->ap_z1 = ap_z1;
}

template class BandSplitterR<float>;
template class BandSplitterR<double>;


template<typename Real>
void SplitterAllpassR<Real>::init(Real f0norm)
{
    const Real w{f0norm * al::MathDefs<Real>::Tau()};
    const Real cw{std::cos(w)};
    if(cw > std::numeric_limits<float>::epsilon())
        coeff = (std::sin(w) - 1.0f) / cw;
    else
        coeff = cw * -0.5f;

    z1 = 0.0f;
}

template<typename Real>
void SplitterAllpassR<Real>::process(Real *samples, int count)
{
    ASSUME(count > 0);

    const Real coeff{this->coeff};
    Real z1{this->z1};
    auto proc_sample = [coeff,&z1](const Real in) noexcept -> Real
    {
        const Real out{in*coeff + z1};
        z1 = in - out*coeff;
        return out;
    };
    std::transform(samples, samples+count, samples, proc_sample);
    this->z1 = z1;
}

template class SplitterAllpassR<float>;
template class SplitterAllpassR<double>;