LinearResample Class Reference

LinearResample is a special case of ArbitraryResample, where we want to resample a signal at linearly spaced intervals (this means we want to upsample or downsample the signal). More...

#include <resample.h>

Collaboration diagram for LinearResample:

Public Member Functions

 LinearResample (int32 samp_rate_in_hz, int32 samp_rate_out_hz, BaseFloat filter_cutoff_hz, int32 num_zeros)
 Constructor. More...
 
void Resample (const VectorBase< BaseFloat > &input, bool flush, Vector< BaseFloat > *output)
 This function does the resampling. More...
 
void Reset ()
 Calling the function Reset() resets the state of the object prior to processing a new signal; it is only necessary if you have called Resample(x, y, false) for some signal, leading to a remainder of the signal being called, but then abandon processing the signal before calling Resample(x, y, true) for the last piece. More...
 
int32 GetInputSamplingRate ()
 
int32 GetOutputSamplingRate ()
 

Private Member Functions

int64 GetNumOutputSamples (int64 input_num_samp, bool flush) const
 This function outputs the number of output samples we will output for a signal with "input_num_samp" input samples. More...
 
void GetIndexes (int64 samp_out, int64 *first_samp_in, int32 *samp_out_wrapped) const
 Given an output-sample index, this function outputs to *first_samp_in the first input-sample index that we have a weight on (may be negative), and to *samp_out_wrapped the index into weights_ where we can get the corresponding weights on the input. More...
 
void SetRemainder (const VectorBase< BaseFloat > &input)
 
void SetIndexesAndWeights ()
 
BaseFloat FilterFunc (BaseFloat) const
 Here, t is a time in seconds representing an offset from the center of the windowed filter function, and FilterFunction(t) returns the windowed filter function, described in the header as h(t) = f(t)g(t), evaluated at t. More...
 

Private Attributes

int32 samp_rate_in_
 
int32 samp_rate_out_
 
BaseFloat filter_cutoff_
 
int32 num_zeros_
 
int32 input_samples_in_unit_
 The number of input samples in the smallest repeating unit: num_samp_in_ = samp_rate_in_hz / Gcd(samp_rate_in_hz, samp_rate_out_hz) More...
 
int32 output_samples_in_unit_
 The number of output samples in the smallest repeating unit: num_samp_out_ = samp_rate_out_hz / Gcd(samp_rate_in_hz, samp_rate_out_hz) More...
 
std::vector< int32first_index_
 The first input-sample index that we sum over, for this output-sample index. More...
 
std::vector< Vector< BaseFloat > > weights_
 Weights on the input samples, for this output-sample index. More...
 
int64 input_sample_offset_
 The number of input samples we have already received for this signal (including anything in remainder_) More...
 
int64 output_sample_offset_
 The number of samples we have already output for this signal. More...
 
Vector< BaseFloatinput_remainder_
 A small trailing part of the previously seen input signal. More...
 

Detailed Description

LinearResample is a special case of ArbitraryResample, where we want to resample a signal at linearly spaced intervals (this means we want to upsample or downsample the signal).

It is more efficient than ArbitraryResample because we can construct it just once.

We require that the input and output sampling rate be specified as integers, as this is an easy way to specify that their ratio be rational.

Definition at line 147 of file resample.h.

Constructor & Destructor Documentation

◆ LinearResample()

LinearResample ( int32  samp_rate_in_hz,
int32  samp_rate_out_hz,
BaseFloat  filter_cutoff_hz,
int32  num_zeros 
)

Constructor.

We make the input and output sample rates integers, because we are going to need to find a common divisor. This should just remind you that they need to be integers. The filter cutoff needs to be less than samp_rate_in_hz/2 and less than samp_rate_out_hz/2. num_zeros controls the sharpness of the filter, more == sharper but less efficient. We suggest around 4 to 10 for normal use.

Definition at line 33 of file resample.cc.

References kaldi::Gcd(), LinearResample::input_samples_in_unit_, KALDI_ASSERT, LinearResample::output_samples_in_unit_, LinearResample::Reset(), LinearResample::samp_rate_in_, LinearResample::samp_rate_out_, and LinearResample::SetIndexesAndWeights().

