1
0
mirror of https://github.com/cookiengineer/audacity synced 2026-02-05 19:21:59 +01:00

Major update to TimeScale effect, incorporating libsbsms-2.0.0, fixes to bug 172, changes to ui

This commit is contained in:
clayton.otey
2011-07-02 18:35:18 +00:00
parent 9869ea4afd
commit a17e741abc
45 changed files with 12912 additions and 6785 deletions

View File

@@ -6,225 +6,244 @@
#include "real.h"
#include "utils.h"
#include <algorithm>
#include "buffer.h"
using namespace std;
namespace _sbsms_ {
#define SBSMS_RESAMPLE_CHUNK_SIZE 8192L
enum { resampleChunkSize = 8192 };
class ResamplerImp {
public:
ResamplerImp(SBSMSResampleCB func, void *data, SlideType slideType = SlideConstant);
~ResamplerImp();
inline long read(audio *audioOut, long frames);
inline void writingComplete();
inline void reset();
inline void init();
inline long samplesInOutput();
protected:
SBSMSFrame frame;
SampleCountType startAbs;
SampleCountType midAbs;
float midAbsf;
SampleCountType endAbs;
SampleCountType writePosAbs;
bool bInput;
SampleBuf *out;
SBSMSResampleCB cb;
void *data;
long inOffset;
SlideType slideType;
Slide *slide;
bool bWritingComplete;
};
Resampler :: Resampler(sbsms_resample_cb cb, void *data)
Resampler :: Resampler(SBSMSResampleCB cb, void *data, SlideType slideType)
{
imp = new ResamplerImp(cb,data,slideType);
}
ResamplerImp :: ResamplerImp(SBSMSResampleCB cb, void *data, SlideType slideType)
{
init();
this->cb = cb;
this->data = data;
bPull = true;
bInput = true;
this->slideType = slideType;
frame.size = 0;
}
Resampler :: Resampler(SampleBuf *in, real ratio)
{
init();
bPull = false;
this->in = in;
bInput = true;
frame.ratio0 = ratio;
frame.ratio1 = ratio;
}
void Resampler :: init()
void ResamplerImp :: init()
{
inOffset = 0;
startAbs = 0;
midAbs = 0;
endAbs = 0;
writePosAbs = 0;
midAbsf = 0.0;
midAbsf = 0.0f;
out = new SampleBuf(0);
slide = NULL;
bWritingComplete = false;
sincZeros = SBSMS_SINC_SAMPLES;
}
void Resampler :: reset()
void Resampler :: reset() { imp->reset(); }
void ResamplerImp :: reset()
{
if(slide) delete slide;
delete out;
init();
frame.size = 0;
bInput = true;
}
long Resampler :: read(audio *audioOut, long samples)
Resampler :: ~Resampler() { delete imp; }
ResamplerImp :: ~ResamplerImp()
{
if(!bPull) {
frame.in = in->getReadBuf();
frame.size = in->n_readable();
if(frame.size) bInput = true;
}
if(slide) delete slide;
delete out;
}
long nRead = out->n_readable();
void updateSlide(Slide *slide, float *f, float *scale, int *maxDist, float *ratio)
{
float stretch = slide->getStretch();
slide->step();
if(stretch <= 1.0f) {
*f = resampleSincRes;
*scale = stretch;
*maxDist = lrintf(resampleSincSamples);
} else {
*f = resampleSincRes / stretch;
*scale = 1.0f;
*maxDist = lrintf(resampleSincSamples * stretch);
}
*ratio = stretch;
}
long Resampler :: read(audio *audioOut, long samples) { return imp->read(audioOut,samples); }
long ResamplerImp :: read(audio *audioOut, long samples)
{
long nRead = out->nReadable();
while(nRead < samples && bInput) {
if(bInput && inOffset == frame.size) {
if(!bPull) {
in->advance(frame.size);
bInput = false;
cb(data,&frame);
if(frame.size) {
if(slide) delete slide;
slide = new Slide(slideType,1.0f/frame.ratio0,1.0f/frame.ratio1,frame.size);
} else {
cb(data,&frame);
if(!frame.size)
bWritingComplete = true;
bWritingComplete = true;
}
if(bWritingComplete) {
bInput = false;
out->grow(midAbs - writePosAbs);
out->writePos += midAbs - writePosAbs;
out->delay = 0;
bInput = false;
long n = (long)(midAbs - writePosAbs);
out->grow(n);
out->writePos += n;
}
inOffset = 0;
}
if(frame.size) {
real dratio = 1.0f/(real)frame.size*(frame.ratio1-frame.ratio0);
real ratio = frame.ratio0 + (real)inOffset*dratio;
real ratiorec = ratio<1.0f?1.0f:1.0f/ratio;
real f = ratiorec*SBSMS_SINC_RES;
int fi = round2int(f-0.5f);
real ff = f - fi;
if(ff<0.0f) {
ff += 1.0f;
fi--;
}
real scale = ratio<1.0f?ratio:1.0f;
int maxDist = round2int(sincZeros*ratio-0.5f);
// absolute start position
startAbs = max((long)0,midAbs-maxDist);
// samples to advance
long advance = max((long)0,startAbs - maxDist - writePosAbs);
writePosAbs += advance;
// absolute end position
endAbs = midAbs + maxDist;
// starting position in output
int start = startAbs - writePosAbs;
assert(start>=0);
// zero point in output
int mid = midAbs - writePosAbs;
// ending position in output
int end = endAbs - writePosAbs;
// provide extra delay for variable rate ratio
out->delay = maxDist<<1;
out->writePos += advance;
if(fabs(ratio-1.0f) < 1e-6f && fabs(dratio) < 1e-8f ) {
// how far ahead to write
int nAhead = mid+frame.size;
out->N = nAhead;
out->grow(nAhead);
long nWrite = min(SBSMS_RESAMPLE_CHUNK_SIZE,frame.size-inOffset);
for(int j=0;j<nWrite;j++) {
out->buf[out->writePos+mid+j][0] += frame.in[j+inOffset][0];
out->buf[out->writePos+mid+j][1] += frame.in[j+inOffset][1];
}
inOffset += nWrite;
midAbsf += ratio*nWrite;
int nWritten = round2int(midAbsf);
midAbsf -= nWritten;
midAbs += nWritten;
if(slideType == SlideIdentity) {
out->write(frame.buf,frame.size);
inOffset = frame.size;
} else {
long nWrite = min(SBSMS_RESAMPLE_CHUNK_SIZE,frame.size-inOffset);
audio *i = &(frame.in[inOffset]);
for(int j=0;j<nWrite;j++) {
// how far ahead to write
int nAhead = end;
out->N = nAhead;
out->grow(nAhead);
audio *o = &(out->buf[out->writePos+start]);
real d = (start-mid-midAbsf)*f;
int di = round2int(d-0.5f);
real df = d-di;
if(df<0.0f) {
df += 1.0f;
di--;
}
real i0 = (*i)[0];
real i1 = (*i)[1];
for(int k=start;k<end;k++) {
int k0 = (di<0)?-di:di;
int k1 = (di<0)?k0-1:k0+1;
real sinc;
if(k1>=SBSMS_SINC_SIZE) {
if(k0>=SBSMS_SINC_SIZE) {
sinc = 0.0f;
} else {
sinc = scale*sincTable[k0];
}
} else if(k0>=SBSMS_SINC_SIZE) {
sinc = scale*sincTable[k1];
} else {
sinc = scale*((1.0f-df)*sincTable[k0] + df*sincTable[k1]);
}
(*o)[0] += i0 * sinc;
(*o)[1] += i1 * sinc;
di += fi;
df += ff;
if(!(df<1.0f)) {
df -= 1.0f;
di++;
}
o++;
}
i++;
midAbsf += ratio;
if(dratio != 0.0f) {
ratio += dratio;
ratiorec = ratio<1.0f?1.0f:1.0f/ratio;
f = ratiorec*SBSMS_SINC_RES;
fi = round2int(f-0.5f);
ff = f - fi;
if(ff<0.0f) {
ff += 1.0f;
fi--;
}
scale = ratio<1.0f?ratio:1.0f;
maxDist = round2int(sincZeros*ratio-0.5f);
}
int nWritten = round2int(midAbsf);
midAbsf -= nWritten;
midAbs += nWritten;
startAbs = max((long)0,midAbs-maxDist);
endAbs = midAbs + maxDist;
start = startAbs - writePosAbs;
mid = midAbs - writePosAbs;
end = endAbs - writePosAbs;
}
inOffset += nWrite;
bool bNoSinc = false;
if(fabs(frame.ratio0-1.0f) < 1e-6f &&
fabs((float)(frame.ratio1 - frame.ratio0)/(float)frame.size) < 1e-9f) {
bNoSinc = true;
}
float f;
float scale;
int maxDist;
float ratio;
updateSlide(slide,&f,&scale,&maxDist,&ratio);
int fi = lrintf(f);
float ff = f - fi;
if(ff<0.0f) {
ff += 1.0f;
fi--;
}
startAbs = max((SampleCountType)0,midAbs-maxDist);
long advance = max(0L,(long)(startAbs - maxDist - writePosAbs));
writePosAbs += advance;
endAbs = midAbs + maxDist;
long start = (long)(startAbs - writePosAbs);
long mid = (long)(midAbs - writePosAbs);
long end = (long)(endAbs - writePosAbs);
out->writePos += advance;
if(bNoSinc) {
int nAhead = mid+frame.size;
out->N = nAhead;
out->grow(nAhead);
long nWrite = min((long)resampleChunkSize,frame.size-inOffset);
for(int j=0;j<nWrite;j++) {
out->buf[out->writePos+mid+j][0] += frame.buf[j+inOffset][0];
out->buf[out->writePos+mid+j][1] += frame.buf[j+inOffset][1];
}
inOffset += nWrite;
midAbsf += nWrite;
int nWritten = lrintf(midAbsf);
midAbsf -= nWritten;
midAbs += nWritten;
} else {
long nWrite = min((long)resampleChunkSize,frame.size-inOffset);
audio *i = &(frame.buf[inOffset]);
for(int j=0;j<nWrite;j++) {
int nAhead = end;
out->N = nAhead;
out->grow(nAhead);
audio *o = &(out->buf[out->writePos+start]);
float d = (start-mid-midAbsf)*f;
int di = lrintf(d);
float df = d-di;
if(df<0.0f) {
df += 1.0f;
di--;
}
float i0 = (*i)[0];
float i1 = (*i)[1];
for(int k=start;k<end;k++) {
int k0 = (di<0)?-di:di;
int k1 = (di<0)?k0-1:k0+1;
float sinc;
if(k1>=resampleSincSize) {
if(k0>=resampleSincSize) {
sinc = 0.0f;
} else {
sinc = scale*sincTable[k0];
}
} else if(k0>=resampleSincSize) {
sinc = scale*sincTable[k1];
} else {
sinc = scale*((1.0f-df)*sincTable[k0] + df*sincTable[k1]);
}
(*o)[0] += i0 * sinc;
(*o)[1] += i1 * sinc;
di += fi;
df += ff;
if(!(df<1.0f)) {
df -= 1.0f;
di++;
}
o++;
}
i++;
updateSlide(slide,&f,&scale,&maxDist,&ratio);
fi = lrintf(f);
ff = f - fi;
if(ff<0.0f) {
ff += 1.0f;
fi--;
}
midAbsf += ratio;
int nWritten = lrintf(midAbsf);
midAbsf -= nWritten;
midAbs += nWritten;
startAbs = max((SampleCountType)0,midAbs-maxDist);
endAbs = midAbs + maxDist;
start = (long)(startAbs - writePosAbs);
mid = (long)(midAbs - writePosAbs);
end = (long)(endAbs - writePosAbs);
}
inOffset += nWrite;
}
}
nRead = out->nReadable();
}
nRead = out->n_readable();
}
nRead = min(samples,out->n_readable());
if(nRead) {
out->read(audioOut,nRead);
out->advance(nRead);
}
return nRead;
out->read(audioOut,samples);
return samples;
}
long Resampler :: samplesInOutput()
long Resampler :: samplesInOutput() { return imp->samplesInOutput(); }
long ResamplerImp :: samplesInOutput()
{
long samplesFromBuffer = round2int(0.5f*(frame.ratio0+frame.ratio1)*(frame.size-inOffset));
return out->writePos + midAbs - writePosAbs - out->readPos + samplesFromBuffer;
long samplesFromBuffer = lrintf(0.5f*(frame.ratio0+frame.ratio1)*(frame.size-inOffset));
return (long)(out->writePos + (midAbs - writePosAbs) - out->readPos + samplesFromBuffer);
}
void Resampler :: writingComplete()
void ResamplerImp :: writingComplete()
{
bWritingComplete = true;
}
Resampler :: ~Resampler()
{
delete out;
}
}