whisper-feature.cc (4667B)
1 /** 2 * Copyright (c) 2023 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 #include "kaldi-native-fbank/csrc/whisper-feature.h" 20 21 #include <cmath> 22 #include <string> 23 #include <vector> 24 25 #include "kaldi-native-fbank/csrc/log.h" 26 #include "kaldi-native-fbank/csrc/mel-computations.h" 27 28 #ifndef M_2PI 29 #define M_2PI 6.283185307179586476925286766559005 30 #endif 31 32 namespace knf { 33 34 std::string WhisperFeatureOptions::ToString() const { 35 std::ostringstream os; 36 os << "WhisperFeatureOptions("; 37 os << "frame_opts=" << frame_opts.ToString() << ", "; 38 os << "dim=" << dim << ")"; 39 return os.str(); 40 } 41 42 static void dft(const std::vector<float> &in, std::vector<float> *out) { 43 // this function is modified from 44 // https://github.com/ggerganov/whisper.cpp/blob/master/whisper.cpp#L2353 45 int32_t N = in.size(); 46 47 out->resize(N * 2); 48 49 auto M_2PI_over_N = M_2PI / N; 50 for (int32_t k = 0; k < N; ++k) { 51 float re = 0; 52 float im = 0; 53 54 for (int32_t n = 0; n < N; ++n) { 55 float angle = M_2PI_over_N * k * n; 56 re += in[n] * cos(angle); 57 im -= in[n] * sin(angle); 58 } 59 60 (*out)[k * 2 + 0] = re; 61 (*out)[k * 2 + 1] = im; 62 } 63 } 64 65 // Cooley-Tukey FFT 66 // poor man's implementation - use something better 67 // input is real-valued 68 // output is complex-valued 69 static void fft(const std::vector<float> &in, std::vector<float> *out) { 70 // this function is copied from 71 // https://github.com/ggerganov/whisper.cpp/blob/master/whisper.cpp#L2373C1-L2429C1 72 73 int32_t N = in.size(); 74 out->resize(N * 2); 75 76 if (N == 1) { 77 (*out)[0] = in[0]; 78 (*out)[1] = 0; 79 return; 80 } 81 82 if (N % 2 == 1) { 83 dft(in, out); 84 return; 85 } 86 87 std::vector<float> even; 88 std::vector<float> odd; 89 90 even.reserve(N / 2); 91 odd.reserve(N / 2); 92 93 for (int32_t i = 0; i != N; ++i) { 94 if (i % 2 == 0) { 95 even.push_back(in[i]); 96 } else { 97 odd.push_back(in[i]); 98 } 99 } 100 101 std::vector<float> even_fft; 102 std::vector<float> odd_fft; 103 104 fft(even, &even_fft); 105 fft(odd, &odd_fft); 106 107 for (int32_t k = 0; k < N / 2; ++k) { 108 float theta = M_2PI * k / N; 109 110 float re = cos(theta); 111 float im = -sin(theta); 112 113 float re_odd = odd_fft[2 * k + 0]; 114 float im_odd = odd_fft[2 * k + 1]; 115 116 (*out)[2 * k + 0] = even_fft[2 * k + 0] + re * re_odd - im * im_odd; 117 (*out)[2 * k + 1] = even_fft[2 * k + 1] + re * im_odd + im * re_odd; 118 119 (*out)[2 * (k + N / 2) + 0] = 120 even_fft[2 * k + 0] - re * re_odd + im * im_odd; 121 (*out)[2 * (k + N / 2) + 1] = 122 even_fft[2 * k + 1] - re * im_odd - im * re_odd; 123 } 124 } 125 126 WhisperFeatureComputer::WhisperFeatureComputer( 127 const WhisperFeatureOptions &opts /*= {}*/) 128 : opts_(opts) { 129 opts_.frame_opts.samp_freq = 16000; 130 opts_.frame_opts.frame_shift_ms = 10; 131 opts_.frame_opts.frame_length_ms = 25; 132 opts_.frame_opts.dither = 0; 133 opts_.frame_opts.preemph_coeff = 0; 134 opts_.frame_opts.remove_dc_offset = false; 135 opts_.frame_opts.window_type = "hann"; 136 opts_.frame_opts.round_to_power_of_two = false; 137 opts_.frame_opts.snip_edges = false; 138 139 MelBanksOptions mel_opts; 140 mel_opts.num_bins = opts_.dim; 141 mel_opts.low_freq = 0; 142 mel_opts.is_librosa = true; 143 144 mel_banks_ = std::make_unique<MelBanks>(mel_opts, opts_.frame_opts, 1.0f); 145 } 146 147 void WhisperFeatureComputer::Compute(float /*signal_raw_log_energy*/, 148 float /*vtln_warp*/, 149 std::vector<float> *signal_frame, 150 float *feature) { 151 KNF_CHECK_EQ(signal_frame->size(), frame_opts_.PaddedWindowSize()); 152 // we have already applied window function to signal_frame before 153 // calling this method 154 std::vector<float> fft_out; 155 fft(*signal_frame, &fft_out); 156 157 int32_t num_fft = signal_frame->size(); 158 std::vector<float> power(num_fft / 2 + 1); 159 for (int32_t i = 0; i <= num_fft / 2; ++i) { 160 float re = fft_out[2 * i + 0]; 161 float im = fft_out[2 * i + 1]; 162 power[i] = re * re + im * im; 163 } 164 165 // feature is pre-allocated by the user 166 mel_banks_->Compute(power.data(), feature); 167 } 168 169 } // namespace knf