36  :
37  samp_rate_in_(samp_rate_in_hz),
38  samp_rate_out_(samp_rate_out_hz),
39  filter_cutoff_(filter_cutoff_hz),
40  num_zeros_(num_zeros) {
41  KALDI_ASSERT(samp_rate_in_hz > 0.0 &&
42  samp_rate_out_hz > 0.0 &&
43  filter_cutoff_hz > 0.0 &&
44  filter_cutoff_hz*2 <= samp_rate_in_hz &&
45  filter_cutoff_hz*2 <= samp_rate_out_hz &&
46  num_zeros > 0);
47 
48  // base_freq is the frequency of the repeating unit, which is the gcd
49  // of the input frequencies.
50  int32 base_freq = Gcd(samp_rate_in_, samp_rate_out_);
53 
55  Reset();
56 }
void Reset()
Calling the function Reset() resets the state of the object prior to processing a new signal; it is o...
Definition: resample.cc:235
void SetIndexesAndWeights()
Definition: resample.cc:104
int32 output_samples_in_unit_
The number of output samples in the smallest repeating unit: num_samp_out_ = samp_rate_out_hz / Gcd(s...
Definition: resample.h:228
I Gcd(I m, I n)
Definition: kaldi-math.h:297
kaldi::int32 int32
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
BaseFloat filter_cutoff_
Definition: resample.h:221
int32 input_samples_in_unit_
The number of input samples in the smallest repeating unit: num_samp_in_ = samp_rate_in_hz / Gcd(samp...
Definition: resample.h:224

Member Function Documentation

◆ FilterFunc()

BaseFloat FilterFunc ( BaseFloat  t) const
private

Here, t is a time in seconds representing an offset from the center of the windowed filter function, and FilterFunction(t) returns the windowed filter function, described in the header as h(t) = f(t)g(t), evaluated at t.

Definition at line 246 of file resample.cc.

References LinearResample::filter_cutoff_, M_2PI, M_PI, and LinearResample::num_zeros_.

Referenced by LinearResample::SetIndexesAndWeights().

246  {
247  BaseFloat window, // raised-cosine (Hanning) window of width
248  // num_zeros_/2*filter_cutoff_
249  filter; // sinc filter function
250  if (fabs(t) < num_zeros_ / (2.0 * filter_cutoff_))
251  window = 0.5 * (1 + cos(M_2PI * filter_cutoff_ / num_zeros_ * t));
252  else
253  window = 0.0; // outside support of window function
254  if (t != 0)
255  filter = sin(M_2PI * filter_cutoff_ * t) / (M_PI * t);
256  else
257  filter = 2 * filter_cutoff_; // limit of the function at t = 0
258  return filter * window;
259 }
#define M_PI
Definition: kaldi-math.h:44
float BaseFloat
Definition: kaldi-types.h:29
BaseFloat filter_cutoff_
Definition: resample.h:221
#define M_2PI
Definition: kaldi-math.h:52

◆ GetIndexes()

void GetIndexes ( int64  samp_out,
int64 *  first_samp_in,
int32 samp_out_wrapped 
) const
inlineprivate

Given an output-sample index, this function outputs to *first_samp_in the first input-sample index that we have a weight on (may be negative), and to *samp_out_wrapped the index into weights_ where we can get the corresponding weights on the input.

Definition at line 137 of file resample.cc.

References LinearResample::first_index_, LinearResample::input_samples_in_unit_, and LinearResample::output_samples_in_unit_.

Referenced by LinearResample::Resample().

139  {
140  // A unit is the smallest nonzero amount of time that is an exact
141  // multiple of the input and output sample periods. The unit index
142  // is the answer to "which numbered unit we are in".
143  int64 unit_index = samp_out / output_samples_in_unit_;
144  // samp_out_wrapped is equal to samp_out % output_samples_in_unit_
145  *samp_out_wrapped = static_cast<int32>(samp_out -
146  unit_index * output_samples_in_unit_);
147  *first_samp_in = first_index_[*samp_out_wrapped] +
148  unit_index * input_samples_in_unit_;
149 }
int32 output_samples_in_unit_
The number of output samples in the smallest repeating unit: num_samp_out_ = samp_rate_out_hz / Gcd(s...
Definition: resample.h:228
kaldi::int32 int32
std::vector< int32 > first_index_
The first input-sample index that we sum over, for this output-sample index.
Definition: resample.h:238
int32 input_samples_in_unit_
The number of input samples in the smallest repeating unit: num_samp_in_ = samp_rate_in_hz / Gcd(samp...
Definition: resample.h:224

◆ GetInputSamplingRate()

int32 GetInputSamplingRate ( )
inline

Definition at line 190 of file resample.h.

References ArbitraryResample::samp_rate_in_.

190 { return samp_rate_in_; }

◆ GetNumOutputSamples()

int64 GetNumOutputSamples ( int64  input_num_samp,
bool  flush 
) const
private

This function outputs the number of output samples we will output for a signal with "input_num_samp" input samples.

If flush == true, we return the largest n such that (n/samp_rate_out_) is in the interval [ 0, input_num_samp/samp_rate_in_ ), and note that the interval is half-open. If flush == false, define window_width as num_zeros / (2.0 * filter_cutoff_); we return the largest n such that (n/samp_rate_out_) is in the interval [ 0, input_num_samp/samp_rate_in_ - window_width ).

Definition at line 58 of file resample.cc.

References LinearResample::filter_cutoff_, kaldi::Lcm(), LinearResample::num_zeros_, LinearResample::samp_rate_in_, and LinearResample::samp_rate_out_.

Referenced by LinearResample::Resample().

59  {
60  // For exact computation, we measure time in "ticks" of 1.0 / tick_freq,
61  // where tick_freq is the least common multiple of samp_rate_in_ and
62  // samp_rate_out_.
63  int32 tick_freq = Lcm(samp_rate_in_, samp_rate_out_);
64  int32 ticks_per_input_period = tick_freq / samp_rate_in_;
65 
66  // work out the number of ticks in the time interval
67  // [ 0, input_num_samp/samp_rate_in_ ).
68  int64 interval_length_in_ticks = input_num_samp * ticks_per_input_period;
69  if (!flush) {
70  BaseFloat window_width = num_zeros_ / (2.0 * filter_cutoff_);
71  // To count the window-width in ticks we take the floor. This
72  // is because since we're looking for the largest integer num-out-samp
73  // that fits in the interval, which is open on the right, a reduction
74  // in interval length of less than a tick will never make a difference.
75  // For example, the largest integer in the interval [ 0, 2 ) and the
76  // largest integer in the interval [ 0, 2 - 0.9 ) are the same (both one).
77  // So when we're subtracting the window-width we can ignore the fractional
78  // part.
79  int32 window_width_ticks = floor(window_width * tick_freq);
80  // The time-period of the output that we can sample gets reduced
81  // by the window-width (which is actually the distance from the
82  // center to the edge of the windowing function) if we're not
83  // "flushing the output".
84  interval_length_in_ticks -= window_width_ticks;
85  }
86  if (interval_length_in_ticks <= 0)
87  return 0;
88  int32 ticks_per_output_period = tick_freq / samp_rate_out_;
89  // Get the last output-sample in the closed interval, i.e. replacing [ ) with
90  // [ ]. Note: integer division rounds down. See
91  // http://en.wikipedia.org/wiki/Interval_(mathematics) for an explanation of
92  // the notation.
93  int64 last_output_samp = interval_length_in_ticks / ticks_per_output_period;
94  // We need the last output-sample in the open interval, so if it takes us to
95  // the end of the interval exactly, subtract one.
96  if (last_output_samp * ticks_per_output_period == interval_length_in_ticks)
97  last_output_samp--;
98  // First output-sample index is zero, so the number of output samples
99  // is the last output-sample plus one.
100  int64 num_output_samp = last_output_samp + 1;
101  return num_output_samp;
102 }
kaldi::int32 int32
I Lcm(I m, I n)
Returns the least common multiple of two integers.
Definition: kaldi-math.h:318
float BaseFloat
Definition: kaldi-types.h:29
BaseFloat filter_cutoff_
Definition: resample.h:221

◆ GetOutputSamplingRate()

int32 GetOutputSamplingRate ( )
inline

Definition at line 191 of file resample.h.

References ArbitraryResample::FilterFunc().

191 { return samp_rate_out_; }

◆ Resample()

void Resample ( const VectorBase< BaseFloat > &  input,
bool  flush,
Vector< BaseFloat > *  output 
)

This function does the resampling.

If you call it with flush == true and you have never called it with flush == false, it just resamples the input signal (it resizes the output to a suitable number of samples).

You can also use this function to process a signal a piece at a time. suppose you break it into piece1, piece2, ... pieceN. You can call

Resample(piece1, &output1, false);
Resample(piece2, &output2, false);
Resample(piece3, &output3, true);

If you call it with flush == false, it won't output the last few samples but will remember them, so that if you later give it a second piece of the input signal it can process it correctly. If your most recent call to the object was with flush == false, it will have internal state; you can remove this by calling Reset(). Empty input is acceptable.

Definition at line 152 of file resample.cc.

References VectorBase< Real >::Dim(), LinearResample::GetIndexes(), LinearResample::GetNumOutputSamples(), rnnlm::i, LinearResample::input_remainder_, LinearResample::input_sample_offset_, KALDI_ASSERT, LinearResample::output_sample_offset_, LinearResample::Reset(), Vector< Real >::Resize(), LinearResample::SetRemainder(), kaldi::VecVec(), and LinearResample::weights_.

Referenced by OnlinePitchFeatureImpl::AcceptWaveform(), kaldi::ResampleWaveform(), UnitTestLinearResample(), and UnitTestLinearResample2().

154  {
155  int32 input_dim = input.Dim();
156  int64 tot_input_samp = input_sample_offset_ + input_dim,
157  tot_output_samp = GetNumOutputSamples(tot_input_samp, flush);
158 
159  KALDI_ASSERT(tot_output_samp >= output_sample_offset_);
160 
161  output->Resize(tot_output_samp - output_sample_offset_);
162 
163  // samp_out is the index into the total output signal, not just the part
164  // of it we are producing here.
165  for (int64 samp_out = output_sample_offset_;
166  samp_out < tot_output_samp;
167  samp_out++) {
168  int64 first_samp_in;
169  int32 samp_out_wrapped;
170  GetIndexes(samp_out, &first_samp_in, &samp_out_wrapped);
171  const Vector<BaseFloat> &weights = weights_[samp_out_wrapped];
172  // first_input_index is the first index into "input" that we have a weight
173  // for.
174  int32 first_input_index = static_cast<int32>(first_samp_in -
176  BaseFloat this_output;
177  if (first_input_index >= 0 &&
178  first_input_index + weights.Dim() <= input_dim) {
179  SubVector<BaseFloat> input_part(input, first_input_index, weights.Dim());
180  this_output = VecVec(input_part, weights);
181  } else { // Handle edge cases.
182  this_output = 0.0;
183  for (int32 i = 0; i < weights.Dim(); i++) {
184  BaseFloat weight = weights(i);
185  int32 input_index = first_input_index + i;
186  if (input_index < 0 && input_remainder_.Dim() + input_index >= 0) {
187  this_output += weight *
188  input_remainder_(input_remainder_.Dim() + input_index);
189  } else if (input_index >= 0 && input_index < input_dim) {
190  this_output += weight * input(input_index);
191  } else if (input_index >= input_dim) {
192  // We're past the end of the input and are adding zero; should only
193  // happen if the user specified flush == true, or else we would not
194  // be trying to output this sample.
195  KALDI_ASSERT(flush);
196  }
197  }
198  }
199  int32 output_index = static_cast<int32>(samp_out - output_sample_offset_);
200  (*output)(output_index) = this_output;
201  }
202 
203  if (flush) {
204  Reset(); // Reset the internal state.
205  } else {
206  SetRemainder(input);
207  input_sample_offset_ = tot_input_samp;
208  output_sample_offset_ = tot_output_samp;
209  }
210 }
int64 output_sample_offset_
The number of samples we have already output for this signal.
Definition: resample.h:249
void Reset()
Calling the function Reset() resets the state of the object prior to processing a new signal; it is o...
Definition: resample.cc:235
void SetRemainder(const VectorBase< BaseFloat > &input)
Definition: resample.cc:212
void GetIndexes(int64 samp_out, int64 *first_samp_in, int32 *samp_out_wrapped) const
Given an output-sample index, this function outputs to *first_samp_in the first input-sample index th...
Definition: resample.cc:137
kaldi::int32 int32
int64 input_sample_offset_
The number of input samples we have already received for this signal (including anything in remainder...
Definition: resample.h:246
Vector< BaseFloat > input_remainder_
A small trailing part of the previously seen input signal.
Definition: resample.h:251
float BaseFloat
Definition: kaldi-types.h:29
int64 GetNumOutputSamples(int64 input_num_samp, bool flush) const
This function outputs the number of output samples we will output for a signal with "input_num_samp" ...
Definition: resample.cc:58
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
std::vector< Vector< BaseFloat > > weights_
Weights on the input samples, for this output-sample index.
Definition: resample.h:241
Real VecVec(const VectorBase< Real > &a, const VectorBase< Real > &b)
Returns dot product between v1 and v2.
Definition: kaldi-vector.cc:37

◆ Reset()

void Reset ( )

Calling the function Reset() resets the state of the object prior to processing a new signal; it is only necessary if you have called Resample(x, y, false) for some signal, leading to a remainder of the signal being called, but then abandon processing the signal before calling Resample(x, y, true) for the last piece.

Call it unnecessarily between signals will not do any harm.

Definition at line 235 of file resample.cc.

References LinearResample::input_remainder_, LinearResample::input_sample_offset_, and LinearResample::output_sample_offset_.

Referenced by LinearResample::LinearResample(), and LinearResample::Resample().

235  {
238  input_remainder_.Resize(0);
239 }
int64 output_sample_offset_
The number of samples we have already output for this signal.
Definition: resample.h:249
int64 input_sample_offset_
The number of input samples we have already received for this signal (including anything in remainder...
Definition: resample.h:246
Vector< BaseFloat > input_remainder_
A small trailing part of the previously seen input signal.
Definition: resample.h:251

◆ SetIndexesAndWeights()

void SetIndexesAndWeights ( )
private

Definition at line 104 of file resample.cc.

References LinearResample::filter_cutoff_, LinearResample::FilterFunc(), LinearResample::first_index_, rnnlm::i, rnnlm::j, LinearResample::num_zeros_, LinearResample::output_samples_in_unit_, LinearResample::samp_rate_in_, LinearResample::samp_rate_out_, and LinearResample::weights_.

Referenced by LinearResample::LinearResample().

104  {
107 
108  double window_width = num_zeros_ / (2.0 * filter_cutoff_);
109 
110  for (int32 i = 0; i < output_samples_in_unit_; i++) {
111  double output_t = i / static_cast<double>(samp_rate_out_);
112  double min_t = output_t - window_width, max_t = output_t + window_width;
113  // we do ceil on the min and floor on the max, because if we did it
114  // the other way around we would unnecessarily include indexes just
115  // outside the window, with zero coefficients. It's possible
116  // if the arguments to the ceil and floor expressions are integers
117  // (e.g. if filter_cutoff_ has an exact ratio with the sample rates),
118  // that we unnecessarily include something with a zero coefficient,
119  // but this is only a slight efficiency issue.
120  int32 min_input_index = ceil(min_t * samp_rate_in_),
121  max_input_index = floor(max_t * samp_rate_in_),
122  num_indices = max_input_index - min_input_index + 1;
123  first_index_[i] = min_input_index;
124  weights_[i].Resize(num_indices);
125  for (int32 j = 0; j < num_indices; j++) {
126  int32 input_index = min_input_index + j;
127  double input_t = input_index / static_cast<double>(samp_rate_in_),
128  delta_t = input_t - output_t;
129  // sign of delta_t doesn't matter.
130  weights_[i](j) = FilterFunc(delta_t) / samp_rate_in_;
131  }
132  }
133 }
BaseFloat FilterFunc(BaseFloat) const
Here, t is a time in seconds representing an offset from the center of the windowed filter function...
Definition: resample.cc:246
int32 output_samples_in_unit_
The number of output samples in the smallest repeating unit: num_samp_out_ = samp_rate_out_hz / Gcd(s...
Definition: resample.h:228
kaldi::int32 int32
std::vector< int32 > first_index_
The first input-sample index that we sum over, for this output-sample index.
Definition: resample.h:238
BaseFloat filter_cutoff_
Definition: resample.h:221
std::vector< Vector< BaseFloat > > weights_
Weights on the input samples, for this output-sample index.
Definition: resample.h:241

◆ SetRemainder()

void SetRemainder ( const VectorBase< BaseFloat > &  input)
private

Definition at line 212 of file resample.cc.

References VectorBase< Real >::Dim(), LinearResample::filter_cutoff_, LinearResample::input_remainder_, LinearResample::num_zeros_, and LinearResample::samp_rate_in_.

Referenced by LinearResample::Resample().

212  {
213  Vector<BaseFloat> old_remainder(input_remainder_);
214  // max_remainder_needed is the width of the filter from side to side,
215  // measured in input samples. you might think it should be half that,
216  // but you have to consider that you might be wanting to output samples
217  // that are "in the past" relative to the beginning of the latest
218  // input... anyway, storing more remainder than needed is not harmful.
219  int32 max_remainder_needed = ceil(samp_rate_in_ * num_zeros_ /
221  input_remainder_.Resize(max_remainder_needed);
222  for (int32 index = - input_remainder_.Dim(); index < 0; index++) {
223  // we interpret "index" as an offset from the end of "input" and
224  // from the end of input_remainder_.
225  int32 input_index = index + input.Dim();
226  if (input_index >= 0)
227  input_remainder_(index + input_remainder_.Dim()) = input(input_index);
228  else if (input_index + old_remainder.Dim() >= 0)
229  input_remainder_(index + input_remainder_.Dim()) =
230  old_remainder(input_index + old_remainder.Dim());
231  // else leave it at zero.
232  }
233 }
kaldi::int32 int32
Vector< BaseFloat > input_remainder_
A small trailing part of the previously seen input signal.
Definition: resample.h:251
BaseFloat filter_cutoff_
Definition: resample.h:221

Member Data Documentation

◆ filter_cutoff_

◆ first_index_

std::vector<int32> first_index_
private

The first input-sample index that we sum over, for this output-sample index.

May be negative; any truncation at the beginning is handled separately. This is just for the first few output samples, but we can extrapolate the correct input-sample index for arbitrary output samples.

Definition at line 238 of file resample.h.

Referenced by LinearResample::GetIndexes(), and LinearResample::SetIndexesAndWeights().

◆ input_remainder_

Vector<BaseFloat> input_remainder_
private

A small trailing part of the previously seen input signal.

Definition at line 251 of file resample.h.

Referenced by LinearResample::Resample(), LinearResample::Reset(), and LinearResample::SetRemainder().

◆ input_sample_offset_

int64 input_sample_offset_
private

The number of input samples we have already received for this signal (including anything in remainder_)

Definition at line 246 of file resample.h.

Referenced by LinearResample::Resample(), and LinearResample::Reset().

◆ input_samples_in_unit_

int32 input_samples_in_unit_
private

The number of input samples in the smallest repeating unit: num_samp_in_ = samp_rate_in_hz / Gcd(samp_rate_in_hz, samp_rate_out_hz)

Definition at line 224 of file resample.h.

Referenced by LinearResample::GetIndexes(), and LinearResample::LinearResample().

◆ num_zeros_

◆ output_sample_offset_

int64 output_sample_offset_
private

The number of samples we have already output for this signal.

Definition at line 249 of file resample.h.

Referenced by LinearResample::Resample(), and LinearResample::Reset().

◆ output_samples_in_unit_

int32 output_samples_in_unit_
private

The number of output samples in the smallest repeating unit: num_samp_out_ = samp_rate_out_hz / Gcd(samp_rate_in_hz, samp_rate_out_hz)

Definition at line 228 of file resample.h.

Referenced by LinearResample::GetIndexes(), LinearResample::LinearResample(), and LinearResample::SetIndexesAndWeights().

◆ samp_rate_in_

◆ samp_rate_out_

◆ weights_

std::vector<Vector<BaseFloat> > weights_
private

Weights on the input samples, for this output-sample index.

Definition at line 241 of file resample.h.

Referenced by LinearResample::Resample(), and LinearResample::SetIndexesAndWeights().


The documentation for this class was generated from the following files: