janitor

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

online-feature.cc (5561B)


      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 // The content in this file is copied/modified from
     20 // This file is copied/modified from kaldi/src/feat/online-feature.cc
     21 
     22 #include "kaldi-native-fbank/csrc/online-feature.h"
     23 
     24 #include <algorithm>
     25 #include <cstddef>
     26 #include <utility>
     27 #include <vector>
     28 
     29 #include "kaldi-native-fbank/csrc/feature-window.h"
     30 #include "kaldi-native-fbank/csrc/log.h"
     31 
     32 namespace knf {
     33 
     34 RecyclingVector::RecyclingVector(int32_t items_to_hold)
     35     : items_to_hold_(items_to_hold == 0 ? -1 : items_to_hold),
     36       first_available_index_(0) {}
     37 
     38 const float *RecyclingVector::At(int32_t index) const {
     39   if (index < first_available_index_) {
     40     KNF_LOG(FATAL) << "Attempted to retrieve feature vector that was "
     41                       "already removed by the RecyclingVector (index = "
     42                    << index << "; "
     43                    << "first_available_index = " << first_available_index_
     44                    << "; "
     45                    << "size = " << Size() << ")";
     46   }
     47   // 'at' does size checking.
     48   return items_.at(index - first_available_index_).data();
     49 }
     50 
     51 void RecyclingVector::PushBack(std::vector<float> item) {
     52   // Note: -1 is a larger number when treated as unsigned
     53   if (items_.size() == static_cast<size_t>(items_to_hold_)) {
     54     items_.pop_front();
     55     ++first_available_index_;
     56   }
     57   items_.push_back(std::move(item));
     58 }
     59 
     60 int32_t RecyclingVector::Size() const {
     61   return first_available_index_ + static_cast<int32_t>(items_.size());
     62 }
     63 
     64 // discard the first n frames
     65 void RecyclingVector::Pop(int32_t n) {
     66   for (int32_t i = 0; i < n && !items_.empty(); ++i) {
     67     items_.pop_front();
     68     ++first_available_index_;
     69   }
     70 }
     71 
     72 template <class C>
     73 OnlineGenericBaseFeature<C>::OnlineGenericBaseFeature(
     74     const typename C::Options &opts)
     75     : computer_(opts),
     76       window_function_(computer_.GetFrameOptions()),
     77       input_finished_(false),
     78       waveform_offset_(0) {}
     79 
     80 template <class C>
     81 void OnlineGenericBaseFeature<C>::AcceptWaveform(float sampling_rate,
     82                                                  const float *waveform,
     83                                                  int32_t n) {
     84   if (n == 0) {
     85     return;  // Nothing to do.
     86   }
     87 
     88   if (input_finished_) {
     89     KNF_LOG(FATAL) << "AcceptWaveform called after InputFinished() was called.";
     90   }
     91 
     92   KNF_CHECK_EQ(sampling_rate, computer_.GetFrameOptions().samp_freq);
     93 
     94   waveform_remainder_.insert(waveform_remainder_.end(), waveform, waveform + n);
     95 
     96   ComputeFeatures();
     97 }
     98 
     99 template <class C>
    100 void OnlineGenericBaseFeature<C>::InputFinished() {
    101   input_finished_ = true;
    102   ComputeFeatures();
    103 }
    104 
    105 template <class C>
    106 void OnlineGenericBaseFeature<C>::ComputeFeatures() {
    107   const FrameExtractionOptions &frame_opts = computer_.GetFrameOptions();
    108 
    109   int64_t num_samples_total = waveform_offset_ + waveform_remainder_.size();
    110 
    111   int32_t num_frames_old = features_.Size();
    112 
    113   int32_t num_frames_new =
    114       NumFrames(num_samples_total, frame_opts, input_finished_);
    115 
    116   KNF_CHECK_GE(num_frames_new, num_frames_old);
    117 
    118   // note: this online feature-extraction code does not support VTLN.
    119   float vtln_warp = 1.0;
    120 
    121   std::vector<float> window;
    122   bool need_raw_log_energy = computer_.NeedRawLogEnergy();
    123 
    124   for (int32_t frame = num_frames_old; frame < num_frames_new; ++frame) {
    125     std::fill(window.begin(), window.end(), 0);
    126     float raw_log_energy = 0.0;
    127     ExtractWindow(waveform_offset_, waveform_remainder_, frame, frame_opts,
    128                   window_function_, &window,
    129                   need_raw_log_energy ? &raw_log_energy : nullptr);
    130 
    131     std::vector<float> this_feature(computer_.Dim());
    132 
    133     computer_.Compute(raw_log_energy, vtln_warp, &window, this_feature.data());
    134     features_.PushBack(std::move(this_feature));
    135   }
    136 
    137   // OK, we will now discard any portion of the signal that will not be
    138   // necessary to compute frames in the future.
    139   int64_t first_sample_of_next_frame =
    140       FirstSampleOfFrame(num_frames_new, frame_opts);
    141 
    142   int32_t samples_to_discard = first_sample_of_next_frame - waveform_offset_;
    143 
    144   if (samples_to_discard > 0) {
    145     // discard the leftmost part of the waveform that we no longer need.
    146     int32_t new_num_samples =
    147         static_cast<int32_t>(waveform_remainder_.size()) - samples_to_discard;
    148 
    149     if (new_num_samples <= 0) {
    150       // odd, but we'll try to handle it.
    151       waveform_offset_ += waveform_remainder_.size();
    152       waveform_remainder_.resize(0);
    153     } else {
    154       std::vector<float> new_remainder(new_num_samples);
    155 
    156       std::copy(waveform_remainder_.begin() + samples_to_discard,
    157                 waveform_remainder_.end(), new_remainder.begin());
    158       waveform_offset_ += samples_to_discard;
    159 
    160       waveform_remainder_.swap(new_remainder);
    161     }
    162   }
    163 }
    164 
    165 template class OnlineGenericBaseFeature<FbankComputer>;
    166 template class OnlineGenericBaseFeature<MfccComputer>;
    167 template class OnlineGenericBaseFeature<WhisperFeatureComputer>;
    168 
    169 }  // namespace knf