Style changes and use of unsigned types in PaulStretch effect
This commit is contained in:
parent
0f417a65c7
commit
b910bf63da
|
@ -41,35 +41,42 @@ Param( Time, float, XO("Time Resolution"), 0.25f, 0.00099f, FLT_MAX, 1
|
|||
class PaulStretch
|
||||
{
|
||||
public:
|
||||
PaulStretch(float rap_,int in_bufsize_,float samplerate_);
|
||||
PaulStretch(float rap_, size_t in_bufsize_, float samplerate_);
|
||||
//in_bufsize is also a half of a FFT buffer (in samples)
|
||||
virtual ~PaulStretch();
|
||||
|
||||
void process(float *smps,int nsmps);
|
||||
|
||||
int in_bufsize;
|
||||
int poolsize;//how many samples are inside the input_pool size (need to know how many samples to fill when seeking)
|
||||
|
||||
int out_bufsize;
|
||||
float *out_buf;
|
||||
|
||||
int get_nsamples();//how many samples are required to be added in the pool next time
|
||||
int get_nsamples_for_fill();//how many samples are required to be added for a complete buffer refill (at start of the song or after seek)
|
||||
|
||||
void set_rap(float newrap);//set the current stretch value
|
||||
|
||||
protected:
|
||||
void process_spectrum(float *WXUNUSED(freq)) {};
|
||||
float samplerate;
|
||||
size_t get_nsamples();//how many samples are required to be added in the pool next time
|
||||
size_t get_nsamples_for_fill();//how many samples are required to be added for a complete buffer refill (at start of the song or after seek)
|
||||
|
||||
private:
|
||||
float *in_pool;//de marimea in_bufsize
|
||||
float rap;
|
||||
float *old_out_smp_buf;
|
||||
void process_spectrum(float *WXUNUSED(freq)) {};
|
||||
|
||||
float *fft_smps,*fft_c,*fft_s,*fft_freq,*fft_tmp;
|
||||
const float samplerate;
|
||||
const float rap;
|
||||
const size_t in_bufsize;
|
||||
|
||||
public:
|
||||
const size_t out_bufsize;
|
||||
float *const out_buf;
|
||||
|
||||
private:
|
||||
float *const old_out_smp_buf;
|
||||
|
||||
public:
|
||||
const size_t poolsize;//how many samples are inside the input_pool size (need to know how many samples to fill when seeking)
|
||||
|
||||
private:
|
||||
float *const in_pool;//de marimea in_bufsize
|
||||
|
||||
double remained_samples;//how many fraction of samples has remained (0..1)
|
||||
|
||||
float *const fft_smps;
|
||||
float *const fft_c;
|
||||
float *const fft_s;
|
||||
float *const fft_freq;
|
||||
float *const fft_tmp;
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -138,7 +145,7 @@ double EffectPaulstretch::CalcPreviewInputLength(double previewLength)
|
|||
{
|
||||
// FIXME: Preview is currently at the project rate, but should really be
|
||||
// at the track rate (bugs 1284 and 852).
|
||||
int minDuration = GetBufferSize(mProjectRate) * 2 + 1;
|
||||
auto minDuration = GetBufferSize(mProjectRate) * 2 + 1;
|
||||
|
||||
// Preview playback may need to be trimmed but this is the smallest selection that we can use.
|
||||
double minLength = std::max<double>(minDuration / mProjectRate, previewLength / mAmount);
|
||||
|
@ -264,7 +271,7 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun
|
|||
return false;
|
||||
}
|
||||
|
||||
if (len < minDuration){ //error because the selection is too short
|
||||
if (len < minDuration) { //error because the selection is too short
|
||||
|
||||
float maxTimeRes = log(len) / log(2.0);
|
||||
maxTimeRes = pow(2.0, floor(maxTimeRes) + 0.5);
|
||||
|
@ -306,8 +313,9 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun
|
|||
}
|
||||
|
||||
|
||||
double adjust_amount=(double)len/((double)len-((double)stretch_buf_size*2.0));
|
||||
amount=1.0+(amount-1.0)*adjust_amount;
|
||||
double adjust_amount = (double)len /
|
||||
((double)len - ((double)stretch_buf_size * 2.0));
|
||||
amount = 1.0 + (amount - 1.0) * adjust_amount;
|
||||
|
||||
auto outputTrack = mFactory->NewWaveTrack(track->GetSampleFormat(),track->GetRate());
|
||||
|
||||
|
@ -315,51 +323,54 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun
|
|||
// This encloses all the allocations of buffers, including those in
|
||||
// the constructor of the PaulStretch object
|
||||
|
||||
PaulStretch stretch(amount,stretch_buf_size,track->GetRate());
|
||||
PaulStretch stretch(amount, stretch_buf_size, track->GetRate());
|
||||
|
||||
auto nget = stretch.get_nsamples_for_fill();
|
||||
|
||||
int bufsize=stretch.poolsize;
|
||||
float *buffer0=new float[bufsize];
|
||||
float *bufferptr0=buffer0;
|
||||
bool first_time=true;
|
||||
auto bufsize = stretch.poolsize;
|
||||
float *buffer0 = new float[bufsize];
|
||||
float *bufferptr0 = buffer0;
|
||||
bool first_time = true;
|
||||
|
||||
int fade_len=100;
|
||||
if (fade_len>(bufsize/2-1)) fade_len=bufsize/2-1;
|
||||
float *fade_track_smps=new float[fade_len];
|
||||
decltype(len) s=0;
|
||||
bool cancelled=false;
|
||||
const auto fade_len = std::min<size_t>(100, bufsize / 2 - 1);
|
||||
float *fade_track_smps = new float[fade_len];
|
||||
decltype(len) s = 0;
|
||||
bool cancelled = false;
|
||||
|
||||
while (s<len){
|
||||
track->Get((samplePtr)bufferptr0,floatSample,start+s,nget);
|
||||
stretch.process(buffer0,nget);
|
||||
while (s < len) {
|
||||
track->Get((samplePtr)bufferptr0, floatSample, start + s, nget);
|
||||
stretch.process(buffer0, nget);
|
||||
|
||||
if (first_time) {
|
||||
stretch.process(buffer0,0);
|
||||
stretch.process(buffer0, 0);
|
||||
};
|
||||
|
||||
s+=nget;
|
||||
s += nget;
|
||||
|
||||
if (first_time){//blend the the start of the selection
|
||||
track->Get((samplePtr)fade_track_smps,floatSample,start,fade_len);
|
||||
first_time=false;
|
||||
for (int i=0;i<fade_len;i++){
|
||||
float fi=(float)i/(float)fade_len;
|
||||
stretch.out_buf[i]=stretch.out_buf[i]*fi+(1.0-fi)*fade_track_smps[i];
|
||||
if (first_time) {//blend the the start of the selection
|
||||
track->Get((samplePtr)fade_track_smps, floatSample, start, fade_len);
|
||||
first_time = false;
|
||||
for (int i = 0; i < fade_len; i++){
|
||||
float fi = (float)i / (float)fade_len;
|
||||
stretch.out_buf[i] =
|
||||
stretch.out_buf[i] * fi + (1.0 - fi) * fade_track_smps[i];
|
||||
};
|
||||
};
|
||||
if (s>=len){//blend the end of the selection
|
||||
if (s >= len) {//blend the end of the selection
|
||||
track->Get((samplePtr)fade_track_smps,floatSample,end-fade_len,fade_len);
|
||||
for (int i=0;i<fade_len;i++){
|
||||
float fi=(float)i/(float)fade_len;
|
||||
int i2=bufsize/2-1-i;
|
||||
stretch.out_buf[i2]=stretch.out_buf[i2]*fi+(1.0-fi)*fade_track_smps[fade_len-1-i];
|
||||
for (int i = 0; i < fade_len; i++){
|
||||
float fi = (float)i / (float)fade_len;
|
||||
auto i2 = bufsize / 2 - 1 - i;
|
||||
stretch.out_buf[i2] =
|
||||
stretch.out_buf[i2] * fi + (1.0 - fi) *
|
||||
fade_track_smps[fade_len - 1 - i];
|
||||
};
|
||||
};
|
||||
|
||||
outputTrack->Append((samplePtr)stretch.out_buf,floatSample,stretch.out_bufsize);
|
||||
outputTrack->Append((samplePtr)stretch.out_buf, floatSample,
|
||||
stretch.out_bufsize);
|
||||
|
||||
nget=stretch.get_nsamples();
|
||||
nget = stretch.get_nsamples();
|
||||
if (TrackProgress(count, (s / (double) len))) {
|
||||
cancelled=true;
|
||||
break;
|
||||
|
@ -388,34 +399,22 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun
|
|||
/*************************************************************/
|
||||
|
||||
|
||||
PaulStretch::PaulStretch(float rap_,int in_bufsize_,float samplerate_)
|
||||
PaulStretch::PaulStretch(float rap_, size_t in_bufsize_, float samplerate_)
|
||||
: samplerate { samplerate }
|
||||
, rap { std::max(1.0f, rap_) }
|
||||
, in_bufsize { in_bufsize_ }
|
||||
, out_bufsize { std::max(size_t{ 8 }, in_bufsize) }
|
||||
, out_buf { new float[out_bufsize] }
|
||||
, old_out_smp_buf { new float[out_bufsize * 2] { 0.0f } }
|
||||
, poolsize { in_bufsize_ * 2 }
|
||||
, in_pool { new float[poolsize] { 0.0f } }
|
||||
, remained_samples { 0.0 }
|
||||
, fft_smps { new float[poolsize] { 0.0f } }
|
||||
, fft_s { new float[poolsize] { 0.0f } }
|
||||
, fft_c { new float[poolsize] { 0.0f } }
|
||||
, fft_freq { new float[poolsize] { 0.0f } }
|
||||
, fft_tmp { new float[poolsize] }
|
||||
{
|
||||
samplerate=samplerate_;
|
||||
rap=rap_;
|
||||
in_bufsize=in_bufsize_;
|
||||
if (rap<1.0) rap=1.0;
|
||||
out_bufsize=in_bufsize;
|
||||
if (out_bufsize<8) out_bufsize=8;
|
||||
|
||||
out_buf=new float[out_bufsize];
|
||||
old_out_smp_buf=new float[out_bufsize*2];for (int i=0;i<out_bufsize*2;i++) old_out_smp_buf[i]=0.0;
|
||||
|
||||
poolsize=in_bufsize_*2;
|
||||
in_pool=new float[poolsize];for (int i=0;i<poolsize;i++) in_pool[i]=0.0;
|
||||
|
||||
remained_samples=0.0;
|
||||
|
||||
fft_smps=new float[poolsize];
|
||||
fft_s=new float[poolsize];
|
||||
fft_c=new float[poolsize];
|
||||
fft_freq=new float[poolsize];
|
||||
fft_tmp=new float[poolsize];
|
||||
for (int i=0;i<poolsize;i++) {
|
||||
fft_smps[i]=0.0;
|
||||
fft_c[i]=0.0;
|
||||
fft_s[i]=0.0;
|
||||
fft_freq[i]=0.0;
|
||||
}
|
||||
}
|
||||
|
||||
PaulStretch::~PaulStretch()
|
||||
|
@ -430,102 +429,103 @@ PaulStretch::~PaulStretch()
|
|||
delete [] fft_tmp;
|
||||
}
|
||||
|
||||
void PaulStretch::set_rap(float newrap)
|
||||
{
|
||||
if (rap>=1.0) rap=newrap;
|
||||
else rap=1.0;
|
||||
}
|
||||
|
||||
void PaulStretch::process(float *smps,int nsmps)
|
||||
{
|
||||
//add NEW samples to the pool
|
||||
if ((smps!=NULL)&&(nsmps!=0)){
|
||||
if (nsmps>poolsize){
|
||||
nsmps=poolsize;
|
||||
if ((smps != NULL) && (nsmps != 0)) {
|
||||
if (nsmps > poolsize) {
|
||||
nsmps = poolsize;
|
||||
}
|
||||
int nleft=poolsize-nsmps;
|
||||
int nleft = poolsize - nsmps;
|
||||
|
||||
//move left the samples from the pool to make room for NEW samples
|
||||
for (int i=0;i<nleft;i++) in_pool[i]=in_pool[i+nsmps];
|
||||
for (int i = 0; i < nleft; i++)
|
||||
in_pool[i] = in_pool[i + nsmps];
|
||||
|
||||
//add NEW samples to the pool
|
||||
for (int i=0;i<nsmps;i++) in_pool[i+nleft]=smps[i];
|
||||
for (int i = 0; i < nsmps; i++)
|
||||
in_pool[i + nleft] = smps[i];
|
||||
}
|
||||
|
||||
//get the samples from the pool
|
||||
for (int i=0;i<poolsize;i++) fft_smps[i]=in_pool[i];
|
||||
WindowFunc(3,poolsize,fft_smps);
|
||||
for (size_t i = 0; i < poolsize; i++)
|
||||
fft_smps[i] = in_pool[i];
|
||||
WindowFunc(eWinFuncHanning, poolsize, fft_smps);
|
||||
|
||||
RealFFT(poolsize,fft_smps,fft_c,fft_s);
|
||||
RealFFT(poolsize, fft_smps, fft_c, fft_s);
|
||||
|
||||
for (int i=0;i<poolsize/2;i++) fft_freq[i]=sqrt(fft_c[i]*fft_c[i]+fft_s[i]*fft_s[i]);
|
||||
for (size_t i = 0; i < poolsize / 2; i++)
|
||||
fft_freq[i] = sqrt(fft_c[i] * fft_c[i] + fft_s[i] * fft_s[i]);
|
||||
process_spectrum(fft_freq);
|
||||
|
||||
|
||||
//put randomize phases to frequencies and do a IFFT
|
||||
float inv_2p15_2pi=1.0/16384.0*(float)M_PI;
|
||||
for (int i=1;i<poolsize/2;i++){
|
||||
unsigned int random=(rand())&0x7fff;
|
||||
float phase=random*inv_2p15_2pi;
|
||||
float s=fft_freq[i]*sin(phase);
|
||||
float c=fft_freq[i]*cos(phase);
|
||||
float inv_2p15_2pi = 1.0 / 16384.0 * (float)M_PI;
|
||||
for (size_t i = 1; i < poolsize / 2; i++) {
|
||||
unsigned int random = (rand()) & 0x7fff;
|
||||
float phase = random * inv_2p15_2pi;
|
||||
float s = fft_freq[i] * sin(phase);
|
||||
float c = fft_freq[i] * cos(phase);
|
||||
|
||||
fft_c[i]=fft_c[poolsize-i]=c;
|
||||
fft_c[i] = fft_c[poolsize - i] = c;
|
||||
|
||||
fft_s[i]=s;fft_s[poolsize-i]=-s;
|
||||
fft_s[i] = s; fft_s[poolsize - i] = -s;
|
||||
}
|
||||
fft_c[0]=fft_s[0]=0.0;
|
||||
fft_c[poolsize/2]=fft_s[poolsize/2]=0.0;
|
||||
fft_c[0] = fft_s[0] = 0.0;
|
||||
fft_c[poolsize / 2] = fft_s[poolsize / 2] = 0.0;
|
||||
|
||||
FFT(poolsize,true,fft_c,fft_s,fft_smps,fft_tmp);
|
||||
FFT(poolsize, true, fft_c, fft_s, fft_smps, fft_tmp);
|
||||
|
||||
float max=0.0,max2=0.0;
|
||||
for (int i=0;i<poolsize;i++){
|
||||
float a=fabs(fft_tmp[i]);
|
||||
if (a>max) max=a;
|
||||
float b=fabs(fft_smps[i]);
|
||||
if (b>max2) max2=b;
|
||||
float max = 0.0, max2 = 0.0;
|
||||
for (size_t i = 0; i < poolsize; i++) {
|
||||
max = std::max(max, fabsf(fft_tmp[i]));
|
||||
max2 = std::max(max2, fabsf(fft_smps[i]));
|
||||
}
|
||||
|
||||
|
||||
//make the output buffer
|
||||
float tmp=1.0/(float) out_bufsize*M_PI;
|
||||
float hinv_sqrt2=0.853553390593f;//(1.0+1.0/sqrt(2))*0.5;
|
||||
float tmp = 1.0 / (float) out_bufsize * M_PI;
|
||||
float hinv_sqrt2 = 0.853553390593f;//(1.0+1.0/sqrt(2))*0.5;
|
||||
|
||||
float ampfactor=1.0;
|
||||
if (rap<1.0) ampfactor=rap*0.707;
|
||||
else ampfactor=(out_bufsize/(float)poolsize)*4.0;
|
||||
float ampfactor = 1.0;
|
||||
if (rap < 1.0)
|
||||
ampfactor = rap * 0.707;
|
||||
else
|
||||
ampfactor = (out_bufsize / (float)poolsize) * 4.0;
|
||||
|
||||
for (int i=0;i<out_bufsize;i++) {
|
||||
float a=(0.5+0.5*cos(i*tmp));
|
||||
float out=fft_smps[i+out_bufsize]*(1.0-a)+old_out_smp_buf[i]*a;
|
||||
out_buf[i]=out*(hinv_sqrt2-(1.0-hinv_sqrt2)*cos(i*2.0*tmp))*ampfactor;
|
||||
for (size_t i = 0; i < out_bufsize; i++) {
|
||||
float a = (0.5 + 0.5 * cos(i * tmp));
|
||||
float out = fft_smps[i + out_bufsize] * (1.0 - a) + old_out_smp_buf[i] * a;
|
||||
out_buf[i] =
|
||||
out * (hinv_sqrt2 - (1.0 - hinv_sqrt2) * cos(i * 2.0 * tmp)) *
|
||||
ampfactor;
|
||||
}
|
||||
|
||||
//copy the current output buffer to old buffer
|
||||
for (int i=0;i<out_bufsize*2;i++) old_out_smp_buf[i]=fft_smps[i];
|
||||
for (size_t i = 0; i < out_bufsize * 2; i++)
|
||||
old_out_smp_buf[i] = fft_smps[i];
|
||||
}
|
||||
|
||||
int PaulStretch::get_nsamples()
|
||||
size_t PaulStretch::get_nsamples()
|
||||
{
|
||||
double r=out_bufsize/rap;
|
||||
int ri=(int)floor(r);
|
||||
double rf=r-floor(r);
|
||||
double r = out_bufsize / rap;
|
||||
auto ri = (size_t)floor(r);
|
||||
double rf = r - floor(r);
|
||||
|
||||
remained_samples+=rf;
|
||||
if (remained_samples>=1.0){
|
||||
ri+=(int)floor(remained_samples);
|
||||
remained_samples=remained_samples-floor(remained_samples);
|
||||
remained_samples += rf;
|
||||
if (remained_samples >= 1.0){
|
||||
ri += (size_t)floor(remained_samples);
|
||||
remained_samples = remained_samples - floor(remained_samples);
|
||||
}
|
||||
|
||||
if (ri>poolsize){
|
||||
ri=poolsize;
|
||||
if (ri > poolsize) {
|
||||
ri = poolsize;
|
||||
}
|
||||
|
||||
return ri;
|
||||
}
|
||||
|
||||
int PaulStretch::get_nsamples_for_fill()
|
||||
size_t PaulStretch::get_nsamples_for_fill()
|
||||
{
|
||||
return poolsize;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue