paulstretch_cpp

PaulStretch
Log | Files | Refs | LICENSE

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