#include "subband.h" #include "real.h" #include "sbsms.h" #include "utils.h" #include using namespace std; namespace _sbsms_ { SubBand :: SubBand(SubBand *parent, int band, int channels, SBSMSQuality *quality, bool bSynthesize) { if(bandparams.bands-1) { sub = new SubBand(this,band+1,channels,quality,bSynthesize); } else { sub = NULL; } this->quality = quality; this->channels = channels; this->parent = parent; this->band = band; int M = (1<params.bands-1); this->N = quality->params.N[band]; int N0 = quality->params.N0[band]; int N1 = quality->params.N1[band]; int N2 = quality->params.N2[band]; this->res = quality->params.res[band]; this->resMask = res - 1; this->bSynthesize = bSynthesize; nGrainsPerFrame = res; if(sub) nGrainsPerFrame *= sub->nGrainsPerFrame; inputFrameSize = M_MAX*quality->params.H; h = inputFrameSize / (M*nGrainsPerFrame); nToDrop0 = (quality->getMaxPresamples()/M - N0/2); nToDrop1 = (quality->getMaxPresamples()/M - N1/2); nToDrop2 = (quality->getMaxPresamples()/M - N2/2); nToWriteForGrain = (quality->getMaxPresamples()/M + N2/2); nToPrepad1 = N1/2; nToPrepad0 = N0/2; nReadFromOutputFrame = 0; for(int i=0; i<3; i++) { nFramesAnalyzed[i] = 0; } for(int c=0; c= minTrial1Band) { grains[0] = new GrainBuf(N, h, N0, hannpoisson); } else { grains[0] = NULL; } if(band >= minTrial2Band) { grains[1] = new GrainBuf(N, h, N1, hannpoisson); } else { grains[1] = NULL; } grains[2] = new GrainBuf(N, h, N2, hannpoisson); for(int c=0; c= minTrial1Band) { analyzedGrains[0][c] = new GrainBuf(N, h, N0, hannpoisson); } else { analyzedGrains[0][c] = NULL; } if(band >= minTrial2Band) { analyzedGrains[1][c] = new GrainBuf(N, h, N1, hannpoisson); } else { analyzedGrains[1][c] = NULL; } analyzedGrains[2][c] = new GrainBuf(N, h, N2, hannpoisson); } #ifdef MULTITHREADED pthread_mutex_init(&dataMutex, NULL); for(int i=0; i<3; i++) { pthread_mutex_init(&grainMutex[i], NULL); } #endif sms = new SMS(sub?sub->sms:NULL,N,band,quality->params.bands-1,h,res,N0,N1,N2,channels,analyzedGrains[2][0]->getWindowFFT()); nTrial2Latency = sms->getTrial2Latency() / nGrainsPerFrame + 1; if(sms->getTrial2Latency() % nGrainsPerFrame) nTrial2Latency++; int nAdjust2LatencyGrains = N1/(2*h); nAdjust2Latency = nAdjust2LatencyGrains / nGrainsPerFrame + 1; if(nAdjust2LatencyGrains % nGrainsPerFrame) nAdjust2Latency++; int nAdjust1LatencyGrains = N0/(2*h); nAdjust1Latency = nAdjust1LatencyGrains / nGrainsPerFrame + 1; if(nAdjust1LatencyGrains % nGrainsPerFrame) nAdjust1Latency++; if(sub) nTrial2Latency = max(nTrial2Latency,sub->nTrial2Latency); if(sub) nAdjust2Latency = max(nAdjust2Latency,sub->nAdjust2Latency); if(sub) nAdjust1Latency = max(nAdjust1Latency,sub->nAdjust1Latency); nMarkLatency = 1; nAssignLatency = 1; nTrial1Latency = 1; nRenderLatency = 1; if(band==0) { SubBand *s = sub; while(s) { s->nTrial2Latency = nTrial2Latency; s->nAdjust2Latency = nAdjust2Latency; s->nAdjust1Latency = nAdjust1Latency; s = s->sub; } } #ifdef MULTITHREADED nWriteSlack = 6; nAnalyzeSlack = 6; nExtractSlack = 6; nMarkSlack = 6; nAssignSlack = 6; nTrial2Slack = 6; nAdjust2Slack = 6; nTrial1Slack = 6; nAdjust1Slack = 6; nRenderSlack = 6; #else nWriteSlack = 2; nAnalyzeSlack = 2; nExtractSlack = 2; nMarkSlack = 2; nAssignSlack = 2; nTrial2Slack = 2; nAdjust2Slack = 2; nTrial1Slack = 2; nAdjust1Slack = 2; nRenderSlack = 2; #endif synthRenderer = NULL; outMixer = NULL; if(bSynthesize) { synthRenderer = new SynthRenderer(channels,M*h); renderers.push_back(synthRenderer); if(sub) { samplesSubOut = new SampleBuf(0); outMixer = new Mixer(synthRenderer,samplesSubOut); } else { outMixer = synthRenderer; } } } SubBand :: ~SubBand() { for(int i=0; i<3; i++) { if(grains[i]) { delete grains[i]; } for(int c=0; caddRenderer(renderer); renderers.push_back(renderer); } void SubBand :: removeRenderer(SBSMSRenderer *renderer) { if(sub) sub->removeRenderer(renderer); renderers.remove(renderer); } void SubBand :: setStretch(float stretch) { #ifdef MULTITHREADED pthread_mutex_lock(&dataMutex); #endif if(!parent) { float oFrameSizef = (stretch==0.0f?1.0f:stretch)*(float)inputFrameSize; totalSizef += oFrameSizef; long oFrameSizei = lrintf(totalSizef); totalSizef -= oFrameSizei; outputFrameSize.write(oFrameSizei); } stretchRender.write(stretch); #ifdef MULTITHREADED pthread_mutex_unlock(&dataMutex); #endif if(sub) sub->setStretch(stretch); } void SubBand :: setPitch(float f) { if(sub) sub->setPitch(f); #ifdef MULTITHREADED pthread_mutex_lock(&dataMutex); #endif pitchRender.write(f); #ifdef MULTITHREADED pthread_mutex_unlock(&dataMutex); #endif } void SubBand :: stepAnalyzeFrame(int i) { if(sub) sub->stepAnalyzeFrame(i); nFramesAnalyzed[i]++; } void SubBand :: stepExtractFrame(int c) { if(sub) sub->stepExtractFrame(c); nFramesExtracted[c]++; } void SubBand :: stepMarkFrame(int c) { if(sub) sub->stepMarkFrame(c); nFramesMarked[c]++; } void SubBand :: stepAssignFrame(int c) { if(sub) sub->stepAssignFrame(c); nFramesAssigned[c]++; } void SubBand :: stepTrial2Frame(int c) { if(sub) sub->stepTrial2Frame(c); nFramesTrialed2[c]++; } void SubBand :: stepAdjust2Frame() { if(sub) sub->stepAdjust2Frame(); nFramesAdjusted2++; } void SubBand :: stepTrial1Frame(int c) { if(sub) sub->stepTrial1Frame(c); nFramesTrialed1[c]++; } void SubBand :: stepAdjust1Frame() { if(sub) sub->stepAdjust1Frame(); #ifdef MULTITHREADED pthread_mutex_lock(&dataMutex); #endif stretchRender.advance(1); pitchRender.advance(1); #ifdef MULTITHREADED pthread_mutex_unlock(&dataMutex); #endif nFramesAdjusted1++; } void SubBand :: stepRenderFrame(int c) { if(sub) sub->stepRenderFrame(c); nFramesRendered[c]++; } void SubBand :: stepReadFrame() { if(sub) sub->stepReadFrame(); nFramesRead++; } bool SubBand :: writeInit() { long n = getFramesAtFront(0); n = min(n,getFramesAtFront(1)); n = min(n,getFramesAtFront(2)); return (n <= nWriteSlack); } long SubBand :: readInit() { long n = nFramesRendered[0]; for(int c=1; creadInit()); return n; } long SubBand :: analyzeInit(int i, bool bSet, long n) { if(!parent) { n = getFramesAtFront(i); for(int c=0; canalyzeInit(i,bSet,n); } } return n; } long SubBand :: extractInit(int c, bool bSet) { long n; if(sub) n = res*sub->extractInit(c,bSet); if(!sub) { n = max(0L,min(1L,nExtractSlack+nMarkLatency-(long)(nFramesExtracted[c]-nFramesMarked[c]))); for(int i=0; i<3; i++) { n = max(0L,min(1L,min(n,(long)(nFramesAnalyzed[i]-nFramesExtracted[c])))); } } if(bSet) { nGrainsToExtract[c] = n; } return n; } long SubBand :: markInit(int c, bool bSet) { long n; if(sub) n = res*sub->markInit(c,bSet); if(!sub) n = max(0L,min(1L,min((long)(nFramesExtracted[c]-nFramesMarked[c])-nMarkLatency, nMarkSlack+nAssignLatency-(long)(nFramesMarked[c]-nFramesAssigned[c])))); if(bSet) { nGrainsToMark[c] = n; } return n; } long SubBand :: assignInit(int c, bool bSet) { long n; if(sub) { n = res * sub->assignInit(c,bSet); } else { n = max(0L,min(1L,min((long)(nFramesMarked[c]-nFramesAssigned[c])-nAssignLatency, nAssignSlack+nTrial2Latency-(long)(nFramesAssigned[c]-nFramesTrialed2[c])))); } if(bSet) { nGrainsToAdvance[c] = n; nGrainsToAssign[c] = n; if(n) { if(nFramesAssigned[c]==0) { sms->start(0,c); } } } return n; } long SubBand :: trial2Init(int c, bool bSet) { long n; if(sub) { n = res * sub->trial2Init(c,bSet); } else { n = max(0L,min(1L,min((long)(nFramesAssigned[c]-nFramesTrialed2[c])-nTrial2Latency, nTrial2Slack+nAdjust2Latency-(long)(nFramesTrialed2[c]-nFramesAdjusted2)))); } if(bSet) { nGrainsToTrial2[c] = n; nGrainsTrialed2[c] = 0; } return n; } long SubBand :: adjust2Init(bool bSet) { long n; if(sub) { n = res * sub->adjust2Init(bSet); } else { n = 1; for(int c=0; ctrial1Init(c,bSet); } else { n = max(0L,min(1L,min((long)(nFramesAdjusted2-nFramesTrialed1[c])-nTrial1Latency, nTrial1Slack+nAdjust1Latency-(long)(nFramesTrialed1[c]-nFramesAdjusted1)))); } if(bSet) { nGrainsToTrial1[c] = n; nGrainsTrialed1[c] = 0; } return n; } long SubBand :: adjust1Init(bool bSet) { long n; if(sub) { n = res * sub->adjust1Init(bSet); } else { n = 1; for(int c=0; crenderInit(c,bSet); } else { n = max(0L,min(1L,min((long)(nFramesAdjusted1-nFramesRendered[c])-nRenderLatency, nRenderSlack-(long)(nFramesRendered[c]-nFramesRead)))); } if(bSet) { nGrainsRendered[c] = 0; nGrainsToRender[c] = n; } return n; } void SubBand :: analyze(int i) { if(sub) sub->analyze(i); if(grains[i]) { vector gV; #ifdef MULTITHREADED pthread_mutex_lock(&grainMutex[i]); #endif for(int k=grains[i]->readPos;kreadPos+nGrainsToAnalyze[i];k++) { grain *g = grains[i]->read(k); gV.push_back(g); } #ifdef MULTITHREADED pthread_mutex_unlock(&grainMutex[i]); #endif for(int k=0;kanalyze(); } #ifdef MULTITHREADED pthread_mutex_lock(&grainMutex[i]); #endif for(int k=0;kwrite(gV[k]); } } grains[i]->advance(nGrainsToAnalyze[i]); #ifdef MULTITHREADED pthread_mutex_unlock(&grainMutex[i]); #endif } } void SubBand :: extract(int c) { if(sub) sub->extract(c); vector gV[3]; for(int i=0; i<3; i++) { if(grains[i]) { #ifdef MULTITHREADED pthread_mutex_lock(&grainMutex[i]); #endif for(int k=analyzedGrains[i][c]->readPos; kreadPos+nGrainsToExtract[c]; k++) { grain *g = analyzedGrains[i][c]->read(k); gV[i].push_back(g); } #ifdef MULTITHREADED pthread_mutex_unlock(&grainMutex[i]); #endif } } for(int k=0;kadd(g0,g1,g2,c); } for(int i=0; i<3; i++) { if(grains[i]) { #ifdef MULTITHREADED pthread_mutex_lock(&grainMutex[i]); #endif analyzedGrains[i][c]->advance(nGrainsToExtract[c]); #ifdef MULTITHREADED pthread_mutex_unlock(&grainMutex[i]); #endif } } } void SubBand :: mark(int c) { long ntodo = parent?1:nGrainsToMark[c]; long ndone = 0; while(ndonemark(nGrainsMarked[c],c); if(nGrainsMarked[c]&resMask || res==1) { if(sub) sub->mark(c); } ndone++; nGrainsMarked[c]++; } } void SubBand :: assign(int c) { for(int ndone=0; ndoneassignStart(c); sms->assignStart(nGrainsAssigned[c],c); } void SubBand :: assignInit(int c) { if(sub) sub->assignInit(c); sms->assignInit(nGrainsAssigned[c],c); } void SubBand :: assignFind(int c) { if(sub) sub->assignFind(c); sms->assignFind(nGrainsAssigned[c],c); } bool SubBand :: assignConnect(int c) { bool bCont = false; if(sub) { if(sub->assignConnect(c)) { bCont = true; } } if(sms->assignConnect(nGrainsAssigned[c],c,false)) { bCont = true; } return bCont; } void SubBand :: assignStep(int c) { sms->assignConnect(nGrainsAssigned[c],c,true); if(sub && !((nGrainsAssigned[c]+1)&resMask)) { sub->assignStep(c); } sms->start(nGrainsAssigned[c]+1,c); } void SubBand :: splitMerge(int c) { nGrainsAssigned[c]++; if(sub && !(nGrainsAssigned[c]&resMask)) { sub->splitMerge(c); } sms->splitMerge(c); } void SubBand :: advance(int c) { long ntodo = parent?1:nGrainsToAdvance[c]; long ndone = 0; while(ndoneadvance(c); } sms->advance(c); nGrainsMarked[c]--; nGrainsAssigned[c]--; nGrainsAdvanced[c]++; ndone++; } } void SubBand :: trial2(int c) { for(int i=0; itrial2Start(c); sms->trial2Start(c); } } void SubBand :: trial2Trial(int c) { if(sub && !(nGrainsTrialed2[c]&resMask)) { sub->trial2Trial(c); } sms->trial2(c); } void SubBand :: trial2End(int c) { nGrainsTrialed2[c]++; if(!(nGrainsTrialed2[c]&resMask)) { if(sub) sub->trial2End(c); sms->trial2End(c); } } void SubBand :: adjust2() { long ntodo = parent?1:nGrainsToAdjust2; long ndone = 0; while(ndoneadjust2(); } sms->adjust2(); ndone++; nGrainsAdjusted2++; } } void SubBand :: trial1(int c) { for(int i=0; itrial1Start(c); sms->trial1Start(c); } } void SubBand :: trial1Trial(int c) { if(sub && !(nGrainsTrialed1[c]&resMask)) { sub->trial1Trial(c); } sms->trial1(c); } void SubBand :: trial1End(int c) { nGrainsTrialed1[c]++; if(!(nGrainsTrialed1[c]&resMask)) { if(sub) sub->trial1End(c); sms->trial1End(c); } } void SubBand :: adjust1() { #ifdef MULTITHREADED pthread_mutex_lock(&dataMutex); #endif float stretch = stretchRender.read(); float f0 = pitchRender.read(pitchRender.readPos); float f1; if(pitchRender.nReadable()>=2) { f1 = pitchRender.read(pitchRender.readPos+1); } else { f1 = f0; } #ifdef MULTITHREADED pthread_mutex_unlock(&dataMutex); #endif long ntodo = parent?1:nGrainsToAdjust1; long ndone = 0; float df = (f1-f0)/(float)nGrainsToAdjust1; while(ndoneadjust1(); } sms->adjust1(stretch,f0+nGrainsAdjusted1*df,f0+(nGrainsAdjusted1+1)*df); ndone++; nGrainsAdjusted1++; } } void SubBand :: readSubSamples() { if(sub) sub->readSubSamples(); if(sub) { audio fromSub[subBufSize]; long nFromSub = 0; do { nFromSub = sub->outMixer->read(fromSub,subBufSize); samplesSubOut->write(fromSub, nFromSub); } while(nFromSub>0); } } long SubBand :: read(audio *buf, long n) { long nRead = 0; long nToRead = n; readSubSamples(); while(nToRead && nRead < n && outputFrameSize.nReadable()) { long nToReadFromOutputFrame = outputFrameSize.read(); nToRead = min(n-nRead,nToReadFromOutputFrame-nReadFromOutputFrame); nToRead = outMixer->read(buf+nRead, nToRead); nReadFromOutputFrame += nToRead; nRead += nToRead; if(nReadFromOutputFrame == nToReadFromOutputFrame) { nReadFromOutputFrame = 0; outputFrameSize.advance(1); stepReadFrame(); } } return nRead; } long SubBand :: renderSynchronous() { for(list::iterator i = renderers.begin(); i != renderers.end(); ++i) { SBSMSRenderer *renderer = *i; renderer->startFrame(); } for(int c=0; c::iterator i = renderers.begin(); i != renderers.end(); ++i) { SBSMSRenderer *renderer = *i; renderer->endFrame(); } long samples = outputFrameSize.read(); outputFrameSize.advance(1); stepReadFrame(); return samples; } void SubBand :: render(int c) { long ntodo = parent?1:nGrainsToRender[c]; long ndone = 0; long nRenderedTotal = 0; while(ndonerender(c); } sms->render(c,renderers); nGrainsRendered[c]++; ndone++; } } void SubBand :: renderComplete(const SampleCountType &samples) { for(list::iterator i = renderers.begin(); i != renderers.end(); ++i) { SBSMSRenderer *renderer = *i; renderer->end(samples); } } long SubBand :: write(audio *inBuf, long n, float stretch, float pitch) { long nWritten = 0; while(nWrittenprepad1(inBuf+nWritten, nToWrite); nToPrepad1 -= nToWrite; } if(nToDrop0) { nToDrop0 -= nToWrite; } else { if(nToPrepad0) { sms->prepad0(inBuf+nWritten, nToWrite); nToPrepad0 -= nToWrite; } #ifdef MULTITHREADED pthread_mutex_lock(&grainMutex[0]); #endif if(grains[0]) { grains[0]->write(inBuf+nWritten, nToWrite); } #ifdef MULTITHREADED pthread_mutex_unlock(&grainMutex[0]); #endif } #ifdef MULTITHREADED pthread_mutex_lock(&grainMutex[1]); #endif if(grains[1]) { grains[1]->write(inBuf+nWritten, nToWrite); } #ifdef MULTITHREADED pthread_mutex_unlock(&grainMutex[1]); #endif } #ifdef MULTITHREADED pthread_mutex_lock(&grainMutex[2]); #endif grains[2]->write(inBuf+nWritten, nToWrite); #ifdef MULTITHREADED pthread_mutex_unlock(&grainMutex[2]); #endif } nWritten += nToWrite; nToWriteForGrain -= nToWrite; if(nToWriteForGrain == 0) { nToWriteForGrain = h; if(!parent) { if(nGrainsWritten == 0) { setStretch(stretch); setPitch(pitch); } nGrainsWritten++; if(nGrainsWritten == nGrainsPerFrame) { nGrainsWritten = 0; } } } } if(sub) { grainsIn->write(inBuf, n); long nGrainsRead = 0; for(int k=grainsIn->readPos;kwritePos;k++) { grain *g = grainsIn->read(k); g->analyze(); grain *gdown = downSampledGrainAllocator->create(); g->downsample(gdown); samplesSubIn->write(gdown, hSub); downSampledGrainAllocator->forget(gdown); nGrainsRead++; } grainsIn->advance(nGrainsRead); long nWriteToSub = samplesSubIn->nReadable(); audio *subBuf = samplesSubIn->getReadBuf(); nWriteToSub = sub->write(subBuf,nWriteToSub,stretch,pitch); samplesSubIn->advance(nWriteToSub); } return n; } void SubBand :: process(bool bRender) { for(int i=0; i<3; i++) { if(analyzeInit(i,true)) { analyze(i); stepAnalyzeFrame(i); } } for(int c=0; cnReadable() / nGrainsPerFrame; } #ifdef MULTITHREADED pthread_mutex_unlock(&grainMutex[i]); #endif if(sub) n = min(n,sub->getFramesAtFront(i)); return n; } long SubBand :: getInputFrameSize() { return inputFrameSize; } }