/* aKode Resampler (fast) Copyright (C) 2004 Allan Sandfeld Jensen 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 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::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::div(temp,sspeed) * (1024L-start_fraction); remainder += Arithm::rem(temp,sspeed) * (1024L-start_fraction); // add fraction from end sample temp= (S)indata[i][real_pos_end]; signal += Arithm::div(temp,sspeed) * (end_fraction); remainder += Arithm::rem(temp,sspeed) * (end_fraction); // add all intermediate samples for(unsigned long j = real_pos_start+1; j::div(temp,sspeed) * 1024L; remainder += Arithm::rem(temp,sspeed) * 1024L; } // add accummulated remainder signal += Arithm::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(in, out, speed, sample_rate); } else if (in->sample_width <= 8) { return _doBuffer(in, out, speed, sample_rate); } else if (in->sample_width <= 16) { return _doBuffer(in, out, speed, sample_rate); } else if (in->sample_width <= 24) { return _doBuffer(in, out, speed, sample_rate); } else return _doBuffer(in, out, speed, sample_rate); } void FastResampler::setSpeed(float _speed) { speed = _speed; } void FastResampler::setSampleRate(unsigned int rate) { sample_rate = rate; } } // namespace