Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

440 lines (375 sloc) 10.402 kb
/*
Copyright (C) 2006-2009 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include "Player.h"
#include "globals.h"
static int player_count=0;
Player::Player():Thread(){
player_count++;
if (player_count>1) {
printf("Error: Player class multiples instances.\n");
exit(1);
};
stretchl=NULL;
stretchr=NULL;
binaural_beats=NULL;
ai=NULL;
newtask.mode=TASK_NONE;
newtask.startpos=0.0;
newtask.rap=1.0;
newtask.fftsize=4096;
task=newtask;
mode=MODE_STOP;
outbuf.n=0;
outbuf.datal=NULL;
outbuf.datar=NULL;
outbuf.size=0;
outbuf.computek=0;
outbuf.outk=0;
outbuf.outpos=0;
outbuf.nfresh=0;
outbuf.in_position=0;
inbuf_i=NULL;
info.position=0;
freeze_mode=false;
bypass_mode=false;
first_in_buf=true;
window_type=W_HANN;
inbuf.l=NULL;
inbuf.r=NULL;
paused=false;
info.playing=false;
info.samplerate=44100;
info.eof=true;
volume=1.0;
};
Player::~Player(){
player_count--;
stop();
if (stretchl) delete stretchl;stretchl=NULL;
if (stretchr) delete stretchr;stretchr=NULL;
if (outbuf.in_position) delete outbuf.in_position;
if (inbuf.l) delete inbuf.l;
if (inbuf.r) delete inbuf.r;
if (inbuf_i) delete inbuf_i;
if (ai) delete ai;
if (binaural_beats) delete binaural_beats;binaural_beats=NULL;
};
Player::ModeType Player::getmode(){
return mode;
};
void Player::startplay(std::string filename, REALTYPE startpos,REALTYPE rap, int fftsize,FILE_TYPE intype,bool bypass,ProcessParameters *ppar,BinauralBeatsParameters *bbpar){
info.playing=false;
info.eof=false;
bypass_mode=bypass;
if (bypass) freeze_mode=false;
paused=false;
taskmutex.lock();
newtask.mode=TASK_START;
newtask.filename=filename;
newtask.startpos=startpos;
newtask.rap=rap;
newtask.fftsize=fftsize;
newtask.intype=intype;
newtask.bypass=bypass;
newtask.ppar=ppar;
newtask.bbpar=bbpar;
taskmutex.unlock();
};
void Player::stop(){
//pun 0 la outbuf
info.playing=false;
/* taskmutex.lock();
newtask.mode=TASK_STOP;
taskmutex.unlock();*/
};
void Player::pause(){
paused=!paused;
};
void Player::seek(REALTYPE pos){
taskmutex.lock();
newtask.mode=TASK_SEEK;
newtask.startpos=pos;
taskmutex.unlock();
};
void Player::freeze(){
freeze_mode=!freeze_mode;
if (bypass_mode) freeze_mode=false;
};
void Player::setrap(REALTYPE newrap){
taskmutex.lock();
newtask.mode=TASK_RAP;
newtask.rap=newrap;
taskmutex.unlock();
};
void Player::set_process_parameters(ProcessParameters *ppar,BinauralBeatsParameters *bbpar){
taskmutex.lock();
newtask.mode=TASK_PARAMETERS;
newtask.ppar=ppar;
newtask.bbpar=bbpar;
taskmutex.unlock();
};
void Player::set_window_type(FFTWindow window){
window_type=window;
};
void Player::set_volume(REALTYPE vol){
volume=vol;
};
void Player::getaudiobuffer(int nsamples, float *out){
if (mode==MODE_PREPARING){
for (int i=0;i<nsamples*2;i++){
out[i]=0.0;
};
return;
};
if (paused){
for (int i=0;i<nsamples*2;i++){
out[i]=0.0;
};
return;
};
bufmutex.lock();
if ((outbuf.n==0)||(outbuf.nfresh==0)){
bufmutex.unlock();
for (int i=0;i<nsamples*2;i++){
out[i]=0.0;
};
return;
};
int k=outbuf.outk,pos=outbuf.outpos;
// printf("%d in_pos=%g\n",info.eof,outbuf.in_position[k]);
if (info.eof) mode=MODE_STOP;
else info.position=outbuf.in_position[k];
for (int i=0;i<nsamples;i++){
out[i*2]=outbuf.datal[k][pos]*volume;
out[i*2+1]=outbuf.datar[k][pos]*volume;
pos++;
if (pos>=outbuf.size) {
pos=0;
k++;
if (k>=outbuf.n) k=0;
outbuf.nfresh--;
//printf("%d %d\n",k,outbuf.nfresh);
if (outbuf.nfresh<0){//Underflow
outbuf.nfresh=0;
for (int j=i;j<nsamples;j++){
out[j*2]=0.0;
out[j*2+1]=0.0;
};
break;
};
};
};
// printf("-------------- %d\n",outbuf.nfresh);
outbuf.outk=k;
outbuf.outpos=pos;
bufmutex.unlock();
// printf("max=%g\n",max);
};
void Player::run(){
while(1){
newtaskcheck();
if (mode==MODE_STOP) sleep(10);
if ((mode==MODE_PLAY)||(mode==MODE_PREPARING)){
computesamples();
};
task.mode=TASK_NONE;
};
};
void Player::newtaskcheck(){
TaskMode newmode=TASK_NONE;
taskmutex.lock();
if (task.mode!=newtask.mode) {
newmode=newtask.mode;
task=newtask;
};
newtask.mode=TASK_NONE;
taskmutex.unlock();
if (newmode==TASK_START){
if (current_filename!=task.filename){
current_filename=task.filename;
task.startpos=0.0;
};
switch (task.intype){
case FILE_VORBIS:ai=new VorbisInputS;
break;
case FILE_MP3:ai=new MP3InputS;
break;
default: ai=new AInputS;
};
if (ai->open(task.filename)){
info.samplerate=ai->info.samplerate;
mode=MODE_PREPARING;
ai->seek(task.startpos);
bufmutex.lock();
if (stretchl) delete stretchl;stretchl=NULL;
if (stretchr) delete stretchr;stretchr=NULL;
stretchl=new ProcessedStretch(task.rap,task.fftsize,window_type,task.bypass,ai->info.samplerate,1);
stretchr=new ProcessedStretch(task.rap,task.fftsize,window_type,task.bypass,ai->info.samplerate,2);
if (binaural_beats) delete binaural_beats;binaural_beats=NULL;
binaural_beats=new BinauralBeats(ai->info.samplerate);
if (stretchl) stretchl->set_parameters(task.ppar);
if (stretchr) stretchr->set_parameters(task.ppar);
if (binaural_beats) binaural_beats->pars=*(task.bbpar);
inbufsize=stretchl->poolsize;
if (inbuf.l) delete []inbuf.l;inbuf.l=NULL;
if (inbuf.r) delete []inbuf.r;inbuf.r=NULL;
inbuf.l=new REALTYPE[inbufsize];
inbuf.r=new REALTYPE[inbufsize];
for (int i=0;i<inbufsize;i++) inbuf.l[i]=inbuf.r[i]=0.0;
if (outbuf.datal){
for (int j=0;j<outbuf.n;j++){
delete [] outbuf.datal[j];
};
delete [] outbuf.datal;
outbuf.datal=NULL;
};
if (outbuf.datar){
for (int j=0;j<outbuf.n;j++){
delete [] outbuf.datar[j];
};
delete [] outbuf.datar;
outbuf.datar=NULL;
};
delete[] inbuf_i;
if (outbuf.in_position) {
delete outbuf.in_position;
outbuf.in_position=NULL;
};
inbuf_i=new short int[inbufsize*2];//for left and right
for (int i=0;i<inbufsize;i++){
inbuf_i[i*2]=inbuf_i[i*2+1]=0;
};
first_in_buf=true;
outbuf.size=stretchl->out_bufsize;
int min_samples=ai->info.samplerate*2;
int n=2*PA_SOUND_BUFFER_SIZE/outbuf.size;
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
// printf("PA_BUFSIZE=%d out_bufsize=%d => %d\n",PA_SOUND_BUFFER_SIZE,outbuf.size,n);
outbuf.n=n;
outbuf.nfresh=0;
outbuf.datal=new float *[outbuf.n];
outbuf.datar=new float *[outbuf.n];
outbuf.computek=0;
outbuf.outk=0;
outbuf.outpos=0;
outbuf.in_position=new float[outbuf.n];
for (int j=0;j<outbuf.n;j++){
outbuf.datal[j]=new float[outbuf.size];
for (int i=0;i<outbuf.size;i++) outbuf.datal[j][i]=0.0;
outbuf.datar[j]=new float[outbuf.size];
for (int i=0;i<outbuf.size;i++) outbuf.datar[j][i]=0.0;
outbuf.in_position[j]=0.0;
};
bufmutex.unlock();
};
};
if (newmode==TASK_SEEK){
if (ai) ai->seek(task.startpos);
first_in_buf=true;
};
if (newmode==TASK_RAP){
if (stretchl) stretchl->set_rap(task.rap);
if (stretchl) stretchr->set_rap(task.rap);
};
if (newmode==TASK_PARAMETERS){
if (stretchl) stretchl->set_parameters(task.ppar);
if (stretchr) stretchr->set_parameters(task.ppar);
if (binaural_beats) binaural_beats->pars=*(task.bbpar);
};
};
void Player::computesamples(){
bufmutex.lock();
bool exitnow=(outbuf.n==0);
if (outbuf.nfresh>=(outbuf.n-1)) exitnow=true;//buffers are full
bufmutex.unlock();
if (exitnow) {
if (mode==MODE_PREPARING) {
info.playing=true;
mode=MODE_PLAY;
};
sleep(10);
return;
};
bool eof=false;
if (!ai) eof=true;
else if (ai->eof) eof=true;
if (eof){
for (int i=0;i<inbufsize;i++){
inbuf_i[i*2]=inbuf_i[i*2+1]=0;
};
outbuf.nfresh++;
bufmutex.lock();
for (int i=0;i<outbuf.size;i++){
outbuf.datal[outbuf.computek][i]=0.0;
outbuf.datar[outbuf.computek][i]=0.0;
};
outbuf.computek++;
if (outbuf.computek>=outbuf.n){
outbuf.computek=0;
};
bufmutex.unlock();
info.eof=true;
return;
};
bool result=true;
float in_pos_100=(REALTYPE) ai->info.currentsample/(REALTYPE)ai->info.nsamples*100.0;
int readsize=stretchl->get_nsamples(in_pos_100);
if (freeze_mode) readsize=0;
if (first_in_buf) readsize=stretchl->get_nsamples_for_fill();
if (readsize) result=(ai->read(readsize,inbuf_i)==(readsize));
if (result){
float in_pos=(REALTYPE) ai->info.currentsample/(REALTYPE)ai->info.nsamples;
if (ai->eof) in_pos=0.0;
REALTYPE tmp=1.0/32768.0;
for (int i=0;i<readsize;i++){
inbuf.l[i]=inbuf_i[i*2]*tmp;
inbuf.r[i]=inbuf_i[i*2+1]*tmp;
};
first_in_buf=false;
stretchl->window_type=window_type;
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);
// stretchl->process_output(stretchl->out_buf,stretchl->out_bufsize);
// stretchr->process_output(stretchr->out_buf,stretchr->out_bufsize);
bufmutex.lock();
for (int i=0;i<outbuf.size;i++){
REALTYPE l=stretchl->out_buf[i],r=stretchr->out_buf[i];
if (l<-1.0) l=-1.0;
else if (l>1.0) l=1.0;
if (r<-1.0) r=-1.0;
else if (r>1.0) r=1.0;
outbuf.datal[outbuf.computek][i]=l;
outbuf.datar[outbuf.computek][i]=r;
};
outbuf.in_position[outbuf.computek]=in_pos;
outbuf.computek++;
if (outbuf.computek>=outbuf.n){
outbuf.computek=0;
};
bufmutex.unlock();
outbuf.nfresh++;
}else{
info.eof=true;
mode=MODE_STOP;
stop();
};
};
Jump to Line
Something went wrong with that request. Please try again.