1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-13 15:17:42 +02:00
audacity/lib-src/sbsms/src/subband.cpp

1006 lines
22 KiB
C++

#include "subband.h"
#include "real.h"
#include "sbsms.h"
#include "utils.h"
#include <algorithm>
using namespace std;
namespace _sbsms_ {
SubBand :: SubBand(SubBand *parent, int band, int channels, SBSMSQuality *quality, bool bSynthesize)
{
if(band<quality->params.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<<band);
int M_MAX = 1<<(quality->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<channels; c++) {
nFramesExtracted[c] = 0;
nFramesMarked[c] = 0;
nFramesAssigned[c] = 0;
nFramesTrialed2[c] = 0;
nFramesTrialed1[c] = 0;
nFramesRendered[c] = 0;
nGrainsMarked[c] = 0;
nGrainsAssigned[c] = 0;
nGrainsTrialed2[c] = 0;
nGrainsTrialed1[c] = 0;
nGrainsAdvanced[c] = 0;
}
nGrainsWritten = 0;
nFramesAdjusted2 = 0;
nGrainsAdjusted2 = 0;
nFramesAdjusted1 = 0;
nGrainsAdjusted1 = 0;
nFramesRead = 0;
totalSizef = 0.0;
if(sub) {
samplesSubIn = new SampleBuf(NDownSample/2);
grainsIn = new GrainBuf(NDownSample, NDownSample/SDownSample, NDownSample, hann);
downSampledGrainAllocator = new GrainAllocator(NDownSample/2,NDownSample/2,hann);
}
if(band >= 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<channels; c++) {
if(band >= 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; c<channels; c++) {
if(analyzedGrains[i][c]) {
delete analyzedGrains[i][c];
}
}
}
delete sms;
if(sub) {
delete sub;
delete grainsIn;
delete samplesSubIn;
delete downSampledGrainAllocator;
if(bSynthesize) {
delete samplesSubOut;
delete outMixer;
}
}
if(bSynthesize) delete synthRenderer;
}
void SubBand :: addRenderer(SBSMSRenderer *renderer)
{
if(sub) sub->addRenderer(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; c<channels; c++) {
n = max(0L,min(1L,min(n,nFramesRendered[c]-nFramesRead)));
}
if(sub) n = min(n,sub->readInit());
return n;
}
long SubBand :: analyzeInit(int i, bool bSet, long n)
{
if(!parent) {
n = getFramesAtFront(i);
for(int c=0; c<channels; c++) {
n = max(0L,min(1L,min(n,nAnalyzeSlack-(long)(nFramesAnalyzed[i]-nFramesExtracted[c]))));
}
}
if(bSet) {
nGrainsToAnalyze[i] = n * nGrainsPerFrame;
if(sub) {
sub->analyzeInit(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; c<channels; c++) {
n = min(n,(long)(nFramesTrialed2[c]-nFramesAdjusted2-nAdjust2Latency));
n = min(n,nAdjust2Slack+nTrial1Latency-(long)(nFramesAdjusted2-nFramesTrialed1[c]));
}
n = max(0L,n);
}
if(bSet) {
nGrainsToAdjust2 = n;
nGrainsAdjusted2 = 0;
}
return n;
}
long SubBand :: trial1Init(int c, bool bSet)
{
long n;
if(sub) {
n = res * sub->trial1Init(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; c<channels; c++) {
n = min(n,(long)(nFramesTrialed1[c]-nFramesAdjusted1-nAdjust1Latency));
n = min(n,nAdjust1Slack+nRenderLatency-(long)(nFramesAdjusted1-nFramesRendered[c]));
}
n = max(0L,n);
}
if(bSet) {
nGrainsToAdjust1 = n;
nGrainsAdjusted1 = 0;
}
return n;
}
long SubBand :: renderInit(int c, bool bSet)
{
long n;
if(sub) {
n = res * sub->renderInit(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<grain*> gV;
#ifdef MULTITHREADED
pthread_mutex_lock(&grainMutex[i]);
#endif
for(int k=grains[i]->readPos;k<grains[i]->readPos+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;k<nGrainsToAnalyze[i];k++) {
gV[k]->analyze();
}
#ifdef MULTITHREADED
pthread_mutex_lock(&grainMutex[i]);
#endif
for(int k=0;k<nGrainsToAnalyze[i];k++) {
for(int c=0; c<channels; c++) {
analyzedGrains[i][c]->write(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<grain*> 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;
k<analyzedGrains[i][c]->readPos+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;k<nGrainsToExtract[c];k++) {
grain *g0 = (grains[0]?gV[0][k]:NULL);
grain *g1 = (grains[1]?gV[1][k]:NULL);
grain *g2 = gV[2][k];
sms->add(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(ndone<ntodo) {
sms->mark(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; ndone<nGrainsToAssign[c]; ndone++) {
assignStart(c);
bool bCont = true;
while(bCont) {
assignInit(c);
assignFind(c);
bCont = assignConnect(c);
}
assignStep(c);
splitMerge(c);
}
}
void SubBand :: assignStart(int c)
{
if(sub && !(nGrainsAssigned[c]&resMask)) sub->assignStart(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(ndone<ntodo) {
if(sub && !(nGrainsAdvanced[c]&resMask)) {
sub->advance(c);
}
sms->advance(c);
nGrainsMarked[c]--;
nGrainsAssigned[c]--;
nGrainsAdvanced[c]++;
ndone++;
}
}
void SubBand :: trial2(int c)
{
for(int i=0; i<nGrainsToTrial2[c]; i++) {
trial2Start(c);
trial2Trial(c);
trial2End(c);
}
}
void SubBand :: trial2Start(int c)
{
if(!(nGrainsTrialed2[c]&resMask)) {
if(sub) sub->trial2Start(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(ndone<ntodo) {
if(!(nGrainsAdjusted2&resMask)) {
if(sub) sub->adjust2();
}
sms->adjust2();
ndone++;
nGrainsAdjusted2++;
}
}
void SubBand :: trial1(int c)
{
for(int i=0; i<nGrainsToTrial1[c]; i++) {
trial1Start(c);
trial1Trial(c);
trial1End(c);
}
}
void SubBand :: trial1Start(int c)
{
if(!(nGrainsTrialed1[c]&resMask)) {
if(sub) sub->trial1Start(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(ndone<ntodo) {
if(!(nGrainsAdjusted1&resMask)) {
if(sub) sub->adjust1();
}
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<SBSMSRenderer*>::iterator i = renderers.begin(); i != renderers.end(); ++i) {
SBSMSRenderer *renderer = *i;
renderer->startFrame();
}
for(int c=0; c<channels; c++) {
renderInit(c,true);
render(c);
stepRenderFrame(c);
}
for(list<SBSMSRenderer*>::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(ndone<ntodo) {
if(sub && !(nGrainsRendered[c]&resMask)) {
sub->render(c);
}
sms->render(c,renderers);
nGrainsRendered[c]++;
ndone++;
}
}
void SubBand :: renderComplete(const SampleCountType &samples)
{
for(list<SBSMSRenderer*>::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(nWritten<n) {
long nToWrite = min(nToWriteForGrain,n-nWritten);
if(nToDrop2) {
nToWrite = min(nToDrop2,nToWrite);
nToDrop2 -= nToWrite;
nToDrop1 -= nToWrite;
nToDrop0 -= nToWrite;
} else {
if(nToDrop1) {
nToWrite = min(nToDrop1,nToWrite);
nToDrop1 -= nToWrite;
nToDrop0 -= nToWrite;
} else {
if(nToDrop0) {
nToWrite = min(nToDrop0,nToWrite);
} else if(nToPrepad0) {
nToWrite = min(nToPrepad0,nToWrite);
}
if(nToPrepad1) {
nToWrite = min(nToPrepad1,nToWrite);
sms->prepad1(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;k<grainsIn->writePos;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; c<channels; c++) {
if(extractInit(c,true)) {
extract(c);
stepExtractFrame(c);
}
if(markInit(c,true)) {
mark(c);
stepMarkFrame(c);
}
if(assignInit(c,true)) {
assign(c);
advance(c);
stepAssignFrame(c);
}
if(trial2Init(c,true)) {
trial2(c);
stepTrial2Frame(c);
}
if(adjust2Init(true)) {
adjust2();
stepAdjust2Frame();
}
if(trial1Init(c,true)) {
trial1(c);
stepTrial1Frame(c);
}
if(adjust1Init(true)) {
adjust1();
stepAdjust1Frame();
}
if(bRender) {
if(renderInit(c,true)) {
render(c);
stepRenderFrame(c);
}
}
}
}
long SubBand :: getFramesAtFront(int i)
{
long n = 65536;
#ifdef MULTITHREADED
pthread_mutex_lock(&grainMutex[i]);
#endif
if(grains[i]) {
n = grains[i]->nReadable() / nGrainsPerFrame;
}
#ifdef MULTITHREADED
pthread_mutex_unlock(&grainMutex[i]);
#endif
if(sub) n = min(n,sub->getFramesAtFront(i));
return n;
}
long SubBand :: getInputFrameSize()
{
return inputFrameSize;
}
}