diff --git a/Control.cpp b/Control.cpp index e257f36..ea7e2b0 100644 --- a/Control.cpp +++ b/Control.cpp @@ -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]; diff --git a/Input/AInputS.cpp b/Input/AInputS.cpp index ac498de..0db1fdb 100644 --- a/Input/AInputS.cpp +++ b/Input/AInputS.cpp @@ -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;iset_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); diff --git a/ProcessedStretch.cpp b/ProcessedStretch.cpp index d23c306..bdf3cbe 100644 --- a/ProcessedStretch.cpp +++ b/ProcessedStretch.cpp @@ -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]; diff --git a/Stretch.cpp b/Stretch.cpp index 5059f6f..fe434be 100644 --- a/Stretch.cpp +++ b/Stretch.cpp @@ -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=1.0)&&(newrap>=1.0)) rap=newrap; }; + +void Stretch::do_analyse_inbuf(REALTYPE *smps){ + //get the frequencies + for (int i=0;ismp[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;ipoolsize){ - 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;ismp[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;ifreq[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;ifreq[i]=infft->freq[poshi]*(1.0-poslo)+infft->freq[poshi+1]*poslo; - }; - }else{//output is shorter - for (int i=0;ifreq[i]=0.0; - REALTYPE rap=(REALTYPE)out_bufsize/(REALTYPE)in_bufsize; - for (int i=0;ifreq[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;ifreq[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;ismp[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;ismp[i]; - for (int i=0;ismp[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;ismp[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){ diff --git a/Stretch.h b/Stretch.h index ea22ebc..8462377 100644 --- a/Stretch.h +++ b/Stretch.h @@ -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; };