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 * Note that this value is ignored when upsampling, which is when 115 * the outputRate is higher than the inputRate. 116 * 117 * @param normalizedCutoff anti-aliasing filter cutoff 118 * @return address of this builder for chaining calls 119 */ setNormalizedCutoff(float normalizedCutoff)120 Builder *setNormalizedCutoff(float normalizedCutoff) { 121 mNormalizedCutoff = normalizedCutoff; 122 return this; 123 } 124 getNumTaps()125 int32_t getNumTaps() const { 126 return mNumTaps; 127 } 128 getChannelCount()129 int32_t getChannelCount() const { 130 return mChannelCount; 131 } 132 getInputRate()133 int32_t getInputRate() const { 134 return mInputRate; 135 } 136 getOutputRate()137 int32_t getOutputRate() const { 138 return mOutputRate; 139 } 140 getNormalizedCutoff()141 float getNormalizedCutoff() const { 142 return mNormalizedCutoff; 143 } 144 145 protected: 146 int32_t mChannelCount = 1; 147 int32_t mNumTaps = 16; 148 int32_t mInputRate = 48000; 149 int32_t mOutputRate = 48000; 150 float mNormalizedCutoff = kDefaultNormalizedCutoff; 151 }; 152 153 virtual ~MultiChannelResampler() = default; 154 155 /** 156 * Factory method for making a resampler that is optimal for the given inputs. 157 * 158 * @param channelCount number of channels, 2 for stereo 159 * @param inputRate sample rate of the input stream 160 * @param outputRate sample rate of the output stream 161 * @param quality higher quality sounds better but uses more CPU 162 * @return an optimal resampler 163 */ 164 static MultiChannelResampler *make(int32_t channelCount, 165 int32_t inputRate, 166 int32_t outputRate, 167 Quality quality); 168 isWriteNeeded()169 bool isWriteNeeded() const { 170 return mIntegerPhase >= mDenominator; 171 } 172 173 /** 174 * Write a frame containing N samples. 175 * 176 * @param frame pointer to the first sample in a frame 177 */ writeNextFrame(const float * frame)178 void writeNextFrame(const float *frame) { 179 writeFrame(frame); 180 advanceWrite(); 181 } 182 183 /** 184 * Read a frame containing N samples. 185 * 186 * @param frame pointer to the first sample in a frame 187 */ readNextFrame(float * frame)188 void readNextFrame(float *frame) { 189 readFrame(frame); 190 advanceRead(); 191 } 192 getNumTaps()193 int getNumTaps() const { 194 return mNumTaps; 195 } 196 getChannelCount()197 int getChannelCount() const { 198 return mChannelCount; 199 } 200 201 static float hammingWindow(float radians, float spread); 202 203 static float sinc(float radians); 204 205 protected: 206 207 explicit MultiChannelResampler(const MultiChannelResampler::Builder &builder); 208 209 /** 210 * Write a frame containing N samples. 211 * Call advanceWrite() after calling this. 212 * @param frame pointer to the first sample in a frame 213 */ 214 virtual void writeFrame(const float *frame); 215 216 /** 217 * Read a frame containing N samples using interpolation. 218 * Call advanceRead() after calling this. 219 * @param frame pointer to the first sample in a frame 220 */ 221 virtual void readFrame(float *frame) = 0; 222 advanceWrite()223 void advanceWrite() { 224 mIntegerPhase -= mDenominator; 225 } 226 advanceRead()227 void advanceRead() { 228 mIntegerPhase += mNumerator; 229 } 230 231 /** 232 * Generate the filter coefficients in optimal order. 233 * 234 * Note that normalizedCutoff is ignored when upsampling, which is when 235 * the outputRate is higher than the inputRate. 236 * 237 * @param inputRate sample rate of the input stream 238 * @param outputRate sample rate of the output stream 239 * @param numRows number of rows in the array that contain a set of tap coefficients 240 * @param phaseIncrement how much to increment the phase between rows 241 * @param normalizedCutoff filter cutoff frequency normalized to Nyquist rate of output 242 */ 243 void generateCoefficients(int32_t inputRate, 244 int32_t outputRate, 245 int32_t numRows, 246 double phaseIncrement, 247 float normalizedCutoff); 248 249 getIntegerPhase()250 int32_t getIntegerPhase() { 251 return mIntegerPhase; 252 } 253 254 static constexpr int kMaxCoefficients = 8 * 1024; 255 std::vector<float> mCoefficients; 256 257 const int mNumTaps; 258 int mCursor = 0; 259 std::vector<float> mX; // delayed input values for the FIR 260 std::vector<float> mSingleFrame; // one frame for temporary use 261 int32_t mIntegerPhase = 0; 262 int32_t mNumerator = 0; 263 int32_t mDenominator = 0; 264 265 266 private: 267 268 #if MCR_USE_KAISER 269 KaiserWindow mKaiserWindow; 270 #else 271 HyperbolicCosineWindow mCoshWindow; 272 #endif 273 274 static constexpr float kDefaultNormalizedCutoff = 0.70f; 275 276 const int mChannelCount; 277 }; 278 279 } /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */ 280 281 #endif //RESAMPLER_MULTICHANNEL_RESAMPLER_H 282