The Open Master Hearing Aid (openMHA)
openMHA
Open community platform for hearing aid algorithm research
|
A class that performs polyphase resampling. More...
Public Member Functions | |
polyphase_resampling_t (unsigned n_up, unsigned n_down, mha_real_t nyquist_ratio, unsigned n_irs, unsigned n_ringbuffer, unsigned n_channels, unsigned n_prefill) | |
Construct a polyphase resampler instance. More... | |
void | write (mha_wave_t &signal) |
Write signal to the ringbuffer. More... | |
void | read (mha_wave_t &signal) |
Read resampled signal. More... | |
unsigned | readable_frames () const |
Number of frames at target sampling rate that can be produced. More... | |
Private Attributes | |
unsigned | upsampling_factor |
Integer upsampling factor. More... | |
unsigned | downsampling_factor |
Integer downsampling factor. More... | |
unsigned | now_index |
Index of "now" in the interpolated sampling rate. More... | |
bool | underflow |
Set to true when an underflow has occurred. More... | |
MHAWindow::hanning_t | impulse_response |
Contains the impulse response of the lowpass filter needed for anti-aliasing. More... | |
MHASignal::ringbuffer_t | ringbuffer |
Storage of input signal. More... | |
A class that performs polyphase resampling.
Background information: When resampling from one sampling rate to another, it helps when one sampling rate is a multiple of the other sampling rate: In the case of upsampling, the samples at the original rate are copied to the upsampled signal spread out with a constant number of zero samples between the originally adjacent samples. The signal is then low-pass filtered to avoid frequency aliasing and to fill the zero-samples with interpolated values. In the case of down-sampling, the signal is first low-pass filtered for anti-aliasing, and only every nth sample of the filtered output is used for the signal at the new sample rate. Of course, for finite-impulse-response (FIR) filters this means that only every nth sample needs to be computed.
When resampling from one sampling rate to another where neither is a multiple of the other, the signal first needs to be upsampled to a sampling rate that is a multiple of both (source and target) sampling rates, and then downsampled again to the target sampling rate. Instead of applying two separate lowpass filters directly after each other (one filter for upsampling and another for downsampling), it is sufficient to apply only one low-pass filter, when producing the output at the final target rate, with a cut-off frequency equal to the lower cut-off-frequency of the replaced two low-pass filters. Not filtering to produce a filtered signal already at the common multiple sampling rate has the side effect that this intermediate signal at the common multiple sampling rate keeps its filler zero samples unaltered. These zero samples can be taken advantage of when filtering to produce the output at the target rate: The zeros do not need to be multiplied with their corresponding filter coefficients, because the result is known to be zero again, and this zero product has no effect on the summation operation to compute a target sample at the target rate. To summarize, the following optimization techniques are available:
The procedure that takes advantage of these optimization possibilites is known as polyphase resampling.
This class implements polyphase resampling in this way for a source sampling rate and a target sampling rate that have common multiple, the interpolation sampling rate. Non-rational and drifting sample rates are outside the scope of this resampler.
MHAFilter::polyphase_resampling_t::polyphase_resampling_t | ( | unsigned | n_up, |
unsigned | n_down, | ||
mha_real_t | nyquist_ratio, | ||
unsigned | n_irs, | ||
unsigned | n_ringbuffer, | ||
unsigned | n_channels, | ||
unsigned | n_prefill | ||
) |
Construct a polyphase resampler instance.
Allocates a ringbuffer with the given capacity n_ringbuffer. Client that triggers the constructor must ensure that the capacity n_ringbuffer and the delay n_prefill are sufficient, i.e. enough old and new samples are always available to compute sufficient samples in using an impulse response of length n_irs. Audio block sizes at both sides of the resampler have to be taken into account. Class MHASignal::blockprocessing_polyphase_resampling_t
takes care of this, and it is recommended to use this class for block-based processing.
Based on n_up, n_down, n_irs and nyquist_ratio, a suitable sinc impulse response is computed and windowed with a hanning window to limit its extent.
The actual source sampling rate, target sampling rate, and interpolation sampling rate are not parameters to this constructors, because only their ratios matter.
n_up | upsampling factor, ratio between interpolation rate and source rate. |
n_down | downsampling factor, ratio between interpolation rate and target rate. |
nyquist_ratio | low pass filter cutoff frequency relative to the nyquist frequency of the smaller of the two sampling rates. Example values: E.g. 0.8, 0.9 |
n_irs | length of impulse response (in samples at interpolation rate) |
n_ringbuffer | length of ringbuffer, in samples at source sampling rate |
n_channels | audio channels count |
n_prefill | Prefill the ringbuffer with this many zero frames in samples at source sampling rate |
void MHAFilter::polyphase_resampling_t::write | ( | mha_wave_t & | signal | ) |
Write signal to the ringbuffer.
Signal contained in signal is appended to the audio frames already present in the ringbuffer.
signal | input signal in original sampling rate |
MHA_Error | Raises exception if there is not enough room or if the number of channels does not match. |
void MHAFilter::polyphase_resampling_t::read | ( | mha_wave_t & | signal | ) |
Read resampled signal.
Will perform the resampling and remove no longer needed samples from the input buffer.
signal | buffer to write the resampled signal to. |
MHA_Error | Raises exception if there is not enough input signal or if the number of channels is too high. |
|
inline |
Number of frames at target sampling rate that can be produced.
This method only checks for enough future samples present, therefore, this number can be positive and a read operation can still fail if there are not enough past samples present to perform the filtering for the first output sample. This could only happen if the constructor parameters n_ringbuffer or n_prefill have been chosen too small, because otherwise the method read ensures that enough past samples are present to compute the next target sample.
|
private |
Integer upsampling factor.
Interpolation rate divided by source rate.
|
private |
Integer downsampling factor.
Interpolation rate divided by target rate.
|
private |
Index of "now" in the interpolated sampling rate.
|
private |
Set to true when an underflow has occurred.
When this is true, then the object can no longer be used. Underflows have to be avoided by clients, e.g. by checking that enough readable_frames are present before calling read
|
private |
Contains the impulse response of the lowpass filter needed for anti-aliasing.
The impulse response is stored at the interpolation sampling rate. We use an instance of MHAWindow::hanning_t here because we are limiting the sinc impulse response with a Hanning window (otherwise the impulse response would extend indefinitely into past and future). And the samples inside an MHAWindow::hanning_t can be altered with *=, which our constructor does.
|
private |
Storage of input signal.
Part of the polyphase resampling optimization is that apart from the FIR impulse response, nothing is stored at the interpolation rate, saving memory and computation cycles.