xref: /aosp_15_r20/external/oboe/src/flowgraph/resampler/MultiChannelResampler.h (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1*05767d91SRobert Wu /*
2*05767d91SRobert Wu  * Copyright 2019 The Android Open Source Project
3*05767d91SRobert Wu  *
4*05767d91SRobert Wu  * Licensed under the Apache License, Version 2.0 (the "License");
5*05767d91SRobert Wu  * you may not use this file except in compliance with the License.
6*05767d91SRobert Wu  * You may obtain a copy of the License at
7*05767d91SRobert Wu  *
8*05767d91SRobert Wu  *      http://www.apache.org/licenses/LICENSE-2.0
9*05767d91SRobert Wu  *
10*05767d91SRobert Wu  * Unless required by applicable law or agreed to in writing, software
11*05767d91SRobert Wu  * distributed under the License is distributed on an "AS IS" BASIS,
12*05767d91SRobert Wu  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*05767d91SRobert Wu  * See the License for the specific language governing permissions and
14*05767d91SRobert Wu  * limitations under the License.
15*05767d91SRobert Wu  */
16*05767d91SRobert Wu 
17*05767d91SRobert Wu #ifndef RESAMPLER_MULTICHANNEL_RESAMPLER_H
18*05767d91SRobert Wu #define RESAMPLER_MULTICHANNEL_RESAMPLER_H
19*05767d91SRobert Wu 
20*05767d91SRobert Wu #include <memory>
21*05767d91SRobert Wu #include <vector>
22*05767d91SRobert Wu #include <sys/types.h>
23*05767d91SRobert Wu #include <unistd.h>
24*05767d91SRobert Wu 
25*05767d91SRobert Wu #ifndef MCR_USE_KAISER
26*05767d91SRobert Wu // It appears from the spectrogram that the HyperbolicCosine window leads to fewer artifacts.
27*05767d91SRobert Wu // And it is faster to calculate.
28*05767d91SRobert Wu #define MCR_USE_KAISER 0
29*05767d91SRobert Wu #endif
30*05767d91SRobert Wu 
31*05767d91SRobert Wu #if MCR_USE_KAISER
32*05767d91SRobert Wu #include "KaiserWindow.h"
33*05767d91SRobert Wu #else
34*05767d91SRobert Wu #include "HyperbolicCosineWindow.h"
35*05767d91SRobert Wu #endif
36*05767d91SRobert Wu 
37*05767d91SRobert Wu #include "ResamplerDefinitions.h"
38*05767d91SRobert Wu 
39*05767d91SRobert Wu namespace RESAMPLER_OUTER_NAMESPACE::resampler {
40*05767d91SRobert Wu 
41*05767d91SRobert Wu class MultiChannelResampler {
42*05767d91SRobert Wu 
43*05767d91SRobert Wu public:
44*05767d91SRobert Wu 
45*05767d91SRobert Wu     enum class Quality : int32_t {
46*05767d91SRobert Wu         Fastest,
47*05767d91SRobert Wu         Low,
48*05767d91SRobert Wu         Medium,
49*05767d91SRobert Wu         High,
50*05767d91SRobert Wu         Best,
51*05767d91SRobert Wu     };
52*05767d91SRobert Wu 
53*05767d91SRobert Wu     class Builder {
54*05767d91SRobert Wu     public:
55*05767d91SRobert Wu         /**
56*05767d91SRobert Wu          * Construct an optimal resampler based on the specified parameters.
57*05767d91SRobert Wu          * @return address of a resampler
58*05767d91SRobert Wu          */
59*05767d91SRobert Wu         MultiChannelResampler *build();
60*05767d91SRobert Wu 
61*05767d91SRobert Wu         /**
62*05767d91SRobert Wu          * The number of taps in the resampling filter.
63*05767d91SRobert Wu          * More taps gives better quality but uses more CPU time.
64*05767d91SRobert Wu          * This typically ranges from 4 to 64. Default is 16.
65*05767d91SRobert Wu          *
66*05767d91SRobert Wu          * For polyphase filters, numTaps must be a multiple of four for loop unrolling.
67*05767d91SRobert Wu          * @param numTaps number of taps for the filter
68*05767d91SRobert Wu          * @return address of this builder for chaining calls
69*05767d91SRobert Wu          */
setNumTaps(int32_t numTaps)70*05767d91SRobert Wu         Builder *setNumTaps(int32_t numTaps) {
71*05767d91SRobert Wu             mNumTaps = numTaps;
72*05767d91SRobert Wu             return this;
73*05767d91SRobert Wu         }
74*05767d91SRobert Wu 
75*05767d91SRobert Wu         /**
76*05767d91SRobert Wu          * Use 1 for mono, 2 for stereo, etc. Default is 1.
77*05767d91SRobert Wu          *
78*05767d91SRobert Wu          * @param channelCount number of channels
79*05767d91SRobert Wu          * @return address of this builder for chaining calls
80*05767d91SRobert Wu          */
setChannelCount(int32_t channelCount)81*05767d91SRobert Wu         Builder *setChannelCount(int32_t channelCount) {
82*05767d91SRobert Wu             mChannelCount = channelCount;
83*05767d91SRobert Wu             return this;
84*05767d91SRobert Wu         }
85*05767d91SRobert Wu 
86*05767d91SRobert Wu         /**
87*05767d91SRobert Wu          * Default is 48000.
88*05767d91SRobert Wu          *
89*05767d91SRobert Wu          * @param inputRate sample rate of the input stream
90*05767d91SRobert Wu          * @return address of this builder for chaining calls
91*05767d91SRobert Wu          */
setInputRate(int32_t inputRate)92*05767d91SRobert Wu         Builder *setInputRate(int32_t inputRate) {
93*05767d91SRobert Wu             mInputRate = inputRate;
94*05767d91SRobert Wu             return this;
95*05767d91SRobert Wu         }
96*05767d91SRobert Wu 
97*05767d91SRobert Wu         /**
98*05767d91SRobert Wu          * Default is 48000.
99*05767d91SRobert Wu          *
100*05767d91SRobert Wu          * @param outputRate sample rate of the output stream
101*05767d91SRobert Wu          * @return address of this builder for chaining calls
102*05767d91SRobert Wu          */
setOutputRate(int32_t outputRate)103*05767d91SRobert Wu         Builder *setOutputRate(int32_t outputRate) {
104*05767d91SRobert Wu             mOutputRate = outputRate;
105*05767d91SRobert Wu             return this;
106*05767d91SRobert Wu         }
107*05767d91SRobert Wu 
108*05767d91SRobert Wu         /**
109*05767d91SRobert Wu          * Set cutoff frequency relative to the Nyquist rate of the output sample rate.
110*05767d91SRobert Wu          * Set to 1.0 to match the Nyquist frequency.
111*05767d91SRobert Wu          * Set lower to reduce aliasing.
112*05767d91SRobert Wu          * Default is 0.70.
113*05767d91SRobert Wu          *
114*05767d91SRobert Wu          * Note that this value is ignored when upsampling, which is when
115*05767d91SRobert Wu          * the outputRate is higher than the inputRate.
116*05767d91SRobert Wu          *
117*05767d91SRobert Wu          * @param normalizedCutoff anti-aliasing filter cutoff
118*05767d91SRobert Wu          * @return address of this builder for chaining calls
119*05767d91SRobert Wu          */
setNormalizedCutoff(float normalizedCutoff)120*05767d91SRobert Wu         Builder *setNormalizedCutoff(float normalizedCutoff) {
121*05767d91SRobert Wu             mNormalizedCutoff = normalizedCutoff;
122*05767d91SRobert Wu             return this;
123*05767d91SRobert Wu         }
124*05767d91SRobert Wu 
getNumTaps()125*05767d91SRobert Wu         int32_t getNumTaps() const {
126*05767d91SRobert Wu             return mNumTaps;
127*05767d91SRobert Wu         }
128*05767d91SRobert Wu 
getChannelCount()129*05767d91SRobert Wu         int32_t getChannelCount() const {
130*05767d91SRobert Wu             return mChannelCount;
131*05767d91SRobert Wu         }
132*05767d91SRobert Wu 
getInputRate()133*05767d91SRobert Wu         int32_t getInputRate() const {
134*05767d91SRobert Wu             return mInputRate;
135*05767d91SRobert Wu         }
136*05767d91SRobert Wu 
getOutputRate()137*05767d91SRobert Wu         int32_t getOutputRate() const {
138*05767d91SRobert Wu             return mOutputRate;
139*05767d91SRobert Wu         }
140*05767d91SRobert Wu 
getNormalizedCutoff()141*05767d91SRobert Wu         float getNormalizedCutoff() const {
142*05767d91SRobert Wu             return mNormalizedCutoff;
143*05767d91SRobert Wu         }
144*05767d91SRobert Wu 
145*05767d91SRobert Wu     protected:
146*05767d91SRobert Wu         int32_t mChannelCount = 1;
147*05767d91SRobert Wu         int32_t mNumTaps = 16;
148*05767d91SRobert Wu         int32_t mInputRate = 48000;
149*05767d91SRobert Wu         int32_t mOutputRate = 48000;
150*05767d91SRobert Wu         float   mNormalizedCutoff = kDefaultNormalizedCutoff;
151*05767d91SRobert Wu     };
152*05767d91SRobert Wu 
153*05767d91SRobert Wu     virtual ~MultiChannelResampler() = default;
154*05767d91SRobert Wu 
155*05767d91SRobert Wu     /**
156*05767d91SRobert Wu      * Factory method for making a resampler that is optimal for the given inputs.
157*05767d91SRobert Wu      *
158*05767d91SRobert Wu      * @param channelCount number of channels, 2 for stereo
159*05767d91SRobert Wu      * @param inputRate sample rate of the input stream
160*05767d91SRobert Wu      * @param outputRate  sample rate of the output stream
161*05767d91SRobert Wu      * @param quality higher quality sounds better but uses more CPU
162*05767d91SRobert Wu      * @return an optimal resampler
163*05767d91SRobert Wu      */
164*05767d91SRobert Wu     static MultiChannelResampler *make(int32_t channelCount,
165*05767d91SRobert Wu                                        int32_t inputRate,
166*05767d91SRobert Wu                                        int32_t outputRate,
167*05767d91SRobert Wu                                        Quality quality);
168*05767d91SRobert Wu 
isWriteNeeded()169*05767d91SRobert Wu     bool isWriteNeeded() const {
170*05767d91SRobert Wu         return mIntegerPhase >= mDenominator;
171*05767d91SRobert Wu     }
172*05767d91SRobert Wu 
173*05767d91SRobert Wu     /**
174*05767d91SRobert Wu      * Write a frame containing N samples.
175*05767d91SRobert Wu      *
176*05767d91SRobert Wu      * @param frame pointer to the first sample in a frame
177*05767d91SRobert Wu      */
writeNextFrame(const float * frame)178*05767d91SRobert Wu     void writeNextFrame(const float *frame) {
179*05767d91SRobert Wu         writeFrame(frame);
180*05767d91SRobert Wu         advanceWrite();
181*05767d91SRobert Wu     }
182*05767d91SRobert Wu 
183*05767d91SRobert Wu     /**
184*05767d91SRobert Wu      * Read a frame containing N samples.
185*05767d91SRobert Wu      *
186*05767d91SRobert Wu      * @param frame pointer to the first sample in a frame
187*05767d91SRobert Wu      */
readNextFrame(float * frame)188*05767d91SRobert Wu     void readNextFrame(float *frame) {
189*05767d91SRobert Wu         readFrame(frame);
190*05767d91SRobert Wu         advanceRead();
191*05767d91SRobert Wu     }
192*05767d91SRobert Wu 
getNumTaps()193*05767d91SRobert Wu     int getNumTaps() const {
194*05767d91SRobert Wu         return mNumTaps;
195*05767d91SRobert Wu     }
196*05767d91SRobert Wu 
getChannelCount()197*05767d91SRobert Wu     int getChannelCount() const {
198*05767d91SRobert Wu         return mChannelCount;
199*05767d91SRobert Wu     }
200*05767d91SRobert Wu 
201*05767d91SRobert Wu     static float hammingWindow(float radians, float spread);
202*05767d91SRobert Wu 
203*05767d91SRobert Wu     static float sinc(float radians);
204*05767d91SRobert Wu 
205*05767d91SRobert Wu protected:
206*05767d91SRobert Wu 
207*05767d91SRobert Wu     explicit MultiChannelResampler(const MultiChannelResampler::Builder &builder);
208*05767d91SRobert Wu 
209*05767d91SRobert Wu     /**
210*05767d91SRobert Wu      * Write a frame containing N samples.
211*05767d91SRobert Wu      * Call advanceWrite() after calling this.
212*05767d91SRobert Wu      * @param frame pointer to the first sample in a frame
213*05767d91SRobert Wu      */
214*05767d91SRobert Wu     virtual void writeFrame(const float *frame);
215*05767d91SRobert Wu 
216*05767d91SRobert Wu     /**
217*05767d91SRobert Wu      * Read a frame containing N samples using interpolation.
218*05767d91SRobert Wu      * Call advanceRead() after calling this.
219*05767d91SRobert Wu      * @param frame pointer to the first sample in a frame
220*05767d91SRobert Wu      */
221*05767d91SRobert Wu     virtual void readFrame(float *frame) = 0;
222*05767d91SRobert Wu 
advanceWrite()223*05767d91SRobert Wu     void advanceWrite() {
224*05767d91SRobert Wu         mIntegerPhase -= mDenominator;
225*05767d91SRobert Wu     }
226*05767d91SRobert Wu 
advanceRead()227*05767d91SRobert Wu     void advanceRead() {
228*05767d91SRobert Wu         mIntegerPhase += mNumerator;
229*05767d91SRobert Wu     }
230*05767d91SRobert Wu 
231*05767d91SRobert Wu     /**
232*05767d91SRobert Wu      * Generate the filter coefficients in optimal order.
233*05767d91SRobert Wu      *
234*05767d91SRobert Wu      * Note that normalizedCutoff is ignored when upsampling, which is when
235*05767d91SRobert Wu      * the outputRate is higher than the inputRate.
236*05767d91SRobert Wu      *
237*05767d91SRobert Wu      * @param inputRate sample rate of the input stream
238*05767d91SRobert Wu      * @param outputRate  sample rate of the output stream
239*05767d91SRobert Wu      * @param numRows number of rows in the array that contain a set of tap coefficients
240*05767d91SRobert Wu      * @param phaseIncrement how much to increment the phase between rows
241*05767d91SRobert Wu      * @param normalizedCutoff filter cutoff frequency normalized to Nyquist rate of output
242*05767d91SRobert Wu      */
243*05767d91SRobert Wu     void generateCoefficients(int32_t inputRate,
244*05767d91SRobert Wu                               int32_t outputRate,
245*05767d91SRobert Wu                               int32_t numRows,
246*05767d91SRobert Wu                               double phaseIncrement,
247*05767d91SRobert Wu                               float normalizedCutoff);
248*05767d91SRobert Wu 
249*05767d91SRobert Wu 
getIntegerPhase()250*05767d91SRobert Wu     int32_t getIntegerPhase() {
251*05767d91SRobert Wu         return mIntegerPhase;
252*05767d91SRobert Wu     }
253*05767d91SRobert Wu 
254*05767d91SRobert Wu     static constexpr int kMaxCoefficients = 8 * 1024;
255*05767d91SRobert Wu     std::vector<float>   mCoefficients;
256*05767d91SRobert Wu 
257*05767d91SRobert Wu     const int            mNumTaps;
258*05767d91SRobert Wu     int                  mCursor = 0;
259*05767d91SRobert Wu     std::vector<float>   mX;           // delayed input values for the FIR
260*05767d91SRobert Wu     std::vector<float>   mSingleFrame; // one frame for temporary use
261*05767d91SRobert Wu     int32_t              mIntegerPhase = 0;
262*05767d91SRobert Wu     int32_t              mNumerator = 0;
263*05767d91SRobert Wu     int32_t              mDenominator = 0;
264*05767d91SRobert Wu 
265*05767d91SRobert Wu 
266*05767d91SRobert Wu private:
267*05767d91SRobert Wu 
268*05767d91SRobert Wu #if MCR_USE_KAISER
269*05767d91SRobert Wu     KaiserWindow           mKaiserWindow;
270*05767d91SRobert Wu #else
271*05767d91SRobert Wu     HyperbolicCosineWindow mCoshWindow;
272*05767d91SRobert Wu #endif
273*05767d91SRobert Wu 
274*05767d91SRobert Wu     static constexpr float kDefaultNormalizedCutoff = 0.70f;
275*05767d91SRobert Wu 
276*05767d91SRobert Wu     const int              mChannelCount;
277*05767d91SRobert Wu };
278*05767d91SRobert Wu 
279*05767d91SRobert Wu } /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
280*05767d91SRobert Wu 
281*05767d91SRobert Wu #endif //RESAMPLER_MULTICHANNEL_RESAMPLER_H
282