1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-12-11 07:06:33 +01:00
Files
audacity/lib-src/sbsms/src/subband.cpp

1228 lines
26 KiB
C++

#include "subband.h"
#include "real.h"
#include "sbsms.h"
#include "utils.h"
#include <algorithm>
using namespace std;
namespace _sbsms_ {
#define SUB_BUF_SIZE 4096
bool subband :: isWriteReady()
{
return (getFramesAtFront() <= 8);
}
bool subband :: isAddReady()
{
return addInit(false)?true:false;
}
bool subband :: isMarkReady()
{
bool bReady = false;
for(int c=0;c<channels;c++) {
if(markInit(false,c))
bReady = true;
}
return bReady;
}
bool subband :: isAssignReady()
{
bool bReady = false;
for(int c=0;c<channels;c++) {
if(assignInit(false,c))
bReady = true;
}
return bReady;
}
bool subband :: isSynthReady()
{
return synthInit(false)?true:false;
}
subband :: subband(subband *parent, unsigned short M, int channels, sbsms_quality *quality, int latency, bool bPreAnalyze, TrackAllocator *ta, PeakAllocator *pa)
{
this->quality = quality;
this->ta = ta;
this->pa = pa;
int k = ilog2(M);
this->channels = channels;
this->parent = parent;
this->N = quality->N[k];
this->M = M;
this->s = quality->S[k];
this->res = quality->res[k];
real pad = quality->pad[k];
if(M<quality->M_MAX)
sub = new subband(this,M*2,channels,quality,latency,bPreAnalyze,ta,pa);
else
sub = NULL;
int Nlo = sub?quality->N[k+1]:0;
nGrainsPerFrame = res;
if(sub) nGrainsPerFrame *= sub->nGrainsPerFrame;
if(sub) resTotal = 2*sub->resTotal;
else resTotal = 1;
nLatencyOriginal = latency;
gPrev = NULL;
init();
// sms
in0 = new GrainBuf(N, h, pad*quality->P[k]);
in1 = new GrainBuf(N, h, pad);
in2 = new GrainBuf(N, h, pad*quality->Q[k]);
// synthesize
smser = new sms(N,(short)M,(short)quality->M_MAX,res,latency,quality->P[k],quality->Q[k],pad,Nlo,channels,ta,pa);
if(!parent && bPreAnalyze) {
this->bPreAnalyze = true;
inPre = new GrainBuf(N, h, 2);
x1[0] = grain :: create(N,pad);
x1[1] = grain :: create(N,pad);
x2[0] = grain :: create(N,pad);
x2[1] = grain :: create(N,pad);
} else {
this->bPreAnalyze = false;
inPre = NULL;
}
if(sub) {
subOut = new SampleBuf(0);
// receive
in = new GrainBuf(N, N/s, 1);
// samples to sub
subIn = new SampleBuf(N/2);
// output samples
outMixer = new Mixer(smser,subOut);
} else {
outMixer = smser;
}
#ifdef MULTITHREADED
pthread_mutex_init(&dataMutex, NULL);
pthread_mutex_init(&bufferMutex, NULL);
#endif
}
long subband :: getFramePos()
{
return nFramesRead;
}
void subband :: seek(long framePos) {
if(sub) sub->seek(framePos);
nFramesWritten = framePos;
nFramesAdded = framePos;
nFramesMarked[0] = framePos;
nFramesMarked[1] = framePos;
nFramesAssigned[0] = framePos;
nFramesAssigned[1] = framePos;
nFramesSynthed = framePos;
nFramesRead = framePos;
}
void subband :: reset() {
if(sub) sub->reset();
init();
inputFrameSize.clear();
outputFrameSize.clear();
aForH.clear();
aSynth.clear();
fSynth.clear();
frameRatio.clear();
in0->clear();
in1->clear();
in2->clear();
if(sub) {
in->clear();
subIn->clear();
subOut->clear();
}
smser->reset();
}
void subband :: init()
{
int ssms = (N*nGrainsPerFrame)/(resTotal*quality->H[2]);
h = N/ssms;
lastInputFrameSize = h*nGrainsPerFrame;
lastFrameA = 1.0f;
lastFrameRatio = 1.0f;
nLatency = nLatencyOriginal;
nToDrop = (quality->N[quality->bands-1]/quality->H[2]*nGrainsPerFrame-ssms)/2;
nDropped = 0;
nFramesSkipped = 0;
nFramesWritten = 0;
nFramesAdded = 0;
nFramesMarked[0] = 0;
nFramesMarked[1] = 0;
nFramesAssigned[0] = 0;
nFramesAssigned[1] = 0;
nFramesSynthed = 0;
nFramesRead = 0;
nTrackPointsWritten = 0;
nTrackPointsMarked[0] = 0;
nTrackPointsMarked[1] = 0;
nTrackPointsAssigned[0] = 0;
nTrackPointsAssigned[1] = 0;
nTrackPointsStarted[0] = 0;
nTrackPointsStarted[1] = 0;
nTrackPointsAdvanced[0] = 0;
nTrackPointsAdvanced[1] = 0;
samplesQueued = 0;
bWritingComplete = false;
totalSizef = 0.0;
}
subband :: ~subband()
{
delete in0;
delete in1;
delete in2;
delete smser;
if(inPre) {
delete inPre;
grain ::destroy(x1[0]);
grain ::destroy(x1[1]);
grain ::destroy(x2[0]);
grain ::destroy(x2[1]);
}
if(sub) {
delete sub;
delete in;
delete subIn;
delete subOut;
delete outMixer;
}
}
void subband :: setFrameSize(int iFrameSize, real a, real ratio)
{
real oFrameSizef = a*(real)iFrameSize;
totalSizef += oFrameSizef;
long oFrameSizei = round2int(totalSizef);
totalSizef -= oFrameSizei;
inputFrameSize.write(iFrameSize);
outputFrameSize.write(oFrameSizei);
lastInputFrameSize = iFrameSize;
lastOutputFrameSize = oFrameSizei;
samplesQueued += oFrameSizei * ratio;
//samplesQueued += oFrameSizei;
}
void subband :: setH(real ratio)
{
real a = aForH.read(aForH.readPos);
if(a > 4.0)
h = quality->H[0];
else if(a > 2.0 && a <= 4.0)
h = quality->H[1];
else if(a >= 0.5 && a <= 2.0)
h = quality->H[2];
else if(a >= 0.25 && a < 0.5)
h = quality->H[3];
else
h = quality->H[4];
h = (h*resTotal)/nGrainsPerFrame;
in0->h = h;
in1->h = h;
in2->h = h;
if(inPre) inPre->h = h;
if(!parent)
setFrameSize(h*nGrainsPerFrame,a,ratio);
aForH.advance(1);
}
void subband :: setAForH(real a)
{
aForH.write(a);
if(sub) sub->setAForH(a);
}
void subband :: setA(real a)
{
aSynth.write(a);
if(sub) sub->setA(a);
lastFrameA = a;
}
void subband :: setF(real f)
{
fSynth.write(f);
if(sub) sub->setF(f);
}
void subband :: setAMod(real a)
{
aMod.write(a);
}
void subband :: setRatio(real ratio)
{
frameRatio.write(ratio);
lastFrameRatio = ratio;
}
void subband :: write_(audio *inBuf, long n, real a, real ratio)
{
long nwritten = 0;
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
while(nwritten<n) {
long ntowrite = min((long)h,n-nwritten);
long ng = in1->write(inBuf+nwritten, ntowrite);
in0->write(inBuf+nwritten, ntowrite);
in2->write(inBuf+nwritten, ntowrite);
nwritten += ntowrite;
long n_advance = 0;
for(int k=0;k<ng;k++) {
if(nDropped < nToDrop) {
n_advance++;
nDropped++;
} else {
if(!parent && nTrackPointsWritten%nGrainsPerFrame == 0) {
real amod;
if(bPreAnalyze && aPreAnalysis.n_readable()) {
amod = aPreAnalysis.read(aPreAnalysis.readPos);
aPreAnalysis.advance(1);
} else {
amod = 1.0f;
}
setA(amod*a);
setAMod(amod);
setRatio(ratio);
setF(1.0f/ratio);
}
if(!parent && (nTrackPointsWritten+1)%nGrainsPerFrame == 0) {
setAForH(a);
}
if((nTrackPointsWritten+1)%nGrainsPerFrame == 0) {
setH(ratio);
nFramesWritten++;
}
nTrackPointsWritten++;
}
}
if(n_advance) {
in0->advance(n_advance);
in1->advance(n_advance);
in2->advance(n_advance);
}
}
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
if(sub) {
in->write(inBuf, n);
long ng_read = 0;
for(int k=in->readPos;k<in->writePos;k++) {
grain *gdown = in->read(k)->downsample();
subIn->write(gdown, N/2/s);
grain :: destroy(gdown);
ng_read++;
}
in->advance(ng_read);
long n_tosub = subIn->n_readable();
audio *subBuf = subIn->getReadBuf();
n_tosub = subIn->read(subBuf,n_tosub);
sub->write_(subBuf,n_tosub,a,ratio);
subIn->advance(n_tosub);
}
}
void subband :: stepAddFrame()
{
if(sub) sub->stepAddFrame();
nFramesAdded++;
}
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 :: stepSynthFrame()
{
if(sub) sub->stepSynthFrame();
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
if(!parent) aMod.advance(1);
aSynth.advance(1);
fSynth.advance(1);
nFramesSynthed++;
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
}
void subband :: stepReadFrame()
{
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
nFramesRead++;
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
}
long subband :: addInit(bool bSet)
{
long n;
if(sub) n = res*sub->addInit(bSet);
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
if(!sub) n = max((long)0,min((long)1,min(in1->n_readable(),4-(nFramesAdded-getFramesMarked()))));
if(bSet) {
nTrackPointsToAdd = n;
}
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return n;
}
void subband :: addTrackPoints()
{
if(sub) sub->addTrackPoints();
vector<grain*> g0V;
vector<grain*> g1V;
vector<grain*> g2V;
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
for(int k=in1->readPos;k<in1->readPos+nTrackPointsToAdd;k++) {
grain *g0 = in0->read(k);
grain *g1 = in1->read(k);
grain *g2 = in2->read(k);
g0V.push_back(g0);
g1V.push_back(g1);
g2V.push_back(g2);
}
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
int size = (int)g1V.size();
for(int k=0;k<size;k++) {
smser->addTrackPoints(g0V[k],g1V[k],g2V[k]);
}
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
in0->advance(nTrackPointsToAdd);
in1->advance(nTrackPointsToAdd);
in2->advance(nTrackPointsToAdd);
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
}
long subband :: markInit(bool bSet, int c)
{
long n;
if(sub) n = res*sub->markInit(bSet,c);
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
if(!sub) n = max((long)0,min((long)1,min(nFramesAdded-nFramesMarked[c]-1,4-(nFramesMarked[c]-nFramesAssigned[c]))));
if(bSet) {
nTrackPointsToMark[c] = n;
}
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return n;
}
void subband :: markDuplicates(int c)
{
long ntodo = parent?1:nTrackPointsToMark[c];
long ndone = 0;
while(ndone<ntodo) {
smser->markDuplicates(nTrackPointsMarked[c],
parent?parent->smser:NULL,
sub?sub->smser:NULL,
c);
if(nTrackPointsMarked[c]%res==1 || res==1) {
if(sub) sub->markDuplicates(c);
}
ndone++;
nTrackPointsMarked[c]++;
}
}
long subband :: assignInit(bool bSet, int c)
{
long n;
if(sub) n = res*sub->assignInit(bSet,c);
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
if(!sub) n = max((long)0,min((long)1,min(nFramesMarked[c]-nFramesAssigned[c]-1,4+nLatency-(nFramesAssigned[c]-nFramesSynthed))));
if(bSet) {
nTrackPointsToAdvance[c] = n;
nTrackPointsToAssign[c] = n;
if(nTrackPointsToAssign[c]) {
if(nFramesAssigned[c]==0) {
smser->assignTrackPoints(nTrackPointsAssigned[c]++,
parent?parent->smser:NULL,
sub?sub->smser:NULL,
c);
smser->startNewTracks(nTrackPointsStarted[c]++,c);
}
}
}
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return n;
}
long subband :: assignTrackPoints(int c)
{
long ntodo = parent?1:nTrackPointsToAssign[c];
long ndone = 0;
while(ndone<ntodo) {
if(nTrackPointsAssigned[c]%res==0) {
if(sub) sub->assignTrackPoints(c);
smser->assignTrackPoints(nTrackPointsAssigned[c]++,
parent?parent->smser:NULL,
sub?sub->smser:NULL,
c);
if(!parent) startNewTracks(c);
} else {
smser->assignTrackPoints(nTrackPointsAssigned[c]++,
parent?parent->smser:NULL,
sub?sub->smser:NULL,
c);
}
if(parent && parent->res != 1)
parent->smser->startNewTracks(parent->nTrackPointsStarted[c]++,c);
ndone++;
}
return nTrackPointsAssigned[c];
}
void subband :: startNewTracks(int c)
{
if(!parent||!sub||nTrackPointsAssigned[c]%2==1||res==1) {
smser->startNewTracks(nTrackPointsStarted[c]++,c);
}
if(sub&&(nTrackPointsAssigned[c]%2==1||res==1)) {
sub->startNewTracks(c);
}
}
void subband :: advanceTrackPoints(int c)
{
long ntodo = parent?1:nTrackPointsToAdvance[c];
long ndone = 0;
while(ndone<ntodo) {
if(nTrackPointsAdvanced[c]%res==0)
if(sub) sub->advanceTrackPoints(c);
smser->advanceTrackPoints(c);
nTrackPointsMarked[c]--;
nTrackPointsAssigned[c]--;
nTrackPointsStarted[c]--;
nTrackPointsAdvanced[c]++;
ndone++;
}
}
long subband :: getFramesAssigned()
{
long assigned = LONG_MAX;
for(int c=0;c<channels;c++) {
if(nFramesAssigned[c] < assigned)
assigned = nFramesAssigned[c];
}
return assigned;
}
long subband :: getFramesMarked()
{
long marked = LONG_MAX;
for(int c=0;c<channels;c++) {
if(nFramesMarked[c] < marked)
marked = nFramesMarked[c];
}
return marked;
}
long subband :: readInit(bool bSet)
{
long n;
if(sub) n = res*sub->readInit(bSet);
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
if(!sub) n = max((long)0,min((long)1,nFramesInFile-getFramesAssigned()));
if(bSet) {
nTrackPointsToAssign[0] = n;
nTrackPointsToAssign[1] = n;
}
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return n;
}
void subband :: readTrackPointsFromFile(FILE *fp)
{
long ntodo = parent?1:nTrackPointsToAssign[0];
long ndone = 0;
while(ndone<ntodo) {
if(nTrackPointsAssigned[0]%res==0)
if(sub) sub->readTrackPointsFromFile(fp);
smser->readTrackPointsFromFile(fp);
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
nTrackPointsAssigned[0]++;
nTrackPointsAssigned[1]++;
nTrackPointsStarted[0]++;
nTrackPointsStarted[1]++;
nTrackPointsMarked[0]++;
nTrackPointsMarked[1]++;
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
ndone++;
}
}
long subband :: writeTrackPointsToFile(FILE *fp)
{
long ntodo = parent?1:nTrackPointsToSynth;
long ndone = 0;
long frameBytes = 0;
while(ndone<ntodo) {
if(nTrackPointsSynthed%res==0)
if(sub) frameBytes += sub->writeTrackPointsToFile(fp);
frameBytes += smser->writeTrackPointsToFile(fp);
nTrackPointsSynthed++;
ndone++;
}
return frameBytes;
}
long subband :: synthInit(bool bSet)
{
long n;
if(sub) n = res*sub->synthInit(bSet);
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
if(!sub) n = max((long)0,min((long)1,getFramesAssigned()-nFramesSynthed-nLatency));
if(bSet) {
nTrackPointsSynthed = 0;
nTrackPointsToSynth = n;
}
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return n;
}
void subband :: synthTracks()
{
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
real a = aSynth.read(aSynth.readPos);
real f0 = fSynth.read(fSynth.readPos);
real f1;
if(fSynth.n_readable()>=2)
f1 = fSynth.read(fSynth.readPos+1);
else
f1 = f0;
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
long ntodo = parent?1:nTrackPointsToSynth;
long ndone = 0;
while(ndone<ntodo) {
if(nTrackPointsSynthed%res==0)
if(sub) sub->synthTracks();
real df = (f1-f0)/(real)nTrackPointsToSynth;
smser->synthTracks(a,f0+nTrackPointsSynthed*df,f0+(nTrackPointsSynthed+1)*df);
nTrackPointsSynthed++;
ndone++;
}
}
void subband :: readSubSamples()
{
if(sub) sub->readSubSamples();
if(sub) {
audio fromSub[SUB_BUF_SIZE];
long n_fromsub = 0;
do {
n_fromsub = min((long)SUB_BUF_SIZE,sub->n_readable());
n_fromsub = sub->read(fromSub,n_fromsub);
subOut->write(fromSub, n_fromsub);
} while(n_fromsub>0);
}
}
long subband :: write(audio *inBuf, long n, real a, real ratio)
{
write_(inBuf, n, a, ratio);
return n;
}
void subband :: process()
{
do {
addInit(true);
addTrackPoints();
if(nTrackPointsToAdd) stepAddFrame();
} while(nTrackPointsToAdd);
for(int c=0;c<channels;c++) {
do {
markInit(true,c);
markDuplicates(c);
if(nTrackPointsToMark[c]) stepMarkFrame(c);
} while(nTrackPointsToMark[c]);
do {
assignInit(true,c);
assignTrackPoints(c);
advanceTrackPoints(c);
if(nTrackPointsToAssign[c]) stepAssignFrame(c);
} while(nTrackPointsToAssign[c]);
}
}
void subband :: setFramesInFile(long frames)
{
if(sub) sub->setFramesInFile(frames);
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
nFramesInFile = frames;
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
}
long subband :: readFromFile(FILE *fp, real a, real ratio)
{
long samples = 0;
if(readInit(true)) {
int framesize;
real amod;
fread(&framesize,sizeof(int),1,fp);
fread(&amod,sizeof(real),1,fp);
readTrackPointsFromFile(fp);
for(int c=0;c<channels;c++)
stepAssignFrame(c);
samples += framesize;
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
setA(1.0f+amod*(a-1.0f));
setAMod(amod);
setF(1.0f/ratio);
setRatio(ratio);
setFrameSize(framesize,a,ratio);
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
}
return samples;
}
void subband :: writeFramePositionsToFile(FILE *fp)
{
long frames = 0;
// samples, frames, channels, quality
long offset = 2*sizeof(long) + sizeof(int) + sizeof(sbsms_quality);
unsigned short maxtrackindex = ta->size();
fseek(fp,offset,SEEK_SET);
fwrite(&maxtrackindex,sizeof(unsigned short),1,fp); offset += sizeof(unsigned short);
fseek(fp,0,SEEK_END);
for(int k=frameBytes.readPos+nFramesSkipped; k<frameBytes.writePos;k++) {
long samples = inputFrameSize.read(k);
int bytes = frameBytes.read(k);
fwrite(&offset,sizeof(long),1,fp);
fwrite(&samples,sizeof(long),1,fp);
offset += bytes;
frames++;
}
//samples
offset = sizeof(long);
fseek(fp,offset,SEEK_SET);
fwrite(&frames,sizeof(long),1,fp);
}
long subband :: getFramesWrittenToFile()
{
long samples = 0;
bool bRead;
do {
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
bRead = (nFramesSynthed > nFramesRead);
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
if(bRead) {
stepReadFrame();
if(nFramesRead > nFramesSkipped)
samples += inputFrameSize.read(nFramesSynthed);
}
} while(bRead);
return samples;
}
long subband :: writeTracksToFile(FILE *fp)
{
long samples = 0;
bool bReady = false;
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
if(inputFrameSize.n_readable() > nFramesSynthed) bReady = true;
if(!bReady) {
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return 0;
}
int framesize = inputFrameSize.read(nFramesSynthed);
real amod = aMod.read(aMod.readPos);
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
samples += framesize;
int bytes = 0;
if(fp) {
fwrite(&framesize,sizeof(int),1,fp); bytes += sizeof(int);
fwrite(&amod,sizeof(real),1,fp); bytes += sizeof(real);
} else {
nFramesSkipped++;
}
bytes += writeTrackPointsToFile(fp);
frameBytes.write(bytes);
frameRatio.advance(1);
outputFrameSize.advance(1);
return samples;
}
long subband :: writeToFile(FILE *fp)
{
long samples = 0;
if(synthInit(true)) {
samples = writeTracksToFile(fp);
stepSynthFrame();
}
return samples;
}
long subband :: synth()
{
long frames = 0;
do {
if(synthInit(true)) {
synthTracks();
stepSynthFrame();
frames++;
}
} while(nTrackPointsToSynth);
return frames;
}
long subband :: zeroPad()
{
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
frameRatio.write(lastFrameRatio);
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
long samples = zeroPad_();
return samples;
}
long subband :: zeroPad_()
{
if(sub) sub->zeroPad_();
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
setFrameSize(lastInputFrameSize,lastFrameA,lastFrameRatio);
smser->zeroPad(lastOutputFrameSize);
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return lastOutputFrameSize;
}
bool subband :: isframe_readable()
{
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
if(!outputFrameSize.n_readable())
return false;
long n = outputFrameSize.read(outputFrameSize.readPos);
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return (n_readable()>=n);
}
long subband :: getSamplesQueued()
{
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
long n = (long)round2int(samplesQueued);
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return n;
}
long subband :: getFramesQueued()
{
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
long n = outputFrameSize.n_readable();
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return n;
}
long subband :: getFramesAtFront()
{
if(sub) return sub->getFramesAtFront();
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
long n = in1->n_readable();
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return n;
}
long subband :: getFramesAtBack()
{
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
long n = getFramesAssigned() - nFramesSynthed;
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return n;
}
long subband :: getLastInputFrameSize()
{
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
long n = lastInputFrameSize;
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
return n;
}
long subband :: n_readable()
{
#ifdef MULTITHREADED
pthread_mutex_lock(&bufferMutex);
#endif
long n = outMixer->n_readable();
#ifdef MULTITHREADED
pthread_mutex_unlock(&bufferMutex);
#endif
return n;
}
long subband :: read(audio *buf, real *ratio0, real *ratio1)
{
readSubSamples();
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
long n = 0;
if(outputFrameSize.n_readable() >= 2) {
n = outputFrameSize.read(outputFrameSize.readPos);
if(n_readable()>=n) {
real rat0 = frameRatio.read(frameRatio.readPos);
real rat1 = frameRatio.read(frameRatio.readPos+1);
if(ratio0 != NULL) *ratio0 = rat0;
if(ratio1 != NULL) *ratio1 = rat1;
samplesQueued -= n*0.5f*(rat0+rat1);
outputFrameSize.advance(1);
inputFrameSize.advance(1);
frameRatio.advance(1);
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
if(buf) {
stepReadFrame();
}
n = read(buf, n);
} else {
n = 0;
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
}
} else {
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
}
return n;
}
long subband :: read(audio *buf, long n)
{
if(n==0)
return 0;
long n_read = n;
#ifdef MULTITHREADED
pthread_mutex_lock(&bufferMutex);
#endif
if(buf) n_read = outMixer->read(buf, n_read);
outMixer->advance(n_read);
#ifdef MULTITHREADED
pthread_mutex_unlock(&bufferMutex);
#endif
return n_read;
}
void subband :: writingComplete()
{
if(sub) sub->writingComplete();
#ifdef MULTITHREADED
pthread_mutex_lock(&dataMutex);
#endif
nLatency = 0;
bWritingComplete = true;
#ifdef MULTITHREADED
pthread_mutex_unlock(&dataMutex);
#endif
}
long subband :: preAnalyze(audio *buf, long n, real a, real ratio)
{
long nwritten = 0;
while(nwritten<n) {
long ntowrite = min((long)(inPre->h),n-nwritten);
inPre->write(buf+nwritten,ntowrite);
nwritten += ntowrite;
long ng_read = 0;
for(int k=inPre->readPos;k<inPre->writePos;k++) {
if(nDropped < nToDrop) {
nDropped++;
} else {
if(!parent && (nTrackPointsWritten)%nGrainsPerFrame == 0) {
grain *g = inPre->read(k);
grain::referenced(g);
real o = calculateOnset(gPrev,g);
onset.write(o);
if(gPrev) grain::forget(gPrev);
gPrev = g;
setA(a);
}
if(!parent && (nTrackPointsWritten+1)%nGrainsPerFrame == 0) {
setAForH(a);
}
if((nTrackPointsWritten+1)%nGrainsPerFrame == 0) {
setH(ratio);
}
nTrackPointsWritten++;
}
ng_read++;
}
inPre->advance(ng_read);
}
long samples = 0;
while(inputFrameSize.n_readable()) {
samples += inputFrameSize.read(inputFrameSize.readPos);
inputFrameSize.advance(1);
outputFrameSize.advance(1);
}
return samples;
}
real subband :: getOnset(long k)
{
real tot = 2.0f*onset.read(k);
real c = 2.0f;
if(k-1>=onset.readPos) {
tot += onset.read(k-1);
c += 1.0f;
}
if(k+1<onset.writePos) {
tot += onset.read(k+1);
c += 1.0f;
}
return tot / c;
}
void subband :: preAnalyzeComplete()
{
long k0 = onset.readPos;
long k1 = onset.writePos;
long kstart = 0;
long kend = 0;
for(long k=k0;k<k1;k++) {
bool bOnset = false;
if(k==k0) {
bOnset = true;
} else {
real o0 = getOnset(k);
if(o0 < 0.1f) continue;
real o1 = getOnset(k-1);
if(o0 < 1.1f*o1) continue;
if(o0 < 0.22f) continue;
bOnset = ((o0 > 0.4f) || (o0>1.4f*o1));
if(!bOnset && k>k0+1) {
real o2 = getOnset(k-2);
bOnset = ((o0 > 1.2f*o1) && (o1 > 1.2f * o2));
if(!bOnset && k>k0+2) {
real o3 = getOnset(k-3);
bOnset = ((o0 > 0.3f) && (o1 > 1.1f * o2) && (o2 > 1.1f * o3));
}
}
}
if(bOnset) {
if(kend != 0) {
calculateA(kstart,kend);
}
kstart = kend;
kend = k;
}
}
calculateA(kstart,k1);
aPreAnalysis.write(1.0f);
aPreAnalysis.advance(1);
}
void subband :: calculateA(long kstart, long kend)
{
real oMax = 0.0f;
real dTotal = 0.0f;
for(long k=kstart;k<kend;k++) {
real o = getOnset(k);
if(o > oMax) oMax = o;
}
oMax *= 1.3;
for(long k=kstart;k<kend;k++) {
real o = getOnset(k);
real d = oMax - o;
dTotal += d;
}
real aAllot = (real)(kend-kstart);
for(long k=kstart;k<kend;k++) {
real o = getOnset(k);
real d = oMax - o;
real da;
if(dTotal == 0.0 || k+1==kend) {
da = aAllot;
} else {
da = d/dTotal*aAllot;
}
dTotal -= d;
aAllot -= da;
aPreAnalysis.write(da);
}
}
real subband :: calculateOnset(grain *g1, grain *g2)
{
_c2evenodd(g2->x, x2[0]->x, x2[1]->x, g2->N);
real o = 1.0f;
if(g1!=NULL) {
int Nover2 = N/2;
int nOnset = 0;
int nThresh = 0;
for(int k=0;k<Nover2;k++) {
real m2 = norm2(x2[0]->x[k]) + norm2(x2[1]->x[k]);
real m1 = norm2(x1[0]->x[k]) + norm2(x1[1]->x[k]);
bool bThresh = (m2 > 1e-6);
bool bOnset = (m2 > 2.0f*m1) && bThresh;
if(bOnset) nOnset++;
if(bThresh) nThresh++;
}
if(nThresh == 0)
o = 0.0f;
else
o = (real)nOnset/(real)nThresh;
}
memcpy(x1[0]->x,x2[0]->x,g2->N*sizeof(audio));
memcpy(x1[1]->x,x2[1]->x,g2->N*sizeof(audio));
return o;
}
}