1 /* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef CONVERSION_FFT_H 17 #define CONVERSION_FFT_H 18 19 #include "fft.h" 20 21 namespace OHOS { 22 namespace Sensors { 23 /** 24 * @brief The parameters required for FFT 25 */ 26 struct FFTInputPara { 27 /** sampling rate of audio file. */ 28 int32_t sampleRate { 0 }; 29 /** the FFT size. This must be a power of 2. */ 30 int32_t fftSize { 0 }; 31 /** the hop size. */ 32 int32_t hopSize { 0 }; 33 /** the window size. */ 34 int32_t windowSize { 0 }; 35 }; 36 37 struct FFTOutputResult { 38 std::vector<float> magnitudes; 39 std::vector<float> phases; 40 std::vector<float> magnitudesDB; 41 std::vector<float> buffer; 42 std::vector<float> window; 43 }; 44 45 /** 46 * Fast fourier transform. For spectral audio process and machine listening. 47 */ 48 class ConversionFFT { 49 public: 50 /** 51 * @brief How to run the FFT - with or without polar conversion 52 */ 53 enum FFTModes { 54 NO_POLAR_CONVERSION = 0, 55 WITH_POLAR_CONVERSION = 1 56 }; 57 58 ConversionFFT() = default; 59 ~ConversionFFT() = default; 60 61 /** 62 * @brief the FFT. 63 * 64 * @param fftSize the FFT size. This must be a power of 2 65 * @param hopSize the hop size 66 * @param windowSize the window size 67 * 68 * @return Returns <b>0</b> if the operation is successful; returns a negative value otherwise. 69 */ 70 int32_t Init(const FFTInputPara &fftPara); 71 72 /** 73 * @brief The sampled data is processed frame by frame 74 * @param values A set of signal data 75 * @return Return 0 when the analysis has run (every [hopsize] samples) 76 */ 77 int32_t Process(const std::vector<double> &values, int32_t &frameCount, std::vector<float> &frameMagsArr); 78 79 /** 80 * @brief Process the sampled data one by one 81 * @param value A sampling value. 82 * @param mode see FFTModes enumeration 83 * @return Return true when the analysis has run (every [hopsize] samples) 84 */ 85 bool ProcessSingle(float value, FFTModes mode = ConversionFFT::WITH_POLAR_CONVERSION); 86 87 /** 88 * @brief Get the complex real object 89 * 90 * @return Return a pointer to an array of values containing the real components of the fft analysis. 91 */ GetReal()92 std::vector<float> GetReal() 93 { 94 return fft_.GetReal(); 95 }; 96 97 /** 98 * @brief Get the complex imaginary part 99 * 100 * @return Return a pointer to an array of values containing the imaginary components of the fft analysis 101 */ GetImag()102 std::vector<float> GetImag() 103 { 104 return fft_.GetImg(); 105 }; 106 107 /** 108 * @brief Get the magnitudes object 109 * 110 * @return a vector of magnitudes (assuming the FFT was calcuated with polar conversion) 111 */ GetMagnitudes()112 std::vector<float> GetMagnitudes() 113 { 114 return fftResult_.magnitudes; 115 } 116 117 /** 118 * @brief Get the magnitudes DB object 119 * 120 * @return Return a vector of magnitudes in decibels (assuming the FFT was calcuated with polar conversion). 121 */ GetMagnitudesDB()122 std::vector<float> GetMagnitudesDB() 123 { 124 return ConvertDB(); 125 } 126 127 /** 128 * @brief Get the phases object 129 * 130 * @return Return a vector of phases (assuming the FFT was calcuated with polar conversion) 131 */ GetPhases()132 std::vector<float> GetPhases() 133 { 134 return fftResult_.phases; 135 } 136 137 /** 138 * @brief Get the num bins object 139 * 140 * @return Return the number of bins in the FFT analysis 141 */ GetNumBins()142 int32_t GetNumBins() const 143 { 144 return bins_; 145 } 146 147 /** 148 * @brief Get the FFT size 149 * 150 * @return Return the FFT size 151 */ GetFFTSize()152 int32_t GetFFTSize() 153 { 154 return para_.fftSize; 155 } 156 157 /** 158 * @brief Get the hop size 159 * 160 * @return Return the hop size 161 */ GetHopSize()162 int32_t GetHopSize() 163 { 164 return para_.hopSize; 165 } 166 167 /** 168 * @brief Get the window size 169 * 170 * @return Return the window size 171 */ GetWindowSize()172 int32_t GetWindowSize() 173 { 174 return para_.windowSize; 175 } 176 177 /** 178 * @brief Calculate the spectral flatness of the most recent FFT 179 * 180 * @return Return the spectral flatness of the most recent FFT calculation 181 */ 182 float GetSpectralFlatness() const; 183 184 /** 185 * @brief Calculate the spectral centroid of the most recent FFT. 186 * 187 * @return Return the spectral centroid of the most recent FFT calculation 188 */ 189 float GetSpectralCentroid() const; 190 191 private: 192 std::vector<float> &ConvertDB(); 193 194 private: 195 FFTInputPara para_; 196 FFTOutputResult fftResult_; 197 int32_t pos_ { 0 }; 198 Fft fft_; 199 bool isFrameFull_ { false }; 200 int32_t bins_ { 0 }; 201 bool isFftCalcFinish_ { false }; 202 }; 203 204 /** 205 * @brief Inverse FFT transform 206 */ 207 class ConversionIFFT { 208 public: 209 /** 210 * @brief Configure what kind of data is being given to the inverse FFT 211 * 212 */ 213 enum FFTModes { 214 /** Magnitudes and phases */ 215 SPECTRUM = 0, 216 /** Real and imaginary components */ 217 COMPLEX = 1 218 }; 219 220 ConversionIFFT() = default; 221 ~ConversionIFFT() = default; 222 223 /** 224 * @brief the inverse FFT. 225 * 226 * @param fftSize the FFT size. This must be a power of 2 227 * @param hopSize the hop size 228 * @param windowSize the window size 229 * @return Returns <b>0</b> if the operation is successful; returns a negative value otherwise. 230 */ 231 int32_t Init(int32_t fftSize, int32_t hopSize, int32_t windowSize); 232 233 /** 234 * @brief the inverse transform. Call this function at audio rate, but update the FFT information at FFT rate. 235 * 236 * @param data1 either magnitudes or real values 237 * @param data2 either phases or imaginary values 238 * @param mode see FFTModes 239 * @return Return the most recent sample an audio signal, creates from the inverse transform of the FFT data 240 */ 241 float Process(const std::vector<float> &mags, const std::vector<float> &phases, 242 const FFTModes mode = ConversionIFFT::SPECTRUM); 243 244 /** 245 * @brief Get the num bins 246 * 247 * @return Return the number of fft bins 248 */ GetNumBins()249 int32_t GetNumBins() const 250 { 251 return bins_; 252 } 253 254 private: 255 FFTInputPara para_; 256 /** output buffer and window. */ 257 FFTOutputResult fftResult_; 258 std::vector<float> ifftOut_; 259 int32_t bins_ { 0 }; 260 int32_t pos_ { 0 }; 261 float nextValue_ { 0.0F }; 262 Fft fft_; 263 }; 264 265 /** 266 * @brief octave analyser. It takes FFT magnitudes and remaps them into pitches 267 */ 268 class ConversionOctave { 269 public: 270 ConversionOctave() = default; 271 ~ConversionOctave() = default; 272 273 /** 274 * @brief Initializes the octave note analyzer 275 * 276 * @param samplingRate the sample rate 277 * @param nBandsInTheFFT the number of bins in the FFT 278 * @param nAveragesPerOctave how many frequency bands to split each octave into 279 * 280 * @return Returns <b>0</b> if the operation is successful; returns a negative value otherwise. 281 */ 282 int32_t Init(float samplingRate, int32_t nBandsInTheFFT, int32_t nAveragesPerOctave); 283 284 /** 285 * @brief Calculate the octave note related parameters 286 * 287 * @param fftData a pointer to an array of fft magnitudes 288 * 289 * @return Returns <b>0</b> if the operation is successful; returns a negative value otherwise. 290 */ 291 int32_t Calculate(const std::vector<float> &fftData); 292 293 private: 294 float samplingRate_ { 0.0F }; // sampling rate in Hz (needed to calculate frequency spans) 295 int32_t nSpectrum_ { 0 }; // number of spectrum bins in the fft 296 /** the number of averages, after analysis */ 297 int32_t nAverages_ { 0 }; // number of averaging bins here 298 float spectrumFrequencySpan_ { 0.0F }; // the "width" of an fft spectrum bin in Hz 299 float firstOctaveFrequency_ { 0.0F }; // the "top" of the first averaging bin here in Hz 300 float averageFrequencyIncrement_ { 0.0F }; // the root-of-two multiplier between averaging bin frequencies 301 /** An array of averages - the energy across the pitch spectrum */ 302 std::shared_ptr<float> averages_ { nullptr }; // the actual averages 303 std::shared_ptr<float> peaks_ { nullptr }; // peaks of the averages, aka "maxAverages" in other implementations 304 std::shared_ptr<int32_t> peakHoldTimes_ { nullptr }; // how long to hold THIS peak meter? decay if == 0 305 int32_t peakHoldTime_ { 0 }; // how long do we hold peaks? (in fft frames) 306 float peakDecayRate_ { 0.0F }; // how quickly the peaks decay: 0f=instantly .. 1f=not at all 307 std::shared_ptr<int32_t> spe2avg_ { nullptr }; // the mapping between spectrum[] indices and averages[] indices 308 // the fft's log equalizer() is no longer of any use (it would be nonsense to log scale 309 // the spectrum values into log-sized average bins) so here's a quick-and-dirty linear 310 // equalizer instead: 311 float linearEQSlope_ { 0.0F }; // the rate of linear eq 312 float linearEQIntercept_ { 0.0F }; // the base linear scaling used at the first averaging bin 313 // the formula is: spectrum[i] * (linearEQIntercept + i * linearEQSlope) 314 // so.. note that clever use of it can also provide a "gain" control of sorts 315 // (fe: set intercept to 2f and slope to 0f to double gain) 316 }; 317 } // namespace Sensors 318 } // namespace OHOS 319 #endif // CONVERSION_FFT_H 320