@@ -274,16 +274,13 @@ void Control::set_stretch_controls(double stretch_s,int mode,double fftsize_s,do | |||||
stretch=pow(10.0,stretch_s*18.0); | stretch=pow(10.0,stretch_s*18.0); | ||||
break; | break; | ||||
case 2: | case 2: | ||||
stretch=1.0/pow(10.0,stretch_s*3.0); | |||||
if (stretch<0.1) stretch=0.1; | |||||
stretch=1.0/pow(10.0,stretch_s*2.0); | |||||
break; | break; | ||||
}; | }; | ||||
fftsize_s=pow(fftsize_s,1.5); | fftsize_s=pow(fftsize_s,1.5); | ||||
double tmp=1.0; | |||||
if (mode==2) tmp=1.0/stretch; | |||||
int bufsize=(int)(pow(2.0,fftsize_s*12.0)*512.0*tmp); | |||||
int bufsize=(int)(pow(2.0,fftsize_s*12.0)*512.0); | |||||
bufsize=optimizebufsize(bufsize); | bufsize=optimizebufsize(bufsize); | ||||
@@ -308,7 +305,7 @@ double Control::get_stretch_control(double stretch,int mode){ | |||||
break; | break; | ||||
case 2: | case 2: | ||||
if (stretch>1.0) return -1; | if (stretch>1.0) return -1; | ||||
result=3.0/(log(stretch)/log(10)); | |||||
result=2.0/(log(stretch)/log(10)); | |||||
break; | break; | ||||
}; | }; | ||||
return result; | return result; | ||||
@@ -425,6 +422,7 @@ string Control::Render(string inaudio,string outaudio,FILE_TYPE outtype,FILE_TYP | |||||
}; | }; | ||||
int readed=0; | int readed=0; | ||||
if (readsize!=0) readed=ai->read(readsize,inbuf_i); | if (readsize!=0) readed=ai->read(readsize,inbuf_i); | ||||
for (int i=0;i<readed;i++) { | for (int i=0;i<readed;i++) { | ||||
inbuf.l[i]=inbuf_i[i*2]/32768.0; | inbuf.l[i]=inbuf_i[i*2]/32768.0; | ||||
inbuf.r[i]=inbuf_i[i*2+1]/32768.0; | inbuf.r[i]=inbuf_i[i*2+1]/32768.0; | ||||
@@ -439,6 +437,9 @@ string Control::Render(string inaudio,string outaudio,FILE_TYPE outtype,FILE_TYP | |||||
stretchl->out_buf[i]*=volume; | stretchl->out_buf[i]*=volume; | ||||
stretchr->out_buf[i]*=volume; | stretchr->out_buf[i]*=volume; | ||||
}; | }; | ||||
int nskip=stretchl->get_skip_nsamples(); | |||||
if (nskip>0) ai->skip(nskip); | |||||
if (outtype==FILE_WAV){ | if (outtype==FILE_WAV){ | ||||
for (int i=0;i<outbufsize;i++) { | for (int i=0;i<outbufsize;i++) { | ||||
REALTYPE l=stretchl->out_buf[i],r=stretchr->out_buf[i]; | REALTYPE l=stretchl->out_buf[i],r=stretchr->out_buf[i]; | ||||
@@ -267,7 +267,7 @@ render();} | |||||
xywh {5 50 985 420} box BORDER_BOX | xywh {5 50 985 420} box BORDER_BOX | ||||
} { | } { | ||||
Fl_Group {} { | Fl_Group {} { | ||||
label Parameters open selected | |||||
label Parameters open | |||||
xywh {5 70 985 400} | xywh {5 70 985 400} | ||||
} { | } { | ||||
Fl_Slider stretch_slider { | Fl_Slider stretch_slider { | ||||
@@ -284,7 +284,8 @@ o->labelcolor(FL_BLUE);} | |||||
} | } | ||||
Fl_Choice mode_choice { | Fl_Choice mode_choice { | ||||
label {Mode:} | label {Mode:} | ||||
callback {refresh();} | |||||
callback {refresh(); | |||||
control.update_player_stretch();} selected | |||||
xywh {850 110 135 20} down_box BORDER_BOX | xywh {850 110 135 20} down_box BORDER_BOX | ||||
} { | } { | ||||
MenuItem {} { | MenuItem {} { | ||||
@@ -715,7 +716,7 @@ selection_pos2->value(100.0);} | |||||
tooltip {drag audio file here to open it} xywh {5 24 1005 22} box FLAT_BOX color 17 align 84 | tooltip {drag audio file here to open it} xywh {5 24 1005 22} box FLAT_BOX color 17 align 84 | ||||
class DDBox | class DDBox | ||||
} | } | ||||
Fl_Group {} { | |||||
Fl_Group {} {open | |||||
xywh {5 475 985 70} box BORDER_BOX | xywh {5 475 985 70} box BORDER_BOX | ||||
} { | } { | ||||
Fl_Group {} {open | Fl_Group {} {open | ||||
@@ -735,7 +736,7 @@ bool bypass=false; | |||||
if (Fl::event_button()==FL_RIGHT_MOUSE) bypass=true; | if (Fl::event_button()==FL_RIGHT_MOUSE) bypass=true; | ||||
control.startplay(bypass);} | control.startplay(bypass);} | ||||
tooltip Play xywh {20 500 40 20} box PLASTIC_UP_BOX | |||||
tooltip {Play - right click to play the original sound} xywh {20 500 40 20} box PLASTIC_UP_BOX | |||||
} | } | ||||
Fl_Button freeze_button { | Fl_Button freeze_button { | ||||
label {@<-> F} | label {@<-> F} | ||||
@@ -791,23 +792,23 @@ control.stopplay();} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
Function {set_mode(Mode mode)} {private | |||||
Function {set_mode(Mode mode)} {open private | |||||
} { | } { | ||||
code {switch (mode){ | code {switch (mode){ | ||||
case STOP: | case STOP: | ||||
play_button->labelcolor(FL_BLACK); | play_button->labelcolor(FL_BLACK); | ||||
mode_choice->activate(); | |||||
//mode_choice->activate(); | |||||
freeze_button->deactivate(); | freeze_button->deactivate(); | ||||
break; | break; | ||||
case PAUSE: | case PAUSE: | ||||
play_button->labelcolor(FL_BLACK); | play_button->labelcolor(FL_BLACK); | ||||
mode_choice->activate(); | |||||
//mode_choice->activate(); | |||||
break; | break; | ||||
case PLAY: | case PLAY: | ||||
play_button->labelcolor(FL_RED); | play_button->labelcolor(FL_RED); | ||||
mode_choice->deactivate(); | |||||
//mode_choice->deactivate(); | |||||
fftsize_slider->labelcolor(FL_BLACK); | fftsize_slider->labelcolor(FL_BLACK); | ||||
freeze_button->activate(); | freeze_button->activate(); | ||||
break; | break; | ||||
@@ -21,21 +21,39 @@ | |||||
#include "../globals.h" | #include "../globals.h" | ||||
class InputS{ | class InputS{ | ||||
public: | |||||
virtual bool open(std::string filename)=0; | |||||
virtual void close()=0; | |||||
virtual int read(int nsmps,short int *smps)=0; | |||||
virtual void seek(double pos)=0;//0=start,1.0=end | |||||
struct { | |||||
int nsamples; | |||||
int nchannels; | |||||
int samplerate; | |||||
int currentsample; | |||||
} info; | |||||
bool eof; | |||||
public: | |||||
InputS(){ | |||||
skipbufsize=1024; | |||||
skipbuf=new short int[skipbufsize*4]; | |||||
}; | |||||
virtual ~InputS(){ | |||||
delete [] skipbuf; | |||||
}; | |||||
virtual bool open(std::string filename)=0; | |||||
virtual void close()=0; | |||||
virtual int read(int nsmps,short int *smps)=0; | |||||
void skip(int nsmps){ | |||||
while ((nsmps>0)&&(!eof)){ | |||||
int readsize=(nsmps<skipbufsize)?nsmps:skipbufsize; | |||||
read(readsize,skipbuf); | |||||
nsmps-=readsize; | |||||
}; | |||||
}; | |||||
virtual void seek(double pos)=0;//0=start,1.0=end | |||||
struct { | |||||
int nsamples; | |||||
int nchannels; | |||||
int samplerate; | |||||
int currentsample; | |||||
} info; | |||||
bool eof; | |||||
private: | |||||
int skipbufsize; | |||||
short int *skipbuf; | |||||
}; | }; | ||||
#endif | #endif | ||||
@@ -312,8 +312,6 @@ void Player::newtaskcheck(){ | |||||
int n=2*PA_SOUND_BUFFER_SIZE/outbuf.size; | int n=2*PA_SOUND_BUFFER_SIZE/outbuf.size; | ||||
if (n<3) n=3;//min 3 buffers | if (n<3) n=3;//min 3 buffers | ||||
if (n<(min_samples/outbuf.size)) n=(min_samples/outbuf.size);//the internal buffers sums "min_samples" amount | if (n<(min_samples/outbuf.size)) n=(min_samples/outbuf.size);//the internal buffers sums "min_samples" amount | ||||
// printf("PA_BUFSIZE=%d out_bufsize=%d => %d\n",PA_SOUND_BUFFER_SIZE,outbuf.size,n); | |||||
outbuf.n=n; | outbuf.n=n; | ||||
outbuf.nfresh=0; | outbuf.nfresh=0; | ||||
outbuf.datal=new float *[outbuf.n]; | outbuf.datal=new float *[outbuf.n]; | ||||
@@ -418,6 +416,9 @@ void Player::computesamples(){ | |||||
binaural_beats->process(stretchl->out_buf,stretchr->out_buf,stretchl->get_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); | // stretchl->process_output(stretchl->out_buf,stretchl->out_bufsize); | ||||
// stretchr->process_output(stretchr->out_buf,stretchr->out_bufsize); | // stretchr->process_output(stretchr->out_buf,stretchr->out_bufsize); | ||||
int nskip=stretchl->get_skip_nsamples(); | |||||
if (nskip>0) ai->skip(nskip); | |||||
bufmutex.lock(); | bufmutex.lock(); | ||||
@@ -1,5 +1,5 @@ | |||||
/* | /* | ||||
Copyright (C) 2006-2009 Nasca Octavian Paul | |||||
Copyright (C) 2006-2011 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | Author: Nasca Octavian Paul | ||||
This program is free software; you can redistribute it and/or modify | This program is free software; you can redistribute it and/or modify | ||||
@@ -178,6 +178,7 @@ Stretch::Stretch(REALTYPE rap_,int bufsize_,FFTWindow w,bool bypass_,REALTYPE sa | |||||
require_new_buffer=false; | require_new_buffer=false; | ||||
c_pos_percents=0.0; | c_pos_percents=0.0; | ||||
extra_onset_time_credit=0.0; | extra_onset_time_credit=0.0; | ||||
skip_samples=0; | |||||
}; | }; | ||||
Stretch::~Stretch(){ | Stretch::~Stretch(){ | ||||
@@ -193,7 +194,8 @@ Stretch::~Stretch(){ | |||||
}; | }; | ||||
void Stretch::set_rap(REALTYPE newrap){ | void Stretch::set_rap(REALTYPE newrap){ | ||||
if ((rap>=1.0)&&(newrap>=1.0)) rap=newrap; | |||||
//if ((rap>=1.0)&&(newrap>=1.0)) | |||||
rap=newrap; | |||||
}; | }; | ||||
void Stretch::do_analyse_inbuf(REALTYPE *smps){ | void Stretch::do_analyse_inbuf(REALTYPE *smps){ | ||||
@@ -327,6 +329,7 @@ REALTYPE Stretch::process(REALTYPE *smps,int nsmps){ | |||||
remained_samples+=r; | remained_samples+=r; | ||||
int result=0; | int result=0; | ||||
if (remained_samples>=1.0){ | if (remained_samples>=1.0){ | ||||
skip_samples=(int)(floor(remained_samples-1.0)*bufsize); | |||||
remained_samples=remained_samples-floor(remained_samples); | remained_samples=remained_samples-floor(remained_samples); | ||||
require_new_buffer=true; | require_new_buffer=true; | ||||
}else{ | }else{ | ||||
@@ -343,6 +346,7 @@ void Stretch::here_is_onset(REALTYPE onset){ | |||||
require_new_buffer=true; | require_new_buffer=true; | ||||
extra_onset_time_credit+=1.0-remained_samples; | extra_onset_time_credit+=1.0-remained_samples; | ||||
remained_samples=0.0; | remained_samples=0.0; | ||||
skip_samples=0; | |||||
}; | }; | ||||
}; | }; | ||||
@@ -356,6 +360,10 @@ int Stretch::get_nsamples_for_fill(){ | |||||
return bufsize*2; | return bufsize*2; | ||||
}; | }; | ||||
int Stretch::get_skip_nsamples(){ | |||||
return skip_samples; | |||||
}; | |||||
REALTYPE Stretch::get_stretch_multiplier(REALTYPE pos_percents){ | REALTYPE Stretch::get_stretch_multiplier(REALTYPE pos_percents){ | ||||
return 1.0; | return 1.0; | ||||
}; | }; | ||||
@@ -80,6 +80,7 @@ class Stretch{ | |||||
int get_nsamples(REALTYPE current_pos_percents);//how many samples are required | 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) | 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) | ||||
int get_skip_nsamples();//used for shorten | |||||
void set_rap(REALTYPE newrap);//set the current stretch value | void set_rap(REALTYPE newrap);//set the current stretch value | ||||
@@ -114,6 +115,7 @@ class Stretch{ | |||||
long double remained_samples;//0..1 | long double remained_samples;//0..1 | ||||
long double extra_onset_time_credit; | long double extra_onset_time_credit; | ||||
REALTYPE c_pos_percents; | REALTYPE c_pos_percents; | ||||
int skip_samples; | |||||
bool require_new_buffer; | bool require_new_buffer; | ||||
bool bypass; | bool bypass; | ||||
}; | }; | ||||
@@ -68,11 +68,11 @@ History: | |||||
20110211(2.1-0) | 20110211(2.1-0) | ||||
- Increased the precision of a paremeter for extreme long stretches | - Increased the precision of a paremeter for extreme long stretches | ||||
2011????(2.) | |||||
20110303(2.2) | |||||
- Improved the stretching algorithm, adding the onset detection | |||||
- Shorten algorithm improvements | |||||
- Added an option to preserve the tonal part or noise part | - Added an option to preserve the tonal part or noise part | ||||
- Ignored the commandline parameters starting with "-" (usefull for macosx) | - Ignored the commandline parameters starting with "-" (usefull for macosx) | ||||
- Improved the algorithm | |||||
- Added onset detection | |||||
Enjoy! :) | Enjoy! :) | ||||
Paul | Paul | ||||