#include "config.h" #include "sbsms.h" #include "real.h" #include "subband.h" #ifdef MULTITHREADED #include #endif #include #include #include using namespace std; namespace _sbsms_ { const SBSMSQualityParams SBSMSQualityStandard = { 8,3, {512,512,384,384,384,384,384,384,0,0}, {168,144,128,96,64,36,24,14,0,0}, {384,288,256,168,128,84,52,28,0,0}, {512,448,360,288,192,128,84,44,0,0}, {1,1,2,1,1,2,1,1,0,0} }; SBSMSQuality :: SBSMSQuality(const SBSMSQualityParams *params) { this->params = *params; } long SBSMSQuality :: getFrameSize() { return (1<<(params.bands-1)) * params.H; } long SBSMSQuality :: getMaxPresamples() { long prepad = 0; for(int i=0; i>1))); } prepad += ((1<<(params.bands-1)) - 1) * (NDownSample>>1); long framesize = (1<<(params.bands-1)) * params.H; long frames = prepad / framesize; if(prepad%framesize) frames++; frames++; prepad = frames * framesize; return prepad; } #ifdef MULTITHREADED class ThreadInterface; #endif class SBSMSImp { public: SBSMSImp(int channels, SBSMSQuality *quality, bool bSynthesize); ~SBSMSImp(); inline long read(SBSMSInterface *iface, audio *buf, long n); inline void addRenderer(SBSMSRenderer *renderer); inline void removeRenderer(SBSMSRenderer *renderer); inline long renderFrame(SBSMSInterface *iface); SubBand *top; #ifdef MULTITHREADED friend class ThreadInterface; ThreadInterface *threadInterface; #endif friend class SBSMS; protected: inline void reset(); float getInputTime(SBSMSInterface *iface); long write(SBSMSInterface *); FILE *fpIn; FILE *fpOut; SBSMSError error; long nPrepad; long nPrepadDone; long nPresamplesDone; SampleCountType nSamplesInputed; SampleCountType nSamplesOutputed; int channels; SBSMSQuality *quality; audio *ina; }; #ifdef MULTITHREADED struct channel_thread_data { int c; ThreadInterface *threadInterface; }; struct analyze_thread_data { int i; ThreadInterface *threadInterface; }; class ThreadInterface { public: friend class SBSMSImp; ThreadInterface(SBSMSImp *sbsms, bool bSynthesize); ~ThreadInterface(); void signalReadWrite(); void signalAnalyze(); void signalExtract(int c); void signalMark(int c); void signalAssign(int c); void signalTrial2(int c); void signalAdjust2(); void signalTrial1(int c); void signalAdjust1(); void signalRender(int c); void waitReadWrite(); void waitAnalyze(int i); void waitExtract(int c); void waitAssign(int c); void waitTrial2(int c); void waitAdjust2(); void waitTrial1(int c); void waitAdjust1(); void waitRender(int c); SubBand *top; int channels; pthread_mutex_t readWriteMutex; pthread_cond_t readWriteCond; pthread_t analyzeThread[3]; pthread_mutex_t analyzeMutex[3]; pthread_cond_t analyzeCond[3]; pthread_t extractThread[2]; pthread_mutex_t extractMutex[2]; pthread_cond_t extractCond[2]; pthread_t assignThread[2]; pthread_mutex_t assignMutex[2]; pthread_cond_t assignCond[2]; pthread_t trial2Thread[2]; pthread_mutex_t trial2Mutex[2]; pthread_cond_t trial2Cond[2]; pthread_t adjust2Thread; pthread_mutex_t adjust2Mutex; pthread_cond_t adjust2Cond; pthread_t trial1Thread[2]; pthread_mutex_t trial1Mutex[2]; pthread_cond_t trial1Cond[2]; pthread_t adjust1Thread; pthread_mutex_t adjust1Mutex; pthread_cond_t adjust1Cond; bool bRenderThread; pthread_t renderThread[2]; pthread_mutex_t renderMutex[2]; pthread_cond_t renderCond[2]; channel_thread_data channelData[2]; analyze_thread_data analyzeData[3]; bool bActive; }; void *analyzeThreadCB(void *data) { analyze_thread_data *analyzeData = (analyze_thread_data*)data; ThreadInterface *threadInterface = analyzeData->threadInterface; SubBand *top = threadInterface->top; int i = analyzeData->i; int channels = threadInterface->channels; while(threadInterface->bActive) { threadInterface->waitAnalyze(i); if(top->analyzeInit(i,true)) { top->analyze(i); top->stepAnalyzeFrame(i); threadInterface->signalReadWrite(); for(int c=0; csignalExtract(c); } } } pthread_exit(NULL); return NULL; } void *extractThreadCB(void *data) { channel_thread_data *channelData = (channel_thread_data*)data; ThreadInterface *threadInterface = channelData->threadInterface; SubBand *top = threadInterface->top; int c = channelData->c; while(threadInterface->bActive) { threadInterface->waitExtract(c); if(top->extractInit(c,true)) { top->extract(c); top->stepExtractFrame(c); threadInterface->signalAnalyze(); threadInterface->signalMark(c); } } pthread_exit(NULL); return NULL; } void *assignThreadCB(void *data) { channel_thread_data *channelData = (channel_thread_data*)data; ThreadInterface *threadInterface = channelData->threadInterface; SubBand *top = threadInterface->top; int c = channelData->c; while(threadInterface->bActive) { threadInterface->waitAssign(c); if(top->markInit(c,true)) { top->mark(c); top->stepMarkFrame(c); threadInterface->signalExtract(c); } if(top->assignInit(c,true)) { top->assign(c); top->advance(c); top->stepAssignFrame(c); threadInterface->signalTrial2(c); } } pthread_exit(NULL); return NULL; } void *trial2ThreadCB(void *data) { channel_thread_data *channelData = (channel_thread_data*)data; ThreadInterface *threadInterface = channelData->threadInterface; SubBand *top = threadInterface->top; int c = channelData->c; while(threadInterface->bActive) { threadInterface->waitTrial2(c); if(top->trial2Init(c,true)) { top->trial2(c); top->stepTrial2Frame(c); threadInterface->signalAssign(c); threadInterface->signalAdjust2(); } } pthread_exit(NULL); return NULL; } void *adjust2ThreadCB(void *data) { ThreadInterface *threadInterface = (ThreadInterface*)data; int channels = threadInterface->channels; SubBand *top = threadInterface->top; while(threadInterface->bActive) { threadInterface->waitAdjust2(); if(top->adjust2Init(true)) { top->adjust2(); top->stepAdjust2Frame(); for(int c=0; csignalTrial2(c); } for(int c=0; csignalTrial1(c); } } } pthread_exit(NULL); return NULL; } void *trial1ThreadCB(void *data) { channel_thread_data *channelData = (channel_thread_data*)data; ThreadInterface *threadInterface = channelData->threadInterface; SubBand *top = threadInterface->top; int c = channelData->c; while(threadInterface->bActive) { threadInterface->waitTrial1(c); if(top->trial1Init(c,true)) { top->trial1(c); top->stepTrial1Frame(c); threadInterface->signalAdjust2(); threadInterface->signalAdjust1(); } } pthread_exit(NULL); return NULL; } void *adjust1ThreadCB(void *data) { ThreadInterface *threadInterface = (ThreadInterface*)data; int channels = threadInterface->channels; SubBand *top = threadInterface->top; while(threadInterface->bActive) { threadInterface->waitAdjust1(); if(top->adjust1Init(true)) { top->adjust1(); top->stepAdjust1Frame(); for(int c=0; csignalTrial1(c); } if(threadInterface->bRenderThread) { for(int c=0; csignalRender(c); } } else { threadInterface->signalReadWrite(); } } } pthread_exit(NULL); return NULL; } void *renderThreadCB(void *data) { channel_thread_data *channelData = (channel_thread_data*)data; ThreadInterface *threadInterface = channelData->threadInterface; SubBand *top = threadInterface->top; int c = channelData->c; while(threadInterface->bActive) { threadInterface->waitRender(c); if(top->renderInit(c,true)) { top->render(c); top->stepRenderFrame(c); threadInterface->signalAdjust1(); threadInterface->signalReadWrite(); } } pthread_exit(NULL); return NULL; } ThreadInterface :: ThreadInterface(SBSMSImp *sbsms, bool bSynthesize) { this->top = sbsms->top; this->channels = sbsms->channels; bActive = true; pthread_cond_init(&readWriteCond, NULL); pthread_mutex_init(&readWriteMutex, NULL); if(bSynthesize) { bRenderThread = true; } else { bRenderThread = false; } for(int i=0; i<3; i++) { analyzeData[i].i = i; analyzeData[i].threadInterface = this; pthread_cond_init(&analyzeCond[i], NULL); pthread_mutex_init(&analyzeMutex[i], NULL); } for(int c=0; cwriteInit() || top->readInit()); } else { if(top->writeInit()) { bReady = true; } else { bReady = true; for(int c=0; crenderInit(c,false)) { bReady = false; break; } } } } if(bReady) { pthread_cond_broadcast(&readWriteCond); } pthread_mutex_unlock(&readWriteMutex); } void ThreadInterface :: signalAnalyze() { for(int i=0; i<3; i++) { pthread_mutex_lock(&analyzeMutex[i]); if(top->analyzeInit(i,false)) { pthread_cond_broadcast(&analyzeCond[i]); } pthread_mutex_unlock(&analyzeMutex[i]); } } void ThreadInterface :: signalExtract(int c) { pthread_mutex_lock(&extractMutex[c]); if(top->extractInit(c,false)) { pthread_cond_broadcast(&extractCond[c]); } pthread_mutex_unlock(&extractMutex[c]); } void ThreadInterface :: signalMark(int c) { pthread_mutex_lock(&assignMutex[c]); if(top->markInit(c,false)) { pthread_cond_broadcast(&assignCond[c]); } pthread_mutex_unlock(&assignMutex[c]); } void ThreadInterface :: signalAssign(int c) { pthread_mutex_lock(&assignMutex[c]); if(top->assignInit(c,false)) { pthread_cond_broadcast(&assignCond[c]); } pthread_mutex_unlock(&assignMutex[c]); } void ThreadInterface :: signalTrial2(int c) { pthread_mutex_lock(&trial2Mutex[c]); if(top->trial2Init(c,false)) { pthread_cond_broadcast(&trial2Cond[c]); } pthread_mutex_unlock(&trial2Mutex[c]); } void ThreadInterface :: signalAdjust2() { pthread_mutex_lock(&adjust2Mutex); if(top->adjust2Init(false)) { pthread_cond_broadcast(&adjust2Cond); } pthread_mutex_unlock(&adjust2Mutex); } void ThreadInterface :: signalTrial1(int c) { pthread_mutex_lock(&trial1Mutex[c]); if(top->trial1Init(c,false)) { pthread_cond_broadcast(&trial1Cond[c]); } pthread_mutex_unlock(&trial1Mutex[c]); } void ThreadInterface :: signalAdjust1() { pthread_mutex_lock(&adjust1Mutex); if(top->adjust1Init(false)) { pthread_cond_broadcast(&adjust1Cond); } pthread_mutex_unlock(&adjust1Mutex); } void ThreadInterface :: signalRender(int c) { pthread_mutex_lock(&renderMutex[c]); if(top->renderInit(c,false)) { pthread_cond_broadcast(&renderCond[c]); } pthread_mutex_unlock(&renderMutex[c]); } void ThreadInterface :: waitReadWrite() { pthread_mutex_lock(&readWriteMutex); bool bReady; if(bRenderThread) { bReady = (top->writeInit() || top->readInit()); } else { if(top->writeInit()) { bReady = true; } else { bReady = true; for(int c=0; crenderInit(c,false)) { bReady = false; break; } } } } if(!bReady) { pthread_cond_wait(&readWriteCond,&readWriteMutex); } pthread_mutex_unlock(&readWriteMutex); } void ThreadInterface :: waitAnalyze(int i) { pthread_mutex_lock(&analyzeMutex[i]); if(!top->analyzeInit(i,false)) { pthread_cond_wait(&analyzeCond[i],&analyzeMutex[i]); } pthread_mutex_unlock(&analyzeMutex[i]); } void ThreadInterface :: waitExtract(int c) { pthread_mutex_lock(&extractMutex[c]); if(!top->extractInit(c,false)) { pthread_cond_wait(&extractCond[c],&extractMutex[c]); } pthread_mutex_unlock(&extractMutex[c]); } void ThreadInterface :: waitAssign(int c) { pthread_mutex_lock(&assignMutex[c]); if(!top->markInit(c,false) && !top->assignInit(c,false)) { pthread_cond_wait(&assignCond[c],&assignMutex[c]); } pthread_mutex_unlock(&assignMutex[c]); } void ThreadInterface :: waitTrial2(int c) { pthread_mutex_lock(&trial2Mutex[c]); if(!top->trial2Init(c,false)) { pthread_cond_wait(&trial2Cond[c],&trial2Mutex[c]); } pthread_mutex_unlock(&trial2Mutex[c]); } void ThreadInterface :: waitAdjust2() { pthread_mutex_lock(&adjust2Mutex); if(!top->adjust2Init(false)) { pthread_cond_wait(&adjust2Cond,&adjust2Mutex); } pthread_mutex_unlock(&adjust2Mutex); } void ThreadInterface :: waitTrial1(int c) { pthread_mutex_lock(&trial1Mutex[c]); if(!top->trial1Init(c,false)) { pthread_cond_wait(&trial1Cond[c],&trial1Mutex[c]); } pthread_mutex_unlock(&trial1Mutex[c]); } void ThreadInterface :: waitAdjust1() { pthread_mutex_lock(&adjust1Mutex); if(!top->adjust1Init(false)) { pthread_cond_wait(&adjust1Cond,&adjust1Mutex); } pthread_mutex_unlock(&adjust1Mutex); } void ThreadInterface :: waitRender(int c) { pthread_mutex_lock(&renderMutex[c]); if(!top->renderInit(c,false)) { pthread_cond_wait(&renderCond[c],&renderMutex[c]); } pthread_mutex_unlock(&renderMutex[c]); } #endif void SBSMSImp :: reset() { nSamplesInputed = 0; nSamplesOutputed = 0; nPrepadDone = 0; nPresamplesDone = 0; } SBSMS :: SBSMS(int channels, SBSMSQuality *quality, bool bSynthesize) { imp = new SBSMSImp(channels,quality,bSynthesize); } SBSMSImp :: SBSMSImp(int channels, SBSMSQuality *quality, bool bSynthesize) { this->channels = channels; this->quality = new SBSMSQuality(&quality->params); error = SBSMSErrorNone; top = new SubBand(NULL,0,channels,quality,bSynthesize); ina = (audio*)malloc(quality->getFrameSize()*sizeof(audio)); nPrepad = quality->getMaxPresamples(); reset(); #ifdef MULTITHREADED threadInterface = new ThreadInterface(this,bSynthesize); #endif } SBSMS :: ~SBSMS() { delete imp; } SBSMSImp :: ~SBSMSImp() { #ifdef MULTITHREADED if(threadInterface) delete threadInterface; #endif if(top) delete top; if(ina) free(ina); if(quality) delete quality; } void SBSMS :: addRenderer(SBSMSRenderer *renderer) { imp->addRenderer(renderer); } void SBSMSImp :: addRenderer(SBSMSRenderer *renderer) { top->addRenderer(renderer); } void SBSMS :: removeRenderer(SBSMSRenderer *renderer) { imp->removeRenderer(renderer); } void SBSMSImp :: removeRenderer(SBSMSRenderer *renderer) { top->removeRenderer(renderer); } SBSMSError SBSMS :: getError() { return imp->error; } float SBSMSImp :: getInputTime(SBSMSInterface *iface) { return (float)nSamplesInputed / (float)iface->getSamplesToInput(); } long SBSMSImp :: write(SBSMSInterface *iface) { long nWrite = 0; float t = getInputTime(iface); float stretch = iface->getStretch(t); float pitch = iface->getPitch(t); long nPresamples = iface->getPresamples(); if(nPrepadDone < nPrepad - nPresamples) { stretch = 1.0f; nWrite = min(quality->getFrameSize(),nPrepad - nPresamples - nPrepadDone); memset(ina,0,nWrite*sizeof(audio)); nPrepadDone += nWrite; } else if(nPresamplesDone < nPresamples) { stretch = 1.0f; nWrite = min(quality->getFrameSize(),nPresamples - nPresamplesDone); nWrite = iface->samples(ina,nWrite); if(nWrite == 0) { nWrite = quality->getFrameSize(); memset(ina,0,nWrite*sizeof(audio)); } else { nPresamplesDone += nWrite; } } else { nWrite = iface->samples(ina,quality->getFrameSize()); nSamplesInputed += nWrite; if(nWrite == 0) { nWrite = quality->getFrameSize(); memset(ina,0,nWrite*sizeof(audio)); } } nWrite = top->write(ina, nWrite, stretch, pitch); return nWrite; } long SBSMS :: read(SBSMSInterface *iface, audio *buf, long n) { return imp->read(iface,buf,n); } long SBSMSImp :: read(SBSMSInterface *iface, audio *buf, long n) { long nReadTotal = 0; while(nReadTotal < n) { long nRead; nRead = n - nReadTotal; nRead = top->read(buf+nReadTotal,nRead); nReadTotal += nRead; if(nRead) { #ifdef MULTITHREADED if(threadInterface->bRenderThread) { for(int c=0; csignalRender(c); } } #endif } else { #ifdef MULTITHREADED threadInterface->waitReadWrite(); #endif if(top->writeInit()) { write(iface); #ifdef MULTITHREADED threadInterface->signalAnalyze(); #endif } } #ifdef MULTITHREADED if(!threadInterface->bRenderThread) { for(int c=0; csignalRender(c); } } #else top->process(true); #endif nSamplesOutputed += nRead; } return nReadTotal; } long SBSMS :: renderFrame(SBSMSInterface *iface) { return imp->renderFrame(iface); } long SBSMSImp :: renderFrame(SBSMSInterface *iface) { long nRendered = 0; while(!nRendered) { bool bReady = true; for(int c=0; crenderInit(c,false)) { bReady = false; break; } } if(bReady) { nRendered = top->renderSynchronous(); } if(nRendered) { #ifdef MULTITHREADED threadInterface->signalAdjust1(); #endif } else { #ifdef MULTITHREADED threadInterface->waitReadWrite(); #endif if(top->writeInit()) { write(iface); } #ifdef MULTITHREADED threadInterface->signalAnalyze(); #endif } #ifdef MULTITHREADED #else top->process(false); #endif if(nSamplesOutputed >= iface->getSamplesToOutput()) { top->renderComplete(iface->getSamplesToOutput()); } nSamplesOutputed += nRendered; } return nRendered; } long SBSMS :: getInputFrameSize() { return imp->top->getInputFrameSize(); } }