]> git.tdb.fi Git - ext/openal.git/blob - core/uhjfilter.h
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / core / uhjfilter.h
1 #ifndef CORE_UHJFILTER_H
2 #define CORE_UHJFILTER_H
3
4 #include <array>
5
6 #include "almalloc.h"
7 #include "alspan.h"
8 #include "bufferline.h"
9
10
11 static constexpr size_t UhjLength256{256};
12 static constexpr size_t UhjLength512{512};
13
14 enum class UhjQualityType : uint8_t {
15     IIR = 0,
16     FIR256,
17     FIR512,
18     Default = IIR
19 };
20
21 extern UhjQualityType UhjDecodeQuality;
22 extern UhjQualityType UhjEncodeQuality;
23
24
25 struct UhjAllPassFilter {
26     struct AllPassState {
27         /* Last two delayed components for direct form II. */
28         float z[2];
29     };
30     std::array<AllPassState,4> mState;
31
32     void process(const al::span<const float,4> coeffs, const al::span<const float> src,
33         const bool update, float *RESTRICT dst);
34 };
35
36
37 struct UhjEncoderBase {
38     virtual ~UhjEncoderBase() = default;
39
40     virtual size_t getDelay() noexcept = 0;
41
42     /**
43      * Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input
44      * signal. The input must use FuMa channel ordering and UHJ scaling (FuMa
45      * with an additional +3dB boost).
46      */
47     virtual void encode(float *LeftOut, float *RightOut,
48         const al::span<const float*const,3> InSamples, const size_t SamplesToDo) = 0;
49 };
50
51 template<size_t N>
52 struct UhjEncoder final : public UhjEncoderBase {
53     static constexpr size_t sFilterDelay{N/2};
54
55     /* Delays and processing storage for the input signal. */
56     alignas(16) std::array<float,BufferLineSize+sFilterDelay> mW{};
57     alignas(16) std::array<float,BufferLineSize+sFilterDelay> mX{};
58     alignas(16) std::array<float,BufferLineSize+sFilterDelay> mY{};
59
60     alignas(16) std::array<float,BufferLineSize> mS{};
61     alignas(16) std::array<float,BufferLineSize> mD{};
62
63     /* History and temp storage for the FIR filter. New samples should be
64      * written to index sFilterDelay*2 - 1.
65      */
66     static constexpr size_t sWXInOffset{sFilterDelay*2 - 1};
67     alignas(16) std::array<float,BufferLineSize + sFilterDelay*2> mWX{};
68
69     alignas(16) std::array<std::array<float,sFilterDelay>,2> mDirectDelay{};
70
71     size_t getDelay() noexcept override { return sFilterDelay; }
72
73     /**
74      * Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input
75      * signal. The input must use FuMa channel ordering and UHJ scaling (FuMa
76      * with an additional +3dB boost).
77      */
78     void encode(float *LeftOut, float *RightOut, const al::span<const float*const,3> InSamples,
79         const size_t SamplesToDo) override;
80
81     DEF_NEWDEL(UhjEncoder)
82 };
83
84 struct UhjEncoderIIR final : public UhjEncoderBase {
85     static constexpr size_t sFilterDelay{1};
86
87     /* Processing storage for the input signal. */
88     alignas(16) std::array<float,BufferLineSize+1> mS{};
89     alignas(16) std::array<float,BufferLineSize+1> mD{};
90     alignas(16) std::array<float,BufferLineSize+sFilterDelay> mWX{};
91     alignas(16) std::array<float,BufferLineSize+sFilterDelay> mTemp{};
92     float mDelayWX{}, mDelayY{};
93
94     UhjAllPassFilter mFilter1WX;
95     UhjAllPassFilter mFilter2WX;
96     UhjAllPassFilter mFilter1Y;
97
98     std::array<UhjAllPassFilter,2> mFilter1Direct;
99     std::array<float,2> mDirectDelay{};
100
101     size_t getDelay() noexcept override { return sFilterDelay; }
102
103     /**
104      * Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input
105      * signal. The input must use FuMa channel ordering and UHJ scaling (FuMa
106      * with an additional +3dB boost).
107      */
108     void encode(float *LeftOut, float *RightOut, const al::span<const float*const,3> InSamples,
109         const size_t SamplesToDo) override;
110
111     DEF_NEWDEL(UhjEncoderIIR)
112 };
113
114
115 struct DecoderBase {
116     static constexpr size_t sMaxPadding{256};
117
118     /* For 2-channel UHJ, shelf filters should use these LF responses. */
119     static constexpr float sWLFScale{0.661f};
120     static constexpr float sXYLFScale{1.293f};
121
122     virtual ~DecoderBase() = default;
123
124     virtual void decode(const al::span<float*> samples, const size_t samplesToDo,
125         const bool updateState) = 0;
126
127     /**
128      * The width factor for Super Stereo processing. Can be changed in between
129      * calls to decode, with valid values being between 0...0.7.
130      */
131     float mWidthControl{0.593f};
132 };
133
134 template<size_t N>
135 struct UhjDecoder final : public DecoderBase {
136     /* The number of extra sample frames needed for input. */
137     static constexpr size_t sInputPadding{N/2};
138
139     alignas(16) std::array<float,BufferLineSize+sInputPadding> mS{};
140     alignas(16) std::array<float,BufferLineSize+sInputPadding> mD{};
141     alignas(16) std::array<float,BufferLineSize+sInputPadding> mT{};
142
143     alignas(16) std::array<float,sInputPadding-1> mDTHistory{};
144     alignas(16) std::array<float,sInputPadding-1> mSHistory{};
145
146     alignas(16) std::array<float,BufferLineSize + sInputPadding*2> mTemp{};
147
148     /**
149      * Decodes a 3- or 4-channel UHJ signal into a B-Format signal with FuMa
150      * channel ordering and UHJ scaling. For 3-channel, the 3rd channel may be
151      * attenuated by 'n', where 0 <= n <= 1. So to decode 2-channel UHJ, supply
152      * 3 channels with the 3rd channel silent (n=0). The B-Format signal
153      * reconstructed from 2-channel UHJ should not be run through a normal
154      * B-Format decoder, as it needs different shelf filters.
155      */
156     void decode(const al::span<float*> samples, const size_t samplesToDo,
157         const bool updateState) override;
158
159     DEF_NEWDEL(UhjDecoder)
160 };
161
162 struct UhjDecoderIIR final : public DecoderBase {
163     /* FIXME: These IIR decoder filters actually have a 1-sample delay on the
164      * non-filtered components, which is not reflected in the source latency
165      * value. sInputPadding is 0, however, because it doesn't need any extra
166      * input samples.
167      */
168     static constexpr size_t sInputPadding{0};
169
170     alignas(16) std::array<float,BufferLineSize> mS{};
171     alignas(16) std::array<float,BufferLineSize> mD{};
172     alignas(16) std::array<float,BufferLineSize+1> mTemp{};
173     float mDelayS{}, mDelayDT{}, mDelayQ{};
174
175     UhjAllPassFilter mFilter1S;
176     UhjAllPassFilter mFilter2DT;
177     UhjAllPassFilter mFilter1DT;
178     UhjAllPassFilter mFilter2S;
179     UhjAllPassFilter mFilter1Q;
180
181     void decode(const al::span<float*> samples, const size_t samplesToDo,
182         const bool updateState) override;
183
184     DEF_NEWDEL(UhjDecoderIIR)
185 };
186
187 template<size_t N>
188 struct UhjStereoDecoder final : public DecoderBase {
189     static constexpr size_t sInputPadding{N/2};
190
191     float mCurrentWidth{-1.0f};
192
193     alignas(16) std::array<float,BufferLineSize+sInputPadding> mS{};
194     alignas(16) std::array<float,BufferLineSize+sInputPadding> mD{};
195
196     alignas(16) std::array<float,sInputPadding-1> mDTHistory{};
197     alignas(16) std::array<float,sInputPadding-1> mSHistory{};
198
199     alignas(16) std::array<float,BufferLineSize + sInputPadding*2> mTemp{};
200
201     /**
202      * Applies Super Stereo processing on a stereo signal to create a B-Format
203      * signal with FuMa channel ordering and UHJ scaling. The samples span
204      * should contain 3 channels, the first two being the left and right stereo
205      * channels, and the third left empty.
206      */
207     void decode(const al::span<float*> samples, const size_t samplesToDo,
208         const bool updateState) override;
209
210     DEF_NEWDEL(UhjStereoDecoder)
211 };
212
213 struct UhjStereoDecoderIIR final : public DecoderBase {
214     static constexpr size_t sInputPadding{0};
215
216     float mCurrentWidth{-1.0f};
217
218     alignas(16) std::array<float,BufferLineSize> mS{};
219     alignas(16) std::array<float,BufferLineSize> mD{};
220     alignas(16) std::array<float,BufferLineSize+1> mTemp{};
221     float mDelayS{}, mDelayD{};
222
223     UhjAllPassFilter mFilter1S;
224     UhjAllPassFilter mFilter2D;
225     UhjAllPassFilter mFilter1D;
226     UhjAllPassFilter mFilter2S;
227
228     void decode(const al::span<float*> samples, const size_t samplesToDo,
229         const bool updateState) override;
230
231     DEF_NEWDEL(UhjStereoDecoderIIR)
232 };
233
234 #endif /* CORE_UHJFILTER_H */