Initial experimental import of bq resampler
This commit is contained in:
@@ -199,7 +199,13 @@ else
|
||||
|
||||
endif # fft
|
||||
|
||||
if resampler == 'libsamplerate'
|
||||
if resampler == 'builtin'
|
||||
config_summary += { 'Resampler': 'Built-in' }
|
||||
message('For resampler: using built-in implementation')
|
||||
library_sources += 'src/dsp/BQResampler.cpp'
|
||||
feature_defines += ['-DUSE_BQRESAMPLER']
|
||||
|
||||
elif resampler == 'libsamplerate'
|
||||
if samplerate_dep.found()
|
||||
config_summary += { 'Resampler': 'libsamplerate' }
|
||||
message('For resampler: using libsamplerate')
|
||||
|
||||
@@ -7,7 +7,7 @@ option('fft',
|
||||
|
||||
option('resampler',
|
||||
type: 'combo',
|
||||
choices: ['auto', 'libsamplerate', 'speex', 'ipp'],
|
||||
choices: ['auto', 'builtin', 'libsamplerate', 'speex', 'ipp'],
|
||||
value: 'auto',
|
||||
description: 'Resampler library to use. Recommended is libsamplerate. The default (auto) will use libsamplerate if available, speex otherwise.')
|
||||
|
||||
|
||||
633
src/dsp/BQResampler.cpp
Normal file
633
src/dsp/BQResampler.cpp
Normal file
@@ -0,0 +1,633 @@
|
||||
//* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Rubber Band Library
|
||||
An audio time-stretching and pitch-shifting library.
|
||||
Copyright 2007-2021 Particular Programs Ltd.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version. See the file
|
||||
COPYING included with this distribution for more information.
|
||||
|
||||
Alternatively, if you have a valid commercial licence for the
|
||||
Rubber Band Library obtained by agreement with the copyright
|
||||
holders, you may redistribute and/or modify it under the terms
|
||||
described in that licence.
|
||||
|
||||
If you wish to distribute code using the Rubber Band Library
|
||||
under terms other than those of the GNU General Public License,
|
||||
you must obtain a valid commercial licence before doing so.
|
||||
*/
|
||||
|
||||
#include "BQResampler.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "system/Allocators.h"
|
||||
#include "system/VectorOps.h"
|
||||
|
||||
#define BQ_R__ R__
|
||||
|
||||
using std::vector;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using std::min;
|
||||
using std::max;
|
||||
|
||||
namespace RubberBand {
|
||||
|
||||
BQResampler::BQResampler(Parameters parameters, int channels) :
|
||||
m_qparams(parameters.quality),
|
||||
m_dynamism(parameters.dynamism),
|
||||
m_ratio_change(parameters.ratioChange),
|
||||
m_debug_level(parameters.debugLevel),
|
||||
m_initial_rate(parameters.referenceSampleRate),
|
||||
m_channels(channels),
|
||||
m_fade_count(0),
|
||||
m_initialised(false)
|
||||
{
|
||||
if (m_debug_level > 0) {
|
||||
cerr << "BQResampler::BQResampler: "
|
||||
<< (m_dynamism == RatioOftenChanging ? "often-changing" : "mostly-fixed")
|
||||
<< ", "
|
||||
<< (m_ratio_change == SmoothRatioChange ? "smooth" : "sudden")
|
||||
<< " ratio changes, ref " << m_initial_rate << " Hz" << endl;
|
||||
}
|
||||
|
||||
if (m_dynamism == RatioOftenChanging) {
|
||||
m_proto_length = m_qparams.proto_p * m_qparams.p_multiple + 1;
|
||||
if (m_debug_level > 0) {
|
||||
cerr << "BQResampler: creating prototype filter of length "
|
||||
<< m_proto_length << endl;
|
||||
}
|
||||
m_prototype = make_filter(m_proto_length, m_qparams.proto_p);
|
||||
m_prototype.push_back(0.0); // interpolate without fear
|
||||
}
|
||||
|
||||
int phase_reserve = 2 * int(round(m_initial_rate));
|
||||
int buffer_reserve = 1000 * m_channels;
|
||||
m_state_a.phase_info.reserve(phase_reserve);
|
||||
m_state_a.buffer.reserve(buffer_reserve);
|
||||
|
||||
if (m_dynamism == RatioOftenChanging) {
|
||||
m_state_b.phase_info.reserve(phase_reserve);
|
||||
m_state_b.buffer.reserve(buffer_reserve);
|
||||
}
|
||||
|
||||
m_s = &m_state_a;
|
||||
m_fade = &m_state_b;
|
||||
}
|
||||
|
||||
BQResampler::BQResampler(const BQResampler &other) :
|
||||
m_qparams(other.m_qparams),
|
||||
m_dynamism(other.m_dynamism),
|
||||
m_ratio_change(other.m_ratio_change),
|
||||
m_debug_level(other.m_debug_level),
|
||||
m_initial_rate(other.m_initial_rate),
|
||||
m_channels(other.m_channels),
|
||||
m_state_a(other.m_state_a),
|
||||
m_state_b(other.m_state_b),
|
||||
m_fade_count(other.m_fade_count),
|
||||
m_prototype(other.m_prototype),
|
||||
m_proto_length(other.m_proto_length),
|
||||
m_initialised(other.m_initialised)
|
||||
{
|
||||
if (other.m_s == &(other.m_state_a)) {
|
||||
m_s = &m_state_a;
|
||||
m_fade = &m_state_b;
|
||||
} else {
|
||||
m_s = &m_state_b;
|
||||
m_fade = &m_state_a;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BQResampler::reset()
|
||||
{
|
||||
m_initialised = false;
|
||||
m_fade_count = 0;
|
||||
}
|
||||
|
||||
BQResampler::QualityParams::QualityParams(Quality q)
|
||||
{
|
||||
switch (q) {
|
||||
case Fastest:
|
||||
p_multiple = 12;
|
||||
proto_p = 160;
|
||||
k_snr = 70.0;
|
||||
k_transition = 0.2;
|
||||
cut = 0.9;
|
||||
break;
|
||||
case FastestTolerable:
|
||||
p_multiple = 62;
|
||||
proto_p = 160;
|
||||
k_snr = 90.0;
|
||||
k_transition = 0.05;
|
||||
cut = 0.975;
|
||||
break;
|
||||
case Best:
|
||||
p_multiple = 122;
|
||||
proto_p = 800;
|
||||
k_snr = 100.0;
|
||||
k_transition = 0.01;
|
||||
cut = 0.995;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
BQResampler::resampleInterleaved(float *const out,
|
||||
int outspace,
|
||||
const float *const in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final) {
|
||||
|
||||
int fade_length = round(m_initial_rate / 1000.0);
|
||||
if (fade_length < 6) {
|
||||
fade_length = 6;
|
||||
}
|
||||
int max_fade = min(outspace, int(floor(incount * ratio))) / 2;
|
||||
if (fade_length > max_fade) {
|
||||
fade_length = max_fade;
|
||||
}
|
||||
|
||||
if (!m_initialised) {
|
||||
state_for_ratio(*m_s, ratio, *m_fade);
|
||||
m_initialised = true;
|
||||
} else if (ratio != m_s->parameters.ratio) {
|
||||
state *tmp = m_fade;
|
||||
m_fade = m_s;
|
||||
m_s = tmp;
|
||||
state_for_ratio(*m_s, ratio, *m_fade);
|
||||
if (m_ratio_change == SmoothRatioChange) {
|
||||
if (m_debug_level > 0) {
|
||||
cerr << "BQResampler: ratio changed, beginning fade of length "
|
||||
<< fade_length << endl;
|
||||
}
|
||||
m_fade_count = fade_length;
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0, o = 0;
|
||||
int bufsize = m_s->buffer.size();
|
||||
|
||||
int incount_samples = incount * m_channels;
|
||||
int outspace_samples = outspace * m_channels;
|
||||
|
||||
while (o < outspace_samples) {
|
||||
while (i < incount_samples && m_s->fill < bufsize) {
|
||||
m_s->buffer[m_s->fill++] = in[i++];
|
||||
}
|
||||
if (m_s->fill == bufsize) {
|
||||
out[o++] = reconstruct_one(m_s);
|
||||
} else if (final && m_s->fill > m_s->centre) {
|
||||
out[o++] = reconstruct_one(m_s);
|
||||
} else if (final && m_s->fill == m_s->centre &&
|
||||
m_s->current_phase != m_s->initial_phase) {
|
||||
out[o++] = reconstruct_one(m_s);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int fbufsize = m_fade->buffer.size();
|
||||
int fi = 0, fo = 0;
|
||||
while (fo < o && m_fade_count > 0) {
|
||||
while (fi < incount_samples && m_fade->fill < fbufsize) {
|
||||
m_fade->buffer[m_fade->fill++] = in[fi++];
|
||||
}
|
||||
if (m_fade->fill == fbufsize) {
|
||||
double r = reconstruct_one(m_fade);
|
||||
double fadeWith = out[fo];
|
||||
double extent = double(m_fade_count - 1) / double(fade_length);
|
||||
double mixture = 0.5 * (1.0 - cos(M_PI * extent));
|
||||
double mixed = r * mixture + fadeWith * (1.0 - mixture);
|
||||
out[fo] = mixed;
|
||||
++fo;
|
||||
if (m_fade->current_channel == 0) {
|
||||
--m_fade_count;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return o / m_channels;
|
||||
}
|
||||
|
||||
int
|
||||
BQResampler::gcd(int a, int b) const
|
||||
{
|
||||
int c = a % b;
|
||||
if (c == 0) return b;
|
||||
else return gcd(b, c);
|
||||
}
|
||||
|
||||
double
|
||||
BQResampler::bessel0(double x) const
|
||||
{
|
||||
static double facsquared[] = {
|
||||
0.0, 1.0, 4.0, 36.0,
|
||||
576.0, 14400.0, 518400.0, 25401600.0,
|
||||
1625702400.0, 131681894400.0, 1.316818944E13, 1.59335092224E15,
|
||||
2.29442532803E17, 3.87757880436E19, 7.60005445655E21,
|
||||
1.71001225272E24, 4.37763136697E26, 1.26513546506E29,
|
||||
4.09903890678E31, 1.47975304535E34
|
||||
};
|
||||
static int nterms = sizeof(facsquared) / sizeof(facsquared[0]);
|
||||
double b = 1.0;
|
||||
for (int n = 1; n < nterms; ++n) {
|
||||
double ff = facsquared[n];
|
||||
double term = pow(x / 2.0, n * 2.0) / ff;
|
||||
b += term;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
vector<double>
|
||||
BQResampler::kaiser(double beta, int len) const
|
||||
{
|
||||
double denominator = bessel0(beta);
|
||||
int half = (len % 2 == 0 ? len/2 : (len+1)/2);
|
||||
vector<double> v(len, 0.0);
|
||||
for (int n = 0; n < half; ++n) {
|
||||
double k = (2.0 * n) / (len-1) - 1.0;
|
||||
v[n] = bessel0 (beta * sqrt(1.0 - k*k)) / denominator;
|
||||
}
|
||||
for (int n = half; n < len; ++n) {
|
||||
v[n] = v[len-1 - n];
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void
|
||||
BQResampler::kaiser_params(double attenuation,
|
||||
double transition,
|
||||
double &beta,
|
||||
int &len) const
|
||||
{
|
||||
if (attenuation > 21.0) {
|
||||
len = 1 + ceil((attenuation - 7.95) / (2.285 * transition));
|
||||
} else {
|
||||
len = 1 + ceil(5.79 / transition);
|
||||
}
|
||||
beta = 0.0;
|
||||
if (attenuation > 50.0) {
|
||||
beta = 0.1102 * (attenuation - 8.7);
|
||||
} else if (attenuation > 21.0) {
|
||||
beta = 0.5842 * (pow (attenuation - 21.0, 0.4)) +
|
||||
0.07886 * (attenuation - 21.0);
|
||||
}
|
||||
}
|
||||
|
||||
vector<double>
|
||||
BQResampler::kaiser_for(double attenuation,
|
||||
double transition,
|
||||
int minlen,
|
||||
int maxlen) const
|
||||
{
|
||||
double beta;
|
||||
int m;
|
||||
kaiser_params(attenuation, transition, beta, m);
|
||||
int mb = m;
|
||||
if (maxlen > 0 && mb > maxlen - 1) {
|
||||
mb = maxlen - 1;
|
||||
} else if (minlen > 0 && mb < minlen) {
|
||||
mb = minlen;
|
||||
}
|
||||
if (mb % 2 == 0) ++mb;
|
||||
if (m_debug_level > 0) {
|
||||
cerr << "BQResampler: window attenuation " << attenuation
|
||||
<< ", transition " << transition
|
||||
<< " -> length " << m << " adjusted to " << mb
|
||||
<< ", beta " << beta << endl;
|
||||
}
|
||||
return kaiser(beta, mb);
|
||||
}
|
||||
|
||||
void
|
||||
BQResampler::sinc_multiply(double peak_to_zero, vector<double> &buf) const
|
||||
{
|
||||
int len = int(buf.size());
|
||||
if (len < 2) return;
|
||||
|
||||
int left = len / 2;
|
||||
int right = (len + 1) / 2;
|
||||
double m = M_PI / peak_to_zero;
|
||||
|
||||
for (int i = 1; i <= right; ++i) {
|
||||
double x = i * m;
|
||||
double sinc = sin(x) / x;
|
||||
if (i <= left) {
|
||||
buf[left - i] *= sinc;
|
||||
}
|
||||
if (i < right) {
|
||||
buf[i + left] *= sinc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BQResampler::params
|
||||
BQResampler::fill_params(double ratio, int num, int denom) const
|
||||
{
|
||||
params p;
|
||||
int g = gcd (num, denom);
|
||||
p.ratio = ratio;
|
||||
p.numerator = num / g;
|
||||
p.denominator = denom / g;
|
||||
p.effective = double(p.numerator) / double(p.denominator);
|
||||
p.peak_to_zero = max(p.denominator, p.numerator);
|
||||
p.peak_to_zero /= m_qparams.cut;
|
||||
p.scale = double(p.numerator) / double(p.peak_to_zero);
|
||||
|
||||
if (m_debug_level > 0) {
|
||||
cerr << "BQResampler: ratio " << p.ratio
|
||||
<< " -> fraction " << p.numerator << "/" << p.denominator
|
||||
<< " with error " << p.effective - p.ratio
|
||||
<< endl;
|
||||
cerr << "BQResampler: peak-to-zero " << p.peak_to_zero
|
||||
<< ", scale " << p.scale
|
||||
<< endl;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
BQResampler::params
|
||||
BQResampler::pick_params(double ratio) const
|
||||
{
|
||||
// Farey algorithm, see
|
||||
// https://www.johndcook.com/blog/2010/10/20/best-rational-approximation/
|
||||
int max_denom = 192000;
|
||||
double a = 0.0, b = 1.0, c = 1.0, d = 0.0;
|
||||
double pa = a, pb = b, pc = c, pd = d;
|
||||
double eps = 1e-9;
|
||||
while (b <= max_denom && d <= max_denom) {
|
||||
double mediant = (a + c) / (b + d);
|
||||
if (fabs(ratio - mediant) < eps) {
|
||||
if (b + d <= max_denom) {
|
||||
return fill_params(ratio, a + c, b + d);
|
||||
} else if (d > b) {
|
||||
return fill_params(ratio, c, d);
|
||||
} else {
|
||||
return fill_params(ratio, a, b);
|
||||
}
|
||||
}
|
||||
if (ratio > mediant) {
|
||||
pa = a; pb = b;
|
||||
a += c; b += d;
|
||||
} else {
|
||||
pc = c; pd = d;
|
||||
c += a; d += b;
|
||||
}
|
||||
}
|
||||
if (fabs(ratio - (pc / pd)) < fabs(ratio - (pa / pb))) {
|
||||
return fill_params(ratio, pc, pd);
|
||||
} else {
|
||||
return fill_params(ratio, pa, pb);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BQResampler::phase_data_for(vector<BQResampler::phase_rec> &target_phase_data,
|
||||
floatbuf &target_phase_sorted_filter,
|
||||
int filter_length,
|
||||
const vector<double> *filter,
|
||||
int initial_phase,
|
||||
int input_spacing,
|
||||
int output_spacing) const
|
||||
{
|
||||
target_phase_data.clear();
|
||||
target_phase_data.reserve(input_spacing);
|
||||
|
||||
for (int p = 0; p < input_spacing; ++p) {
|
||||
int next_phase = p - output_spacing;
|
||||
while (next_phase < 0) next_phase += input_spacing;
|
||||
next_phase %= input_spacing;
|
||||
double dspace = double(input_spacing);
|
||||
int zip_length = ceil(double(filter_length - p) / dspace);
|
||||
int drop = ceil(double(max(0, output_spacing - p)) / dspace);
|
||||
phase_rec phase;
|
||||
phase.next_phase = next_phase;
|
||||
phase.drop = drop;
|
||||
phase.length = zip_length;
|
||||
phase.start_index = 0; // we fill this in below if needed
|
||||
target_phase_data.push_back(phase);
|
||||
}
|
||||
|
||||
if (m_dynamism == RatioMostlyFixed) {
|
||||
if (!filter) throw std::logic_error("filter required at phase_data_for in RatioMostlyFixed mode");
|
||||
target_phase_sorted_filter.clear();
|
||||
target_phase_sorted_filter.reserve(filter_length);
|
||||
for (int p = initial_phase; ; ) {
|
||||
phase_rec &phase = target_phase_data[p];
|
||||
phase.start_index = target_phase_sorted_filter.size();
|
||||
for (int i = 0; i < phase.length; ++i) {
|
||||
target_phase_sorted_filter.push_back
|
||||
((*filter)[i * input_spacing + p]);
|
||||
}
|
||||
p = phase.next_phase;
|
||||
if (p == initial_phase) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<double>
|
||||
BQResampler::make_filter(int filter_length, double peak_to_zero) const
|
||||
{
|
||||
vector<double> filter;
|
||||
filter.reserve(filter_length);
|
||||
|
||||
vector<double> kaiser = kaiser_for(m_qparams.k_snr, m_qparams.k_transition,
|
||||
1, filter_length);
|
||||
int k_length = kaiser.size();
|
||||
|
||||
if (k_length == filter_length) {
|
||||
sinc_multiply(peak_to_zero, kaiser);
|
||||
return kaiser;
|
||||
} else {
|
||||
kaiser.push_back(0.0);
|
||||
double m = double(k_length - 1) / double(filter_length - 1);
|
||||
for (int i = 0; i < filter_length; ++i) {
|
||||
double ix = i * m;
|
||||
int iix = floor(ix);
|
||||
double remainder = ix - iix;
|
||||
double value = 0.0;
|
||||
value += kaiser[iix] * (1.0 - remainder);
|
||||
value += kaiser[iix+1] * remainder;
|
||||
filter.push_back(value);
|
||||
}
|
||||
sinc_multiply(peak_to_zero, filter);
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BQResampler::state_for_ratio(BQResampler::state &target_state,
|
||||
double ratio,
|
||||
const BQResampler::state &BQ_R__ prev_state) const
|
||||
{
|
||||
params parameters = pick_params(ratio);
|
||||
target_state.parameters = parameters;
|
||||
|
||||
target_state.filter_length =
|
||||
int(parameters.peak_to_zero * m_qparams.p_multiple + 1);
|
||||
|
||||
if (target_state.filter_length % 2 == 0) {
|
||||
++target_state.filter_length;
|
||||
}
|
||||
|
||||
int half_length = target_state.filter_length / 2; // nb length is odd
|
||||
int input_spacing = parameters.numerator;
|
||||
int initial_phase = half_length % input_spacing;
|
||||
|
||||
target_state.initial_phase = initial_phase;
|
||||
target_state.current_phase = initial_phase;
|
||||
|
||||
if (m_dynamism == RatioMostlyFixed) {
|
||||
|
||||
if (m_debug_level > 0) {
|
||||
cerr << "BQResampler: creating filter of length "
|
||||
<< target_state.filter_length << endl;
|
||||
}
|
||||
|
||||
vector<double> filter =
|
||||
make_filter(target_state.filter_length, parameters.peak_to_zero);
|
||||
|
||||
phase_data_for(target_state.phase_info,
|
||||
target_state.phase_sorted_filter,
|
||||
target_state.filter_length, &filter,
|
||||
target_state.initial_phase,
|
||||
input_spacing,
|
||||
parameters.denominator);
|
||||
} else {
|
||||
phase_data_for(target_state.phase_info,
|
||||
target_state.phase_sorted_filter,
|
||||
target_state.filter_length, 0,
|
||||
target_state.initial_phase,
|
||||
input_spacing,
|
||||
parameters.denominator);
|
||||
}
|
||||
|
||||
int buffer_left = half_length / input_spacing;
|
||||
int buffer_right = buffer_left + 1;
|
||||
|
||||
int buffer_length = buffer_left + buffer_right;
|
||||
buffer_length = max(buffer_length,
|
||||
int(prev_state.buffer.size() / m_channels));
|
||||
|
||||
target_state.centre = buffer_length / 2;
|
||||
target_state.left = target_state.centre - buffer_left;
|
||||
target_state.fill = target_state.centre;
|
||||
|
||||
buffer_length *= m_channels;
|
||||
target_state.centre *= m_channels;
|
||||
target_state.left *= m_channels;
|
||||
target_state.fill *= m_channels;
|
||||
|
||||
int n_phases = int(target_state.phase_info.size());
|
||||
|
||||
if (m_debug_level > 0) {
|
||||
cerr << "BQResampler: " << m_channels << " channel(s) interleaved"
|
||||
<< ", buffer left " << buffer_left
|
||||
<< ", right " << buffer_right
|
||||
<< ", total " << buffer_length << endl;
|
||||
|
||||
cerr << "BQResampler: input spacing " << input_spacing
|
||||
<< ", output spacing " << parameters.denominator
|
||||
<< ", initial phase " << initial_phase
|
||||
<< " of " << n_phases << endl;
|
||||
}
|
||||
|
||||
if (prev_state.buffer.size() > 0) {
|
||||
if (int(prev_state.buffer.size()) == buffer_length) {
|
||||
target_state.buffer = prev_state.buffer;
|
||||
target_state.fill = prev_state.fill;
|
||||
} else {
|
||||
target_state.buffer = floatbuf(buffer_length, 0.0);
|
||||
for (int i = 0; i < prev_state.fill; ++i) {
|
||||
int offset = i - prev_state.centre;
|
||||
int new_ix = offset + target_state.centre;
|
||||
if (new_ix >= 0 && new_ix < buffer_length) {
|
||||
target_state.buffer[new_ix] = prev_state.buffer[i];
|
||||
target_state.fill = new_ix + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int phases_then = int(prev_state.phase_info.size());
|
||||
double distance_through =
|
||||
double(prev_state.current_phase) / double(phases_then);
|
||||
target_state.current_phase = round(n_phases * distance_through);
|
||||
if (target_state.current_phase >= n_phases) {
|
||||
target_state.current_phase = n_phases - 1;
|
||||
}
|
||||
} else {
|
||||
target_state.buffer = floatbuf(buffer_length, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
BQResampler::reconstruct_one(state *s) const
|
||||
{
|
||||
const phase_rec &pr = s->phase_info[s->current_phase];
|
||||
int phase_length = pr.length;
|
||||
double result = 0.0;
|
||||
|
||||
if (m_dynamism == RatioMostlyFixed) {
|
||||
int phase_start = pr.start_index;
|
||||
if (m_channels == 1) {
|
||||
result = v_multiply_and_sum
|
||||
(s->phase_sorted_filter.data() + phase_start,
|
||||
s->buffer.data() + s->left,
|
||||
phase_length);
|
||||
} else {
|
||||
for (int i = 0; i < phase_length; ++i) {
|
||||
result +=
|
||||
s->phase_sorted_filter[phase_start + i] *
|
||||
s->buffer[s->left + i * m_channels + s->current_channel];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
double m = double(m_proto_length - 1) / double(s->filter_length - 1);
|
||||
for (int i = 0; i < phase_length; ++i) {
|
||||
double sample =
|
||||
s->buffer[s->left + i * m_channels + s->current_channel];
|
||||
int filter_index = i * s->parameters.numerator + s->current_phase;
|
||||
double proto_index = m * filter_index;
|
||||
int iix = floor(proto_index);
|
||||
double remainder = proto_index - iix;
|
||||
double filter_value = m_prototype[iix] * (1.0 - remainder);
|
||||
filter_value += m_prototype[iix+1] * remainder;
|
||||
result += filter_value * sample;
|
||||
}
|
||||
}
|
||||
|
||||
s->current_channel = (s->current_channel + 1) % m_channels;
|
||||
|
||||
if (s->current_channel == 0) {
|
||||
|
||||
if (pr.drop > 0) {
|
||||
int drop = pr.drop * m_channels;
|
||||
v_move(s->buffer.data(), s->buffer.data() + drop,
|
||||
int(s->buffer.size()) - drop);
|
||||
for (int i = 1; i <= drop; ++i) {
|
||||
s->buffer[s->buffer.size() - i] = 0.0;
|
||||
}
|
||||
s->fill -= drop;
|
||||
}
|
||||
|
||||
s->current_phase = pr.next_phase;
|
||||
}
|
||||
|
||||
return result * s->parameters.scale;
|
||||
}
|
||||
|
||||
}
|
||||
165
src/dsp/BQResampler.h
Normal file
165
src/dsp/BQResampler.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Rubber Band Library
|
||||
An audio time-stretching and pitch-shifting library.
|
||||
Copyright 2007-2021 Particular Programs Ltd.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version. See the file
|
||||
COPYING included with this distribution for more information.
|
||||
|
||||
Alternatively, if you have a valid commercial licence for the
|
||||
Rubber Band Library obtained by agreement with the copyright
|
||||
holders, you may redistribute and/or modify it under the terms
|
||||
described in that licence.
|
||||
|
||||
If you wish to distribute code using the Rubber Band Library
|
||||
under terms other than those of the GNU General Public License,
|
||||
you must obtain a valid commercial licence before doing so.
|
||||
*/
|
||||
|
||||
#ifndef BQ_BQRESAMPLER_H
|
||||
#define BQ_BQRESAMPLER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "system/Allocators.h"
|
||||
#include "system/VectorOps.h"
|
||||
|
||||
namespace RubberBand {
|
||||
|
||||
class BQResampler
|
||||
{
|
||||
public:
|
||||
enum Quality { Best, FastestTolerable, Fastest };
|
||||
enum Dynamism { RatioOftenChanging, RatioMostlyFixed };
|
||||
enum RatioChange { SmoothRatioChange, SuddenRatioChange };
|
||||
|
||||
struct Parameters {
|
||||
Quality quality;
|
||||
Dynamism dynamism;
|
||||
RatioChange ratioChange;
|
||||
double referenceSampleRate;
|
||||
int debugLevel;
|
||||
|
||||
Parameters() :
|
||||
quality(FastestTolerable),
|
||||
dynamism(RatioMostlyFixed),
|
||||
ratioChange(SmoothRatioChange),
|
||||
referenceSampleRate(44100),
|
||||
debugLevel(0) { }
|
||||
};
|
||||
|
||||
BQResampler(Parameters parameters, int channels);
|
||||
BQResampler(const BQResampler &);
|
||||
|
||||
int resampleInterleaved(float *const out, int outspace,
|
||||
const float *const in, int incount,
|
||||
double ratio, bool final);
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
struct QualityParams {
|
||||
int p_multiple;
|
||||
int proto_p;
|
||||
double k_snr;
|
||||
double k_transition;
|
||||
double cut;
|
||||
QualityParams(Quality);
|
||||
};
|
||||
|
||||
const QualityParams m_qparams;
|
||||
const Dynamism m_dynamism;
|
||||
const RatioChange m_ratio_change;
|
||||
const int m_debug_level;
|
||||
const double m_initial_rate;
|
||||
const int m_channels;
|
||||
|
||||
struct params {
|
||||
double ratio;
|
||||
int numerator;
|
||||
int denominator;
|
||||
double effective;
|
||||
double peak_to_zero;
|
||||
double scale;
|
||||
params() : ratio(1.0), numerator(1), denominator(1),
|
||||
effective(1.0), peak_to_zero(0), scale(1.0) { }
|
||||
};
|
||||
|
||||
struct phase_rec {
|
||||
int next_phase;
|
||||
int length;
|
||||
int start_index;
|
||||
int drop;
|
||||
phase_rec() : next_phase(0), length(0), start_index(0), drop(0) { }
|
||||
};
|
||||
|
||||
typedef std::vector<float, RubberBand::StlAllocator<float> > floatbuf;
|
||||
|
||||
struct state {
|
||||
params parameters;
|
||||
int initial_phase;
|
||||
int current_phase;
|
||||
int current_channel;
|
||||
int filter_length;
|
||||
std::vector<phase_rec> phase_info;
|
||||
floatbuf phase_sorted_filter;
|
||||
floatbuf buffer;
|
||||
int left;
|
||||
int centre;
|
||||
int fill;
|
||||
state() : initial_phase(0), current_phase(0), current_channel(0),
|
||||
filter_length(0), left(0), centre(0), fill(0) { }
|
||||
};
|
||||
|
||||
state m_state_a;
|
||||
state m_state_b;
|
||||
|
||||
state *m_s; // points at either m_state_a or m_state_b
|
||||
state *m_fade; // whichever one m_s does not point to
|
||||
|
||||
int m_fade_count;
|
||||
|
||||
std::vector<double> m_prototype;
|
||||
int m_proto_length;
|
||||
bool m_initialised;
|
||||
|
||||
int gcd(int a, int b) const;
|
||||
double bessel0(double x) const;
|
||||
std::vector<double> kaiser(double beta, int len) const;
|
||||
void kaiser_params(double attenuation, double transition,
|
||||
double &beta, int &len) const;
|
||||
std::vector<double> kaiser_for(double attenuation, double transition,
|
||||
int minlen, int maxlen) const;
|
||||
void sinc_multiply(double peak_to_zero, std::vector<double> &buf) const;
|
||||
|
||||
params fill_params(double ratio, int num, int denom) const;
|
||||
params pick_params(double ratio) const;
|
||||
|
||||
std::vector<double> make_filter(int filter_length,
|
||||
double peak_to_zero) const;
|
||||
|
||||
void phase_data_for(std::vector<phase_rec> &target_phase_data,
|
||||
floatbuf &target_phase_sorted_filter,
|
||||
int filter_length,
|
||||
const std::vector<double> *filter,
|
||||
int initial_phase,
|
||||
int input_spacing,
|
||||
int output_spacing) const;
|
||||
|
||||
void state_for_ratio(state &target_state,
|
||||
double ratio,
|
||||
const state &R__ prev_state) const;
|
||||
|
||||
double reconstruct_one(state *s) const;
|
||||
|
||||
BQResampler &operator=(const BQResampler &); // not provided
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Rubber Band Library
|
||||
@@ -22,7 +22,9 @@
|
||||
*/
|
||||
|
||||
#include "Resampler.h"
|
||||
#include "base/Profiler.h"
|
||||
|
||||
#include "system/Allocators.h"
|
||||
#include "system/VectorOps.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
@@ -30,9 +32,6 @@
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "system/Allocators.h"
|
||||
#include "system/VectorOps.h"
|
||||
|
||||
#ifdef HAVE_IPP
|
||||
#include <ippversion.h>
|
||||
#if (IPP_VERSION_MAJOR < 7)
|
||||
@@ -42,6 +41,10 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SAMPLERATE
|
||||
#define HAVE_LIBSAMPLERATE 1
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBSAMPLERATE
|
||||
#include <samplerate.h>
|
||||
#endif
|
||||
@@ -51,18 +54,26 @@
|
||||
#endif
|
||||
|
||||
#ifdef USE_SPEEX
|
||||
#include "speex/speex_resampler.h"
|
||||
#include "../speex/speex_resampler.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_BQRESAMPLER
|
||||
#include "BQResampler.h"
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_IPP
|
||||
#ifndef HAVE_LIBSAMPLERATE
|
||||
#ifndef HAVE_LIBRESAMPLE
|
||||
#ifndef USE_SPEEX
|
||||
#ifndef USE_BQRESAMPLER
|
||||
#error No resampler implementation selected!
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define BQ_R__ R__
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -73,16 +84,16 @@ class Resampler::Impl
|
||||
public:
|
||||
virtual ~Impl() { }
|
||||
|
||||
virtual int resample(float *const R__ *const R__ out,
|
||||
virtual int resample(float *const BQ_R__ *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ *const R__ in,
|
||||
const float *const BQ_R__ *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final) = 0;
|
||||
|
||||
virtual int resampleInterleaved(float *const R__ out,
|
||||
virtual int resampleInterleaved(float *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ in,
|
||||
const float *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final) = 0;
|
||||
@@ -99,20 +110,21 @@ namespace Resamplers {
|
||||
class D_IPP : public Resampler::Impl
|
||||
{
|
||||
public:
|
||||
D_IPP(Resampler::Quality quality, int channels, double initialSampleRate,
|
||||
D_IPP(Resampler::Quality quality, Resampler::RatioChange,
|
||||
int channels, double initialSampleRate,
|
||||
int maxBufferSize, int debugLevel);
|
||||
~D_IPP();
|
||||
|
||||
int resample(float *const R__ *const R__ out,
|
||||
int resample(float *const BQ_R__ *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ *const R__ in,
|
||||
const float *const BQ_R__ *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final);
|
||||
|
||||
int resampleInterleaved(float *const R__ out,
|
||||
int resampleInterleaved(float *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ in,
|
||||
const float *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final = false);
|
||||
@@ -144,6 +156,7 @@ protected:
|
||||
};
|
||||
|
||||
D_IPP::D_IPP(Resampler::Quality /* quality */,
|
||||
Resampler::RatioChange /* ratioChange */,
|
||||
int channels, double initialSampleRate,
|
||||
int maxBufferSize, int debugLevel) :
|
||||
m_state(0),
|
||||
@@ -152,7 +165,7 @@ D_IPP::D_IPP(Resampler::Quality /* quality */,
|
||||
m_debugLevel(debugLevel)
|
||||
{
|
||||
if (m_debugLevel > 0) {
|
||||
cerr << "Resampler::Resampler: using IPP implementation" << endl;
|
||||
cerr << "Resampler::Resampler: using implementation: IPP" << endl;
|
||||
}
|
||||
|
||||
m_window = 32;
|
||||
@@ -190,7 +203,7 @@ D_IPP::D_IPP(Resampler::Quality /* quality */,
|
||||
setBufSize(maxBufferSize + m_history);
|
||||
|
||||
if (m_debugLevel > 1) {
|
||||
cerr << "D_IPP: bufsize = " << m_bufsize << ", window = " << m_window << ", nStep = " << nStep << ", history = " << m_history << endl;
|
||||
cerr << "bufsize = " << m_bufsize << ", window = " << m_window << ", nStep = " << nStep << ", history = " << m_history << endl;
|
||||
}
|
||||
|
||||
int specSize = 0;
|
||||
@@ -214,18 +227,13 @@ D_IPP::D_IPP(Resampler::Quality /* quality */,
|
||||
9.0f,
|
||||
m_state[c],
|
||||
hint);
|
||||
|
||||
if (m_debugLevel > 1) {
|
||||
cerr << "D_IPP: Resampler state size = " << specSize << ", allocated at "
|
||||
<< m_state[c] << endl;
|
||||
}
|
||||
|
||||
m_lastread[c] = m_history;
|
||||
m_time[c] = m_history;
|
||||
}
|
||||
|
||||
if (m_debugLevel > 1) {
|
||||
cerr << "D_IPP: Resampler init done" << endl;
|
||||
cerr << "Resampler init done" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,9 +256,9 @@ D_IPP::setBufSize(int sz)
|
||||
{
|
||||
if (m_debugLevel > 1) {
|
||||
if (m_bufsize > 0) {
|
||||
cerr << "D_IPP: resize bufsize " << m_bufsize << " -> ";
|
||||
cerr << "resize bufsize " << m_bufsize << " -> ";
|
||||
} else {
|
||||
cerr << "D_IPP: initialise bufsize to ";
|
||||
cerr << "initialise bufsize to ";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,13 +271,13 @@ D_IPP::setBufSize(int sz)
|
||||
int n1 = m_bufsize + m_history + 2;
|
||||
|
||||
if (m_debugLevel > 1) {
|
||||
cerr << "D_IPP: inbuf allocating " << m_bufsize << " + " << m_history << " + 2 = " << n1 << endl;
|
||||
cerr << "inbuf allocating " << m_bufsize << " + " << m_history << " + 2 = " << n1 << endl;
|
||||
}
|
||||
|
||||
int n2 = (int)lrintf(ceil((m_bufsize - m_history) * m_factor + 2));
|
||||
|
||||
if (m_debugLevel > 1) {
|
||||
cerr << "D_IPP: outbuf allocating (" << m_bufsize << " - " << m_history << ") * " << m_factor << " + 2 = " << n2 << endl;
|
||||
cerr << "outbuf allocating (" << m_bufsize << " - " << m_history << ") * " << m_factor << " + 2 = " << n2 << endl;
|
||||
}
|
||||
|
||||
m_inbuf = reallocate_and_zero_extend_channels
|
||||
@@ -277,30 +285,15 @@ D_IPP::setBufSize(int sz)
|
||||
|
||||
m_outbuf = reallocate_and_zero_extend_channels
|
||||
(m_outbuf, m_channels, m_outbufsz, m_channels, n2);
|
||||
|
||||
|
||||
m_inbufsz = n1;
|
||||
m_outbufsz = n2;
|
||||
|
||||
if (m_debugLevel > 2) {
|
||||
|
||||
cerr << "D_IPP: inbuf ptr = " << m_inbuf << ", channel inbufs ";
|
||||
for (int c = 0; c < m_channels; ++c) {
|
||||
cerr << m_inbuf[c] << " ";
|
||||
}
|
||||
cerr << "at " << m_inbufsz * sizeof(float) << " bytes each" << endl;
|
||||
|
||||
cerr << "D_IPP: outbuf ptr = " << m_outbuf << ", channel outbufs ";
|
||||
for (int c = 0; c < m_channels; ++c) {
|
||||
cerr << m_outbuf[c] << " ";
|
||||
}
|
||||
cerr << "at " << m_outbufsz * sizeof(float) << " bytes each" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
D_IPP::resample(float *const R__ *const R__ out,
|
||||
D_IPP::resample(float *const BQ_R__ *const BQ_R__ out,
|
||||
int outspace,
|
||||
const float *const R__ *const R__ in,
|
||||
const float *const BQ_R__ *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final)
|
||||
@@ -311,7 +304,7 @@ D_IPP::resample(float *const R__ *const R__ out,
|
||||
}
|
||||
|
||||
if (m_debugLevel > 2) {
|
||||
cerr << "D_IPP: incount = " << incount << ", ratio = " << ratio << ", est space = " << lrintf(ceil(incount * ratio)) << ", outspace = " << outspace << ", final = " << final << endl;
|
||||
cerr << "incount = " << incount << ", ratio = " << ratio << ", est space = " << lrintf(ceil(incount * ratio)) << ", outspace = " << outspace << ", final = " << final << endl;
|
||||
}
|
||||
|
||||
for (int c = 0; c < m_channels; ++c) {
|
||||
@@ -328,7 +321,7 @@ D_IPP::resample(float *const R__ *const R__ out,
|
||||
}
|
||||
|
||||
if (m_debugLevel > 2) {
|
||||
cerr << "D_IPP: lastread advanced to " << m_lastread[0] << endl;
|
||||
cerr << "lastread advanced to " << m_lastread[0] << endl;
|
||||
}
|
||||
|
||||
int got = doResample(outspace, ratio, final);
|
||||
@@ -341,9 +334,9 @@ D_IPP::resample(float *const R__ *const R__ out,
|
||||
}
|
||||
|
||||
int
|
||||
D_IPP::resampleInterleaved(float *const R__ out,
|
||||
D_IPP::resampleInterleaved(float *const BQ_R__ out,
|
||||
int outspace,
|
||||
const float *const R__ in,
|
||||
const float *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final)
|
||||
@@ -354,7 +347,7 @@ D_IPP::resampleInterleaved(float *const R__ out,
|
||||
}
|
||||
|
||||
if (m_debugLevel > 2) {
|
||||
cerr << "D_IPP: incount = " << incount << ", ratio = " << ratio << ", est space = " << lrintf(ceil(incount * ratio)) << ", outspace = " << outspace << ", final = " << final << endl;
|
||||
cerr << "incount = " << incount << ", ratio = " << ratio << ", est space = " << lrintf(ceil(incount * ratio)) << ", outspace = " << outspace << ", final = " << final << endl;
|
||||
}
|
||||
|
||||
for (int c = 0; c < m_channels; ++c) {
|
||||
@@ -371,7 +364,7 @@ D_IPP::resampleInterleaved(float *const R__ out,
|
||||
}
|
||||
|
||||
if (m_debugLevel > 2) {
|
||||
cerr << "D_IPP: lastread advanced to " << m_lastread[0] << " after injection of "
|
||||
cerr << "lastread advanced to " << m_lastread[0] << " after injection of "
|
||||
<< incount << " samples" << endl;
|
||||
}
|
||||
|
||||
@@ -392,20 +385,20 @@ D_IPP::doResample(int outspace, double ratio, bool final)
|
||||
int n = m_lastread[c] - m_history - int(m_time[c]);
|
||||
|
||||
if (c == 0 && m_debugLevel > 2) {
|
||||
cerr << "D_IPP: at start, lastread = " << m_lastread[c] << ", history = "
|
||||
cerr << "at start, lastread = " << m_lastread[c] << ", history = "
|
||||
<< m_history << ", time = " << m_time[c] << ", therefore n = "
|
||||
<< n << endl;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
if (c == 0 && m_debugLevel > 1) {
|
||||
cerr << "D_IPP: not enough input samples to do anything" << endl;
|
||||
cerr << "not enough input samples to do anything" << endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == 0 && m_debugLevel > 2) {
|
||||
cerr << "D_IPP: before resample call, time = " << m_time[c] << endl;
|
||||
cerr << "before resample call, time = " << m_time[c] << endl;
|
||||
}
|
||||
|
||||
// We're committed to not overrunning outspace, so we need to
|
||||
@@ -414,7 +407,7 @@ D_IPP::doResample(int outspace, double ratio, bool final)
|
||||
int limit = int(floor(outspace / ratio));
|
||||
if (n > limit) {
|
||||
if (c == 0 && m_debugLevel > 1) {
|
||||
cerr << "D_IPP: trimming input samples from " << n << " to " << limit
|
||||
cerr << "trimming input samples from " << n << " to " << limit
|
||||
<< " to avoid overrunning " << outspace << " at output"
|
||||
<< endl;
|
||||
}
|
||||
@@ -431,26 +424,26 @@ D_IPP::doResample(int outspace, double ratio, bool final)
|
||||
m_state[c]);
|
||||
|
||||
int t = int(floor(m_time[c]));
|
||||
|
||||
|
||||
int moveFrom = t - m_history;
|
||||
|
||||
|
||||
if (c == 0 && m_debugLevel > 2) {
|
||||
cerr << "D_IPP: converted " << n << " samples to " << outcount
|
||||
cerr << "converted " << n << " samples to " << outcount
|
||||
<< " (nb outbufsz = " << m_outbufsz
|
||||
<< "), time advanced to " << m_time[c] << endl;
|
||||
cerr << "D_IPP: rounding time to " << t << ", lastread = "
|
||||
cerr << "rounding time to " << t << ", lastread = "
|
||||
<< m_lastread[c] << ", history = " << m_history << endl;
|
||||
cerr << "D_IPP: will move " << m_lastread[c] - moveFrom
|
||||
cerr << "will move " << m_lastread[c] - moveFrom
|
||||
<< " unconverted samples back from index " << moveFrom
|
||||
<< " to 0" << endl;
|
||||
}
|
||||
|
||||
|
||||
if (moveFrom >= m_lastread[c]) {
|
||||
|
||||
moveFrom = m_lastread[c];
|
||||
|
||||
if (c == 0 && m_debugLevel > 2) {
|
||||
cerr << "D_IPP: number of samples to move is <= 0, "
|
||||
cerr << "number of samples to move is <= 0, "
|
||||
<< "not actually moving any" << endl;
|
||||
}
|
||||
} else {
|
||||
@@ -464,7 +457,7 @@ D_IPP::doResample(int outspace, double ratio, bool final)
|
||||
m_time[c] -= moveFrom;
|
||||
|
||||
if (c == 0 && m_debugLevel > 2) {
|
||||
cerr << "D_IPP: lastread reduced to " << m_lastread[c]
|
||||
cerr << "lastread reduced to " << m_lastread[c]
|
||||
<< ", time reduced to " << m_time[c]
|
||||
<< endl;
|
||||
}
|
||||
@@ -483,7 +476,7 @@ D_IPP::doResample(int outspace, double ratio, bool final)
|
||||
int additionalcount = 0;
|
||||
|
||||
if (c == 0 && m_debugLevel > 2) {
|
||||
cerr << "D_IPP: final call, padding input with " << m_history
|
||||
cerr << "final call, padding input with " << m_history
|
||||
<< " zeros (symmetrical with m_history)" << endl;
|
||||
}
|
||||
|
||||
@@ -492,14 +485,14 @@ D_IPP::doResample(int outspace, double ratio, bool final)
|
||||
}
|
||||
|
||||
if (c == 0 && m_debugLevel > 2) {
|
||||
cerr << "D_IPP: before resample call, time = " << m_time[c] << endl;
|
||||
cerr << "before resample call, time = " << m_time[c] << endl;
|
||||
}
|
||||
|
||||
int nAdditional = m_lastread[c] - int(m_time[c]);
|
||||
|
||||
if (n + nAdditional > limit) {
|
||||
if (c == 0 && m_debugLevel > 1) {
|
||||
cerr << "D_IPP: trimming final input samples from " << nAdditional
|
||||
cerr << "trimming final input samples from " << nAdditional
|
||||
<< " to " << (limit - n)
|
||||
<< " to avoid overrunning " << outspace << " at output"
|
||||
<< endl;
|
||||
@@ -517,9 +510,9 @@ D_IPP::doResample(int outspace, double ratio, bool final)
|
||||
m_state[c]);
|
||||
|
||||
if (c == 0 && m_debugLevel > 2) {
|
||||
cerr << "D_IPP: converted " << n << " samples to " << additionalcount
|
||||
cerr << "converted " << n << " samples to " << additionalcount
|
||||
<< ", time advanced to " << m_time[c] << endl;
|
||||
cerr << "D_IPP: outcount = " << outcount << ", additionalcount = " << additionalcount << ", sum " << outcount + additionalcount << endl;
|
||||
cerr << "outcount = " << outcount << ", additionalcount = " << additionalcount << ", sum " << outcount + additionalcount << endl;
|
||||
}
|
||||
|
||||
if (c == 0) {
|
||||
@@ -529,7 +522,7 @@ D_IPP::doResample(int outspace, double ratio, bool final)
|
||||
}
|
||||
|
||||
if (m_debugLevel > 2) {
|
||||
cerr << "D_IPP: returning " << outcount << " samples" << endl;
|
||||
cerr << "returning " << outcount << " samples" << endl;
|
||||
}
|
||||
|
||||
return outcount;
|
||||
@@ -548,20 +541,21 @@ D_IPP::reset()
|
||||
class D_SRC : public Resampler::Impl
|
||||
{
|
||||
public:
|
||||
D_SRC(Resampler::Quality quality, int channels, double initialSampleRate,
|
||||
D_SRC(Resampler::Quality quality, Resampler::RatioChange ratioChange,
|
||||
int channels, double initialSampleRate,
|
||||
int maxBufferSize, int m_debugLevel);
|
||||
~D_SRC();
|
||||
|
||||
int resample(float *const R__ *const R__ out,
|
||||
int resample(float *const BQ_R__ *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ *const R__ in,
|
||||
const float *const BQ_R__ *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final);
|
||||
|
||||
int resampleInterleaved(float *const R__ out,
|
||||
int resampleInterleaved(float *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ in,
|
||||
const float *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final = false);
|
||||
@@ -579,11 +573,12 @@ protected:
|
||||
int m_ioutsize;
|
||||
double m_prevRatio;
|
||||
bool m_ratioUnset;
|
||||
bool m_smoothRatios;
|
||||
int m_debugLevel;
|
||||
};
|
||||
|
||||
D_SRC::D_SRC(Resampler::Quality quality, int channels, double,
|
||||
int maxBufferSize, int debugLevel) :
|
||||
D_SRC::D_SRC(Resampler::Quality quality, Resampler::RatioChange ratioChange,
|
||||
int channels, double, int maxBufferSize, int debugLevel) :
|
||||
m_src(0),
|
||||
m_iin(0),
|
||||
m_iout(0),
|
||||
@@ -592,25 +587,41 @@ D_SRC::D_SRC(Resampler::Quality quality, int channels, double,
|
||||
m_ioutsize(0),
|
||||
m_prevRatio(1.0),
|
||||
m_ratioUnset(true),
|
||||
m_smoothRatios(ratioChange == Resampler::SmoothRatioChange),
|
||||
m_debugLevel(debugLevel)
|
||||
{
|
||||
if (m_debugLevel > 0) {
|
||||
cerr << "Resampler::Resampler: using libsamplerate implementation"
|
||||
<< endl;
|
||||
cerr << "Resampler::Resampler: using implementation: libsamplerate"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
if (channels < 1) {
|
||||
cerr << "Resampler::Resampler: unable to create resampler: invalid channel count " << channels << " supplied" << endl;
|
||||
#ifdef NO_EXCEPTIONS
|
||||
throw Resampler::ImplementationError;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
int err = 0;
|
||||
m_src = src_new(quality == Resampler::Best ? SRC_SINC_BEST_QUALITY :
|
||||
quality == Resampler::Fastest ? SRC_LINEAR :
|
||||
SRC_SINC_FASTEST,
|
||||
quality == Resampler::Fastest ? SRC_SINC_FASTEST :
|
||||
SRC_SINC_MEDIUM_QUALITY,
|
||||
channels, &err);
|
||||
|
||||
if (err) {
|
||||
cerr << "Resampler::Resampler: failed to create libsamplerate resampler: "
|
||||
<< src_strerror(err) << endl;
|
||||
<< src_strerror(err) << endl;
|
||||
#ifndef NO_EXCEPTIONS
|
||||
throw Resampler::ImplementationError;
|
||||
#endif
|
||||
return;
|
||||
} else if (!m_src) {
|
||||
cerr << "Resampler::Resampler: failed to create libsamplerate resampler, but no error reported?" << endl;
|
||||
#ifndef NO_EXCEPTIONS
|
||||
throw Resampler::ImplementationError;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (maxBufferSize > 0 && m_channels > 1) {
|
||||
@@ -631,9 +642,9 @@ D_SRC::~D_SRC()
|
||||
}
|
||||
|
||||
int
|
||||
D_SRC::resample(float *const R__ *const R__ out,
|
||||
D_SRC::resample(float *const BQ_R__ *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ *const R__ in,
|
||||
const float *const BQ_R__ *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final)
|
||||
@@ -661,15 +672,15 @@ D_SRC::resample(float *const R__ *const R__ out,
|
||||
}
|
||||
|
||||
int
|
||||
D_SRC::resampleInterleaved(float *const R__ out,
|
||||
D_SRC::resampleInterleaved(float *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ in,
|
||||
const float *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final)
|
||||
{
|
||||
SRC_DATA data;
|
||||
|
||||
|
||||
// libsamplerate smooths the filter change over the duration of
|
||||
// the processing block to avoid artifacts due to sudden changes,
|
||||
// and it uses outcount to determine how long to smooth the change
|
||||
@@ -682,7 +693,7 @@ D_SRC::resampleInterleaved(float *const R__ out,
|
||||
outcount = int(ceil(incount * ratio) + 5);
|
||||
}
|
||||
|
||||
if (m_ratioUnset) {
|
||||
if (m_ratioUnset || !m_smoothRatios) {
|
||||
|
||||
// The first time we set a ratio, we want to do it directly
|
||||
src_set_ratio(m_src, ratio);
|
||||
@@ -724,10 +735,9 @@ D_SRC::resampleInterleaved(float *const R__ out,
|
||||
|
||||
data.input_frames = incount;
|
||||
data.output_frames = outcount;
|
||||
|
||||
data.src_ratio = ratio;
|
||||
data.end_of_input = (final ? 1 : 0);
|
||||
|
||||
|
||||
int err = src_process(m_src, &data);
|
||||
|
||||
if (err) {
|
||||
@@ -737,7 +747,7 @@ D_SRC::resampleInterleaved(float *const R__ out,
|
||||
throw Resampler::ImplementationError;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
return (int)data.output_frames_gen;
|
||||
}
|
||||
|
||||
@@ -755,20 +765,21 @@ D_SRC::reset()
|
||||
class D_Resample : public Resampler::Impl
|
||||
{
|
||||
public:
|
||||
D_Resample(Resampler::Quality quality, int channels, double initialSampleRate,
|
||||
D_Resample(Resampler::Quality quality, Resampler::RatioChange,
|
||||
int channels, double initialSampleRate,
|
||||
int maxBufferSize, int m_debugLevel);
|
||||
~D_Resample();
|
||||
|
||||
int resample(float *const R__ *const R__ out,
|
||||
int resample(float *const BQ_R__ *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ *const R__ in,
|
||||
const float *const BQ_R__ *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final);
|
||||
|
||||
int resampleInterleaved(float *const R__ out,
|
||||
int resampleInterleaved(float *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ in,
|
||||
const float *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final);
|
||||
@@ -799,7 +810,7 @@ D_Resample::D_Resample(Resampler::Quality quality,
|
||||
m_debugLevel(debugLevel)
|
||||
{
|
||||
if (m_debugLevel > 0) {
|
||||
cerr << "Resampler::Resampler: using libresample implementation"
|
||||
cerr << "Resampler::Resampler: using implementation: libresample"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
@@ -836,9 +847,9 @@ D_Resample::~D_Resample()
|
||||
}
|
||||
|
||||
int
|
||||
D_Resample::resample(float *const R__ *const R__ out,
|
||||
D_Resample::resample(float *const BQ_R__ *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ *const R__ in,
|
||||
const float *const BQ_R__ *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final)
|
||||
@@ -895,9 +906,9 @@ D_Resample::resample(float *const R__ *const R__ out,
|
||||
}
|
||||
|
||||
int
|
||||
D_Resample::resampleInterleaved(float *const R__ out,
|
||||
D_Resample::resampleInterleaved(float *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ in,
|
||||
const float *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final)
|
||||
@@ -937,25 +948,174 @@ D_Resample::reset()
|
||||
|
||||
#endif /* HAVE_LIBRESAMPLE */
|
||||
|
||||
#ifdef USE_BQRESAMPLER
|
||||
|
||||
class D_BQResampler : public Resampler::Impl
|
||||
{
|
||||
public:
|
||||
D_BQResampler(Resampler::Parameters params, int channels);
|
||||
~D_BQResampler();
|
||||
|
||||
int resample(float *const BQ_R__ *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const BQ_R__ *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final);
|
||||
|
||||
int resampleInterleaved(float *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final = false);
|
||||
|
||||
int getChannelCount() const { return m_channels; }
|
||||
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
BQResampler *m_resampler;
|
||||
float *m_iin;
|
||||
float *m_iout;
|
||||
int m_channels;
|
||||
int m_iinsize;
|
||||
int m_ioutsize;
|
||||
int m_debugLevel;
|
||||
};
|
||||
|
||||
D_BQResampler::D_BQResampler(Resampler::Parameters params, int channels) :
|
||||
m_resampler(0),
|
||||
m_iin(0),
|
||||
m_iout(0),
|
||||
m_channels(channels),
|
||||
m_iinsize(0),
|
||||
m_ioutsize(0),
|
||||
m_debugLevel(params.debugLevel)
|
||||
{
|
||||
if (m_debugLevel > 0) {
|
||||
cerr << "Resampler::Resampler: using implementation: BQResampler" << endl;
|
||||
}
|
||||
|
||||
BQResampler::Parameters rparams;
|
||||
switch (params.quality) {
|
||||
case Resampler::Best:
|
||||
rparams.quality = BQResampler::Best;
|
||||
break;
|
||||
case Resampler::FastestTolerable:
|
||||
rparams.quality = BQResampler::FastestTolerable;
|
||||
break;
|
||||
case Resampler::Fastest:
|
||||
rparams.quality = BQResampler::Fastest;
|
||||
break;
|
||||
}
|
||||
switch (params.dynamism) {
|
||||
case Resampler::RatioOftenChanging:
|
||||
rparams.dynamism = BQResampler::RatioOftenChanging;
|
||||
break;
|
||||
case Resampler::RatioMostlyFixed:
|
||||
rparams.dynamism = BQResampler::RatioMostlyFixed;
|
||||
break;
|
||||
}
|
||||
switch (params.ratioChange) {
|
||||
case Resampler::SmoothRatioChange:
|
||||
rparams.ratioChange = BQResampler::SmoothRatioChange;
|
||||
break;
|
||||
case Resampler::SuddenRatioChange:
|
||||
rparams.ratioChange = BQResampler::SuddenRatioChange;
|
||||
break;
|
||||
}
|
||||
rparams.referenceSampleRate = params.initialSampleRate;
|
||||
rparams.debugLevel = params.debugLevel;
|
||||
|
||||
m_resampler = new BQResampler(rparams, m_channels);
|
||||
|
||||
if (params.maxBufferSize > 0 && m_channels > 1) {
|
||||
m_iinsize = params.maxBufferSize * m_channels;
|
||||
m_ioutsize = params.maxBufferSize * m_channels * 2;
|
||||
m_iin = allocate<float>(m_iinsize);
|
||||
m_iout = allocate<float>(m_ioutsize);
|
||||
}
|
||||
}
|
||||
|
||||
D_BQResampler::~D_BQResampler()
|
||||
{
|
||||
delete m_resampler;
|
||||
deallocate(m_iin);
|
||||
deallocate(m_iout);
|
||||
}
|
||||
|
||||
int
|
||||
D_BQResampler::resample(float *const BQ_R__ *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const BQ_R__ *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final)
|
||||
{
|
||||
if (m_channels == 1) {
|
||||
return resampleInterleaved(*out, outcount, *in, incount, ratio, final);
|
||||
}
|
||||
|
||||
if (incount * m_channels > m_iinsize) {
|
||||
m_iin = reallocate<float>(m_iin, m_iinsize, incount * m_channels);
|
||||
m_iinsize = incount * m_channels;
|
||||
}
|
||||
if (outcount * m_channels > m_ioutsize) {
|
||||
m_iout = reallocate<float>(m_iout, m_ioutsize, outcount * m_channels);
|
||||
m_ioutsize = outcount * m_channels;
|
||||
}
|
||||
|
||||
v_interleave(m_iin, in, m_channels, incount);
|
||||
|
||||
int n = resampleInterleaved(m_iout, outcount, m_iin, incount, ratio, final);
|
||||
|
||||
v_deinterleave(out, m_iout, m_channels, n);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
D_BQResampler::resampleInterleaved(float *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final)
|
||||
{
|
||||
return m_resampler->resampleInterleaved(out, outcount,
|
||||
in, incount,
|
||||
ratio, final);
|
||||
}
|
||||
|
||||
void
|
||||
D_BQResampler::reset()
|
||||
{
|
||||
m_resampler->reset();
|
||||
}
|
||||
|
||||
#endif /* USE_BQRESAMPLER */
|
||||
|
||||
#ifdef USE_SPEEX
|
||||
|
||||
class D_Speex : public Resampler::Impl
|
||||
{
|
||||
public:
|
||||
D_Speex(Resampler::Quality quality, int channels, double initialSampleRate,
|
||||
D_Speex(Resampler::Quality quality, Resampler::RatioChange,
|
||||
int channels, double initialSampleRate,
|
||||
int maxBufferSize, int debugLevel);
|
||||
~D_Speex();
|
||||
|
||||
int resample(float *const R__ *const R__ out,
|
||||
int resample(float *const BQ_R__ *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ *const R__ in,
|
||||
const float *const BQ_R__ *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final);
|
||||
|
||||
int resampleInterleaved(float *const R__ out,
|
||||
int resampleInterleaved(float *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ in,
|
||||
const float *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final = false);
|
||||
@@ -982,7 +1142,7 @@ protected:
|
||||
double ratio, bool final);
|
||||
};
|
||||
|
||||
D_Speex::D_Speex(Resampler::Quality quality,
|
||||
D_Speex::D_Speex(Resampler::Quality quality, Resampler::RatioChange,
|
||||
int channels, double initialSampleRate,
|
||||
int maxBufferSize, int debugLevel) :
|
||||
m_resampler(0),
|
||||
@@ -1000,7 +1160,7 @@ D_Speex::D_Speex(Resampler::Quality quality,
|
||||
quality == Resampler::Fastest ? 0 : 4);
|
||||
|
||||
if (m_debugLevel > 0) {
|
||||
cerr << "Resampler::Resampler: using Speex implementation with q = "
|
||||
cerr << "Resampler::Resampler: using implementation: Speex with q = "
|
||||
<< q << endl;
|
||||
}
|
||||
|
||||
@@ -1093,9 +1253,9 @@ D_Speex::setRatio(double ratio)
|
||||
}
|
||||
|
||||
int
|
||||
D_Speex::resample(float *const R__ *const R__ out,
|
||||
D_Speex::resample(float *const BQ_R__ *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ *const R__ in,
|
||||
const float *const BQ_R__ *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final)
|
||||
@@ -1136,9 +1296,9 @@ D_Speex::resample(float *const R__ *const R__ out,
|
||||
}
|
||||
|
||||
int
|
||||
D_Speex::resampleInterleaved(float *const R__ out,
|
||||
D_Speex::resampleInterleaved(float *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ in,
|
||||
const float *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final)
|
||||
@@ -1236,6 +1396,9 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
|
||||
#ifdef HAVE_LIBRESAMPLE
|
||||
m_method = 3;
|
||||
#endif
|
||||
#ifdef USE_BQRESAMPLER
|
||||
m_method = 4;
|
||||
#endif
|
||||
#ifdef HAVE_LIBSAMPLERATE
|
||||
m_method = 1;
|
||||
#endif
|
||||
@@ -1251,6 +1414,9 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
|
||||
#ifdef USE_SPEEX
|
||||
m_method = 2;
|
||||
#endif
|
||||
#ifdef USE_BQRESAMPLER
|
||||
m_method = 4;
|
||||
#endif
|
||||
#ifdef HAVE_LIBSAMPLERATE
|
||||
m_method = 1;
|
||||
#endif
|
||||
@@ -1266,6 +1432,9 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
|
||||
#ifdef USE_SPEEX
|
||||
m_method = 2;
|
||||
#endif
|
||||
#ifdef USE_BQRESAMPLER
|
||||
m_method = 4;
|
||||
#endif
|
||||
#ifdef HAVE_LIBSAMPLERATE
|
||||
m_method = 1;
|
||||
#endif
|
||||
@@ -1281,7 +1450,7 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
|
||||
case 0:
|
||||
#ifdef HAVE_IPP
|
||||
d = new Resamplers::D_IPP
|
||||
(params.quality,
|
||||
(params.quality, params.ratioChange,
|
||||
channels,
|
||||
params.initialSampleRate, params.maxBufferSize, params.debugLevel);
|
||||
#else
|
||||
@@ -1293,7 +1462,7 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
|
||||
case 1:
|
||||
#ifdef HAVE_LIBSAMPLERATE
|
||||
d = new Resamplers::D_SRC
|
||||
(params.quality,
|
||||
(params.quality, params.ratioChange,
|
||||
channels,
|
||||
params.initialSampleRate, params.maxBufferSize, params.debugLevel);
|
||||
#else
|
||||
@@ -1305,7 +1474,7 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
|
||||
case 2:
|
||||
#ifdef USE_SPEEX
|
||||
d = new Resamplers::D_Speex
|
||||
(params.quality,
|
||||
(params.quality, params.ratioChange,
|
||||
channels,
|
||||
params.initialSampleRate, params.maxBufferSize, params.debugLevel);
|
||||
#else
|
||||
@@ -1317,12 +1486,21 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
|
||||
case 3:
|
||||
#ifdef HAVE_LIBRESAMPLE
|
||||
d = new Resamplers::D_Resample
|
||||
(params.quality,
|
||||
(params.quality, params.ratioChange,
|
||||
channels,
|
||||
params.initialSampleRate, params.maxBufferSize, params.debugLevel);
|
||||
#else
|
||||
cerr << "Resampler::Resampler: No implementation available!" << endl;
|
||||
abort();
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 4:
|
||||
#ifdef USE_BQRESAMPLER
|
||||
d = new Resamplers::D_BQResampler(params, channels);
|
||||
#else
|
||||
cerr << "Resampler::Resampler: No implementation available!" << endl;
|
||||
abort();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -1340,26 +1518,24 @@ Resampler::~Resampler()
|
||||
}
|
||||
|
||||
int
|
||||
Resampler::resample(float *const R__ *const R__ out,
|
||||
Resampler::resample(float *const BQ_R__ *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ *const R__ in,
|
||||
const float *const BQ_R__ *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final)
|
||||
{
|
||||
Profiler profiler("Resampler::resample");
|
||||
return d->resample(out, outcount, in, incount, ratio, final);
|
||||
}
|
||||
|
||||
int
|
||||
Resampler::resampleInterleaved(float *const R__ out,
|
||||
Resampler::resampleInterleaved(float *const BQ_R__ out,
|
||||
int outcount,
|
||||
const float *const R__ in,
|
||||
const float *const BQ_R__ in,
|
||||
int incount,
|
||||
double ratio,
|
||||
bool final)
|
||||
{
|
||||
Profiler profiler("Resampler::resampleInterleaved");
|
||||
return d->resampleInterleaved(out, outcount, in, incount, ratio, final);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
//* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Rubber Band Library
|
||||
@@ -32,6 +32,9 @@ class Resampler
|
||||
{
|
||||
public:
|
||||
enum Quality { Best, FastestTolerable, Fastest };
|
||||
enum Dynamism { RatioOftenChanging, RatioMostlyFixed };
|
||||
enum RatioChange { SmoothRatioChange, SuddenRatioChange };
|
||||
|
||||
enum Exception { ImplementationError };
|
||||
|
||||
struct Parameters {
|
||||
@@ -41,6 +44,22 @@ public:
|
||||
*/
|
||||
Quality quality;
|
||||
|
||||
/**
|
||||
* Performance hint indicating whether the ratio is expected
|
||||
* to change regularly or not. If not, more work may happen on
|
||||
* ratio changes to reduce work when ratio is unchanged.
|
||||
*/
|
||||
Dynamism dynamism;
|
||||
|
||||
/**
|
||||
* Hint indicating whether to smooth transitions, via filter
|
||||
* interpolation or some such method, at ratio change
|
||||
* boundaries, or whether to make a precise switch to the new
|
||||
* ratio without regard to audible artifacts. The actual
|
||||
* effect of this depends on the implementation in use.
|
||||
*/
|
||||
RatioChange ratioChange;
|
||||
|
||||
/**
|
||||
* Rate of expected input prior to resampling: may be used to
|
||||
* determine the filter bandwidth for the quality setting. If
|
||||
@@ -67,6 +86,8 @@ public:
|
||||
|
||||
Parameters() :
|
||||
quality(FastestTolerable),
|
||||
dynamism(RatioMostlyFixed),
|
||||
ratioChange(SmoothRatioChange),
|
||||
initialSampleRate(44100),
|
||||
maxBufferSize(0),
|
||||
debugLevel(0) { }
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include <new> // for std::bad_alloc
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#ifndef HAVE_POSIX_MEMALIGN
|
||||
#ifndef _WIN32
|
||||
#ifndef __APPLE__
|
||||
@@ -309,6 +311,96 @@ private:
|
||||
T *m_t;
|
||||
};
|
||||
|
||||
/** Allocator for use with STL classes, e.g. vector, to ensure
|
||||
* alignment. Based on example code by Stephan T. Lavavej.
|
||||
*
|
||||
* e.g. std::vector<float, StlAllocator<float> > v;
|
||||
*/
|
||||
template <typename T>
|
||||
class StlAllocator
|
||||
{
|
||||
public:
|
||||
typedef T *pointer;
|
||||
typedef const T *const_pointer;
|
||||
typedef T &reference;
|
||||
typedef const T &const_reference;
|
||||
typedef T value_type;
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
StlAllocator() { }
|
||||
StlAllocator(const StlAllocator&) { }
|
||||
template <typename U> StlAllocator(const StlAllocator<U>&) { }
|
||||
~StlAllocator() { }
|
||||
|
||||
T *
|
||||
allocate(const size_t n) const {
|
||||
if (n == 0) return 0;
|
||||
if (n > max_size()) {
|
||||
#ifndef NO_EXCEPTIONS
|
||||
throw std::length_error("Size overflow in StlAllocator::allocate()");
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
return ::RubberBand::allocate<T>(n);
|
||||
}
|
||||
|
||||
void
|
||||
deallocate(T *const p, const size_t) const {
|
||||
::RubberBand::deallocate(p);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
T *
|
||||
allocate(const size_t n, const U *) const {
|
||||
return allocate(n);
|
||||
}
|
||||
|
||||
T *
|
||||
address(T &r) const {
|
||||
return &r;
|
||||
}
|
||||
|
||||
const T *
|
||||
address(const T &s) const {
|
||||
return &s;
|
||||
}
|
||||
|
||||
size_t
|
||||
max_size() const {
|
||||
return (static_cast<size_t>(0) - static_cast<size_t>(1)) / sizeof(T);
|
||||
}
|
||||
|
||||
template <typename U> struct rebind {
|
||||
typedef StlAllocator<U> other;
|
||||
};
|
||||
|
||||
bool
|
||||
operator==(const StlAllocator &) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(const StlAllocator &) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
construct(T *const p, const T &t) const {
|
||||
void *const pv = static_cast<void *>(p);
|
||||
new (pv) T(t);
|
||||
}
|
||||
|
||||
void
|
||||
destroy(T *const p) const {
|
||||
p->~T();
|
||||
}
|
||||
|
||||
private:
|
||||
StlAllocator& operator=(const StlAllocator&);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -491,6 +491,58 @@ inline T v_sum(const T *const R__ src,
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T v_multiply_and_sum(const T *const R__ src1,
|
||||
const T *const R__ src2,
|
||||
const int count)
|
||||
{
|
||||
T result = T();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
result += src1[i] * src2[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined HAVE_IPP
|
||||
template<>
|
||||
inline float v_multiply_and_sum(const float *const R__ src1,
|
||||
const float *const R__ src2,
|
||||
const int count)
|
||||
{
|
||||
float dp;
|
||||
ippsDotProd_32f(src1, src2, count, &dp);
|
||||
return dp;
|
||||
}
|
||||
template<>
|
||||
inline double v_multiply_and_sum(const double *const R__ src1,
|
||||
const double *const R__ src2,
|
||||
const int count)
|
||||
{
|
||||
double dp;
|
||||
ippsDotProd_64f(src1, src2, count, &dp);
|
||||
return dp;
|
||||
}
|
||||
#elif defined HAVE_VDSP
|
||||
template<>
|
||||
inline float v_multiply_and_sum(const float *const R__ src1,
|
||||
const float *const R__ src2,
|
||||
const int count)
|
||||
{
|
||||
float dp;
|
||||
vDSP_dotpr(src1, 1, src2, 1, &dp, count);
|
||||
return dp;
|
||||
}
|
||||
template<>
|
||||
inline double v_multiply_and_sum(const double *const R__ src1,
|
||||
const double *const R__ src2,
|
||||
const int count)
|
||||
{
|
||||
double dp;
|
||||
vDSP_dotprD(src1, 1, src2, 1, &dp, count);
|
||||
return dp;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
inline void v_log(T *const R__ dst,
|
||||
const int count)
|
||||
|
||||
Reference in New Issue
Block a user