mel-computations.h (6233B)
1 /** 2 * Copyright (c) 2022 Xiaomi Corporation (authors: Fangjun Kuang) 3 * 4 * See LICENSE for clarification regarding multiple authors 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 // This file is copied/modified from kaldi/src/feat/mel-computations.h 19 #ifndef KALDI_NATIVE_FBANK_CSRC_MEL_COMPUTATIONS_H_ 20 #define KALDI_NATIVE_FBANK_CSRC_MEL_COMPUTATIONS_H_ 21 22 #include <cmath> 23 #include <cstdint> 24 #include <sstream> 25 #include <string> 26 #include <utility> 27 #include <vector> 28 29 #include "kaldi-native-fbank/csrc/feature-window.h" 30 31 namespace knf { 32 struct FrameExtractionOptions; 33 34 struct MelBanksOptions { 35 int32_t num_bins = 25; // e.g. 25; number of triangular bins 36 float low_freq = 20; // e.g. 20; lower frequency cutoff 37 38 // an upper frequency cutoff; 0 -> no cutoff, negative 39 // ->added to the Nyquist frequency to get the cutoff. 40 float high_freq = 0; 41 42 float vtln_low = 100; // vtln lower cutoff of warping function. 43 44 // vtln upper cutoff of warping function: if negative, added 45 // to the Nyquist frequency to get the cutoff. 46 float vtln_high = -500; 47 48 bool debug_mel = false; 49 // htk_mode is a "hidden" config, it does not show up on command line. 50 // Enables more exact compatibility with HTK, for testing purposes. Affects 51 // mel-energy flooring and reproduces a bug in HTK. 52 bool htk_mode = false; 53 54 // Note that if you set is_librosa, you probably need to set 55 // low_freq to 0. 56 // Please see 57 // https://librosa.org/doc/main/generated/librosa.filters.mel.html 58 bool is_librosa = false; 59 60 // used only when is_librosa=true 61 // Possible values: "", slaney. We don't support a numeric value here, but 62 // it can be added on demand. 63 // See https://librosa.org/doc/main/generated/librosa.filters.mel.html 64 std::string norm = "slaney"; 65 66 std::string ToString() const { 67 std::ostringstream os; 68 os << "num_bins: " << num_bins << "\n"; 69 os << "low_freq: " << low_freq << "\n"; 70 os << "high_freq: " << high_freq << "\n"; 71 os << "vtln_low: " << vtln_low << "\n"; 72 os << "vtln_high: " << vtln_high << "\n"; 73 os << "debug_mel: " << debug_mel << "\n"; 74 os << "htk_mode: " << htk_mode << "\n"; 75 os << "is_librosa: " << is_librosa << "\n"; 76 os << "norm: " << norm << "\n"; 77 return os.str(); 78 } 79 }; 80 81 std::ostream &operator<<(std::ostream &os, const MelBanksOptions &opts); 82 83 class MelBanks { 84 public: 85 // see also https://en.wikipedia.org/wiki/Mel_scale 86 // htk, mel to hz 87 static inline float InverseMelScale(float mel_freq) { 88 return 700.0f * (expf(mel_freq / 1127.0f) - 1.0f); 89 } 90 91 // htk, hz to mel 92 static inline float MelScale(float freq) { 93 return 1127.0f * logf(1.0f + freq / 700.0f); 94 } 95 96 // slaney, mel to hz 97 static inline float InverseMelScaleSlaney(float mel_freq) { 98 if (mel_freq <= 15) { 99 return 200.0f / 3 * mel_freq; 100 } 101 102 // return 1000 * expf((mel_freq - 15) * logf(6.4f) / 27); 103 104 // Note: log(6.4)/27 = 0.06875177742094911 105 106 return 1000 * expf((mel_freq - 15) * 0.06875177742094911f); 107 } 108 109 // slaney, hz to mel 110 static inline float MelScaleSlaney(float freq) { 111 if (freq <= 1000) { 112 return freq * 3 / 200.0f; 113 } 114 115 // return 15 + 27 * logf(freq / 1000) / logf(6.4f) 116 // 117 // Note: 27/log(6.4) = 14.545078505785561 118 119 return 15 + 14.545078505785561f * logf(freq / 1000); 120 } 121 122 static float VtlnWarpFreq( 123 float vtln_low_cutoff, 124 float vtln_high_cutoff, // discontinuities in warp func 125 float low_freq, 126 float high_freq, // upper+lower frequency cutoffs in 127 // the mel computation 128 float vtln_warp_factor, float freq); 129 130 static float VtlnWarpMelFreq(float vtln_low_cutoff, float vtln_high_cutoff, 131 float low_freq, float high_freq, 132 float vtln_warp_factor, float mel_freq); 133 134 // TODO(fangjun): Remove vtln_warp_factor 135 MelBanks(const MelBanksOptions &opts, 136 const FrameExtractionOptions &frame_opts, float vtln_warp_factor); 137 138 // Initialize with a 2-d weights matrix 139 // @param weights Pointer to the start address of the matrix 140 // @param num_rows It equls to number of mel bins 141 // @param num_cols It equals to (number of fft bins)/2+1 142 MelBanks(const float *weights, int32_t num_rows, int32_t num_cols); 143 144 /// Compute Mel energies (note: not log energies). 145 /// At input, "fft_energies" contains the FFT energies (not log). 146 /// 147 /// @param fft_energies 1-D array of size num_fft_bins/2+1 148 /// @param mel_energies_out 1-D array of size num_mel_bins 149 void Compute(const float *fft_energies, float *mel_energies_out) const; 150 151 int32_t NumBins() const { return bins_.size(); } 152 153 private: 154 // for kaldi-compatible 155 void InitKaldiMelBanks(const MelBanksOptions &opts, 156 const FrameExtractionOptions &frame_opts, 157 float vtln_warp_factor); 158 159 // for librosa-compatible 160 // See https://librosa.org/doc/main/generated/librosa.filters.mel.html 161 void InitLibrosaMelBanks(const MelBanksOptions &opts, 162 const FrameExtractionOptions &frame_opts, 163 float vtln_warp_factor); 164 165 private: 166 // the "bins_" vector is a vector, one for each bin, of a pair: 167 // (the first nonzero fft-bin), (the vector of weights). 168 std::vector<std::pair<int32_t, std::vector<float>>> bins_; 169 170 // TODO(fangjun): Remove debug_ and htk_mode_ 171 bool debug_ = false; 172 bool htk_mode_ = false; 173 }; 174 175 // Compute liftering coefficients (scaling on cepstral coeffs) 176 // coeffs are numbered slightly differently from HTK: the zeroth 177 // index is C0, which is not affected. 178 void ComputeLifterCoeffs(float Q, std::vector<float> *coeffs); 179 180 } // namespace knf 181 182 #endif // KALDI_NATIVE_FBANK_CSRC_MEL_COMPUTATIONS_H_