janitor

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

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