Browse Source

Changed the stretching algorithm

master
Nasca Octavian PAUL 13 years ago
parent
commit
e29b5f803e
6 changed files with 108 additions and 125 deletions
  1. +2
    -2
      Control.cpp
  2. +2
    -1
      Input/AInputS.cpp
  3. +3
    -3
      Player.cpp
  4. +1
    -1
      ProcessedStretch.cpp
  5. +81
    -111
      Stretch.cpp
  6. +19
    -7
      Stretch.h

+ 2
- 2
Control.cpp View File

@@ -476,10 +476,10 @@ string Control::Render(string inaudio,string outaudio,FILE_TYPE outtype,FILE_TYP
stretchl->set_parameters(&ppar);
stretchr->set_parameters(&ppar);

outbufsize=stretchl->out_bufsize;
outbufsize=stretchl->get_bufsize();
int *outbuf=new int[outbufsize*2];

int poolsize=stretchl->poolsize;
int poolsize=stretchl->get_max_bufsize();

inbuf.l=new REALTYPE[poolsize];
inbuf.r=new REALTYPE[poolsize];


+ 2
- 1
Input/AInputS.cpp View File

@@ -72,10 +72,11 @@ int AInputS::read(int nsmps,short int *smps){
int readed=afReadFrames(handle,AF_DEFAULT_TRACK,smps,nsmps);
info.currentsample+=readed;
if (readed!=nsmps) {
if (readed>=0) for (int i=readed;i<nsmps;i++) smps[i]=0;
info.currentsample=info.nsamples;
eof=true;
};
return readed;
return nsmps;
};

void AInputS::seek(double pos){


+ 3
- 3
Player.cpp View File

@@ -270,7 +270,7 @@ void Player::newtaskcheck(){
if (stretchr) stretchr->set_parameters(task.ppar);
if (binaural_beats) binaural_beats->pars=*(task.bbpar);

inbufsize=stretchl->poolsize;
inbufsize=stretchl->get_max_bufsize();
if (inbuf.l) delete []inbuf.l;inbuf.l=NULL;
if (inbuf.r) delete []inbuf.r;inbuf.r=NULL;
inbuf.l=new REALTYPE[inbufsize];
@@ -304,7 +304,7 @@ void Player::newtaskcheck(){
};
first_in_buf=true;

outbuf.size=stretchl->out_bufsize;
outbuf.size=stretchl->get_bufsize();

int min_samples=ai->info.samplerate*2;
int n=2*PA_SOUND_BUFFER_SIZE/outbuf.size;
@@ -407,7 +407,7 @@ void Player::computesamples(){
stretchr->window_type=window_type;
stretchl->process(inbuf.l,readsize);
stretchr->process(inbuf.r,readsize);
binaural_beats->process(stretchl->out_buf,stretchr->out_buf,stretchl->out_bufsize,in_pos_100);
binaural_beats->process(stretchl->out_buf,stretchr->out_buf,stretchl->get_bufsize(),in_pos_100);
// stretchl->process_output(stretchl->out_buf,stretchl->out_bufsize);
// stretchr->process_output(stretchr->out_buf,stretchr->out_bufsize);



+ 1
- 1
ProcessedStretch.cpp View File

@@ -120,7 +120,7 @@ void ProcessParameters::getfromXML(XMLwrapper *xml){
};

ProcessedStretch::ProcessedStretch(REALTYPE rap_,int in_bufsize_,FFTWindow w,bool bypass_,REALTYPE samplerate_,int stereo_mode_):Stretch(rap_,in_bufsize_,w,bypass_,samplerate_,stereo_mode_){
nfreq=out_bufsize;
nfreq=bufsize;
infreq=new REALTYPE[nfreq];
sumfreq=new REALTYPE[nfreq];
tmpfreq1=new REALTYPE[nfreq];


+ 81
- 111
Stretch.cpp View File

@@ -141,38 +141,39 @@ void FFT::applywindow(FFTWindow type){
/*******************************************/


Stretch::Stretch(REALTYPE rap_,int in_bufsize_,FFTWindow w,bool bypass_,REALTYPE samplerate_,int stereo_mode_){
Stretch::Stretch(REALTYPE rap_,int bufsize_,FFTWindow w,bool bypass_,REALTYPE samplerate_,int stereo_mode_){

samplerate=samplerate_;
rap=rap_;
in_bufsize=in_bufsize_;
bufsize=bufsize_;
bypass=bypass_;
stereo_mode=stereo_mode_;
if (rap>=1.0){//stretch
out_bufsize=in_bufsize;
}else{
//shorten
out_bufsize=(int)(in_bufsize*rap);
if (bufsize<8) bufsize=8;

out_buf=new REALTYPE[bufsize];
old_freq=new REALTYPE[bufsize];
old_smps=new REALTYPE[bufsize];
old_out_smps=new REALTYPE[bufsize*2];
for (int i=0;i<bufsize*2;i++) old_out_smps[i]=0.0;
for (int i=0;i<bufsize;i++) {
old_freq[i]=0.0;
old_smps[i]=0.0;
};
if (out_bufsize<8) out_bufsize=8;

if (bypass) out_bufsize=in_bufsize;

out_buf=new REALTYPE[out_bufsize];
old_out_smp_buf=new REALTYPE[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 REALTYPE[poolsize];for (int i=0;i<poolsize;i++) in_pool[i]=0.0;

infft=new FFT(poolsize);
outfft=new FFT(out_bufsize*2);
infft=new FFT(bufsize*2);
outfft=new FFT(bufsize*2);
remained_samples=0.0;
window_type=w;
require_new_buffer=false;
c_pos_percents=0.0;
};

Stretch::~Stretch(){
delete [] old_freq;
delete [] out_buf;
delete [] old_out_smp_buf;
delete [] in_pool;
delete [] old_smps;
delete [] old_out_smps;
delete infft;
delete outfft;
};
@@ -180,123 +181,92 @@ Stretch::~Stretch(){
void Stretch::set_rap(REALTYPE newrap){
if ((rap>=1.0)&&(newrap>=1.0)) rap=newrap;
};
void Stretch::do_analyse_inbuf(REALTYPE *smps){
//get the frequencies
for (int i=0;i<bufsize;i++) {
infft->smp[i]=old_smps[i];
infft->smp[i+bufsize]=smps[i];

old_freq[i]=infft->freq[i];
old_smps[i]=smps[i];
};
infft->applywindow(window_type);
infft->smp2freq();
};

void Stretch::process(REALTYPE *smps,int nsmps){
if (bypass){
for (int i=0;i<out_bufsize;i++) out_buf[i]=smps[i];
for (int i=0;i<bufsize;i++) out_buf[i]=smps[i];
//post-process the output
// process_output(out_buf,out_bufsize);
// process_output(out_buf,bufsize);
return;
};
//add new samples to the pool
if ((smps!=NULL)&&(nsmps!=0)){
if (nsmps>poolsize){
printf("Warning nsmps> inbufsize on Stretch::process() %d>%d\n",nsmps,poolsize);
nsmps=poolsize;
};
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];

//add new samples to the pool
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++) infft->smp[i]=in_pool[i];


infft->applywindow(window_type);
infft->smp2freq();


if (out_bufsize==in_bufsize){//output is the same as the input (as usual)
for (int i=0;i<in_bufsize;i++) outfft->freq[i]=infft->freq[i];
} else {
if (out_bufsize>in_bufsize){//output is longer
REALTYPE rap=(REALTYPE)in_bufsize/(REALTYPE)out_bufsize;
for (int i=0;i<out_bufsize;i++) {
REALTYPE pos=i*rap;
int poshi=(int)floor(pos);
REALTYPE poslo=pos-floor(pos);
outfft->freq[i]=infft->freq[poshi]*(1.0-poslo)+infft->freq[poshi+1]*poslo;
};
}else{//output is shorter
for (int i=0;i<out_bufsize;i++) outfft->freq[i]=0.0;
REALTYPE rap=(REALTYPE)out_bufsize/(REALTYPE)in_bufsize;
for (int i=0;i<in_bufsize;i++) {
REALTYPE pos=i*rap;
int poshi=(int)(floor(pos));
// #warning sa folosesc si poslo
outfft->freq[poshi]+=infft->freq[i];
};
if (smps!=NULL){
if ((nsmps!=0)&&(nsmps!=bufsize)&&(nsmps!=bufsize*2)){
printf("Warning wrong nsmps on Stretch::process() %d,%d\n",nsmps,bufsize);
return;
};
if (nsmps!=0){//new data arrived: update the frequency components
do_analyse_inbuf(smps);
if (nsmps==bufsize*2) do_analyse_inbuf(smps+bufsize);
};
//compute the output spectrum
for (int i=0;i<bufsize;i++) {
outfft->freq[i]=infft->freq[i]*remained_samples+old_freq[i]*(1.0-remained_samples);
};
process_spectrum(outfft->freq);

outfft->freq2smp();

//make the output buffer
REALTYPE tmp=1.0/(float) bufsize*M_PI;
REALTYPE hinv_sqrt2=0.853553390593;//(1.0+1.0/sqrt(2))*0.5;

REALTYPE ampfactor=2.0;
//remove the resulted unwanted amplitude modulation (caused by the interference of N and N+1 windowed buffer and compute the output buffer
for (int i=0;i<bufsize;i++) {
REALTYPE a=(0.5+0.5*cos(i*tmp));
REALTYPE out=outfft->smp[i+bufsize]*(1.0-a)+old_out_smps[i]*a;
out_buf[i]=out*(hinv_sqrt2-(1.0-hinv_sqrt2)*cos(i*2.0*tmp))*ampfactor;
};
};

process_spectrum(outfft->freq);

outfft->freq2smp();

//make the output buffer
REALTYPE tmp=1.0/(float) out_bufsize*M_PI;
REALTYPE hinv_sqrt2=0.853553390593;//(1.0+1.0/sqrt(2))*0.5;

REALTYPE ampfactor=1.0;
if (rap<1.0) ampfactor=rap*0.707;
else ampfactor=(out_bufsize/(float)poolsize)*4.0;
//copy the current output buffer to old buffer
for (int i=0;i<bufsize*2;i++) old_out_smps[i]=outfft->smp[i];

for (int i=0;i<out_bufsize;i++) {
REALTYPE a=(0.5+0.5*cos(i*tmp));
REALTYPE out=outfft->smp[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]=outfft->smp[i];

//post-process the output
//process_output(out_buf,out_bufsize);
};


int Stretch::get_nsamples(REALTYPE current_pos_percents){
if (bypass) return out_bufsize;
if (rap<1.0) return poolsize/2;//pentru shorten
long double used_rap=rap*get_stretch_multiplier(c_pos_percents);


long double used_rap=rap*get_stretch_multiplier(current_pos_percents);

long double r=out_bufsize/used_rap;
int ri=(int)floor(r);
long double rf=r-floor(r);
long double r=1.0/used_rap;

long double old_remained_samples_test=remained_samples;
remained_samples+=rf;
remained_samples+=r;
int result=0;
if (remained_samples>=1.0){
ri+=(int)floor(remained_samples);
remained_samples=remained_samples-floor(remained_samples);
require_new_buffer=true;
}else{
require_new_buffer=false;
};

long double rf_test=remained_samples-old_remained_samples_test;//this value should be almost like "rf" (for most of the time with the exception of changing the "ri" value) for extremely long stretches (otherwise the shown stretch value is not accurate)
// long double rf_test=remained_samples-old_remained_samples_test;//this value should be almost like "rf" (for most of the time with the exception of changing the "ri" value) for extremely long stretches (otherwise the shown stretch value is not accurate)
//for stretch up to 10^18x "long double" must have at least 64 bits in the fraction part (true for gcc compiler on x86 and macosx)
};

// long double zzz=1.0;//quick test by adding a "largish" number and substracting it again
// rf_test+=zzz;
// rf_test-=zzz;

// printf("remained_samples=%.20Lg rf=%.20Lg rf_test=%.20Lg\n",remained_samples,rf,rf_test);
// printf("rf=%g rf_test=%g\n",(double)rf,(double)(rf_test));

if (ri>poolsize){
ri=poolsize;
};

return ri;
int Stretch::get_nsamples(REALTYPE current_pos_percents){
if (bypass) return bufsize;
c_pos_percents=current_pos_percents;
return require_new_buffer?bufsize:0;
};

int Stretch::get_nsamples_for_fill(){
return poolsize;
return bufsize*2;
};

REALTYPE Stretch::get_stretch_multiplier(REALTYPE pos_percents){


+ 19
- 7
Stretch.h View File

@@ -62,33 +62,45 @@ class Stretch{
//in_bufsize is also a half of a FFT buffer (in samples)
virtual ~Stretch();

int get_max_bufsize(){
return bufsize*2;
};
int get_bufsize(){
return bufsize;
};

void process(REALTYPE *smps,int nsmps);
// virtual void process_output(REALTYPE *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;
REALTYPE *out_buf;//pot sa pun o variabila "max_out_bufsize" si asta sa fie marimea lui out_buf si pe out_bufsize sa il folosesc ca marime adaptiva

int get_nsamples(REALTYPE current_pos_percents);//how many samples are required to be added in the pool next time
int get_nsamples(REALTYPE current_pos_percents);//how many samples are required
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(REALTYPE newrap);//set the current stretch value

FFTWindow window_type;
protected:
int bufsize;

virtual void process_spectrum(REALTYPE *freq){};
virtual REALTYPE get_stretch_multiplier(REALTYPE pos_percents);
REALTYPE samplerate;
int stereo_mode;//0=mono,1=left,2=right
private:
REALTYPE *in_pool;//de marimea in_bufsize

void do_analyse_inbuf(REALTYPE *smps);

// REALTYPE *in_pool;//de marimea in_bufsize
REALTYPE rap;
REALTYPE *old_out_smp_buf;
REALTYPE *old_out_smps;
REALTYPE *old_freq,*old_smps;

FFT *infft,*outfft;
long double remained_samples;//how many fraction of samples has remained (0..1)
long double remained_samples;//0..1
REALTYPE c_pos_percents;
bool require_new_buffer;
bool bypass;
};



Loading…
Cancel
Save