feature-window.h (7023B)
1 // kaldi-native-fbank/csrc/feature-window.h 2 // 3 // Copyright (c) 2022 Xiaomi Corporation (authors: Fangjun Kuang) 4 5 // This file is copied/modified from kaldi/src/feat/feature-window.h 6 7 #ifndef KALDI_NATIVE_FBANK_CSRC_FEATURE_WINDOW_H_ 8 #define KALDI_NATIVE_FBANK_CSRC_FEATURE_WINDOW_H_ 9 10 #include <sstream> 11 #include <string> 12 #include <vector> 13 #include <cstdint> 14 15 #include "kaldi-native-fbank/csrc/log.h" 16 17 namespace knf { 18 19 inline int32_t RoundUpToNearestPowerOfTwo(int32_t n) { 20 // copied from kaldi/src/base/kaldi-math.cc 21 KNF_CHECK_GT(n, 0); 22 n--; 23 n |= n >> 1; 24 n |= n >> 2; 25 n |= n >> 4; 26 n |= n >> 8; 27 n |= n >> 16; 28 return n + 1; 29 } 30 31 struct FrameExtractionOptions { 32 float samp_freq = 16000; 33 float frame_shift_ms = 10.0f; // in milliseconds. 34 float frame_length_ms = 25.0f; // in milliseconds. 35 36 float dither = 0.00003f; // Amount of dithering, 0.0 means no dither. 37 // Value 0.00003f is equivalent to 1.0 in kaldi. 38 39 float preemph_coeff = 0.97f; // Preemphasis coefficient. 40 bool remove_dc_offset = true; // Subtract mean of wave before FFT. 41 std::string window_type = "povey"; // e.g. Hamming window 42 // May be "hamming", "rectangular", "povey", "hanning", "hann", "sine", 43 // "blackman". 44 // "povey" is a window I made to be similar to Hamming but to go to zero at 45 // the edges, it's pow((0.5 - 0.5*cos(n/N*2*pi)), 0.85) I just don't think the 46 // Hamming window makes sense as a windowing function. 47 bool round_to_power_of_two = true; 48 float blackman_coeff = 0.42f; 49 bool snip_edges = true; 50 // bool allow_downsample = false; 51 // bool allow_upsample = false; 52 53 int32_t WindowShift() const { 54 return static_cast<int32_t>(samp_freq * 0.001f * frame_shift_ms); 55 } 56 int32_t WindowSize() const { 57 return static_cast<int32_t>(samp_freq * 0.001f * frame_length_ms); 58 } 59 int32_t PaddedWindowSize() const { 60 return (round_to_power_of_two ? RoundUpToNearestPowerOfTwo(WindowSize()) 61 : WindowSize()); 62 } 63 std::string ToString() const { 64 std::ostringstream os; 65 #define KNF_PRINT(x) os << #x << ": " << x << "\n" 66 KNF_PRINT(samp_freq); 67 KNF_PRINT(frame_shift_ms); 68 KNF_PRINT(frame_length_ms); 69 KNF_PRINT(dither); 70 KNF_PRINT(preemph_coeff); 71 KNF_PRINT(remove_dc_offset); 72 KNF_PRINT(window_type); 73 KNF_PRINT(round_to_power_of_two); 74 KNF_PRINT(blackman_coeff); 75 KNF_PRINT(snip_edges); 76 // KNF_PRINT(allow_downsample); 77 // KNF_PRINT(allow_upsample); 78 #undef KNF_PRINT 79 return os.str(); 80 } 81 }; 82 83 std::ostream &operator<<(std::ostream &os, const FrameExtractionOptions &opts); 84 85 class FeatureWindowFunction { 86 public: 87 FeatureWindowFunction() = default; 88 explicit FeatureWindowFunction(const FrameExtractionOptions &opts); 89 /** 90 * @param wave Pointer to a 1-D array of shape [window_size]. 91 * It is modified in-place: wave[i] = wave[i] * window_[i]. 92 * @param 93 */ 94 void Apply(float *wave) const; 95 const std::vector<float> &GetWindow() const { return window_; } 96 97 private: 98 std::vector<float> window_; // of size opts.WindowSize() 99 }; 100 101 int64_t FirstSampleOfFrame(int32_t frame, const FrameExtractionOptions &opts); 102 103 /** 104 This function returns the number of frames that we can extract from a wave 105 file with the given number of samples in it (assumed to have the same 106 sampling rate as specified in 'opts'). 107 108 @param [in] num_samples The number of samples in the wave file. 109 @param [in] opts The frame-extraction options class 110 111 @param [in] flush True if we are asserting that this number of samples 112 is 'all there is', false if we expecting more data to possibly come in. This 113 only makes a difference to the answer 114 if opts.snip_edges== false. For offline feature extraction you always want 115 flush == true. In an online-decoding context, once you know (or decide) that 116 no more data is coming in, you'd call it with flush == true at the end to 117 flush out any remaining data. 118 */ 119 int32_t NumFrames(int64_t num_samples, const FrameExtractionOptions &opts, 120 bool flush = true); 121 122 /* 123 ExtractWindow() extracts a windowed frame of waveform (possibly with a 124 power-of-two, padded size, depending on the config), including all the 125 processing done by ProcessWindow(). 126 127 @param [in] sample_offset If 'wave' is not the entire waveform, but 128 part of it to the left has been discarded, then the 129 number of samples prior to 'wave' that we have 130 already discarded. Set this to zero if you are 131 processing the entire waveform in one piece, or 132 if you get 'no matching function' compilation 133 errors when updating the code. 134 @param [in] wave The waveform 135 @param [in] f The frame index to be extracted, with 136 0 <= f < NumFrames(sample_offset + wave.Dim(), opts, true) 137 @param [in] opts The options class to be used 138 @param [in] window_function The windowing function, as derived from the 139 options class. 140 @param [out] window The windowed, possibly-padded waveform to be 141 extracted. Will be resized as needed. 142 @param [out] log_energy_pre_window If non-NULL, the log-energy of 143 the signal prior to pre-emphasis and multiplying by 144 the windowing function will be written to here. 145 */ 146 void ExtractWindow(int64_t sample_offset, const std::vector<float> &wave, 147 int32_t f, const FrameExtractionOptions &opts, 148 const FeatureWindowFunction &window_function, 149 std::vector<float> *window, 150 float *log_energy_pre_window = nullptr); 151 152 /** 153 This function does all the windowing steps after actually 154 extracting the windowed signal: depending on the 155 configuration, it does dithering, dc offset removal, 156 preemphasis, and multiplication by the windowing function. 157 @param [in] opts The options class to be used 158 @param [in] window_function The windowing function-- should have 159 been initialized using 'opts'. 160 @param [in,out] window A vector of size opts.WindowSize(). Note: 161 it will typically be a sub-vector of a larger vector of size 162 opts.PaddedWindowSize(), with the remaining samples zero, 163 as the FFT code is more efficient if it operates on data with 164 power-of-two size. 165 @param [out] log_energy_pre_window If non-NULL, then after dithering and 166 DC offset removal, this function will write to this pointer the log of 167 the total energy (i.e. sum-squared) of the frame. 168 */ 169 void ProcessWindow(const FrameExtractionOptions &opts, 170 const FeatureWindowFunction &window_function, float *window, 171 float *log_energy_pre_window = nullptr); 172 173 // Compute the inner product of two vectors 174 float InnerProduct(const float *a, const float *b, int32_t n); 175 176 } // namespace knf 177 178 #endif // KALDI_NATIVE_FBANK_CSRC_FEATURE_WINDOW_H_