feature-fbank.cc (3965B)
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 19 // This file is copied/modified from kaldi/src/feat/feature-fbank.cc 20 // 21 #include "kaldi-native-fbank/csrc/feature-fbank.h" 22 23 #include <algorithm> 24 #include <limits> 25 #include <utility> 26 #include <vector> 27 28 #include "kaldi-native-fbank/csrc/feature-functions.h" 29 #include "kaldi-native-fbank/csrc/kaldi-math.h" 30 #include "kaldi-native-fbank/csrc/log.h" 31 32 namespace knf { 33 34 std::ostream &operator<<(std::ostream &os, const FbankOptions &opts) { 35 os << opts.ToString(); 36 return os; 37 } 38 39 FbankComputer::FbankComputer(const FbankOptions &opts) 40 : opts_(opts), rfft_(opts.frame_opts.PaddedWindowSize()) { 41 if (opts.energy_floor > 0.0f) { 42 log_energy_floor_ = logf(opts.energy_floor); 43 } 44 45 // We'll definitely need the filterbanks info for VTLN warping factor 1.0. 46 // [note: this call caches it.] 47 GetMelBanks(1.0f); 48 } 49 50 FbankComputer::~FbankComputer() { 51 for (auto iter = mel_banks_.begin(); iter != mel_banks_.end(); ++iter) 52 delete iter->second; 53 } 54 55 const MelBanks *FbankComputer::GetMelBanks(float vtln_warp) { 56 MelBanks *this_mel_banks = nullptr; 57 58 // std::map<float, MelBanks *>::iterator iter = mel_banks_.find(vtln_warp); 59 auto iter = mel_banks_.find(vtln_warp); 60 if (iter == mel_banks_.end()) { 61 this_mel_banks = new MelBanks(opts_.mel_opts, opts_.frame_opts, vtln_warp); 62 mel_banks_[vtln_warp] = this_mel_banks; 63 } else { 64 this_mel_banks = iter->second; 65 } 66 return this_mel_banks; 67 } 68 69 void FbankComputer::Compute(float signal_raw_log_energy, float vtln_warp, 70 std::vector<float> *signal_frame, float *feature) { 71 const MelBanks &mel_banks = *(GetMelBanks(vtln_warp)); 72 73 KNF_CHECK_EQ(signal_frame->size(), opts_.frame_opts.PaddedWindowSize()); 74 75 // Compute energy after window function (not the raw one). 76 if (opts_.use_energy && !opts_.raw_energy) { 77 signal_raw_log_energy = std::log( 78 std::max<float>(InnerProduct(signal_frame->data(), signal_frame->data(), 79 signal_frame->size()), 80 std::numeric_limits<float>::epsilon())); 81 } 82 rfft_.Compute(signal_frame->data()); // signal_frame is modified in-place 83 ComputePowerSpectrum(signal_frame); 84 85 // Use magnitude instead of power if requested. 86 if (!opts_.use_power) { 87 Sqrt(signal_frame->data(), signal_frame->size() / 2 + 1); 88 } 89 90 int32_t mel_offset = ((opts_.use_energy && !opts_.htk_compat) ? 1 : 0); 91 92 // Its length is opts_.mel_opts.num_bins 93 float *mel_energies = feature + mel_offset; 94 95 // Sum with mel filter banks over the power spectrum 96 mel_banks.Compute(signal_frame->data(), mel_energies); 97 98 if (opts_.use_log_fbank) { 99 // Avoid log of zero (which should be prevented anyway by dithering). 100 for (int32_t i = 0; i != opts_.mel_opts.num_bins; ++i) { 101 auto t = std::max(mel_energies[i], std::numeric_limits<float>::epsilon()); 102 mel_energies[i] = std::log(t); 103 } 104 } 105 106 // Copy energy as first value (or the last, if htk_compat == true). 107 if (opts_.use_energy) { 108 if (opts_.energy_floor > 0.0 && signal_raw_log_energy < log_energy_floor_) { 109 signal_raw_log_energy = log_energy_floor_; 110 } 111 int32_t energy_index = opts_.htk_compat ? opts_.mel_opts.num_bins : 0; 112 feature[energy_index] = signal_raw_log_energy; 113 } 114 } 115 116 } // namespace knf