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