Control.cpp (15465B)
1 /* 2 Copyright (C) 2006-2011 Nasca Octavian Paul 3 Author: Nasca Octavian Paul 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of version 2 of the GNU General Public License 7 as published by the Free Software Foundation. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License (version 2) for more details. 13 14 You should have received a copy of the GNU General Public License (version 2) 15 along with this program; if not, write to the Free Software Foundation, 16 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 #include <math.h> 19 #include <stdlib.h> 20 #include <FL/Fl.H> 21 #include "globals.h" 22 #include "Control.h" 23 #include "XMLwrapper.h" 24 using namespace std; 25 26 Control::Control(){ 27 player=new Player(); 28 player->start(); 29 30 wavinfo.samplerate=44100; 31 wavinfo.nsamples=0; 32 wavinfo.intype=FILE_WAV; 33 wav32bit=false; 34 35 process.bufsize=16384; 36 process.stretch=4.0; 37 process.onset_detection_sensitivity=0.0; 38 39 seek_pos=0.0; 40 window_type=W_HANN; 41 info.render_percent=-1.0; 42 info.cancel_render=false; 43 volume=1.0; 44 45 46 gui_sliders.fftsize_s=0.5; 47 gui_sliders.stretch_s=0.5; 48 gui_sliders.mode_s=0; 49 50 51 ///#warning test 52 /// process.transient.enable=true; 53 }; 54 55 Control::~Control(){ 56 // delete player; face crash daca il las 57 }; 58 59 60 bool Control::set_input_filename(string filename,FILE_TYPE intype){ 61 InputS *ai=NULL; 62 if (intype==FILE_VORBIS) ai=new VorbisInputS; 63 if (intype==FILE_MP3) ai=new MP3InputS; 64 if (intype==FILE_WAV) ai=new AInputS; 65 if (!ai) return false; 66 wavinfo.filename=filename; 67 wavinfo.intype=intype; 68 bool result=ai->open(wavinfo.filename); 69 if (result) { 70 wavinfo.samplerate=ai->info.samplerate; 71 wavinfo.nsamples=ai->info.nsamples; 72 /// if (process.transient.enable) { 73 /// pre_analyse_whole_audio(ai); 74 /// }; 75 76 delete ai; 77 }else{ 78 wavinfo.filename=""; 79 wavinfo.samplerate=0; 80 wavinfo.nsamples=0; 81 delete ai; 82 }; 83 return result; 84 }; 85 86 string Control::get_input_filename(){ 87 return wavinfo.filename; 88 }; 89 string Control::get_input_filename_and_info(){ 90 int seconds=wavinfo.nsamples/wavinfo.samplerate; 91 const int size=200; 92 char tmp[size];tmp[size-1]=0; 93 snprintf(tmp,size-1," ( samplerate=%d; duration=%02d:%02d:%02d )",wavinfo.samplerate,seconds/3600,(seconds/60)%60,seconds%60); 94 95 string filename=wavinfo.filename; 96 int len=filename.length(); 97 if (len>70)filename=filename.substr(0,25)+"..."+filename.substr(len-35); 98 return filename+tmp; 99 }; 100 /*string Control::get_recommanded_output_filename(){ 101 return "none"; 102 }; 103 */ 104 105 106 std::string Control::get_stretch_info(){ 107 const int size=200; 108 char tmp[size];tmp[size-1]=0; 109 110 if (wavinfo.nsamples==0) return "Stretch: "; 111 112 113 double realduration=wavinfo.nsamples/wavinfo.samplerate*process.stretch; 114 115 if (realduration>(365.25*86400.0*1.0e12)){//more than 1 trillion years 116 double duration=(realduration/(365.25*86400.0*1.0e12));//my 117 snprintf(tmp,size,"Stretch: %.7gx (%g trillion years)",process.stretch,duration); 118 return tmp; 119 }; 120 if (realduration>(365.25*86400.0*1.0e9)){//more than 1 billion years 121 double duration=(realduration/(365.25*86400.0*1.0e9));//my 122 snprintf(tmp,size,"Stretch: %.7gx (%g billion years)",process.stretch,duration); 123 return tmp; 124 }; 125 if (realduration>(365.25*86400.0*1.0e6)){//more than 1 million years 126 double duration=(realduration/(365.25*86400.0*1.0e6));//my 127 snprintf(tmp,size,"Stretch: %.7gx (%g million years)",process.stretch,duration); 128 return tmp; 129 }; 130 if (realduration>(365.25*86400.0*2000.0)){//more than two millenniums 131 int duration=(int)(realduration/(365.25*86400.0));//years 132 int years=duration%1000; 133 int milleniums=duration/1000; 134 135 char stryears[size];stryears[0]=0; 136 if (years!=0){ 137 if (years==1) snprintf(stryears,size," 1 year"); 138 else snprintf(stryears,size," %d years",years); 139 }; 140 snprintf(tmp,size,"Stretch: %.7gx (%d milleniums%s)",process.stretch,milleniums,stryears); 141 return tmp; 142 }; 143 if (realduration>(365.25*86400.0)){//more than 1 year 144 int duration=(int) (realduration/3600.0);//hours 145 int hours=duration%24; 146 int days=(duration/24)%365; 147 int years=duration/(365*24); 148 149 char stryears[size];stryears[0]=0; 150 if (years==1) snprintf(stryears,size,"1 year "); 151 else snprintf(stryears,size,"%d years ",years); 152 153 char strdays[size];strdays[0]=0; 154 if (days>0){ 155 if (days==1) snprintf(strdays,size,"1 day"); 156 else snprintf(strdays,size,"%d days",days); 157 }; 158 if (years>=10) hours=0; 159 char strhours[size];strhours[0]=0; 160 if (hours>0){ 161 snprintf(strhours,size," %d h",hours); 162 }; 163 164 snprintf(tmp,size,"Stretch: %.7gx (%s%s%s)",process.stretch,stryears,strdays,strhours); 165 return tmp; 166 }else{//less than 1 year 167 int duration=(int)(realduration);//seconds 168 169 char strdays[size];strdays[0]=0; 170 int days=duration/86400; 171 if (days>0){ 172 if (days==1) snprintf(strdays,size,"1 day "); 173 else snprintf(strdays,size,"%d days ",duration/86400); 174 }; 175 REALTYPE stretch=process.stretch; 176 if (stretch>=1.0){ 177 stretch=((int) (stretch*100.0))*0.01; 178 }; 179 snprintf(tmp,size,"Stretch: %.7gx (%s%.2d:%.2d:%.2d)", 180 stretch,strdays,(duration/3600)%24,(duration/60)%60,duration%60); 181 return tmp; 182 }; 183 return ""; 184 }; 185 186 string Control::get_fftsize_info(){ 187 const int size=200; 188 char tmp[size];tmp[size-1]=0; 189 190 string fftsizelabel; 191 fftsizelabel+="Window size (samples): "; 192 193 if (wavinfo.nsamples==0) return fftsizelabel; 194 fftsizelabel+=getfftsizestr(process.bufsize); 195 196 return fftsizelabel; 197 }; 198 199 string Control::get_fftresolution_info(){ 200 string resolution="Resolution: "; 201 if (wavinfo.nsamples==0) return resolution; 202 203 //todo: unctime and uncfreq are correct computed? Need to check later. 204 REALTYPE unctime=process.bufsize/(REALTYPE)wavinfo.samplerate*sqrt(2.0); 205 REALTYPE uncfreq=1.0/unctime*sqrt(2.0); 206 char tmp[100]; 207 snprintf(tmp,100,"%.5g seconds",unctime);resolution+=tmp; 208 snprintf(tmp,100," (%.5g Hz)",uncfreq);resolution+=tmp; 209 return resolution; 210 }; 211 212 213 void Control::startplay(bool bypass){ 214 if ((!player->info.playing)||(player->info.samplerate!=wavinfo.samplerate)){ 215 stopplay(); 216 sleep(200); 217 #ifdef HAVE_JACK 218 JACKaudiooutputinit(player,wavinfo.samplerate); 219 #else 220 PAaudiooutputinit(player,wavinfo.samplerate); 221 #endif 222 }; 223 if (wavinfo.filename!="") player->startplay(wavinfo.filename,seek_pos,process.stretch,process.bufsize,wavinfo.intype,bypass,&ppar,&bbpar); 224 // sleep(100); 225 // update_process_parameters(); 226 }; 227 void Control::stopplay(){ 228 player->stop(); 229 player->seek(0.0); 230 seek_pos=0; 231 #ifdef HAVE_JACK 232 JACKclose(); 233 #else 234 PAfinish(); 235 #endif 236 }; 237 void Control::pauseplay(){ 238 player->pause(); 239 }; 240 241 void Control::freezeplay(){ 242 player->freeze(); 243 }; 244 245 void Control::set_volume(REALTYPE vol){ 246 volume=vol; 247 player->set_volume(vol); 248 }; 249 250 251 void Control::set_seek_pos(REALTYPE x){ 252 seek_pos=x; 253 player->seek(x); 254 }; 255 REALTYPE Control::get_seek_pos(){ 256 if (player->getmode()==Player::MODE_PLAY) seek_pos=player->info.position; 257 return seek_pos; 258 }; 259 260 261 void Control::set_stretch_controls(double stretch_s,int mode,double fftsize_s,double onset_detection_sensitivity){ 262 gui_sliders.stretch_s=stretch_s; 263 gui_sliders.mode_s=mode; 264 gui_sliders.fftsize_s=fftsize_s; 265 266 double stretch=1.0; 267 switch(mode){ 268 case 0: 269 stretch_s=pow(stretch_s,1.2); 270 stretch=pow(10.0,stretch_s*4.0); 271 break; 272 case 1: 273 stretch_s=pow(stretch_s,1.5); 274 stretch=pow(10.0,stretch_s*18.0); 275 break; 276 case 2: 277 stretch=1.0/pow(10.0,stretch_s*2.0); 278 break; 279 }; 280 281 282 fftsize_s=pow(fftsize_s,1.5); 283 int bufsize=(int)(pow(2.0,fftsize_s*12.0)*512.0); 284 285 bufsize=optimizebufsize(bufsize); 286 287 process.stretch=stretch; 288 process.bufsize=bufsize; 289 process.onset_detection_sensitivity=onset_detection_sensitivity; 290 291 }; 292 293 double Control::get_stretch_control(double stretch,int mode){ 294 double result=1.0; 295 switch(mode){ 296 case 0: 297 if (stretch<1.0) return -1; 298 stretch=(log(stretch)/log(10))*0.25; 299 result=pow(stretch,1.0/1.2); 300 break; 301 case 1: 302 if (stretch<1.0) return -1; 303 stretch=(log(stretch)/log(10))/18.0; 304 result=pow(stretch,1.0/1.5); 305 break; 306 case 2: 307 if (stretch>1.0) return -1; 308 result=2.0/(log(stretch)/log(10)); 309 break; 310 }; 311 return result; 312 }; 313 314 315 void Control::update_player_stretch(){ 316 player->setrap(process.stretch); 317 player->set_onset_detection_sensitivity(process.onset_detection_sensitivity); 318 }; 319 320 321 int abs_val(int x){ 322 if (x<0) return -x; 323 else return x; 324 }; 325 326 327 int Control::get_optimized_updown(int n,bool up){ 328 int orig_n=n; 329 while(true){ 330 n=orig_n; 331 #ifndef KISSFFT 332 while (!(n%11)) n/=11; 333 while (!(n%7)) n/=7; 334 #endif 335 while (!(n%5)) n/=5; 336 while (!(n%3)) n/=3; 337 while (!(n%2)) n/=2; 338 if (n<2) break; 339 if (up) orig_n++; 340 else orig_n--; 341 if (orig_n<4) return 4; 342 }; 343 return orig_n; 344 }; 345 int Control::optimizebufsize(int n){ 346 int n1=get_optimized_updown(n,false); 347 int n2=get_optimized_updown(n,true); 348 if ((n-n1)<(n2-n)) return n1; 349 else return n2; 350 }; 351 352 353 354 void Control::set_window_type(FFTWindow window){ 355 window_type=window; 356 if (player) player->set_window_type(window); 357 }; 358 359 360 string Control::Render(string inaudio,string outaudio,FILE_TYPE outtype,FILE_TYPE intype,REALTYPE pos1,REALTYPE pos2){ 361 if (pos2<pos1){ 362 REALTYPE tmp=pos2; 363 pos2=pos1; 364 pos1=tmp; 365 }; 366 InputS *ai=NULL; 367 switch(intype){ 368 case FILE_VORBIS:ai=new VorbisInputS; 369 break; 370 case FILE_MP3:ai=new MP3InputS; 371 break; 372 default:ai=new AInputS; 373 }; 374 AOutputS ao; 375 VorbisOutputS vorbisout; 376 info.cancel_render=false; 377 if (!ai->open(inaudio)){ 378 return "Error: Could not open audio file (or file format not recognized) :"+inaudio; 379 }; 380 BinauralBeats bb(ai->info.samplerate); 381 bb.pars=bbpar; 382 if (outtype==FILE_WAV) ao.newfile(outaudio,ai->info.samplerate,wav32bit); 383 if (outtype==FILE_VORBIS) vorbisout.newfile(outaudio,ai->info.samplerate); 384 385 ai->seek(pos1); 386 387 int inbufsize=process.bufsize; 388 389 if (inbufsize<32) inbufsize=32; 390 short int *inbuf_i=new short int[inbufsize*8]; 391 int outbufsize; 392 struct{ 393 REALTYPE *l,*r; 394 }inbuf; 395 ProcessedStretch *stretchl=new ProcessedStretch(process.stretch,inbufsize,window_type,false,ai->info.samplerate,1); 396 ProcessedStretch *stretchr=new ProcessedStretch(process.stretch,inbufsize,window_type,false,ai->info.samplerate,2); 397 stretchl->set_onset_detection_sensitivity(process.onset_detection_sensitivity); 398 stretchr->set_onset_detection_sensitivity(process.onset_detection_sensitivity); 399 stretchl->set_parameters(&ppar); 400 stretchr->set_parameters(&ppar); 401 402 outbufsize=stretchl->get_bufsize(); 403 int *outbuf=new int[outbufsize*2]; 404 405 int poolsize=stretchl->get_max_bufsize(); 406 407 inbuf.l=new REALTYPE[poolsize]; 408 inbuf.r=new REALTYPE[poolsize]; 409 for (int i=0;i<poolsize;i++) inbuf.l[i]=inbuf.r[i]=0.0; 410 411 int readsize=0; 412 const int pause_max_write=65536; 413 int pause_write=0; 414 bool firstbuf=true; 415 while(!ai->eof){ 416 float in_pos=(REALTYPE) ai->info.currentsample/(REALTYPE)ai->info.nsamples; 417 if (firstbuf){ 418 readsize=stretchl->get_nsamples_for_fill(); 419 firstbuf=false; 420 }else{ 421 readsize=stretchl->get_nsamples(in_pos*100.0); 422 }; 423 int readed=0; 424 if (readsize!=0) readed=ai->read(readsize,inbuf_i); 425 426 for (int i=0;i<readed;i++) { 427 inbuf.l[i]=inbuf_i[i*2]/32768.0; 428 inbuf.r[i]=inbuf_i[i*2+1]/32768.0; 429 }; 430 REALTYPE onset_l=stretchl->process(inbuf.l,readed); 431 REALTYPE onset_r=stretchr->process(inbuf.r,readed); 432 REALTYPE onset=(onset_l>onset_r)?onset_l:onset_r; 433 stretchl->here_is_onset(onset); 434 stretchr->here_is_onset(onset); 435 bb.process(stretchl->out_buf,stretchr->out_buf,outbufsize,in_pos*100.0); 436 for (int i=0;i<outbufsize;i++) { 437 stretchl->out_buf[i]*=volume; 438 stretchr->out_buf[i]*=volume; 439 }; 440 int nskip=stretchl->get_skip_nsamples(); 441 if (nskip>0) ai->skip(nskip); 442 443 if (outtype==FILE_WAV){ 444 for (int i=0;i<outbufsize;i++) { 445 REALTYPE l=stretchl->out_buf[i],r=stretchr->out_buf[i]; 446 if (l<-1.0) l=-1.0; 447 else if (l>1.0) l=1.0; 448 if (r<-1.0) r=-1.0; 449 else if (r>1.0) r=1.0; 450 outbuf[i*2]=(int)(l*32767.0*65536.0); 451 outbuf[i*2+1]=(int)(r*32767.0*65536.0); 452 }; 453 ao.write(outbufsize,outbuf); 454 }; 455 if (outtype==FILE_VORBIS) vorbisout.write(outbufsize,stretchl->out_buf,stretchr->out_buf); 456 457 REALTYPE totalf=ai->info.currentsample/(REALTYPE)ai->info.nsamples-pos1; 458 if (totalf>(pos2-pos1)) break; 459 460 info.render_percent=(totalf*100.0/(pos2-pos1+0.001)); 461 pause_write+=outbufsize; 462 if (pause_write>pause_max_write){ 463 float tmp=outbufsize/1000000.0; 464 if (tmp>0.1) tmp=0.1; 465 Fl::wait(0.01+tmp); 466 pause_write=0; 467 if (info.cancel_render) break; 468 }; 469 }; 470 471 delete stretchl; 472 delete stretchr; 473 delete []outbuf; 474 delete []inbuf_i; 475 delete []inbuf.l; 476 delete []inbuf.r; 477 478 info.render_percent=-1.0; 479 return ""; 480 }; 481 482 483 484 string Control::getfftsizestr(int fftsize){ 485 int size=100; 486 char tmp[size];tmp[size-1]=0; 487 if (fftsize<1024.0) snprintf(tmp,size-1,"%d",fftsize); 488 else if (fftsize<(1024.0*1024.0)) snprintf(tmp,size-1,"%.4gK",fftsize/1024.0); 489 else if (fftsize<(1024.0*1024.0*1024.0)) snprintf(tmp,size-1,"%.4gM",fftsize/(1024.0*1024.0)); 490 else snprintf(tmp,size-1,"%.7gG",fftsize/(1024.0*1024.0*1024.0)); 491 return tmp; 492 }; 493 494 void Control::update_process_parameters(){ 495 if (player) player->set_process_parameters(&ppar,&bbpar); 496 }; 497 498 bool Control::save_parameters(const char *filename){ 499 XMLwrapper *xml=new XMLwrapper(); 500 501 xml->beginbranch("PAULSTRETCH"); 502 xml->beginbranch("STRETCH_PARAMETERS"); 503 xml->beginbranch("BASE"); 504 xml->addpar("bufsize",process.bufsize); 505 xml->addparreal("stretch",process.stretch); 506 507 xml->addparreal("fftsize_s",gui_sliders.fftsize_s); 508 xml->addparreal("stretch_s",gui_sliders.stretch_s); 509 xml->addpar("mode_s",gui_sliders.mode_s); 510 511 xml->addpar("window_type",window_type); 512 xml->addparreal("volume",volume); 513 xml->addparreal("onset_detection_sensitivity",process.onset_detection_sensitivity); 514 515 xml->endbranch(); 516 517 xml->beginbranch("PROCESS"); 518 ppar.add2XML(xml); 519 xml->endbranch(); 520 521 xml->beginbranch("BINAURAL_BEATS"); 522 bbpar.add2XML(xml); 523 xml->endbranch(); 524 525 xml->endbranch(); 526 xml->endbranch(); 527 528 int result=xml->saveXMLfile(filename); 529 delete xml; 530 return true; 531 }; 532 533 bool Control::load_parameters(const char *filename){ 534 XMLwrapper *xml=new XMLwrapper(); 535 536 if (xml->loadXMLfile(filename)<0) { 537 delete xml; 538 return false; 539 }; 540 541 542 if (xml->enterbranch("PAULSTRETCH")==0) { 543 delete xml; 544 return false; 545 }; 546 547 if (xml->enterbranch("STRETCH_PARAMETERS")){ 548 if (xml->enterbranch("BASE")){ 549 process.bufsize=xml->getpar("bufsize",process.bufsize,16,2e9); 550 process.stretch=xml->getparreal("stretch",process.stretch); 551 gui_sliders.fftsize_s=xml->getparreal("fftsize_s",gui_sliders.fftsize_s); 552 gui_sliders.stretch_s=xml->getparreal("stretch_s",gui_sliders.stretch_s); 553 gui_sliders.mode_s=xml->getpar("mode_s",gui_sliders.mode_s,0,2); 554 window_type=(FFTWindow)xml->getpar("window_type",window_type,0,4); 555 process.onset_detection_sensitivity=xml->getparreal("onset_detection_sensitivity",0.0); 556 volume=xml->getparreal("volume",1.0); 557 xml->exitbranch(); 558 }; 559 560 if (xml->enterbranch("PROCESS")){ 561 ppar.getfromXML(xml); 562 xml->exitbranch(); 563 }; 564 565 if (xml->enterbranch("BINAURAL_BEATS")){ 566 bbpar.getfromXML(xml); 567 xml->exitbranch(); 568 }; 569 570 xml->exitbranch(); 571 }; 572 delete xml; 573 574 set_stretch_controls(gui_sliders.stretch_s,gui_sliders.mode_s,gui_sliders.fftsize_s,process.onset_detection_sensitivity); 575 576 set_window_type(window_type); 577 set_volume(volume); 578 update_process_parameters(); 579 return true; 580 }; 581 582