Player.cpp (10883B)
1 /* 2 Copyright (C) 2006-2009 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 <stdlib.h> 19 #include <stdio.h> 20 #include <unistd.h> 21 #include <math.h> 22 #include "Player.h" 23 #include "globals.h" 24 25 static int player_count=0; 26 27 Player::Player():Thread(){ 28 player_count++; 29 if (player_count>1) { 30 printf("Error: Player class multiples instances.\n"); 31 exit(1); 32 }; 33 34 stretchl=NULL; 35 stretchr=NULL; 36 binaural_beats=NULL; 37 38 ai=NULL; 39 40 newtask.mode=TASK_NONE; 41 newtask.startpos=0.0; 42 newtask.rap=1.0; 43 newtask.fftsize=4096; 44 45 task=newtask; 46 mode=MODE_STOP; 47 48 outbuf.n=0; 49 outbuf.datal=NULL; 50 outbuf.datar=NULL; 51 outbuf.size=0; 52 outbuf.computek=0; 53 outbuf.outk=0; 54 outbuf.outpos=0; 55 outbuf.nfresh=0; 56 outbuf.in_position=0; 57 inbuf_i=NULL; 58 info.position=0; 59 freeze_mode=false; 60 bypass_mode=false; 61 first_in_buf=true; 62 window_type=W_HANN; 63 inbuf.l=NULL; 64 inbuf.r=NULL; 65 66 paused=false; 67 68 info.playing=false; 69 info.samplerate=44100; 70 info.eof=true; 71 volume=1.0; 72 onset_detection_sensitivity=0.0; 73 }; 74 75 Player::~Player(){ 76 player_count--; 77 78 stop(); 79 if (stretchl) delete stretchl;stretchl=NULL; 80 if (stretchr) delete stretchr;stretchr=NULL; 81 if (outbuf.in_position) delete outbuf.in_position; 82 if (inbuf.l) delete inbuf.l; 83 if (inbuf.r) delete inbuf.r; 84 if (inbuf_i) delete inbuf_i; 85 if (ai) delete ai; 86 if (binaural_beats) delete binaural_beats;binaural_beats=NULL; 87 }; 88 89 Player::ModeType Player::getmode(){ 90 return mode; 91 }; 92 93 void Player::startplay(std::string filename, REALTYPE startpos,REALTYPE rap, int fftsize,FILE_TYPE intype,bool bypass,ProcessParameters *ppar,BinauralBeatsParameters *bbpar){ 94 info.playing=false; 95 info.eof=false; 96 bypass_mode=bypass; 97 if (bypass) freeze_mode=false; 98 paused=false; 99 taskmutex.lock(); 100 newtask.mode=TASK_START; 101 newtask.filename=filename; 102 newtask.startpos=startpos; 103 newtask.rap=rap; 104 newtask.fftsize=fftsize; 105 newtask.intype=intype; 106 newtask.bypass=bypass; 107 newtask.ppar=ppar; 108 newtask.bbpar=bbpar; 109 taskmutex.unlock(); 110 }; 111 112 void Player::stop(){ 113 //pun 0 la outbuf 114 info.playing=false; 115 /* taskmutex.lock(); 116 newtask.mode=TASK_STOP; 117 taskmutex.unlock();*/ 118 }; 119 void Player::pause(){ 120 paused=!paused; 121 }; 122 123 void Player::seek(REALTYPE pos){ 124 taskmutex.lock(); 125 newtask.mode=TASK_SEEK; 126 newtask.startpos=pos; 127 taskmutex.unlock(); 128 }; 129 void Player::freeze(){ 130 freeze_mode=!freeze_mode; 131 if (bypass_mode) freeze_mode=false; 132 }; 133 134 void Player::setrap(REALTYPE newrap){ 135 taskmutex.lock(); 136 newtask.mode=TASK_RAP; 137 newtask.rap=newrap; 138 taskmutex.unlock(); 139 }; 140 141 void Player::set_process_parameters(ProcessParameters *ppar,BinauralBeatsParameters *bbpar){ 142 taskmutex.lock(); 143 newtask.mode=TASK_PARAMETERS; 144 newtask.ppar=ppar; 145 newtask.bbpar=bbpar; 146 taskmutex.unlock(); 147 }; 148 149 150 void Player::set_window_type(FFTWindow window){ 151 window_type=window; 152 }; 153 154 void Player::set_volume(REALTYPE vol){ 155 volume=vol; 156 }; 157 void Player::set_onset_detection_sensitivity(REALTYPE onset){ 158 onset_detection_sensitivity=onset; 159 }; 160 161 void Player::getaudiobuffer(int nsamples, float *out){ 162 if (mode==MODE_PREPARING){ 163 for (int i=0;i<nsamples*2;i++){ 164 out[i]=0.0; 165 }; 166 return; 167 }; 168 if (paused){ 169 for (int i=0;i<nsamples*2;i++){ 170 out[i]=0.0; 171 }; 172 return; 173 }; 174 175 bufmutex.lock(); 176 if ((outbuf.n==0)||(outbuf.nfresh==0)){ 177 bufmutex.unlock(); 178 for (int i=0;i<nsamples*2;i++){ 179 out[i]=0.0; 180 }; 181 return; 182 }; 183 int k=outbuf.outk,pos=outbuf.outpos; 184 185 // printf("%d in_pos=%g\n",info.eof,outbuf.in_position[k]); 186 if (info.eof) mode=MODE_STOP; 187 else info.position=outbuf.in_position[k]; 188 for (int i=0;i<nsamples;i++){ 189 out[i*2]=outbuf.datal[k][pos]*volume; 190 out[i*2+1]=outbuf.datar[k][pos]*volume; 191 192 pos++; 193 if (pos>=outbuf.size) { 194 pos=0; 195 k++; 196 if (k>=outbuf.n) k=0; 197 198 outbuf.nfresh--; 199 //printf("%d %d\n",k,outbuf.nfresh); 200 201 if (outbuf.nfresh<0){//Underflow 202 outbuf.nfresh=0; 203 for (int j=i;j<nsamples;j++){ 204 out[j*2]=0.0; 205 out[j*2+1]=0.0; 206 }; 207 break; 208 }; 209 210 }; 211 }; 212 outbuf.outk=k; 213 outbuf.outpos=pos; 214 bufmutex.unlock(); 215 216 217 }; 218 219 220 void Player::run(){ 221 while(1){ 222 newtaskcheck(); 223 224 if (mode==MODE_STOP) sleep(10); 225 if ((mode==MODE_PLAY)||(mode==MODE_PREPARING)){ 226 computesamples(); 227 }; 228 229 230 task.mode=TASK_NONE; 231 232 }; 233 }; 234 235 void Player::newtaskcheck(){ 236 TaskMode newmode=TASK_NONE; 237 taskmutex.lock(); 238 if (task.mode!=newtask.mode) { 239 newmode=newtask.mode; 240 task=newtask; 241 }; 242 newtask.mode=TASK_NONE; 243 taskmutex.unlock(); 244 245 if (newmode==TASK_START){ 246 if (current_filename!=task.filename){ 247 current_filename=task.filename; 248 task.startpos=0.0; 249 }; 250 switch (task.intype){ 251 case FILE_VORBIS:ai=new VorbisInputS; 252 break; 253 case FILE_MP3:ai=new MP3InputS; 254 break; 255 default: ai=new AInputS; 256 }; 257 if (ai->open(task.filename)){ 258 info.samplerate=ai->info.samplerate; 259 mode=MODE_PREPARING; 260 ai->seek(task.startpos); 261 262 bufmutex.lock(); 263 264 if (stretchl) delete stretchl;stretchl=NULL; 265 if (stretchr) delete stretchr;stretchr=NULL; 266 stretchl=new ProcessedStretch(task.rap,task.fftsize,window_type,task.bypass,ai->info.samplerate,1); 267 stretchr=new ProcessedStretch(task.rap,task.fftsize,window_type,task.bypass,ai->info.samplerate,2); 268 if (binaural_beats) delete binaural_beats;binaural_beats=NULL; 269 binaural_beats=new BinauralBeats(ai->info.samplerate); 270 271 if (stretchl) stretchl->set_parameters(task.ppar); 272 if (stretchr) stretchr->set_parameters(task.ppar); 273 if (binaural_beats) binaural_beats->pars=*(task.bbpar); 274 275 inbufsize=stretchl->get_max_bufsize(); 276 if (inbuf.l) delete []inbuf.l;inbuf.l=NULL; 277 if (inbuf.r) delete []inbuf.r;inbuf.r=NULL; 278 inbuf.l=new REALTYPE[inbufsize]; 279 inbuf.r=new REALTYPE[inbufsize]; 280 for (int i=0;i<inbufsize;i++) inbuf.l[i]=inbuf.r[i]=0.0; 281 282 if (outbuf.datal){ 283 for (int j=0;j<outbuf.n;j++){ 284 delete [] outbuf.datal[j]; 285 }; 286 delete [] outbuf.datal; 287 outbuf.datal=NULL; 288 }; 289 if (outbuf.datar){ 290 for (int j=0;j<outbuf.n;j++){ 291 delete [] outbuf.datar[j]; 292 }; 293 delete [] outbuf.datar; 294 outbuf.datar=NULL; 295 }; 296 delete[] inbuf_i; 297 298 if (outbuf.in_position) { 299 delete outbuf.in_position; 300 outbuf.in_position=NULL; 301 }; 302 303 inbuf_i=new short int[inbufsize*2];//for left and right 304 for (int i=0;i<inbufsize;i++){ 305 inbuf_i[i*2]=inbuf_i[i*2+1]=0; 306 }; 307 first_in_buf=true; 308 309 outbuf.size=stretchl->get_bufsize(); 310 311 int min_samples=ai->info.samplerate*2; 312 int n=2*PA_SOUND_BUFFER_SIZE/outbuf.size; 313 if (n<3) n=3;//min 3 buffers 314 if (n<(min_samples/outbuf.size)) n=(min_samples/outbuf.size);//the internal buffers sums "min_samples" amount 315 outbuf.n=n; 316 outbuf.nfresh=0; 317 outbuf.datal=new float *[outbuf.n]; 318 outbuf.datar=new float *[outbuf.n]; 319 outbuf.computek=0; 320 outbuf.outk=0; 321 outbuf.outpos=0; 322 outbuf.in_position=new float[outbuf.n]; 323 for (int j=0;j<outbuf.n;j++){ 324 outbuf.datal[j]=new float[outbuf.size]; 325 for (int i=0;i<outbuf.size;i++) outbuf.datal[j][i]=0.0; 326 outbuf.datar[j]=new float[outbuf.size]; 327 for (int i=0;i<outbuf.size;i++) outbuf.datar[j][i]=0.0; 328 outbuf.in_position[j]=0.0; 329 }; 330 331 bufmutex.unlock(); 332 333 }; 334 }; 335 if (newmode==TASK_SEEK){ 336 if (ai) ai->seek(task.startpos); 337 first_in_buf=true; 338 }; 339 if (newmode==TASK_RAP){ 340 if (stretchl) stretchl->set_rap(task.rap); 341 if (stretchl) stretchr->set_rap(task.rap); 342 }; 343 if (newmode==TASK_PARAMETERS){ 344 if (stretchl) stretchl->set_parameters(task.ppar); 345 if (stretchr) stretchr->set_parameters(task.ppar); 346 if (binaural_beats) binaural_beats->pars=*(task.bbpar); 347 }; 348 }; 349 350 void Player::computesamples(){ 351 bufmutex.lock(); 352 bool exitnow=(outbuf.n==0); 353 if (outbuf.nfresh>=(outbuf.n-1)) exitnow=true;//buffers are full 354 355 bufmutex.unlock(); 356 if (exitnow) { 357 if (mode==MODE_PREPARING) { 358 info.playing=true; 359 mode=MODE_PLAY; 360 }; 361 sleep(10); 362 return; 363 }; 364 365 bool eof=false; 366 if (!ai) eof=true; 367 else if (ai->eof) eof=true; 368 if (eof){ 369 for (int i=0;i<inbufsize;i++){ 370 inbuf_i[i*2]=inbuf_i[i*2+1]=0; 371 }; 372 outbuf.nfresh++; 373 bufmutex.lock(); 374 for (int i=0;i<outbuf.size;i++){ 375 outbuf.datal[outbuf.computek][i]=0.0; 376 outbuf.datar[outbuf.computek][i]=0.0; 377 }; 378 outbuf.computek++; 379 if (outbuf.computek>=outbuf.n){ 380 outbuf.computek=0; 381 }; 382 bufmutex.unlock(); 383 info.eof=true; 384 return; 385 }; 386 387 bool result=true; 388 float in_pos_100=(REALTYPE) ai->info.currentsample/(REALTYPE)ai->info.nsamples*100.0; 389 int readsize=stretchl->get_nsamples(in_pos_100); 390 391 392 if (first_in_buf) readsize=stretchl->get_nsamples_for_fill(); 393 else if (freeze_mode) readsize=0; 394 if (readsize) result=(ai->read(readsize,inbuf_i)==(readsize)); 395 if (result){ 396 float in_pos=(REALTYPE) ai->info.currentsample/(REALTYPE)ai->info.nsamples; 397 if (ai->eof) in_pos=0.0; 398 399 REALTYPE tmp=1.0/32768.0; 400 for (int i=0;i<readsize;i++){ 401 inbuf.l[i]=inbuf_i[i*2]*tmp; 402 inbuf.r[i]=inbuf_i[i*2+1]*tmp; 403 }; 404 405 stretchl->window_type=window_type; 406 stretchr->window_type=window_type; 407 REALTYPE s_onset=onset_detection_sensitivity; 408 stretchl->set_onset_detection_sensitivity(s_onset); 409 stretchr->set_onset_detection_sensitivity(s_onset); 410 bool freezing=freeze_mode&&(!first_in_buf); 411 stretchl->set_freezing(freezing); 412 stretchr->set_freezing(freezing); 413 414 REALTYPE onset_l=stretchl->process(inbuf.l,readsize); 415 REALTYPE onset_r=stretchr->process(inbuf.r,readsize); 416 REALTYPE onset=(onset_l>onset_r)?onset_l:onset_r; 417 stretchl->here_is_onset(onset); 418 stretchr->here_is_onset(onset); 419 420 binaural_beats->process(stretchl->out_buf,stretchr->out_buf,stretchl->get_bufsize(),in_pos_100); 421 // stretchl->process_output(stretchl->out_buf,stretchl->out_bufsize); 422 // stretchr->process_output(stretchr->out_buf,stretchr->out_bufsize); 423 int nskip=stretchl->get_skip_nsamples(); 424 if (nskip>0) ai->skip(nskip); 425 426 427 first_in_buf=false; 428 bufmutex.lock(); 429 430 for (int i=0;i<outbuf.size;i++){ 431 REALTYPE l=stretchl->out_buf[i],r=stretchr->out_buf[i]; 432 if (l<-1.0) l=-1.0; 433 else if (l>1.0) l=1.0; 434 if (r<-1.0) r=-1.0; 435 else if (r>1.0) r=1.0; 436 437 outbuf.datal[outbuf.computek][i]=l; 438 outbuf.datar[outbuf.computek][i]=r; 439 }; 440 outbuf.in_position[outbuf.computek]=in_pos; 441 outbuf.computek++; 442 if (outbuf.computek>=outbuf.n){ 443 outbuf.computek=0; 444 }; 445 bufmutex.unlock(); 446 outbuf.nfresh++; 447 }else{ 448 info.eof=true; 449 mode=MODE_STOP; 450 stop(); 451 }; 452 }; 453