You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
5.3 KiB
157 lines
5.3 KiB
/* aKode Resampler (fast)
|
|
|
|
Copyright (C) 2004 Allan Sandfeld Jensen <kde@carewolf.com>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "audioframe.h"
|
|
#include "arithmetic.h"
|
|
#include "fast_resampler.h"
|
|
|
|
#define FR_FIDELITY (1<<10)
|
|
|
|
namespace aKode {
|
|
|
|
FastResampler* FastResamplerPlugin::openResampler() {
|
|
return new FastResampler();
|
|
}
|
|
|
|
extern "C" { FastResamplerPlugin fast_resampler; }
|
|
|
|
FastResampler::FastResampler() : speed(1.0), sample_rate(44100) {}
|
|
|
|
// A fast resampling by linear interpolation
|
|
// I assume you know binary arithmetics and convertions if you're reading this
|
|
// T is the input/output type, Arithm defines the used arithmetic
|
|
template<typename T, typename S, template<typename S_Type> class Arithm>
|
|
static bool _doBuffer(AudioFrame* in, AudioFrame* out, float speed, unsigned sample_rate)
|
|
{
|
|
unsigned long vt_pos_start = 0; // virtual positions of new sample
|
|
unsigned long vt_pos_end;;
|
|
unsigned long real_pos_start, real_pos_end;
|
|
long start_fraction, end_fraction;
|
|
|
|
unsigned long vt_end = in->length * 1024 -1;
|
|
|
|
int int_speed;
|
|
unsigned long out_length;
|
|
{
|
|
float resample_speed = in->sample_rate/(float)sample_rate;
|
|
resample_speed *= speed;
|
|
int_speed = (unsigned int)(resample_speed*1024.0+0.5);
|
|
|
|
out_length = (in->length/int_speed)*1024;
|
|
unsigned long out_rem = (in->length%int_speed)*1024 + (int_speed-1);
|
|
out_length += out_rem/int_speed;
|
|
|
|
out->reserveSpace(in, out_length);
|
|
out->sample_rate = sample_rate;
|
|
}
|
|
vt_pos_end = int_speed;
|
|
|
|
unsigned char channels = in->channels; // take copy to reduce alias-induced reads
|
|
unsigned long out_pos = 0;
|
|
|
|
T** indata = (T**)in->data; // templating ;)
|
|
T** outdata = (T**)out->data;
|
|
|
|
S sspeed = (S)int_speed;
|
|
S smax = Arithm<S>::max(in->sample_width);
|
|
|
|
while(out_pos < out_length && vt_pos_start < vt_end) {
|
|
real_pos_start = vt_pos_start / 1024; start_fraction = vt_pos_start % 1024;
|
|
real_pos_end = vt_pos_end / 1024; end_fraction = vt_pos_end % 1024;
|
|
|
|
if (real_pos_start == real_pos_end) {
|
|
for(int i=0; i<channels; i++) {
|
|
outdata[i][out_pos] = indata[i][real_pos_start];
|
|
}
|
|
} else {
|
|
for(int i=0; i<channels; i++) {
|
|
S signal = 0;
|
|
S remainder = 0;
|
|
S temp;
|
|
|
|
// add fraction from starting sample
|
|
temp = (S)indata[i][real_pos_start];
|
|
signal += Arithm<S>::div(temp,sspeed) * (1024L-start_fraction);
|
|
remainder += Arithm<S>::rem(temp,sspeed) * (1024L-start_fraction);
|
|
|
|
// add fraction from end sample
|
|
temp= (S)indata[i][real_pos_end];
|
|
signal += Arithm<S>::div(temp,sspeed) * (end_fraction);
|
|
remainder += Arithm<S>::rem(temp,sspeed) * (end_fraction);
|
|
|
|
// add all intermediate samples
|
|
for(unsigned long j = real_pos_start+1; j<real_pos_end; j++) {
|
|
temp= (S)indata[i][j];
|
|
signal += Arithm<S>::div(temp,sspeed) * 1024L;
|
|
remainder += Arithm<S>::rem(temp,sspeed) * 1024L;
|
|
}
|
|
|
|
// add accummulated remainder
|
|
signal += Arithm<S>::div(remainder,sspeed);
|
|
|
|
// clip to maximum, just to be safe
|
|
if (signal > smax) signal = smax;
|
|
else
|
|
if (signal < -smax) signal = -smax;
|
|
|
|
outdata[i][out_pos] = (T)signal;
|
|
}
|
|
}
|
|
out_pos++;
|
|
vt_pos_start = vt_pos_end;
|
|
vt_pos_end += int_speed;
|
|
if (vt_pos_end > vt_end) vt_pos_end = vt_end;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool FastResampler::doFrame(AudioFrame* in, AudioFrame* out)
|
|
{
|
|
if (speed == 1.0 && in->sample_rate == sample_rate) {
|
|
swapFrames(out, in);
|
|
return true;
|
|
}
|
|
if (in->sample_width < 0) {
|
|
return _doBuffer<float, float, Arithm_FP>(in, out, speed, sample_rate);
|
|
} else
|
|
if (in->sample_width <= 8) {
|
|
return _doBuffer<int8_t, int32_t, Arithm_Int>(in, out, speed, sample_rate);
|
|
} else
|
|
if (in->sample_width <= 16) {
|
|
return _doBuffer<int16_t, int32_t, Arithm_Int>(in, out, speed, sample_rate);
|
|
} else
|
|
if (in->sample_width <= 24) {
|
|
return _doBuffer<int32_t, int32_t, Arithm_Int>(in, out, speed, sample_rate);
|
|
} else
|
|
return _doBuffer<int32_t, int64_t, Arithm_Int>(in, out, speed, sample_rate);
|
|
}
|
|
|
|
void FastResampler::setSpeed(float _speed)
|
|
{
|
|
speed = _speed;
|
|
}
|
|
|
|
void FastResampler::setSampleRate(unsigned int rate)
|
|
{
|
|
sample_rate = rate;
|
|
}
|
|
|
|
} // namespace
|