janitor

janitor
git clone https://git.prime8.dev/janitor.git
Log | Files | Refs | README | LICENSE

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_